//:://///////////////////////////////////////////// //:: Invocation include: Casting //:: inv_inc_invoke //:://///////////////////////////////////////////// /** @file Defines structures and functions for handling initiating a invocation @author Fox @date Created - 2008.1.26 @thanks to Ornedan for his work on Psionics upon which this is based. */ //::////////////////////////////////////////////// //::////////////////////////////////////////////// ////////////////////////////////////////////////// /* Constants */ ////////////////////////////////////////////////// const string PRC_INVOKING_CLASS = "PRC_CurrentInvocation_InitiatingClass"; const string PRC_INVOCATION_LEVEL = "PRC_CurrentInvocation_Level"; const string INV_DEBUG_IGNORE_CONSTRAINTS = "INV_DEBUG_IGNORE_CONSTRAINTS"; /** * The variable in which the invocation token is stored. If no token exists, * the variable is set to point at the invoker itself. That way OBJECT_INVALID * means the variable is unitialised. */ //const string PRC_INVOCATION_TOKEN_VAR = "PRC_InvocationToken"; //const string PRC_INVOCATION_TOKEN_NAME = "PRC_INVOKETOKEN"; //const float PRC_INVOCATION_HB_DELAY = 0.5f; ////////////////////////////////////////////////// /* Structures */ ////////////////////////////////////////////////// /** * A structure that contains common data used during invocation. */ struct invocation{ /* Generic stuff */ /// The creature Truespeaking the Invocation object oInvoker; /// Whether the invocation is successful or not int bCanInvoke; /// The creature's invoker level in regards to this invocation int nInvokerLevel; /// The invocation's spell ID int nInvocationId; }; ////////////////////////////////////////////////// /* Function prototypes */ ////////////////////////////////////////////////// /** * Determines if the invocation that is currently being attempted to be TrueSpoken * can in fact be truespoken. Determines metainvocations used. * * @param oInvoker A creature attempting to truespeak a invocation at this moment. * @param oTarget The target of the invocation, if any. For pure Area of Effect. * invocations, this should be OBJECT_INVALID. Otherwise the main * target of the invocation as returned by PRCGetSpellTargetObject(). * * @return A invocation structure that contains the data about whether * the invocation was successfully initiated and some other * commonly used data, like the PC's invoker level for this invocation. */ struct invocation EvaluateInvocation(object oInvoker, object oTarget); /** * Causes OBJECT_SELF to use the given invocation. * * @param nInvocation The index of the invocation to use in spells.2da or an UTTER_* * @param nClass The index of the class to use the invocation as in classes.2da or a CLASS_TYPE_* * @param nLevelOverride An optional override to normal invoker level. * @param bInstant If true invocation will be used without casting animations (eldritch sculptor) * Default: 0, which means the parameter is ignored. */ void UseInvocation(int nInvocation, int nClass, int nLevelOverride = 0, int bInstant = FALSE); /** * A debugging function. Takes a invocation structure and * makes a string describing the contents. * * @param move A set of invocation data * @return A string describing the contents of move */ string DebugInvocation2Str(struct invocation invoked); /** * Stores a invocation structure as a set of local variables. If * a structure was already stored with the same name on the same object, * it is overwritten. * * @param oObject The object on which to store the structure * @param sName The name under which to store the structure * @param move The invocation structure to store */ void SetLocalInvocation(object oObject, string sName, struct invocation invoked); /** * Retrieves a previously stored invocation structure. If no structure is stored * by the given name, the structure returned is empty. * * @param oObject The object from which to retrieve the structure * @param sName The name under which the structure is stored * @return The structure built from local variables stored on oObject under sName */ struct invocation GetLocalInvocation(object oObject, string sName); /** * Deletes a stored invocation structure. * * @param oObject The object on which the structure is stored * @param sName The name under which the structure is stored */ void DeleteLocalInvocation(object oObject, string sName); ////////////////////////////////////////////////// /* Includes */ ////////////////////////////////////////////////// //#include "inv_inc_invfunc" //Access in parent #include "prc_spellf_inc" ////////////////////////////////////////////////// /* Internal functions */ ////////////////////////////////////////////////// /** Internal function. * Handles Spellfire absorption when a utterance is used on a friendly spellfire * user. */ struct invocation _DoInvocationSpellfireFriendlyAbsorption(struct invocation invoked, object oTarget) { if(GetLocalInt(oTarget, "SpellfireAbsorbFriendly") && GetIsFriend(oTarget, invoked.oInvoker) ) { if(CheckSpellfire(invoked.oInvoker, oTarget, TRUE)) { PRCShowSpellResist(invoked.oInvoker, oTarget, SPELL_RESIST_MANTLE); invoked.bCanInvoke = FALSE; } } return invoked; } /** Internal function. * Sets invocation-related local variables. * * @param oInvoker The creature currently casting invocation * @param nClass Invocation casting class constant * @param nLevel Invocation level */ void _SetInvocationVariables(object oInvoker, int nClass, int nLevel) { if (DEBUG) FloatingTextStringOnCreature(GetName(oInvoker)+" is a "+IntToString(nClass)+" at "+IntToString(nLevel)+" invocation level", oInvoker); SetLocalInt(oInvoker, PRC_INVOKING_CLASS, nClass + 1); SetLocalInt(oInvoker, PRC_INVOCATION_LEVEL, nLevel); } /** Internal function. * Deletes invocation-related local variables. * * @param oInvoker The creature currently initiating a invocation */ void _CleanInvocationVariables(object oInvoker) { DeleteLocalInt(oInvoker, PRC_INVOKING_CLASS); DeleteLocalInt(oInvoker, PRC_INVOCATION_LEVEL); } /** Internal function. * Determines whether a invocation token exists. If one does, returns it. * * @param oInvoker A creature whose invocation token to get * @return The invocation token if it exists, OBJECT_INVALID otherwise. */ /*object _GetInvocationToken(object oInvoker) { object oInvokeToken = GetLocalObject(oInvoker, PRC_INVOCATION_TOKEN_VAR); // If the token object is no longer valid, set the variable to point at invoker if(!GetIsObjectValid(oInvokeToken)) { oInvokeToken = oInvoker; SetLocalObject(oInvoker, PRC_INVOCATION_TOKEN_VAR, oInvokeToken); } // Check if there is no token if(oInvokeToken == oInvoker) oInvokeToken = OBJECT_INVALID; return oInvokeToken; }*/ /** Internal function. * Destroys the given invocation token and sets the creature's invocation token variable * to point at itself. * * @param oInvoker The invoker whose token to destroy * @param oInvokeToken The token to destroy */ /*void _DestroyInvocationToken(object oInvoker, object oInvokeToken) { DestroyObject(oInvokeToken); SetLocalObject(oInvoker, PRC_INVOCATION_TOKEN_VAR, oInvoker); }*/ /** Internal function. * Destroys the previous invocation token, if any, and creates a new one. * * @param oInvoker A creature for whom to create a invocation token * @return The newly created token */ /*object _CreateInvocationToken(object oInvoker) { object oInvokeToken = _GetInvocationToken(oInvoker); object oStore = GetObjectByTag("PRC_MANIFTOKEN_STORE"); //GetPCSkin(oInvoker); // Delete any previous tokens if(GetIsObjectValid(oInvokeToken)) _DestroyInvocationToken(oInvoker, oInvokeToken); // Create new token and store a reference to it oInvokeToken = CreateItemOnObject(PRC_INVOCATION_TOKEN_NAME, oStore); SetLocalObject(oInvoker, PRC_INVOCATION_TOKEN_VAR, oInvokeToken); Assert(GetIsObjectValid(oInvokeToken), "GetIsObjectValid(oInvokeToken)", "ERROR: Unable to create invocation token! Store object: " + DebugObject2Str(oStore), "inv_inc_invoke", "_CreateInvocationToken()"); return oInvokeToken; }*/ /** Internal function. * Determines whether the given invoker is doing something that would * interrupt initiating a invocation or affected by an effect that would do * the same. * * @param oInvoker A creature on which _InvocationHB() is running * @return TRUE if the creature can continue initiating, * FALSE otherwise */ /*int _InvocationStateCheck(object oInvoker) { int nAction = GetCurrentAction(oInvoker); // If the current action is not among those that could either be used to truespeak the invocation or movement, the invocation fails if(!(nAction || ACTION_CASTSPELL || nAction == ACTION_INVALID || nAction || ACTION_ITEMCASTSPELL || nAction == ACTION_MOVETOPOINT || nAction || ACTION_USEOBJECT || nAction == ACTION_WAIT ) ) return FALSE; // Affected by something that prevents one from initiating effect eTest = GetFirstEffect(oInvoker); int nEType; while(GetIsEffectValid(eTest)) { nEType = GetEffectType(eTest); if(nEType == EFFECT_TYPE_CUTSCENE_PARALYZE || nEType == EFFECT_TYPE_DAZED || nEType == EFFECT_TYPE_PARALYZE || nEType == EFFECT_TYPE_PETRIFY || nEType == EFFECT_TYPE_SLEEP || nEType == EFFECT_TYPE_STUNNED ) return FALSE; // Get next effect eTest = GetNextEffect(oInvoker); } return TRUE; }*/ /** Internal function. * Runs while the given creature is initiating. If they move, take other actions * that would cause them to interrupt initiating the invocation or are affected by an * effect that would cause such interruption, deletes the invocation token. * Stops if such condition occurs or something else destroys the token. * * @param oInvoker A creature initiating a invocation * @param lInvoker The location where the invoker was when starting the invocation * @param oInvokeToken The invocation token that controls the ongoing invocation */ /*void _InvocationHB(object oInvoker, location lInvoker, object oInvokeToken) { if(DEBUG) DoDebug("_InvocationHB() running:\n" + "oInvoker = " + DebugObject2Str(oInvoker) + "\n" + "lInvoker = " + DebugLocation2Str(lInvoker) + "\n" + "oInvokeToken = " + DebugObject2Str(oInvokeToken) + "\n" + "Distance between invocation start location and current location: " + FloatToString(GetDistanceBetweenLocations(lInvoker, GetLocation(oInvoker))) + "\n" ); if(GetIsObjectValid(oInvokeToken)) { // Continuance check if(GetDistanceBetweenLocations(lInvoker, GetLocation(oInvoker)) > 2.0f || // Allow some variance in the location to account for dodging and random fidgeting !_InvocationStateCheck(oInvoker) // Action and effect check ) { if(DEBUG) DoDebug("_InvocationHB(): invoker moved or lost concentration, destroying token"); _DestroyInvocationToken(oInvoker, oInvokeToken); // Inform invoker FloatingTextStrRefOnCreature(16832980, oInvoker, FALSE); // "You have lost concentration on the invocation you were attempting to cast!" } // Schedule next HB else DelayCommand(PRC_INVOCATION_HB_DELAY, _InvocationHB(oInvoker, lInvoker, oInvokeToken)); } }*/ /** Internal function. * Checks if the invoker is in range to use the invocation they are trying to use. * If not, queues commands to make the invoker to run into range. * * @param oInvoker A creature initiating a invocation * @param nInvocation SpellID of the invocation being initiated * @param lTarget The target location or the location of the target object */ /*void _InvocationRangeCheck(object oInvoker, int nInvocation, location lTarget) { float fDistance = GetDistanceBetweenLocations(GetLocation(oInvoker), lTarget); float fRangeLimit; string sRange = Get2DACache("spells", "Range", nInvocation); // Personal range invocations are always in range if(sRange == "P") return; // Ranges according to the CCG spells.2da page else if(sRange == "T") fRangeLimit = 2.25f; else if(sRange == "S") fRangeLimit = 8.0f; else if(sRange == "M") fRangeLimit = 20.0f; else if(sRange == "L") fRangeLimit = 40.0f; // See if we are out of range if(fDistance > fRangeLimit) { // Create waypoint for the movement object oWP = CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", lTarget); // Move into range, with a bit of fudge-factor //ActionMoveToObject(oWP, TRUE, fRangeLimit - 0.15f); // CleanUp ActionDoCommand(DestroyObject(oWP)); // CleanUp, paranoia AssignCommand(oWP, ActionDoCommand(DestroyObject(oWP, 60.0f))); } }*/ /** Internal function. * Assigns the fakecast command that is used to display the conjuration VFX when using an invocation. * Separated from UseInvocation() due to a bug with ActionFakeCastSpellAtObject(), which requires * use of ClearAllActions() to work around. * The problem is that if the target is an item on the ground, if the actor is out of spell * range when doing the fakecast, they will run on top of the item instead of to the edge of * the spell range. This only happens if there was a "real action" in the actor's action queue * immediately prior to the fakecast. */ /*void _AssignUseInvocationFakeCastCommands(object oInvoker, object oTarget, location lTarget, int nSpellID) { // Nuke actions to prevent the fakecast action from bugging ClearAllActions(); if(GetIsObjectValid(oTarget)) ActionCastFakeSpellAtObject(nSpellID, oTarget, PROJECTILE_PATH_TYPE_DEFAULT); else ActionCastFakeSpellAtLocation(nSpellID, lTarget, PROJECTILE_PATH_TYPE_DEFAULT); }*/ /** Internal function. * Places the cheatcasting of the real invocation into the invoker's action queue. */ /*void _UseInvocationAux(object oInvoker, object oInvokeToken, int nSpellId, object oTarget, location lTarget, int nInvocation, int nClass, int nLevelOverride) { if(DEBUG) DoDebug("_UseInvocationAux() running:\n" + "oInvoker = " + DebugObject2Str(oInvoker) + "\n" + "oInvokeToken = " + DebugObject2Str(oInvokeToken) + "\n" + "nSpellId = " + IntToString(nSpellId) + "\n" + "oTarget = " + DebugObject2Str(oTarget) + "\n" + "lTarget = " + DebugLocation2Str(lTarget) + "\n" + "nInvocation = " + IntToString(nInvocation) + "\n" + "nClass = " + IntToString(nClass) + "\n" + "nLevelOverride = " + IntToString(nLevelOverride) + "\n" ); // Make sure nothing has interrupted this invocation if(GetIsObjectValid(oInvokeToken)) { if(DEBUG) DoDebug("_UseInvocationAux(): Token was valid, queueing actual invocation"); // Set the class to cast as SetLocalInt(oInvoker, PRC_INVOKING_CLASS, nClass + 1); // Set the invocation's level SetLocalInt(oInvoker, PRC_INVOCATION_LEVEL, StringToInt(lookup_spell_innate(nSpellId))); if(nLevelOverride != 0) AssignCommand(oInvoker, ActionDoCommand(SetLocalInt(oInvoker, PRC_CASTERLEVEL_OVERRIDE, nLevelOverride))); if(GetIsObjectValid(oTarget)) AssignCommand(oInvoker, ActionCastSpellAtObject(nInvocation, oTarget, METAMAGIC_NONE, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE)); else AssignCommand(oInvoker, ActionCastSpellAtLocation(nInvocation, lTarget, METAMAGIC_NONE, TRUE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE)); if(nLevelOverride != 0) AssignCommand(oInvoker, ActionDoCommand(DeleteLocalInt(oInvoker, PRC_CASTERLEVEL_OVERRIDE))); // Destroy the invocation token for this invocation _DestroyInvocationToken(oInvoker, oInvokeToken); } }*/ ////////////////////////////////////////////////// /* Function definitions */ ////////////////////////////////////////////////// struct invocation EvaluateInvocation(object oInvoker, object oTarget) { /* Get some data */ int bIgnoreConstraints = (DEBUG) ? GetLocalInt(oInvoker, INV_DEBUG_IGNORE_CONSTRAINTS) : FALSE; // invoker-related stuff int nInvokerLevel = GetInvokerLevel(oInvoker); int nInvocationLevel = GetInvocationLevel(oInvoker); int nClass = GetInvokingClass(oInvoker); /* Initialise the invocation structure */ struct invocation invoked; invoked.oInvoker = oInvoker; invoked.bCanInvoke = TRUE; // Assume successfull invocation by default invoked.nInvokerLevel = nInvokerLevel; invoked.nInvocationId = PRCGetSpellId(); if (DEBUG) FloatingTextStringOnCreature(GetName(oInvoker)+" is a "+IntToString(nClass)+" casting invocation "+IntToString(invoked.nInvocationId)+", a "+IntToString(nInvocationLevel)+" level invocation, at "+IntToString(nInvokerLevel)+" invoker level", oInvoker); // Skip doing anything if something has prevented a successful invocation already by this point //if(invoked.bCanInvoke) //{ invoked = _DoInvocationSpellfireFriendlyAbsorption(invoked, oTarget); //}//end if if(DEBUG) DoDebug("EvaluateInvocation(): Final result:\n" + DebugInvocation2Str(invoked)); // Initiate invocation-related variable CleanUp //DelayCommand(0.5f, _CleanInvocationVariables(oInvoker)); return invoked; } void UseInvocation(int nInvocation, int nClass, int nLevelOverride = 0, int bInstant = FALSE) { if(nClass < 0) nClass = CLASS_TYPE_WARLOCK; object oInvoker = OBJECT_SELF; // object oSkin = GetPCSkin(oInvoker); // object oTarget = PRCGetSpellTargetObject(); // object oInvokeToken; // location lTarget = PRCGetSpellTargetLocation(); // int nSpellID = PRCGetSpellId(); //int nInvocationDur = StringToInt(Get2DACache("spells", "ConjTime", nInvocation)) + StringToInt(Get2DACache("spells", "CastTime", nInvocation)); // This is a test case to speed up the impact of the melee attacks, as PerformAttackRound takes the full 6 second. // int nInvocationDur = 0; // Setup invocation-related variables ActionDoCommand(_SetInvocationVariables(oInvoker, nClass, StringToInt(lookup_spell_innate(nInvocation)))); // Cast the actual invocation ActionCastSpell(nInvocation, nLevelOverride, 0, 0, METAMAGIC_NONE, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, bInstant); // Initiate invocation-related variable CleanUp ActionDoCommand(_CleanInvocationVariables(oInvoker)); // Normally swift action invocations check /*if(Get2DACache("feat", "Constant", GetClassFeatFromPower(nInvocation, nClass)) == "SWIFT_ACTION" && // The invocation is swift action to use TakeSwiftAction(oInvoker) // And the invoker can take a swift action now ) { nInvocationDur = 0; }*/ /*if(DEBUG) DoDebug("UseInvocation(): invoker is " + DebugObject2Str(oInvoker) + "\n" + "nInvocation = " + IntToString(nInvocation) + "\n" + "nClass = " + IntToString(nClass) + "\n" + "nLevelOverride = " + IntToString(nLevelOverride) + "\n" + "invocation duration = " + IntToString(nInvocationDur) + "ms \n" //+ "Token exists = " + DebugBool2String(GetIsObjectValid(oInvokeToken)) );*/ // Create the invocation token. Deletes any old tokens and cancels corresponding invocations as a side effect //oInvokeToken = _CreateInvocationToken(oInvoker); /// @todo Hook to the invoker's OnDamaged event for the concentration checks to avoid losing the invocation // Nuke action queue to prevent cheating with creative invocation stacking. // Probably not necessary anymore - Ornedan //if(DEBUG) SendMessageToPC(oInvoker, "Clearing all actions in preparation for second stage of the invocation."); //ClearAllActions(); // If out of range, move to range //_InvocationRangeCheck(oInvoker, nInvocation, GetIsObjectValid(oTarget) ? GetLocation(oTarget) : lTarget); // Start the invocation monitor HB //DelayCommand(IntToFloat(nInvocationDur), ActionDoCommand(_InvocationHB(oInvoker, GetLocation(oInvoker), oInvokeToken))); // Assuming the spell isn't used as a swift action, fakecast for visuals /*if(nInvocationDur > 0) { // Hack. Workaround of a bug with the fakecast actions. See function comment for details ActionDoCommand(_AssignUseInvocationFakeCastCommands(oInvoker, oTarget, lTarget, nSpellID)); }*/ // Action queue the function that will cheatcast the actual invocation //DelayCommand(IntToFloat(nInvocationDur), AssignCommand(oInvoker, ActionDoCommand(_UseInvocationAux(oInvoker, oInvokeToken, nSpellID, oTarget, lTarget, nInvocation, nClass, nLevelOverride)))); } string DebugInvocation2Str(struct invocation invoked) { string sRet; sRet += "oInvoker = " + DebugObject2Str(invoked.oInvoker) + "\n"; sRet += "bCanInvoke = " + DebugBool2String(invoked.bCanInvoke) + "\n"; sRet += "nInvokerLevel = " + IntToString(invoked.nInvokerLevel); return sRet; } void SetLocalInvocation(object oObject, string sName, struct invocation invoked) { //SetLocal (oObject, sName + "_", ); SetLocalObject(oObject, sName + "_oInvoker", invoked.oInvoker); SetLocalInt(oObject, sName + "_bCanInvoke", invoked.bCanInvoke); SetLocalInt(oObject, sName + "_nInvokerLevel", invoked.nInvokerLevel); SetLocalInt(oObject, sName + "_nSpellID", invoked.nInvocationId); } struct invocation GetLocalInvocation(object oObject, string sName) { struct invocation invoked; invoked.oInvoker = GetLocalObject(oObject, sName + "_oInvoker"); invoked.bCanInvoke = GetLocalInt(oObject, sName + "_bCanInvoke"); invoked.nInvokerLevel = GetLocalInt(oObject, sName + "_nInvokerLevel"); invoked.nInvocationId = GetLocalInt(oObject, sName + "_nSpellID"); return invoked; } void DeleteLocalInvocation(object oObject, string sName) { DeleteLocalObject(oObject, sName + "_oInvoker"); DeleteLocalInt(oObject, sName + "_bCanInvoke"); DeleteLocalInt(oObject, sName + "_nInvokerLevel"); DeleteLocalInt(oObject, sName + "_nSpellID"); } void InvocationDebugIgnoreConstraints(object oInvoker) { SetLocalInt(oInvoker, INV_DEBUG_IGNORE_CONSTRAINTS, TRUE); DelayCommand(0.0f, DeleteLocalInt(oInvoker, INV_DEBUG_IGNORE_CONSTRAINTS)); } // Test main //void main(){}