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

2778 lines
96 KiB
Plaintext
Raw Permalink Blame History

/*:://////////////////////////////////////////////
//:: Spells Include
//:: SMP_INC_SPELLS
//:://////////////////////////////////////////////
Reference numbers, may be useful:
1 foot = 0.32 meter.
10 feet = 3.33M.
See SMP_INC_Constants.nss for the full list.
This include file holds a lot of basic reusable functions, much like the
NW_i0_spells did for the original Bioware spells. It also includes all
relivant sub-include files.
This is included in each spell file, and thusly only one include reference is
needed.
//:://////////////////////////////////////////////
//:: Created By: Jasperre
//:: Created On: 2003
//::////////////////////////////////////////////*/
// All AOE functions
#include "SMP_INC_AOE"
// All Applying wrappers - EG for damage (for, say, Shield Other)
#include "SMP_INC_APPLY"
// All Array functions
#include "SMP_INC_ARRAY"
// All spell componant checks - gems, items ETC
#include "SMP_INC_COMPNENT"
// All new spell constants (Includes polymorph and visuals includes)
// * Included at least in SMP_INC_EFFECTS
//#include "SMP_INC_CONSTANT"
// All difficulty functions (mainly not used)
#include "SMP_INC_DIFFICLT"
// All dispel magic things
#include "SMP_INC_DISPEL"
// All effect creating functions
#include "SMP_INC_EFFECTS"
// All Item Property checking, and adding
#include "SMP_INC_ITEMPROP"
// All removal things (RemoveEffect)
#include "SMP_INC_REMOVE"
// All resisting spell (ResistSpell) functions
#include "SMP_INC_RESIST"
// All spell save functions
#include "SMP_INC_SAVES"
// All touch and Range touch attack functions
#include "SMP_INC_TOUCHAKK"
// All turning functions (Which normally stops spells)
#include "SMP_INC_TURNING"
// Settings
#include "SMP_INC_SETTINGS"
// Summoning spells
#include "SMP_INC_SUMMON"
// Special: Debug include
#include "SMP_INC_DEBUG"
// Constants for SMP_GetDuration().
const int SMP_ROUNDS = 1; // 6 Seconds
const int SMP_MINUTES = 2; // 60 Seconds
const int SMP_HOURS = 3; // Default: 120 Seconds
// SMP_INC_SPELLS. This allows the application of a random delay to effects
// based on time parameters passed in.
// - Min default = 0.4, Max default = 1.1. Min = 0.1, Max = 10.0.
float SMP_GetRandomDelay(float fMinimumTime = 0.4, float MaximumTime = 1.1);
// SMP_INC_SPELLS. Returns true if oTarget is a humanoid
int SMP_GetIsHumanoid(object oTarget = OBJECT_SELF);
// SMP_INC_SPELLS. Totals the amount of items of sTag in oTargets inventory.
int SMP_TotalItemsOfBlueprint(object oTarget, string sBluePrint);
// SMP_INC_SPELLS. Destroys all items of sBluePrint on oTarget.
void SMP_DestroyItemsOfBluePrint(object oTarget, string sBluePrint);
// SMP_INC_SPELLS. This alerts all DM's of the spell being cast, and of name of
// the target, also reports Caster Level and DC for save.
void SMP_AlertDMsOfSpell(string sName, int nSpellSaveDC, int nCasterLevel);
// SMP_INC_SPELLS. This will check to see if there is a DM playing on the server
// at all. Some spells will force a DM to do the effects, else it'd be scripted
// and very limited (Wish, Miracle...etc).
// * TRUE if a DM is playing in the player (frist/next) list, else FALSE.
int SMP_GetIsDMPlaying();
// SMP_INC_SPELLS. Wrapper for the signal event. Smaller :-P
// * Default to a HOSTILE spell. :-)
// * It uses OBJECT_SELF as the default caster
// It uses SignalEvent(oTarget, EventSpellCastAt(oCaster, nSpell, bHarmful));
// It won't fire it at a PC, to reduce lag.
void SMP_SignalSpellCastAt(object oTarget, int nSpell, int bHarmful = TRUE, object oCaster = OBJECT_SELF);
// SMP_INC_SPELLS.
// * Returns true if oCreature does not have a mind
int SMP_SpellsIsMindless(object oCreature);
// SMP_INC_SPELLS.
// * Returns true or false depending on whether the creature is flying or not
int SMP_SpellsIsFlying(object oCreature);
// SMP_INC_SPELLS.
// * Returns true if the creature has flesh
int SMP_SpellsIsImmuneToPetrification(object oCreature);
// SMP_INC_SPELLS. Bullrush attack
// - Uses oTarget's strength, add modifiers, against nCasterModifier.
// - Reports results to caster and target
int SMP_Bullrush(object oTarget, int nCasterModifier, object oCaster = OBJECT_SELF);
// SMP_INC_SPELLS. Bullrush
// - Returns TRUE if oCreature is immune to bullrush
// - Oozes, for instance.
int SMP_ImmuneToBullrush(object oCreature);
// SMP_INC_SPELLS. Bullrush.
// * Returns the size modifier for bullrush in spells (XP1)
// +4 for every size over medium
// -4 for every size under medium. Medium = 0.
int SMP_GetSizeModifier(object oCreature);
// SMP_INC_SPELLS. Bullrush.
// * Returns TRUE if oCreature is steady.
// - Has more then 2 legs
// - Is steadying themselves by use of Defensive Casting or Expertise.
// - Is steady by moving slowly around!
int SMP_GetIsSteady(object oCreature);
// SMP_INC_SPELLS. Moves the target back from their current position,
// away from oTarget, fDistance.
// NEED TO REPLACE WITH REPULSION THING
void SMP_DoMoveBackwards(object oSource, object oTarget, float fDistance);
// SMP_INC_SPELLS. Can the creature be destroyed without breaking a plot?
// - Immortal, Plot or DM returns FALSE.
int SMP_CanCreatureBeDestroyed(object oTarget);
// SMP_INC_SPELLS. Returns TRUE if oTarget is an Minotaur. Maze spell uses this.
int SMP_GetIsMinotaur(object oTarget);
// SMP_INC_SPELLS. Is oTarget in a maze area? (enables some spells really)
int SMP_IsInMazeArea(object oTarget = OBJECT_SELF);
// SMP_INC_SPELLS. Is oTarget in a Imprisonment area? (only used to check to jump back really)
int SMP_IsInPrisonArea(object oTarget = OBJECT_SELF);
// SMP_INC_SPELLS. Returns TRUE if oTarget is an Ethereal, or an Ethereal creature
int SMP_GetIsEthereal(object oTarget);
// SMP_INC_SPELLS. Returns TRUE if oTarget is an Astral creature
int SMP_GetIsAstral(object oTarget);
// SMP_INC_SPELLS. Returns TRUE if oTarget is Crystalline - earthy
int SMP_GetIsCrystalline(object oTarget);
// SMP_INC_SPELLS. This returns TRUE if they are Incorporeal, via. local variable,
// spell or effect
int SMP_GetIsIncorporeal(object oTarget);
// SMP_INC_SPELLS. Immune to polymorph - also plays approprate effect.
// * Returns TRUE if oTarget cannot be polymorphed.
int SMP_ImmuneToPolymorph(object oTarget);
// SMP_INC_SPELLS. This returns a positive, negative or zero number
// Add this to any DC's for sleep.
// * Adds 2 for lullaby.
int SMP_GetSleepSaveModifier(object oTarget);
// SMP_INC_SPELLS.
// * FALSE if they are a Non-living creature. Dead objects have no effect on result.
// * sDebug - If this is filled, it is sent to the caster, if it returns FALSE.
int SMP_GetIsAliveCreature(object oTarget, string sDebug = "");
// SMP_INC_SPELLS. Sorts out metamagic checks, using Random()
// * nDiceSides (EG: 6 for D6 dice) * nNumberOfDice (EG: 2, for 2d6)
// * nBonus - Bonus to at the end.
// * Does include Maximise and Empower checks.
// * nTouch - If 2, it is a critcal, and does double what it would normally return.
int SMP_MaximizeOrEmpower(int nDiceSides, int nNumberOfDice, int nMeta, int nBonus = 0, int nTouch = 0);
// SMP_INC_SPELLS. Works out a dice-rolled time.
// * nType - use SMP_ROUNDS (6 sec), SMP_MINUTES (60 sec), SMP_HOURS (mod dependant)
// * nDiceSides, nNumberOfDice - The dice (EG 5, 6sided dice = 6, 5)
// * nMeta - Metamagic feat EXTEND is used here
// * nBonus - Added before metamagic, such as 4d(caster level) + Bonus.
float SMP_GetRandomDuration(int nType, int nDiceSides, int nNumberOfDice, int nMeta, int nBonusTime = 0);
// SMP_INC_SPELLS. Works out a normal time. Useful wrapper.
// * nType - use SMP_ROUNDS (6 sec), SMP_MINUTES (60 sec), SMP_HOURS (mod dependant)
// * nTime - the time in hours, rounds or turns
// * nMeta - The metamagic feat EXTEND is also taken into account.
float SMP_GetDuration(int nType, int nTime, int nMeta);
// SMP_INC_SPELLS. Does a fortitude check and applys EffectPetrify :-)
// - Taken from Bioware's petrify. More generic however.
// - No ReactionType checks.
// - Will not petrify immune creatures
// * oTarget - Target
// * nCasterLevel - Either the hit dice of the creature or the caster level
// * nFortSaveDC: pass in this number from the spell script
// - It will also apply bonuses of a construct.
void SMP_SpellFortitudePetrify(object oTarget, int nCasterLevel, int nFortSaveDC);
// SMP_INC_SPELLS. Creates a new location from lLocation on a varying X and Y
// value, in increments of 1 meter.
// * nRandom - this is the number you want to randomise. It will be up to HALF
// this in meters from lLocation, north south east or west.
location SMP_GetRandomLocation(location lLocation, int nRandom);
// SMP_INC_SPELLS. Returns bolts, arrows, bullets or -1 for the ammo item type used by oWeapon.
int SMP_GetWeaponsAmmoType(object oWeapon);
// SMP_INC_SPELLS. Gets the right slot for nBaseAmmoType or -1.
int SMP_GetAmmoSlot(int nBaseAmmoType);
// SMP_INC_SPELLS. Is the creature dazzeled?
// Spells include:
// - Flare
int SMP_GetIsDazzled(object oTarget);
// SMP_INC_SPELLS. Can the caster, oCaster, teleport to lTarget without disrupting a module?
// - Trigger, if at the location or the caster, stops it
// - The area can be made "No teleport"
// - Includes a check for SMP_GetDimensionalAnchor(oCaster);.
// TRUE if they can NOT teleport to lTarget.
int SMP_CannotTeleport(object oCaster, location lTarget);
// SMP_INC_SPELLS. Returns TRUE if oCreature is locked in this dimension by:
// - Dimensional Anchor
// - Dimensional Lock
// - Forbiddance
int SMP_GetDimensionalAnchor(object oCreature);
// SMP_INC_SPELLS.
// This is used for some spells to limit creatures by size. EG: Dimension door.
// Returns: 1 for Medium, small and tiny creatures.
// 2 for Large (Equivilant of 2 medium creatures)
// 4 for Huge creature sizes (Equivilant of 2 Large creatures)
int SMP_SizeEquvilant(object oCreature);
// SMP_INC_SPELLS. Removes all Fatigue/Exhaustion from oTarget.
void SMP_RemoveFatigue(object oTarget);
// SMP_INC_SPELLS. Applys a new Fatigue effect to oTarget, if not already got it...
// * If bExhaustion is TRUE, it applies Exhaustion instead.
// * Exhaustion "overrides" any fatigue, and using the Bioware problem of
// ability penalties not stacking, will mearly apply exhasution over fatigue.
// (Noting, of course, speed decreases stack. Anyone exhausted also becomes fatiged,
// but not vice versa).
// * Stats: Fatigue: 20% move penalty. -2 Dex and STR.
// Exhaustion: An additional -4 to Dex and STR, -20% speed. (so -6, 40%)
void SMP_ApplyFatigue(object oTarget, int bExhaustion = FALSE, int nDurationType = DURATION_TYPE_PERMANENT, float fDuration = 0.0);
// SMP_INC_SPELLS.
// Returns iHighest if it is over nHighest, or nLowest if under nLowest, or
// the integer put in (nInteger) if between them already.
int SMP_LimitInteger(int nInteger, int nHighest = 100, int nLowest = 1);
// SMP_INC_SPELLS. This is fired from AI files.
// - Removes cirtain spells if the target is attacked, harmed and so on during
// the spells effects.
void SMP_RemoveSpellsIfAttacked(object oAttacked = OBJECT_SELF);
// SMP_INC_SPELLS. This DESTROYS oTarget.
// - Removes plot flags, all inventory, before proper destorying.
void SMP_PermamentlyRemove(object oTarget);
// SMP_INC_SPELLS. Increase or decrease a stored integer on oTarget, by
// nAmount, under sName
// * Returns Stored amount + nAmount, the new integer set.
int SMP_IncreaseStoredInteger(object oTarget, string sName, int nAmount = 1);
// SMP_INC_SPELLS. Use in DelayCommand(), to delete integer under sName
// on oTarget. Deleted only if oTarget is valid!
void SMP_DelayedDeleteInteger(object oTarget, string sName);
// SMP_INC_SPELLS. Returns TRUE if oTarget's subrace is plant, or integer SMP_PLANT is valid.
int SMP_GetIsPlant(object oTarget);
// SMP_INC_SPELLS. Returns TRUE if oTarget's subrace is water elemental,
// or thier appearance is that of a water elemental.
int SMP_GetIsWaterElemental(object oTarget);
// SMP_INC_SPELLS.
// This will make sure that oTarget is not commandable, and also that the
// commandable was not applied by some other spell which is active.
void SMP_SetCommandableOnSafe(object oTarget, int nSpellRemove);
// SMP_INC_SPELLS.
// Automatically reports sucess or failure for the ability check. The roll
// of d20 + nAbility's scrore needs to be >= nDC.
int SMP_AbilityCheck(object oCheck, int nAbility, int nDC);
// SMP_INC_SPELLS. Applys the visual effect nVis, across from oStart to the object oTarget,
// at intervals of 0.05, playing the visual in the direction.
void SMP_ApplyBeamAlongVisuals(int nVis, object oStart, object oTarget, float fIncrement = 1.0);
// SMP_INC_SPELLS. Returns TRUE if sunlight will kill/seriously damage/almost
// obliterate oTarget, IE: Vampires.
int SMP_GetHateSun(object oTarget);
// SMP_INC_SPELLS.
// This will check if they have any charges for nSpellId, or not as the case
// may be.
// * You can use bFeedback set to FALSE to surpress feedback (EG: test Call
// Lightning Storm and then Call Lightning, surpress CLS's feedback first).
// * Sucess always has feedback!
// * TRUE if the check passes, else FALSE
int SMP_CheckChargesForSpell(int nSpellId, int bFeedback = TRUE, object oCaster = OBJECT_SELF);
// SMP_INC_SPELLS. This will apply a duration effect, and set an amount of charges
// left to use nSpellId's power for, if they concentrate for another round using
// a special item.
void SMP_AddChargesForSpell(int nSpellId, int nCharges, float fDuration, object oCaster = OBJECT_SELF);
// SMP_INC_SPELLS. This changed oArea's music to iTrack for fDuration.
// * Note: If either tracks are already nTrack, they don't change.
void SMP_PlayMusicForDuration(object oArea, int nTrack, float fDuration);
// SMP_INC_SPELLS. This changes it permantly. (used in PlayMusicForDuration).
// * Set bNightOrDay to TRUE for daytime music.
void SMP_ChangeMusicPermantly(object oArea, int nTrack, int bNightOrDay);
// SMP_INC_SPELLS. This performs an area wether check.
// * Changes oAreas wether to nNewWether for fDuration.
void SMP_ChangeAreaWether(object oArea, int nNewWether, float fDuration);
// SMP_INC_SPELLS.
// This will check the target, to see if they have broken thier concentration
// by moving, doing something else, or not being able to do anything.
// * It sets SMP_CONCENTRATION_CHECK_ + IntToString(nSpellId) to TRUE if broken.
int SMP_ConcentrationCheck(object oTarget, int nSpellId);
// SMP_INC_SPELLS.
// This does a "detect" check for PC rogues - the range is 5ft non-search-mode,
// and 10ft for search mode. The DC is 25 + nLevel.
void SMP_MagicalTrapsDetect(int nLevel);
// SMP_INC_SPELLS, This removes:
// ability damage, blinded, confused,
// dazed, dazzled, deafened, diseased, exhausted, fatigued, feebleminded,
// insanity, nauseated, sickened, stunned, and poisoned.
// * Note that SMP_SPELL_SYMBOL_OF_INSANITY, as well as SMP_SPELL_INSANTY are both the "insanity"
void SMP_HealSpellRemoval(object oTarget);
// SMP_INC_SPELLS. Checks if they are a shapechanger subtype (so can cancle polymorph)
// * They will be able to if they are a shapechanger class
// * They can be a NPC and be a sub-race Shapechanger, or RACIAL_TYPE_SHAPECHANGER.
int SMP_GetIsShapechangerSubtype(object oTarget);
// SMP_INC_SPELLS. If sStoredTo integer on oTarget is nInteger, we delete it.
void SMP_DeleteIntInTime(string sStoredTo, object oTarget, int nInteger);
// SMP_INC_SPELLS. Loops all objects of nObjectType, nearest firest, until it finds sTag's.
object SMP_GetNearestObjectByTagToLocation(int nObjectType, string sTag, location lTarget);
// SMP_INC_SPELLS. Loops all objects of sTag from oCreator's location
// until it finds the nearest created by oCreator, and which is nearest to
// OBJECT_SELF.
object SMP_GetNearestAOEOfTagToUs(string sTag, object oCreator);
// SMP_INC_SPELLS. Returns the base armor type as a number, of oItem
// -1 if invalid, or not armor, or just plain not found.
// 0 to 8 as the value of AC got from the armor - 0 for none, 8 for Full plate.
int SMP_GetArmorType(object oItem);
// SMP_INC_SPELLS. Returns TRUE if oItem is a metal-based weapon.
// * FALSE if invalid, or not a weapon, or just plain not found.
int SMP_GetIsMetalWeapon(object oItem);
// SMP_INC_SPELLS. Returns TRUE if oItem is a metal-based armor.
// * FALSE if invalid, or not armor, or just plain not found.
int SMP_GetIsMetalArmor(object oItem);
// Returns TRUE if oObject is a creature, and is made of metal
int SMP_GetIsFerrous(object oObject);
// SMP_INC_SPELLS. Returns TRUE if oItem is any shield.
// 0 if invalid, or not a shield, or just plain not found.
int SMP_GetIsShield(object oItem);
// SMP_INC_SPELLS. SPELL HOOK FOR ALL PLAYER SPELLS
// Returns TRUE if they can cast the spell, FALSE means they cannot.
// * Note: By using the "Master" column, this hook automatically checks for the
// main, master spell for GetSpellId(). This means no input is needed, it is
// all automatic.
int SMP_SpellHookCheck();
// SMP_INC_SPELLS. This is used for the spell "Explosive Runes".
// - When reading a scroll or book (And there is a new "Read" 'spell' too),
// the runes will trigger and explode for 6d6 damage and some blast damage.
// Returns TRUE if they explode!
int SMP_ExplosiveRunes();
// SMP_INC_SPELLS. This does the explosion effects for oItem, if they had
// explosive runes fire this.
// It will also destroy the item, oItem, if it was not plot.
void SMP_ExplosiveRunesExplode(object oItem);
// SMP_INC_SPELLS. Checks if oTarget was summoned via. a spell.
int SMP_GetIsSummonedCreature(object oTarget);
// SMP_INC_SPELLS. Moves back oTarget from oCaster, fDistance.
// Antilife shell ETC uses this.
void SMP_PerformMoveBack(object oCaster, object oTarget, float fDistance, int bOriginalCommandable);
// SMP_INC_SPELLS. Destroys oObject utterly.
// - Turns off Plot Flag, Cursed Flag and Stolen flag.
// - Then uses a standard DestroyObject() command.
void SMP_CompletelyDestroyObject(object oObject);
// SMP_INC_SPELLS.
// Depending on if oTarget is a PC or an NPC, it will "Disintegrate them as the spell"
// and should create some dust where the items will go.
// * PC's are just damaged normally.
// * Cirtain placables are damaged past thier plot status.
// * Cirtain spells on oTarget are destroyed/removed
// * Executes "SMP_AIL_Disinteg" for NPC's.
void SMP_DisintegrateDamage(object oTarget, effect eVis, int nDam);
// SMP_INC_SPELLS. Returns the bonus to Charisma, Wisdom or Intelligence.
// * Uses GetLastSpellCastClass()
// * Will return Charisma as default.
// * Only can be used in impact scripts
// Will be used in some spells which require the "Bonus to spells" bonus.
int SMP_GetAppropriateAbilityBonus();
// SMP_INC_SPELLS. This performs a grapple check against nAC.
// To use it for "opposed" checks, mearly put the amount the oTarget got into
// nAC, such as Black Tentacles.
// Check is made as an attack roll at:
// * Base attack bonus + Strength modifier + special size modifier
// Note:
// Special Size Modifier: The special size modifier for a grapple check is as
// follows: Colossal +16, Gargantuan +12, Huge +8, Large +4, Medium +0,
// Small <20>4, Tiny <20>8, Diminutive <20>12, Fine <20>16. Use this number in place of the
// normal size modifier you use when making an attack roll.
// * Use SMP_GrappleSizeBonus() to get a creatures nSizeMod.
// * Relays to oTarget and oSource (if any) the result of the check.
int SMP_GrappleCheck(object oTarget, int nBAB, int nStrMod, int nSizeMod, int nAC, object oSource = OBJECT_SELF);
// SMP_INC_SPELLS. Special Size Modifier: The special size modifier for a grapple check is as
// follows: Colossal +16, Gargantuan +12, Huge +8, Large +4, Medium +0,
// Small <20>4, Tiny <20>8, Diminutive <20>12, Fine <20>16.
int SMP_GrappleSizeBonus(object oCreature);
// SMP_INC_SPELLS. This will roll an attack roll, using nBAB, nStrMod, nExtra
// against nAC, that is, oTarget's AC (or should be). Relays the results
// as if it was a proper attack.
// NOTE: Returns FALSE on a miss, but else returns the total attack roll of all 3 things
// plus the d20.
int SMP_AttackCheck(object oTarget, int nBAB, int nStrMod, int nExtra, int nAC, object oSource = OBJECT_SELF);
// SMP_INC_SPELLS. Use AssignCommand() to do this on another person, it will set cutscene mode
// for a few seconds (if not already in a cutscene) and move them to lTarget's
// location, then remove the cutscene mode. It will mean no effects are removed
// and it always is sucessful.
// * lTarget is where to move to
// * nGoVis/nAppearVis, if not VFX_NONE, will be applied at the target location
// and the person moving location as appropriate.
void SMP_ForceMovementToLocation(location lTarget, int nGoVis = VFX_NONE, int nAppearVis = VFX_NONE);
// SMP_INC_SPELLS. Roughly gets the weight of oCreature, in tenths of pounds.
// * Based on creature size.
// * Use with GetWeight(oCreature) to get what they are carrying plus the creature weight
int SMP_GetCreatureWeight(object oCreature);
// SMP_INC_SPELLS. This will check if lTarget and lSource are on the same plane
// of exsistance.
// * Used to stop escape from Maze, Prismatic's Plane, Imprisonment.
int SMP_CheckIfSamePlane(location lSource, location lTarget);
// SMP_INC_SPELLS. SMP_GetHitDiceByXP
// HitDice is determined by player's xp, not by whether or not they have leveled
// * Solve for hd from xp = hd * (hd - 1) * 500
// hd = 1/50 * (sqrt(5) * sqrt(xp + 125) + 25)
int SMP_GetHitDiceByXP(object oCreature);
// SMP_INC_SPELLS. This will get the targets character level, not hit dice,
// and so will be used in death stuff to calculate thier actual character level.
// * Can be used on NPC's, and will use GetHitDice(oTarget);
int SMP_GetCharacterLevel(object oTarget);
// SMP_INC_SPELLS. This will get the correct amount of experience to set a person
// to for there to be a level loss of 1, so they have the exact amount needed
// for the previous level.
// * Will return 1 if at level 1.
int SMP_GetLevelLossXP(int nHD);
// SMP_INC_SPELLs. Removes all avalible castings of nSpell on oCreature
// - oCreature: creature to modify
// - nSpell: constant SPELL_*
void SMP_DecrementAllRemainingSpellUses(object oCreature, int nSpell);
/*:://////////////////////////////////////////////
//:: Functions
//:://////////////////////////////////////////////
Functions start.
//:://////////////////////////////////////////////
//:: Created By: Jasperre
//::////////////////////////////////////////////*/
// SMP_INC_SPELLS.
// * FALSE if they are a Non-living creature. Dead objects have no effect on result.
// * sDebug - If this is filled, it is sent to the caster, if it returns FALSE.
int SMP_GetIsAliveCreature(object oTarget, string sDebug = "")
{
// invalid (IE dead etc) races and so on.
int nRace = GetRacialType(oTarget);
// Needs to be a creature
if(GetObjectType(oTarget) != OBJECT_TYPE_CREATURE ||
// Needs to be a valid race (not a dead or un-alive one!)
nRace == RACIAL_TYPE_CONSTRUCT ||
nRace == RACIAL_TYPE_UNDEAD)
{
if(sDebug != "")
{
SendMessageToPC(OBJECT_SELF, sDebug);
}
return FALSE;
}
return TRUE;
}
// SMP_INC_SPELLS. Returns true if oTarget is a humanoid
int SMP_GetIsHumanoid(object oTarget)
{
int nRacial = GetRacialType(oTarget);
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:
{
return TRUE;
}
break;
}
return FALSE;
}
// SMP_INC_SPELLS. This allows the application of a random delay to effects
// based on time parameters passed in.
// - Min default = 0.4, Max default = 1.1. Min = 0.1, Max = 10.0.
float SMP_GetRandomDelay(float fMinimumTime = 0.4, float MaximumTime = 1.1)
{
float fRandom = MaximumTime - fMinimumTime;
int nRandom;
if(fRandom < 0.0)
{
return 0.0;
}
else
{
nRandom = FloatToInt(fRandom * 10.0);
nRandom = Random(nRandom) + 1;
fRandom = IntToFloat(nRandom);
fRandom /= 10.0;
return fRandom + fMinimumTime;
}
}
// SMP_INC_SPELLS. Totals the amount of items of sTag in oTargets inventory.
int SMP_TotalItemsOfBlueprint(object oTarget, string sBluePrint)
{
object oItem = GetFirstItemInInventory(oTarget);
int nCount = 0;
while(GetIsObjectValid(oItem))
{
if(GetResRef(oItem) == sBluePrint)
{
nCount += GetNumStackedItems(oItem);
}
oItem = GetNextItemInInventory(oTarget);
}
return nCount;
}
// SMP_INC_SPELLS. Destroys all items of sBluePrint on oTarget.
void SMP_DestroyItemsOfBluePrint(object oTarget, string sBluePrint)
{
object oItem = GetFirstItemInInventory(oTarget);
while(GetIsObjectValid(oItem))
{
if(GetResRef(oItem) == sBluePrint)
{
DestroyObject(oItem);
}
oItem = GetNextItemInInventory(oTarget);
}
}
// SMP_INC_SPELLS. This alerts all DM's of the spell being cast, and of name of
// the target, also reports Caster Level and DC for save.
void SMP_AlertDMsOfSpell(string sName, int nSpellSaveDC, int nCasterLevel)
{
string sMessage;
string sTarget = "None";
object oTarget = GetSpellTargetObject();
object oArea = GetArea(OBJECT_SELF);
if(GetIsObjectValid(oTarget))
{
sTarget = GetName(oTarget);
}
sMessage = "[SPELL CAST: "+sName+"] [Caster: "+GetName(OBJECT_SELF)+"] [Caster Level: "+IntToString(nCasterLevel)+"] [Target: "+sTarget+"] [Area :"+GetName(oArea)+"] [SaveDC: "+IntToString(nSpellSaveDC)+"]";
SendMessageToAllDMs(sMessage);
}
// SMP_INC_SPELLS. This will check to see if there is a DM playing on the server
// at all. Some spells will force a DM to do the effects, else it'd be scripted
// and very limited (Wish, Miracle...etc).
// * TRUE if a DM is playing in the player (frist/next) list, else FALSE.
int SMP_GetIsDMPlaying()
{
// Loop PC list
object oPC = GetFirstPC();
while(GetIsObjectValid(oPC))
{
// Check if DM, or DM possessed (IE: Might be possessing something somehow)
if(GetIsDM(oPC) || GetIsDMPossessed(oPC))
{
return TRUE;
}
// Get next PC
oPC = GetNextPC();
}
// No DM
return FALSE;
}
// SMP_INC_SPELLS. Wrapper for the signal event. Smaller :-P
// * Default to a HOSTILE spell. :-)
// * It uses OBJECT_SELF as the default caster
// It uses SignalEvent(oTarget, EventSpellCastAt(oCaster, nSpell, bHarmful));
// It won't fire it at a PC, to reduce lag.
void SMP_SignalSpellCastAt(object oTarget, int nSpell, int bHarmful = TRUE, object oCaster = OBJECT_SELF)
{
if(GetIsPC(oTarget)) return;
SignalEvent(oTarget, EventSpellCastAt(oCaster, nSpell, bHarmful));
}
// SMP_INC_SPELLS.
// * Returns true if oCreature does not have a mind
int SMP_SpellsIsMindless(object oCreature)
{
int nRacialType = GetRacialType(oCreature);
switch(nRacialType)
{
case RACIAL_TYPE_ELEMENTAL:
case RACIAL_TYPE_UNDEAD:
case RACIAL_TYPE_VERMIN:
case RACIAL_TYPE_CONSTRUCT:
return TRUE;
}
return FALSE;
}
// SMP_INC_SPELLS.
// * Returns true or false depending on whether the creature is flying or not
int SMP_SpellsIsFlying(object oCreature)
{
int nAppearance = GetAppearanceType(oCreature);
int bFlying = FALSE;
switch(nAppearance)
{
case APPEARANCE_TYPE_ALLIP:
case APPEARANCE_TYPE_BAT:
case APPEARANCE_TYPE_BAT_HORROR:
case APPEARANCE_TYPE_ELEMENTAL_AIR:
case APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER:
case APPEARANCE_TYPE_FAERIE_DRAGON:
case APPEARANCE_TYPE_FALCON:
case APPEARANCE_TYPE_FAIRY:
case APPEARANCE_TYPE_HELMED_HORROR:
case APPEARANCE_TYPE_IMP:
case APPEARANCE_TYPE_LANTERN_ARCHON:
case APPEARANCE_TYPE_MEPHIT_AIR:
case APPEARANCE_TYPE_MEPHIT_DUST:
case APPEARANCE_TYPE_MEPHIT_EARTH:
case APPEARANCE_TYPE_MEPHIT_FIRE:
case APPEARANCE_TYPE_MEPHIT_ICE:
case APPEARANCE_TYPE_MEPHIT_MAGMA:
case APPEARANCE_TYPE_MEPHIT_OOZE:
case APPEARANCE_TYPE_MEPHIT_SALT:
case APPEARANCE_TYPE_MEPHIT_STEAM:
case APPEARANCE_TYPE_MEPHIT_WATER:
case APPEARANCE_TYPE_QUASIT:
case APPEARANCE_TYPE_RAVEN:
case APPEARANCE_TYPE_SHADOW:
case APPEARANCE_TYPE_SHADOW_FIEND:
case APPEARANCE_TYPE_SPECTRE:
case APPEARANCE_TYPE_WILL_O_WISP:
case APPEARANCE_TYPE_WRAITH:
case APPEARANCE_TYPE_WYRMLING_BLACK:
case APPEARANCE_TYPE_WYRMLING_BLUE:
case APPEARANCE_TYPE_WYRMLING_BRASS:
case APPEARANCE_TYPE_WYRMLING_BRONZE:
case APPEARANCE_TYPE_WYRMLING_COPPER:
case APPEARANCE_TYPE_WYRMLING_GOLD:
case APPEARANCE_TYPE_WYRMLING_GREEN:
case APPEARANCE_TYPE_WYRMLING_RED:
case APPEARANCE_TYPE_WYRMLING_SILVER:
case APPEARANCE_TYPE_WYRMLING_WHITE:
case APPEARANCE_TYPE_ELEMENTAL_WATER:
case APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER:
// hordes
case 401: //beholder
case 402: //beholder
case 403: //beholder
case 419: // harpy
case 430: // Demi Lich
case 472: // Hive mother
{
bFlying = TRUE;
}
break;
}
if(!bFlying)
{
// Checking effect appear disappear - like flying dragons
bFlying = SMP_GetHasEffect(EFFECT_TYPE_DISAPPEARAPPEAR, oCreature);
}
return bFlying;
}
// SMP_INC_SPELLS.
// * Returns true if the creature has flesh
int SMP_SpellsIsImmuneToPetrification(object oCreature)
{
int nAppearance = GetAppearanceType(oCreature);
int bImmune = FALSE;
switch (nAppearance)
{
case APPEARANCE_TYPE_BASILISK:
case APPEARANCE_TYPE_COCKATRICE:
case APPEARANCE_TYPE_MEDUSA:
case APPEARANCE_TYPE_ALLIP:
case APPEARANCE_TYPE_ELEMENTAL_AIR:
case APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER:
case APPEARANCE_TYPE_ELEMENTAL_EARTH:
case APPEARANCE_TYPE_ELEMENTAL_EARTH_ELDER:
case APPEARANCE_TYPE_ELEMENTAL_FIRE:
case APPEARANCE_TYPE_ELEMENTAL_FIRE_ELDER:
case APPEARANCE_TYPE_ELEMENTAL_WATER:
case APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER:
case APPEARANCE_TYPE_GOLEM_STONE:
case APPEARANCE_TYPE_GOLEM_IRON:
case APPEARANCE_TYPE_GOLEM_CLAY:
case APPEARANCE_TYPE_GOLEM_BONE:
case APPEARANCE_TYPE_GORGON:
case APPEARANCE_TYPE_HEURODIS_LICH:
case APPEARANCE_TYPE_LANTERN_ARCHON:
case APPEARANCE_TYPE_SHADOW:
case APPEARANCE_TYPE_SHADOW_FIEND:
case APPEARANCE_TYPE_SHIELD_GUARDIAN:
case APPEARANCE_TYPE_SKELETAL_DEVOURER:
case APPEARANCE_TYPE_SKELETON_CHIEFTAIN:
case APPEARANCE_TYPE_SKELETON_COMMON:
case APPEARANCE_TYPE_SKELETON_MAGE:
case APPEARANCE_TYPE_SKELETON_PRIEST:
case APPEARANCE_TYPE_SKELETON_WARRIOR:
case APPEARANCE_TYPE_SKELETON_WARRIOR_1:
case APPEARANCE_TYPE_SPECTRE:
case APPEARANCE_TYPE_WILL_O_WISP:
case APPEARANCE_TYPE_WRAITH:
case APPEARANCE_TYPE_BAT_HORROR:
// Hordes
case APPEARANCE_TYPE_DRACOLICH: // Dracolich:
case APPEARANCE_TYPE_MINDFLAYER_ALHOON: // Alhoon
case APPEARANCE_TYPE_DRAGON_SHADOW: // shadow dragon
case APPEARANCE_TYPE_GOLEM_MITHRAL: // mithral golem
case APPEARANCE_TYPE_GOLEM_ADAMANTIUM: // admantium golem
case APPEARANCE_TYPE_DEMI_LICH: // Demi Lich
case APPEARANCE_TYPE_ANIMATED_CHEST: // animated chest
case APPEARANCE_TYPE_GOLEM_DEMONFLESH: // golems
case APPEARANCE_TYPE_DWARF_GOLEM: // golems
{
bImmune = TRUE;
}
}
// No death for things that cannot be destroyed.
if(!bImmune)
{
bImmune = SMP_CanCreatureBeDestroyed(oCreature);
}
// Item Property Immunity to Petrification (But no IMMUNITY_TYPE_PETRIFICATION)
// does exsist. This is ResistSpell() == 2
if(!bImmune && ResistSpell(OBJECT_SELF, oCreature) == 2)
{
bImmune == TRUE;
}
return bImmune;
}
/*:://////////////////////////////////////////////
//:: Name Bullrush Attack
//:: Function Name SMP_Bullrush
//:://////////////////////////////////////////////
Performs a D&D bullrush attack against oTarget.
- Used to push back a person in forceful hand.
//:://////////////////////////////////////////////
//:: Created By: Jasperre
//::////////////////////////////////////////////*/
// SMP_INC_SPELLS. Bullrush attack
// - Uses oTarget's strength, add modifiers, against nCasterModifier.
// - Reports results to caster and target
int SMP_Bullrush(object oTarget, int nCasterModifier, object oCaster = OBJECT_SELF)
{
// Check if oTarget is immune to bullrush
if(SMP_ImmuneToBullrush(oTarget))
{
return FALSE;
}
// Get the modifier for the target
int nTargetModifier = GetAbilityModifier(ABILITY_STRENGTH, oTarget);
// Add 2 if they are steady
if(SMP_GetIsSteady(oTarget))
{
nTargetModifier += 2;
}
// Add size modifier
nTargetModifier += SMP_GetSizeModifier(oTarget);
// We now make the rolls
int nCasterRoll = d20();
int nTargetRoll = d20();
string sMessage = "Bullrush Attack! Charger Roll: " + IntToString(nCasterRoll) + ", Modifier: " + IntToString(nCasterModifier) + ". Defender Roll: " + IntToString(nTargetRoll) + ", Modifier: " + IntToString(nTargetModifier) + ". RESULT: ";
// Check results and relay
if(nCasterRoll + nCasterModifier > nTargetRoll + nTargetModifier)
{
// Charger beats the defender
sMessage += "Charger Wins!";
FloatingTextStringOnCreature(sMessage, oTarget, FALSE);
FloatingTextStringOnCreature(sMessage, oCaster, FALSE);
// Return TRUE.
return TRUE;
}
else
{
// Defender beats the charger
sMessage += "Defender Wins!";
FloatingTextStringOnCreature(sMessage, oTarget, FALSE);
FloatingTextStringOnCreature(sMessage, oCaster, FALSE);
// Return FALSE
return FALSE;
}
// Default to false if error somehow.
return FALSE;
}
// SMP_INC_SPELLS. Bullrush
// - Returns TRUE if oCreature is immune to bullrush
// - Oozes, for instance.
int SMP_ImmuneToBullrush(object oCreature)
{
// Return immune if local variable set
if(GetLocalInt(oCreature, "SMP_SPELL_IMMUNE_TO_BULLRUSH")) return TRUE;
int nAppearance = GetAppearanceType(oCreature);
// Is it some odd creature, which is immune to being held or pushed back?
// - EG: Oozes.
switch(nAppearance)
{
case APPEARANCE_TYPE_ARCH_TARGET:
case APPEARANCE_TYPE_COMBAT_DUMMY:
{
return TRUE;
}
break;
}
return FALSE;
}
// SMP_INC_SPELLS. Bullrush.
// * Returns the size modifier for bullrush in spells (XP1)
// +4 for every size over medium
// -4 for every size under medium. Medium = 0.
int SMP_GetSizeModifier(object oCreature)
{
int nSize = GetCreatureSize(oCreature);
int nModifier = 0;
switch(nSize)
{
case CREATURE_SIZE_TINY: nModifier = -8; break;
case CREATURE_SIZE_SMALL: nModifier = -4; break;
case CREATURE_SIZE_MEDIUM: nModifier = 0; break;
case CREATURE_SIZE_LARGE: nModifier = 4; break;
case CREATURE_SIZE_HUGE: nModifier = 8; break;
}
return nModifier;
}
// SMP_INC_SPELLS. Bullrush.
// * Returns TRUE if oCreature is steady.
// - Has more then 2 legs
// - Is steadying themselves by use of Defensive Casting or Expertise.
// - Is steady by moving slowly around!
int SMP_GetIsSteady(object oCreature)
{
// They are steady if moving slowly.
int iSpeed = GetMovementRate(oCreature);
// 0 = PC Movement Speed or invalid oCreature
// 1 = Immobile
// 2 = Very Slow
// 3 = Slow
// 4 = Normal
// 5 = Fast
// 6 = Very Fast
// 7 = Creature Default (defined in appearance.2da)
// 8 = DM Speed
if(iSpeed == 1 || iSpeed == 2 || iSpeed == 3)
{
return TRUE;
}
int nAppearance = GetAppearanceType(oCreature);
// Has it got more then two legs, or is otherwise steady? (such as a tree
// is steady, or ooze would be steady :-) ).
switch(nAppearance)
{
case APPEARANCE_TYPE_ARANEA: // 6-8 legs
case APPEARANCE_TYPE_BADGER: // 4
case APPEARANCE_TYPE_BADGER_DIRE: // 4
case APPEARANCE_TYPE_BASILISK: // 4
case APPEARANCE_TYPE_BEAR_BLACK: // 4
case APPEARANCE_TYPE_BEAR_BROWN: // 4
case APPEARANCE_TYPE_BEAR_DIRE: // 4
case APPEARANCE_TYPE_BEAR_KODIAK: // 4
case APPEARANCE_TYPE_BEAR_POLAR: // 4
case APPEARANCE_TYPE_BEETLE_FIRE: // 6
case APPEARANCE_TYPE_BEETLE_SLICER: // 6
case APPEARANCE_TYPE_BEETLE_STAG: // 6
case APPEARANCE_TYPE_BEETLE_STINK: // 6
case APPEARANCE_TYPE_BOAR: // 4
case APPEARANCE_TYPE_BOAR_DIRE: // 4
case APPEARANCE_TYPE_CAT_CAT_DIRE: // 4
case APPEARANCE_TYPE_CAT_COUGAR: // 4
case APPEARANCE_TYPE_CAT_CRAG_CAT: // 4
case APPEARANCE_TYPE_CAT_JAGUAR: // 4
case APPEARANCE_TYPE_CAT_KRENSHAR: // 4
case APPEARANCE_TYPE_CAT_LEOPARD: // 4
case APPEARANCE_TYPE_CAT_LION: // 4
case APPEARANCE_TYPE_CAT_MPANTHER: // 4
case APPEARANCE_TYPE_CAT_PANTHER: // 4
case APPEARANCE_TYPE_COW: // 4
case APPEARANCE_TYPE_DEER: // 4
case APPEARANCE_TYPE_DEER_STAG: // 4
case APPEARANCE_TYPE_DOG: // 4
case APPEARANCE_TYPE_DOG_BLINKDOG: // 4
case APPEARANCE_TYPE_DOG_DIRE_WOLF: // 4
case APPEARANCE_TYPE_DOG_FENHOUND: // 4
case APPEARANCE_TYPE_DOG_HELL_HOUND:// 4
case APPEARANCE_TYPE_DOG_SHADOW_MASTIF:// 4
case APPEARANCE_TYPE_DOG_WINTER_WOLF:// 4
case APPEARANCE_TYPE_DOG_WOLF: // 4
case APPEARANCE_TYPE_DOG_WORG: // 4
// Note - We count large dragons as always being steady
case APPEARANCE_TYPE_DRAGON_BLACK:
case APPEARANCE_TYPE_DRAGON_BLUE:
case APPEARANCE_TYPE_DRAGON_BRASS:
case APPEARANCE_TYPE_DRAGON_BRONZE:
case APPEARANCE_TYPE_DRAGON_COPPER:
case APPEARANCE_TYPE_DRAGON_GOLD:
case APPEARANCE_TYPE_DRAGON_GREEN:
case APPEARANCE_TYPE_DRAGON_RED:
case APPEARANCE_TYPE_DRAGON_SILVER:
case APPEARANCE_TYPE_DRAGON_WHITE:
case APPEARANCE_TYPE_FORMIAN_MYRMARCH:// 4
case APPEARANCE_TYPE_FORMIAN_QUEEN: // 4
case APPEARANCE_TYPE_FORMIAN_WARRIOR:// 4
case APPEARANCE_TYPE_FORMIAN_WORKER:// 4
case APPEARANCE_TYPE_GORGON: // 4
case APPEARANCE_TYPE_GYNOSPHINX: // 4
case APPEARANCE_TYPE_INTELLECT_DEVOURER:// 4
case APPEARANCE_TYPE_MANTICORE: // 4
case APPEARANCE_TYPE_OX: // 4
case APPEARANCE_TYPE_RAT: // 4
case APPEARANCE_TYPE_RAT_DIRE: // 4
case APPEARANCE_TYPE_SPHINX: // 4
case APPEARANCE_TYPE_SPIDER_DIRE: // 6-8
case APPEARANCE_TYPE_SPIDER_GIANT: // 6-8
case APPEARANCE_TYPE_SPIDER_PHASE: // 6-8
case APPEARANCE_TYPE_SPIDER_SWORD: // 6-8
case APPEARANCE_TYPE_SPIDER_WRAITH: // 6-8
case APPEARANCE_TYPE_STINGER: // 4
case APPEARANCE_TYPE_STINGER_CHIEFTAIN:// 4
case APPEARANCE_TYPE_STINGER_MAGE: // 4
case APPEARANCE_TYPE_STINGER_WARRIOR:// 4
case APPEARANCE_TYPE_WAR_DEVOURER: // 4
{
return TRUE;
}
break;
}
return FALSE;
}
// SMP_INC_SPELLS. Moves the target back from their current position,
// away from oTarget, fDistance.
void SMP_DoMoveBackwards(object oSource, object oTarget, float fDistance)
{
// Get new location fDistance behind them.
location lMoveTo = SMP_GetLocationBehind(oSource, oTarget, fDistance);
// Move them back to that location using the special function
AssignCommand(oTarget, SMP_ForceMovementToLocation(lMoveTo));
}
// SMP_INC_SPELLS. Can the creature be destroyed without breaking a plot?
// - Immortal, Plot or DM returns FALSE.
int SMP_CanCreatureBeDestroyed(object oTarget)
{
if (GetPlotFlag(oTarget) == FALSE &&
GetImmortal(oTarget) == FALSE &&
GetIsDM(oTarget) == FALSE &&
GetIsDead(oTarget) == FALSE)
{
return TRUE;
}
return FALSE;
}
// SMP_INC_SPELLS. Is oTarget in a maze area? (enables some spells really)
int SMP_IsInMazeArea(object oTarget = OBJECT_SELF)
{
// Maze waypoint
object oWP = GetWaypointByTag(SMP_S_MAZE_TARGET);
if(GetIsObjectValid(oWP) && GetArea(oWP) == GetArea(oTarget))
{
// Return TRUE if same area
return TRUE;
}
// Return FALSE
return FALSE;
}
// SMP_INC_SPELLS. Is oTarget in a Imprisonment area? (only used to check to jump back really)
int SMP_IsInPrisonArea(object oTarget = OBJECT_SELF)
{
// Imprisonment waypoint
object oWP = GetWaypointByTag(SMP_S_IMPRISONMENT_TARGET);
if(GetIsObjectValid(oWP) && GetArea(oWP) == GetArea(oTarget))
{
// Return TRUE if same area
return TRUE;
}
// Return FALSE
return FALSE;
}
// SMP_INC_SPELLS. Returns TRUE if oTarget is an Minotaur. Maze spell uses this.
int SMP_GetIsMinotaur(object oTarget)
{
int nAppearance = GetAppearanceType(oTarget);
int bReturn = FALSE;
switch (nAppearance)
{
case APPEARANCE_TYPE_MINOGON:
case APPEARANCE_TYPE_MINOTAUR:
case APPEARANCE_TYPE_MINOTAUR_CHIEFTAIN:
case APPEARANCE_TYPE_MINOTAUR_SHAMAN:
{
bReturn = TRUE;
}
break;
}
// Minotaur subrace
if(FindSubString("MINOTAUR", GetStringUpperCase(GetSubRace(oTarget))) > FALSE)
{
bReturn = TRUE;
}
return bReturn;
}
// SMP_INC_SPELLS. Returns TRUE if oTarget is an Astral creature
int SMP_GetIsAstral(object oTarget)
{
if(GetLocalInt(oTarget, "SPELL_IS_ASTRAL"))
{
return TRUE;
}
return FALSE;
}
// SMP_INC_SPELLS. Returns TRUE if oTarget is an Ethereal, or an Ethereal creature
int SMP_GetIsEthereal(object oTarget)
{
if(SMP_GetHasEffect(EFFECT_TYPE_ETHEREAL, oTarget) ||
GetLocalInt(oTarget, "SPELL_IS_ETHEREAL"))
{
return TRUE;
}
return FALSE;
}
// SMP_INC_SPELLS. This returns TRUE if they are Incorporeal, via. local variable,
// spell or effect
int SMP_GetIsIncorporeal(object oTarget)
{
// Incorporal flag
if(GetLocalInt(oTarget, "INCORPOREAL")) return TRUE;
// Check Etherealness
if(SMP_GetIsEthereal(oTarget)) return TRUE;
// Check appearance type
switch(GetAppearanceType(oTarget))
{
case APPEARANCE_TYPE_INVISIBLE_STALKER:
case APPEARANCE_TYPE_SHADOW:
case APPEARANCE_TYPE_SHADOW_FIEND:
case APPEARANCE_TYPE_WRAITH:
{
return TRUE;
}
break;
}
// Spells
if(GetHasSpellEffect(SMP_SPELL_GASEOUS_FORM, oTarget))
{
return TRUE;
}
return FALSE;
}
// Immune to polymorph - also plays approprate effect.
// * Returns TRUE if oTarget cannot be polymorphed.
int SMP_ImmuneToPolymorph(object oTarget)
{
if(SMP_GetIsIncorporeal(oTarget))
{
effect eMantle = EffectVisualEffect(VFX_IMP_SPELL_MANTLE_USE);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eMantle, oTarget);
return TRUE;
}
return FALSE;
}
// SMP_INC_SPELLS. Returns TRUE if oTarget is Crystalline - earthy
int SMP_GetIsCrystalline(object oTarget)
{
if(GetLocalInt(oTarget, SMP_CRYSTALLINE))
{
return TRUE;
}
// Check appearance
switch(GetAppearanceType(oTarget))
{
case APPEARANCE_TYPE_ELEMENTAL_EARTH:
case APPEARANCE_TYPE_ELEMENTAL_EARTH_ELDER:
{
return TRUE;
}
break;
}
return FALSE;
}
// SMP_INC_SPELLS. Sorts out metamagic checks, using Random()
// * nDiceSides (EG: 6 for D6 dice) * nNumberOfDice (EG: 2, for 2d6)
// * nBonus - Bonus to at the end.
// * Does include Maximise and Empower checks.
// * nTouch - If 2, it is a critcal, and does double what it would normally return.
int SMP_MaximizeOrEmpower(int nDiceSides, int nNumberOfDice, int nMeta, int nBonus = 0, int nTouch = 0)
{
int nDiceReturn, nCnt;
//Resolve metamagic
if(nMeta == METAMAGIC_MAXIMIZE)
{
nDiceReturn = nDiceSides * nNumberOfDice;
}
else
{
// Else, can be empowered or normal. Roll dice
for(nCnt = 1; nCnt <= nNumberOfDice; nCnt++)
{
nDiceReturn += Random(nDiceSides) + 1;
}
// Resolve metamagic empower
if(nMeta == METAMAGIC_EMPOWER)
{
nDiceReturn = nDiceReturn + (nDiceReturn/2);
}
}
// Add bonus.
nDiceReturn += nBonus;
// Make sure we multiply if touch attack based.
if(nTouch == 2)
{
nDiceReturn * 2;
}
return nDiceReturn;
}
// SMP_INC_SPELLS. Works out a dice-rolled time.
// * nType - use SMP_ROUNDS (6 sec), SMP_MINUTES (60 sec), SMP_HOURS (mod dependant)
// * nDiceSides, nNumberOfDice - The dice (EG 5, 6sided dice = 6, 5)
// * nMeta - Metamagic feat EXTEND is used here
// * nBonus - Added before metamagic, such as 4d(caster level) + Bonus.
float SMP_GetRandomDuration(int nType, int nDiceSides, int nNumberOfDice, int nMeta, int nBonusTime = 0)
{
int nDiceRolls, nCnt;
// Roll dice
for(nCnt = 1; nCnt <= nNumberOfDice; nCnt++)
{
nDiceRolls = nDiceRolls + Random(nDiceSides - 1) + 1;
}
// Resolve metamagic
int nTotal = nDiceRolls + nBonusTime;
if(nMeta == METAMAGIC_EXTEND)
{
nTotal *= 2;// x2 duration
}
// Returns the right time
float fTime;
if(nType == SMP_ROUNDS)
{
fTime = RoundsToSeconds(nTotal);
}
else if(nType == SMP_MINUTES)
{
fTime = TurnsToSeconds(nTotal);
}
else if(nType == SMP_HOURS)
{
fTime = HoursToSeconds(nTotal);
}
return fTime;
}
// SMP_INC_SPELLS. Works out a normal time. Useful wrapper.
// * nType - use SMP_ROUNDS (6 sec), SMP_MINUTES (60 sec), SMP_HOURS (mod dependant)
// * nTime - the time in hours, rounds or turns
// * nMeta - The metamagic feat EXTEND is also taken into account..
float SMP_GetDuration(int nType, int nTime, int nMeta)
{
// Error checking
if(nTime < 1) nTime = 1;
// Resolve metamagic
if(nMeta == METAMAGIC_EXTEND)
{
nTime *= 2;// x2 duration
}
// Returns the right time
float fTime;
if(nType == SMP_ROUNDS)
{
fTime = RoundsToSeconds(nTime);
}
else if(nType == SMP_MINUTES)
{
fTime = TurnsToSeconds(nTime);
}
else if(nType == SMP_HOURS)
{
fTime = HoursToSeconds(nTime);
}
return fTime;
}
// SMP_INC_SPELLS. Does a fortitude check and applys EffectPetrify :-)
// - Taken from Bioware's petrify. More generic however.
// - No ReactionType checks.
// - Will not petrify immune creatures
// * oTarget - Target
// * nCasterLevel - Either the hit dice of the creature or the caster level
// * nFortSaveDC: pass in this number from the spell script
// - It will also apply bonuses of a construct.
void SMP_SpellFortitudePetrify(object oTarget, int nCasterLevel, int nFortSaveDC)
{
// * Exit if creature is immune to petrification
if(SMP_SpellsIsImmuneToPetrification(oTarget)) return;
float fDifficulty = 0.0;
int bShowPopup = FALSE;
// Declare effects
// * Proper, statue, link. Construct immunities linked.
effect eLink = SMP_CreateProperPetrifyEffectLink();
// Do a fortitude save check
if(!SMP_SavingThrow(SAVING_THROW_FORT, oTarget, nFortSaveDC))
{
// * The duration is permanent against NPCs but only temporary against PCs
// unless the PC's are playing core rules or higher.
if(GetIsPC(oTarget))
{
// * Under hardcore rules or higher, this is an instant death
if(GetGameDifficulty() >= GAME_DIFFICULTY_CORE_RULES)
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget);
// Death panel
DelayCommand(2.75, PopUpDeathGUIPanel(oTarget, FALSE , TRUE, 40579));
}
else
{
// Apply for nCasterLevel rounds.
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nCasterLevel));
}
}
else
// * NPCs get full effect. No death panel.
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget);
}
// April 2003: Clearing actions to kick them out of conversation when petrified
AssignCommand(oTarget, ClearAllActions());
}
}
// SMP_INC_SPELLS. Creates a new location from lLocation on a varying X and Y value, in increments
// of 1 meter.
// * nRandom - this is the number you want to randomise. It will be up to HALF
// this in meters from lLocation, north south east or west.
location SMP_GetRandomLocation(location lLocation, int nRandom)
{
vector vOld = GetPositionFromLocation(lLocation);
float fFacing = IntToFloat(Random(360));
float fNewX = vOld.x + IntToFloat(Random(nRandom) - (nRandom/2));
float fNewY = vOld.y + IntToFloat(Random(nRandom) - (nRandom/2));
float fNewZ = vOld.z;
vector vNew = Vector(fNewX, fNewY, fNewZ);
location lReturn = Location(GetAreaFromLocation(lLocation), vNew, fFacing);
// Return the finnished one
return lReturn;
}
// SMP_INC_SPELLS. Returns bolts, arrows, bullets or -1 for the ammo item type used by oWeapon.
int SMP_GetWeaponsAmmoType(object oWeapon)
{
int nItemType = GetBaseItemType(oWeapon);
if(nItemType == BASE_ITEM_LONGBOW || nItemType == BASE_ITEM_SHORTBOW)
{
return BASE_ITEM_ARROW;
}
else if(nItemType == BASE_ITEM_HEAVYCROSSBOW || nItemType == BASE_ITEM_LIGHTCROSSBOW)
{
return BASE_ITEM_BOLT;
}
else if(nItemType == BASE_ITEM_SLING)
{
return BASE_ITEM_BULLET;
}
return -1;
}
// SMP_INC_SPELLS. Gets the right slot for iBaseAmmoType or -1.
int SMP_GetAmmoSlot(int nBaseAmmoType)
{
if(nBaseAmmoType == BASE_ITEM_ARROW)
{
return INVENTORY_SLOT_ARROWS;
}
else if(nBaseAmmoType == BASE_ITEM_BOLT)
{
return INVENTORY_SLOT_BOLTS;
}
else if(nBaseAmmoType == BASE_ITEM_BULLET)
{
return INVENTORY_SLOT_BULLETS;
}
return -1;
}
// SMP_INC_SPELLS. Is the creature dazzeled?
// Spells include:
// - Flare
int SMP_GetIsDazzled(object oTarget)
{
effect eCheck = GetFirstEffect(oTarget);
int nSpell;
while(GetIsEffectValid(eCheck))
{
nSpell = GetEffectSpellId(eCheck);
// Check spells
switch(nSpell)
{
case SMP_SPELL_FLARE:
{
return TRUE;
}
break;
}
eCheck = GetNextEffect(oTarget);
}
return FALSE;
}
// SMP_INC_SPELLS. Can the caster, oCaster, teleport to lTarget without disrupting a module?
// - Trigger, if at the location or the caster, stops it
// - The area can be made "No teleport"
int SMP_CannotTeleport(object oCaster, location lTarget)
{
// Check for Dimensional Anchor
if(SMP_GetDimensionalAnchor(oCaster))
{
SendMessageToPC(oCaster, "Your Dimensional Anchor stops extraplanar travel!");
return TRUE;
}
// Check for waypoint
object oWP = GetWaypointByTag("SMP_SPELL_NO_TELEPORT_WP");
if(GetIsObjectValid(oWP))
{
// Return TRUE - cannot teleport
SendMessageToPC(oCaster, "Your movement spell is disrupted!");
return TRUE;
}
// Get nearest teleport trigger.
object oTeleportTrigger = GetNearestObjectByTag("SMP_SPELL_NO_TELEPORT", oCaster);
// Make sure oCaster is not in the trigger
if(GetIsObjectValid(oTeleportTrigger) &&
GetObjectType(oTeleportTrigger) == OBJECT_TYPE_TRIGGER)
{
// Loop objects in the trigger
object oInTrig = GetFirstInPersistentObject(oTeleportTrigger, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oInTrig))
{
// Cannot teleport if in the trigger
if(oInTrig == oCaster)
{
SendMessageToPC(oCaster, "Your movement spell is disrupted!");
return TRUE;
}
oInTrig = GetNextInPersistentObject(oTeleportTrigger, OBJECT_TYPE_CREATURE);
}
// If we didn't find the caster was in the known trigger, check the
// location
// Make sure, that the location is valid, and not in a trigger
// - We create a placeable object, invisible object, of a new tag mind
// you, for this.
string sCaster = ObjectToString(oCaster);
object oNewPlaceable = CreateObject(OBJECT_TYPE_PLACEABLE, "invis", lTarget, FALSE, sCaster);
// We check the nearest trigger to the target location
oTeleportTrigger = GetNearestObjectByTag("SMP_SPELL_NO_TELEPORT", oNewPlaceable);
if(GetIsObjectValid(oTeleportTrigger))
{
if(GetObjectType(oTeleportTrigger) == OBJECT_TYPE_TRIGGER)
{
// Loop the objects in the teleport trigger
oInTrig = GetFirstInPersistentObject(oTeleportTrigger, OBJECT_TYPE_PLACEABLE);
while(GetIsObjectValid(oInTrig))
{
// Cannot teleport if in the trigger
if(oInTrig == oNewPlaceable)
{
DestroyObject(oNewPlaceable);
SendMessageToPC(oCaster, "Your movement spell is disrupted!");
return TRUE;
}
oInTrig = GetNextInPersistentObject(oTeleportTrigger, OBJECT_TYPE_PLACEABLE);
}
}
}
// We check for any Forbiddance in the target location.
oTeleportTrigger = GetNearestObjectByTag(SMP_AOE_TAG_PER_FORBIDDANCE, oNewPlaceable);
if(GetIsObjectValid(oTeleportTrigger))
{
if(GetObjectType(oTeleportTrigger) == OBJECT_TYPE_AREA_OF_EFFECT)
{
// Loop the objects in the teleport trigger
oInTrig = GetFirstInPersistentObject(oTeleportTrigger, OBJECT_TYPE_PLACEABLE);
while(GetIsObjectValid(oInTrig))
{
// Cannot teleport if in the trigger
if(oInTrig == oNewPlaceable)
{
DestroyObject(oNewPlaceable);
SendMessageToPC(oCaster, "Your movement spell is disrupted by Dimensional Lock!");
return TRUE;
}
oInTrig = GetNextInPersistentObject(oTeleportTrigger, OBJECT_TYPE_PLACEABLE);
}
}
}
// FINALLY, we check for any Dimensional Anchors in the target location.
oTeleportTrigger = GetNearestObjectByTag(SMP_AOE_TAG_PER_DIMENSIONAL_LOCK, oNewPlaceable);
if(GetIsObjectValid(oTeleportTrigger))
{
if(GetObjectType(oTeleportTrigger) == OBJECT_TYPE_AREA_OF_EFFECT)
{
// Loop the objects in the teleport trigger
oInTrig = GetFirstInPersistentObject(oTeleportTrigger, OBJECT_TYPE_PLACEABLE);
while(GetIsObjectValid(oInTrig))
{
// Cannot teleport if in the trigger
if(oInTrig == oNewPlaceable)
{
DestroyObject(oNewPlaceable);
SendMessageToPC(oCaster, "Your movement spell is disrupted by Dimensional Lock!");
return TRUE;
}
oInTrig = GetNextInPersistentObject(oTeleportTrigger, OBJECT_TYPE_PLACEABLE);
}
}
}
}
// We can teleport or whatever.
return FALSE;
}
// SMP_INC_SPELLS. Returns TRUE if oCreature is locked in this dimension by:
// - Dimensional Anchor
// - Dimensional Lock
int SMP_GetDimensionalAnchor(object oCreature)
{
if(GetHasSpellEffect(SMP_SPELL_DIMENSIONAL_ANCHOR, oCreature) ||
GetHasSpellEffect(SMP_SPELL_DIMENSIONAL_LOCK, oCreature) ||
GetHasSpellEffect(SMP_SPELL_FORBIDDANCE, oCreature))
{
return TRUE;
}
return FALSE;
}
// This is used for some spells to limit creatures by size. EG: Dimension door.
// This returns:
// - 1 for Medium, small and tiny creatures.
// - 2 for Large (Equivilant of 2 medium creatures)
// - 4 for Huge creature sizes (Equivilant of 2 Large creatures)
int SMP_SizeEquvilant(object oCreature)
{
int nReturn = 1;
int nSize = GetCreatureSize(oCreature);
// Check size of creature
switch(nSize)
{
case CREATURE_SIZE_TINY: nReturn = 1; break;
case CREATURE_SIZE_SMALL: nReturn = 1; break;
case CREATURE_SIZE_MEDIUM: nReturn = 1; break;
case CREATURE_SIZE_LARGE: nReturn = 2; break;
case CREATURE_SIZE_HUGE: nReturn = 4; break;
}
return nReturn;
}
// SMP_INC_SPELLS. Removes all Fatigue/Exhaustion from oTarget.
void SMP_RemoveFatigue(object oTarget)
{
// Check for spells of X type...
// - Ability Fatigue is just fatigue :-)
object oFatigue = GetObjectByTag("SMP_PLC_FATIGUE");
effect eCheck = GetFirstEffect(oTarget);
while(GetIsEffectValid(eCheck))
{
// Check creator of the effect is fatigue
if(GetEffectCreator(eCheck) == oFatigue)
{
RemoveEffect(oTarget, eCheck);
}
eCheck = GetNextEffect(oTarget);
}
}
// SMP_INC_SPELLS. Applys a new Fatigue effect to oTarget, if not already got it...
// * If bExhaustion is TRUE, it applies Exhaustion instead.
// * Exhaustion "overrides" any fatigue, and using the Bioware problem of
// ability penalties not stacking, will mearly apply exhasution over fatigue.
// (Noting, of course, speed decreases stack. Anyone exhausted also becomes fatiged,
// but not vice versa).
// * Stats: Fatigue: 20% move penalty. -2 Dex and STR.
// Exhaustion: An additional -4 to Dex and STR, -20% speed. (so -6, 40%)
void SMP_ApplyFatigue(object oTarget, int bExhaustion = FALSE, int nDurationType = DURATION_TYPE_PERMANENT, float fDuration = 0.0)
{
// Get the fatigue creator
object oCreator = GetObjectByTag("SMP_PLC_FATIGUE");
// Set the object to affect, the duration type and the duration, and if
// fatigue.
SetLocalObject(oCreator, "FATIGUE_TARGET", oTarget);
SetLocalInt(oCreator, "FATIGUE_DURATION_TYPE", nDurationType);
SetLocalFloat(oCreator, "FATIGUE_DURATION", fDuration);
SetLocalInt(oCreator, "FATIGUE_EXHAUSTION", bExhaustion);
// Make them apply effects in the script.
// * Fatigue is defined by who created the fatigue.
ExecuteScript("SMP_ail_fatigue", oCreator);
}
// SMP_INC_SPELLS.
// Returns iHighest if it is over nHighest, or nLowest if under nLowest, or
// the integer put in (nInteger) if between them already.
int SMP_LimitInteger(int nInteger, int nHighest = 100, int nLowest = 1)
{
if(nInteger > nHighest)
{
return nHighest;
}
else if(nInteger < nLowest)
{
return nLowest;
}
return nInteger;
}
// SMP_INC_SPELLS. This is fired from AI files.
// - Removes cirtain spells if the target is attacked, harmed and so on during
// the spells effects.
void SMP_RemoveSpellsIfAttacked(object oAttacked = OBJECT_SELF)
{
// - Removes Halt Undead effects
SMP_RemoveSpellEffectsFromTarget(SMP_SPELL_HALT_UNDEAD, oAttacked);
// - Others...
}
// SMP_INC_SPELLS. This DESTROYS oTarget.
// - Removes plot flags, all inventory, before proper destorying.
void SMP_PermamentlyRemove(object oTarget)
{
// Error check
if(GetIsPC(oTarget)) return;
// We can destroy them
SetPlotFlag(oTarget, FALSE);
SetImmortal(oTarget, FALSE);
// If a creature, make sure their corpse is off
if(GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
{
AssignCommand(oTarget, ClearAllActions());
AssignCommand(oTarget, SetIsDestroyable(TRUE, FALSE, FALSE));
SetLootable(oTarget, FALSE);
}
// Destory inventory
if(GetHasInventory(oTarget))
{
object oItem = GetFirstItemInInventory(oTarget);
while(GetIsObjectValid(oItem))
{
SetPlotFlag(oItem, FALSE);
DestroyObject(oItem);
oItem = GetNextItemInInventory(oTarget);
}
}
// Destroy target
DestroyObject(oTarget);
}
// SMP_INC_SPELLS. Increase or decrease a stored integer on oTarget, by
// nAmount, under sName
// * Returns Stored amount + nAmount, the new integer set.
int SMP_IncreaseStoredInteger(object oTarget, string sName, int nAmount = 1)
{
// Get old
int nOriginal = GetLocalInt(oTarget, sName);
// Add new
int nNew = nOriginal + nAmount;
// Set new
SetLocalInt(oTarget, sName, nNew);
// Return the new value
return nNew;
}
// SMP_INC_SPELLS. Use in DelayCommand(), to delete integer under sName
// on oTarget. Deleted only if oTarget is valid!
void SMP_DelayedDeleteInteger(object oTarget, string sName)
{
if(GetIsObjectValid(oTarget))
{
DeleteLocalInt(oTarget, sName);
}
}
// SMP_INC_SPELLS. Returns TRUE if oTarget's subrace is plant, or integer SMP_PLANT is valid.
int SMP_GetIsPlant(object oTarget)
{
if(FindSubString(GetStringUpperCase(GetSubRace(oTarget)), "PLANT") >= 0)
{
return TRUE;
}
else if(GetLocalInt(oTarget, SMP_PLANT))
{
return TRUE;
}
return FALSE;
}
// SMP_INC_SPELLS. Returns TRUE if oTarget's subrace is water elemental,
// or thier appearance is that of a water elemental.
int SMP_GetIsWaterElemental(object oTarget)
{
string sSubrace = GetStringUpperCase(GetSubRace(oTarget));
if(FindSubString(sSubrace, "WATER") >= 0 &&
FindSubString(sSubrace, "ELEMENTAL") >= 0)
{
return TRUE;
}
// Check appearance type
switch(GetAppearanceType(oTarget))
{
case APPEARANCE_TYPE_ELEMENTAL_WATER:
case APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER:
{
return TRUE;
}
break;
}
return FALSE;
}
// SMP_INC_SPELLS.
// This will make sure that oTarget is not commandable, and also that the
// commandable was not applied by some other spell which is active.
void SMP_SetCommandableOnSafe(object oTarget, int iSpellRemove)
{
if(GetIsObjectValid(oTarget) && !GetCommandable(oTarget))
{
// Check spells which use SetCommandable
if((!GetHasSpellEffect(SMP_SPELL_BESTOW_CURSE, oTarget) || iSpellRemove == SMP_SPELL_BESTOW_CURSE) &&
(!GetHasSpellEffect(SMP_SPELL_IMPRISONMENT, oTarget) || iSpellRemove == SMP_SPELL_IMPRISONMENT))
{
SetCommandable(TRUE, oTarget);
}
}
}
// SMP_INC_SPELLS.
// Automatically reports sucess or failure for the ability check. The roll
// of d20 + nAbility's scrore needs to be >= nDC.
int SMP_AbilityCheck(object oCheck, int nAbility, int nDC)
{
int nAbilityScore = GetAbilityScore(oCheck, nAbility);
if(nAbilityScore + d20() >= nDC)
{
SendMessageToPC(oCheck, "Ability Check: Pass");
return TRUE;
}
else
{
SendMessageToPC(oCheck, "Ability Check: Fail");
}
return FALSE;
}
// SMP_INC_SPELLS. Applys the visual effect nVis, across from oStart to the object oTarget,
// at intervals of 0.05, playing the visual in the direction.
void SMP_ApplyBeamAlongVisuals(int nVis, object oStart, object oTarget, float fIncrement = 1.0)
{
effect eVis = EffectVisualEffect(nVis);
float fDelay;
object oArea = GetArea(oStart);
vector vTarget = GetPosition(oStart);
vector vCaster = GetPosition(oTarget);
vector vEffectStep = vTarget - vCaster; /* Get the vector from caster to target */
int iFXCount = FloatToInt(VectorMagnitude(vEffectStep)/fIncrement); /* Determine the number of effects needed */
vEffectStep = (VectorNormalize(vEffectStep) * fIncrement); /* generate the normalized vector (assuming a length of 1m) */
vector vEffect = vCaster + vEffectStep; /* first Effect location (fIncrement from caster) */
while(iFXCount > 0)
{
fDelay += 0.05;
DelayCommand(fDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, Location(oArea, vEffect, 0.0)));
vEffect += vEffectStep; /* Move effect location 1m */
iFXCount--; /* decrement the effect counter */
}
}
// SMP_INC_SPELLS. Returns TRUE if sunlight will kill/seriously damage/almost
// obliterate oTarget, IE: Vampires.
int SMP_GetHateSun(object oTarget)
{
switch(GetAppearanceType(oTarget))
{
case APPEARANCE_TYPE_VAMPIRE_MALE:
case APPEARANCE_TYPE_VAMPIRE_FEMALE:
{
return TRUE;
}
break;
}
// Check subrace
string sSubrace = GetStringUpperCase(GetSubRace(oTarget));
// Check subraces
if(FindSubString(sSubrace, "VAMPIRE") >= 0)
{
return TRUE;
}
return FALSE;
}
// SMP_INC_SPELLS. This will apply a duration effect, and set an amount of charges
// left to use nSpellId's power for, if they concentrate for another round using
// a special item.
void SMP_AddChargesForSpell(int nSpellId, int nCharges, float fDuration, object oCaster = OBJECT_SELF)
{
// Variable name
string sVariableName = "SMP_SPELL_CHARGES" + IntToString(nSpellId);
// New spell from a scroll or normal spell, ETC.
// Set charges and apply new effect
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
// Remove previous effects and apply this one
SMP_PRCRemoveSpellEffects(nSpellId, oCaster, oCaster);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, oCaster, fDuration);
// New charges
SetLocalInt(oCaster, sVariableName, nCharges);
// Message
SendMessageToPC(oCaster, "You can release the spell " + IntToString(nCharges) + " more times.");
}
// SMP_INC_SPELLS.
// This will check if they have any charges for nSpellId, or not as the case
// may be.
// * You can use bFeedback set to FALSE to surpress feedback (EG: test Call
// Lightning Storm and then Call Lightning, surpress CLS's feedback first).
// * Sucess always has feedback!
// * TRUE if the check passes, else FALSE
int SMP_CheckChargesForSpell(int nSpellId, int bFeedback = TRUE, object oCaster = OBJECT_SELF)
{
// Check caster item
string sVariableName = "SMP_SPELL_CHARGES" + IntToString(nSpellId);
// Check charges used by this item - do we have the effects at all?
if(SMP_GetHasSpellEffectFromCaster(nSpellId, oCaster, oCaster))
{
// Got the spell's effects, so thats good.
int nChargesNow = GetLocalInt(oCaster, sVariableName);
// Check charges
if(nChargesNow <= 0)
{
// No charges left
if(bFeedback) SendMessageToPC(oCaster, "You have no more charges of this spell to release.");
DeleteLocalInt(oCaster, sVariableName);
SMP_PRCRemoveSpellEffects(nSpellId, oCaster, oCaster);
return FALSE;
}
else
{
// Decrease charges by 1
nChargesNow--;
SetLocalInt(oCaster, sVariableName, nChargesNow);
SendMessageToPC(oCaster, "You can release the spell " + IntToString(nChargesNow) + " more times.");
return TRUE;
}
}
// Not got the spell's effects, bad, can't cast more
DeleteLocalInt(oCaster, sVariableName);
if(bFeedback) SendMessageToPC(oCaster, "You have not cast this spell in time, or not cast it at all, and cannot use another stored charge");
return FALSE;
}
// SMP_INC_SPELLS. This changes it permantly. (used in PlayMusicForDuration).
// * Set bNightOrDay to TRUE for daytime music.
void SMP_ChangeMusicPermantly(object oArea, int nTrack, int bNightOrDay)
{
MusicBackgroundStop(oArea);
if(bNightOrDay)
{
MusicBackgroundChangeDay(oArea, nTrack);
}
else
{
MusicBackgroundChangeNight(oArea, nTrack);
}
MusicBackgroundPlay(oArea);
}
// SMP_INC_SPELLS. This changed oArea's music to iTrack for fDuration.
// * Note: If either tracks are already nTrack, they don't change.
void SMP_PlayMusicForDuration(object oArea, int nTrack, float fDuration)
{
int nMusicNight = MusicBackgroundGetNightTrack(oArea);
int nMusicDay = MusicBackgroundGetDayTrack(oArea);
// Change it.
MusicBackgroundStop(oArea);
if(nMusicNight != nTrack)
{
MusicBackgroundChangeNight(oArea, nTrack);
DelayCommand(fDuration, SMP_ChangeMusicPermantly(oArea, nMusicNight, FALSE));
}
if(nMusicDay != nTrack)
{
MusicBackgroundChangeDay(oArea, nTrack);
DelayCommand(fDuration, SMP_ChangeMusicPermantly(oArea, nMusicDay, TRUE));
}
MusicBackgroundPlay(oArea);
}
// SMP_INC_SPELLS. This performs an area wether check.
// * Changes oAreas wether to nNewWether for fDuration.
void SMP_ChangeAreaWether(object oArea, int nNewWether, float fDuration)
{
// Return on error.
if(fDuration < 0.0 || nNewWether > 2 || nNewWether < -1 || !GetIsObjectValid(oArea)) return;
SetWeather(GetArea(OBJECT_SELF), nNewWether);
DelayCommand(fDuration, SetWeather(GetArea(OBJECT_SELF), WEATHER_USE_AREA_SETTINGS));
}
// SMP_INC_SPELLS.
// This will check the target, to see if they have broken thier concentration
// by moving, doing something else, or not being able to do anything.
// * It sets SMP_CONCENTRATION_CHECK_ + IntToString(nSpellId) to TRUE if broken.
int SMP_ConcentrationCheck(object oTarget, int nSpellId)
{
switch(GetCurrentAction(oTarget))
{
// Basically, the INVALID ones are put here.
case ACTION_DISABLETRAP:
case ACTION_TAUNT:
case ACTION_PICKPOCKET:
case ACTION_ATTACKOBJECT:
case ACTION_COUNTERSPELL:
case ACTION_FLAGTRAP:
case ACTION_CASTSPELL:
case ACTION_ITEMCASTSPELL:
{
// Not OK
SetLocalInt(oTarget, "SMP_CONCENTRATION_CHECK_" + IntToString(nSpellId), TRUE);
}
break;
default:
{
// All OK
}
break;
}
// Check if they can cast a spell!
effect eCheck = GetFirstEffect(oTarget);
while(GetIsEffectValid(eCheck))
{
switch(GetEffectType(eCheck))
{
case EFFECT_TYPE_CUTSCENE_PARALYZE:
case EFFECT_TYPE_CUTSCENEIMMOBILIZE:
case EFFECT_TYPE_DAZED:
case EFFECT_TYPE_FRIGHTENED:
case EFFECT_TYPE_PARALYZE:
case EFFECT_TYPE_PETRIFY:
case EFFECT_TYPE_POLYMORPH:
case EFFECT_TYPE_SLEEP:
case EFFECT_TYPE_STUNNED:
case EFFECT_TYPE_TURNED:
{
SetLocalInt(oTarget, "SMP_CONCENTRATION_CHECK_" + IntToString(nSpellId), TRUE);
return TRUE;
}
break;
}
eCheck = GetNextEffect(oTarget);
}
return FALSE;
}
// SMP_INC_SPELLS.
// This does a "detect" check for PC rogues - the range is 5ft non-search-mode,
// and 10ft for search mode. The DC is 25 + nLevel.
void SMP_MagicalTrapsDetect(int nLevel)
{
}
// SMP_INC_SPELLS, This removes:
// ability damage, blinded, confused,
// dazed, dazzled, deafened, diseased, exhausted, fatigued, feebleminded,
// insanity, nauseated, sickened, stunned, and poisoned.
void SMP_HealSpellRemoval(object oTarget)
{
// ability damage, blinded, confused,
// dazed, dazzled, deafened, diseased, exhausted, fatigued, feebleminded,
// insanity, nauseated, sickened, stunned, and poisoned.
effect eCheck = GetFirstEffect(oTarget);
// Loop effects
while(GetIsEffectValid(eCheck))
{
// Remove cirtain spells
switch(GetEffectSpellId(eCheck))
{
// - Feeblemind
case SMP_SPELL_FEEBLEMIND:
// - All insanity
case SMP_SPELL_INSANITY:
case SMP_SPELL_SYMBOL_OF_INSANITY:
// - Dazzeled
case SMP_SPELL_FLARE:
{
// Remove this effect (and its linked effects)
RemoveEffect(oTarget, eCheck);
}
break;
// Other effects
default:
{
// Remove cirtain effects
switch(GetEffectType(eCheck))
{
case EFFECT_TYPE_DAZED:
case EFFECT_TYPE_DEAF:
case EFFECT_TYPE_DISEASE:
case EFFECT_TYPE_STUNNED:
case EFFECT_TYPE_POISON:
{
RemoveEffect(oTarget, eCheck);
}
break;
}
}
break;
}
// Get next effect
eCheck = GetNextEffect(oTarget);
}
// Remove fatige
SMP_RemoveFatigue(oTarget);
}
// SMP_INC_SPELLS. Checks if they are a shapechanger subtype (so can cancle polymorph)
// * They will be able to if they are a shapechanger class
// * They can be a NPC and be a sub-race Shapechanger, or RACIAL_TYPE_SHAPECHANGER.
int SMP_GetIsShapechangerSubtype(object oTarget)
{
// Shapechanger class is inherant.
if(GetLevelByClass(CLASS_TYPE_SHAPECHANGER, oTarget) >= 1 ||
// Racial type: Shapechanger
GetRacialType(oTarget) == RACIAL_TYPE_SHAPECHANGER ||
// NPC with the shapechanger subrace
(!GetIsPC(oTarget) &&
FindSubString(GetStringUpperCase(GetSubRace(oTarget)), "SHAPECHANGER")))
{
return TRUE;
}
return FALSE;
}
// If sStoredTo integer on oTarget is nInteger, we delete it.
void SMP_DeleteIntInTime(string sStoredTo, object oTarget, int nInteger)
{
// Check if the integer is equal
if(GetLocalInt(oTarget, sStoredTo) == nInteger)
{
DeleteLocalInt(oTarget, sStoredTo);
}
}
// Loops all objects of nObjectType, nearest firest, until it finds sTag's.
object SMP_GetNearestObjectByTagToLocation(int nObjectType, string sTag, location lTarget)
{
int nCnt = 1;
object oObject = GetNearestObjectToLocation(nObjectType, lTarget, nCnt);
while(GetIsObjectValid(oObject))
{
// Check tag
if(GetTag(oObject) == sTag)
{
return oObject;
}
// Next one
nCnt++;
oObject = GetNearestObjectToLocation(nObjectType, lTarget, nCnt);
}
return OBJECT_INVALID;
}
// SMP_INC_SPELLS. Loops all objects of sTag from oCreator's location
// until it finds the nearest created by oCreator, and which is nearest to
// OBJECT_SELF.
object SMP_GetNearestAOEOfTagToUs(string sTag, object oCreator)
{
// Area check
if(GetArea(oCreator) != GetArea(OBJECT_SELF)) return OBJECT_INVALID;
// Loop the AOE's
int nCnt = 1;
object oReturn = OBJECT_INVALID;
float fLowestdistance = 1000.0;
object oAOE = GetNearestObjectByTag(sTag, oCreator, nCnt);
while(GetIsObjectValid(oAOE))
{
// Check AOE creator
if(GetObjectType(oAOE) == OBJECT_TYPE_AREA_OF_EFFECT &&
GetAreaOfEffectCreator(oAOE) == oCreator)
{
// Check distance
if(GetDistanceBetween(oAOE, OBJECT_SELF) <= fLowestdistance)
{
oReturn = oAOE;
}
}
// Next one
nCnt++;
oAOE = GetNearestObjectByTag(sTag, oCreator, nCnt);
}
return oReturn;
}
// SMP_INC_SPELLS. Returns the base armor type as a number, of oItem
// -1 if invalid, or not armor, or just plain not found.
// 0 to 8 as the value of AC got from the armor - 0 for none, 8 for Full plate.
int SMP_GetArmorType(object oItem)
{
// Make sure the item is valid and is an armor.
if (!GetIsObjectValid(oItem))
return -1;
if (GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
return -1;
// Get the identified flag for safe keeping.
int bIdentified = GetIdentified(oItem);
SetIdentified(oItem,FALSE);
int nType = -1;
switch (GetGoldPieceValue(oItem))
{
case 1: nType = 0; break; // None
case 5: nType = 1; break; // Padded
case 10: nType = 2; break; // Leather
case 15: nType = 3; break; // Studded Leather / Hide
case 100: nType = 4; break; // Chain Shirt / Scale Mail
case 150: nType = 5; break; // Chainmail / Breastplate
case 200: nType = 6; break; // Splint Mail / Banded Mail
case 600: nType = 7; break; // Half-Plate
case 1500: nType = 8; break; // Full Plate
}
// Restore the identified flag, and return armor type.
SetIdentified(oItem,bIdentified);
return nType;
}
// SMP_INC_SPELLS. Returns TRUE if oItem is a metal-based weapon.
// * FALSE if invalid, or not a weapon, or just plain not found.
int SMP_GetIsMetalWeapon(object oItem)
{
// Make sure the item is valid
if(!GetIsObjectValid(oItem)) return FALSE;
// Check the item type of oItem.
switch(GetBaseItemType(oItem))
{
// List all, but uncomment non-metal, or mainly non-metal ones.
case BASE_ITEM_BASTARDSWORD:
case BASE_ITEM_BATTLEAXE:
//case BASE_ITEM_CLUB:
case BASE_ITEM_DAGGER:
//case BASE_ITEM_DART:
case BASE_ITEM_DIREMACE:
case BASE_ITEM_DOUBLEAXE:
case BASE_ITEM_DWARVENWARAXE:
case BASE_ITEM_GREATAXE:
case BASE_ITEM_GREATSWORD:
case BASE_ITEM_HALBERD:
case BASE_ITEM_HANDAXE:
//case BASE_ITEM_HEAVYCROSSBOW:
case BASE_ITEM_HEAVYFLAIL:
case BASE_ITEM_KAMA:
case BASE_ITEM_KATANA:
case BASE_ITEM_KUKRI:
//case BASE_ITEM_LIGHTCROSSBOW:
case BASE_ITEM_LIGHTFLAIL:
case BASE_ITEM_LIGHTHAMMER:
case BASE_ITEM_LIGHTMACE:
//case BASE_ITEM_LONGBOW:
case BASE_ITEM_LONGSWORD:
case BASE_ITEM_MAGICSTAFF:
case BASE_ITEM_MORNINGSTAR:
//case BASE_ITEM_QUARTERSTAFF:
case BASE_ITEM_RAPIER:
case BASE_ITEM_SCIMITAR:
case BASE_ITEM_SCYTHE:
//case BASE_ITEM_SHORTBOW:
//case BASE_ITEM_SHORTSPEAR:
case BASE_ITEM_SHORTSWORD:
//case BASE_ITEM_SHURIKEN:
case BASE_ITEM_SICKLE:
//case BASE_ITEM_SLING:
case BASE_ITEM_TWOBLADEDSWORD:
case BASE_ITEM_WARHAMMER:
//case BASE_ITEM_WHIP:
{
return TRUE;
}
break;
}
return FALSE;
}
// SMP_INC_SPELLS. Returns TRUE if oItem is a metal-based armor.
// * FALSE if invalid, or not armor, or just plain not found.
int SMP_GetIsMetalArmor(object oItem)
{
// Make sure the item is valid
if(!GetIsObjectValid(oItem)) return FALSE;
// Check the item type of oItem.
if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
{
// 4 is chain, anything bigger is of course more.
if(SMP_GetArmorType(oItem) >= 4)
{
return TRUE;
}
}
return FALSE;
}
// Returns TRUE if oObject is a creature, and is made of metal
int SMP_GetIsFerrous(object oObject)
{
// Make sure the object is valid
if(!GetIsObjectValid(oObject)) return FALSE;
// Make sure it is a creature
if(GetObjectType(oObject) != OBJECT_TYPE_CREATURE) return FALSE;
// Check appearance
switch(GetAppearanceType(oObject))
{
// Metal creatures (some golems mainly)
case APPEARANCE_TYPE_BAT_HORROR:
case APPEARANCE_TYPE_GOLEM_IRON:
case APPEARANCE_TYPE_MINOGON:
case APPEARANCE_TYPE_HELMED_HORROR:
{
return TRUE;
}
}
// Not metal
return FALSE;
}
// SMP_INC_SPELLS. Returns TRUE if oItem is any shield.
// 0 if invalid, or not a shield, or just plain not found.
int SMP_GetIsShield(object oItem)
{
int bReturn = FALSE;
switch(GetBaseItemType(oItem))
{
case BASE_ITEM_LARGESHIELD:
case BASE_ITEM_SMALLSHIELD:
case BASE_ITEM_TOWERSHIELD:
{
bReturn = TRUE;
}
break;
}
return bReturn;
}
// SPELL HOOK FOR ALL PLAYER SPELLS
// Returns TRUE if they can cast the spell, FALSE means they cannot.
// * nSpellID - The spell ID of the spell.
// If it is the default, SPELL_INVALID, it will use GetSpellId();
int SMP_SpellHookCheck()
{
// Debug
SMP_Debug("hook Check fired, object self: " + GetName(OBJECT_SELF));
// Execute the spell hook file directly on the caster
ExecuteScript("smp_spellhook", OBJECT_SELF);
// Get return value
int bReturn = GetLocalInt(OBJECT_SELF, "SMP_SPELLHOOK_RETURN");
// Debug
SMP_Debug("HOOK RESULT 2: " + IntToString(bReturn));
return bReturn;
}
// This is used for the spell "Explosive Runes".
// - When reading a scroll or book (And there is a new "Read" 'spell' too),
// the runes will trigger and explode for 6d6 damage and some blast damage.
// Returns TRUE if they explode!
int SMP_ExplosiveRunes()
{
// Get item
object oItem = GetSpellCastItem();
int nType = GetBaseItemType(oItem);
// Check if valid, and if a book or a scroll
if(GetIsObjectValid(oItem))
{
if(nType == BASE_ITEM_BLANK_SCROLL ||
nType == BASE_ITEM_ENCHANTED_SCROLL ||
nType == BASE_ITEM_SPELLSCROLL || // Invalid but hey, who cares?
nType == BASE_ITEM_BOOK)
{
// Check for explosive runes integer
if(GetLocalInt(oItem, SMP_EXPLOSIVE_RUNES_SET))
{
// Use the function
SMP_ExplosiveRunesExplode(oItem);
// Explosive runes! ouch!
return TRUE;
}
}
}
return FALSE;
}
// This does the explosion effects for oItem, if they had explosive runes fire this.
// It will also destroy the item, oItem, if it was not plot.
void SMP_ExplosiveRunesExplode(object oItem)
{
// Get caster and DC
object oCaster = GetLocalObject(oItem, SMP_EXPLOSIVE_RUNES_OBJECT);
int nSpellSaveDC = GetLocalInt(oItem, SMP_EXPLOSIVE_RUNES_DC);
// Declare effects
effect eVis = EffectVisualEffect(VFX_IMP_MAGBLUE);
int nDam;
float fDelay;
// We do damage to all those in the AOE. The caster gets no save.
// 10 feet range. Location: Caster
location lTarget = GetLocation(OBJECT_SELF);
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_FEET_10, lTarget, TRUE);
while(GetIsObjectValid(oTarget))
{
// No check of reaction type. PvP doesn't apply as it
// could be read in a no PvP area.
// Signal spell cast at
SignalEvent(oTarget, EventSpellCastAt(oCaster, SMP_SPELL_EXPLOSIVE_RUNES));
// Get delay
fDelay = GetDistanceToObject(oTarget)/20;
// Check spell resistance
if(!SMP_SpellResistanceCheck(oCaster, oTarget, fDelay))
{
// Roll damage
nDam = d6(6);
// Reflex Saving throw for half damage
if(oTarget != OBJECT_SELF)
{
nDam = SMP_GetAdjustedDamage(SAVING_THROW_REFLEX, nDam, oTarget, nSpellSaveDC, SAVING_THROW_TYPE_SPELL, oCaster, fDelay);
}
// Apply damage and visual
if(nDam > 0)
{
// Do force magical damage
DelayCommand(fDelay, SMP_ApplyDamageVFXToObject(oTarget, eVis, nDam));
}
}
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_FEET_10, lTarget, TRUE);
}
// Note we also destroy the object it was written on, unless
// it is plot, because it also takes damage!
if(!GetPlotFlag(oItem))
{
DestroyObject(oItem);
}
}
// Checks if oTarget was summoned via. a spell.
int SMP_GetIsSummonedCreature(object oTarget)
{
// Check associate type
if(GetAssociateType(oTarget) == ASSOCIATE_TYPE_SUMMONED)
{
return TRUE;
}
// Master assoicated one - a henchman. No henchman check though.
if(GetLocalInt(oTarget, "SMP_SUMMON_SPELL") > 0)
{
return TRUE;
}
// Not a summon
return FALSE;
}
// Moves back oTarget from oCaster, fDistance.
// Antilife shell ETC uses this.
void SMP_PerformMoveBack(object oCaster, object oTarget, float fDistance, int bOriginalCommandable)
{
// Get new location, fDistance, behind them.
location lMoveTo = SMP_GetLocationBehind(oCaster, oTarget, fDistance);
// Move the target back to that point
SetCommandable(TRUE, oTarget);
// Assign commands
AssignCommand(oTarget, JumpToLocation(lMoveTo));
// Set to original commandability.
SetCommandable(bOriginalCommandable);
}
// SMP_INC_SPELLS. Destroys oObject utterly.
// - Turns off Plot Flag, Cursed Flag and Stolen flag.
// - Then uses a standard DestroyObject() command.
void SMP_CompletelyDestroyObject(object oObject)
{
// Turn off all the flags.
SetItemCursedFlag(oObject, FALSE);
SetPlotFlag(oObject, FALSE);
SetItemCursedFlag(oObject, FALSE);
// Destroy it
DestroyObject(oObject);
}
// SMP_INC_SPELLS.
// Depending on if oTarget is a PC or an NPC, it will "Disintegrate them as the spell"
// and should create some dust where the items will go.
// * PC's are just damaged normally.
// * Cirtain placables are damaged past thier plot status.
// * Cirtain spells on oTarget are destroyed/removed
// * Executes "SMP_AIL_Disinteg" for NPC's.
void SMP_DisintegrateDamage(object oTarget, effect eVis, int nDam)
{
// Object type
if(GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
{
// Remove any Interposing Hands
// * Note: All of the *Hand* spells can do this, so we remove all
// Attack Penalties (which is what interposing hand applies).
SMP_RemoveInterposingHands(oTarget);
// If we do not remove any spheres, we will be OK
if(!SMP_RemoveSpellEffectsFromTarget(SMP_SPELL_RESILIENT_SPHERE, oTarget) &&
!SMP_RemoveSpellEffectsFromTarget(SMP_SPELL_TELEKINETIC_SPHERE, oTarget))
{
// PC version - just damage
if(GetIsPC(oTarget))
{
// Apply damage
SMP_ApplyDamageVFXToObject(oTarget, eVis, nDam);
}
else
{
// NPC version
// Get HP
int nHP = GetCurrentHitPoints(oTarget);
// - Will it kill them?
int bPreviousLootable = GetLootable(oTarget);
if(GetLootable(oTarget) && nDam >= nHP)
{
// Turn off lootable
SetLootable(oTarget, FALSE);
}
// Apply damage and VFX
SMP_ApplyDamageVFXToObject(oTarget, eVis, nDam);
// If an NPC, and dead now, we fire the script.
if(nDam >= nHP)
{
ExecuteScript("SMP_AIL_DISINTEG", oTarget);
}
else
{
// Else, re-do the lootable flag from before
// * EG: Shield other worked, for instance
SetLootable(oTarget, bPreviousLootable);
}
}
}
}
else
{
// Cirtain placables are damaged.
}
}
// SMP_INC_SPELLS. Returns the bonus to Charisma, Wisdom or Intelligence.
// * Uses GetLastSpellCastClass()
// * Will return Charisma as default.
// * Only can be used in impact scripts
// Will be used in some spells which require the "Bonus to spells" bonus.
int SMP_GetAppropriateAbilityBonus()
{
int nClass = GetLastSpellCastClass();
switch(nClass)
{
case CLASS_TYPE_BARD:
case CLASS_TYPE_SORCERER:
case CLASS_TYPE_INVALID:
{
// Return Charisma bonus
return GetAbilityModifier(ABILITY_CHARISMA);
}
break;
case CLASS_TYPE_WIZARD:
{
// Return Intelligence bonus
return GetAbilityModifier(ABILITY_INTELLIGENCE);
}
break;
case CLASS_TYPE_CLERIC:
case CLASS_TYPE_PALADIN:
case CLASS_TYPE_RANGER:
{
// Return Wisdom bonus
return GetAbilityModifier(ABILITY_WISDOM);
}
break;
}
// Return default of Charisma
return GetAbilityModifier(ABILITY_CHARISMA);
}
// SMP_INC_SPELLS. This performs a grapple check against nAC.
// To use it for "opposed" checks, mearly put the amount the oTarget got into
// nAC, such as Black Tentacles.
// Check is made as an attack roll at:
// * Base attack bonus + Strength modifier + special size modifier
// Note:
// Special Size Modifier: The special size modifier for a grapple check is as
// follows: Colossal +16, Gargantuan +12, Huge +8, Large +4, Medium +0,
// Small <20>4, Tiny <20>8, Diminutive <20>12, Fine <20>16. Use this number in place of the
// normal size modifier you use when making an attack roll.
// * Use SMP_GrappleSizeBonus() to get a creatures nSizeMod.
// * Relays to oTarget and oSource (if any) the result of the check.
int SMP_GrappleCheck(object oTarget, int nBAB, int nStrMod, int nSizeMod, int nAC, object oSource = OBJECT_SELF)
{
// Get the source's roll.
int nBase = nBAB + nStrMod + nSizeMod;
int nRoll = d20();
// Result:
int bResult;
// Start relay string
string sRelay = "Grapple check against " + GetName(oTarget) + ". Roll: " + IntToString(nRoll) + " + " + IntToString(nBase) + " VS " + IntToString(nAC) + ": ";
// Check the result
if(nBase + nRoll >= nAC)
{
// Sucess!
bResult = TRUE;
// We relay sucess
sRelay += "Grapple Sucessful.";
}
else
{
// Failure!
bResult = FALSE;
// We relay failure
sRelay += "Grapple Failed.";
}
// Send messages
if(GetIsObjectValid(oSource))
{
SendMessageToPC(oSource, sRelay);
}
if(oSource != oTarget)
{
SendMessageToPC(oTarget, sRelay);
}
return bResult;
}
// Special Size Modifier: The special size modifier for a grapple check is as
// follows: Colossal +16, Gargantuan +12, Huge +8, Large +4, Medium +0,
// Small <20>4, Tiny <20>8, Diminutive <20>12, Fine <20>16.
int SMP_GrappleSizeBonus(object oCreature)
{
// Default to 0
if(GetObjectType(oCreature) != OBJECT_TYPE_CREATURE) return FALSE;
// Check creature size
switch(GetCreatureSize(oCreature))
{
// Modifiers are 4 differences each stage away from "Normal" medium size
case CREATURE_SIZE_HUGE: return 8; break;
case CREATURE_SIZE_LARGE: return 4; break;
case CREATURE_SIZE_MEDIUM: return 0; break;
case CREATURE_SIZE_SMALL: return -4; break;
case CREATURE_SIZE_TINY: return -8; break;
}
// Default to 0
return FALSE;
}
// SMP_INC_SPELLS. This will roll an attack roll, using nBAB, nStrMod, nExtra
// against nAC, that is, oTarget's AC (or should be). Relays the results
// as if it was a proper attack.
// NOTE: Returns FALSE on a miss, but else returns the total attack roll of all 3 things
// plus the d20.
int SMP_AttackCheck(object oTarget, int nBAB, int nStrMod, int nExtra, int nAC, object oSource = OBJECT_SELF)
{
// Get the source's roll.
int nBase = nBAB + nStrMod + nExtra;
int nRoll = d20();
// Result:
int bResult;
// Start relay string
string sRelay = "Attack roll against " + GetName(oTarget) + ". Roll: " + IntToString(nRoll) + " + " + IntToString(nBase) + " VS " + IntToString(nAC) + ": ";
// Check the result
if(nBase + nRoll >= nAC)
{
// Sucess!
// * Return the total attack roll (for disipline checks etc)
bResult = nBase + nRoll;
// We relay sucess
sRelay += "Attack Hit.";
}
else
{
// Failure!
bResult = FALSE;
// We relay failure
sRelay += "Attack Missed.";
}
// Send messages
if(GetIsObjectValid(oSource))
{
SendMessageToPC(oSource, sRelay);
}
if(oSource != oTarget)
{
SendMessageToPC(oTarget, sRelay);
}
return bResult;
}
// Use AssignCommand() to do this on another person, it will set cutscene mode
// for a few seconds (if not already in a cutscene) and move them to lTarget's
// location, then remove the cutscene mode. It will mean no effects are removed
// and it always is sucessful.
// * lTarget is where to move to
// * nGoVis/nAppearVis, if not VFX_NONE, will be applied at the target location
// and the person moving location as appropriate.
void SMP_ForceMovementToLocation(location lTarget, int nGoVis = VFX_NONE, int nAppearVis = VFX_NONE)
{
// Special start; we set cutscene mode. Use OBJECT_SELF as the person
object oSelf = OBJECT_SELF;
// Will not move them if they are already plot somehow.
// * catches exsisting cutscenes
if(GetPlotFlag(oSelf)) return;
// Clear all actions
ClearAllActions();
// Set it ON
SetCutsceneMode(oSelf, TRUE);
// Apply visuals
if(nGoVis != VFX_NONE)
{
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(nGoVis), GetLocation(oSelf));
}
if(nAppearVis != VFX_NONE)
{
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(nAppearVis), lTarget);
}
// Move them
int bResetFalse = FALSE;
if(!GetCommandable(oSelf))
{
// Needs to be set commandable
SetCommandable(TRUE, oSelf);
bResetFalse = TRUE;
}
JumpToLocation(lTarget);
// Set the cutscene mode OFF as an action
ActionDoCommand(SetCutsceneMode(oSelf, FALSE));
// Reset the state of commandable if need be.
if(bResetFalse == FALSE)
{
// Reset commandable state.
SetCommandable(FALSE, oSelf);
}
}
// Roughly gets the weight of oCreature, in tenths of pounds.
// * Based on creature size.
// * Use with GetWeight(oCreature) to get what they are carrying plus the creature weight
int SMP_GetCreatureWeight(object oCreature)
{
// Default to 0
if(GetObjectType(oCreature) != OBJECT_TYPE_CREATURE) return FALSE;
// Check creature size
switch(GetCreatureSize(oCreature))
{
// All * 10, so in tenths of pounds
case CREATURE_SIZE_HUGE: return 10000; break;
case CREATURE_SIZE_LARGE: return 3500; break;
case CREATURE_SIZE_MEDIUM: return 2000; break;
case CREATURE_SIZE_SMALL: return 600; break;
case CREATURE_SIZE_TINY: return 150; break;
}
// Default to 0
return FALSE;
}
// SMP_INC_SPELLS. This will check if lTarget and lSource are on the same plane
// of exsistance.
// * Used to stop escape from Maze, Prismatic's Plane, Imprisonment.
int SMP_CheckIfSamePlane(location lSource, location lTarget)
{
// Check if lSource is a "non material plane"
object oSourceArea = GetAreaFromLocation(lSource);
object oTargetArea = GetAreaFromLocation(lTarget);
// Check if both valid first
if(!GetIsObjectValid(oSourceArea) || !GetIsObjectValid(oTargetArea)) return FALSE;
// Check the source area?
string sTag = GetTag(oSourceArea);
if(sTag == "SMP_MAZE" || sTag == "SMP_IMPRISONMENT" || sTag == "SMP_PRISPLANE")
{
// Cannot work.
return FALSE;
}
// Check target area
sTag = GetTag(oTargetArea);
if(sTag == "SMP_MAZE" || sTag == "SMP_IMPRISONMENT" || sTag == "SMP_PRISPLANE")
{
// Cannot work.
return FALSE;
}
// TRUE, they ARE on the same plane
// * Default return value
return TRUE;
}
// SMP_INC_SPELLS. SMP_GetHitDiceByXP
// HitDice is determined by player's xp, not by whether or not they have leveled
// * Solve for hd from xp = hd * (hd - 1) * 500
// hd = 1/50 * (sqrt(5) * sqrt(xp + 125) + 25)
int SMP_GetHitDiceByXP(object oCreature)
{
float fXP = IntToFloat(GetXP(oCreature));
int nHD = FloatToInt(0.02f * (sqrt(5.0f) * sqrt(fXP + 125.0f) + 25.0f));
// Limit it to 40 levels (they can go well over level 40 with masses of XP, but
// it cannot add anything to total HD)
if (GetIsPC(oCreature) && nHD > 40)
nHD = 40;
return nHD;
}
// SMP_INC_SPELLS. This will get the targets character level, not hit dice,
// and so will be used in death stuff to calculate thier actual character level.
// * Can be used on NPC's, and will use GetHitDice(oTarget);
// * THanks to th1ef, who did the "GetHitDiceByXP" function used in this
int SMP_GetCharacterLevel(object oTarget)
{
// If NPC (or DM, gah!) we return the HD of the target
if(!GetIsPC(oTarget) || GetIsDM(oTarget))
{
return GetHitDice(oTarget);
}
// Else, must be a PC
return SMP_GetHitDiceByXP(oTarget);
}
// SMP_INC_SPELLS. This will get the correct amount of experience to set a person
// to for there to be a level loss of 1, so they have the exact amount needed
// for the previous level.
// * Will return 1 if at level 1.
int SMP_GetLevelLossXP(int nHD)
{
// Take 1 HD off nHD to get the next level down.
nHD--;
// we calculate, based on the new nHD value, the XP needed for that level.
int nReturn = ((nHD * (nHD - 1)) / 2) * 1000;
// Cannot be 0. Can be 1.
if(nReturn < 1) nReturn = 1;
// Return it
return nReturn;
}
// SMP_INC_SPELLs. Removes all avalible castings of nSpell on oCreature
// - oCreature: creature to modify
// - nSpell: constant SPELL_*
void SMP_DecrementAllRemainingSpellUses(object oCreature, int nSpell)
{
int i, nUses = GetHasSpell(nSpell, oCreature);
if(nUses > 0)
{
for(i = 1; i <= nUses; i++)
{
DecrementRemainingSpellUses(oCreature, nSpell);
}
}
}
// End of file Debug lines. Uncomment below "/*" with "//" and compile.
/*
void main()
{
return;
}
//*/