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

713 lines
26 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 Spell Confusion Heartbeat script
//:: FileName SMP_ail_confuse
//:://////////////////////////////////////////////
This runs on a creature when they have the effect:
// Create a Confuse effect
effect EffectConfused()
On them.
This will randomly do an action according to the 3.5 rules:
- Taken from the Confusion Spell description.
This spell causes the targets to become confused, making them unable to
independently determine what they will do.
Roll on the following table at the beginning of each subjects turn each
round to see what the subject does in that round.
d% Behavior
01-10 Attack caster with melee or ranged weapons (or close with caster if
attack is not possible).
11-20 Act normally.
21-50 Do nothing but babble incoherently.
51-70 Flee away from caster at top possible speed.
71-100 Attack nearest creature (for this purpose, a familiar counts as part
of the subjects self).
A confused character who cant carry out the indicated action does nothing
but babble incoherently. Attackers are not at any special advantage when
attacking a confused character. Any confused character who is attacked
automatically attacks its attackers on its next turn, as long as it is still
confused when its turn comes. Note that a confused character will not make
attacks of opportunity against any creature that it is not already devoted
to attacking (either because of its most recent action or because it has just
been attacked).
NOTE:
"Insanity" is mearly considered a permament version of Confusion, and
should be permament and made SupernaturalEffect().
NOTE:
If they ONLY have Song Of Discord's effects, this means we have a 50% chance
of attacking the nearest alive creature (who is not dying) with the most
powerful thing.
NOTE:
If they have Hypontism's spell effects, and are not naturally confused, they
will just stop and face the creator of the effect (if not valid, it depissitates)
NOTE:
If they have Rainbow Patters spell effects, they will face a location set
on them, and will override Song of discords effects.
NOTE:
If they have the effects from Suggestion (or Mass Suggestion) then they
will take that action, unless they are confused or have any of the above
effects.
//:://////////////////////////////////////////////
//:: Created By: Jasperre
//::////////////////////////////////////////////*/
#include "SMP_INC_AILMENT"
// Returns the nearest seen or heard caster of confusion (if a valid creature object)
object GetConfusionCreator(object oSelf, int nSpellId = SPELL_INVALID);
// Babble incoherantly!
void Babble();
// Does an action based on nSpellId, returns FALSE if they have not completed
// it yet, or TRUE if they should be released.
int SuggestionResult(int nSpellId);
void main()
{
// Declare everything
object oSelf = OBJECT_SELF;
object oTarget, oFamiliar, oCreator;
// If any of these are TRUE, we have a confusion effect of that spell.
int bHypnotism, bSongOfDiscord, bConfusionNormal, bIrresistibleDance,
bRainbowPattern, bSuggestion, nSuggestionSpell, nSpellId;
// We need to check Calm Emotions
// - If TRUE, surpress
if(SMP_AilmentCheckCalmEmotions())
{
SendMessageToPC(OBJECT_SELF, "Your calm emotions blocks confusion.");
DelayCommand(0.0, SetCommandable(TRUE, oSelf));
return;
}
// Get all effects
effect eCheck = GetFirstEffect(oSelf);
while(GetIsEffectValid(eCheck))
{
// Only check confusion effects
if(GetEffectType(eCheck) == EFFECT_TYPE_CONFUSED)
{
nSpellId = GetEffectSpellId(eCheck);
switch(nSpellId)
{
case SMP_SPELL_SONG_OF_DISCORD:
{
// Song of Discords spell effects.
bSongOfDiscord = TRUE;
}
break;
case SMP_SPELL_HYPNOTISM:
case SMP_SPELLABILITY_BABBLE: // (Allip babble causes this too)
{
// Hypnotism's spell effects
bHypnotism = TRUE;
}
break;
case SMP_SPELL_IRRESISTIBLE_DANCE:
{
// Irresistible Dance's spell effects
bIrresistibleDance = TRUE;
}
break;
case SMP_SPELL_RAINBOW_PATTERN:
{
// Rainbow Pattern's spell effects
bRainbowPattern = TRUE;
}
break;
case SMP_SPELL_SUGGESTION:
case SMP_SPELL_SUGGESTION_PUT_WEAPON_DOWN:
case SMP_SPELL_SUGGESTION_RUN_FROM_HOSTILE:
case SMP_SPELL_SUGGESTION_MOVE_TOWARDS_ME:
case SMP_SPELL_SUGGESTION_MOVE_AWAY_FROM_ME:
case SMP_SPELL_SUGGESTION_SIT_DOWN:
case SMP_SPELL_SUGGESTION_MASS:
case SMP_SPELL_SUGGESTION_MASS_PUT_WEAPON_DOWN:
case SMP_SPELL_SUGGESTION_MASS_RUN_FROM_HOSTILE:
case SMP_SPELL_SUGGESTION_MASS_MOVE_TOWARDS_ME:
case SMP_SPELL_SUGGESTION_MASS_MOVE_AWAY_FROM_ME:
case SMP_SPELL_SUGGESTION_MASS_SIT_DOWN:
{
// Got any of the suggestion spells (or sub-dial) effects.
bSuggestion = TRUE;
nSuggestionSpell = nSpellId;
}
break;
default:
{
// We have another confusion effect
bConfusionNormal = TRUE;
}
break;
}
}
eCheck = GetNextEffect(oSelf);
}
// Order of priority:
// 1 - If we have confusion from a normal source, we do random babblings
// 2 - If we are under the effect of Hypnotism, we look at the Hypnotism creator.
// 3 - If we are dancing, we dance (Irresistible Dance)
// 4 - If we are under the effect of a Rainbow Pattern, we face a cirtain location.
// 5 - If we are Discorded, we will 50% of the time attack the nearest creature
// Are we affected by any Non-other-spell-created Confusion?
// - Top priority
if(bConfusionNormal == TRUE)
{
// Table roll is a d100
int nRandom = d100();
int nCnt;
// What do we do?
// 01-10 Attack caster with melee or ranged weapons (or close with caster if
// attack is not possible).
if(nRandom <= 10)
{
// Make sure the creature is commandable for the round
SetCommandable(TRUE);
// Clear all previous actions.
ClearAllActions();
// Get our confusion creator!
oTarget = GetConfusionCreator(oSelf);
if(GetIsObjectValid(oTarget))
{
// Range check to use bow
if(GetDistanceToObject(oTarget) >= 5.0)
{
// Equip a ranged weapon
ActionEquipMostDamagingRanged();
}
else
{
// Equip a melee weapon
ActionEquipMostDamagingMelee();
}
ActionAttack(oTarget);
}
else
// A confused character who cant carry out the indicated action does nothing
// but babble incoherently.
{
Babble();
}
// Stop the confused person changing this action
SetCommandable(FALSE);
}
// 11-20 Act normally.
// We let them act normally
else if(nRandom <= 20)
{
SendMessageToPC(OBJECT_SELF, "You suddenly feel a short amount of freedom from your confusion!");
DelayCommand(0.0, SetCommandable(TRUE, oSelf));
return;
}
// 21-50 Do nothing but babble incoherently.
else if(nRandom <= 50)
{
// Make sure the creature is commandable for the round
SetCommandable(TRUE);
// Clear all previous actions.
ClearAllActions();
Babble();
// Stop the confused person changing this action
SetCommandable(FALSE);
}
// 51-70 Flee away from caster at top possible speed.
else if(nRandom <= 70)
{
// Make sure the creature is commandable for the round
SetCommandable(TRUE);
// Clear all previous actions.
ClearAllActions();
// Get our confusion creator!
oTarget = GetConfusionCreator(OBJECT_SELF);
if(GetIsObjectValid(oTarget))
{
// Run from them
ActionMoveAwayFromObject(oTarget, TRUE, 100.0);
}
else
// A confused character who cant carry out the indicated action does nothing
// but babble incoherently.
{
Babble();
}
// Stop the confused person changing this action
SetCommandable(FALSE);
}
// 71-100 Attack nearest creature (for this purpose, a familiar counts as part
// of the subjects self).
else
{
// Make sure the creature is commandable for the round
SetCommandable(TRUE);
// Clear all previous actions.
ClearAllActions();
nCnt = 1;
// We don't ever attack familiars, ourself
oFamiliar = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, OBJECT_SELF);
oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, nCnt);
while(GetIsObjectValid(oTarget))
{
// Stop if it is not a familiar (our own)
if(oTarget != oFamiliar)
{
break;
}
nCnt++;
oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE);
}
// Check target validness
if(GetIsObjectValid(oTarget) && oTarget != oFamiliar)
{
// Range check to use bow
if(GetDistanceToObject(oTarget) >= 5.0)
{
// Equip a ranged weapon
ActionEquipMostDamagingRanged();
}
else
{
// Equip a melee weapon
ActionEquipMostDamagingMelee();
}
ActionAttack(oTarget);
}
else
// A confused character who cant carry out the indicated action does nothing
// but babble incoherently.
{
Babble();
}
// Stop the confused person changing this action
SetCommandable(FALSE);
}
// End confusion
return;
}
// Hypnotism effects
else if(bHypnotism == TRUE)
{
// Stare at the creator of the hypnotism - if valid. If not, we definatly
// remove it
oCreator = GetConfusionCreator(oSelf, SMP_SPELL_HYPNOTISM);
if(GetIsObjectValid(oCreator))
{
// Make sure the creature is commandable for the round
SetCommandable(TRUE);
// Clear all previous actions.
ClearAllActions();
// Set facing
SetFacingPoint(GetPosition(oCreator));
// Stop the confused person changing this action
SetCommandable(FALSE);
}
else
{
// Invalid, remove the effects
SMP_RemoveSpellEffectsFromTarget(SMP_SPELL_HYPNOTISM, oSelf);
}
// End Hypnotism
return;
}
// Are we affected by Irresistible Dance?
else if(bIrresistibleDance == TRUE)
{
// Make sure the creature is commandable for the round
SetCommandable(TRUE);
// Clear all previous actions.
ClearAllActions();
// Do a random Speakstring to show we are dancing
if(!GetHasSpellEffect(SMP_SPELL_SILENCE, oSelf))
{
switch(GetRacialType(OBJECT_SELF))
{
case RACIAL_TYPE_DWARF:
case RACIAL_TYPE_HALFELF:
case RACIAL_TYPE_HALFORC:
case RACIAL_TYPE_ELF:
case RACIAL_TYPE_GNOME:
case RACIAL_TYPE_HUMANOID_GOBLINOID:
case RACIAL_TYPE_HALFLING:
case RACIAL_TYPE_HUMAN:
case RACIAL_TYPE_HUMANOID_MONSTROUS:
case RACIAL_TYPE_HUMANOID_ORC:
case RACIAL_TYPE_HUMANOID_REPTILIAN:
{
// Some nice random speak :-)
switch (d20())
{
case(1):{ SpeakString("Cha-cha-cha...");} break;
case(2):{ SpeakString("Ooooohhh, yeah...");} break;
case(3):{ SpeakString("Dancin' baby...");} break;
case(4):{ SpeakString("Tonight I'll be singin'...");} break;
case(5):{ SpeakString("What a good beat...");} break;
case(6):{ SpeakString("Toe tapping...");} break;
case(7):{ SpeakString("Foot movin'...");} break;
case(8):{ SpeakString("I feel the pulse...");} break;
case(9):{ SpeakString("Give me space! Give me room!");} break;
case(10):{ SpeakString("You can't stop me!");} break;
default:{ SpeakString("*Dances*");} break;
}
}
break;
default:
{
// Show we are dancing
SpeakString("*Dances*");
}
break;
}
}
else
{
// Show we are dancing
SpeakString("*Dances*");
}
// Unequip our right and left hand things
object oEquipped = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oSelf);
if(GetIsObjectValid(oEquipped))
{
ActionUnequipItem(oEquipped);
}
oEquipped = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oSelf);
if(GetIsObjectValid(oEquipped))
{
ActionUnequipItem(oEquipped);
}
// We dance baby, yeah!
// Randomly play a few animations
// Some nice random speak :-)
switch (d6())
{
case(1):{ ActionPlayAnimation(ANIMATION_LOOPING_CONJURE1, 1.0, 3.0); } break;
case(2):{ ActionPlayAnimation(ANIMATION_LOOPING_CONJURE2, 1.0, 3.0); } break;
case(3):{ ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 3.0); } break;
case(4):{ ActionPlayAnimation(ANIMATION_LOOPING_GET_MID, 1.0, 3.0); } break;
case(5):{ ActionPlayAnimation(ANIMATION_LOOPING_LISTEN, 1.0, 3.0); } break;
case(6):{ ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR, 1.0, 3.0); } break;
}
switch (d10())
{
case(1):{ ActionPlayAnimation(ANIMATION_FIREFORGET_BOW); } break;
case(2):{ ActionPlayAnimation(ANIMATION_FIREFORGET_DODGE_DUCK); } break;
case(3):{ ActionPlayAnimation(ANIMATION_FIREFORGET_DODGE_SIDE); } break;
case(4):{ ActionPlayAnimation(ANIMATION_FIREFORGET_GREETING); } break;
case(5):{ ActionPlayAnimation(ANIMATION_FIREFORGET_SALUTE); } break;
case(6):{ ActionPlayAnimation(ANIMATION_FIREFORGET_STEAL); } break;
case(7):{ ActionPlayAnimation(ANIMATION_FIREFORGET_TAUNT); } break;
case(8):{ ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY1); } break;
case(9):{ ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY2); } break;
case(10):{ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY3); } break;
}
// Stop the confused person changing this action
SetCommandable(FALSE);
}
// Are we affected by Rainbow Pattern?
else if(bRainbowPattern == TRUE)
{
// Make sure the creature is commandable for the round
SetCommandable(TRUE);
// Clear all previous actions.
ClearAllActions();
// Face a pre-set location
location lFace = GetLocalLocation(OBJECT_SELF, "SMP_SPELL_RAINBOW_LOCATION");
// Set facing point
SetFacingPoint(GetPositionFromLocation(lFace));
// Stop the confused person changing this action
SetCommandable(FALSE);
// End Rainbow Pattern
return;
}
// Suggestion?
else if(bSuggestion == TRUE)
{
// Do the different actions
// Make sure the creature is commandable for the round
SetCommandable(TRUE);
// If they have not got out of it...
if(!SuggestionResult(nSuggestionSpell))
{
// ...Stop the confused person changing this action
SetCommandable(FALSE);
}
// End Suggestion
return;
}
// Are we affected by Song of Discord?
else //if(bSongOfDiscord == TRUE)
{
// Make sure the creature is commandable for the round
SetCommandable(TRUE);
// 50% chance of normal actions
if(d2() == 1)
{
// Can do things normally
FloatingTextStringOnCreature("Your mind returns to normal temporarily from the song of discord", oSelf, FALSE);
}
else
{
// Must attack nearest creature, whoever it is
FloatingTextStringOnCreature("Your mind is discorded! You attack the nearest person!", oSelf, FALSE);
// Stop what we were doing.
ClearAllActions();
// Do a new action using this script - all it does is do a
// maximum of 2 actions
ExecuteScript("SMP_AIL_SongDisc", oSelf);
// Stop the confused person changing this action
SetCommandable(FALSE);
}
// End Song of Discord
return;
}
}
// Returns the nearest seen or heard caster of confusion (if a valid creature object)
object GetConfusionCreator(object oSelf, int nSpellId = SPELL_INVALID)
{
object oCasterReturn, oCreator;
object oArea = GetArea(oSelf);
effect eCheck = GetFirstEffect(oSelf);
float fLowestDistance = 300.0;
float fDistance;
while(GetIsEffectValid(eCheck))
{
// Only check confusion effects and the right nSpellId
if(GetEffectType(eCheck) == EFFECT_TYPE_CONFUSED &&
(nSpellId == SPELL_INVALID || GetEffectSpellId(eCheck) == nSpellId))
{
// 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
oCasterReturn = oCreator;
fLowestDistance = fDistance;
}
}
}
}
return oCasterReturn;
}
// Babble incoherantly!
void Babble()
{
// Do we do babbling? Only humanoid + PC races will, other will not.
int nRacial = GetRacialType(OBJECT_SELF);
// Check race
switch(nRacial)
{
case RACIAL_TYPE_DWARF:
case RACIAL_TYPE_HALFELF:
case RACIAL_TYPE_HALFORC:
case RACIAL_TYPE_ELF:
case RACIAL_TYPE_GNOME:
case RACIAL_TYPE_HUMANOID_GOBLINOID:
case RACIAL_TYPE_HALFLING:
case RACIAL_TYPE_HUMAN:
case RACIAL_TYPE_HUMANOID_MONSTROUS:
case RACIAL_TYPE_HUMANOID_ORC:
case RACIAL_TYPE_HUMANOID_REPTILIAN:
{
// Some nice random speak :-)
switch (d20())
{
case(1):{ SpeakString("*blurbleyla!*");} break;
case(2):{ SpeakString("*Jiapa!*");} break;
case(3):{ SpeakString("*Duhhhhhh*");} break;
case(4):{ SpeakString("*Weeeeee!*");} break;
case(5):{ SpeakString("*oopsalbongo!*");} break;
case(6):{ SpeakString("*yeee!*");} break;
case(7):{ SpeakString("*...*");} break;
case(8):{ SpeakString("*paaannnddaaaa*");} break;
case(9):{ SpeakString("*Whatcadomatey?*");} break;
case(10):{ SpeakString("*Memememe!*");} break;
default:{ SpeakString("*babbles incoherently*");} break;
}
}
default:
{
SpeakString("*babbles incoherently*");
}
break;
}
}
// Does an action based on nSpellId, returns FALSE if they have not completed
// it yet, or TRUE if they should be released.
int SuggestionResult(int nSpellId)
{
// Creator of the confusion (or suggestion in this case)
object oCreator;
switch(nSpellId)
{
// Default (First) case, put down weapons.
case SMP_SPELL_SUGGESTION:
case SMP_SPELL_SUGGESTION_MASS:
case SMP_SPELL_SUGGESTION_PUT_WEAPON_DOWN:
case SMP_SPELL_SUGGESTION_MASS_PUT_WEAPON_DOWN:
{
// Got any?
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
if(GetIsObjectValid(oWeapon))
{
// Clear all previous actions.
ClearAllActions();
// Remove it
ActionWait(2.0);
ActionUnequipItem(oWeapon);
// Check lefthand
oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND);
if(GetIsObjectValid(oWeapon))
{
// Remove it
ActionWait(2.0);
ActionUnequipItem(oWeapon);
}
// Returns FALSE, cannot cancel this suggestion this turn
return FALSE;
}
}
break;
// Second case: Run from hostiles.
case SMP_SPELL_SUGGESTION_RUN_FROM_HOSTILE:
case SMP_SPELL_SUGGESTION_MASS_RUN_FROM_HOSTILE:
{
// Get nearest enemy
// * Alive, Seen, Enemy
object oEnemy = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_IS_ALIVE, TRUE);
if(GetIsObjectValid(oEnemy))
{
// Clear all previous actions.
ClearAllActions();
// Move away
ActionMoveAwayFromObject(oEnemy, TRUE, 60.0);
// Returns FALSE, cannot cancel this suggestion this turn
return FALSE;
}
}
break;
// Third case: Move towards the creator
case SMP_SPELL_SUGGESTION_MOVE_TOWARDS_ME:
case SMP_SPELL_SUGGESTION_MASS_MOVE_TOWARDS_ME:
{
// Move towards the creator until we are close
oCreator = GetConfusionCreator(OBJECT_SELF, nSpellId);
// Same area, and seen or heard
if((GetObjectSeen(oCreator) || GetObjectHeard(oCreator)) &&
GetArea(oCreator) == GetArea(OBJECT_SELF))
{
// Must be >= 3M away
if(GetDistanceToObject(oCreator) > 3.0)
{
// Clear all previous actions.
ClearAllActions();
// Move
ActionForceMoveToObject(oCreator, TRUE, 1.0, 6.0);
// Returns FALSE, cannot cancel this suggestion this turn
return FALSE;
}
}
}
break;
// Fourth Case: Move away from the caster
case SMP_SPELL_SUGGESTION_MOVE_AWAY_FROM_ME:
case SMP_SPELL_SUGGESTION_MASS_MOVE_AWAY_FROM_ME:
{
// Move towards the creator until we are close
oCreator = GetConfusionCreator(OBJECT_SELF, nSpellId);
// Same area, and seen or heard
if((GetObjectSeen(oCreator) || GetObjectHeard(oCreator)) &&
GetArea(oCreator) == GetArea(OBJECT_SELF))
{
// Must be <= 50.0M away
if(GetDistanceToObject(oCreator) <= 50.0)
{
// Clear all previous actions.
ClearAllActions();
// Move
ActionMoveAwayFromObject(oCreator, TRUE, 51.0);
// Returns FALSE, cannot cancel this suggestion this turn
return FALSE;
}
}
}
break;
// Last (Fifth) cast: Sit down for a while.
case SMP_SPELL_SUGGESTION_SIT_DOWN:
case SMP_SPELL_SUGGESTION_MASS_SIT_DOWN:
{
// Sitting already?
int nSitting = GetLocalInt(OBJECT_SELF, "SMP_SUGGESTION_TEMP_SITTING");
if(nSitting == 0)
{
// Clear all previous actions.
ClearAllActions();
// Set counter back to 6
SetLocalInt(OBJECT_SELF, "SMP_SUGGESTION_TEMP_SITTING", 6);
}
else
{
// Take one off until we reset the sitting
SetLocalInt(OBJECT_SELF, "SMP_SUGGESTION_TEMP_SITTING", --nSitting);
}
// Sit down, simple as that, until the duration runs out. We of
// course get it canceled when damaged...
ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS);
}
break;
}
// Now, it seems it is complete, so return TRUE - do not stop them
// from moving, and remove the effect from this spell, from us.
SMP_RemoveSpellEffectsFromTarget(nSpellId);
return TRUE;
}