PRC8/nwn/nwnprc/trunk/include/inc_epicspellai.nss
Jaysyn904 6ec137a24e Updated AMS marker feats
Updated AMS marker feats.  Removed arcane & divine marker feats.  Updated Dread Necromancer for epic progression. Updated weapon baseitem models.  Updated new weapons for crafting & npc equip.
 Updated prefix.  Updated release archive.
2024-02-11 14:01:05 -05:00

709 lines
26 KiB
Plaintext

/*
for reference
SpellRngPers 0
SpellRngTouch 2.25
SpellRngShrt 8
SpellRngMed 20
SpellRngLng 40
*/
void DoEpicSpellcasterSpawn();
int DoEpicSpells();
int TestConditions(int nSpellID);
object GetSuitableTaget(int nSpellID);
void MakeEpicSpellsKnownAIList();
#include "inc_epicspells"
//#include "inc_epicspelldef"
//#include "inc_epicspellfnc"
#include "inc_utility"
//returns True if it casts something
int DoEpicSpells()
{
//checks for able to cast anything epic
if(!GetIsEpicSpellcaster(OBJECT_SELF))
return FALSE;
if(GetSpellSlots(OBJECT_SELF) < 1)
return FALSE;
// DoDebug("Checking for EpicSpells");
int nSpellID;
int bTest;
int i;
object oTarget;
//sanity test
if(!array_exists(OBJECT_SELF,"AI_KnownEpicSpells"))
{
if(DEBUG) DoDebug("ERROR: DoEpicSpells: AI_KnownEpicSpells array does not exist, creating");
MakeEpicSpellsKnownAIList();
}
//do specific conditon tests first
//non implemented at moment
//test all spells in known spell array setup on spawn
for(i=0; i<array_get_size(OBJECT_SELF,"AI_KnownEpicSpells");i++)
{
nSpellID = array_get_int(OBJECT_SELF,"AI_KnownEpicSpells", i);
oTarget = GetSuitableTaget(nSpellID);
if(GetIsObjectValid(oTarget)
&& TestConditions(nSpellID)
&& GetCanCastSpell(OBJECT_SELF, nSpellID))
{
ClearAllActions();
int nRealSpellID = StringToInt(Get2DACache("feats", "SpellID",
StringToInt(Get2DACache("EpicSpells", "SpellFeatID", nSpellID))));
ActionCastSpellAtObject(nRealSpellID,oTarget, METAMAGIC_NONE, TRUE);
return TRUE;
}
}
//if no epic spell can be cast, go through normal tests
return FALSE;
}
int TestConditions(int nSpellID)
{
int i;
float fDist;
switch(nSpellID)
{
//personal buffs have no extra checks
//gethasspelleffect is automatically done
case SPELL_EPIC_ACHHEEL:
case SPELL_EPIC_EP_WARD:
case SPELL_EPIC_WHIP_SH:
case SPELL_EPIC_CON_RES:
return TRUE;
break;
//not sure what or how to test at the moment
case SPELL_EPIC_ARMY_UN:
case SPELL_EPIC_PATHS_B:
case SPELL_EPIC_GEMCAGE:
return FALSE;
break;
//timestop checks if already cast
case SPELL_EPIC_GR_TIME:
if(GetHasSpellEffect(
StringToInt(Get2DACache("feats", "SpellID",
StringToInt(Get2DACache("EpicSpells", "SpellFeatID", nSpellID)))
))
)
return FALSE;
else
return TRUE;
break;
//summons check if a summon already exists
case SPELL_EPIC_UNHOLYD:
case SPELL_EPIC_SUMABER:
case SPELL_EPIC_TWINF:
case SPELL_EPIC_MUMDUST:
case SPELL_EPIC_DRG_KNI:
if(GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_SUMMONED))
&& !GetPRCSwitch(PRC_MULTISUMMON))
return FALSE;
else
return TRUE;
break;
//leechfield checks if enemy undead nearby (25m)
case SPELL_EPIC_LEECH_F:
fDist = GetDistanceToObject(GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, 1, CREATURE_TYPE_RACIAL_TYPE,
RACIAL_TYPE_UNDEAD));
if(fDist == -1.0 || fDist > 25.0)
return TRUE;
else
return FALSE;
//Order Restored is alignment sensitive. Only castable by lawful
case SPELL_EPIC_ORDER_R:
if(GetAlignmentLawChaos(OBJECT_SELF) == ALIGNMENT_LAWFUL
&& GetAlignmentLawChaos(GetNearestCreature(
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY)) == ALIGNMENT_CHAOTIC)
return TRUE;
else
return FALSE;
//Anarchy's Call is alignment sensitive. Only castable by Chaotic
case SPELL_EPIC_ANARCHY:
if(GetAlignmentLawChaos(OBJECT_SELF) == ALIGNMENT_CHAOTIC
&& GetAlignmentLawChaos(GetNearestCreature(
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY)) == ALIGNMENT_LAWFUL)
return TRUE;
else
return FALSE;
//touchbuffs pass automatically because of target selection checks
case SPELL_EPIC_HERCALL:
case SPELL_EPIC_CHAMP_V:
case SPELL_EPIC_DEADEYE:
case SPELL_EPIC_DULBLAD:
case SPELL_EPIC_EP_M_AR:
case SPELL_EPIC_EP_SP_R:
case SPELL_EPIC_ET_FREE:
case SPELL_EPIC_FLEETNS:
case SPELL_EPIC_GR_SP_RE:
case SPELL_EPIC_HERCEMP:
case SPELL_EPIC_IMPENET:
case SPELL_EPIC_TRANVIT:
case SPELL_EPIC_UNIMPIN:
case SPELL_EPIC_AL_MART:
return TRUE;
break;
//single hostile spells
case SPELL_EPIC_GR_RUIN:
case SPELL_EPIC_RUINN:
case SPELL_EPIC_GODSMIT:
case SPELL_EPIC_NAILSKY:
case SPELL_EPIC_ENSLAVE:
case SPELL_EPIC_MORI:
case SPELL_EPIC_THEWITH:
case SPELL_EPIC_PSION_S:
case SPELL_EPIC_DWEO_TH:
case SPELL_EPIC_SP_WORM:
case SPELL_EPIC_SINGSUN:
return TRUE;
break;
//aoe hostile spells
case SPELL_EPIC_ANBLAST:
case SPELL_EPIC_ANBLIZZ:
case SPELL_EPIC_A_STONE:
case SPELL_EPIC_MASSPEN:
case SPELL_EPIC_HELBALL:
case SPELL_EPIC_MAGMA_B:
case SPELL_EPIC_TOLO_KW:
return TRUE;
break;
//fail spells that tha AI cant work with anyway
case SPELL_EPIC_CELCOUN:
case SPELL_EPIC_CON_REU:
case SPELL_EPIC_DREAMSC:
case SPELL_EPIC_EP_RPLS:
case SPELL_EPIC_FIEND_W:
case SPELL_EPIC_HELSEND:
case SPELL_EPIC_LEG_ART:
case SPELL_EPIC_PIOUS_P:
case SPELL_EPIC_PLANCEL:
case SPELL_EPIC_RISEN_R:
case SPELL_EPIC_UNSEENW:
return FALSE;
//fail spells that dont work at the moment
case SPELL_EPIC_BATTLEB:
case SPELL_EPIC_DTHMARK:
// case SPELL_EPIC_HELSEND:
// case SPELL_EPIC_EP_RPLS:
// case SPELL_EPIC_LEG_ART:
case SPELL_EPIC_LIFE_FT:
case SPELL_EPIC_NIGHTSU:
case SPELL_EPIC_PEERPEN:
// case SPELL_EPIC_RISEN_R:
case SPELL_EPIC_SYMRUST:
return FALSE;
}
return FALSE;
}
object GetSuitableTaget(int nSpellID)
{
object oTarget;
object oTest;
int i;
float fDist;
int nRealSpellID = StringToInt(Get2DACache("feats", "SpellID",
StringToInt(Get2DACache("EpicSpells", "SpellFeatID", nSpellID))));
switch(nSpellID)
{
//personal spells always target self
case SPELL_EPIC_ACHHEEL:
case SPELL_EPIC_ALLHOPE:
case SPELL_EPIC_ANARCHY:
case SPELL_EPIC_ARMY_UN:
case SPELL_EPIC_BATTLEB:
case SPELL_EPIC_CELCOUN:
case SPELL_EPIC_DIREWIN:
case SPELL_EPIC_DREAMSC:
case SPELL_EPIC_EP_WARD:
case SPELL_EPIC_FIEND_W:
case SPELL_EPIC_GR_TIME:
case SPELL_EPIC_HELSEND:
case SPELL_EPIC_LEG_ART:
case SPELL_EPIC_ORDER_R:
case SPELL_EPIC_PATHS_B:
case SPELL_EPIC_PEERPEN:
case SPELL_EPIC_PESTIL:
case SPELL_EPIC_PIOUS_P:
case SPELL_EPIC_RAINFIR:
case SPELL_EPIC_RISEN_R:
case SPELL_EPIC_WHIP_SH:
return OBJECT_SELF;
break;
//summons target nearest enemy, or self if enemies over short range
case SPELL_EPIC_UNHOLYD:
case SPELL_EPIC_SUMABER:
case SPELL_EPIC_TWINF:
case SPELL_EPIC_MUMDUST:
case SPELL_EPIC_DRG_KNI:
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
if(GetDistanceToObject(oTarget) > RADIUS_SIZE_SMALL)//assuming radius size is the same as range
return OBJECT_SELF;
else
return oTarget;
break;
//touchbuffs target self, or nearest ally without the effect
//maximum 5m distance, dont want to wander too far
//will separate those best cast on others laters
case SPELL_EPIC_HERCALL:
case SPELL_EPIC_CHAMP_V:
case SPELL_EPIC_DEADEYE:
case SPELL_EPIC_DULBLAD:
case SPELL_EPIC_EP_M_AR:
case SPELL_EPIC_EP_RPLS:
case SPELL_EPIC_EP_SP_R:
case SPELL_EPIC_ET_FREE:
case SPELL_EPIC_FLEETNS:
case SPELL_EPIC_GR_SP_RE:
case SPELL_EPIC_HERCEMP:
case SPELL_EPIC_IMPENET:
case SPELL_EPIC_TRANVIT:
case SPELL_EPIC_UNIMPIN:
case SPELL_EPIC_UNSEENW:
case SPELL_EPIC_CON_RES:
fDist = 5.0;
if(!GetHasSpellEffect(nRealSpellID))
return OBJECT_SELF;
else
{
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,OBJECT_SELF, i);
while(!GetHasSpellEffect(nRealSpellID, oTarget)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
}
break;
case SPELL_EPIC_AL_MART:
fDist = 5.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,OBJECT_SELF, i);
while(!GetHasSpellEffect(nRealSpellID, oTarget)
&& GetCurrentHitPoints(oTarget) > GetCurrentHitPoints(OBJECT_SELF)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
{
oTest = GetLocalObject(OBJECT_SELF, "oAILastMart");
if(GetIsObjectValid(oTest)
&& !GetIsDead(oTest)
&& GetCurrentHitPoints(oTest) > GetMaxHitPoints(oTest)/10)
return OBJECT_INVALID;
return oTarget;
}
break;
//hostile spells
//area effect descriminants
case SPELL_EPIC_ANBLAST:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetCurrentHitPoints(oTarget) > 35
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
case SPELL_EPIC_ANBLIZZ:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetCurrentHitPoints(oTarget) > 70
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
case SPELL_EPIC_A_STONE:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetFortitudeSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
case SPELL_EPIC_MASSPEN:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetFortitudeSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
//singe target
case SPELL_EPIC_ENSLAVE:
fDist = 80.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
case SPELL_EPIC_NAILSKY:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
case SPELL_EPIC_GR_RUIN:
case SPELL_EPIC_RUINN:
case SPELL_EPIC_DTHMARK:
case SPELL_EPIC_GODSMIT:
case SPELL_EPIC_SINGSUN:
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
return oTarget;
break;
//area effect indescriminants
case SPELL_EPIC_HELBALL:
case SPELL_EPIC_MAGMA_B:
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
return oTarget;
break;
case SPELL_EPIC_LEECH_F:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID)
&& GetDistanceToObject(oTarget) < fDist
&& GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
//check to not target those immune to insta-death
case SPELL_EPIC_TOLO_KW:
fDist = 40.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetIsImmune(oTarget,IMMUNITY_TYPE_DEATH)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
case SPELL_EPIC_MORI:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetIsImmune(oTarget,IMMUNITY_TYPE_DEATH)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) >= fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
break;
//check to not target those immune to ability lowering
case SPELL_EPIC_THEWITH:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetIsImmune(oTarget,IMMUNITY_TYPE_ABILITY_DECREASE)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetFortitudeSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID))
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
//aslo willcheck
case SPELL_EPIC_PSION_S:
fDist = 20.0;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetIsImmune(oTarget,IMMUNITY_TYPE_ABILITY_DECREASE)
&& GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID))
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
break;
//target spellcasters
//just gets last spellcaster
//or those with classes in spellcasting
case SPELL_EPIC_DWEO_TH:
fDist = 20.0;
oTarget = GetLastSpellCaster();
if(GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetIsEnemy(oTarget))
return oTarget;
else
{
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetLevelByClass(CLASS_TYPE_CLERIC) ==0
&& GetLevelByClass(CLASS_TYPE_DRUID) ==0
&& GetLevelByClass(CLASS_TYPE_WIZARD) ==0
&& GetLevelByClass(CLASS_TYPE_SORCERER) ==0
&& GetDistanceToObject(oTarget) < fDist
&& i < 10)
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID; //no suitable targets
else
return oTarget;
}
break;
//target spellcasters
//just gets last spellcaster
//or those with classes in spellcasting
//also checks will fail will test
case SPELL_EPIC_SP_WORM:
fDist = 8.0;
oTarget = GetLastSpellCaster();
if(GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetIsEnemy(oTarget)
&& GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF) +
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID))
return oTarget;
else
{
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
while(GetLevelByClass(CLASS_TYPE_CLERIC) ==0
&& GetLevelByClass(CLASS_TYPE_DRUID) ==0
&& GetLevelByClass(CLASS_TYPE_WIZARD) ==0
&& GetLevelByClass(CLASS_TYPE_SORCERER) ==0
&& GetDistanceToObject(oTarget) < fDist
&& i < 10
&& GetWillSavingThrow(oTarget)+10 >
GetEpicSpellSaveDC(OBJECT_SELF, oTarget, nSpellID))
{
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY,OBJECT_SELF, i);
}
if(GetDistanceToObject(oTarget) > fDist
|| i >= 10)
return OBJECT_INVALID;
else
return oTarget; //no suitable targets
}
break;
}
return OBJECT_INVALID;
}
void DoEpicSpellcasterSpawn()
{
//checks for able to cast anything epic
if(!GetIsEpicSpellcaster(OBJECT_SELF))
return;
int nLevel = GetHitDice(OBJECT_SELF);
//give pseudoXP if not already given
if(!GetXP(OBJECT_SELF))
{
int nXP =(nLevel*(nLevel-1))*500;
nXP = nXP + FloatToInt(IntToFloat(nLevel)*1000.0*((IntToFloat(Random(51))+25.0)/100.0));
SetXP(OBJECT_SELF, nXP);
}
//fill slots
ReplenishSlots(OBJECT_SELF);
//TEMP
//This stuff gives them some Epic Spells for free
if(!GetCastableFeatCount(OBJECT_SELF))
{
int nSlots = GetEpicSpellSlotLimit(OBJECT_SELF)+3;
int i;
for(i=0;i<nSlots;i++)
{
GiveFeat(OBJECT_SELF, Random(71)+429);
}
}
//setup AI list
DelayCommand(1.0, ActionDoCommand(MakeEpicSpellsKnownAIList()));
}
void MakeEpicSpellsKnownAIList()
{
// DoDebug("Building EpicSpells Known list");
int nTemp;
int nHighestDC;
int nHighestDCID;
int j;
int i;
array_create(OBJECT_SELF, "AI_KnownEpicSpells");
//record what spells in an array
// array_create(OBJECT_SELF, "AI_KnownEpicSpells");
string sLabel = Get2DACache("epicspellseeds", "LABEL", i);
while(sLabel != "")
{
if(GetHasFeat(GetFeatForSpell(i)))
{
array_set_int(OBJECT_SELF, "AI_KnownEpicSpells",array_get_size(OBJECT_SELF, "AI_KnownEpicSpells") ,i);
}
i++;
sLabel = Get2DACache("epicspellseeds", "LABEL", i);
}
// DoDebug("Finished recording known spells");
//sort spells into descending DC order
//move starting point down list
for (j=0;j<array_get_size(OBJECT_SELF, "AI_KnownEpicSpells");j++)
{
//for each start get the first spells DC + position
nHighestDC = GetDCForSpell(array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",j));
nHighestDCID = j;
//check each spell lower on the list for higher DC
for (i=j;i<array_get_size(OBJECT_SELF, "AI_KnownEpicSpells");i++)
{
//if so, mark highest to that spell
if(GetDCForSpell(array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",i)) > nHighestDC)
{
nHighestDC = GetDCForSpell(array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",i));
nHighestDCID = i;
}
}
//once you have checked all spells lower, swap the top one with the highest DC
nTemp = array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",j);
array_set_int(OBJECT_SELF, "AI_KnownEpicSpells",j,array_get_int(OBJECT_SELF, "AI_KnownEpicSpells",nHighestDCID));
array_set_int(OBJECT_SELF, "AI_KnownEpicSpells",nHighestDCID, nTemp);
}
// DoDebug("Finished sorting known spells");
}
// Test main
//void main(){}