Jump to content

UFO Salvage


Hobbes77

Recommended Posts

I'm trying to find out the amounts of UFO Power Sources, Nav Computers, etc. that can be recovered after a UFO mission.

 

I've found the function for the Alien Base on XGStrategyAI, function CreateAlienBase()

function CreateAlienBase()
		default:
			kMission.m_kDesc.m_kAlienSquad = DetermineAlienBaseSquad();
			kMission.m_arrArtifacts[172] = 75;
			kMission.m_arrArtifacts[179] = 3;
			kMission.m_arrArtifacts[171] = int(class'XGTacticalGameCore'.default.UFO_ELERIUM_PER_POWER_SOURCE[Game().GetDifficulty()] * float(kMission.m_arrArtifacts[179]));
			kMission.m_arrArtifacts[178] = 4;
			kMission.m_arrArtifacts[176] = 15;
			kMission.m_arrArtifacts[175] = 10;
			kMission.m_arrArtifacts[174] = 1;
			kMission.m_arrArtifacts[180] = 1;

For individual UFOs there's also some definitions set on DefaultGameCore.ini

ALLOY_UFO_BALANCE=2.5
ALLOY_UFO_BALANCE=2
ALLOY_UFO_BALANCE=2
ALLOY_UFO_BALANCE=2
UFO_ELERIUM_PER_POWER_SOURCE=30
UFO_ELERIUM_PER_POWER_SOURCE=25
UFO_ELERIUM_PER_POWER_SOURCE=25
UFO_ELERIUM_PER_POWER_SOURCE=25

UFOAlloys=30	;eShip_UFOSmallScout
UFOAlloys=60	;eShip_UFOLargeScout
UFOAlloys=80	;eShip_UFOAbductor
UFOAlloys=100	;eShip_UFOSupply
UFOAlloys=130	;eShip_UFOBattle
UFOAlloys=60	;eShip_UFOEthereal

MIN_WRECKED_ALLOYS=0.5
MAX_WRECKED_ALLOYS=0.9
MAX_LOST_WRECKED_ELERIUM=0.75
MIN_LOST_WRECKED_ELERIUM=0.5

However, the DetermineCrashLoot function for UFO at XGStrategy doesn't list the amount of Nav Computers/UFO Power Sources per UFO type.

