PRC8_fork/nwn/nwnprc/trunk/smp/smp_inc_wish.nss
Jaysyn904 6ec137a24e Updated AMS marker feats
Updated AMS marker feats.  Removed arcane & divine marker feats.  Updated Dread Necromancer for epic progression. Updated weapon baseitem models.  Updated new weapons for crafting & npc equip.
 Updated prefix.  Updated release archive.
2024-02-11 14:01:05 -05:00

612 lines
24 KiB
Plaintext
Raw Permalink Blame History

/*:://////////////////////////////////////////////
//:: Name Wish functions
//:: FileName SMP_INC_WISH
//:://////////////////////////////////////////////
Functions for the Wish, Miracle and so on spells.
These can be used, therefore, in those scripts, and replaces the SMP_INC_SPELLS
line, as it will include it here.
Not just wish effects, but also wish checks :-)
Call these functions from a script from a wish creature or DM.
//:://////////////////////////////////////////////
//:: Created By: Jasperre
//::////////////////////////////////////////////*/
#include "SMP_INC_SPELLS"
// Note: You must set on the person calling these functions a name - under
// SMP_WISH_NAME, so it can be used to send a correct message:
// "You cannot cast Magic Missile using Wish", might be "using Miracle" instead.
// Remember:
const string SMP_WISH_NAME_LOCAL = "SMP_WISH_NAME_LOCAL";
// SPECIAL
// SMP_INC_WISH. Gets the wish's name - IE: Miracle, Limited Wish, Wish, for things like
// "You cannot cast Magic Missile using Miracle"
string SMP_WishGetName();
// SMP_INC_WISH. Checks if oObject is within oWisher's LOS
// * Placables, doors, items. Creatures use GetObjectSeen()/Heard().
int SMP_WishGetObjectInLOS(object oTarget, object oWisher);
// SMP_INC_WISH. Applies the loop onto oWisher of what they can see in thier LOS (40M)
// * Only call this directly from the object doing the wish, so oWisher should
// always be OBJECT_SELF
void SMP_WishSetLOS(object oWisher = OBJECT_SELF);
// SMP_INC_WISH. Deletes all locals set in SMP_WishSetLOS().
void SMP_WishDeleteLOS(location lWisher, string sLocal);
// CHECKS
// Note 2: Given the above local setting, whenever it says "Wish" inside debug
// strings, it'll be subsituted as approprate.
// SMP_INC_WISH. This will make sure cirtain spells can *never* be cast from wish.
// * TRUE if they cannot cast it ever, period.
// Debugs using: "You cannot cast 'GetName(nSpellId)' using Wish" (or other..)
int SMP_WishGetIsUncastableSpell(object oWisher, int nSpellId);
// SMP_INC_WISH. This makes sure that oTarget is a valid target for nSpellId, using range,
// types of target affected,
// * TRUE if they ARE a valid target
// If FALSE Debug: "You cannot cast nSpellId at oTarget"... + Reason
int SMP_WishGetIsSpellTargetValid(object oWisher, object oTarget, int nSpellId);
// SMP_INC_WISH. Deciphers sName into a spell id's number. This, sadly, will
// do a large loop. Use wisely! It uses FindSubString(), and so must match
// pretty well. Does capitalise both.
// * loops the spell values on SMP_ArrayGetObject(SMP_2DA_NAME_SPELLS, SMP_2DA_COLUMN_SPELLS_NAME);
// * Returns SPELL_INVALID as default, if no spell is found to be a match.
int SMP_WishGetSpellId(string sName, object oWisher);
// SMP_INC_WISH. This is from this (this is from Wish, it is similar for others)
// <20> Duplicate any wizard or sorcerer spell of 8th level or lower, provided the
// spell is not of a school prohibited to you. (nClassBan = any spell from nClass's normal list)
// <20> Duplicate any other spell of 6th level or lower, provided the spell is not
// of a school prohibited to you. (nAnyBan = Any spell from any list, not banned via. school)
// <20> Duplicate any wizard or sorcerer spell of 7th level or lower even if it<69>s
// of a prohibited school. (nClassNoBan = Any spell from this class's list, up to this level)
// <20> Duplicate any other spell of 5th level or lower even if it<69>s of a
// prohibited school. (nAny = Any other spell, even opposing schools)
// In this example: nClassBan = 7, nClassNoBan = 8, nAnyBan = 6, nAny = 5.
// * Put in CLASS_TYPE_WIZARD or CLASS_TYPE_CLERIC for nClass, always.
int SMP_WishGetIsSpellValid(object oWisher, int nClass, int nSpellId, int nClassBan, int nClassNoBan, int nAnyBan, int nAny);
// SMP_INC_WISH. Get a valid target for wish, using sName. We will loop all
// objects which we allow (In order: Creatuers, then any Placables, Doors,
// Items on the Ground).
// * Can use bCreatureOnly to only check creatures in range.
// * Only will use seen creatures, that oWisher can see, or objects that are within
// oWisher's LOS too (we do a loop in the SMP_S_WISH script, or similar, to
// set it up using functions here).
// * Returns OBJECT_INVALID in case of no valid target to return
// * Can use bSeenOnly to force the object to be seen (ala, spell targeting)
// Gets the nearest target, of course, a placable with name sNAme could be nearer
// then a creature with sName, but we return the creature first. Also, hardly happens.
object SMP_WishGetTargetByName(object oWisher, string sName, int bCreatureOnly = FALSE, int bSeenOnly = FALSE);
// EFFECTS
// SMP_INC_WISH. Cures oWisher's party of all damage, to thier maximum hit points, if they
// are at -10 or higher hit points
void SMP_WishDoCurePartyDamage(object oWisher);
// SMP_INC_WISH. Cures oWisher's party of nAffiction
void SMP_WishDoCurePartyAffiction(object oWisher, int nAffiction);
// SMP_INC_WISH. Makes oWisher cast nSpellId at oTarget
void SMP_WishCastSpellAtObject(object oWisher, int nSpellId, object oTarget);
// SMP_INC_WISH. Makes oWisher undo the harmful effects of all Insanity spells on oTarget
void SMP_WishRemoveInsanity(object oWisher, object oTarget);
// SMP_INC_WISH. Makes oWisher attempt to teleport oTarget to lLocation.
// Must be used seperatly on each person. Willing people go for free, else, it
// uses nSpellSaveDC, and nCasterLevel to do the checks for resistance and will save
// * Reports saves normally, etc.
// * No other feedback.
// * Returns TRUE if sucessful, so a complete feedback can be made up.
int SMP_WishTeleportPerson(object oWisher, object oTarget, location lTarget, int nSpellSaveDC, int nCasterLevel);
// Creates a particular item for oWisher, named by them, it will search a database
// of items to get which one to create.
// void SMP_WishCreateMundateItem()
// Creates magical of above
// FINISH!!!!
// START SPECIAL
// Gets the wish's name
string SMP_WishGetName()
{
return GetLocalString(OBJECT_SELF, SMP_WISH_NAME_LOCAL);
}
// Checks if oObject is within oWisher's LOS
// * Placables, doors, items. Creatures use GetObjectSeen()/Heard().
int SMP_WishGetObjectInLOS(object oTarget, object oWisher)
{
// Check local on the target
string sLocal = "SMP_WISH_LOS" + ObjectToString(oWisher);
// Local gets set on the target if they are in the wishers LOS. Gets
// removed too after wish is cast.
if(GetLocalInt(oTarget, sLocal))
{
return TRUE;
}
return FALSE;
}
// Applies the loop onto oWisher of what they can see in thier LOS (40M)
// * Only call this directly from the object doing the wish, so oWisher should
// always be OBJECT_SELF
void SMP_WishSetLOS(object oWisher = OBJECT_SELF)
{
// Check LOS of those objects:
// * Placables, doors, items
string sLocal = "SMP_WISH_LOS" + ObjectToString(oWisher);
location lWisher = GetLocation(oWisher);
object oLOS = GetFirstObjectInShape(SHAPE_SPHERE, 40.0, lWisher, TRUE, OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_DOOR | OBJECT_TYPE_ITEM);
while(GetIsObjectValid(oLOS))
{
// Set local on them
SetLocalInt(oLOS, sLocal, TRUE);
// Get next object
oLOS = GetNextObjectInShape(SHAPE_SPHERE, 40.0, lWisher, TRUE, OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_DOOR | OBJECT_TYPE_ITEM);
}
// Delay the deletion
DelayCommand(6.0, SMP_WishDeleteLOS(lWisher, sLocal));
}
// Deletes all locals set in SMP_WishSetLOS().
void SMP_WishDeleteLOS(location lWisher, string sLocal)
{
// Delete all previous (if any) locals.
// This is delayed after they have been set. Should clear up them all
int nCnt = 1;
object oLOS = GetNearestObjectToLocation(OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_DOOR | OBJECT_TYPE_ITEM, lWisher, nCnt);
while(GetIsObjectValid(oLOS) && GetDistanceBetweenLocations(lWisher, GetLocation(oLOS)) <= 41.0)
{
// Delete the local.
DeleteLocalInt(oLOS, sLocal);
nCnt++;
oLOS = GetNearestObjectToLocation(OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_DOOR | OBJECT_TYPE_ITEM, lWisher, nCnt);
}
}
// START CHECKS
// This will make sure cirtain spells can *never* be cast from wish.
// * TRUE if they cannot cast it ever, period.
// Debugs using: "You cannot cast 'GetName(nSpellId)' using Wish"
int SMP_WishGetIsUncastableSpell(object oWisher, int nSpellId)
{
switch(nSpellId)
{
// Spells which have more then 1 round casting time
//case SMP_SPELL_RAISE_DEAD:
//{
// SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + " using " + SMP_WishGetName() + " because it takes longer then a round to cast");
// return TRUE;
//}
break;
// Spells which are duplicated by the resurrection part of all these spells
case SMP_SPELL_RAISE_DEAD:
//case SMP_SPELL_RESURRECTION:
//case SMP_SPELL_TRUE_RESURRECTION:
{
SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + " because you can duplicate its effects using " + SMP_WishGetName() + " anyway.");
return TRUE;
}
break;
}
// Default return - no debug
return FALSE;
}
// This makes sure that oTarget is a valid target for nSpellId, using range,
// types of target affected,
// * TRUE if they ARE a valid target
// If FALSE Debug: "You cannot cast nSpellId at oTarget
int SMP_WishGetIsSpellTargetValid(object oWisher, object oTarget, int nSpellId)
{
// Check the target type (IE: Self, creature, trigger ETC)
int nTargetsType = GetObjectType(oTarget);
int nSpellTargetType = SMP_ArrayGetSpellTargetType(nSpellId);
// If the spell can be cast at any location, it can be cast at any object
// too (because otherwise some locations under people cannot be hit right)
if(!SMP_GetIsTargetTypeLocation(nSpellTargetType))
{
// Check for any object, regardless (cannot target the ground with
// wish, it targets a specific being)
if(!SMP_GetIsTargetTypeObject(nSpellTargetType))
{
// This spell cannot target any object
SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + " at " + GetName(oTarget) + " because the spell doesn't allow it");
return FALSE;
}
// Check each type.
switch(nTargetsType)
{
case OBJECT_TYPE_CREATURE:
{
// Special case for self
if(oTarget == oWisher)
{
if(!SMP_GetIsTargetTypeSelf(nSpellTargetType))
{
// Cannot cast at yourself.
SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + " at yourself.");
return FALSE;
}
}
// Check default
if(!SMP_GetIsTargetTypeCreature(nSpellTargetType))
{
// Cannot cast at a creature.
SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + " at a creature.");
return FALSE;
}
}
case OBJECT_TYPE_DOOR:
{
// Check door
if(!SMP_GetIsTargetTypeDoor(nSpellTargetType))
{
SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + " at a door.");
return FALSE;
}
}
case OBJECT_TYPE_ITEM:
{
// Check item
if(!SMP_GetIsTargetTypeItem(nSpellTargetType))
{
SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + " at an item.");
return FALSE;
}
}
case OBJECT_TYPE_PLACEABLE:
{
// Check placeable
if(!SMP_GetIsTargetTypePlaceable(nSpellTargetType))
{
SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + " at a placeable.");
return FALSE;
}
}
}
}
// Check the range of this spell
float fRange = SMP_ArrayGetSpellRange(nSpellId);
// Note: We make the "personal" range 1.0 here, in case some spell uses it.
// ABOVE is a nicer check for target type, and is more by the book.
if(fRange == 0.0) fRange = 1.0;
if(SMP_ArrayGetSpellRange(nSpellId) > GetDistanceBetween(oWisher, oTarget))
{
// Cannot cast - to far away
SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + ", the target is too far away");
return FALSE;
}
// Return TRUE by default, allowing the target as valid
return TRUE;
}
// Deciphers sName into a spell id's number. This, sadly, will do a large loop.
// Use wisely! It uses FindSubString(), and so must match pretty well. Does capitalise both.
// * loops the spell values on SMP_ArrayGetObject(SMP_2DA_NAME_SPELLS, SMP_2DA_COLUMN_SPELLS_NAME);
// * Returns SPELL_INVALID as default, if no spell is found to be a match.
int SMP_WishGetSpellId(string sName, object oWisher)
{
string sCheck, sSpell;
int nCnt;
// Uppercase of sName.
sCheck = GetStringUpperCase(sName);
// We set the last spell name got by this onto OBJECT_SELF, and oWisher's
// Id. This is retrieved first, and checked (they might have asked to cast
// the same spell, but wrong syntax etc. before).
nCnt = GetLocalInt(OBJECT_SELF, "SMP_WISH_LASTSPELLNAME" + ObjectToString(oWisher));
// We won't ever recheck spell entry 0, because it returns 0 on default
if(nCnt > 0)
{
// Get the spell name at nCnt
sSpell = GetStringUpperCase(SMP_ArrayGetSpellName(nCnt));
// Check the two strings together
if(FindSubString(sCheck, sSpell) >= 0)
{
// Return nCnt - the names match
return nCnt;
}
}
// Loop all the spell names until we find a match.
// * Check only real spells.
for(nCnt = SMP_SPELLS_2DA_MIN_SPELL_ENTRY;
nCnt <= SMP_SPELLS_2DA_MAX_ENTRY; nCnt++)
{
// Get the spell name at nCnt
sSpell = GetStringUpperCase(SMP_ArrayGetSpellName(nCnt));
// Check the two strings together
if(FindSubString(sCheck, sSpell) >= 0)
{
// Return nCnt - the names match
return nCnt;
}
}
return SPELL_INVALID;
}
// This is from this (this is from Wish, it is similar for others)
// <20> Duplicate any wizard or sorcerer spell of 8th level or lower, provided the
// spell is not of a school prohibited to you. (nClassBan = any spell from nClass's normal list)
// <20> Duplicate any other spell of 6th level or lower, provided the spell is not
// of a school prohibited to you. (nAnyBan = Any spell from any list, not banned via. school)
// <20> Duplicate any wizard or sorcerer spell of 7th level or lower even if it<69>s
// of a prohibited school. (nClassNoBan = Any spell from this class's list, up to this level)
// <20> Duplicate any other spell of 5th level or lower even if it<69>s of a
// prohibited school. (nAny = Any other spell, even opposing schools)
// In this example: nClassBan = 7, nClassNoBan = 8, nAnyBan = 6, nAny = 5.
// * Put in CLASS_TYPE_WIZARD or CLASS_TYPE_CLERIC for nClass, always.
int SMP_WishGetIsSpellValid(object oWisher, int nClass, int nSpellId, int nClassBan, int nClassNoBan, int nAnyBan, int nAny)
{
// MUST BE CASTABLE NORMALLY
if(!SMP_ArrayGetSpellIsPCCastable(nSpellId))
{
// Cannot cast it
SpeakString("You cannot cast " + SMP_ArrayGetSpellName(nSpellId) + " because it is on no class' spell list");
return FALSE;
}
// Get nSpellId's level, from nClass and nInnate
int nClassLevel = SMP_ArrayGetSpellLevel(nSpellId, nClass);
int nInnateLevel = SMP_ArrayGetSpellLevelGeneral(nSpellId, oWisher);
// Check if they can cast it regardless of class, or school
if(nInnateLevel <= nAny)
{
// Can cast it!
return TRUE;
}
// Have they got nSpellId on thier list of spells?
if(nClassLevel != -1)
{
// Check if they can cast it due to it being on thier class list, and it is
// of a low enough level, and so we can cast it (never mind spell schools)
// we check here
if(nClassLevel <= nClassNoBan)
{
// Can cast it!
return TRUE;
}
// Checks for the spell school one
//if(SMP_ArrayGetSpellSchool(nSpellId) != WHAT_THIER_BANNED_SPELL_SCHOOL_IS)
//{
// if(nClassLevel <= nClassBan)
// {
// // Can cast it!
// return TRUE;
// }
//}
}
// Check for the spell school for all class lists.
//if(SMP_ArrayGetSpellSchool(nSpellId) != WHAT_THIER_BANNED_SPELL_SCHOOL_IS)
//{
// if(nInnateLevel <= nAnyBan)
// {
// // Can cast it!
// return TRUE;
// }
//}
// Cannot cast it (default return)
return FALSE;
}
// Get a valid target for wish, using sName. We will loop all objects which we
// allow (In order: Creatuers, then any Placables, Doors, Items on the Ground).
// * Can use bCreatureOnly to only check creatures in range.
// * Only will use seen creatures, that oWisher can see, or objects that are within
// oWisher's LOS too (we do a loop in the SMP_S_WISH script, or similar, to
// set it up using functions here).
// * Returns OBJECT_INVALID in case of no valid target to return
// * Can use bSeenOnly to force the object to be seen (ala, spell targeting)
// Gets the nearest target, of course, a placable with name sNAme could be nearer
// then a creature with sName, but we return the creature first. Also, hardly happens.
object SMP_WishGetTargetByName(object oWisher, string sName, int bCreatureOnly = FALSE, int bSeenOnly = FALSE)
{
// Loop all creatures first
int nCnt = 1;
object oCheck = GetNearestObject(OBJECT_TYPE_CREATURE, oWisher, nCnt);
while(GetIsObjectValid(oCheck))
{
if(FindSubString(sName, GetName(oCheck)) >= 0)
{
// Check if seen, or can sometimes be heard
if(GetObjectSeen(oCheck, oWisher) ||
(bSeenOnly == FALSE && GetObjectHeard(oCheck, oWisher)))
{
// Return them
return oCheck;
}
}
nCnt++;
oCheck = GetNearestObject(OBJECT_TYPE_CREATURE, oWisher, nCnt);
}
// Check placables, doors and items last
nCnt = 1;
oCheck = GetNearestObject(OBJECT_TYPE_DOOR | OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE, oWisher, nCnt);
while(GetIsObjectValid(oCheck))
{
if(FindSubString(sName, GetName(oCheck)) >= 0)
{
// Check if in LOS
if(SMP_WishGetObjectInLOS(oCheck, oWisher))
{
// Return them
return oCheck;
}
}
nCnt++;
oCheck = GetNearestObject(OBJECT_TYPE_DOOR | OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE, oWisher, nCnt);
}
// Default return value
return OBJECT_INVALID;
}
// START FUNCTIONS
// Cures oWisher's party of all damage, to thier maximum hit points, if they
// are at -10 or higher hit points
void SMP_WishDoCurePartyDamage(object oWisher)
{
// Get PC party members, and our area
effect eHeal;
effect eVis = EffectVisualEffect(VFX_IMP_HEALING_L);
object oArea = GetArea(oWisher);
object oMember = GetFirstFactionMember(oWisher, TRUE);
while(GetIsObjectValid(oMember))
{
// Must be in same area
if(GetArea(oMember) == oArea)
{
// Heal them
eHeal = EffectHeal(GetMaxHitPoints(oMember));
SMP_ApplyInstantAndVFX(oMember, eVis, eHeal);
}
// Get next member
oMember = GetNextFactionMember(oWisher, TRUE);
}
// Loop NPC's
oMember = GetFirstFactionMember(oWisher, FALSE);
while(GetIsObjectValid(oMember))
{
// Must be in same area
if(GetArea(oMember) == oArea)
{
// Heal them
eHeal = EffectHeal(GetMaxHitPoints(oMember));
SMP_ApplyInstantAndVFX(oMember, eVis, eHeal);
}
// Get next member
oMember = GetNextFactionMember(oWisher, FALSE);
}
}
// Cures oWisher's party of nAffiction
void SMP_WishDoCurePartyAffiction(object oWisher, int nAffiction)
{
// Get PC party members, and our area
effect eVis = EffectVisualEffect(VFX_IMP_HEALING_L);
object oArea = GetArea(oWisher);
object oMember = GetFirstFactionMember(oWisher, TRUE);
while(GetIsObjectValid(oMember))
{
// Must be in same area
if(GetArea(oMember) == oArea)
{
// Heal them
SMP_RemoveSpecificEffect(nAffiction, oMember, SUBTYPE_IGNORE);
SMP_ApplyVFX(oMember, eVis);
}
// Get next member
oMember = GetNextFactionMember(oWisher, TRUE);
}
// Loop NPC's
oMember = GetFirstFactionMember(oWisher, FALSE);
while(GetIsObjectValid(oMember))
{
// Must be in same area
if(GetArea(oMember) == oArea)
{
// Heal them
SMP_RemoveSpecificEffect(nAffiction, oMember, SUBTYPE_IGNORE);
SMP_ApplyVFX(oMember, eVis);
}
// Get next member
oMember = GetNextFactionMember(oWisher, FALSE);
}
}
// Makes oWisher cast nSpellId at oTarget
void SMP_WishCastSpellAtObject(object oWisher, int nSpellId, object oTarget)
{
// Say we have done the wish
SpeakString("Your " + SMP_WishGetName() + " is granted, you cast " + SMP_ArrayGetSpellName(nSpellId));
// Assign the wisher to cast the spell
AssignCommand(oWisher, ActionCastSpellAtObject(nSpellId, oTarget, METAMAGIC_NONE, TRUE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
}
// Makes oWisher undo the harmful effects of all Insanity spells on oTarget
void SMP_WishRemoveInsanity(object oWisher, object oTarget)
{
// Say we have done the wish
SpeakString("Your " + SMP_WishGetName() + " is granted, Insanity will be removed from " + GetName(oTarget));
// Send messages
// * Not in yet, might not add
// Loop effects, remove isanity
effect eCheck = GetFirstEffect(oTarget);
while(GetIsEffectValid(eCheck))
{
switch(GetEffectSpellId(eCheck))
{
// - All insanity
case SMP_SPELL_INSANITY:
case SMP_SPELL_SYMBOL_OF_INSANITY:
{
// Remove it
RemoveEffect(oTarget, eCheck);
}
break;
}
}
}
// Makes oWisher attempt to teleport oTarget to lLocation.
// Must be used seperatly on each person. Willing people go for free, else, it
// uses nSpellSaveDC, and nCasterLevel to do the checks for resistance and will save
// * Reports saves normally, etc.
// * No other feedback.
// * Returns TRUE if sucessful, so a complete feedback can be made up.
int SMP_WishTeleportPerson(object oWisher, object oTarget, location lTarget, int nSpellSaveDC, int nCasterLevel)
{
// If the target is in the party of oWisher, it is automatic.
if(GetFactionEqual(oWisher, oTarget))
{
// Move them (with some feedback to them)
SendMessageToPC(oTarget, "*You are teleported by Wish to a new location*");
AssignCommand(oTarget, SMP_ForceMovementToLocation(lTarget, VFX_FNF_TELEPORT_OUT, VFX_FNF_TELEPORT_IN));
return TRUE;
}
// Else, check saves and spell resistance.
// Spell resistance (Only)
if(!SMP_SpellResistanceManualCheck(oWisher, oTarget, nCasterLevel, 9))
{
// * Will save negates (And note: It is save type spell, because this isn't a
// spell script).
if(!SMP_SavingThrow(SAVING_THROW_WILL, oTarget, nSpellSaveDC, SAVING_THROW_TYPE_SPELL, oWisher))
{
// Move them! (Forcefully)
SendMessageToPC(oTarget, "*You are teleported by Wish to a new location*");
AssignCommand(oTarget, SMP_ForceMovementToLocation(lTarget, VFX_FNF_TELEPORT_OUT, VFX_FNF_TELEPORT_IN));
return TRUE;
}
}
// Failed to teleport them
return FALSE;
}
// End of file Debug lines. Uncomment below "/*" with "//" and compile.
/*
void main()
{
return;
}
//*/