348 lines
11 KiB
Plaintext
348 lines
11 KiB
Plaintext
////////////////////////////////////////////////////////////////////////////////
|
|
// ai_header - shared functions used in computer controlled team AI
|
|
// By Deva Bryson Winblood. 04/13/2004
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int MAX_AI_UNITS = 30;
|
|
int AI_GUARD = 2;
|
|
int AI_FOLLOW = 5;
|
|
int AI_GUARD_LAIR = 11;
|
|
int AI_HEAL = 9;
|
|
int AI_RAID = 17;
|
|
int AI_RAID_ATTACK = 1;
|
|
int AI_RAID_GOLD = 3;
|
|
int AI_RAID_MANA = 2;
|
|
//////////////////////////////
|
|
// PROTOTYPES
|
|
//////////////////////////////
|
|
|
|
// returns the starting waypoint where players and leaders spawn
|
|
object fnAIGetLairStart(string sID);
|
|
|
|
// returns the object that the taxes are stored in for this team
|
|
object fnAIGetLairChest(string sID);
|
|
|
|
// returns how many units currently have 30 max for AI controlled team
|
|
int fnAICountMembers(string sID);
|
|
|
|
// returns a unit that matches the sTag type. If bNotBusy is set to
|
|
// TRUE it will only return 1 that is not on a RAID, GUARD, or GUARD LAIR
|
|
object fnAIGetMemberByType(string sID,string sTag,int bNotBusy=FALSE);
|
|
|
|
// returns a unit that is not on RAID, GUARD, or GUARD LAIR
|
|
// if bIncludeGuardLair is set to TRUE then it will return them if they
|
|
// are doing Guard Lair also.
|
|
object fnAIGetNonBusyMember(string sID,int bIncludeGuardLair=FALSE);
|
|
|
|
// This returns how many of the sTag unit are currently under this AI Team
|
|
// Leaders control.
|
|
int fnAICountMemberType(string sID,string sTag);
|
|
|
|
// This AI works with 30 units. This will return a # to an unaffiliated
|
|
// number that can be used to create a new unit.
|
|
int fnAIGetEmptyUnitNumber(string sID);
|
|
|
|
// This will create sRes unit at location and assign it to unit
|
|
// nNum 1-30.
|
|
object fnAICreateUnit(string sID,string sRes,location lLoc,int nNum);
|
|
|
|
// this returns a unit that is wounded down to nPercent or less of
|
|
// their life. If bIncludeRaid is set to FALSE it will not return
|
|
// any units on raiding missions.
|
|
object fnAIGetWoundedUnit(string sID,int nPercent,int bIncludeRaid=FALSE);
|
|
|
|
// returns the ID of the team that has the most trespass counts against this
|
|
// team sID.
|
|
string fnAIGetLargestTrespasser(string sID);
|
|
|
|
// returns the ID of a team that has trespassed randomly chosen.
|
|
string fnAIGetRandomTrespasser(string sID);
|
|
|
|
// upgrade the unit oUnit to a new unit sRes with the same mission,
|
|
// same nNum, etc.
|
|
void fnAIUpgradeUnit(object oUnit,string sRes);
|
|
|
|
// returns the team unit type # from the tag und25 would return 25
|
|
int fnAIGetUnitNumberFromTag(string sTag);
|
|
|
|
// This function should be called once before any of the other AI
|
|
// functions as it will populate the statistics and reduce the
|
|
// amount of processing that would otherwise be required for some
|
|
// of these.
|
|
void fnAISetupStatistics(string sID);
|
|
|
|
//////////////////////////////
|
|
// FUNCTIONS
|
|
//////////////////////////////
|
|
object fnAIGetLairStart(string sID)
|
|
{
|
|
object oWP=GetWaypointByTag(sID+"_START");
|
|
return oWP;
|
|
} // fnAIGetLairStart()
|
|
|
|
object fnAIGetLairChest(string sID)
|
|
{
|
|
object oOb=GetObjectByTag(sID+"_CHEST");
|
|
return oOb;
|
|
} // fnAIGetLairChest()
|
|
|
|
int fnAICountMembers(string sID)
|
|
{
|
|
int nRet=0;
|
|
object oMod=GetModule();
|
|
string sUnit;
|
|
sUnit="nAdvAIUnitT"+sID;
|
|
nRet=GetLocalInt(oMod,sUnit+"UC");
|
|
return nRet;
|
|
} // fnAICountMembers()
|
|
|
|
object fnAIGetMemberByType(string sID,string sTag,int bNotBusy=FALSE)
|
|
{
|
|
object oRet=OBJECT_INVALID;
|
|
string sUnit;
|
|
object oMod=GetModule();
|
|
object oUnit;
|
|
int nState;
|
|
int nL=1;
|
|
while(nL<MAX_AI_UNITS+1&&oRet==OBJECT_INVALID)
|
|
{ // get member
|
|
sUnit="oAdvAIUnit"+IntToString(nL);
|
|
oUnit=GetLocalObject(oMod,sUnit);
|
|
if (oUnit!=OBJECT_INVALID&&GetTag(oUnit)==sTag)
|
|
{ // busy
|
|
if (bNotBusy==FALSE) return oRet;
|
|
else { // see if busy
|
|
nState=GetLocalInt(oUnit,"nMState");
|
|
if (nState!=AI_GUARD&&nState!=AI_FOLLOW&&nState!=AI_HEAL&&nState!=AI_GUARD_LAIR&&nState!=AI_RAID) return oRet;
|
|
} // see if busy
|
|
} // busy
|
|
nL++;
|
|
} // get member
|
|
return oRet;
|
|
} // fnAIAIGetMembersByType()
|
|
|
|
object fnAIGetNonBusyMember(string sID,int bIncludeGuardLair=FALSE)
|
|
{
|
|
object oRet=OBJECT_INVALID;
|
|
string sUnit;
|
|
object oMod=GetModule();
|
|
object oUnit;
|
|
int nState;
|
|
int nL=1;
|
|
while(nL<MAX_AI_UNITS+1&&oRet==OBJECT_INVALID)
|
|
{ // get member
|
|
sUnit="oAdvAIUnit"+IntToString(nL);
|
|
oUnit=GetLocalObject(oMod,sUnit);
|
|
if (oUnit!=OBJECT_INVALID)
|
|
{ // unit
|
|
nState=GetLocalInt(oUnit,"nMState");
|
|
if (nState!=AI_GUARD&&nState!=AI_FOLLOW&&nState!=AI_HEAL&&nState!=AI_RAID)
|
|
{ // possible candidate
|
|
if (bIncludeGuardLair==FALSE) return oUnit;
|
|
else if (nState!=AI_GUARD_LAIR) return oUnit;
|
|
} // possible candidate
|
|
} // unit
|
|
nL++;
|
|
} // get member
|
|
return oRet;
|
|
} // fnAIGetNonBusyMember()
|
|
|
|
int fnAICountMemberType(string sID,string sTag)
|
|
{
|
|
int nRet=0;
|
|
object oMod=GetModule();
|
|
string sUnit;
|
|
object oUnit;
|
|
nRet=fnAIGetUnitNumberFromTag(GetTag(oUnit));
|
|
sUnit="nAdvAIUnitC"+sID+IntToString(nRet);
|
|
nRet=GetLocalInt(oMod,sUnit);
|
|
return nRet;
|
|
} // fnAICountMemberType()
|
|
|
|
int fnAIGetEmptyUnitNumber(string sID)
|
|
{
|
|
int nRet=0;
|
|
int nL=1;
|
|
string sUnit;
|
|
object oMod=GetModule();
|
|
while(nL<MAX_AI_UNITS+1&&nRet==0)
|
|
{ // find empty slot
|
|
sUnit="oAdvAIUnit"+IntToString(nL);
|
|
if (GetLocalObject(oMod,sUnit)==OBJECT_INVALID) nRet=nL;
|
|
nL++;
|
|
} // find empty slot
|
|
return nRet;
|
|
} // fnAIGetEmptyUnitNumber()
|
|
|
|
object fnAICreateUnit(string sID,string sRes,location lLoc,int nNum)
|
|
{
|
|
object oRet=OBJECT_INVALID;
|
|
object oMod=GetModule();
|
|
string sUnit="oAdvAIUnit"+sID+IntToString(nNum);
|
|
object oCreate=CreateObject(OBJECT_TYPE_CREATURE,sRes,lLoc);
|
|
//object oDM=GetFirstPC();
|
|
//while(oDM!=OBJECT_INVALID&&GetIsDM(oDM)!=TRUE)
|
|
//{
|
|
// oDM=GetNextPC();
|
|
//}
|
|
//if (GetIsDM(oDM)==TRUE) SendMessageToPC(oDM,GetName(oCreate)+" created in area "+GetName(GetArea(oCreate))+" RES="+sRes+" nNum="+IntToString(nNum));
|
|
SetLocalString(oCreate,"sTeamID",sID);
|
|
SetLocalObject(oMod,sUnit,oCreate);
|
|
SetLocalInt(oCreate,"nAIControlNum",nNum);
|
|
oRet=oCreate;
|
|
if (oCreate!=OBJECT_INVALID) PrintString(GetName(oCreate)+" spawned.");
|
|
return oRet;
|
|
} // fnAICreateUnit()
|
|
|
|
object fnAIGetWoundedUnit(string sID,int nPercent,int bIncludeRaid=FALSE)
|
|
{
|
|
object oRet=OBJECT_INVALID;
|
|
int nMax;
|
|
int nCur;
|
|
int nP;
|
|
int nL=1;
|
|
int nState;
|
|
string sUnit;
|
|
object oUnit;
|
|
float fP;
|
|
object oMod=GetModule();
|
|
while(nL<MAX_AI_UNITS+1&&oRet==OBJECT_INVALID)
|
|
{ // find wounded
|
|
sUnit="oAdvAIUnit"+IntToString(nL);
|
|
oUnit=GetLocalObject(oMod,sUnit);
|
|
if (oUnit!=OBJECT_INVALID)
|
|
{ // !OI
|
|
nMax=GetMaxHitPoints(oUnit);
|
|
nCur=GetCurrentHitPoints(oUnit);
|
|
if (nMax!=nCur)
|
|
{ // wounded
|
|
if ((bIncludeRaid==FALSE&&GetLocalInt(oUnit,"nMState")!=AI_RAID)||bIncludeRaid==TRUE)
|
|
{ // okay to use
|
|
fP=IntToFloat(nCur)/IntToFloat(nMax);
|
|
fP=fP*100;
|
|
nP=FloatToInt(fP);
|
|
if (nP<=nPercent) return oUnit;
|
|
} // okay to use
|
|
} // wounded
|
|
} // !OI
|
|
nL++;
|
|
} // find wounded
|
|
return oRet;
|
|
} // fnAIGetWoundedUnit()
|
|
|
|
string fnAIGetLargestTrespasser(string sID)
|
|
{
|
|
string sRet="NA";
|
|
object oMod=GetModule();
|
|
string sTresPrefix="nAITrespass"+sID+"_";
|
|
int nCount=0;
|
|
if (sID!="DWF"&&GetLocalInt(oMod,sTresPrefix+"DWF")>nCount) { nCount=GetLocalInt(oMod,sTresPrefix+"DWF"); sRet="DWF"; }
|
|
if (sID!="UND"&&GetLocalInt(oMod,sTresPrefix+"UND")>nCount) { nCount=GetLocalInt(oMod,sTresPrefix+"UND"); sRet="UND"; }
|
|
if (sID!="UNC"&&GetLocalInt(oMod,sTresPrefix+"UNC")>nCount) { nCount=GetLocalInt(oMod,sTresPrefix+"UNC"); sRet="UNC"; }
|
|
if (sID!="SPID"&&GetLocalInt(oMod,sTresPrefix+"SPID")>nCount) { nCount=GetLocalInt(oMod,sTresPrefix+"SPID"); sRet="SPID"; }
|
|
return sRet;
|
|
} // fnAIGetLargestTrespasser()
|
|
|
|
string fnAIGetRandomTrespasser(string sID)
|
|
{
|
|
string sRet="NA";
|
|
object oMod=GetModule();
|
|
int nCount=0;
|
|
int nR;
|
|
string sTresPrefix="nAITrespass"+sID+"_";
|
|
if (fnAIGetLargestTrespasser(sID)!="NA")
|
|
{ // there is a trespasser
|
|
while(sRet=="NA")
|
|
{ // get trespasser
|
|
nR=d4();
|
|
if (sID!="DWF"&&GetLocalInt(oMod,sTresPrefix+"DWF")>nCount&&nR==1) return "DWF";
|
|
else if (sID!="UND"&&GetLocalInt(oMod,sTresPrefix+"UND")>nCount&&nR==2) return "UND";
|
|
else if (sID!="UNC"&&GetLocalInt(oMod,sTresPrefix+"UNC")>nCount&&nR==3) return "UNC";
|
|
else if (sID!="SPID"&&GetLocalInt(oMod,sTresPrefix+"SPID")>nCount&&nR==4) return "SPID";
|
|
} // get trespasser
|
|
} // there is a trespasser
|
|
return sRet;
|
|
} // fnAIGetRandomTrespasser()
|
|
|
|
void fnAIUpgradeUnit(object oUnit,string sRes)
|
|
{
|
|
string sID=GetLocalString(oUnit,"sTeamID");
|
|
int nNum=GetLocalInt(oUnit,"nAIControlNum");
|
|
object oMod=GetModule();
|
|
string sUnit="oAdvAIUnit"+sID+IntToString(nNum);
|
|
int nMState=GetLocalInt(oUnit,"nMState");
|
|
object oDest=GetLocalObject(oUnit,"oDestWP");
|
|
int nParm=GetLocalInt(oUnit,"nParm");
|
|
int nRun=GetLocalInt(oUnit,"nRun");
|
|
object oNew=CreateObject(OBJECT_TYPE_CREATURE,sRes,GetLocation(oUnit));
|
|
DestroyObject(oUnit);
|
|
SetLocalString(oNew,"sTeamID",sID);
|
|
SetLocalInt(oNew,"nAIControlNum",nNum);
|
|
SetLocalInt(oNew,"nMState",nMState);
|
|
SetLocalObject(oNew,"oDestWP",oDest);
|
|
SetLocalInt(oNew,"nParm",nParm);
|
|
SetLocalInt(oNew,"nRun",nRun);
|
|
SetLocalObject(oMod,sUnit,oNew);
|
|
} // fnAIUpgradeUnit()
|
|
|
|
int fnAIGetUnitNumberFromTag(string sTag)
|
|
{
|
|
int nRet=0;
|
|
string sParse=GetStringRight(sTag,2);
|
|
if (StringToInt(GetStringLeft(sParse,1))==0) sParse=GetStringRight(sTag,1);
|
|
nRet=StringToInt(sParse);
|
|
return nRet;
|
|
} // fnAIGetUnitNumberFromTag()
|
|
|
|
void fnAISetupStatistics(string sID)
|
|
{
|
|
object oMod=GetModule();
|
|
int nL=0;
|
|
int nS;
|
|
string sUnit;
|
|
object oUnit;
|
|
int nUC=0;
|
|
int nD=0;
|
|
int nG=0;
|
|
int nO=0;
|
|
// clear statistics
|
|
while(nL<30)
|
|
{ // clear total
|
|
sUnit="nAdvAIUnitC"+sID+IntToString(nL);
|
|
DeleteLocalInt(oMod,sUnit);
|
|
nL++;
|
|
} // clear total
|
|
sUnit="nAdvAIUnitT"+sID;
|
|
DeleteLocalInt(oMod,sUnit+"D"); // defensive
|
|
DeleteLocalInt(oMod,sUnit+"G"); // guard
|
|
DeleteLocalInt(oMod,sUnit+"O"); // offensive
|
|
// get new statistics
|
|
nL=1;
|
|
while(nL<MAX_AI_UNITS+1)
|
|
{ // look at each unit
|
|
sUnit="oAdvAIUnit"+sID+IntToString(nL);
|
|
oUnit=GetLocalObject(oMod,sUnit);
|
|
if (oUnit!=OBJECT_INVALID)
|
|
{ // !OI
|
|
nS=GetLocalInt(oUnit,"nMState");
|
|
nUC++;
|
|
if (nS==AI_GUARD_LAIR||nS==AI_GUARD||nS==AI_HEAL) nD++;
|
|
if (nS==AI_GUARD) nG++;
|
|
if (nS==AI_RAID) nO++;
|
|
nS=fnAIGetUnitNumberFromTag(GetTag(oUnit));
|
|
sUnit="nAdvAIUnitC"+sID+IntToString(nS);
|
|
nS=GetLocalInt(oMod,sUnit);
|
|
nS++;
|
|
SetLocalInt(oMod,sUnit,nS);
|
|
} // !OI
|
|
nL++;
|
|
} // look at each unit
|
|
sUnit="nAdvAIUnitT"+sID;
|
|
SetLocalInt(oMod,sUnit+"D",nD);
|
|
SetLocalInt(oMod,sUnit+"G",nG);
|
|
SetLocalInt(oMod,sUnit+"O",nO);
|
|
SetLocalInt(oMod,sUnit+"UC",nUC);
|
|
} // fnAISetupStatistics()
|
|
|
|
//void main(){}
|