Enemy roles improvement:

- lowered ENEMYROLES_TURNSTOUNCOVER
- increased ENEMY_MEDICS_SEARCHRADIUS
- new option: ENEMY_MEDICS_WOUND_MINAMOUNT controls how serious a wound must be before a medic considers it worthy of attention
- new option: ENEMY_MEDICS_HEAL_SELF: medics can heal themselves
- new option: ENEMY_OFFICERS_SURRENDERSTRENGTHBONUS adds a team surrender strength bonus for officers
- tanks cannot become medics, and can't be treated by them either
- Menubutton for Role symbol toggle is red if off and green if on
- wounded soldiers seek medics, max range is ENEMY_MEDICS_SEARCHRADIUS / 2
- direct sight line between medic and target is no longer required

- if hostile civilians allied to the army are in sector, their surrender strength is added to the enemy team

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7080 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2014-03-17 21:27:19 +00:00
parent b1ebd3ea6a
commit e1b581e466
10 changed files with 285 additions and 63 deletions
+5 -2
View File
@@ -1478,15 +1478,18 @@ void LoadGameExternalOptions()
//################# Tactical Enemy Role Settings ##################
// Flugente: enemy roles
gGameExternalOptions.fEnemyRoles = iniReader.ReadBoolean("Tactical Enemy Role Settings", "ENEMYROLES", TRUE);
gGameExternalOptions.usTurnsToUncover = iniReader.ReadInteger("Tactical Enemy Role Settings", "ENEMYROLES_TURNSTOUNCOVER", 6, 0, 20);
gGameExternalOptions.usTurnsToUncover = iniReader.ReadInteger("Tactical Enemy Role Settings", "ENEMYROLES_TURNSTOUNCOVER", 4, 0, 20);
gGameExternalOptions.fEnemyMedics = iniReader.ReadBoolean("Tactical Enemy Role Settings", "ENEMY_MEDICS", TRUE);
gGameExternalOptions.dEnemyMedicMedKitDrainFactor = iniReader.ReadFloat ("Tactical Enemy Role Settings", "ENEMY_MEDICS_MEDKITDRAINFACTOR", 0.1f, 0.01f, 1.0f);
gGameExternalOptions.sEnemyMedicsSearchRadius = iniReader.ReadInteger("Tactical Enemy Role Settings", "ENEMY_MEDICS_SEARCHRADIUS", 20, 5, 60);
gGameExternalOptions.sEnemyMedicsSearchRadius = iniReader.ReadInteger("Tactical Enemy Role Settings", "ENEMY_MEDICS_SEARCHRADIUS", 40, 5, 60);
gGameExternalOptions.sEnemyMedicsWoundMinAmount = iniReader.ReadInteger("Tactical Enemy Role Settings", "ENEMY_MEDICS_WOUND_MINAMOUNT", 5000, 0, 50000);
gGameExternalOptions.fEnemyMedicsHealSelf = iniReader.ReadBoolean("Tactical Enemy Role Settings", "ENEMY_MEDICS_HEAL_SELF", TRUE);
gGameExternalOptions.fEnemyOfficers = iniReader.ReadBoolean("Tactical Enemy Role Settings", "ENEMY_OFFICERS", TRUE);
gGameExternalOptions.usEnemyOfficersPerTeamSize = iniReader.ReadInteger("Tactical Enemy Role Settings", "ENEMY_OFFICERS_REQUIREDTEAMSIZE", 10, 1, 64);
gGameExternalOptions.usEnemyOfficersMax = iniReader.ReadInteger("Tactical Enemy Role Settings", "ENEMY_OFFICERS_MAX", 4, 1, 10);
gGameExternalOptions.sEnemyOfficerSuppressionResistanceBonus = iniReader.ReadInteger("Tactical Enemy Role Settings", "ENEMY_OFFICERS_SUPPRESSION_RESISTANCE_BONUS", 10, 0, 50);
gGameExternalOptions.dEnemyOfficerMoraleModifier = iniReader.ReadFloat ("Tactical Enemy Role Settings", "ENEMY_OFFICERS_MORALE_MODIFIER", 0.1f, 0.00f, 1.0f);
gGameExternalOptions.dEnemyOfficerSurrenderStrengthBonus = iniReader.ReadFloat ("Tactical Enemy Role Settings", "ENEMY_OFFICERS_SURRENDERSTRENGTHBONUS", 0.1f, 0.00f, 1.0f);
//################# Tactical Cover System Settings ##################
+3
View File
@@ -1351,11 +1351,14 @@ typedef struct
BOOLEAN fEnemyMedics;
FLOAT dEnemyMedicMedKitDrainFactor;
INT16 sEnemyMedicsSearchRadius;
INT32 sEnemyMedicsWoundMinAmount;
BOOLEAN fEnemyMedicsHealSelf;
BOOLEAN fEnemyOfficers;
UINT16 usEnemyOfficersPerTeamSize;
UINT16 usEnemyOfficersMax;
INT8 sEnemyOfficerSuppressionResistanceBonus;
FLOAT dEnemyOfficerMoraleModifier;
FLOAT dEnemyOfficerSurrenderStrengthBonus;
// Sandro: Alternative weapon holding (rifles fired from hip / pistols fired one-handed)
+20
View File
@@ -10265,6 +10265,26 @@ void PrisonerSurrenderMessageBoxCallBack( UINT8 ubExitValue )
}
}
// hostile civs
firstid = gTacticalStatus.Team[ CIV_TEAM ].bFirstID;
lastid = gTacticalStatus.Team[ CIV_TEAM ].bLastID;
for ( uiCnt = firstid, pSoldier = MercPtrs[ uiCnt ]; uiCnt <= lastid; ++uiCnt, ++pSoldier)
{
if( pSoldier->bActive && ( pSoldier->sSectorX == gWorldSectorX ) && ( pSoldier->sSectorY == gWorldSectorY ) && ( pSoldier->bSectorZ == gbWorldSectorZ) )
{
// if a civilian is not neutral and on the enemy side, add his strength to the team
if ( !pSoldier->aiData.bNeutral && pSoldier->bSide == 1 )
enemysidestrength += pSoldier->GetSurrenderStrength();
}
}
// enemy team gets a bonus if it has officers around
BOOL officertype = OFFICER_NONE;
if ( HighestEnemyOfficersInSector( officertype ) )
{
enemysidestrength = enemysidestrength * (1.0f + gGameExternalOptions.dEnemyOfficerSurrenderStrengthBonus * officertype);
}
// print out values
if ( gGameExternalOptions.fDisplaySurrenderSValues )
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_SURRENDER_VALUES], playersidestrength, gGameExternalOptions.fSurrenderMultiplier * enemysidestrength );
+81 -52
View File
@@ -12642,9 +12642,9 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1
}
// if we are going to do the surgery
// Flugente: AI medics are allowed to perform surgery without first aid kits
if (pVictim->iHealableInjury > 0 && this->fDoingSurgery && this->ubID != pVictim->ubID && gGameOptions.fNewTraitSystem
&& (NUM_SKILL_TRAITS( this, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery)
// Flugente: AI medics are allowed to perform surgery without first aid kits, and can do this on themselves
if (pVictim->iHealableInjury > 0 && this->fDoingSurgery && (this->ubID != pVictim->ubID || (gGameExternalOptions.fEnemyMedicsHealSelf && this->bTeam == ENEMY_TEAM) )
&& gGameOptions.fNewTraitSystem && (NUM_SKILL_TRAITS( this, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery)
&& (Item[this->inv[ HANDPOS ].usItem].medicalkit || this->bTeam == ENEMY_TEAM) )
{
fOnSurgery = TRUE;
@@ -16308,22 +16308,19 @@ void SOLDIERTYPE::DropSectorEquipment()
// sevenfm: take item from inventory to HANDPOS
void SOLDIERTYPE::TakeNewItemFromInventory(UINT16 usItem)
{
INT8 i;
OBJECTTYPE* pObj = NULL;
INT8 invsize = (INT8)this->inv.size();
if ( !UsingNewInventorySystem() )
return;
// this feature works now only in realtime
if( (gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) )
return;
// this feature works now only in realtime
if( (gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) )
return;
if(this->inv[HANDPOS].exists())
return;
// search for item with same id
for ( i = 0; i < invsize; i++)
INT8 invsize = (INT8)this->inv.size();
for ( INT8 i = 0; i < invsize; ++i)
{
if ( ( this->inv[i].exists() == true ) && ( this->inv[i].usItem == usItem ) )
{
@@ -16336,25 +16333,24 @@ void SOLDIERTYPE::TakeNewItemFromInventory(UINT16 usItem)
// sevenfm: take item from inventory to HANDPOS
void SOLDIERTYPE::TakeNewBombFromInventory(UINT16 usItem)
{
INT8 i;
OBJECTTYPE* pObj = NULL;
INT8 invsize = (INT8)this->inv.size();
if ( !UsingNewInventorySystem() )
return;
INT8 i;
if ( !UsingNewInventorySystem() )
return;
if(this->inv[HANDPOS].exists())
return;
if(this->inv[HANDPOS].exists())
return;
// search for item with same id
for ( i = 0; i < invsize; i++)
// search for item with same id
INT8 invsize = (INT8)this->inv.size();
for ( i = 0; i < invsize; ++i)
{
if ( ( this->inv[i].exists() == true ) && ( this->inv[i].usItem == usItem ) )
{
if ( ( this->inv[i].exists() == true ) && ( this->inv[i].usItem == usItem ) )
{
this->inv[i].MoveThisObjectTo(this->inv[HANDPOS], 1, this);
return;
}
this->inv[i].MoveThisObjectTo(this->inv[HANDPOS], 1, this);
return;
}
}
// search for any item with class IC_BOMB
// take tripwire-activated item only if used item is tripwire activated
@@ -16988,16 +16984,7 @@ INT8 SOLDIERTYPE::GetSuppressionResistanceBonus()
BOOL officertype = OFFICER_NONE;
if ( HighestEnemyOfficersInSector( officertype ) )
{
switch ( officertype )
{
case OFFICER_LIEUTNANT:
bonus += gGameExternalOptions.sEnemyOfficerSuppressionResistanceBonus;
break;
case OFFICER_CAPTAIN:
bonus += gGameExternalOptions.sEnemyOfficerSuppressionResistanceBonus * 2;
break;
}
bonus += gGameExternalOptions.sEnemyOfficerSuppressionResistanceBonus * officertype;
}
}
@@ -17098,16 +17085,7 @@ FLOAT SOLDIERTYPE::GetMoraleModifier()
BOOL officertype = OFFICER_NONE;
if ( HighestEnemyOfficersInSector( officertype ) )
{
switch ( officertype )
{
case OFFICER_LIEUTNANT:
mod += gGameExternalOptions.dEnemyOfficerMoraleModifier;
break;
case OFFICER_CAPTAIN:
mod += gGameExternalOptions.dEnemyOfficerMoraleModifier * 2;
break;
}
mod += gGameExternalOptions.dEnemyOfficerMoraleModifier * officertype;
}
return mod;
@@ -18298,6 +18276,10 @@ BOOLEAN SOLDIERTYPE::CanMedicAI()
if ( !gGameExternalOptions.fEnemyRoles || !gGameExternalOptions.fEnemyMedics || this->bTeam != ENEMY_TEAM )
return FALSE;
// this is not for tanks
if ( TANK(this) )
return FALSE;
if ( HAS_SKILL_TRAIT( this, DOCTOR_NT) )
{
if ( FindFirstAidKit(this) != NO_SLOT || FindMedKit(this) != NO_SLOT )
@@ -18326,8 +18308,12 @@ BOOLEAN SOLDIERTYPE::AIDoctorFriend()
if ( pSoldier->bTeam != ENEMY_TEAM )
return FALSE;
// if this guy is wounded should always be the case, otherwise this function was calleed needlessly
if ( pSoldier->stats.bLife < pSoldier->stats.bLifeMax )
// this is not for tanks
if ( TANK(pSoldier) )
return FALSE;
// if this guy is wounded, heal him (should always be the case, otherwise this function was called needlessly)
if ( pSoldier->iHealableInjury > 0 )
{
// move medkit into hand - if we don't have a medkit in our hands, abort
if ( !MakeSureMedKitIsInHand( this ) )
@@ -18365,6 +18351,49 @@ BOOLEAN SOLDIERTYPE::AIDoctorFriend()
return FALSE;
}
// AI-only: heal self. Do NOT, repeat, NOT use this with mercs!
BOOLEAN SOLDIERTYPE::AIDoctorSelf()
{
if ( this->bTeam != ENEMY_TEAM )
return FALSE;
// if this guy is wounded, heal him (should always be the case, otherwise this function was called needlessly)
if ( this->iHealableInjury > 0 )
{
// move medkit into hand - if we don't have a medkit in our hands, abort
if ( !MakeSureMedKitIsInHand( this ) )
return FALSE;
if( gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_CROUCH )
{
this->EVENT_InitNewSoldierAnim( START_AID, 0 , FALSE );
}
// AI medics always perform surgery
this->fDoingSurgery = TRUE;
UINT16 usKitPts = TotalPoints( &(this->inv[ HANDPOS ] ) );
// note the current hp
INT8 oldlife = this->stats.bLife;
UINT16 uiPointsUsed = this->SoldierDressWound( this, usKitPts, usKitPts );
UseKitPoints( &(this->inv[ HANDPOS ] ), (UINT16)(uiPointsUsed * gGameExternalOptions.dEnemyMedicMedKitDrainFactor), this );
// healing done will be displayed the next time the player sees this soldier
this->flags.fDisplayDamage = TRUE;
this->sDamage -= this->stats.bLife - oldlife;
// alert ourself
this->aiData.bAlertStatus = min(this->aiData.bAlertStatus, STATUS_RED);
return TRUE;
}
return FALSE;
}
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
{
@@ -20934,7 +20963,7 @@ UINT8 RegainDamagedStats( SOLDIERTYPE * pSoldier, UINT16 usAmountRegainedHundred
return( 0 );
// Second, run through all damagable stats
for (cnt = 0; cnt < NUM_DAMAGABLE_STATS; cnt++)
for (cnt = 0; cnt < NUM_DAMAGABLE_STATS; ++cnt)
{
// if we have a damaged stat here
if (pSoldier->ubCriticalStatDamage[cnt] > 0 )
@@ -21020,7 +21049,7 @@ UINT8 RegainDamagedStats( SOLDIERTYPE * pSoldier, UINT16 usAmountRegainedHundred
break;
}
// Throw a message if healed anything
if ( gSkillTraitValues.fDORepStShouldThrowMessage )
if ( gSkillTraitValues.fDORepStShouldThrowMessage && pSoldier->bTeam != ENEMY_TEAM )
{
if ( usStatIncreasement == 1 )
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_REGAINED_ONE_POINTS_OF_STAT], pSoldier->GetName(), sStat );
@@ -21076,7 +21105,7 @@ UINT8 RegainDamagedStats( SOLDIERTYPE * pSoldier, UINT16 usAmountRegainedHundred
gMercProfiles[ pSoldier->ubProfile ].bLifeMax = pSoldier->stats.bLifeMax; // update profile
// Throw a message if healed anything
if ( gSkillTraitValues.fDORepStShouldThrowMessage )
if ( gSkillTraitValues.fDORepStShouldThrowMessage && pSoldier->bTeam != ENEMY_TEAM )
{
if ( usStatIncreasement == 1 )
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_REGAINED_ONE_POINTS_OF_STAT], pSoldier->GetName(), sStat );
@@ -21119,7 +21148,7 @@ UINT8 RegainDamagedStats( SOLDIERTYPE * pSoldier, UINT16 usAmountRegainedHundred
gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->stats.bStrength; // update profile
// Throw a message if healed anything
if ( gSkillTraitValues.fDORepStShouldThrowMessage )
if ( gSkillTraitValues.fDORepStShouldThrowMessage && pSoldier->bTeam != ENEMY_TEAM )
{
if ( usStatIncreasement == 1 )
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_REGAINED_ONE_POINTS_OF_STAT], pSoldier->GetName(), sStat );
+1
View File
@@ -1828,6 +1828,7 @@ public:
BOOLEAN HasSniper();
BOOLEAN CanMedicAI(); // AI-only: can we heal a wounded ally? Do NOT, repeat, NOT use this with mercs!
BOOLEAN AIDoctorFriend(); // AI-only: heal a wounded friend. Do NOT, repeat, NOT use this with mercs!
BOOLEAN AIDoctorSelf(); // AI-only: heal self. Do NOT, repeat, NOT use this with mercs!
//////////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -7824,7 +7824,7 @@ void HandleTacticalCoverMenu( void )
gzUserDefinedButtonColor[0] = 0;
gzUserDefinedButtonColor[1] = FONT_MCOLOR_LTYELLOW;
gzUserDefinedButtonColor[2] = FONT_MCOLOR_LTYELLOW;
gzUserDefinedButtonColor[4] = FONT_LTRED;
gzUserDefinedButtonColor[4] = gDisplayEnemyRoles ? FONT_MCOLOR_LTGREEN : FONT_LTRED;
gzUserDefinedButtonColor[8] = FONT_ORANGE;
gzUserDefinedButtonColor[9] = FONT_ORANGE;
gzUserDefinedButtonColor[10] = FONT_ORANGE;
+7
View File
@@ -2312,6 +2312,13 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier)
}
break;
case AI_ACTION_DOCTOR_SELF:
{
pSoldier->AIDoctorSelf();
ActionDone( pSoldier );
}
break;
default:
#ifdef BETAVERSION
NumMessage("ExecuteAction - Illegal action type = ",pSoldier->aiData.bAction);
+67 -5
View File
@@ -595,6 +595,7 @@ BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier)
break;
case AI_ACTION_DOCTOR:
case AI_ACTION_DOCTOR_SELF:
bMinPointsNeeded = 20; // TODO
break;
@@ -3089,6 +3090,10 @@ UINT8 GetClosestFlaggedSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 au
// must be on the same level
if ( pFriend->pathing.bLevel != pSoldier->pathing.bLevel )
continue;
// this is not for tanks
if ( TANK(pFriend) )
return FALSE;
// skip if this guy is dead
if ( pFriend->stats.bLife <= 0 )
@@ -3131,16 +3136,20 @@ UINT8 GetClosestWoundedSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 au
if (!pFriend)
continue;
// skip ourselves
if (pFriend->ubID == pSoldier->ubID)
// skip ourselves (if not allowed)
if ( !gGameExternalOptions.fEnemyMedicsHealSelf && pFriend->ubID == pSoldier->ubID)
continue;
// must be on the same level
if ( pFriend->pathing.bLevel != pSoldier->pathing.bLevel )
continue;
// this is not for tanks
if ( TANK(pFriend) )
return FALSE;
// skip if this guy is dead, not wounded or cannot be healed
if ( pFriend->stats.bLife <= 0 || pFriend->iHealableInjury <= 0 || pFriend->stats.bLife >= pFriend->stats.bLifeMax )
// skip if this guy is dead, or not wounded (enough)
if ( pFriend->stats.bLife <= 0 || pFriend->iHealableInjury < gGameExternalOptions.sEnemyMedicsWoundMinAmount )
continue;
// are we close enough?
@@ -3148,7 +3157,60 @@ UINT8 GetClosestWoundedSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 au
if ( friendrange < range)
{
// can we see this guy?
if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pFriend->sGridNo, pSoldier->pathing.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
//if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pFriend->sGridNo, pSoldier->pathing.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
{
range = friendrange;
id = pFriend->ubID;
}
}
}
return id;
}
// get the id of the closest medic (closer than x tiles) of a specific team
UINT8 GetClosestMedicSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 auTeam )
{
UINT8 id = NOBODY;
UINT32 uiLoop;
SOLDIERTYPE * pFriend;
INT16 range = aRange;
// go through each soldier, looking for "friends" (soldiers on same team)
for (uiLoop = gTacticalStatus.Team[ auTeam ].bFirstID; uiLoop < gTacticalStatus.Team[ auTeam ].bLastID; ++uiLoop)
{
pFriend = MercPtrs[ uiLoop ];
// if this merc is inactive, not in sector, or dead
if (!pFriend)
continue;
// skip ourselves (we seek OTHER people)
if ( pFriend->ubID == pSoldier->ubID)
continue;
// must be on the same level
if ( pFriend->pathing.bLevel != pSoldier->pathing.bLevel )
continue;
// this is not for tanks
if ( TANK(pFriend) )
return FALSE;
// skip this guy if he is dead or unconscious
if ( pFriend->stats.bLife < OKLIFE )
continue;
// skip if this guy if he is no medic
if ( !pFriend->CanMedicAI() )
continue;
// are we close enough?
INT16 friendrange = SpacesAway(pSoldier->sGridNo, pFriend->sGridNo);
if ( friendrange < range)
{
// can we see this guy?
//if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pFriend->sGridNo, pSoldier->pathing.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
{
range = friendrange;
id = pFriend->ubID;
+96 -3
View File
@@ -936,7 +936,20 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
{
UINT8 ubPerson = GetClosestWoundedSoldierID( pSoldier, gGameExternalOptions.sEnemyMedicsSearchRadius, pSoldier->bTeam);
if ( ubPerson != NOBODY )
// are we ourselves the patient?
if ( ubPerson == pSoldier->ubID )
{
// if not already crouched, crouch down first
if ( gAnimControl[ pSoldier->usAnimState ].ubHeight != ANIM_CROUCH && IsValidStance( pSoldier, ANIM_CROUCH ) && GetAPsToChangeStance( pSoldier, ANIM_CROUCH ) <= pSoldier->bActionPoints )
{
pSoldier->aiData.usActionData = ANIM_CROUCH;
return(AI_ACTION_CHANGE_STANCE);
}
return(AI_ACTION_DOCTOR_SELF);
}
else if ( ubPerson != NOBODY )
{
if ( PythSpacesAway(pSoldier->sGridNo, MercPtrs[ubPerson]->sGridNo) < 2 )
{
@@ -965,6 +978,24 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
{
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, MercPtrs[ubPerson]->sGridNo, 20, AI_ACTION_SEEK_FRIEND, 0);
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
{
return(AI_ACTION_SEEK_FRIEND);
}
}
}
}
// if we are not a medic, but are wounded, seek a medic
else if ( pSoldier->iHealableInjury >= gGameExternalOptions.sEnemyMedicsWoundMinAmount )
{
UINT8 ubPerson = GetClosestMedicSoldierID( pSoldier, gGameExternalOptions.sEnemyMedicsSearchRadius / 2, pSoldier->bTeam);
if ( ubPerson != NOBODY )
{
if ( PythSpacesAway(pSoldier->sGridNo, MercPtrs[ubPerson]->sGridNo) > 1 )
{
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, MercPtrs[ubPerson]->sGridNo, 20, AI_ACTION_SEEK_FRIEND, 0);
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
{
return(AI_ACTION_SEEK_FRIEND);
@@ -1619,7 +1650,20 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
{
UINT8 ubPerson = GetClosestWoundedSoldierID( pSoldier, gGameExternalOptions.sEnemyMedicsSearchRadius, pSoldier->bTeam);
if ( ubPerson != NOBODY )
// are we ourselves the patient?
if ( ubPerson == pSoldier->ubID )
{
// if not already crouched, crouch down first
if ( gAnimControl[ pSoldier->usAnimState ].ubHeight != ANIM_CROUCH && IsValidStance( pSoldier, ANIM_CROUCH ) && GetAPsToChangeStance( pSoldier, ANIM_CROUCH ) <= pSoldier->bActionPoints )
{
pSoldier->aiData.usActionData = ANIM_CROUCH;
return(AI_ACTION_CHANGE_STANCE);
}
return(AI_ACTION_DOCTOR_SELF);
}
else if ( ubPerson != NOBODY )
{
if ( PythSpacesAway(pSoldier->sGridNo, MercPtrs[ubPerson]->sGridNo) < 2 )
{
@@ -1648,6 +1692,24 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
{
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, MercPtrs[ubPerson]->sGridNo, 20, AI_ACTION_SEEK_FRIEND, 0);
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
{
return(AI_ACTION_SEEK_FRIEND);
}
}
}
}
// if we are not a medic, but are wounded, seek a medic
else if ( pSoldier->iHealableInjury >= gGameExternalOptions.sEnemyMedicsWoundMinAmount )
{
UINT8 ubPerson = GetClosestMedicSoldierID( pSoldier, gGameExternalOptions.sEnemyMedicsSearchRadius / 2, pSoldier->bTeam);
if ( ubPerson != NOBODY )
{
if ( PythSpacesAway(pSoldier->sGridNo, MercPtrs[ubPerson]->sGridNo) > 1 )
{
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, MercPtrs[ubPerson]->sGridNo, 20, AI_ACTION_SEEK_FRIEND, 0);
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
{
return(AI_ACTION_SEEK_FRIEND);
@@ -2943,7 +3005,20 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
{
UINT8 ubPerson = GetClosestWoundedSoldierID( pSoldier, gGameExternalOptions.sEnemyMedicsSearchRadius, pSoldier->bTeam);
if ( ubPerson != NOBODY )
// are we ourselves the patient?
if ( ubPerson == pSoldier->ubID )
{
// if not already crouched, crouch down first
if ( gAnimControl[ pSoldier->usAnimState ].ubHeight != ANIM_CROUCH && IsValidStance( pSoldier, ANIM_CROUCH ) && GetAPsToChangeStance( pSoldier, ANIM_CROUCH ) <= pSoldier->bActionPoints )
{
pSoldier->aiData.usActionData = ANIM_CROUCH;
return(AI_ACTION_CHANGE_STANCE);
}
return(AI_ACTION_DOCTOR_SELF);
}
else if ( ubPerson != NOBODY )
{
if ( PythSpacesAway(pSoldier->sGridNo, MercPtrs[ubPerson]->sGridNo) < 2 )
{
@@ -2972,6 +3047,24 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
{
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, MercPtrs[ubPerson]->sGridNo, 20, AI_ACTION_SEEK_FRIEND, 0);
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
{
return(AI_ACTION_SEEK_FRIEND);
}
}
}
}
// if we are not a medic, but are wounded, seek a medic
else if ( pSoldier->iHealableInjury >= gGameExternalOptions.sEnemyMedicsWoundMinAmount )
{
UINT8 ubPerson = GetClosestMedicSoldierID( pSoldier, gGameExternalOptions.sEnemyMedicsSearchRadius / 2, pSoldier->bTeam);
if ( ubPerson != NOBODY )
{
if ( PythSpacesAway(pSoldier->sGridNo, MercPtrs[ubPerson]->sGridNo) > 1 )
{
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, MercPtrs[ubPerson]->sGridNo, 20, AI_ACTION_SEEK_FRIEND, 0);
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
{
return(AI_ACTION_SEEK_FRIEND);
+4
View File
@@ -105,6 +105,7 @@ typedef enum
AI_ACTION_FREE_PRISONER, // added by Flugente: free a prisoner
AI_ACTION_USE_SKILL, // added by Flugente: perform a skill, which one is stored in usAISkillUse
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!!!
} ActionType;
@@ -266,4 +267,7 @@ UINT8 GetClosestFlaggedSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 au
// get the id of the closest soldier (closer than x tiles) of a specific team that is wounded that we can currently see
UINT8 GetClosestWoundedSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 auTeam );
// get the id of the closest medic (closer than x tiles) of a specific team
UINT8 GetClosestMedicSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 auTeam );
#endif