Spawn Points - XCOM:EU 2012

From Nexus Mods Wiki
Jump to: navigation, search


Overview

The following is derived from the Nexus Forums threads Modding EXALT and R&D XCOM Map Alterations.

Spawn points (objects of XComSpawnPoint class) are used to mark positions of XCOM soldiers, civilians and dynamic aliens on map. (See the wiki article Maps - XCOM:EU 2012 for more about maps in general.) XCOM soldiers and civilians use base XComSpawnPoint class and aliens use XComSpawnPoint_Alien class.

XComSpawnPoint_Alien inherits from XComSpawnPoint and is used specifically for dynamic alien spawns (See the wiki article Units deployment - XCOM:EU 2012 for more about the Wave System that populates these spawn points.)

Spawn points contain (mostly) the location of a specific point in space on the current map. (See #TheWorld.PersistentLevel.XComSpawnPoint_Alien_40 in the Separate Content section.)

Programs and Tools

Details

Spawn Points

Technically a single spawn point is a single tile position, and so is only valid for a single unit. However, pawns are placed in a 3x3 grid centered on the defined map spawn point. In general usage the six spawn points for XCOM Soldiers (albeit multiple sets of six for the multiple possible PlayerStart positions) have come to be referred to as if a single 'spawn point' circle, with the "circle" implied and the term used for both XCOM soldiers and aliens.

XComAlienPodManager creates additional spawn points in the 3x3 grid centered on the defined map spawn point, and then places the alien pawns around the newly created spawn point. For 2 aliens they are at 180º ends, while for 3 aliens they are at 120º. Hence things can start to get a bit crowded once more than 8 aliens are getting spawned. Experiments with placing the first alien at the center point and the remaining aliens around the center point have allowed up to 9 aliens to be placed, completely filling out the 3x3 grid.

There is a bunch of code present to try and place aliens in "good" locations, including moving the point up the Z-axis and then snapping it to the floor. However attempts to array aliens in a larger circle radius extending beyond the 3x3 grid started to have problems. (In theory this should be okay, though.)

Aliens are spawned from the definitions in the strategy game (e.g. XGStrategyAI.DetermineAbductionSquad or XGStrategyAI.DetermineSpecialMissionSquad) are created in XComAlienPodManager.OvermindSpawn. However this doesn't appear to be how dynamic alien stats are initialized, which makes it more difficult to "beef up" the alien stats for things like the final Temple Ship mission.

The spawn point is retrieved separately for each alien placed :

kSpawnPt = kPod.GetSpawnPoint(iNum, vLoc, true);

This function is in XComAlienPod.

XComAlienPod.GetSpawnPoint has a couple of branches. If the third (optional) parameter is left blank or is false, then the code uses CustomStartLocations (but only if the array has non-zero length). Code such as :

vLoc_Out = XComTacticalGRI(WorldInfo.GRI).GetClosestValidLocation(vLoc_Out, none,, false);

is used liberally to try and ensure a valid spawn location.

If the 3rd parameter is true, then the "circle method" of generating additional spawn points around the center point is used:

if(iAlien < NumAliens)
{
  vLoc_Out = GetDistributedLocationAround(Location, iAlien, Rotation, true);
  kSpawnPoint = Spawn(class'XComSpawnPoint_Alien',,, vLoc_Out, rotator(Location - vLoc_Out),, true);
  return kSpawnPoint;
}

The GetDistributedLocationAround function selects a position in an adjacent tile (in the 3x3 grid surrounding the given spawn point location), and the next line spawns a new XComSpawnPoint_Alien at the designated location, and returns that spawn point to place the alien into.

A similar method was modded to dynamically create additional generic spawn points near the existing six soldier spawn points in order to handle spawning more than six soldiers (without having to alter the mapfile).

Actually, a map package doesn't provide the info on individual spawn points. It provides only XComAlienPod info, which holds default properties on the whole "Spawn" and location is just one of those. XComAlienPod map objects serve as "templates" for creating pods of a specified type at a specified location. They deal with the pod as a whole.

There are NumAliens_Min and NumAliens_Max properties. They are used in PodManager to create test pods for debug purposes.

Council Missions and EXALT Missions use different dynamic aliens spawn methods. All EXALT maps, except HQ, use the XComWaveSystem to add dynamic aliens in waves. Some of the alien stats are defined in map objects, and alien types are chosen randomly from the list of available aliens in the current squad. (See the wiki article Units deployment - XCOM:EU 2012. The XCOM HQ Assault map uses the XComWaveSystem for alien waves deployment too, and it is BIG.

Council Missions and the Temple Ship mission use triggers (zones on map or global events) to spawn a group of aliens. For example, there are a couple of SeqAct_AlienContent_Request and SeqAct_SpawnAlien objects in MainSequence of the Temple Ship map package, in which alien type and some other properties are defined.

XComAlienPod is a base class for all alien pods. It has three child classes: XComAlienPod_Abduction, XComAlienPod_Hunter and XComAlienPod_Terror.

It looks like XComAlienPod can either contain a single Location (in which case all of the aliens in the pod are distributed around that location);

OR

The XComAlienPod can contain a CustomStartLocations array, in which case the alien is placed at CustomStartLocations[iAlien].Location. The CustomStartLocations array is prototyped as a class variable in XComAlienPod as:

var() array<XComSpawnPoint> CustomStartLocations;

which is indeed a dynamic array of XComSpawnPoint's. (The "()" after the var tag that UE Explorer is displaying means it can be edited directly in Unreal Editor.)

XComAlienPod is ... a "Pod". It literally is, in that pods are already placed on maps via XComAlienPod_X archetypes. They are not only locations; although in most cases only location info is used.

Example: (See #XComAlienPod'TheWorld.PersistentLevel.XComAlienPod_2' in Separate Content section.)

Pre-placed pods usually describe some generic pod, so the actual pod is spawned from kAlienSquad array. But you can set all the details inside a map object, i.e. embed a pod in a map directly. You can set pod type, pod main alien ... all the info which is settable in a script, as every class property can be initialized in the archetype.

XComAlienPod map info is used in XComAlienPodManager in functions:

  • LoadInit
  • InitPods
  • SelectSpecialtyPods
  • GenerateSpawnList
  • DebugLogAllPods
  • HasPodsInGroup
  • and in XGAIPlayer_Animal (for civilians): GetGoodCoverPoints_Civilian function.

The Wave System

The following is derived from investigations in the Nexus Mod Talk Forum thread Modding Exalt, by wghost81.

XGOvermind.Init function initializes all map spawns and contains InitWaveSystem call (along with DeployPods call).

InitWaveSystem requests WorldInfo on AllActors of class XComWaveSystem and calls XComWaveSystem.Init function. This function checks if wave is valid and calls InitScalableList function.

InitScalableList iterates through all Pods in AlienSquad and calls AddCharTypeToScalableList for eMain, eSupport1 and eSupport2 types.

AddCharTypeToScalableList sorts aliens by type and adds them to three lists:

  • m_arrScalableList contains all the types available,
  • m_arrScalableFlyInList contains only flying units,
  • m_arrScalableDropInList contains only character with HasTraversal property (i.e. those, who can climb ladders).

When comes the time for another wave, SpawnGroup function is called, which in turn calls to SetScalingAliens function.

If alien group is Scalable (which is set in properties of alien wave), SetScalingAliens initializes AlienType with random alien from one of the Scalable Groups, described above. If group is not scalable, it forces ExaltOperatives for Exalt maps and ThinMan for the other maps.

In DefaultMaps.ini AlienType is defined explicitly for Council Missions via DynamicAliens array, but not defined (eChar_None) for Exalt maps. I think it's done to allow for two different Exalt types (regular and elite) for the same maps.

Interesting note: if we'll try and remove all forced ThinMan for Council Missions, we'll be able to change dynamic aliens by altering SetScalingAliens function.

See also the wiki article Units deployment - XCOM:EU 2012.

Separate Content

TheWorld.PersistentLevel.XComSpawnPoint_Alien_40

FindObjectEntry
Name to find: TheWorld.PersistentLevel.XComSpawnPoint_Alien_40
Found Export Object:
0x000001D6 (470): XComSpawnPoint_Alien'TheWorld.PersistentLevel.XComSpawnPoint_Alien_40'
    TypeRef: 0xFFFFFFB0 -> XComSpawnPoint_Alien
    ParentClassRef: 0x00000000 ->
    OwnerRef: 0x0000000C -> PersistentLevel
    NameIdx: 0x000001EC (Index) 0x00000029 (Numeric) -> XComSpawnPoint_Alien_40
    ArchetypeRef: 0x00000000 ->
    ObjectFlagsH: 0x00000000
    ObjectFlagsL: 0x02070001
        0x00000001: Transactional
        0x00010000: LoadForClient
        0x00020000: LoadForServer
        0x00040000: LoadForEdit
        0x02000000: HasStack
    SerialSize: 0x000000B3 (179)
    SerialOffset: 0x00059B94
    ExportFlags: 0x00000000
    NetObjectCount: 0
    GUID: 00000000000000000000000000000000
    Unknown1: 0x00000000
Attempting deserialization:
UObject:
    PrevObjRef = 0xFFFFFFB0 -> XComSpawnPoint_Alien
UDefaultPropertiesList:
UDefaultProperty:
    NameIdx: 0x000000D1 (Index) 0x00000000 (Numeric) -> Location
    TypeIdx: 0x000001A8 (Index) 0x00000000 (Numeric) -> StructProperty
    PropertySize: 0x0000000C
    ArrayIdx: 0x00000000
    InnerNameIdx: 0x000001D0 (Index) 0x00000000 (Numeric) -> Vector
    Vector (X, Y, Z) = (0x441BFFFD, 0x4536FFFF, 0x4203FFF8) = (624, 2928, 33)
UDefaultProperty:
    NameIdx: 0x00000156 (Index) 0x00000000 (Numeric) -> Rotation
    TypeIdx: 0x000001A8 (Index) 0x00000000 (Numeric) -> StructProperty
    PropertySize: 0x0000000C
    ArrayIdx: 0x00000000
    InnerNameIdx: 0x00000157 (Index) 0x00000000 (Numeric) -> Rotator
    Rotator (Pitch, Yaw, Roll) = (0x00000000, 0xFFFFC000, 0x00000000) = (0, 4294950912, 0)
UDefaultProperty:
    NameIdx: 0x00000018 (Index) 0x00000000 (Numeric) -> bDirtyComponents
    TypeIdx: 0x0000002B (Index) 0x00000000 (Numeric) -> BoolProperty
    PropertySize: 0x00000000
    ArrayIdx: 0x00000000
    Boolean value: 0x00 = false
UDefaultProperty:
    NameIdx: 0x000001AA (Index) 0x00000000 (Numeric) -> Tag
    TypeIdx: 0x000000F8 (Index) 0x00000000 (Numeric) -> NameProperty
    PropertySize: 0x00000008
    ArrayIdx: 0x00000000
    Name: 0x000001EB (Index) 0x00000000 (Numeric) = XComSpawnPoint
UDefaultProperty:
    NameIdx: 0x000000FD (Index) 0x00000000 (Numeric) -> None
Stream relative position: 0x000000B3 (179)
UObjectUnknown:
    Object unknown, can't deserialize!


XComAlienPod'TheWorld.PersistentLevel.XComAlienPod_2'

0x000037AF (14255): XComAlienPod'TheWorld.PersistentLevel.XComAlienPod_2'
    TypeRef: 0xFFFFFF40 -> XComAlienPod
    ParentClassRef: 0x00000000 ->
    OwnerRef: 0x00000770 -> PersistentLevel
    NameIdx: 0x00000E74 (Index) 0x00000003 (Numeric) -> XComAlienPod_2
    ArchetypeRef: 0x00000000 ->
    ObjectFlagsH: 0x00000000
    ObjectFlagsL: 0x02070001
        0x00000001: Transactional
        0x00010000: LoadForClient
        0x00020000: LoadForServer
        0x00040000: LoadForEdit
        0x02000000: HasStack
    SerialSize: 0x00000166 (358)
    SerialOffset: 0x01D12B90
    ExportFlags: 0x00000000
    NetObjectCount: 0
    GUID: 00000000000000000000000000000000
    Unknown1: 0x00000000
UObject:
    PrevObjRef = 0xFFFFFF40 -> XComAlienPod
Can't deserialize stack: skipping!
UDefaultPropertiesList:
UDefaultProperty:
    NameIdx: 0x000009F8 (Index) 0x00000000 (Numeric) -> PodIndex
    TypeIdx: 0x000006BA (Index) 0x00000000 (Numeric) -> IntProperty
    PropertySize: 0x00000004
    ArrayIdx: 0x00000000
    Integer: 0x00000002 = 2
UDefaultProperty:
    NameIdx: 0x0000073A (Index) 0x00000000 (Numeric) -> LoopType
    TypeIdx: 0x000002D7 (Index) 0x00000000 (Numeric) -> ByteProperty
    PropertySize: 0x00000008
    ArrayIdx: 0x00000000
    InnerNameIdx: 0x000004F7 (Index) 0x00000000 (Numeric) -> EPathLoopType
    Name: 0x000009BD (Index) 0x00000000 (Numeric) = PATH_TYPE_FORWARD_BACKWARD_LOOP
UDefaultProperty:
    NameIdx: 0x000006FC (Index) 0x00000000 (Numeric) -> LightEnvironment
    TypeIdx: 0x000008FC (Index) 0x00000000 (Numeric) -> ObjectProperty
    PropertySize: 0x00000004
    ArrayIdx: 0x00000000
    Object: 0x000003D6 = DynamicLightEnvironmentComponent_3538
UDefaultProperty:
    NameIdx: 0x000008F2 (Index) 0x00000000 (Numeric) -> NumAliens_Min
    TypeIdx: 0x000006BA (Index) 0x00000000 (Numeric) -> IntProperty
    PropertySize: 0x00000004
    ArrayIdx: 0x00000000
    Integer: 0x00000003 = 3
UDefaultProperty:
    NameIdx: 0x000008F1 (Index) 0x00000000 (Numeric) -> NumAliens_Max
    TypeIdx: 0x000006BA (Index) 0x00000000 (Numeric) -> IntProperty
    PropertySize: 0x00000004
    ArrayIdx: 0x00000000
    Integer: 0x00000003 = 3
UDefaultProperty:
    NameIdx: 0x000009F9 (Index) 0x00000000 (Numeric) -> PodMesh
    TypeIdx: 0x000008FC (Index) 0x00000000 (Numeric) -> ObjectProperty
    PropertySize: 0x00000004
    ArrayIdx: 0x00000000
    Object: 0x00002FDD = StaticMeshComponent_371
UDefaultProperty:
    NameIdx: 0x000009BF (Index) 0x00000000 (Numeric) -> PathNodes
    TypeIdx: 0x0000017F (Index) 0x00000000 (Numeric) -> ArrayProperty
    PropertySize: 0x00000010
    ArrayIdx: 0x00000000
    NumElements = 0x00000003 = 3
    ArrayInnerType = None
    PathNodes[0]:
    Unsafe guess: It's an Integer: 0x00003799 = 14233 or a Reference: 0x00003799 -> XComAlienPathNode_0
    PathNodes[1]:
    Unsafe guess: It's an Integer: 0x000037A5 = 14245 or a Reference: 0x000037A5 -> XComAlienPathNode_2
    PathNodes[2]:
    Unsafe guess: It's an Integer: 0x0000379A = 14234 or a Reference: 0x0000379A -> XComAlienPathNode_1
UDefaultProperty:
    NameIdx: 0x00000309 (Index) 0x00000000 (Numeric) -> CenterpieceMesh
    TypeIdx: 0x000008FC (Index) 0x00000000 (Numeric) -> ObjectProperty
    PropertySize: 0x00000004
    ArrayIdx: 0x00000000
    Object: 0x00002FDE = StaticMeshComponent_372
UDefaultProperty:
    NameIdx: 0x0000071A (Index) 0x00000000 (Numeric) -> Location
    TypeIdx: 0x00000C54 (Index) 0x00000000 (Numeric) -> StructProperty
    PropertySize: 0x0000000C
    ArrayIdx: 0x00000000
    InnerNameIdx: 0x00000E19 (Index) 0x00000000 (Numeric) -> Vector
    Vector (X, Y, Z) = (0xC4164382, 0xC3D60B27, 0x43420622) = (-601.055, -428.087, 194.024)
UDefaultProperty:
    NameIdx: 0x00000D1B (Index) 0x00000000 (Numeric) -> Tag
    TypeIdx: 0x000008D1 (Index) 0x00000000 (Numeric) -> NameProperty
    PropertySize: 0x00000008
    ArrayIdx: 0x00000000
    Name: 0x00000E74 (Index) 0x00000000 (Numeric) = XComAlienPod
UDefaultProperty:
    NameIdx: 0x000008EA (Index) 0x00000000 (Numeric) -> None
Stream relative position (debug info): 0x00000166 (358)


References

Referred to by this article:



That refer to this article: