Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
2778 lines
96 KiB
Plaintext
2778 lines
96 KiB
Plaintext
/*:://////////////////////////////////////////////
|
||
//:: 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;
|
||
}
|
||
//*/
|