Jump to content

R&D Modding Ammo


Amineri

Recommended Posts

  • Replies 71
  • Created
  • Last Reply

Top Posters In This Topic

Might be the source of the problem?

 

XComGame >> UITacticalHUD_AbilityContainer >> BuildAbilities ()

// End:0x264
                    if(kAbility.GetType() == 45)
                    {
                        kActiveWeapon = kUnit.GetInventory().GetActiveWeapon();
                        // End:0x24B
                        if((kActiveWeapon != none) && kActiveWeapon.iAmmo <= 0)
                        {
                            m_arrAbilities.InsertItem(0, kAbility);
                            ++ forceAbilitySlot;
                        }
                        // End:0x261
                        else
                        {
                            m_arrAbilities.AddItem(kAbility);
                        }
                    }

I'm pretty sure ability 45 is reload ... but there must be some logic somewhere else that prevents the ability from being added if ammo >= 100. perhaps changing kActiveWeapon.iAmmo <= 0) to <= 200 would do the trick, but not sure.

Link to comment
Share on other sites

Okay, after some additional thought I have an entirely new approach to deal with the inability-to-fire/cant-reload issue being caused by the native code checks. This new approach would limit firing and suppression properly (might still be some issues with Flush if it's new ammo usage is turned down though) and still allow reloading as usual.

 

It involves a bit more misdirection specifically aimed at fooling the native code...

 

Vanilla weapons all have 4 / 8 shots or 3 / 6 shots for Heavy weapons.

 

In terms of ammo usage that is 25 / 12 or 33 / 16 ammo used per shot. Clearly the native code limits the use of an ability based on remaining ammo (e.g. have iAmmo == 50 cannot suppress with eWP_Heavy weapon).

 

For non-ammo conservation situation, there are the following breaks:

  • iAmmo ==20 : cannot shoot or suppress any weapon
  • iAmmo == 40 : can shoot any weapon but cannot suppress with any weapon
  • iAmmo == 70 : can shoot or suppress with any weapon

 

For ammo conservation situation, there are the following breaks:

  • iAmmo == 10: cannot shoot or suppress any weapon
  • iAmmo == 20: can shoot any weapon but cannot suppress with any weapon
  • iAmmo == 35: can shoot or suppress with any weapon

 

So, my solution is to NOT use the XGWeapon.iAmmo variable any longer to store the remaining ammo. Instead, iAmmo will be set to the specific value above after a shot is taken specifically to cause the native code to allow/suppress abilities correctly (Flush apparently uses a lot of ammo in vanilla, so it may be unavailable when suppression is unavailable -- will need more testing).

 

To hold the actual ammo count I plan to use the XG_Weapon.m_iTurnFired variable, which is currently only used to store a 1 to store whether a weapon overheated, and overheat functionality was disabled and no-one wants it back :)

 

Since the process of setting ammo would be more complicated with this change, requiring both setting the m_iTurnFired variable to record the ammo used and setting the iAmmo variable to make the native code exhibity the correct behavior, I'll have to get rid of the ApplyAmmoCost function, and wrap the ammo-setting functionality into the new ammo-retrieval function XGWeapon.GraduatedOdds.

 

I have one unused parameter left in that function (a class) which I can leave as none or set non-none to flag whether GraduatedOdds should update the ammo or just return the ammo consumed. The only case this flag would be set is in XGAbilityTree.ApplyActionCost.

 

When setting ammo, the GraduatedOdds functions will test the ammo per shot, the real amount of remaining ammo stored in m_TurnFired, whether Ammo Conservation is enabled, and will set the iAmmo value accordingly to generate correct behavior from the native code in terms of ability availability.

 

The GetRemainingAmmo function will be changed to return m_iTurnFired instead of iAmmo. There are a couple of places in the upk code where iAmmo is accessed or set directly -- those will be patched to access m_iTurnFired instead.

 

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

 

As for Flush, I'm going to change its default ammo consumption to equal that of Suppression. I have some other thoughts in mind to make flush more viable. In truth I think Flush is actually a quite viable skill already, but is pretty underappreciated due to it being placed opposite to the incredibly useful Rapid Fire.

 

Flush does the following already in vanilla:

  1. Grants +30 to aim for the shot (an AMAZING amount)
  2. Forces the targetted unit to move at least 7.5 tiles from its current position (480.0 UE units)
  3. Shot does 50% of normal damage
  4. Consumes additional ammo (not sure how much more -- 2x or 3x?)

If necessary the amount the damage is reduce could be modified to maybe 60% or so, but with a +30 aim adding much to damage could quickly become overpowered. Flush nearly negates full cover with its aim bonus, so letting it do any more than 50% damage would be pretty OP.

Link to comment
Share on other sites

I actually think flush is fine, just in a poor place in the vanilla assault perk tree. It's great for finishing off badly wounded aliens.

 

Other than suppression, the other biggie that is OP by the any-action-with-any-ammo feature is Rapid Fire -- my assault rifles have three bursts per magazine, but the trooper was able to use it twice.

