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