Alangara_PRC8/_module/nss/zep_inc_demi.nss
Jaysyn904 86feb9ca6f Initial commit
Initial commit.
2024-06-05 21:21:06 -04:00

296 lines
12 KiB
Plaintext

//::///////////////////////////////////////////////
//:: Demilich constants, includes, and scripts for
//:: use with CEP adaptation of Demigog's demilich.
//::///////////////////////////////////////////////
//::--------------------------------------------------------------
//:: Begin Demilich Constants and functions added by Loki Hakanin
//::--------------------------------------------------------------
#include "zep_inc_scrptdlg"
//First is RESREF of demilich skull placable to be created
//when the demilich goes into resting mode.
const string ZEP_DEMI_SKULL_RESREF = "zep_demi_skull";
//Second is RESREF of matching dust plume.
const string ZEP_DEMI_DUST_RESREF = "zep_demi_dust";
//Also have matching TAGs for the above two:
const string ZEP_DEMI_SKULL_TAG = "zep_demi_skull";
const string ZEP_DEMI_DUST_TAG = "zep_demi_dust";
//Following sets the save DC of the demilich's attempt to
//slay arcane spellcaters and trap their souls.
const int DEMILICH_SOUL_EAT_SAVE_DC = 15;
//Following sets the maximum number of soulgem victims the
//demilich will take on at a time. Recommend this not be
//set higher than 8 or so, since LocalObject varibles are
//used to keep track of the victims.
const int DEMILICH_NUM_SOULGEMS = 8;
//Sets the minimum level an arcane caster must be in order
//for the demilich to attampt to pull out their soul upon
//a spell being cast at it.
const int DEMILICH_POWER_THRESHOLD = 15;
//Last we have the new tag which the demliich will use to
//differentiate a regenerating demilich from a normal one.
const string ZEP_DEMI_REGEN_SKULL = "zep_demi_skull_regen";
//Time, in seconds, for Demilich to regenerate from battle
//injuries. Defaults to 5 minutes. Note that PCs must use
//Holy Water on the demilich's bones in the span of that
//time in order to destroy it once and for all.
const int ZEP_DEMI_REGEN_TIME = 300;
//Messages Displayed over head of victims of soul-geming just
//before they are killed again by the Demilich's heartbeat
//script.
//Note that messages are concatenated with the name of the
//slain creature for a personalized effect.
string ZEP_DEMI_RESLAY_MSG = GetStringByStrRef(nZEPCantBeRaised ,GENDER_MALE);
//" jerks upright and spasms for a few moments before collapsing again.";
string ZEP_DEMI_RESLAY_MSG2 = GetStringByStrRef(nZEPNoRaiseExplan ,GENDER_MALE);
//"Until the demilich's captive souls are freed, its victims cannot be raised.";
//Next float variable defines the demilich's perception range,
//while resting or regenerating, in meters.
const float ZEP_DEMI_PERC_RANGE = 5.0;
//Following messages are used for demilich's respawn scripts.
//First displayed by a just-respawned demilich that was
//regenerating.
//Latter displayed by a disturbed demilich that is responding
//to intruders.
string ZEP_DEMI_REGEN_MSG = GetStringByStrRef(nZEPDemiRestored,GENDER_MALE);
//"At last, I am restored...";
string ZEP_DEMI_DIST_MSG = GetStringByStrRef(nZEPDemiDisturbed ,GENDER_MALE);
//"You disturb my work!";
//Following is message spoken in Demilich's OnSpellCastAt
//script if he's hit by a spell from a high level caster
string ZEP_DEMI_ONSPELL_MSG = GetStringByStrRef(nZEPDemiHavePower ,GENDER_MALE);
//"Yes, I sense you have power...your potential shall be mine!";
//Following defines RESREF and TAG of item that is needed
//to destroy a regenerating demilich.
const string ZEP_DEMI_DEST_RESREF = "zep_holy_water";
const string ZEP_DEMI_DEST_TAG = "zep_holy_water";
//Following is name of conversation to start if someone uses
//the demilich's bone pile. First is for a default bone pile
//and second is for a regenerating bone pile that has already
//been defeated once.
const string ZEP_DEMI_ONUSE_CONV = "zep_demi_bones";
const string ZEP_DEMI_ONUSE_REGEN = "zep_demi_regen_c";
//Following string is floating text displayed over the
//demilich upon it's final destruction.
string ZEP_DEMI_FINAL_DEST = GetStringByStrRef(nZEPDemiVictFree ,GENDER_MALE);
//"With the demilich destroyed, the souls of its victims are released to their bodies.";
//Following flag sets whether to automatically resurrect
//victims of soul-gem entrappment upon the demilich's
//destruction.
const int ZEP_DEMI_RESS_VICTIMS = FALSE;
//::-------------------------------------------------
//:: Begin Demilich Functions added by Loki Hakanin
//::-------------------------------------------------
//Function will spawn appropriate bones and dust plume
//for demilich. Will also copy over variables associated
//with any soultrapped victims, and change tag to flag bone
//pile as regenerating as necessary.
// Arguments:
// object oDemilichToReplace = The demilich that we're going
// to despawn
// int nWasDestroyed = Are we replacing the demilich with a
// rest-mode bone pile (FALSE), or a
// regenerating bone pile (TRUE)?
void ZEPDemilichSpawnBones(object oDemilichToReplace,int nWasDestroyed);
void ZEPDemilichSpawnBones(object oDemilichToReplace,int nWasDestroyed)
{
//So we'll first get the Demilich's location, and then create
//a pair of the usual demilich placables there. However,
//if the demilich is regenerating from wounds, we'll change
//the tag of the skull pile to the ZEP_DEMI_REGEN_SKULL
//constant value.
//The scripts on the skull will use this tag to determine
//if it is a fresh (i.e. undestroyed) demilich, or a crippled,
//regenerating one.
//We will also copy over the NumSouls local variable and the
//set of LocalObjects pointing to the Demlich's set of soul-
//gem'em victims, if any.
location lDestroyedLocation = GetLocation(oDemilichToReplace);
object oSkullPile;
//If Demliich in question was destroyed, we create the skull
//pile with the variant tag defined above, allowing the
//skull pile to differentiate itself from a "healthy"
//demilich. This saves us a local variable.
if (nWasDestroyed)
oSkullPile=CreateObject(OBJECT_TYPE_PLACEABLE,ZEP_DEMI_SKULL_RESREF,lDestroyedLocation,FALSE,ZEP_DEMI_REGEN_SKULL);
else oSkullPile=CreateObject(OBJECT_TYPE_PLACEABLE,ZEP_DEMI_SKULL_RESREF,lDestroyedLocation,FALSE);
object oDustPlume=CreateObject(OBJECT_TYPE_PLACEABLE,ZEP_DEMI_DUST_RESREF,lDestroyedLocation,FALSE);
//Now for the copying. Loop through all GemVictim objects,
//based on NumSouls. Remember that GemVictim indexes start
//from 0 (like an array in many programming languages),
//though the Numsouls variable is a positive int.
int nCounter=0;
int nNumSouls=GetLocalInt(oDemilichToReplace,"NumSouls");
//SendMessageToAllDMs(("NumSouls(SpawnBones):"+(IntToString(nNumSouls))));
//Set NumSouls counter on skull pile
SetLocalInt(oSkullPile,"NumSouls",nNumSouls);
string sVictimCounterName="GemVictim";
object oVictimCounter;
for (nCounter=0; nCounter < nNumSouls; nCounter++)
{
//Get object variable name, then set a variable on the
//skull pile with the same name, pointing to same
//object.
//Note we don't delete the local objects of the Demlich
//here as they will be cleaned up upon the final destruction
//of the demilich, which always follows this function's call.
sVictimCounterName=("GemVictim"+(IntToString(nCounter)));
oVictimCounter=GetLocalObject(oDemilichToReplace,sVictimCounterName);
// if (oVictimCounter==OBJECT_INVALID)
// SendMessageToAllDMs(("VictimCount("+(IntToString(nCounter))+") invalid."));
SetLocalObject(oSkullPile,sVictimCounterName,oVictimCounter);
}
}
//Function will play some dazed effects for a second,
//display some text explaining that the resurrection spell
//fails due to the demilich having oCreatureToSlay's soul,
//and then re-kills them.
void ZEPDemilichReSlay(object oCreatureToSlay);
void ZEPDemilichReSlay(object oCreatureToSlay)
{
//We'll get the name of our victim and concatenate it with
//our first message. This personalizes things a bit.
string sVictimName=GetName(oCreatureToSlay);
AssignCommand(oCreatureToSlay,ClearAllActions());
//Play spasm animation:
AssignCommand(oCreatureToSlay,ActionPlayAnimation(ANIMATION_FIREFORGET_SPASM));
//At the same time, display a descriptive string about the
//creature's state.
FloatingTextStringOnCreature((sVictimName+ZEP_DEMI_RESLAY_MSG),oCreatureToSlay,FALSE);
//Kill the creature again.
ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectDeath(FALSE),oCreatureToSlay);
//Further descriptive string.
DelayCommand(6.0,FloatingTextStringOnCreature(ZEP_DEMI_RESLAY_MSG2,oCreatureToSlay,FALSE));
}
//Function will kill all soulgem victims of the Demilich again
//if they have been raised, playing some appriopriate animations
//and VFX, and displaying some text.
//Essentially, we'll check against the NumSouls variable
//on our demilich, and then cycle through all GemVictim
//local objects, running a function to display effects and
//kill them as necessary.
void ZEPDemilichReSlaySoulGemVictims(object oDemilich);
void ZEPDemilichReSlaySoulGemVictims(object oDemilich)
{
int nCounter=0; //Counter for variable names
int nNumSouls=GetLocalInt(oDemilich,"NumSouls"); //Number of consumed souls
string sVictimCounterName; //Used with nCounter to create proper local variable name
object oVictimCounter; //Counter for actual objects pointed to by demilich's victim list.
//Don't forget, Counter (i.e., the "GemVictim" variable
//name index) starts from 0, like an array index.
//But nNumSouls is a positive int, so this for loop should be
//logically consistent.
for (nCounter=0; nCounter < nNumSouls; nCounter++)
{
sVictimCounterName=("GemVictim"+(IntToString(nCounter)));
oVictimCounter=GetLocalObject(oDemilich,sVictimCounterName);
//If the victim has more than 0 HPs... (i.e. is alive)
//we'll kill them again, with explanatory text.
if (GetCurrentHitPoints(oVictimCounter) > 0)
ZEPDemilichReSlay(oVictimCounter);
}
}
//Following function spawns a demilich from the bones
//that it left behind, either when resting or regenerating.
//Note that the soulgem victim list is copied over, and
//therefore preserved.
//Arguments:
// oSourceBones- the bone placable that relevant variables
// will be copied over from.
// nDestroyBones- destroy object oSourceBones upon completion
// of the function...TRUE= destroy it, FALSE = do nothing.
object ZEPDemilichFromBones(object oSourceBones, int nDestroyBones);
object ZEPDemilichFromBones(object oSourceBones, int nDestroyBones)
{
//First we create the Demilich.
object oReturnDemilich=CreateObject(OBJECT_TYPE_CREATURE,"zep_demi_lich",GetLocation(oSourceBones));
//Now we'll use a loop to copy over the soulgem victim list.
int nNumSouls = GetLocalInt(oSourceBones,"NumSouls");
int nCounter=0;
string sVarNameCounter;
object oVictimCounter;
//For loop will use int counter, concatenated with "GemVictim"
//to generate correct variable names. Will then retrieve
//these variables from the oSourceBones object and copy
//them over to our new Demilich.
for (nCounter=0; nCounter < nNumSouls; nCounter++)
{
sVarNameCounter = ("GemVictim"+IntToString(nCounter));
oVictimCounter = GetLocalObject(oSourceBones,sVarNameCounter);
SetLocalObject(oReturnDemilich,sVarNameCounter,oVictimCounter);
}
//Now we set the "NumSouls" counter on our newsly-spawned
//Demilich.
SetLocalInt(oReturnDemilich,"NumSouls",nNumSouls);
//Now, we're going to compare our bone pile's resref against
//the regenerating resref. If it's the same, we display the
//regeneration message (defined above).
//Else we play the default "disturbed" message, since this
//function is called in two ways...a regenerating demilich
//or a disturbed Demilich.
string sBonePileTag=GetTag(oSourceBones);
if (sBonePileTag == ZEP_DEMI_REGEN_SKULL)
{
AssignCommand(oReturnDemilich,ActionSpeakString(ZEP_DEMI_REGEN_MSG,TALKVOLUME_SHOUT));
FloatingTextStringOnCreature(ZEP_DEMI_REGEN_MSG,oReturnDemilich);
}
else
{
AssignCommand(oReturnDemilich,ActionSpeakString(ZEP_DEMI_DIST_MSG,TALKVOLUME_SHOUT));
FloatingTextStringOnCreature(ZEP_DEMI_DIST_MSG,oReturnDemilich);
}
//Last, if the user has specified that we should destroy the
//bones and dust plume, we do so.
if (nDestroyBones == TRUE)
{
object oDustPlume=GetNearestObjectByTag(ZEP_DEMI_DUST_TAG);
// if (oDustPlume==OBJECT_INVALID)
// SendMessageToAllDMs("Bad Dust plume!");
DestroyObject(oDustPlume);
DestroyObject(oSourceBones);
}
return oReturnDemilich;
}
//:: ---------------------------------------
//:: End Demilich functions and constants
//:: ---------------------------------------