diff --git a/Multiplayer/client.cpp b/Multiplayer/client.cpp index 1e0d9e27..c6216a21 100644 --- a/Multiplayer/client.cpp +++ b/Multiplayer/client.cpp @@ -3716,55 +3716,56 @@ void send_bullet( BULLET * pBullet,UINT16 usHandItem ) void recieveBULLET(RPCParameters *rpcParameters) { - netb_struct* netb = (netb_struct*)rpcParameters->input; + netb_struct* netb = (netb_struct*)rpcParameters->input; - INT32 net_iBullet=netb->net_bullet.iBullet; + INT32 net_iBullet=netb->net_bullet.iBullet; - SOLDIERTYPE * pFirer=MercPtrs[ netb->net_bullet.ubFirerID ]; + SOLDIERTYPE * pFirer = NULL; + INT8 bTeam = OUR_TEAM; + if ( netb->net_bullet.ubFirerID != NOBODY ) + { + pFirer = MercPtrs[ netb->net_bullet.ubFirerID ]; + bTeam=pFirer->bTeam; + } - INT8 bTeam=pFirer->bTeam; - - INT32 iBullet; - BULLET * pBullet; - - iBullet = CreateBullet( netb->net_bullet.ubFirerID, 0, netb->net_bullet.usFlags,netb->usHandItem ); - - if (iBullet == -1) - { + BULLET * pBullet; + INT32 iBullet = CreateBullet( netb->net_bullet.ubFirerID, 0, netb->net_bullet.usFlags,netb->usHandItem ); + #ifdef BETAVERSION - ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"Failed to create bullet"); + if (iBullet == -1) + { + ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"Failed to create bullet"); + } #endif - } - - //add bullet to bullet table for translation - bTable[bTeam][net_iBullet].remote_id = net_iBullet; - bTable[bTeam][net_iBullet].local_id = iBullet; + //add bullet to bullet table for translation + bTable[bTeam][net_iBullet].remote_id = net_iBullet; + bTable[bTeam][net_iBullet].local_id = iBullet; - pBullet = GetBulletPtr( iBullet ); + pBullet = GetBulletPtr( iBullet ); - //ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"Created Bullet Id: %d",iBullet); + //ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"Created Bullet Id: %d",iBullet); - pBullet->fCheckForRoof=netb->net_bullet.fCheckForRoof; - pBullet->qIncrX=netb->net_bullet.qIncrX; - pBullet->qIncrY=netb->net_bullet.qIncrY; - pBullet->qIncrZ=netb->net_bullet.qIncrZ; - pBullet->sHitBy=netb->net_bullet.sHitBy; - pBullet->ddHorizAngle=netb->net_bullet.ddHorizAngle; - pBullet->fAimed=netb->net_bullet.fAimed; - pBullet->ubItemStatus=netb->net_bullet.ubItemStatus; - pBullet->qCurrX=netb->net_bullet.qCurrX; - pBullet->qCurrY=netb->net_bullet.qCurrY; - pBullet->qCurrZ=netb->net_bullet.qCurrZ; - pBullet->iImpact=netb->net_bullet.iImpact; - pBullet->iRange=netb->net_bullet.iRange; - pBullet->sTargetGridNo=netb->net_bullet.sTargetGridNo; - pBullet->bStartCubesAboveLevelZ=netb->net_bullet.bStartCubesAboveLevelZ; - pBullet->bEndCubesAboveLevelZ=netb->net_bullet.bEndCubesAboveLevelZ; - pBullet->iDistanceLimit=netb->net_bullet.iDistanceLimit; + pBullet->fCheckForRoof=netb->net_bullet.fCheckForRoof; + pBullet->qIncrX=netb->net_bullet.qIncrX; + pBullet->qIncrY=netb->net_bullet.qIncrY; + pBullet->qIncrZ=netb->net_bullet.qIncrZ; + pBullet->sHitBy=netb->net_bullet.sHitBy; + pBullet->ddHorizAngle=netb->net_bullet.ddHorizAngle; + pBullet->fAimed=netb->net_bullet.fAimed; + pBullet->ubItemStatus=netb->net_bullet.ubItemStatus; + pBullet->qCurrX=netb->net_bullet.qCurrX; + pBullet->qCurrY=netb->net_bullet.qCurrY; + pBullet->qCurrZ=netb->net_bullet.qCurrZ; + pBullet->iImpact=netb->net_bullet.iImpact; + pBullet->iRange=netb->net_bullet.iRange; + pBullet->sTargetGridNo=netb->net_bullet.sTargetGridNo; + pBullet->bStartCubesAboveLevelZ=netb->net_bullet.bStartCubesAboveLevelZ; + pBullet->bEndCubesAboveLevelZ=netb->net_bullet.bEndCubesAboveLevelZ; + pBullet->iDistanceLimit=netb->net_bullet.iDistanceLimit; - FireBullet( pFirer, pBullet, FALSE ); + FireBullet( pFirer->ubID, pBullet, FALSE ); } void send_changestate (EV_S_CHANGESTATE * SChangeState) diff --git a/Multiplayer/connect.h b/Multiplayer/connect.h index f9fd34ff..df804dab 100644 --- a/Multiplayer/connect.h +++ b/Multiplayer/connect.h @@ -123,7 +123,7 @@ void send_disarm_explosive(UINT32 sGridNo, UINT32 uiWorldIndex, UINT8 ubID); void OpenChatMsgBox(void); -INT8 FireBullet( SOLDIERTYPE * pFirer, BULLET * pBullet, BOOLEAN fFake ); +INT8 FireBullet( UINT8 ubFirer, BULLET * pBullet, BOOLEAN fFake ); void reapplySETTINGS(); @@ -155,7 +155,7 @@ extern char cServerName[30]; // WANNE: This features seems to work without any errors, so it is enabled :) #define ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV -#define ENABLE_COLLISION (is_server && pBullet->pFirer->ubID<120) || (!is_server && is_client && pBullet->pFirer->ubID<20) || (!is_server && !is_client) +#define ENABLE_COLLISION (is_server && pBullet->ubFirerID<120) || (!is_server && is_client && pBullet->ubFirerID<20) || (!is_server && !is_client) extern bool auto_retry; extern int giNumTries; diff --git a/Tactical/Bullets.h b/Tactical/Bullets.h index 689eb99f..44c70a0f 100644 --- a/Tactical/Bullets.h +++ b/Tactical/Bullets.h @@ -56,7 +56,7 @@ typedef struct UINT32 uiLastUpdate; UINT8 ubTilesPerUpdate; UINT16 usClockTicksPerUpdate; - SOLDIERTYPE *pFirer; + SOLDIERTYPE *pFirer; // Flugente: WARNING! We cannot assume this will be valid. Check wether ubFirerID is NOBODY first INT32 sOrigGridNo; // HEADROCK HAM 5.1: Original tile does not necessarily have to be the pFirer's tile INT32 sTargetGridNo; INT16 sHitBy; diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index c39d956b..9d59a242 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -2332,7 +2332,6 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend INT32 iImpact, iDamage; EV_S_WEAPONHIT SWeaponHit; INT32 sRange; - SOLDIERTYPE * pFirer = pBullet->pFirer; FLOAT dZPosRelToMerc; UINT8 ubHitLocation = AIM_SHOT_RANDOM; UINT8 ubAttackDirection; @@ -2348,10 +2347,16 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend BOOLEAN fCanSpewBlood = FALSE; INT8 bSpewBloodLevel; + SOLDIERTYPE * pFirer = NULL; + if ( pBullet->ubFirerID != NOBODY ) + { + pFirer = pBullet->pFirer; + } + // HEADROCK HAM 5: Fragments read attacking weapon from explosive, not from firer. Theoretically, // all bullets should read this value... UINT16 usAttackingWeapon = 0; - if (pBullet->fFragment) + if ( pBullet->ubFirerID == NOBODY || pBullet->fFragment) { usAttackingWeapon = pBullet->fromItem; } @@ -2387,7 +2392,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend else if (pBullet->fFragment) { // Read ammo type from the explosive data. - ubAmmoType = Explosive[Item[pBullet->fromItem].ubClassIndex].ubFragType; + ubAmmoType = Explosive[Item[usAttackingWeapon].ubClassIndex].ubFragType; } else { @@ -2397,7 +2402,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend // HEADROCK HAM 5.1: This is an utter hack, but it may be necessary. This soldier is hit by a fragment, // so he needs to have his animations be interruptible. This takes care of soldiers hitting themselves // with their own fragments. - if (pBullet->fFragment && pTarget == pBullet->pFirer) + if ( pBullet->ubFirerID != NOBODY && pBullet->fFragment && pTarget == pBullet->pFirer) { if (pTarget->usAniCode >1) { @@ -2592,7 +2597,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend // Determine damage, checking guy's armour, etc sRange = GetRangeInCellCoordsFromGridNoDiff( pBullet->sOrigGridNo, pTarget->sGridNo ); - if ( gTacticalStatus.uiFlags & GODMODE && !(pFirer->flags.uiStatusFlags & SOLDIER_PC)) + if ( gTacticalStatus.uiFlags & GODMODE && pBullet->ubFirerID != NOBODY && !(pFirer->flags.uiStatusFlags & SOLDIER_PC)) { // in god mode, and firer is computer controlled iImpact = 0; @@ -2600,7 +2605,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend } else if (fIntended) { - if (pFirer->aiData.bOppList[pTarget->ubID] == SEEN_CURRENTLY) + if ( pBullet->ubFirerID != NOBODY && pFirer->aiData.bOppList[pTarget->ubID] == SEEN_CURRENTLY) { sHitBy = pBullet->sHitBy; } @@ -2622,7 +2627,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend iDamage = BulletImpact( pFirer, pBullet, pTarget, ubHitLocation, iImpact, sHitBy, &ubSpecial ); // handle hit here... // HEADROCK HAM 5: Fragments not counted as shots. - if( ( pFirer->bTeam == 0 ) && !(pBullet->fFragment) ) + if( pBullet->ubFirerID != NOBODY && pFirer->bTeam == OUR_TEAM && !(pBullet->fFragment) ) { // SANDRO - new mercs' records // if we shoot with buckshot or similar, do not count a hit for every pellet @@ -2641,7 +2646,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend // intentionally shot pTarget->flags.fIntendedTarget = TRUE; - if ( (pBullet->usFlags & BULLET_FLAG_BUCKSHOT) && ( pTarget->ubID == pFirer->ubTargetID ) ) + if ( pBullet->ubFirerID != NOBODY && (pBullet->usFlags & BULLET_FLAG_BUCKSHOT) && ( pTarget->ubID == pFirer->ubTargetID ) ) { pTarget->bNumPelletsHitBy++; } @@ -2656,7 +2661,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend // we aimed though, so now that the bullet hits the intended target, we can calculate extra experience // based on the aiming value. - if (UsingNewCTHSystem() == true && pFirer->bTeam == gbPlayerNum && pBullet->fAimed) // Only for single shot, first bullet in volley, or first bullet in spread. + if ( UsingNewCTHSystem() && pBullet->ubFirerID != NOBODY && pFirer->bTeam == gbPlayerNum && pBullet->fAimed) // Only for single shot, first bullet in volley, or first bullet in spread. { UINT16 usExpGain = 10; usExpGain = (usExpGain * pBullet->sHitBy) / 100; @@ -2758,7 +2763,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend } // check to see if someone was accidentally hit when no target was specified by the player - if ( pFirer->bTeam == gbPlayerNum && pFirer->ubTargetID == NOBODY && pTarget->aiData.bNeutral ) + if ( pBullet->ubFirerID != NOBODY && pFirer->bTeam == gbPlayerNum && pFirer->ubTargetID == NOBODY && pTarget->aiData.bNeutral ) { if ( pTarget->ubCivilianGroup == KINGPIN_CIV_GROUP || pTarget->ubCivilianGroup == HICKS_CIV_GROUP ) { @@ -2770,30 +2775,28 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend // get touchy pFirer->ubTargetID = pTarget->ubID; } - } - // Send event for getting hit memset( &(SWeaponHit), 0, sizeof( SWeaponHit ) ); SWeaponHit.usSoldierID = pTarget->ubID; - SWeaponHit.uiUniqueId = pTarget->uiUniqueSoldierIdValue; + SWeaponHit.uiUniqueId = pTarget->uiUniqueSoldierIdValue; // HEADROCK HAM 5: Already defined. SWeaponHit.usWeaponIndex = usAttackingWeapon; - SWeaponHit.sDamage = (INT16) iDamage; + SWeaponHit.sDamage = (INT16) iDamage; // breath loss is based on original impact of bullet SWeaponHit.sBreathLoss = (INT16) ( (iImpact * APBPConstants[BP_GET_WOUNDED] * (pTarget->bBreathMax * 100 - pTarget->sBreathRed)) / 10000 ); // HEADROCK HAM 5.1: Bullet data contains the correct original GridNo SWeaponHit.usDirection = GetDirectionFromGridNo( pBullet->sOrigGridNo, pTarget ); - SWeaponHit.sXPos = (INT16)pTarget->dXPos; - SWeaponHit.sYPos = (INT16)pTarget->dYPos; - SWeaponHit.sZPos = 20; - SWeaponHit.sRange = sRange; - SWeaponHit.ubAttackerID = pFirer->ubID; - SWeaponHit.fHit = TRUE; - SWeaponHit.ubLocation = ubHitLocation; + SWeaponHit.sXPos = (INT16)pTarget->dXPos; + SWeaponHit.sYPos = (INT16)pTarget->dYPos; + SWeaponHit.sZPos = 20; + SWeaponHit.sRange = sRange; + SWeaponHit.ubAttackerID = pBullet->ubFirerID; + SWeaponHit.fHit = TRUE; + SWeaponHit.ubLocation = ubHitLocation; - if ( (pFirer->bDoBurst) && (ubSpecial == FIRE_WEAPON_NO_SPECIAL) ) + if ( pBullet->ubFirerID != NOBODY && pFirer->bDoBurst && (ubSpecial == FIRE_WEAPON_NO_SPECIAL) ) { // the animation required by the bullet hit (head explosion etc) overrides the // hit-by-a-burst animation @@ -2826,7 +2829,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend // adjust for bullet going through person iImpact -= CalcBodyImpactReduction( ubAmmoType, ubHitLocation ); // adjust for other side of armour! - iImpact -= TotalArmourProtection( pFirer, pTarget, ubHitLocation, iImpact, ubAmmoType ); + iImpact -= TotalArmourProtection( pTarget, ubHitLocation, iImpact, ubAmmoType ); if (iImpact > 0) { pBullet->iImpact = (INT8) iImpact; @@ -2905,7 +2908,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend return( fStopped ); } -void BulletHitStructure( BULLET * pBullet, UINT16 usStructureID, INT32 iImpact, SOLDIERTYPE * pFirer, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT qCurrZ, BOOLEAN fStopped ) +void BulletHitStructure( BULLET * pBullet, UINT16 usStructureID, INT32 iImpact, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT qCurrZ, BOOLEAN fStopped ) { EV_S_STRUCTUREHIT SStructureHit; @@ -2915,10 +2918,10 @@ void BulletHitStructure( BULLET * pBullet, UINT16 usStructureID, INT32 iImpact, // HEADROCK HAM 5.1: Bullet already contains this data... SStructureHit.usWeaponIndex = pBullet->fromItem; SStructureHit.bWeaponStatus = pBullet->ubItemStatus; - SStructureHit.ubAttackerID = pFirer->ubID; + SStructureHit.ubAttackerID = pBullet->ubFirerID; SStructureHit.usStructureID = usStructureID; - SStructureHit.iImpact = iImpact; - SStructureHit.iBullet = pBullet->iBullet; + SStructureHit.iImpact = iImpact; + SStructureHit.iBullet = pBullet->iBullet; if (is_networked) SStructureHit.fStopped = fStopped; @@ -2961,7 +2964,7 @@ void BulletMissed( BULLET *pBullet, SOLDIERTYPE * pFirer ) send_miss(&SMiss); } - ShotMiss( pFirer->ubID, pBullet->iBullet ); + ShotMiss( pBullet->ubFirerID, pBullet->iBullet ); } UINT32 ChanceOfBulletHittingStructure( INT32 iDistance, INT32 iDistanceToTarget, INT16 sHitBy ) @@ -4048,7 +4051,8 @@ void CalculateFiringIncrementsSimple( DOUBLE ddHorizAngle, DOUBLE ddVerticAngle, pBullet->qIncrY = FloatToFixed( (FLOAT) sin( ddHorizAngle ) ); pBullet->qIncrZ = FloatToFixed( (FLOAT) ( sin( ddVerticAngle ) / sin( (PI/2) - ddVerticAngle ) * HEIGHTUNITS_PER_CELL ) );//dnl ch60 010913 } -INT8 FireBullet( SOLDIERTYPE * pFirer, BULLET * pBullet, BOOLEAN fFake ) + +INT8 FireBullet( UINT8 ubFirer, BULLET * pBullet, BOOLEAN fFake ) { //DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FireBullet")); @@ -4058,20 +4062,32 @@ INT8 FireBullet( SOLDIERTYPE * pFirer, BULLET * pBullet, BOOLEAN fFake ) pBullet->bLOSIndexY = CONVERT_WITHINTILE_TO_INDEX( FIXEDPT_TO_INT32( pBullet->qCurrY ) % CELL_Y_SIZE ); pBullet->iCurrCubesZ = CONVERT_HEIGHTUNITS_TO_INDEX( FIXEDPT_TO_INT32( pBullet->qCurrZ ) ); pBullet->iLoop = 1; - pBullet->pFirer = pFirer; pBullet->iImpactReduction = 0; pBullet->sGridNo = MAPROWCOLTOPOS( pBullet->iCurrTileY, pBullet->iCurrTileX ); + if ( ubFirer != NOBODY ) + pBullet->pFirer = MercPtrs[ ubFirer ]; + else + pBullet->pFirer = NULL; + //DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FireBullet: bullet info set")); if (fFake) { - pBullet->ubTargetID = pFirer->ubCTGTTargetID; + if ( ubFirer != NOBODY ) + pBullet->ubTargetID = pBullet->pFirer->ubCTGTTargetID; + else + pBullet->ubTargetID = NOBODY; + return( CalcChanceToGetThrough( pBullet ) ); } else { - pBullet->ubTargetID = pFirer->ubTargetID; + if ( ubFirer != NOBODY ) + pBullet->ubTargetID = pBullet->pFirer->ubTargetID; + else + pBullet->ubTargetID = NOBODY; + //if ( gGameSettings.fOptions[ TOPTION_HIDE_BULLETS ] ) //{ // pBullet->uiLastUpdate = 0; @@ -4100,12 +4116,12 @@ INT8 FireBullet( SOLDIERTYPE * pFirer, BULLET * pBullet, BOOLEAN fFake ) // ///////////////////////////////////////////////////////////////////////////////////// //} - if ( Item[ pFirer->usAttackingWeapon ].usItemClass == IC_THROWING_KNIFE ) + if ( ubFirer != NOBODY && Item[ pBullet->pFirer->usAttackingWeapon ].usItemClass == IC_THROWING_KNIFE ) { pBullet->usClockTicksPerUpdate = 30; } // HEADROCK HAM 5: Bomb Fragments - else if (pBullet->fFragment) + else if (ubFirer == NOBODY && pBullet->fFragment) { pBullet->usClockTicksPerUpdate = 30; } @@ -4113,10 +4129,10 @@ INT8 FireBullet( SOLDIERTYPE * pFirer, BULLET * pBullet, BOOLEAN fFake ) { //afp-start //always a fast bullet if ( pBullet->usFlags & ( BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_KNIFE | BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME /*| BULLET_FLAG_TRACER*/ ) ) - pBullet->usClockTicksPerUpdate = (Weapon[ pFirer->usAttackingWeapon ].ubBulletSpeed + GetBulletSpeedBonus(&pFirer->inv[pFirer->ubAttackingHand]) ) / 10; + pBullet->usClockTicksPerUpdate = (Weapon[ pBullet->pFirer->usAttackingWeapon ].ubBulletSpeed + GetBulletSpeedBonus(&pBullet->pFirer->inv[pBullet->pFirer->ubAttackingHand]) ) / 10; else if (gGameSettings.fOptions[TOPTION_ALTERNATE_BULLET_GRAPHICS]) - pBullet->usClockTicksPerUpdate = (Weapon[ pFirer->usAttackingWeapon ].ubBulletSpeed + GetBulletSpeedBonus(&pFirer->inv[pFirer->ubAttackingHand]) ) / 10; + pBullet->usClockTicksPerUpdate = (Weapon[ pBullet->pFirer->usAttackingWeapon ].ubBulletSpeed + GetBulletSpeedBonus(&pBullet->pFirer->inv[pBullet->pFirer->ubAttackingHand]) ) / 10; else pBullet->usClockTicksPerUpdate = 1; //afp-end @@ -4597,7 +4613,7 @@ INT8 FireBulletGivenTargetNCTH( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, } if (fFake) { - bCTGT = FireBullet( pFirer, pBullet, TRUE ); + bCTGT = FireBullet( pFirer->ubID, pBullet, TRUE ); RemoveBullet( iBullet ); return( bCTGT ); } @@ -4610,7 +4626,7 @@ INT8 FireBulletGivenTargetNCTH( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, // } //hayden if(is_client)send_bullet( pBullet, usHandItem ); - FireBullet( pFirer, pBullet, FALSE ); + FireBullet( pFirer->ubID, pBullet, FALSE ); } } @@ -5103,7 +5119,7 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA } if (fFake) { - bCTGT = FireBullet( pFirer, pBullet, TRUE ); + bCTGT = FireBullet( pFirer->ubID, pBullet, TRUE ); RemoveBullet( iBullet ); return( bCTGT ); } @@ -5118,7 +5134,7 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA if(is_client) send_bullet( pBullet, usHandItem ); - FireBullet( pFirer, pBullet, FALSE ); + FireBullet( pFirer->ubID, pBullet, FALSE ); } } @@ -5149,7 +5165,7 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA // Note that this function does not make provisions for Fake Firing. There is no need for it, and it would needlessly // complicate things anyway. // Also note we receive start coordinates from the bomb itself, because there's nowhere else to get them. -INT8 FireFragmentGivenTarget( SOLDIERTYPE * pThrower, FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usExplosiveItem ) +INT8 FireFragmentGivenTarget( UINT8 ubOwner, FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usExplosiveItem ) { // Artificial... dStartZ++; @@ -5214,7 +5230,7 @@ INT8 FireFragmentGivenTarget( SOLDIERTYPE * pThrower, FLOAT dStartX, FLOAT dStar ubImpact =(UINT8) Explosive[Item[usExplosiveItem].ubClassIndex].ubFragDamage; - iBullet = CreateBullet( pThrower->ubID, false, usBulletFlags, usExplosiveItem ); + iBullet = CreateBullet( ubOwner, false, usBulletFlags, usExplosiveItem ); if (iBullet == -1) { //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Failed to create bullet") ); @@ -5289,7 +5305,7 @@ INT8 FireFragmentGivenTarget( SOLDIERTYPE * pThrower, FLOAT dStartX, FLOAT dStar pBullet->fTracer = false; if(is_client)send_bullet( pBullet, usExplosiveItem ); - FireBullet( pThrower, pBullet, FALSE ); + FireBullet( ubOwner, pBullet, FALSE ); ///////////////////////////////////////////////////////////////////////////////////// // SANDRO - new mercs' records @@ -5759,7 +5775,7 @@ INT8 FireBulletGivenTargetTrapOnly( SOLDIERTYPE* pThrower, OBJECTTYPE* pObj, INT }*/ if(is_client)send_bullet( pBullet, pObj->usItem ); - FireBullet( pThrower, pBullet, FALSE ); + FireBullet( pThrower->ubID, pBullet, FALSE ); } ///////////////////////// SOUND //////////////////////////// @@ -6153,7 +6169,7 @@ void MoveBullet( INT32 iBullet ) { // hit a roof StopBullet( pBullet->iBullet ); - BulletHitStructure( pBullet, 0, 0, pBullet->pFirer, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); + BulletHitStructure( pBullet, 0, 0, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); return; } @@ -6201,7 +6217,7 @@ void MoveBullet( INT32 iBullet ) } // this might be a close call - if ( MercPtrs[ pStructure->usStructureID ]->bTeam == gbPlayerNum && pBullet->pFirer->bTeam != gbPlayerNum && sDesiredLevel == MercPtrs[ pStructure->usStructureID ]->pathing.bLevel ) + if ( pBullet->ubFirerID != NOBODY && MercPtrs[ pStructure->usStructureID ]->bTeam == gbPlayerNum && pBullet->pFirer->bTeam != gbPlayerNum && sDesiredLevel == MercPtrs[ pStructure->usStructureID ]->pathing.bLevel ) { MercPtrs[ pStructure->usStructureID ]->flags.fCloseCall = TRUE; } @@ -6214,7 +6230,7 @@ void MoveBullet( INT32 iBullet ) // apply suppression, regardless of friendly or enemy // except if friendly, not within a few tiles of shooter - if ( MercPtrs[ pStructure->usStructureID ]->bSide != pBullet->pFirer->bSide || pBullet->iLoop > MIN_DIST_FOR_SCARE_FRIENDS ) + if ( pBullet->ubFirerID == NOBODY || MercPtrs[ pStructure->usStructureID ]->bSide != pBullet->pFirer->bSide || pBullet->iLoop > MIN_DIST_FOR_SCARE_FRIENDS ) { // buckshot has only a 1 in 2 chance of applying a suppression point // HEADROCK HAM 5: For NCTH, make pellets as effective as any other bullet. @@ -6249,7 +6265,7 @@ void MoveBullet( INT32 iBullet ) // else fall through default: MercPtrs[pStructure->usStructureID]->ubSuppressionPoints++; - MercPtrs[pStructure->usStructureID]->ubSuppressorID = pBullet->pFirer->ubID; + MercPtrs[pStructure->usStructureID]->ubSuppressorID = pBullet->ubFirerID; break; } } @@ -6322,7 +6338,7 @@ void MoveBullet( INT32 iBullet ) if (ubTargetID != NOBODY) { pTarget = MercPtrs[ ubTargetID ]; - if ( IS_MERC_BODY_TYPE( pTarget ) && pBullet->pFirer->bSide != pTarget->bSide ) + if ( IS_MERC_BODY_TYPE( pTarget ) && (pBullet->ubFirerID == NOBODY || pBullet->pFirer->bSide != pTarget->bSide) ) { // HEADROCK HAM 5: For NCTH, make pellets as effective as any other bullet. BOOLEAN fInflictSuppression = FALSE; @@ -6356,7 +6372,7 @@ void MoveBullet( INT32 iBullet ) // else fall through default: pTarget->ubSuppressionPoints++; - pTarget->ubSuppressorID = pBullet->pFirer->ubID; + pTarget->ubSuppressorID = pBullet->ubFirerID; break; } } @@ -6368,7 +6384,6 @@ void MoveBullet( INT32 iBullet ) pTarget->flags.fCloseCall = TRUE; } */ - } } } @@ -6389,13 +6404,13 @@ void MoveBullet( INT32 iBullet ) //hayden not hit ground if(ENABLE_COLLISION) { - if (iCurrAboveLevelZ < 0) - { - // ground is in the way! - StopBullet( pBullet->iBullet ); - BulletHitStructure( pBullet, INVALID_STRUCTURE_ID, 0, pBullet->pFirer, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); - return; - } + if (iCurrAboveLevelZ < 0) + { + // ground is in the way! + StopBullet( pBullet->iBullet ); + BulletHitStructure( pBullet, INVALID_STRUCTURE_ID, 0, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); + return; + } } // check for the existence of structures if (iNumLocalStructures == 0 && !pRoofStructure) @@ -6447,20 +6462,20 @@ void MoveBullet( INT32 iBullet ) //hayden, stop hit ground if(ENABLE_COLLISION) { - if (pBullet->qCurrZ + pBullet->qIncrZ * iStepsToTravel < qLandHeight) - { - // WANNE - BMP: BUGFIX: Had to change abs to _abs64 because FIXEDPT is now INT64 - //iStepsToTravel = __min( iStepsToTravel, abs( (pBullet->qCurrZ - qLandHeight) / pBullet->qIncrZ ) ); - iStepsToTravel = __min( iStepsToTravel, _abs64( (pBullet->qCurrZ - qLandHeight) / pBullet->qIncrZ ) ); + if (pBullet->qCurrZ + pBullet->qIncrZ * iStepsToTravel < qLandHeight) + { + // WANNE - BMP: BUGFIX: Had to change abs to _abs64 because FIXEDPT is now INT64 + //iStepsToTravel = __min( iStepsToTravel, abs( (pBullet->qCurrZ - qLandHeight) / pBullet->qIncrZ ) ); + iStepsToTravel = __min( iStepsToTravel, _abs64( (pBullet->qCurrZ - qLandHeight) / pBullet->qIncrZ ) ); - pBullet->qCurrX += pBullet->qIncrX * iStepsToTravel; - pBullet->qCurrY += pBullet->qIncrY * iStepsToTravel; - pBullet->qCurrZ += pBullet->qIncrZ * iStepsToTravel; + pBullet->qCurrX += pBullet->qIncrX * iStepsToTravel; + pBullet->qCurrY += pBullet->qIncrY * iStepsToTravel; + pBullet->qCurrZ += pBullet->qIncrZ * iStepsToTravel; - StopBullet( pBullet->iBullet ); - BulletHitStructure( pBullet, INVALID_STRUCTURE_ID, 0, pBullet->pFirer, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); - return; - } + StopBullet( pBullet->iBullet ); + BulletHitStructure( pBullet, INVALID_STRUCTURE_ID, 0, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); + return; + } } // HEADROCK HAM B2.5: Changed condition to read fTracer flag directly from bullet's struct. @@ -6542,7 +6557,7 @@ void MoveBullet( INT32 iBullet ) { if (pStructure->fFlags & STRUCTURE_PERSON) { - if(!(UsingNewCTHSystem() || pBullet->fFragment || (pBullet->usFlags & BULLET_FLAG_BUCKSHOT)) && fIntended && pBullet->sHitBy < 0 && pBullet->pFirer->ubTargetID == pStructure->usStructureID)//dnl ch60 010913 don't hit target if CTH roll decide to miss + if(!(UsingNewCTHSystem() || pBullet->fFragment || (pBullet->usFlags & BULLET_FLAG_BUCKSHOT)) && fIntended && pBullet->sHitBy < 0 && pBullet->ubFirerID != NOBODY && pBullet->pFirer->ubTargetID == pStructure->usStructureID)//dnl ch60 010913 don't hit target if CTH roll decide to miss { gpLocalStructure[iStructureLoop] = NULL; //SendFmtMsg("shoot me, miss me, lucky me :-)"); @@ -6626,7 +6641,7 @@ void MoveBullet( INT32 iBullet ) // bullet must end here! StopBullet( pBullet->iBullet ); - BulletHitStructure( pBullet, pStructure->usStructureID, 1, pBullet->pFirer, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); + BulletHitStructure( pBullet, pStructure->usStructureID, 1, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); return; } } @@ -6703,13 +6718,13 @@ void MoveBullet( INT32 iBullet ) else if ( iRemainingImpact <= 0 ) { StopBullet( pBullet->iBullet ); - BulletHitStructure( pBullet, pStructure->usStructureID, 1, pBullet->pFirer, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); + BulletHitStructure( pBullet, pStructure->usStructureID, 1, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); return; } else if (fHitStructure && (gubLocalStructureNumTimesHit[iStructureLoop] == 0) ) { // play animation to indicate structure being hit - BulletHitStructure( pBullet, pStructure->usStructureID, 1, pBullet->pFirer, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, FALSE ); + BulletHitStructure( pBullet, pStructure->usStructureID, 1, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, FALSE ); gubLocalStructureNumTimesHit[iStructureLoop] = 1; } } @@ -6741,7 +6756,7 @@ void MoveBullet( INT32 iBullet ) if ( 1 /*HandleBulletStructureInteraction( pBullet, pRoofStructure, &fHitStructure ) <= 0 */) { StopBullet( pBullet->iBullet ); - BulletHitStructure( pBullet, 0, 0, pBullet->pFirer, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); + BulletHitStructure( pBullet, 0, 0, pBullet->qCurrX, pBullet->qCurrY, pBullet->qCurrZ, TRUE ); return; } /* @@ -6839,7 +6854,7 @@ void MoveBullet( INT32 iBullet ) } // check to see if bullet is close to target - if ( pBullet->pFirer->ubTargetID != NOBODY && !(pBullet->pFirer->flags.uiStatusFlags & SOLDIER_ATTACK_NOTICED) && PythSpacesAway( pBullet->sGridNo, pBullet->sTargetGridNo ) <= 3 ) + if ( pBullet->ubFirerID != NOBODY && pBullet->pFirer->ubTargetID != NOBODY && !(pBullet->pFirer->flags.uiStatusFlags & SOLDIER_ATTACK_NOTICED) && PythSpacesAway( pBullet->sGridNo, pBullet->sTargetGridNo ) <= 3 ) { pBullet->pFirer->flags.uiStatusFlags |= SOLDIER_ATTACK_NOTICED; } @@ -6847,7 +6862,6 @@ void MoveBullet( INT32 iBullet ) // unless the distance is integral, after the loop there will be a // fractional amount of distance remaining which is unchecked // but we shouldn't(?) need to check it because the target is there! - } diff --git a/Tactical/LOS.h b/Tactical/LOS.h index 5e602df3..c0eccefb 100644 --- a/Tactical/LOS.h +++ b/Tactical/LOS.h @@ -68,7 +68,7 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA // HEADROCK HAM 4: Changed the name of one argument to avoid confusion with the new CTH system. INT8 FireBulletGivenTargetNCTH( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usHandItem, INT16 sApertureRatio, BOOLEAN fBuckshot, BOOLEAN fFake ); // HEADROCK HAM 5: Function for fragments ejected from an explosion. -INT8 FireFragmentGivenTarget( SOLDIERTYPE * pThrower, FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usExplosiveItem ); +INT8 FireFragmentGivenTarget( UINT8 ubOwner, FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usExplosiveItem ); // Flugente: fire a shot from a gun that has no user (used for traps with attached guns) INT8 FireBulletGivenTargetTrapOnly( SOLDIERTYPE* pThrower, OBJECTTYPE* pObj, INT32 gridno, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, INT16 sHitBy); diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 756502d6..0b8ffe44 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -15949,7 +15949,7 @@ void SOLDIERTYPE::StartMultiTurnAction(UINT8 usActionType) void SOLDIERTYPE::CancelMultiTurnAction(BOOLEAN fFinished) { // stop action - if ( !fFinished ) + if ( !fFinished && this->usMultiTurnAction ) ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szMTATextStr[STR_MTA_CANCEL], this->GetName(), szMTATextStr[this->usMultiTurnAction] ); bOverTurnAPS = 0; diff --git a/Tactical/Weapons.cpp b/Tactical/Weapons.cpp index 7b731f8b..dc8e70e9 100644 --- a/Tactical/Weapons.cpp +++ b/Tactical/Weapons.cpp @@ -4234,17 +4234,20 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) return( TRUE ); } -BOOLEAN DoSpecialEffectAmmoMiss( UINT8 ubAttackerID, INT32 sGridNo, INT16 sXPos, INT16 sYPos, INT16 sZPos, BOOLEAN fSoundOnly, BOOLEAN fFreeupAttacker, INT32 iBullet ) +BOOLEAN DoSpecialEffectAmmoMiss( UINT8 ubAttackerID, UINT16 usWeaponIndex, INT32 sGridNo, INT16 sXPos, INT16 sYPos, INT16 sZPos, BOOLEAN fSoundOnly, BOOLEAN fFreeupAttacker, INT32 iBullet ) { ANITILE_PARAMS AniParams; - UINT8 ubAmmoType; - UINT16 usItem; + UINT8 ubAmmoType = 0; + UINT16 usItem = usWeaponIndex; // Flugente: check for underbarrel weapons and use that object if necessary - OBJECTTYPE* pObj = MercPtrs[ ubAttackerID ]->GetUsedWeapon( &MercPtrs[ ubAttackerID ]->inv[ MercPtrs[ ubAttackerID ]->ubAttackingHand ] ); + if ( ubAttackerID != NOBODY ) + { + OBJECTTYPE* pObj = MercPtrs[ ubAttackerID ]->GetUsedWeapon( &MercPtrs[ ubAttackerID ]->inv[ MercPtrs[ ubAttackerID ]->ubAttackingHand ] ); - ubAmmoType = (*pObj)[0]->data.gun.ubGunAmmoType; - usItem = (*pObj).usItem; + ubAmmoType = (*pObj)[0]->data.gun.ubGunAmmoType; + usItem = (*pObj).usItem; + } memset( &AniParams, 0, sizeof( ANITILE_PARAMS ) ); @@ -4252,14 +4255,14 @@ BOOLEAN DoSpecialEffectAmmoMiss( UINT8 ubAttackerID, INT32 sGridNo, INT16 sXPos, { if ( !fSoundOnly ) { - AniParams.sGridNo = sGridNo; + AniParams.sGridNo = sGridNo; AniParams.ubLevelID = ANI_TOPMOST_LEVEL; - AniParams.sDelay = (INT16)( 100 ); + AniParams.sDelay = (INT16)( 100 ); AniParams.sStartFrame = 0; - AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_ALWAYS_TRANSLUCENT; - AniParams.sX = sXPos; - AniParams.sY = sYPos; - AniParams.sZ = sZPos; + AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_ALWAYS_TRANSLUCENT; + AniParams.sX = sXPos; + AniParams.sY = sYPos; + AniParams.sZ = sZPos; strcpy( AniParams.zCachedFile, "TILECACHE\\MINIBOOM.STI" ); @@ -4289,14 +4292,14 @@ BOOLEAN DoSpecialEffectAmmoMiss( UINT8 ubAttackerID, INT32 sGridNo, INT16 sXPos, { if ( !fSoundOnly ) { - AniParams.sGridNo = sGridNo; + AniParams.sGridNo = sGridNo; AniParams.ubLevelID = ANI_TOPMOST_LEVEL; - AniParams.sDelay = (INT16)( 100 ); + AniParams.sDelay = (INT16)( 100 ); AniParams.sStartFrame = 0; - AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_ALWAYS_TRANSLUCENT; - AniParams.sX = sXPos; - AniParams.sY = sYPos; - AniParams.sZ = sZPos; + AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_ALWAYS_TRANSLUCENT; + AniParams.sX = sXPos; + AniParams.sY = sYPos; + AniParams.sZ = sZPos; strcpy( AniParams.zCachedFile, "TILECACHE\\ZGRAV_D.STI" ); @@ -4326,14 +4329,14 @@ BOOLEAN DoSpecialEffectAmmoMiss( UINT8 ubAttackerID, INT32 sGridNo, INT16 sXPos, { if ( !fSoundOnly ) { - AniParams.sGridNo = sGridNo; + AniParams.sGridNo = sGridNo; AniParams.ubLevelID = ANI_TOPMOST_LEVEL; - AniParams.sDelay = (INT16)( 100 ); + AniParams.sDelay = (INT16)( 100 ); AniParams.sStartFrame = 0; - AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_ALWAYS_TRANSLUCENT; - AniParams.sX = sXPos; - AniParams.sY = sYPos; - AniParams.sZ = sZPos; + AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_ALWAYS_TRANSLUCENT; + AniParams.sX = sXPos; + AniParams.sY = sYPos; + AniParams.sZ = sZPos; strcpy( AniParams.zCachedFile, "TILECACHE\\ZGRAV_C.STI" ); @@ -4396,13 +4399,18 @@ BOOLEAN DoSpecialEffectAmmoMiss( UINT8 ubAttackerID, INT32 sGridNo, INT16 sXPos, void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 sBreathLoss, UINT16 usDirection, INT16 sXPos, INT16 sYPos, INT16 sZPos, INT16 sRange , UINT8 ubAttackerID, BOOLEAN fHit, UINT8 ubSpecial, UINT8 ubHitLocation ) { - SOLDIERTYPE *pTargetSoldier, *pSoldier; - OBJECTTYPE *pObj; - // Get attacker - pSoldier = MercPtrs[ ubAttackerID ]; + SOLDIERTYPE* pTargetSoldier = NULL; + SOLDIERTYPE* pSoldier = NULL; + OBJECTTYPE* pObj = NULL; - // Flugente: check for underbarrel weapons and use that object if necessary - pObj = pSoldier->GetUsedWeapon( &pSoldier->inv[pSoldier->ubAttackingHand] ); + // Get attacker + if ( ubAttackerID != NOBODY ) + { + pSoldier = MercPtrs[ ubAttackerID ]; + + // Flugente: check for underbarrel weapons and use that object if necessary + pObj = pSoldier->GetUsedWeapon( &pSoldier->inv[pSoldier->ubAttackingHand] ); + } // Get Target pTargetSoldier = MercPtrs[ usSoldierID ]; @@ -4412,7 +4420,7 @@ void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 s // CALLAHAN START BUGFIX // 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 || EXPLOSIVE_GUN( usWeaponIndex )) // WANNE: This fixes the bug, that ONE shot LAWs do not explode on a direct target hit! + if ( pObj && (pObj->usItem == usWeaponIndex || EXPLOSIVE_GUN( usWeaponIndex ) ) ) // WANNE: This fixes the bug, that ONE shot LAWs do not explode on a direct target hit! { ubAmmoType = (*pObj)[0]->data.gun.ubGunAmmoType; } @@ -4437,7 +4445,7 @@ void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 s IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), C1, pTargetSoldier->pathing.bLevel ); } // changed rpg type to work only with two flags matching - else if ( !Item[usWeaponIndex].singleshotrocketlauncher && Item[usWeaponIndex].rocketlauncher) + else if ( pSoldier && !Item[usWeaponIndex].singleshotrocketlauncher && Item[usWeaponIndex].rocketlauncher) //we shouldn't be able to have an underbarrel firing mode in this step, so we keep the original code :JMich { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("WeaponHit: RPG7 item: %d, Ammo: %d",pSoldier->inv[HANDPOS].usItem , pSoldier->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) ); @@ -4446,9 +4454,12 @@ void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 s //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( &(pSoldier->inv[pSoldier->ubAttackingHand ]), pSoldier->inv[pSoldier->ubAttackingHand ].usItem ); - if(pLaunchable){ + if(pLaunchable) + { pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = pLaunchable->usItem; - } else { + } + else + { pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE; } } @@ -4471,14 +4482,14 @@ void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 s return; } - DoSpecialEffectAmmoMiss( ubAttackerID, pTargetSoldier->sGridNo, sXPos, sYPos, sZPos, FALSE, FALSE, 0 ); + DoSpecialEffectAmmoMiss( ubAttackerID, usWeaponIndex, pTargetSoldier->sGridNo, sXPos, sYPos, sZPos, FALSE, FALSE, 0 ); // OK, SHOT HAS HIT, DO THINGS APPROPRIATELY // ATE: This is 'cause of that darn smoke effect that could potentially kill // the poor bastard .. so check if ( !pTargetSoldier->flags.fDoingExternalDeath ) { - pTargetSoldier->EVENT_SoldierGotHit( usWeaponIndex, sDamage, sBreathLoss, usDirection, sRange, ubAttackerID, ubSpecial, ubHitLocation, 0, NOWHERE ); + pTargetSoldier->EVENT_SoldierGotHit( usWeaponIndex, sDamage, sBreathLoss, usDirection, sRange, ubAttackerID, ubSpecial, ubHitLocation, 0, NOWHERE ); } // else // { @@ -4502,17 +4513,16 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN BOOLEAN fHitSameStructureAsBefore; BULLET * pBullet; SOLDIERTYPE * pAttacker = NULL; - OBJECTTYPE * pObj; + OBJECTTYPE * pObj = NULL; pBullet = GetBulletPtr( iBullet ); Assert(pBullet); // Flugente: check for underbarrel weapons and use that object if necessary - pObj = MercPtrs[ ubAttackerID ]->GetUsedWeapon( &MercPtrs [ ubAttackerID ]->inv[MercPtrs[ubAttackerID]->ubAttackingHand] ); - - // Get attacker - if (ubAttackerID != NOBODY) + if ( ubAttackerID != NOBODY ) { + pObj = MercPtrs[ ubAttackerID ]->GetUsedWeapon( &MercPtrs [ ubAttackerID ]->inv[MercPtrs[ubAttackerID]->ubAttackingHand] ); + pAttacker = MercPtrs[ ubAttackerID ]; } @@ -4561,8 +4571,6 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN sGridNo = MAPROWCOLTOPOS( (sYPos/CELL_Y_SIZE), (sXPos/CELL_X_SIZE) ); if ( !fHitSameStructureAsBefore ) { - - if (sZPos > WALL_HEIGHT) { MakeNoise( ubAttackerID, sGridNo, 1, gpWorldLevelData[sGridNo].ubTerrainID, ubHitVolume, NOISE_BULLET_IMPACT ); @@ -4571,18 +4579,19 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN { MakeNoise( ubAttackerID, sGridNo, 0, gpWorldLevelData[sGridNo].ubTerrainID, ubHitVolume, NOISE_BULLET_IMPACT ); } - } if (fStopped) { // marke need another attacker id assignment - SOLDIERTYPE *pSoldier; + SOLDIERTYPE *pSoldier = NULL; // Get attacker - pSoldier = MercPtrs[ ubAttackerID ]; + if ( ubAttackerID != NOBODY ) + pSoldier = MercPtrs[ ubAttackerID ]; + // marke added one 'or' to get this working with HE ammo - if ( Item[usWeaponIndex].rocketlauncher || AmmoTypes[ (*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1) + if ( Item[usWeaponIndex].rocketlauncher || (pObj && AmmoTypes[ (*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1 )) { // Reduce attacker count! DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - end of LAW fire") ); @@ -4596,7 +4605,7 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN 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) + else if ( ubAttackerID != NOBODY && !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 ) ); @@ -4604,9 +4613,12 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN //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){ + if(pLaunchable) + { pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = pLaunchable->usItem; - } else { + } + else + { pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE; } } @@ -4661,7 +4673,7 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN case MGCLASS: // Guy has missed, play random sound - if ( MercPtrs[ ubAttackerID ]->bTeam == gbPlayerNum ) + if ( ubAttackerID != NOBODY && MercPtrs[ ubAttackerID ]->bTeam == gbPlayerNum ) { if ( !MercPtrs[ ubAttackerID ]->bDoBurst ) { @@ -4678,7 +4690,7 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN case MONSTERCLASS: - DoSpecialEffectAmmoMiss( ubAttackerID, sGridNo, sXPos, sYPos, sZPos, FALSE, TRUE, iBullet ); + DoSpecialEffectAmmoMiss( ubAttackerID, usWeaponIndex, sGridNo, sXPos, sYPos, sZPos, FALSE, TRUE, iBullet ); RemoveBullet( iBullet ); // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - monster attack hit structure") ); @@ -4769,7 +4781,7 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN UINT16 usItem = pBullet->fromItem; if(usStructureID == INVALID_STRUCTURE_ID) { - for(int i=0; ifromItem) { usItem = Item[i].uiIndex;// clean the blood from knife, actually this should be done during repair @@ -4859,7 +4871,7 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN else { - if ( !fStopped || !DoSpecialEffectAmmoMiss( ubAttackerID, sGridNo, sXPos, sYPos, sZPos, FALSE, TRUE, iBullet ) ) + if ( !fStopped || !DoSpecialEffectAmmoMiss( ubAttackerID, usWeaponIndex, sGridNo, sXPos, sYPos, sZPos, FALSE, TRUE, iBullet ) ) { if ( sZPos == 0 ) { @@ -4882,13 +4894,13 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN // Add ripple memset( &AniParams, 0, sizeof( ANITILE_PARAMS ) ); - AniParams.sGridNo = sGridNo; - AniParams.ubLevelID = ANI_STRUCT_LEVEL; - AniParams.usTileType = THIRDMISS; - AniParams.usTileIndex = THIRDMISS1; - AniParams.sDelay = 50; - AniParams.sStartFrame = 0; - AniParams.uiFlags = ANITILE_FORWARD; + AniParams.sGridNo = sGridNo; + AniParams.ubLevelID = ANI_STRUCT_LEVEL; + AniParams.usTileType = THIRDMISS; + AniParams.usTileIndex = THIRDMISS1; + AniParams.sDelay = 50; + AniParams.sStartFrame = 0; + AniParams.uiFlags = ANITILE_FORWARD; pNode = CreateAnimationTile( &AniParams ); @@ -4897,15 +4909,14 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN pNode->pLevelNode->sRelativeX = sXPos; pNode->pLevelNode->sRelativeY = sYPos; pNode->pLevelNode->sRelativeZ = sZPos; - } memset( &AniParams, 0, sizeof( ANITILE_PARAMS ) ); - AniParams.sGridNo = sGridNo; + AniParams.sGridNo = sGridNo; AniParams.ubLevelID = ANI_STRUCT_LEVEL; - AniParams.usTileType = usMissTileType; + AniParams.usTileType = usMissTileType; AniParams.usTileIndex = usMissTileIndex; - AniParams.sDelay = 80; + AniParams.sDelay = 80; AniParams.sStartFrame = 0; if (fStopped) { @@ -4932,12 +4943,9 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN // ATE: Show misses...( if our team ) if ( gGameSettings.fOptions[ TOPTION_SHOW_MISSES ] ) { - if ( ubAttackerID != NOBODY ) + if ( ubAttackerID != NOBODY && MercPtrs[ ubAttackerID ]->bTeam == gbPlayerNum ) { - if ( MercPtrs[ ubAttackerID ]->bTeam == gbPlayerNum ) - { - LocateGridNo( sGridNo ); - } + LocateGridNo( sGridNo ); } } } @@ -9191,7 +9199,7 @@ INT32 ArmourProtection( SOLDIERTYPE * pTarget, UINT16 ubArmourType, INT16 * pbSt } -INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iImpact, UINT8 ubAmmoType ) +INT32 TotalArmourProtection( SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iImpact, UINT8 ubAmmoType ) { INT32 iTotalProtection = 0, iSlot; OBJECTTYPE * pArmour; @@ -9207,7 +9215,6 @@ INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 u iTotalProtection += ArmourProtection( pTarget, (UINT8) pVehicleList[ pTarget->bVehicleID ].sArmourType, &bDummyStatus, iImpact, ubAmmoType, &dummyCoverage ); //pVehicleList[ pTarget->bVehicleID ].sExternalArmorLocationsStatus[ ubHitLocation ] = bDummyStatus; - } else { @@ -9226,7 +9233,6 @@ INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 u default: iSlot = VESTPOS; break; - } //zwwooooo - IoV: It can plates for the LBE bulletproof. Like CRIAS, MBSS, HSGI WASATCH... @@ -9254,53 +9260,53 @@ INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 u if ( iImpact > iTotalProtection ) { - pArmour = &(pTarget->inv[ iSlot ]); - if (pArmour->exists() == true) - { - for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists()) - { - // bullet got through jacket; apply ceramic plate armour - iTotalProtection += ArmourProtection( pTarget, Item[iter->usItem].ubClassIndex, &((*iter)[0]->data.objectStatus), iImpact, ubAmmoType, &plateHit ); - if ( (*iter)[0]->data.objectStatus < USABLE ) - { - // destroy plates! - pArmour->RemoveAttachment(&(*iter)); - DirtyMercPanelInterface( pTarget, DIRTYLEVEL2 ); -//#ifdef ENGLISH - if ( pTarget->bTeam == gbPlayerNum ) - { - // report plates destroyed! - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[61], pTarget->name ); - } -//#endif - } - break;//original code only used the first ceramic plate - } - } - - - // if the plate didn't stop the bullet... - if ( iImpact > iTotalProtection ) + pArmour = &(pTarget->inv[ iSlot ]); + if (pArmour->exists() == true) { - iTotalProtection += ArmourProtection( pTarget, Item[pArmour->usItem].ubClassIndex, &((*pArmour)[0]->data.objectStatus), iImpact, ubAmmoType, &plateHit ); - if ( (*pArmour)[0]->data.objectStatus < USABLE ) - { - //Madd: put any attachments that someone might have added to the armour in the merc's inventory - for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) { - if ( !AutoPlaceObject( pTarget, &(*iter), FALSE ) && iter->exists()) - { // put it on the ground - AddItemToPool( pTarget->sGridNo, &(*iter), 1, pTarget->pathing.bLevel, 0 , -1 ); + for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) { + if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists()) + { + // bullet got through jacket; apply ceramic plate armour + iTotalProtection += ArmourProtection( pTarget, Item[iter->usItem].ubClassIndex, &((*iter)[0]->data.objectStatus), iImpact, ubAmmoType, &plateHit ); + if ( (*iter)[0]->data.objectStatus < USABLE ) + { + // destroy plates! + pArmour->RemoveAttachment(&(*iter)); + DirtyMercPanelInterface( pTarget, DIRTYLEVEL2 ); + //#ifdef ENGLISH + if ( pTarget->bTeam == gbPlayerNum ) + { + // report plates destroyed! + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[61], pTarget->name ); + } + //#endif } + break;//original code only used the first ceramic plate } + } - DeleteObj( pArmour );//takes care of attachments, no need to remove() or erase() - DirtyMercPanelInterface( pTarget, DIRTYLEVEL2 ); + // if the plate didn't stop the bullet... + if ( iImpact > iTotalProtection ) + { + iTotalProtection += ArmourProtection( pTarget, Item[pArmour->usItem].ubClassIndex, &((*pArmour)[0]->data.objectStatus), iImpact, ubAmmoType, &plateHit ); + if ( (*pArmour)[0]->data.objectStatus < USABLE ) + { + //Madd: put any attachments that someone might have added to the armour in the merc's inventory + for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) { + if ( !AutoPlaceObject( pTarget, &(*iter), FALSE ) && iter->exists()) + { // put it on the ground + AddItemToPool( pTarget->sGridNo, &(*iter), 1, pTarget->pathing.bLevel, 0 , -1 ); + } + } + + DeleteObj( pArmour );//takes care of attachments, no need to remove() or erase() + DirtyMercPanelInterface( pTarget, DIRTYLEVEL2 ); + } } } } } - } + return( iTotalProtection ); } @@ -9310,7 +9316,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, UINT16 usAttackingWeapon = 0; INT32 sOrigGridNo = 0; BOOLEAN fFragment = FALSE; - if (pBullet == NULL) + if (pBullet == NULL && pFirer ) { usAttackingWeapon = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType; sOrigGridNo = pFirer->sGridNo; @@ -9353,7 +9359,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, ubAmmoType = AMMO_KNIFE; } // HEADROCK HAM 5: Added provisions for fragments, which are not fired from the weapon in your hand. - else if ( fFragment == FALSE ) + else if ( !fFragment && pFirer ) { // Flugente: check for underbarrel weapons and use that object if necessary OBJECTTYPE* pObj = pFirer->GetUsedWeapon( &pFirer->inv[pFirer->ubAttackingHand] ); @@ -9409,7 +9415,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, } else { - iImpact = iOrigImpact - TotalArmourProtection( pFirer, pTarget, ubHitLocation, iOrigImpact, ubAmmoType ); + iImpact = iOrigImpact - TotalArmourProtection( pTarget, ubHitLocation, iOrigImpact, ubAmmoType ); } // calc minimum damage @@ -9431,7 +9437,6 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, { iImpact += (pTarget->bNumPelletsHitBy - 1) / 2; } - } if (gfNextShotKills) @@ -9468,7 +9473,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, //} //////////////////////////////////////////////////////////////////////////////////// - if ( gGameOptions.fNewTraitSystem ) // new traits bonuses - SANDRO + if ( gGameOptions.fNewTraitSystem && pFirer ) // new traits bonuses - SANDRO { // Throwing skill increases damage of knives here if ( (ubAmmoType == AMMO_KNIFE) && HAS_SKILL_TRAIT( pFirer, THROWING_NT )) @@ -9609,8 +9614,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, // don't do critical hits against people who are gonna die! if( !IsAutoResolveActive() ) { - - if ( AmmoTypes[ubAmmoType].knife && pFirer->aiData.bOppList[ pTarget->ubID ] == SEEN_CURRENTLY && !fFragment ) + if ( AmmoTypes[ubAmmoType].knife && pFirer && 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 ) @@ -9673,7 +9677,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, } BOOLEAN fMaliciousHit = FALSE; // SANDRO - Malicious characters inflict stat loss more often - if ( gGameOptions.fNewTraitSystem && pFirer->ubProfile != NO_PROFILE && !fFragment) + if ( gGameOptions.fNewTraitSystem && pFirer && pFirer->ubProfile != NO_PROFILE && !fFragment) { if ( gMercProfiles[ pFirer->ubProfile ].bCharacterTrait == CHAR_TRAIT_MALICIOUS ) { @@ -9697,9 +9701,10 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_SOLDIER_HIT_TO_GROIN], pTarget->GetName() ); } - // Gain morale for inflicting critical hit - HandleMoraleEvent( pFirer, MORALE_MALICIOUS_HIT, pFirer->sSectorX, pFirer->sSectorY, pFirer->bSectorZ ); + if ( pFirer ) + // Gain morale for inflicting critical hit + HandleMoraleEvent( pFirer, MORALE_MALICIOUS_HIT, pFirer->sSectorX, pFirer->sSectorY, pFirer->bSectorZ ); } else { @@ -9902,7 +9907,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, } // SANDRO - Gain morale for inflicting critical hit if malicious character - if ( fMaliciousHit ) + if ( fMaliciousHit && pFirer ) { HandleMoraleEvent( pFirer, MORALE_MALICIOUS_HIT, pFirer->sSectorX, pFirer->sSectorY, pFirer->bSectorZ ); } @@ -10225,9 +10230,12 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO void ShotMiss( UINT8 ubAttackerID, INT32 iBullet ) { - BOOLEAN fDoMissForGun = FALSE; - SOLDIERTYPE *pAttacker; - BULLET *pBullet; + BOOLEAN fDoMissForGun = FALSE; + SOLDIERTYPE* pAttacker = NULL; + BULLET* pBullet; + + if ( ubAttackerID == NOBODY ) + return; pAttacker = MercPtrs[ ubAttackerID ]; @@ -10237,7 +10245,7 @@ void ShotMiss( UINT8 ubAttackerID, INT32 iBullet ) if ( (pAttacker->bTeam != Menptr[ pAttacker->ubOppNum ].bTeam ) ) { // if OPPONENT is under our control - if (Menptr[ pAttacker->ubOppNum ].bTeam == gbPlayerNum ) + if (Menptr[ pAttacker->ubOppNum ].bTeam == gbPlayerNum ) { // AGILITY GAIN: Opponent "dodged" a bullet shot at him (it missed) StatChange( MercPtrs[ pAttacker->ubOppNum ], AGILAMT, 5, FROM_FAILURE ); @@ -10301,7 +10309,7 @@ void ShotMiss( UINT8 ubAttackerID, INT32 iBullet ) // PLAY SOUND AND FLING DEBRIS // RANDOMIZE SOUND SYSTEM - if ( !DoSpecialEffectAmmoMiss( ubAttackerID, NOWHERE, 0, 0, 0, TRUE, TRUE, 0 ) ) + if ( !DoSpecialEffectAmmoMiss( ubAttackerID, MercPtrs[ ubAttackerID ]->usAttackingWeapon, NOWHERE, 0, 0, 0, TRUE, TRUE, 0 ) ) { PlayJA2Sample( MISS_1 + Random(8), RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); } diff --git a/Tactical/Weapons.h b/Tactical/Weapons.h index e827a6be..b943c26d 100644 --- a/Tactical/Weapons.h +++ b/Tactical/Weapons.h @@ -480,7 +480,7 @@ extern BOOLEAN IsGunWeaponModeCapable( OBJECTTYPE* pObject, WeaponMode weaponMod extern BOOLEAN IsGunBurstCapable( OBJECTTYPE* pObject, BOOLEAN fNotify, SOLDIERTYPE *pSoldier = NULL ); extern BOOLEAN IsGunAutofireCapable( OBJECTTYPE* pObject ); extern INT32 CalcBodyImpactReduction( UINT8 ubAmmoType, UINT8 ubHitLocation ); -extern INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iImpact, UINT8 ubAmmoType ); +extern INT32 TotalArmourProtection( SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iImpact, UINT8 ubAmmoType ); extern INT32 ArmourPercent( SOLDIERTYPE * pSoldier ); extern void GetTargetWorldPositions( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, FLOAT *pdXPos, FLOAT *pdYPos, FLOAT *pdZPos ); diff --git a/Tactical/bullets.cpp b/Tactical/bullets.cpp index c42d47fc..3e376e3b 100644 --- a/Tactical/bullets.cpp +++ b/Tactical/bullets.cpp @@ -152,7 +152,11 @@ void HandleBulletSpecialFlags( INT32 iBulletIndex ) else if ( pBullet->usFlags & ( BULLET_FLAG_KNIFE ) ) { strcpy( AniParams.zCachedFile, "TILECACHE\\KNIFING.STI" ); - pBullet->ubItemStatus = pBullet->pFirer->inv[ HANDPOS ][0]->data.objectStatus; + + if ( pBullet->ubFirerID != NOBODY ) + pBullet->ubItemStatus = pBullet->pFirer->inv[ HANDPOS ][0]->data.objectStatus; + else + pBullet->ubItemStatus = 100; } // Get direction to use for this guy.... diff --git a/TileEngine/Explosion Control.cpp b/TileEngine/Explosion Control.cpp index f9a27f86..5de75063 100644 --- a/TileEngine/Explosion Control.cpp +++ b/TileEngine/Explosion Control.cpp @@ -104,7 +104,7 @@ BOOLEAN ExpAffect( INT32 sBombGridNo, INT32 sGridNo, UINT32 uiDist, UINT16 usIte UINT8 DetermineFlashbangEffect( SOLDIERTYPE *pSoldier, INT8 ubExplosionDir, BOOLEAN fInBuilding); // HEADROCK HAM 5.1: Explosion Fragments launcher -void FireFragments( SOLDIERTYPE * pThrower, INT16 sX, INT16 sY, INT16 sZ, UINT16 usItem, UINT8 ubDirection = DIRECTION_IRRELEVANT ); +void FireFragments( UINT8 ubOwner, INT16 sX, INT16 sY, INT16 sZ, UINT16 usItem, UINT8 ubDirection = DIRECTION_IRRELEVANT ); // Flugente: shoot a gun without anyone operating it (used for makeshift traps wih guns) void FireFragmentsTrapGun( SOLDIERTYPE* pThrower, INT32 gridno, INT16 sZ, OBJECTTYPE* pObj, UINT8 ubDirection = NORTH ); @@ -383,7 +383,7 @@ void InternalIgniteExplosion( UINT8 ubOwner, INT16 sX, INT16 sY, INT16 sZ, INT32 if (Explosive[ Item[ usItem ].ubClassIndex ].usNumFragments > 0 ) { // HEADROCK HAM 5: Deactivated until the release of HAM 5.1. - FireFragments( MercPtrs[ubOwner], sX, sY, sZ, usItem, ubDirection ); + FireFragments( ubOwner, sX, sY, sZ, usItem, ubDirection ); } // Flugente: Items can have secondary explosions @@ -4992,7 +4992,7 @@ UINT8 DetermineFlashbangEffect( SOLDIERTYPE *pSoldier, INT8 ubExplosionDir, BOOL // HEADROCK HAM 5.1: This handles launching fragments out of an explosion. The number of fragments is read from // the Explosives.XML file, and they each have a set amount of damage and range as well. They are currently // fired at completely random trajectories. -void FireFragments( SOLDIERTYPE * pThrower, INT16 sX, INT16 sY, INT16 sZ, UINT16 usItem, UINT8 ubDirection ) +void FireFragments( UINT8 ubOwner, INT16 sX, INT16 sY, INT16 sZ, UINT16 usItem, UINT8 ubDirection ) { UINT16 usNumFragments = Explosive[Item[usItem].ubClassIndex].usNumFragments; UINT16 ubFragRange = Explosive[Item[usItem].ubClassIndex].ubFragRange; @@ -5074,7 +5074,7 @@ void FireFragments( SOLDIERTYPE * pThrower, INT16 sX, INT16 sY, INT16 sZ, UINT16 FLOAT dStartY = (FLOAT)sY + (dRandomY * ((FLOAT)Random(4)+1.0f)); FLOAT dStartZ = (FLOAT)sZ + (dRandomZ * ((FLOAT)Random(4)+1.0f)); - FireFragmentGivenTarget( pThrower, dStartX, dStartY, dStartZ, dEndX, dEndY, dEndZ, usItem ); + FireFragmentGivenTarget( ubOwner, dStartX, dStartY, dStartZ, dEndX, dEndY, dEndZ, usItem ); } }