Jump to content

Fixing Enemy Within Suppression Bug(s)


Amineri

Recommended Posts

So there are sort of two quasi-related Suppression bugs that were introduced in Enemy Within.

 

1) The first is that units can become "unglued" from and unable to use cover any longer. This appears to be caused by the variable bSteppingOutOfCover which gets stuck in a true state. When true, it causes the XGUnit.ProcessNewPosition to exit early, preventing a unit from entering cover after it moves.

 

2) The second is that units that have stepped out from cover do not always return to cover when Suppression ends. Each XGUnit has a class variable StoredEnterCoverAction which stores the action to re-enter cover. From some reason in certain cases this action isn't taken, resulting in the unit remaining in the "stepped out" position.

 

Unfortunately the actual code that handles this is native code : XGUnitNativeBase.ClearSuppressionTargets() appears to be the function that is supposed to clean up when a unit stops suppressing for whatever reason.

 

To work around this, I created a new helper function out of XGUnit.DebugVisibilityForSelf. This function acts as an intermediate for ClearSuppressionTargets. All of the 15 places that ClearSuppressionTargets are normally called are redirected to DebugVisibilityForSelf. DebugVisibilityForSelf then calls the native ClearSuppressionTargets and then executes some additional "clean-up" code to try and ensure that the suppression terminated properly.

 

The UEExplorer decompiled code for DebugVisibilityForSelf is :

simulated function DebugVisibilityForSelf(optional Canvas kCanvas, optional Vector vScreenPos)
{
    GetCharacter().m_kChar.aUpgrades[10] = GetCharacter().m_kChar.aUpgrades[10] & 1;
    ClearSuppressionTargets();
    if(bSteppingOutOfCover)
    {
        bSteppingOutOfCover = false;
        // End:0xDB
        if((StoredEnterCoverAction != none) && !StoredEnterCoverAction.m_bExecute)
        {
            AddAction(StoredEnterCoverAction);
        }
        CallProcessNewPosition();
    }
    return;                                
}

The first line is unrelated to the bugfix and is a Long War feature I added to make certain units automatically gain the Opportunist perk while Suppressing. This line removes the temporary boost.

The second line calls the vanilla, native ClearSuppressionTargets.

Following that is a test to see if bSteppingOutOfCover is still incorrectly set to true. If so, then it is set to false (which prevents the unit from ever becoming permanently "unglued" from cover).

Then StoredEnterCoverAction is then checked to see if it is non-null and hasn't already either been executed or in the process of executing. If so, then the action is added in order to cause the unit to re-enter cover.

Finally, CallProcessNewPosition is invoked to update the Unit state based on the current position (i.e. update cover buffs).

 

Here is the UPKmodder modfile for this function :

 

 

MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=DebugVisibilityForSelf@XGUnit
RESIZE=B0

//helper function to remove free Opportunist perk for LMG suppressors when ClearSuppressionTargets is called

//also attempt to fix issues with "unglued" Suppression


[BEFORE_HEX]
[HEADER]
03 00 00 00 03 00 00 00
[/HEADER]
[code]

04 0B 
	//return

53 
//	

[/CODE]
00 00 00 00 01 02
[/BEFORE_HEX]


[AFTER_HEX]
[HEADER]
EF 00 00 00 B3 00 00 00
[/HEADER]
[code]

//GetCharacter().m_kChar.aUpgrades[10] = GetCharacter().m_kChar.aUpgrades[10] & 1  // ePerk_Opportunist // remove extra opportunist flag
0F 1A 2C 0A 35 54 0F 00 00 58 0F 00 00 00 00 19 1B E5 37 00 00 00 00 00 00 16 09 00 03 B8 00 00 00 01 03 B8 00 00 9C 1A 2C 0A 35 54 0F 00 00 58 0F 00 00 00 00 19 1B E5 37 00 00 00 00 00 00 16 09 00 03 B8 00 00 00 01 03 B8 00 00 2C 01 16  

1b B8 13 00 00 00 00 00 00 16 
//ClearSuppressionTargets()

//if(bSteppingOutOfCover)
07 E5 00 2D 01 28 3A 00 00 

	//bSteppingOutOfCover = false
	14 2D 01 28 3A 00 00 28 

	//if((StoredEnterCoverAction != none) && !StoredEnterCoverAction.m_bExecute)
	07 DB 00 82 77 01 C5 39 00 00 2A 16 18 22 00 81 19 01 C5 39 00 00 0A 00 37 D5 00 00 00 2D 01 37 D5 00 00 16 16 	

		//AddAction(StoredEnterCoverAction);
		1B D4 01 00 00 00 00 00 00 01 C5 39 00 00 4A 16 

	//CallProcessNewPosition()
	1B 1B 11 00 00 00 00 00 00 16 

