Amineri Posted July 5, 2013 Author Share Posted July 5, 2013 Thank you for the feedback and confirmation that the bug happens on other systems. Discovered it was behaving identically for my game, once I got a save-game that replicated the situation. Took my several hours of trial and error to finally trace down what the problem was. Apparently any change to any variable or accessor function of a Unit that is utilizing the "ConstantCombat" functionality (basically just Suppression, now), causes the ConstantCombat animation to turn off as a side effect. The unit initiating suppression uses a Fire action to do so, which in turn can cause another unit with Covering Fire to be able to take a reaction fire shot at it, so a unit initiating suppression has to go through the code check as well, which apparently caused the animation to stop. Even just assigning 'true' to a boolean variable was enough to turn off the animation. I tracked down a function that restarted the animation (i.e. luckily found) named UpdateSuppression(). Three of the four hex functions are revised, so here are all hex changes : Suppression + Covering Fire Fix Hex Changes XGUnit.AddPerkStamp -- helper function called from outside XGUnit that checks for Suppression with Covering Fire original hex: header: BD AF 00 00 50 55 00 00 00 00 00 00 A2 AF 00 00 00 00 00 00 00 00 00 00 A8 AF 00 00 00 00 00 00 BA 01 00 00 FF 44 00 00 AE 00 00 00 66 00 00 00 body: 0B 0F 35 0B 30 00 00 0C 30 00 00 00 01 00 A3 AF 00 00 00 A8 AF 00 00 0F 35 09 30 00 00 0C 30 00 00 00 01 00 A3 AF 00 00 00 A7 AF 00 00 0F 35 08 30 00 00 0C 30 00 00 00 01 00 A3 AF 00 00 00 A6 AF 00 00 0F 35 0A 30 00 00 0C 30 00 00 00 01 00 A3 AF 00 00 00 A5 AF 00 00 04 00 A3 AF 00 00 04 3A A4 AF 00 00 53 new hex: (virtual 0x76) header: BD AF 00 00 50 55 00 00 00 00 00 00 A2 AF 00 00 00 00 00 00 00 00 00 00 A8 AF 00 00 00 00 00 00 BA 01 00 00 FF 44 00 00 76 00 00 00 66 00 00 00 body: 0B 0F 2D 01 92 AF 00 00 27 1B E6 5A 00 00 00 00 00 00 17 16 0F 2D 01 92 AF 00 00 28 1B A4 6E 00 00 00 00 00 00 16 04 00 A3 AF 00 00 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 3A A4 AF 00 00 53 --------------------------- XGUnit.ProcessSingleSuppressingEnemy -- helper function that tests whether covering fire is necessary original hex: header: FD B1 00 00 50 55 00 00 00 00 00 00 E6 B1 00 00 00 00 00 00 00 00 00 00 E8 B1 00 00 00 00 00 00 52 0F 00 00 95 E8 01 00 5D 00 00 00 45 00 00 00 body: 14 2D 00 E7 B1 00 00 28 07 47 00 1B F0 3C 00 00 00 00 00 00 16 14 2D 00 E7 B1 00 00 19 1A 25 01 A2 30 00 00 0C 00 50 31 00 00 00 1B 21 69 00 00 00 00 00 00 17 4A 16 04 2D 00 E7 B1 00 00 04 3A E8 B1 00 00 53 new hex: (virtual 0x51) header: FD B1 00 00 50 55 00 00 00 00 00 00 E6 B1 00 00 00 00 00 00 00 00 00 00 E8 B1 00 00 00 00 00 00 52 0F 00 00 95 E8 01 00 51 00 00 00 45 00 00 00 body: 04 84 19 1B 7B 31 00 00 00 00 00 00 16 0C 00 EA A2 00 00 00 1B B8 36 00 00 00 00 00 00 2C 2F 16 18 0D 00 81 2D 01 92 AF 00 00 16 16 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 3A E8 B1 00 00 53 --------------------------- XGUnit.ProcessSuppression -- rebuilt to check for covering fire if boolean set original hex: header: 1D B1 00 00 50 55 00 00 00 00 00 00 03 B1 00 00 00 00 00 00 00 00 00 00 08 B1 00 00 00 00 00 00 F2 09 00 00 B2 4B 01 00 DF 00 00 00 9B 00 00 00 body: (155 bytes) 19 00 08 B1 00 00 13 00 00 00 00 00 00 1B D5 34 00 00 00 00 00 00 00 07 B1 00 00 16 0F 00 05 B1 00 00 25 07 BD 00 96 00 05 B1 00 00 36 00 07 B1 00 00 16 0F 00 06 B1 00 00 10 00 05 B1 00 00 00 07 B1 00 00 19 00 06 B1 00 00 13 00 00 00 00 00 00 1B 27 69 00 00 00 00 00 00 00 08 B1 00 00 16 19 00 06 B1 00 00 0A 00 00 00 00 00 00 1B 6F 11 00 00 00 00 00 00 16 A5 00 05 B1 00 00 16 06 33 00 19 00 08 B1 00 00 0A 00 00 00 00 00 00 1B 6D 11 00 00 00 00 00 00 16 04 0B 53 new hex: (virtual 0xD3) header: 1D B1 00 00 50 55 00 00 00 00 00 00 03 B1 00 00 00 00 00 00 00 00 00 00 08 B1 00 00 00 00 00 00 F2 09 00 00 B2 4B 01 00 D3 00 00 00 9B 00 00 00 body: 19 00 08 B1 00 00 13 00 00 00 00 00 00 1B D5 34 00 00 00 00 00 00 00 07 B1 00 00 16 58 00 07 B1 00 00 00 06 B1 00 00 00 4A A9 00 07 A8 00 19 00 06 B1 00 00 0A 00 E8 B1 00 00 00 1B E5 5A 00 00 00 00 00 00 16 19 00 06 B1 00 00 13 00 00 00 00 00 00 1B 27 69 00 00 00 00 00 00 00 08 B1 00 00 16 19 00 06 B1 00 00 0A 00 00 00 00 00 00 1B 6F 11 00 00 00 00 00 00 16 31 30 19 00 08 B1 00 00 0A 00 00 00 00 00 00 1B 6D 11 00 00 00 00 00 00 16 0B 0B 0B 0B 0B 0B 0B 04 0B 53 ------------------------------- XGAction_Fire.state'ShutDownToIdle' -- add new call for suppression and move both up before unit enters cover. original hex: (next line at 0x656) 07 60 05 84 2D 01 1D 83 00 00 18 0B 00 2D 01 ED 82 00 00 16 1C 9C FC FF FF 21 6E 25 00 00 00 00 00 00 4A 16 19 01 40 BC 00 00 0A 00 00 00 00 00 00 1B B9 5D 00 00 00 00 00 00 16 07 99 05 2D 01 04 83 00 00 1B F5 5D 00 00 00 00 00 00 16 06 99 05 07 56 06 82 82 2D 01 24 83 00 00 18 0D 00 77 01 DD 82 00 00 2A 16 16 18 22 00 81 19 01 DD 82 00 00 0A 00 57 7C 00 00 00 1B 32 3E 00 00 00 00 00 00 16 16 16 19 01 41 BC 00 00 0D 00 00 00 00 00 00 1B 0D 04 00 00 00 00 00 00 25 27 27 16 07 56 06 19 01 41 BC 00 00 0A 00 59 31 00 00 00 1B 5B 3E 00 00 00 00 00 00 16 07 4E 06 19 01 41 BC 00 00 0A 00 59 31 00 00 00 1B 5B 3E 00 00 00 00 00 00 16 61 00 1E CD CC CC 3D 16 06 21 06 61 00 1E 00 00 80 3F 16 new hex : (next line at 0x656 ) 07 E9 05 82 82 2D 01 24 83 00 00 18 0D 00 77 01 DD 82 00 00 2A 16 16 18 22 00 81 19 01 DD 82 00 00 0A 00 57 7C 00 00 00 1B 32 3E 00 00 00 00 00 00 16 16 16 19 01 41 BC 00 00 0D 00 00 00 00 00 00 1B 0D 04 00 00 00 00 00 00 25 27 27 16 07 C6 05 19 01 41 BC 00 00 0A 00 59 31 00 00 00 1B 5B 3E 00 00 00 00 00 00 16 61 00 1E 00 00 80 3F 16 06 96 05 0B 0B 0B 19 01 41 BC 00 00 0A 00 A4 AF 00 00 00 1B 2C 02 00 00 00 00 00 00 2A 2A 2A 4A 16 07 19 06 84 2D 01 1D 83 00 00 18 0B 00 2D 01 ED 82 00 00 16 1C 9C FC FF FF 21 6E 25 00 00 00 00 00 00 4A 16 19 01 40 BC 00 00 0A 00 00 00 00 00 00 1B B9 5D 00 00 00 00 00 00 16 07 4F 06 2D 01 04 83 00 00 1B F5 5D 00 00 00 00 00 00 16 0B 0B 0B 0B 0B 0B 0B I tested the ability for a Suppressing unit to take a reaction shot at a suppressed unit that fires (even at another target) by temporarily disabling the test for the Covering Fire perk, and everything worked as I hoped. Note that there is a small potentially negative side effect : the ProcessSuppression function has a blanket functionality that clears the unit's suppression list (i.e. units that are suppressing it). This used to occur only when the unit moved, after the Suppression effects had taken place. This now also happens when a unit fire, even if the suppressing unit doesn't have Covering Fire and so wasn't able to shoot. However, this only makes a difference if the targeted unit can take two fire actions (e.g. Double Tap and maybe Rapid Fire), or can Shoot and then move (e.g. Bullet Swarm). The first fire or move action performed will clear the suppression, regardless of whether a shot was taken. Another note : Covering Fire and the ability to ignore cover. This may actually be pretty limited. There are many cases where a unit is in cover but can shoot without having to step out of cover. Low Cover, for example. Or being in Full Cover but having LOS to your target from your square. In these cases I think the unit will retain cover, but it's difficult to say for certain, as I haven't traced down whether the unit actually leaves cover to shoot in all circumstances. Link to comment Share on other sites More sharing options...
Zybertryx Posted July 5, 2013 Share Posted July 5, 2013 Very cool, thanks, you're a machine :D As for the "potentially negative side effect" that could almost be considered a feature rather than a bug. I often suppress a suppressor to break its suppression, allowing the suppressed soldier to move freely. This would mean that those few appropriately perk'd up Colonels are able to break their own suppression though in doing so they 'waste' one of their "super-perk" shots. Fair enough. I'll run with this as standard and report any further oddities (if there are any to report). Link to comment Share on other sites More sharing options...
johnnylump Posted July 5, 2013 Share Posted July 5, 2013 Note that there is a small potentially negative side effect : the ProcessSuppression function has a blanket functionality that clears the unit's suppression list (i.e. units that are suppressing it). This used to occur only when the unit moved, after the Suppression effects had taken place. This now also happens when a unit fire, even if the suppressing unit doesn't have Covering Fire and so wasn't able to shoot. However, this only makes a difference if the targeted unit can take two fire actions (e.g. Double Tap and maybe Rapid Fire), or can Shoot and then move (e.g. Bullet Swarm). The first fire or move action performed will clear the suppression, regardless of whether a shot was taken. Let me make sure I understand this: My Gunner has Bullet Swarm. An alien suppresses my gunner. My gunner takes a shot with Bullet Swarm at any target (not necessarily the suppressor). The suppression ends without the alien being able to take a reaction shot, and the Gunner can now move freely with the second action. It is irrelevant whether either the gunner or the alien has covering fire. Is that correct? Link to comment Share on other sites More sharing options...
Amineri Posted July 5, 2013 Author Share Posted July 5, 2013 Let me make sure I understand this: My Gunner has Bullet Swarm. An alien suppresses my gunner. My gunner takes a shot with Bullet Swarm at any target (not necessarily the suppressor). The suppression ends without the alien being able to take a reaction shot, and the Gunner can now move freely with the second action. It is irrelevant whether either the gunner or the alien has covering fire. Is that correct? This is correct. Unfortunately the way that the ProcessSuppression function was set up it assumes that all suppression units have identical triggers. It loops over each suppression unit, letting each take its reaction shot. After the loop is over there is a single call that clears all suppressing targets from the unit. kUnit.GetSuppressingEnemies(arrSuppressors); foreach arrSuppressors(kSuppressor,) { if(kSuppressor.ProcessSingleSuppressingEnemy()) { kSuppressor.TakeSuppressionOverwatchShot(kUnit); kSuppressor.ClearSuppressionTargets(); } } kUnit.ClearSuppressingEnemies(); So, there's no way without a pretty major overhaul to make the unit retain the suppression unless it actually takes the shot. It is possible to make Suppression have Covering Fire "built in", however. Basically I added the conditional that the suppressing unit had to have the Covering Fire perk (tested via the helper ProcessSingleSuppressingEnemy) in order to take the reaction shot. However, by going into the function at all it's going to clear the SuppressingEnemies list. If there are two units suppressing another third unit, and one has covering fire and one doesn't, there's no good way to resolve this. If the third unit fires then 1 Suppressing unit should shoot and end its suppression, while the other one shouldn't. However, the code doesn't easily allow it. The alternative is to not clear the Suppression list, in which case even if the unit moves the suppressing unit would still be suppressing it (at least for panic moves, with this function). Another alternative is to always allow Suppression units to take the reaction shot regardless of having the Covering Fire perk or not. In a sense this still works, because the first shot of Bullet Swarm was still at a -30 to hit, so Suppression does mostly cancel out 1 action of the unit, just not the whole turn. ---------------------------------- I also found a logical error in my function that was checking for Covering Fire. The same function is used for both move checks for panicking units and for covering fire checks against units that are firing. The error was in the helper function XGUnit.ProcessSingleSuppressingEnemy. I used and OR when I should have used an AND :Was: return GetCharacter().HasUpgrade(47) || !m_bLeftBehind; Should have been: return GetCharacter().HasUpgrade(47) && !m_bLeftBehind; The m_bLeftBehind isn't being used for it's intended use -- it's just a "safe" variable that has no possible effect until the end of the mission, so I temporarily set it to true and then back to false to emulate passing the parameter that I can't pass. It indicates whether the ProcessSuppression is for covering fire only. Here is the updated hex: XGUnit.ProcessSingleSuppressingEnemy original hex: header: FD B1 00 00 50 55 00 00 00 00 00 00 E6 B1 00 00 00 00 00 00 00 00 00 00 E8 B1 00 00 00 00 00 00 52 0F 00 00 95 E8 01 00 5D 00 00 00 45 00 00 00 body: 14 2D 00 E7 B1 00 00 28 07 47 00 1B F0 3C 00 00 00 00 00 00 16 14 2D 00 E7 B1 00 00 19 1A 25 01 A2 30 00 00 0C 00 50 31 00 00 00 1B 21 69 00 00 00 00 00 00 17 4A 16 04 2D 00 E7 B1 00 00 04 3A E8 B1 00 00 53 new hex: (virtual 0x51) header: FD B1 00 00 50 55 00 00 00 00 00 00 E6 B1 00 00 00 00 00 00 00 00 00 00 E8 B1 00 00 00 00 00 00 52 0F 00 00 95 E8 01 00 51 00 00 00 45 00 00 00 body: 04 82 19 1B 7B 31 00 00 00 00 00 00 16 0C 00 EA A2 00 00 00 1B B8 36 00 00 00 00 00 00 2C 2F 16 18 0D 00 81 2D 01 92 AF 00 00 16 16 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 3A E8 B1 00 00 53 However, if you want to leave Covering Fire effectively "built-in" to Suppression then you can just leave this alone. :smile: Link to comment Share on other sites More sharing options...
johnnylump Posted July 5, 2013 Share Posted July 5, 2013 Thanks for clarifying. Hmm. I suspect our one-action smoke grenade might also clear the suppression, too, then. The alternative is to not clear the Suppression list, in which case even if the unit moves the suppressing unit would still be suppressing it (at least for panic moves, with this function). I gotta say I'm curious what the visuals would look like with this. Would the tracers follow the running trooper? Link to comment Share on other sites More sharing options...
Amineri Posted July 5, 2013 Author Share Posted July 5, 2013 Thanks for clarifying. Hmm. I suspect our one-action smoke grenade might also clear the suppression, too, then. I'm not sure if throwing grenades is handled through XGAction_Fire, so I don't know if they trigger covering fire. I know that the sectoid mindmerge triggers covering fire, however. Needs more experimentation to resolve. I've also noted the oddity that using Flush on an Overwatching alien doesn't appear to cancel the Overwatch despite the alien's movement. Link to comment Share on other sites More sharing options...
Zybertryx Posted July 6, 2013 Share Posted July 6, 2013 (edited) Ah, looks Iike I misread you. But again it doesn't seem that bad; I noticed that when I was suppressing a sectoid, in its turn it used mind meld on another sectoid and I actually gained a reaction shot from that (and that 'broke' my suppression though it served its purpose - he didn't fire at me although he was the closest and most threatening alien). So it seems that any action taken by the suppressed will end the suppression but the aim penalty for suppression serves its purpose and the action which breaks the suppression earns the reaction shot, even without having moved. I kinda like this, previously, if a pod rolled up and you suppressed the closest alien, the others would stupidly mind meld with that one (the closest one). Now this isn't so - well I've never seen a suppressed sectoid mind meld another one before (it's often the other way around). This is better to be honest. Edited July 6, 2013 by Zybertryx Link to comment Share on other sites More sharing options...
seraglio73 Posted July 14, 2013 Share Posted July 14, 2013 Awesome stuff here Aminieri! I'm wondering about the Vengeance perk. If it indeed works, how would someone go about making it available to soldiers. Could it just be added to ToolBoks perk tree editor? Link to comment Share on other sites More sharing options...
Amineri Posted July 14, 2013 Author Share Posted July 14, 2013 Awesome stuff here Aminieri! I'm wondering about the Vengeance perk. If it indeed works, how would someone go about making it available to soldiers. Could it just be added to ToolBoks perk tree editor? I'm pretty sure that johnnylump has added this perk to Long War for certain alien leaders, plus available via an equippable module for SHIVs. I'm not sure if it has a working icon and localization text, but apparently the perk code works fine with no extra modding required. Link to comment Share on other sites More sharing options...
johnnylump Posted July 14, 2013 Share Posted July 14, 2013 Yep, I tested Vengeance (in a limited fashion) and it worked. Every time you're hit, you take a reaction shot back. I suspect it was left out of the final build because1) It was unlikely an X-Com soldier would find it useful, as you can only take a few hits in a battle before you are done for2) It would be way too annoying on the aliens -- think of a pod of Thin Men getting a free shot every time you hit them So I've put it on a certain kind of alien leader -- it's likely you'll only rarely encounter it on more than one bad guy in a battle, which seems about right. Link to comment Share on other sites More sharing options...
Recommended Posts