Link to comment
Share on other sites

Main reason I didn't give Flush to Heavys was that if using Unlimited Ammo it becomes an insanely awesome ability. So I left it with Support, the ability doesn't need to be changed as we've already re-balanced it but it should still cost as much ammo as Suppression and I believe it probably does 2.5 as plenty of times after a flush in vanilla there used to be tiny bit of ammo left but not enough to actually fire the weapon.

Link to comment
Share on other sites

I actually think flush is fine, just in a poor place in the vanilla assault perk tree. It's great for finishing off badly wounded aliens.

 

Other than suppression, the other biggie that is OP by the any-action-with-any-ammo feature is Rapid Fire -- my assault rifles have three bursts per magazine, but the trooper was able to use it twice.

 

Good call pointing issue with Rapid Fire having the similar issues.

 

I've changed the default ammo usage for flush to require 2 shots just as suppression does.

 

Here's my prototype for setting iAmmo so that the native code does/doesn't restrict abilities appropriately:

	if(kHumanPlayer != none) // check to see should assign ammo instead of just returning ammo used
	{
		m_iTurnFire -= iAdjustment; // remove ammo used
		if(m_iTurnFired >= (100/iFactor)) // has enough ammo to fire
		{
			if(bCantLose) // has Ammo Conservation
			{
				iAmmo = 20;  // set iAmmo to allow Fire action but not Suppression
			}
			else // doesn't have Ammo Conservations
			{
				iAmmo = 40;  // set iAmmo to allow Fire action but not Suppression
			}
		}
		if(m_iTurnFired >= 2* (100/iFactor))  // has enough ammo to suppress
		{
			iAmmo = 90;  // set iAmmo to allow any ability to be used, and Reload available
		}
		if(m_iTurnFired < (100 / iFactor))  // not enough ammo to do anything
		{
			iAmmo = 0;   // set iAmmo to empty
			m_iTurnFired = 0;  // set actual ammo to empty
		}
	}

I think that 20 ammo is sufficient to fire but not suppress with any weapon in vanilla if A.C. is complete. (LMG uses 16 ammo per shot, all else uses 12)

Same for 40 ammo if A.C. is not complete (LMG uses 33 ammo per shot, all else uses 25)

Setting to 90 ammo should allow reloading after any shot action is taken that uses ammo

Setting to 0 should inhibit any firing-type actions under all circumstances.

 

Hopefully this will fix the Suppression and Rapid Fire issues, make it so that abilities can be used appropriately to the actual ammo remaining, and allow for reloading when any ammo is used.

 

Next I have to look into the reload function to see if I can properly set both variable, or come up with some alternative.

Link to comment
Share on other sites

Okay, hopefully third time is the charm!

 

I've reworked the ammo system a bit more.

 

  • XGWeapon.iAmmo no longer stores the current ammo -- instead it is set in order to produce desired effect in native code (ability availability)
  • XGWeapon.m_iTurnFired now holds current ammo -- default set to 100
  • XGAbility_Targeted.GraduatedOdds (new ammocost function) will set iAmmo and m_iTurnFired if a non-null value is passed in 2nd parameter
  • various other function changes to support this system

Functionally it should do the following:

  • Reload ability is available at all times excepting when ammo is full
  • Suppression / flush should be unavailable when ammo is low (less than 2x single shot left)
  • Flush default ammo usage is double, like Suppression
  • Regular shots should be available until clip shows empty -- upon reaching ammo < single shot, ammo is set to 0
  • clip-sizes up to 12 should work as before (setting 13 shots will allow 14 due to round-off error)

Here is the complete hex code (before/after relative to vanilla):

 

 