//return
04 0B 

//null ops
0B 0B 0B 0B 0B 0B 0B 

//EOS
53 
[/CODE]
00 00 00 02 01 02

[/AFTER_HEX] 

 

 

 

Note that this includes some changes to flags in the function footer to allow the function to work (thanks to JL for figuring this out). Note that leaving the first Opportunist line in a vanilla game won't have any negative side effects, since perks in vanilla are always set in bit 0.

 

There are a couple of changes necessary in order to alter the function parameters so that the call to DebugVisibilityForSelf is the same number of bytes as ClearSuppressionTargets, making swapping the calls simpler.

 

 

MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=UNSPECIFIED // no hex references in file
FUNCTION=vScreenPos@DebugVisibilityForSelf@XGUnit

[BEFORE_HEX]
<|None|> 00 00 00 00 
00 00 00 00 
01 00 00 00 
80 00 00 00 00 00 00 00 
<|None|> 00 00 00 00 
[/BEFORE_HEX]


[AFTER_HEX]
<|None|> 00 00 00 00 
00 00 00 00 
01 00 00 00 
90 00 00 00 00 00 00 00 
<|None|> 00 00 00 00 
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=UNSPECIFIED // no hex references in file
FUNCTION=kCanvas@DebugVisibilityForSelf@XGUnit

// alter flags to change parameter variable to optional parameter variable

[BEFORE_HEX]
<|None|> 00 00 00 00 
{|vScreenPos@DebugVisibilityForSelf@XGUnit|} 
01 00 00 00 
80 00 00 00 00 00 00 00 
<|None|> 00 00 00 00 
[/BEFORE_HEX]


[AFTER_HEX]
<|None|> 00 00 00 00 
{|vScreenPos@DebugVisibilityForSelf@XGUnit|} 
01 00 00 00 
90 00 00 00 00 00 00 00 
<|None|> 00 00 00 00 
[/AFTER_HEX]
 

 

 

 

These two changes alter the parameter flags, converting the parameters into optional parameters.

 

 

The next change is to re-direct the vanilla 15 calls to ClearSuppressionTargets to the DebugVisibilityForSelf helper. Following are the 15 UPKmodder files I used to update all of them:

 

 

 

MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=RunForCover@XGUnit

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//ClearSuppressionTargets()
1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//DebugVisibilityForSelf()
1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX]
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=ProcessSuppression@XGUnit

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//kSuppressor.ClearSuppressionTargets()
19 00 D2 C6 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]


[AFTER_HEX]
[code]
//kSuppressor.DebugVisibilityForSelf()
19 00 D2 C6 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX]
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=OnDeath@XGUnit

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//ClearSuppressionTargets()
1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//DebugVisibilityForSelf()
1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=ClearAbilitiesOnMindControl@XGUnit

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//ClearSuppressionTargets()
1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//DebugVisibilityForSelf()
1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=ClearAbilitiesOnDeath@XGUnit

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//ClearSuppressionTargets()
1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//DebugVisibilityForSelf()
1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX]
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=BeginTurn@XGUnit

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//ClearSuppressionTargets()
1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//DebugVisibilityForSelf()
1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=Executing@XGAction_TakeDamage

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//m_kUnit.ClearSuppressionTargets()
19 01 25 D5 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//m_kUnit.DebugVisibilityForSelf()
19 01 25 D5 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=Executing@XGAction_Strangle

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//m_kTarget.ClearSuppressionTargets()
19 01 6C 97 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//m_kTarget.DebugVisibilityForSelf()
19 01 6C 97 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=BeginState@CriticallyWounded@XGAction_CriticallyWounded

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//m_kUnit.ClearSuppressionTargets()
19 01 25 D5 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//m_kUnit.DebugVisibilityForSelf()
19 01 25 D5 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=ProcessSuppression@XGAction_BeginMove

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//kOverwatcher.ClearSuppressionTargets()
19 00 53 90 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//kOverwatcher.DebugVisibilityForSelf()
19 00 53 90 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=ApplyEffect@XGAbility_Grapple

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//m_kUnit.ClearSuppressionTargets()
19 01 42 8B 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//m_kUnit.DebugVisiblityForSelf()
19 01 42 8B 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=ApplyEffect@XGAbility_FlashBang

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//kUnit.ClearSuppressionTargets()
19 00 5F 8D 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//kUnit.DebugVisiblityForSelf()
19 00 5F 8D 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=ApplyEffect@XGAbility_Electropulse

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//kUnit.ClearSuppressionTargets()
19 00 50 8D 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//kUnit.DebugVisiblityForSelf()
19 00 50 8D 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=RemoveEffectsFromSelf@XGAbilityTree

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//kAbility.m_kUnit.ClearSuppressionTargets()
19 19 00 8C 8E 00 00 09 00 42 8B 00 00 00 01 42 8B 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//kAbility.m_kUnit.DebugVisiblityForSelf()
19 19 00 8C 8E 00 00 09 00 42 8B 00 00 00 01 42 8B 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 
MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=OnExaltHackingArrayInteraction@XComRadarArrayActor

