Professional Documents
Culture Documents
Table of Contents
Table of Contents
Overall design
X2EventManager TriggerEvent
X2DownloadableContent calls
Pod Jobs
Overall design
The XCOM 2 modding SDK provides a variety of methods for implementing changes to the
base game. The following methods were used in order to implement the Long War 2 overhaul
mod:
Long War 2 contains the design changes that are too fundamental or too interconnected to exist
within a standalone mod. It contains a replacement XComGame.upk to allow nearly complete
access to the game systems (excepting elements in native code or Core/Engine).
However, changes to the XComGame.upk are as minimal as possible, favoring adding new
interfaces that allow the desired functionality to be implemented via standalone methods. The
goals of this approach are to minimize difficulty when merging updates/patches released by
Firaxis and to increase intercompatibility with other mods. Thus, many of the changes to the
XComGame.upk will consist of adding TriggerEvent calls or adding delegate function hooks --
these will then be utilized using the same approaches as are used in standalone mods. Very
little - if any - Long War 2 specific code is implemented in XComGame, except for
enabling/reusing pre-existing features that were disabled in the base game. In theory you
should be able to run XCOM 2 using the Long War 2 XComGame.upk and play a regular,
unmodded game of XCOM 2 (except for some bug fixes!).
There are three general methods by which new hooks have been added into XComGame.upk
changes : X2EventManager TriggerEvent, X2DownloadableContent calls, and new config
variables. These correspond to adding additional usable elements to options 1, 3 and 5 above.
X2EventManager TriggerEvent
This is a common, flexible method of allowing Mods to hook themselves into core game
functionality. This method allows passing control to any mod that has registered to the event,
and relative order of execution between mods is supported via the event priority. It is efficient,
Modding Long War 2
flexible, and powerful, and has generally been the favored approach used in the development of
LW2.
However, in some cases a TriggerEvent can cause instabilities. This primarily occurs with
classes that are loaded and functionality that is run when loading into the UIShell and during
campaign startup. In this case, an old version of X2EventManager (loaded during the save into
UIShell, which is used to load soldier for the initial screen) persists while creating a new
campaign, which can cause crashes when starting a new campaign with an existing save file
present in savedata. These will typically be identifiable by an assertion in the log complaining
that the event delegate function you are using to service the event does not exist in some
completely unrelated class, often a base-game glass like XComGameState_Item. In many
cases we replaced this functionality with the X2DownloadableContentInfo method in order to
avoid such issues.
Data passing is often handled by the class XComLWTuple, which has been added to the
XComGame package. Note that the functionality of XComLWTuple is identical to that of the
LWTuple previous released in the Toolbox mod, but the two are not directly interoperable. The
XComLWTuple class is used to pass data between XComGame and mod components, while
the LWTuple class is used to pass data directly between mod components.
Not all triggered events use XComLWTuple - it is used only when more data has to be passed
than can be handled by the two EventData / EventSource objects specified in the TriggerEvent
parameters, or when the event is expected to be of type ELR_Immediate, and data has to be
passed back to the triggering function.
//setup Tuple-to pass the overkill damage, and pass/return the bleedoutchance
Tuple = new class'XComLWTuple';
Tuple.Id = 'OverrideBleedoutChance';
Tuple.Data.Add(2);
Tuple.Data[0].kind = XComLWTVInt;
Tuple.Data[0].i = BleedoutChance;
Tuple.Data[1].kind = XComLWTVInt;
Tuple.Data[1].i = OverkillDamage;
return Tuple.Data[0].i;
}
Modding Long War 2
X2DownloadableContent calls
These are created in the same manner that Firaxis created them -- by adding new methods to
the X2DownloadableContent class in XComGame. This works, but carries with it a few
restrictions.
Because class X2DownloadableContentInfo is native(Core), its class variable list must remain
synchronized with the native C++ code defines in XCom2.exe. Therefore it is not possible to
add config or localized variables to X2DownloadableContentInfo. However, adding new non-
native functions works without issue. This is how new methods were added to provide additional
hooks.
Further, the X2DownloadableContentInfo method is less efficient. It always loops over all
installed mods, making one call for each mod present. For most mods, this results in the default
nothing happens, but it adds overhead not present in the registered system from
X2EventManager. The order in which X2DownloadableContent calls are made is dependent
upon the mod load order, and there is no way in which to override or control this.
X2DownloadableContentInfo for this reason was only typically used for the following two cases :
1) passing structure data that was awkward/difficult to pass via XComLWTuple, 2) The code can
be run during UIShell / campaign-startup in such a way as to cause fatal CTD errors when using
X2EventManager calls.
/// <summary>
/// Called from XComParcelManager:ChooseSoldierSpawn
// Allows DLC/Mods to override the soldier spawn point selection logic
// return the selected spawn point, or none to use default logic
/// </summary>
static function XComGroupSpawn OverrideSoldierSpawn(vector ObjectiveLocation,
array<XComGroupSpawn> arrSpawns)
{
return none;
}
Modding Long War 2
These config variable can be modified by mod config merging in the same manner as any other
config variable in XCOM 2, allowing mods the ability to change the default behavior of the
game. Without changing the config, the behavior will be identical to the base game functionality.
An example of this is :
// If this flag is set, units in yellow alert will not peek around cover to determine LoS - similar to
// green units. This is useful when yellow alert is enabled because you can be in a situation where a
// soldier is only a single tile out of LoS from a green unit, and that neighboring tile that they would
// have LoS from is the tile they will use to peek. The unit will appear to be out of LoS of any unit, but
// any action that alerts that nearby pod will suddenly bring you into LoS and activate the pod when it
// begins peeking. Examples are a nearby out-of-los pod activating when you shoot at another pod you can
// see from concealment, or a nearby pod activating despite no aliens being in LoS when you break
// concealment by hacking an objective (which alerts all pods).
var config bool NoPeekInYellowAlert;
The UI classes that are still class overrides remain where we needed to make extensive
changes to the UI elements. Even if we rewrote these changes to not require a class override,
its likely that any other mod overriding these same UI classes would not be compatible despite
something like the Alternative Mod Launcher not reporting a potential conflict, simply because
two mods attempting to radically rewrite the UI will likely interfere with each other unless they
were specifically written to be aware of the other mod. For example, by positioning UI elements
on top of each other, assuming it was using empty space.
The mechanism by which these UI class overrides occurs has changed from base XCOM 2.
The base ModClassOverrides is not recursive -- it wont allow an override of an override. We
have added some specific instances of overriding class which allows these classes to have their
overrides overridden. This functionality will be added with the first LW2 patch to the Helpers_LW
class, with config in XComGameCore.ini. The classes so affected are :
[XComGame.Helpers_LW]
Modding Long War 2
+UIDynamicClassOverrides=(BaseGameClass="UISquadSelect",
ModClass="LW_Toolbox_Integrated.UISquadSelect_LW")
+UIDynamicClassOverrides=(BaseGameClass="UIAfterAction",
ModClass="LW_Toolbox_Integrated.UIAfterAction_LW")
+UIDynamicClassOverrides=(BaseGameClass="UIStrategyMapItem_Region",
ModClass="LW_Overhaul.UIStrategyMapItem_Region_LW")
+UIDynamicClassOverrides=(BaseGameClass="UIStrategyMapItem_Mission",
ModClass="LW_Overhaul.UIStrategyMapItem_Mission_LW")
+UIDynamicClassOverrides=(BaseGameClass="UIOptionsPCScreen",
ModClass="LW_Toolbox_Integrated.UIOptionsPCScreen_LW")
+UIDynamicClassOverrides=(BaseGameClass="UIPersonnel_SoldierListItem",
ModClass="LW_Toolbox_Integrated.UIPersonnel_SoldierListItem_LW")
The format is the same as for regular ModClassOverrides. One of the above classes can be in
turn overridden, although as with regular class overrides, only one mod may do so. The format
for such would be, for example :
+UIDynamicClassOverrides=(BaseGameClass="UISquadSelect_LW",
ModClass="MyNewMod.UISquadSelect_MyNewMod")
One class was left as a regular class Override -- X2Action_MoveClimbWall. This class was a
stub left in base XCOM 2, and no base XCOM 2 units use the associated traversal
eTraversal_WallClimb. This traversal (and the override class) were used in the standalone
AlienPack. This X2Action should work for any character type that allows the associated
traversal.
Long War 2 changes many of the fundamental systems of XCOM 2, so even outside of class
overrides it is probable that many other mods will either not work or not work completely with
Long War 2 simply because the underlying systems they were modding have been changed.
Such conflicts wont be reported by the AML simply because there is no apparently conflict - the
situation is more like mods breaking after an official game patch.
Tuple.Data[0].Kind = LWTVInt;
Tuple.Data[0].i = Major;
Tuple.Data[1].Kind = LWTVInt;
Tuple.Data[1].i = Minor;
Tuple.Data[2].Kind = LWTVInt;
Tuple.Data[2].i = Build;
Modding Long War 2
On release, the Build is undefined, but is reserved for possible future use.
The differences are primarily in how units are configured to appear in pods and the job system,
as those systems were reworked a bit for Long War 2.
For all new and base-game enemy types, we have broken down both the
Leader/FollowerLevelSpawnWeights so that each ForceLevel has its own SpawnWeight
defined. This is in contrast to the base game, which defined things as a simpler on/off binary. As
is usually required for mod interoperability, adding units to SupportedFollowers will allow pods to
be created consisting of multiple types.
Long War 2 makes more extensive use of the AI Jobs system. This is defined in AIJobs.ini For
one, the JobListing MoveOrderPriority is now obeyed, so that units with certain certain jobs will
act before others. For example, the Scout Job with MoveOrderPriority=10 will take its action
before a unit with the Hunter Job with MoveOrderPriority=35. We have added some new AIJobs
compared to base XCOM 2.
New units should be assigned to which job types they should try and undertake. Relative priority
is defined by the order in the ValidChar array in each JobListing. To make it easier to integrate a
new enemy type in the AIJobs system, we have defined a new config array variable
JobListingAdditions. The format of this config is :
+JobListingAdditions=(JobName=Soldier, NewCharacterName="SectoidM2_LW",
BeforeUnit="Sectoid", AfterUnit="AdvCaptainM2", DefaultPosition=25)
This contains redundant information to allow inserting a new unit into a JobListing ValidChar
array with uncertainty about what other mods may also be inserting new character types. It will
first attempt to place the new unit before the BeforeUnit. If it cannot, then it will attempt to
insert the unit just after the AfterUnit. If it cannot do that either, then it will insert directly by
index value using DefaultPosition.
One change made by Long War 2 that should not need any modder adjustment is the
composition of alien pods. Long War 2 uses larger pods (generally up to 8). The base XCOM 2
always creates alien pods to be of the same unit type, which could result in a single pod of 8
consisting of identical alien unit types (excepting the leader). In Long War 2, such monolithic
alien pods are broken down into more diverse types. There is a hook available for this purpose
that other mods can tie into if they wish, in X2DLCInfo.PostEncounterCreation.
Modding Long War 2
Activities differ from missions in that activities are more like containers for one or more
missions. Narratively speaking, these correspond with actions that the strategy AI is performing,
and which the XCOM player will try and counter. Activities allow the handling of multiple mission
chains, as well as managing the mechanics by which activities (and therefore missions) are
discovered through player actions.
Activities define a variety of things, some via template, and some via config data associated with
that template. In this way creating an activity is somewhat similar to creating a new ability. Each
activity must at the least define :
Duration_Hours=144, \\
DurationRand_Hours=48 \\
)
MissionTree[1] = ( MissionFamilies[0]="Terror_LW", \\
MissionFamilies[1]="Defend_LW", \\
Duration_Hours=24, \\
DurationRand_Hours=5, \\
ForceActivityDetection=true \\
)
The activity template ValidateTemplate method checks for these required elements, and that
each defined mission exists, reporting any missing items.
Further optional information can be defined for each activity. See Long War 2 activities for
further examples.
However, in Long War 2, nearly all items are built individually. The Schematic system present
in base XCOM 2 is not used in these cases. The reason for this revolves around the infiltration
system, and the need to build up a larger roster to support handling multiple missions
simultaneously. Unlike the fatigue system from Long War for XCom: Enemy Within, the player
now requires enough gear to equip multiple squads of soldiers simultaneously. This in turn
drove the decision to remove schematics.
Long War 2 makes use of template mods that remove the schematic system from all existing
item templates. This is true of other modded-in items as well as the base XCOM 2 items.
However, exceptions to this can be made via the config array SchematicsToPreserve. This was
done for the DLC AlienHunter weapons and armor (since they upgrade an existing piece of gear
instead of creating a new one). If not added to this list, modded in items will also have
schematics removed.
This means that strategy-level costs for building items have to be defined within the individual
item template, and not just at the schematic level. Long War 2 makes use of config data that will
reconfigured existing templates to do this, defined in LW_Overhaul.ini. For example, to adjust
the base XCOM 2 magnetic assault rifle :
These same config lines can be used to define how the individual weapon will be used in Long
War 2. These config lines will not be used if the user is not playing Long War 2, allowing a
single mod to be used for both base XCOM 2 and for Long War 2.
One consequence of the removal of schematics is that primary weapons need to be defined
specially so that they display a nice looking inventory image in the Tech popups and when
building them in Engineering. This is done by defining the strInventoryImage value in the item
template to be the image path to the composite image, which in base XCOM 2 was assigned to
the schematic. Alternatively, the InventoryImage field in the Long War 2 ItemTable config can be
used to define this, as shown above.
has its own unique secondary weapon, although this is not a required feature for a new class to
be added.
As in base XCOM 2, techs can provide an item when research is complete (for example,
Proving Ground). With the removal of schematics, Long War 2 makes more use of this, with
many techs granting a single copy of an item related to the research. For example the tech
LaserWeapons now grants a single AssaultRifle_LS weapon item upon research completion.
This is not technically required, but may be included for balance.
As with weapon items, Techs can be configured specifically for Long War 2 in the
LW_Overhaul.ini, via the TechTable config array. For example :
+TechTable=(TechTemplateName="LaserWeapons", ProvingGround=false,
ResearchPointCost=4000, ModPointsToCompleteOnly=false,
PrereqTech1="ModularWeapons", PrereqTech2="HybridMaterials",
PrereqTech3="", SupplyCost=0,AlloyCost=2,
CrystalCost=5, CoreCost=0, ReqItemTemplateName1="",
ReqItemCost1=0, ReqItemTemplateName2="",
ReqItemCost2=0, ItemGranted="AssaultRifle_LS",
RequiredScienceScore=10)
This TechTable entry is only used if Long War 2 is active, thus allowing a single mod that adds
a tech to be used both for base XCOM 2 and Long War 2.
Instead of a set of 3 Dark Events per GuerillaOps mission as in base XCOM 2, Dark Events in
Long War 2 are tied to two particular activities -- COINResearch and COINOps. The
COINResearch activity handles tactical Dark Events, while COINOps handles strategy Dark
Events. This is defined via the X2DarkEventTemplate.bTactical field.
Long War 2 redefines many Dark Events to be of permanent duration, so once achieved they
persist for the rest of the campaign. These are typically in the form of an upgrade to one or
more ADVENT/alien units. Other Dark Events are of limited duration. Because of this, is it
possible for more than 3 Dark Events to be active at once (indeed, 10+ by mid/late campaign is
not uncommon).
Some base XCOM 2 Dark Events did not work with the reworked strategy layer, so were
removed. This was done in code, not via config. Mods that add sets of Dark Events, only some
Modding Long War 2
of which may be appropriate, may need to check to see if Long War 2 is installed before some
of them are activated.
Long War 2 defines 2 new config arrays within AI.ini - BehaviorRemovals and NewBehaviors.
These are placed in AI.ini in the section [LW_Overhaul.UIScreenListener_Shell]
BehaviorRemoval will remove a single named entry from the Behaviors array, as defined by
BehaviorName. This allows removal and replacement of targeted lines without the nuclear
option of removing all of them, or trying to match the entire (possibly multi-line) entry.
This removal occurs when the UIShell is loaded, which is after base XCOM 2 loads the config
data and validates it. For this reason, we also added the NewBehaviors, which adds new entries
to the Behaviors array at this same time. After all such config entries are processed, the
BehaviorTree validation is run again, which will display (to log and as redscreen) any errors that
occur due to this modification.
3) For loading screen movies, the Bink audio will always be suppressed and the akEvent
buzzing audio will always be played. We do not know of any workaround for this. Such
loading screen movies should be configured to play in XComEngine.ini in the section
[FullScreenMovie]. Each movie should be added to both the UnskippableMovies and
LoadMapMovies arrays.
4) For in-game cutscene movies, a NarrativeMoment archetype should be created for each
bink to be played. The name of the Bink movie file (without extension) should go into the
str Bink field, and the Bink Audio Event field should be left blank (this will allow
embedded Bink audio to be played).
5) The narrative moment would be used as usual, typically played in an objective, or linked
to a tech :
Template.TechStartedNarrative = "LWNarrativeMoments_Bink.Strategy.Autopsy_MutonM3_LW";
Up- and down-throttling guided pods either to or away from XCOM depending on how many
active units there are and the difficulty level. Up-throttling would move pods toward XCOM after
a few turns of no contact, while down-throttling moved pods away from XCOM if they were
Modding Long War 2
already engaged with enough enemies. Both of these systems have been disabled in Long
War 2: the pods will not magically move toward or away from you to attempt to control the
number of engaged enemies at any given time.
The cross-pod interception would cause a pod to stop patrolling and move directly toward
XCOM if the midpoint of the XCOM squad passes the midpoint of the pod along the line of play.
In other words, if you passed a pod without activating it on the way to the objective, it would stop
patrolling and start moving directly toward XCOM. This system has also been disabled.
The map-wide alerts are used only in a small number of special missions (especially Avenger
Defense) and are usually placed by the Kismet script for a mission. For the most part these
integrate tightly with AIJobs for these special missions. The Pod Jobs system does not replace
these mechanisms, but it can co-exist with them (see the special Avenger Defense jobs in the
.ini for example to get LW2s new modified encounters to work in much the same way with the
default Avenger Defense kismet).
Together, these systems controlled how unactivated pods moved around in a mission, and parts
2, 3, and 4 controlled how a pod would move outside its normal patrol encounter zone. Pod
Jobs replaces 2 and 3. The purpose of pod jobs is to get unactivated pods to move around the
map, generally in response to XCOM - the pod manager places alerts for particular pods to get
them to move to particular locations.
Pod Jobs
Pod Jobs are managed by the XComGameState_LWPodManager class. The jobs themselves
are defined in LWPodJobs_DefaultJobSet from templates of type LWPodJobTemplate.
Subclasses of XComGameState_LWPodJob define the job behaviors. The jobs are configured
in XComLW_PodManager.ini, which has a large comment at the top describing all the
configurable options for defining a job.
When most missions begin, all pods are typically in green alert and XCOM is frequently
concealed. In this state pod jobs are not active and most pods will patrol within their zones. Pod
Jobs do not activate until XCOM breaks concealment, and many jobs are not available until at
least one pod enters red alert. At this point the enemies are aware of XCOM and (most) jobs
may begin. Pods that enter yellow alert can take jobs once squad concealment is broken:
something has aroused their suspicion, but until the first pod enters red alert green pods will not
take jobs.
Pod Jobs are processed at the start of each alien turn, where jobs are assigned to eligible pods
and then executed. Job execution generally sets an alert at a particular location on the map
depending on the job in question. Pods that take a job will typically keep that job until they
activate, they reach their destination, or enough turns have passed without being able to
complete the job, but exactly when a job is considered finished depends on the job itself. The
job generally will drop an alert indicating where the pod should move, and the pod will then
move toward that alert during usual AI turn processing. Once a pod activates, pod jobs are no
longer useful for it and the default AI btree takes over.
1. Intercept - the pod will move toward XCOMs last known position in an attempt to
engage them.
2. Block - The pod will try to move between XCOM and the objective, but will not move to
engage.
3. Flank - The pod will attempt to move to a position off to the side of XCOM (relative to the
LoP), and wait there, shadowing XCOM as they move until they become engaged with
another pod, at which time theyll move in to attack from the flank. This job shows some
limited communication between pods.
4. Guard - The pod will move to the objective in an attempt to protect it. If it reaches the
objective without finding XCOM, itll give up the job and may choose another.
5. Defend - The pod will move to the objective and stay there even if unengaged, patrolling
in a small area around the objective.
New jobs can be defined by adding job templates to the LWPodJobs_DefaultJobSet. If the job is
a simple move to a particular location they can often be implemented through the existing
XComGameState_LWPodJob_MoveToLocation class without requiring any new code except to
determine and optionally update the position they should move to with delegates set in the
template. If the job is more complex, it may require a custom subclass of
XComGameState_LWPodJob to handle its behavior (see XComGameState_LWPodJob_Flank
for an example, only the flank job required a custom subclass).
Several of the new mission types introduced in Long War 2 do have special plot and/or parcel
requirements, and so new assets wont be selected for these missions unless the required
objective tags are added to the new asset (after verifying they contain the necessary custom
objects). For example, the Jailbreak mission definition contains the following line:
RequiredParcelObjectiveTags[0]="Jailbreak_LW", \\
Only parcels with this tag are chosen. This particular instance requires at least 6 VIP objective
spawn points on the map. Only one of the base game parcels had enough, so we added clones
of some of the other CityCenter parcels with jail cells, adding additional spawn points in the cells
and tagging them with this mission type.
RequiredPlotObjectiveTags[0]="Rendezvous", \\
These plots dont have anything too special, just slots for regular wilderness parcels. They
disallow the more built-up ADVENT facilities, UFOs, or the Avenger from appearing since these
mission types also use Wilderness maps.
Modding Long War 2
Many other new mission types just use standard plot and parcel requirements, and the
additional maps should work with these out of the box. For example, IntelRaid and
TroopManeuvers. The full list of missions and their plot/parcel requirements can be found in
XComMissions.ini.