mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
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:
+5
-2
@@ -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 ##################
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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!
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user