//redirect ClearSuppressionTargets to DebugVisibilityForSelf

[BEFORE_HEX]
[code]
//kAlien.ClearSuppressionTargets()
19 00 26 78 00 00 0A 00 00 00 00 00 00 1B B8 13 00 00 00 00 00 00 16 
[/CODE]
[/BEFORE_HEX]

[AFTER_HEX]
[code]
//kAlien.DebugVisiblityForSelf()
19 00 26 78 00 00 0A 00 00 00 00 00 00 1B 86 17 00 00 00 00 00 00 16 
[/CODE]
[/AFTER_HEX] 

 

 

 

This should be all that is necessary in order to add the basic EW Suppression bugfix.

 

------------------------------

 

A couple of optional changes I coded up and that are included in Long War (as of v3.0 beta 7).

 

The first is a change that makes certain classes of weapons automatically gain the Opportunist perk when Suppressing. This was created for the Long War Gunner subclass, which has only the LMG and no Rocket Launcher :

 

 

MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=ConstantCombatSuppress@XGUnit
RESIZE=D0

// grant free temporary use of Opportunist for LMG-using Suppressors

[BEFORE_HEX]
[HEADER]
A6 00 00 00 6E 00 00 00 
[/HEADER]
[code]
//m_bSuppressing = bSuppress && kTarget != none
14 2D 01 2F C5 00 00 82 2D 00 46 C6 00 00 18 0D 00 77 00 45 C6 00 00 2A 16 16 

//if(m_bSuppressing)
07 69 00 2D 01 2F C5 00 00 

	//m_kForceConstantCombatTarget = kTarget
	0F 01 DE C4 00 00 00 45 C6 00 00 

	//kTarget.m_kConstantCombatUnitTargettingMe = self
	0F 19 00 45 C6 00 00 09 00 DD 39 00 00 00 01 DD 39 00 00 17 

//else
06 A3 00 

	//if(m_kForceConstantCombatTarget != none)
	07 98 00 77 01 DE C4 00 00 2A 16 

		//m_kForceConstantCombatTarget.m_kConstantCombatUnitTargettingMe = none
		0F 19 01 DE C4 00 00 09 00 DD 39 00 00 00 01 DD 39 00 00 2A 

	//m_kForceConstantCombatTarget = none
	0F 01 DE C4 00 00 2A 

//return
04 0B 

//EOS
53 
[/CODE]
[/BEFORE_HEX]


[AFTER_HEX]
[HEADER]
C2 01 00 00 3E 01 00 00 
[/HEADER]
[code]
//m_bSuppressing = bSuppress && kTarget != none
14 2D 01 2F C5 00 00 82 2D 00 46 C6 00 00 18 0D 00 77 00 45 C6 00 00 2A 16 16 