All hex changes for Ammo Cost mod
Change to make ApplyAmmoCost into a helper function to reset ammo upon reload
original hex:
52 B9 00 00 50 55 00 00 00 00 00 00 3C B9 00 00 00 00 00 00 00 00 00 00 3D B9 00 00 00 00 00 00 D9 00 00 00 45 1A 00 00 31 00 00 00 21 00 00 00 A2 01 1E B9 00 00 00 3D B9 00 00 16 07 2E 00 9A 01 1E B9 00 00 26 16 0F 01 1E B9 00 00 25 04 0B 53
new hex: (virtual 0x2D)
52 B9 00 00 50 55 00 00 00 00 00 00 3C B9 00 00 00 00 00 00 00 00 00 00 3D B9 00 00 00 00 00 00 D9 00 00 00 45 1A 00 00 2D 00 00 00 21 00 00 00 0F 01 1C B9 00 00 00 3D B9 00 00 0F 01 1E B9 00 00 2C 64 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 0B 53
Remove call to ApplyAmmoCost in XGAbilityTree.ApplyActionCost
original hex:
kAbility.m_kWeapon.ApplyAmmoCost(iCost); (61=0x3D virtual) (41=0x29 file) 20=0x14 delta
19 19 00 C4 7E 00 00 09 00 E8 BB 00 00 00 01 E8 BB 00 00 13 00 00 00 00 00 00 1B EF 03 00 00 00 00 00 00 00 C3 7E 00 00 16
new hex:
null ops
00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B
---------------------------------------------
Change XGAbilityTree.ApplyActionCost to call XGAbility_Targeted.GraduatedOdds instead of XGTacticalGameCore.GetAmmoCost
original hex for just function: (next 0x1EB)
iCost = XComGameReplicationInfo(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kGameCore.GetAmmoCost(kAbility.m_kWeapon.GameplayType(), kAbility.GetType(), kAbility.m_kUnit.GetPlayer().HasFoundryHistory(10), kAbility.m_kUnit.GetCharacter().m_kChar, kAbility.m_bReactionFire); (259 file, 379 virtual bytes -- 120 extra)
0F 00 C3 7E 00 00 19 19 2E FE 2C 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 F0 2C 00 00 00 01 F0 2C 00 00 13 01 42 10 00 00 00 1B 16 31 00 00 00 00 00 00 38 3A 19 19 00 C4 7E 00 00 09 00 E8 BB 00 00 00 01 E8 BB 00 00 0A 00 E8 9B 00 00 00 1B 92 30 00 00 00 00 00 00 16 19 00 C4 7E 00 00 0A 00 1C 7C 00 00 00 1B 1E 35 00 00 00 00 00 00 16 19 19 19 00 C4 7E 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 EB B2 00 00 00 1B 0A 34 00 00 00 00 00 00 16 0C 00 9E 94 00 00 00 1B 7A 36 00 00 00 00 00 00 24 0A 16 19 19 19 00 C4 7E 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 63 B4 00 00 00 1B 7B 31 00 00 00 00 00 00 16 09 00 C3 A2 00 00 00 01 C3 A2 00 00 19 00 C4 7E 00 00 0A 00 D2 7B 00 00 00 2D 01 D2 7B 00 00 16
new function call: (next 0x1EB)
iCost = kAbility.GraduatedOdds(0, kAbility, kAbility.m_kUnit.GetPlayer().HasFoundryHistory(10)); (92 file, 128 virtual bytes -- 36 extra)
0F 00 C3 7E 00 00 19 00 C4 7E 00 00 61 00 B9 7C 00 00 00 1B E1 35 00 00 00 00 00 00 2C 00 00 C4 7E 00 00 19 19 19 00 C4 7E 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 EB B2 00 00 00 1B 0A 34 00 00 00 00 00 00 16 0C 00 9E 94 00 00 00 1B 7A 36 00 00 00 00 00 00 24 0A 16 16 0B 0B 0B 0B 0B 0B 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 00 00 00 C3 7E 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 0B 0B 0B 0B 0B
---------------------------------------------
Alter UITacticalHUD_WeaponPanel.SetWeaponAndAmmo to call XGAbility_Targeted.GraduatedOdds instead of XGTacticalGameCore.GetAmmoCost
****TWO IDENTICAL CALLS****
call 2 hex: (identical to call 1 ) (254 file, 370 virtual bytes -- 116 additional)
0F 35 C8 FC FF FF 32 F9 FF FF 00 01 00 72 27 00 00 38 3F 19 19 2E FE 2C 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 F0 2C 00 00 00 01 F0 2C 00 00 F5 00 42 10 00 00 00 1B 16 31 00 00 00 00 00 00 38 3A 19 19 00 70 27 00 00 09 00 E8 BB 00 00 00 01 E8 BB 00 00 0A 00 E8 9B 00 00 00 1B 92 30 00 00 00 00 00 00 16 19 00 70 27 00 00 0A 00 1C 7C 00 00 00 1B 1E 35 00 00 00 00 00 00 16 19 19 19 00 70 27 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 EB B2 00 00 00 1B 0A 34 00 00 00 00 00 00 16 0C 00 9E 94 00 00 00 1B 7A 36 00 00 00 00 00 00 24 0A 16 19 19 19 00 70 27 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 63 B4 00 00 00 1B 7B 31 00 00 00 00 00 00 16 09 00 C3 A2 00 00 00 01 C3 A2 00 00 4A 16
new function call:
myValue.N = float(kTAbility.GraduatedOdds(0, none, kTAbility.m_kUnit.GetPlayer().HasFoundryHistory(10))); (101 file, 141 virtual bytes -- 40 extra)
0F 35 C8 FC FF FF 32 F9 FF FF 00 01 00 72 27 00 00 38 3F 19 00 70 27 00 00 59 00 B9 7C 00 00 00 1B E1 35 00 00 00 00 00 00 2C 00 2A 19 19 19 00 70 27 00 00 09 00 E6 7B 00 00 00 01 E6 7B 00 00 0A 00 EB B2 00 00 00 1B 0A 34 00 00 00 00 00 00 16 0C 00 9E 94 00 00 00 1B 7A 36 00 00 00 00 00 00 24 0A 16 16 0B 0B 0B 0B 0B 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 00 00 00 70 27 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 0B 0B
---------------------------------------------
Rewrite XGUnit.ReactionWeaponCheck to call XGAbility_Targeted.GraduatedOdds instead of XGTacticalGameCore.GetAmmoCost
original hex:
CA B7 00 00 50 55 00 00 00 00 00 00 B3 B7 00 00 00 00 00 00 00 00 00 00 B5 B7 00 00 00 00 00 00 F6 31 00 00 88 45 06 00 5F 01 00 00 07 01 00 00 0F 00 B4 B7 00 00 19 1B CC 32 00 00 00 00 00 00 16 0A 00 2C 0A 00 00 00 1B ED 30 00 00 00 00 00 00 16 07 3B 00 72 00 B4 B7 00 00 2A 16 04 28 07 2E 01 96 19 00 B4 B7 00 00 0A 00 3B B9 00 00 00 1B 6A 34 00 00 00 00 00 00 16 19 19 2E FE 2C 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 F0 2C 00 00 00 01 F0 2C 00 00 6F 00 42 10 00 00 00 1B 16 31 00 00 00 00 00 00 38 3A 19 00 B4 B7 00 00 0A 00 E8 9B 00 00 00 1B 92 30 00 00 00 00 00 00 16 2C 07 19 1B 0A 34 00 00 00 00 00 00 16 0C 00 9E 94 00 00 00 1B 7A 36 00 00 00 00 00 00 24 0A 16 19 1B 7B 31 00 00 00 00 00 00 16 09 00 C3 A2 00 00 00 01 C3 A2 00 00 27 16 16 04 28 07 52 01 19 00 B4 B7 00 00 0A 00 47 B9 00 00 00 1B F8 3D 00 00 00 00 00 00 16 04 28 04 27 04 3A B5 B7 00 00 53
new hex: (virtual 0x15B)
header:
CA B7 00 00 50 55 00 00 00 00 00 00 B3 B7 00 00 00 00 00 00 00 00 00 00 B5 B7 00 00 00 00 00 00 F6 31 00 00 88 45 06 00 5B 01 00 00 07 01 00 00 0F 00 B4 B7 00 00 19 1B CC 32 00 00 00 00 00 00 16 0A 00 2C 0A 00 00 00 1B ED 30 00 00 00 00 00 00 16 07 3B 00 72 00 B4 B7 00 00 2A 16 04 28 0F 00 54 B7 00 00 9E 35 9C 0D 00 00 AA 0D 00 00 00 00 19 00 B4 B7 00 00 09 00 14 B9 00 00 00 01 14 B9 00 00 94 1A 2C 0C 35 D1 0D 00 00 D5 0D 00 00 00 01 19 01 0A 31 00 00 09 00 C3 A2 00 00 00 01 C3 A2 00 00 2C 10 16 16 07 2D 01 96 19 00 B4 B7 00 00 0A 00 3B B9 00 00 00 1B 6A 34 00 00 00 00 00 00 16 12 20 66 7D 00 00 36 00 BC 7C 00 00 00 1B E1 35 00 00 00 00 00 00 00 54 B7 00 00 2A 19 1B 0A 34 00 00 00 00 00 00 16 0C 00 9E 94 00 00 00 1B 7A 36 00 00 00 00 00 00 24 0A 16 16 16 04 28 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 0B04 27 04 3A B5 B7 00 00 53
---------------------------------------------
Rewrite XGAbility_Targeted.GraduatedOdds into the new Ammo Costing function -- also can apply ammo used
original hex:
D4 7C 00 00 50 55 00 00 00 00 00 00 B8 7C 00 00 00 00 00 00 00 00 00 00 BF 7C 00 00 00 00 00 00 73 02 00 00 CF 54 00 00 3D 04 00 00 0D 03 00 00 0F 00 BA 7C 00 00 19 19 00 BE 7C 00 00 0A 00 56 94 00 00 00 1B C5 34 00 00 00 00 00 00 16 0A 00 40 AC 00 00 00 1B 95 33 00 00 00 00 00 00 16 07 F2 01 19 19 19 2E 64 2D 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 71 2D 00 00 00 01 71 2D 00 00 09 00 A3 9C 00 00 00 01 A3 9C 00 00 0A 00 A8 9F 00 00 00 2D 01 A8 9F 00 00 07 F2 01 82 81 19 01 E6 7B 00 00 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 18 21 00 19 1B 38 34 00 00 00 00 00 00 16 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 07 F2 01 82 82 2D 00 BD 7C 00 00 18 5F 00 77 19 2E 64 2D 00 00 2E FE 2C 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 69 2D 00 00 00 01 69 2D 00 00 2A 16 16 18 74 00 81 19 19 2E 64 2D 00 00 2E FE 2C 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 69 2D 00 00 00 01 69 2D 00 00 0A 00 97 4C 00 00 00 2D 01 97 4C 00 00 16 16 04 25 07 08 02 99 00 BA 7C 00 00 2C 04 16 04 1D FF FF FF FF 0F 00 B9 7C 00 00 93 F9 2C 04 19 19 00 BE 7C 00 00 0A 00 56 94 00 00 00 1B C5 34 00 00 00 00 00 00 16 0A 00 87 AC 00 00 00 1B AD 33 00 00 00 00 00 00 16 16 00 BA 7C 00 00 16 07 39 03 82 82 19 01 E6 7B 00 00 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 18 23 00 81 19 1B 38 34 00 00 00 00 00 00 16 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 16 18 0D 00 97 00 BF 7C 00 00 25 16 16 0F 00 BB 7C 00 00 91 00 BF 7C 00 00 2C 05 16 07 1E 03 99 00 BF 7C 00 00 2C 32 16 A1 00 BB 7C 00 00 F9 2C 1E 90 19 19 01 E6 7B 00 00 0A 00 EB B2 00 00 00 1B 0A 34 00 00 00 00 00 00 16 09 00 DB 93 00 00 00 01 DB 93 00 00 2C 0F 16 16 16 A1 00 BB 7C 00 00 90 00 B9 7C 00 00 2C 0F 16 16 06 18 04 07 18 04 82 81 19 01 E6 7B 00 00 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 18 21 00 19 1B 38 34 00 00 00 00 00 00 16 0A 00 B5 32 00 00 00 1B DB 3D 00 00 00 00 00 00 16 16 0F 00 BB 7C 00 00 90 8F 19 19 1B 38 34 00 00 00 00 00 00 16 0A 00 EB B2 00 00 00 1B 0A 34 00 00 00 00 00 00 16 09 00 DC 93 00 00 00 01 DC 93 00 00 16 2C 0A 16 07 FD 03 82 9A 00 BA 7C 00 00 26 16 18 0B 00 2D 00 BD 7C 00 00 16 0F 00 BB 7C 00 00 8F 00 BF 7C 00 00 16 06 18 04 A1 00 BB 7C 00 00 90 00 B9 7C 00 00 1D E7 FF FF FF 16 16 04 FB 92 00 BF 7C 00 00 00 BB 7C 00 00 16 25 2C 64 16 04 3A BC 7C 00 00 53
new hex : (virtual 0x435)
D4 7C 00 00 50 55 00 00 00 00 00 00 B8 7C 00 00 00 00 00 00 00 00 00 00 BF 7C 00 00 00 00 00 00 73 02 00 00 CF 54 00 00 35 04 00 00 0D 03 00 00 0F 00 BB 7C 00 00 25 07 37 00 9B 00 BF 7C 00 00 25 16 0F 00 BB 7C 00 00 9C 00 BF 7C 00 00 1D FF FF 00 00 16 06 CD 00 07 48 00 72 01 E8 BB 00 00 2A 16 04 25 07 6E 00 19 01 E8 BB 00 00 0C 00 4F B9 00 00 00 1B 9A 36 00 00 00 00 00 00 2C 0A 16 04 25 07 92 00 19 01 E8 BB 00 00 0A 00 4D B9 00 00 00 1B D6 3D 00 00 00 00 00 00 16 04 25 0F 00 BB 7C 00 00 35 9C 0D 00 00 AA 0D 00 00 00 00 19 01 E8 BB 00 00 09 00 14 B9 00 00 00 01 14 B9 00 00 07 F6 00 81 2D 00 BD 7C 00 00 16 0F 00 B9 7C 00 00 FD 00 BB 7C 00 00 2C 64 16 06 0D 01 0F 00 B9 7C 00 00 91 00 BB 7C 00 00 2C 64 16 07 3A 01 9B 00 BF 7C 00 00 25 16 0F 00 BA 7C 00 00 9C 95 00 BF 7C 00 00 2C 10 16 2C FF 16 06 8D 01 0F 00 BA 7C 00 00 1A 2C 0C 35 D1 0D 00 00 D5 0D 00 00 00 01 19 19 01 E6 7B 00 00 09 00 0A 31 00 00 00 01 0A 31 00 00 09 00 C3 A2 00 00 00 01 C3 A2 00 00 07 AC 01 97 9C 00 BA 7C 00 00 26 16 25 16 A1 00 B9 7C 00 00 2C 02 16 07 DA 01 97 9C 00 BA 7C 00 00 2C FE 16 25 16 A1 00 B9 7C 00 00 90 2C 01 95 00 BA 7C 00 00 26 16 16 16 0F 00 B9 7C 00 00 FA 00 B9 7C 00 00 2C 01 16 0F 00 BB 7C 00 00 91 2C 64 00 B9 7C 00 00 16 07 B3 03 9A 00 BF 7C 00 00 25 16 07 3F 02 9A 1B 1E 35 00 00 00 00 00 00 16 2C 11 16 0F 00 BB 7C 00 00 90 2C 02 00 BB 7C 00 00 16 07 67 02 9A 1B 1E 35 00 00 00 00 00 00 16 2C 0C 16 0F 00 BB 7C 00 00 90 2C 01 00 BB 7C 00 00 16 07 B3 03 77 00 BE 7C 00 00 2A 16 0F 00 BA 7C 00 00 A2 19 01 E8 BB 00 00 09 00 1C B9 00 00 00 01 1C B9 00 00 00 BB 7C 00 00 16 07 16 03 99 00 BA 7C 00 00 91 2C 64 00 B9 7C 00 00 16 16 07 F5 02 2D 00 BD 7C 00 00 0F 19 01 E8 BB 00 00 09 00 1E B9 00 00 00 01 1E B9 00 00 2C 14 06 16 03 0F 19 01 E8 BB 00 00 09 00 1E B9 00 00 00 01 1E B9 00 00 2C 28 07 56 03 99 00 BA 7C 00 00 90 2C 02 91 2C 64 00 B9 7C 00 00 16 16 16 0F 19 01 E8 BB 00 00 09 00 1E B9 00 00 00 01 1E B9 00 00 2C 5A 07 B3 03 96 00 BA 7C 00 00 91 2C 64 00 B9 7C 00 00 16 16 0F 19 01 E8 BB 00 00 09 00 1E B9 00 00 00 01 1E B9 00 00 2C 00 0F 19 01 E8 BB 00 00 09 00 1C B9 00 00 00 01 1C B9 00 00 2C 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 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 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 04 00 BB 7C 00 00 53
-----------------------------------------
Disable call to GraduatedOdds in XGAbility_Targeted.AdjustToHit
Change first conditional from:
if(kPlayer.m_bCantLose || XComTacticalGRI(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kBattle.m_kDesc.m_iDifficulty == 0)
07 C2 02 84 19 00 C1 7C 00 00 0A 00 D9 93 00 00 00 2D 01 D9 93 00 00 18 80 00 9A 19 19 19 2E 64 2D 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 71 2D 00 00 00 01 71 2D 00 00 09 00 A3 9C 00 00 00 01 A3 9C 00 00 09 00 B2 9F 00 00 00 01 B2 9F 00 00 25 16 16
to:
if(kPlayer.m_bCantLose && XComTacticalGRI(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kBattle.m_kDesc.m_iDifficulty < 0)
07 C2 02 82 19 00 C1 7C 00 00 0A 00 D9 93 00 00 00 2D 01 D9 93 00 00 18 80 00 96 19 19 19 2E 64 2D 00 00 19 12 20 4F FE FF FF 0A 00 D8 F9 FF FF 00 1C F6 FB FF FF 16 09 00 98 F9 FF FF 00 01 98 F9 FF FF 09 00 71 2D 00 00 00 01 71 2D 00 00 09 00 A3 9C 00 00 00 01 A3 9C 00 00 09 00 B2 9F 00 00 00 01 B2 9F 00 00 25 16 16
-----------------------------------------
Change to XGGUnit.Reload to reset both by calling ApplyAmmoCost m_iTurnFired and iAmmo
original:
header:
A7 B6 00 00 50 55 00 00 00 00 00 00 90 B6 00 00 00 00 00 00 00 00 00 00 92 B6 00 00 00 00 00 00 7F 2B 00 00 21 75 05 00 A5 00 00 00 79 00 00 00
body:
07 95 00 9A 38 3A 01 C1 FE FF FF 38 3A 24 03 16 0F 19 00 92 B6 00 00 09 00 1E B9 00 00 00 01 1E B9 00 00 2C 64 0F 00 91 B6 00 00 1C 3D FC FF FF 20 8D 87 00 00 01 ED F9 FF FF 4A 4A 4A 4A 4A 4A 16 19 00 91 B6 00 00 0B 00 89 87 00 00 00 1B 44 3A 00 00 00 00 00 00 17 16 1B 92 01 00 00 00 00 00 00 00 91 B6 00 00 4A 16 07 A2 00 1B C6 3C 00 00 00 00 00 00 16 04 0B 53
new: (virtual 0xA1)
header:
A7 B6 00 00 50 55 00 00 00 00 00 00 90 B6 00 00 00 00 00 00 00 00 00 00 92 B6 00 00 00 00 00 00 7F 2B 00 00 21 75 05 00 A1 00 00 00 79 00 00 00
body:
07 95 00 9A 38 3A 01 C1 FE FF FF 38 3A 24 03 16 19 00 92 B6 00 00 0C 00 00 00 00 00 00 1B EF 03 00 00 00 00 00 00 2C 64 16 0F 00 91 B6 00 00 1C 3D FC FF FF 20 8D 87 00 00 01 ED F9 FF FF 4A 4A 4A 4A 4A 4A 16 19 00 91 B6 00 00 0B 00 89 87 00 00 00 1B 44 3A 00 00 00 00 00 00 17 16 1B 92 01 00 00 00 00 00 00 00 91 B6 00 00 4A 16 04 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 53
-----------------------------------------
Need to create default value of m_iTurnFired of 100
Change XGWeapon.default.fFiringRate=1.5 into XGWeapon.default.m_iTurnFired=100
original:
02 2D 00 00 00 00 00 00 2A 2E 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 C0 3F
new:
1E 4C 00 00 00 00 00 00 9D 3B 00 00 00 00 00 00 04 00 00 00 00 00 00 00 64 00 00 00
-----------------------------------------
Change XGUnit.SetAutoFiringRate to not make assignment, so that default m_fAutoFiringRate is used
original hex:
E7 B1 00 00 50 55 00 00 00 00 00 00 D1 B1 00 00 00 00 00 00 00 00 00 00 D2 B1 00 00 00 00 00 00 F8 0E 00 00 3A DE 01 00 16 00 00 00 0E 00 00 00 0F 01 52 AF 00 00 00 D2 B1 00 00 04 0B 53 00 00 00 02 00 02 00 5E 61 00 00 00 00 00 00
new hex:
E7 B1 00 00 50 55 00 00 00 00 00 00 D1 B1 00 00 00 00 00 00 00 00 00 00 D2 B1 00 00 00 00 00 00 F8 0E 00 00 3A DE 01 00 16 00 00 00 0E 00 00 00 0B 01 52 AF 00 00 00 D2 B1 00 00 04 0B 53 00 00 00 02 00 02 00 5E 61 00 00 00 00 00 00
-----------------------------------------
Change GetRemainingAmmo to return m_iTurnFired instead of iAmmo
original hex:
header:
50 B9 00 00 50 55 00 00 00 00 00 00 3A B9 00 00 00 00 00 00 00 00 00 00 3B B9 00 00 00 00 00 00 D5 00 00 00 0A 1A 00 00 15 00 00 00 0D 00 00 00
body:
04 01 1E B9 00 00 04 3A 3B B9 00 00 53
new hex: (virtual 0x15)
header:
50 B9 00 00 50 55 00 00 00 00 00 00 3A B9 00 00 00 00 00 00 00 00 00 00 3B B9 00 00 00 00 00 00 D5 00 00 00 0A 1A 00 00 11 00 00 00 0D 00 00 00
body:
04 01 1C B9 00 00 04 3A 3B B9 00 00 53
-----------------------------------------
XGAIBehavior.HasPredeterminedAbility
original:
m_kUnit.GetInventory().GetPrimaryWeapon().GetRemainingAmmo() == 0 (part of)
18 4F 00 9A 19 19 19 01 B8 8A 00 00 0A
new:
m_kUnit.GetInventory().GetPrimaryWeapon().GetRemainingAmmo() <= 0 (part of)
18 4F 00 98 19 19 19 01 B8 8A 00 00 0A
-----------------------------------------
XGAIBehavior.GetPredeterminedAbility
original:
if(m_kUnit.GetInventory().GetPrimaryWeapon().GetRemainingAmmo() == 0) (part of)
07 EE 00 9A 19 19 19 01 B8 8A 00 00 0A
if(m_kUnit.GetInventory().GetPrimaryWeapon().GetRemainingAmmo() <= 0) (part of)
07 EE 00 98 19 19 19 01 B8 8A 00 00 0A
-----------------------------------------
XGAIAbilityDM.AI_IntangiblesScore
original:
kWeapon.GetRemainingAmmo() == 0) (part of)
18 23 00 9A 19 00 0A 89 00 00 0A 00 3B B9
new:
kWeapon.GetRemainingAmmo() <= 0) (part of)
18 23 00 98 19 00 0A 89 00 00 0A 00 3B B9
-----------------------------------------
XGAction_Fire.UpdateAimingView
original:
m_kWeapon.GetRemainingAmmo() == 0 (part of)
18 23 00 9A 19 01 E2 82 00 00 0A 00 3B B9
new:
m_kWeapon.GetRemainingAmmo() <= 0 (part of)
18 23 00 98 19 01 E2 82 00 00 0A 00 3B B9
-----------------------------------------
XGAction_Fire.InternalCompleteAction
original:
m_kUnit.UnitSpeak(((iAmmoLeft == 0) ? 8 : 7)); (part of)
45 9A 00 31 85 00 00 25 16 02 00 24 08
new:
m_kUnit.UnitSpeak(((iAmmoLeft <= 0) ? 8 : 7)); (part of)
45 98 00 31 85 00 00 25 16 02 00 24 08
-----------------------------------------
UITacticalHUD_WeaponPanel.SetWeaponAndAmmo
original:
(kWeapon.GetRemainingAmmo() == 0) && (part of)
82 9A 19 00 73 27 00 00 0A 00 3B B9
new:
(kWeapon.GetRemainingAmmo() <= 0) && (part of)
82 98 19 00 73 27 00 00 0A 00 3B B9

 

 

 

 

Known issues:

  • Developer Console SetAmmo functions will not work correctly (will fix after testing of current version is 'done')
  • Flush may be unavailable in some situations in which Suppression is available, despite both using the same amount of ammo

 

For those who wish to see it, the new AmmoCost function (GraduatedOdds) should decompiles as (this has comments added):

 

 

 

function int GraduatedOdds(int iHitChance, XGPlayer kHumanPlayer, bool bCantLose)
{
    local int iAdjustment, iSoldiers, iFactor;

	iAdjustment = 0; 
	if(iHitChance != 0) // check for passed ammo/perk info
	{
		iAdjustment = iHitChance & 0xFFFF;  // use passed ammo info
	}
	else
	{
		if(m_kWeapon == none)
		{
			return 0;
		}	
		if(m_kWeapon.HasProperty(eWP_UnlimitedAmmo)) ((10))
		{
			return 0;
		}
		if(m_kWeapon.IsMelee())
		{
			return 0;
		}
		iAdjustment = m_kWeapon.m_kTWeapon.iSuppression; // retrieve weapon ammo info is none was supplied in parameter
	}
	if(!bCantLose) // doesn't have bHasAmmoConservation
	{
		iFactor = iAdjustment % 100; // get NumShots -- no Ammo Conservation
	}
	else // has ammo conservation
	{
		iFactor = iAdjustment / 100; // get NumShots -- w/ Ammo Conservation
	}
	if(iHitChance != 0) // check for passed ammo/perk info
	{
		iSoldiers = (iHitChance >> 16) & 0xFF; //use passed perk info
	}
	else
		iSoldiers = m_kUnit.m_kCharacter.m_kChar.aUpgrades[12]; // store perk 12 (vanilla ButtonUp) for later checks
	}
	if ((iSoldiers & 1) >  0) // explicitly test for perk 12 (vanilla ButtonUp) assigned through perk tree
	{
		iFactor += 2; // add 2 shots for perk -- can be customized separately from item count
	}
	if(iSoldiers & 254) >  0) // explicitly test for perk 12 (vanilla ButtonUp) assigned via items
	{
		iFactor += 1*(iSoldiers >> 1); // add shots equal to the number of equipped items
	}
	iFactor = Max(iFactor, 1); // prevent divide-by-zero errors
	iAdjustment = 100 / iFactor; // convert NumShots into Ammo Used -- valid for 12 or fewer shots
	if(iHitChance == 0)
	{
		if (GetType() == eAbility_ShotSuppress) ((17))
		{
			iAdjustment = 2 * iAdjustment;
		}
		if (GetType() == eAbility_ShotFlush) ((12))
		{
			iAdjustment = 2 * iAdjustment;
		}
		if(kHumanPlayer != none) // check to see should assign ammo instead of just returning ammo used
		{
			iSoldiers = (m_kWeapon.m_iTurnFired -= iAdjustment); // remove ammo used, store result in iSoldier
			if(iSoldiers >= (100/iFactor)) // has enough ammo to fire
			{
				if(bCantLose) // has Ammo Conservation
				{
					m_kWeapon.iAmmo = 20;  // set iAmmo to allow Fire action but not Suppression
				}
				else // doesn't have Ammo Conservations
				{
					m_kWeapon.iAmmo = 40;  // set iAmmo to allow Fire action but not Suppression
				}
			}
			if(iSoldiers >= 2* (100/iFactor))  // has enough ammo to suppress
			{
				m_kWeapon.iAmmo = 90;  // set iAmmo to allow any ability to be used
			}
			if(iSoldiers < (100 / iFactor))  // not enough ammo to do anything
			{
				m_kWeapon.iAmmo = 0;   // set iAmmo to empty
				m_kWeapon.m_iTurnFired = 0;  // set actual ammo to empty
			}
		}
	}
	return iAdjustment;
}
 

 

 

Link to comment
Share on other sites

Tried it twice and it crashes on start-up :S

 

Okay, I did a search-compare directly from the above post to my game and found the source of the problem:

 

The following hex change had the incorrect header virtual size (had 0x11, should have had 0x15)

Change GetRemainingAmmo to return m_iTurnFired instead of iAmmo
 
original hex:
header:
50 B9 00 00 50 55 00 00 00 00 00 00 3A B9 00 00 00 00 00 00 00 00 00 00 3B B9 00 00 00 00 00 00 D5 00 00 00 0A 1A 00 00 15 00 00 00 0D 00 00 00 
 
body:
04 01 1E B9 00 00 04 3A 3B B9 00 00 53 
 
 
new hex: (virtual 0x15)
header:
50 B9 00 00 50 55 00 00 00 00 00 00 3A B9 00 00 00 00 00 00 00 00 00 00 3B B9 00 00 00 00 00 00 D5 00 00 00 0A 1A 00 00 15 00 00 00 0D 00 00 00 
 
body:
04 01 1C B9 00 00 04 3A 3B B9 00 00 53 

All other hex in my game is identical. Sorry about that ... too many changes @_@

Edited by Amineri
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...