Updated AMS marker feats. Removed arcane & divine marker feats. Updated Dread Necromancer for epic progression. Updated weapon baseitem models. Updated new weapons for crafting & npc equip. Updated prefix. Updated release archive.
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;
|
||
}
|
||
//*/
|