2026/02/08 Update
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.
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include "NW_I0_GENERIC"
|
||||
#include "nw_i0_spells"
|
||||
#include "inc_persist_loca"
|
||||
#include "inc_nwnx_funcs"
|
||||
|
||||
effect VoPDamage(int nTotalEnhancement)
|
||||
{
|
||||
@@ -37,6 +38,68 @@ effect VoPDamage(int nTotalEnhancement)
|
||||
return eDamage;
|
||||
}
|
||||
|
||||
void ConvertVoPFeatsToNWNxEE(object oPC)
|
||||
{
|
||||
if (GetPersistantLocalInt(oPC, "VoP_NWNxEE_Feats_Converted")) return;
|
||||
if (!GetHasFeat(FEAT_VOWOFPOVERTY, oPC)) return;
|
||||
|
||||
// Remove any lingering VoP feat effects
|
||||
effect eLoop = GetFirstEffect(oPC);
|
||||
while (GetIsEffectValid(eLoop))
|
||||
{
|
||||
string sTag = GetEffectTag(eLoop);
|
||||
if (GetStringLeft(sTag, 7) == "VoPFeat")
|
||||
RemoveEffect(oPC, eLoop);
|
||||
eLoop = GetNextEffect(oPC);
|
||||
}
|
||||
|
||||
// Reapply intrinsic feats for each stored VoPFeatID entry
|
||||
int i = 1;
|
||||
string sKey;
|
||||
while (GetPersistantLocalInt(oPC, "VoPFeatID" + IntToString(i)))
|
||||
{
|
||||
int nFeatID = StringToInt(Get2DAString("prc_vop_feats", "FeatIndex", i - 1));
|
||||
if (nFeatID > 0)
|
||||
{
|
||||
PRC_Funcs_AddFeat(oPC, nFeatID);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
SetPersistantLocalInt(oPC, "VoP_NWNxEE_Feats_Converted", TRUE);
|
||||
}
|
||||
|
||||
|
||||
void ConvertVoPToNWNxEE(object oPC)
|
||||
{
|
||||
if (GetPersistantLocalInt(oPC, "VoP_NWNxEE_Converted")) return;
|
||||
if (!GetHasFeat(FEAT_VOWOFPOVERTY, oPC)) return;
|
||||
|
||||
int nLevel = GetCharacterLevel(oPC) - GetPersistantLocalInt(oPC, "VoPLevel1") + 1;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
int i;
|
||||
|
||||
// Remove existing VoP ability item properties
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
RemoveSpecificProperty(oSkin, ITEM_PROPERTY_ABILITY_BONUS, i, -1, 1, "VoPBoostStat"+IntToString(i), -1, DURATION_TYPE_PERMANENT);
|
||||
}
|
||||
|
||||
// Reapply intrinsic bonuses for each stored VoPBoost
|
||||
for (i = 1; i <= nLevel; i++)
|
||||
{
|
||||
int nStored = GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(i));
|
||||
if (nStored >= 10)
|
||||
{
|
||||
int stat = nStored - 10;
|
||||
int value = 2 * (1 + (nLevel - i) / 4);
|
||||
PRC_Funcs_ModAbilityScore(oPC, stat, value);
|
||||
}
|
||||
}
|
||||
|
||||
SetPersistantLocalInt(oPC, "VoP_NWNxEE_Converted", TRUE);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int nEvent = GetRunningEvent();
|
||||
@@ -83,7 +146,13 @@ void main()
|
||||
|
||||
if(nEvent == FALSE)
|
||||
{
|
||||
//Check if level up bonus has already been chosen and given for any of past VoP levels
|
||||
if (GetPRCSwitch("PRC_NWNXEE_ENABLED") && GetPRCSwitch("PRC_PRCX_ENABLED"))
|
||||
ConvertVoPToNWNxEE(oPC);
|
||||
|
||||
if (GetPRCSwitch("PRC_NWNXEE_ENABLED") && GetPRCSwitch("PRC_PRCX_ENABLED"))
|
||||
ConvertVoPFeatsToNWNxEE(oPC);
|
||||
|
||||
//Check if level up bonus has already been chosen and given for any of past VoP levels
|
||||
for(nLevelCheck=1; nLevelCheck <= nLevel; nLevelCheck++)
|
||||
{
|
||||
//Call stat boost dialogue for level 7 and each 4 levels after that
|
||||
@@ -93,14 +162,37 @@ void main()
|
||||
SetPersistantLocalInt(oPC,"VoPBoostCheck",nLevelCheck);
|
||||
StartDynamicConversation("ft_vowpoverty_ab", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
}
|
||||
|
||||
//Applying stat boosts
|
||||
//Applying stat boosts
|
||||
if(GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(nLevelCheck)) >= 10)
|
||||
{
|
||||
int stat = GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(nLevelCheck)) - 10;
|
||||
int value = 2 * (1 + (nLevel - nLevelCheck) / 4);
|
||||
|
||||
if (GetPRCSwitch("PRC_NWNXEE_ENABLED") && GetPRCSwitch("PRC_PRCX_ENABLED"))
|
||||
{
|
||||
// Track last applied intrinsic bonus per ability to avoid stacking
|
||||
string sKey = "VoP_EE_Boost_" + IntToString(stat);
|
||||
int nLastApplied = GetPersistantLocalInt(oPC, sKey);
|
||||
int nDelta = value - nLastApplied;
|
||||
if (nDelta > 0)
|
||||
{
|
||||
PRC_Funcs_ModAbilityScore(oPC, stat, nDelta);
|
||||
SetPersistantLocalInt(oPC, sKey, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback to item property on skin (overwrites, so safe to run each level)
|
||||
SetCompositeBonus(oSkin, "VoPBoostStat"+IntToString(stat), value, ITEM_PROPERTY_ABILITY_BONUS, stat);
|
||||
}
|
||||
}
|
||||
/* //Applying stat boosts
|
||||
if(GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(nLevelCheck)) >= 10)
|
||||
{
|
||||
int stat = GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(nLevelCheck)) - 10;
|
||||
int value = 2 * (1 + (nLevel - nLevelCheck) / 4);
|
||||
SetCompositeBonus(oSkin, "VoPBoostStat"+IntToString(stat), value, ITEM_PROPERTY_ABILITY_BONUS, stat);
|
||||
}
|
||||
} */
|
||||
|
||||
//Call exalted feat for each even level
|
||||
if (!GetPersistantLocalInt(oPC, "VoPFeat"+IntToString(nLevelCheck)) && (nLevelCheck-(nLevelCheck/2)*2 == 0))
|
||||
|
||||
@@ -16,17 +16,180 @@
|
||||
#include "NW_I0_GENERIC"
|
||||
#include "inc_persist_loca"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Constant defintions */
|
||||
//////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////
|
||||
/* Constant definitions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
const int STAGE_SELECT_ABIL = 0;
|
||||
const int STAGE_CONFIRM_SELECTION = 1;
|
||||
|
||||
const int STRREF_SELECTED_HEADER2 = 16824210; // "Is this correct?"
|
||||
const int STRREF_YES = 4752; // "Yes"
|
||||
const int STRREF_NO = 4753; // "No"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function definitions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
int i, j, nTest, nRow;
|
||||
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
|
||||
int nStage = GetStage(oPC);
|
||||
int nLevel = GetPersistantLocalInt(oPC, "VoPFeatCheck");
|
||||
|
||||
// Check which of the conversation scripts called the scripts
|
||||
if(nValue == 0) // All of them set the DynConv_Var to non-zero value, so something is wrong -> abort
|
||||
{
|
||||
if(DEBUG) DoDebug("ft_vowpoverty_ft: Aborting due to error.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(nValue == DYNCONV_SETUP_STAGE)
|
||||
{
|
||||
// Check if this stage is marked as already set up
|
||||
// This stops list duplication when scrolling
|
||||
if(!GetIsStageSetUp(nStage, oPC))
|
||||
{
|
||||
// Maneuver selection stage
|
||||
if(nStage == STAGE_SELECT_ABIL)
|
||||
{
|
||||
//Check which Feats have been added by this ability
|
||||
int nTotalRows = Get2DARowCount("prc_vop_feats");
|
||||
effect eCheckEffect = GetFirstEffect(oPC);
|
||||
while (GetIsEffectValid(eCheckEffect))
|
||||
{
|
||||
for(nRow=0; nRow <= nTotalRows; nRow++)
|
||||
{
|
||||
string nFeat = Get2DAString("prc_vop_feats","FeatIndex",nRow);
|
||||
if(GetEffectTag(eCheckEffect) == "VoPFeat"+nFeat) SetLocalInt(oPC,"VoPFeat"+nFeat,1);
|
||||
}
|
||||
eCheckEffect = GetNextEffect(oPC);
|
||||
}
|
||||
|
||||
SetHeader("Choose an Exalted Feat for this new level under a Vow of Poverty:");
|
||||
//Add new option depending if it was not selected and char has all prereqs
|
||||
for(nRow=0; nRow <= nTotalRows; nRow++)
|
||||
{
|
||||
//Get prereqs from 2DA
|
||||
string sName = Get2DAString("prc_vop_feats","Name",nRow);
|
||||
int nFeat = StringToInt(Get2DAString("prc_vop_feats","FeatIndex",nRow));
|
||||
int nPreReq1 = StringToInt(Get2DAString("prc_vop_feats","PreReq1",nRow));
|
||||
int nPreReq2 = StringToInt(Get2DAString("prc_vop_feats","PreReq2",nRow));
|
||||
int nCon = StringToInt(Get2DAString("prc_vop_feats","Con",nRow));
|
||||
int nWis = StringToInt(Get2DAString("prc_vop_feats","Wis",nRow));
|
||||
int nCha = StringToInt(Get2DAString("prc_vop_feats","Cha",nRow));
|
||||
int nBAB = StringToInt(Get2DAString("prc_vop_feats","BAB",nRow));
|
||||
int nLaw = StringToInt(Get2DAString("prc_vop_feats","Law",nRow));
|
||||
|
||||
int nAllPreReq = 1;
|
||||
|
||||
//Check if prereqs exist and, if so, if they are met - if not, set bol to 0
|
||||
if(nPreReq1>0 && !GetHasFeat(nPreReq1, oPC)) nAllPreReq = 0;
|
||||
if(nPreReq1==213 && GetLevelByClass(CLASS_TYPE_MONK, oPC) >= 1) nAllPreReq = 1; //for Ki Strike and monks
|
||||
if(nPreReq2>0 && !GetHasFeat(nPreReq2, oPC)) nAllPreReq = 0;
|
||||
if(nCon>0 && GetAbilityScore(oPC,ABILITY_CONSTITUTION, TRUE) < nCon) nAllPreReq = 0;
|
||||
if(nWis>0 && GetAbilityScore(oPC,ABILITY_WISDOM, TRUE) < nWis) nAllPreReq = 0;
|
||||
if(nCha>0 && GetAbilityScore(oPC,ABILITY_CHARISMA, TRUE) < nCha) nAllPreReq = 0;
|
||||
if(nBAB>0 && GetBaseAttackBonus(oPC) < nBAB) nAllPreReq = 0;
|
||||
if(nLaw>0 && !(GetAlignmentLawChaos(oPC) == ALIGNMENT_LAWFUL)) nAllPreReq = 0;
|
||||
|
||||
if (!GetHasFeat(nFeat, oPC) && !GetLocalInt(oPC, "VoPFeat"+IntToString(nFeat)) && nAllPreReq == 1) AddChoice(sName, nFeat, oPC);
|
||||
}
|
||||
|
||||
AddChoice("Cancel (you will get no Exalted Feats this level)", 0, oPC);
|
||||
SetDefaultTokens(); //If there are more than 10 options, add Next
|
||||
MarkStageSetUp(STAGE_SELECT_ABIL, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRM_SELECTION)
|
||||
{
|
||||
int nFeat = GetLocalInt(oPC, "VoP_SelectedFeat");
|
||||
string sText = GetStringByStrRef(StringToInt(Get2DAString("feat", "FEAT", nFeat))) + "\n\n";
|
||||
sText += GetStringByStrRef(StringToInt(Get2DAString("feat", "DESCRIPTION", nFeat))) + "\n\n";
|
||||
sText += GetStringByStrRef(STRREF_SELECTED_HEADER2); // "Is this correct?"
|
||||
SetHeader(sText);
|
||||
AddChoice(GetStringByStrRef(STRREF_YES), TRUE, oPC);
|
||||
AddChoice(GetStringByStrRef(STRREF_NO), FALSE, oPC);
|
||||
MarkStageSetUp(STAGE_CONFIRM_SELECTION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
// Do token setup
|
||||
SetupTokens();
|
||||
}
|
||||
else if(nValue == DYNCONV_EXITED)
|
||||
{
|
||||
if(DEBUG) DoDebug("ft_vowpoverty_ft: Running exit handler");
|
||||
DeleteLocalInt(oPC, "VoP_SelectedFeat");
|
||||
}
|
||||
else if(nValue == DYNCONV_ABORTED)
|
||||
{
|
||||
// This section should never be run, since aborting this conversation should
|
||||
// always be forbidden and as such, any attempts to abort the conversation
|
||||
// should be handled transparently by the system
|
||||
if(DEBUG) DoDebug("ft_vowpoverty_ft: ERROR: Conversation abort section run");
|
||||
DeleteLocalInt(oPC, "VoP_SelectedFeat");
|
||||
}
|
||||
// Handle PC response
|
||||
else
|
||||
{
|
||||
int nChoice = GetChoice(oPC);
|
||||
if(nStage == STAGE_SELECT_ABIL)
|
||||
{
|
||||
if (nChoice == 0)
|
||||
{
|
||||
// Cancel chosen
|
||||
DeletePersistantLocalInt(oPC,"VoPFeatCheck");
|
||||
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
|
||||
return;
|
||||
}
|
||||
SetLocalInt(oPC, "VoP_SelectedFeat", nChoice);
|
||||
nStage = STAGE_CONFIRM_SELECTION;
|
||||
MarkStageNotSetUp(STAGE_SELECT_ABIL, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRM_SELECTION)
|
||||
{
|
||||
if (nChoice == TRUE) // Yes
|
||||
{
|
||||
int nFeat = GetLocalInt(oPC, "VoP_SelectedFeat");
|
||||
SetPersistantLocalInt(oPC, "VoPFeat"+IntToString(nLevel), 1);
|
||||
SetPersistantLocalInt(oPC, "VoPFeatID" + IntToString(nFeat), 1);
|
||||
|
||||
if (GetPRCSwitch("PRC_NWNXEE_ENABLED") && GetPRCSwitch("PRC_PRCX_ENABLED"))
|
||||
{
|
||||
PRC_Funcs_AddFeat(oPC, nFeat);
|
||||
}
|
||||
else
|
||||
{
|
||||
effect eBonusFeat = EffectBonusFeat(nFeat);
|
||||
eBonusFeat = UnyieldingEffect(eBonusFeat);
|
||||
eBonusFeat = TagEffect(eBonusFeat, "VoPFeat"+IntToString(nFeat));
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBonusFeat, oPC);
|
||||
}
|
||||
|
||||
DeleteLocalInt(oPC, "VoP_SelectedFeat");
|
||||
DeletePersistantLocalInt(oPC,"VoPFeatCheck");
|
||||
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
|
||||
}
|
||||
else // No
|
||||
{
|
||||
nStage = STAGE_SELECT_ABIL;
|
||||
MarkStageNotSetUp(STAGE_CONFIRM_SELECTION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("ft_vowpoverty_ft: New stage: " + IntToString(nStage));
|
||||
|
||||
// Store the stage value. If it has been changed, this clears out the choices
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
const int STAGE_SELECT_ABIL = 0;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function defintions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void main()
|
||||
/* void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
@@ -144,5 +307,5 @@ void main()
|
||||
// Store the stage value. If it has been changed, this clears out the choices
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
|
||||
@@ -205,6 +205,8 @@ void AddDomainFeat(object oPC, object oSkin, int bFuncs)
|
||||
itemproperty ipIP =ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ELECTRICAL, IP_CONST_DAMAGERESIST_5);
|
||||
IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
|
||||
}
|
||||
|
||||
|
||||
if (GetHasFeat(FEAT_WAR_DOMAIN_POWER, oPC))
|
||||
{
|
||||
int nWarFocus = GetPersistantLocalInt(oPC, "WarDomainWeaponPersistent");
|
||||
@@ -239,7 +241,8 @@ void AddDomainFeat(object oPC, object oSkin, int bFuncs)
|
||||
}
|
||||
|
||||
}
|
||||
if (GetHasFeat(FEAT_DOMAIN_POWER_METAL, oPC))
|
||||
|
||||
if (GetHasFeat(FEAT_DOMAIN_POWER_METAL, oPC))
|
||||
{
|
||||
int nWFocus = GetPersistantLocalInt(oPC, "MetalDomainWeaponPersistent");
|
||||
// If they've already chosen a weapon, reapply the feats if they dont have it
|
||||
@@ -297,8 +300,17 @@ void main()
|
||||
|
||||
object oPC = OBJECT_SELF;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
|
||||
if(DEBUG) DoDebug("PRC Domain Skin is running");
|
||||
|
||||
int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED);
|
||||
int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED);
|
||||
int bFuncs = (nNWNxEE && nPRCx);
|
||||
|
||||
if(DEBUG) DoDebug("prc_domain_skin: Starting");
|
||||
|
||||
if (bFuncs)
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_domain_skin: NWNxEE detected.");
|
||||
}
|
||||
|
||||
// This is above the check to stop because AddDomainFeat needs this to run beforehand.
|
||||
// Puts the domain power feats on the skin for the appropriate domains.
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
|
||||
#include "prc_inc_combat"
|
||||
|
||||
void AddVerdantHealing(object oSkin,int iFH)
|
||||
{
|
||||
if(GetLocalInt(oSkin, "ForestMaster_FastHealing") == iFH) return;
|
||||
|
||||
SetCompositeBonus(oSkin,"ForestMaster_FastHealing",iFH,ITEM_PROPERTY_REGENERATION);
|
||||
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Declare major variables
|
||||
@@ -20,6 +28,10 @@ void main()
|
||||
|
||||
itemproperty ipIP;
|
||||
|
||||
int iFH = GetHasFeat(FEAT_SOL_FAST_HEALING_1,oPC);
|
||||
|
||||
if (iFH) AddVerdantHealing(oSkin,iFH);
|
||||
|
||||
|
||||
//:: We aren't being called from onPlayerUnequipItem event, instead from the PRCEvalFeats
|
||||
if(nEvent == FALSE)
|
||||
|
||||
@@ -78,33 +78,40 @@ void main()
|
||||
// should be handled transparently by the system
|
||||
if(DEBUG) DoDebug("prc_forsake_abil: ERROR: Conversation abort section run");
|
||||
}
|
||||
// Handle PC response
|
||||
else
|
||||
{
|
||||
int nChoice = GetChoice(oPC);
|
||||
if(DEBUG) DoDebug("prc_forsake_abil: Handling PC response, stage = " + IntToString(nStage) + "; nChoice = " +
|
||||
IntToString(nChoice) + "; choice text = '" + GetChoiceText(oPC) + "'");
|
||||
if(nStage == STAGE_SELECT_ABIL)
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_forsake_abil: nChoice: " + IntToString(nChoice));
|
||||
|
||||
effect eAbility = EffectAbilityIncrease(nChoice, 1);
|
||||
eAbility = UnyieldingEffect(eAbility);
|
||||
eAbility = TagEffect(eAbility, "ForsakerAbilityBoost");
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eAbility, oPC); //Give the boost
|
||||
|
||||
SetPersistantLocalInt(oPC, "ForsakerBoost"+IntToString(nClass), nChoice+1); //Register the boost has been given
|
||||
DeletePersistantLocalInt(oPC,"ForsakerBoostCheck");
|
||||
|
||||
// And we're all done
|
||||
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("prc_forsake_abil: New stage: " + IntToString(nStage));
|
||||
|
||||
// Store the stage value. If it has been changed, this clears out the choices
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
// Handle PC response
|
||||
else
|
||||
{
|
||||
int nChoice = GetChoice(oPC);
|
||||
if(DEBUG) DoDebug("prc_forsake_abil: Handling PC response, stage = " + IntToString(nStage) + "; nChoice = " +
|
||||
IntToString(nChoice) + "; choice text = '" + GetChoiceText(oPC) + "'");
|
||||
if(nStage == STAGE_SELECT_ABIL)
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_forsake_abil: nChoice: " + IntToString(nChoice));
|
||||
|
||||
if (GetPRCSwitch("PRC_NWNXEE_ENABLED") && GetPRCSwitch("PRC_PRCX_ENABLED"))
|
||||
{
|
||||
// Apply intrinsic ability bonus via NWNxEE
|
||||
PRC_Funcs_ModAbilityScore(oPC, nChoice, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback to effect-based
|
||||
effect eAbility = EffectAbilityIncrease(nChoice, 1);
|
||||
eAbility = UnyieldingEffect(eAbility);
|
||||
eAbility = TagEffect(eAbility, "ForsakerAbilityBoost");
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eAbility, oPC);
|
||||
}
|
||||
|
||||
SetPersistantLocalInt(oPC, "ForsakerBoost"+IntToString(nClass), nChoice+1);
|
||||
DeletePersistantLocalInt(oPC,"ForsakerBoostCheck");
|
||||
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("prc_forsake_abil: New stage: " + IntToString(nStage));
|
||||
|
||||
// Store the stage value. If it has been changed, this clears out the choices
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
/* // Handle PC response
|
||||
else
|
||||
{
|
||||
|
||||
@@ -514,7 +514,7 @@ void SummonCelestialCompanion(object oPC, string sResRef, int nHD, int nHealerLv
|
||||
nStat += nEpicBonus / 2;
|
||||
|
||||
eBonus = EffectACIncrease(nArmour);
|
||||
if(GetPRCSwitch(PRC_NWNX_FUNCS))
|
||||
if(GetPRCSwitch(PRC_NWNXEE_ENABLED))
|
||||
{
|
||||
PRC_Funcs_ModAbilityScore(oComp, ABILITY_STRENGTH, nStat);
|
||||
PRC_Funcs_ModAbilityScore(oComp, ABILITY_DEXTERITY, nStat);
|
||||
|
||||
@@ -35,7 +35,7 @@ void main()
|
||||
SetCompositeBonus(oSkin, "SkillMLPer", nMorninglordLevel, ITEM_PROPERTY_SKILL_BONUS,SKILL_PERFORM);
|
||||
SetCompositeBonus(oSkin, "SkillMLCW", nMorninglordLevel, ITEM_PROPERTY_SKILL_BONUS,SKILL_CRAFT_WEAPON);
|
||||
SetCompositeBonus(oSkin, "SkillMLCG", nMorninglordLevel, ITEM_PROPERTY_SKILL_BONUS,SKILL_CRAFT_GENERAL);
|
||||
SetCompositeBonus(oSkin, "SkillMLCA", nMorninglordLevel, ITEM_PROPERTY_SKILL_BONUS,SKILL_CRAFT_ALCHEMY);
|
||||
SetCompositeBonus(oSkin, "SkillMLCAL", nMorninglordLevel, ITEM_PROPERTY_SKILL_BONUS,SKILL_CRAFT_ALCHEMY);
|
||||
SetCompositeBonus(oSkin, "SkillMLPoi", nMorninglordLevel, ITEM_PROPERTY_SKILL_BONUS,SKILL_CRAFT_POISON);
|
||||
|
||||
if (nMorninglordLevel >= 6)
|
||||
|
||||
@@ -12,106 +12,157 @@
|
||||
#include "inc_persistsql"
|
||||
#include "prc_craft_cv_inc"
|
||||
|
||||
//:: Restore crafting state on login with offline time calculation
|
||||
void RestoreCraftingStateOnLogin(object oPC)
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | RestoreCraftingStateOnLogin called for " + GetName(oPC));
|
||||
|
||||
// Check switch conditions
|
||||
if(!(!GetPRCSwitch(PRC_DISABLE_CRAFT) &&
|
||||
GetPRCSwitch(PRC_CRAFTING_TIME_SCALE) > 1))
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | Switch conditions not met for crafting restore");
|
||||
return;
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | Switch conditions met, checking for saved crafting state");
|
||||
|
||||
if(SQLocalsPlayer_GetInt(oPC, "crafting_active"))
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | Found active crafting state, restoring...");
|
||||
|
||||
// Get basic crafting state
|
||||
string sUUID = SQLocalsPlayer_GetString(oPC, "crafting_item_uuid");
|
||||
int nRounds = SQLocalsPlayer_GetInt(oPC, "crafting_rounds");
|
||||
int nCost = SQLocalsPlayer_GetInt(oPC, "crafting_cost");
|
||||
int nXP = SQLocalsPlayer_GetInt(oPC, "crafting_xp");
|
||||
string sFile = SQLocalsPlayer_GetString(oPC, "crafting_file");
|
||||
int nLine = SQLocalsPlayer_GetInt(oPC, "crafting_line");
|
||||
int nIPType = SQLocalsPlayer_GetInt(oPC, "crafting_ip_type");
|
||||
int nIPSubtype = SQLocalsPlayer_GetInt(oPC, "crafting_ip_subtype");
|
||||
int nIPCostTable = SQLocalsPlayer_GetInt(oPC, "crafting_ip_costtable");
|
||||
int nIPParam1 = SQLocalsPlayer_GetInt(oPC, "crafting_ip_param1");
|
||||
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | Initial data - UUID: " + sUUID + ", rounds: " + IntToString(nRounds) +
|
||||
", cost: " + IntToString(nCost) + ", xp: " + IntToString(nXP));
|
||||
|
||||
// Calculate offline progress
|
||||
int nLogoutTime = SQLocalsPlayer_GetInt(oPC, "crafting_last_timestamp");
|
||||
int nCurrentTime = GetCurrentUnixTimestamp();
|
||||
if(DEBUG) DoDebug("prc_onenter >> RestoreCraftingStateOnLogin() | GetCurrentUnixTimestamp is:" + IntToString(nCurrentTime) +".");
|
||||
|
||||
if(nLogoutTime > 0 && nCurrentTime > nLogoutTime)
|
||||
{
|
||||
// Calculate real time elapsed in seconds
|
||||
int nSecondsOffline = nCurrentTime - nLogoutTime;
|
||||
if(DEBUG) DoDebug("prc_onenter >> RestoreCraftingStateOnLogin() | nSecondsOffline is:" + IntToString(nSecondsOffline) +".");
|
||||
|
||||
// Each round is always 6 seconds real time
|
||||
int nRoundsOffline = nSecondsOffline / 6;
|
||||
if(DEBUG) DoDebug("prc_onenter >> RestoreCraftingStateOnLogin() | nRoundsOffline is:" + IntToString(nRoundsOffline) +".");
|
||||
|
||||
// Subtract offline progress from remaining rounds
|
||||
nRounds -= nRoundsOffline;
|
||||
if(nRounds < 1) nRounds = 1; // Minimum 1 round to finish
|
||||
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | Offline progress - time diff: " + IntToString(nSecondsOffline) +
|
||||
"s, rounds progress: " + IntToString(nRoundsOffline) +
|
||||
", new rounds: " + IntToString(nRounds));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | No valid logout time found, using saved rounds: " + IntToString(nRounds));
|
||||
}
|
||||
|
||||
// Find the crafting item
|
||||
object oItem = GetItemByUUID(oPC, sUUID);
|
||||
if(GetIsObjectValid(oItem))
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | Found item, restoring crafting session");
|
||||
|
||||
// Reconstruct the itemproperty
|
||||
itemproperty ip;
|
||||
if(nIPType > 0)
|
||||
{
|
||||
ip = ConstructIP(nIPType, nIPSubtype, nIPCostTable, nIPParam1);
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | About to call CraftingHB with " + IntToString(nRounds) + " rounds, cost: " + IntToString(nCost) + ", xp: " + IntToString(nXP));
|
||||
|
||||
// Notify player
|
||||
FloatingTextStringOnCreature("Resuming crafting session: " + IntToString(nRounds) + " round(s) remaining", oPC);
|
||||
|
||||
// Restart the crafting heartbeat with all correct parameters
|
||||
AssignCommand(oPC, ClearAllActions(TRUE));
|
||||
SetLocalInt(oPC, "PRC_CRAFT_RESTORED", 1);
|
||||
DelayCommand(3.0, CraftingHB(oPC, oItem, ip, nCost, nXP, sFile, nLine, nRounds));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | Failed to find item with UUID: " + sUUID);
|
||||
FloatingTextStringOnCreature("Crafting session could not be restored - item not found", oPC);
|
||||
// Clear the invalid crafting state
|
||||
SQLocalsPlayer_SetInt(oPC, "crafting_active", 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_oneter >> RestoreCraftingStateOnLogin | No saved crafting state found");
|
||||
}
|
||||
// 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;
|
||||
@@ -137,7 +188,7 @@ void RestoreForsakerAbilities(object oPC)
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eAbility, oPC);
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
/**
|
||||
* Reads the 2da file onenter_locals.2da and sets local variables
|
||||
|
||||
@@ -414,8 +414,72 @@ void main()
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HEALING_L_LAW), oHealTarget);
|
||||
}
|
||||
|
||||
// Blood in the Water
|
||||
if (GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
// Blood in the Water
|
||||
if (GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
{
|
||||
// Fake critical hit check
|
||||
if (d20() >= GetWeaponCriticalRange(oSpellOrigin, oItem))
|
||||
{
|
||||
string sBlood = GetCreatureBloodColor(oSpellTarget);
|
||||
int bGhost = GetIsIncorporeal(oSpellTarget);
|
||||
int nRace = MyPRCGetRacialType(oSpellTarget);
|
||||
|
||||
effect eVFX;
|
||||
if (sBlood == "R") eVFX = EffectVisualEffect(VFX_COM_CHUNK_RED_SMALL);
|
||||
else if (sBlood == "Y") eVFX = EffectVisualEffect(VFX_COM_CHUNK_YELLOW_SMALL);
|
||||
else if (sBlood == "W") eVFX = EffectVisualEffect(VFX_COM_BLOOD_SPARK_SMALL);
|
||||
else if (sBlood == "G") eVFX = EffectVisualEffect(VFX_COM_CHUNK_GREEN_SMALL);
|
||||
else if (sBlood == "N")
|
||||
{
|
||||
if (nRace == RACIAL_TYPE_UNDEAD)
|
||||
{
|
||||
if (bGhost) eVFX = EffectVisualEffect(VFX_COM_HIT_DIVINE);
|
||||
else eVFX = EffectVisualEffect(VFX_COM_CHUNK_BONE_MEDIUM);
|
||||
}
|
||||
else eVFX = EffectVisualEffect(VFX_COM_CHUNK_STONE_SMALL);
|
||||
}
|
||||
else
|
||||
{
|
||||
eVFX = EffectVisualEffect(VFX_COM_CHUNK_RED_SMALL); // fallback VFX
|
||||
}
|
||||
|
||||
// Increase total bonus stack count
|
||||
int nStacks = GetLocalInt(oSpellOrigin, "BITW_STACKS") + 1;
|
||||
SetLocalInt(oSpellOrigin, "BITW_STACKS", nStacks);
|
||||
|
||||
// Cap stacks at 20
|
||||
if(nStacks > 20) nStacks = 20;
|
||||
|
||||
// Store time of last crit as integer seconds
|
||||
SetLocalInt(oSpellOrigin, "BITW_LASTCRIT", (GetTimeHour() * 3600) + (GetTimeMinute() * 60) + GetTimeSecond());
|
||||
|
||||
// Remove old BITW_BUFF effect before applying updated buff
|
||||
effect eOld = GetFirstEffect(oSpellOrigin);
|
||||
while (GetIsEffectValid(eOld))
|
||||
{
|
||||
if (GetEffectTag(eOld) == "BITW_BUFF")
|
||||
{
|
||||
RemoveEffect(oSpellOrigin, eOld);
|
||||
}
|
||||
eOld = GetNextEffect(oSpellOrigin);
|
||||
}
|
||||
|
||||
// Apply new combined attack and damage bonus with total stacks
|
||||
effect eBuff = EffectLinkEffects(
|
||||
EffectAttackIncrease(nStacks),
|
||||
EffectDamageIncrease(IPGetDamageBonusConstantFromNumber(nStacks), DAMAGE_TYPE_SLASHING)
|
||||
);
|
||||
eBuff = TagEffect(eBuff, "BITW_BUFF");
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBuff, oSpellOrigin);
|
||||
|
||||
// Schedule decay check in 60 seconds (will only reset if no new crit since last)
|
||||
DelayCommand(60.0, CheckBloodInTheWaterDecay(oSpellOrigin));
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oSpellTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/* if (GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
{
|
||||
// Fake critical hit check
|
||||
if (d20() >= GetWeaponCriticalRange(oSpellOrigin, oItem))
|
||||
@@ -475,62 +539,8 @@ void main()
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oSpellTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/* if (GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
{
|
||||
// Fake critical hit check
|
||||
if (d20() >= GetWeaponCriticalRange(oSpellOrigin, oItem))
|
||||
{
|
||||
string sBlood = GetCreatureBloodColor(oSpellTarget);
|
||||
int bGhost = GetIsIncorporeal(oSpellTarget);
|
||||
int nRace = MyPRCGetRacialType(oSpellTarget);
|
||||
|
||||
effect eVFX;
|
||||
if (sBlood == "R") eVFX = EffectVisualEffect(VFX_COM_CHUNK_RED_SMALL);
|
||||
if (sBlood == "Y") eVFX = EffectVisualEffect(VFX_COM_CHUNK_YELLOW_SMALL);
|
||||
if (sBlood == "W") eVFX = EffectVisualEffect(VFX_COM_BLOOD_SPARK_SMALL);
|
||||
if (sBlood == "G") eVFX = EffectVisualEffect(VFX_COM_CHUNK_GREEN_SMALL);
|
||||
if (sBlood == "N")
|
||||
{
|
||||
if (nRace == RACIAL_TYPE_UNDEAD)
|
||||
{
|
||||
if (bGhost) eVFX = EffectVisualEffect(VFX_COM_HIT_DIVINE);
|
||||
else eVFX = EffectVisualEffect(VFX_COM_CHUNK_BONE_MEDIUM);
|
||||
}
|
||||
else eVFX = EffectVisualEffect(VFX_COM_CHUNK_STONE_SMALL);
|
||||
}
|
||||
|
||||
// --- STACKING LOGIC ---
|
||||
int nStacks = GetLocalInt(oSpellOrigin, "BITW_STACKS");
|
||||
nStacks += 1;
|
||||
SetLocalInt(oSpellOrigin, "BITW_STACKS", nStacks);
|
||||
|
||||
// Remove any old bonus effect
|
||||
effect eOld = GetFirstEffect(oSpellOrigin);
|
||||
while (GetIsEffectValid(eOld))
|
||||
{
|
||||
if (GetEffectTag(eOld) == "BITW_BUFF")
|
||||
{
|
||||
RemoveEffect(oSpellOrigin, eOld);
|
||||
}
|
||||
eOld = GetNextEffect(oSpellOrigin);
|
||||
}
|
||||
|
||||
// Apply new combined attack/damage bonus
|
||||
effect eBuff = EffectLinkEffects(
|
||||
EffectAttackIncrease(nStacks),
|
||||
EffectDamageIncrease(IPGetDamageBonusConstantFromNumber(nStacks), DAMAGE_TYPE_SLASHING));
|
||||
|
||||
eBuff = TagEffect(eBuff, "BITW_BUFF");
|
||||
|
||||
DelayCommand(0.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBuff, oSpellOrigin, TurnsToSeconds(1)));
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oSpellTarget);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/* if(GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR && !GetIsImmune(oSpellTarget, IMMUNITY_TYPE_CRITICAL_HIT) )
|
||||
{
|
||||
// Fake critical hit check
|
||||
|
||||
@@ -165,7 +165,16 @@ void main()
|
||||
OnLoad_Fresh(oModule);
|
||||
}
|
||||
|
||||
//NWNX_Funcs plugin test:
|
||||
//:: NWNxEE Detection
|
||||
int bNWNxEE = NWNXGetIsAvailable();
|
||||
|
||||
if (bNWNxEE)
|
||||
{
|
||||
SetPRCSwitch(PRC_NWNXEE_ENABLED, TRUE);
|
||||
if(DEBUG) DoDebug("NWNxEE detected.");
|
||||
}
|
||||
|
||||
//NWNX_Funcs plugin test:
|
||||
//PRC_Funcs_Init(oModule);
|
||||
}
|
||||
|
||||
@@ -199,7 +208,7 @@ void OnLoad_Fresh(object oModule)
|
||||
SetModuleSwitch(MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS, TRUE); /// @todo This is somewhat intrusive, make it unnecessary and remove
|
||||
|
||||
// Run a script to determine if the PRC Companion is present
|
||||
ExecuteScript("hakmarker", OBJECT_SELF);
|
||||
//ExecuteScript("hakmarker", OBJECT_SELF); //:: script no longer present in project - Jaysyn
|
||||
|
||||
//delay this to avoid TMIs
|
||||
DelayCommand(0.01, CreateSwitchNameArray());
|
||||
|
||||
@@ -436,6 +436,19 @@ void DemiLich(object oPC)
|
||||
}
|
||||
}
|
||||
|
||||
void CoCDodgePrereq(object oPC)
|
||||
{
|
||||
//Champion of Corellon
|
||||
SetLocalInt(oPC, "PRC_PrereqCoC", 1);
|
||||
if(GetHasFeat(FEAT_DODGE, oPC) ||
|
||||
GetHasFeat(FEAT_EXPEDITIOUS_DODGE, oPC) ||
|
||||
GetHasFeat(FEAT_DESERT_WIND_DODGE, oPC) ||
|
||||
GetHasFeat(FEAT_MIDNIGHT_DODGE, oPC))
|
||||
{
|
||||
DeleteLocalInt(oPC, "PRC_PrereqCoC");
|
||||
}
|
||||
}
|
||||
|
||||
void reqDomains()
|
||||
{
|
||||
//Black Flame Zealot
|
||||
@@ -1986,6 +1999,7 @@ void main()
|
||||
AOTSPreReqs(oPC);
|
||||
AbChamp(oPC);
|
||||
AnimaMageReq(oPC);
|
||||
CoCDodgePrereq(oPC);
|
||||
Cultist(oPC);
|
||||
DalQuor(oPC);
|
||||
DemiLich(oPC);
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
//::///////////////////////////////////////////////
|
||||
#include "prc_inc_spells"
|
||||
|
||||
void AddVerdantHealing(object oSkin,int iFH)
|
||||
{
|
||||
if(GetLocalInt(oSkin, "VerdantLord_FastHealing") == iFH) return;
|
||||
|
||||
SetCompositeBonus(oSkin,"VerdantLord_FastHealing",iFH,ITEM_PROPERTY_REGENERATION);
|
||||
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Declare major variables
|
||||
@@ -16,6 +24,10 @@ void main()
|
||||
effect eEffect;
|
||||
|
||||
itemproperty ipIP;
|
||||
|
||||
int iFH = GetHasFeat(FEAT_SOL_FAST_HEALING_1,oPC);
|
||||
|
||||
if (iFH) AddVerdantHealing(oSkin,iFH);
|
||||
|
||||
//:: Setup Gaea’s Embrace ///////////////////////////////////////////////////////////////
|
||||
/* Gaea’s Embrace: At 10th level, the verdant lord permanently becomes a plant
|
||||
|
||||
@@ -18,7 +18,8 @@ void main()
|
||||
|
||||
if(GetHasSpellEffect(SPELL_SPELL_RAGE, oPC))
|
||||
{
|
||||
IncrementRemainingFeatUses(oPC, FEAT_SPELL_RAGE);
|
||||
PRCRemoveSpellEffects(SPELL_SPELL_RAGE, oPC, oPC);
|
||||
IncrementRemainingFeatUses(oPC, FEAT_SPELL_RAGE);
|
||||
return;
|
||||
}
|
||||
if(GetHasSpellEffect(SPELLABILITY_BARBARIAN_RAGE, oPC))
|
||||
|
||||
@@ -78,9 +78,17 @@ void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
|
||||
SendMessageToPC(oPC,
|
||||
"NWNxEE=" + IntToString(GetPRCSwitch(PRC_NWNXEE_ENABLED)) +
|
||||
" PRCx=" + IntToString(GetPRCSwitch(PRC_PRCX_ENABLED)));
|
||||
|
||||
int nHD = GetHitDice(oPC);
|
||||
itemproperty ipIP;
|
||||
int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
|
||||
|
||||
int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED);
|
||||
int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED);
|
||||
int bFuncs = (nNWNxEE && nPRCx);
|
||||
|
||||
//darkvision
|
||||
ipIP = ItemPropertyDarkvision();
|
||||
|
||||
@@ -78,9 +78,13 @@ void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
|
||||
int nHD = GetHitDice(oPC);
|
||||
itemproperty ipIP;
|
||||
int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
|
||||
|
||||
int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED);
|
||||
int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED);
|
||||
int bFuncs = (nNWNxEE && nPRCx);
|
||||
|
||||
//darkvision
|
||||
ipIP = ItemPropertyDarkvision();
|
||||
|
||||
@@ -100,7 +100,11 @@ void main()
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
int nHD = GetHitDice(oPC);
|
||||
itemproperty ipIP;
|
||||
int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
|
||||
|
||||
int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED);
|
||||
int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED);
|
||||
int bFuncs = (nNWNxEE && nPRCx);
|
||||
|
||||
int iTest = GetPersistantLocalInt(oPC, "NWNX_Template_hceles");
|
||||
|
||||
//wings
|
||||
|
||||
@@ -157,7 +157,11 @@ void main()
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
int nHD = GetHitDice(oPC);
|
||||
itemproperty ipIP;
|
||||
int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
|
||||
|
||||
int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED);
|
||||
int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED);
|
||||
int bFuncs = (nNWNxEE && nPRCx);
|
||||
|
||||
int iTest = GetPersistantLocalInt(oPC, "NWNX_Template_hdragon");
|
||||
int nSubTemplate = GetPersistantLocalInt(oPC, "HalfDragon_Template");
|
||||
int nWingType, iType, lResis, pImmune, dImmune, iSpell, iSpel2, sResis;
|
||||
|
||||
@@ -122,7 +122,11 @@ void main()
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
int nHD = GetHitDice(oPC);
|
||||
itemproperty ipIP;
|
||||
int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
|
||||
|
||||
int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED);
|
||||
int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED);
|
||||
int bFuncs = (nNWNxEE && nPRCx);
|
||||
|
||||
int iTest = GetPersistantLocalInt(oPC, "NWNX_Template_hfiend");
|
||||
|
||||
//wings
|
||||
|
||||
@@ -349,7 +349,11 @@ void main()
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
int nHD = GetHitDice(oPC);
|
||||
itemproperty ipIP;
|
||||
int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
|
||||
|
||||
int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED);
|
||||
int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED);
|
||||
int bFuncs = (nNWNxEE && nPRCx);
|
||||
|
||||
int iTestLich = GetPersistantLocalInt(oPC, "NWNX_Template_lich");
|
||||
int iTestDemi = GetPersistantLocalInt(oPC, "NWNX_Template_demilich");
|
||||
|
||||
|
||||
@@ -51,7 +51,11 @@ void main()
|
||||
object oPC = OBJECT_SELF;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
itemproperty ipIP;
|
||||
int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
|
||||
|
||||
int nNWNxEE = GetPRCSwitch(PRC_NWNXEE_ENABLED);
|
||||
int nPRCx = GetPRCSwitch(PRC_PRCX_ENABLED);
|
||||
int bFuncs = (nNWNxEE && nPRCx);
|
||||
|
||||
int iTest = GetPersistantLocalInt(oPC, "NWNX_Template_necropolitan");
|
||||
|
||||
//NOTE: this maintains the Necropolitan template
|
||||
|
||||
Reference in New Issue
Block a user