/////////////////////////////////////////////////////////////////////////////// // VARIABLE DECLARATIONS /////////////////////////////////////////////////////////////////////////////// const string PRC_Rest_Generation = "PRC_Rest_Generation"; const string PRC_Rest_Generation_Check = "PRC_Rest_Generation_Check"; const string PRC_ForcedRestDetector_Generation = "PRC_ForcedRestDetector_Generation"; /////////////////////////////////////////////////////////////////////////////// // INCLUDES /////////////////////////////////////////////////////////////////////////////// #include "prc_alterations" /////////////////////////////////////////////////////////////////////////////// // FUNCTION DECLARATIONS /////////////////////////////////////////////////////////////////////////////// // Returns the number of henchmen a player has. int GetNumHenchmen(object oPC); // returns the float time in seconds to close the given distance float GetTimeToCloseDistance(float fMeters, object oPC, int bIsRunning = FALSE); /* PRC ForceRest wrapper * * ForceRest does not trigger the module's OnRest event, nor will the targeted player show up * when GetLastPCRested is used. This wrapper can be used to ForceRest a target, while still * running the PRC's OnRest script. */ void PRCForceRest(object oPC); void PRCForceRested(object oPC); /////////////////////////////////////////////////////////////////////////////// // FUNCTION DEFINITIONS /////////////////////////////////////////////////////////////////////////////// int GetNumHenchmen(object oPC) { if (!GetIsPC(oPC)) return -1; int nLoop, nCount; for (nLoop = 1; nLoop <= GetMaxHenchmen(); nLoop++) { if (GetIsObjectValid(GetHenchman(oPC, nLoop))) nCount++; } return nCount; } float GetTimeToCloseDistance(float fMeters, object oPC, int bIsRunning = FALSE) { float fTime = 0.0; float fSpeed = 0.0; int iMoveRate = GetMovementRate(oPC); switch(iMoveRate) { case 0: fSpeed = 2.0; break; case 1: fSpeed = 0.0; break; case 2: fSpeed = 0.75; break; case 3: fSpeed = 1.25; break; case 4: fSpeed = 1.75; break; case 5: fSpeed = 2.25; break; case 6: fSpeed = 2.75; break; case 7: fSpeed = 2.0; // could change to creature default in the appearance.2da. break; case 8: fSpeed = 5.50; break; } // movement speed doubled if running if(bIsRunning) fSpeed *= 2.0; // other effects that can change movement speed if( PRCGetHasEffect(EFFECT_TYPE_HASTE, oPC) ) fSpeed *= 2.0; if( PRCGetHasEffect(EFFECT_TYPE_MOVEMENT_SPEED_INCREASE, oPC) ) fSpeed *= 2.0; if( PRCGetHasEffect(EFFECT_TYPE_SLOW, oPC) ) fSpeed /= 2.0; if( PRCGetHasEffect(EFFECT_TYPE_MOVEMENT_SPEED_DECREASE, oPC) ) fSpeed /= 2.0; if( GetHasFeat(FEAT_BARBARIAN_ENDURANCE, oPC) ) fSpeed *= 1.1; // 10% gain if( GetHasFeat(FEAT_MONK_ENDURANCE, oPC) ) { float fBonus = 0.1 * (GetLevelByClass(CLASS_TYPE_MONK, oPC) / 3 ); if (fBonus > 0.90) fBonus = 0.9; fBonus += 1.0; fSpeed *= fBonus; } // final calculation fTime = fMeters / fSpeed; return fTime; } int PRC_NextGeneration(int nCurrentGeneration) { nCurrentGeneration++; if (nCurrentGeneration > 30000) nCurrentGeneration = 1; return nCurrentGeneration; } //TODO: TRIED THIS CLEANER VERSION AND IT DIDN'T WORK; FIX IT AND USE IT LATER // effect _prc_inc_ForcedRestDetectorEffect() // { // //Create an extraordinary effect, which is removed only by resting. // //Therefore, if it disappears, we know that resting has happened. // return ExtraordinaryEffect(EffectVisualEffect(VFX_DUR_CESSATE_NEUTRAL)); // //TODO: this could match effects that are not ours. Make it more unique somehow. // } // // void _prc_inc_ApplyForcedRestDetectorEffect(object oPC) // { // ApplyEffectToObject(DURATION_TYPE_PERMANENT, _prc_inc_ForcedRestDetectorEffect(), oPC); // } // // int _prc_inc_TestForcedRestDetectorEffect(effect eEffect) // { // effect eTestEffect = _prc_inc_ForcedRestDetectorEffect(); // return GetEffectType(eEffect) == GetEffectType(eTestEffect) && // GetEffectSubType(eEffect) == GetEffectSubType(eTestEffect) && // GetEffectDurationType(eEffect) == GetEffectDurationType(eTestEffect) && // GetEffectSpellId(eEffect) == -1; // } void _prc_inc_ApplyForcedRestDetectorEffect(object oPC) { //Apply an extraordinary effect, which is removed only by resting ApplyEffectToObject(DURATION_TYPE_PERMANENT, ExtraordinaryEffect(EffectVisualEffect(VFX_DUR_CESSATE_NEUTRAL)), oPC); //TODO: this could match effects that are not ours. Make it more unique somehow. } int _prc_inc_TestForcedRestDetectorEffect(effect eEffect) { return GetEffectType(eEffect) == EFFECT_TYPE_VISUALEFFECT && GetEffectSubType(eEffect) == SUBTYPE_EXTRAORDINARY && GetEffectDurationType(eEffect) == DURATION_TYPE_PERMANENT && GetEffectSpellId(eEffect) == -1; //TODO: this could match effects that are not ours. Make it more unique somehow. } void _prc_inc_ForcedRestDetector(object oPC, int nExpectedGeneration) { int nGeneration = GetLocalInt(oPC, PRC_ForcedRestDetector_Generation); if (nGeneration != nExpectedGeneration) { //There's another forced rest detector running, so stop ourselves and let that one continue DoDebug("STOPPING DUPLICATE FORCED REST DETECTOR"); return; } nGeneration = PRC_NextGeneration(nGeneration); SetLocalInt(oPC, PRC_ForcedRestDetector_Generation, nGeneration); int nRestGeneration = GetLocalInt(oPC, PRC_Rest_Generation); int nRestGenerationCheck = GetLocalInt(oPC, PRC_Rest_Generation_Check); if (nRestGeneration != nRestGenerationCheck) { //A normal rest happened, and the delayed commands it schedules may still //be executing or waiting to execute, so do nothing and check back later. SetLocalInt(oPC, PRC_Rest_Generation_Check, nRestGeneration); DelayCommand(10.0f, _prc_inc_ApplyForcedRestDetectorEffect(oPC)); DelayCommand(10.1f, _prc_inc_ForcedRestDetector(oPC, nGeneration)); } else { int bFound = FALSE; effect eEffect = GetFirstEffect(oPC); while (GetIsEffectValid(eEffect)) { if (_prc_inc_TestForcedRestDetectorEffect(eEffect)) { bFound = TRUE; break; } eEffect = GetNextEffect(oPC); } if (!bFound) { DoDebug("FORCED REST DETECTED"); PRCForceRested(oPC); //This executes the normal resting code, which will be detected above the next time this function executes } //Schedule next check DelayCommand(1.0f, _prc_inc_ForcedRestDetector(oPC, nGeneration)); } } void StartForcedRestDetector(object oPC) { //TODO: make a way for the detector to detect that forced rest has already happened, or else do it here now (but how?) DoDebug("STARTING FORCED REST DETECTOR"); _prc_inc_ApplyForcedRestDetectorEffect(oPC); SetLocalInt(oPC, PRC_Rest_Generation_Check, GetLocalInt(oPC, PRC_Rest_Generation)); int nGeneration = GetLocalInt(oPC, PRC_ForcedRestDetector_Generation); DelayCommand(1.0f, _prc_inc_ForcedRestDetector(oPC, nGeneration)); } void PRCForceRest(object oPC) { ForceRest(oPC); PRCForceRested(oPC); } void PRCForceRested(object oPC) { //The PC has been forced rested--fix the problems this causes. SetLocalInt(oPC, "PRC_ForceRested", 1); ExecuteScript("prc_rest", oPC); }