//if(m_bSuppressing)
07 7D 01 2D 01 2F C5 00 00 

	//m_kForceConstantCombatTarget = kTarget
	0F 01 DE C4 00 00 00 45 C6 00 00 

	//kTarget.m_kConstantCombatUnitTargettingMe = self
	0F 19 00 45 C6 00 00 09 00 DD 39 00 00 00 01 DD 39 00 00 17 

	//if(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.WeaponHasProperty(GetInventory().GetActiveWeapon().ItemType(), 4))  // eWP_Support
	07 7A 01 19 19 2E 54 32 00 00 19 12 20 35 FE FF FF 0A 00 92 F9 FF FF 00 1C D5 FB FF FF 16 09 00 50 F9 FF FF 00 01 50 F9 FF FF 09 00 46 32 00 00 00 01 46 32 00 00 44 00 D0 86 00 00 00 1B 68 7F 00 00 00 00 00 00 38 3A 19 19 1B 56 39 00 00 00 00 00 00 16 0A 00 26 0B 00 00 00 1B 4F 37 00 00 00 00 00 00 16 0A 00 E7 BB 00 00 00 1B D8 46 00 00 00 00 00 00 16 2C 04 16 

		//GetCharacter().m_kChar.aUpgrades[10] = GetCharacter().m_kChar.aUpgrades[10] | 2  // ePerk_Opportunist // grant extra opportunist flag
		0F 1A 2C 0A 35 54 0F 00 00 58 0F 00 00 00 00 19 1B E5 37 00 00 00 00 00 00 16 09 00 03 B8 00 00 00 01 03 B8 00 00 9E 1A 2C 0A 35 54 0F 00 00 58 0F 00 00 00 00 19 1B E5 37 00 00 00 00 00 00 16 09 00 03 B8 00 00 00 01 03 B8 00 00 2C 02 16  

//else
06 B7 01 

	//if(m_kForceConstantCombatTarget != none)
	07 AC 01 77 01 DE C4 00 00 2A 16 

		//m_kForceConstantCombatTarget.m_kConstantCombatUnitTargettingMe = none
		0F 19 01 DE C4 00 00 09 00 DD 39 00 00 00 01 DD 39 00 00 2A 

	//m_kForceConstantCombatTarget = none
	0F 01 DE C4 00 00 2A 

//return
04 0B 

//null ops
0B 0B 0B 0B 0B 0B 0B 0B 

//EOS
53 
[/CODE]
[/AFTER_HEX] 

 

 

 

The key line here that would need to be tweaked for vanilla is :

if(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.WeaponHasProperty(GetInventory().GetActiveWeapon().ItemType(), 4))  // eWP_Support

This tests the current weapon for a particular property that has to be present. In Long War LMG-class weapons are tagged with eWP_Support (eWP_Heavy is used for Rocket Launchers).

 

--------

 

