johnnylump Posted February 1, 2013 Share Posted February 1, 2013 (edited) This thread will attempt to develop four modifications to X-com to create a more interesting game. If we can get them working, I intend to use them in my Long War mod, but I expect they may be useful for other mods, as well. These are probably more complicated than simply switching a value or sign in a function, and I hope some of you more skilled than I with rescripting are willing and able to collaborate. I'll update each post as I find things that will move the ball forward. Please help!#1Each interceptor or firestorm kill gives that ship a +2% chance to hit in future interceptionsPurpose: To improve the interception game by allowing individual craft to gain experience that makes them more effective; this will create more interesting strategic decisions as players must weigh when to commit their best fighterspseudocode: tohit = tohit + (2 * this interceptor's kills)relevant variable: XGShip_Interceptor.m_iConfirmedKills (int) relevant function: XComStrategyGame, XGInterceptionEngagement, function UpdateWeapons Here's the code that fires a ship's weapon: if(Rand(100) <= akShipWeapons[iWeapon].iToHit) { kCombatExchange.bHit = true; kCombatExchange.iDamage = GetShipDamage(akShipWeapons[iWeapon], kCombatExchange); }This code seems to be in play for both UFOs and interceptors.At this point, I'm unclear if iToHit just references the default weapons table, or if it is a separately held variable that can be changed.The first challenge here is finding enough bytes in the (fortunately long) function to add three mathematical operations and two variable references. The second is ensuring interceptor kills is an accessible variable inside this function. More specific pseudocode would beif Rand (100) <= akShipWeapons[iWeapon].iToHit + (shipnum * shipkills * 2)It looks like the UFO is always ship number 0 in an interception, so the bonus would always be 0, while the interceptor is always ship number 1, so the bonus would be shipkills * 2. VERDICT: This works! I'll make available the rescripted updateweapons function; just pm me. Edited February 17, 2013 by johnnylump Link to comment Share on other sites More sharing options...
johnnylump Posted February 1, 2013 Author Share Posted February 1, 2013 (edited) #2 Randomize grenade / explosives damagePurpose: Grenades are a "sure thing" to hit a target; the risk-reward fun will increase if they don't always do the same damage.pseudocode: GrenadeDamage = GrenadeDamage -1 + random (3) UPDATED VERDICT: THIS WORKS! Thanks and full credit to Amineri for solving this one. A simple hex changes does this! It puts explosives (grenades and rockets) in the same category as other weapons, applying a range of damage. Damage roulette also reportedly affects these classes of weapons as well. In XComGame.upk, class XGTacticalGameCore, function CalcOverallDamage() Original: 07 9F 00 1B 8C 71 00 00 00 00 00 00 00 F3 76 00 00 2C 09 16 04 00 EE 76 00 00Replace: 07 9F 00 9A 00 F3 76 00 00 2C 08 16 04 00 EE 76 00 00 0B 0B 0B 0B 0B 0B 0B 0B Edited March 12, 2013 by johnnylump Link to comment Share on other sites More sharing options...
johnnylump Posted February 1, 2013 Author Share Posted February 1, 2013 (edited) #3 Give weaker aliens more hit points after a certain point in the gamePurpose: Sectoids, Thin Men, Floaters and Chrysallids are too easy to kill once you develop experienced troopers carrying plasma weapons. To keep a greater variety of threatening aliens in the mid and late game, why not buff these critters after a certain amount of time has passed to give them a fighting chance?(Several options here; you might make "officers" and only buff the leader of a pod, but not the subordinates)Pseudocode: If GetMonth() >= 6 && AlienType = sectoid, thin men, floater or chyrsallid then hp += 2-Sectoid is Alien 4, Floater 5, Thinman 6, Chrysalid 13-XComStrategyGame.XGStrategyAI.BuildPod modifies individual aliens in pods, but I'm not sure if you can change hit points here- Have not found where data from DGC.ini is read into variables- XComGame.XGUnit.SpawnPawn is a possibility, but it prolly won't work, as there are multiple function calls to XGUnitNativeBase.GetUnitMaxHP in various other functions- GetUnitNativeBase.GetUnitMaxHP is a native simulated function, which I don't know how to edit (I think native means C++ script, possibly in the .exe, and simulated means something to do with multiplayer)If I can find the bytes, may attempt a simpler change in SpawnPawn, something like MaxHealth = MaxHealth + GetMonth div 4, so all aliens get an extra hit point every four months.VERDICT: I think this won't work. Hit Points are assigned in XGUnit.SpawnPawn in XComGame. But GetMonth() doesn't appear in XComGame at all, and using its bytecode from XComStrategyGame calls a different function. There's no way to tell anything in XComGame how much time has passed in the strategy game, so it may not be possible to level up aliens based on time that has passed. Update: We're trying to upgrade aliens midgame using the ground mission count as the temporally relevant variable, and giving damage reduction or regeneration abilities as an alternative to more hit points. Stay tuned. Edited March 15, 2013 by johnnylump Link to comment Share on other sites More sharing options...
johnnylump Posted February 1, 2013 Author Share Posted February 1, 2013 (edited) #4 Alien FightersPurpose: Make alien scouts more of a threat in mid and late game by giving them the double plasma cannon previously found only on bigger shipsPseudocode: If GetMonth () >= 6 and ship = small scout or large scout then weapon = double plasma cannon No joy here so far. A GetMonth() call in UpdateShips is the apparent cause of a crash during save game load. I would note that GetMonth() isn't used anywhere in XGItemTree. Hmm, I wonder, though, if some of the ever-had-item triggers might work instead. However, we still don't know whether UpdateShips would be called more than once. Update: Progress! Game.GetAct() works in the UpdateShips () function, so I've seen large scouts with varying weapons depending on what Act the game is in. Further testing underway. Verdict: It works! By rescripting BuildShips AND including a call in another regularly-called function (in my case, ShouldHunt, which I've also rescripted and had some bytes to spare), I've seen UFOs upgrade after certain conditions are met. Instead of using GetAct() I used EverHadItem(), which checks if you've ever had a particular item in your inventory. I used alien corpses, which means I can calibrate alien UFO upgrades to GetMonth(), as certain aliens appear in certain months. Here's the function I'm using: function UpdateShips() { UpdateShip(2, 2000, 10, 8, 0, 0); UpdateShip(1, 1500, 10, 2500, 5, 0); UpdateShip(3, 3500, 15, 3500, 25, 16); UpdateShip(4, 3500, 40, 800, 0, 7); UpdateShip(5, 3000, 30, 2000, 0, 7); UpdateShip(6, 2000, 25, 3000, 30, 0); UpdateShip(7, 2000, 20, 2800, 20, 0); UpdateShip(8, 3000, 35, 3700, 50, 20); UpdateShip(9, 3500, 60, 2500, 64, 25); BuildShipWeapons(); // End:0x146 if(STORAGE().EverHadItem(151)) { BuildShip(5, m_strSizeMedium, 80, 9); } // End:0x191 if(STORAGE().EverHadItem(147)) { BuildShip(4, m_strSizeSmall, 79, 8, 8); } // End:0x21C if(STORAGE().EverHadItem(189)) { UpdateShip(5, 3000, 30, 2000, 30, 7); UpdateShip(6, 2000, 25, 3500, 35, 7); BuildShipWeapon(9, -1, 101, 1.0, 900, 20, 40); } UpdateAllShipTemplates(); //return; } A small scout with two Plasma Cannon I is a sight to see. Rewriting this script alone, however, will create some problems, as it's only called on game load, so the player would have to exit the game and come back. Putting a call in ShouldHunt() means it will be called fairly regularly when UFOs are zipping around. Edited March 8, 2013 by johnnylump Link to comment Share on other sites More sharing options...
Drakous79 Posted February 5, 2013 Share Posted February 5, 2013 Add #4 In theory, it needs extra conditional in BuildShips() fuction, but there's no space.if (GetMonth () >= 6) { BuildShip(4, m_strSizeSmall, 79, 9, 8); } else { BuildShip(4, m_strSizeSmall, 79, 8); }In UpdateShips() function is Large Scout's Code the same for all difficulties (if you haven't modded it). Required space could be freed by deleting UpdateShip(4, 1500, 20, 800, 0, 7); from all cases and putting it before the switch along with the conditional. But dunno about updating m_arrShips array. Add #1-#3 Nice ideas, that would be cool to script. But with bytecode, it is pain :( Link to comment Share on other sites More sharing options...
graaa Posted February 6, 2013 Share Posted February 6, 2013 Now that you've got the capability to add more UFO encounters in the game, I love the idea of being able to work with the interceptors more so I love these ideas. It'd be so cool if you could customize the interceptors (add decals, color, items) and have them level up and gain perks just like your soldiers do, however I know that is beyond our capabilities at present. #1 is a step in the right direction though! Also I like #3 a lot, especially because I'm tired of going on late game council missions with 100% thinmen that are incredibly weak. The proper solution would be to have council missions level up enemies as the months go by, but I can settle for stronger thinmen lol. Link to comment Share on other sites More sharing options...
johnnylump Posted February 6, 2013 Author Share Posted February 6, 2013 (edited) Add #4 In theory, it needs extra conditional in BuildShips() fuction, but there's no space.if (GetMonth () >= 6) { BuildShip(4, m_strSizeSmall, 79, 9, 8); } else { BuildShip(4, m_strSizeSmall, 79, 8); }In UpdateShips() function is Large Scout's Code the same for all difficulties (if you haven't modded it). Required space could be freed by deleting UpdateShip(4, 1500, 20, 800, 0, 7); from all cases and putting it before the switch along with the conditional. But dunno about updating m_arrShips array. Add #1-#3 Nice ideas, that would be cool to script. But with bytecode, it is pain :( @ Drak When is a class' INIT function called? Only at the game start? On loading? PLEASE prove me wrong, but I think UpdateShips() is only called from XGItemTree's Init function. If so, this wouldn't work. (Or, weirdly, only after you reload a game.) @ Graa I'll have to look, but it may be easier to edit alien rosters for council missions than to make certain species tougher. I'd prefer to make certain aliens tougher, though, just so we can keep more variety in the late game. (My mod usually has 12 missions a month, so variety would keep the late game missions more interesting). Hit points is looking very difficult unless there is a breakthrough in editing native functions; an alternative is to jack up their defense rating and make them harder to hit in the first place. Edited February 6, 2013 by johnnylump Link to comment Share on other sites More sharing options...
Drakous79 Posted February 6, 2013 Share Posted February 6, 2013 When is a class' INIT function called? Only at the game start? On loading? PLEASE prove me wrong, but I think UpdateShips() is only called from XGItemTree's Init function. If so, this wouldn't work. (Or, weirdly, only after you reload a game.)I guess it's called, when the class is loaded. Maybe on a transition between tactical and strategic layer. I don't know UnrealScript well to confirm it. Link to comment Share on other sites More sharing options...
johnnylump Posted February 6, 2013 Author Share Posted February 6, 2013 When is a class' INIT function called? Only at the game start? On loading? PLEASE prove me wrong, but I think UpdateShips() is only called from XGItemTree's Init function. If so, this wouldn't work. (Or, weirdly, only after you reload a game.)I guess it's called, when the class is loaded. Maybe on a transition between tactical and strategic layer. I don't know UnrealScript well to confirm it. Thinking about it more, I would guess it's called whenever the class is created, but when is that? If you're correct, then this would very likely work. I'll have to give it a try. Link to comment Share on other sites More sharing options...
bokauk Posted February 6, 2013 Share Posted February 6, 2013 When is a class' INIT function called? Only at the game start? On loading? PLEASE prove me wrong, but I think UpdateShips() is only called from XGItemTree's Init function. If so, this wouldn't work. (Or, weirdly, only after you reload a game.) I haven't been following this discussion, so I'm not sure if this is what you mean or if it will be useful... :) It looks like the XGItemTree > Init() function is called from XGFacility_Engineering > Init(), which is called from XGHeadQuaters > CreateFacilities(). XGFacility_Engineering function Init(bool bLoadingFromSave) { BaseInit(); m_kItems = Spawn(class'XGItemTree'); m_kItems.Init(); // End:0x6a if(m_arrMusingTracker.Length == 0) { m_arrMusingTracker.Add(6); } } UpdateShips() is called from XGItemTree > Init() > BuildShips() as you mentioned, but it's also called from XGStrategy > ChangeDifficulty(). There's a different UpdateShips() function in XGGeoscape as well, which I think is only called from XGGeoscape > GameTick(). :) Link to comment Share on other sites More sharing options...
Recommended Posts