Hobbes77 Posted January 9, 2014 Share Posted January 9, 2014 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 More sharing options...
Amineri Posted January 9, 2014 Share Posted January 9, 2014 (edited) 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 January 9, 2014 by Amineri Link to comment Share on other sites More sharing options...
johnnylump Posted January 10, 2014 Share Posted January 10, 2014 Check out XGItemTree >> DetermineShipSalvage 4 is Small Scout5 is Large Scout6 is Abductor7 is Supply Barge8 is Battleship9 is Overseer Link to comment Share on other sites More sharing options...
Hobbes77 Posted January 10, 2014 Author Share Posted January 10, 2014 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 More sharing options...
dubiousintent Posted January 10, 2014 Share Posted January 10, 2014 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 More sharing options...
johnnylump Posted January 10, 2014 Share Posted January 10, 2014 (edited) I'd put this in spoiler tags but I don't know how.167 is Stasis Tank168 is Nav Computers169 is Alien Surgery170 is Power Supply179 is Fusion Core180 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 January 10, 2014 by johnnylump Link to comment Share on other sites More sharing options...
Hobbes77 Posted January 10, 2014 Author Share Posted January 10, 2014 Check out XGItemTree >> DetermineShipSalvage 4 is Small Scout5 is Large Scout6 is Abductor7 is Supply Barge8 is Battleship9 is Overseer Bingo. Thanks to both of you :) Link to comment Share on other sites More sharing options...
Drakous79 Posted January 10, 2014 Share Posted January 10, 2014 I'd put this in spoiler tags but I don't know how. Can be done by using spoiler tags. [spoiler][/spoiler] Link to comment Share on other sites More sharing options...
johnnylump Posted January 10, 2014 Share Posted January 10, 2014 Thanks! Link to comment Share on other sites More sharing options...
Amineri Posted January 10, 2014 Share Posted January 10, 2014 (edited) 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 January 10, 2014 by Amineri Link to comment Share on other sites More sharing options...
Recommended Posts