Jump to content

R&D XCOM Map Alterations


Amineri

Recommended Posts

  • Replies 473
  • Created
  • Last Reply

Top Posters In This Topic

Tried to add a new pods on maps dynamically, but failed. :sad:

 

As I suspected, XComAlienPodManager does affects XComAlienPod map object. In fact, it initializes them before any actual deployment begins. I got crazy with battle init process and can't claim I understand it all, but that's what I found out so far.

 

XGBattle has two states (amongst many others): Initing and Loading. First is used for creating a battle and second for loading a battle from save. Both states call for InitPlayers function which initializes all players.

 

XGBattle_SP extends XGBattle for single player game. InitPlayers function spawns XComAlienPodManager class and calls for InitPods pods function, which iterates through all XComAlienPod objects and initializes them. If I understood correctly, it is done before Overmind initialization. XGAIPlayer spawns an Overmind, after AI player is created, and Overmind spawns XGDeployAI to perform actual deployment.

 

I tried to spawn a new XComAlienPod Actor at different initialization states, but failed. My code works somehow, but no aliens are actually spawned at new point. In fact, no aliens are spawned at all. Either I'm doing everything wrong, or it has something to do with pod meshes, which are defined for map pods in map files directly and for which I use default values.

 

My next step will be to understand how TheWorld.PersistentLevel object works and try to add new pods into maps directly. But it will be difficult.

 

Now, some more info on map objects.

 

Any scripted class which has "placeable" keyword can be placed on the map. That is how all pods, meld containers, radar arrays, salvage items, etc are placed on maps.

 

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

 

 

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)

 

Typically, map pods contain location data, patrol path data, meshes data. Special mission pods can force alien type via ForceAlienType (boolean) and AlienType variables.

 

XComSpawnPoint class is used to mark positions of XCOM soldiers, civilians and dynamic aliens. XCOM soldiers and civilians use base XComSpawnPoint class and aliens use XComSpawnPoint_Alien class, which extends XComSpawnPoint class. Spawn points contain location data mostly.

Edited by wghost81
Link to comment
Share on other sites

 

I tried to spawn a new XComAlienPod Actor at different initialization states, but failed. My code works somehow, but no aliens are actually spawned at new point. In fact, no aliens are spawned at all. Either I'm doing everything wrong, or it has something to do with pod meshes, which are defined for map pods in map files directly and for which I use default values.

 

Basically all of the initialization of meshes and other art assets is controlled through XGBattleDesc :

  • BuildAlienContent
  • BuildAlienContentFromLoadout
  • DetermineAlienPawnContent
  • GenerateAliens
  • InitAlienLoadoutInfos
  • MapAlienToPawn

In particular InitAlienLoadoutInfos loops through all of the pods and adds the pod members info to m_arrTeamLoadoutInfos[PlayerIndex].m_arrUnits

 

m_arrTeamLoadoutInfos is accessed through the accessor function XGBattleDesc.GetTeamLoadoutInfo. However it is never invoked visibly in XComGame.upk, so I can only suppose that it is called from a native function.

 

I'd had occasional problems with not loading pawn meshes for aliens with early versions of the larger pods mod, and had to modify the InitAlienLoadoutInfos function, so it does actually have functionality.

 

InitAlienLoadoutInfos is called from XGBattle_SP.InitDescription. InitDescription is the 3rd line in XGBattle.state'Initing', so it gets called quite early.

 

 

This is how meshes are loaded for aliens defined in the strategy game, at least. If aliens defined in the maps files have to have their assets cooked into the map, that would be strange and awkward, but I suppose it could be.

Edited by Amineri
Link to comment
Share on other sites

Regarding class'XComAlienPod' :

 

For the most part these are accessed from the map via commands such as :

    foreach WorldInfo.AllActors(class'XComAlienPod', kPod)
    {
        arrPods.AddItem(kPod);        
    }

However, it is possible to spawn new objects of this type.

 

In XComAlienPodManager.ConvertPodType (which converts between specialist version such as XComAlienPod_Abduction) is the code :

            kClassName = 'XComAlienPod';
            kNewPodType = class'XComAlienPod';
            // End:0xE1
            if(kSpawn.kSpawnLoc.IsA(kClassName))
            {
                return false;
            }
            ++ m_nReplacedPods;
            kPod = XComAlienPod(Spawn(kNewPodType,,, kSpawn.kSpawnLoc.Location, kSpawn.kSpawnLoc.Rotation,, true));
            kPod.SetData(kSpawn.kSpawnLoc);
            m_arrSpawnList[iSpawnIdx].kSpawnLoc = kPod;

which spawns a new XComAlienPod of a particular type and then replaces the old version within the XComAlienPodManager.m_arrSpawnList.

 

