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.
372 lines
18 KiB
Plaintext
372 lines
18 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Spell Include: Dimension Door
|
|
//:: spinc_dimdoor
|
|
//::///////////////////////////////////////////////
|
|
/** @file
|
|
Handles the internal functioning of the Dimension
|
|
Door -type spells, powers and SLAs.
|
|
|
|
@author Ornedan
|
|
@date Created - 2005.10.07
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:://////////////////////////////////////////////
|
|
|
|
#include "prc_inc_spells"
|
|
#include "prc_inc_teleport"
|
|
//#include "prc_inc_listener"
|
|
#include "prc_inc_chat"
|
|
#include "x0_i0_position"
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Constant defintions */
|
|
//////////////////////////////////////////////////
|
|
|
|
const int DIMENSIONDOOR_SELF = 0;
|
|
const int DIMENSIONDOOR_PARTY = 1;
|
|
|
|
|
|
|
|
// Internal constants
|
|
const string DD_CASTERLVL = "PRC_DimensionDoor_CasterLvl";
|
|
const string DD_TELEPORTINGPARTY = "PRC_DimensionDoor_TeleportingParty";
|
|
const string DD_LOCATION = "PRC_DimensionDoor_Location";
|
|
const string DD_DISTANCE = "PRC_DimensionDoor_Distance";
|
|
const string DD_FIRSTSTAGE_DONE = "PRC_DimensionDoor_FirstStageDone";
|
|
const string DD_SCRIPTTOCALL = "PRC_DimensionDoor_ScriptToCallOnTeleport";
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function prototypes */
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Runs the using of a Dimension Door (-like) spell / power / SLA.
|
|
* The target location is either the location of a target object gotten
|
|
* with PRCGetSpellTargetObject() or if the target was a location on the
|
|
* ground, PRCGetSpellTargetLocation(). The actual target location may
|
|
* be different if bUseDirDist is TRUE.
|
|
*
|
|
* @param oCaster The creature using a spell / power / SLA to Dimension Door
|
|
* @param nCasterLvl The creature's caster / manifester level in regards to this use
|
|
* @param nSpellID The spellID currently in effect. If not specified, PRCGetSpellId()
|
|
* will be used to retrieve it.
|
|
* @param sScriptToCall Optionally, a script may be ExecuteScript'd for each of the teleportees
|
|
* after they have reached their destination. This is used to specify
|
|
* the name of such script.
|
|
*
|
|
* @param bSelfOrParty Determines whether this use of Dimension Door teleports only oCaster or
|
|
* also all it's faction memers within 10ft radius (subject to the general
|
|
* teleporting carry limits).
|
|
* Valid values: DIMENSIONDOOR_SELF and DIMENSIONDOOR_PARTY
|
|
*
|
|
* @param bUseDirDist If TRUE, the target location of the spell given via targeting cursor
|
|
* is used only to specify the direction of actual target location,
|
|
* relative to oCaster, and distance is specified via a listener.
|
|
* Otherwise, the target location specified via targeting cursor is used
|
|
* as the actual target.
|
|
*/
|
|
void DimensionDoor(object oCaster, int nCasterLvl, int nSpellID = -1, string sScriptToCall = "",
|
|
int bSelfOrParty = DIMENSIONDOOR_SELF, int bUseDirDist = FALSE
|
|
);
|
|
|
|
|
|
/********************\
|
|
* Internal Functions *
|
|
\********************/
|
|
|
|
/**
|
|
* Extracts data from local variables, calls DoDimensionDoorTeleport() using
|
|
* that data and then does CleanLocals().
|
|
*
|
|
* @param oCaster creature using Dimension Door
|
|
*/
|
|
void DimensionDoorAux(object oCaster);
|
|
|
|
/**
|
|
* Determines the target location of a Dimension Door. If using the
|
|
* direction & distance listener trick, the direction of the location
|
|
* is calculated from the base target location and distance is based
|
|
* on the caster's speech.
|
|
* Otherwise, the base target location is used.
|
|
*
|
|
* @param oCaster creature using Dimension Door
|
|
* @param nCasterLvl oCaster's caster or manifester level in regards to this
|
|
* Dimension Door use
|
|
* @param lBaseTarget the base target location, obtained via normal targeting
|
|
* @param fDistance the distance specified by speech for the direction &
|
|
* distance trick. If this is 0.0f, the trick is not used.
|
|
*
|
|
* @return The location where this Dimension Door is supposed jump
|
|
* it's targets to.
|
|
*/
|
|
location GetDimensionDoorLocation(object oCaster, int nCasterLvl, location lBaseTarget, float fDistance);
|
|
|
|
/**
|
|
* Does the actual teleporting and VFX.
|
|
*
|
|
* @param oCaster The user of the Dimension Door being run
|
|
* @param lTarget The location to teleport to
|
|
* @param bTeleportingParty Whether this dimension door is teleporting only the user
|
|
* or also surrounding party. Determines the size of the VFX
|
|
* @param sScriptToCall The script to call for each teleporting object once it has
|
|
* reached the destination
|
|
*/
|
|
void DoDimensionDoorTeleport(object oCaster, location lTarget, int bTeleportingParty, string sScriptToCall);
|
|
|
|
/**
|
|
* Deletes local variables used to preserve state over delays by these functions.
|
|
*
|
|
* @param oCaster creature on whom the data was stored
|
|
*/
|
|
void CleanLocals(object oCaster);
|
|
|
|
/**
|
|
* A wrapper for assigning two commands at once after a delay from DoDimensionDoorTeleport().
|
|
* First, the jump command and then, if the script is non-blank, a call to ExecuteScript
|
|
* the given post-jump script.
|
|
*
|
|
* @param oJumpee creature being teleported by Dimension Door
|
|
* @param lTarget the location to jump to
|
|
* @param sScriptToCall script for oJumpee to execute once it has jumped
|
|
*/
|
|
void AssignDimensionDoorCommands(object oJumpee, location lTarget, string sScriptToCall);
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function defintions */
|
|
//////////////////////////////////////////////////
|
|
|
|
void DimensionDoor(object oCaster, int nCasterLvl, int nSpellID = -1, string sScriptToCall = "",
|
|
int bSelfOrParty = DIMENSIONDOOR_SELF, int bUseDirDist = FALSE
|
|
)
|
|
{
|
|
if(DEBUG) DoDebug("spinc_dimdoor: Running DimensionDoor()" + (GetLocalInt(oCaster, DD_FIRSTSTAGE_DONE) ? ": ERROR: Called while in second stage!":""));
|
|
|
|
/* Main spellscript */
|
|
if(!GetLocalInt(oCaster, DD_FIRSTSTAGE_DONE))
|
|
{
|
|
// Get the spell's base target location
|
|
location lTarget = GetIsObjectValid(PRCGetSpellTargetObject()) ? // Are we teleporting to some object, or just at a spot on the ground?
|
|
GetLocation(PRCGetSpellTargetObject()) : // Teleporting to some object
|
|
PRCGetSpellTargetLocation(); // Teleporting to a spot on the ground
|
|
|
|
|
|
// Run the code to build an array of targets on the caster
|
|
GetTeleportingObjects(oCaster, nCasterLvl, bSelfOrParty == DIMENSIONDOOR_PARTY);
|
|
|
|
if(!bUseDirDist)
|
|
{
|
|
SetLocalInt(oCaster, DD_FIRSTSTAGE_DONE, TRUE);
|
|
}
|
|
else
|
|
{
|
|
//SpawnListener("prc_dimdoor_aux", GetLocation(oCaster), "**", oCaster, 10.0f);
|
|
AddChatEventHook(oCaster, "prc_dimdoor_aux", 10.0f);
|
|
SendMessageToPCByStrRef(oCaster, 16825211); // "You have 10 seconds to speak the distance (in meters)"
|
|
DelayCommand(10.0f, CleanLocals(oCaster));
|
|
}
|
|
|
|
// Store the location in either case. For the direction and distance version, it's used to determine direction.
|
|
SetLocalLocation(oCaster, DD_LOCATION, lTarget);
|
|
|
|
// Store various other data for use in DimensionDoorAux()
|
|
SetLocalInt(oCaster, DD_CASTERLVL, nCasterLvl);
|
|
SetLocalInt(oCaster, DD_TELEPORTINGPARTY, bSelfOrParty == DIMENSIONDOOR_PARTY);
|
|
SetLocalString(oCaster, DD_SCRIPTTOCALL, sScriptToCall);
|
|
}
|
|
if(GetLocalInt(oCaster, DD_FIRSTSTAGE_DONE))
|
|
{
|
|
DimensionDoorAux(oCaster);
|
|
}
|
|
}
|
|
|
|
void DimensionDoorAux(object oCaster)
|
|
{
|
|
DoDimensionDoorTeleport(oCaster,
|
|
GetDimensionDoorLocation(oCaster,
|
|
GetLocalInt(oCaster, DD_CASTERLVL),
|
|
GetLocalLocation(oCaster, DD_LOCATION),
|
|
GetLocalFloat(oCaster, DD_DISTANCE)
|
|
),
|
|
GetLocalInt(oCaster, DD_TELEPORTINGPARTY),
|
|
GetLocalString(oCaster, DD_SCRIPTTOCALL)
|
|
);
|
|
CleanLocals(oCaster);
|
|
}
|
|
|
|
location GetDimensionDoorLocation(object oCaster, int nCasterLvl, location lBaseTarget, float fDistance)
|
|
{
|
|
if(DEBUG) DoDebug("spinc_dimdoor: GetDimensionDoorLocation(" + GetName(oCaster) + ", " + IntToString(nCasterLvl) + ", " + LocationToString(lBaseTarget) + ", " + FloatToString(fDistance) + ")");
|
|
// Default to base target
|
|
location lTarget = lBaseTarget;
|
|
|
|
// First, check if we are using the Direction & Distance mode
|
|
if(fDistance != 0.0f)
|
|
{
|
|
if(DEBUG) DoDebug("spinc_dimdoor: Calculating the new location based on direction and distance");
|
|
// Make sure the distance jumped is in range
|
|
if(GetLocalInt(oCaster, "DimensionalJaunt") && fDistance > FeetToMeters(5.0 * (nCasterLvl)))
|
|
{
|
|
DeleteLocalInt(oCaster, "DimensionalJaunt");
|
|
fDistance = FeetToMeters(5.0 * (nCasterLvl));
|
|
string sPretty = FloatToString(fDistance);
|
|
sPretty = GetSubString(sPretty, 0, FindSubString(sPretty, ".") + 2); // Trunctate decimals to the last two
|
|
sPretty += "m"; // Note the unit. Since this is SI, the letter should be universal
|
|
// "You can't teleport that far, distance limited to"
|
|
SendMessageToPC(oCaster, GetStringByStrRef(16825210) + " " + sPretty);
|
|
}
|
|
else if(GetLocalInt(oCaster, "FleeTheScene") && fDistance > FeetToMeters(25.0 + 5.0 * (nCasterLvl / 2)))
|
|
{
|
|
DeleteLocalInt(oCaster, "FleeTheScene");
|
|
fDistance = FeetToMeters(25.0 + 5.0 * (nCasterLvl / 2));
|
|
string sPretty = FloatToString(fDistance);
|
|
sPretty = GetSubString(sPretty, 0, FindSubString(sPretty, ".") + 2); // Trunctate decimals to the last two
|
|
sPretty += "m"; // Note the unit. Since this is SI, the letter should be universal
|
|
// "You can't teleport that far, distance limited to"
|
|
SendMessageToPC(oCaster, GetStringByStrRef(16825210) + " " + sPretty);
|
|
}
|
|
else if(GetLocalInt(oCaster, "Treewalk") && fDistance > FeetToMeters(60.0))
|
|
{
|
|
fDistance = FeetToMeters(60.0);
|
|
string sPretty = FloatToString(fDistance);
|
|
sPretty = GetSubString(sPretty, 0, FindSubString(sPretty, ".") + 2); // Trunctate decimals to the last two
|
|
sPretty += "m"; // Note the unit. Since this is SI, the letter should be universal
|
|
// "You can't teleport that far, distance limited to"
|
|
SendMessageToPC(oCaster, GetStringByStrRef(16825210) + " " + sPretty);
|
|
}
|
|
else if(fDistance > FeetToMeters(400.0 + 40.0 * nCasterLvl))
|
|
{
|
|
fDistance = FeetToMeters(400.0 + 40.0 * nCasterLvl);
|
|
string sPretty = FloatToString(fDistance);
|
|
sPretty = GetSubString(sPretty, 0, FindSubString(sPretty, ".") + 2); // Trunctate decimals to the last two
|
|
sPretty += "m"; // Note the unit. Since this is SI, the letter should be universal
|
|
// "You can't teleport that far, distance limited to"
|
|
SendMessageToPC(oCaster, GetStringByStrRef(16825210) + " " + sPretty);
|
|
}
|
|
location lCaster = GetLocation(oCaster);
|
|
vector vCaster = GetPositionFromLocation(lCaster);
|
|
vector vBaseTarget = GetPositionFromLocation(lBaseTarget);
|
|
/*float fAngle = acos((vBaseTarget.x - vCaster.x) / GetDistanceBetweenLocations(lCaster, lBaseTarget));
|
|
// The above formula only returns values [0, 180], so it needs to be mirrored if the caster is moving towards negative y
|
|
if((vBaseTarget.y - vCaster.y) < 0.0f)
|
|
fAngle = -fAngle;
|
|
*/
|
|
float fAngle = GetRelativeAngleBetweenLocations(lCaster, lBaseTarget);
|
|
if(DEBUG) DoDebug("spinc_dimdoor: Angle is " + FloatToString(fAngle));
|
|
vector vTarget = Vector(vCaster.x + cos(fAngle) * fDistance,
|
|
vCaster.y + sin(fAngle) * fDistance,
|
|
vCaster.z
|
|
);
|
|
// Sanity checks to make sure the location is not out of map bounds in the negative direction.
|
|
if(vTarget.x < 0.0f) vTarget.x = 0.0f;
|
|
if(vTarget.y < 0.0f) vTarget.y = 0.0f;
|
|
|
|
lTarget = Location(GetAreaFromLocation(lBaseTarget), vTarget, GetFacingFromLocation(lBaseTarget));
|
|
}
|
|
|
|
if (GetLocalInt(oCaster, "BlackLabyrinth"))
|
|
return GenerateNewLocationFromLocation(lTarget, FeetToMeters(5.0*d4()), IntToFloat(Random(360)), IntToFloat(Random(360)));
|
|
/* This works, but it was replaced with the direction & distance trick above since that has more versatility in
|
|
selecting the target even though it is slower due to both not fitting on the radial.
|
|
Left here in case it needs to be brought back at a later date.
|
|
|
|
else if(GetHasTeleportQuickSelection(oCaster, PRC_TELEPORT_ACTIVE_QUICKSELECTION))
|
|
{
|
|
if(DEBUG) DoDebug("spinc_dimdoor: Quickselect is active");
|
|
location lTest = MetalocationToLocation(GetActiveTeleportQuickSelection(oCaster, FALSE));
|
|
|
|
if(GetArea(oCaster) == GetAreaFromLocation(lTest))
|
|
{
|
|
if(DEBUG) DoDebug("spinc_dimdoor: Quickselect is in same area");
|
|
if(GetDistanceBetweenLocations(GetLocation(oCaster), lTest) <= FeetToMeters(400.0 + 40.0 * nCasterLvl))
|
|
{
|
|
if(DEBUG) DoDebug("spinc_dimdoor: Quickselect is in range");
|
|
// Used the active quickselection, so clear it
|
|
RemoveTeleportQuickSelection(oCaster, PRC_TELEPORT_ACTIVE_QUICKSELECTION);
|
|
lTarget = lTest;
|
|
}
|
|
}
|
|
}*/
|
|
|
|
// Return the target gotten after possible modifications
|
|
return lTarget;
|
|
}
|
|
|
|
void DoDimensionDoorTeleport(object oCaster, location lTarget, int bTeleportingParty, string sScriptToCall)
|
|
{
|
|
location lCaster = GetLocation(oCaster);
|
|
object oTarget;
|
|
int i;
|
|
|
|
// Check if it's valid for the caster to teleport. If he can't go, no-one goes
|
|
if(GetCanTeleport(oCaster, lTarget, TRUE, TRUE))
|
|
{
|
|
// Loop over the targets, checking if they can teleport. Redundant check on the caster, but shouldn't cause any trouble
|
|
for(i = 0; i < array_get_size(oCaster, PRC_TELEPORTING_OBJECTS_ARRAY); i++)
|
|
{
|
|
oTarget = array_get_object(oCaster, PRC_TELEPORTING_OBJECTS_ARRAY, i);
|
|
if(GetCanTeleport(oTarget, lTarget, TRUE))
|
|
{
|
|
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY), oTarget, 0.55));
|
|
DelayCommand(1.5, AssignDimensionDoorCommands(oTarget, lTarget, sScriptToCall));
|
|
}
|
|
}
|
|
|
|
// VFX //
|
|
//DrawLineFromCenter(DURATION_TYPE_INSTANT, VFX_IMP_WIND, lCenter, 21.0, 0.0, 0.0, 29, 2.0, "z");
|
|
//BeamPolygon(1, 73, lCenter, 5.0, 8, 3.0, "invisobj", 1.0, 0.0, 0.0, "z", -1, -1, 0.0, 1.0, 2.0);
|
|
|
|
// Make the caster animate for the second of delay
|
|
AssignCommand(oCaster, ClearAllActions());
|
|
AssignCommand(oCaster, SetFacingPoint(GetPositionFromLocation(lTarget)));
|
|
AssignCommand(oCaster, ActionPlayAnimation(ANIMATION_LOOPING_CONJURE1, 1.0f, 1.0f));
|
|
|
|
// First, spawn a circle of ligntning around the caster
|
|
BeamPolygon(DURATION_TYPE_PERMANENT, VFX_BEAM_LIGHTNING, lCaster,
|
|
bTeleportingParty ? FeetToMeters(10.0) : FeetToMeters(3.0), // Single TP: 3ft radius; Party TP: 10ft radius
|
|
bTeleportingParty ? 15 : 10, // More nodes for the group VFX
|
|
1.5f, "prc_invisobj", 1.0f, 0.0f, 0.0f, "z", 0.0f, 0.0f,
|
|
-1, -1, 0.0f, 1.0f, // No secondary VFX
|
|
2.0f // Non-zero lifetime, so the placeables eventually get removed
|
|
);
|
|
|
|
|
|
//BeamPolygon(1, 73, lCaster, 5.0, 8, 3.0, "prc_invisobj", 1.0, 0.0, 0.0, "z", -1, -1, 0.0, 1.0, 2.0);
|
|
|
|
// After a moment, draw a line from the caster to the destination
|
|
DelayCommand(1.0, DrawLineFromVectorToVector(DURATION_TYPE_INSTANT, VFX_IMP_WIND, GetArea(oCaster), GetPositionFromLocation(lCaster), GetPositionFromLocation(lTarget), 0.0,
|
|
FloatToInt(GetDistanceBetweenLocations(lCaster, lTarget)), // One VFX every meter
|
|
0.5));
|
|
// Then, spawn a circle of ligtning at the destination
|
|
DelayCommand(0.5, BeamPolygon(DURATION_TYPE_TEMPORARY, VFX_BEAM_LIGHTNING, lTarget,
|
|
bTeleportingParty ? FeetToMeters(10.0) : FeetToMeters(3.0),
|
|
bTeleportingParty ? 15 : 10,
|
|
1.5, "prc_invisobj", 1.0, 0.0, 0.0, "z", 0.0f, 0.0f, -1, -1, 0.0, 1.0, 2.0));
|
|
}
|
|
|
|
// Cleanup
|
|
array_delete(oCaster, PRC_TELEPORTING_OBJECTS_ARRAY);
|
|
}
|
|
|
|
void AssignDimensionDoorCommands(object oJumpee, location lTarget, string sScriptToCall)
|
|
{
|
|
AssignCommand(oJumpee, JumpToLocation(lTarget));
|
|
if(sScriptToCall != "")
|
|
AssignCommand(oJumpee, ActionDoCommand(ExecuteScript(sScriptToCall, oJumpee)));
|
|
DelayCommand(0.5, ShadowPounce(oJumpee));
|
|
}
|
|
|
|
void CleanLocals(object oCaster)
|
|
{
|
|
DeleteLocalInt (oCaster, DD_CASTERLVL);
|
|
DeleteLocalInt (oCaster, DD_TELEPORTINGPARTY);
|
|
DeleteLocalLocation(oCaster, DD_LOCATION);
|
|
DeleteLocalFloat (oCaster, DD_DISTANCE);
|
|
DeleteLocalInt (oCaster, DD_FIRSTSTAGE_DONE);
|
|
DeleteLocalString (oCaster, DD_SCRIPTTOCALL);
|
|
}
|
|
|
|
|
|
// Test main
|
|
//void main(){} |