#ifdef PRECOMPILEDHEADERS #include "Tactical All.h" #else #include #include #include "wcheck.h" #include "stdlib.h" #include "debug.h" #include "MemMan.h" #include "Overhead Types.h" #include "Soldier Control.h" #include "Animation Cache.h" #include "Animation Data.h" #include "Animation Control.h" #include "weapons.h" #include "soldier ani.h" #include "Random.h" #include "video.h" #include "vobject_blitters.h" #include "Sound Control.h" #include "isometric utils.h" #include "Handle UI.h" #include "Event Pump.h" #include "opplist.h" #include "lighting.h" #include "ai.h" #include "renderworld.h" #include "interactive tiles.h" #include "points.h" #include "message.h" #include "world items.h" #include "physics.h" #include "soldier create.h" #include "dialogue control.h" #include "soldier functions.h" #include "rotting corpses.h" #include "merc entering.h" #include "soldier add.h" #include "soldier profile.h" #include "soldier functions.h" #include "interface.h" #include "qarray.h" #include "soldier macros.h" #include "Strategic Town Loyalty.h" #include "Squads.h" #include "worldman.h" #include "structure wrap.h" #include "pathai.h" #include "pits.h" #include "text.h" #include "npc.h" #include "meanwhile.h" #include "Explosion Control.h" #include "fov.h" #include "campaign.h" #include "los.h" #include "GameSettings.h" #include "Boxing.h" #include "drugs and alcohol.h" #include "Smell.h" #include "GameSettings.h" #include "interface dialogue.h" #include "Strategic Status.h" #endif #define NO_JUMP 0 #define MAX_ANIFRAMES_PER_FLASH 2 //#define TIME_FOR_RANDOM_ANIM_CHECK 10 #define TIME_FOR_RANDOM_ANIM_CHECK 2 BOOLEAN gfLastMercTalkedAboutKillingID = NOBODY; extern void AddFuelToVehicle( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVehicle ); DOUBLE gHopFenceForwardSEDist[ NUMSOLDIERBODYTYPES ] = { 2.2, 0.7, 3.2, 0.7 }; DOUBLE gHopFenceForwardNWDist[ NUMSOLDIERBODYTYPES ] = { 2.7, 1.0, 2.7, 1.0 }; DOUBLE gHopFenceForwardFullSEDist[ NUMSOLDIERBODYTYPES ] = { 1.1, 1.0, 2.1, 1.1 }; DOUBLE gHopFenceForwardFullNWDist[ NUMSOLDIERBODYTYPES ] = { 0.8, 0.2, 2.7, 0.8 }; DOUBLE gFalloffBackwardsDist[ NUMSOLDIERBODYTYPES ] = { 1, 0.8, 1, 1 }; DOUBLE gClimbUpRoofDist[ NUMSOLDIERBODYTYPES ] = { 2, 0.1, 2, 2 }; DOUBLE gClimbUpRoofLATDist[ NUMSOLDIERBODYTYPES ] = { 0.7, 0.5, 0.7, 0.5 }; DOUBLE gClimbDownRoofStartDist[ NUMSOLDIERBODYTYPES ] = { 5.0, 1.0, 1, 1 }; DOUBLE gClimbUpRoofDistGoingLower[ NUMSOLDIERBODYTYPES ] = { 0.9, 0.1, 1, 1 }; BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse ); void CheckForAndHandleSoldierIncompacitated( SOLDIERTYPE *pSoldier ); BOOLEAN CheckForImproperFireGunEnd( SOLDIERTYPE *pSoldier ); BOOLEAN OKHeightDest( SOLDIERTYPE *pSoldier, INT16 sNewGridNo ); BOOLEAN HandleUnjamAnimation( SOLDIERTYPE *pSoldier ); extern void HandleSystemNewAISituation( SOLDIERTYPE *pSoldier, BOOLEAN fResetABC ); extern void PlaySoldierFootstepSound( SOLDIERTYPE *pSoldier ); extern UINT8 NumCapableEnemyInSector( ); extern BOOLEAN gfKillingGuysForLosingBattle; extern UINT8 gubInterruptProvoker; extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ); // Animation code explanations! // // 0-399: Actual animation frame indices // 400-499: Object manipulation codes // 500-598: Jump to frame x-501, same state. Obvious limit 0-97 // 600-699: Jump to new state x-600, frame 0 // 700-798: Play sound // 800-999: Jump to new state x-700, frame 0 (starts with 100) // BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) { EV_S_FIREWEAPON SFireWeapon; UINT16 sNewAniFrame, anAniFrame; INT8 ubCurrentHeight; UINT16 usOldAnimState; static UINT32 uiJumpAddress = NO_JUMP; INT16 sNewGridNo; INT16 sX, sY; BOOLEAN fStop; UINT32 cnt; UINT8 ubDiceRoll; // Percentile dice roll UINT8 ubRandomHandIndex; // Index value into random animation table to use base don what is in the guys hand... UINT16 usItem; RANDOM_ANI_DEF *pAnimDef; UINT8 ubNewDirection; UINT8 ubDesiredHeight; BOOLEAN bOKFireWeapon; BOOLEAN bWeaponJammed; BOOLEAN fFreeUpAttacker=FALSE; UINT16 usUIMovementMode; do { // Get new frame code sNewAniFrame = gusAnimInst[ pSoldier->usAnimState ][ pSoldier->usAniCode ]; // Handle muzzle flashes if ( pSoldier->bMuzFlashCount > 0 ) { // FLash for about 3 frames if ( pSoldier->bMuzFlashCount > MAX_ANIFRAMES_PER_FLASH ) { pSoldier->bMuzFlashCount = 0; if ( pSoldier->iMuzFlash != -1 ) { LightSpriteDestroy( pSoldier->iMuzFlash ); pSoldier->iMuzFlash = -1; } } else { pSoldier->bMuzFlashCount++; } } if ( pSoldier->bBreathCollapsed ) { // ATE: If we have fallen, and we can't get up... no // really, if we were told to collapse but have been hit after, don't // do anything... if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_HITSTOP | ANIM_HITFINISH ) ) { pSoldier->bBreathCollapsed = FALSE; } else if ( pSoldier->bLife == 0 ) { // Death takes precedence... pSoldier->bBreathCollapsed = FALSE; } else if ( pSoldier->usPendingAnimation == FALLFORWARD_ROOF || pSoldier->usPendingAnimation == FALLOFF || pSoldier->usAnimState == FALLFORWARD_ROOF || pSoldier->usAnimState == FALLOFF ) { pSoldier->bBreathCollapsed = FALSE; } else { // Wait here until we are free.... if ( !pSoldier->fInNonintAnim ) { // UNset UI UnSetUIBusy( pSoldier->ubID ); SoldierCollapse( pSoldier ); pSoldier->bBreathCollapsed = FALSE; return( TRUE ); } } } // Check for special code if ( sNewAniFrame < 399 ) { // Adjust / set true ani frame // Use -1 because ani files are 1-based, these are 0-based ConvertAniCodeToAniFrame( pSoldier, (INT16)( sNewAniFrame - 1 ) ); // Adjust frame control pos, and try again pSoldier->usAniCode++; break; } else if ( sNewAniFrame < 500 ) { // Switch on special code switch( sNewAniFrame ) { case 402: // DO NOT MOVE FOR THIS FRAME pSoldier->fPausedMove = TRUE; break; case 403: // MOVE GUY FORWARD SOME VALUE MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)0.7 ); break; case 404: // MOVE GUY BACKWARD SOME VALUE // Use same function as forward, but is -ve values! MoveMercFacingDirection( pSoldier , TRUE, (FLOAT)1 ); break; case 405: return( TRUE ); case 406: // Move merc up if ( pSoldier->bDirection == NORTH ) { SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->sHeightAdjustment + 2 ) ); } else { SetSoldierHeight( pSoldier, (FLOAT)( pSoldier->sHeightAdjustment + 3 ) ); } break; case 408: // CODE: SPECIAL MOVE CLIMB UP ROOF EVENT // re-enable sight gTacticalStatus.uiFlags &= (~DISALLOW_SIGHT); { INT16 sXPos, sYPos; //usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)DirectionInc( pSoldier->bDirection ) ); ConvertMapPosToWorldTileCenter( pSoldier->sTempNewGridNo, &sXPos, &sYPos ); EVENT_SetSoldierPosition( pSoldier, (FLOAT)sXPos, (FLOAT)sYPos ); } // Move two CC directions EVENT_SetSoldierDirection( pSoldier, gTwoCCDirection[ pSoldier->bDirection ] ); EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection ); // Set desired anim height! pSoldier->ubDesiredHeight = ANIM_CROUCH; // Madd usUIMovementMode = GetMoveStateBasedOnStance( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ); pSoldier->usUIMovementMode = usUIMovementMode; // Move merc up specific height SetSoldierHeight( pSoldier, (FLOAT)50 ); // ATE: Change interface level..... // CJC: only if we are a player merc if (pSoldier->bTeam == gbPlayerNum) { if (gTacticalStatus.fAutoBandageMode) { // in autobandage, handle as AI, but add roof marker too FreeUpNPCFromRoofClimb( pSoldier ); HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, TRUE, TRUE ); } else { // OK, UNSET INTERFACE FIRST UnSetUIBusy( pSoldier->ubID ); if ( pSoldier->ubID == gusSelectedSoldier ) { ChangeInterfaceLevel( 1 ); } HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, TRUE, TRUE ); } } else { FreeUpNPCFromRoofClimb( pSoldier ); } // ATE: Handle sight... HandleSight( pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT ); break; case 409: //CODE: MOVE DOWN SetSoldierHeight( pSoldier, (FLOAT)( pSoldier->sHeightAdjustment - 2 ) ); break; case 410: // Move merc down specific height SetSoldierHeight( pSoldier, (FLOAT)0 ); break; case 411: // CODE: SPECIALMOVE CLIMB DOWN EVENT // Move two C directions EVENT_SetSoldierDirection( pSoldier, gTwoCDirection[ pSoldier->bDirection ] ); EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection ); // Adjust height SetSoldierHeight( pSoldier, (FLOAT)gClimbDownRoofStartDist[ pSoldier->ubBodyType ] ); // Adjust position MoveMercFacingDirection( pSoldier , TRUE, (FLOAT)3.5 ); break; case 412: // CODE: HANDLING PRONE DOWN - NEED TO MOVE GUY BACKWARDS! MoveMercFacingDirection( pSoldier , FALSE, (FLOAT).2 ); break; case 413: // CODE: HANDLING PRONE UP - NEED TO MOVE GUY FORWARDS! MoveMercFacingDirection( pSoldier , TRUE, (FLOAT).2 ); break; case 430: DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: case 430"); // SHOOT GUN // MAKE AN EVENT, BUT ONLY DO STUFF IF WE OWN THE GUY! SFireWeapon.usSoldierID = pSoldier->ubID; SFireWeapon.uiUniqueId = pSoldier->uiUniqueSoldierIdValue; SFireWeapon.sTargetGridNo = pSoldier->sTargetGridNo; SFireWeapon.bTargetLevel = pSoldier->bTargetLevel; SFireWeapon.bTargetCubeLevel= pSoldier->bTargetCubeLevel; AddGameEvent( S_FIREWEAPON, 0, &SFireWeapon ); //DIGICRAB: Burst UnCap //Loop around in the animation if we still have burst rounds to fire if (pSoldier->bDoBurst && (pSoldier->bDoBurst <= ((pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst(&pSoldier->inv[HANDPOS]))) || (( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst <= Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst)) )) { if(pSoldier->usAnimState == 44 || pSoldier->usAnimState == 109 || pSoldier->usAnimState == 108 && pSoldier->usAniCode == 33) //we are standing, crounching or prone, firing the fast shot pSoldier->usAniCode = 3; else if(pSoldier->usAnimState == 175 && pSoldier->usAniCode == 37) //we are firing down to something very close, last shot pSoldier->usAniCode = 14; } //DIGICRAB: Burst Sound //This code is stolen from Tactical\Weapons.c - UseGun(...) if (pSoldier->bDoBurst && pSoldier->iBurstSoundID == NO_SAMPLE && Weapon[ pSoldier->usAttackingWeapon ].sSound != 0 && Item[ pSoldier->usAttackingWeapon ].usItemClass != IC_THROWING_KNIFE ) { // Switch on silencer... INT16 noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] ); if( noisefactor < MAX_PERCENT_NOISE_VOLUME_FOR_SILENCED_SOUND || Weapon[ pSoldier->usAttackingWeapon ].ubAttackVolume <= 10 ) { INT32 uiSound; uiSound = Weapon [ pSoldier->usAttackingWeapon ].silencedSound; //if ( Weapon[ pSoldier->usAttackingWeapon ].ubCalibre == AMMO9 || Weapon[ pSoldier->usAttackingWeapon ].ubCalibre == AMMO38 || Weapon[ pSoldier->usAttackingWeapon ].ubCalibre == AMMO57 ) //{ // uiSound = S_SILENCER_1; //} //else //{ // uiSound = S_SILENCER_2; //} //randomize the rate a bit so that the sound is more believable PlayJA2Sample( uiSound, 44100-Random(5000)-Random(5000)-Random(5000), SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } else { INT8 volume = HIGHVOLUME; if ( noisefactor < 100 ) volume = (volume * noisefactor) / 100; //randomize the rate a bit so that the sound is more believable PlayJA2Sample( Weapon[ pSoldier->usAttackingWeapon ].sSound, 44100-Random(5000)-Random(5000)-Random(5000), SoundVolume( volume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } } break; case 431: // FLASH FRAME WHITE pSoldier->pForcedShade = White16BPPPalette; break; case 432: // PLAY RANDOM IMPACT SOUND! // PlayJA2Sample( (UINT8)( BULLET_IMPACT_1 + Random(3) ), RATE_11025, MIDVOLUME, 1, MIDDLEPAN ); // PLAY RANDOM GETTING HIT SOUND // DoMercBattleSound( pSoldier, BATTLE_SOUND_HIT1 ); break; case 433: // CODE: GENERIC HIT! CheckForAndHandleSoldierIncompacitated( pSoldier ); break; case 434: // JUMP TO ANOTHER ANIMATION ( BLOOD ) IF WE WANT BLOOD uiJumpAddress = pSoldier->usAnimState; ChangeSoldierState( pSoldier, FLYBACK_HIT_BLOOD_STAND, 0, FALSE ); return( TRUE ); break; case 435: // HOOK FOR A RETURN JUMP break; case 436: // Loop through script to find entry address if ( uiJumpAddress == NO_JUMP ) { break; } usOldAnimState = pSoldier->usAnimState; pSoldier->usAniCode = 0; do { // Get new frame code anAniFrame = gusAnimInst[ uiJumpAddress ][ pSoldier->usAniCode ]; if ( anAniFrame == 435 ) { // START PROCESSING HERE ChangeSoldierState( pSoldier, (UINT16)uiJumpAddress, pSoldier->usAniCode, FALSE ); return( TRUE ); } // Adjust frame control pos, and try again pSoldier->usAniCode++; } while( anAniFrame != 999 ); uiJumpAddress = NO_JUMP; if ( anAniFrame == 999 ) { // Fail jump, re-load old anim ChangeSoldierState( pSoldier, usOldAnimState, 0, FALSE ); return( TRUE ); } break; case 437: // CHANGE DIRECTION AND GET-UP //sGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)(-1 * DirectionInc( pSoldier->bDirection ) ) ); //ConvertMapPosToWorldTileCenter( pSoldier->sGridNo, &sXPos, &sYPos ); //SetSoldierPosition( pSoldier, (FLOAT)sXPos, (FLOAT)sYPos ); // Reverse direction EVENT_SetSoldierDirection( pSoldier, gOppositeDirection[ pSoldier->bDirection ] ); EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection ); ChangeSoldierState( pSoldier, GETUP_FROM_ROLLOVER, 0 , FALSE ); return( TRUE ); case 438: //CODE: START HOLD FLASH pSoldier->fForceShade = TRUE; break; case 439: //CODE: END HOLD FLASH pSoldier->fForceShade = FALSE; break; case 440: //CODE: Set buddy as dead! { BOOLEAN fMadeCorpse; // ATE: Piggyback here on stopping the burn sound... if ( pSoldier->usAnimState == CHARIOTS_OF_FIRE || pSoldier->usAnimState == BODYEXPLODING ) { SoundStop( pSoldier->uiPendingActionData1 ); } CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse ); if ( fMadeCorpse ) { return( FALSE ); } else { return( TRUE ); } } break; case 441: // CODE: Show muzzle flash if ( pSoldier->bVisible == -1 ) { break; } if ( !pSoldier->fMuzzleFlash ) { break; } // DO ONLY IF WE'RE AT A GOOD LEVEL if ( ubAmbientLightLevel < MIN_AMB_LEVEL_FOR_MERC_LIGHTS ) { break; } if( ( pSoldier->iMuzFlash=LightSpriteCreate("L-R03.LHT", 0 ) )==(-1)) { return( TRUE ); } LightSpritePower(pSoldier->iMuzFlash, TRUE); // Get one move forward { UINT16 usNewGridNo; INT16 sXPos, sYPos; usNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( pSoldier->bDirection ) ); ConvertGridNoToCenterCellXY( usNewGridNo, &sXPos, &sYPos ); LightSpritePosition( pSoldier->iMuzFlash, (INT16)(sXPos/CELL_X_SIZE), (INT16)(sYPos/CELL_Y_SIZE)); // Start count pSoldier->bMuzFlashCount = 1; } break; case 442: //CODE: FOR A NON-INTERRUPTABLE SCRIPT - SIGNAL DONE pSoldier->fInNonintAnim = FALSE; // ATE: if it's the begin cower animation, unset ui, cause it could // be from player changin stance if ( pSoldier->usAnimState == START_COWER ) { UnSetUIBusy( pSoldier->ubID ); } break; case 443: // MOVE GUY FORWARD FOR FENCE HOP ANIMATION switch( pSoldier->bDirection ) { case SOUTH: case EAST: MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gHopFenceForwardSEDist[ pSoldier->ubBodyType ] ); break; case NORTH: case WEST: MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gHopFenceForwardNWDist[ pSoldier->ubBodyType ] ); break; } break; case 444: // CODE: End Hop Fence // MOVE TO FORCASTED GRIDNO sX = CenterX( pSoldier->sForcastGridno ); sY = CenterY( pSoldier->sForcastGridno ); EVENT_InternalSetSoldierPosition( pSoldier, (FLOAT) sX, (FLOAT) sY, FALSE, FALSE, FALSE ); EVENT_SetSoldierDirection( pSoldier, gTwoCDirection[ pSoldier->bDirection ] ); pSoldier->sZLevelOverride = -1; EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection ); if ( gTacticalStatus.bBoxingState == BOXING_WAITING_FOR_PLAYER || gTacticalStatus.bBoxingState == PRE_BOXING || gTacticalStatus.bBoxingState == BOXING ) { BoxingMovementCheck( pSoldier ); } if ( SetOffBombsInGridNo( pSoldier->ubID, pSoldier->sGridNo, FALSE, pSoldier->bLevel )) { EVENT_StopMerc( pSoldier, pSoldier->sGridNo, pSoldier->bDirection ); return( TRUE ); } // If we are at our final destination, goto stance of our movement stance... // Only in realtime... //if ( !( gTacticalStatus.uiFlags & INCOMBAT ) ) // This has to be here to make guys continue along fence path if ( pSoldier->sGridNo == pSoldier->sFinalDestination ) { if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != gAnimControl[ pSoldier->usUIMovementMode ].ubEndHeight ) { // Goto Stance... pSoldier->fDontChargeAPsForStanceChange = TRUE; ChangeSoldierStance( pSoldier, gAnimControl[ pSoldier->usUIMovementMode ].ubEndHeight ); return( TRUE ); } else { SoldierGotoStationaryStance( pSoldier ); // Set UI Busy UnSetUIBusy( pSoldier->ubID ); return( TRUE ); } } break; case 445: // CODE: MOVE GUY FORWARD ONE TILE, BASED ON WHERE WE ARE FACING switch( pSoldier->bDirection ) { case SOUTH: case EAST: MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gHopFenceForwardFullSEDist[ pSoldier->ubBodyType ] ); break; case NORTH: case WEST: MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gHopFenceForwardFullNWDist[ pSoldier->ubBodyType ] ); break; } break; case 446: // CODE: Turn pause move flag on pSoldier->uiStatusFlags |= SOLDIER_PAUSEANIMOVE; break; case 447: // TRY TO FALL!!! if ( pSoldier ->fTryingToFall ) { INT16 sLastAniFrame; // TRY FORWARDS... // FIRST GRIDNO sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) ); if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->bLevel, pSoldier->bDirection, FALLFORWARD_HITDEATH_STOP ) ) { // SECOND GRIDNO // sNewGridNo = NewGridNo( (UINT16)sNewGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) ); // if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->bLevel, pSoldier->bDirection, FALLFORWARD_HITDEATH_STOP ) ) { // ALL'S OK HERE... pSoldier->fTryingToFall = FALSE; break; } } // IF HERE, INCREMENT DIRECTION // ATE: Added Feb1 - can be either direction.... if ( pSoldier->fFallClockwise ) { EVENT_SetSoldierDirection( pSoldier, gOneCDirection[ pSoldier->bDirection ] ); } else { EVENT_SetSoldierDirection( pSoldier, gOneCCDirection[ pSoldier->bDirection ] ); } EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection ); sLastAniFrame = gusAnimInst[ pSoldier->usAnimState ][ ( pSoldier->usAniCode - 2 ) ]; ConvertAniCodeToAniFrame( pSoldier, (INT16)( sLastAniFrame ) ); if ( pSoldier->bDirection == pSoldier->bStartFallDir ) { // GO FORWARD HERE... pSoldier ->fTryingToFall = FALSE; break;; } // IF HERE, RETURN SO WE DONOT INCREMENT DIR return( TRUE ); } break; case 448: // CODE: HANDLE BURST // FIRST CHECK IF WE'VE REACHED MAX FOR GUN fStop = FALSE; if ( ( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst > Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst) || (pSoldier->bWeaponMode != WM_ATTACHED_GL_BURST && pSoldier->bDoBurst > ((pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst(&pSoldier->inv[HANDPOS])))) ) { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because burst size too large"); fStop = TRUE; fFreeUpAttacker = TRUE; } // CHECK IF WE HAVE AMMO LEFT, IF NOT, END ANIMATION! if ( !EnoughAmmo( pSoldier, FALSE, pSoldier->ubAttackingHand ) ) { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because not enough ammo"); fStop = TRUE; fFreeUpAttacker = TRUE; if ( pSoldier->bTeam == gbPlayerNum ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ BURST_FIRE_DEPLETED_CLIP_STR ] ); } } // Why only check for a jam on the first bullet? else if (pSoldier->bDoBurst == 1) { // CHECK FOR GUN JAM bWeaponJammed = CheckForGunJam( pSoldier ); if ( bWeaponJammed == TRUE ) { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because weapon jammed"); fStop = TRUE; fFreeUpAttacker = TRUE; // stop shooting! // Yeah, but what does this have to do with that? // pSoldier->bBulletsLeft = 0; // OK, Stop burst sound... if ( pSoldier->iBurstSoundID != NO_SAMPLE ) { SoundStop( pSoldier->iBurstSoundID ); } if ( pSoldier->bTeam == gbPlayerNum ) { PlayJA2Sample( S_DRYFIRE1, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Gun jammed!" ); } DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - aborting start of attack due to burst gun jam") ); FreeUpAttacker( ); } else if ( bWeaponJammed == 255 ) { // Play intermediate animation... if ( HandleUnjamAnimation( pSoldier ) ) { return( TRUE ); } } } if ( fStop ) { if(pSoldier->bDoAutofire) //reset the autofire cursor after firing { pSoldier->autofireLastStep = FALSE; pSoldier->bDoAutofire = 1; } pSoldier->fDoSpread = FALSE; pSoldier->bDoBurst = 1; // pSoldier->fBurstCompleted = TRUE; if ( fFreeUpAttacker ) { // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - aborting start of attack") ); // FreeUpAttacker( pSoldier->ubID ); } // ATE; Reduce it due to animation being stopped... // 0verhaul: No longer necessary or desired // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - Burst animation ended") ); // ReduceAttackBusyCount( pSoldier->ubID, FALSE ); if ( CheckForImproperFireGunEnd( pSoldier ) ) { return( TRUE ); } // END: GOTO AIM STANCE BASED ON HEIGHT // If we are a robot - we need to do stuff different here // 0verhaul: Ya know, if the robot simply used the same animation for standing and rifle standing, // we probably wouldn't need this special case code. if ( AM_A_ROBOT( pSoldier ) ) { ChangeSoldierState( pSoldier, STANDING, 0 , FALSE ); } else { switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) { case ANIM_STAND: ChangeSoldierState( pSoldier, AIM_RIFLE_STAND, 0 , FALSE ); break; case ANIM_PRONE: ChangeSoldierState( pSoldier, AIM_RIFLE_PRONE, 0 , FALSE ); break; case ANIM_CROUCH: ChangeSoldierState( pSoldier, AIM_RIFLE_CROUCH, 0 , FALSE ); break; } } return( TRUE ); } // MOVETO CURRENT SPREAD LOCATION if ( pSoldier->fDoSpread ) { if ( pSoldier->sSpreadLocations[ pSoldier->fDoSpread - 1 ] != 0 ) { EVENT_SetSoldierDirection( pSoldier, (INT8)GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, pSoldier->sSpreadLocations[ pSoldier->fDoSpread - 1 ] ) ); EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection ); } } break; case 449: //CODE: FINISH BURST pSoldier->fDoSpread = FALSE; pSoldier->bDoBurst = 1; // pSoldier->fBurstCompleted = TRUE; break; case 450: //CODE: BEGINHOPFENCE // MOVE TWO FACGIN GRIDNOS sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) ); sNewGridNo = NewGridNo( (UINT16)sNewGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) ); pSoldier->sForcastGridno = sNewGridNo; break; case 451: // CODE: MANAGE START z-buffer override switch( pSoldier->bDirection ) { case NORTH: case WEST: pSoldier->sZLevelOverride = TOPMOST_Z_LEVEL; break; } break; case 452: // CODE: MANAGE END z-buffer override switch( pSoldier->bDirection ) { case SOUTH: case EAST: pSoldier->sZLevelOverride = TOPMOST_Z_LEVEL; break; case NORTH: case WEST: pSoldier->sZLevelOverride = -1; break; } break; case 453: //CODE: FALLOFF ROOF ( BACKWARDS ) - MOVE BACK SOME! // Use same function as forward, but is -ve values! MoveMercFacingDirection( pSoldier , TRUE, (FLOAT)gFalloffBackwardsDist[ pSoldier->ubBodyType ] ); break; case 454: // CODE: HANDLE CLIMBING ROOF, // Move merc up if ( pSoldier->bDirection == NORTH ) { SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment + gClimbUpRoofDist[ pSoldier->ubBodyType ] ) ); } else { SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment + gClimbUpRoofDist[ pSoldier->ubBodyType ] ) ); } break; case 455: // MOVE GUY FORWARD SOME VALUE MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)gClimbUpRoofLATDist[ pSoldier->ubBodyType ] ); // MOVE DOWN SOME VALUE TOO! SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment - gClimbUpRoofDistGoingLower[ pSoldier->ubBodyType ] ) ); break; case 456: // CODE: HANDLE CLIMBING ROOF, // Move merc DOWN if ( pSoldier->bDirection == NORTH ) { SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment - gClimbUpRoofDist[ pSoldier->ubBodyType ] ) ); } else { SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment - gClimbUpRoofDist[ pSoldier->ubBodyType ] ) ); } break; case 457: // CODE: CHANGCE STANCE TO STANDING SendChangeSoldierStanceEvent( pSoldier, ANIM_STAND ); break; case 459: // CODE: CHANGE ATTACKING TO FIRST HAND pSoldier->ubAttackingHand = HANDPOS; pSoldier->usAttackingWeapon = pSoldier->inv[pSoldier->ubAttackingHand].usItem; // Adjust fReloading to FALSE pSoldier->fReloading = FALSE; break; case 458: // CODE: CHANGE ATTACKING TO SECOND HAND pSoldier->ubAttackingHand = SECONDHANDPOS; pSoldier->usAttackingWeapon = pSoldier->inv[pSoldier->ubAttackingHand].usItem; // Adjust fReloading to FALSE pSoldier->fReloading = FALSE; break; case 460: case 461: //CODE: THORW ITEM // Launch ITem! if ( pSoldier->pTempObject != NULL && pSoldier->pThrowParams != NULL ) { // ATE: If we are armmed... if ( pSoldier->pThrowParams->ubActionCode == THROW_ARM_ITEM ) { //AXP 25.03.2007: MinAPsToThrow now actually returns the real cost, not 0 // ATE: Deduct points! DeductPoints( pSoldier, MinAPsToThrow( pSoldier, pSoldier->sTargetGridNo, FALSE ), 0 ); } else { // ATE: Deduct points! DeductPoints( pSoldier, AP_TOSS_ITEM, 0 ); } CreatePhysicalObject( pSoldier->pTempObject, pSoldier->pThrowParams->dLifeSpan, pSoldier->pThrowParams->dX, pSoldier->pThrowParams->dY, pSoldier->pThrowParams->dZ, pSoldier->pThrowParams->dForceX, pSoldier->pThrowParams->dForceY, pSoldier->pThrowParams->dForceZ, pSoldier->ubID, pSoldier->pThrowParams->ubActionCode, pSoldier->pThrowParams->uiActionData, FALSE ); // Remove object //RemoveObjFrom( &(pSoldier->inv[ HANDPOS ] ), 0 ); // Update UI DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); MemFree( pSoldier->pTempObject ); pSoldier->pTempObject = NULL; MemFree( pSoldier->pThrowParams ); pSoldier->pThrowParams = NULL; } break; case 462: // CODE: MOVE UP FROM CLIFF CLIMB pSoldier->dHeightAdjustment += (float)2.1; pSoldier->sHeightAdjustment = (INT16)pSoldier->dHeightAdjustment; // Move over some... //MoveMercFacingDirection( pSoldier , FALSE, (FLOAT)0.5 ); break; case 463: // MOVE GUY FORWARD SOME VALUE // Creature move MoveMercFacingDirection( pSoldier, FALSE, (FLOAT)1.5 ); break; case 464: // CODE: END CLIFF CLIMB pSoldier->dHeightAdjustment = (float)0; pSoldier->sHeightAdjustment = (INT16)pSoldier->dHeightAdjustment; // Set new gridno { INT16 sTempGridNo, sNewX, sNewY; //Get Next GridNo; sTempGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (INT16)( DirectionInc(pSoldier->bDirection ) ) ); // Get center XY ConvertGridNoToCenterCellXY( sTempGridNo, &sNewX, &sNewY ); // Set position EVENT_SetSoldierPosition( pSoldier, sNewX, sNewY ); // Move two CC directions EVENT_SetSoldierDirection( pSoldier, gTwoCCDirection[ pSoldier->bDirection ] ); EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection ); // Set desired anim height! pSoldier->ubDesiredHeight = ANIM_CROUCH; pSoldier->sFinalDestination = pSoldier->sGridNo; } break; case 465: // CODE: SET GUY TO LIFE OF 0 pSoldier->bLife = 0; break; case 466: // CODE: ADJUST TO OUR DEST HEIGHT if ( pSoldier->sHeightAdjustment != pSoldier->sDesiredHeight ) { INT16 sDiff = pSoldier->sHeightAdjustment - pSoldier->sDesiredHeight; if ( abs( sDiff ) > 4 ) { if ( sDiff > 0 ) { // Adjust! SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment - 2 ) ); } else { // Adjust! SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->dHeightAdjustment + 2 ) ); } } else { // Adjust! SetSoldierHeight( pSoldier, (FLOAT)(pSoldier->sDesiredHeight) ); } } else { // Goto eating animation if ( pSoldier->sDesiredHeight == 0 ) { ChangeSoldierState( pSoldier, CROW_EAT, 0 , FALSE ); } else { // We should leave now! TacticalRemoveSoldier( pSoldier->ubID ); return( FALSE ); } return( TRUE ); } break; case 467: ///CODE: FOR HELIDROP, SET DIRECTION EVENT_SetSoldierDirection( pSoldier, EAST ); EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection ); gfIngagedInDrop = FALSE; // OK, now get a sweetspot ( not the place we are now! ) // sNewGridNo = FindGridNoFromSweetSpotExcludingSweetSpot( pSoldier, pSoldier->sGridNo, 5, &ubNewDirection ); //sNewGridNo = FindRandomGridNoFromSweetSpotExcludingSweetSpot( pSoldier, pSoldier->sGridNo, 3, &ubNewDirection ); sNewGridNo = FindGridNoFromSweetSpotExcludingSweetSpotInQuardent( pSoldier, pSoldier->sGridNo, 3, &ubNewDirection, SOUTHEAST ); // Check for merc arrives quotes... HandleMercArrivesQuotes( pSoldier ); // Find a path to it! EVENT_GetNewSoldierPath( pSoldier, sNewGridNo, WALKING ); return( TRUE ); break; case 468: // CODE: End PUNCH { BOOLEAN fNPCPunch = FALSE; // ATE: Put some code in for NPC punches... if ( pSoldier->uiStatusFlags & SOLDIER_NPC_DOING_PUNCH ) { fNPCPunch = TRUE; // Turn off pSoldier->uiStatusFlags &= (~SOLDIER_NPC_DOING_PUNCH ); // Trigger approach... TriggerNPCWithGivenApproach( pSoldier->ubProfile, (UINT8)pSoldier->uiPendingActionData4, FALSE ); } // Are we a martial artist? { BOOLEAN fMartialArtist = FALSE; if ( pSoldier->ubProfile != NO_PROFILE ) { if ( gMercProfiles[ pSoldier->ubProfile ].bSkillTrait == MARTIALARTS || gMercProfiles[ pSoldier->ubProfile ].bSkillTrait2 == MARTIALARTS ) { fMartialArtist = TRUE; } } if ( gAnimControl[ pSoldier->usAnimState ].ubHeight == ANIM_CROUCH ) { if ( fNPCPunch ) { ChangeSoldierStance( pSoldier, ANIM_STAND ); return( TRUE ); } else { ChangeSoldierState( pSoldier, CROUCHING, 0, FALSE ); return( TRUE ); } } else { if ( fMartialArtist && !AreInMeanwhile( ) ) { ChangeSoldierState( pSoldier, NINJA_BREATH, 0, FALSE ); return( TRUE ); } else { ChangeSoldierState( pSoldier, PUNCH_BREATH, 0, FALSE ); return( TRUE ); } } } } break; case 469: // CODE: Begin martial artist attack DoNinjaAttack( pSoldier ); return( TRUE ); break; case 470: // CODE: CHECK FOR OK WEAPON SHOT! bOKFireWeapon = OKFireWeapon( pSoldier ); if ( bOKFireWeapon == FALSE ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Fire Weapon: Gun Cannot fire, code 470") ); // OK, SKIP x # OF FRAMES // Skip 3 frames, ( a third ia added at the end of switch.. ) For a total of 4 pSoldier->usAniCode += 4; // Reduce by a bullet... // pSoldier->bBulletsLeft--; PlayJA2Sample( S_DRYFIRE1, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); // Free-up! DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - gun failed to fire") ); FreeUpAttacker( ); } else if ( bOKFireWeapon == 255 ) { // Play intermediate animation... if ( HandleUnjamAnimation( pSoldier ) ) { return( TRUE ); } } break; case 471: // CODE: Turn pause move flag off pSoldier->uiStatusFlags &= (~SOLDIER_PAUSEANIMOVE); break; case 472: { BOOLEAN fGoBackToAimAfterHit; // Save old flag, then reset. If we do nothing special here, at least go back // to aim if we were. fGoBackToAimAfterHit = pSoldier->fGoBackToAimAfterHit; pSoldier->fGoBackToAimAfterHit = FALSE; if ( !( pSoldier->uiStatusFlags & SOLDIER_TURNINGFROMHIT ) ) { switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) { case ANIM_STAND: // OK, we can do some cool things here - first is to make guy walkl back a bit... // ChangeSoldierState( pSoldier, STANDING_HIT_BEGINCROUCHDOWN, 0, FALSE ); // return( TRUE ); break; } } // CODE: HANDLE ANY RANDOM HIT VARIATIONS WE WISH TO DO..... if ( fGoBackToAimAfterHit ) { if ( pSoldier->bLife >= OKLIFE ) { InternalSoldierReadyWeapon( pSoldier, pSoldier->bDirection, FALSE ); } return( TRUE ); } } break; case 473: // CODE: CHECK IF WE HAVE JUST JAMMED / OUT OF AMMO, DONOT CONTINUE, BUT // GOTO STATIONARY ANIM if ( CheckForImproperFireGunEnd( pSoldier ) ) { return( TRUE ); } break; case 474: // CODE: GETUP FROM SLEEP ChangeSoldierStance( pSoldier, ANIM_STAND ); return( TRUE ); case 475: // CODE: END CLIMB DOWN ROOF pSoldier->ubDesiredHeight = ANIM_STAND; pSoldier->sFinalDestination = pSoldier->sGridNo; // re-enable sight gTacticalStatus.uiFlags &= (~DISALLOW_SIGHT); // ATE: Change interface level..... // CJC: only if we are a player merc if ( (pSoldier->bTeam == gbPlayerNum) && !gTacticalStatus.fAutoBandageMode) { if ( pSoldier->ubID == gusSelectedSoldier ) { ChangeInterfaceLevel( 0 ); } // OK, UNSET INTERFACE FIRST UnSetUIBusy( pSoldier->ubID ); } else { FreeUpNPCFromRoofClimb( pSoldier ); } pSoldier->usUIMovementMode = WALKING; // ATE: Handle sight... HandleSight( pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT ); break; case 476: // CODE: GOTO PREVIOUS ANIMATION ChangeSoldierState( pSoldier, ( pSoldier->sPendingActionData2 ), (UINT8)( pSoldier->uiPendingActionData1 + 1 ), FALSE ); return( TRUE ); break; case 477: // CODE: Locate to target ( if an AI guy.. ) if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT ) ) { if ( pSoldier->bTeam != gbPlayerNum ) { // only locate if the enemy is visible or he's aiming at a player if ( pSoldier->bVisible != -1 || (pSoldier->ubTargetID != NOBODY && MercPtrs[ pSoldier->ubTargetID ]->bTeam == gbPlayerNum) ) { LocateGridNo( pSoldier->sTargetGridNo ); } } } break; case 478: // CODE: Decide to turn from hit....... { INT8 bNewDirection; UINT32 uiChance; // ONLY DO THIS IF CERTAIN CONDITIONS ARISE! // For one, only do for mercs! if ( pSoldier->ubBodyType <= REGFEMALE ) { // Secondly, don't if we are going to collapse if ( pSoldier->bLife >= OKLIFE && pSoldier->bBreath > 0 && pSoldier->bLevel == 0 ) { // Save old direction pSoldier->uiPendingActionData1 = pSoldier->bDirection; // If we got a head shot...more chance of turning... if ( pSoldier->ubHitLocation != AIM_SHOT_HEAD ) { uiChance = Random( 100 ); // 30 % chance to change direction one way if ( uiChance < 30 ) { bNewDirection = gOneCDirection[ pSoldier->bDirection ]; } // 30 % chance to change direction the other way else if ( uiChance >= 30 && uiChance < 60 ) { bNewDirection = gOneCCDirection[ pSoldier->bDirection ]; } // 30 % normal.... else { bNewDirection = pSoldier->bDirection; } EVENT_SetSoldierDirection( pSoldier, bNewDirection ); EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->bDirection ); } else { // OK, 50% chance here to turn... uiChance = Random( 100 ); if ( uiChance < 50 ) { // OK, pick a larger direction to goto.... pSoldier->uiStatusFlags |= SOLDIER_TURNINGFROMHIT; // This becomes an attack busy situation gTacticalStatus.ubAttackBusyCount++; DebugAttackBusy( String( "Soldier turning from a hit. Increasing attack busy. Now %d\n", gTacticalStatus.ubAttackBusyCount ) ); // Pick evenly between both if ( Random( 50 ) < 25 ) { bNewDirection = gOneCDirection[ pSoldier->bDirection ]; bNewDirection = gOneCDirection[ bNewDirection ]; bNewDirection = gOneCDirection[ bNewDirection ]; } else { bNewDirection = gOneCCDirection[ pSoldier->bDirection ]; bNewDirection = gOneCCDirection[ bNewDirection ]; bNewDirection = gOneCCDirection[ bNewDirection ]; } EVENT_SetSoldierDesiredDirection( pSoldier, bNewDirection ); } } } } break; } case 479: // CODE: Return to old direction...... if ( pSoldier->ubBodyType <= REGFEMALE ) { // Secondly, don't if we are going to collapse //if ( pSoldier->bLife >= OKLIFE && pSoldier->bBreath > 0 ) //{ /// if ( !( pSoldier->uiStatusFlags & SOLDIER_TURNINGFROMHIT ) ) // { /// pSoldier->bDirection = (INT8)pSoldier->uiPendingActionData1; // pSoldier->bDesiredDirection = (INT8)pSoldier->uiPendingActionData1; // } //} } break; case 480: // 0verhaul: This is handled in the ReduceAttackBusyCount call // CODE: FORCE FREE ATTACKER // Release attacker //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, code 480") ); //ReleaseSoldiersAttacker( pSoldier ); //FREEUP GETTING HIT FLAG //pSoldier->fGettingHit = FALSE; break; case 481: // CODE: CUT FENCE... CutWireFence( pSoldier->sTargetGridNo ); break; case 482: // CODE: END CRIPPLE KICKOUT... KickOutWheelchair( pSoldier ); break; case 483: // CODE: HANDLE DROP BOMB... HandleSoldierDropBomb( pSoldier, pSoldier->sPendingActionData2 ); break; case 484: // CODE: HANDLE REMOTE... HandleSoldierUseRemote( pSoldier, pSoldier->sPendingActionData2 ); break; case 485: // CODE: Try steal..... // UnSetUIBusy( pSoldier->ubID); UseHandToHand( pSoldier, pSoldier->sPendingActionData2, TRUE ); //jackaians: //if we are not waiting for the pickup menu to be displayed // if (guiPendingOverrideEvent != G_GETTINGITEM) // { // PreventFromTheFreezingBug(pSoldier); // } break; case 486: // CODE: GIVE ITEM SoldierGiveItemFromAnimation( pSoldier ); if (pSoldier->ubProfile != NO_PROFILE && pSoldier->ubProfile >= FIRST_NPC ) { TriggerNPCWithGivenApproach( pSoldier->ubProfile, APPROACH_DONE_GIVING_ITEM, FALSE ); } break; case 487: // CODE: DROP ITEM SoldierHandleDropItem( pSoldier ); break; case 489: //CODE: REMOVE GUY FRMO WORLD DUE TO EXPLOSION //ChangeSoldierState( pSoldier, RAISE_RIFLE, 0 , FALSE ); //return( TRUE ); //Delete guy //TacticalRemoveSoldier( pSoldier->ubID ); //return( FALSE ); break; case 490: // CODE: HANDLE END ITEM PICKUP //LOOK INTO HAND, RAISE RIFLE IF WE HAVE ONE.... /* if ( pSoldier->inv[ HANDPOS ].usItem != NOTHING ) { // CHECK IF GUN if ( Item[ pSoldier->inv[ HANDPOS ].usItem ].usItemClass == IC_GUN ) { if ( Weapon[ pSoldier->inv[ HANDPOS ].usItem ].ubWeaponClass != HANDGUNCLASS ) { // RAISE ChangeSoldierState( pSoldier, RAISE_RIFLE, 0 , FALSE ); return( TRUE ); } } } */ break; case 491: // CODE: HANDLE RANDOM BREATH ANIMATION //if ( pSoldier->bLife > INJURED_CHANGE_THREASHOLD ) if ( pSoldier->bLife >= OKLIFE ) { // Increment time from last update pSoldier->uiTimeOfLastRandomAction++; if ( pSoldier->uiTimeOfLastRandomAction > TIME_FOR_RANDOM_ANIM_CHECK || pSoldier->bLife < INJURED_CHANGE_THREASHOLD || GetDrunkLevel( pSoldier ) >= BORDERLINE ) { pSoldier->uiTimeOfLastRandomAction = 0; // Don't do any in water! if ( !MercInWater( pSoldier ) ) { // OK, make a dice roll ubDiceRoll = (UINT8)Random( 100 ); // Determine what is in our hand; usItem = pSoldier->inv[ HANDPOS ].usItem; // Default to nothing in hand ( nothing in quotes, we do have something but not just visible ) ubRandomHandIndex = RANDOM_ANIM_NOTHINGINHAND; if ( usItem != NOTHING ) { if ( Item[ usItem ].usItemClass == IC_GUN ) { // if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) ) if ( (Item[ usItem ].twohanded ) ) { // Set to rifle ubRandomHandIndex = RANDOM_ANIM_RIFLEINHAND; } else { // Don't EVER do a trivial anim... break; } } } // Check which animation to play.... for ( cnt = 0; cnt < MAX_RANDOM_ANIMS_PER_BODYTYPE; cnt++ ) { pAnimDef = &( gRandomAnimDefs[ pSoldier->ubBodyType ][ cnt ] ); if ( pAnimDef->sAnimID != 0 ) { // If it's an injured animation and we are not in the threashold.... if ( ( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && pSoldier->bLife >= INJURED_CHANGE_THREASHOLD ) { continue; } // If we need to do an injured one, don't do any others... if ( !( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && pSoldier->bLife < INJURED_CHANGE_THREASHOLD ) { continue; } // If it's a drunk animation and we are not in the threashold.... if ( ( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && GetDrunkLevel( pSoldier ) < BORDERLINE ) { continue; } // If we need to do an injured one, don't do any others... if ( !( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && GetDrunkLevel( pSoldier ) >= BORDERLINE ) { continue; } // Check if it's our hand if ( pAnimDef->ubHandRestriction != RANDOM_ANIM_IRRELEVENTINHAND && pAnimDef->ubHandRestriction != ubRandomHandIndex ) { continue; } // Check if it's casual and we're in combat and it's not our guy if ( ( pAnimDef->ubFlags & RANDOM_ANIM_CASUAL ) ) { // If he's a bad guy, do not do it! if ( pSoldier->bTeam != gbPlayerNum || ( gTacticalStatus.uiFlags & INCOMBAT ) ) { continue; } } // If we are an alternate big guy and have been told to use a normal big merc ani... if ( ( pAnimDef->ubFlags & RANDOM_ANIM_FIRSTBIGMERC ) && ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) ) { continue; } // If we are a normal big guy and have been told to use an alternate big merc ani... if ( ( pAnimDef->ubFlags & RANDOM_ANIM_SECONDBIGMERC ) && !( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) ) { continue; } // Check if it's the proper height if ( pAnimDef->ubAnimHeight == gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) { // OK, If we rolled a value that lies within the range for this random animation, use this one! if ( ubDiceRoll >= pAnimDef->ubStartRoll && ubDiceRoll <= pAnimDef->ubEndRoll ) { // Are we playing a sound if ( pAnimDef->sAnimID == RANDOM_ANIM_SOUND ) { if ( pSoldier->ubBodyType == COW ) { if ( Random( 2 ) == 1 ) { if ( ( gTacticalStatus.uiFlags & INCOMBAT ) && pSoldier->bVisible == -1 ) { // DO this every 10th time or so... if ( Random( 100 ) < 10 ) { // Play sound PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } } else { // Play sound PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } } } else { // Play sound PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } } else { ChangeSoldierState( pSoldier, pAnimDef->sAnimID, 0 , FALSE ); } return( TRUE ); } } } } } } } break; case 492: // SIGNAL DODGE! // ATE: Only do if we're not inspecial case... if ( !( pSoldier->uiStatusFlags & SOLDIER_NPC_DOING_PUNCH ) ) { SOLDIERTYPE *pTSoldier; UINT32 uiMercFlags; UINT16 usSoldierIndex; if ( FindSoldier( pSoldier->sTargetGridNo, &usSoldierIndex, &uiMercFlags, FIND_SOLDIER_GRIDNO ) ) { GetSoldier( &pTSoldier, usSoldierIndex ); // IF WE ARE AN ANIMAL, CAR, MONSTER, DONT'T DODGE if ( IS_MERC_BODY_TYPE( pTSoldier ) ) { // ONLY DODGE IF WE ARE SEEN if ( pTSoldier->bOppList[ pSoldier->ubID ] != 0 || pTSoldier->bTeam == pSoldier->bTeam ) { if ( gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND ) { // OK, stop merc.... EVENT_StopMerc( pTSoldier, pTSoldier->sGridNo, pTSoldier->bDirection ); if ( pTSoldier->bTeam != gbPlayerNum ) { CancelAIAction( pTSoldier, TRUE ); } // Turn towards the person! EVENT_SetSoldierDesiredDirection( pTSoldier, GetDirectionFromGridNo( pSoldier->sGridNo, pTSoldier ) ); // PLAY SOLDIER'S DODGE ANIMATION ChangeSoldierState( pTSoldier, DODGE_ONE, 0 , FALSE ); } } } } } break; case 493: //CODE: PICKUP ITEM! // CHECK IF THIS EVENT HAS BEEN SETUP //if ( pSoldier->ubPendingAction == MERC_PICKUPITEM ) //{ // DROP ITEM HandleSoldierPickupItem( pSoldier, pSoldier->uiPendingActionData1, (INT16)(pSoldier->uiPendingActionData4 ), pSoldier->bPendingActionData3 ); // EVENT HAS BEEN HANDLED pSoldier->ubPendingAction = NO_PENDING_ACTION; //} //else //{ // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: CODE 493 Error, Pickup item action called but not setup" ); //} break; case 494: //CODE: OPEN STRUCT! // CHECK IF THIS EVENT HAS BEEN SETUP //if ( pSoldier->ubPendingAction == MERC_OPENSTRUCT ) //{ SoldierHandleInteractiveObject( pSoldier ); // EVENT HAS BEEN HANDLED pSoldier->ubPendingAction = NO_PENDING_ACTION; //} //else //{ // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: CODE 494 Error, OPen door action called but not setup" ); //} break; case 495: if (pSoldier->bAction == AI_ACTION_UNLOCK_DOOR || (pSoldier->bAction == AI_ACTION_LOCK_DOOR && !(pSoldier->fAIFlags & AI_LOCK_DOOR_INCLUDES_CLOSE) ) ) { // EVENT HAS BEEN HANDLED pSoldier->ubPendingAction = NO_PENDING_ACTION; // do nothing here } else { pSoldier->fAIFlags &= ~(AI_LOCK_DOOR_INCLUDES_CLOSE); pSoldier->ubDoorOpeningNoise = DoorOpeningNoise( pSoldier ); if ( SoldierHandleInteractiveObject( pSoldier ) ) { // HANDLE SIGHT! //HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT ); InitOpplistForDoorOpening(); MakeNoise( pSoldier->ubID, pSoldier->sGridNo, pSoldier->bLevel, gpWorldLevelData[pSoldier->sGridNo].ubTerrainID, pSoldier->ubDoorOpeningNoise, NOISE_CREAKING ); // gfDelayResolvingBestSighting = FALSE; gubInterruptProvoker = pSoldier->ubID; AllTeamsLookForAll( TRUE ); // ATE: Now, check AI guy to cancel what he was going.... HandleSystemNewAISituation( pSoldier, TRUE ); } // EVENT HAS BEEN HANDLED pSoldier->ubPendingAction = NO_PENDING_ACTION; } break; case 496: // CODE: GOTO PREVIOUS ANIMATION ChangeSoldierState( pSoldier, pSoldier->usOldAniState, pSoldier->sOldAniCode, FALSE ); return( TRUE ); case 497: // CODE: CHECK FOR UNCONSCIOUS OR DEATH // IF 496 - GOTO PREVIOUS ANIMATION, OTHERWISE PAUSE ANIMATION if ( pSoldier->bLife == 0 ) { //HandleSoldierDeath( pSoldier ); // If guy is now dead, and we have not played death sound before, play if ( pSoldier->bLife == 0 && !pSoldier->fDeadSoundPlayed ) { if ( pSoldier->usAnimState != JFK_HITDEATH ) { DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 ); pSoldier->fDeadSoundPlayed = TRUE; } } if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] ) { // If we are dead, play some death animations!! switch( pSoldier->usAnimState ) { case FLYBACK_HIT: ChangeSoldierState( pSoldier, FLYBACK_HIT_DEATH, 0, FALSE ); break; case GENERIC_HIT_DEATHTWITCHNB: case FALLFORWARD_FROMHIT_STAND: case ENDFALLFORWARD_FROMHIT_CROUCH: ChangeSoldierState( pSoldier, GENERIC_HIT_DEATH, 0, FALSE ); break; case FALLBACK_HIT_DEATHTWITCHNB: case FALLBACK_HIT_STAND: ChangeSoldierState( pSoldier, FALLBACK_HIT_DEATH, 0, FALSE ); break; case PRONE_HIT_DEATHTWITCHNB: case PRONE_LAY_FROMHIT: ChangeSoldierState( pSoldier, PRONE_HIT_DEATH, 0, FALSE ); break; case FALLOFF: ChangeSoldierState( pSoldier, FALLOFF_DEATH, 0, FALSE ); break; case FALLFORWARD_ROOF: ChangeSoldierState( pSoldier, FALLOFF_FORWARD_DEATH, 0, FALSE); break; case ADULTMONSTER_DYING: ChangeSoldierState( pSoldier, ADULTMONSTER_DYING_STOP, 0, FALSE); break; case LARVAE_DIE: ChangeSoldierState( pSoldier, LARVAE_DIE_STOP, 0, FALSE); break; case QUEEN_DIE: ChangeSoldierState( pSoldier, QUEEN_DIE_STOP, 0, FALSE); break; case INFANT_DIE: ChangeSoldierState( pSoldier, INFANT_DIE_STOP, 0, FALSE); break; case CRIPPLE_DIE: ChangeSoldierState( pSoldier, CRIPPLE_DIE_STOP, 0, FALSE); break; case ROBOTNW_DIE: ChangeSoldierState( pSoldier, ROBOTNW_DIE_STOP, 0, FALSE); break; case CRIPPLE_DIE_FLYBACK: ChangeSoldierState( pSoldier, CRIPPLE_DIE_FLYBACK_STOP, 0, FALSE); break; default: // IF we are here - something is wrong - we should have a death animation here DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Ani: Death sequence needed for animation %d", pSoldier->usAnimState ) ); } } else { BOOLEAN fMadeCorpse; CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse ); // ATE: Needs to be FALSE! return( FALSE ); } return( TRUE ); } else { // We can safely be here as well.. ( ie - next turn we may be able to get up ) // DO SOME CHECKS HERE TO FREE UP ATTACKERS IF WE ARE WAITING AT SPECIFIC ANIMATIONS if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_HITFINISH ) ) { gfPotentialTeamChangeDuringDeath = TRUE; // 0verhaul: This is now already handled // Release attacker // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, code 497 = check for death") ); // ReleaseSoldiersAttacker( pSoldier ); // ATE: OK - the above call can potentially // render the soldier bactive to false - check heare if ( !pSoldier->bActive ) { return( FALSE ); } gfPotentialTeamChangeDuringDeath = FALSE; // FREEUP GETTING HIT FLAG pSoldier->fGettingHit = FALSE; } HandleCheckForDeathCommonCode( pSoldier ); return( TRUE ); } break; case 498: // CONDITONAL JUMP // If we have a pending animation, play it, else continue if ( pSoldier->usPendingAnimation != NO_PENDING_ANIMATION ) { ChangeSoldierState( pSoldier, pSoldier->usPendingAnimation, 0, FALSE ); pSoldier->usPendingAnimation = NO_PENDING_ANIMATION; return( TRUE ); } break; // JUMP TO NEXT STATIONARY ANIMATION ACCORDING TO HEIGHT case 499: if (!(pSoldier->uiStatusFlags & SOLDIER_PC)) { if ( pSoldier->bAction == AI_ACTION_PULL_TRIGGER ) { if ( pSoldier->usAnimState == AI_PULL_SWITCH && gTacticalStatus.ubAttackBusyCount == 0 && gubElementsOnExplosionQueue == 0 ) { FreeUpNPCFromPendingAction( pSoldier ); } } else if ( pSoldier->bAction == AI_ACTION_PENDING_ACTION || pSoldier->bAction == AI_ACTION_OPEN_OR_CLOSE_DOOR || pSoldier->bAction == AI_ACTION_YELLOW_ALERT || pSoldier->bAction == AI_ACTION_RED_ALERT || pSoldier->bAction == AI_ACTION_PULL_TRIGGER || pSoldier->bAction == AI_ACTION_CREATURE_CALL || pSoldier->bAction == AI_ACTION_UNLOCK_DOOR || pSoldier->bAction == AI_ACTION_LOCK_DOOR ) { if ( pSoldier->usAnimState == PICKUP_ITEM || pSoldier->usAnimState == ADJACENT_GET_ITEM || pSoldier->usAnimState == DROP_ITEM || pSoldier->usAnimState == END_OPEN_DOOR || pSoldier->usAnimState == END_OPEN_DOOR_CROUCHED || pSoldier->usAnimState == CLOSE_DOOR || pSoldier->usAnimState == MONSTER_UP || pSoldier->usAnimState == AI_RADIO || pSoldier->usAnimState == AI_CR_RADIO || pSoldier->usAnimState == END_OPENSTRUCT || pSoldier->usAnimState == END_OPENSTRUCT_CROUCHED || pSoldier->usAnimState == QUEEN_CALL ) { FreeUpNPCFromPendingAction( pSoldier ); } } } ubDesiredHeight = pSoldier->ubDesiredHeight; // Check if we are at the desired height if ( pSoldier->ubDesiredHeight == gAnimControl[ pSoldier->usAnimState ].ubEndHeight || pSoldier->ubDesiredHeight == NO_DESIRED_HEIGHT ) { // Adjust movement mode...... if ( pSoldier->bTeam == gbPlayerNum && !pSoldier->fContinueMoveAfterStanceChange ) { usUIMovementMode = GetMoveStateBasedOnStance( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ); // ATE: if we are currently running but have been told to walk, don't! if ( pSoldier->usUIMovementMode == RUNNING && usUIMovementMode == WALKING ) { // No! } else { pSoldier->usUIMovementMode = usUIMovementMode; } } pSoldier->ubDesiredHeight = NO_DESIRED_HEIGHT; // 0verhaul: This is moved to the animation state transition code to make sure it isn't sidestepped. // if (pSoldier->fChangingStanceDueToSuppression) // { // pSoldier->fChangingStanceDueToSuppression = FALSE; // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - end of suppression stance change") ); // ReduceAttackBusyCount( pSoldier->ubSuppressorID, FALSE ); // } if ( pSoldier->usPendingAnimation == NO_PENDING_ANIMATION && ( pSoldier->fTurningFromPronePosition != 3 ) && ( pSoldier->fTurningFromPronePosition != 1 ) ) { if ( gTacticalStatus.ubAttackBusyCount == 0 ) { // OK, UNSET INTERFACE FIRST UnSetUIBusy( pSoldier->ubID ); // ( before we could get interrupted potentially by an interrupt ) } } // Check to see if we have changed stance and need to update visibility if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_STANCECHANGEANIM) { if ( pSoldier->usPendingAnimation == NO_PENDING_ANIMATION && gTacticalStatus.ubAttackBusyCount == 0 && pSoldier->fTurningFromPronePosition != 3 && pSoldier->fTurningFromPronePosition != 1 ) { HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO | SIGHT_INTERRUPT ); } else { HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO ); } // Keep ui busy if we are now in a hidden interrupt // say we're prone and we crouch, we may get a hidden // interrupt and in such a case we'd really like the UI // still locked if ( gfHiddenInterrupt ) { guiPendingOverrideEvent = LA_BEGINUIOURTURNLOCK; HandleTacticalUI( ); } // ATE: Now, check AI guy to cancel what he was going.... HandleSystemNewAISituation( pSoldier, TRUE ); } // Have we finished opening doors? if ( pSoldier->usAnimState == END_OPEN_DOOR || pSoldier->usAnimState == END_OPEN_DOOR_CROUCHED || pSoldier->usAnimState == CRIPPLE_CLOSE_DOOR || pSoldier->usAnimState == CRIPPLE_END_OPEN_DOOR ) { // Are we told to continue movement...? if ( pSoldier->bEndDoorOpenCode == 1 ) { // OK, set this value to 2 such that once we are into a new gridno, // we close the door! pSoldier->bEndDoorOpenCode = 2; // yes.. EVENT_GetNewSoldierPath( pSoldier, pSoldier->sFinalDestination, pSoldier->usUIMovementMode ); if ( !( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_MOVING ) ) ) { if ( pSoldier->sAbsoluteFinalDestination != NOWHERE ) { CancelAIAction( pSoldier, FORCE ); } } // OK, this code, pSoldier->bEndDoorOpenCode will be set to 0 if anythiing // cuases guy to stop - StopMerc() will set it... return( TRUE ); } } // Check if we should contine into a moving animation if ( pSoldier->usPendingAnimation != NO_PENDING_ANIMATION ) { UINT16 usPendingAnimation = pSoldier->usPendingAnimation; pSoldier->usPendingAnimation = NO_PENDING_ANIMATION; ChangeSoldierState( pSoldier, usPendingAnimation, 0, FALSE ); return( TRUE ); } // Alrighty, do we wish to continue if ( pSoldier->fContinueMoveAfterStanceChange ) { // OK, if the code is == 2, get the path and try to move.... if ( pSoldier->fContinueMoveAfterStanceChange == 2 ) { pSoldier->usPathIndex++; if ( pSoldier->usPathIndex > pSoldier->usPathDataSize ) { pSoldier->usPathIndex = pSoldier->usPathDataSize; } if ( pSoldier->usPathIndex == pSoldier->usPathDataSize ) { // Stop, don't do anything..... } else { EVENT_InitNewSoldierAnim( pSoldier, pSoldier->usUIMovementMode, 0 , FALSE ); // UNSET LOCK PENDING ACTION COUNTER FLAG pSoldier->uiStatusFlags &= ( ~SOLDIER_LOCKPENDINGACTIONCOUNTER ); } } else { SelectMoveAnimationFromStance( pSoldier ); } pSoldier->fContinueMoveAfterStanceChange = FALSE; return( TRUE ); } SoldierGotoStationaryStance( pSoldier ); return( TRUE ); } else { ubCurrentHeight = gAnimControl[ pSoldier->usAnimState ].ubEndHeight; // We need to go more, continue if ( ubDesiredHeight == ANIM_STAND && ubCurrentHeight == ANIM_CROUCH ) { // Return here because if now, we will skipp a few frames ChangeSoldierState( pSoldier, KNEEL_UP, 0 , FALSE ); return( TRUE ); } if ( ubDesiredHeight == ANIM_CROUCH && ubCurrentHeight == ANIM_STAND ) { // Return here because if now, we will skipp a few frames ChangeSoldierState( pSoldier, KNEEL_DOWN, 0 , FALSE ); return( TRUE ); } else if ( ubDesiredHeight == ANIM_PRONE && ubCurrentHeight == ANIM_CROUCH ) { // Return here because if now, we will skipp a few frames ChangeSoldierState( pSoldier, PRONE_DOWN, 0 , FALSE ); return( TRUE ); } else if ( ubDesiredHeight == ANIM_CROUCH && ubCurrentHeight == ANIM_PRONE ) { // Return here because if now, we will skipp a few frames ChangeSoldierState( pSoldier, PRONE_UP, 0 , FALSE ); return( TRUE ); } } // IF we are here - something is wrong - we should have a death animation here #ifdef JA2BETAVERSION ScreenMsg( FONT_ORANGE, MSG_BETAVERSION, L"Soldier Ani: GOTO Stance not chained properly: %d %d %d", ubDesiredHeight, ubCurrentHeight, pSoldier->usAnimState ); #endif SoldierGotoStationaryStance( pSoldier ); return( TRUE ); } // Adjust frame control pos, and try again pSoldier->usAniCode++; } else if ( sNewAniFrame > 499 && sNewAniFrame < 599 ) { // Jump, // Do not adjust, just try again pSoldier->usAniCode = sNewAniFrame - 501; } else if ( sNewAniFrame > 599 && sNewAniFrame <= 699 ) { // Jump, to animation script EVENT_InitNewSoldierAnim( pSoldier, (UINT16)(sNewAniFrame - 600 ), 0 , FALSE ); return( TRUE ); } else if ( sNewAniFrame > 799 && sNewAniFrame <= 899 ) { // Jump, to animation script ( But in the 100's range ) EVENT_InitNewSoldierAnim( pSoldier, (UINT16)(sNewAniFrame - 700 ), 0 , FALSE ); return( TRUE ); } else if ( sNewAniFrame > 899 && sNewAniFrame <= 999 ) { // Jump, to animation script ( But in the 200's range ) EVENT_InitNewSoldierAnim( pSoldier, (UINT16)(sNewAniFrame - 700 ), 0 , FALSE ); return( TRUE ); } else if ( sNewAniFrame > 699 && sNewAniFrame < 799 ) { switch( sNewAniFrame ) { case 702: // Play fall to knees sound PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( FALL_1 + Random(2) ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE ); break; case 703: case 704: // Play footprints PlaySoldierFootstepSound( pSoldier ); break; case 705: // PLay body splat sound PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)BODY_SPLAT_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 706: // PLay head splat PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)HEADSPLAT_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) , TRUE ); break; case 707: // PLay creature battle cry PlayJA2StreamingSample( (UINT8)CREATURE_BATTLECRY_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); break; case 708: // PLay lock n' load sound for gun.... // Get LNL sound for current gun { UINT16 usItem; UINT16 usSoundID; usItem = pSoldier->inv[ HANDPOS ].usItem; if ( usItem != NOTHING ) { usSoundID = Weapon[ usItem ].sLocknLoadSound; if ( usSoundID != 0 ) { PlayJA2Sample( usSoundID, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } } } break; case 709: // Knife throw sound... PlayJA2Sample( Weapon[ THROWING_KNIFE ].sSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); break; case 710: // Monster footstep in if ( SoldierOnScreen( pSoldier->ubID ) ) { PlaySoldierJA2Sample( pSoldier->ubID, ACR_STEP_1, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 711: // Monster footstep in if ( SoldierOnScreen( pSoldier->ubID ) ) { PlaySoldierJA2Sample( pSoldier->ubID, ACR_STEP_2, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 712: // Monster footstep in if ( SoldierOnScreen( pSoldier->ubID ) ) { PlaySoldierJA2Sample( pSoldier->ubID, LCR_MOVEMENT, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 713: // Monster footstep in if ( pSoldier->ubBodyType == INFANT_MONSTER ) { if ( SoldierOnScreen( pSoldier->ubID ) ) { PlaySoldierJA2Sample( pSoldier->ubID, BCR_DRAGGING, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } } break; case 714: // Lunges.... PlaySoldierJA2Sample( pSoldier->ubID, ACR_LUNGE, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 715: // Swipe PlaySoldierJA2Sample( pSoldier->ubID, ACR_SWIPE, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 716: // Eat flesh PlaySoldierJA2Sample( pSoldier->ubID, ACR_EATFLESH, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 717: // Battle cry { INT32 iSoundID=0; BOOLEAN fDoCry = FALSE; //if ( SoldierOnScreen( pSoldier->ubID ) ) { switch( pSoldier->usActionData ) { case CALL_1_PREY: if ( pSoldier->ubBodyType == QUEENMONSTER ) { iSoundID = LQ_SMELLS_THREAT; } else { iSoundID = ACR_SMEEL_PREY; } fDoCry = TRUE; break; case CALL_MULTIPLE_PREY: if ( pSoldier->ubBodyType == QUEENMONSTER ) { iSoundID = LQ_SMELLS_THREAT; } else { iSoundID = ACR_SMELL_THREAT; } fDoCry = TRUE; break; case CALL_ATTACKED: if ( pSoldier->ubBodyType == QUEENMONSTER ) { iSoundID = LQ_ENRAGED_ATTACK; } else { iSoundID = ACR_SMELL_THREAT; } fDoCry = TRUE; break; case CALL_CRIPPLED: if ( pSoldier->ubBodyType == QUEENMONSTER ) { iSoundID = LQ_CRIPPLED; } else { iSoundID = ACR_CRIPPLED; } fDoCry = TRUE; break; } if ( fDoCry ) { PlayJA2Sample( iSoundID, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } } } break; case 718: PlaySoldierJA2Sample( pSoldier->ubID, LQ_RUPTURING, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 719: // Spit attack start sound... PlaySoldierJA2Sample( pSoldier->ubID, LQ_ENRAGED_ATTACK, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 720: // Spit attack start sound... PlaySoldierJA2Sample( pSoldier->ubID, LQ_WHIP_ATTACK, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 721: // Play fall from knees to ground... PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( FALL_TO_GROUND_1 + Random(3) ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE ); if ( pSoldier->usAnimState == FALLFORWARD_FROMHIT_STAND ) { CheckEquipmentForFragileItemDamage( pSoldier, 20 ); } break; case 722: // Play fall heavy PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( HEAVY_FALL_1 ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE ); if ( pSoldier->usAnimState == FALLFORWARD_FROMHIT_CROUCH ) { CheckEquipmentForFragileItemDamage( pSoldier, 15 ); } break; case 723: // Play armpit noise... PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( IDLE_ARMPIT ), RATE_11025, SoundVolume( LOWVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 724: // Play ass scratch // PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( IDLE_SCRATCH ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 725: // Play back crack PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( IDLE_BACKCRACK ), RATE_11025, SoundVolume( LOWVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 726: // Kickin door PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( KICKIN_DOOR ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 727: // Swoosh PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( SWOOSH_1 + Random( 6 ) ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 728: // Creature fall PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( ACR_FALL_1 ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 729: // grab roof.... PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( GRAB_ROOF ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 730: // end climb roof.... PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( LAND_ON_ROOF ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 731: // Stop climb roof.. PlaySoldierJA2Sample( pSoldier->ubID, (UINT8)( FALL_TO_GROUND_1 + Random(3) ), RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 732: // Play die sound DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 ); pSoldier->fDeadSoundPlayed = TRUE; break; case 750: // CODE: Move Vehicle UP if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) { // SetSoldierHeight( pSoldier, (FLOAT)( pSoldier->sHeightAdjustment + 1 ) ); } break; case 751: // CODE: Move vehicle down if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) { // SetSoldierHeight( pSoldier, (FLOAT)( pSoldier->sHeightAdjustment - 1 ) ); } break; case 752: // Code: decapitate DecapitateCorpse( pSoldier, pSoldier->sTargetGridNo, pSoldier->bTargetLevel ); break; case 753: // code: freeup attcker DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count..., CODE FROM ANIMATION %s ( %d )", gAnimControl[ pSoldier->usAnimState ].zAnimStr, pSoldier->usAnimState ) ); DebugAttackBusy( String("@@@@@@@ Reducing attacker busy count..., CODE FROM ANIMATION %s ( %d )\n", gAnimControl[ pSoldier->usAnimState ].zAnimStr, pSoldier->usAnimState ) ); // ReduceAttackBusyCount( pSoldier->ubID, FALSE ); // ATE: Here, reduce again if creaturequeen tentical attack... // Uh, why not add a second 753 code to the queen swipe instead of adding code to make things more complex? if ( pSoldier->usAnimState == QUEEN_SWIPE ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count for end of queen swipe\n" ) ); DebugAttackBusy( "@@@@@@@ Reducing attacker busy count for end of queen swipe" ); // ReduceAttackBusyCount( pSoldier->ubID, FALSE ); } break; case 754: HandleFallIntoPitFromAnimation( pSoldier->ubID ); break; case 755 : DishoutQueenSwipeDamage( pSoldier ); break; case 756: // Reload robot.... { UINT8 ubPerson; SOLDIERTYPE *pRobot; // Get pointer... ubPerson = WhoIsThere2( pSoldier->sPendingActionData2, pSoldier->bLevel ); if ( ubPerson != NOBODY && MercPtrs[ ubPerson ]->uiStatusFlags & SOLDIER_ROBOT ) { pRobot = MercPtrs[ ubPerson ]; ReloadGun( pRobot, &(pRobot->inv[ HANDPOS ] ), pSoldier->pTempObject ); // OK, check what was returned and place in inventory if it's non-zero if ( pSoldier->pTempObject->usItem != NOTHING ) { // Add to inv.. AutoPlaceObject( pSoldier, pSoldier->pTempObject, TRUE ); } MemFree( pSoldier->pTempObject ); pSoldier->pTempObject = NULL; } } break; case 757: // INcrement attacker busy count.... // gTacticalStatus.ubAttackBusyCount++; DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!! Incrementing attacker busy count..., CODE FROM ANIMATION %s ( %d ) : Count now %d", gAnimControl[ pSoldier->usAnimState ].zAnimStr, pSoldier->usAnimState, gTacticalStatus.ubAttackBusyCount ) ); DebugAttackBusy( String("!!!!! CODE FROM ANIMATION %s ( %d )\n", gAnimControl[ pSoldier->usAnimState ].zAnimStr, pSoldier->usAnimState ) ); break; case 758: // Trigger after slap... TriggerNPCWithGivenApproach( QUEEN, APPROACH_DONE_SLAPPED , TRUE ); break; case 759: // Getting hit by slap { SOLDIERTYPE *pTarget; pTarget = FindSoldierByProfileID( ELLIOT, FALSE ); if ( pTarget ) { EVENT_InitNewSoldierAnim( pTarget, SLAP_HIT, 0 , FALSE ); // Play noise.... //PlaySoldierJA2Sample( pTarget->ubID, ( S_SLAP_IMPACT ), RATE_11025, SoundVolume( HIGHVOLUME, pTarget->sGridNo ), 1, SoundDir( pTarget->sGridNo ), TRUE ); //DoMercBattleSound( pTarget, (INT8)( BATTLE_SOUND_HIT1 + Random( 2 ) ) ); } } break; case 760: // Get some blood..... // Corpse Id is from pending action data GetBloodFromCorpse( pSoldier ); // Dirty interface.... DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); break; case 761: { // Dish out damage! EVENT_SoldierGotHit( MercPtrs[ pSoldier->uiPendingActionData4 ], TAKE_DAMAGE_BLADE, (INT16) 25, (INT16) 25, gOppositeDirection[ pSoldier->bDirection ], 50, pSoldier->ubID, 0, ANIM_PRONE, 0, 0 ); } break; case 762: { // CODE: Set off Trigger INT8 bPanicTrigger; bPanicTrigger = ClosestPanicTrigger( pSoldier ); SetOffPanicBombs( pSoldier->ubID, bPanicTrigger ); // any AI guy has been specially given keys for this, now take them // away pSoldier->bHasKeys = pSoldier->bHasKeys >> 1; } break; case 763: // CODE: Drop item at gridno if ( pSoldier->pTempObject != NULL ) { if ( pSoldier->bVisible != -1 ) { PlayJA2Sample( THROW_IMPACT_2, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } AddItemToPool( pSoldier->sPendingActionData2, pSoldier->pTempObject, 1, pSoldier->bLevel, 0 , -1 ); NotifySoldiersToLookforItems( ); MemFree( pSoldier->pTempObject ); pSoldier->pTempObject = NULL; } break; case 764: PlaySoldierJA2Sample( pSoldier->ubID, PICKING_LOCK, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 765: // Flyback hit - do blood! // PLace in existing tile and one back... { INT16 sNewGridNo; InternalDropBlood( pSoldier->sGridNo, pSoldier->bLevel, 0, (UINT8)(MAXBLOODQUANTITY), 1 ); // Move forward one gridno.... sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)( DirectionInc( gOppositeDirection[ pSoldier->bDirection ] ) ) ); InternalDropBlood( sNewGridNo, pSoldier->bLevel, 0, (UINT8)(MAXBLOODQUANTITY), 1 ); } break; case 766: // Say COOL quote DoMercBattleSound( pSoldier, BATTLE_SOUND_COOL1 ); break; case 767: // Slap sound effect PlaySoldierJA2Sample( pSoldier->ubID, SLAP_2, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE ); break; case 768: // OK, after ending first aid, stand up if not in combat.... if ( NumCapableEnemyInSector( ) == 0 ) { // Stand up... ChangeSoldierStance( pSoldier, ANIM_STAND ); return( FALSE ); } break; case 769: // ATE: LOOK HERE FOR CODE IN INTERNALS FOR // REFUELING A VEHICLE // THE GAS_CAN IS IN THE MERCS MAIN HAND AT THIS TIME { UINT8 ubPerson; SOLDIERTYPE *pVehicle; // Get pointer to vehicle... ubPerson = WhoIsThere2( pSoldier->sPendingActionData2, pSoldier->bLevel ); pVehicle = MercPtrs[ ubPerson ]; // this is a ubID for soldiertype.... AddFuelToVehicle( pSoldier, pVehicle ); fInterfacePanelDirty = DIRTYLEVEL2; } break; case 770: PlayJA2Sample( USE_WIRE_CUTTERS, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); break; case 771: PlayJA2Sample( BLOODCAT_ATTACK, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); break; case 772: //CODE: FOR A REALTIME NON-INTERRUPTABLE SCRIPT - SIGNAL DONE pSoldier->fRTInNonintAnim = FALSE; break; case 773: // Kneel up... if ( !pSoldier->bStealthMode ) { PlaySoldierJA2Sample( pSoldier->ubID, KNEEL_UP_SOUND, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 774: // Kneel down.. if ( !pSoldier->bStealthMode ) { PlaySoldierJA2Sample( pSoldier->ubID, KNEEL_DOWN_SOUND, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 775: // prone up.. if ( !pSoldier->bStealthMode ) { PlaySoldierJA2Sample( pSoldier->ubID, PRONE_UP_SOUND, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 776: // prone down.. if ( !pSoldier->bStealthMode ) { PlaySoldierJA2Sample( pSoldier->ubID, PRONE_DOWN_SOUND, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 777: // picking something up if ( !pSoldier->bStealthMode ) { PlaySoldierJA2Sample( pSoldier->ubID, PICKING_SOMETHING_UP, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 778: if ( !pSoldier->bStealthMode ) { PlaySoldierJA2Sample( pSoldier->ubID, ENTER_DEEP_WATER_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 779: PlaySoldierJA2Sample( pSoldier->ubID, COW_FALL, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 780: PlaySoldierJA2Sample( pSoldier->ubID, COW_HIT_SND, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 781: PlaySoldierJA2Sample( pSoldier->ubID, ACR_DIE_PART2, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE ); break; case 782: PlaySoldierJA2Sample( pSoldier->ubID, CREATURE_DISSOLVE_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE ); break; case 784: PlaySoldierJA2Sample( pSoldier->ubID, CREATURE_FALL, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE ); break; case 785: if ( Random( 5 ) == 0 ) { PlaySoldierJA2Sample( pSoldier->ubID, CROW_PECKING_AT_FLESH, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } break; case 786: PlaySoldierJA2Sample( pSoldier->ubID, CROW_FLYING_AWAY, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 787: PlaySoldierJA2Sample( pSoldier->ubID, SLAP_1, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), FALSE ); break; case 788: PlaySoldierJA2Sample( pSoldier->ubID, MORTAR_START, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 789: PlaySoldierJA2Sample( pSoldier->ubID, MORTAR_LOAD, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 790: PlaySoldierJA2Sample( pSoldier->ubID, COW_FALL_2, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; case 791: PlaySoldierJA2Sample( pSoldier->ubID, FENCE_OPEN, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); break; } // Adjust frame control pos, and try again pSoldier->usAniCode++; } else if ( sNewAniFrame == 999 ) { // Go to start, by default pSoldier->usAniCode = 0; } // Loop here until we break on a real item! } while ( TRUE ); // We're done return( TRUE ); } #define MIN_DEADLINESS_FOR_LIKE_GUN_QUOTE 20 BOOLEAN ShouldMercSayHappyWithGunQuote( SOLDIERTYPE *pSoldier ) { // How do we do this.... if ( QuoteExp_GotGunOrUsedGun[ pSoldier->ubProfile ] == QUOTE_SATISFACTION_WITH_GUN_AFTER_KILL ) { // For one, only once a day... if ( pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_LIKESGUN ) { return( FALSE ); } // is it a gun? if ( Item[ pSoldier->usAttackingWeapon ].usItemClass & IC_GUN ) { // Is our weapon powerfull enough? if ( Weapon[ pSoldier->usAttackingWeapon ].ubDeadliness > MIN_DEADLINESS_FOR_LIKE_GUN_QUOTE ) { // 20 % chance? if ( Random( 100 ) < 20 ) { return( TRUE ); } } } } return( FALSE ); } void SayBuddyWitnessedQuoteFromKill( SOLDIERTYPE *pKillerSoldier, INT16 sGridNo, INT8 bLevel ) { UINT8 ubMercsInSector[ 20 ] = { 0 }; INT8 bBuddyIndex[ 20 ] = { -1 }; INT8 bTempBuddyIndex; UINT8 ubNumMercs = 0; UINT8 ubChosenMerc; SOLDIERTYPE *pTeamSoldier; INT32 cnt; INT16 sDistVisible = FALSE; UINT16 usQuoteNum; // Loop through all our guys and randomly say one from someone in our sector // set up soldier ptr as first element in mercptrs list cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // run through list for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++ ) { // Add guy if he's a candidate... if ( OK_INSECTOR_MERC( pTeamSoldier ) && !AM_AN_EPC( pTeamSoldier ) && !( pTeamSoldier->uiStatusFlags & SOLDIER_GASSED ) && !(AM_A_ROBOT( pTeamSoldier )) && !pTeamSoldier->fMercAsleep && pTeamSoldier->sGridNo != NOWHERE ) { // Are we a buddy of killer? bTempBuddyIndex = WhichBuddy( pTeamSoldier->ubProfile, pKillerSoldier->ubProfile ); if ( bTempBuddyIndex != -1 ) { switch( bTempBuddyIndex ) { case 0: if ( pTeamSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_BUDDY_1_WITNESSED ) { continue; } break; case 1: if ( pTeamSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_BUDDY_2_WITNESSED ) { continue; } break; case 2: if ( pTeamSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_BUDDY_3_WITNESSED ) { continue; } break; } // TO LOS check to killed // Can we see location of killer? sDistVisible = DistanceVisible( pTeamSoldier, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, pKillerSoldier->sGridNo, pKillerSoldier->bLevel, pKillerSoldier ); if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, pKillerSoldier->sGridNo, pKillerSoldier->bLevel, (UINT8)3, (UINT8) sDistVisible, TRUE ) == 0 ) { continue; } // Can we see location of killed? sDistVisible = DistanceVisible( pTeamSoldier, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel, pTeamSoldier ); if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, bLevel, (UINT8)3, (UINT8) sDistVisible, TRUE ) == 0 ) { continue; } // OK, a good candidate... ubMercsInSector[ ubNumMercs ] = (UINT8)cnt; bBuddyIndex[ ubNumMercs ] = bTempBuddyIndex; ubNumMercs++; } } } // If we are > 0 if ( ubNumMercs > 0 ) { // Do random check here... if ( Random( 100 ) < 20 ) { ubChosenMerc = (UINT8)Random( ubNumMercs ); switch( bBuddyIndex[ ubChosenMerc ] ) { case 0: usQuoteNum = QUOTE_BUDDY_1_GOOD; MercPtrs[ ubMercsInSector[ ubChosenMerc ] ]->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_1_WITNESSED; break; case 1: usQuoteNum = QUOTE_BUDDY_2_GOOD; MercPtrs[ ubMercsInSector[ ubChosenMerc ] ]->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_2_WITNESSED; break; case 2: usQuoteNum = QUOTE_LEARNED_TO_LIKE_WITNESSED; MercPtrs[ ubMercsInSector[ ubChosenMerc ] ]->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_BUDDY_3_WITNESSED; break; } TacticalCharacterDialogue( MercPtrs[ ubMercsInSector[ ubChosenMerc ] ], usQuoteNum ); } } } void HandleKilledQuote( SOLDIERTYPE *pKilledSoldier, SOLDIERTYPE *pKillerSoldier, INT16 sGridNo, INT8 bLevel ) { SOLDIERTYPE *pTeamSoldier; INT32 cnt; UINT8 ubMercsInSector[ 20 ] = { 0 }; UINT8 ubNumMercs = 0; UINT8 ubChosenMerc; BOOLEAN fDoSomeoneElse = FALSE; BOOLEAN fCanWeSeeLocation = FALSE; INT16 sDistVisible = FALSE; gfLastMercTalkedAboutKillingID = pKilledSoldier->ubID; // Can we see location? sDistVisible = DistanceVisible( pKillerSoldier, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel, pKillerSoldier ); fCanWeSeeLocation = ( SoldierTo3DLocationLineOfSightTest( pKillerSoldier, sGridNo, bLevel, (UINT8)3, (UINT8) sDistVisible, TRUE ) != 0 ); // Are we killing mike? if ( pKilledSoldier->ubProfile == 149 && pKillerSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) { // Can we see? if ( fCanWeSeeLocation ) { TacticalCharacterDialogue( pKillerSoldier, QUOTE_AIM_KILLED_MIKE ); } } // Are we killing factory mamager? else if ( pKilledSoldier->ubProfile == 139 ) { // Can we see? //f ( fCanWeSeeLocation ) { TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_FACTORY_MANAGER ); } } else { // Steps here... // If not head shot, just say killed quote // If head shot... // If we have a head shot saying,, randomly try that one // If not doing that one, search for anybody who can see person // If somebody did, play his quote plus attackers killed quote. // Checkf for headhot! if ( pKilledSoldier->usAnimState == JFK_HITDEATH ) { //Randomliy say it! if ( Random( 100 ) < 40 ) { TacticalCharacterDialogue( pKillerSoldier, QUOTE_HEADSHOT ); } else { fDoSomeoneElse = TRUE; } if ( fDoSomeoneElse ) { // Check if a person is here that has this quote.... cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // run through list for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++ ) { if ( cnt != pKillerSoldier->ubID ) { if ( OK_INSECTOR_MERC( pTeamSoldier ) && !( pTeamSoldier->uiStatusFlags & SOLDIER_GASSED ) && !AM_AN_EPC( pTeamSoldier ) ) { // Can we see location? sDistVisible = DistanceVisible( pTeamSoldier, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel, pTeamSoldier ); if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, bLevel, 3, (UINT8) sDistVisible, TRUE ) ) { ubMercsInSector[ ubNumMercs ] = (UINT8)cnt; ubNumMercs++; } } } } // Did we find anybody? if ( ubNumMercs > 0 ) { ubChosenMerc = (UINT8)Random( ubNumMercs ); // We have a random chance of not saying our we killed a guy quote if ( Random( 100 ) < 50 ) { // Say this guys quote but the killer's quote as well.... // if killed was not a plain old civ, say quote if (pKilledSoldier->bTeam != CIV_TEAM || pKilledSoldier->ubCivilianGroup != 0) { TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_AN_ENEMY ); } } TacticalCharacterDialogue( MercPtrs[ ubMercsInSector[ ubChosenMerc ] ], QUOTE_HEADSHOT ); } else { // Can we see? if ( fCanWeSeeLocation ) { // Say this guys quote but the killer's quote as well.... // if killed was not a plain old civ, say quote if (pKilledSoldier->bTeam != CIV_TEAM || pKilledSoldier->ubCivilianGroup != 0) { TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_AN_ENEMY ); } } } } } else { // Can we see? if ( fCanWeSeeLocation ) { // if killed was not a plain old civ, say quote if (pKilledSoldier->bTeam != CIV_TEAM || pKilledSoldier->ubCivilianGroup != 0) { // Are we happy with our gun? if ( ShouldMercSayHappyWithGunQuote( pKillerSoldier ) ) { TacticalCharacterDialogue( pKillerSoldier, QUOTE_SATISFACTION_WITH_GUN_AFTER_KILL ); pKillerSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_LIKESGUN; } else // Randomize between laugh, quote... { if ( Random( 100 ) < 33 && pKilledSoldier->ubBodyType != BLOODCAT ) { // If it's a creature...... if ( pKilledSoldier->uiStatusFlags & SOLDIER_MONSTER ) { TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_A_CREATURE ); } else { TacticalCharacterDialogue( pKillerSoldier, QUOTE_KILLED_AN_ENEMY ); } } else { if ( Random( 50 ) == 25 ) { DoMercBattleSound( pKillerSoldier, (INT8)( BATTLE_SOUND_LAUGH1 ) ); } else { DoMercBattleSound( pKillerSoldier, (INT8)( BATTLE_SOUND_COOL1 ) ); } } } // Buddy witnessed? SayBuddyWitnessedQuoteFromKill( pKillerSoldier, sGridNo, bLevel ); } } } } } BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse ) { BOOLEAN fBuddyJustDead = FALSE; *pfMadeCorpse = FALSE; if ( pSoldier->bLife == 0 && !( pSoldier->uiStatusFlags & SOLDIER_DEAD ) ) { // Cancel services here... ReceivingSoldierCancelServices( pSoldier ); GivingSoldierCancelServices( pSoldier ); if ( pSoldier->iMuzFlash != -1 ) { LightSpriteDestroy( pSoldier->iMuzFlash ); pSoldier->iMuzFlash = -1; } if ( pSoldier->iLight != -1 ) { LightSpriteDestroy( pSoldier->iLight ); } //FREEUP GETTING HIT FLAG pSoldier->fGettingHit = FALSE; // Find next closest team member! if ( pSoldier->bTeam == gbPlayerNum ) { // Set guy to close panel! // ONLY IF VISIBLE ON SCREEN if ( IsMercPortraitVisible( pSoldier->ubID ) ) { fInterfacePanelDirty = DIRTYLEVEL2; } pSoldier->fUIdeadMerc = TRUE; if ( !gfKillingGuysForLosingBattle ) { // ATE: THIS IS S DUPLICATE SETTING OF SOLDIER_DEAD. Is set in StrategicHandlePlayerTeamMercDeath() // also, but here it's needed to tell tectical to ignore this dude... // until StrategicHandlePlayerTeamMercDeath() can get called after death skull interface is done pSoldier->uiStatusFlags |= SOLDIER_DEAD; } } else { UINT8 ubAssister; // IF this guy has an attacker and he's a good guy, play sound if ( pSoldier->ubAttackerID != NOBODY ) { if ( MercPtrs[ pSoldier->ubAttackerID ]->bTeam == gbPlayerNum && gTacticalStatus.ubAttackBusyCount > 0 ) { gTacticalStatus.fKilledEnemyOnAttack = TRUE; gTacticalStatus.ubEnemyKilledOnAttack = pSoldier->ubID; gTacticalStatus.ubEnemyKilledOnAttackLocation = pSoldier->sGridNo; gTacticalStatus.bEnemyKilledOnAttackLevel = pSoldier->bLevel; gTacticalStatus.ubEnemyKilledOnAttackKiller = pSoldier->ubAttackerID; // also check if we are in mapscreen, if so update soldier's list if( guiCurrentScreen == MAP_SCREEN ) { ReBuildCharactersList( ); } } else if ( pSoldier->bVisible == TRUE ) { // We were a visible enemy, say laugh! if ( Random(3) == 0 && !CREATURE_OR_BLOODCAT( MercPtrs[ pSoldier->ubAttackerID ] ) ) { DoMercBattleSound( MercPtrs[ pSoldier->ubAttackerID ], BATTLE_SOUND_LAUGH1 ); } } } // Handle NPC Dead HandleNPCTeamMemberDeath( pSoldier ); // if a friendly with a profile, increment kills // militia also now track kills... if ( pSoldier->ubAttackerID != NOBODY ) { if ( MercPtrs[ pSoldier->ubAttackerID ]->bTeam == gbPlayerNum ) { // increment kills gMercProfiles[ MercPtrs[ pSoldier->ubAttackerID ]->ubProfile ].usKills++; gStrategicStatus.usPlayerKills++; } else if ( MercPtrs[ pSoldier->ubAttackerID ]->bTeam == MILITIA_TEAM ) { // get a kill! 2 points! MercPtrs[ pSoldier->ubAttackerID ]->ubMilitiaKills += 2; } } // JA2 Gold: if previous and current attackers are the same, the next-to-previous attacker gets the assist if (pSoldier->ubPreviousAttackerID == pSoldier->ubAttackerID) { ubAssister = pSoldier->ubNextToPreviousAttackerID; } else { ubAssister = pSoldier->ubPreviousAttackerID; } if ( ubAssister != NOBODY && ubAssister != pSoldier->ubAttackerID ) { if ( MercPtrs[ ubAssister ]->bTeam == gbPlayerNum ) { gMercProfiles[ MercPtrs[ ubAssister ]->ubProfile ].usAssists++; } else if ( MercPtrs[ ubAssister ]->bTeam == MILITIA_TEAM ) { // get an assist - 1 points MercPtrs[ ubAssister ]->ubMilitiaKills += 1; } } /* // handle assist // if killer is assister, don't increment if ( pSoldier->ubPreviousAttackerID != NOBODY && pSoldier->ubPreviousAttackerID != pSoldier->ubAttackerID ) { if ( MercPtrs[ pSoldier->ubPreviousAttackerID ]->bTeam == gbPlayerNum ) { gMercProfiles[ MercPtrs[ pSoldier->ubPreviousAttackerID ]->ubProfile ].usAssists++; } else if ( MercPtrs[ pSoldier->ubPreviousAttackerID ]->bTeam == MILITIA_TEAM ) { // get an assist - 1 points MercPtrs[ pSoldier->ubPreviousAttackerID ]->ubMilitiaKills += 1; } } */ } if ( TurnSoldierIntoCorpse( pSoldier, TRUE, TRUE ) ) { *pfMadeCorpse = TRUE; } // Remove mad as target, one he has died! RemoveManAsTarget( pSoldier ); // Re-evaluate visiblitiy for the team! BetweenTurnsVisibilityAdjustments(); // 0verhaul: This is now handled in the death state transitions // if ( pSoldier->bTeam != gbPlayerNum ) // { // if ( !pSoldier->fDoingExternalDeath ) // { // // Release attacker // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, code 497 = handle soldier death") ); // ReleaseSoldiersAttacker( pSoldier ); // } // } if ( !( *pfMadeCorpse ) ) { fBuddyJustDead = TRUE; } } if ( pSoldier->bLife > 0 ) { // If we are here - something funny has heppende // We either have played a death animation when we are not dead, or we are calling // this ani code in an animation which is not a death animation DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: Death animation called when not dead..." ); } return( fBuddyJustDead ); } void HandlePlayerTeamMemberDeathAfterSkullAnimation( SOLDIERTYPE *pSoldier ) { // 0verhaul: This is now handled in the death state transition. // Release attacker // if ( !pSoldier->fDoingExternalDeath ) // { // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Releasesoldierattacker, code 497 = handle soldier death") ); // ReleaseSoldiersAttacker( pSoldier ); // } HandlePlayerTeamMemberDeath( pSoldier ); // now remove character from a squad RemoveCharacterFromSquads( pSoldier ); } BOOLEAN CheckForAndHandleSoldierDeath( SOLDIERTYPE *pSoldier, BOOLEAN *pfMadeCorpse ) { if ( HandleSoldierDeath( pSoldier, pfMadeCorpse ) ) { // Select approriate death switch( pSoldier->usAnimState ) { case FLYBACK_HIT_DEATH: ChangeSoldierState( pSoldier, FLYBACK_HITDEATH_STOP, 0, FALSE ); break; case GENERIC_HIT_DEATH: ChangeSoldierState( pSoldier, FALLFORWARD_HITDEATH_STOP, 0, FALSE ); break; case FALLBACK_HIT_DEATH: ChangeSoldierState( pSoldier, FALLBACK_HITDEATH_STOP, 0, FALSE ); break; case PRONE_HIT_DEATH: ChangeSoldierState( pSoldier, PRONE_HITDEATH_STOP, 0, FALSE ); break; case JFK_HITDEATH: ChangeSoldierState( pSoldier, JFK_HITDEATH_STOP, 0, FALSE ); break; case FALLOFF_DEATH: ChangeSoldierState( pSoldier, FALLOFF_DEATH_STOP, 0, FALSE ); break; case FALLOFF_FORWARD_DEATH: ChangeSoldierState( pSoldier, FALLOFF_FORWARD_DEATH_STOP, 0, FALSE ); break; case WATER_DIE: ChangeSoldierState( pSoldier, WATER_DIE_STOP, 0, FALSE ); break; case DEEP_WATER_DIE: ChangeSoldierState( pSoldier, DEEP_WATER_DIE_STOPPING, 0, FALSE ); break; case COW_DYING: ChangeSoldierState( pSoldier, COW_DYING_STOP, 0, FALSE); break; case BLOODCAT_DYING: ChangeSoldierState( pSoldier, BLOODCAT_DYING_STOP, 0, FALSE); break; default: // IF we are here - something is wrong - we should have an animation stop here DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: CODE 440 Error, Death STOP not handled" ); } return( TRUE ); } return( FALSE ); } //#define TESTFALLBACK //#define TESTFALLFORWARD void CheckForAndHandleSoldierIncompacitated( SOLDIERTYPE *pSoldier ) { INT16 sNewGridNo; if ( pSoldier->bLife < OKLIFE ) { // Cancel services here... ReceivingSoldierCancelServices( pSoldier ); GivingSoldierCancelServices( pSoldier ); // If we are a monster, set life to zero ( no unconscious ) switch( pSoldier->ubBodyType ) { case ADULTFEMALEMONSTER: case AM_MONSTER: case YAF_MONSTER: case YAM_MONSTER: case LARVAE_MONSTER: case INFANT_MONSTER: case CRIPPLECIV: case ROBOTNOWEAPON: case QUEENMONSTER: case TANK_NW: case TANK_NE: pSoldier->bLife = 0; break; } // OK, if we are in a meanwhile and this is elliot... if ( AreInMeanwhile( ) ) { SOLDIERTYPE *pQueen; pQueen = FindSoldierByProfileID( QUEEN, FALSE ); if ( pQueen ) { TriggerNPCWithGivenApproach( QUEEN, APPROACH_DONE_SLAPPED, FALSE ); } } // We are unconscious now, play randomly, this animation continued, or a new death if ( CheckSoldierHitRoof( pSoldier ) ) { return; } // If guy is now dead, play sound! if ( pSoldier->bLife == 0 ) { if ( !AreInMeanwhile() ) { DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 ); pSoldier->fDeadSoundPlayed = TRUE; } } // Randomly fall back or forward, if we are in the standing hit animation if ( pSoldier->usAnimState == GENERIC_HIT_STAND || pSoldier->usAnimState == STANDING_BURST_HIT || pSoldier->usAnimState == RIFLE_STAND_HIT ) { INT8 bTestDirection = pSoldier->bDirection; BOOLEAN fForceDirection = FALSE; BOOLEAN fDoFallback = FALSE; // Lesh: lets fix dead humans fallback through obstacles // TRY FALLING BACKWARDS, ( ONLY IF WE ARE A MERC! ) #ifdef TESTFALLBACK if ( IS_MERC_BODY_TYPE( pSoldier ) ) #elif defined ( TESTFALLFORWARD ) if ( 0 ) #else if ( Random(100 ) > 40 && IS_MERC_BODY_TYPE( pSoldier ) && !IsProfileATerrorist( pSoldier->ubProfile ) ) #endif { // CHECK IF WE HAVE AN ATTACKER, TAKE OPPOSITE DIRECTION! if ( pSoldier->ubAttackerID != NOBODY ) { // Find direction! bTestDirection = (INT8)GetDirectionFromGridNo( MercPtrs[ pSoldier->ubAttackerID ]->sGridNo, pSoldier ); fForceDirection = TRUE; } sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( gOppositeDirection[ bTestDirection ] ) ); if ( OKFallDirection( pSoldier, sNewGridNo, pSoldier->bLevel, bTestDirection, FLYBACK_HIT ) ) { // CHECKED BEHIND GRIDS - OK fDoFallback = TRUE; } else { fDoFallback = FALSE; } } else { fDoFallback = FALSE; } if ( !fDoFallback ) { // 1 ) REC DIRECTION // 2 ) SET FLAG FOR STARTING TO FALL BeginTyingToFall( pSoldier ); ChangeSoldierState( pSoldier, FALLFORWARD_FROMHIT_STAND, 0, FALSE ); return; } else { // ALL'S OK HERE..... IF WE FORCED DIRECTION, SET! if ( fForceDirection ) { EVENT_SetSoldierDesiredDirection( pSoldier, bTestDirection ); EVENT_SetSoldierDirection( pSoldier, bTestDirection ); } ChangeToFallbackAnimation( pSoldier, pSoldier->bDirection ); return; } } else if ( pSoldier->usAnimState == GENERIC_HIT_CROUCH ) { ChangeSoldierState( pSoldier, FALLFORWARD_FROMHIT_CROUCH, 0 , FALSE); BeginTyingToFall( pSoldier ); return; } else if ( pSoldier->usAnimState == GENERIC_HIT_PRONE ) { ChangeSoldierState( pSoldier, PRONE_LAY_FROMHIT, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == ADULTMONSTER_HIT ) { ChangeSoldierState( pSoldier, ADULTMONSTER_DYING, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == LARVAE_HIT ) { ChangeSoldierState( pSoldier, LARVAE_DIE, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == QUEEN_HIT ) { ChangeSoldierState( pSoldier, QUEEN_DIE, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == CRIPPLE_HIT ) { ChangeSoldierState( pSoldier, CRIPPLE_DIE, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == ROBOTNW_HIT ) { ChangeSoldierState( pSoldier, ROBOTNW_DIE, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == INFANT_HIT ) { ChangeSoldierState( pSoldier, INFANT_DIE, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == COW_HIT ) { ChangeSoldierState( pSoldier, COW_DYING, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == BLOODCAT_HIT ) { ChangeSoldierState( pSoldier, BLOODCAT_DYING, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == WATER_HIT ) { ChangeSoldierState( pSoldier, WATER_DIE, 0 , FALSE ); return; } else if ( pSoldier->usAnimState == DEEP_WATER_HIT ) { ChangeSoldierState( pSoldier, DEEP_WATER_DIE, 0 , FALSE ); return; } else { // We have missed something here - send debug msg DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Soldier Ani: Genmeric hit not chained" ); } } } BOOLEAN CheckForAndHandleSoldierDyingNotFromHit( SOLDIERTYPE *pSoldier ) { if ( pSoldier->bLife == 0 ) { DoMercBattleSound( pSoldier, BATTLE_SOUND_DIE1 ); pSoldier->fDeadSoundPlayed = TRUE; // 0verhaul: The bBeingAttackedCount is now obsolete. // Increment being attacked count // pSoldier->bBeingAttackedCount++; if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] ) { switch( pSoldier->usAnimState ) { case FLYBACKHIT_STOP: ChangeSoldierState( pSoldier, FLYBACK_HIT_DEATH, 0, FALSE ); break; case FALLFORWARD_FROMHIT_STAND: case FALLFORWARD_FROMHIT_CROUCH: case STAND_FALLFORWARD_STOP: ChangeSoldierState( pSoldier, GENERIC_HIT_DEATH, 0, FALSE ); break; case FALLBACKHIT_STOP: ChangeSoldierState( pSoldier, FALLBACK_HIT_DEATH, 0, FALSE ); break; case PRONE_LAYFROMHIT_STOP: case PRONE_LAY_FROMHIT: ChangeSoldierState( pSoldier, PRONE_HIT_DEATH, 0, FALSE ); break; case FALLOFF_STOP: ChangeSoldierState( pSoldier, FALLOFF_DEATH, 0, FALSE ); break; case FALLOFF_FORWARD_STOP: ChangeSoldierState( pSoldier, FALLOFF_FORWARD_DEATH, 0, FALSE); break; case ADULTMONSTER_HIT: ChangeSoldierState( pSoldier, ADULTMONSTER_DYING, 0 , FALSE ); break; case LARVAE_HIT: ChangeSoldierState( pSoldier, LARVAE_DIE, 0 , FALSE ); break; case QUEEN_HIT: ChangeSoldierState( pSoldier, QUEEN_DIE, 0 , FALSE ); break; case CRIPPLE_HIT: ChangeSoldierState( pSoldier, CRIPPLE_DIE, 0 , FALSE ); break; case ROBOTNW_HIT: ChangeSoldierState( pSoldier, ROBOTNW_DIE, 0 , FALSE ); break; case INFANT_HIT: ChangeSoldierState( pSoldier, INFANT_DIE, 0 , FALSE ); break; case COW_HIT: ChangeSoldierState( pSoldier, COW_DYING, 0 , FALSE ); break; case BLOODCAT_HIT: ChangeSoldierState( pSoldier, BLOODCAT_DYING, 0 , FALSE ); break; default: DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Control: Death state %d has no death hit", pSoldier->usAnimState ) ); { BOOLEAN fMadeCorpse; CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse ); } break; } } else { BOOLEAN fMadeCorpse; CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse ); } return( TRUE ); } return( FALSE ); } BOOLEAN CheckForImproperFireGunEnd( SOLDIERTYPE *pSoldier ) { if ( AM_A_ROBOT( pSoldier ) ) { return( FALSE ); } // Check single hand for jammed status, ( or ammo is out.. ) if ( pSoldier->inv[ HANDPOS ].bGunAmmoStatus < 0 || pSoldier->inv[ HANDPOS ].ubGunShotsLeft == 0 ) { // If we have 2 pistols, donot go back! if ( Item[ pSoldier->inv[ SECONDHANDPOS ].usItem ].usItemClass != IC_GUN ) { // OK, put gun down.... InternalSoldierReadyWeapon( pSoldier, pSoldier->bDirection, TRUE ); return( TRUE ); } } return( FALSE ); } BOOLEAN OKHeightDest( SOLDIERTYPE *pSoldier, INT16 sNewGridNo ) { if ( pSoldier->bLevel == 0 ) { return( TRUE ); } // Check if there is a lower place here.... if ( IsLowerLevel( sNewGridNo ) ) { return( FALSE ); } return( TRUE ); } BOOLEAN HandleUnjamAnimation( SOLDIERTYPE *pSoldier ) { // OK, play intermediate animation here..... save in pending animation data, the current // code we are at! pSoldier->uiPendingActionData1 = pSoldier->usAniCode; pSoldier->sPendingActionData2 = pSoldier->usAnimState; // Check what animatnion we should do..... switch( pSoldier->usAnimState ) { case SHOOT_RIFLE_STAND: case STANDING_BURST: case FIRE_STAND_BURST_SPREAD: // Normal shoot rifle.... play ChangeSoldierState( pSoldier, STANDING_SHOOT_UNJAM, 0 , FALSE ); return( TRUE ); case PRONE_BURST: case SHOOT_RIFLE_PRONE: // Normal shoot rifle.... play ChangeSoldierState( pSoldier, PRONE_SHOOT_UNJAM, 0 , FALSE ); return( TRUE ); case CROUCHED_BURST: case SHOOT_RIFLE_CROUCH: // Normal shoot rifle.... play ChangeSoldierState( pSoldier, CROUCH_SHOOT_UNJAM, 0 , FALSE ); return( TRUE ); case SHOOT_DUAL_STAND: // Normal shoot rifle.... play ChangeSoldierState( pSoldier, STANDING_SHOOT_DWEL_UNJAM, 0 , FALSE ); return( TRUE ); case SHOOT_DUAL_PRONE: // Normal shoot rifle.... play ChangeSoldierState( pSoldier, PRONE_SHOOT_DWEL_UNJAM, 0 , FALSE ); return( TRUE ); case SHOOT_DUAL_CROUCH: // Normal shoot rifle.... play ChangeSoldierState( pSoldier, CROUCH_SHOOT_DWEL_UNJAM, 0 , FALSE ); return( TRUE ); case FIRE_LOW_STAND: case FIRE_BURST_LOW_STAND: // Normal shoot rifle.... play ChangeSoldierState( pSoldier, STANDING_SHOOT_LOW_UNJAM, 0 , FALSE ); return( TRUE ); } return( FALSE ); } #if 0 //OK, if here, if our health is still good, but we took a lot of damage, try to fall down! if ( pSoldier->bLife >= OKLIFE ) { // Randomly fall back or forward, if we are in the standing hit animation if ( pSoldier->usAnimState == GENERIC_HIT_STAND || pSoldier->usAnimState == RIFLE_STAND_HIT ) { INT8 bTestDirection = pSoldier->bDirection; BOOLEAN fForceDirection = FALSE; BOOLEAN fDoFallback = FALSE; // As the damage pretty brutal? // TRY FALLING BACKWARDS, ( ONLY IF WE ARE A MERC! ) if ( Random( 1000 ) > 40 && IS_MERC_BODY_TYPE( pSoldier ) ) { // CHECK IF WE HAVE AN ATTACKER, TAKE OPPOSITE DIRECTION! if ( pSoldier->ubAttackerID != NOBODY ) { // Find direction! bTestDirection = (INT8)GetDirectionFromGridNo( MercPtrs[ pSoldier->ubAttackerID ]->sGridNo, pSoldier ); fForceDirection = TRUE; } sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)(-1 * DirectionInc( bTestDirection ) ) ); if ( NewOKDestination( pSoldier, sNewGridNo, TRUE, pSoldier->bLevel ) && OKHeightDest( pSoldier, sNewGridNo ) ) { // ALL'S OK HERE..... IF WE FORCED DIRECTION, SET! if ( fForceDirection ) { EVENT_SetSoldierDirection( pSoldier, bTestDirection ); EVENT_SetSoldierDesiredDirection( pSoldier, bTestDirection ); } ChangeSoldierState( pSoldier, FALLBACK_HIT_STAND, 0, FALSE ); return; } } } } #endif BOOLEAN OKFallDirection( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bLevel, INT8 bTestDirection, UINT16 usAnimState ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"OKFallDirection"); STRUCTURE_FILE_REF * pStructureFileRef; UINT16 usAnimSurface; // How are the movement costs? if ( gubWorldMovementCosts[ sGridNo ][ bTestDirection ][ bLevel ] > TRAVELCOST_SHORE ) { return( FALSE ); } //NOT ok if in water.... if ( GetTerrainType( sGridNo ) == MED_WATER || GetTerrainType( sGridNo ) == DEEP_WATER || GetTerrainType( sGridNo ) == LOW_WATER ) { return( FALSE ); } // How are we for OK dest? if (!NewOKDestination( pSoldier, sGridNo, TRUE, bLevel ) ) { return( FALSE ); } usAnimSurface = DetermineSoldierAnimationSurface( pSoldier, usAnimState ); pStructureFileRef = GetAnimationStructureRef( pSoldier->ubID, usAnimSurface, usAnimState ); if ( pStructureFileRef ) { UINT16 usStructureID; INT16 sTestGridNo; // must make sure that structure data can be added in the direction of the target usStructureID = pSoldier->ubID; // Okay this is really SCREWY but it's due to the way this function worked before and must // work now. The function is passing in an adjacent gridno but we need to place the structure // data in the tile BEFORE. So we take one step back in the direction opposite to bTestDirection // and use that gridno sTestGridNo = NewGridNo( sGridNo, (UINT16)( DirectionInc( gOppositeDirection[ bTestDirection ] ) ) ); if ( ! OkayToAddStructureToWorld( sTestGridNo, bLevel, &(pStructureFileRef->pDBStructureRef[ gOneCDirection[ bTestDirection ] ]), usStructureID ) ) { // can't go in that dir! return( FALSE ); } } return( TRUE ); } BOOLEAN HandleCheckForDeathCommonCode( SOLDIERTYPE *pSoldier ) { // Do we have a primary pending animation? if ( pSoldier->usPendingAnimation2 != NO_PENDING_ANIMATION ) { ChangeSoldierState( pSoldier, pSoldier->usPendingAnimation2, 0, FALSE ); pSoldier->usPendingAnimation2 = NO_PENDING_ANIMATION; return( TRUE ); } // CHECK IF WE HAVE A PENDING ANIMATION HERE if ( pSoldier->usPendingAnimation != NO_PENDING_ANIMATION ) { ChangeSoldierState( pSoldier, pSoldier->usPendingAnimation, 0, FALSE ); pSoldier->usPendingAnimation = NO_PENDING_ANIMATION; return( TRUE ); } // OTHERWISE, GOTO APPROPRIATE STOPANIMATION! pSoldier->bCollapsed = TRUE; // CC has requested - handle sight here... HandleSight( pSoldier, SIGHT_LOOK ); // ATE: If it is our turn, make them try to getup... if ( gTacticalStatus.ubCurrentTeam == pSoldier->bTeam ) { // Try to getup... BeginSoldierGetup( pSoldier ); // Check this to see if above worked if ( !pSoldier->bCollapsed ) { return( TRUE ); } } switch( pSoldier->usAnimState ) { case FLYBACK_HIT: ChangeSoldierState( pSoldier, FLYBACKHIT_STOP, 0, FALSE ); break; case GENERIC_HIT_DEATHTWITCHNB: case FALLFORWARD_FROMHIT_STAND: case ENDFALLFORWARD_FROMHIT_CROUCH: ChangeSoldierState( pSoldier, STAND_FALLFORWARD_STOP, 0, FALSE ); break; case FALLBACK_HIT_DEATHTWITCHNB: case FALLBACK_HIT_STAND: ChangeSoldierState( pSoldier, FALLBACKHIT_STOP, 0, FALSE ); break; case PRONE_HIT_DEATHTWITCHNB: case PRONE_LAY_FROMHIT: ChangeSoldierState( pSoldier, PRONE_LAYFROMHIT_STOP, 0, FALSE ); break; case FALLOFF: ChangeSoldierState( pSoldier, FALLOFF_STOP, 0, FALSE ); break; case FALLFORWARD_ROOF: ChangeSoldierState( pSoldier, FALLOFF_FORWARD_STOP, 0, FALSE); break; default: // IF we are here - something is wrong - we should have a death animation here DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Ani: unconscious hit sequence needed for animation %d", pSoldier->usAnimState ) ); } // OTHERWISE, GOTO APPROPRIATE STOPANIMATION! pSoldier->bCollapsed = TRUE; // ATE: If it is our turn, make them try to getup... if ( gTacticalStatus.ubCurrentTeam == pSoldier->bTeam ) { // Try to getup... BeginSoldierGetup( pSoldier ); // Check this to see if above worked if ( !pSoldier->bCollapsed ) { return( TRUE ); } } switch( pSoldier->usAnimState ) { case FLYBACK_HIT: ChangeSoldierState( pSoldier, FLYBACKHIT_STOP, 0, FALSE ); break; case GENERIC_HIT_DEATHTWITCHNB: case FALLFORWARD_FROMHIT_STAND: case ENDFALLFORWARD_FROMHIT_CROUCH: ChangeSoldierState( pSoldier, STAND_FALLFORWARD_STOP, 0, FALSE ); break; case FALLBACK_HIT_DEATHTWITCHNB: case FALLBACK_HIT_STAND: ChangeSoldierState( pSoldier, FALLBACKHIT_STOP, 0, FALSE ); break; case PRONE_HIT_DEATHTWITCHNB: case PRONE_LAY_FROMHIT: ChangeSoldierState( pSoldier, PRONE_LAYFROMHIT_STOP, 0, FALSE ); break; case FALLOFF: ChangeSoldierState( pSoldier, FALLOFF_STOP, 0, FALSE ); break; case FALLFORWARD_ROOF: ChangeSoldierState( pSoldier, FALLOFF_FORWARD_STOP, 0, FALSE); break; default: // IF we are here - something is wrong - we should have a death animation here DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Soldier Ani: unconscious hit sequence needed for animation %d", pSoldier->usAnimState ) ); } return( TRUE ); } void KickOutWheelchair( SOLDIERTYPE *pSoldier ) { INT16 sNewGridNo; // Move forward one gridno.... sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, (UINT16)( DirectionInc( pSoldier->bDirection ) ) ); // ATE: Make sure that the gridno is unoccupied! if ( !NewOKDestination( pSoldier, sNewGridNo, TRUE, pSoldier->bLevel ) ) { // We should just stay put - will look kind of funny but nothing I can do! sNewGridNo = pSoldier->sGridNo; } EVENT_StopMerc( pSoldier, sNewGridNo, pSoldier->bDirection ); pSoldier->ubBodyType = REGMALE; if ( pSoldier->ubProfile == SLAY && pSoldier->bTeam == CIV_TEAM && !pSoldier->bNeutral ) { HandleNPCDoAction( pSoldier->ubProfile, NPC_ACTION_THREATENINGLY_RAISE_GUN, 0 ); } else { EVENT_InitNewSoldierAnim( pSoldier, STANDING, 0 , TRUE ); } // If this person has a profile ID, set body type to regmale if ( pSoldier->ubProfile != NO_PROFILE ) { gMercProfiles[ pSoldier->ubProfile ].ubBodyType = REGMALE; } }