From 14554090574cd7ec12ead8b8ee528170dc260858 Mon Sep 17 00:00:00 2001 From: Sevenfm Date: Sat, 25 Jan 2020 19:02:53 +0000 Subject: [PATCH] AI: - before deciding anything, stop cowering animation - before deciding anything, stop giving aid animation - before deciding to raise weapon, check if weapon can be raised - simplified scope check - removed duplicate code in Red AI Added missing actions to gzActionStr[]. Fixed OKLIFE checks. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8740 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- Strategic/Assignments.cpp | 6 +- Strategic/Hourly Update.cpp | 2 +- Strategic/Strategic Movement.cpp | 4 +- Tactical/Overhead.cpp | 11 +- TacticalAI/AIMain.cpp | 70 +++++++++-- TacticalAI/AIUtils.cpp | 16 +++ TacticalAI/Attacks.cpp | 2 +- TacticalAI/DecideAction.cpp | 200 +++++++++++++++---------------- TacticalAI/Medical.cpp | 2 +- TacticalAI/ai.h | 2 + 10 files changed, 189 insertions(+), 126 deletions(-) diff --git a/Strategic/Assignments.cpp b/Strategic/Assignments.cpp index e70a80e3..4372aa9e 100644 --- a/Strategic/Assignments.cpp +++ b/Strategic/Assignments.cpp @@ -9282,7 +9282,7 @@ void HandleHealingByNaturalCauses( SOLDIERTYPE *pSoldier ) { continue; // NEXT!!! } - if (pMedic->stats.bLife > OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 + if (pMedic->stats.bLife >= OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && pMedic->ubID != pSoldier->ubID && HAS_SKILL_TRAIT( pMedic, DOCTOR_NT )) { bRegenerationBonus += NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ); @@ -13531,7 +13531,7 @@ void AssignmentMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason ) if (bSlot == NO_SLOT) continue;// no medical kit! - if (pMedic->stats.bLife > OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && ( NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery )) + if (pMedic->stats.bLife >= OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && ( NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery )) { if (pBestMedic != NULL) { @@ -13813,7 +13813,7 @@ void AssignmentMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason ) if (bSlot == NO_SLOT) continue;// no medical kit! - if (pMedic->stats.bLife > OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && ( NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery )) + if (pMedic->stats.bLife >= OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && ( NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery )) { if (pBestMedic != NULL) { diff --git a/Strategic/Hourly Update.cpp b/Strategic/Hourly Update.cpp index f13f12f4..1e2ff7b5 100644 --- a/Strategic/Hourly Update.cpp +++ b/Strategic/Hourly Update.cpp @@ -584,7 +584,7 @@ void HourlyDisabilityUpdate( ) { // don't do this if we are at low health, or in combat, or travelling, or a patient or doctor // only do this if we are rather healed - if ( pSoldier->stats.bLife > OKLIFE && pSoldier->stats.bLifeMax > 0 && (FLOAT)(pSoldier->stats.bLife) / (FLOAT)(pSoldier->stats.bLifeMax) > 0.9f + if ( pSoldier->stats.bLife >= OKLIFE && pSoldier->stats.bLifeMax > 0 && (FLOAT)(pSoldier->stats.bLife) / (FLOAT)(pSoldier->stats.bLifeMax) > 0.9f && !pSoldier->flags.fBetweenSectors && !gTacticalStatus.fEnemyInSector && !IS_PATIENT( pSoldier->bAssignment ) && pSoldier->bAssignment != IN_TRANSIT ) { diff --git a/Strategic/Strategic Movement.cpp b/Strategic/Strategic Movement.cpp index 30af1eec..be25cec0 100644 --- a/Strategic/Strategic Movement.cpp +++ b/Strategic/Strategic Movement.cpp @@ -5441,7 +5441,7 @@ BOOLEAN TestForBloodcatAmbush( GROUP *pGroup ) { if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) ) { - if ( MercPtrs[ i ]->sSectorX == pGroup->ubSectorX && MercPtrs[ i ]->sSectorY == pGroup->ubSectorY && MercPtrs[ i ]->bAssignment != ASSIGNMENT_POW && MercPtrs[ i ]->stats.bLife > OKLIFE ) + if ( MercPtrs[ i ]->sSectorX == pGroup->ubSectorX && MercPtrs[ i ]->sSectorY == pGroup->ubSectorY && MercPtrs[ i ]->bAssignment != ASSIGNMENT_POW && MercPtrs[ i ]->stats.bLife >= OKLIFE ) { if( HAS_SKILL_TRAIT( MercPtrs[ i ], SCOUTING_NT ) && MercPtrs[ i ]->ubProfile != NO_PROFILE ) { @@ -5939,7 +5939,7 @@ BOOLEAN ScoutIsPresentInSquad( INT16 ubSectorNumX, INT16 ubSectorNumY ) { if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) ) { - if ( MercPtrs[ i ]->sSectorX == ubSectorNumX && MercPtrs[ i ]->sSectorY == ubSectorNumY && MercPtrs[ i ]->bAssignment != ASSIGNMENT_POW && MercPtrs[ i ]->stats.bLife > OKLIFE ) + if ( MercPtrs[ i ]->sSectorX == ubSectorNumX && MercPtrs[ i ]->sSectorY == ubSectorNumY && MercPtrs[ i ]->bAssignment != ASSIGNMENT_POW && MercPtrs[ i ]->stats.bLife >= OKLIFE ) { if( HAS_SKILL_TRAIT( MercPtrs[ i ], SCOUTING_NT )) { diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index a2c914dd..15f6a61d 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -339,6 +339,15 @@ CHAR8 gzActionStr[][ 30 ] = "TRAVERSE DOWN", "OFFER SURRENDER", "RAISE GUN", + "STEAL MOVE", + "RELOAD GUN" + "JUMP WINDOW", + "FREE PRISONER", + "USE SKILL", + "DOCTOR", + "DOCTOR SELF", + "SELFDETONATE", + "STOP MEDIC", }; CHAR8 gzDirectionStr[][ 30 ] = @@ -6847,7 +6856,7 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) if ( (pTeamSoldier->usSoldierFlagMask & SOLDIER_POW) && !(pTeamSoldier->flags.uiStatusFlags & SOLDIER_DEAD) ) { // if we arrive here and the guy has lifepoints < OKLIFE, something is very odd... better take him prisoner and remove him anyway - //if ( pTeamSoldier->stats.bLife > OKLIFE && pTeamSoldier->stats.bLife != 0 ) + //if ( pTeamSoldier->stats.bLife >= OKLIFE && pTeamSoldier->stats.bLife != 0 ) { // officers and generals are 'special' prisoners... if ( pTeamSoldier->usSoldierFlagMask & SOLDIER_VIP ) diff --git a/TacticalAI/AIMain.cpp b/TacticalAI/AIMain.cpp index c5aed983..235f4407 100644 --- a/TacticalAI/AIMain.cpp +++ b/TacticalAI/AIMain.cpp @@ -2147,19 +2147,46 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) } break; - case AI_ACTION_STOP_COWERING: - // make sure action data is set right - if ( pSoldier->flags.uiStatusFlags & SOLDIER_COWERING ) - { - pSoldier->aiData.usActionData = ANIM_STAND; - pSoldier->SetSoldierCowerState( FALSE ); - } - else - { - // nothing to do! - ActionDone( pSoldier ); - return( FALSE ); - } + case AI_ACTION_STOP_COWERING: + if (SoldierAI(pSoldier)) + { + // sevenfm: stop cowering for soldiers + if (pSoldier->usAnimState == COWERING) + { + if (gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_STAND) + { + pSoldier->ubDesiredHeight = ANIM_STAND; + pSoldier->EVENT_InitNewSoldierAnim(END_COWER, 0, FALSE); + } + else if (gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_CROUCH) + { + pSoldier->ubDesiredHeight = ANIM_CROUCH; + pSoldier->EVENT_InitNewSoldierAnim(END_COWER_CROUCHED, 0, FALSE); + } + } + else if (pSoldier->usAnimState == COWERING_PRONE) + { + if (gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_PRONE) + { + pSoldier->ubDesiredHeight = ANIM_PRONE; + pSoldier->EVENT_InitNewSoldierAnim(END_COWER_PRONE, 0, FALSE); + } + } + // clear cowering flag + pSoldier->flags.uiStatusFlags &= (~SOLDIER_COWERING); + } + else if (pSoldier->flags.uiStatusFlags & SOLDIER_COWERING) + { + // stop cowering for civilians + pSoldier->aiData.usActionData = ANIM_STAND; + pSoldier->SetSoldierCowerState(FALSE); + } + else + { + // nothing to do! + ActionDone(pSoldier); + return(FALSE); + } break; case AI_ACTION_GIVE_AID: // help injured/dying friend @@ -2348,6 +2375,23 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) } break; + case AI_ACTION_STOP_MEDIC: + if (pSoldier->stats.bLife >= OKLIFE && + pSoldier->bBreath > 0 && + !pSoldier->bCollapsed && + (pSoldier->usAnimState == GIVING_AID || pSoldier->usAnimState == GIVING_AID_PRN)) + { + if (gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_PRONE) + pSoldier->ChangeSoldierState(END_AID_PRN, 0, 0); + else + pSoldier->ChangeSoldierState(END_AID, 0, 0); + } + pSoldier->ubServiceCount = 0; + pSoldier->ubServicePartner = NOBODY; + pSoldier->fDoingSurgery = FALSE; + ActionDone(pSoldier); + break; + case AI_ACTION_SELFDETONATE: { pSoldier->SelfDetonate( ); diff --git a/TacticalAI/AIUtils.cpp b/TacticalAI/AIUtils.cpp index 95e80daa..33b3d7d5 100644 --- a/TacticalAI/AIUtils.cpp +++ b/TacticalAI/AIUtils.cpp @@ -4343,3 +4343,19 @@ BOOLEAN NorthSpot(INT32 sSpot, INT8 bLevel) return FALSE; } + +// use soldier AI - merc bodytype, no robots/tanks/boxers/etc +BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier) +{ + CHECKF(pSoldier); + + if (!IS_MERC_BODY_TYPE(pSoldier) || + pSoldier->aiData.bNeutral || + pSoldier->flags.uiStatusFlags & SOLDIER_BOXER || + ARMED_VEHICLE(pSoldier) || + pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE || + AM_A_ROBOT(pSoldier)) + return FALSE; + + return TRUE; +} \ No newline at end of file diff --git a/TacticalAI/Attacks.cpp b/TacticalAI/Attacks.cpp index 8860a8de..09984be4 100644 --- a/TacticalAI/Attacks.cpp +++ b/TacticalAI/Attacks.cpp @@ -3370,7 +3370,7 @@ BOOLEAN GetBestAoEGridNo(SOLDIERTYPE *pSoldier, INT32* pGridNo, INT16 aRadius, U continue; // dying or captured friends are 'helpless' anyway, we are willing to sacrifice them :-) - if ( uCheckFriends && pSoldier->bSide == pFriend->bSide && pFriend->stats.bLife > OKLIFE && !(pFriend->usSoldierFlagMask & SOLDIER_POW) ) + if ( uCheckFriends && pSoldier->bSide == pFriend->bSide && pFriend->stats.bLife >= OKLIFE && !(pFriend->usSoldierFlagMask & SOLDIER_POW) ) { // active friend, remember where he is so that we DON'T blow him up! // this includes US, since we don't want to blow OURSELVES up either diff --git a/TacticalAI/DecideAction.cpp b/TacticalAI/DecideAction.cpp index 0b4dd692..6637857e 100644 --- a/TacticalAI/DecideAction.cpp +++ b/TacticalAI/DecideAction.cpp @@ -1377,7 +1377,8 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen: Snipers like to raise weapons, sniper = %d",pSoldier->sniper)); if ( pSoldier->aiData.bOrders == SNIPER && pSoldier->sniper == 0 && ( pSoldier->pathing.bLevel == 1 || Random(100) < 40 ) && (pSoldier->bBreath > 30 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 20) ) { - if ( !(WeaponReady(pSoldier)) ) // SANDRO - only call this if we are not in readied position yet + if (!WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) { @@ -1398,10 +1399,10 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) //////////////////////////////////////////////////////////////////////////// // SANDRO - occasionally, allow regular soldiers to scan around too - if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || - (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) + if (IsScoped(&pSoldier->inv[HANDPOS])) { - if (!(WeaponReady(pSoldier))) + if (!WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION) { if ((!gfTurnBasedAI || ((GetAPsToReadyWeapon( pSoldier, PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ) ) ) <= pSoldier->bActionPoints)) && (pSoldier->bBreath > 30 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 20) ) @@ -1809,7 +1810,10 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) sprintf(tempstr,"%s - TURNS TOWARDS NOISE to face direction %d",pSoldier->name,pSoldier->aiData.usActionData); AIPopMessage(tempstr); #endif - if ( pSoldier->aiData.bOrders == SNIPER && (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) + if ( pSoldier->aiData.bOrders == SNIPER && + (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30) && + !WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) { @@ -1818,10 +1822,11 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) } //////////////////////////////////////////////////////////////////////////// // SANDRO - allow regular soldiers to raise scoped weapons to see farther away too - if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || - (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) + if (IsScoped(&pSoldier->inv[HANDPOS])) { - if (!(WeaponReady(pSoldier)) && (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) + if (!WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION && + (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ) ) <= pSoldier->bActionPoints) { @@ -2377,12 +2382,14 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) { //////////////////////////////////////////////////////////////////////////// // SANDRO - raise weapon maybe - if (!(WeaponReady(pSoldier)) && pSoldier->ubDirection == ubNoiseDir && (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) // if we are facing the direction of where the noise came from + if (!WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION && + pSoldier->ubDirection == ubNoiseDir && // if we are facing the direction of where the noise came from + (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) { if (!gfTurnBasedAI || (((GetAPsToReadyWeapon( pSoldier, PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ) ) ) + GetAPsToChangeStance( pSoldier, ANIM_CROUCH )) <= pSoldier->bActionPoints)) { - if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || - (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) + if (IsScoped(&pSoldier->inv[HANDPOS])) { pSoldier->aiData.bNextAction = AI_ACTION_RAISE_GUN; } @@ -2398,12 +2405,14 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) { //////////////////////////////////////////////////////////////////////////// // SANDRO - raise weapon maybe - if (!(WeaponReady(pSoldier)) && pSoldier->ubDirection == ubNoiseDir && (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) // if we are facing the direction of where the noise came from + if (!WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION && + pSoldier->ubDirection == ubNoiseDir && // if we are facing the direction of where the noise came from + (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ) <= pSoldier->bActionPoints) { - if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || - (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) + if (IsScoped(&pSoldier->inv[HANDPOS])) { if ( Random(100) < 35 ) { @@ -2483,6 +2492,28 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) // can this guy move to any of the neighbouring squares ? (sets TRUE/FALSE) ubCanMove = (pSoldier->bActionPoints >= MinPtsToMove(pSoldier)); + // sevenfm: before deciding anything, stop cowering + if (SoldierAI(pSoldier) && + ubCanMove && + pSoldier->stats.bLife >= OKLIFE && + !pSoldier->bCollapsed && + !pSoldier->bBreathCollapsed && + (pSoldier->usAnimState == COWERING || pSoldier->usAnimState == COWERING_PRONE)) + { + return AI_ACTION_STOP_COWERING; + } + + // sevenfm: stop giving aid + if (SoldierAI(pSoldier) && + pSoldier->bActionPoints > 0 && + pSoldier->stats.bLife >= OKLIFE && + !pSoldier->bCollapsed && + !pSoldier->bBreathCollapsed && + (pSoldier->usAnimState == GIVING_AID || pSoldier->usAnimState == GIVING_AID_PRN)) + { + return AI_ACTION_STOP_MEDIC; + } + // if we're an alerted enemy, and there are panic bombs or a trigger around if ( (!PTR_CIVILIAN || pSoldier->ubProfile == WARDEN) && ( ( gTacticalStatus.Team[pSoldier->bTeam].bAwareOfOpposition || (pSoldier->ubID == gTacticalStatus.ubTheChosenOne) || (pSoldier->ubProfile == WARDEN) ) && (gTacticalStatus.fPanicFlags & (PANIC_BOMBS_HERE | PANIC_TRIGGERS_HERE ) ) ) ) @@ -2566,75 +2597,8 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) } } - if ( fCivilian && !( pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV || pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && - gTacticalStatus.bBoxingState == NOT_BOXING) - { - if ( FindAIUsableObjClass( pSoldier, IC_WEAPON ) == ITEM_NOT_FOUND ) - { - // cower in fear!! - if ( pSoldier->flags.uiStatusFlags & SOLDIER_COWERING ) - { - if ( gfTurnBasedAI || gTacticalStatus.fEnemyInSector ) // battle! - { - // in battle! - if ( pSoldier->aiData.bLastAction == AI_ACTION_COWER ) - { - // do nothing - pSoldier->aiData.usActionData = NOWHERE; - return( AI_ACTION_NONE ); - } - else - { - // set up next action to run away - pSoldier->aiData.usNextActionData = FindSpotMaxDistFromOpponents( pSoldier ); - if (!TileIsOutOfBounds(pSoldier->aiData.usNextActionData)) - { - pSoldier->aiData.bNextAction = AI_ACTION_RUN_AWAY; - pSoldier->aiData.usActionData = ANIM_STAND; - return( AI_ACTION_STOP_COWERING ); - } - else - { - return( AI_ACTION_NONE ); - } - } - } - else - { - if ( pSoldier->aiData.bNewSituation == NOT_NEW_SITUATION ) - { - // stop cowering, not in battle, timer expired - // we have to turn off whatever is necessary to stop status red... - pSoldier->aiData.bAlertStatus = STATUS_GREEN; - return( AI_ACTION_STOP_COWERING ); - } - else - { - return( AI_ACTION_NONE ); - } - } - } - else - { - if ( gfTurnBasedAI || gTacticalStatus.fEnemyInSector ) - { - // battle - cower!!! - pSoldier->aiData.usActionData = ANIM_CROUCH; - return( AI_ACTION_COWER ); - } - else // not in battle, cower for a certain length of time - { - pSoldier->aiData.bNextAction = AI_ACTION_WAIT; - pSoldier->aiData.usNextActionData = (UINT16) REALTIME_CIV_AI_DELAY; - pSoldier->aiData.usActionData = ANIM_CROUCH; - return( AI_ACTION_COWER ); - } - } - } - } - - - if ( fCivilian && !( pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV || pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) + //if (fCivilian && !(pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV || pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) && gTacticalStatus.bBoxingState == NOT_BOXING) + if (fCivilian && !(pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV || pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE)) { if ( FindAIUsableObjClass( pSoldier, IC_WEAPON ) == ITEM_NOT_FOUND ) { @@ -2826,7 +2790,6 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if (BestShot.bWeaponIn != NO_SLOT) { OBJECTTYPE * gun = &pSoldier->inv[BestShot.bWeaponIn]; DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("decideactionred: men in sector %d, ubspotters called by %d, nobody %d",gTacticalStatus.Team[pSoldier->bTeam].bMenInSector,gTacticalStatus.ubSpottersCalledForBy,NOBODY )); - //if ( ( ( IsScoped(gun) && GunRange(gun) > pSoldier->GetMaxDistanceVisible(BestShot.sTarget, BestShot.bTargetLevel) ) || pSoldier->aiData.bOrders == SNIPER ) && if ( ( ( IsScoped(gun) && GunRange(gun, pSoldier) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) && // SANDRO - added argument (gTacticalStatus.Team[pSoldier->bTeam].bMenInSector > 1) && (gTacticalStatus.ubSpottersCalledForBy == NOBODY)) @@ -3925,10 +3888,10 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) } // raise weapon if not raised - if( PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ) != INVALID_ANIMATION && - !WeaponReady(pSoldier) && - (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50) && - pSoldier->bActionPoints >= GetAPsToReadyWeapon( pSoldier, PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ) ) ) + if (!WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION && + (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding(pSoldier, TRUE) < 50) && + pSoldier->bActionPoints >= GetAPsToReadyWeapon(pSoldier, PickSoldierReadyAnimation(pSoldier, FALSE, FALSE))) { return AI_ACTION_RAISE_GUN; } @@ -4202,7 +4165,10 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) sprintf(tempstr,"%s - TURNS TOWARDS CLOSEST ENEMY to face direction %d",pSoldier->name,pSoldier->aiData.usActionData); AIPopMessage(tempstr); #endif - if ( pSoldier->aiData.bOrders == SNIPER && !(WeaponReady(pSoldier)) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50) ) + if ( pSoldier->aiData.bOrders == SNIPER && + !WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION && + (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50) ) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) { @@ -4211,10 +4177,11 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) } //////////////////////////////////////////////////////////////////////////// // SANDRO - allow regular soldiers to raise scoped weapons to see rather away too - else if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || - (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) + else if (IsScoped(&pSoldier->inv[HANDPOS])) { - if (!(WeaponReady(pSoldier)) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) + if (!WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION && + (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) { @@ -4232,7 +4199,9 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) } //////////////////////////////////////////////////////////////////////////// // SANDRO - allow regular soldiers to raise scoped weapons to see farther away too - else if ( pSoldier->ubDirection == ubOpponentDir && !(WeaponReady(pSoldier))) + else if ( pSoldier->ubDirection == ubOpponentDir && + !WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION) { if ((!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ) <= pSoldier->bActionPoints) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) { @@ -4240,8 +4209,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) { return AI_ACTION_RAISE_GUN; } - else if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || - (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) + else if (IsScoped(&pSoldier->inv[HANDPOS])) { if ( Random(100) < 40 ) { @@ -4420,10 +4388,11 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) // determine direction from this soldier to the closest opponent ubOpponentDir = atan8(CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo),CenterX(sClosestOpponent),CenterY(sClosestOpponent)); - if (!(WeaponReady(pSoldier)) && pSoldier->ubDirection == ubOpponentDir ) + if (!WeaponReady(pSoldier) && + pSoldier->ubDirection == ubOpponentDir && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION) { - if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || - (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) + if (IsScoped(&pSoldier->inv[HANDPOS])) { if ( Random(100) < 40 ) { @@ -4481,7 +4450,8 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionRed: sniper raising gun...")); if ((!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) { - if (!(WeaponReady(pSoldier))) + if (!WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION) { pSoldier->sniper = 1; return AI_ACTION_RAISE_GUN; @@ -4498,12 +4468,13 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) { //////////////////////////////////////////////////////////////////////////// // SANDRO - raise weapon maybe - if (!(WeaponReady(pSoldier)) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) // if we are facing the direction of where the noise came from + if (!WeaponReady(pSoldier) && + PickSoldierReadyAnimation(pSoldier, FALSE, FALSE) != INVALID_ANIMATION && + (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ) <= pSoldier->bActionPoints) { - if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || - (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) + if (IsScoped(&pSoldier->inv[HANDPOS])) { if ( Random(100) < 35 ) { @@ -4588,6 +4559,28 @@ INT16 ubMinAPCost; ubCanMove = 0; } + // sevenfm: before deciding anything, stop cowering + if (SoldierAI(pSoldier) && + ubCanMove && + pSoldier->stats.bLife >= OKLIFE && + !pSoldier->bCollapsed && + !pSoldier->bBreathCollapsed && + (pSoldier->usAnimState == COWERING || pSoldier->usAnimState == COWERING_PRONE)) + { + return AI_ACTION_STOP_COWERING; + } + + // sevenfm: stop giving aid + if (SoldierAI(pSoldier) && + pSoldier->bActionPoints > 0 && + pSoldier->stats.bLife >= OKLIFE && + !pSoldier->bCollapsed && + !pSoldier->bBreathCollapsed && + (pSoldier->usAnimState == GIVING_AID || pSoldier->usAnimState == GIVING_AID_PRN)) + { + return AI_ACTION_STOP_MEDIC; + } + if ( (pSoldier->bTeam == ENEMY_TEAM || pSoldier->ubProfile == WARDEN) && (gTacticalStatus.fPanicFlags & PANIC_TRIGGERS_HERE) && (gTacticalStatus.ubTheChosenOne == NOBODY) ) { INT8 bPanicTrigger; @@ -8383,7 +8376,7 @@ INT8 ZombieDecideActionBlack(SOLDIERTYPE *pSoldier) BestAttack.iAttackValue = 0; - if (BestStab.ubPossible && ((BestStab.iAttackValue > BestAttack.iAttackValue) || (ubBestAttackAction == AI_ACTION_NONE))) + if (BestStab.ubPossible && ((BestStab.iAttackValue > BestAttack.iAttackValue))) { // zombies are always punching... BestAttack.iAttackValue = BestStab.iAttackValue; @@ -9966,7 +9959,6 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK ) if ( BestShot.bWeaponIn != NO_SLOT ) { OBJECTTYPE * gun = &pSoldier->inv[BestShot.bWeaponIn]; DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "ArmedVehicleDecideActionRed: men in sector %d, ubspotters called by %d, nobody %d", gTacticalStatus.Team[pSoldier->bTeam].bMenInSector, gTacticalStatus.ubSpottersCalledForBy, NOBODY ) ); - //if ( ( ( IsScoped(gun) && GunRange(gun) > pSoldier->GetMaxDistanceVisible(BestShot.sTarget, BestShot.bTargetLevel) ) || pSoldier->aiData.bOrders == SNIPER ) && if ( ((IsScoped( gun ) && GunRange( gun, pSoldier ) > MaxNormalDistanceVisible( )) || pSoldier->aiData.bOrders == SNIPER) && // SANDRO - added argument (gTacticalStatus.Team[pSoldier->bTeam].bMenInSector > 1) && (gTacticalStatus.ubSpottersCalledForBy == NOBODY) ) diff --git a/TacticalAI/Medical.cpp b/TacticalAI/Medical.cpp index 6fd76f2e..216c2f5d 100644 --- a/TacticalAI/Medical.cpp +++ b/TacticalAI/Medical.cpp @@ -508,7 +508,7 @@ BOOLEAN DoctorIsPresent( SOLDIERTYPE * pPatient, BOOLEAN fOnDoctorAssignmentChec continue; // NEXT!!! } - if (pMedic->stats.bLife > OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && (NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery)) + if (pMedic->stats.bLife >= OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && (NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery)) { fDoctorHasBeenFound = TRUE; } diff --git a/TacticalAI/ai.h b/TacticalAI/ai.h index 95dbcf00..2e621913 100644 --- a/TacticalAI/ai.h +++ b/TacticalAI/ai.h @@ -108,6 +108,7 @@ typedef enum AI_ACTION_DOCTOR, // added by Flugente: AI-ONLY! bandage/surgery on fellow AI. DO NOT USE THIS FOR MERCS!!! AI_ACTION_DOCTOR_SELF, // added by Flugente: AI-ONLY! bandage/surgery on self. DO NOT USE THIS FOR MERCS!!! AI_ACTION_SELFDETONATE, // added by Flugente: blow up an explosive in own inventory + AI_ACTION_STOP_MEDIC, // sevenfm: stop giving aid animation } ActionType; @@ -301,6 +302,7 @@ BOOLEAN AnyCoverFromSpot( INT32 sSpot, INT8 bLevel, INT32 sThreatLoc, INT8 bThre UINT8 CountSeenEnemiesLastTurn( SOLDIERTYPE *pSoldier ); BOOLEAN NorthSpot(INT32 sSpot, INT8 bLevel); +BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier); #define MAX_FLANKS_RED 25 #define MAX_FLANKS_YELLOW 25