mirror of
https://github.com/1dot13/source.git
synced 2026-07-29 13:52:17 +02:00
Original Source for 1.13 Mod High Resolution version from 12/06/05
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@21 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -0,0 +1,540 @@
|
||||
#ifdef PRECOMPILEDHEADERS
|
||||
#include "AI All.h"
|
||||
#else
|
||||
#include "AIInternals.h"
|
||||
#include "ai.h"
|
||||
#include "pathai.h"
|
||||
#include "items.h"
|
||||
#include "World Items.h"
|
||||
#endif
|
||||
|
||||
#include "Queen Command.h"
|
||||
|
||||
void MakeClosestEnemyChosenOne()
|
||||
{
|
||||
UINT32 cnt;
|
||||
INT16 sPathCost, sShortestPath = 1000;
|
||||
INT8 bOldKeys = -1;
|
||||
UINT8 ubClosestEnemy = NOBODY;
|
||||
SOLDIERTYPE * pSoldier;
|
||||
INT8 bPanicTrigger;
|
||||
INT16 sPanicTriggerGridNo;
|
||||
|
||||
if ( ! (gTacticalStatus.fPanicFlags & PANIC_TRIGGERS_HERE) )
|
||||
{
|
||||
#ifdef BETAVERSION
|
||||
PopMessage("MakeClosestEnemyChosenOne: ERROR - Panic Trigger is NOWHERE");
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NeedToRadioAboutPanicTrigger() )
|
||||
{
|
||||
// no active panic triggers
|
||||
return;
|
||||
}
|
||||
|
||||
// consider every enemy, looking for the closest capable, unbusy one
|
||||
for (cnt = 0; cnt < guiNumMercSlots; cnt++)
|
||||
{
|
||||
pSoldier = MercSlots[cnt];
|
||||
|
||||
if (!pSoldier) // if this merc is inactive, or not here
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if this merc is unconscious, or dead
|
||||
if (pSoldier->bLife < OKLIFE)
|
||||
{
|
||||
continue; // next soldier
|
||||
}
|
||||
|
||||
// if this guy's too tired to go
|
||||
if (pSoldier->bBreath < OKBREATH)
|
||||
{
|
||||
continue; // next soldier
|
||||
}
|
||||
|
||||
if ( gWorldSectorX == TIXA_SECTOR_X && gWorldSectorY == TIXA_SECTOR_Y )
|
||||
{
|
||||
if ( pSoldier->ubProfile != WARDEN )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// only consider for army guys
|
||||
if (pSoldier->bTeam != ENEMY_TEAM )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if this guy is in battle with opponent(s)
|
||||
if (pSoldier->bOppCnt > 0)
|
||||
{
|
||||
continue; // next soldier
|
||||
}
|
||||
|
||||
// if this guy is still in serious shock
|
||||
if (pSoldier->bShock > 2)
|
||||
{
|
||||
continue; // next soldier
|
||||
}
|
||||
|
||||
if ( pSoldier->bLevel != 0 )
|
||||
{
|
||||
// screw having guys on the roof go for panic triggers!
|
||||
continue; // next soldier
|
||||
}
|
||||
|
||||
bPanicTrigger = ClosestPanicTrigger( pSoldier );
|
||||
if (bPanicTrigger == -1)
|
||||
{
|
||||
continue; // next soldier
|
||||
}
|
||||
|
||||
sPanicTriggerGridNo = gTacticalStatus.sPanicTriggerGridNo[ bPanicTrigger ];
|
||||
if (sPanicTriggerGridNo == NOWHERE)
|
||||
{
|
||||
// this should never happen!
|
||||
continue;
|
||||
}
|
||||
|
||||
// remember whether this guy had keys before
|
||||
//bOldKeys = pSoldier->bHasKeys;
|
||||
|
||||
// give him keys to see if with them he can get to the panic trigger
|
||||
pSoldier->bHasKeys = (pSoldier->bHasKeys << 1) | 1;
|
||||
|
||||
// we now path directly to the panic trigger
|
||||
|
||||
|
||||
// if he can't get to a spot where he could get at the panic trigger
|
||||
/*
|
||||
if ( FindAdjacentGridEx( pSoldier, gTacticalStatus.sPanicTriggerGridno, &ubDirection, &sAdjSpot, FALSE, FALSE ) == -1 )
|
||||
{
|
||||
pSoldier->bHasKeys = bOldKeys;
|
||||
continue; // next merc
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// ok, this enemy appears to be eligible
|
||||
|
||||
// FindAdjacentGrid set HandGrid for us. If we aren't at that spot already
|
||||
if (pSoldier->sGridNo != sPanicTriggerGridNo)
|
||||
{
|
||||
// get the AP cost for this enemy to go to target position
|
||||
sPathCost = PlotPath( pSoldier, sPanicTriggerGridNo, FALSE, FALSE, FALSE, WALKING, FALSE, FALSE, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
sPathCost = 0;
|
||||
}
|
||||
|
||||
// set his keys value back to what it was before this hack
|
||||
pSoldier->bHasKeys = (pSoldier->bHasKeys >> 1 );
|
||||
|
||||
// if he can get there (or is already there!)
|
||||
if (sPathCost || (pSoldier->sGridNo == sPanicTriggerGridNo))
|
||||
{
|
||||
if (sPathCost < sShortestPath)
|
||||
{
|
||||
sShortestPath = sPathCost;
|
||||
ubClosestEnemy = pSoldier->ubID;
|
||||
}
|
||||
}
|
||||
//else
|
||||
//NameMessage(pSoldier,"can't get there...");
|
||||
}
|
||||
|
||||
// if we found have an eligible enemy, make him our "chosen one"
|
||||
if (ubClosestEnemy < NOBODY)
|
||||
{
|
||||
gTacticalStatus.ubTheChosenOne = ubClosestEnemy; // flag him as the chosen one
|
||||
|
||||
#ifdef TESTVERSION
|
||||
NumMessage("TEST MSG: The chosen one is ",TheChosenOne);
|
||||
#endif
|
||||
|
||||
pSoldier = MercPtrs[gTacticalStatus.ubTheChosenOne];
|
||||
if ( pSoldier->bAlertStatus < STATUS_RED )
|
||||
{
|
||||
pSoldier->bAlertStatus = STATUS_RED;
|
||||
CheckForChangingOrders( pSoldier );
|
||||
}
|
||||
SetNewSituation( pSoldier ); // set new situation for the chosen one
|
||||
pSoldier->bHasKeys = (pSoldier->bHasKeys << 1) | 1; // cheat and give him keys to every door
|
||||
//pSoldier->bHasKeys = TRUE;
|
||||
}
|
||||
#ifdef TESTVERSION
|
||||
else
|
||||
PopMessage("TEST MSG: Couldn't find anyone eligible to become TheChosenOne!");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PossiblyMakeThisEnemyChosenOne( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
INT32 iAPCost, iPathCost;
|
||||
//INT8 bOldKeys;
|
||||
INT8 bPanicTrigger;
|
||||
INT16 sPanicTriggerGridNo;
|
||||
UINT32 uiPercentEnemiesKilled;
|
||||
|
||||
if ( ! (gTacticalStatus.fPanicFlags & PANIC_TRIGGERS_HERE) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( pSoldier->bLevel != 0 )
|
||||
{
|
||||
// screw having guys on the roof go for panic triggers!
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bPanicTrigger = ClosestPanicTrigger( pSoldier );
|
||||
if (bPanicTrigger == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sPanicTriggerGridNo = gTacticalStatus.sPanicTriggerGridNo[ bPanicTrigger ];
|
||||
|
||||
uiPercentEnemiesKilled = (UINT32)( 100 * (UINT32)(gTacticalStatus.ubArmyGuysKilled) / (UINT32)( gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector + gTacticalStatus.ubArmyGuysKilled ) );
|
||||
if ( gTacticalStatus.ubPanicTolerance[ bPanicTrigger ] > uiPercentEnemiesKilled )
|
||||
{
|
||||
// not yet... not yet
|
||||
return;
|
||||
}
|
||||
|
||||
//bOldKeys = pSoldier->bHasKeys;
|
||||
pSoldier->bHasKeys = (pSoldier->bHasKeys << 1) | 1;
|
||||
|
||||
// if he can't get to a spot where he could get at the panic trigger
|
||||
iAPCost = AP_PULL_TRIGGER;
|
||||
if (pSoldier->sGridNo != sPanicTriggerGridNo)
|
||||
{
|
||||
iPathCost = PlotPath( pSoldier, sPanicTriggerGridNo, FALSE, FALSE, FALSE, RUNNING, FALSE, FALSE, 0);
|
||||
if (iPathCost == 0)
|
||||
{
|
||||
//pSoldier->bHasKeys = bOldKeys;
|
||||
pSoldier->bHasKeys = (pSoldier->bHasKeys >> 1);
|
||||
return;
|
||||
}
|
||||
iAPCost += iPathCost;
|
||||
|
||||
}
|
||||
|
||||
if ( iAPCost <= CalcActionPoints( pSoldier ) * 2)
|
||||
{
|
||||
// go!!!
|
||||
gTacticalStatus.ubTheChosenOne = pSoldier->ubID;
|
||||
return;
|
||||
}
|
||||
// else return keys to normal
|
||||
//pSoldier->bHasKeys = bOldKeys;
|
||||
pSoldier->bHasKeys = (pSoldier->bHasKeys >> 1);
|
||||
}
|
||||
|
||||
|
||||
INT8 PanicAI(SOLDIERTYPE *pSoldier, UINT8 ubCanMove)
|
||||
{
|
||||
BOOLEAN fFoundRoute = FALSE;
|
||||
INT8 bSlot;
|
||||
INT32 iPathCost;
|
||||
INT8 bPanicTrigger;
|
||||
INT16 sPanicTriggerGridNo;
|
||||
#ifdef DEBUGDECISIONS
|
||||
STR16 tempstr;
|
||||
#endif
|
||||
|
||||
// if there are panic bombs here
|
||||
if (gTacticalStatus.fPanicFlags & PANIC_BOMBS_HERE)
|
||||
{
|
||||
// if enemy is holding a portable panic bomb detonator, he tries to use it
|
||||
bSlot = FindTrigger( pSoldier );
|
||||
if (bSlot != NO_SLOT)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// ACTIVATE DETONATOR: blow up sector's panic bombs
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// if we have enough APs to activate it now
|
||||
if (pSoldier->bActionPoints >= AP_USE_REMOTE)
|
||||
{
|
||||
#ifdef TESTVERSION
|
||||
sprintf((CHAR *)tempstr,"TEST MSG: %s - ACTIVATING his DETONATOR!",pSoldier->name);
|
||||
PopMessage(tempstr);
|
||||
#endif
|
||||
// blow up all the PANIC bombs!
|
||||
return(AI_ACTION_USE_DETONATOR);
|
||||
}
|
||||
else // otherwise, wait a turn
|
||||
{
|
||||
pSoldier->usActionData = NOWHERE;
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no panic bombs, or no portable detonator
|
||||
|
||||
// if there's a panic trigger here (DOESN'T MATTER IF ANY PANIC BOMBS EXIST!)
|
||||
if ( gTacticalStatus.fPanicFlags & PANIC_TRIGGERS_HERE )
|
||||
{
|
||||
// Have WE been chosen to go after the trigger?
|
||||
if (pSoldier->ubID == gTacticalStatus.ubTheChosenOne)
|
||||
{
|
||||
bPanicTrigger = ClosestPanicTrigger( pSoldier );
|
||||
if (bPanicTrigger == -1)
|
||||
{
|
||||
// augh!
|
||||
return( -1 );
|
||||
}
|
||||
sPanicTriggerGridNo = gTacticalStatus.sPanicTriggerGridNo[ bPanicTrigger ];
|
||||
|
||||
// if not standing on the panic trigger
|
||||
if (pSoldier->sGridNo != sPanicTriggerGridNo)
|
||||
{
|
||||
// determine whether we can still get there
|
||||
iPathCost = PlotPath( pSoldier, sPanicTriggerGridNo, FALSE, FALSE, FALSE, RUNNING, FALSE, FALSE, 0);
|
||||
if (iPathCost != 0)
|
||||
{
|
||||
fFoundRoute = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fFoundRoute = TRUE;
|
||||
}
|
||||
|
||||
// if we managed to find an adjacent spot
|
||||
if (fFoundRoute)
|
||||
{
|
||||
|
||||
/*
|
||||
*** COMMENTED OUT BECAUSE WE DON'T HAVE SUPPORT ROUTINES YET
|
||||
|
||||
// make sure it's not in water (those triggers can't be pulled)
|
||||
if (Water(Terrain(gTacticalStatus.sHandGrid),Structure(gTacticalStatus.sHandGrid)))
|
||||
{
|
||||
#ifdef BETAVERSION
|
||||
PopMessage("BAD SCENARIO DESIGN: Enemies can't use this panic trigger!");
|
||||
#endif
|
||||
gTacticalStatus.ubTheChosenOne = NOBODY; // strip him of his Chosen One status
|
||||
// don't bother replacing him either, the next won't have more luck!
|
||||
return(-1);
|
||||
}
|
||||
|
||||
*/
|
||||
// if we are at that spot now
|
||||
if (pSoldier->sGridNo == sPanicTriggerGridNo)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////
|
||||
// PULL THE PANIC TRIGGER!
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// and we have enough APs left to pull the trigger
|
||||
if (pSoldier->bActionPoints >= AP_PULL_TRIGGER)
|
||||
{
|
||||
// blow up the all the PANIC bombs (or just the journal)
|
||||
pSoldier->usActionData = sPanicTriggerGridNo;
|
||||
|
||||
#ifdef TESTVERSION
|
||||
sprintf((CHAR *)tempstr,"TEST MSG: %s - PULLS PANIC TRIGGER at grid %d",
|
||||
pSoldier->name,pSoldier->usActionData);
|
||||
PopMessage(tempstr);
|
||||
#endif
|
||||
|
||||
return(AI_ACTION_PULL_TRIGGER);
|
||||
}
|
||||
else // otherwise, wait a turn
|
||||
{
|
||||
pSoldier->usActionData = NOWHERE;
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
}
|
||||
else // we are NOT at the HandGrid spot
|
||||
{
|
||||
// if we can move at least 1 square's worth
|
||||
if (ubCanMove)
|
||||
{
|
||||
// if we can get to the HandGrid spot to yank the trigger
|
||||
// animations don't allow trigger-pulling from water, so we won't!
|
||||
if (LegalNPCDestination(pSoldier,sPanicTriggerGridNo,ENSURE_PATH,NOWATER,0))
|
||||
{
|
||||
pSoldier->usActionData = sPanicTriggerGridNo;
|
||||
pSoldier->bPathStored = TRUE;
|
||||
|
||||
#ifdef DEBUGDECISIONS
|
||||
sprintf((CHAR *)tempstr,"%s - GETTING CLOSER to PANIC TRIGGER at grid %d (Trigger at %d)", pSoldier->name,pSoldier->usActionData,sPanicTriggerGridNo);
|
||||
AIPopMessage(tempstr);
|
||||
#endif
|
||||
|
||||
return(AI_ACTION_GET_CLOSER);
|
||||
}
|
||||
else // Oh oh, the chosen one can't get to the trigger!
|
||||
{
|
||||
#ifdef TESTVERSION
|
||||
PopMessage("TEST MSG: Oh oh! !legalDest - ChosenOne can't get to the trigger!");
|
||||
#endif
|
||||
gTacticalStatus.ubTheChosenOne = NOBODY; // strip him of his Chosen One status
|
||||
MakeClosestEnemyChosenOne(); // and replace him!
|
||||
}
|
||||
}
|
||||
else // can't move, wait 1 turn
|
||||
{
|
||||
pSoldier->usActionData = NOWHERE;
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Oh oh, the chosen one can't get to the trigger!
|
||||
{
|
||||
#ifdef TESTVERSION
|
||||
PopMessage("TEST MSG: Oh oh! !adjacentFound - ChosenOne can't get to the trigger!");
|
||||
#endif
|
||||
gTacticalStatus.ubTheChosenOne = NOBODY; // strip him of his Chosen One status
|
||||
MakeClosestEnemyChosenOne(); // and replace him!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no action decided
|
||||
return(-1);
|
||||
}
|
||||
|
||||
void InitPanicSystem( void )
|
||||
{
|
||||
// start by assuming there is no panic bombs or triggers here
|
||||
gTacticalStatus.ubTheChosenOne = NOBODY;
|
||||
FindPanicBombsAndTriggers();
|
||||
}
|
||||
|
||||
INT8 ClosestPanicTrigger( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
INT8 bLoop;
|
||||
INT16 sDistance;
|
||||
INT16 sClosestDistance = 1000;
|
||||
INT8 bClosestTrigger = -1;
|
||||
UINT32 uiPercentEnemiesKilled;
|
||||
|
||||
uiPercentEnemiesKilled = (UINT32)( 100 * (UINT32)(gTacticalStatus.ubArmyGuysKilled) / (UINT32)( gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector + gTacticalStatus.ubArmyGuysKilled ) );
|
||||
|
||||
for ( bLoop = 0; bLoop < NUM_PANIC_TRIGGERS; bLoop++ )
|
||||
{
|
||||
if ( gTacticalStatus.sPanicTriggerGridNo[ bLoop ] != NOWHERE )
|
||||
{
|
||||
|
||||
if ( gTacticalStatus.ubPanicTolerance[ bLoop ] > uiPercentEnemiesKilled )
|
||||
{
|
||||
// not yet... not yet...
|
||||
continue; // next trigger
|
||||
}
|
||||
|
||||
// in Tixa
|
||||
if ( gWorldSectorX == TIXA_SECTOR_X && gWorldSectorY == TIXA_SECTOR_Y )
|
||||
{
|
||||
// screen out everyone but the warden
|
||||
if ( pSoldier->ubProfile != WARDEN )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// screen out the second/later panic trigger if the first one hasn't been triggered
|
||||
if ( bLoop > 0 && gTacticalStatus.sPanicTriggerGridNo[ bLoop - 1 ] != NOWHERE )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sDistance = PythSpacesAway( pSoldier->sGridNo, gTacticalStatus.sPanicTriggerGridNo[ bLoop ] );
|
||||
if (sDistance < sClosestDistance)
|
||||
{
|
||||
sClosestDistance = sDistance;
|
||||
bClosestTrigger = bLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return( bClosestTrigger );
|
||||
}
|
||||
|
||||
BOOLEAN NeedToRadioAboutPanicTrigger( void )
|
||||
{
|
||||
UINT32 uiPercentEnemiesKilled;
|
||||
INT8 bLoop;
|
||||
|
||||
if ( !(gTacticalStatus.fPanicFlags & PANIC_TRIGGERS_HERE) || gTacticalStatus.ubTheChosenOne != NOBODY )
|
||||
{
|
||||
// already done!
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
if ( gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector == 0 )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
if ( gWorldSectorX == TIXA_SECTOR_X && gWorldSectorY == TIXA_SECTOR_Y )
|
||||
{
|
||||
SOLDIERTYPE * pSoldier;
|
||||
pSoldier = FindSoldierByProfileID( WARDEN, FALSE );
|
||||
if ( !pSoldier || pSoldier->ubID == gTacticalStatus.ubTheChosenOne )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uiPercentEnemiesKilled = (UINT32)( 100 * (UINT32)(gTacticalStatus.ubArmyGuysKilled) / (UINT32)( gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector + gTacticalStatus.ubArmyGuysKilled ) );
|
||||
|
||||
for ( bLoop = 0; bLoop < NUM_PANIC_TRIGGERS; bLoop++ )
|
||||
{
|
||||
// if the bomb exists and its tolerance has been exceeded
|
||||
if ( (gTacticalStatus.sPanicTriggerGridNo[ bLoop ] != NOWHERE) && ( uiPercentEnemiesKilled >= gTacticalStatus.ubPanicTolerance[ bLoop ] ) )
|
||||
{
|
||||
return( TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
|
||||
#define STAIRCASE_GRIDNO 12067
|
||||
#define STAIRCASE_DIRECTION 0
|
||||
|
||||
INT8 HeadForTheStairCase( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
UNDERGROUND_SECTORINFO * pBasementInfo;
|
||||
|
||||
pBasementInfo = FindUnderGroundSector( 3, MAP_ROW_P, 1 );
|
||||
if ( pBasementInfo && pBasementInfo->uiTimeCurrentSectorWasLastLoaded != 0 && ( pBasementInfo->ubNumElites + pBasementInfo->ubNumTroops + pBasementInfo->ubNumAdmins ) < 5 )
|
||||
{
|
||||
return( AI_ACTION_NONE );
|
||||
}
|
||||
|
||||
if ( PythSpacesAway( pSoldier->sGridNo, STAIRCASE_GRIDNO ) < 2 )
|
||||
{
|
||||
return( AI_ACTION_TRAVERSE_DOWN );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( LegalNPCDestination( pSoldier, STAIRCASE_GRIDNO, ENSURE_PATH, WATEROK, 0 ) )
|
||||
{
|
||||
pSoldier->usActionData = STAIRCASE_GRIDNO;
|
||||
return( AI_ACTION_GET_CLOSER );
|
||||
}
|
||||
}
|
||||
return( AI_ACTION_NONE );
|
||||
}
|
||||
|
||||
#define WARDEN_ALARM_GRIDNO 9376
|
||||
#define WARDEN_GAS_GRIDNO 9216
|
||||
// in both cases, direction 6
|
||||
Reference in New Issue
Block a user