Archived Spellman's Project content. Added missing Diamond Dragon stat feats. Hospitaler's should be able to take Extra Turning. Dodge proxies should allow entry into Champion of Corellon. Mounted Combat is a prereq for Champion of Corellon. Only Clerics have Domain reqs to enter Morninglord. Verdant Lord was missing BAB 4 entry requirement. Diamond Dragons don't get spellcraft. Re-added Korobokuru race. Added .ltr tables for Korobokuru. Capped Blood in the Water at +20. Capped Pearl of Black Doubt at +20. Added json_GetFirstKnownSpell() and json_GetNextKnownSpell(). Updated all old NWNx functions to work with NWNxEE. Added new switch to enable optional PRCX / NWNxEE shims. Commented out ConvoCC switches on inc_switch_setup.nss Diamond Dragon's stat increases are intrinsic when using NWNxEE. Forsaker's stat increases are intrinsic when using NWNxEE. Vow of Poverty's stat increases are intrinsic when using NWNxEE. Cloud Dragon summon should be Neutral Good. Fixed Verdant Lord's regen. Fixed Forest Master's regen. Morninglord's Creative Fire should affect Alchemy. Added yes/no dialog when choosing Vow of Poverty bonus Exalted Feats. Racial natural AC should be intrinsic when NWNxEE is enabled. Transcendent Vitality's CON bonus is intrinsic when NWNxEE is enabled.
620 lines
23 KiB
Plaintext
620 lines
23 KiB
Plaintext
#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"
|
|
#include "prc_inc_factotum"
|
|
#include "inc_persistsql"
|
|
#include "prc_craft_cv_inc"
|
|
|
|
// Restore crafting state on login with offline time calculation
|
|
void RestoreCraftingStateOnLogin(object oPC)
|
|
{
|
|
if(DEBUG) DoDebug("DEBUG: RestoreCraftingStateOnLogin called");
|
|
|
|
// Check switch conditions
|
|
if(GetPRCSwitch(PRC_PW_LOCATION_TRACKING) &&
|
|
!GetPRCSwitch(PRC_DISABLE_CRAFT) &&
|
|
GetPRCSwitch(PRC_CRAFTING_TIME_SCALE) > 1)
|
|
{
|
|
if(DEBUG) DoDebug("DEBUG: Switch conditions not met for crafting restore");
|
|
return;
|
|
}
|
|
|
|
if(DEBUG) DoDebug("DEBUG: Switch conditions met, checking for saved crafting state");
|
|
|
|
// Check if player has saved crafting state
|
|
if(SQLocalsPlayer_GetInt(oPC, "crafting_active"))
|
|
{
|
|
// Get logout time
|
|
struct time tLogoutTime = GetPersistantLocalTime(oPC, "crafting_logout_time");
|
|
|
|
// Get current login time
|
|
struct time tLoginTime = GetTimeAndDate();
|
|
|
|
// Calculate offline time difference
|
|
struct time tOfflineTime = TimeSubtract(tLoginTime, tLogoutTime);
|
|
|
|
// Convert offline time to rounds (6 seconds per round)
|
|
int nOfflineRounds = tOfflineTime.nSecond / 6;
|
|
nOfflineRounds += tOfflineTime.nMinute * 10; // 10 rounds per minute
|
|
nOfflineRounds += tOfflineTime.nHour * 600; // 600 rounds per hour
|
|
nOfflineRounds += tOfflineTime.nDay * 14400; // 14400 rounds per day
|
|
|
|
// Load saved crafting parameters
|
|
object oItem = SQLocalsPlayer_GetObject(oPC, "crafting_item");
|
|
int nCost = SQLocalsPlayer_GetInt(oPC, "crafting_cost");
|
|
int nXP = SQLocalsPlayer_GetInt(oPC, "crafting_xp");
|
|
int nRounds = SQLocalsPlayer_GetInt(oPC, "crafting_rounds");
|
|
string sFile = SQLocalsPlayer_GetString(oPC, "crafting_file");
|
|
int nLine = SQLocalsPlayer_GetInt(oPC, "crafting_line");
|
|
|
|
// Calculate remaining rounds after offline time
|
|
nRounds = nRounds - nOfflineRounds;
|
|
|
|
// Check if crafting is complete
|
|
if(nRounds <= 0)
|
|
{
|
|
// Set to 1 round so it completes normally
|
|
nRounds = 1;
|
|
FloatingTextStringOnCreature("Your item is almost finished crafting!", oPC);
|
|
}
|
|
|
|
// Restore local variables needed for crafting
|
|
SetLocalObject(oPC, "PRC_CRAFT_ITEM", oItem);
|
|
SetLocalInt(oPC, "PRC_CRAFT_COST", nCost);
|
|
SetLocalInt(oPC, "PRC_CRAFT_XP", nXP);
|
|
SetLocalInt(oPC, "PRC_CRAFT_ROUNDS", nRounds);
|
|
SetLocalString(oPC, "PRC_CRAFT_FILE", sFile);
|
|
SetLocalInt(oPC, "PRC_CRAFT_LINE", nLine);
|
|
|
|
// Restart the crafting heartbeat
|
|
SetLocalInt(oPC, "PRC_CRAFT_HB", 1);
|
|
|
|
// Re-attach concentration monitoring
|
|
AddEventScript(oPC, EVENT_VIRTUAL_ONDAMAGED, "prc_od_conc", FALSE, FALSE);
|
|
|
|
// Resume crafting with remaining rounds
|
|
itemproperty ip = GetFirstItemProperty(oItem);
|
|
DelayCommand(6.0, CraftingHB(oPC, oItem, ip, nCost, nXP, sFile, nLine, nRounds));
|
|
|
|
// Clear the saved state
|
|
SQLocalsPlayer_SetInt(oPC, "crafting_active", 0);
|
|
|
|
FloatingTextStringOnCreature("Crafting resumed with " + IntToString(nRounds) + " rounds remaining", oPC);
|
|
}
|
|
else
|
|
{
|
|
if(DEBUG) DoDebug("DEBUG: No saved crafting state found");
|
|
}
|
|
}
|
|
|
|
void ConvertForsakerToNWNxEE(object oPC)
|
|
{
|
|
// Run only once per PC
|
|
if (GetPersistantLocalInt(oPC, "Forsaker_NWNxEE_Converted")) return;
|
|
|
|
int nForsakerLevel = GetLevelByClass(CLASS_TYPE_FORSAKER, oPC);
|
|
if (!nForsakerLevel) return;
|
|
|
|
// Remove any lingering ForsakerAbilityBoost effects
|
|
effect eLoop = GetFirstEffect(oPC);
|
|
while (GetIsEffectValid(eLoop))
|
|
{
|
|
if (GetEffectTag(eLoop) == "ForsakerAbilityBoost")
|
|
RemoveEffect(oPC, eLoop);
|
|
eLoop = GetNextEffect(oPC);
|
|
}
|
|
|
|
// Apply intrinsic bonuses for each stored level
|
|
int i;
|
|
for (i = 1; i <= nForsakerLevel; i++)
|
|
{
|
|
int nAbility = GetPersistantLocalInt(oPC, "ForsakerBoost" + IntToString(i));
|
|
if (nAbility > 0 && nAbility <= 6)
|
|
{
|
|
PRC_Funcs_ModAbilityScore(oPC, nAbility - 1, 1);
|
|
}
|
|
}
|
|
|
|
// Mark as converted
|
|
SetPersistantLocalInt(oPC, "Forsaker_NWNxEE_Converted", TRUE);
|
|
}
|
|
|
|
void RestoreForsakerAbilities(object oPC)
|
|
{
|
|
// If using NWNxEE intrinsic bonuses, convert once and skip restoration
|
|
if (GetPRCSwitch("PRC_NWNXEE_ENABLED") && GetPRCSwitch("PRC_PRCX_ENABLED"))
|
|
{
|
|
ConvertForsakerToNWNxEE(oPC);
|
|
return;
|
|
}
|
|
|
|
// Existing effect-based restoration logic follows...
|
|
int nForsakerLevel = GetLevelByClass(CLASS_TYPE_FORSAKER, oPC);
|
|
int i;
|
|
|
|
// Remove existing Forsaker ability effects first
|
|
effect eLoop = GetFirstEffect(oPC);
|
|
while(GetIsEffectValid(eLoop))
|
|
{
|
|
if(GetEffectTag(eLoop) == "ForsakerAbilityBoost")
|
|
RemoveEffect(oPC, eLoop);
|
|
eLoop = GetNextEffect(oPC);
|
|
}
|
|
|
|
for(i = 1; i <= nForsakerLevel; i++)
|
|
{
|
|
int nAbility = GetPersistantLocalInt(oPC, "ForsakerBoost" + IntToString(i));
|
|
|
|
if(nAbility > 0 && nAbility <= 6)
|
|
{
|
|
effect eAbility = EffectAbilityIncrease(nAbility - 1, 1);
|
|
eAbility = SupernaturalEffect(eAbility);
|
|
eAbility = TagEffect(eAbility, "ForsakerAbilityBoost");
|
|
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eAbility, oPC);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* void RestoreForsakerAbilities(object oPC)
|
|
{
|
|
int nForsakerLevel = GetLevelByClass(CLASS_TYPE_FORSAKER, oPC);
|
|
int i;
|
|
|
|
// Remove existing Forsaker ability effects first
|
|
effect eLoop = GetFirstEffect(oPC);
|
|
while(GetIsEffectValid(eLoop))
|
|
{
|
|
if(GetEffectTag(eLoop) == "ForsakerAbilityBoost")
|
|
RemoveEffect(oPC, eLoop);
|
|
eLoop = GetNextEffect(oPC);
|
|
}
|
|
|
|
for(i = 1; i <= nForsakerLevel; i++)
|
|
{
|
|
int nAbility = GetPersistantLocalInt(oPC, "ForsakerBoost" + IntToString(i));
|
|
|
|
if(nAbility > 0 && nAbility <= 6)
|
|
{
|
|
effect eAbility = EffectAbilityIncrease(nAbility - 1, 1);
|
|
eAbility = SupernaturalEffect(eAbility);
|
|
eAbility = TagEffect(eAbility, "ForsakerAbilityBoost"); // Add tag for removal
|
|
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eAbility, oPC);
|
|
}
|
|
}
|
|
} */
|
|
|
|
/**
|
|
* 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 <= 8; 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();
|
|
|
|
if(DEBUG) DoDebug("onEnter DEBUG: PW_LOC=" + IntToString(GetPRCSwitch(PRC_PW_LOCATION_TRACKING)) +
|
|
" DISABLE_CRAFT=" + IntToString(GetPRCSwitch(PRC_DISABLE_CRAFT)) +
|
|
" TIME_SCALE=" + IntToString(GetPRCSwitch(PRC_CRAFTING_TIME_SCALE)));
|
|
|
|
//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);
|
|
|
|
// 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);
|
|
if (GetHasFeat(FEAT_VOWOFPOVERTY, oPC) == TRUE)
|
|
{
|
|
ExecuteScript("prc_vop_feats_oe", oPC);
|
|
}
|
|
|
|
if (GetLevelByClass(CLASS_TYPE_FORSAKER, oPC) >= 1)
|
|
{
|
|
RestoreForsakerAbilities(oPC);
|
|
}
|
|
|
|
if(GetLevelByClass(CLASS_TYPE_FACTOTUM, oPC) > 0)
|
|
{
|
|
// Re-add all event hooks that were lost during disconnect
|
|
AddEventScript(oPC, EVENT_ONPLAYERREST_FINISHED, "prc_factotum", FALSE, FALSE);
|
|
// Reinitialize the Inspiration system
|
|
DeleteLocalInt(oPC, "InspirationHB");
|
|
DeleteLocalInt(oPC, "InspirationHBRunning");
|
|
TriggerInspiration(oPC, FALSE);
|
|
SetLocalInt(oPC, "InspirationHB", TRUE);
|
|
}
|
|
|
|
ResetTouchOfVitality(oPC);
|
|
DelayCommand(0.15, DeleteLocalInt(oPC,"ONENTER"));
|
|
|
|
//:: 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);
|
|
|
|
// Handle Hidden Talent
|
|
if(GetHasFeat(FEAT_HIDDEN_TALENT, oPC) && !GetPersistantLocalInt(oPC, "HiddenTalentChosen"))
|
|
{
|
|
if(DEBUG) DoDebug("prc_onenter: Entering Hidden Talent Branch");
|
|
// Trigger Hidden Talent power selection conversation
|
|
//DelayCommand(0.5, ExecuteScript("psi_hidntalent", oPC));
|
|
DelayCommand(1.0f, StartDynamicConversation("ft_hidntalent_ft", oPC, DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, FALSE, 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));
|
|
|
|
// Only restore crafting state if PW features and PnP crafting are enabled
|
|
if(!GetPRCSwitch(PRC_DISABLE_CRAFT) &&
|
|
GetPRCSwitch(PRC_CRAFTING_TIME_SCALE) > 1)
|
|
{
|
|
if(DEBUG) DoDebug("prc_onenter: Calling RestoreCraftingStateOnLogin in 6 seconds.");
|
|
DelayCommand(6.0, RestoreCraftingStateOnLogin(oPC));
|
|
//if(DEBUG) DoDebug("DEBUG: About to call RestoreCraftingStateOnLogin immediately");
|
|
//RestoreCraftingStateOnLogin(oPC);
|
|
}
|
|
|
|
//:: Display PRC8 version
|
|
FloatingTextStringOnCreature("PRC8 Version: " + PRC_VERSION, oPC, FALSE);
|
|
} |