HAM5.5b2 merged in!

Notes:
-There may still be bugs!! (In fact, I almost guarantee it -- there's
-Ammo box code added to HR's crate code
-Splitting a crate/box also automatically refills half empty magazines
-new pathing arrows for map screen not included
-code for scouts to know where enemies are going doesn't appear to work... but i'm not sure it was completed.
-lots of gobledy gook (chinese?) comments turned back to english
-also added Bob's popups
-other languages besides english still need to have there language.cpp files updated with array changes
-AI enhancements by Warmsteel (reloading, suppression, roaming, avoiding gas, and other fixes)

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5181 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
MaddMugsy
2012-04-10 23:45:46 +00:00
parent ab3412e5ed
commit c845f9f117
72 changed files with 10737 additions and 2362 deletions
+251 -102
View File
@@ -1747,9 +1747,19 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
OBJECTTYPE* pA= &(*iter);
if ( (*pA)[0]->data.objectStatus >=USABLE)
{
INT8 bAmmoReliability = Item[(*pObjAttHand)[0]->data.gun.usGunAmmoItem].bReliability;
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 *
(Item[ iter->usItem ].bReliability + bAmmoReliability), 0);
INT16 ammoReliability = Item[(*pObjAttHand)[0]->data.gun.usGunAmmoItem].bReliability;
// HEADROCK HAM 5: Variable base chance
if ( UsingNewCTHSystem() == true)
{
UINT16 usBaseChance = gGameCTHConstants.BASIC_RELIABILITY_ODDS;
FLOAT dReliabilityRatio = 3.0f * ((FLOAT)usBaseChance / (FLOAT)BASIC_DEPRECIATE_CHANCE); // Compare original odds to new odds.
uiDepreciateTest = usBaseChance + (INT16)( dReliabilityRatio * (Item[ iter->usItem ].bReliability + ammoReliability) );
uiDepreciateTest = max(0, uiDepreciateTest);
}
else
{
uiDepreciateTest = max(0,BASIC_DEPRECIATE_CHANCE + 3 * (Item[ iter->usItem ].bReliability + ammoReliability));
}
if ( !PreRandom( uiDepreciateTest ) && ( (*pObjAttHand)[0]->data.objectStatus > 1) )
(*pA)[0]->data.objectStatus--;
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"rel =%d ",Item[ iter->usItem ].bReliability );
@@ -2107,8 +2117,18 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
//}
// Flugente FTW 1: Added a malus to reliability for overheated guns
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * GetReliability( pObjAttHand ) - iOverheatReliabilityMalus, 0);
// HEADROCK HAM 5: Variable NCTH base change
if ( UsingNewCTHSystem() == true)
{
UINT16 usBaseChance = gGameCTHConstants.BASIC_RELIABILITY_ODDS;
FLOAT dReliabilityRatio = 3.0f * ((FLOAT)usBaseChance / (FLOAT)BASIC_DEPRECIATE_CHANCE); // Compare original odds to new odds.
uiDepreciateTest = usBaseChance + (INT16)( dReliabilityRatio * GetReliability( &(pSoldier->inv[pSoldier->ubAttackingHand]) - iOverheatReliabilityMalus) );
uiDepreciateTest = max(0, uiDepreciateTest);
}
else
{
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * GetReliability( pObjAttHand ) - iOverheatReliabilityMalus, 0);
}
if ( !PreRandom( uiDepreciateTest ) && ( (*pObjAttHand)[0]->data.objectStatus > 1) )
{
(*pObjAttHand)[0]->data.objectStatus--;
@@ -2284,9 +2304,19 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
OBJECTTYPE* pA= &(*iter);
if ( (*pA)[0]->data.objectStatus >=USABLE)
{
INT8 bAmmoReliability = Item[(*pObjUsed)[0]->data.gun.usGunAmmoItem].bReliability;
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 *
(Item[ iter->usItem ].bReliability + bAmmoReliability), 0);
INT16 ammoReliability = Item[(*pObjUsed)[0]->data.gun.usGunAmmoItem].bReliability;
// HEADROCK HAM 5: Variable base chance
if ( UsingNewCTHSystem() == true )
{
UINT16 usBaseChance = gGameCTHConstants.BASIC_RELIABILITY_ODDS;
FLOAT dReliabilityRatio = 3.0f * ((FLOAT)usBaseChance / (FLOAT)BASIC_DEPRECIATE_CHANCE); // Compare original odds to new odds.
uiDepreciateTest = usBaseChance + (INT16)( dReliabilityRatio * (Item[ iter->usItem ].bReliability + ammoReliability) );
uiDepreciateTest = __max(0, uiDepreciateTest);
}
else
{
uiDepreciateTest = __max(0,BASIC_DEPRECIATE_CHANCE + 3 * (Item[ iter->usItem ].bReliability + ammoReliability));
}
if ( !PreRandom( uiDepreciateTest ) && ( (*pObjUsed)[0]->data.objectStatus > 1) )
(*pA)[0]->data.objectStatus--;
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"rel =%d ",Item[ iter->usItem ].bReliability );
@@ -2675,7 +2705,17 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
*/
// Flugente FTW 1: Added a malus to reliability for overheated guns
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * ( GetReliability( pObjUsed ) ) - iOverheatReliabilityMalus, 0);
if ( UsingNewCTHSystem() == true )
{
UINT16 usBaseChance = gGameCTHConstants.BASIC_RELIABILITY_ODDS;
FLOAT dReliabilityRatio = 3.0f * ((FLOAT)usBaseChance / (FLOAT)BASIC_DEPRECIATE_CHANCE); // Compare original odds to new odds.
uiDepreciateTest = usBaseChance + (INT16)( dReliabilityRatio * GetReliability( &(pSoldier->inv[ pSoldier->ubAttackingHand ])) - iOverheatReliabilityMalus);
uiDepreciateTest = max(0, uiDepreciateTest);
}
else
{
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * ( GetReliability( pObjUsed ) ) - iOverheatReliabilityMalus, 0);
}
if ( !PreRandom( uiDepreciateTest ) && ( (*pObjUsed)[0]->data.objectStatus > 1) )
{
@@ -4003,14 +4043,27 @@ void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 s
MakeNoise( ubAttackerID, pTargetSoldier->sGridNo, pTargetSoldier->pathing.bLevel, gpWorldLevelData[pTargetSoldier->sGridNo].ubTerrainID, Weapon[ usWeaponIndex ].ubHitVolume, NOISE_BULLET_IMPACT );
// CALLAHAN START BUGFIX
if ( EXPLOSIVE_GUN( usWeaponIndex ) || AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
// Provisions for Fragments, which are resulting from a different weapon than the one we are holding in our hand.
UINT8 ubAmmoType = 0;
if ( pObj->usItem == usWeaponIndex )
{
ubAmmoType = (*pObj)[0]->data.gun.ubGunAmmoType;
}
else
{
// Must be a fragment.
ubAmmoType = Explosive[Item[usWeaponIndex].ubClassIndex].ubFragType;
usWeaponIndex = 1; // Set to default gun.
}
if ( EXPLOSIVE_GUN( usWeaponIndex ) || AmmoTypes[ubAmmoType].explosionSize > 1)
// CALLAHAN END BUGFIX
{
// Reduce attacker count!
//TODO: Madd --- I don't think this code will ever get called for the HE ammo -- the EXPLOSIVE_GUN check filters out regular guns
// marke test mag ammo type: pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType
// 2cond 'or' added
if ( Item[usWeaponIndex].rocketlauncher || AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1 )
if ( Item[usWeaponIndex].rocketlauncher || AmmoTypes[ubAmmoType].explosionSize > 1 )
{
if ( Item[usWeaponIndex].singleshotrocketlauncher )
{
@@ -4032,15 +4085,16 @@ void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 s
pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
else if ( AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
else if ( AmmoTypes[ubAmmoType].explosionSize > 1)
{
// re-routed the Highexplosive value to define exposion type
IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].highExplosive , pTargetSoldier->pathing.bLevel );
IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), AmmoTypes[ubAmmoType].highExplosive , pTargetSoldier->pathing.bLevel );
// pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
else // tank cannon
{
// HEADROCK HAM 5 TODO: TANK_SHELL!
IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), TANK_SHELL, pTargetSoldier->pathing.bLevel );
}
@@ -4088,10 +4142,29 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
// Flugente: check for underbarrel weapons and use that object if necessary
pObj = MercPtrs[ ubAttackerID ]->GetUsedWeapon( &MercPtrs [ ubAttackerID ]->inv[MercPtrs[ubAttackerID]->ubAttackingHand] );
if ( fStopped && ubAttackerID != NOBODY )
// Get attacker
if (ubAttackerID != NOBODY)
{
pAttacker = MercPtrs[ ubAttackerID ];
}
// HEADROCK HAM 5: Define differently for fragments
UINT8 ubHitVolume = 0;
UINT8 ubAmmoType = 0;
if (pBullet->fFragment)
{
ubHitVolume = 1;
ubAmmoType = Explosive[Item[pBullet->fromItem].ubClassIndex].ubFragType;
}
else
{
ubHitVolume = Weapon[usWeaponIndex].ubHitVolume;
ubAmmoType = (*pObj)[0]->data.gun.ubGunAmmoType;
}
if ( fStopped && ubAttackerID != NOBODY )
{
if ( pAttacker->ubOppNum != NOBODY )
{
// if it was another team shooting at someone under our control
@@ -4124,11 +4197,11 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
if (sZPos > WALL_HEIGHT)
{
MakeNoise( ubAttackerID, sGridNo, 1, gpWorldLevelData[sGridNo].ubTerrainID, Weapon[ usWeaponIndex ].ubHitVolume, NOISE_BULLET_IMPACT );
MakeNoise( ubAttackerID, sGridNo, 1, gpWorldLevelData[sGridNo].ubTerrainID, ubHitVolume, NOISE_BULLET_IMPACT );
}
else
{
MakeNoise( ubAttackerID, sGridNo, 0, gpWorldLevelData[sGridNo].ubTerrainID, Weapon[ usWeaponIndex ].ubHitVolume, NOISE_BULLET_IMPACT );
MakeNoise( ubAttackerID, sGridNo, 0, gpWorldLevelData[sGridNo].ubTerrainID, ubHitVolume, NOISE_BULLET_IMPACT );
}
}
@@ -4146,30 +4219,35 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
// Reduce attacker count!
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - end of LAW fire") );
// FreeUpAttacker( ubAttackerID );
if ( Item[usWeaponIndex].singleshotrocketlauncher )
// HEADROCK HAM 5: Fragments fired by such weapons should not explode.
if ( pBullet->fFragment == false)
{
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, C1, (INT8)( sZPos >= WALL_HEIGHT ) );
}
// changed too to use 2 flag to determine
else if ( !Item[usWeaponIndex].singleshotrocketlauncher && Item[usWeaponIndex].rocketlauncher)
//there shouldn't be a way to enter here with an UnderBarrel weapon, so retaining original code :JMich
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("StructureHit: RPG7 item: %d, Ammo: %d",pAttacker->inv[HANDPOS].usItem , pAttacker->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) );
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem , (INT8)( sZPos >= WALL_HEIGHT ) );
//This is just to make multishot launchers work in semi auto. It's not really a permanent solution because it still doesn't allow autofire, but it will do for now.
OBJECTTYPE * pLaunchable = FindLaunchableAttachment( &(pAttacker->inv[pAttacker->ubAttackingHand ]), pAttacker->inv[pAttacker->ubAttackingHand ].usItem );
if(pLaunchable){
pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = pLaunchable->usItem;
} else {
pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
if ( Item[usWeaponIndex].singleshotrocketlauncher )
{
// HEADROCK HAM 5 TODO: C1!!!
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, C1, (INT8)( sZPos >= WALL_HEIGHT ) );
}
// changed too to use 2 flag to determine
else if ( !Item[usWeaponIndex].singleshotrocketlauncher && Item[usWeaponIndex].rocketlauncher)
//there shouldn't be a way to enter here with an UnderBarrel weapon, so retaining original code :JMich
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("StructureHit: RPG7 item: %d, Ammo: %d",pAttacker->inv[HANDPOS].usItem , pAttacker->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) );
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem , (INT8)( sZPos >= WALL_HEIGHT ) );
//This is just to make multishot launchers work in semi auto. It's not really a permanent solution because it still doesn't allow autofire, but it will do for now.
OBJECTTYPE * pLaunchable = FindLaunchableAttachment( &(pAttacker->inv[pAttacker->ubAttackingHand ]), pAttacker->inv[pAttacker->ubAttackingHand ].usItem );
if(pLaunchable){
pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = pLaunchable->usItem;
} else {
pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
else if ( AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
{
// re-routed the Highexplosive value to define exposion type
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, AmmoTypes[ (*pObj)[0]->data.gun.ubGunAmmoType].highExplosive , (INT8)( sZPos >= WALL_HEIGHT ) );
// pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
else if ( AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
{
// re-routed the Highexplosive value to define exposion type
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, AmmoTypes[ (*pObj)[0]->data.gun.ubGunAmmoType].highExplosive , (INT8)( sZPos >= WALL_HEIGHT ) );
// pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
// Moved here to make sure ABC stays >0 until everything done
@@ -4184,6 +4262,7 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
//DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - end of TANK fire") );
//FreeUpAttacker( ubAttackerID );
// HEADROCK HAM 5 TODO: Tank shell!!
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, TANK_SHELL, (INT8)( sZPos >= WALL_HEIGHT ) );
//FreeUpAttacker( (UINT8) ubAttackerID );
@@ -4202,67 +4281,83 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
DamageStructure( pStructure, (UINT8)iImpact, STRUCTURE_DAMAGE_GUNFIRE, sGridNo, sXPos, sYPos, ubAttackerID );
}
switch( Weapon[ usWeaponIndex ].ubWeaponClass )
// HEADROCK HAM 5: Fragments are not fired from guns, so they need a special case.
if (pBullet->fFragment == false)
{
case HANDGUNCLASS:
case RIFLECLASS:
case SHOTGUNCLASS:
case SMGCLASS:
case MGCLASS:
switch( Weapon[ usWeaponIndex ].ubWeaponClass )
{
case HANDGUNCLASS:
case RIFLECLASS:
case SHOTGUNCLASS:
case SMGCLASS:
case MGCLASS:
// Guy has missed, play random sound
if ( MercPtrs[ ubAttackerID ]->bTeam == gbPlayerNum )
{
if ( !MercPtrs[ ubAttackerID ]->bDoBurst )
// Guy has missed, play random sound
if ( MercPtrs[ ubAttackerID ]->bTeam == gbPlayerNum )
{
if ( Random( 40 ) == 0 )
if ( !MercPtrs[ ubAttackerID ]->bDoBurst )
{
MercPtrs[ ubAttackerID ]->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
if ( Random( 40 ) == 0 )
{
MercPtrs[ ubAttackerID ]->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
}
}
}
}
//fDoMissForGun = TRUE;
//break;
fDoMissForGun = TRUE;
break;
//fDoMissForGun = TRUE;
//break;
fDoMissForGun = TRUE;
break;
case MONSTERCLASS:
case MONSTERCLASS:
DoSpecialEffectAmmoMiss( ubAttackerID, sGridNo, sXPos, sYPos, sZPos, FALSE, TRUE, iBullet );
RemoveBullet( iBullet );
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - monster attack hit structure") );
// FreeUpAttacker( (UINT8) ubAttackerID );
//PlayJA2Sample( SPIT_RICOCHET , RATE_11025, uiMissVolume, 1, SoundDir( sGridNo ) );
break;
case KNIFECLASS:
// When it hits the ground, leave on map...
if ( Item[ usWeaponIndex ].usItemClass == IC_THROWING_KNIFE )
{
// OK, have we hit ground?
if ( usStructureID == INVALID_STRUCTURE_ID )
{
// Add item
CreateItem( usWeaponIndex, bWeaponStatus, &gTempObject );
AddItemToPool( sGridNo, &gTempObject, -1 , 0, 0, -1 );
// Make team look for items
NotifySoldiersToLookforItems( );
}
if ( !fHitSameStructureAsBefore )
{
PlayJA2Sample( MISS_KNIFE, RATE_11025, uiMissVolume, 1, SoundDir( sGridNo ) );
}
DoSpecialEffectAmmoMiss( ubAttackerID, sGridNo, sXPos, sYPos, sZPos, FALSE, TRUE, iBullet );
RemoveBullet( iBullet );
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - knife attack hit structure") );
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - monster attack hit structure") );
// FreeUpAttacker( (UINT8) ubAttackerID );
}
//PlayJA2Sample( SPIT_RICOCHET , RATE_11025, uiMissVolume, 1, SoundDir( sGridNo ) );
break;
case KNIFECLASS:
// When it hits the ground, leave on map...
if ( Item[ usWeaponIndex ].usItemClass == IC_THROWING_KNIFE )
{
// OK, have we hit ground?
if ( usStructureID == INVALID_STRUCTURE_ID )
{
// Add item
CreateItem( usWeaponIndex, bWeaponStatus, &gTempObject );
AddItemToPool( sGridNo, &gTempObject, -1 , 0, 0, -1 );
// Make team look for items
NotifySoldiersToLookforItems( );
}
if ( !fHitSameStructureAsBefore )
{
PlayJA2Sample( MISS_KNIFE, RATE_11025, uiMissVolume, 1, SoundDir( sGridNo ) );
}
RemoveBullet( iBullet );
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - knife attack hit structure") );
// FreeUpAttacker( (UINT8) ubAttackerID );
}
}
}
else
{
if ( sZPos == 0 )
{
PlayJA2Sample( MISS_G2 , RATE_11025, 5, 1, SoundDir( sGridNo ) );
}
else
{
PlayJA2Sample( MISS_1 + Random(8), RATE_11025, 5, 1, SoundDir( sGridNo ) );
}
RemoveBullet( iBullet );
}
if ( fDoMissForGun )
@@ -8442,8 +8537,24 @@ INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 u
return( iTotalProtection );
}
INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iOrigImpact, INT16 sHitBy, UINT8 * pubSpecial )
// HEADROCK HAM 5: Added argument the bullet!
INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iOrigImpact, INT16 sHitBy, UINT8 * pubSpecial )
{
UINT16 usAttackingWeapon = 0;
INT32 sOrigGridNo = 0;
BOOLEAN fFragment = FALSE;
if (pBullet == NULL)
{
usAttackingWeapon = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType;
sOrigGridNo = pFirer->sGridNo;
}
else
{
usAttackingWeapon = pBullet->fromItem;
sOrigGridNo = pBullet->sOrigGridNo;
fFragment = pBullet->fFragment;
}
INT32 iImpact, iFluke, iBonus, iImpactForCrits = 0;
INT8 bStatLoss = 0;
UINT8 ubAmmoType;
@@ -8452,17 +8563,21 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
// in MoveBullet.
// Set a few things up:
if ( Item[ pFirer->usAttackingWeapon ].usItemClass == IC_THROWING_KNIFE )
if ( Item[ usAttackingWeapon ].usItemClass == IC_THROWING_KNIFE )
{
ubAmmoType = AMMO_KNIFE;
}
else
// HEADROCK HAM 5: Added provisions for fragments, which are not fired from the weapon in your hand.
else if ( fFragment == FALSE )
{
// Flugente: check for underbarrel weapons and use that object if necessary
OBJECTTYPE* pObj = pFirer->GetUsedWeapon( &pFirer->inv[pFirer->ubAttackingHand] );
ubAmmoType = (*pObj)[0]->data.gun.ubGunAmmoType;
}
else
{
ubAmmoType = Explosive[Item[usAttackingWeapon].ubClassIndex].ubFragType;
}
if ( TANK( pTarget ) )
{
@@ -8569,7 +8684,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
}
// Sniper trait adds bonus damage per aim click
if (HAS_SKILL_TRAIT( pFirer, SNIPER_NT ) && (pFirer->aiData.bAimTime >= gSkillTraitValues.ubSNDamageBonusFromNumClicks))
if (HAS_SKILL_TRAIT( pFirer, SNIPER_NT ) && (pFirer->aiData.bAimTime >= gSkillTraitValues.ubSNDamageBonusFromNumClicks) && !fFragment)
{
iImpact += (INT32)(iImpact * (pFirer->aiData.bAimTime - gSkillTraitValues.ubSNDamageBonusFromNumClicks + 1) * gSkillTraitValues.ubSNDamageBonusPerClick * NUM_SKILL_TRAITS( pFirer, SNIPER_NT ))/100; // +5% per trait
}
@@ -8593,8 +8708,15 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0)
iImpact -= ((iImpact * gGameExternalOptions.sEnemyEliteDamageResistance) /100);
iImpact = max( 1, iImpact);
// HEADROCK HAM 5.1: Oh sandro, you rendered zerominimumdamage moot...
if ( AmmoTypes[ubAmmoType].zeroMinimumDamage )
{
iImpact = __max( 0, iImpact );
}
else
{
iImpact = __max( 1, iImpact);
}
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -8622,7 +8744,15 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
case MIKE:
// Only 1/2 of the bonus
iImpact -= (INT32)(iImpact * gGameExternalOptions.usSpecialNPCStronger / 200);
iImpact = max( 1, iImpact);
// HEADROCK HAM 5.1: Oh sandro, you rendered zerominimumdamage moot...
if ( AmmoTypes[ubAmmoType].zeroMinimumDamage )
{
iImpact = __max( 0, iImpact );
}
else
{
iImpact = __max( 1, iImpact);
}
break;
}
}
@@ -8631,7 +8761,16 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
////////////////////////////////////////////////////////////////////////////////////
// STOMP traits - Bodybuilding damage resistance
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pTarget, BODYBUILDING_NT ) )
iImpact = max( 1, (INT32)(iImpact * (100 - gSkillTraitValues.ubBBDamageResistance) / 100));
// HEADROCK HAM 5.1: Oh sandro, you rendered zerominimumdamage moot...
if ( AmmoTypes[ubAmmoType].zeroMinimumDamage )
{
iImpact = __max( 0, (INT32)(iImpact * (100 - gSkillTraitValues.ubBBDamageResistance) / 100));
}
else
{
iImpact = __max( 1, (INT32)(iImpact * (100 - gSkillTraitValues.ubBBDamageResistance) / 100));
}
////////////////////////////////////////////////////////////////////////////////////
AdjustImpactByHitLocation( iImpact, ubHitLocation, &iImpact, &iImpactForCrits );
@@ -8642,7 +8781,8 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
// is the blow deadly enough for an instant kill?
// HEADROCK HAM 3.6: Reattached "Max Distance For Messy Death" tag from the XML! God knows why it wasn't attached when they MADE THAT TAG.
//if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && pFirer->usAttackingWeapon == BARRETT ))
if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= Weapon[ pFirer->usAttackingWeapon ].maxdistformessydeath )
// HEADROCK HAM 5.1: Using usAttackingWeapon
if ( PythSpacesAway( sOrigGridNo, pTarget->sGridNo ) <= Weapon[ usAttackingWeapon ].maxdistformessydeath )
{
if (iImpactForCrits > MIN_DAMAGE_FOR_INSTANT_KILL && iImpactForCrits < pTarget->stats.bLife)
{
@@ -8695,7 +8835,8 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
// since this value is much lower than the others, it only applies at short range...
// HEADROCK HAM 3.6: Reattached "Max Distance For Messy Death" tag from the XML! God knows why it wasn't attached when they MADE THAT TAG.
//if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && pFirer->usAttackingWeapon == BARRETT ))
if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= Weapon[ pFirer->usAttackingWeapon ].maxdistformessydeath )
// HEADROCK HAM 5.1: Using usAttackingWeapon
if ( PythSpacesAway( sOrigGridNo, pTarget->sGridNo ) <= Weapon[ usAttackingWeapon ].maxdistformessydeath )
{
if (iImpact > MIN_DAMAGE_FOR_INSTANT_KILL && iImpact < pTarget->stats.bLife)
{
@@ -8741,7 +8882,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
if( !IsAutoResolveActive() )
{
if ( AmmoTypes[ubAmmoType].knife && pFirer->aiData.bOppList[ pTarget->ubID ] == SEEN_CURRENTLY )
if ( AmmoTypes[ubAmmoType].knife && pFirer->aiData.bOppList[ pTarget->ubID ] == SEEN_CURRENTLY && !fFragment )
{
// is this a stealth attack?
if ( pTarget->aiData.bOppList[ pFirer->ubID ] == NOT_HEARD_OR_SEEN && !CREATURE_OR_BLOODCAT( pTarget )
@@ -8793,10 +8934,18 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
if (iImpactForCrits > 0 && iImpactForCrits < pTarget->stats.bLife && !(pTarget->flags.uiStatusFlags & SOLDIER_MONSTER) ) // not to monsters - SANDRO
{
UINT32 uiCritChance = (iImpactForCrits / 2) + (pFirer->aiData.bAimTime * 5);
UINT32 uiCritChance = 0;
if (fFragment)
{
uiCritChance = (iImpactForCrits / 2);
}
else
{
uiCritChance = (iImpactForCrits / 2) + (pFirer->aiData.bAimTime * 5);
}
BOOLEAN fMaliciousHit = FALSE;
// SANDRO - Malicious characters inflict stat loss more often
if ( gGameOptions.fNewTraitSystem && pFirer->ubProfile != NO_PROFILE )
if ( gGameOptions.fNewTraitSystem && pFirer->ubProfile != NO_PROFILE && !fFragment)
{
if ( gMercProfiles[ pFirer->ubProfile ].bCharacterTrait == CHAR_TRAIT_MALICIOUS )
{