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