#include "inc_leto_prc" #include "x2_inc_switches" #include "prc_inc_teleport" #include "prc_inc_leadersh" #include "prc_inc_domain" #include "prc_inc_shifting" #include "true_inc_trufunc" #include "prc_craft_inc" #include "prc_inc_dragsham" #include "shd_inc_myst" #include "prc_inc_template" /** * Reads the 2da file onenter_locals.2da and sets local variables * on the entering PC accordingly. 2da format same as personal_switches.2da, * see prc_inc_switches header comment for details. * * @param oPC The PC that just entered the module */ void DoAutoLocals(object oPC) { int i = 0; string sSwitchName, sSwitchType, sSwitchValue; // Use Get2DAString() instead of Get2DACache() to avoid caching. while((sSwitchName = Get2DAString("onenter_locals", "SwitchName", i)) != "") { // Read rest of the line sSwitchType = Get2DAString("onenter_locals", "SwitchType", i); sSwitchValue = Get2DAString("onenter_locals", "SwitchValue", i); // Determine switch type and set the var if (sSwitchType == "float") SetLocalFloat(oPC, sSwitchName, StringToFloat(sSwitchValue)); else if(sSwitchType == "int") SetLocalInt(oPC, sSwitchName, StringToInt(sSwitchValue)); else if(sSwitchType == "string") SetLocalString(oPC, sSwitchName, sSwitchValue); // Increment loop counter i += 1; } } //Restore appearance void RestoreAppearance(object oCreature) { if(!RestoreTrueAppearance(oCreature) && DEBUG) DoDebug("prc_onenter: RestoreAppearance failed"); } void CopyAMSArray(object oHideToken, object oAMSToken, int nClass, string sArray, int nMin, int nMax, int nLoopSize = 100) { int i = nMin; while(i < nMin + nLoopSize && i < nMax) { int nSpell = array_get_int(oAMSToken, sArray, i); int nSpellbookID = RealSpellToSpellbookID(nClass, nSpell); if(nSpellbookID) array_set_int(oHideToken, sArray, i, nSpellbookID); i++; } if(i < nMax) DelayCommand(0.0, CopyAMSArray(oHideToken, oAMSToken, nClass, sArray, i, nMax)); } void DoRestoreAMS(object oPC, int nClass, object oHideToken, object oAMSToken) { string sSpellbook; int nSpellbookType = GetSpellbookTypeForClass(nClass); if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS) { sSpellbook = "Spellbook"+IntToString(nClass); if(DEBUG) DoDebug("DoRestoreAMS: "+sSpellbook); if(persistant_array_exists(oPC, sSpellbook)) array_delete(oHideToken, sSpellbook); array_create(oHideToken, sSpellbook); int nSize = array_get_size(oAMSToken, sSpellbook); if(DEBUG) DoDebug("DoRestoreAMS: array size = "+IntToString(nSize)); if(nSize) DelayCommand(0.0, CopyAMSArray(oHideToken, oAMSToken, nClass, sSpellbook, 0, nSize)); } else if(nSpellbookType == SPELLBOOK_TYPE_PREPARED) { int i; for(i = 0; i <= 9; i++) { sSpellbook = "Spellbook_Known_"+IntToString(nClass)+"_"+IntToString(i); if(DEBUG) DoDebug("DoRestoreAMS: "+sSpellbook); if(array_exists(oHideToken, sSpellbook)) array_delete(oHideToken, sSpellbook); array_create(oHideToken, sSpellbook); int nSize = array_get_size(oAMSToken, sSpellbook); if(DEBUG) DoDebug("DoRestoreAMS: array size = "+IntToString(nSize)); if(nSize) DelayCommand(0.0, CopyAMSArray(oHideToken, oAMSToken, nClass, sSpellbook, 0, nSize)); array_delete(oHideToken, "Spellbook"+IntToString(i)+"_"+IntToString(nClass)); array_delete(oHideToken, "NewSpellbookMem_"+IntToString(nClass)); } } } void OnEnter_AMSCompatibilityCheck(object oPC) { object oAMSToken = GetHideToken(oPC, TRUE); object oHideToken = GetHideToken(oPC); //check PRC version string sVersion = GetLocalString(oAMSToken, "ams_version"); //DoDebug("AMS version = "+sVersion); if(sVersion != AMS_VERSION) { SetLocalInt(oPC, "AMS_RESTORE", 1); int i; for(i = 1; i <= 3; i++) { int nClass = GetClassByPosition(i, oPC); DelayCommand(0.2, DoRestoreAMS(oPC, nClass, oHideToken, oAMSToken)); } DelayCommand(2.0, WipeSpellbookHideFeats(oPC)); SetLocalString(oAMSToken, "ams_version", AMS_VERSION); DelayCommand(5.0, DeleteLocalInt(oPC, "AMS_RESTORE")); } } void main() { //The composite properties system gets confused when an exported //character re-enters. Local Variables are lost and most properties //get re-added, sometimes resulting in larger than normal bonuses. //The only real solution is to wipe the skin on entry. This will //mess up the lich, but only until I hook it into the EvalPRC event - //hopefully in the next update // -Aaon Graywolf object oPC = GetEnteringObject(); //FloatingTextStringOnCreature("PRC on enter was called", oPC, FALSE); // Since OnEnter event fires for the PC when loading a saved game (no idea why, // since it makes saving and reloading change the state of the module), // make sure that the event gets run only once // but not in MP games, so check if it's single player or not!! if(GetLocalInt(oPC, "PRC_ModuleOnEnterDone") && (GetPCPublicCDKey(oPC) == "")) return; // Use a local integer to mark the event as done for the PC, so that it gets // cleared when the character is saved. else SetLocalInt(oPC, "PRC_ModuleOnEnterDone", TRUE); //if server is loading, boot player if(GetLocalInt(GetModule(), PRC_PW_LOGON_DELAY+"_TIMER")) { BootPC(oPC); return; } DoDebug("Running modified prc_onenter with PW CD check"); // Verify players CD key if(GetPRCSwitch(PRC_PW_SECURITY_CD_CHECK)) { DoDebug("PRC_PW_SECURITY_CD_CHECK switch set on the module"); if(ExecuteScriptAndReturnInt("prc_onenter_cd", oPC)) return; } DoDebug("CD-check OK - continue executing prc_onenter"); // Prevent Items on area creation from trigering the GetPCSkin script if (GetObjectType(oPC) != OBJECT_TYPE_CREATURE) return; // return here for DMs as they don't need all this stuff if(GetIsDM(oPC)) return; // Setup class info for EvalPRCFeats() SetupCharacterData(oPC); //do this first so other things dont interfere with it if(GetPRCSwitch(PRC_USE_LETOSCRIPT)) LetoPCEnter(oPC); if(GetPRCSwitch(PRC_CONVOCC_ENABLE) && !GetPRCSwitch(PRC_CONVOCC_CUSTOM_START_LOCATION) && ExecuteScriptAndReturnInt("prc_ccc_main", OBJECT_SELF)) return; // ebonfowl: taking a risk here and commenting this out, it seems obsolete and it is very hard to fix without having an AMS token //check spellbooks for compatibility with other PRC versions //DelayCommand(10.0f, OnEnter_AMSCompatibilityCheck(oPC)); object oSkin = GetPCSkin(oPC); ScrubPCSkin(oPC, oSkin); DeletePRCLocalInts(oSkin); // Gives people the proper spells from their bonus domains // This should run before EvalPRCFeats, because it sets a variable DelayCommand(0.0, CheckBonusDomains(oPC)); // Set the uses per day for domains DelayCommand(0.0, BonusDomainRest(oPC)); // Clear old variables for AMS DelayCommand(0.0, ClearLawLocalVars(oPC)); DelayCommand(0.0, ClearMystLocalVars(oPC)); DelayCommand(0.0, ClearLegacyUses(oPC)); DelayCommand(0.0, DeleteLocalInt(oPC, "RestTimer")); //remove effects from hides, can stack otherwise effect eTest=GetFirstEffect(oPC); while (GetIsEffectValid(eTest)) { if(GetEffectSubType(eTest) == SUBTYPE_SUPERNATURAL && (GetEffectType(eTest) == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE || GetEffectType(eTest) == EFFECT_TYPE_MOVEMENT_SPEED_INCREASE //add other types here ) && !GetIsObjectValid(GetEffectCreator(eTest)) ) RemoveEffect(oPC, eTest); eTest=GetNextEffect(oPC); } SetLocalInt(oPC,"ONENTER",1); // Make sure we reapply any bonuses before the player notices they are gone. DelayCommand(0.1, EvalPRCFeats(oPC)); DelayCommand(0.1, FeatSpecialUsePerDay(oPC)); // Check to see which special prc requirements (i.e. those that can't be done) // through the .2da's, the entering player already meets. ExecuteScript("prc_prereq", oPC); ExecuteScript("prc_psi_ppoints", oPC); ResetTouchOfVitality(oPC); DelayCommand(0.15, DeleteLocalInt(oPC,"ONENTER")); if(GetPRCSwitch(PRC_LETOSCRIPT_FIX_ABILITIES) && !GetIsDM(oPC)) PRCLetoEnter(oPC); //PW tracking starts here if(GetPRCSwitch(PRC_PNP_DEATH_ENABLE)) { //cleanup. int nStatus = GetPersistantLocalInt(oPC, "STATUS"); if (nStatus != ALIVE) AddEventScript(oPC, EVENT_ONHEARTBEAT, "prc_timer_dying", TRUE, FALSE); // Make us fall over if we should be on the floor. if (nStatus == BLEEDING || STABLE || DEAD) AssignCommand(oPC, DelayCommand(0.03, PlayAnimation(ANIMATION_LOOPING_DEAD_BACK, 1.0, 4.0))); // If PRC Death is enabled we require HP tracking too SetPRCSwitch(PRC_PW_HP_TRACKING, TRUE); } if(GetPRCSwitch(PRC_PW_HP_TRACKING)) { // Make sure we actually have stored HP data to read if(GetPersistantLocalInt(oPC, "persist_HP_stored") == -1) { // Read the stored level and set accordingly. int nHP = GetPersistantLocalInt(oPC, "persist_HP"); int nDamage = GetCurrentHitPoints(oPC)-nHP; if (nDamage >= 1) ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL), oPC); } } if(GetPRCSwitch(PRC_PW_TIME)) { struct time tTime = GetPersistantLocalTime(oPC, "persist_Time"); //first pc logging on if(GetIsObjectValid(GetFirstPC()) && !GetIsObjectValid(GetNextPC())) { SetTimeAndDate(tTime); } RecalculateTime(); } if(GetPRCSwitch(PRC_PW_LOCATION_TRACKING)) { struct metalocation lLoc = GetPersistantLocalMetalocation(oPC, "persist_loc"); DelayCommand(6.0, AssignCommand(oPC, JumpToLocation(MetalocationToLocation(lLoc)))); } if(GetPRCSwitch(PRC_PW_MAPPIN_TRACKING) && !GetLocalInt(oPC, "PRC_PW_MAPPIN_TRACKING_Done")) { //this local is set so that this is only done once per server session SetLocalInt(oPC, "PRC_PW_MAPPIN_TRACKING_Done", TRUE); int nCount = GetPersistantLocalInt(oPC, "MapPinCount"); int i; for(i=1; i<=nCount; i++) { struct metalocation mlocLoc = GetPersistantLocalMetalocation(oPC, "MapPin_"+IntToString(i)); CreateMapPinFromMetalocation(mlocLoc, oPC); } } if(GetPRCSwitch(PRC_PW_DEATH_TRACKING)) { if(GetPersistantLocalInt(oPC, "persist_dead")) { int nDamage=9999; ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(DAMAGE_TYPE_MAGICAL, nDamage), oPC); ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oPC); } } if(GetPRCSwitch(PRC_PW_SPELL_TRACKING)) { string sSpellList = GetPersistantLocalString(oPC, "persist_spells"); string sTest; string sChar; while(GetStringLength(sSpellList)) { sChar = GetStringLeft(sSpellList,1); if(sChar == "|") { int nSpell = StringToInt(sTest); DecrementRemainingSpellUses(oPC, nSpell); sTest == ""; } else sTest += sChar; sSpellList = GetStringRight(sSpellList, GetStringLength(sSpellList)-1); } } //check for persistant golems if(persistant_array_exists(oPC, "GolemList")) { MultisummonPreSummon(oPC, TRUE); int i; for(i=1;i<persistant_array_get_size(oPC, "GolemList");i++) { string sResRef = persistant_array_get_string(oPC, "GolemList",i); effect eSummon = SupernaturalEffect(EffectSummonCreature(sResRef)); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSummon, oPC); } } if(GetPRCSwitch(PRC_PNP_ANIMATE_DEAD) || GetPRCSwitch(PRC_MULTISUMMON)) { MultisummonPreSummon(oPC, TRUE); } // Create map pins from marked teleport locations if the PC has requested that such be done. if(GetLocalInt(oPC, PRC_TELEPORT_CREATE_MAP_PINS)) DelayCommand(10.0f, TeleportLocationsToMapPins(oPC)); if(GetPRCSwitch(PRC_XP_USE_SIMPLE_RACIAL_HD) && !GetXP(oPC)) { int nRealRace = GetRacialType(oPC); int nRacialHD = StringToInt(Get2DACache("ECL", "RaceHD", nRealRace)); int nRacialClass = StringToInt(Get2DACache("ECL", "RaceClass", nRealRace)); if(nRacialHD) { if(!GetPRCSwitch(PRC_XP_USE_SIMPLE_RACIAL_HD_NO_FREE_XP)) { int nNewXP = nRacialHD*(nRacialHD+1)*500; //+1 for the original class level SetXP(oPC, nNewXP); if(GetPRCSwitch(PRC_XP_USE_SIMPLE_LA)) DelayCommand(1.0, SetPersistantLocalInt(oPC, sXP_AT_LAST_HEARTBEAT, nNewXP)); } if(GetPRCSwitch(PRC_XP_USE_SIMPLE_RACIAL_HD_NO_SELECTION)) { int i; for(i=0;i<nRacialHD;i++) { LevelUpHenchman(oPC, nRacialClass, TRUE); } } } } // Insert various debug things here if(DEBUG) { // Duplicate PRCItemPropertyBonusFeat monitor SpawnNewThread("PRC_Duplicate_IPBFeat_Mon", "prc_debug_hfeatm", 30.0f, oPC); } if(GetHasFeat(FEAT_SPELLFIRE_WIELDER, oPC)) SpawnNewThread("PRC_Spellfire", "prc_spellfire_hb", 6.0f, oPC); //if the player logged off while being registered as a cohort if(GetPersistantLocalInt(oPC, "RegisteringAsCohort")) AssignCommand(GetModule(), CheckHB(oPC)); // If the PC logs in shifted, unshift them if(GetPersistantLocalInt(oPC, SHIFTER_ISSHIFTED_MARKER)) UnShift(oPC); if(GetPRCSwitch(PRC_ON_ENTER_RESTORE_APPEARANCE)) DelayCommand(2.0f, RestoreAppearance(oPC)); // Set up local variables based on a 2da file DelayCommand(1.0 ,DoAutoLocals(oPC)); ExecuteScript("tob_evnt_recover", oPC); // This prevents the LA function from eating XP on login SetLocalInt(oPC, "PRC_ECL_Delay", TRUE); SetPersistantLocalInt(oPC, sXP_AT_LAST_HEARTBEAT, GetXP(oPC)); DelayCommand(10.0, DeleteLocalInt(oPC, "PRC_ECL_Delay")); // Execute scripts hooked to this event for the player triggering it //How can this work? The PC isnt a valid object before this. - Primogenitor //Some stuff may have gone "When this PC next logs in, run script X" - Ornedan ExecuteAllScriptsHookedToEvent(oPC, EVENT_ONCLIENTENTER); // Start the PC HeartBeat for PC's if(GetIsPC(oPC)) AssignCommand(GetModule(), ExecuteScript("prc_onhb_indiv", oPC)); }