Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
360 lines
12 KiB
Plaintext
360 lines
12 KiB
Plaintext
/*:://////////////////////////////////////////////
|
|
//:: Spell Name Status
|
|
//:: Spell FileName PHS_S_Status
|
|
//:://////////////////////////////////////////////
|
|
//:: In Game Spell desctiption
|
|
//:://////////////////////////////////////////////
|
|
Divination
|
|
Level: Clr 2
|
|
Components: V, S
|
|
Casting Time: 1 standard action
|
|
Range: Touch
|
|
Targets: One living party member per three levels within 10M (30ft)
|
|
Duration: 1 hour/level
|
|
Saving Throw: Will negates (harmless)
|
|
Spell Resistance: Yes (harmless)
|
|
|
|
When you need to keep track of comrades who may get separated, status allows
|
|
you to mentally monitor their relative positions and general condition. You
|
|
are aware of direction and distance to the creatures and any conditions
|
|
affecting them: unharmed, wounded, disabled, staggered, unconscious, dying,
|
|
nauseated, panicked, stunned, poisoned, diseased, confused, or the like.
|
|
Once the spell has been cast upon the subjects, the distance between them
|
|
and the caster does not affect the spell as long as they are on the same
|
|
plane of existence. If a subject leaves the plane, or if it dies, the spell
|
|
ceases to function for it. The spell reports the status of allies once
|
|
every 15 seconds.
|
|
//:://////////////////////////////////////////////
|
|
//:: Spell Effects Applied / Notes
|
|
//:://////////////////////////////////////////////
|
|
Puts the effects on each party member within 10M (up to 1 per 3 caster
|
|
levels) and then does a 15 second delayed check on party members for the
|
|
spells effect. If it is cast again, the originals are lost.
|
|
|
|
Anyone who dies (and thusly will lose the good visual effect on them) or
|
|
gets it dispelled, will be ignored and removed from the array.
|
|
|
|
Anyone in another plane (explicitly Maze and so on) will be removed from the
|
|
array and the spell effect removed.
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Jasperre
|
|
//::////////////////////////////////////////////*/
|
|
|
|
#include "PHS_INC_SPELLS"
|
|
|
|
const string ARRAY_NAME = "PHS_STATUS_ARRAY";
|
|
|
|
// You are aware of direction and distance to the creatures and any conditions
|
|
// affecting them: unharmed, wounded, disabled, staggered, unconscious, dying,
|
|
// nauseated, panicked, stunned, poisoned, diseased, confused, or the like.
|
|
struct StatusOfPerson
|
|
{
|
|
// Status'
|
|
int Poison;
|
|
int Panicked;
|
|
int Stunned;
|
|
int Diseased;
|
|
int Confused;
|
|
int Paralyzed;
|
|
int Stone;
|
|
int Cursed;
|
|
int Deaf;
|
|
int Blind;
|
|
// Wounds
|
|
int Unharmed;
|
|
int Wounded;
|
|
int Dying;
|
|
int Dead;
|
|
};
|
|
|
|
// Runs a check for the caster so they know what is going on for thier allies.
|
|
void StatusCheck(object oCaster, int nTimesCast);
|
|
|
|
// Do status check for the members of oCaster's party, using bPCOnly to check the
|
|
// correct stuff in GetFirstFactionMember(), thusly called twice.
|
|
void StatusOfParty(object oCaster, int bPCOnly);
|
|
|
|
// Gets the status of oPerson with integers returned.
|
|
struct StatusOfPerson GetStatusOfPerson(object oCreature);
|
|
|
|
void main()
|
|
{
|
|
// Spell hook check.
|
|
if(PHS_SpellHookCheck(PHS_SPELL_STATUS)) return;
|
|
|
|
// Define ourselves.
|
|
object oCaster = OBJECT_SELF;
|
|
object oTarget;
|
|
location lSelf = GetLocation(oCaster);
|
|
int nCasterLevel = PHS_GetCasterLevel();
|
|
int nMetaMagic = PHS_GetMetaMagicFeat();
|
|
float fDelay;
|
|
int nMaxTargets = PHS_LimitInteger(nCasterLevel/3);
|
|
int nCnt = 0;
|
|
|
|
// Duration - 1 hour/level
|
|
float fDuration = PHS_GetDuration(PHS_HOURS, nCasterLevel, nMetaMagic);
|
|
|
|
// Declare effects
|
|
effect eVis = EffectVisualEffect(VFX_IMP_HEAD_HOLY);
|
|
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
|
|
effect eCasterDur = EffectVisualEffect(VFX_DUR_MAGICAL_SIGHT);
|
|
|
|
// AOE visual applied.
|
|
effect eImpact = EffectVisualEffect(VFX_FNF_LOS_HOLY_30);
|
|
PHS_ApplyLocationVFX(lSelf, eImpact);
|
|
|
|
// Add one to times cast
|
|
int nTimesCast = PHS_IncreaseStoredInteger(oCaster, "PHS_STATUS_TIMES_CAST");
|
|
|
|
// Remove this spells effect from all party members
|
|
// * PC's then NPC's.
|
|
PHS_RemoveSpellEffectsFromFactionCaster(PHS_SPELL_STATUS, oCaster, oCaster, TRUE);
|
|
PHS_RemoveSpellEffectsFromFactionCaster(PHS_SPELL_STATUS, oCaster, oCaster, FALSE);
|
|
|
|
// Loop allies - and apply the effects. AOE is 30ft, 10M
|
|
oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_FEET_30, lSelf);
|
|
while(GetIsObjectValid(oTarget) && nCnt < nMaxTargets)
|
|
{
|
|
// Only affects party members (and a special case for ourselves)
|
|
if((GetFactionEqual(oTarget, oCaster) || oTarget == oCaster) &&
|
|
// Make sure they are not immune to spells
|
|
!PHS_TotalSpellImmunity(oTarget))
|
|
{
|
|
// Fire cast spell at event for the specified target
|
|
PHS_SignalSpellCastAt(oTarget, PHS_SPELL_STATUS, FALSE);
|
|
|
|
// One more target done
|
|
nCnt++;
|
|
|
|
// Remove previous effects from this spell (of course, you cannot
|
|
// be in 2 parties at once! Sorts dispel problems mainly). Only
|
|
// remove spell effects from this caster!
|
|
PHS_RemoveSpellEffects(PHS_SPELL_STATUS, oCaster, oTarget);
|
|
|
|
// Check if us
|
|
if(oTarget == oCaster)
|
|
{
|
|
// Apply visual effect to us, a special one.
|
|
PHS_ApplyDuration(oTarget, eCasterDur, fDuration);
|
|
}
|
|
else
|
|
{
|
|
// Delay for visuals and effects.
|
|
fDelay = GetDistanceBetween(oCaster, oTarget)/20;
|
|
|
|
// Apply normal cessate to track oTarget.
|
|
DelayCommand(fDelay, PHS_ApplyVFX(oTarget, eVis));
|
|
PHS_ApplyDuration(oTarget, eDur, fDuration);
|
|
}
|
|
}
|
|
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_FEET_30, lSelf);
|
|
}
|
|
// Do first 15 second heartbeat
|
|
StatusCheck(oCaster, nTimesCast);
|
|
}
|
|
|
|
// Runs a check for the caster so they know what is going on for thier allies.
|
|
void StatusCheck(object oCaster, int nTimesCast)
|
|
{
|
|
// Make sure we don't stop
|
|
if(!GetIsObjectValid(oCaster) ||
|
|
!GetHasSpellEffect(PHS_SPELL_STATUS, oCaster) ||
|
|
GetLocalInt(oCaster, "PHS_STATUS_TIMES_CAST") != nTimesCast ||
|
|
GetIsDead(oCaster))
|
|
{
|
|
PHS_RemoveSpellEffects(PHS_SPELL_STATUS, oCaster, oCaster);
|
|
// Stop
|
|
return;
|
|
}
|
|
|
|
// We check for the spell effect on party members (NPC and PC!) in any area
|
|
// apart from different planes.
|
|
SendMessageToPC(oCaster, "Status Check:");
|
|
|
|
// PC's status'
|
|
StatusOfParty(oCaster, TRUE);
|
|
// NPC's status'
|
|
StatusOfParty(oCaster, FALSE);
|
|
|
|
// Delay another check
|
|
DelayCommand(15.0, StatusCheck(oCaster, nTimesCast));
|
|
}
|
|
|
|
// Do status check for the members of oCaster's party, using bPCOnly to check the
|
|
// correct stuff in GetFirstFactionMember(), thusly called twice.
|
|
void StatusOfParty(object oCaster, int bPCOnly)
|
|
{
|
|
// Declare stuff
|
|
string sAffictions = "";
|
|
struct StatusOfPerson Status;
|
|
int nSize;
|
|
|
|
// Get first party member
|
|
object oParty = GetFirstFactionMember(oCaster, bPCOnly);
|
|
while(GetIsObjectValid(oParty))
|
|
{
|
|
// Got the spells effects from oCaster?
|
|
if(PHS_GetHasSpellEffectFromCaster(PHS_SPELL_STATUS, oParty, oCaster) &&
|
|
!GetIsDead(oParty))
|
|
{
|
|
// If not in our plane, remove the status visuals
|
|
if(!PHS_CheckIfSamePlane(GetLocation(oCaster), GetLocation(oParty)))
|
|
{
|
|
// Remove the spells effects
|
|
PHS_RemoveSpellEffects(PHS_SPELL_STATUS, oCaster, oParty);
|
|
}
|
|
else
|
|
{
|
|
// Add on what stuff oParty has
|
|
Status = GetStatusOfPerson(oParty);
|
|
|
|
// Check if dead
|
|
|
|
// Sort out sAffictions total.
|
|
sAffictions = "Status of " + GetName(oParty) + " is that they are: ";
|
|
nSize = GetStringLength(sAffictions);
|
|
|
|
// Add them all as we see them
|
|
if(Status.Poison == TRUE)
|
|
{
|
|
sAffictions += "poisoned, ";
|
|
}
|
|
if(Status.Panicked == TRUE)
|
|
{
|
|
sAffictions += "panicked, ";
|
|
}
|
|
if(Status.Stunned == TRUE)
|
|
{
|
|
sAffictions += "stunned, ";
|
|
}
|
|
if(Status.Confused == TRUE)
|
|
{
|
|
sAffictions += "confused, ";
|
|
}
|
|
if(Status.Paralyzed == TRUE)
|
|
{
|
|
sAffictions += "paralyzed, ";
|
|
}
|
|
if(Status.Stone == TRUE)
|
|
{
|
|
sAffictions += "turned to stone, ";
|
|
}
|
|
if(Status.Cursed == TRUE)
|
|
{
|
|
sAffictions += "cursed, ";
|
|
}
|
|
if(Status.Deaf == TRUE)
|
|
{
|
|
sAffictions += "deaf, ";
|
|
}
|
|
if(Status.Blind == TRUE)
|
|
{
|
|
sAffictions += "blind, ";
|
|
}
|
|
// If we havn't added anything, we don't add "and ". However, if
|
|
// we have added anything to sAffictions, we add a "and " to make
|
|
// it look correct. EG:
|
|
// "Status of George is that they are: unharmed"
|
|
// "Status of George is that they are: blind, and wounded"
|
|
// "Status of George is that they are: turned to stone, cursed, and unharmed"
|
|
if(nSize != GetStringLength(sAffictions))
|
|
{
|
|
// Add "and"
|
|
sAffictions += "and ";
|
|
}
|
|
// Do wounded status
|
|
if(Status.Dying == TRUE)
|
|
{
|
|
sAffictions += "dying.";
|
|
}
|
|
else if(Status.Wounded == TRUE)
|
|
{
|
|
sAffictions += "wounded.";
|
|
}
|
|
// Must be unharmed!
|
|
else //if(Status.Unharmed == TRUE)
|
|
{
|
|
sAffictions += "unharmed.";
|
|
}
|
|
// Send message
|
|
SendMessageToPC(oCaster, sAffictions);
|
|
}
|
|
}
|
|
// Get next member
|
|
oParty = GetNextFactionMember(oCaster, bPCOnly);
|
|
}
|
|
}
|
|
|
|
// Gets the status of oPerson with integers returned.
|
|
struct StatusOfPerson GetStatusOfPerson(object oCreature)
|
|
{
|
|
// Return structure
|
|
struct StatusOfPerson Return;
|
|
|
|
// Loop effects
|
|
effect eCheck = GetFirstEffect(oCreature);
|
|
while(GetIsEffectValid(eCheck))
|
|
{
|
|
// Check type of effect
|
|
switch(GetEffectType(eCheck))
|
|
{
|
|
// Status'
|
|
case EFFECT_TYPE_POISON:
|
|
Return.Poison = TRUE;
|
|
break;
|
|
case EFFECT_TYPE_FRIGHTENED:
|
|
case EFFECT_TYPE_TURNED:
|
|
Return.Panicked = TRUE;
|
|
break;
|
|
case EFFECT_TYPE_STUNNED:
|
|
Return.Stunned = TRUE;
|
|
break;
|
|
case EFFECT_TYPE_DISEASE:
|
|
Return.Diseased = TRUE;
|
|
break;
|
|
case EFFECT_TYPE_CONFUSED:
|
|
Return.Confused = TRUE;
|
|
break;
|
|
case EFFECT_TYPE_PARALYZE:
|
|
Return.Paralyzed = TRUE;
|
|
break;
|
|
case EFFECT_TYPE_PETRIFY:
|
|
Return.Stone = TRUE;
|
|
break;
|
|
case EFFECT_TYPE_CURSE:
|
|
Return.Cursed = TRUE;
|
|
break;
|
|
case EFFECT_TYPE_DEAF:
|
|
Return.Deaf = TRUE;
|
|
break;
|
|
case EFFECT_TYPE_BLINDNESS:
|
|
Return.Blind = TRUE;
|
|
break;
|
|
}
|
|
eCheck = GetNextEffect(oCreature);
|
|
}
|
|
// Wounds
|
|
int nHP = GetCurrentHitPoints(oCreature);
|
|
int nMaxHP = GetMaxHitPoints(oCreature);
|
|
// Set variables
|
|
if(nHP >= nMaxHP)
|
|
{
|
|
Return.Unharmed = TRUE;
|
|
}
|
|
else if(nHP > 0)
|
|
{
|
|
Return.Wounded = TRUE;
|
|
}
|
|
else if(nHP > -10)
|
|
{
|
|
Return.Dying = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Return.Dead = TRUE;
|
|
}
|
|
// Return Return ( ;-) )
|
|
return Return;
|
|
}
|