function DetermineCrashLoot(XGShip_UFO kUFO, XGStrategyActor.EShipWeapon eWeapon)
{
	local int iItem, iSurvived, iTotal, iSurvivalChance;
	local float fAlloySurvival;

	iItem = 170 + 1;
	J0x0f:

	// End:0x61c Loop:True
	if(iItem < 180)
	{
		iTotal = kUFO.m_kTShip.arrSalvage[iItem];
		// End:0x76 Loop:False
		if(iTotal == 0)
		{
		}
		// End:0x60e
		else
		{
			// End:0x89 Loop:False
			if(iItem == 171)
			{
			}
			// End:0x60e
			else
			{
				// ObjectIndex:17235 BlockSize:0
				switch(iItem)
				{
					// End:0xce
					case 179:
						iSurvivalChance = int(class'XGTacticalGameCore'.default.UFO_PS_SURVIVE);
						// End:0x1cb
						break;
					// End:0x100
					case 177:
						iSurvivalChance = int(class'XGTacticalGameCore'.default.UFO_NAV_SURVIVE);
						// End:0x1cb
						break;
					// End:0x132
					case 175:
						iSurvivalChance = int(class'XGTacticalGameCore'.default.UFO_FOOD_SURVIVE);
						// End:0x1cb
						break;
					// End:0x164
					case 174:
						iSurvivalChance = int(class'XGTacticalGameCore'.default.UFO_ENTERTAINMENT_SURVIVE);
						// End:0x1cb
						break;
					// End:0x196
					case 176:
						iSurvivalChance = int(class'XGTacticalGameCore'.default.UFO_STASIS_SURVIVE);
						// End:0x1cb
						break;
					// End:0x1c8
					case 178:
						iSurvivalChance = int(class'XGTacticalGameCore'.default.UFO_SURGERY_SURVIVE);
						// End:0x1cb
						break;
					// End:0xffff
					default:
						fAlloySurvival = RandRange(class'XGTacticalGameCore'.default.MIN_WRECKED_ALLOYS, class'XGTacticalGameCore'.default.MAX_WRECKED_ALLOYS);
						// End:0x24a Loop:False
						if(eWeapon == 6)
						{
							iSurvivalChance = 100;
							fAlloySurvival = 1.00;
						}
						// End:0x27f Loop:False
						if(iItem == 172)
						{
							iSurvived = int(float(iTotal) * fAlloySurvival);
						}
						// End:0x2a5
						else
						{
							iSurvived = GetSurvivingCollectibles(iTotal, iSurvivalChance);
						}
						// End:0x3cd Loop:False
						if(iItem == 179)
						{
							kUFO.m_kTShip.arrSalvage[171] -= int(RandRange(class'XGTacticalGameCore'.default.MIN_LOST_WRECKED_ELERIUM * class'XGTacticalGameCore'.default.UFO_ELERIUM_PER_POWER_SOURCE[Game().GetDifficulty()], class'XGTacticalGameCore'.default.MAX_LOST_WRECKED_ELERIUM * class'XGTacticalGameCore'.default.UFO_ELERIUM_PER_POWER_SOURCE[Game().GetDifficulty()]) * float(iTotal - iSurvived));
						}
						kUFO.m_kTShip.arrSalvage[iItem] = iSurvived;
						// ObjectIndex:17235 BlockSize:0
						switch(iItem)
						{
							// End:0x476
							case 179:
								kUFO.m_kTShip.arrSalvage[186] = iTotal - iSurvived;
								// End:0x60e
								break;
							// End:0x4c7
							case 177:
								kUFO.m_kTShip.arrSalvage[184] = iTotal - iSurvived;
								// End:0x60e
								break;
							// End:0x518
							case 175:
								kUFO.m_kTShip.arrSalvage[182] = iTotal - iSurvived;
								// End:0x60e
								break;
							// End:0x569
							case 174:
								kUFO.m_kTShip.arrSalvage[181] = iTotal - iSurvived;
								// End:0x60e
								break;
							// End:0x5ba
							case 176:
								kUFO.m_kTShip.arrSalvage[183] = iTotal - iSurvived;
								// End:0x60e
								break;
							// End:0x60b
							case 178:
								kUFO.m_kTShip.arrSalvage[185] = iTotal - iSurvived;
								// End:0x60e
								break;
							// End:0xffff
							default:
							}
						}
						++ iItem;
						// This is an implied JumpToken; Continue!
						goto J0x0f;
					}
					iItem = 170 + 1;
					J0x62b:

					// End:0x649 Loop:True
					if(iItem < 190)
					{
						++ iItem;
						// This is an implied JumpToken; Continue!
						goto J0x62b;
					}
}

Any ideas where to look?

Link to comment
Share on other sites

I don't think these are generated in the strategy game but in the tactical game. After all, if you blow up a UFO Power Source / UFO Navigation in the tactical game, you get a damaged item in the strategy game instead of the functional one.

 

This happens in a few places, but the final assemblage of "loot" that you take back to XCOM HQ is assembled in the XGSummaryUI.CollectArtifactsFromDeadAliens. This stores all of the collected items into the kDesc.m_kDropShipCargoInfo.m_arrArtifacts item array. kDesc is a local of type XGBattleDesc.

 

The function itself directly implements the collection of quite a few items, including alien corpses, captives, captured alien weapons from captives, EXALT weapons, and alloy/elerium/meld from robotic units. However weapon fragments, and parts from UFOs are computed elsewhere and simply copied into the array via the code :

    I = 160 + 1;
    J0x15A:
    // End:0x1DE [Loop If]
    if(I < 182)
    {
        kDesc.m_kDropShipCargoInfo.m_arrArtifacts[I] = kDesc.m_arrArtifacts[I];
        ++ I;
        // [Loop Continue]
        goto J0x15A;
    }

Tracing back where this is filled out (at least for UFOs), lead me back to the native function XComCollectible.CollectCollectibles. I'm pretty sure that this is what puts together the list of UFO and weapon fragments collected based on what actors remain active in the map. All this happens in the function XGBattle.CollectLoot

 

Meld however is treated separately with its own function XGBattle.GetRecoveredMeldAmount, which is not a native function. We can see the type of code that must be getting invoked by the native function collecting UFO parts :

    foreach AllActors(class'XComMeldContainerActor', kMeldContainerActor)
    {
        // End:0x8B
        if(kMeldContainerActor.IsCollected() || !kMeldContainerActor.IsDestroyed())
        {
            iMeldRecovered += kMeldContainerActor.GetMeldAmount();
        }        
    } 

It loops over all actors in the map of type class'XComMeldContainerActor', checks that they were recovered or at least not yet destroyed. The actual meld amount is stored with the MeldContainerActor.

 

So I'm thinking that the number of UFO Power Supplies, UFO Navigations, are actually defined by the map designer placing the number of such actors on the map. Damage to the actors during tactical combat results in them being swapped out for the damaged version which is then collected instead.

Edited by Amineri
Link to comment
Share on other sites

Tracing back where this is filled out (at least for UFOs), lead me back to the native function XComCollectible.CollectCollectibles. I'm pretty sure that this is what puts together the list of UFO and weapon fragments collected based on what actors remain active in the map. All this happens in the function XGBattle.CollectLoot

 

I can't seem to be able to find that function. Under which class is located?

Link to comment
Share on other sites

 

Tracing back where this is filled out (at least for UFOs), lead me back to the native function XComCollectible.CollectCollectibles. I'm pretty sure that this is what puts together the list of UFO and weapon fragments collected based on what actors remain active in the map. All this happens in the function XGBattle.CollectLoot

 

I can't seem to be able to find that function. Under which class is located?

 

Native functions are buried in the game engine and not accessible. At least at this point in time, they cannot be modified. While we have figured out how to provide an alternative to a native function (see the 'UPK File Format' thread), the real issue is one of not being certain we are covering everything it does perform.

 

-Dubious-

Link to comment
Share on other sites

I'd put this in spoiler tags but I don't know how.

167 is Stasis Tank

168 is Nav Computers

169 is Alien Surgery

170 is Power Supply

179 is Fusion Core

180 is Ethereal Device

function DetermineShipSalvage(out TShip kShip)
{
    kShip.arrSalvage.Add(226);
    switch(kShip.eType)
    {
        // End:0xDB
        case 4:
            kShip.arrSalvage[168] = 2;
            kShip.arrSalvage[162] = Alloys(class'XGTacticalGameCore'.default.UFOAlloys[0]);
            kShip.arrSalvage[170] = 1;
            // End:0x4DF
            break;
        // End:0x171
        case 5:
            kShip.arrSalvage[168] = 4;
            kShip.arrSalvage[162] = Alloys(class'XGTacticalGameCore'.default.UFOAlloys[1]);
            kShip.arrSalvage[170] = 2;
            // End:0x4DF
            break;
        // End:0x24C
        case 6:
            kShip.arrSalvage[168] = 4;
            kShip.arrSalvage[162] = Alloys(class'XGTacticalGameCore'.default.UFOAlloys[2]);
            kShip.arrSalvage[170] = 2;
            kShip.arrSalvage[169] = 2;
            kShip.arrSalvage[167] = 6;
            // End:0x4DF
            break;
        // End:0x36B
        case 7:
            kShip.arrSalvage[168] = 4;
            kShip.arrSalvage[162] = Alloys(class'XGTacticalGameCore'.default.UFOAlloys[3]);
            kShip.arrSalvage[170] = 4;
            kShip.arrSalvage[169] = 2;
            kShip.arrSalvage[167] = 8;
            kShip.arrSalvage[166] = 10;
            kShip.arrSalvage[165] = 2;
            // End:0x4DF
            break;
        // End:0x424
        case 8:
            kShip.arrSalvage[168] = 6;
            kShip.arrSalvage[162] = Alloys(class'XGTacticalGameCore'.default.UFOAlloys[4]);
            kShip.arrSalvage[170] = 4;
            kShip.arrSalvage[179] = 2;
            // End:0x4DF
            break;
        // End:0x4DC
        case 9:
            kShip.arrSalvage[168] = 4;
            kShip.arrSalvage[162] = Alloys(class'XGTacticalGameCore'.default.UFOAlloys[5]);
            kShip.arrSalvage[170] = 4;
            kShip.arrSalvage[180] = 1;
            // End:0x4DF
            break;
        // End:0xFFFF
        default:
            kShip.arrSalvage[161] = Elerium(kShip.arrSalvage[170]);
            //return;
    }    
}
Edited by johnnylump
Link to comment
Share on other sites

So, wow, this is more complex than I thought... which If I thought about it a bit more I'd realize it had to be so, as EMP vs regular weapons alter (at the strategy level) the chances of the various UFO power source / UFO navigation elements being already replaced with destroyed versions when the crash mission initializes.

 

Did a little more digging based on the above strategy function and found that the arrSalvage structure is used in both CreateCrashMission and CreateLandedUFOMission via a line like :

   kMission.m_arrArtifacts = kUFO.m_kTShip.arrSalvage;

The function DetermineCrashLoot handles the replacement of undamaged items (in the item ID range 165-170 for EW) with damage items (in the item ID range 172-177), along with the alloys and elerium.

 

Presumably on mission startup this is used to initialize the destructable actors within the UFO. However what is unclear is what happens if the strategy number doesn't match the total number of specified actors within the mapfile (e.g. if the strategy game specifies 1 or 3 UFO power sources on a small scout map).

Edited by Amineri
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...