PRC8/nwn/nwnprc/trunk/smp/smp_ail_fear.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

403 lines
16 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*:://////////////////////////////////////////////
//:: Name Fear Heartbeat
//:: FileName SMP_ail_fear
//:://////////////////////////////////////////////
This is the fear heartbeat, for PCs and NPCs, who have this effect on them:
// Create a Frighten effect
effect EffectFrightened()
Ok, lowdown:
- Fear can be applied multiple times from multiple spells
- It stops all movement dispite any SetCommandable's. Might work after a
short delay somehow.
- Can be commandable after the fear, whatever happens.
Description:
Shaken: A shaken character takes a -2 penalty on attack rolls, saving throws, skill
checks, and ability checks.
Shaken is a less severe state of fear than frightened or panicked.
Frightened: A frightened creature flees from the source of its fear as best it can.
If unable to flee, it may fight. A frightened creature takes a -2 penalty on all
attack rolls, saving throws, skill checks, and ability checks. A frightened
creature can use special abilities, including spells, to flee; indeed, the
creature must use such means if they are the only way to escape.
Frightened is like shaken, except that the creature must flee if possible.
Panicked is a more extreme state of fear.
Panicked: A panicked creature must drop anything it holds and flee at top speed
from the source of its fear, as well as any other dangers it encounters, along
a random path. It cant take any other actions. In addition, the creature takes
a -2 penalty on all saving throws, skill checks, and ability checks. If cornered,
a panicked creature cowers and does not attack, typically using the total
defense action in combat. A panicked creature can use special abilities,
including spells, to flee; indeed, the creature must use such means if they are
the only way to escape.
Panicked is a more extreme state of fear than shaken or frightened.
In NWN:
* 1 = Shaken: Characters who are shaken take a -2 penalty on attack rolls,
saving throws, skill checks, and ability checks.)
* 2 = Frightened: Characters who are frightened are shaken, and in addition
they flee from the source of their fear as quickly as they can. They
can choose the path of their flight. Other than that stipulation, once
they are out of sight (or hearing) of the source of their fear, they
can act as they want. However, if the duration of their fear continues,
characters can be forced to flee once more if the source of their fear
presents itself again. Characters unable to flee can fight (though they
are still shaken).
* 3 = Panicked: Characters who are panicked are shaken, and they run away
from the source of their fear as quickly as they can. Other than running
away from the source, their path is random. They flee from all other
dangers that confront them rather than facing those dangers. Panicked
characters cower if they are prevented from fleeing.
Note: SMP_SPELL_REMOVE_FEAR will surpress any effects!
//:://////////////////////////////////////////////
//:: Created By: Jasperre
//:: Created On: July+
//::////////////////////////////////////////////*/
#include "SMP_INC_AILMENT"
#include "SMP_INC_EFFECTS"
// Get the nearest valid creator of fear in the area.
// Must be seen or heard, else they are not a source of fear visible to us (we
// are unaware of them, so we can just do things normally)
object GetNearestPersonWhoCreatedFear(object oSelf);
// When panicked and need to cower, this does it.
void Cower(object oSelf);
const string SMP_FEAR_LAST_LOCATION = "SMP_FEAR_LAST_LOCATION";
const string SMP_LAST_FEAR = "SMP_LAST_FEAR";
const int SMP_FEAR_INVALID = 0;
const int SMP_FEAR_SHAKEN = 1;
const int SMP_FEAR_FRIGHTENED = 2;
const int SMP_FEAR_FRIGHTENED_OK = 3;
const int SMP_FEAR_COWER = 4;
const int SMP_FEAR_PANIC = 5;
void main()
{
// Allow the target to recieve commands for the round
SetCommandable(TRUE);
// Get self
object oSelf = OBJECT_SELF;
object oFear, oNearestFearer;
// We need to check Calm Emotions
// - If TRUE, surpress
if(SMP_AilmentCheckCalmEmotions())
{
SendMessageToPC(OBJECT_SELF, "Your calm emotions blocks fear.");
DelayCommand(0.0, SetCommandable(TRUE, oSelf));
return;
}
// Set/Get location now
location lLastLocation = GetLocalLocation(oSelf, SMP_FEAR_LAST_LOCATION);
location lOurLocation = GetLocation(oSelf);
SetLocalLocation(oSelf, SMP_FEAR_LAST_LOCATION, lOurLocation);
// If we are under the effects of SMP_SPELL_REMOVE_FEAR, this heartbeat
// fails.
if(GetHasSpellEffect(SMP_SPELL_REMOVE_FEAR, oSelf))
{
// We surpress our fear!
SendMessageToPC(oSelf, "You suppress your fear due to the effects of Remove Fear!");
DelayCommand(0.0, SetCommandable(TRUE, oSelf));
SetLocalInt(oSelf, SMP_LAST_FEAR, SMP_FEAR_INVALID);
return;
}
// Apply an amount of 6 second "Shaken"
effect eShaken = SMP_CreateShakenEffectsLink();
eShaken = ExtraordinaryEffect(eShaken);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShaken, oSelf, 6.0);
// Get fear number, 0-3.
effect eCheck = GetFirstEffect(oSelf);
int nSpellId, nFearAmount;
// Loop effects
while(GetIsEffectValid(eCheck))
{
// Check for stacked fear effects.
if(GetEffectType(eCheck) == EFFECT_TYPE_FRIGHTENED)
{
nSpellId = GetEffectSpellId(eCheck);
switch(nSpellId)
{
// Causes SHAKEN alone (1)
case SMP_SPELL_DOOM:
{
nFearAmount += 1;
}
break;
// Causes FRIGHTENED alone (2)
//case :
//{
// nFearAmount += 2;
//}
//break;
// Causes PANICKED alone (3)
case SMP_SPELL_CHILL_TOUCH:
case SMP_SPELL_SYMBOL_OF_FEAR:
{
nFearAmount += 3;
}
break;
// Special
// - Eyebite. Applies 1d4 rounds of panic (local int is 1)
// else will be just shaken.
case SMP_SPELL_EYEBITE:
{
if(GetLocalInt(oSelf, "SMP_SPELL_EYEBITE_FEAR") == 1)
{
nFearAmount += 3;
}
else
{
nFearAmount += 1;
}
}
break;
// - Fear. normally Panic. If local integer, it means the
// panic, else shaken.
case SMP_SPELL_FEAR:
{
if(GetLocalInt(oSelf, "SMP_SPELL_FEAR_FEAR") == 1)
{
// Normal panic
nFearAmount += 3;
}
else
{
// Mearly shaken
nFearAmount += 1;
}
}
break;
// Cause fear + scare - normally Frightned, but could be normal
// shaken.
case SMP_SPELL_CAUSE_FEAR:
{
if(GetLocalInt(oSelf, "SMP_SPELL_CAUSE_FEAR_FEAR") == 1)
{
// Normal fright
nFearAmount += 2;
}
else
{
// Mearly shaken
nFearAmount += 1;
}
}
break;
case SMP_SPELL_SCARE:
{
if(GetLocalInt(oSelf, "SMP_SPELL_SCARE_FEAR") == 1)
{
// Normal fright
nFearAmount += 2;
}
else
{
// Mearly shaken
nFearAmount += 1;
}
}
break;
// Anything created by anything else will be Frightened.
default:
{
nFearAmount += 2;
}
break;
}
}
eCheck = GetNextEffect(oSelf);
}
// Make sure it isn't over 3
if(nFearAmount > 3)
{
nFearAmount = 3;
}
// Ok, fear effects:
switch(nFearAmount)
{
// * 1 = Shaken: Characters who are shaken take a -2 penalty on attack rolls,
// saving throws, skill checks, and ability checks.)
case 1:
{
// We are only shaken. We should be able to revieve commands
SendMessageToPC(oSelf, "You are shaken, the panic implies penalities but there in no need to run.");
DelayCommand(0.0, SetCommandable(TRUE, oSelf));
SetLocalInt(oSelf, SMP_LAST_FEAR, SMP_FEAR_SHAKEN);
}
break;
// * 2 = Frightened: Characters who are frightened are shaken, and in addition
// they flee from the source of their fear as quickly as they can. They
// can choose the path of their flight. Other than that stipulation, once
// they are out of sight (or hearing) of the source of their fear, they
// can act as they want. However, if the duration of their fear continues,
// characters can be forced to flee once more if the source of their fear
// presents itself again. Characters unable to flee can fight (though they
// are still shaken).
case 2:
{
// Get the nearest person who created any of our fear effects
oNearestFearer = GetNearestPersonWhoCreatedFear(oSelf);
// If valid, we run from it
if(GetIsObjectValid(oNearestFearer))
{
// Were we frightened like this before?
if(GetLocalInt(oSelf, SMP_LAST_FEAR) == SMP_FEAR_FRIGHTENED)
{
if(VectorMagnitude(GetPositionFromLocation(lLastLocation) - GetPositionFromLocation(lOurLocation)) < 0.5)
{
// If we havn't been able to move more then 0.5M away from
// our previous location, we'll fight!
SendMessageToPC(oSelf, "You are frightened and cornored! Fight!");
DelayCommand(0.0, SetCommandable(TRUE, oSelf));
SetLocalInt(oSelf, SMP_LAST_FEAR, SMP_FEAR_FRIGHTENED_OK);
return;
}
}
// Want to add a flee move
SetCommandable(TRUE, oSelf);
// Move, and notify
ClearAllActions();
SendMessageToPC(oSelf, "You are frightened! You flee from " + GetName(oNearestFearer));
ActionMoveAwayFromObject(oNearestFearer, TRUE, 60.0);
// Unable to change this action
SetCommandable(FALSE, oSelf);
SetLocalInt(oSelf, SMP_LAST_FEAR, SMP_FEAR_FRIGHTENED);
}
else
{
SendMessageToPC(oSelf, "You are frightened, however, you do not seem to see the creature you fear and can do as you wish...");
DelayCommand(0.0, SetCommandable(TRUE, oSelf));
SetLocalInt(oSelf, SMP_LAST_FEAR, SMP_FEAR_FRIGHTENED_OK);
}
}
break;
// * 3 = Panicked: Characters who are panicked are shaken, and they run away
// from the source of their fear as quickly as they can. Other than running
// away from the source, their path is random. They flee from all other
// dangers that confront them rather than facing those dangers. Panicked
// characters cower if they are prevented from fleeing.
case 3:
{
// Get the nearest person who created any of our fear effects
oNearestFearer = GetNearestPersonWhoCreatedFear(oSelf);
// If valid, we run from it
if(!GetIsObjectValid(oNearestFearer))
{
// Get nearest enemy to run from
oNearestFearer = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, oSelf, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_IS_ALIVE, TRUE);
// No valid seen? try heard
if(!GetIsObjectValid(oNearestFearer))
{
// Nearest heard
oNearestFearer = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, oSelf, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_IS_ALIVE, TRUE);
}
}
// Not valid? urg..cower!
if(!GetIsObjectValid(oNearestFearer))
{
Cower(oSelf);
return;
}
else
{
// Were we frightened like this before?
if(GetLocalInt(oSelf, SMP_LAST_FEAR) == SMP_FEAR_PANIC)
{
if(VectorMagnitude(GetPositionFromLocation(lLastLocation) - GetPositionFromLocation(lOurLocation)) < 0.5)
{
// If we havn't been able to move more then 0.5M away from
// our previous location - cower
Cower(oSelf);
return;
}
}
// Want to move away
SetCommandable(TRUE, oSelf);
SendMessageToPC(oSelf, "You are panicked! You flee from " + GetName(oNearestFearer));
ActionMoveAwayFromObject(oNearestFearer, TRUE, 60.0);
// Unable to change this action
SetCommandable(FALSE, oSelf);
SetLocalInt(oSelf, SMP_LAST_FEAR, SMP_FEAR_PANIC);
}
}
break;
}
}
// Get the nearest valid creator of fear in the area.
// Must be seen or heard, else they are not a source of fear visible to us (we
// are unaware of them, so we can just do things normally)
object GetNearestPersonWhoCreatedFear(object oSelf)
{
// Get fear creators
effect eCheck = GetFirstEffect(oSelf);
object oCreator, oFearReturn;
object oArea = GetArea(oSelf);
float fLowestDistance = 300.0;
float fDistance;
// Loop effects
while(GetIsEffectValid(eCheck))
{
// Check for creators of fear
if(GetEffectType(eCheck) == EFFECT_TYPE_FRIGHTENED)
{
// Get the creator
oCreator = GetEffectCreator(eCheck);
// Check if valid, and same area, and they are seen or heard
if(GetIsObjectValid(oCreator) && GetArea(oCreator) == oArea &&
GetObjectType(oCreator) == OBJECT_TYPE_CREATURE &&
(GetObjectSeen(oCreator, oSelf) || GetObjectHeard(oCreator, oSelf)))
{
// Get distance to them
fDistance = GetDistanceBetween(oCreator, oSelf);
if(fDistance < fLowestDistance)
{
// Now this is the one we fear most
oFearReturn = oCreator;
fLowestDistance = fDistance;
}
}
}
}
return oFearReturn;
}
// When panicked and need to cower, this does it.
void Cower(object oSelf)
{
// Want to cower
SetCommandable(TRUE, oSelf);
// Cower, and notify
SendMessageToPC(oSelf, "You are panicked! You Cower in fear!");
// Check if we were "cowereing" before
if(GetLocalInt(oSelf, SMP_LAST_FEAR) != SMP_FEAR_COWER)
{
ClearAllActions();
ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT, 1.0, 999999.0);
}
// Unable to change this action
SetCommandable(FALSE, oSelf);
SetLocalInt(oSelf, SMP_LAST_FEAR, SMP_FEAR_COWER);
}