An even more interesting example of creating a brand new XComAlienPod dynamically is in XComAlienPodManager.CheckAlienCounts

                if((iCurrTotal < XComTacticalGRI(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kBattle.m_kDesc.m_kAlienInfo.iNumAliens) && arrPathPods.Length > 0)
                {
                    iRand = class'XComEngine'.static.SyncRand(arrPathPods.Length, (string(Name) @ string(GetStateName())) @ string(GetFuncName()));
                    kPod = Spawn(class'XComAlienPod',,, arrPathPods[iRand].Location, arrPathPods[iRand].Rotation,, true);
                    kPod.SetData(arrPathPods[iRand], false);
                    kPod.m_kPathOrigin = arrPathPods[iRand];
                    kPod.NumAliens = Min(2, XComTacticalGRI(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kBattle.m_kDesc.m_kAlienInfo.iNumAliens - iCurrTotal);
                    kPod.Init();
                    kPodList.AddItem(kPod);
                    arrPathPods.Remove(iRand, 1);
                    iCurrTotal += kPod.NumAliens;
                    SetDynamicAI(kPod);
                    // [Loop Continue]
                    goto J0x897;
                }

This is a loop that can add multiple new class'XComAlienPod' objects, which are stored into the out parameter dynamic array kPodList.

 

CheckAlienCounts is called from XComAlienPodManager.SpawnAllPodAliens. Presumably it is designed to dynamically create additional XComAlienPods in order to support more aliens.

Link to comment
Share on other sites

Amineri, yes, I used the exact same examples to spawn new pods, but failed. As far as I can tell, none of those examples are actually used in game. BTW, the last one seems to attempt to spawn dynamic patrols. Since most of those function use min and max alien per pod values, defined in map packages, I suspect they are used for creating debug missions. Otherwise larger pods wouldn't work.
Link to comment
Share on other sites

Seems, I finally found something. :smile:

 

I skipped all the checks in XGAIPlayer.CreateSquad to call SpawnAliensFromList for regular missions. I also changed number of aliens to 10 from 4. I started a new Impossible game and got 8 totally randomly placed and already activated sectoids. It's not what I need, but at least it's a start. Now I need to understand how it can be re-purposed to create fully-functional alien pods, controlled by XComAlienPodManager. Hope it can be done.

Edited by wghost81
Link to comment
Share on other sites

Turns out I was doing a right thing from the beginning, but I was simply doing it wrong. :smile:

 

Now, that's a brand new pod, which falls into pod manager "jurisdiction":

 

http://i.imgur.com/1yyNxFw.jpg

 

It acts just like normal pod, only problem is: it is placed at the world center. :smile: I used a "borrowed" variable to pass new pod location to Spawn function, but it didn't worked. May be because it was borrowed, I don't know. But I intend to find out. :smile:

Edited by wghost81
Link to comment
Share on other sites

Here it is :smile:

 

http://i.imgur.com/fGzXCxR.jpg

 

Turns out, there are XComNoSpawnVolume map objects, which define alien and civilian no spawn zones. And I managed to pick a test point right inside one of them. :smile:

 

Randomly spawned individual aliens do not respect no spawn zones (at least as it seemed to me), but alien pods do. That's why my newly spawned pod ended up in center of the world: spawn point was invalid, so engine relocated new actor to default (0, 0, 0) point.

 

Now, what exactly I did. I've added a test code into XGDeployAI.GetPossibleSpawns:

vValidLoc = World().FindClosestValidLocation(vect(1391, 623, 64), false, false, true);
kPod = Spawn(class'XComAlienPod',,, vValidLoc,,, true);
kPod.Init();
m_arrPossibleSpawns.AddItem(kPod);
Since XGDeployAI deploys whatever it can wherever it can :smile: it worked just fine: my new pod "placeholder" was successfully occupied, XComAlienPodManager successfully converted new pod into abduction pod and performed actual pod spawn.

 

Level bounds are "known" to the World object, so my original plan was to add a number of random spawn points inside level, let the existing code sort them along with original ones, divide the whole set to iNumPods subsets and deploy all pods at random points inside subsets. This will ensure that pods will be spawned around the whole map and won't end up clustered in one corner.

Edited by wghost81
Link to comment
Share on other sites

Sounds like some quite excellent progress :)

 

The above two posts represent adding additional pods that spawn during the XGBattle_SP.AlienPlayerDeferredInit(), correct? As best I can tell, in order to speed up loading times, only the human side pawns/units are loaded/created before presenting the "Start Mission" button to the player, with the alien side loading in the background in the first couple of seconds while the player is making the first move.

 

Being able to add additional random pods (or replacing old pods with new randomized locations) will go a long way toward adding replayability to the maps.

 

However what I'd also be interested in is a way to trigger aliens appearing during a mission, in a manner simlar to how the Mutons appear in the Slingshot Confounding Light mission. (I recognize that it's quite possible that the particle effects may be baked into the map instead of in a separate upk).

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...