Files
source/Tactical/Soldier Ani.cpp
2025-12-09 00:35:18 +02:00

5085 lines
164 KiB
C++

#include "stdlib.h"
#include "DEBUG.H"
#include "MemMan.h"
#include "Overhead Types.h"
#include "Soldier Control.h" // I need this here - SANDRO
#include "Animation Data.h"
#include "Animation Control.h"
#include "Weapons.h"
#include "Soldier Ani.h"
#include "random.h"
#include "video.h"
#include "shading.h"
#include "Sound Control.h"
#include "Isometric Utils.h"
#include "Handle UI.h"
#include "Event Pump.h"
#include "opplist.h"
#include "lighting.h"
#include "ai.h"
#include "renderworld.h"
#include "Interactive Tiles.h"
#include "Points.h"
#include "message.h"
#include "world items.h"
#include "physics.h"
#include "Soldier Create.h"
#include "Dialogue Control.h"
#include "Soldier Functions.h"
#include "Rotting Corpses.h"
#include "merc entering.h"
#include "Soldier Add.h"
#include "Soldier Profile.h"
#include "Interface.h"
#include "qarray.h"
#include "Soldier macros.h"
#include "Squads.h"
#include "worldman.h"
#include "Structure Wrap.h"
#include "PATHAI.H"
#include "pits.h"
#include "Text.h"
#include "NPC.h"
#include "Explosion Control.h"
#include "LOS.h"
#include "GameSettings.h"
#include "Boxing.h"
#include "Drugs And Alcohol.h"
#include "Smell.h"
#include "interface Dialogue.h"
#include "Strategic Status.h"
#include "Food.h"
#include "CampaignStats.h" // added by Flugente
#include "DynamicDialogue.h" // added by Flugente
#include "MilitiaIndividual.h" // added by Flugente
#include "Town Militia.h" // added by Flugente
#include "PreBattle Interface.h" // added by Flugente
#include "Rebel Command.h"
#include "Civ Quotes.h"
#include "connect.h"
#include "fresh_header.h"
#ifdef JA2UB
#else
#include "Meanwhile.h"
#endif // JA2UB
//forward declarations of common classes to eliminate includes
class OBJECTTYPE;
class SOLDIERTYPE;
#define NO_JUMP 0
#define MAX_ANIFRAMES_PER_FLASH 3
//#define TIME_FOR_RANDOM_ANIM_CHECK 10
#define TIME_FOR_RANDOM_ANIM_CHECK 1
SoldierID gfLastMercTalkedAboutKillingID = NOBODY;
extern void AddFuelToVehicle( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVehicle );
DOUBLE gHopFenceForwardSEDist[ NUMSOLDIERBODYTYPES ] = { 2.2, 0.7, 3.2, 0.7 };
DOUBLE gHopFenceForwardNWDist[ NUMSOLDIERBODYTYPES ] = { 2.7, 1.0, 2.7, 1.0 };
DOUBLE gHopFenceForwardFullSEDist[ NUMSOLDIERBODYTYPES ] = { 1.1, 1.0, 2.1, 1.1 };
DOUBLE gHopFenceForwardFullNWDist[ NUMSOLDIERBODYTYPES ] = { 0.8, 0.2, 2.7, 0.8 };
DOUBLE gFalloffBackwardsDist[ NUMSOLDIERBODYTYPES ] = { 1, 0.8, 1, 1 };
DOUBLE gClimbUpRoofDist[ NUMSOLDIERBODYTYPES ] = { 2, 0.1, 2, 2 };
DOUBLE gClimbUpRoofLATDist[ NUMSOLDIERBODYTYPES ] = { 0.7, 0.5, 0.7, 0.5 };
DOUBLE gClimbDownRoofStartDist[ NUMSOLDIERBODYTYPES ] = { 5.0, 1.0, 1, 1 };
DOUBLE gClimbUpRoofDistGoingLower[ NUMSOLDIERBODYTYPES ] = { 0.9, 0.0, 1, 0.9 };
BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse );
void CheckForAndHandleSoldierIncompacitated( SOLDIERTYPE *pSoldier );
BOOLEAN CheckForImproperFireGunEnd( SOLDIERTYPE *pSoldier );
BOOLEAN OKHeightDest( SOLDIERTYPE *pSoldier, INT32 sNewGridNo );
BOOLEAN HandleUnjamAnimation( SOLDIERTYPE *pSoldier );
extern void HandleSystemNewAISituation( SOLDIERTYPE *pSoldier, BOOLEAN fResetABC );
extern void PlaySoldierFootstepSound( SOLDIERTYPE *pSoldier );
extern UINT16 NumCapableEnemyInSector( );
extern BOOLEAN gfKillingGuysForLosingBattle;
extern SoldierID gubInterruptProvoker;
extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance );
extern bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass, BOOLEAN alsoRemoveFromGroup );
extern void PlaySplashSound(INT32 sGridNo);
// Animation code explanations!
//
// 0-399: Actual animation frame indices
// 400-499: Object manipulation codes
// 500-598: Jump to frame x-501, same state. Obvious limit 0-97
// 600-699: Jump to new state x-600, frame 0
// 700-798: Play sound
// 800-999: Jump to new state x-700, frame 0 (starts with 100)
//
BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier )
{
EV_S_FIREWEAPON SFireWeapon;
UINT16 sNewAniFrame, anAniFrame;
INT8 ubCurrentHeight;
UINT16 usOldAnimState;
static UINT32 uiJumpAddress = NO_JUMP;
INT32 sNewGridNo;
INT16 sX, sY;
BOOLEAN fStop;
UINT32 cnt;
UINT8 ubDiceRoll; // Percentile dice roll
UINT8 ubRandomHandIndex; // Index value into random animation table to use base don what is in the guys hand...
UINT16 usItem;
RANDOM_ANI_DEF *pAnimDef;
UINT8 ubNewDirection;
UINT8 ubDesiredHeight;
BOOLEAN bOKFireWeapon;
BOOLEAN bWeaponJammed;
BOOLEAN fFreeUpAttacker=FALSE;
UINT16 usUIMovementMode;
do
{
// Get new frame code
sNewAniFrame = gusAnimInst[ pSoldier->usAnimState ][ pSoldier->usAniCode ];
// Handle muzzle flashes
if ( pSoldier->bMuzFlashCount > 0 )
{
// FLash for about 3 frames
if ( pSoldier->bMuzFlashCount > MAX_ANIFRAMES_PER_FLASH )
{
pSoldier->bMuzFlashCount = 0;
if ( pSoldier->iMuzFlash != -1 )
{
LightSpriteDestroy( pSoldier->iMuzFlash );
pSoldier->iMuzFlash = -1;
}
}
else
{
pSoldier->bMuzFlashCount++;
}
}
if ( pSoldier->bBreathCollapsed )
{
// ATE: If we have fallen, and we can't get up... no
// really, if we were told to collapse but have been hit after, don't
// do anything...
if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_HITSTOP | ANIM_HITFINISH ) )
{
pSoldier->bBreathCollapsed = FALSE;
}
else if ( pSoldier->stats.bLife == 0 )
{
// Death takes precedence...
pSoldier->bBreathCollapsed = FALSE;
}
else if ( pSoldier->usPendingAnimation == FALLFORWARD_ROOF || pSoldier->usPendingAnimation == FALLOFF || pSoldier->usAnimState == FALLFORWARD_ROOF || pSoldier->usAnimState == FALLOFF )
{
pSoldier->bBreathCollapsed = FALSE;
}
else
{
// Wait here until we are free....
if ( !pSoldier->flags.fInNonintAnim )
{
// UNset UI
UnSetUIBusy( pSoldier->ubID );
SoldierCollapse( pSoldier );
pSoldier->bBreathCollapsed = FALSE;
return( TRUE );
}
}
}
// Check for special code
if ( sNewAniFrame < 399 )
{
// Adjust / set true ani frame
// Use -1 because ani files are 1-based, these are 0-based
pSoldier->ConvertAniCodeToAniFrame( (INT16)( sNewAniFrame - 1 ) );
// Adjust frame control pos, and try again
pSoldier->usAniCode++;
break;
}
else if ( sNewAniFrame < 500 )
{
// Switch on special code
switch( sNewAniFrame )
{
case 402:
// DO NOT MOVE FOR THIS FRAME
pSoldier->flags.fPausedMove = TRUE;
break;
case 403:
// MOVE GUY FORWARD SOME VALUE
MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)0.7 );
break;
case 404:
// MOVE GUY BACKWARD SOME VALUE
sNewGridNo = pSoldier->sGridNo;
// Use same function as forward, but is -ve values!
MoveMercFacingDirection( pSoldier , TRUE, (FLOAT)1 );
//shadooow: since we just moved from original grid to the jump destination, now it is proper time to change bLevel
if (sNewGridNo != pSoldier->sGridNo)
{
pSoldier->pathing.bLevel = 0;
}
break;
case 405:
return( TRUE );
case 406:
// Move merc up
if ( pSoldier->ubDirection == NORTH )
{
pSoldier->SetSoldierHeight( (FLOAT)(pSoldier->sHeightAdjustment + 2 ) );
}
else
{
pSoldier->SetSoldierHeight( (FLOAT)( pSoldier->sHeightAdjustment + 3 ) );
}
break;
case 408:
// CODE: SPECIAL MOVE CLIMB UP ROOF EVENT
// Moved here because this represents "already on the roof", so breath collapses and interrupts should
// keep the soldier on the roof where he belongs
// Move merc up specific height
pSoldier->SetSoldierHeight( (FLOAT)50 );
{
INT16 sXPos, sYPos;
//sNewGridNo = NewGridNo( pSoldier->sGridNo, (UINT16)DirectionInc( pSoldier->ubDirection ) );
ConvertGridNoToCenterCellXY( pSoldier->sTempNewGridNo, &sXPos, &sYPos );
pSoldier->EVENT_SetSoldierPosition( (FLOAT)sXPos, (FLOAT)sYPos );
}
// re-enable sight
gTacticalStatus.uiFlags &= (~DISALLOW_SIGHT);
// Move two CC directions
pSoldier->EVENT_SetSoldierDirection( gTwoCCDirection[ pSoldier->ubDirection ] );
pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection );
// Set desired anim height!
pSoldier->ubDesiredHeight = ANIM_CROUCH;
// Madd
usUIMovementMode = pSoldier->GetMoveStateBasedOnStance( gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
pSoldier->usUIMovementMode = usUIMovementMode;
// ATE: Change interface level.....
// CJC: only if we are a player merc
if (pSoldier->bTeam == gbPlayerNum)
{
if (gTacticalStatus.fAutoBandageMode)
{
// in autobandage, handle as AI, but add roof marker too
FreeUpNPCFromRoofClimb( pSoldier );
HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, TRUE, TRUE );
}
else
{
// OK, UNSET INTERFACE FIRST
UnSetUIBusy( pSoldier->ubID );
if ( pSoldier->ubID == gusSelectedSoldier )
{
ChangeInterfaceLevel( 1 );
}
HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, TRUE, TRUE );
}
}
else
{
FreeUpNPCFromRoofClimb( pSoldier );
}
// ATE: Handle sight...
HandleSight( pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT );
break;
case 409:
//CODE: MOVE DOWN
pSoldier->SetSoldierHeight( (FLOAT)( pSoldier->sHeightAdjustment - 2 ) );
break;
case 410:
// Move merc down specific height
pSoldier->SetSoldierHeight( (FLOAT)0 );
break;
case 411:
// CODE: SPECIALMOVE CLIMB DOWN EVENT
// Move two C directions
pSoldier->EVENT_SetSoldierDirection( gTwoCDirection[ pSoldier->ubDirection ] );
// Remove the roof marker
HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, FALSE, TRUE );
pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection );
// Adjust height //shadooow: do not change bLevel yet, we are still at roof!
pSoldier->InternalSetSoldierHeight((FLOAT)gClimbDownRoofStartDist[pSoldier->ubBodyType], FALSE);
// Adjust position
MoveMercFacingDirection( pSoldier , TRUE, (FLOAT)3.5 );
break;
case 412:
// CODE: HANDLING PRONE DOWN - NEED TO MOVE GUY BACKWARDS!
MoveMercFacingDirection( pSoldier , FALSE, (FLOAT).2 );
break;
case 413:
// CODE: HANDLING PRONE UP - NEED TO MOVE GUY FORWARDS!
MoveMercFacingDirection( pSoldier , TRUE, (FLOAT).2 );
break;
case 430:
{
// sevenfm: breaking window with crowbar code
if (pSoldier->inv[HANDPOS].exists() &&
(ItemIsCrowbar(pSoldier->inv[HANDPOS].usItem) && Item[pSoldier->inv[HANDPOS].usItem].usItemClass & (IC_PUNCH) ||
Item[pSoldier->inv[HANDPOS].usItem].usItemClass & IC_GUN && ItemIsTwoHanded(pSoldier->inv[HANDPOS].usItem) && ItemIsMetal(pSoldier->inv[HANDPOS].usItem)))
{
INT32 sWindowGridNo = pSoldier->sTargetGridNo;
if (pSoldier->ubDirection == NORTH || pSoldier->ubDirection == WEST)
sWindowGridNo = NewGridNo(pSoldier->sGridNo, (UINT16)DirectionInc((UINT8)pSoldier->ubDirection));
// is there really an intact window that we jump through?
if (IsJumpableWindowPresentAtGridNo(sWindowGridNo, pSoldier->ubDirection, TRUE) && !IsJumpableWindowPresentAtGridNo(sWindowGridNo, pSoldier->ubDirection, FALSE))
{
STRUCTURE * pStructure = FindStructure(sWindowGridNo, STRUCTURE_WALLNWINDOW);
if (pStructure && !(pStructure->fFlags & STRUCTURE_OPEN))
{
// intact window found. Smash it!
WindowHit(sWindowGridNo, pStructure->usStructureID, (pSoldier->ubDirection == SOUTH || pSoldier->ubDirection == EAST), TRUE);
// damage weapon
if (Chance(50 - 10 * min(5, Item[pSoldier->inv[HANDPOS].usItem].bReliability)))
{
pSoldier->inv[HANDPOS][0]->data.objectStatus--;
if (Random(100) < Item[pSoldier->inv[HANDPOS].usItem].usDamageChance)
{
pSoldier->inv[HANDPOS][0]->data.sRepairThreshold--;
}
}
}
}
}
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: case 430");
// SHOOT GUN
// MAKE AN EVENT, BUT ONLY DO STUFF IF WE OWN THE GUY!
SFireWeapon.usSoldierID = pSoldier->ubID;
SFireWeapon.uiUniqueId = pSoldier->uiUniqueSoldierIdValue;
SFireWeapon.sTargetGridNo = pSoldier->sTargetGridNo;
SFireWeapon.bTargetLevel = pSoldier->bTargetLevel;
SFireWeapon.bTargetCubeLevel= pSoldier->bTargetCubeLevel;
if((is_server && pSoldier->ubID<120) || (!is_server && is_client && pSoldier->ubID<20) || (!is_server && !is_client) )
{
//only carry on if own merc
AddGameEvent( S_FIREWEAPON, 0, &SFireWeapon );
//hayden
if(is_server || (is_client && pSoldier->ubID <20) )
send_fireweapon( &SFireWeapon );
}
OBJECTTYPE* pObjHand = pSoldier->GetUsedWeapon( &pSoldier->inv[HANDPOS] );
//DIGICRAB: Burst UnCap
//Loop around in the animation if we still have burst rounds to fire
if (pSoldier->bDoBurst && !(pSoldier->IsValidSecondHandBurst())
&& ( pSoldier->bDoBurst <= ( (pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst( pObjHand )) )
|| (( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst <= Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst)) ))
{
if(pSoldier->usAnimState == STANDING_BURST || pSoldier->usAnimState == CROUCHED_BURST || pSoldier->usAnimState == PRONE_BURST || pSoldier->usAnimState == BURST_ALTERNATIVE_STAND && pSoldier->usAniCode == 33) //we are standing, crounching or prone, firing the fast shot
pSoldier->usAniCode = 3;
else if(pSoldier->usAnimState == FIRE_BURST_LOW_STAND || pSoldier->usAnimState == LOW_BURST_ALTERNATIVE_STAND && pSoldier->usAniCode == 37) //we are firing down to something very close, last shot
pSoldier->usAniCode = 14;
else if(pSoldier->usAnimState == TANK_BURST)//dnl ch64 280813 fix 6 round burst limitation
{
if(pSoldier->bDoBurst < pSoldier->bDoAutofire)//!!! this will be fine as long you not decide to equip tank with other weapons add limitted ammo, weapon jam, etc.
pSoldier->usAniCode = 4;
else
pSoldier->usAniCode = 34;
}
else if(pSoldier->usAnimState == ROBOT_BURST_SHOOT) //silversurfer: Bugfix JaggZilla #532 6 round burst limitation
{
if(pSoldier->bDoBurst < pSoldier->bDoAutofire)
pSoldier->usAniCode = 4;
else
pSoldier->usAniCode = 34;
}
}
OBJECTTYPE* pObjUsed = pSoldier->GetUsedWeapon( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
UINT16 usedGun = pSoldier->GetUsedWeaponNumber( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
//DIGICRAB: Burst Sound
//This code is stolen from Tactical\Weapons.c - UseGun(...)
if (pSoldier->bDoBurst && pSoldier->iBurstSoundID == NO_SAMPLE && Weapon[ usedGun ].sSound != 0 && Item[ usedGun ].usItemClass != IC_THROWING_KNIFE )
{
// Switch on silencer...
INT16 noisefactor = GetPercentNoiseVolume( pObjUsed );
if( noisefactor < gGameExternalOptions.gubMaxPercentNoiseSilencedSound || Weapon[ usedGun ].ubAttackVolume <= 10 )
{
INT32 uiSound;
uiSound = Weapon [ usedGun ].silencedSound;
//if ( Weapon[ pSoldier->usAttackingWeapon ].ubCalibre == AMMO9 || Weapon[ pSoldier->usAttackingWeapon ].ubCalibre == AMMO38 || Weapon[ pSoldier->usAttackingWeapon ].ubCalibre == AMMO57 )
//{
// uiSound = S_SILENCER_1;
//}
//else
//{
// uiSound = S_SILENCER_2;
//}
//randomize the rate a bit so that the sound is more believable
PlayJA2Sample( uiSound, 44100-Random(5000)-Random(5000)-Random(5000), SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
else
{
INT8 volume = HIGHVOLUME;
if ( noisefactor < 100 ) volume = (volume * noisefactor) / 100;
//randomize the rate a bit so that the sound is more believable
PlayJA2Sample( Weapon[ usedGun ].sSound, 44100-Random(5000)-Random(5000)-Random(5000), SoundVolume( volume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
}
break;
case 431:
// FLASH FRAME WHITE
pSoldier->pForcedShade = White16BPPPalette;
break;
case 432:
// PLAY RANDOM IMPACT SOUND!
// PlayJA2Sample( (UINT8)( BULLET_IMPACT_1 + Random(3) ), RATE_11025, MIDVOLUME, 1, MIDDLEPAN );
// PLAY RANDOM GETTING HIT SOUND
// pSoldier->DoMercBattleSound( BATTLE_SOUND_HIT1 );
break;
case 433:
// CODE: GENERIC HIT!
CheckForAndHandleSoldierIncompacitated( pSoldier );
break;
case 434:
// JUMP TO ANOTHER ANIMATION ( BLOOD ) IF WE WANT BLOOD
uiJumpAddress = pSoldier->usAnimState;
pSoldier->ChangeSoldierState( FLYBACK_HIT_BLOOD_STAND, 0, FALSE );
return( TRUE );
break;
case 435:
// HOOK FOR A RETURN JUMP
break;
case 436:
// Loop through script to find entry address
if ( uiJumpAddress == NO_JUMP )
{
break;
}
usOldAnimState = pSoldier->usAnimState;
pSoldier->usAniCode = 0;
do
{
// Get new frame code
anAniFrame = gusAnimInst[ uiJumpAddress ][ pSoldier->usAniCode ];
if ( anAniFrame == 435 )
{
// START PROCESSING HERE
pSoldier->ChangeSoldierState( (UINT16)uiJumpAddress, pSoldier->usAniCode, FALSE );
return( TRUE );
}
// Adjust frame control pos, and try again
pSoldier->usAniCode++;
}
while( anAniFrame != 999 );
uiJumpAddress = NO_JUMP;
if ( anAniFrame == 999 )
{
// Fail jump, re-load old anim
pSoldier->ChangeSoldierState( usOldAnimState, 0, FALSE );
return( TRUE );
}
break;
case 437:
// CHANGE DIRECTION AND GET-UP
//sGridNo = NewGridNo( pSoldier->sGridNo, (UINT16)(-1 * DirectionInc( pSoldier->ubDirection ) ) );
//ConvertMapPosToWorldTileCenter( pSoldier->sGridNo, &sXPos, &sYPos );
//SetSoldierPosition( pSoldier, (FLOAT)sXPos, (FLOAT)sYPos );
// Reverse direction
pSoldier->EVENT_SetSoldierDirection( gOppositeDirection[ pSoldier->ubDirection ] );
pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection );
pSoldier->ChangeSoldierState( GETUP_FROM_ROLLOVER, 0 , FALSE );
return( TRUE );
case 438:
//CODE: START HOLD FLASH
pSoldier->flags.fForceShade = TRUE;
break;
case 439:
//CODE: END HOLD FLASH
pSoldier->flags.fForceShade = FALSE;
break;
case 440:
//CODE: Set buddy as dead!
{
BOOLEAN fMadeCorpse;
// ATE: Piggyback here on stopping the burn sound...
if ( pSoldier->usAnimState == CHARIOTS_OF_FIRE ||
pSoldier->usAnimState == BODYEXPLODING )
{
SoundStop( pSoldier->aiData.uiPendingActionData1 );
}
CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse );
if ( fMadeCorpse )
{
return( FALSE );
}
else
{
return( TRUE );
}
}
break;
case 441:
// CODE: Show muzzle flash
{
OBJECTTYPE* pObjAttHand = pSoldier->GetUsedWeapon(&pSoldier->inv[pSoldier->ubAttackingHand]);
if (IsFlashSuppressor(pObjAttHand, pSoldier) || (*pObjAttHand)[0]->data.gun.bGunAmmoStatus < 0)
{
pSoldier->flags.fMuzzleFlash = FALSE;
}
else
{
pSoldier->flags.fMuzzleFlash = TRUE;
}
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("UseGun: Muzzle flash = %d", pSoldier->flags.fMuzzleFlash));
}
if ( !pSoldier->flags.fMuzzleFlash )
{
break;
}
// DO ONLY IF WE'RE AT A GOOD LEVEL
if ( ubAmbientLightLevel < MIN_AMB_LEVEL_FOR_MERC_LIGHTS )
{
break;
}
if( ( pSoldier->iMuzFlash=LightSpriteCreate("L-R03.LHT", 0 ) )==(-1))
{
return( TRUE );
}
LightSpritePower(pSoldier->iMuzFlash, TRUE);
// Get one move forward
{
INT32 usNewGridNo;
INT16 sXPos, sYPos;
usNewGridNo = NewGridNo( pSoldier->sGridNo, DirectionInc( pSoldier->ubDirection ) );
ConvertGridNoToCenterCellXY( usNewGridNo, &sXPos, &sYPos );
LightSpritePosition( pSoldier->iMuzFlash, (INT16)(sXPos/CELL_X_SIZE), (INT16)(sYPos/CELL_Y_SIZE));
// Start count
pSoldier->bMuzFlashCount = 1;
}
break;
case 442:
//CODE: FOR A NON-INTERRUPTABLE SCRIPT - SIGNAL DONE
pSoldier->flags.fInNonintAnim = FALSE;
// ATE: if it's the begin cower animation, unset ui, cause it could
// be from player changin stance
if ( pSoldier->usAnimState == START_COWER || pSoldier->usAnimState == START_COWER_CROUCHED || pSoldier->usAnimState == START_COWER_PRONE )
{
UnSetUIBusy( pSoldier->ubID );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SANDRO - if pending interrupt flag was set for after-attack type of interupt, try to resolve it now
else if ( UsingImprovedInterruptSystem() )
{
if ( ResolvePendingInterrupt( pSoldier, AFTERACTION_INTERRUPT ) )
{
pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
pSoldier->ubPendingDirection = NO_PENDING_DIRECTION;
// "artificially" set lock ui flag in this case
if (pSoldier->bTeam == gbPlayerNum)
{
//AddTopMessage( COMPUTER_INTERRUPT_MESSAGE, Message[STR_INTERRUPT] );
guiPendingOverrideEvent = LU_BEGINUILOCK;
HandleTacticalUI( );
}
return( TRUE );
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
break;
case 443:
// MOVE GUY FORWARD FOR FENCE HOP ANIMATION
switch( pSoldier->ubDirection )
{
case SOUTH:
case EAST:
MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gHopFenceForwardSEDist[ pSoldier->ubBodyType ] );
break;
case NORTH:
case WEST:
MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gHopFenceForwardNWDist[ pSoldier->ubBodyType ] );
break;
}
break;
case 444:
// CODE: End Hop Fence
// MOVE TO FORCASTED GRIDNO
ConvertGridNoToCenterCellXY(pSoldier->sForcastGridno, &sX, &sY);
pSoldier->EVENT_InternalSetSoldierPosition( (FLOAT) sX, (FLOAT) sY, FALSE, FALSE, FALSE );
pSoldier->EVENT_SetSoldierDirection( gTwoCDirection[ pSoldier->ubDirection ] );
pSoldier->sZLevelOverride = -1;
pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection );
if ( gTacticalStatus.bBoxingState == BOXING_WAITING_FOR_PLAYER || gTacticalStatus.bBoxingState == PRE_BOXING || gTacticalStatus.bBoxingState == BOXING )
{
BoxingMovementCheck( pSoldier );
}
if ( SetOffBombsInGridNo( pSoldier->ubID, pSoldier->sGridNo, FALSE, pSoldier->pathing.bLevel ))
{
pSoldier->EVENT_StopMerc( pSoldier->sGridNo, pSoldier->ubDirection );
return( TRUE );
}
// take the correct stance
if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != gAnimControl[ pSoldier->usUIMovementMode ].ubEndHeight )
{
// Goto Stance...
pSoldier->ChangeSoldierStance( gAnimControl[ pSoldier->usUIMovementMode ].ubEndHeight );
if ( pSoldier->sGridNo == pSoldier->pathing.sFinalDestination )
{
// Set UI Busy
UnSetUIBusy( pSoldier->ubID );
}
return( TRUE );
}
break;
case 445:
// CODE: MOVE GUY FORWARD ONE TILE, BASED ON WHERE WE ARE FACING
switch( pSoldier->ubDirection )
{
case SOUTH:
case EAST:
MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gHopFenceForwardFullSEDist[ pSoldier->ubBodyType ] );
break;
case NORTH:
case WEST:
MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gHopFenceForwardFullNWDist[ pSoldier->ubBodyType ] );
break;
}
break;
case 446:
// CODE: Turn pause move flag on
pSoldier->flags.uiStatusFlags |= SOLDIER_PAUSEANIMOVE;
break;
case 447:
// TRY TO FALL!!!
if ( pSoldier->flags.fTryingToFall )
{
INT16 sLastAniFrame;
// TRY FORWARDS...
// FIRST GRIDNO
sNewGridNo = NewGridNo( pSoldier->sGridNo, DirectionInc( pSoldier->ubDirection ) );
if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->pathing.bLevel, pSoldier->ubDirection, FALLFORWARD_HITDEATH_STOP ) )
{
// SECOND GRIDNO
// sNewGridNo = NewGridNo( sNewGridNo, (UINT16)( DirectionInc( pSoldier->ubDirection ) ) );
// if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->pathing.bLevel, pSoldier->ubDirection, FALLFORWARD_HITDEATH_STOP ) )
{
// ALL'S OK HERE...
pSoldier->flags.fTryingToFall = FALSE;
break;
}
}
// IF HERE, INCREMENT DIRECTION
// ATE: Added Feb1 - can be either direction....
if ( pSoldier->flags.fFallClockwise )
{
pSoldier->EVENT_SetSoldierDirection( gOneCDirection[ pSoldier->ubDirection ] );
}
else
{
pSoldier->EVENT_SetSoldierDirection( gOneCCDirection[ pSoldier->ubDirection ] );
}
pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection );
sLastAniFrame = gusAnimInst[ pSoldier->usAnimState ][ ( pSoldier->usAniCode - 2 ) ];
pSoldier->ConvertAniCodeToAniFrame( (INT16)( sLastAniFrame ) );
if ( pSoldier->ubDirection == pSoldier->bStartFallDir )
{
// GO FORWARD HERE...
pSoldier->flags.fTryingToFall = FALSE;
break;;
}
// IF HERE, RETURN SO WE DONOT INCREMENT DIR
return( TRUE );
}
break;
case 448:
{
// CODE: HANDLE BURST
// FIRST CHECK IF WE'VE REACHED MAX FOR GUN
fStop = FALSE;
OBJECTTYPE* pObjHand = pSoldier->GetUsedWeapon( &pSoldier->inv[HANDPOS] );
if ( ( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst > Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst) )
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because gl max burst size reached");
fStop = TRUE;
fFreeUpAttacker = TRUE;
}
else if (pSoldier->bWeaponMode != WM_ATTACHED_GL_BURST && !(pSoldier->IsValidSecondHandBurst()) && (pSoldier->bDoBurst > ((pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst( pObjHand )))))
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because gun max burst size reached");
fStop = TRUE;
fFreeUpAttacker = TRUE;
}
else if (pSoldier->bWeaponMode != WM_ATTACHED_GL_BURST && pSoldier->IsValidSecondHandBurst() && (pSoldier->bDoBurst > ((pSoldier->bDoAutofire)?(2*pSoldier->bDoAutofire):(2*GetShotsPerBurst( pObjHand )))))
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because dual max burst size reached");
fStop = TRUE;
fFreeUpAttacker = TRUE;
}
// CHECK IF WE HAVE AMMO LEFT, IF NOT, END ANIMATION!
if ( !EnoughAmmo( pSoldier, FALSE, pSoldier->ubAttackingHand ) )
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because not enough ammo");
fStop = TRUE;
fFreeUpAttacker = TRUE;
if ( pSoldier->bTeam == gbPlayerNum )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ BURST_FIRE_DEPLETED_CLIP_STR ] );
}
}
// Why only check for a jam on the first bullet?
else if (pSoldier->bDoBurst == 1)
{
// CHECK FOR GUN JAM
bWeaponJammed = CheckForGunJam( pSoldier );
if ( bWeaponJammed == TRUE )
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because weapon jammed");
fStop = TRUE;
fFreeUpAttacker = TRUE;
// stop shooting!
// Yeah, but what does this have to do with that?
// pSoldier->bBulletsLeft = 0;
// OK, Stop burst sound...
if ( pSoldier->iBurstSoundID != NO_SAMPLE )
{
SoundStop( pSoldier->iBurstSoundID );
}
if ( pSoldier->bTeam == gbPlayerNum )
{
PlayJA2Sample( S_DRYFIRE1, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Gun jammed!" );
}
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - aborting start of attack due to burst gun jam") );
FreeUpAttacker( );
}
else if ( bWeaponJammed == 255 )
{
// Play intermediate animation...
if ( HandleUnjamAnimation( pSoldier ) )
{
return( TRUE );
}
}
}
if ( fStop )
{
if(pSoldier->bDoAutofire) //reset the autofire cursor after firing
{
pSoldier->flags.autofireLastStep = FALSE;
pSoldier->bDoAutofire = 1;
}
pSoldier->flags.fDoSpread = FALSE;
pSoldier->bDoBurst = 1;
// pSoldier->flags.fBurstCompleted = TRUE;
if ( fFreeUpAttacker )
{
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - aborting start of attack") );
// FreeUpAttacker( pSoldier->ubID );
}
// ATE; Reduce it due to animation being stopped...
// 0verhaul: No longer necessary or desired
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - Burst animation ended") );
// ReduceAttackBusyCount( pSoldier->ubID, FALSE );
if ( CheckForImproperFireGunEnd( pSoldier ) )
{
return( TRUE );
}
// END: GOTO AIM STANCE BASED ON HEIGHT
// If we are a robot - we need to do stuff different here
// 0verhaul: Ya know, if the robot simply used the same animation for standing and rifle standing,
// we probably wouldn't need this special case code.
if ( AM_A_ROBOT( pSoldier ) )
{
pSoldier->ChangeSoldierState( STANDING, 0 , FALSE );
}
else
{
switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
{
case ANIM_STAND:
if ( pSoldier->usAnimState == BURST_DUAL_STAND )
pSoldier->ChangeSoldierState( AIM_DUAL_STAND, 0 , FALSE );
else if ( pSoldier->usAnimState == BURST_ALTERNATIVE_STAND || pSoldier->usAnimState == LOW_BURST_ALTERNATIVE_STAND )
pSoldier->ChangeSoldierState( AIM_ALTERNATIVE_STAND, 0 , FALSE );
else
pSoldier->ChangeSoldierState( AIM_RIFLE_STAND, 0 , FALSE );
break;
case ANIM_PRONE:
if ( pSoldier->usAnimState == BURST_DUAL_PRONE )
pSoldier->ChangeSoldierState( AIM_DUAL_PRONE, 0 , FALSE );
else
pSoldier->ChangeSoldierState( AIM_RIFLE_PRONE, 0 , FALSE );
break;
case ANIM_CROUCH:
if ( pSoldier->usAnimState == BURST_DUAL_CROUCH )
pSoldier->ChangeSoldierState( AIM_DUAL_CROUCH, 0 , FALSE );
else
pSoldier->ChangeSoldierState( AIM_RIFLE_CROUCH, 0 , FALSE );
break;
}
}
return( TRUE );
}
// MOVETO CURRENT SPREAD LOCATION
if ( pSoldier->flags.fDoSpread )
{
if ( pSoldier->sSpreadLocations[ pSoldier->flags.fDoSpread - 1 ] != 0 )
{
pSoldier->EVENT_SetSoldierDirection( (INT8)GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, pSoldier->sSpreadLocations[ pSoldier->flags.fDoSpread - 1 ] ) );
pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection );
}
}
}
break;
case 449:
//CODE: FINISH BURST
pSoldier->flags.fDoSpread = FALSE;
pSoldier->bDoBurst = 1;
// pSoldier->flags.fBurstCompleted = TRUE;
break;
case 450:
//CODE: BEGINHOPFENCE
// MOVE TWO FACGIN GRIDNOS
// Flugente: the old complicaed method relied on pSoldier->pathing.usPathingData to be filled correctly - which it often wasn't.
// This is unneccessary, as we've already filled sTempNewGridNo with the correct data
// we could fill sForcastGridno when initiating the jump, but lets keep this as a hook
if ( pSoldier->sTempNewGridNo != NOWHERE )
pSoldier->sForcastGridno = pSoldier->sTempNewGridNo;
else
// hey, it's better than nowhere
pSoldier->sForcastGridno = pSoldier->sGridNo;
break;
case 451:
// CODE: MANAGE START z-buffer override
switch( pSoldier->ubDirection )
{
case NORTH:
case WEST:
pSoldier->sZLevelOverride = TOPMOST_Z_LEVEL;
break;
}
break;
case 452:
// CODE: MANAGE END z-buffer override
switch( pSoldier->ubDirection )
{
case SOUTH:
case EAST:
pSoldier->sZLevelOverride = TOPMOST_Z_LEVEL;
break;
case NORTH:
case WEST:
pSoldier->sZLevelOverride = -1;
break;
}
break;
case 453:
//CODE: FALLOFF ROOF ( BACKWARDS ) - MOVE BACK SOME!
// Use same function as forward, but is -ve values!
MoveMercFacingDirection( pSoldier , TRUE, (FLOAT)gFalloffBackwardsDist[ pSoldier->ubBodyType ] );
break;
case 454:
// CODE: HANDLE CLIMBING ROOF,
// Move merc up
if ( pSoldier->ubDirection == NORTH )
{
pSoldier->SetSoldierHeight( (FLOAT)(pSoldier->aiData.dHeightAdjustment + gClimbUpRoofDist[ pSoldier->ubBodyType ] ) );
}
else
{
pSoldier->SetSoldierHeight( (FLOAT)(pSoldier->aiData.dHeightAdjustment + gClimbUpRoofDist[ pSoldier->ubBodyType ] ) );
}
break;
case 455:
// MOVE GUY FORWARD SOME VALUE
MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gClimbUpRoofLATDist[ pSoldier->ubBodyType ] );
// MOVE DOWN SOME VALUE TOO!
pSoldier->SetSoldierHeight( (FLOAT)(pSoldier->aiData.dHeightAdjustment - gClimbUpRoofDistGoingLower[ pSoldier->ubBodyType ] ) );
break;
case 456:
// CODE: HANDLE CLIMBING ROOF,
// Move merc DOWN
if ( pSoldier->ubDirection == NORTH )
{
pSoldier->SetSoldierHeight( (FLOAT)(pSoldier->aiData.dHeightAdjustment - gClimbUpRoofDist[ pSoldier->ubBodyType ] ) );
}
else
{
pSoldier->SetSoldierHeight( (FLOAT)(pSoldier->aiData.dHeightAdjustment - gClimbUpRoofDist[ pSoldier->ubBodyType ] ) );
}
break;
case 457:
// CODE: CHANGCE STANCE TO STANDING
SendChangeSoldierStanceEvent( pSoldier, ANIM_STAND );
break;
case 459:
// CODE: CHANGE ATTACKING TO FIRST HAND
pSoldier->ubAttackingHand = HANDPOS;
pSoldier->usAttackingWeapon = pSoldier->inv[pSoldier->ubAttackingHand].usItem;
// Adjust fReloading to FALSE
pSoldier->flags.fReloading = FALSE;
break;
case 458:
// CODE: CHANGE ATTACKING TO SECOND HAND
pSoldier->ubAttackingHand = SECONDHANDPOS;
pSoldier->usAttackingWeapon = pSoldier->inv[pSoldier->ubAttackingHand].usItem;
// Adjust fReloading to FALSE
pSoldier->flags.fReloading = FALSE;
break;
case 460:
case 461:
//CODE: THROW ITEM
// Launch ITem!
if ( pSoldier->pTempObject != NULL && pSoldier->pThrowParams != NULL )
{
// ATE: If we are armmed...
if ( pSoldier->pThrowParams->ubActionCode == THROW_ARM_ITEM )
{
//AXP 25.03.2007: MinAPsToThrow now actually returns the real cost, not 0
// ATE: Deduct points!
DeductPoints( pSoldier, MinAPsToThrow( pSoldier, pSoldier->sTargetGridNo, FALSE ), 0, AFTERACTION_INTERRUPT );
}
else
{
// ATE: Deduct points!
DeductPoints( pSoldier, APBPConstants[AP_TOSS_ITEM], 0, AFTERACTION_INTERRUPT );
}
// sevenfm: show flash light
UINT16 usItem = pSoldier->pTempObject->usItem;
UINT16 usBuddyItem = Item[usItem].usBuddyItem;
if (pSoldier->pThrowParams->ubActionCode == THROW_ARM_ITEM &&
(ItemIsFlare(usItem) ||
Explosive[Item[usItem].ubClassIndex].ubType == EXPLOSV_FLARE ||
Explosive[Item[usItem].ubClassIndex].ubType == EXPLOSV_BURNABLEGAS ||
usBuddyItem && (Item[usBuddyItem].usItemClass & IC_EXPLOSV) && (ItemIsFlare(usBuddyItem) || Explosive[Item[usBuddyItem].ubClassIndex].ubType == EXPLOSV_FLARE)))
{
if ((pSoldier->iMuzFlash = LightSpriteCreate("L-R03.LHT", 0)) != -1)
{
LightSpritePower(pSoldier->iMuzFlash, TRUE);
INT32 usNewGridNo;
INT16 sXPos, sYPos;
usNewGridNo = NewGridNo(pSoldier->sGridNo, DirectionInc(pSoldier->ubDirection));
ConvertGridNoToCenterCellXY(usNewGridNo, &sXPos, &sYPos);
LightSpritePosition(pSoldier->iMuzFlash, (INT16)(sXPos / CELL_X_SIZE), (INT16)(sYPos / CELL_Y_SIZE));
// Start count
pSoldier->bMuzFlashCount = 1;
}
}
INT32 iRealObjectID = CreatePhysicalObject( pSoldier->pTempObject, pSoldier->pThrowParams->dLifeSpan, pSoldier->pThrowParams->dX, pSoldier->pThrowParams->dY, pSoldier->pThrowParams->dZ, pSoldier->pThrowParams->dForceX, pSoldier->pThrowParams->dForceY, pSoldier->pThrowParams->dForceZ, pSoldier->ubID, pSoldier->pThrowParams->ubActionCode, pSoldier->pThrowParams->uiActionData, FALSE );
// OJW - 20091002 - Explosives
if (is_networked && is_client)
{
if (pSoldier->bTeam == 0 || (pSoldier->bTeam == 1 && is_server))
{
send_grenade( pSoldier->pTempObject, pSoldier->pThrowParams->dLifeSpan, pSoldier->pThrowParams->dX, pSoldier->pThrowParams->dY, pSoldier->pThrowParams->dZ, pSoldier->pThrowParams->dForceX, pSoldier->pThrowParams->dForceY, pSoldier->pThrowParams->dForceZ, pSoldier->sTargetGridNo, pSoldier->ubID, pSoldier->pThrowParams->ubActionCode, pSoldier->pThrowParams->uiActionData, iRealObjectID, true);
}
}
// Remove object
//RemoveObjFrom( &(pSoldier->inv[ HANDPOS ] ), 0 );
// Update UI
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
OBJECTTYPE::DeleteMe( &pSoldier->pTempObject );
MemFree( pSoldier->pThrowParams );
pSoldier->pThrowParams = NULL;
}
break;
case 462:
// CODE: MOVE UP FROM CLIFF CLIMB
pSoldier->aiData.dHeightAdjustment += (float)2.1;
pSoldier->sHeightAdjustment = (INT16)pSoldier->aiData.dHeightAdjustment;
// Move over some...
//MoveMercFacingDirection( pSoldier , FALSE, (FLOAT)0.5 );
break;
case 463:
// MOVE GUY FORWARD SOME VALUE
// Creature move
MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)1.5 );
break;
case 464:
// CODE: END CLIFF CLIMB
pSoldier->aiData.dHeightAdjustment = (float)0;
pSoldier->sHeightAdjustment = (INT16)pSoldier->aiData.dHeightAdjustment;
// Set new gridno
{
INT32 sTempGridNo;
INT16 sNewX, sNewY;
//Get Next GridNo;
sTempGridNo = NewGridNo( pSoldier->sGridNo, DirectionInc(pSoldier->ubDirection ) );
// Get center XY
ConvertGridNoToCenterCellXY( sTempGridNo, &sNewX, &sNewY );
// Set position
pSoldier->EVENT_SetSoldierPosition( sNewX, sNewY );
// Move two CC directions
pSoldier->EVENT_SetSoldierDirection( gTwoCCDirection[ pSoldier->ubDirection ] );
pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection );
// Set desired anim height!
pSoldier->ubDesiredHeight = ANIM_CROUCH;
pSoldier->pathing.sFinalDestination = pSoldier->sGridNo;
}
break;
case 465:
// CODE: SET GUY TO LIFE OF 0
pSoldier->stats.bLife = 0;
break;
case 466:
// CODE: ADJUST TO OUR DEST HEIGHT
if ( pSoldier->sHeightAdjustment != pSoldier->sDesiredHeight )
{
INT16 sDiff = pSoldier->sHeightAdjustment - pSoldier->sDesiredHeight;
if ( abs( sDiff ) > 4 )
{
if ( sDiff > 0 )
{
// Adjust!
pSoldier->SetSoldierHeight( (FLOAT)(pSoldier->aiData.dHeightAdjustment - 2 ) );
}
else
{
// Adjust!
pSoldier->SetSoldierHeight( (FLOAT)(pSoldier->aiData.dHeightAdjustment + 2 ) );
}
}
else
{
// Adjust!
pSoldier->SetSoldierHeight( (FLOAT)(pSoldier->sDesiredHeight) );
}
}
else
{
// Goto eating animation
if ( pSoldier->sDesiredHeight == 0 )
{
pSoldier->ChangeSoldierState( CROW_EAT, 0 , FALSE );
}
else
{
// We should leave now!
TacticalRemoveSoldier( pSoldier->ubID );
return( FALSE );
}
return( TRUE );
}
break;
case 467:
///CODE: FOR HELIDROP, SET DIRECTION
pSoldier->EVENT_SetSoldierDirection( EAST );
pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection );
gfIngagedInDrop = FALSE;
// OK, now get a sweetspot ( not the place we are now! )
// sNewGridNo = FindGridNoFromSweetSpotExcludingSweetSpot( pSoldier, pSoldier->sGridNo, 5, &ubNewDirection );
//sNewGridNo = FindRandomGridNoFromSweetSpotExcludingSweetSpot( pSoldier, pSoldier->sGridNo, 3, &ubNewDirection );
sNewGridNo = FindGridNoFromSweetSpotExcludingSweetSpotInQuardent( pSoldier, pSoldier->sGridNo, 3, &ubNewDirection, SOUTHEAST );
// Check for merc arrives quotes...
HandleMercArrivesQuotes( pSoldier );
// Find a path to it!
pSoldier->EVENT_GetNewSoldierPath( sNewGridNo, WALKING );
return( TRUE );
break;
case 468:
// CODE: End PUNCH
{
BOOLEAN fNPCPunch = FALSE;
// ATE: Put some code in for NPC punches...
if ( pSoldier->flags.uiStatusFlags & SOLDIER_NPC_DOING_PUNCH )
{
fNPCPunch = TRUE;
// Turn off
pSoldier->flags.uiStatusFlags &= (~SOLDIER_NPC_DOING_PUNCH );
// Trigger approach...
TriggerNPCWithGivenApproach( pSoldier->ubProfile, (UINT8)pSoldier->aiData.uiPendingActionData4, FALSE );
}
// Are we a martial artist?
{
BOOLEAN fMartialArtist = FALSE;
if ( pSoldier->ubProfile != NO_PROFILE && pSoldier->ubBodyType == REGMALE ) // SANDRO - added check for body type
{
// SANDRO - old/new traits
if (gGameOptions.fNewTraitSystem)
{
if ( NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 ) )
{
fMartialArtist = TRUE;
}
}
else
{
if ( ProfileHasSkillTrait( pSoldier->ubProfile, MARTIALARTS_OT ) > 0 )
{
fMartialArtist = TRUE;
}
}
}
if ( gAnimControl[ pSoldier->usAnimState ].ubHeight == ANIM_CROUCH )
{
if ( fNPCPunch )
{
pSoldier->ChangeSoldierStance( ANIM_STAND );
return( TRUE );
}
else
{
pSoldier->ChangeSoldierState( CROUCHING, 0, FALSE );
return( TRUE );
}
}
else
{
#ifdef JA2UB
//Ja25 No meanwhiles
if ( fMartialArtist )
#else
if ( fMartialArtist && !AreInMeanwhile( ) )
#endif
{
pSoldier->ChangeSoldierState( NINJA_BREATH, 0, FALSE );
return( TRUE );
}
else
{
pSoldier->ChangeSoldierState( PUNCH_BREATH, 0, FALSE );
return( TRUE );
}
}
}
}
break;
case 469:
// CODE: Begin martial artist attack
pSoldier->DoNinjaAttack( );
return( TRUE );
break;
case 470:
// CODE: CHECK FOR OK WEAPON SHOT!
bOKFireWeapon = OKFireWeapon( pSoldier );
if ( bOKFireWeapon == FALSE )
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Fire Weapon: Gun Cannot fire, code 470") );
// OK, SKIP x # OF FRAMES
// Skip 3 frames, ( a third ia added at the end of switch.. ) For a total of 4
pSoldier->usAniCode += 4;
// Reduce by a bullet...
// pSoldier->bBulletsLeft--;
PlayJA2Sample( S_DRYFIRE1, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
// Free-up!
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - gun failed to fire") );
FreeUpAttacker( );
}
else if ( bOKFireWeapon == 255 )
{
// Play intermediate animation...
if ( HandleUnjamAnimation( pSoldier ) )
{
return( TRUE );
}
}
break;
case 471:
// CODE: Turn pause move flag off
pSoldier->flags.uiStatusFlags &= (~SOLDIER_PAUSEANIMOVE);
break;
case 472:
{
INT8 bGoBackToAimAfterHit;
// Save old flag, then reset. If we do nothing special here, at least go back
// to aim if we were.
bGoBackToAimAfterHit = pSoldier->flags.bGoBackToAimAfterHit;
pSoldier->flags.bGoBackToAimAfterHit = NO_SPEC_STANCE_AFTER_HIT;
// CODE: HANDLE ANY RANDOM HIT VARIATIONS WE WISH TO DO.....
if ( pSoldier->stats.bLife >= OKLIFE && bGoBackToAimAfterHit)
{
if ( bGoBackToAimAfterHit == GO_TO_AIM_AFTER_HIT )
{
pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, FALSE, FALSE );
}
else if ( bGoBackToAimAfterHit == GO_TO_ALTERNATIVE_AIM_AFTER_HIT && (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND) )
{
pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, FALSE, TRUE );
}
else if ( bGoBackToAimAfterHit == GO_TO_HTH_BREATH_AFTER_HIT && (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND))
{
if ( Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_NONE | IC_PUNCH) )
{
if ((((NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) ||
(HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && pSoldier->ubBodyType == REGMALE )
{
if(is_networked)
pSoldier->ChangeSoldierState( NINJA_BREATH, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( NINJA_BREATH, 0 , FALSE );
}
else
{
if(is_networked)
pSoldier->ChangeSoldierState( PUNCH_BREATH, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( PUNCH_BREATH, 0 , FALSE );
}
}
else if ( Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_BLADE) )
{
if(is_networked)
pSoldier->ChangeSoldierState( KNIFE_BREATH, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( KNIFE_BREATH, 0 , FALSE );
}
}
else if ( bGoBackToAimAfterHit == GO_TO_COWERING_AFTER_HIT )
{
if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH)
{
if(is_networked)
pSoldier->ChangeSoldierState( START_COWER_CROUCHED, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( START_COWER_CROUCHED, 0 , FALSE );
}
else if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)
{
if(is_networked)
pSoldier->ChangeSoldierState( START_COWER_PRONE, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( START_COWER_PRONE, 0 , FALSE );
}
}
return( TRUE );
}
}
break;
case 473:
// CODE: CHECK IF WE HAVE JUST JAMMED / OUT OF AMMO, DONOT CONTINUE, BUT
// GOTO STATIONARY ANIM
if ( CheckForImproperFireGunEnd( pSoldier ) )
{
return( TRUE );
}
break;
case 474:
// CODE: GETUP FROM SLEEP
pSoldier->ChangeSoldierStance( ANIM_STAND );
return( TRUE );
case 475:
// CODE: END CLIMB DOWN ROOF
pSoldier->ubDesiredHeight = ANIM_STAND;
pSoldier->pathing.sFinalDestination = pSoldier->sGridNo;
// re-enable sight
gTacticalStatus.uiFlags &= (~DISALLOW_SIGHT);
// ATE: Change interface level.....
// CJC: only if we are a player merc
if ( (pSoldier->bTeam == gbPlayerNum) && !gTacticalStatus.fAutoBandageMode)
{
if ( pSoldier->ubID == gusSelectedSoldier )
{
ChangeInterfaceLevel( 0 );
}
// OK, UNSET INTERFACE FIRST
UnSetUIBusy( pSoldier->ubID );
}
else
{
FreeUpNPCFromRoofClimb( pSoldier );
}
if(pSoldier->usUIMovementMode != RUNNING)
pSoldier->usUIMovementMode = WALKING;
// ATE: Handle sight...
HandleSight( pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT );
break;
case 476:
// CODE: GOTO PREVIOUS ANIMATION
pSoldier->ChangeSoldierState( ( pSoldier->aiData.sPendingActionData2 ), (UINT8)( pSoldier->aiData.uiPendingActionData1 + 1 ), FALSE );
return( TRUE );
break;
case 477:
// CODE: Locate to target ( if an AI guy.. )
if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT ) )
{
if ( pSoldier->bTeam != gbPlayerNum )
{
// only locate if the enemy is visible or he's aiming at a player
if ( pSoldier->bVisible != -1 || (pSoldier->ubTargetID != NOBODY && pSoldier->ubTargetID->bTeam == gbPlayerNum) )
{
LocateGridNo( pSoldier->sTargetGridNo );
}
}
}
break;
case 478:
// CODE: Decide to turn from hit.......
{
INT8 bNewDirection;
UINT32 uiChance;
// ONLY DO THIS IF CERTAIN CONDITIONS ARISE!
// For one, only do for mercs!
// Flugente: don't do this while equipping a shield, as this renders them almost useless
if ( pSoldier->ubBodyType <= REGFEMALE && !pSoldier->IsRiotShieldEquipped( ) )
{
// Secondly, don't if we are going to collapse
if ( pSoldier->stats.bLife >= OKLIFE && pSoldier->bBreath > 0 && pSoldier->pathing.bLevel == 0 )
{
// Save old direction
pSoldier->aiData.uiPendingActionData1 = pSoldier->ubDirection;
// If we got a head shot...more chance of turning...
if ( pSoldier->ubHitLocation != AIM_SHOT_HEAD )
{
uiChance = Random( 100 );
// 30 % chance to change direction one way
if ( uiChance < 30 )
{
bNewDirection = gOneCDirection[ pSoldier->ubDirection ];
}
// 30 % chance to change direction the other way
else if ( uiChance >= 30 && uiChance < 60 )
{
bNewDirection = gOneCCDirection[ pSoldier->ubDirection ];
}
// 30 % normal....
else
{
bNewDirection = pSoldier->ubDirection;
}
pSoldier->EVENT_SetSoldierDirection( bNewDirection );
pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection );
}
else
{
// OK, 50% chance here to turn...
uiChance = Random( 100 );
if ( uiChance < 50 )
{
// OK, pick a larger direction to goto....
pSoldier->flags.uiStatusFlags |= SOLDIER_TURNINGFROMHIT;
// This becomes an attack busy situation
// 0verhaul: There is an attack busy problem with this. The soldier could be in mid-turn
// when another bullet is fired (auto-fire or dual-wield, for instance), and the soldier is
// knocked down in the middle of the turn. In such a case, the attack busy does not get
// cancelled. So if we indeed need to keep the attack busy (which may not be the case),
// we will need to find a more reliable method. For now, I'm going to cancel out the
// ABC adjustment here and we'll see if there needs to be something in its place.
//gTacticalStatus.ubAttackBusyCount++;
DebugAttackBusy( String( "Soldier turning from a hit. Not Increasing attack busy. Now %d\n", gTacticalStatus.ubAttackBusyCount ) );
// Pick evenly between both
if ( Random( 50 ) < 25 )
{
bNewDirection = gOneCDirection[ pSoldier->ubDirection ];
bNewDirection = gOneCDirection[ bNewDirection ];
bNewDirection = gOneCDirection[ bNewDirection ];
}
else
{
bNewDirection = gOneCCDirection[ pSoldier->ubDirection ];
bNewDirection = gOneCCDirection[ bNewDirection ];
bNewDirection = gOneCCDirection[ bNewDirection ];
}
pSoldier->EVENT_SetSoldierDesiredDirection( bNewDirection );
}
}
}
}
break;
}
case 479:
// CODE: Return to old direction......
if ( pSoldier->ubBodyType <= REGFEMALE )
{
// Secondly, don't if we are going to collapse
//if ( pSoldier->stats.bLife >= OKLIFE && pSoldier->bBreath > 0 )
//{
/// if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_TURNINGFROMHIT ) )
// {
/// pSoldier->ubDirection = (INT8)pSoldier->aiData.uiPendingActionData1;
// pSoldier->pathing.bDesiredDirection = (INT8)pSoldier->aiData.uiPendingActionData1;
// }
//}
}
break;
case 480:
// 0verhaul: This is handled in the ReduceAttackBusyCount call
// CODE: FORCE FREE ATTACKER
// Release attacker
//DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, code 480") );
//ReleaseSoldiersAttacker( pSoldier );
//FREEUP GETTING HIT FLAG
//pSoldier->flags.fGettingHit = FALSE;
break;
case 481:
// CODE: CUT FENCE...
CutWireFence( pSoldier->sTargetGridNo );
break;
case 482:
// CODE: END CRIPPLE KICKOUT...
KickOutWheelchair( pSoldier );
break;
case 483:
// CODE: HANDLE DROP BOMB...
HandleSoldierDropBomb( pSoldier, pSoldier->aiData.sPendingActionData2 );
break;
case 484:
// CODE: HANDLE REMOTE...
HandleSoldierUseRemote( pSoldier, pSoldier->aiData.sPendingActionData2 );
break;
case 485:
// CODE: Try steal.....
// UnSetUIBusy( pSoldier->ubID);
UseHandToHand( pSoldier, pSoldier->aiData.sPendingActionData2, TRUE );
//jackaians:
//if we are not waiting for the pickup menu to be displayed
// if (guiPendingOverrideEvent != G_GETTINGITEM)
// {
// PreventFromTheFreezingBug(pSoldier);
// }
break;
case 486:
// CODE: GIVE ITEM
SoldierGiveItemFromAnimation( pSoldier );
// if (pSoldier->ubProfile != NO_PROFILE && pSoldier->ubProfile >= FIRST_NPC )
//new profiles by Jazz
if (pSoldier->ubProfile != NO_PROFILE && ( gMercProfiles[pSoldier->ubProfile].Type == PROFILETYPE_RPC ||
gMercProfiles[pSoldier->ubProfile].Type == PROFILETYPE_NPC ||
gMercProfiles[pSoldier->ubProfile].Type == PROFILETYPE_VEHICLE ) )
{
TriggerNPCWithGivenApproach( pSoldier->ubProfile, APPROACH_DONE_GIVING_ITEM, FALSE );
}
break;
case 487:
// CODE: DROP ITEM
SoldierHandleDropItem( pSoldier );
break;
case 489:
//CODE: REMOVE GUY FRMO WORLD DUE TO EXPLOSION
//pSoldier->ChangeSoldierState( RAISE_RIFLE, 0 , FALSE );
//return( TRUE );
//Delete guy
//TacticalRemoveSoldier( pSoldier->ubID );
//return( FALSE );
break;
case 490:
// CODE: HANDLE END ITEM PICKUP
//LOOK INTO HAND, RAISE RIFLE IF WE HAVE ONE....
/*
if ( pSoldier->inv[ HANDPOS ].exists() == true )
{
// CHECK IF GUN
if ( Item[ pSoldier->inv[ HANDPOS ].usItem ].usItemClass == IC_GUN )
{
if ( Weapon[ pSoldier->inv[ HANDPOS ].usItem ].ubWeaponClass != HANDGUNCLASS )
{
// RAISE
pSoldier->ChangeSoldierState( RAISE_RIFLE, 0 , FALSE );
return( TRUE );
}
}
}
*/
break;
case 491:
// SANDRO - I've been here, messing with stuff...
// CODE: HANDLE RANDOM BREATH ANIMATION
//if ( pSoldier->stats.bLife > INJURED_CHANGE_THREASHOLD )
if ( pSoldier->stats.bLife >= OKLIFE )
{
// Increment time from last update
pSoldier->uiTimeOfLastRandomAction++;
if ( pSoldier->uiTimeOfLastRandomAction > TIME_FOR_RANDOM_ANIM_CHECK || pSoldier->stats.bLife < INJURED_CHANGE_THREASHOLD || GetDrunkLevel( pSoldier ) >= BORDERLINE )
{
pSoldier->uiTimeOfLastRandomAction = 0;
// Don't play these generally if this is the guy selected by player, as this one is "awaiting orders"
if (pSoldier->ubID != gusSelectedSoldier || Random( 10 ) == 0 )
{
// Don't do any in water!
// Also don't play if we are in the middle of something
if ( !pSoldier->MercInWater( ) && !pSoldier->flags.fTurningUntilDone )
{
// OK, make a dice roll
ubDiceRoll = (UINT8)Random( 100 );
// Determine what is in our hand;
usItem = pSoldier->inv[ HANDPOS ].usItem;
// Default to nothing in hand ( nothing in quotes, we do have something but not just visible )
ubRandomHandIndex = RANDOM_ANIM_NOTHINGINHAND;
if ( pSoldier->inv[ HANDPOS ].exists() == true )
{
if ( Item[ usItem ].usItemClass == IC_GUN )
{
// if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) )
if (ItemIsTwoHanded(usItem))
{
// Set to rifle
ubRandomHandIndex = RANDOM_ANIM_RIFLEINHAND;
}
//else
//{
// // Don't EVER do a trivial anim...
// break;
// ubRandomHandIndex = RANDOM_ANIM_NOTHINGORPISTOLINHAND;
//}
}
}
// Check which animation to play....
for ( cnt = 0; cnt < MAX_RANDOM_ANIMS_PER_BODYTYPE; cnt++ )
{
pAnimDef = &( gRandomAnimDefs[ pSoldier->ubBodyType ][ cnt ] );
if ( pAnimDef->sAnimID != 0 )
{
BOOLEAN fStarving = FALSE;
UINT8 foodsituation;
UINT8 watersituation;
GetFoodSituation( pSoldier, &foodsituation, &watersituation );
if ( foodsituation >= FOOD_VERY_LOW || watersituation >= FOOD_VERY_LOW )
fStarving = TRUE;
// If it's an injured animation and we are not in the threashold....
if ( ( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && pSoldier->stats.bLife >= INJURED_CHANGE_THREASHOLD && !fStarving )
{
continue;
}
// If we need to do an injured one, don't do any others...
if ( !( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && (pSoldier->stats.bLife < INJURED_CHANGE_THREASHOLD || fStarving) )
{
continue;
}
// If it's a drunk animation and we are not in the threashold....
if ( ( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && GetDrunkLevel( pSoldier ) < BORDERLINE && !fStarving )
{
continue;
}
// If we need to do an injured one, don't do any others...
if ( !( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && (GetDrunkLevel( pSoldier ) >= BORDERLINE || fStarving) )
{
continue;
}
// Check if it's our hand
/*if ( pAnimDef->ubHandRestriction != RANDOM_ANIM_IRRELEVENTINHAND && pAnimDef->ubHandRestriction != ubRandomHandIndex )
{
continue;
}*/
// Don't do this if a pistol in hand
if ( ubRandomHandIndex == RANDOM_ANIM_RIFLEINHAND && pAnimDef->sAnimID == BIGGUY_STONE )
{
continue;
}
// Check if it's casual and we're in combat and it's not our guy
if ( ( pAnimDef->ubFlags & RANDOM_ANIM_CASUAL ) )
{
// If he's a bad guy, do not do it!
if ( pSoldier->bTeam != gbPlayerNum || ( gTacticalStatus.uiFlags & INCOMBAT ) )
{
continue;
}
}
// If it is lookaround animation, don't play it if we see at least one enemy
if ( pAnimDef->ubFlags & RANDOM_ANIM_LOOKAROUND )
{
// enemy on sight, don't pretend we don't see him!
if ( pSoldier->aiData.bOppCnt > 0 )
{
continue;
}
}
// If it is lookaround animation, don't play it if we see at least one enemy
if ( pAnimDef->ubFlags & RANDOM_ANIM_SHOWOFF )
{
// enemy on sight, don't pretend we don't see him!
if ( pSoldier->ubProfile != NO_PROFILE )
{
if ( Random( 10 ) < 9 && !DoesMercHavePersonality( pSoldier, CHAR_TRAIT_SHOWOFF ) )
{
continue;
}
}
else
{
if ( Random( 10 ) < 7 )
{
continue;
}
}
}
// If we are an alternate big guy and have been told to use a normal big merc ani...
//if ( ( pAnimDef->ubFlags & RANDOM_ANIM_FIRSTBIGMERC ) && ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) )
if ( ( pAnimDef->ubFlags & RANDOM_ANIM_FIRSTBIGMERC ) && !( DecideAltAnimForBigMerc( pSoldier )) )
{
continue;
}
// If we are a normal big guy and have been told to use an alternate big merc ani...
//if ( ( pAnimDef->ubFlags & RANDOM_ANIM_SECONDBIGMERC ) && !( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) )
if ( ( pAnimDef->ubFlags & RANDOM_ANIM_SECONDBIGMERC ) && ( DecideAltAnimForBigMerc( pSoldier )) )
{
continue;
}
// Check if it's the proper height
if ( pAnimDef->ubAnimHeight == gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
{
// OK, If we rolled a value that lies within the range for this random animation, use this one!
if ( ubDiceRoll >= pAnimDef->ubStartRoll && ubDiceRoll <= pAnimDef->ubEndRoll )
{
// Are we playing a sound
if ( pAnimDef->sAnimID == RANDOM_ANIM_SOUND )
{
if ( pSoldier->ubBodyType == COW )
{
if ( Random( 10 ) == 1 )
{
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) && pSoldier->bVisible == -1 )
{
// DO this every 10th time or so...
if ( Random( 100 ) < 10 )
{
// Play sound
if (pSoldier->bVisible == TRUE || TeamMemberNear(gbPlayerNum, pSoldier->sGridNo, TACTICAL_RANGE))
PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
else
{
// Play sound
if (pSoldier->bVisible == TRUE || TeamMemberNear(gbPlayerNum, pSoldier->sGridNo, TACTICAL_RANGE))
PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
}
else if ( pSoldier->ubBodyType == CROW )
{
if ( Random( 4 ) == 1 )
{
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) && pSoldier->bVisible == -1 )
{
// DO this every 10th time or so...
if ( Random( 100 ) < 10 )
{
// Play sound
if (pSoldier->bVisible == TRUE || TeamMemberNear(gbPlayerNum, pSoldier->sGridNo, TACTICAL_RANGE))
PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
else
{
// Play sound
if (pSoldier->bVisible == TRUE || TeamMemberNear(gbPlayerNum, pSoldier->sGridNo, TACTICAL_RANGE))
PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
}
else
{
// Play sound
if (pSoldier->bVisible == TRUE || TeamMemberNear(gbPlayerNum, pSoldier->sGridNo, TACTICAL_RANGE))
PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
else
{
if ( pAnimDef->ubHandRestriction != RANDOM_ANIM_IRRELEVENTINHAND && pAnimDef->ubHandRestriction != ubRandomHandIndex )
{
// only if we are told to play an anim without rifle and we have a rifle (we can lower it for an instance), not vice versa
if ( pAnimDef->ubHandRestriction == RANDOM_ANIM_RIFLEINHAND && ubRandomHandIndex != RANDOM_ANIM_RIFLEINHAND )
{
continue;
}
// this is not for enemy fools, only for cool mercs
if ( pSoldier->bTeam != gbPlayerNum )
{
continue;
}
// these funny moves are not likely to be used in combat
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
{
if ( pSoldier->aiData.bMorale < 95 ) // .. unless we are really confident about ourselves
{
continue;
}
else
{
if ( Random( 2 ) == 1 ) // even if we are, still make them show seldomly
continue;
}
}
if ( Random( 4 ) == 1 ) // make this rare as we need to lower the weapon -> make the move -> raise the weapon again... rather show off
{
continue;
}
}
// generally make funny moves less common in combat, we need to focus!
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) && !( pAnimDef->ubFlags & ( RANDOM_ANIM_INJURED )) && !( pAnimDef->ubFlags & ( RANDOM_ANIM_DRUNK )) && !( pAnimDef->ubFlags & ( RANDOM_ANIM_LOOKAROUND )) )
{
if ( Random( 3 ) == 1 )
continue;
}
// finally if we got here, send state change
pSoldier->ChangeSoldierState( pAnimDef->sAnimID, 0 , FALSE );
}
return( TRUE );
}
}
}
}
}
}
}
}
break;
case 492:
// SIGNAL DODGE!
// ATE: Only do if we're not inspecial case...
if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_NPC_DOING_PUNCH ) )
{
SOLDIERTYPE *pTSoldier;
UINT32 uiMercFlags;
SoldierID usSoldierIndex;
if ( FindSoldier( pSoldier->sTargetGridNo, &usSoldierIndex, &uiMercFlags, FIND_SOLDIER_GRIDNO ) )
{
GetSoldier( &pTSoldier, usSoldierIndex );
// IF WE ARE AN ANIMAL, CAR, MONSTER, DONT'T DODGE
if ( IS_MERC_BODY_TYPE( pTSoldier ) )
{
// ONLY DODGE IF WE ARE SEEN
if ( pTSoldier->aiData.bOppList[ pSoldier->ubID ] != 0 || pTSoldier->bTeam == pSoldier->bTeam )
{
if ( gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND )
{
// OK, stop merc....
pTSoldier->EVENT_StopMerc( pTSoldier->sGridNo, pTSoldier->ubDirection );
if ( pTSoldier->bTeam != gbPlayerNum )
{
DebugAI(AI_MSG_INFO, pTSoldier, String("CancelAIAction: dodge"));
CancelAIAction( pTSoldier, TRUE );
}
// SANDRO - Set goback to aim after hit flag
if (( Item[ pTSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_BLADE | IC_PUNCH | IC_NONE) ) && pTSoldier->stats.bLife > 30 && pTSoldier->bBreath > 25 && (gAnimControl[ pTSoldier->usAnimState ].ubEndHeight == ANIM_STAND) )
{
if ( pTSoldier->stats.bLife > 30 && pTSoldier->bBreath > 25 )
{
pTSoldier->flags.bGoBackToAimAfterHit = GO_TO_HTH_BREATH_AFTER_HIT;
}
}
// If we were aiming
// actually no... favor htH a bit more, by making the opponent drop his readied stance when attacked in close combat, regardless he will dodge it or not
//else if ( gAnimControl[ pTSoldier->usAnimState ].uiFlags & ANIM_FIREREADY )
//{
// if ( gAnimControl[ pTSoldier->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING ) // alternative weapon holding stance
// pTSoldier->flags.bGoBackToAimAfterHit = GO_TO_ALTERNATIVE_AIM_AFTER_HIT;
// else // standard
// pTSoldier->flags.bGoBackToAimAfterHit = GO_TO_AIM_AFTER_HIT;
//}
// if we were cowering (this is different from the bellow, we don't use that status flag for this animation)
else if ( pTSoldier->usAnimState == COWERING )
{
pTSoldier->flags.bGoBackToAimAfterHit = GO_TO_COWERING_AFTER_HIT;
}
else
{
pTSoldier->flags.bGoBackToAimAfterHit = NO_SPEC_STANCE_AFTER_HIT;
}
// Turn towards the person!
pTSoldier->EVENT_SetSoldierDesiredDirection( GetDirectionFromGridNo( pSoldier->sGridNo, pTSoldier ) );
// PLAY SOLDIER'S DODGE ANIMATION
pTSoldier->ChangeSoldierState( DODGE_ONE, 0 , FALSE );
// SANDRO - after dodging melee attack go to apropriate stance
//if ( (gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND) && pTSoldier->stats.bLife > 30 && pTSoldier->bBreath > 25 && (Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_PUNCH || Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_NONE))
//{
// if ((((NUM_SKILL_TRAITS( pTSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) ||
// (HAS_SKILL_TRAIT( pTSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) &&
// pTSoldier->ubBodyType == REGMALE )
// {
// //pTSoldier->usPendingAnimation = NINJA_GOTOBREATH;
// pTSoldier->usPendingAnimation = NINJA_BREATH ;
// }
// else
// {
// pTSoldier->usPendingAnimation = PUNCH_BREATH ;
// }
//}
//else if ( (gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND) && pTSoldier->stats.bLife > 30 && pTSoldier->bBreath > 25 && (Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE))
//{
// //pTSoldier->usPendingAnimation = KNIFE_GOTOBREATH;
// pTSoldier->usPendingAnimation = KNIFE_BREATH ;
//}
}
}
}
}
}
break;
case 493:
//CODE: PICKUP ITEM!
// CHECK IF THIS EVENT HAS BEEN SETUP
//if ( pSoldier->aiData.ubPendingAction == MERC_PICKUPITEM )
//{
// DROP ITEM
HandleSoldierPickupItem( pSoldier, pSoldier->aiData.uiPendingActionData1, pSoldier->aiData.uiPendingActionData4, pSoldier->aiData.bPendingActionData3 );
// EVENT HAS BEEN HANDLED
pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION;
//}
//else
//{
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: CODE 493 Error, Pickup item action called but not setup" );
//}
break;
case 494:
//CODE: OPEN STRUCT!
// CHECK IF THIS EVENT HAS BEEN SETUP
//if ( pSoldier->aiData.ubPendingAction == MERC_OPENSTRUCT )
//{
SoldierHandleInteractiveObject( pSoldier );
// EVENT HAS BEEN HANDLED
pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION;
//}
//else
//{
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: CODE 494 Error, OPen door action called but not setup" );
//}
break;
case 495:
if (pSoldier->aiData.bAction == AI_ACTION_UNLOCK_DOOR || (pSoldier->aiData.bAction == AI_ACTION_LOCK_DOOR && !(pSoldier->aiData.fAIFlags & AI_LOCK_DOOR_INCLUDES_CLOSE) ) )
{
// EVENT HAS BEEN HANDLED
pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION;
// do nothing here
}
else
{
pSoldier->aiData.fAIFlags &= ~(AI_LOCK_DOOR_INCLUDES_CLOSE);
pSoldier->ubDoorOpeningNoise = DoorOpeningNoise( pSoldier );
if ( SoldierHandleInteractiveObject( pSoldier ) )
{
// HANDLE SIGHT!
HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT );
InitOpplistForDoorOpening();
//shadooow: this has been moved inside HandleDoorsOpenClose
//MakeNoise( pSoldier->ubID, pSoldier->aiData.sPendingActionData2, pSoldier->pathing.bLevel, gpWorldLevelData[pSoldier->sGridNo].ubTerrainID, pSoldier->ubDoorOpeningNoise, NOISE_CREAKING );
// gfDelayResolvingBestSighting = FALSE;
gubInterruptProvoker = pSoldier->ubID;
AllTeamsLookForAll( TRUE );
// ATE: Now, check AI guy to cancel what he was going....
HandleSystemNewAISituation( pSoldier, TRUE );
}
// EVENT HAS BEEN HANDLED
pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION;
}
break;
case 496:
// CODE: GOTO PREVIOUS ANIMATION
pSoldier->ChangeSoldierState( pSoldier->usOldAniState, pSoldier->sOldAniCode, FALSE );
return( TRUE );
case 497:
// CODE: CHECK FOR UNCONSCIOUS OR DEATH
// IF 496 - GOTO PREVIOUS ANIMATION, OTHERWISE PAUSE ANIMATION
if ( pSoldier->stats.bLife == 0 )
{
//HandleSoldierDeath( pSoldier );
// If guy is now dead, and we have not played death sound before, play
if ( pSoldier->stats.bLife == 0 && !pSoldier->flags.fDeadSoundPlayed )
{
if ( pSoldier->usAnimState != JFK_HITDEATH )
{
pSoldier->DoMercBattleSound( BATTLE_SOUND_DIE1 );
pSoldier->flags.fDeadSoundPlayed = TRUE;
}
}
if ( pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_CRYO] && pSoldier->usAnimState != CRYO_DEATH && pSoldier->usAnimState != CRYO_DEATH_CROUCHED )
{
if ( gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_STAND )
pSoldier->ChangeSoldierState( CRYO_DEATH, 0, TRUE );
else
pSoldier->ChangeSoldierState( CRYO_DEATH_CROUCHED, 0, TRUE );
}
else if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] )
{
// If we are dead, play some death animations!!
switch( pSoldier->usAnimState )
{
case FLYBACK_HIT:
pSoldier->ChangeSoldierState( FLYBACK_HIT_DEATH, 0, FALSE );
break;
case GENERIC_HIT_DEATHTWITCHNB:
case FALLFORWARD_FROMHIT_STAND:
case ENDFALLFORWARD_FROMHIT_CROUCH:
pSoldier->ChangeSoldierState( GENERIC_HIT_DEATH, 0, FALSE );
break;
case FALLBACK_HIT_DEATHTWITCHNB:
case FALLBACK_HIT_STAND:
pSoldier->ChangeSoldierState( FALLBACK_HIT_DEATH, 0, FALSE );
break;
case PRONE_HIT_DEATHTWITCHNB:
case PRONE_LAY_FROMHIT:
pSoldier->ChangeSoldierState( PRONE_HIT_DEATH, 0, FALSE );
break;
case FALLOFF:
pSoldier->ChangeSoldierState( FALLOFF_DEATH, 0, FALSE );
break;
case FALLFORWARD_ROOF:
pSoldier->ChangeSoldierState( FALLOFF_FORWARD_DEATH, 0, FALSE);
break;
case ADULTMONSTER_DYING:
pSoldier->ChangeSoldierState( ADULTMONSTER_DYING_STOP, 0, FALSE);
break;
case LARVAE_DIE:
pSoldier->ChangeSoldierState( LARVAE_DIE_STOP, 0, FALSE);
break;
case QUEEN_DIE:
pSoldier->ChangeSoldierState( QUEEN_DIE_STOP, 0, FALSE);
break;
case INFANT_DIE:
pSoldier->ChangeSoldierState( INFANT_DIE_STOP, 0, FALSE);
break;
case CRIPPLE_DIE:
pSoldier->ChangeSoldierState( CRIPPLE_DIE_STOP, 0, FALSE);
break;
case ROBOTNW_DIE:
pSoldier->ChangeSoldierState( ROBOTNW_DIE_STOP, 0, FALSE);
break;
case CRIPPLE_DIE_FLYBACK:
pSoldier->ChangeSoldierState( CRIPPLE_DIE_FLYBACK_STOP, 0, FALSE);
break;
default:
// IF we are here - something is wrong - we should have a death animation here
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Ani: Death sequence needed for animation %d", pSoldier->usAnimState ) );
}
}
else
{
BOOLEAN fMadeCorpse;
CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse );
// ATE: Needs to be FALSE!
return( FALSE );
}
return( TRUE );
}
else
{
// We can safely be here as well.. ( ie - next turn we may be able to get up )
// DO SOME CHECKS HERE TO FREE UP ATTACKERS IF WE ARE WAITING AT SPECIFIC ANIMATIONS
if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_HITFINISH ) )
{
gfPotentialTeamChangeDuringDeath = TRUE;
// 0verhaul: This is now already handled
// Release attacker
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, code 497 = check for death") );
// ReleaseSoldiersAttacker( pSoldier );
// ATE: OK - the above call can potentially
// render the soldier bactive to false - check heare
if ( !pSoldier->bActive )
{
return( FALSE );
}
gfPotentialTeamChangeDuringDeath = FALSE;
// FREEUP GETTING HIT FLAG
pSoldier->flags.fGettingHit = FALSE;
}
HandleCheckForDeathCommonCode( pSoldier );
return( TRUE );
}
break;
case 498:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SANDRO - if pending interrupt flag was set for before-attack type of interupt, try to resolve it now
if ( UsingImprovedInterruptSystem() )
{
if ( ResolvePendingInterrupt( pSoldier, BEFORESHOT_INTERRUPT ) )
{
if ( pSoldier->flags.fTurningToShoot )
pSoldier->flags.fTurningToShoot = FALSE;
pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
pSoldier->ubPendingDirection = NO_PENDING_DIRECTION;
// "artificially" set lock ui flag in this case
if (pSoldier->bTeam == gbPlayerNum)
{
//AddTopMessage( COMPUTER_INTERRUPT_MESSAGE, Message[STR_INTERRUPT] );
guiPendingOverrideEvent = LU_BEGINUILOCK;
HandleTacticalUI( );
}
return( TRUE );
break;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CONDITONAL JUMP
// If we have a pending animation, play it, else continue
if ( pSoldier->usPendingAnimation != NO_PENDING_ANIMATION )
{
pSoldier->ChangeSoldierState( pSoldier->usPendingAnimation, 0, FALSE );
pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
return( TRUE );
}
break;
// JUMP TO NEXT STATIONARY ANIMATION ACCORDING TO HEIGHT
case 499:
if (!(pSoldier->flags.uiStatusFlags & SOLDIER_PC))
{
if ( pSoldier->aiData.bAction == AI_ACTION_PULL_TRIGGER )
{
if ( pSoldier->usAnimState == AI_PULL_SWITCH && gTacticalStatus.ubAttackBusyCount == 0 && gubElementsOnExplosionQueue == 0 )
{
FreeUpNPCFromPendingAction( pSoldier );
}
}
else if ( pSoldier->aiData.bAction == AI_ACTION_PENDING_ACTION
|| pSoldier->aiData.bAction == AI_ACTION_OPEN_OR_CLOSE_DOOR
|| pSoldier->aiData.bAction == AI_ACTION_YELLOW_ALERT
|| pSoldier->aiData.bAction == AI_ACTION_RED_ALERT
|| pSoldier->aiData.bAction == AI_ACTION_PULL_TRIGGER
|| pSoldier->aiData.bAction == AI_ACTION_CREATURE_CALL
|| pSoldier->aiData.bAction == AI_ACTION_UNLOCK_DOOR
|| pSoldier->aiData.bAction == AI_ACTION_LOCK_DOOR )
{
if ( pSoldier->usAnimState == PICKUP_ITEM || pSoldier->usAnimState == ADJACENT_GET_ITEM || pSoldier->usAnimState == ADJACENT_GET_ITEM_CROUCHED || pSoldier->usAnimState == DROP_ITEM || pSoldier->usAnimState == END_OPEN_DOOR || pSoldier->usAnimState == END_OPEN_DOOR_CROUCHED || pSoldier->usAnimState == CLOSE_DOOR || pSoldier->usAnimState == MONSTER_UP || pSoldier->usAnimState == AI_RADIO || pSoldier->usAnimState == AI_CR_RADIO || pSoldier->usAnimState == END_OPENSTRUCT || pSoldier->usAnimState == END_OPENSTRUCT_CROUCHED || pSoldier->usAnimState == QUEEN_CALL )
{
FreeUpNPCFromPendingAction( pSoldier );
}
}
}
ubDesiredHeight = pSoldier->ubDesiredHeight;
// Check if we are at the desired height
if ( pSoldier->ubDesiredHeight == gAnimControl[ pSoldier->usAnimState ].ubEndHeight || pSoldier->ubDesiredHeight == NO_DESIRED_HEIGHT )
{
// Adjust movement mode......
if ( pSoldier->bTeam == gbPlayerNum && !pSoldier->flags.fContinueMoveAfterStanceChange )
{
usUIMovementMode = pSoldier->GetMoveStateBasedOnStance( gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
// ATE: if we are currently running but have been told to walk, don't!
if ( pSoldier->usUIMovementMode == RUNNING && usUIMovementMode == WALKING )
{
// No!
}
else
{
pSoldier->usUIMovementMode = usUIMovementMode;
}
}
if (pSoldier->usAnimState == DODGE_ONE && pSoldier->usPendingAnimation == NO_PENDING_ANIMATION )
{
INT8 bGoBackToAimAfterHit = pSoldier->flags.bGoBackToAimAfterHit;
pSoldier->flags.bGoBackToAimAfterHit = NO_SPEC_STANCE_AFTER_HIT;
// CODE: HANDLE ANY RANDOM HIT VARIATIONS WE WISH TO DO.....
if ( pSoldier->stats.bLife >= OKLIFE && bGoBackToAimAfterHit )
{
if ( bGoBackToAimAfterHit == GO_TO_AIM_AFTER_HIT )
{
pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, FALSE, FALSE );
}
else if ( bGoBackToAimAfterHit == GO_TO_ALTERNATIVE_AIM_AFTER_HIT && (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND) )
{
pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, FALSE, TRUE );
}
else if ( bGoBackToAimAfterHit == GO_TO_HTH_BREATH_AFTER_HIT && (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND))
{
if ( Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_NONE | IC_PUNCH) )
{
if ((((NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) ||
(HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && pSoldier->ubBodyType == REGMALE )
{
if(is_networked)
pSoldier->ChangeSoldierState( NINJA_BREATH, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( NINJA_BREATH, 0 , FALSE );
}
else
{
if(is_networked)
pSoldier->ChangeSoldierState( PUNCH_BREATH, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( PUNCH_BREATH, 0 , FALSE );
}
}
else if ( Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_BLADE) )
{
if(is_networked)
pSoldier->ChangeSoldierState( KNIFE_BREATH, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( KNIFE_BREATH, 0 , FALSE );
}
}
else if ( bGoBackToAimAfterHit == GO_TO_COWERING_AFTER_HIT )
{
if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH)
{
if(is_networked)
pSoldier->ChangeSoldierState( START_COWER_CROUCHED, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( START_COWER_CROUCHED, 0 , FALSE );
}
else if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)
{
if(is_networked)
pSoldier->ChangeSoldierState( START_COWER_PRONE, 0 , FALSE );
else
pSoldier->EVENT_InitNewSoldierAnim( START_COWER_PRONE, 0 , FALSE );
}
}
return( TRUE );
}
}
pSoldier->ubDesiredHeight = NO_DESIRED_HEIGHT;
// 0verhaul: This is moved to the animation state transition code to make sure it isn't sidestepped.
// if (pSoldier->flags.fChangingStanceDueToSuppression)
// {
// pSoldier->flags.fChangingStanceDueToSuppression = FALSE;
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - end of suppression stance change") );
// ReduceAttackBusyCount( pSoldier->ubSuppressorID, FALSE );
// }
if ( pSoldier->usPendingAnimation == NO_PENDING_ANIMATION &&
( pSoldier->flags.bTurningFromPronePosition != TURNING_FROM_PRONE_ENDING_UP_FROM_MOVE ) &&
( pSoldier->flags.bTurningFromPronePosition != TURNING_FROM_PRONE_ON ) )
{
if ( gTacticalStatus.ubAttackBusyCount == 0 )
{
// OK, UNSET INTERFACE FIRST
UnSetUIBusy( pSoldier->ubID );
// ( before we could get interrupted potentially by an interrupt )
}
}
// Check to see if we have changed stance and need to update visibility
if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_STANCECHANGEANIM)
{
if ( pSoldier->usPendingAnimation == NO_PENDING_ANIMATION &&
gTacticalStatus.ubAttackBusyCount == 0 &&
pSoldier->flags.bTurningFromPronePosition != TURNING_FROM_PRONE_ENDING_UP_FROM_MOVE &&
pSoldier->flags.bTurningFromPronePosition != TURNING_FROM_PRONE_ON )
{
HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT );
}
else
{
HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO );
}
// Keep ui busy if we are now in a hidden interrupt
// say we're prone and we crouch, we may get a hidden
// interrupt and in such a case we'd really like the UI
// still locked
if ( gfHiddenInterrupt )
{
guiPendingOverrideEvent = LA_BEGINUIOURTURNLOCK;
HandleTacticalUI( );
}
// ATE: Now, check AI guy to cancel what he was going....
HandleSystemNewAISituation( pSoldier, TRUE );
// sevenfm: update tree visibility after changing stance
if (//pSoldier->bVisible != -1 &&
pSoldier->bTeam != OUR_TEAM &&
(pSoldier->bTeam != MILITIA_TEAM || !gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa))
UpdateTreeVisibility();
}
// Have we finished opening doors?
// 0verhaul: Added additional check: Are we told to stop at this point, maybe due to being interrupted?
if ( !pSoldier->flags.fNoAPToFinishMove &&
(pSoldier->usAnimState == END_OPEN_DOOR ||
pSoldier->usAnimState == END_OPEN_DOOR_CROUCHED ||
pSoldier->usAnimState == CRIPPLE_CLOSE_DOOR ||
pSoldier->usAnimState == CRIPPLE_END_OPEN_DOOR ) )
{
// Are we told to continue movement...?
if ( pSoldier->bEndDoorOpenCode == 1 )
{
// OK, set this value to 2 such that once we are into a new gridno,
// we close the door!
pSoldier->bEndDoorOpenCode = 2;
// yes..
pSoldier->EVENT_GetNewSoldierPath( pSoldier->pathing.sFinalDestination, pSoldier->usUIMovementMode );
if ( !( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_MOVING ) ) )
{
if (!TileIsOutOfBounds(pSoldier->sAbsoluteFinalDestination))
{
DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: end door open code"));
CancelAIAction( pSoldier, FORCE );
}
}
// OK, this code, pSoldier->bEndDoorOpenCode will be set to 0 if anythiing
// cuases guy to stop - StopMerc() will set it...
return( TRUE );
}
}
// Check if we should contine into a moving animation
if ( pSoldier->usPendingAnimation != NO_PENDING_ANIMATION )
{
UINT16 usPendingAnimation = pSoldier->usPendingAnimation;
pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
pSoldier->ChangeSoldierState( usPendingAnimation, 0, FALSE );
return( TRUE );
}
// Alrighty, do we wish to continue
if ( pSoldier->flags.fContinueMoveAfterStanceChange )
{
// OK, if the code is == 2, get the path and try to move....
if ( pSoldier->flags.fContinueMoveAfterStanceChange == 2 )
{
pSoldier->pathing.usPathIndex++;
if ( pSoldier->pathing.usPathIndex > pSoldier->pathing.usPathDataSize )
{
pSoldier->pathing.usPathIndex = pSoldier->pathing.usPathDataSize;
}
if ( pSoldier->pathing.usPathIndex == pSoldier->pathing.usPathDataSize )
{
// Stop, don't do anything.....
// 0verhaul: Only if not at the final destination
// Another reason for rebuilding the animation system. This should be part of a common
// path continuation code so that any other bug fixes won't need to be duplicated in other areas.
if ( pSoldier->sGridNo != pSoldier->pathing.sFinalDestination)
{
if ( !pSoldier->EVENT_InternalGetNewSoldierPath( pSoldier->pathing.sFinalDestination, pSoldier->usUIMovementMode, 2, FALSE ) )
{
}
}
}
else
{
pSoldier->EVENT_InitNewSoldierAnim( pSoldier->usUIMovementMode, 0 , FALSE );
// UNSET LOCK PENDING ACTION COUNTER FLAG
pSoldier->flags.uiStatusFlags &= ( ~SOLDIER_LOCKPENDINGACTIONCOUNTER );
}
}
else
{
SelectMoveAnimationFromStance( pSoldier );
}
pSoldier->flags.fContinueMoveAfterStanceChange = FALSE;
return( TRUE );
}
pSoldier->SoldierGotoStationaryStance( );
return( TRUE );
}
else
{
ubCurrentHeight = gAnimControl[ pSoldier->usAnimState ].ubEndHeight;
// We need to go more, continue
if ( ubDesiredHeight == ANIM_STAND && ubCurrentHeight == ANIM_CROUCH )
{
// Return here because if now, we will skipp a few frames
pSoldier->ChangeSoldierState( KNEEL_UP, 0 , FALSE );
return( TRUE );
}
if ( ubDesiredHeight == ANIM_CROUCH && ubCurrentHeight == ANIM_STAND )
{
// Return here because if now, we will skipp a few frames
pSoldier->ChangeSoldierState( KNEEL_DOWN, 0 , FALSE );
return( TRUE );
}
else if ( ubDesiredHeight == ANIM_PRONE && ubCurrentHeight == ANIM_CROUCH )
{
// Return here because if now, we will skipp a few frames
pSoldier->ChangeSoldierState( PRONE_DOWN, 0 , FALSE );
return( TRUE );
}
else if ( ubDesiredHeight == ANIM_CROUCH && ubCurrentHeight == ANIM_PRONE )
{
// Return here because if now, we will skipp a few frames
pSoldier->ChangeSoldierState( PRONE_UP, 0 , FALSE );
return( TRUE );
}
}
// IF we are here - something is wrong - we should have a death animation here
#ifdef JA2BETAVERSION
ScreenMsg( FONT_ORANGE, MSG_BETAVERSION, L"Soldier Ani: GOTO Stance not chained properly: %d %d %d", ubDesiredHeight, ubCurrentHeight, pSoldier->usAnimState );
#endif
pSoldier->SoldierGotoStationaryStance( );
return( TRUE );
}
// Adjust frame control pos, and try again
pSoldier->usAniCode++;
}
else if ( sNewAniFrame > 499 && sNewAniFrame < 599 )
{
// Jump,
// Do not adjust, just try again
pSoldier->usAniCode = sNewAniFrame - 501;
}
else if ( sNewAniFrame > 599 && sNewAniFrame <= 699 )
{
// SANDRO - added some hacking in here, so I don't need to overwrite all those animation frame scripts
switch(pSoldier->usAnimState)
{
// go to apropriate stance for alternative weapon holding
case READY_ALTERNATIVE_STAND:
case SHOOT_ALTERNATIVE_STAND:
case BURST_ALTERNATIVE_STAND:
case LOW_SHOT_ALTERNATIVE_STAND:
case LOW_BURST_ALTERNATIVE_STAND:
pSoldier->EVENT_InitNewSoldierAnim( AIM_ALTERNATIVE_STAND, 0 , FALSE );
return( TRUE );
break;
// hack to raise rifle after using idle animation without one in hand
case REG_SQUISH:
case REG_PULL:
case BIGBUY_FLEX:
case BIGBUY_STRECH:
case FEM_KICKSN:
case FEM_WIPE:
if ( pSoldier->inv[ HANDPOS ].exists() == true && Item[ pSoldier->inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && ItemIsTwoHanded(pSoldier->inv[ HANDPOS ].usItem) )
{
pSoldier->EVENT_InitNewSoldierAnim( RAISE_RIFLE, 0 , FALSE );
return( TRUE );
}
break;
default:
break;
}
// Jump, to animation script
pSoldier->EVENT_InitNewSoldierAnim( (UINT16)(sNewAniFrame - 600 ), 0 , FALSE );
return( TRUE );
}
else if ( sNewAniFrame > 799 && sNewAniFrame <= 899 )
{
// Jump, to animation script ( But in the 100's range )
pSoldier->EVENT_InitNewSoldierAnim( (UINT16)(sNewAniFrame - 700 ), 0 , FALSE );
return( TRUE );
}
else if ( sNewAniFrame > 899 && sNewAniFrame <= 999 )
{
// Jump, to animation script ( But in the 200's range )
pSoldier->EVENT_InitNewSoldierAnim( (UINT16)(sNewAniFrame - 700 ), 0 , FALSE );
return( TRUE );
}
else if ( sNewAniFrame > 699 && sNewAniFrame < 799 )
{
switch( sNewAniFrame )
{
case 702:
// Play fall to knees sound
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( FALL_1 + Random(2) ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE );
break;
case 703:
case 704:
// Play footprints
PlaySoldierFootstepSound( pSoldier );
break;
case 705:
// PLay body splat sound
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)BODY_SPLAT_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 706:
// PLay head splat
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)HEADSPLAT_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) , TRUE );
break;
case 707:
// PLay creature battle cry
PlayJA2StreamingSample( (UINT8)CREATURE_BATTLECRY_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
break;
case 708:
// PLay lock n' load sound for gun....
// Get LNL sound for current gun
{
UINT16 usItem;
UINT16 usSoundID;
usItem = pSoldier->inv[ HANDPOS ].usItem;
OBJECTTYPE* pObjUsed = pSoldier->GetUsedWeapon( &pSoldier->inv[ HANDPOS ] );
UINT16 usItemUsemUsed = pSoldier->GetUsedWeaponNumber( &pSoldier->inv[ HANDPOS ] );
if ( pObjUsed->exists() == true )
{
usSoundID = Weapon[ usItemUsemUsed ].sLocknLoadSound;
if ( usSoundID != 0 )
{
if (pSoldier->bVisible == TRUE || TeamMemberNear(gbPlayerNum, pSoldier->sGridNo, TACTICAL_RANGE))
PlayJA2Sample( usSoundID, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
}
break;
case 709:
// Knife throw sound...
// anv: possiblity to use custom sounds for throwing knives
{
UINT16 usedWeapon = pSoldier->GetUsedWeaponNumber( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
if ( Weapon[ usedWeapon ].sSound != 0 )
{
PlayJA2Sample( Weapon[ usedWeapon ].sSound, 44100-Random(5000)-Random(5000)-Random(5000), SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
else
{
PlayJA2Sample( Weapon[ THROWING_KNIFE ].sSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
break;
case 710:
// Monster footstep in
if ( SoldierOnScreen( pSoldier->ubID ) )
{
PlaySoldierJA2Sample( pSoldier->ubID, ACR_STEP_1, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 711:
// Monster footstep in
if ( SoldierOnScreen( pSoldier->ubID ) )
{
PlaySoldierJA2Sample( pSoldier->ubID, ACR_STEP_2, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 712:
// Monster footstep in
if ( SoldierOnScreen( pSoldier->ubID ) )
{
PlaySoldierJA2Sample( pSoldier->ubID, LCR_MOVEMENT, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 713:
// Monster footstep in
if ( pSoldier->ubBodyType == INFANT_MONSTER )
{
if ( SoldierOnScreen( pSoldier->ubID ) )
{
PlaySoldierJA2Sample( pSoldier->ubID, BCR_DRAGGING, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
}
break;
case 714:
// Lunges....
PlaySoldierJA2Sample( pSoldier->ubID, ACR_LUNGE, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 715:
// Swipe
PlaySoldierJA2Sample( pSoldier->ubID, ACR_SWIPE, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 716:
// Eat flesh
PlaySoldierJA2Sample( pSoldier->ubID, ACR_EATFLESH, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 717:
// Battle cry
{
INT32 iSoundID=0;
BOOLEAN fDoCry = FALSE;
//if ( SoldierOnScreen( pSoldier->ubID ) )
{
switch( pSoldier->aiData.usActionData )
{
case CALL_1_PREY:
if ( pSoldier->ubBodyType == QUEENMONSTER )
{
iSoundID = LQ_SMELLS_THREAT;
}
else
{
iSoundID = ACR_SMEEL_PREY;
}
fDoCry = TRUE;
break;
case CALL_MULTIPLE_PREY:
if ( pSoldier->ubBodyType == QUEENMONSTER )
{
iSoundID = LQ_SMELLS_THREAT;
}
else
{
iSoundID = ACR_SMELL_THREAT;
}
fDoCry = TRUE;
break;
case CALL_ATTACKED:
if ( pSoldier->ubBodyType == QUEENMONSTER )
{
iSoundID = LQ_ENRAGED_ATTACK;
}
else
{
iSoundID = ACR_SMELL_THREAT;
}
fDoCry = TRUE;
break;
case CALL_CRIPPLED:
if ( pSoldier->ubBodyType == QUEENMONSTER )
{
iSoundID = LQ_CRIPPLED;
}
else
{
iSoundID = ACR_CRIPPLED;
}
fDoCry = TRUE;
break;
}
if ( fDoCry )
{
PlayJA2Sample( iSoundID, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
}
break;
case 718:
PlaySoldierJA2Sample( pSoldier->ubID, LQ_RUPTURING, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 719:
// Spit attack start sound...
PlaySoldierJA2Sample( pSoldier->ubID, LQ_ENRAGED_ATTACK, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 720:
// Spit attack start sound...
PlaySoldierJA2Sample( pSoldier->ubID, LQ_WHIP_ATTACK, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 721:
// Play fall from knees to ground...
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( FALL_TO_GROUND_1 + Random(3) ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE );
if ( pSoldier->usAnimState == FALLFORWARD_FROMHIT_STAND )
{
CheckEquipmentForFragileItemDamage( pSoldier, 20 );
}
break;
case 722:
// Play fall heavy
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( HEAVY_FALL_1 ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE );
if ( pSoldier->usAnimState == FALLFORWARD_FROMHIT_CROUCH )
{
CheckEquipmentForFragileItemDamage( pSoldier, 15 );
}
break;
case 723:
// Play armpit noise...
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( IDLE_ARMPIT ), RATE_11025, SoundVolume( LOWVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 724:
// Play ass scratch
// PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( IDLE_SCRATCH ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 725:
// Play back crack
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( IDLE_BACKCRACK ), RATE_11025, SoundVolume( LOWVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 726:
// Kickin door
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( KICKIN_DOOR ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 727:
// Swoosh
// anv: possiblity to use custom sounds for melee weapons
{
UINT16 usedWeapon = pSoldier->GetUsedWeaponNumber( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
if ( Weapon[ usedWeapon ].sSound != 0 )
{
PlayJA2Sample( Weapon[ usedWeapon ].sSound, 44100-Random(5000)-Random(5000)-Random(5000), SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
else
{
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( SWOOSH_1 + Random( 6 ) ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
// Flugente: play a little sound for melee attacks
if ( !usedWeapon || Item[usedWeapon].usItemClass & IC_PUNCH )
{
pSoldier->DoMercBattleSound( BATTLE_SOUND_PUNCH );
}
else if ( Item[usedWeapon].usItemClass & (IC_BLADE | IC_THROWING_KNIFE) )
{
pSoldier->DoMercBattleSound( BATTLE_SOUND_KNIFE );
}
}
break;
case 728:
// Creature fall
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( ACR_FALL_1 ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 729:
// grab roof....
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( GRAB_ROOF ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 730:
// end climb roof....
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( LAND_ON_ROOF ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 731:
// Stop climb roof..
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( FALL_TO_GROUND_1 + Random(3) ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 732:
// Play die sound
pSoldier->DoMercBattleSound( BATTLE_SOUND_DIE1 );
pSoldier->flags.fDeadSoundPlayed = TRUE;
break;
case 750:
// CODE: Move Vehicle UP
if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
// pSoldier->SetSoldierHeight( (FLOAT)( pSoldier->sHeightAdjustment + 1 ) );
}
break;
case 751:
// CODE: Move vehicle down
if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
// pSoldier->SetSoldierHeight( (FLOAT)( pSoldier->sHeightAdjustment - 1 ) );
}
break;
case 752:
// Code: decapitate
//DecapitateCorpse( pSoldier, pSoldier->sTargetGridNo, pSoldier->bTargetLevel );
// Flugente: instead of jsut decapitating, we call a selection window where we can choose what to do with the corpse
HandleSoldierUseCorpse( pSoldier, pSoldier->sTargetGridNo, pSoldier->bTargetLevel ); // Flugente: handle corpses
break;
case 753:
// code: freeup attcker
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count..., CODE FROM ANIMATION %s ( %d )", gAnimControl[ pSoldier->usAnimState ].zAnimStr, pSoldier->usAnimState ) );
DebugAttackBusy( String("@@@@@@@ Reducing attacker busy count..., CODE FROM ANIMATION %s ( %d )\n", gAnimControl[ pSoldier->usAnimState ].zAnimStr, pSoldier->usAnimState ) );
// ReduceAttackBusyCount( pSoldier->ubID, FALSE );
// ATE: Here, reduce again if creaturequeen tentical attack...
// Uh, why not add a second 753 code to the queen swipe instead of adding code to make things more complex?
if ( pSoldier->usAnimState == QUEEN_SWIPE )
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count for end of queen swipe\n" ) );
DebugAttackBusy( "@@@@@@@ Reducing attacker busy count for end of queen swipe" );
// ReduceAttackBusyCount( pSoldier->ubID, FALSE );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SANDRO - if pending interrupt flag was set for after-attack type of interupt, try to resolve it now
if ( UsingImprovedInterruptSystem() )
{
ResolvePendingInterrupt( pSoldier, AFTERACTION_INTERRUPT );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
break;
case 754:
HandleFallIntoPitFromAnimation( pSoldier->ubID );
break;
case 755 :
DishoutQueenSwipeDamage( pSoldier );
break;
case 756:
// Reload robot....
{
SoldierID ubPerson = WhoIsThere2( pSoldier->aiData.sPendingActionData2, pSoldier->pathing.bLevel );
if ( ubPerson != NOBODY && ubPerson->flags.uiStatusFlags & SOLDIER_ROBOT )
{
SOLDIERTYPE *pRobot = ubPerson;
ReloadGun( pRobot, &(pRobot->inv[ HANDPOS ] ), pSoldier->pTempObject );
// OK, check what was returned and place in inventory if it's non-zero
if ( pSoldier->pTempObject->exists() == true )
{
// Add to inv..
AutoPlaceObject( pSoldier, pSoldier->pTempObject, TRUE );
}
OBJECTTYPE::DeleteMe( &pSoldier->pTempObject );
}
}
break;
case 757:
// INcrement attacker busy count....
// gTacticalStatus.ubAttackBusyCount++;
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!! Incrementing attacker busy count..., CODE FROM ANIMATION %s ( %d ) : Count now %d", gAnimControl[ pSoldier->usAnimState ].zAnimStr, pSoldier->usAnimState, gTacticalStatus.ubAttackBusyCount ) );
DebugAttackBusy( String("!!!!! CODE FROM ANIMATION %s ( %d )\n", gAnimControl[ pSoldier->usAnimState ].zAnimStr, pSoldier->usAnimState ) );
break;
case 758:
// Trigger after slap...
TriggerNPCWithGivenApproach( QUEEN, APPROACH_DONE_SLAPPED , TRUE );
break;
case 759:
// Getting hit by slap
{
SOLDIERTYPE *pTarget;
pTarget = FindSoldierByProfileID( ELLIOT, FALSE );
if ( pTarget )
{
pTarget->EVENT_InitNewSoldierAnim( SLAP_HIT, 0 , FALSE );
// Play noise....
//PlaySoldierJA2Sample( pTarget->ubID, ( S_SLAP_IMPACT ), RATE_11025, SoundVolume( HIGHVOLUME, pTarget->sGridNo ), 1, SoundDir( pTarget->sGridNo ), TRUE );
//DoMercBattleSound( pTarget, (INT8)( BATTLE_SOUND_HIT1 + Random( 2 ) ) );
}
}
break;
case 760:
// Get some blood.....
// Corpse Id is from pending action data
GetBloodFromCorpse( pSoldier );
// Dirty interface....
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
break;
case 761:
{
// Dish out damage!
MercPtrs[ pSoldier->aiData.uiPendingActionData4 ]->EVENT_SoldierGotHit( TAKE_DAMAGE_BLADE, (INT16) 25, (INT16) 25, gOppositeDirection[ pSoldier->ubDirection ], 50, pSoldier->ubID, 0, ANIM_PRONE, 0, 0 );
}
break;
case 762:
{
// CODE: Set off Trigger
INT8 bPanicTrigger = ClosestPanicTrigger( pSoldier );
if (bPanicTrigger != -1)
{
SetOffPanicBombs( pSoldier->ubID, bPanicTrigger );
}
// any AI guy has been specially given keys for this, now take them
// away
pSoldier->flags.bHasKeys = pSoldier->flags.bHasKeys >> 1;
}
break;
case 763:
// CODE: Drop item at gridno
if ( pSoldier->pTempObject != NULL )
{
if ( pSoldier->bVisible != -1 )
{
if (Water(pSoldier->aiData.sPendingActionData2, pSoldier->pathing.bLevel))
{
UINT16 usItem = pSoldier->pTempObject->usItem;
INT32 sGridNo = pSoldier->aiData.sPendingActionData2;
if (HasItemFlag(usItem, CORPSE))
PlayJA2Sample(ENTER_DEEP_WATER_1, RATE_11025, SoundVolume(MIDVOLUME, sGridNo), 1, SoundDir(sGridNo));
else if (Item[usItem].ubWeight > 10)
PlayJA2Sample(ENTER_WATER_1, RATE_11025, SoundVolume(MIDVOLUME, sGridNo), 1, SoundDir(sGridNo));
else
PlaySplashSound(sGridNo);
}
else
{
PlayJA2Sample(THROW_IMPACT_2, RATE_11025, SoundVolume(MIDVOLUME, pSoldier->sGridNo), 1, SoundDir(pSoldier->sGridNo));
}
}
AddItemToPool( pSoldier->aiData.sPendingActionData2, pSoldier->pTempObject, 1, pSoldier->pathing.bLevel, 0 , -1 );
NotifySoldiersToLookforItems( );
OBJECTTYPE::DeleteMe( &pSoldier->pTempObject );
}
break;
case 764:
PlaySoldierJA2Sample( pSoldier->ubID, PICKING_LOCK, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 765:
// Flyback hit - do blood!
// PLace in existing tile and one back...
{
INT32 sNewGridNo;
InternalDropBlood( pSoldier->sGridNo, pSoldier->pathing.bLevel, 0, (UINT8)(MAXBLOODQUANTITY), 1 );
// Move forward one gridno....
sNewGridNo = NewGridNo( pSoldier->sGridNo, DirectionInc( gOppositeDirection[ pSoldier->ubDirection ] ) );
InternalDropBlood( sNewGridNo, pSoldier->pathing.bLevel, 0, (UINT8)(MAXBLOODQUANTITY), 1 );
}
break;
case 766:
// Flugente: if doing this action a lot, this gets annoying - only play sound sometimes
if ( Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) )
{
// Say COOL quote
pSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 );
}
break;
case 767:
// Slap sound effect
PlaySoldierJA2Sample( pSoldier->ubID, SLAP_2, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE );
break;
case 768:
// OK, after ending first aid, stand up if not in combat....
if ( NumCapableEnemyInSector( ) == 0 )
{
// Stand up...
pSoldier->ChangeSoldierStance( ANIM_STAND );
return( FALSE );
}
break;
case 769:
// ATE: LOOK HERE FOR CODE IN INTERNALS FOR
// REFUELING A VEHICLE
// THE GAS_CAN IS IN THE MERCS MAIN HAND AT THIS TIME
{
// Get pointer to vehicle...
SoldierID ubPerson = WhoIsThere2( pSoldier->aiData.sPendingActionData2, pSoldier->pathing.bLevel );
if ( ubPerson != NOBODY )
{
SOLDIERTYPE *pVehicle = ubPerson;
// this is a ubID for soldiertype....
AddFuelToVehicle( pSoldier, pVehicle );
fInterfacePanelDirty = DIRTYLEVEL2;
}
}
break;
case 770:
PlayJA2Sample( USE_WIRE_CUTTERS, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
break;
case 771:
PlayJA2Sample( BLOODCAT_ATTACK, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
break;
case 772:
//CODE: FOR A REALTIME NON-INTERRUPTABLE SCRIPT - SIGNAL DONE
pSoldier->flags.fRTInNonintAnim = FALSE;
break;
case 773:
// Kneel up...
if ( !pSoldier->bStealthMode )
{
PlaySoldierJA2Sample( pSoldier->ubID, KNEEL_UP_SOUND, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 774:
// Kneel down..
if ( !pSoldier->bStealthMode )
{
PlaySoldierJA2Sample( pSoldier->ubID, KNEEL_DOWN_SOUND, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 775:
// prone up..
if ( !pSoldier->bStealthMode )
{
PlaySoldierJA2Sample( pSoldier->ubID, PRONE_UP_SOUND, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 776:
// prone down..
if ( !pSoldier->bStealthMode )
{
PlaySoldierJA2Sample( pSoldier->ubID, PRONE_DOWN_SOUND, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 777:
// picking something up
if ( !pSoldier->bStealthMode )
{
PlaySoldierJA2Sample( pSoldier->ubID, PICKING_SOMETHING_UP, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 778:
if (!pSoldier->bStealthMode && (pSoldier->bVisible == TRUE || TeamMemberNear(gbPlayerNum, pSoldier->sGridNo, TACTICAL_RANGE)))
{
PlaySoldierJA2Sample( pSoldier->ubID, ENTER_DEEP_WATER_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 779:
PlaySoldierJA2Sample( pSoldier->ubID, COW_FALL, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 780:
PlaySoldierJA2Sample( pSoldier->ubID, COW_HIT_SND, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 781:
PlaySoldierJA2Sample( pSoldier->ubID, ACR_DIE_PART2, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE );
break;
case 782:
PlaySoldierJA2Sample( pSoldier->ubID, CREATURE_DISSOLVE_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE );
break;
case 784:
PlaySoldierJA2Sample( pSoldier->ubID, CREATURE_FALL, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE );
break;
case 785:
if ( Random( 5 ) == 0 )
{
PlaySoldierJA2Sample( pSoldier->ubID, CROW_PECKING_AT_FLESH, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
}
break;
case 786:
PlaySoldierJA2Sample( pSoldier->ubID, CROW_FLYING_AWAY, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 787:
PlaySoldierJA2Sample( pSoldier->ubID, SLAP_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE );
break;
case 788:
PlaySoldierJA2Sample( pSoldier->ubID, MORTAR_START, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 789:
PlaySoldierJA2Sample( pSoldier->ubID, MORTAR_LOAD, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 790:
PlaySoldierJA2Sample( pSoldier->ubID, COW_FALL_2, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 791:
PlaySoldierJA2Sample( pSoldier->ubID, FENCE_OPEN, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
break;
case 792:
break;
}
// Adjust frame control pos, and try again
pSoldier->usAniCode++;
}
else if ( sNewAniFrame == 999 )
{
// Go to start, by default
pSoldier->usAniCode = 0;
}
else if ( sNewAniFrame > 999 && sNewAniFrame <= 1099 )
{
// Jump, to animation script ( in the 300+ range )
pSoldier->EVENT_InitNewSoldierAnim( (UINT16)(sNewAniFrame - 700 ), 0 , FALSE );
return( TRUE );
}
else if ( sNewAniFrame > 1099 )
{
switch( sNewAniFrame )
{
case 1101:
// SANDRO - dual burst check for repeating animation
{
OBJECTTYPE* pObjHand = pSoldier->GetUsedWeapon( &pSoldier->inv[pSoldier->ubAttackingHand] );
if (pSoldier->bDoBurst && ( pSoldier->bDoBurst <= ( (pSoldier->bDoAutofire)?(2*pSoldier->bDoAutofire):(2*GetShotsPerBurst( pObjHand )) ) ))
{
if ( pSoldier->usAnimState == BURST_DUAL_PRONE )
pSoldier->usAniCode = 2;
else
pSoldier->usAniCode = 1;
}
else
{
pSoldier->usAniCode++;
}
break;
}
case 1102:
// SANDRO - end dual burst check for going to proper aim state
switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
{
case ANIM_STAND:
pSoldier->EVENT_InitNewSoldierAnim( AIM_DUAL_STAND, 0 , FALSE );
break;
case ANIM_CROUCH:
pSoldier->EVENT_InitNewSoldierAnim( AIM_DUAL_CROUCH, 0 , FALSE );
break;
case ANIM_PRONE:
pSoldier->EVENT_InitNewSoldierAnim( AIM_DUAL_PRONE, 0 , FALSE );
break;
}
return( TRUE );
break;
}
}
// Loop here until we break on a real item!
} while ( TRUE );
// We're done
return( TRUE );
}
#define MIN_DEADLINESS_FOR_LIKE_GUN_QUOTE 20
BOOLEAN ShouldMercSayHappyWithGunQuote( SOLDIERTYPE *pSoldier )
{
// How do we do this....
if ( QuoteExp[ pSoldier->ubProfile ].QuoteExpGotGunOrUsedGun == QUOTE_SATISFACTION_WITH_GUN_AFTER_KILL )
{
// For one, only once a day...
if ( pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_LIKESGUN )
{
return( FALSE );
}
// is it a gun?
if ( Item[ pSoldier->usAttackingWeapon ].usItemClass & IC_GUN )
{
// Is our weapon powerfull enough?
if ( Weapon[ pSoldier->usAttackingWeapon ].ubDeadliness > MIN_DEADLINESS_FOR_LIKE_GUN_QUOTE )
{
// 20 % chance?
if ( Chance( 20 ) )
{
return( TRUE );
}
}
}
}
return( FALSE );
}
void SayBuddyWitnessedQuoteFromKill( SOLDIERTYPE *pKillerSoldier, INT32 sGridNo, INT8 bLevel )
{
// WDS - make number of mercenaries, etc. be configurable
std::vector<UINT16> ubMercsInSector (CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS, 0);
// UINT8 ubMercsInSector[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ] = { 0 };
std::vector<INT8> bBuddyIndex (CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS, -1);
// INT8 bBuddyIndex[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ] = { -1 };
INT8 bTempBuddyIndex;
UINT16 ubNumMercs = 0;
UINT16 ubChosenMerc;
SOLDIERTYPE *pTeamSoldier;
UINT16 usQuoteNum;
BOOLEAN buddyquoteused = FALSE;
// Loop through all our guys and randomly say one from someone in our sector
// Flugente: as we only play a sound in 20% of all cases, pass that check first before going through all this stuff
if ( !Chance( 20 ) )
return;
// set up soldier ptr as first element in mercptrs list
SoldierID cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
// run through list
for ( ; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ++cnt )
{
pTeamSoldier = cnt;
// Add guy if he's a candidate...
if ( OK_INSECTOR_MERC( pTeamSoldier ) && !AM_AN_EPC( pTeamSoldier ) && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !(AM_A_ROBOT( pTeamSoldier ))
&& !pTeamSoldier->flags.fMercAsleep && !TileIsOutOfBounds(pTeamSoldier->sGridNo) && pTeamSoldier->ubProfile != pKillerSoldier->ubProfile )
{
// Are we a buddy of killer?
bTempBuddyIndex = WhichBuddy( pTeamSoldier->ubProfile, pKillerSoldier->ubProfile );
if ( bTempBuddyIndex != -1 )
{
switch( bTempBuddyIndex )
{
case 0:
if ( pTeamSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_BUDDY_1_WITNESSED )
{
continue;
}
break;
case 1:
if ( pTeamSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_BUDDY_2_WITNESSED )
{
continue;
}
break;
case 2:
if ( pTeamSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_BUDDY_3_WITNESSED )
{
continue;
}
break;
case 3:
if ( pTeamSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_BUDDY_4_WITNESSED )
{
continue;
}
break;
case 4:
if ( pTeamSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_BUDDY_5_WITNESSED )
{
continue;
}
break;
case 5:
if ( pTeamSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_BUDDY_6_WITNESSED )
{
continue;
}
break;
}
// TO LOS check to killed
// Can we see location of killer?
if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, pKillerSoldier->sGridNo, pKillerSoldier->pathing.bLevel, 3, TRUE, CALC_FROM_ALL_DIRS ) == 0 )
{
continue;
}
// Can we see location of killed?
if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, bLevel, 3, TRUE, CALC_FROM_ALL_DIRS ) == 0 )
{
continue;
}
// OK, a good candidate...
ubMercsInSector[ ubNumMercs ] = (UINT16)cnt;
bBuddyIndex[ ubNumMercs ] = bTempBuddyIndex;
++ubNumMercs;
}
}
}
// If we are > 0
if ( ubNumMercs > 0 )
{
ubChosenMerc = (UINT16)Random( ubNumMercs );
SOLDIERTYPE *pChosen = MercPtrs[ubMercsInSector[ubChosenMerc]];
switch( bBuddyIndex[ ubChosenMerc ] )
{
case 0:
usQuoteNum = QUOTE_BUDDY_1_GOOD;
pChosen->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_1_WITNESSED;
break;
case 1:
usQuoteNum = QUOTE_BUDDY_2_GOOD;
pChosen->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_2_WITNESSED;
break;
case 2:
if( pChosen->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC )
usQuoteNum = QUOTE_AIM_BUDDY_3_GOOD;
else
usQuoteNum = QUOTE_NON_AIM_BUDDY_3_GOOD;
pChosen->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_3_WITNESSED;
break;
case 3:
if( pChosen->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC )
usQuoteNum = QUOTE_AIM_BUDDY_4_GOOD;
else
usQuoteNum = QUOTE_NON_AIM_BUDDY_4_GOOD;
pChosen->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_4_WITNESSED;
break;
case 4:
if( pChosen->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC )
usQuoteNum = QUOTE_AIM_BUDDY_5_GOOD;
else
usQuoteNum = QUOTE_NON_AIM_BUDDY_5_GOOD;
pChosen->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_5_WITNESSED;
break;
case 5:
usQuoteNum = QUOTE_LEARNED_TO_LIKE_WITNESSED;
pChosen->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_6_WITNESSED;
break;
}
TacticalCharacterDialogue( pChosen, usQuoteNum );
buddyquoteused = TRUE;
}
// Flugente: if we want to play a sound, but have not found a fitting buddy, try additional dialogue
// this could be expensive, as we need quite a few sight tests here...
if ( !buddyquoteused && pKillerSoldier->bTeam == gbPlayerNum )
{
cnt = gTacticalStatus.Team[gbPlayerNum].bFirstID;
for ( ; cnt <= gTacticalStatus.Team[gbPlayerNum].bLastID; ++cnt )
{
pTeamSoldier = cnt;
// we do not exclude the buddies from above. If we get to this point, it might have been a buddy that already said his line. In that case additional dialogue might play other ones
// Add guy if he's a candidate...
if ( OK_INSECTOR_MERC( pTeamSoldier ) && !AM_AN_EPC( pTeamSoldier ) && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !( AM_A_ROBOT( pTeamSoldier ) )
&& !pTeamSoldier->flags.fMercAsleep && !TileIsOutOfBounds( pTeamSoldier->sGridNo ) )//&& pTeamSoldier->ubProfile != pKillerSoldier->ubProfile )
{
// TO LOS check to killed
// Can we see location of killer?
// not if we're the killer
if ( pTeamSoldier->ubID != pKillerSoldier->ubID &&
SoldierTo3DLocationLineOfSightTest( pTeamSoldier, pKillerSoldier->sGridNo, pKillerSoldier->pathing.bLevel, 3, TRUE, CALC_FROM_ALL_DIRS ) == 0 )
{
continue;
}
// Can we see location of killed?
if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, bLevel, 3, TRUE, CALC_FROM_ALL_DIRS ) == 0 )
{
continue;
}
AdditionalTacticalCharacterDialogue_CallsLua( pTeamSoldier, ADE_WITNESS_GOOD, pKillerSoldier->ubProfile, 0 );
}
}
}
}
void HandleKilledQuote( SOLDIERTYPE *pKilledSoldier, SOLDIERTYPE *pKillerSoldier, INT32 sGridNo, INT8 bLevel )
{
SOLDIERTYPE *pTeamSoldier;
// WDS - make number of mercenaries, etc. be configurable
std::vector<UINT16> ubMercsInSector (CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS, 0);
UINT16 ubNumMercs = 0;
UINT16 ubChosenMerc;
BOOLEAN fDoSomeoneElse = FALSE;
gfLastMercTalkedAboutKillingID = pKilledSoldier->ubID;
// Can we see location?
BOOLEAN fCanWeSeeLocation = ( SoldierTo3DLocationLineOfSightTest( pKillerSoldier, sGridNo, bLevel, 3, TRUE, CALC_FROM_ALL_DIRS ) != 0 );
// Are we killing mike?
if ( pKilledSoldier->ubProfile == MIKE && ( pKillerSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC || ( pKillerSoldier->ubWhatKindOfMercAmI == MERC_TYPE__MERC && gMercProfiles[pKillerSoldier->ubProfile].bLearnToHate == 255 ) ) )
{
// Can we see?
if ( fCanWeSeeLocation )
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_AIM_KILLED_MIKE );
}
}
// Are we killing factory mamager?
else if ( pKilledSoldier->ubProfile == DOREEN )
{
// Can we see?
//f ( fCanWeSeeLocation )
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_FACTORY_MANAGER );
}
}
else
{
// Steps here...
// If not head shot, just say killed quote
// If head shot...
// If we have a head shot saying,, randomly try that one
// If not doing that one, search for anybody who can see person
// If somebody did, play his quote plus attackers killed quote.
// Checkf for headhot!
if ( pKilledSoldier->usAnimState == JFK_HITDEATH )
{
//Randomliy say it!
if ( Random( 100 ) < 40 )
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_HEADSHOT );
}
else
{
fDoSomeoneElse = TRUE;
}
if ( fDoSomeoneElse )
{
// Check if a person is here that has this quote....
SoldierID cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
// run through list
for ( ; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ++cnt )
{
pTeamSoldier = cnt;
if ( cnt != pKillerSoldier->ubID )
{
if ( OK_INSECTOR_MERC( pTeamSoldier ) && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !AM_AN_EPC( pTeamSoldier ) )
{
// Can we see location?
if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, bLevel, 3, TRUE, CALC_FROM_ALL_DIRS ) )
{
ubMercsInSector[ ubNumMercs ] = (UINT16)cnt;
ubNumMercs++;
}
}
}
}
// Did we find anybody?
if ( ubNumMercs > 0 )
{
ubChosenMerc = (UINT16)Random( ubNumMercs );
// We have a random chance of not saying our we killed a guy quote
if ( Random( 100 ) < 50 )
{
// Say this guys quote but the killer's quote as well....
// if killed was not a plain old civ, say quote
if (pKilledSoldier->bTeam != CIV_TEAM || pKilledSoldier->ubCivilianGroup != 0)
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_AN_ENEMY );
}
}
TacticalCharacterDialogue( MercPtrs[ ubMercsInSector[ ubChosenMerc ] ], QUOTE_HEADSHOT );
}
else
{
// Can we see?
if ( fCanWeSeeLocation )
{
// Say this guys quote but the killer's quote as well....
// if killed was not a plain old civ, say quote
if (pKilledSoldier->bTeam != CIV_TEAM || pKilledSoldier->ubCivilianGroup != 0)
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_AN_ENEMY );
}
}
}
}
}
else
{
// Can we see?
if ( fCanWeSeeLocation )
{
// if killed was not a plain old civ, say quote
if (pKilledSoldier->bTeam != CIV_TEAM || pKilledSoldier->ubCivilianGroup != 0)
{
// Are we happy with our gun?
if ( ShouldMercSayHappyWithGunQuote( pKillerSoldier ) )
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_SATISFACTION_WITH_GUN_AFTER_KILL );
pKillerSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_LIKESGUN;
}
else if ( pKillerSoldier->bSide == pKilledSoldier->bSide )
{
// if the attacker was from the same side, play a curse
pKillerSoldier->DoMercBattleSound( (INT8)(BATTLE_SOUND_CURSE1) );
}
else
// Randomize between laugh, quote...
{
if ( Random( 100 ) < 33 && pKilledSoldier->ubBodyType != BLOODCAT )
{
// If it's a creature......
if ( pKilledSoldier->flags.uiStatusFlags & SOLDIER_MONSTER )
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_A_CREATURE );
}
else
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_AN_ENEMY );
}
}
else
{
if ( Random( 50 ) == 25 )
{
pKillerSoldier->DoMercBattleSound( (INT8)( BATTLE_SOUND_LAUGH1 ) );
}
else
{
pKillerSoldier->DoMercBattleSound( (INT8)( BATTLE_SOUND_COOL1 ) );
}
}
}
// Buddy witnessed?
SayBuddyWitnessedQuoteFromKill( pKillerSoldier, sGridNo, bLevel );
}
}
}
}
}
BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
{
BOOLEAN fBuddyJustDead = FALSE;
*pfMadeCorpse = FALSE;
if ( pSoldier->stats.bLife == 0 && !( pSoldier->flags.uiStatusFlags & SOLDIER_DEAD ) )
{
// Haydent/send death info
if (is_networked)
{
if(pSoldier->bTeam==0)
send_death(pSoldier);
else if(pSoldier->bTeam <6 && ((gTacticalStatus.ubTopMessageType == PLAYER_TURN_MESSAGE) || (gTacticalStatus.ubTopMessageType == PLAYER_INTERRUPT_MESSAGE)))
send_death(pSoldier);
}
// anv: enemy taunts after kill
SOLDIERTYPE *pKillerSoldier = NULL;
if(pSoldier->ubAttackerID != NOBODY)
{
pKillerSoldier = pSoldier->ubAttackerID;
}
else if(pSoldier->ubPreviousAttackerID != NOBODY)
{
pKillerSoldier = pSoldier->ubPreviousAttackerID;
}
if(pKillerSoldier != NULL)
{
if( pSoldier->usAnimState == JFK_HITDEATH )
PossiblyStartEnemyTaunt( pKillerSoldier, TAUNT_HEAD_POP, pSoldier->ubID );
else if( Item[pKillerSoldier->usAttackingWeapon].usItemClass & IC_GUN )
PossiblyStartEnemyTaunt( pKillerSoldier, TAUNT_KILL_GUNFIRE, pSoldier->ubID );
else if( Item[pKillerSoldier->usAttackingWeapon].usItemClass & IC_BLADE )
PossiblyStartEnemyTaunt( pKillerSoldier, TAUNT_KILL_BLADE, pSoldier->ubID );
else if( Item[pKillerSoldier->usAttackingWeapon].usItemClass & IC_PUNCH )
PossiblyStartEnemyTaunt( pKillerSoldier, TAUNT_KILL_HTH, pSoldier->ubID );
else if( Item[pKillerSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE )
PossiblyStartEnemyTaunt( pKillerSoldier, TAUNT_KILL_THROWING_KNIFE, pSoldier ->ubID);
else
PossiblyStartEnemyTaunt( pKillerSoldier, TAUNT_KILL, pSoldier->ubID );
}
// Cancel services here...
pSoldier->ReceivingSoldierCancelServices( );
pSoldier->GivingSoldierCancelServices( );
if ( pSoldier->iMuzFlash != -1 )
{
LightSpriteDestroy( pSoldier->iMuzFlash );
pSoldier->iMuzFlash = -1;
}
if ( pSoldier->iLight != -1 )
{
LightSpriteDestroy( pSoldier->iLight );
}
//FREEUP GETTING HIT FLAG
pSoldier->flags.fGettingHit = FALSE;
// Find next closest team member!
if ( pSoldier->bTeam == gbPlayerNum )
{
// Set guy to close panel!
// ONLY IF VISIBLE ON SCREEN
if ( IsMercPortraitVisible( pSoldier->ubID ) )
{
fInterfacePanelDirty = DIRTYLEVEL2;
}
pSoldier->flags.fUIdeadMerc = TRUE;
if ( !gfKillingGuysForLosingBattle )
{
// ATE: THIS IS S DUPLICATE SETTING OF SOLDIER_DEAD. Is set in StrategicHandlePlayerTeamMercDeath()
// also, but here it's needed to tell tectical to ignore this dude...
// until StrategicHandlePlayerTeamMercDeath() can get called after death skull interface is done
pSoldier->flags.uiStatusFlags |= SOLDIER_DEAD;
}
}
else
{
//////////////////////////////////////////////////////////////
// SANDRO - some changes here
SoldierID ubAttacker = pSoldier->ubAttackerID;
SoldierID ubAssister = pSoldier->ubPreviousAttackerID;
// If attacker is nobody, and we died, then set the last attacker(if exists) as our killer
if ( ubAttacker == NOBODY )
{
if ( ubAssister != NOBODY )
{
ubAttacker = pSoldier->ubPreviousAttackerID;
ubAssister = pSoldier->ubNextToPreviousAttackerID;
}
else if ( pSoldier->ubNextToPreviousAttackerID != NOBODY )
{
ubAttacker = pSoldier->ubNextToPreviousAttackerID;
ubAssister = NOBODY;
}
}
else
{
if ( ubAssister == NOBODY )
{
ubAssister = pSoldier->ubNextToPreviousAttackerID;
}
}
//////////////////////////////////////////////////////////////
{
// anv: note that ubAttacker can be already different from pSoldier->ubAttackerID
// IF this guy has an attacker and he's a good guy, play sound
if ( pSoldier->ubAttackerID < NOBODY )
{
if ( pSoldier->ubAttackerID->bTeam == gbPlayerNum && gTacticalStatus.ubAttackBusyCount > 0 )
{
gTacticalStatus.fKilledEnemyOnAttack = TRUE;
gTacticalStatus.ubEnemyKilledOnAttack = pSoldier->ubID;
gTacticalStatus.ubEnemyKilledOnAttackLocation = pSoldier->sGridNo;
gTacticalStatus.bEnemyKilledOnAttackLevel = pSoldier->pathing.bLevel;
gTacticalStatus.ubEnemyKilledOnAttackKiller = ubAttacker;
// also check if we are in mapscreen, if so update soldier's list
if( guiCurrentScreen == MAP_SCREEN )
{
ReBuildCharactersList( );
}
}
else if ( pSoldier->bVisible == TRUE )
{
// We were a visible enemy, say laugh!
if ( Random(3) == 0 && !CREATURE_OR_BLOODCAT( ubAttacker ) )
{
// if the attacker was from the same team, play a curse, otherwise play a laugh
if ( ubAttacker->bSide == pSoldier->bSide )
ubAttacker->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
else
ubAttacker->DoMercBattleSound( BATTLE_SOUND_LAUGH1 );
}
}
}
// Handle NPC Dead
HandleNPCTeamMemberDeath( pSoldier );
// if a friendly with a profile, increment kills
// militia also now track kills...
if ( ubAttacker != NOBODY )
{
if ( ubAttacker->bTeam == gbPlayerNum )
{
// increment kills
/////////////////////////////////////////////////////////////////////////////////////
// SANDRO - experimental - more specific statistics of mercs
switch(pSoldier->ubSoldierClass)
{
case SOLDIER_CLASS_ROBOT:
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsOthers++;
break;
case SOLDIER_CLASS_ELITE :
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsElites++;
break;
case SOLDIER_CLASS_ARMY :
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsRegulars++;
break;
case SOLDIER_CLASS_ADMINISTRATOR :
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsAdmins++;
break;
case SOLDIER_CLASS_CREATURE :
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsCreatures++;
break;
case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsZombies++;
break;
case SOLDIER_CLASS_BANDIT:
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsOthers++;
break;
default :
if ( CREATURE_OR_BLOODCAT( pSoldier ) )
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsCreatures++;
else if ( ARMED_VEHICLE( pSoldier ) )
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsTanks++;
else if ( pSoldier->bTeam == CIV_TEAM && !pSoldier->aiData.bNeutral && pSoldier->bSide != gbPlayerNum )
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsHostiles++;
else
{
gMercProfiles[ ubAttacker->ubProfile ].records.usKillsOthers++;
// Flugente: dynamic opinions: if this guy is not hostile towards us, then some mercs will complain about killing civilians
if (gGameExternalOptions.fDynamicOpinions && pSoldier->bTeam != OUR_TEAM && (pSoldier->aiData.bNeutral || pSoldier->bSide == ubAttacker->bSide) )
{
// not for killing animals though...
if ( pSoldier->ubBodyType != CROW && pSoldier->ubBodyType != COW )
HandleDynamicOpinionChange( ubAttacker, OPINIONEVENT_CIVKILLER, TRUE, TRUE );
}
}
break;
}
//gMercProfiles[ pSoldier->ubAttackerID->ubProfile ].usKills++;
/////////////////////////////////////////////////////////////////////////////////////
gStrategicStatus.usPlayerKills++;
// Flugente: dynamic opinions: if this guy is not hostile towards us, then some mercs will complain about killing civilians
if (gGameExternalOptions.fDynamicOpinions)
{
if (pSoldier->bTeam != OUR_TEAM && (pSoldier->aiData.bNeutral || pSoldier->bSide == ubAttacker->bSide))
{
// not for killing animals though...
if (pSoldier->ubBodyType != CROW && pSoldier->ubBodyType != COW)
HandleDynamicOpinionChange(ubAttacker, OPINIONEVENT_CIVKILLER, TRUE, TRUE);
}
else
{
// if this enemy was attacking a freshly wounded merc, it is likely they posed a real threat - the merc will be thankful for saving their life
if (pSoldier->ubTargetID != NOBODY && pSoldier->ubTargetID->bBleeding > 10)
{
AddOpinionEvent(pSoldier->ubTargetID->ubProfile, ubAttacker->ubProfile, OPINIONEVENT_BATTLE_SAVIOUR);
}
else
{
// complain about a fragthief, or thank for assistance - correct event is chosen internally
HandleDynamicOpinionChange(ubAttacker, OPINIONEVENT_FRAGTHIEF, TRUE, TRUE);
}
}
}
}
else if ( ubAttacker->bTeam == MILITIA_TEAM )
{
// get a kill! 2 points!
ubAttacker->ubMilitiaKills += 1;
}
}
if ( ubAssister != NOBODY && ubAssister != ubAttacker )
{
if ( ubAssister->bTeam == gbPlayerNum )
{
/////////////////////////////////////////////////////////////////////////////////////
// SANDRO - new mercs' records
if( ubAttacker != NOBODY )
{
if( ubAttacker->bTeam == gbPlayerNum )
gMercProfiles[ ubAssister->ubProfile ].records.usAssistsMercs++;
else if ( ubAttacker->bTeam == MILITIA_TEAM )
gMercProfiles[ ubAssister->ubProfile ].records.usAssistsMilitia++;
else
gMercProfiles[ ubAssister->ubProfile ].records.usAssistsOthers++;
}
else
{
gMercProfiles[ ubAssister->ubProfile ].records.usAssistsOthers++;
}
//gMercProfiles[ ubAssister->ubProfile ].usAssists++;
/////////////////////////////////////////////////////////////////////////////////////
}
else if ( ubAssister->bTeam == MILITIA_TEAM )
{
// get an assist - 1 points
ubAssister->ubMilitiaAssists += 1;
}
}
/*
// handle assist
// if killer is assister, don't increment
if ( pSoldier->ubPreviousAttackerID != NOBODY && pSoldier->ubPreviousAttackerID != pSoldier->ubAttackerID )
{
if ( MercPtrs[ pSoldier->ubPreviousAttackerID ]->bTeam == gbPlayerNum )
{
gMercProfiles[ MercPtrs[ pSoldier->ubPreviousAttackerID ]->ubProfile ].usAssists++;
}
else if ( MercPtrs[ pSoldier->ubPreviousAttackerID ]->bTeam == MILITIA_TEAM )
{
// get an assist - 1 points
MercPtrs[ pSoldier->ubPreviousAttackerID ]->ubMilitiaAssists += 1;
}
}
*/
}
}
// rftr: soldier bounty payout
RebelCommand::ApplySoldierBounty(pSoldier);
// Flugente: campaign stats
gCurrentIncident.AddStat( pSoldier, CAMPAIGNHISTORY_TYPE_KILL );
// Flugente: for raids, we need to keep track of killed forces
if ( GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
AddRaidPersonnel( -( pSoldier->ubBodyType == BLOODCAT ), -( pSoldier->ubSoldierClass == SOLDIER_CLASS_ZOMBIE ), -( pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT ) );
}
// Flugente: individual militia
MILITIA militia;
if ( GetMilitia( pSoldier->usIndividualMilitiaID, &militia ) && !(militia.flagmask & MILITIAFLAG_DEAD) )
{
militia.healthratio = 0.0f;
militia.flagmask |= MILITIAFLAG_DEAD;
// note the current incident (when closing the incident, we only do this for those still alive)
MILITIA_BATTLEREPORT report;
report.id = GetIdOfCurrentlyOngoingIncident( );
report.flagmask = MILITIA_BATTLEREPORT_FLAG_DIED;
if ( pSoldier->ubMilitiaKills )
report.flagmask |= MILITIA_BATTLEREPORT_FLAG_KILLEDENEMY;
militia.history.push_back( report );
UpdateMilitia(militia);
}
if ( TurnSoldierIntoCorpse( pSoldier, TRUE, TRUE ) )
{
*pfMadeCorpse = TRUE;
}
// Flugente: VIPs
if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP )
{
DeleteVIP( pSoldier->sSectorX, pSoldier->sSectorY );
}
// Flugente: turncoats
if ( pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT )
RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass, FALSE );
// Flugente: additional dialogue
if ( pSoldier->ubProfile != NO_PROFILE )
{
AdditionalTacticalCharacterDialogue_AllInSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ, pSoldier->ubProfile, ADE_NPC_DEATH,
pSoldier->ubProfile, pKillerSoldier ? pKillerSoldier->ubProfile : NO_PROFILE, pSoldier->ubBodyType );
}
// Remove mad as target, one he has died!
RemoveManAsTarget( pSoldier );
// Re-evaluate visiblitiy for the team!
BetweenTurnsVisibilityAdjustments();
// 0verhaul: This is now handled in the death state transitions
// if ( pSoldier->bTeam != gbPlayerNum )
// {
// if ( !pSoldier->flags.fDoingExternalDeath )
// {
// // Release attacker
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, code 497 = handle soldier death") );
// ReleaseSoldiersAttacker( pSoldier );
// }
// }
if ( !( *pfMadeCorpse ) )
{
fBuddyJustDead = TRUE;
}
}
if ( pSoldier->stats.bLife > 0 )
{
// If we are here - something funny has heppende
// We either have played a death animation when we are not dead, or we are calling
// this ani code in an animation which is not a death animation
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: Death animation called when not dead..." );
}
return( fBuddyJustDead );
}
void HandlePlayerTeamMemberDeathAfterSkullAnimation( SOLDIERTYPE *pSoldier )
{
// 0verhaul: This is now handled in the death state transition.
// Release attacker
// if ( !pSoldier->flags.fDoingExternalDeath )
// {
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, code 497 = handle soldier death") );
// ReleaseSoldiersAttacker( pSoldier );
// }
HandlePlayerTeamMemberDeath( pSoldier );
// now remove character from a squad
RemoveCharacterFromSquads( pSoldier );
}
BOOLEAN CheckForAndHandleSoldierDeath( SOLDIERTYPE *pSoldier, BOOLEAN *pfMadeCorpse )
{
if ( HandleSoldierDeath( pSoldier, pfMadeCorpse ) )
{
// Select approriate death
switch( pSoldier->usAnimState )
{
case FLYBACK_HIT_DEATH:
pSoldier->ChangeSoldierState( FLYBACK_HITDEATH_STOP, 0, FALSE );
break;
case GENERIC_HIT_DEATH:
pSoldier->ChangeSoldierState( FALLFORWARD_HITDEATH_STOP, 0, FALSE );
break;
case FALLBACK_HIT_DEATH:
pSoldier->ChangeSoldierState( FALLBACK_HITDEATH_STOP, 0, FALSE );
break;
case PRONE_HIT_DEATH:
pSoldier->ChangeSoldierState( PRONE_HITDEATH_STOP, 0, FALSE );
break;
case JFK_HITDEATH:
pSoldier->ChangeSoldierState( JFK_HITDEATH_STOP, 0, FALSE );
break;
case FALLOFF_DEATH:
pSoldier->ChangeSoldierState( FALLOFF_DEATH_STOP, 0, FALSE );
break;
case FALLOFF_FORWARD_DEATH:
pSoldier->ChangeSoldierState( FALLOFF_FORWARD_DEATH_STOP, 0, FALSE );
break;
case WATER_DIE:
pSoldier->ChangeSoldierState( WATER_DIE_STOP, 0, FALSE );
break;
case DEEP_WATER_DIE:
pSoldier->ChangeSoldierState( DEEP_WATER_DIE_STOPPING, 0, FALSE );
break;
case COW_DYING:
pSoldier->ChangeSoldierState( COW_DYING_STOP, 0, FALSE);
break;
case BLOODCAT_DYING:
pSoldier->ChangeSoldierState( BLOODCAT_DYING_STOP, 0, FALSE);
break;
default:
// IF we are here - something is wrong - we should have an animation stop here
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: CODE 440 Error, Death STOP not handled" );
}
return( TRUE );
}
return( FALSE );
}
//#define TESTFALLBACK
//#define TESTFALLFORWARD
void CheckForAndHandleSoldierIncompacitated( SOLDIERTYPE *pSoldier )
{
INT32 sNewGridNo;
if ( pSoldier->stats.bLife < OKLIFE )
{
// Cancel services here...
pSoldier->ReceivingSoldierCancelServices( );
pSoldier->GivingSoldierCancelServices( );
// If we are a monster, set life to zero ( no unconscious )
switch( pSoldier->ubBodyType )
{
case ADULTFEMALEMONSTER:
case AM_MONSTER:
case YAF_MONSTER:
case YAM_MONSTER:
case LARVAE_MONSTER:
case INFANT_MONSTER:
case CRIPPLECIV:
case ROBOTNOWEAPON:
case QUEENMONSTER:
case TANK_NW:
case TANK_NE:
case COMBAT_JEEP:
pSoldier->stats.bLife = 0;
break;
}
// OK, if we are in a meanwhile and this is elliot...
#ifdef JA2UB
//ja25: No queen
#else
if ( AreInMeanwhile( ) )
{
SOLDIERTYPE *pQueen;
pQueen = FindSoldierByProfileID( QUEEN, FALSE );
if ( pQueen )
{
TriggerNPCWithGivenApproach( QUEEN, APPROACH_DONE_SLAPPED, FALSE );
}
}
#endif
// We are unconscious now, play randomly, this animation continued, or a new death
if ( pSoldier->CheckSoldierHitRoof( ) )
{
return;
}
// If guy is now dead, play sound!
if ( pSoldier->stats.bLife == 0 )
{
#ifdef JA2UB
//Ja25 No meanwhiles
#else
if ( !AreInMeanwhile() )
#endif
{
pSoldier->DoMercBattleSound( BATTLE_SOUND_DIE1 );
pSoldier->flags.fDeadSoundPlayed = TRUE;
}
}
// Randomly fall back or forward, if we are in the standing hit animation
if ( pSoldier->usAnimState == GENERIC_HIT_STAND || pSoldier->usAnimState == STANDING_BURST_HIT || pSoldier->usAnimState == RIFLE_STAND_HIT )
{
INT8 bTestDirection = pSoldier->ubDirection;
BOOLEAN fForceDirection = FALSE;
BOOLEAN fDoFallback = FALSE;
BOOLEAN fAlwaysFallBack = FALSE; // added by SANDRO
// Lesh: lets fix dead humans fallback through obstacles
// TRY FALLING BACKWARDS, ( ONLY IF WE ARE A MERC! )
#ifdef TESTFALLBACK
if ( IS_MERC_BODY_TYPE( pSoldier ) )
#elif defined ( TESTFALLFORWARD )
if ( 0 )
#else
// SANDRO - if Martial Artist took someone down, always fall back if possible (for the fun)
if ( pSoldier->ubAttackerID != NOBODY && gGameOptions.fNewTraitSystem )
{
if ( HAS_SKILL_TRAIT( pSoldier->ubAttackerID, MARTIAL_ARTS_NT ) && (!pSoldier->ubAttackerID->usAttackingWeapon || ItemIsBrassKnuckles(pSoldier->ubAttackerID->inv[HANDPOS].usItem)) )
{
fAlwaysFallBack = TRUE;
}
}
if ( (Random(100 ) > 40 || fAlwaysFallBack) && IS_MERC_BODY_TYPE( pSoldier ) && !IsProfileATerrorist( pSoldier->ubProfile ) )
#endif
{
// CHECK IF WE HAVE AN ATTACKER, TAKE OPPOSITE DIRECTION!
if ( pSoldier->ubAttackerID != NOBODY )
{
// Find direction!
bTestDirection = (INT8)GetDirectionFromGridNo( pSoldier->ubAttackerID->sGridNo, pSoldier );
fForceDirection = TRUE;
}
sNewGridNo = NewGridNo( pSoldier->sGridNo, DirectionInc( gOppositeDirection[ bTestDirection ] ) );
if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->pathing.bLevel, bTestDirection, FLYBACK_HIT ) )
{
// CHECKED BEHIND GRIDS - OK
fDoFallback = TRUE;
}
else
{
fDoFallback = FALSE;
}
}
else
{
fDoFallback = FALSE;
}
if ( !fDoFallback )
{
// 1 ) REC DIRECTION
// 2 ) SET FLAG FOR STARTING TO FALL
pSoldier->BeginTyingToFall( );
pSoldier->ChangeSoldierState( FALLFORWARD_FROMHIT_STAND, 0, FALSE );
return;
}
else
{
// ALL'S OK HERE..... IF WE FORCED DIRECTION, SET!
if ( fForceDirection )
{
pSoldier->EVENT_SetSoldierDesiredDirection( bTestDirection );
pSoldier->EVENT_SetSoldierDirection( bTestDirection );
}
pSoldier->ChangeToFallbackAnimation( pSoldier->ubDirection );
return;
}
}
else if ( pSoldier->usAnimState == GENERIC_HIT_CROUCH || pSoldier->usAnimState == CIV_COWER_HIT)
{
pSoldier->ChangeSoldierState( FALLFORWARD_FROMHIT_CROUCH, 0 , FALSE);
pSoldier->BeginTyingToFall( );
return;
}
else if ( pSoldier->usAnimState == GENERIC_HIT_PRONE )
{
pSoldier->ChangeSoldierState( PRONE_LAY_FROMHIT, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == ADULTMONSTER_HIT )
{
pSoldier->ChangeSoldierState( ADULTMONSTER_DYING, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == LARVAE_HIT )
{
pSoldier->ChangeSoldierState( LARVAE_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == QUEEN_HIT )
{
pSoldier->ChangeSoldierState( QUEEN_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == CRIPPLE_HIT )
{
pSoldier->ChangeSoldierState( CRIPPLE_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == ROBOTNW_HIT )
{
pSoldier->ChangeSoldierState( ROBOTNW_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == INFANT_HIT )
{
pSoldier->ChangeSoldierState( INFANT_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == COW_HIT )
{
pSoldier->ChangeSoldierState( COW_DYING, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == BLOODCAT_HIT )
{
pSoldier->ChangeSoldierState( BLOODCAT_DYING, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == WATER_HIT )
{
pSoldier->ChangeSoldierState( WATER_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == DEEP_WATER_HIT )
{
pSoldier->ChangeSoldierState( DEEP_WATER_DIE, 0 , FALSE );
return;
}
else
{
// We have missed something here - send debug msg
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: Genmeric hit not chained" );
}
}
}
BOOLEAN CheckForAndHandleSoldierDyingNotFromHit( SOLDIERTYPE *pSoldier )
{
if ( pSoldier->stats.bLife == 0 )
{
pSoldier->DoMercBattleSound( BATTLE_SOUND_DIE1 );
pSoldier->flags.fDeadSoundPlayed = TRUE;
// 0verhaul: The bBeingAttackedCount is now obsolete.
// Increment being attacked count
// pSoldier->bBeingAttackedCount++;
// OJW - Send bleeding death
if (is_networked)
{
if(pSoldier->bTeam==0) send_death(pSoldier);
else if(pSoldier->bTeam <6 && ((gTacticalStatus.ubTopMessageType == PLAYER_TURN_MESSAGE) || (gTacticalStatus.ubTopMessageType == PLAYER_INTERRUPT_MESSAGE)))send_death(pSoldier);
else if (pSoldier->bTeam < 6 && (is_server)) send_death(pSoldier);
}
// Flugente: cows only have one death animation. If we're not in the proper aniamtion, enforce it, otherwise the corpse isn't created
if ( pSoldier->ubBodyType == COW
&& pSoldier->usAnimState != COW_HIT )
pSoldier->ChangeSoldierState( COW_DYING, 0, FALSE );
if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] )
{
switch( pSoldier->usAnimState )
{
case FLYBACKHIT_STOP:
pSoldier->ChangeSoldierState( FLYBACK_HIT_DEATH, 0, FALSE );
break;
case FALLFORWARD_FROMHIT_STAND:
case FALLFORWARD_FROMHIT_CROUCH:
case STAND_FALLFORWARD_STOP:
pSoldier->ChangeSoldierState( GENERIC_HIT_DEATH, 0, FALSE );
break;
case FALLBACKHIT_STOP:
pSoldier->ChangeSoldierState( FALLBACK_HIT_DEATH, 0, FALSE );
break;
case PRONE_LAYFROMHIT_STOP:
case PRONE_LAY_FROMHIT:
pSoldier->ChangeSoldierState( PRONE_HIT_DEATH, 0, FALSE );
break;
case FALLOFF_STOP:
pSoldier->ChangeSoldierState( FALLOFF_DEATH, 0, FALSE );
break;
case FALLOFF_FORWARD_STOP:
pSoldier->ChangeSoldierState( FALLOFF_FORWARD_DEATH, 0, FALSE);
break;
case ADULTMONSTER_HIT:
pSoldier->ChangeSoldierState( ADULTMONSTER_DYING, 0 , FALSE );
break;
case LARVAE_HIT:
pSoldier->ChangeSoldierState( LARVAE_DIE, 0 , FALSE );
break;
case QUEEN_HIT:
pSoldier->ChangeSoldierState( QUEEN_DIE, 0 , FALSE );
break;
case CRIPPLE_HIT:
pSoldier->ChangeSoldierState( CRIPPLE_DIE, 0 , FALSE );
break;
case ROBOTNW_HIT:
pSoldier->ChangeSoldierState( ROBOTNW_DIE, 0 , FALSE );
break;
case INFANT_HIT:
pSoldier->ChangeSoldierState( INFANT_DIE, 0 , FALSE );
break;
case COW_HIT:
pSoldier->ChangeSoldierState( COW_DYING, 0 , FALSE );
break;
case BLOODCAT_HIT:
pSoldier->ChangeSoldierState( BLOODCAT_DYING, 0 , FALSE );
break;
default:
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Control: Death state %d has no death hit", pSoldier->usAnimState ) );
{
BOOLEAN fMadeCorpse;
CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse );
}
break;
}
}
else
{
BOOLEAN fMadeCorpse;
CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse );
}
return( TRUE );
}
return( FALSE );
}
BOOLEAN CheckForImproperFireGunEnd( SOLDIERTYPE *pSoldier )
{
if ( AM_A_ROBOT( pSoldier ) )
{
return( FALSE );
}
//dnl ch72 260913
OBJECTTYPE *pObjHand;
BOOLEAN outOfAmmo;
if(pSoldier->bWeaponMode == WM_ATTACHED_GL || pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST || pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO)
pObjHand = FindAttachment_GrenadeLauncher(&pSoldier->inv[HANDPOS]);
else
pObjHand = pSoldier->GetUsedWeapon(&pSoldier->inv[HANDPOS]);
// Extracted from EnoughAmmo() to avoid double calculation of pObjHand
if (Item[ pObjHand->usItem ].usItemClass & IC_LAUNCHER)
outOfAmmo = (FindAttachmentByClass( pObjHand, IC_GRENADE ) == NULL && FindAttachmentByClass( pObjHand, IC_BOMB ) == NULL);
else
outOfAmmo = (*pObjHand)[0]->data.gun.ubGunShotsLeft == 0;
// Check single hand for jammed status, ( or ammo is out.. )
if ( (*pObjHand)[0]->data.gun.bGunAmmoStatus < 0 || outOfAmmo )
{
// If we have 2 pistols, donot go back!
if ( Item[ pSoldier->inv[ SECONDHANDPOS ].usItem ].usItemClass != IC_GUN )
{
// OK, put gun down....
pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, TRUE, FALSE );
return( TRUE );
}
}
// SANDRO: if we are holding up a very heavy gun, and can't do it anymore, lower it
if ( gGameExternalOptions.ubEnergyCostForWeaponWeight && pSoldier->bBreath < OKBREATH )
{
// Check for breath collapse, though this should rarely happen
if ( pSoldier->CheckForBreathCollapse( ) )
{
UnSetUIBusy( pSoldier->ubID );
SoldierCollapse( pSoldier );
pSoldier->bBreathCollapsed = FALSE;
return( TRUE );
}
// ok, if this gun is rather heavy, and cost us at least 3 energy points per turn, and we got very low on breath
else if ( (GetBPCostPer10APsForGunHolding( pSoldier ) * 10) >= (300 * gGameExternalOptions.ubEnergyCostForWeaponWeight / 100) )
{
// throw quote
if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_LOW_BREATH ) )
{
TacticalCharacterDialogue( pSoldier, QUOTE_OUT_OF_BREATH );
pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_LOW_BREATH;
}
// Put gun down....
pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, TRUE, FALSE );
return( TRUE );
}
}
return( FALSE );
}
BOOLEAN OKHeightDest( SOLDIERTYPE *pSoldier, INT32 sNewGridNo )
{
if ( pSoldier->pathing.bLevel == 0 )
{
return( TRUE );
}
// Check if there is a lower place here....
if ( IsLowerLevel( sNewGridNo ) )
{
return( FALSE );
}
return( TRUE );
}
BOOLEAN HandleUnjamAnimation( SOLDIERTYPE *pSoldier )
{
// OK, play intermediate animation here..... save in pending animation data, the current
// code we are at!
pSoldier->aiData.uiPendingActionData1 = pSoldier->usAniCode;
pSoldier->aiData.sPendingActionData2 = pSoldier->usAnimState;
// Check what animatnion we should do.....
switch( pSoldier->usAnimState )
{
case SHOOT_RIFLE_STAND:
case STANDING_BURST:
case FIRE_STAND_BURST_SPREAD:
// Normal shoot rifle.... play
pSoldier->ChangeSoldierState( STANDING_SHOOT_UNJAM, 0 , FALSE );
return( TRUE );
case PRONE_BURST:
case SHOOT_RIFLE_PRONE:
// Normal shoot rifle.... play
pSoldier->ChangeSoldierState( PRONE_SHOOT_UNJAM, 0 , FALSE );
return( TRUE );
case CROUCHED_BURST:
case SHOOT_RIFLE_CROUCH:
// Normal shoot rifle.... play
pSoldier->ChangeSoldierState( CROUCH_SHOOT_UNJAM, 0 , FALSE );
return( TRUE );
case SHOOT_DUAL_STAND:
case BURST_DUAL_STAND:
// Normal shoot rifle.... play
pSoldier->ChangeSoldierState( STANDING_SHOOT_DWEL_UNJAM, 0 , FALSE );
return( TRUE );
case SHOOT_DUAL_PRONE:
case BURST_DUAL_PRONE:
// Normal shoot rifle.... play
pSoldier->ChangeSoldierState( PRONE_SHOOT_DWEL_UNJAM, 0 , FALSE );
return( TRUE );
case SHOOT_DUAL_CROUCH:
case BURST_DUAL_CROUCH:
// Normal shoot rifle.... play
pSoldier->ChangeSoldierState( CROUCH_SHOOT_DWEL_UNJAM, 0 , FALSE );
return( TRUE );
case FIRE_LOW_STAND:
case FIRE_BURST_LOW_STAND:
// Normal shoot rifle.... play
pSoldier->ChangeSoldierState( STANDING_SHOOT_LOW_UNJAM, 0 , FALSE );
return( TRUE );
case SHOOT_ALTERNATIVE_STAND:
case BURST_ALTERNATIVE_STAND:
// Normal shoot rifle.... play
pSoldier->ChangeSoldierState( UNJAM_ALTERNATIVE_STAND, 0 , FALSE );
return( TRUE );
case LOW_SHOT_ALTERNATIVE_STAND:
case LOW_BURST_ALTERNATIVE_STAND:
// Normal shoot rifle.... play
pSoldier->ChangeSoldierState( LOW_UNJAM_ALTERNATIVE_STAND, 0 , FALSE );
return( TRUE );
}
return( FALSE );
}
BOOLEAN OKFallDirection( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT8 ubTestDirection, UINT16 usAnimState )
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"OKFallDirection");
STRUCTURE_FILE_REF * pStructureFileRef;
UINT16 usAnimSurface;
UINT8 bOverTerrainType;
// WANNE - MP: MP crashed here, so I added the prevention
if (TileIsOutOfBounds(sGridNo))
return ( FALSE );
// How are the movement costs?
if ( gubWorldMovementCosts[ sGridNo ][ ubTestDirection ][ bLevel ] > TRAVELCOST_SHORE )
{
return( FALSE );
}
bOverTerrainType = GetTerrainType( sGridNo);
// WANNE.WATER: If our soldier is not on the ground level and the tile is a "water" tile, then simply set the tile to "FLAT_GROUND"
// This should fix "problems" for special modified maps
if ( TERRAIN_IS_WATER( bOverTerrainType) && bLevel > 0 )
bOverTerrainType = FLAT_GROUND;
//NOT ok if in water....
if ( TERRAIN_IS_WATER( bOverTerrainType) )
{
return( FALSE );
}
// How are we for OK dest?
if (!NewOKDestination( pSoldier, sGridNo, TRUE, bLevel ) )
{
return( FALSE );
}
usAnimSurface = DetermineSoldierAnimationSurface( pSoldier, usAnimState );
pStructureFileRef = GetAnimationStructureRef( pSoldier->ubID, usAnimSurface, usAnimState );
if ( pStructureFileRef )
{
UINT16 usStructureID;
INT32 sTestGridNo;
// must make sure that structure data can be added in the direction of the target
usStructureID = pSoldier->ubID;
// Okay this is really SCREWY but it's due to the way this function worked before and must
// work now. The function is passing in an adjacent gridno but we need to place the structure
// data in the tile BEFORE. So we take one step back in the direction opposite to bTestDirection
// and use that gridno
sTestGridNo = NewGridNo( sGridNo, DirectionInc( gOppositeDirection[ ubTestDirection ] ) );
if ( ! OkayToAddStructureToWorld( sTestGridNo, bLevel, &(pStructureFileRef->pDBStructureRef[ gOneCDirection[ ubTestDirection ] ]), usStructureID ) )
{
// can't go in that dir!
return( FALSE );
}
}
return( TRUE );
}
BOOLEAN HandleCheckForDeathCommonCode( SOLDIERTYPE *pSoldier )
{
//shadooow: fix for going back to cower animation after collapsing
if (pSoldier->CheckForBreathCollapse() || pSoldier->bCollapsed)
{
pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
pSoldier->usPendingAnimation2 = NO_PENDING_ANIMATION;
}
else
{
// Do we have a primary pending animation?
if (pSoldier->usPendingAnimation2 != NO_PENDING_ANIMATION)
{
pSoldier->ChangeSoldierState(pSoldier->usPendingAnimation2, 0, FALSE);
pSoldier->usPendingAnimation2 = NO_PENDING_ANIMATION;
return(TRUE);
}
// CHECK IF WE HAVE A PENDING ANIMATION HERE
if (pSoldier->usPendingAnimation != NO_PENDING_ANIMATION)
{
pSoldier->ChangeSoldierState(pSoldier->usPendingAnimation, 0, FALSE);
pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
return(TRUE);
}
}
// OTHERWISE, GOTO APPROPRIATE STOPANIMATION!
pSoldier->bCollapsed = TRUE;
// CC has requested - handle sight here...
HandleSight( pSoldier, SIGHT_LOOK );
// ATE: If it is our turn, make them try to getup...
if ( gTacticalStatus.ubCurrentTeam == pSoldier->bTeam )
{
// Try to getup...
pSoldier->BeginSoldierGetup( );
// Check this to see if above worked
if ( !pSoldier->bCollapsed )
{
return( TRUE );
}
}
switch( pSoldier->usAnimState )
{
case FLYBACK_HIT:
pSoldier->ChangeSoldierState( FLYBACKHIT_STOP, 0, FALSE );
break;
case GENERIC_HIT_DEATHTWITCHNB:
case FALLFORWARD_FROMHIT_STAND:
case ENDFALLFORWARD_FROMHIT_CROUCH:
pSoldier->ChangeSoldierState( STAND_FALLFORWARD_STOP, 0, FALSE );
break;
case FALLBACK_HIT_DEATHTWITCHNB:
case FALLBACK_HIT_STAND:
pSoldier->ChangeSoldierState( FALLBACKHIT_STOP, 0, FALSE );
break;
case PRONE_HIT_DEATHTWITCHNB:
case PRONE_LAY_FROMHIT:
pSoldier->ChangeSoldierState( PRONE_LAYFROMHIT_STOP, 0, FALSE );
break;
case FALLOFF:
pSoldier->ChangeSoldierState( FALLOFF_STOP, 0, FALSE );
break;
case FALLFORWARD_ROOF:
pSoldier->ChangeSoldierState( FALLOFF_FORWARD_STOP, 0, FALSE);
break;
default:
// IF we are here - something is wrong - we should have a death animation here
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Ani: unconscious hit sequence needed for animation %d", pSoldier->usAnimState ) );
}
// OTHERWISE, GOTO APPROPRIATE STOPANIMATION!
pSoldier->bCollapsed = TRUE;
// ATE: If it is our turn, make them try to getup...
if ( gTacticalStatus.ubCurrentTeam == pSoldier->bTeam )
{
// Try to getup...
pSoldier->BeginSoldierGetup( );
// Check this to see if above worked
if ( !pSoldier->bCollapsed )
{
return( TRUE );
}
}
switch( pSoldier->usAnimState )
{
case FLYBACK_HIT:
pSoldier->ChangeSoldierState( FLYBACKHIT_STOP, 0, FALSE );
break;
case GENERIC_HIT_DEATHTWITCHNB:
case FALLFORWARD_FROMHIT_STAND:
case ENDFALLFORWARD_FROMHIT_CROUCH:
pSoldier->ChangeSoldierState( STAND_FALLFORWARD_STOP, 0, FALSE );
break;
case FALLBACK_HIT_DEATHTWITCHNB:
case FALLBACK_HIT_STAND:
pSoldier->ChangeSoldierState( FALLBACKHIT_STOP, 0, FALSE );
break;
case PRONE_HIT_DEATHTWITCHNB:
case PRONE_LAY_FROMHIT:
pSoldier->ChangeSoldierState( PRONE_LAYFROMHIT_STOP, 0, FALSE );
break;
case FALLOFF:
pSoldier->ChangeSoldierState( FALLOFF_STOP, 0, FALSE );
break;
case FALLFORWARD_ROOF:
pSoldier->ChangeSoldierState( FALLOFF_FORWARD_STOP, 0, FALSE);
break;
default:
// IF we are here - something is wrong - we should have a death animation here
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Ani: unconscious hit sequence needed for animation %d", pSoldier->usAnimState ) );
}
return( TRUE );
}
void KickOutWheelchair( SOLDIERTYPE *pSoldier )
{
INT32 sNewGridNo;
// Move forward one gridno....
sNewGridNo = NewGridNo( pSoldier->sGridNo, DirectionInc( pSoldier->ubDirection ) );
// ATE: Make sure that the gridno is unoccupied!
if ( !NewOKDestination( pSoldier, sNewGridNo, TRUE, pSoldier->pathing.bLevel ) )
{
// We should just stay put - will look kind of funny but nothing I can do!
sNewGridNo = pSoldier->sGridNo;
}
pSoldier->EVENT_StopMerc( sNewGridNo, pSoldier->ubDirection );
pSoldier->ubBodyType = REGMALE;
if ( pSoldier->ubProfile == SLAY && pSoldier->bTeam == CIV_TEAM && !pSoldier->aiData.bNeutral )
{
HandleNPCDoAction( pSoldier->ubProfile, NPC_ACTION_THREATENINGLY_RAISE_GUN, 0 );
}
else
{
pSoldier->EVENT_InitNewSoldierAnim( STANDING, 0 , TRUE );
}
// If this person has a profile ID, set body type to regmale
if ( pSoldier->ubProfile != NO_PROFILE )
{
gMercProfiles[ pSoldier->ubProfile ].ubBodyType = REGMALE;
}
}