//////////////////////////////////////////////////////////////////////// // Astral Plane Heartbeat //////////////////////////////////////////////////////////////////////// #include "antistuck_h" int fnCountResidents() { // return how many NPCs in the area int nRet=0; int nC=1; object oCr=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,OBJECT_SELF,nC,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_NOT_PC); while(oCr!=OBJECT_INVALID) { // count nRet++; nC++; oCr=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,OBJECT_SELF,nC,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_NOT_PC); } // count return nRet; } // fnCountResidents() void fnMoveTo() { // move to point and despawn object oMe=OBJECT_SELF; object oDest=GetLocalObject(oMe,"oBDest"); float fDist=GetDistanceBetween(oMe,oDest); effect eVis=EffectVisualEffect(VFX_FNF_IMPLOSION); if (GetIsInCombat(oMe)!=TRUE) { // not fighting if (fDist<3.0) { // arrived ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oMe,3.0); DelayCommand(2.0,DestroyObject(oMe)); } // arrived else { // move AssignCommand(oMe,ASActionMoveToObject(oDest,FALSE,1.0)); } // move } // not fighting DelayCommand(10.0,fnMoveTo()); } // fnMoveTo() void fnDestroyContainer(object oContainer) { // empty items object oItem=GetFirstItemInInventory(oContainer); while(oItem!=OBJECT_INVALID) { DelayCommand(0.2,DestroyObject(oItem)); oItem=GetNextItemInInventory(oContainer); } DelayCommand(0.3,DestroyObject(oContainer)); } // fnDestroyContainer() object fnSpawn(string sRes,location lLoc,int nVis=VFX_FNF_SUMMON_MONSTER_1) { // create creature object oRet; effect eVis=EffectVisualEffect(nVis); ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eVis,lLoc,1.0); oRet=CreateObject(OBJECT_TYPE_CREATURE,sRes,lLoc,FALSE); return oRet; } // fnSpawn() void fnWander() { // wander object oMe=OBJECT_SELF; object oEnemy=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,oMe,1,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); int nR; if (GetIsInCombat(oMe)!=TRUE&&oEnemy==OBJECT_INVALID) { // wander oEnemy=GetNearestObject(OBJECT_TYPE_ITEM,oMe,1); if (oEnemy!=OBJECT_INVALID&&GetDistanceBetween(oEnemy,oMe)<20.0) { // cleanup item AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,ActionMoveToObject(oEnemy,TRUE,1.0)); AssignCommand(oMe,ActionDoCommand(fnDestroyContainer(oEnemy))); } // cleanup item else { // check for containers oEnemy=GetNearestObject(OBJECT_TYPE_PLACEABLE,oMe,1); if (oEnemy!=OBJECT_INVALID&&GetDistanceBetween(oEnemy,oMe)<20.0&&GetHasInventory(oEnemy)==TRUE) { // empty container AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,ActionMoveToObject(oEnemy,TRUE,1.0)); AssignCommand(oMe,ActionDoCommand(fnDestroyContainer(oEnemy))); } // empty container else { // move nR=d20(); oEnemy=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,nR); AssignCommand(oMe,ASActionMoveToObject(oEnemy,FALSE,1.0)); } // move }// check for containers } // wander DelayCommand(15.0,fnWander()); } // fnWander() void fnDestroy() { // destroy self object oMe=OBJECT_SELF; object oEnemy=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,oMe,1,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); effect eVis=EffectVisualEffect(VFX_FNF_IMPLOSION); if (GetIsInCombat(oMe)!=TRUE&&oEnemy==OBJECT_INVALID) { // Destroy Self ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eVis,GetLocation(oMe),3.0); DelayCommand(1.0,DestroyObject(oMe)); } // Destroy Self else { // wait a bit longer DelayCommand(20.0,fnDestroy()); } // wait a bit longer } // fnDestroy() void fnAssignBehavior(object oCreature,int nBehavior) { // start the behavior for the NPC creature // 1 = wander for 2 game hours // 2 = wander for 4 game hours // 3 = go to another spawn point and despawn // 4 = wander for 6 game hours object oDest; object oNear; int nR; float fDelay=HoursToSeconds(2); if (nBehavior==2) fDelay=HoursToSeconds(4); else if (nBehavior==4) fDelay=HoursToSeconds(6); if (nBehavior!=3) { // wander AssignCommand(oCreature,fnWander()); AssignCommand(oCreature,DelayCommand(fDelay,fnDestroy())); } // wander else { // move to destination oNear=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,oCreature,1); oDest=OBJECT_INVALID; if (oNear!=OBJECT_INVALID) { // see if has a destination oDest=GetLocalObject(oNear,"oBDest"); } // see if has a destination if (oDest==OBJECT_INVALID) { // find a destination oNear=GetNearestObject(OBJECT_TYPE_WAYPOINT,oCreature,1); nR=d6(); oDest=GetWaypointByTag("ASTRAL_SPAWN"+IntToString(nR)); if (oDest==oNear) { // pick another nR++; if (nR>6) nR=1; oDest=GetWaypointByTag("ASTRAL_SPAWN"+IntToString(nR)); } // pick another } // find a destination SetLocalObject(oCreature,"oBDest",oDest); AssignCommand(oCreature,fnMoveTo()); } // move to destination } // fnAssignBehavior() void fnResidents(object oMe) { // determine if need to spawn creatures and handle their behaviour object oArea=GetArea(oMe); object oMod=GetModule(); int nEvil=GetLocalInt(oMod,"nEvilPower"); int nR; int nC=fnCountResidents(); int nSP=d6(); object oCR; object oSpawnPoint=GetWaypointByTag("ASTRAL_SPAWN"+IntToString(nSP)); location lLoc=GetLocation(oSpawnPoint); string sRes; int nBehavior=d4(); //SendMessageToPC(GetFirstPC()," COUNT of ASTRAL CREATURES:"+IntToString(nC)); if (nC<8) { // spawn chance nR=d100(); //SendMessageToPC(GetFirstPC(),"Rolled a "+IntToString(nR)+" percentile."); if (nR<21) { // spawn nR=d100()+(nEvil/100); if (nR<34) { // Githyanki nR=d100(); if (nR<11) { // lone warlock oCR=fnSpawn("githyankiwarlock",lLoc); fnAssignBehavior(oCR,nBehavior); } // lone warlock else if (nR<21) { // lone gith oCR=fnSpawn("githyankigith",lLoc); fnAssignBehavior(oCR,nBehavior); } // lone gith else if (nR<95) { // company oCR=fnSpawn("githyankiwarrior",lLoc); fnAssignBehavior(oCR,3); oCR=fnSpawn("githyankiwarrior",lLoc); fnAssignBehavior(oCR,3); oCR=fnSpawn("githyankiwarrior",lLoc); fnAssignBehavior(oCR,3); oCR=fnSpawn("githyankiwarrior",lLoc); fnAssignBehavior(oCR,3); } // company else { // squad oCR=fnSpawn("githyankiwarrior",lLoc); fnAssignBehavior(oCR,3); oCR=CreateObject(OBJECT_TYPE_CREATURE,"githyankiwarrior",lLoc); fnAssignBehavior(oCR,3); oCR=CreateObject(OBJECT_TYPE_CREATURE,"githyankiwarrior",lLoc); fnAssignBehavior(oCR,3); oCR=CreateObject(OBJECT_TYPE_CREATURE,"githyankiwarrior",lLoc); fnAssignBehavior(oCR,3); oCR=CreateObject(OBJECT_TYPE_CREATURE,"githyankiwarlock",lLoc); fnAssignBehavior(oCR,3); oCR=CreateObject(OBJECT_TYPE_CREATURE,"githyankigith",lLoc); fnAssignBehavior(oCR,3); } // squad } // Githyanki else if (nR<60) { // Deva nR=d100(); if (nR<34) { // Movanic oCR=fnSpawn("movanicdeva",lLoc,VFX_FNF_SUMMON_MONSTER_2); fnAssignBehavior(oCR,nBehavior); } // Movanic else if (nR<67) { // Monadic oCR=fnSpawn("monadicdeva",lLoc,VFX_FNF_SUMMON_MONSTER_2); fnAssignBehavior(oCR,nBehavior); } // Monadic else if (nR<91) { // Astral oCR=fnSpawn("astraldeva",lLoc,VFX_FNF_SUMMON_MONSTER_3); fnAssignBehavior(oCR,nBehavior); } // Astral else if (nR<99) { // Planetar oCR=fnSpawn("planetar",lLoc,VFX_FNF_SUMMON_CELESTIAL); fnAssignBehavior(oCR,nBehavior); } // Planetar else { // solar oCR=fnSpawn("solar",lLoc,VFX_FNF_SUMMON_CELESTIAL); fnAssignBehavior(oCR,nBehavior); } // solar } // Deva else if (nR<75) { // elementals nR=d100(); if (nR<34) { // fire nR=d100(); if (nR<21) sRes="fire001"; else if (nR<91) sRes="firehuge001"; else { sRes="fireelder001"; } nR=VFX_IMP_FLAME_M; } // fire else if (nR<67) { // earth nR=d100(); if (nR<21) sRes="earth001"; else if (nR<91) sRes="earthhuge001"; else { sRes="eartheld001"; } nR=VFX_IMP_BREACH; } // earth else { // air nR=d100(); if (nR<21) sRes="air001"; else if (nR<91) sRes="airhuge001"; else { sRes="airelder001"; } nR=VFX_IMP_LIGHTNING_M; } // air oCR=fnSpawn(sRes,lLoc,nR); fnAssignBehavior(oCR,nBehavior); } // elementals else if (nR<85) { // miscellaneous nR=d100(); if (nR<34) { // passing through oCR=fnSpawn("azer002",lLoc,VFX_IMP_FLAME_M); fnAssignBehavior(oCR,3); oCR=CreateObject(OBJECT_TYPE_CREATURE,"azer002",lLoc); fnAssignBehavior(oCR,3); oCR=CreateObject(OBJECT_TYPE_CREATURE,"azer003",lLoc); fnAssignBehavior(oCR,3); oCR=CreateObject(OBJECT_TYPE_CREATURE,"azer003",lLoc); fnAssignBehavior(oCR,3); } // passing through else { // other nR=d100(); if (nR<8) { nR=VFX_FNF_SUMMON_MONSTER_2; sRes="nighthag"; } else if (nR<20) { nR=VFX_FNF_SUMMON_MONSTER_2; sRes="rakshasa001"; } else if (nR<30) { nR=VFX_FNF_SUMMON_MONSTER_1; sRes="dmquasit001"; } else if (nR<40) { nR=VFX_FNF_SUMMON_MONSTER_1; sRes="imp001"; } else if (nR<50) { nR=VFX_FNF_SUMMON_MONSTER_2; sRes="drider002"; } else if (nR==50) { nR=VFX_FNF_SUMMONDRAGON; sRes="dragonpris002"; } else if (nR==51) { nR=VFX_FNF_UNDEAD_DRAGON; sRes="dracolich002"; } else if (nR==52) { nR=VFX_FNF_SUMMON_EPIC_UNDEAD; sRes="lich002"; } else if (nR==53) { nR=VFX_FNF_SUMMON_UNDEAD; sRes="demilich003"; } else { // Slaad nR=d100(); if (nR<34) sRes="slaadred001"; else if (nR<51) sRes="slaadbl001"; else if (nR<76) sRes="slaadgrn001"; else if (nR<88) sRes="slaadgray001"; else if (nR<95) sRes="slaaddeth001"; else if (nR<99) sRes="slaadwhite002"; else { sRes="slaadblack002"; } nR=VFX_FNF_SUMMON_MONSTER_3; } // slaad oCR=fnSpawn(sRes,lLoc,nR); fnAssignBehavior(oCR,nBehavior); } // other } // miscellaneous else { // fiends nR=d100(); if (nR<50) { // least nR=d100(); if (nR<51) sRes="erinyes001"; else { sRes="dmsucubus001"; } } // least else if (nR<70) { // lesser nR=d100(); if (nR<51) sRes="maurezhi"; else { sRes="dmvrock001"; } } // lesser else if (nR<80) { // mid nR=d100(); if (nR<51) sRes="devil002"; else { sRes="demon001"; } } // mid else if (nR<99) { // upper nR=d100(); if (nR<51) sRes="devil003"; else { sRes="balorboss001"; } } // upper else { // greatest sRes="demonlord"; } // greatest oCR=fnSpawn(sRes,lLoc,VFX_FNF_SUMMON_GATE); fnAssignBehavior(oCR,nBehavior); } // fiends //SendMessageToPC(GetFirstPC(),"A "+GetName(oCR)+" should have spawned at "+GetName(oSpawnPoint)+"."); } // spawn } // spawn chance } // fnResidents() void fnVisualEffects(object oMe) { // do Astral plane visual effects effect eVis1=EffectVisualEffect(VFX_IMP_TORNADO); effect eVis2=EffectVisualEffect(VFX_FNF_SMOKE_PUFF); effect eVis3=EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_ACID); effect eVis4=EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_EVIL); effect eVis5=EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_NATURE); effect eVis6=EffectVisualEffect(VFX_FNF_ELECTRIC_EXPLOSION); int nC=1; int nR; int nX; int nY; int nZ; vector vVec; location lLoc; object oArea=GetArea(oMe); while(nC<9) { // play visual effects nX=Random(16)*10; nY=Random(16)*10; nZ=Random(4)*6; vVec=Vector(IntToFloat(nX),IntToFloat(nY),IntToFloat(nZ)); lLoc=Location(oArea,vVec,0.0); nR=d20(); if (nR<3) ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY,eVis1,lLoc,6.0); else if (nR<8) ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eVis2,lLoc,3.0); else if (nR<12) ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eVis3,lLoc,3.0); else if (nR<15) ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eVis4,lLoc,3.0); else if (nR<18) ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eVis5,lLoc,3.0); else { ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eVis6,lLoc,3.0); } nC++; } // play visual effects } // fnResidents() void main() { object oMe=OBJECT_SELF; object oPC=GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oMe,1); if (oPC!=OBJECT_INVALID) { // PCs present SendMessageToPC(oPC,"You are wandering through the astral plane."); fnResidents(oMe); fnVisualEffects(oMe); } // PCs present ExecuteScript("area_hb_clean",oMe); }