The second optional change has to do with the timing of the Suppression reaction shot. In vanilla the reaction shot is triggered just prior to the unit exiting cover and losing its cover bonus (so the Suppression reaction shot suffers from both the reaction penalty (70% of normal chance to hit), but the unit also retains its cover bonus.

 

The following modfile changes the order so that the Suppressive reaction shot happens immediately after the unit leaves cover and loses its cover bonus.

 

 

 

MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
FUNCTION=Executing@XGAction_BeginMove

// process suppression shots after the unit has left cover and lost the cover bonuses

[BEFORE_HEX]
[HEADER]

[/HEADER]
[code]
//if((WorldInfo.NetMode != NM_Standalone) && !WorldInfo.IsConsoleBuild())
//07 50 00 82 9B 38 3A 19 01 A6 F9 FF FF 09 00 8F FE FF FF 00 01 8F FE FF FF 38 3A 24 00 16 18 23 00 81 19 01 A6 F9 FF FF 0B 00 C4 FE FF FF 00 1C 2E FA FF FF 4A 16 16 16 

//HACK_fGhettoStuckLoopingTimeoutSeconds = 10.0
//0F 01 18 90 00 00 1E 00 00 20 41 

//if(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kCameraManager.WaitForCamera())
//07 01 01 19 19 2E 54 32 00 00 19 12 20 35 FE FF FF 0A 00 92 F9 FF FF 00 1C D5 FB FF FF 16 09 00 50 F9 FF FF 00 01 50 F9 FF FF 09 00 42 32 00 00 00 01 42 32 00 00 0A 00 C1 49 00 00 00 1B 07 7F 00 00 00 00 00 00 16 

	//Sleep(0.050)
//	61 00 1E CD CC 4C 3D 16 

	//if(HACK_fGhettoStuckLoopingTimeoutSeconds <= 0.0)
//	07 FE 00 B2 01 18 90 00 00 1E 00 00 00 00 16 

		//HACK_fGhettoStuckLoopingTimeoutSeconds = 10.0
//		0F 01 18 90 00 00 1E 00 00 20 41 

		//goto 'AfterWaitForCameraManager'
//		0D 21 02 03 00 00 00 00 00 00 

	//goto J0x5F
//	06 5F 00 


//start 0x101
//if(m_kUnit.IsBeingSuppressed())
07 25 02 19 01 25 D5 00 00 0A 00 EB 35 00 00 00 1B 7D 44 00 00 00 00 00 00 16 

	//ProcessSuppression(m_kUnit)
	1B 7A 66 00 00 00 00 00 00 01 25 D5 00 00 16 

	//if(m_kUnit.m_eCoverState != 0)
	07 BD 01 9B 38 3A 19 01 25 D5 00 00 09 00 20 3A 00 00 00 01 20 3A 00 00 38 3A 24 00 16 

		//if(m_kPawn.MovementNode != none)
		07 BD 01 77 19 01 24 D5 00 00 09 00 F7 3B 00 00 00 01 F7 3B 00 00 2A 16 

			//m_kPawn.MovementNode.SetActiveChild(1, 0.10)
			19 19 01 24 D5 00 00 09 00 F7 3B 00 00 00 01 F7 3B 00 00 10 00 00 00 00 00 00 1B 2E 6D 00 00 00 00 00 00 26 1E CD CC CC 3D 16 

	//HACK_fGhettoStuckLoopingTimeoutSeconds = 10.0
	0F 01 18 90 00 00 1E 00 00 20 41 

	//if(m_kPres.CAMIsBusy())
	07 25 02 19 01 22 D5 00 00 0A 00 9B 74 00 00 00 1B 59 11 00 00 00 00 00 00 16 

		//Sleep(0.0)
		61 00 1E 00 00 00 00 16 

		//if(HACK_fGhettoStuckLoopingTimeoutSeconds <= 0.0)
		07 22 02 B2 01 18 90 00 00 1E 00 00 00 00 16 

			//HACK_fGhettoStuckLoopingTimeoutSeconds = 10.0
			0F 01 18 90 00 00 1E 00 00 20 41 

			//goto 'AfterOverwatchProcessing'
			0D 21 00 03 00 00 00 00 00 00 

		//goto J0x1CC
		06 CC 01 

// label AfterOverwatchProcessing 

//if(m_kUnit.GetCharacter().m_kChar.iType == 2)
07 B1 02 9A 35 56 0F 00 00 58 0F 00 00 00 00 19 19 01 25 D5 00 00 0A 00 D0 C9 00 00 00 1B E5 37 00 00 00 00 00 00 16 09 00 03 B8 00 00 00 01 03 B8 00 00 2C 02 16 

	//m_kPawn.FlyingLegMaskNode.SetBlendTarget(0.0, 0.20)
	19 19 01 24 D5 00 00 09 00 F8 3B 00 00 00 01 F8 3B 00 00 14 00 00 00 00 00 00 1B 81 6D 00 00 00 00 00 00 1E 00 00 00 00 1E CD CC 4C 3E 16 

//if((m_arrReplicatedPathPoints[1].eTraversal == 1) && m_kUnit.m_eCoverState != 0)
07 29 04 82 9A 38 3A 35 35 62 00 00 37 62 00 00 00 00 1A 26 01 1C 90 00 00 38 3A 24 01 16 18 27 00 9B 38 3A 19 01 25 D5 00 00 09 00 20 3A 00 00 00 01 20 3A 00 00 38 3A 24 00 16 16 

	//m_kUnit.IdleStateMachine.ExitFromCover(m_arrReplicatedPathPoints[1].vRawPathPoint - m_kPawn.Location)
	19 19 01 25 D5 00 00 09 00 CF 39 00 00 00 01 CF 39 00 00 48 00 00 00 00 00 00 1B F1 30 00 00 00 00 00 00 D8 35 36 62 00 00 37 62 00 00 00 00 1A 26 01 1C 90 00 00 19 01 24 D5 00 00 09 00 94 F8 FF FF 00 01 94 F8 FF FF 16 16 

	//if(m_kUnit.IdleStateMachine.IsEvaluatingStance())
	07 B9 03 19 19 01 25 D5 00 00 09 00 CF 39 00 00 00 01 CF 39 00 00 0A 00 33 5A 00 00 00 1B E9 44 00 00 00 00 00 00 16 

		//Sleep(0.0)
		61 00 1E 00 00 00 00 16 

		//while loop
		06 77 03 

	//if(!m_kUnit.IdleStateMachine.IsDormant())
	07 29 04 81 19 19 01 25 D5 00 00 09 00 CF 39 00 00 00 01 CF 39 00 00 0A 00 35 5A 00 00 00 1B CA 44 00 00 00 00 00 00 16 16 

		//m_kUnit.IdleStateMachine.GoDormant()
		19 19 01 25 D5 00 00 09 00 CF 39 00 00 00 01 CF 39 00 00 0D 00 00 00 00 00 00 1B B9 3C 00 00 00 00 00 00 4A 4A 4A 16 

//m_kUnit.UnClaimCover()
19 01 25 D5 00 00 0A 00 00 00 00 00 00 1B 77 7A 00 00 00 00 00 00 16 

//m_kUnit.RemoveCoverBonuses()
19 01 25 D5 00 00 0A 00 00 00 00 00 00 1B C3 68 00 00 00 00 00 00 16 

[/CODE]
[/BEFORE_HEX]


[AFTER_HEX]
[HEADER]

[/HEADER]
[code]
//if((WorldInfo.NetMode != NM_Standalone) && !WorldInfo.IsConsoleBuild())
//07 50 00 82 9B 38 3A 19 01 A6 F9 FF FF 09 00 8F FE FF FF 00 01 8F FE FF FF 38 3A 24 00 16 18 23 00 81 19 01 A6 F9 FF FF 0B 00 C4 FE FF FF 00 1C 2E FA FF FF 4A 16 16 16 

//HACK_fGhettoStuckLoopingTimeoutSeconds = 10.0
//0F 01 18 90 00 00 1E 00 00 20 41 

//if(XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kCameraManager.WaitForCamera())
//07 01 01 19 19 2E 54 32 00 00 19 12 20 35 FE FF FF 0A 00 92 F9 FF FF 00 1C D5 FB FF FF 16 09 00 50 F9 FF FF 00 01 50 F9 FF FF 09 00 42 32 00 00 00 01 42 32 00 00 0A 00 C1 49 00 00 00 1B 07 7F 00 00 00 00 00 00 16 

	//Sleep(0.050)
//	61 00 1E CD CC 4C 3D 16 

	//if(HACK_fGhettoStuckLoopingTimeoutSeconds <= 0.0)
//	07 FE 00 B2 01 18 90 00 00 1E 00 00 00 00 16 

		//HACK_fGhettoStuckLoopingTimeoutSeconds = 10.0
//		0F 01 18 90 00 00 1E 00 00 20 41 

		//goto 'AfterWaitForCameraManager'
//		0D 21 02 03 00 00 00 00 00 00 

	//goto J0x5F
//	06 5F 00 


//start 0x101
//if(m_kUnit.GetCharacter().m_kChar.iType == 2)
07 8D 01 9A 35 56 0F 00 00 58 0F 00 00 00 00 19 19 01 25 D5 00 00 0A 00 D0 C9 00 00 00 1B E5 37 00 00 00 00 00 00 16 09 00 03 B8 00 00 00 01 03 B8 00 00 2C 02 16 

	//m_kPawn.FlyingLegMaskNode.SetBlendTarget(0.0, 0.20)
	19 19 01 24 D5 00 00 09 00 F8 3B 00 00 00 01 F8 3B 00 00 14 00 00 00 00 00 00 1B 81 6D 00 00 00 00 00 00 1E 00 00 00 00 1E CD CC 4C 3E 16 

//if((m_arrReplicatedPathPoints[1].eTraversal == 1) && m_kUnit.m_eCoverState != 0)
07 05 03 82 9A 38 3A 35 35 62 00 00 37 62 00 00 00 00 1A 26 01 1C 90 00 00 38 3A 24 01 16 18 27 00 9B 38 3A 19 01 25 D5 00 00 09 00 20 3A 00 00 00 01 20 3A 00 00 38 3A 24 00 16 16 

	//m_kUnit.IdleStateMachine.ExitFromCover(m_arrReplicatedPathPoints[1].vRawPathPoint - m_kPawn.Location)
	19 19 01 25 D5 00 00 09 00 CF 39 00 00 00 01 CF 39 00 00 48 00 00 00 00 00 00 1B F1 30 00 00 00 00 00 00 D8 35 36 62 00 00 37 62 00 00 00 00 1A 26 01 1C 90 00 00 19 01 24 D5 00 00 09 00 94 F8 FF FF 00 01 94 F8 FF FF 16 16 

	//if(m_kUnit.IdleStateMachine.IsEvaluatingStance())
	07 95 02 19 19 01 25 D5 00 00 09 00 CF 39 00 00 00 01 CF 39 00 00 0A 00 33 5A 00 00 00 1B E9 44 00 00 00 00 00 00 16 

		//Sleep(0.0)
		61 00 1E 00 00 00 00 16 

		//while loop
		06 53 02 

	//if(!m_kUnit.IdleStateMachine.IsDormant())
	07 05 03 81 19 19 01 25 D5 00 00 09 00 CF 39 00 00 00 01 CF 39 00 00 0A 00 35 5A 00 00 00 1B CA 44 00 00 00 00 00 00 16 16 

		//m_kUnit.IdleStateMachine.GoDormant()
		19 19 01 25 D5 00 00 09 00 CF 39 00 00 00 01 CF 39 00 00 0D 00 00 00 00 00 00 1B B9 3C 00 00 00 00 00 00 4A 4A 4A 16 

//m_kUnit.UnClaimCover()
19 01 25 D5 00 00 0A 00 00 00 00 00 00 1B 77 7A 00 00 00 00 00 00 16 

//m_kUnit.RemoveCoverBonuses()
19 01 25 D5 00 00 0A 00 00 00 00 00 00 1B C3 68 00 00 00 00 00 00 16 

//if(m_kUnit.IsBeingSuppressed())
07 67 04 19 01 25 D5 00 00 0A 00 EB 35 00 00 00 1B 7D 44 00 00 00 00 00 00 16 

	//ProcessSuppression(m_kUnit)
	1B 7A 66 00 00 00 00 00 00 01 25 D5 00 00 16 

	//if(m_kUnit.m_eCoverState != 0)
	07 FF 03 9B 38 3A 19 01 25 D5 00 00 09 00 20 3A 00 00 00 01 20 3A 00 00 38 3A 24 00 16 

		//if(m_kPawn.MovementNode != none)
		07 FF 03 77 19 01 24 D5 00 00 09 00 F7 3B 00 00 00 01 F7 3B 00 00 2A 16 

			//m_kPawn.MovementNode.SetActiveChild(1, 0.10)
			19 19 01 24 D5 00 00 09 00 F7 3B 00 00 00 01 F7 3B 00 00 10 00 00 00 00 00 00 1B 2E 6D 00 00 00 00 00 00 26 1E CD CC CC 3D 16 

	//HACK_fGhettoStuckLoopingTimeoutSeconds = 10.0
	0F 01 18 90 00 00 1E 00 00 20 41 

	//if(m_kPres.CAMIsBusy())
	07 67 04 19 01 22 D5 00 00 0A 00 9B 74 00 00 00 1B 59 11 00 00 00 00 00 00 16 

		//Sleep(0.0)
		61 00 1E 00 00 00 00 16 

		//if(HACK_fGhettoStuckLoopingTimeoutSeconds <= 0.0)
		07 64 04 B2 01 18 90 00 00 1E 00 00 00 00 16 

			//HACK_fGhettoStuckLoopingTimeoutSeconds = 10.0
			0F 01 18 90 00 00 1E 00 00 20 41 

			//goto 'AfterOverwatchProcessing'
			0D 21 00 03 00 00 00 00 00 00 

		//while loop
		06 0E 04 

// label AfterOverwatchProcessing 

//0b
[/CODE]
[/AFTER_HEX]

[BEFORE_HEX]

0C FE 02 00 00 00 00 00 00 11 0C 00 00 
00 03 00 00 00 00 00 00 25 02 00 00 // AfterOverWatchProcessing -- position 0x252
02 03 00 00 00 00 00 00 01 01 00 00 
BC 09 00 00 00 00 00 00 00 00 00 00 
51 60 00 00 00 00 00 00 FF FF 00 00 

[/BEFORE_HEX]

[AFTER_HEX]

0C FE 02 00 00 00 00 00 00 11 0C 00 00 
00 03 00 00 00 00 00 00 67 04 00 00 //AfterOverwatchProcessing -- position 0x467
02 03 00 00 00 00 00 00 01 01 00 00 
BC 09 00 00 00 00 00 00 00 00 00 00 
51 60 00 00 00 00 00 00 FF FF 00 00 

[/AFTER_HEX] 

 

 

 

 

Enjoy! :smile:

Edited by Amineri
Link to comment
Share on other sites

  • Recently Browsing   0 members

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