Files
source/Tactical/Soldier Ani.cpp
T
Overhaul 99e45d697e Fix to make soldier continue towards destination if previous path ended with a special move
Re-integrated LUA and console.  Still many things to finish though.


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1048 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-07-14 04:25:07 +00:00

4107 lines
119 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include <stdio.h>
#include <string.h>
#include "wcheck.h"
#include "stdlib.h"
#include "debug.h"
#include "MemMan.h"
#include "Overhead Types.h"
#include "Soldier Control.h"
#include "Animation Cache.h"
#include "Animation Data.h"
#include "Animation Control.h"
#include "weapons.h"
#include "soldier ani.h"
#include "Random.h"
#include "video.h"
#include "vobject_blitters.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 "soldier functions.h"
#include "interface.h"
#include "qarray.h"
#include "soldier macros.h"
#include "Strategic Town Loyalty.h"
#include "Squads.h"
#include "worldman.h"
#include "structure wrap.h"
#include "pathai.h"
#include "pits.h"
#include "text.h"
#include "npc.h"
#include "meanwhile.h"
#include "Explosion Control.h"
#include "fov.h"
#include "campaign.h"
#include "los.h"
#include "GameSettings.h"
#include "Boxing.h"
#include "drugs and alcohol.h"
#include "Smell.h"
#include "GameSettings.h"
#include "interface dialogue.h"
#include "Strategic Status.h"
#endif
#define NO_JUMP 0
#define MAX_ANIFRAMES_PER_FLASH 2
//#define TIME_FOR_RANDOM_ANIM_CHECK 10
#define TIME_FOR_RANDOM_ANIM_CHECK 2
BOOLEAN 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.1, 1, 1 };
BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse );
void CheckForAndHandleSoldierIncompacitated( SOLDIERTYPE *pSoldier );
BOOLEAN CheckForImproperFireGunEnd( SOLDIERTYPE *pSoldier );
BOOLEAN OKHeightDest( SOLDIERTYPE *pSoldier, INT16 sNewGridNo );
BOOLEAN HandleUnjamAnimation( SOLDIERTYPE *pSoldier );
extern void HandleSystemNewAISituation( SOLDIERTYPE *pSoldier, BOOLEAN fResetABC );
extern void PlaySoldierFootstepSound( SOLDIERTYPE *pSoldier );
extern UINT8 NumCapableEnemyInSector( );
extern BOOLEAN gfKillingGuysForLosingBattle;
extern UINT8 gubInterruptProvoker;
extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady );
// 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;
INT16 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->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->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
ConvertAniCodeToAniFrame( pSoldier, (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->fPausedMove = TRUE;
break;
case 403:
// MOVE GUY FORWARD SOME VALUE
MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)0.7 );
break;
case 404:
// MOVE GUY BACKWARD SOME VALUE
// Use same function as forward, but is -ve values!
MoveMercFacingDirection( pSoldier , TRUE, (FLOAT)1 );
break;
case 405:
return( TRUE );
case 406:
// Move merc up
if ( pSoldier->bDirection == NORTH )
{
SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->sHeightAdjustment + 2 ) );
}
else
{
SetSoldierHeight( pSoldier, (FLOAT)( pSoldier->sHeightAdjustment + 3 ) );
}
break;
case 408:
// CODE: SPECIAL MOVE CLIMB UP ROOF EVENT
// re-enable sight
gTacticalStatus.uiFlags &= (~DISALLOW_SIGHT);
{
INT16 sXPos, sYPos;
//usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)DirectionInc( pSoldier->bDirection ) );
ConvertMapPosToWorldTileCenter( pSoldier->sTempNewGridNo, &sXPos, &sYPos );
EVENT_SetSoldierPosition( pSoldier, (FLOAT)sXPos, (FLOAT)sYPos );
}
// Move two CC directions
EVENT_SetSoldierDirection( pSoldier, gTwoCCDirection[ pSoldier->bDirection ] );
EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
// Set desired anim height!
pSoldier->ubDesiredHeight = ANIM_CROUCH;
// Madd
usUIMovementMode = GetMoveStateBasedOnStance( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
pSoldier->usUIMovementMode = usUIMovementMode;
// Move merc up specific height
SetSoldierHeight( pSoldier, (FLOAT)50 );
// 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
SetSoldierHeight( pSoldier, (FLOAT)( pSoldier->sHeightAdjustment - 2 ) );
break;
case 410:
// Move merc down specific height
SetSoldierHeight( pSoldier, (FLOAT)0 );
break;
case 411:
// CODE: SPECIALMOVE CLIMB DOWN EVENT
// Move two C directions
EVENT_SetSoldierDirection( pSoldier, gTwoCDirection[ pSoldier->bDirection ] );
EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
// Adjust height
SetSoldierHeight( pSoldier, (FLOAT)gClimbDownRoofStartDist[ pSoldier->ubBodyType ] );
// 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:
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;
AddGameEvent( S_FIREWEAPON, 0, &SFireWeapon );
//DIGICRAB: Burst UnCap
//Loop around in the animation if we still have burst rounds to fire
if (pSoldier->bDoBurst && (pSoldier->bDoBurst <= ((pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst(&pSoldier->inv[HANDPOS]))) || (( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst <= Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst)) ))
{
if(pSoldier->usAnimState == 44 || pSoldier->usAnimState == 109 || pSoldier->usAnimState == 108 && pSoldier->usAniCode == 33) //we are standing, crounching or prone, firing the fast shot
pSoldier->usAniCode = 3;
else if(pSoldier->usAnimState == 175 && pSoldier->usAniCode == 37) //we are firing down to something very close, last shot
pSoldier->usAniCode = 14;
}
//DIGICRAB: Burst Sound
//This code is stolen from Tactical\Weapons.c - UseGun(...)
if (pSoldier->bDoBurst && pSoldier->iBurstSoundID == NO_SAMPLE && Weapon[ pSoldier->usAttackingWeapon ].sSound != 0 && Item[ pSoldier->usAttackingWeapon ].usItemClass != IC_THROWING_KNIFE )
{
// Switch on silencer...
INT16 noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
if( noisefactor < MAX_PERCENT_NOISE_VOLUME_FOR_SILENCED_SOUND || Weapon[ pSoldier->usAttackingWeapon ].ubAttackVolume <= 10 )
{
INT32 uiSound;
uiSound = Weapon [ pSoldier->usAttackingWeapon ].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[ pSoldier->usAttackingWeapon ].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
// DoMercBattleSound( pSoldier, 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;
ChangeSoldierState( pSoldier, 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
ChangeSoldierState( pSoldier, (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
ChangeSoldierState( pSoldier, usOldAnimState, 0, FALSE );
return( TRUE );
}
break;
case 437:
// CHANGE DIRECTION AND GET-UP
//sGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)(-1 * DirectionInc( pSoldier->bDirection ) ) );
//ConvertMapPosToWorldTileCenter( pSoldier->sGridNo, &sXPos, &sYPos );
//SetSoldierPosition( pSoldier, (FLOAT)sXPos, (FLOAT)sYPos );
// Reverse direction
EVENT_SetSoldierDirection( pSoldier, gOppositeDirection[ pSoldier->bDirection ] );
EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
ChangeSoldierState( pSoldier, GETUP_FROM_ROLLOVER, 0 , FALSE );
return( TRUE );
case 438:
//CODE: START HOLD FLASH
pSoldier->fForceShade = TRUE;
break;
case 439:
//CODE: END HOLD FLASH
pSoldier->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->uiPendingActionData1 );
}
CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse );
if ( fMadeCorpse )
{
return( FALSE );
}
else
{
return( TRUE );
}
}
break;
case 441:
// CODE: Show muzzle flash
if ( pSoldier->bVisible == -1 )
{
break;
}
if ( !pSoldier->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
{
UINT16 usNewGridNo;
INT16 sXPos, sYPos;
usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( pSoldier->bDirection ) );
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->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 )
{
UnSetUIBusy( pSoldier->ubID );
}
break;
case 443:
// MOVE GUY FORWARD FOR FENCE HOP ANIMATION
switch( pSoldier->bDirection )
{
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
sX = CenterX( pSoldier->sForcastGridno );
sY = CenterY( pSoldier->sForcastGridno );
EVENT_InternalSetSoldierPosition( pSoldier, (FLOAT) sX, (FLOAT) sY, FALSE, FALSE, FALSE );
EVENT_SetSoldierDirection( pSoldier, gTwoCDirection[ pSoldier->bDirection ] );
pSoldier->sZLevelOverride = -1;
EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
if ( gTacticalStatus.bBoxingState == BOXING_WAITING_FOR_PLAYER || gTacticalStatus.bBoxingState == PRE_BOXING || gTacticalStatus.bBoxingState == BOXING )
{
BoxingMovementCheck( pSoldier );
}
if ( SetOffBombsInGridNo( pSoldier->ubID, pSoldier->sGridNo, FALSE, pSoldier->bLevel ))
{
EVENT_StopMerc( pSoldier, pSoldier->sGridNo, pSoldier->bDirection );
return( TRUE );
}
// If we are at our final destination, goto stance of our movement stance...
// Only in realtime...
//if ( !( gTacticalStatus.uiFlags & INCOMBAT ) )
// This has to be here to make guys continue along fence path
#if 0
if ( pSoldier->sGridNo == pSoldier->sFinalDestination )
{
if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != gAnimControl[ pSoldier->usUIMovementMode ].ubEndHeight )
{
// Goto Stance...
pSoldier->fDontChargeAPsForStanceChange = TRUE;
ChangeSoldierStance( pSoldier, gAnimControl[ pSoldier->usUIMovementMode ].ubEndHeight );
return( TRUE );
}
else
{
//SoldierGotoStationaryStance( pSoldier );
// Set UI Busy
UnSetUIBusy( pSoldier->ubID );
//return( TRUE );
}
}
#endif
break;
case 445:
// CODE: MOVE GUY FORWARD ONE TILE, BASED ON WHERE WE ARE FACING
switch( pSoldier->bDirection )
{
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->uiStatusFlags |= SOLDIER_PAUSEANIMOVE;
break;
case 447:
// TRY TO FALL!!!
if ( pSoldier ->fTryingToFall )
{
INT16 sLastAniFrame;
// TRY FORWARDS...
// FIRST GRIDNO
sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) );
if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->bLevel, pSoldier->bDirection, FALLFORWARD_HITDEATH_STOP ) )
{
// SECOND GRIDNO
// sNewGridNo = NewGridNo( (UINT16)sNewGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) );
// if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->bLevel, pSoldier->bDirection, FALLFORWARD_HITDEATH_STOP ) )
{
// ALL'S OK HERE...
pSoldier->fTryingToFall = FALSE;
break;
}
}
// IF HERE, INCREMENT DIRECTION
// ATE: Added Feb1 - can be either direction....
if ( pSoldier->fFallClockwise )
{
EVENT_SetSoldierDirection( pSoldier, gOneCDirection[ pSoldier->bDirection ] );
}
else
{
EVENT_SetSoldierDirection( pSoldier, gOneCCDirection[ pSoldier->bDirection ] );
}
EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
sLastAniFrame = gusAnimInst[ pSoldier->usAnimState ][ ( pSoldier->usAniCode - 2 ) ];
ConvertAniCodeToAniFrame( pSoldier, (INT16)( sLastAniFrame ) );
if ( pSoldier->bDirection == pSoldier->bStartFallDir )
{
// GO FORWARD HERE...
pSoldier ->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;
if ( ( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst > Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst) || (pSoldier->bWeaponMode != WM_ATTACHED_GL_BURST && pSoldier->bDoBurst > ((pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst(&pSoldier->inv[HANDPOS])))) )
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because burst size too large");
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->autofireLastStep = FALSE;
pSoldier->bDoAutofire = 1;
}
pSoldier->fDoSpread = FALSE;
pSoldier->bDoBurst = 1;
// pSoldier->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 ) )
{
ChangeSoldierState( pSoldier, STANDING, 0 , FALSE );
}
else
{
switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
{
case ANIM_STAND:
ChangeSoldierState( pSoldier, AIM_RIFLE_STAND, 0 , FALSE );
break;
case ANIM_PRONE:
ChangeSoldierState( pSoldier, AIM_RIFLE_PRONE, 0 , FALSE );
break;
case ANIM_CROUCH:
ChangeSoldierState( pSoldier, AIM_RIFLE_CROUCH, 0 , FALSE );
break;
}
}
return( TRUE );
}
// MOVETO CURRENT SPREAD LOCATION
if ( pSoldier->fDoSpread )
{
if ( pSoldier->sSpreadLocations[ pSoldier->fDoSpread - 1 ] != 0 )
{
EVENT_SetSoldierDirection( pSoldier, (INT8)GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, pSoldier->sSpreadLocations[ pSoldier->fDoSpread - 1 ] ) );
EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
}
}
break;
case 449:
//CODE: FINISH BURST
pSoldier->fDoSpread = FALSE;
pSoldier->bDoBurst = 1;
// pSoldier->fBurstCompleted = TRUE;
break;
case 450:
//CODE: BEGINHOPFENCE
// MOVE TWO FACGIN GRIDNOS
sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) );
sNewGridNo = NewGridNo( (UINT16)sNewGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) );
pSoldier->sForcastGridno = sNewGridNo;
break;
case 451:
// CODE: MANAGE START z-buffer override
switch( pSoldier->bDirection )
{
case NORTH:
case WEST:
pSoldier->sZLevelOverride = TOPMOST_Z_LEVEL;
break;
}
break;
case 452:
// CODE: MANAGE END z-buffer override
switch( pSoldier->bDirection )
{
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->bDirection == NORTH )
{
SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment + gClimbUpRoofDist[ pSoldier->ubBodyType ] ) );
}
else
{
SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment + gClimbUpRoofDist[ pSoldier->ubBodyType ] ) );
}
break;
case 455:
// MOVE GUY FORWARD SOME VALUE
MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gClimbUpRoofLATDist[ pSoldier->ubBodyType ] );
// MOVE DOWN SOME VALUE TOO!
SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment - gClimbUpRoofDistGoingLower[ pSoldier->ubBodyType ] ) );
break;
case 456:
// CODE: HANDLE CLIMBING ROOF,
// Move merc DOWN
if ( pSoldier->bDirection == NORTH )
{
SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment - gClimbUpRoofDist[ pSoldier->ubBodyType ] ) );
}
else
{
SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->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->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->fReloading = FALSE;
break;
case 460:
case 461:
//CODE: THORW 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 );
}
else
{
// ATE: Deduct points!
DeductPoints( pSoldier, AP_TOSS_ITEM, 0 );
}
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 );
// Remove object
//RemoveObjFrom( &(pSoldier->inv[ HANDPOS ] ), 0 );
// Update UI
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
MemFree( pSoldier->pTempObject );
pSoldier->pTempObject = NULL;
MemFree( pSoldier->pThrowParams );
pSoldier->pThrowParams = NULL;
}
break;
case 462:
// CODE: MOVE UP FROM CLIFF CLIMB
pSoldier->dHeightAdjustment += (float)2.1;
pSoldier->sHeightAdjustment = (INT16)pSoldier->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->dHeightAdjustment = (float)0;
pSoldier->sHeightAdjustment = (INT16)pSoldier->dHeightAdjustment;
// Set new gridno
{
INT16 sTempGridNo, sNewX, sNewY;
//Get Next GridNo;
sTempGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (INT16)( DirectionInc(pSoldier->bDirection ) ) );
// Get center XY
ConvertGridNoToCenterCellXY( sTempGridNo, &sNewX, &sNewY );
// Set position
EVENT_SetSoldierPosition( pSoldier, sNewX, sNewY );
// Move two CC directions
EVENT_SetSoldierDirection( pSoldier, gTwoCCDirection[ pSoldier->bDirection ] );
EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
// Set desired anim height!
pSoldier->ubDesiredHeight = ANIM_CROUCH;
pSoldier->sFinalDestination = pSoldier->sGridNo;
}
break;
case 465:
// CODE: SET GUY TO LIFE OF 0
pSoldier->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!
SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment - 2 ) );
}
else
{
// Adjust!
SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment + 2 ) );
}
}
else
{
// Adjust!
SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->sDesiredHeight) );
}
}
else
{
// Goto eating animation
if ( pSoldier->sDesiredHeight == 0 )
{
ChangeSoldierState( pSoldier, CROW_EAT, 0 , FALSE );
}
else
{
// We should leave now!
TacticalRemoveSoldier( pSoldier->ubID );
return( FALSE );
}
return( TRUE );
}
break;
case 467:
///CODE: FOR HELIDROP, SET DIRECTION
EVENT_SetSoldierDirection( pSoldier, EAST );
EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
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!
EVENT_GetNewSoldierPath( pSoldier, sNewGridNo, WALKING );
return( TRUE );
break;
case 468:
// CODE: End PUNCH
{
BOOLEAN fNPCPunch = FALSE;
// ATE: Put some code in for NPC punches...
if ( pSoldier->uiStatusFlags & SOLDIER_NPC_DOING_PUNCH )
{
fNPCPunch = TRUE;
// Turn off
pSoldier->uiStatusFlags &= (~SOLDIER_NPC_DOING_PUNCH );
// Trigger approach...
TriggerNPCWithGivenApproach( pSoldier->ubProfile, (UINT8)pSoldier->uiPendingActionData4, FALSE );
}
// Are we a martial artist?
{
BOOLEAN fMartialArtist = FALSE;
if ( pSoldier->ubProfile != NO_PROFILE )
{
if ( gMercProfiles[ pSoldier->ubProfile ].bSkillTrait == MARTIALARTS || gMercProfiles[ pSoldier->ubProfile ].bSkillTrait2 == MARTIALARTS )
{
fMartialArtist = TRUE;
}
}
if ( gAnimControl[ pSoldier->usAnimState ].ubHeight == ANIM_CROUCH )
{
if ( fNPCPunch )
{
ChangeSoldierStance( pSoldier, ANIM_STAND );
return( TRUE );
}
else
{
ChangeSoldierState( pSoldier, CROUCHING, 0, FALSE );
return( TRUE );
}
}
else
{
if ( fMartialArtist && !AreInMeanwhile( ) )
{
ChangeSoldierState( pSoldier, NINJA_BREATH, 0, FALSE );
return( TRUE );
}
else
{
ChangeSoldierState( pSoldier, PUNCH_BREATH, 0, FALSE );
return( TRUE );
}
}
}
}
break;
case 469:
// CODE: Begin martial artist attack
DoNinjaAttack( pSoldier );
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->uiStatusFlags &= (~SOLDIER_PAUSEANIMOVE);
break;
case 472:
{
BOOLEAN fGoBackToAimAfterHit;
// Save old flag, then reset. If we do nothing special here, at least go back
// to aim if we were.
fGoBackToAimAfterHit = pSoldier->fGoBackToAimAfterHit;
pSoldier->fGoBackToAimAfterHit = FALSE;
if ( !( pSoldier->uiStatusFlags & SOLDIER_TURNINGFROMHIT ) )
{
switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight )
{
case ANIM_STAND:
// OK, we can do some cool things here - first is to make guy walkl back a bit...
// ChangeSoldierState( pSoldier, STANDING_HIT_BEGINCROUCHDOWN, 0, FALSE );
// return( TRUE );
break;
}
}
// CODE: HANDLE ANY RANDOM HIT VARIATIONS WE WISH TO DO.....
if ( fGoBackToAimAfterHit )
{
if ( pSoldier->bLife >= OKLIFE )
{
InternalSoldierReadyWeapon( pSoldier, pSoldier->bDirection, 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
ChangeSoldierStance( pSoldier, ANIM_STAND );
return( TRUE );
case 475:
// CODE: END CLIMB DOWN ROOF
pSoldier->ubDesiredHeight = ANIM_STAND;
pSoldier->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 );
}
pSoldier->usUIMovementMode = WALKING;
// ATE: Handle sight...
HandleSight( pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT );
break;
case 476:
// CODE: GOTO PREVIOUS ANIMATION
ChangeSoldierState( pSoldier, ( pSoldier->sPendingActionData2 ), (UINT8)( pSoldier->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 && MercPtrs[ 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!
if ( pSoldier->ubBodyType <= REGFEMALE )
{
// Secondly, don't if we are going to collapse
if ( pSoldier->bLife >= OKLIFE && pSoldier->bBreath > 0 && pSoldier->bLevel == 0 )
{
// Save old direction
pSoldier->uiPendingActionData1 = pSoldier->bDirection;
// 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->bDirection ];
}
// 30 % chance to change direction the other way
else if ( uiChance >= 30 && uiChance < 60 )
{
bNewDirection = gOneCCDirection[ pSoldier->bDirection ];
}
// 30 % normal....
else
{
bNewDirection = pSoldier->bDirection;
}
EVENT_SetSoldierDirection( pSoldier, bNewDirection );
EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection );
}
else
{
// OK, 50% chance here to turn...
uiChance = Random( 100 );
if ( uiChance < 50 )
{
// OK, pick a larger direction to goto....
pSoldier->uiStatusFlags |= SOLDIER_TURNINGFROMHIT;
// This becomes an attack busy situation
gTacticalStatus.ubAttackBusyCount++;
DebugAttackBusy( String( "Soldier turning from a hit. Increasing attack busy. Now %d\n", gTacticalStatus.ubAttackBusyCount ) );
// Pick evenly between both
if ( Random( 50 ) < 25 )
{
bNewDirection = gOneCDirection[ pSoldier->bDirection ];
bNewDirection = gOneCDirection[ bNewDirection ];
bNewDirection = gOneCDirection[ bNewDirection ];
}
else
{
bNewDirection = gOneCCDirection[ pSoldier->bDirection ];
bNewDirection = gOneCCDirection[ bNewDirection ];
bNewDirection = gOneCCDirection[ bNewDirection ];
}
EVENT_SetSoldierDesiredDirection( pSoldier, bNewDirection );
}
}
}
}
break;
}
case 479:
// CODE: Return to old direction......
if ( pSoldier->ubBodyType <= REGFEMALE )
{
// Secondly, don't if we are going to collapse
//if ( pSoldier->bLife >= OKLIFE && pSoldier->bBreath > 0 )
//{
/// if ( !( pSoldier->uiStatusFlags & SOLDIER_TURNINGFROMHIT ) )
// {
/// pSoldier->bDirection = (INT8)pSoldier->uiPendingActionData1;
// pSoldier->bDesiredDirection = (INT8)pSoldier->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->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->sPendingActionData2 );
break;
case 484:
// CODE: HANDLE REMOTE...
HandleSoldierUseRemote( pSoldier, pSoldier->sPendingActionData2 );
break;
case 485:
// CODE: Try steal.....
// UnSetUIBusy( pSoldier->ubID);
UseHandToHand( pSoldier, pSoldier->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 )
{
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
//ChangeSoldierState( pSoldier, 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 ].usItem != NOTHING )
{
// CHECK IF GUN
if ( Item[ pSoldier->inv[ HANDPOS ].usItem ].usItemClass == IC_GUN )
{
if ( Weapon[ pSoldier->inv[ HANDPOS ].usItem ].ubWeaponClass != HANDGUNCLASS )
{
// RAISE
ChangeSoldierState( pSoldier, RAISE_RIFLE, 0 , FALSE );
return( TRUE );
}
}
}
*/
break;
case 491:
// CODE: HANDLE RANDOM BREATH ANIMATION
//if ( pSoldier->bLife > INJURED_CHANGE_THREASHOLD )
if ( pSoldier->bLife >= OKLIFE )
{
// Increment time from last update
pSoldier->uiTimeOfLastRandomAction++;
if ( pSoldier->uiTimeOfLastRandomAction > TIME_FOR_RANDOM_ANIM_CHECK || pSoldier->bLife < INJURED_CHANGE_THREASHOLD || GetDrunkLevel( pSoldier ) >= BORDERLINE )
{
pSoldier->uiTimeOfLastRandomAction = 0;
// Don't do any in water!
if ( !MercInWater( pSoldier ) )
{
// 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 ( usItem != NOTHING )
{
if ( Item[ usItem ].usItemClass == IC_GUN )
{
// if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) )
if ( (Item[ usItem ].twohanded ) )
{
// Set to rifle
ubRandomHandIndex = RANDOM_ANIM_RIFLEINHAND;
}
else
{
// Don't EVER do a trivial anim...
break;
}
}
}
// Check which animation to play....
for ( cnt = 0; cnt < MAX_RANDOM_ANIMS_PER_BODYTYPE; cnt++ )
{
pAnimDef = &( gRandomAnimDefs[ pSoldier->ubBodyType ][ cnt ] );
if ( pAnimDef->sAnimID != 0 )
{
// If it's an injured animation and we are not in the threashold....
if ( ( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && pSoldier->bLife >= INJURED_CHANGE_THREASHOLD )
{
continue;
}
// If we need to do an injured one, don't do any others...
if ( !( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && pSoldier->bLife < INJURED_CHANGE_THREASHOLD )
{
continue;
}
// If it's a drunk animation and we are not in the threashold....
if ( ( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && GetDrunkLevel( pSoldier ) < BORDERLINE )
{
continue;
}
// If we need to do an injured one, don't do any others...
if ( !( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && GetDrunkLevel( pSoldier ) >= BORDERLINE )
{
continue;
}
// Check if it's our hand
if ( pAnimDef->ubHandRestriction != RANDOM_ANIM_IRRELEVENTINHAND && pAnimDef->ubHandRestriction != ubRandomHandIndex )
{
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 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 ) )
{
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 ) )
{
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( 2 ) == 1 )
{
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) && pSoldier->bVisible == -1 )
{
// DO this every 10th time or so...
if ( Random( 100 ) < 10 )
{
// Play sound
PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
else
{
// Play sound
PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
}
else
{
// Play sound
PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
else
{
ChangeSoldierState( pSoldier, pAnimDef->sAnimID, 0 , FALSE );
}
return( TRUE );
}
}
}
}
}
}
}
break;
case 492:
// SIGNAL DODGE!
// ATE: Only do if we're not inspecial case...
if ( !( pSoldier->uiStatusFlags & SOLDIER_NPC_DOING_PUNCH ) )
{
SOLDIERTYPE *pTSoldier;
UINT32 uiMercFlags;
UINT16 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->bOppList[ pSoldier->ubID ] != 0 || pTSoldier->bTeam == pSoldier->bTeam )
{
if ( gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND )
{
// OK, stop merc....
EVENT_StopMerc( pTSoldier, pTSoldier->sGridNo, pTSoldier->bDirection );
if ( pTSoldier->bTeam != gbPlayerNum )
{
CancelAIAction( pTSoldier, TRUE );
}
// Turn towards the person!
EVENT_SetSoldierDesiredDirection( pTSoldier, GetDirectionFromGridNo( pSoldier->sGridNo, pTSoldier ) );
// PLAY SOLDIER'S DODGE ANIMATION
ChangeSoldierState( pTSoldier, DODGE_ONE, 0 , FALSE );
}
}
}
}
}
break;
case 493:
//CODE: PICKUP ITEM!
// CHECK IF THIS EVENT HAS BEEN SETUP
//if ( pSoldier->ubPendingAction == MERC_PICKUPITEM )
//{
// DROP ITEM
HandleSoldierPickupItem( pSoldier, pSoldier->uiPendingActionData1, (INT16)(pSoldier->uiPendingActionData4 ), pSoldier->bPendingActionData3 );
// EVENT HAS BEEN HANDLED
pSoldier->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->ubPendingAction == MERC_OPENSTRUCT )
//{
SoldierHandleInteractiveObject( pSoldier );
// EVENT HAS BEEN HANDLED
pSoldier->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->bAction == AI_ACTION_UNLOCK_DOOR || (pSoldier->bAction == AI_ACTION_LOCK_DOOR && !(pSoldier->fAIFlags & AI_LOCK_DOOR_INCLUDES_CLOSE) ) )
{
// EVENT HAS BEEN HANDLED
pSoldier->ubPendingAction = NO_PENDING_ACTION;
// do nothing here
}
else
{
pSoldier->fAIFlags &= ~(AI_LOCK_DOOR_INCLUDES_CLOSE);
pSoldier->ubDoorOpeningNoise = DoorOpeningNoise( pSoldier );
if ( SoldierHandleInteractiveObject( pSoldier ) )
{
// HANDLE SIGHT!
//HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT );
InitOpplistForDoorOpening();
MakeNoise( pSoldier->ubID, pSoldier->sGridNo, pSoldier->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->ubPendingAction = NO_PENDING_ACTION;
}
break;
case 496:
// CODE: GOTO PREVIOUS ANIMATION
ChangeSoldierState( pSoldier, 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->bLife == 0 )
{
//HandleSoldierDeath( pSoldier );
// If guy is now dead, and we have not played death sound before, play
if ( pSoldier->bLife == 0 && !pSoldier->fDeadSoundPlayed )
{
if ( pSoldier->usAnimState != JFK_HITDEATH )
{
DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 );
pSoldier->fDeadSoundPlayed = TRUE;
}
}
if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] )
{
// If we are dead, play some death animations!!
switch( pSoldier->usAnimState )
{
case FLYBACK_HIT:
ChangeSoldierState( pSoldier, FLYBACK_HIT_DEATH, 0, FALSE );
break;
case GENERIC_HIT_DEATHTWITCHNB:
case FALLFORWARD_FROMHIT_STAND:
case ENDFALLFORWARD_FROMHIT_CROUCH:
ChangeSoldierState( pSoldier, GENERIC_HIT_DEATH, 0, FALSE );
break;
case FALLBACK_HIT_DEATHTWITCHNB:
case FALLBACK_HIT_STAND:
ChangeSoldierState( pSoldier, FALLBACK_HIT_DEATH, 0, FALSE );
break;
case PRONE_HIT_DEATHTWITCHNB:
case PRONE_LAY_FROMHIT:
ChangeSoldierState( pSoldier, PRONE_HIT_DEATH, 0, FALSE );
break;
case FALLOFF:
ChangeSoldierState( pSoldier, FALLOFF_DEATH, 0, FALSE );
break;
case FALLFORWARD_ROOF:
ChangeSoldierState( pSoldier, FALLOFF_FORWARD_DEATH, 0, FALSE);
break;
case ADULTMONSTER_DYING:
ChangeSoldierState( pSoldier, ADULTMONSTER_DYING_STOP, 0, FALSE);
break;
case LARVAE_DIE:
ChangeSoldierState( pSoldier, LARVAE_DIE_STOP, 0, FALSE);
break;
case QUEEN_DIE:
ChangeSoldierState( pSoldier, QUEEN_DIE_STOP, 0, FALSE);
break;
case INFANT_DIE:
ChangeSoldierState( pSoldier, INFANT_DIE_STOP, 0, FALSE);
break;
case CRIPPLE_DIE:
ChangeSoldierState( pSoldier, CRIPPLE_DIE_STOP, 0, FALSE);
break;
case ROBOTNW_DIE:
ChangeSoldierState( pSoldier, ROBOTNW_DIE_STOP, 0, FALSE);
break;
case CRIPPLE_DIE_FLYBACK:
ChangeSoldierState( pSoldier, 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->fGettingHit = FALSE;
}
HandleCheckForDeathCommonCode( pSoldier );
return( TRUE );
}
break;
case 498:
// CONDITONAL JUMP
// If we have a pending animation, play it, else continue
if ( pSoldier->usPendingAnimation != NO_PENDING_ANIMATION )
{
ChangeSoldierState( pSoldier, pSoldier->usPendingAnimation, 0, FALSE );
pSoldier->usPendingAnimation = NO_PENDING_ANIMATION;
return( TRUE );
}
break;
// JUMP TO NEXT STATIONARY ANIMATION ACCORDING TO HEIGHT
case 499:
if (!(pSoldier->uiStatusFlags & SOLDIER_PC))
{
if ( pSoldier->bAction == AI_ACTION_PULL_TRIGGER )
{
if ( pSoldier->usAnimState == AI_PULL_SWITCH && gTacticalStatus.ubAttackBusyCount == 0 && gubElementsOnExplosionQueue == 0 )
{
FreeUpNPCFromPendingAction( pSoldier );
}
}
else if ( pSoldier->bAction == AI_ACTION_PENDING_ACTION
|| pSoldier->bAction == AI_ACTION_OPEN_OR_CLOSE_DOOR
|| pSoldier->bAction == AI_ACTION_YELLOW_ALERT
|| pSoldier->bAction == AI_ACTION_RED_ALERT
|| pSoldier->bAction == AI_ACTION_PULL_TRIGGER
|| pSoldier->bAction == AI_ACTION_CREATURE_CALL
|| pSoldier->bAction == AI_ACTION_UNLOCK_DOOR
|| pSoldier->bAction == AI_ACTION_LOCK_DOOR )
{
if ( pSoldier->usAnimState == PICKUP_ITEM || pSoldier->usAnimState == ADJACENT_GET_ITEM || 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->fContinueMoveAfterStanceChange )
{
usUIMovementMode = GetMoveStateBasedOnStance( pSoldier, 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;
}
}
pSoldier->ubDesiredHeight = NO_DESIRED_HEIGHT;
// 0verhaul: This is moved to the animation state transition code to make sure it isn't sidestepped.
// if (pSoldier->fChangingStanceDueToSuppression)
// {
// pSoldier->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->fTurningFromPronePosition != 3 ) && ( pSoldier->fTurningFromPronePosition != 1 ) )
{
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->fTurningFromPronePosition != 3 && pSoldier->fTurningFromPronePosition != 1 )
{
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 );
}
// Have we finished opening doors?
if ( 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..
EVENT_GetNewSoldierPath( pSoldier, pSoldier->sFinalDestination, pSoldier->usUIMovementMode );
if ( !( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_MOVING ) ) )
{
if ( pSoldier->sAbsoluteFinalDestination != NOWHERE )
{
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;
ChangeSoldierState( pSoldier, usPendingAnimation, 0, FALSE );
return( TRUE );
}
// Alrighty, do we wish to continue
if ( pSoldier->fContinueMoveAfterStanceChange )
{
// OK, if the code is == 2, get the path and try to move....
if ( pSoldier->fContinueMoveAfterStanceChange == 2 )
{
pSoldier->usPathIndex++;
if ( pSoldier->usPathIndex > pSoldier->usPathDataSize )
{
pSoldier->usPathIndex = pSoldier->usPathDataSize;
}
if ( pSoldier->usPathIndex == pSoldier->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->sFinalDestination)
{
if ( !EVENT_InternalGetNewSoldierPath( pSoldier, pSoldier->sFinalDestination, pSoldier->usUIMovementMode, 2, FALSE ) )
{
}
}
}
else
{
EVENT_InitNewSoldierAnim( pSoldier, pSoldier->usUIMovementMode, 0 , FALSE );
// UNSET LOCK PENDING ACTION COUNTER FLAG
pSoldier->uiStatusFlags &= ( ~SOLDIER_LOCKPENDINGACTIONCOUNTER );
}
}
else
{
SelectMoveAnimationFromStance( pSoldier );
}
pSoldier->fContinueMoveAfterStanceChange = FALSE;
return( TRUE );
}
SoldierGotoStationaryStance( pSoldier );
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
ChangeSoldierState( pSoldier, KNEEL_UP, 0 , FALSE );
return( TRUE );
}
if ( ubDesiredHeight == ANIM_CROUCH && ubCurrentHeight == ANIM_STAND )
{
// Return here because if now, we will skipp a few frames
ChangeSoldierState( pSoldier, 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
ChangeSoldierState( pSoldier, 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
ChangeSoldierState( pSoldier, 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
SoldierGotoStationaryStance( pSoldier );
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 )
{
// Jump, to animation script
EVENT_InitNewSoldierAnim( pSoldier, (UINT16)(sNewAniFrame - 600 ), 0 , FALSE );
return( TRUE );
}
else if ( sNewAniFrame > 799 && sNewAniFrame <= 899 )
{
// Jump, to animation script ( But in the 100's range )
EVENT_InitNewSoldierAnim( pSoldier, (UINT16)(sNewAniFrame - 700 ), 0 , FALSE );
return( TRUE );
}
else if ( sNewAniFrame > 899 && sNewAniFrame <= 999 )
{
// Jump, to animation script ( But in the 200's range )
EVENT_InitNewSoldierAnim( pSoldier, (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;
if ( usItem != NOTHING )
{
usSoundID = Weapon[ usItem ].sLocknLoadSound;
if ( usSoundID != 0 )
{
PlayJA2Sample( usSoundID, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
}
}
break;
case 709:
// Knife throw sound...
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->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
PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( SWOOSH_1 + Random( 6 ) ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE );
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
DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 );
pSoldier->fDeadSoundPlayed = TRUE;
break;
case 750:
// CODE: Move Vehicle UP
if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
{
// SetSoldierHeight( pSoldier, (FLOAT)( pSoldier->sHeightAdjustment + 1 ) );
}
break;
case 751:
// CODE: Move vehicle down
if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
{
// SetSoldierHeight( pSoldier, (FLOAT)( pSoldier->sHeightAdjustment - 1 ) );
}
break;
case 752:
// Code: decapitate
DecapitateCorpse( pSoldier, pSoldier->sTargetGridNo, pSoldier->bTargetLevel );
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 );
}
break;
case 754:
HandleFallIntoPitFromAnimation( pSoldier->ubID );
break;
case 755 :
DishoutQueenSwipeDamage( pSoldier );
break;
case 756:
// Reload robot....
{
UINT8 ubPerson;
SOLDIERTYPE *pRobot;
// Get pointer...
ubPerson = WhoIsThere2( pSoldier->sPendingActionData2, pSoldier->bLevel );
if ( ubPerson != NOBODY && MercPtrs[ ubPerson ]->uiStatusFlags & SOLDIER_ROBOT )
{
pRobot = MercPtrs[ 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->usItem != NOTHING )
{
// Add to inv..
AutoPlaceObject( pSoldier, pSoldier->pTempObject, TRUE );
}
MemFree( pSoldier->pTempObject );
pSoldier->pTempObject = NULL;
}
}
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 )
{
EVENT_InitNewSoldierAnim( pTarget, 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!
EVENT_SoldierGotHit( MercPtrs[ pSoldier->uiPendingActionData4 ], TAKE_DAMAGE_BLADE, (INT16) 25, (INT16) 25, gOppositeDirection[ pSoldier->bDirection ], 50, pSoldier->ubID, 0, ANIM_PRONE, 0, 0 );
}
break;
case 762:
{
// CODE: Set off Trigger
INT8 bPanicTrigger;
bPanicTrigger = ClosestPanicTrigger( pSoldier );
SetOffPanicBombs( pSoldier->ubID, bPanicTrigger );
// any AI guy has been specially given keys for this, now take them
// away
pSoldier->bHasKeys = pSoldier->bHasKeys >> 1;
}
break;
case 763:
// CODE: Drop item at gridno
if ( pSoldier->pTempObject != NULL )
{
if ( pSoldier->bVisible != -1 )
{
PlayJA2Sample( THROW_IMPACT_2, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
}
AddItemToPool( pSoldier->sPendingActionData2, pSoldier->pTempObject, 1, pSoldier->bLevel, 0 , -1 );
NotifySoldiersToLookforItems( );
MemFree( pSoldier->pTempObject );
pSoldier->pTempObject = NULL;
}
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...
{
INT16 sNewGridNo;
InternalDropBlood( pSoldier->sGridNo, pSoldier->bLevel, 0, (UINT8)(MAXBLOODQUANTITY), 1 );
// Move forward one gridno....
sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)( DirectionInc( gOppositeDirection[ pSoldier->bDirection ] ) ) );
InternalDropBlood( sNewGridNo, pSoldier->bLevel, 0, (UINT8)(MAXBLOODQUANTITY), 1 );
}
break;
case 766:
// Say COOL quote
DoMercBattleSound( pSoldier, 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...
ChangeSoldierStance( pSoldier, 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
{
UINT8 ubPerson;
SOLDIERTYPE *pVehicle;
// Get pointer to vehicle...
ubPerson = WhoIsThere2( pSoldier->sPendingActionData2, pSoldier->bLevel );
pVehicle = MercPtrs[ 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->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 )
{
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;
}
// Adjust frame control pos, and try again
pSoldier->usAniCode++;
}
else if ( sNewAniFrame == 999 )
{
// Go to start, by default
pSoldier->usAniCode = 0;
}
// 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_GotGunOrUsedGun[ pSoldier->ubProfile ] == 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 ( Random( 100 ) < 20 )
{
return( TRUE );
}
}
}
}
return( FALSE );
}
void SayBuddyWitnessedQuoteFromKill( SOLDIERTYPE *pKillerSoldier, INT16 sGridNo, INT8 bLevel )
{
UINT8 ubMercsInSector[ 20 ] = { 0 };
INT8 bBuddyIndex[ 20 ] = { -1 };
INT8 bTempBuddyIndex;
UINT8 ubNumMercs = 0;
UINT8 ubChosenMerc;
SOLDIERTYPE *pTeamSoldier;
INT32 cnt;
INT16 sDistVisible = FALSE;
UINT16 usQuoteNum;
// Loop through all our guys and randomly say one from someone in our sector
// set up soldier ptr as first element in mercptrs list
cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
// run through list
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++ )
{
// Add guy if he's a candidate...
if ( OK_INSECTOR_MERC( pTeamSoldier ) && !AM_AN_EPC( pTeamSoldier ) && !( pTeamSoldier->uiStatusFlags & SOLDIER_GASSED ) && !(AM_A_ROBOT( pTeamSoldier )) && !pTeamSoldier->fMercAsleep && pTeamSoldier->sGridNo != NOWHERE )
{
// 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;
}
// TO LOS check to killed
// Can we see location of killer?
sDistVisible = DistanceVisible( pTeamSoldier, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, pKillerSoldier->sGridNo, pKillerSoldier->bLevel, pKillerSoldier );
if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, pKillerSoldier->sGridNo, pKillerSoldier->bLevel, (UINT8)3, (UINT8) sDistVisible, TRUE ) == 0 )
{
continue;
}
// Can we see location of killed?
sDistVisible = DistanceVisible( pTeamSoldier, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel, pTeamSoldier );
if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, bLevel, (UINT8)3, (UINT8) sDistVisible, TRUE ) == 0 )
{
continue;
}
// OK, a good candidate...
ubMercsInSector[ ubNumMercs ] = (UINT8)cnt;
bBuddyIndex[ ubNumMercs ] = bTempBuddyIndex;
ubNumMercs++;
}
}
}
// If we are > 0
if ( ubNumMercs > 0 )
{
// Do random check here...
if ( Random( 100 ) < 20 )
{
ubChosenMerc = (UINT8)Random( ubNumMercs );
switch( bBuddyIndex[ ubChosenMerc ] )
{
case 0:
usQuoteNum = QUOTE_BUDDY_1_GOOD;
MercPtrs[ ubMercsInSector[ ubChosenMerc ] ]->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_1_WITNESSED;
break;
case 1:
usQuoteNum = QUOTE_BUDDY_2_GOOD;
MercPtrs[ ubMercsInSector[ ubChosenMerc ] ]->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_2_WITNESSED;
break;
case 2:
usQuoteNum = QUOTE_LEARNED_TO_LIKE_WITNESSED;
MercPtrs[ ubMercsInSector[ ubChosenMerc ] ]->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_3_WITNESSED;
break;
}
TacticalCharacterDialogue( MercPtrs[ ubMercsInSector[ ubChosenMerc ] ], usQuoteNum );
}
}
}
void HandleKilledQuote( SOLDIERTYPE *pKilledSoldier, SOLDIERTYPE *pKillerSoldier, INT16 sGridNo, INT8 bLevel )
{
SOLDIERTYPE *pTeamSoldier;
INT32 cnt;
UINT8 ubMercsInSector[ 20 ] = { 0 };
UINT8 ubNumMercs = 0;
UINT8 ubChosenMerc;
BOOLEAN fDoSomeoneElse = FALSE;
BOOLEAN fCanWeSeeLocation = FALSE;
INT16 sDistVisible = FALSE;
gfLastMercTalkedAboutKillingID = pKilledSoldier->ubID;
// Can we see location?
sDistVisible = DistanceVisible( pKillerSoldier, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel, pKillerSoldier );
fCanWeSeeLocation = ( SoldierTo3DLocationLineOfSightTest( pKillerSoldier, sGridNo, bLevel, (UINT8)3, (UINT8) sDistVisible, TRUE ) != 0 );
// Are we killing mike?
if ( pKilledSoldier->ubProfile == 149 && pKillerSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC )
{
// Can we see?
if ( fCanWeSeeLocation )
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_AIM_KILLED_MIKE );
}
}
// Are we killing factory mamager?
else if ( pKilledSoldier->ubProfile == 139 )
{
// 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....
cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
// run through list
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++ )
{
if ( cnt != pKillerSoldier->ubID )
{
if ( OK_INSECTOR_MERC( pTeamSoldier ) && !( pTeamSoldier->uiStatusFlags & SOLDIER_GASSED ) && !AM_AN_EPC( pTeamSoldier ) )
{
// Can we see location?
sDistVisible = DistanceVisible( pTeamSoldier, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel, pTeamSoldier );
if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, bLevel, 3, (UINT8) sDistVisible, TRUE ) )
{
ubMercsInSector[ ubNumMercs ] = (UINT8)cnt;
ubNumMercs++;
}
}
}
}
// Did we find anybody?
if ( ubNumMercs > 0 )
{
ubChosenMerc = (UINT8)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
// Randomize between laugh, quote...
{
if ( Random( 100 ) < 33 && pKilledSoldier->ubBodyType != BLOODCAT )
{
// If it's a creature......
if ( pKilledSoldier->uiStatusFlags & SOLDIER_MONSTER )
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_A_CREATURE );
}
else
{
TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_AN_ENEMY );
}
}
else
{
if ( Random( 50 ) == 25 )
{
DoMercBattleSound( pKillerSoldier, (INT8)( BATTLE_SOUND_LAUGH1 ) );
}
else
{
DoMercBattleSound( pKillerSoldier, (INT8)( BATTLE_SOUND_COOL1 ) );
}
}
}
// Buddy witnessed?
SayBuddyWitnessedQuoteFromKill( pKillerSoldier, sGridNo, bLevel );
}
}
}
}
}
BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
{
BOOLEAN fBuddyJustDead = FALSE;
*pfMadeCorpse = FALSE;
if ( pSoldier->bLife == 0 && !( pSoldier->uiStatusFlags & SOLDIER_DEAD ) )
{
// Cancel services here...
ReceivingSoldierCancelServices( pSoldier );
GivingSoldierCancelServices( pSoldier );
if ( pSoldier->iMuzFlash != -1 )
{
LightSpriteDestroy( pSoldier->iMuzFlash );
pSoldier->iMuzFlash = -1;
}
if ( pSoldier->iLight != -1 )
{
LightSpriteDestroy( pSoldier->iLight );
}
//FREEUP GETTING HIT FLAG
pSoldier->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->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->uiStatusFlags |= SOLDIER_DEAD;
}
}
else
{
UINT8 ubAssister;
// IF this guy has an attacker and he's a good guy, play sound
if ( pSoldier->ubAttackerID != NOBODY )
{
if ( MercPtrs[ pSoldier->ubAttackerID ]->bTeam == gbPlayerNum && gTacticalStatus.ubAttackBusyCount > 0 )
{
gTacticalStatus.fKilledEnemyOnAttack = TRUE;
gTacticalStatus.ubEnemyKilledOnAttack = pSoldier->ubID;
gTacticalStatus.ubEnemyKilledOnAttackLocation = pSoldier->sGridNo;
gTacticalStatus.bEnemyKilledOnAttackLevel = pSoldier->bLevel;
gTacticalStatus.ubEnemyKilledOnAttackKiller = pSoldier->ubAttackerID;
// 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( MercPtrs[ pSoldier->ubAttackerID ] ) )
{
DoMercBattleSound( MercPtrs[ pSoldier->ubAttackerID ], BATTLE_SOUND_LAUGH1 );
}
}
}
// Handle NPC Dead
HandleNPCTeamMemberDeath( pSoldier );
// if a friendly with a profile, increment kills
// militia also now track kills...
if ( pSoldier->ubAttackerID != NOBODY )
{
if ( MercPtrs[ pSoldier->ubAttackerID ]->bTeam == gbPlayerNum )
{
// increment kills
gMercProfiles[ MercPtrs[ pSoldier->ubAttackerID ]->ubProfile ].usKills++;
gStrategicStatus.usPlayerKills++;
}
else if ( MercPtrs[ pSoldier->ubAttackerID ]->bTeam == MILITIA_TEAM )
{
// get a kill! 2 points!
MercPtrs[ pSoldier->ubAttackerID ]->ubMilitiaKills += 2;
}
}
// JA2 Gold: if previous and current attackers are the same, the next-to-previous attacker gets the assist
if (pSoldier->ubPreviousAttackerID == pSoldier->ubAttackerID)
{
ubAssister = pSoldier->ubNextToPreviousAttackerID;
}
else
{
ubAssister = pSoldier->ubPreviousAttackerID;
}
if ( ubAssister != NOBODY && ubAssister != pSoldier->ubAttackerID )
{
if ( MercPtrs[ ubAssister ]->bTeam == gbPlayerNum )
{
gMercProfiles[ MercPtrs[ ubAssister ]->ubProfile ].usAssists++;
}
else if ( MercPtrs[ ubAssister ]->bTeam == MILITIA_TEAM )
{
// get an assist - 1 points
MercPtrs[ ubAssister ]->ubMilitiaKills += 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 ]->ubMilitiaKills += 1;
}
}
*/
}
if ( TurnSoldierIntoCorpse( pSoldier, TRUE, TRUE ) )
{
*pfMadeCorpse = TRUE;
}
// 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->fDoingExternalDeath )
// {
// // Release attacker
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, code 497 = handle soldier death") );
// ReleaseSoldiersAttacker( pSoldier );
// }
// }
if ( !( *pfMadeCorpse ) )
{
fBuddyJustDead = TRUE;
}
}
if ( pSoldier->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->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:
ChangeSoldierState( pSoldier, FLYBACK_HITDEATH_STOP, 0, FALSE );
break;
case GENERIC_HIT_DEATH:
ChangeSoldierState( pSoldier, FALLFORWARD_HITDEATH_STOP, 0, FALSE );
break;
case FALLBACK_HIT_DEATH:
ChangeSoldierState( pSoldier, FALLBACK_HITDEATH_STOP, 0, FALSE );
break;
case PRONE_HIT_DEATH:
ChangeSoldierState( pSoldier, PRONE_HITDEATH_STOP, 0, FALSE );
break;
case JFK_HITDEATH:
ChangeSoldierState( pSoldier, JFK_HITDEATH_STOP, 0, FALSE );
break;
case FALLOFF_DEATH:
ChangeSoldierState( pSoldier, FALLOFF_DEATH_STOP, 0, FALSE );
break;
case FALLOFF_FORWARD_DEATH:
ChangeSoldierState( pSoldier, FALLOFF_FORWARD_DEATH_STOP, 0, FALSE );
break;
case WATER_DIE:
ChangeSoldierState( pSoldier, WATER_DIE_STOP, 0, FALSE );
break;
case DEEP_WATER_DIE:
ChangeSoldierState( pSoldier, DEEP_WATER_DIE_STOPPING, 0, FALSE );
break;
case COW_DYING:
ChangeSoldierState( pSoldier, COW_DYING_STOP, 0, FALSE);
break;
case BLOODCAT_DYING:
ChangeSoldierState( pSoldier, 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 )
{
INT16 sNewGridNo;
if ( pSoldier->bLife < OKLIFE )
{
// Cancel services here...
ReceivingSoldierCancelServices( pSoldier );
GivingSoldierCancelServices( pSoldier );
// 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:
pSoldier->bLife = 0;
break;
}
// OK, if we are in a meanwhile and this is elliot...
if ( AreInMeanwhile( ) )
{
SOLDIERTYPE *pQueen;
pQueen = FindSoldierByProfileID( QUEEN, FALSE );
if ( pQueen )
{
TriggerNPCWithGivenApproach( QUEEN, APPROACH_DONE_SLAPPED, FALSE );
}
}
// We are unconscious now, play randomly, this animation continued, or a new death
if ( CheckSoldierHitRoof( pSoldier ) )
{
return;
}
// If guy is now dead, play sound!
if ( pSoldier->bLife == 0 )
{
if ( !AreInMeanwhile() )
{
DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 );
pSoldier->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->bDirection;
BOOLEAN fForceDirection = FALSE;
BOOLEAN fDoFallback = FALSE;
// 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
if ( Random(100 ) > 40 && 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( MercPtrs[ pSoldier->ubAttackerID ]->sGridNo, pSoldier );
fForceDirection = TRUE;
}
sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( gOppositeDirection[ bTestDirection ] ) );
if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->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
BeginTyingToFall( pSoldier );
ChangeSoldierState( pSoldier, FALLFORWARD_FROMHIT_STAND, 0, FALSE );
return;
}
else
{
// ALL'S OK HERE..... IF WE FORCED DIRECTION, SET!
if ( fForceDirection )
{
EVENT_SetSoldierDesiredDirection( pSoldier, bTestDirection );
EVENT_SetSoldierDirection( pSoldier, bTestDirection );
}
ChangeToFallbackAnimation( pSoldier, pSoldier->bDirection );
return;
}
}
else if ( pSoldier->usAnimState == GENERIC_HIT_CROUCH )
{
ChangeSoldierState( pSoldier, FALLFORWARD_FROMHIT_CROUCH, 0 , FALSE);
BeginTyingToFall( pSoldier );
return;
}
else if ( pSoldier->usAnimState == GENERIC_HIT_PRONE )
{
ChangeSoldierState( pSoldier, PRONE_LAY_FROMHIT, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == ADULTMONSTER_HIT )
{
ChangeSoldierState( pSoldier, ADULTMONSTER_DYING, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == LARVAE_HIT )
{
ChangeSoldierState( pSoldier, LARVAE_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == QUEEN_HIT )
{
ChangeSoldierState( pSoldier, QUEEN_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == CRIPPLE_HIT )
{
ChangeSoldierState( pSoldier, CRIPPLE_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == ROBOTNW_HIT )
{
ChangeSoldierState( pSoldier, ROBOTNW_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == INFANT_HIT )
{
ChangeSoldierState( pSoldier, INFANT_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == COW_HIT )
{
ChangeSoldierState( pSoldier, COW_DYING, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == BLOODCAT_HIT )
{
ChangeSoldierState( pSoldier, BLOODCAT_DYING, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == WATER_HIT )
{
ChangeSoldierState( pSoldier, WATER_DIE, 0 , FALSE );
return;
}
else if ( pSoldier->usAnimState == DEEP_WATER_HIT )
{
ChangeSoldierState( pSoldier, 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->bLife == 0 )
{
DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 );
pSoldier->fDeadSoundPlayed = TRUE;
// 0verhaul: The bBeingAttackedCount is now obsolete.
// Increment being attacked count
// pSoldier->bBeingAttackedCount++;
if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] )
{
switch( pSoldier->usAnimState )
{
case FLYBACKHIT_STOP:
ChangeSoldierState( pSoldier, FLYBACK_HIT_DEATH, 0, FALSE );
break;
case FALLFORWARD_FROMHIT_STAND:
case FALLFORWARD_FROMHIT_CROUCH:
case STAND_FALLFORWARD_STOP:
ChangeSoldierState( pSoldier, GENERIC_HIT_DEATH, 0, FALSE );
break;
case FALLBACKHIT_STOP:
ChangeSoldierState( pSoldier, FALLBACK_HIT_DEATH, 0, FALSE );
break;
case PRONE_LAYFROMHIT_STOP:
case PRONE_LAY_FROMHIT:
ChangeSoldierState( pSoldier, PRONE_HIT_DEATH, 0, FALSE );
break;
case FALLOFF_STOP:
ChangeSoldierState( pSoldier, FALLOFF_DEATH, 0, FALSE );
break;
case FALLOFF_FORWARD_STOP:
ChangeSoldierState( pSoldier, FALLOFF_FORWARD_DEATH, 0, FALSE);
break;
case ADULTMONSTER_HIT:
ChangeSoldierState( pSoldier, ADULTMONSTER_DYING, 0 , FALSE );
break;
case LARVAE_HIT:
ChangeSoldierState( pSoldier, LARVAE_DIE, 0 , FALSE );
break;
case QUEEN_HIT:
ChangeSoldierState( pSoldier, QUEEN_DIE, 0 , FALSE );
break;
case CRIPPLE_HIT:
ChangeSoldierState( pSoldier, CRIPPLE_DIE, 0 , FALSE );
break;
case ROBOTNW_HIT:
ChangeSoldierState( pSoldier, ROBOTNW_DIE, 0 , FALSE );
break;
case INFANT_HIT:
ChangeSoldierState( pSoldier, INFANT_DIE, 0 , FALSE );
break;
case COW_HIT:
ChangeSoldierState( pSoldier, COW_DYING, 0 , FALSE );
break;
case BLOODCAT_HIT:
ChangeSoldierState( pSoldier, 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 );
}
// Check single hand for jammed status, ( or ammo is out.. )
if ( pSoldier->inv[ HANDPOS ].bGunAmmoStatus < 0 || pSoldier->inv[ HANDPOS ].ubGunShotsLeft == 0 )
{
// If we have 2 pistols, donot go back!
if ( Item[ pSoldier->inv[ SECONDHANDPOS ].usItem ].usItemClass != IC_GUN )
{
// OK, put gun down....
InternalSoldierReadyWeapon( pSoldier, pSoldier->bDirection, TRUE );
return( TRUE );
}
}
return( FALSE );
}
BOOLEAN OKHeightDest( SOLDIERTYPE *pSoldier, INT16 sNewGridNo )
{
if ( pSoldier->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->uiPendingActionData1 = pSoldier->usAniCode;
pSoldier->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
ChangeSoldierState( pSoldier, STANDING_SHOOT_UNJAM, 0 , FALSE );
return( TRUE );
case PRONE_BURST:
case SHOOT_RIFLE_PRONE:
// Normal shoot rifle.... play
ChangeSoldierState( pSoldier, PRONE_SHOOT_UNJAM, 0 , FALSE );
return( TRUE );
case CROUCHED_BURST:
case SHOOT_RIFLE_CROUCH:
// Normal shoot rifle.... play
ChangeSoldierState( pSoldier, CROUCH_SHOOT_UNJAM, 0 , FALSE );
return( TRUE );
case SHOOT_DUAL_STAND:
// Normal shoot rifle.... play
ChangeSoldierState( pSoldier, STANDING_SHOOT_DWEL_UNJAM, 0 , FALSE );
return( TRUE );
case SHOOT_DUAL_PRONE:
// Normal shoot rifle.... play
ChangeSoldierState( pSoldier, PRONE_SHOOT_DWEL_UNJAM, 0 , FALSE );
return( TRUE );
case SHOOT_DUAL_CROUCH:
// Normal shoot rifle.... play
ChangeSoldierState( pSoldier, CROUCH_SHOOT_DWEL_UNJAM, 0 , FALSE );
return( TRUE );
case FIRE_LOW_STAND:
case FIRE_BURST_LOW_STAND:
// Normal shoot rifle.... play
ChangeSoldierState( pSoldier, STANDING_SHOOT_LOW_UNJAM, 0 , FALSE );
return( TRUE );
}
return( FALSE );
}
#if 0
//OK, if here, if our health is still good, but we took a lot of damage, try to fall down!
if ( pSoldier->bLife >= OKLIFE )
{
// Randomly fall back or forward, if we are in the standing hit animation
if ( pSoldier->usAnimState == GENERIC_HIT_STAND || pSoldier->usAnimState == RIFLE_STAND_HIT )
{
INT8 bTestDirection = pSoldier->bDirection;
BOOLEAN fForceDirection = FALSE;
BOOLEAN fDoFallback = FALSE;
// As the damage pretty brutal?
// TRY FALLING BACKWARDS, ( ONLY IF WE ARE A MERC! )
if ( Random( 1000 ) > 40 && IS_MERC_BODY_TYPE( pSoldier ) )
{
// CHECK IF WE HAVE AN ATTACKER, TAKE OPPOSITE DIRECTION!
if ( pSoldier->ubAttackerID != NOBODY )
{
// Find direction!
bTestDirection = (INT8)GetDirectionFromGridNo( MercPtrs[ pSoldier->ubAttackerID ]->sGridNo, pSoldier );
fForceDirection = TRUE;
}
sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)(-1 * DirectionInc( bTestDirection ) ) );
if ( NewOKDestination( pSoldier, sNewGridNo, TRUE, pSoldier->bLevel ) && OKHeightDest( pSoldier, sNewGridNo ) )
{
// ALL'S OK HERE..... IF WE FORCED DIRECTION, SET!
if ( fForceDirection )
{
EVENT_SetSoldierDirection( pSoldier, bTestDirection );
EVENT_SetSoldierDesiredDirection( pSoldier, bTestDirection );
}
ChangeSoldierState( pSoldier, FALLBACK_HIT_STAND, 0, FALSE );
return;
}
}
}
}
#endif
BOOLEAN OKFallDirection( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bLevel, INT8 bTestDirection, UINT16 usAnimState )
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"OKFallDirection");
STRUCTURE_FILE_REF * pStructureFileRef;
UINT16 usAnimSurface;
// How are the movement costs?
if ( gubWorldMovementCosts[ sGridNo ][ bTestDirection ][ bLevel ] > TRAVELCOST_SHORE )
{
return( FALSE );
}
//NOT ok if in water....
if ( GetTerrainType( sGridNo ) == MED_WATER || GetTerrainType( sGridNo ) == DEEP_WATER || GetTerrainType( sGridNo ) == LOW_WATER )
{
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;
INT16 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, (UINT16)( DirectionInc( gOppositeDirection[ bTestDirection ] ) ) );
if ( ! OkayToAddStructureToWorld( sTestGridNo, bLevel, &(pStructureFileRef->pDBStructureRef[ gOneCDirection[ bTestDirection ] ]), usStructureID ) )
{
// can't go in that dir!
return( FALSE );
}
}
return( TRUE );
}
BOOLEAN HandleCheckForDeathCommonCode( SOLDIERTYPE *pSoldier )
{
// Do we have a primary pending animation?
if ( pSoldier->usPendingAnimation2 != NO_PENDING_ANIMATION )
{
ChangeSoldierState( pSoldier, 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 )
{
ChangeSoldierState( pSoldier, 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...
BeginSoldierGetup( pSoldier );
// Check this to see if above worked
if ( !pSoldier->bCollapsed )
{
return( TRUE );
}
}
switch( pSoldier->usAnimState )
{
case FLYBACK_HIT:
ChangeSoldierState( pSoldier, FLYBACKHIT_STOP, 0, FALSE );
break;
case GENERIC_HIT_DEATHTWITCHNB:
case FALLFORWARD_FROMHIT_STAND:
case ENDFALLFORWARD_FROMHIT_CROUCH:
ChangeSoldierState( pSoldier, STAND_FALLFORWARD_STOP, 0, FALSE );
break;
case FALLBACK_HIT_DEATHTWITCHNB:
case FALLBACK_HIT_STAND:
ChangeSoldierState( pSoldier, FALLBACKHIT_STOP, 0, FALSE );
break;
case PRONE_HIT_DEATHTWITCHNB:
case PRONE_LAY_FROMHIT:
ChangeSoldierState( pSoldier, PRONE_LAYFROMHIT_STOP, 0, FALSE );
break;
case FALLOFF:
ChangeSoldierState( pSoldier, FALLOFF_STOP, 0, FALSE );
break;
case FALLFORWARD_ROOF:
ChangeSoldierState( pSoldier, 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...
BeginSoldierGetup( pSoldier );
// Check this to see if above worked
if ( !pSoldier->bCollapsed )
{
return( TRUE );
}
}
switch( pSoldier->usAnimState )
{
case FLYBACK_HIT:
ChangeSoldierState( pSoldier, FLYBACKHIT_STOP, 0, FALSE );
break;
case GENERIC_HIT_DEATHTWITCHNB:
case FALLFORWARD_FROMHIT_STAND:
case ENDFALLFORWARD_FROMHIT_CROUCH:
ChangeSoldierState( pSoldier, STAND_FALLFORWARD_STOP, 0, FALSE );
break;
case FALLBACK_HIT_DEATHTWITCHNB:
case FALLBACK_HIT_STAND:
ChangeSoldierState( pSoldier, FALLBACKHIT_STOP, 0, FALSE );
break;
case PRONE_HIT_DEATHTWITCHNB:
case PRONE_LAY_FROMHIT:
ChangeSoldierState( pSoldier, PRONE_LAYFROMHIT_STOP, 0, FALSE );
break;
case FALLOFF:
ChangeSoldierState( pSoldier, FALLOFF_STOP, 0, FALSE );
break;
case FALLFORWARD_ROOF:
ChangeSoldierState( pSoldier, 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 )
{
INT16 sNewGridNo;
// Move forward one gridno....
sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) );
// ATE: Make sure that the gridno is unoccupied!
if ( !NewOKDestination( pSoldier, sNewGridNo, TRUE, pSoldier->bLevel ) )
{
// We should just stay put - will look kind of funny but nothing I can do!
sNewGridNo = pSoldier->sGridNo;
}
EVENT_StopMerc( pSoldier, sNewGridNo, pSoldier->bDirection );
pSoldier->ubBodyType = REGMALE;
if ( pSoldier->ubProfile == SLAY && pSoldier->bTeam == CIV_TEAM && !pSoldier->bNeutral )
{
HandleNPCDoAction( pSoldier->ubProfile, NPC_ACTION_THREATENINGLY_RAISE_GUN, 0 );
}
else
{
EVENT_InitNewSoldierAnim( pSoldier, 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;
}
}