Files
source/Tactical/Soldier Ani.cpp
T
Overhaul 7a27e7105d New attack busy system
Added missing #includes

Added LUA scripting and console

Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain

Fixed signedness of many grid variables used in GetMouseMapPos calls

Fixed enemy weapon choosing:  Sometimes a mortar is chosen but later rejected, but the grenade class was not reset.  Caused assertion failure

Added checks so enemies don't try to chuck RPG grenades with their hands

Now possible to shoot a someone in the head if he's in water

Fixed InitSightArrays to also clear soldier interrupt duel points.  This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called.

Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have

Removed early setting of muzzle flash.  This would allow enemies to get an interrupt before you even fired.

Fixed item dropping by AI.  If AI tried to drop something while standing it would cause deadlock

Change to greatly speed up closing the sector inventory window in an unloaded sector

Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting


Check builddefines.h for the conditional flags.  Of greatest interest might be LUA_CONSOLE.  This will cause the game to bring up a command console when run.  However this console is severely lacking in many areas.  If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated.  The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus.

LUA scripting is very limited, basically just proof of concept.  There is one global variable, the Soldiers array.  An array index gives you the soldier in that slot in the currently loaded sector.  The soldier has a few things that can be accessed:  name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid)


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-06-09 09:01:04 +00:00

4094 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 ( 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 );
}
}
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.....
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.....
}
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;
}
}