Added Vow of Poverty

Added Vow of Poverty, Jaebrin, Hobgoblin Warsoul & Forsaker fixes (thanks PRC5 & @Fencas).  Added iprp_matcost.2da for new materials.  Updated PRC8 Tester module.  Cohorts updated to support 8 classes. Fixed ranged disarm w/ Fighter. Updated release archive.
This commit is contained in:
Jaysyn904
2024-12-26 17:37:36 -05:00
parent 02658b7717
commit e81e395031
73 changed files with 29545 additions and 28368 deletions

View File

@@ -113,7 +113,7 @@ void main()
if (GetLocked(oTarget) && !GetLockKeyRequired(oTarget))
{
int iDC = GetLockUnlockDC(oTarget);
if(d20(1) + GetClassByPosition(CLASS_TYPE_OCULAR) >= iDC)
if(d20(1) + GetLevelByClass(CLASS_TYPE_OCULAR, oCaster) >= iDC)
{
SetLocked(oTarget, FALSE);
AssignCommand(oTarget, SpeakString("**Click**"));
@@ -137,7 +137,7 @@ void main()
if (GetLocked(oTarget) && GetLockKeyRequired(oTarget))
{
int iDC = GetLockUnlockDC(oTarget);
if(d20(1) + GetClassByPosition(CLASS_TYPE_OCULAR) >= iDC)
if(d20(1) + GetLevelByClass(CLASS_TYPE_OCULAR, oCaster) >= iDC)
{
SetLocked(oTarget, FALSE);
AssignCommand(oTarget, SpeakString("**Click**"));

View File

@@ -0,0 +1,203 @@
//::///////////////////////////////////////////////
//:: Name Vow of Poverty
//:: FileName ft_vowofpoverty.nss
//:: Created By: Fencas
//:: Created On: 2024-12-02
//:: Based On: Stratovarius' Forsaker
//:://////////////////////////////////////////////
#include "prc_inc_combat"
#include "inc_dynconv"
#include "prc_class_const"
#include "prc_inc_clsfunc"
#include "prc_alterations"
#include "NW_I0_GENERIC"
#include "nw_i0_spells"
effect VoPDamage(int nTotalEnhancement) //Just for unarmed, so just bludgeoning
{
effect eDamage;
if (nTotalEnhancement>=15) eDamage = EffectDamageIncrease(DAMAGE_BONUS_15,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=14) eDamage = EffectDamageIncrease(DAMAGE_BONUS_14,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=13) eDamage = EffectDamageIncrease(DAMAGE_BONUS_13,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=12) eDamage = EffectDamageIncrease(DAMAGE_BONUS_12,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=11) eDamage = EffectDamageIncrease(DAMAGE_BONUS_11,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=10) eDamage = EffectDamageIncrease(DAMAGE_BONUS_10,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=9) eDamage = EffectDamageIncrease(DAMAGE_BONUS_9,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=8) eDamage = EffectDamageIncrease(DAMAGE_BONUS_8,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=7) eDamage = EffectDamageIncrease(DAMAGE_BONUS_7,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=6) eDamage = EffectDamageIncrease(DAMAGE_BONUS_6,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=5) eDamage = EffectDamageIncrease(DAMAGE_BONUS_5,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=4) eDamage = EffectDamageIncrease(DAMAGE_BONUS_4,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=3) eDamage = EffectDamageIncrease(DAMAGE_BONUS_3,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=2) eDamage = EffectDamageIncrease(DAMAGE_BONUS_2,DAMAGE_TYPE_BLUDGEONING);
else if (nTotalEnhancement>=1) eDamage = EffectDamageIncrease(DAMAGE_BONUS_1,DAMAGE_TYPE_BLUDGEONING);
return eDamage;
}
void main()
{
object oPC;
oPC = OBJECT_SELF;
object oItem;
object oArmor;
object oShield;
object oSkin = GetPCSkin(oPC);
int nSlot;
int nEvent = GetRunningEvent();
int nLevel = GetCharacterLevel(oPC);
int nLevelCheck;
int nACArmor = 4+nLevel/3;
int nACDeflection = nLevel/6;
int nACNatural = nLevel/8;
int nRegen = 1+(nLevel-17)/7;
int nDR = 5*(1+(nLevel-10)/9);
int nER = (10*(1+(nLevel-13)/7))-5;
int nForsakerBonus = GetLevelByClass(CLASS_TYPE_FORSAKER, oPC)/2;
int nExaltedStrike;
int nTotalEnhancement;
//Enhancement bonus for unarmed damage and weapons; consider the bigger, Forsaker or VoP
if(nLevel>=10) nExaltedStrike = 1+(nLevel-7)/3;
else if(nLevel>=4) nExaltedStrike = 1;
if(nForsakerBonus>=nExaltedStrike) nTotalEnhancement = nForsakerBonus;
else nTotalEnhancement = nExaltedStrike;
// We aren't being called from any event, instead from EvalPRCFeats
if(nEvent == FALSE)
{
//Check if level up bonus has already been chosen and given for any of past Forsaker levels
for(nLevelCheck=1; nLevelCheck <= nLevel; nLevelCheck++)
{
if (!GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(nLevelCheck)) && (nLevelCheck-(nLevelCheck/4)*4 == 3) && (nLevelCheck >= 7) && (nLevelCheck <= 27))
{
//Call stat boost dialogue for level 7 and each 4 levels after that
AssignCommand(oPC, ClearAllActions(TRUE));
SetPersistantLocalInt(oPC,"VoPBoostCheck",nLevelCheck);
StartDynamicConversation("ft_vowofpoverty_abil", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
}
}
//AC Armor +4 on 1st, then +1 each 3 levels
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(EffectACIncrease(nACArmor, AC_ARMOUR_ENCHANTMENT_BONUS)), oPC);
//Deflection Armor +1 each 6 levels
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(EffectACIncrease(nACDeflection, AC_DEFLECTION_BONUS)), oPC);
//Resistences +1 on 7, then each 5 levels; must use SetPersistantLocalInt to avoid duplication on new levels
if ((nLevel>=7) && (nLevel-(nLevel/5)*5 == 2))
{
if (!GetPersistantLocalInt(oPC, "VoPResistance"+IntToString(nLevel)))
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, ExtraordinaryEffect(EffectSavingThrowIncrease(SAVING_THROW_ALL, 1, SAVING_THROW_TYPE_ALL)), oPC);
SetPersistantLocalInt(oPC, "VoPResistance"+IntToString(nLevel),1);
}
}
//Natural Armor +1 each 8 levels
ApplyEffectToObject(DURATION_TYPE_PERMANENT, ExtraordinaryEffect(EffectACIncrease(nACNatural, AC_NATURAL_BONUS)), oPC);
//DR 5/Enhancement starting 10, +5 each 9 levels
if (nLevel >= 10) ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(EffectDamageReduction(nDR,nTotalEnhancement)),oPC);
//Energy resistance 5 for acid, cold ,electrical, fire and sonic on 13th, than +10 each 7 levels
if (nLevel>=13)
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamageResistance(DAMAGE_TYPE_ACID, nER, 0, FALSE), oPC);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamageResistance(DAMAGE_TYPE_COLD, nER, 0, FALSE), oPC);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamageResistance(DAMAGE_TYPE_ELECTRICAL, nER, 0, FALSE), oPC);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamageResistance(DAMAGE_TYPE_FIRE, nER, 0, FALSE), oPC);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamageResistance(DAMAGE_TYPE_SONIC, nER, 0, FALSE), oPC);
}
//Freedom of Movement at 14th
if (nLevel>=14) IPSafeAddItemProperty(oSkin, ItemPropertyFreeAction(), 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, TRUE, TRUE);
//Regeneration 1 at 17th, +1 at each 7 levels
if (nLevel>=17) SetCompositeBonus(oSkin, "VoPFH", nRegen, ITEM_PROPERTY_REGENERATION);
//True Seeing at 18th
if (nLevel>=18) IPSafeAddItemProperty(oSkin, ItemPropertyTrueSeeing(), 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, TRUE, TRUE);
// Enhacement bonus - only applies to weapons (or unarmed)
if(GetIsUnarmed(oPC)) //If it is unarmed, give enhancement bonus to self
{
RemoveSpecificEffect(EFFECT_TYPE_ATTACK_INCREASE, oPC); //Remove any prior bonus to avoid duplication
RemoveSpecificEffect(EFFECT_TYPE_DAMAGE_INCREASE, oPC);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectAttackIncrease(nTotalEnhancement), oPC); //Then set the bonus again
ApplyEffectToObject(DURATION_TYPE_PERMANENT, VoPDamage(nTotalEnhancement), oPC);
}
else
{
object oItemR = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC);
object oItemL = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oPC);
if(IPGetIsMeleeWeapon(oItemR) || GetWeaponRanged(oItemR))
{
RemoveSpecificEffect(EFFECT_TYPE_ATTACK_INCREASE, oPC);
RemoveSpecificEffect(EFFECT_TYPE_DAMAGE_INCREASE, oPC);
IPSafeAddItemProperty(oItemR, ItemPropertyEnhancementBonus(nTotalEnhancement));
}
else if(IPGetIsMeleeWeapon(oItemL) || GetWeaponRanged(oItemL))
{
RemoveSpecificEffect(EFFECT_TYPE_ATTACK_INCREASE, oPC);
RemoveSpecificEffect(EFFECT_TYPE_DAMAGE_INCREASE, oPC);
IPSafeAddItemProperty(oItemL, ItemPropertyEnhancementBonus(nTotalEnhancement));
}
}
// For some reason, EVENT_ONPLAYEREQUIPITEM just works with weapons, so it is better to check all other items for magic elsewhere
for (nSlot=0; nSlot < 13; nSlot++) //All but creatures slots
{
oItem=GetItemInSlot(nSlot, oPC);
if((GetIsItemPropertyValid(GetFirstItemProperty(oItem)) && !(nSlot == 4 || nSlot == 5)) //Check if it is magical (all items but on the hands)
|| (nSlot == 1 && GetBaseAC(oItem) >= 1) //Check if it is an armor (AC>0)
|| (nSlot == 5 && GetBaseItemType(oItem) == BASE_ITEM_SMALLSHIELD || //Check if it is a shield
GetBaseItemType(oItem) == BASE_ITEM_LARGESHIELD ||
GetBaseItemType(oItem) == BASE_ITEM_TOWERSHIELD))
{
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionUnequipItem(oItem));
FloatingTextStringOnCreature(GetName(oItem)+" would break your vow!", oPC, FALSE);
}
}
if(DEBUG) DoDebug("ft_vowofpoverty: Adding eventhooks");
AddEventScript(oPC, EVENT_ONPLAYEREQUIPITEM, "ft_vowofpoverty", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "ft_vowofpoverty", TRUE, FALSE);
}
// We are called from the OnPlayerUnEquipItem eventhook. Remove OnHitCast: Unique Power from oPC's weapon
else if(nEvent == EVENT_ONPLAYEREQUIPITEM)
{
oItem = GetPCItemLastEquipped();
int iWeaponAllowed = GetBaseItemType(oItem) == BASE_ITEM_CLUB
|| GetBaseItemType(oItem) == BASE_ITEM_DAGGER
|| GetBaseItemType(oItem) == BASE_ITEM_DART
|| GetBaseItemType(oItem) == BASE_ITEM_HEAVYCROSSBOW
|| GetBaseItemType(oItem) == BASE_ITEM_LIGHTCROSSBOW
|| GetBaseItemType(oItem) == BASE_ITEM_LIGHTMACE
|| GetBaseItemType(oItem) == BASE_ITEM_MORNINGSTAR
|| GetBaseItemType(oItem) == BASE_ITEM_QUARTERSTAFF
|| GetBaseItemType(oItem) == BASE_ITEM_SICKLE
|| GetBaseItemType(oItem) == BASE_ITEM_SLING
|| GetBaseItemType(oItem) == BASE_ITEM_SHORTSPEAR
|| GetBaseItemType(oItem) == BASE_ITEM_BOLT
|| GetBaseItemType(oItem) == BASE_ITEM_GOAD
|| GetBaseItemType(oItem) == BASE_ITEM_KATAR
|| GetBaseItemType(oItem) == BASE_ITEM_HEAVY_MACE
|| GetBaseItemType(oItem) == BASE_ITEM_BULLET;
if(GetIsItemPropertyValid(GetFirstItemProperty(oItem)) || !iWeaponAllowed) //Check if weapon is magical or not on allowed list
{
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionUnequipItem(oItem));
FloatingTextStringOnCreature(GetName(oItem)+" would break your vow!", oPC, FALSE);
}
}
else if(nEvent == EVENT_ONPLAYERUNEQUIPITEM)
{
oItem = GetItemLastUnequipped();
if((IPGetIsMeleeWeapon(oItem) || GetWeaponRanged(oItem))) IPRemoveAllItemProperties(oItem, DURATION_TYPE_PERMANENT); //Remove bonus from unequiped weapons
}
}

View File

@@ -0,0 +1,126 @@
//:://////////////////////////////////////////////
//:: Vow of Poverty Ability Boost Conversation
//:: ft_vowofpoverty_abil
//:://////////////////////////////////////////////
/** @file
This allows you to choose ability to boost.
@original author Stratovarius
@date Created - 27.12.2019
@modified by Fencas
@data modified - 2024-12-03
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "prc_inc_function"
#include "NW_I0_GENERIC"
//////////////////////////////////////////////////
/* Constant defintions */
//////////////////////////////////////////////////
const int STAGE_SELECT_ABIL = 0;
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
void main()
{
object oPC = GetPCSpeaker();
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
int nLevel = GetPersistantLocalInt(oPC, "VoPBoostCheck");
int i, j, nStr, nDex, nCon, nInt, nWis, nCha, nTest;
// 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_vowofpoverty_abil: 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)
{
for(i = 0; i <= nLevel; i++)
{
if(GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(i))>=10)
{
nTest = GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(i))-10;
if (nTest == ABILITY_STRENGTH) nStr++;
if (nTest == ABILITY_DEXTERITY) nDex++;
if (nTest == ABILITY_CONSTITUTION) nCon++;
if (nTest == ABILITY_INTELLIGENCE) nInt++;
if (nTest == ABILITY_WISDOM) nWis++;
if (nTest == ABILITY_CHARISMA) nCha++;
}
}
SetHeader("Choose which ability to boost for this new level under a Vow of Poverty:");
//If an ability has already been chosen, do not add it (avoid duplication)
if (nStr == 0) AddChoice("Strength", ABILITY_STRENGTH, oPC);
if (nDex == 0) AddChoice("Dexterity", ABILITY_DEXTERITY, oPC);
if (nCon == 0) AddChoice("Constitution", ABILITY_CONSTITUTION, oPC);
if (nInt == 0) AddChoice("Intelligence", ABILITY_INTELLIGENCE, oPC);
if (nWis == 0) AddChoice("Wisdom", ABILITY_WISDOM, oPC);
if (nCha == 0) AddChoice("Charisma", ABILITY_CHARISMA, oPC);
MarkStageSetUp(STAGE_SELECT_ABIL, oPC);
}
}
// Do token setup
SetupTokens();
}
else if(nValue == DYNCONV_EXITED)
{
if(DEBUG) DoDebug("ft_vowofpoverty_abil: Running exit handler");
}
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_vowofpoverty_abil: ERROR: Conversation abort section run");
}
// Handle PC response
else
{
int nChoice = GetChoice(oPC);
if(nStage == STAGE_SELECT_ABIL)
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT,UnyieldingEffect(EffectAbilityIncrease(nChoice,2)),oPC); //Give the boost for the chosen option
SetPersistantLocalInt(oPC, "VoPBoost"+IntToString(GetCharacterLevel(oPC)),(nChoice+10)); //Register the boost has been given
//Give the boost for the ones chosen before
for(i = 0; i < nLevel; i++)
{
if(GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(i))>=10)
{
nTest = GetPersistantLocalInt(oPC, "VoPBoost"+IntToString(i))-10;
for(j = 0; j <= 5; j++)
{
if(j == nTest) ApplyEffectToObject(DURATION_TYPE_PERMANENT,UnyieldingEffect(EffectAbilityIncrease(j,2)),oPC);
}
}
}
DeletePersistantLocalInt(oPC,"VoPBoostCheck");
// And we're all done
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
}
if(DEBUG) DoDebug("ft_vowofpoverty_abil: New stage: " + IntToString(nStage));
// Store the stage value. If it has been changed, this clears out the choices
SetStage(nStage, oPC);
}
}

View File

@@ -132,7 +132,7 @@ void PopulateList(object oPC, int nLevel, int iClass, int nChoice)
}
}
if(iClass == 3)
if(iClass == 8)
{
SetDefaultTokens();
DeleteLocalInt(oPC, "DynConv_Waiting");

View File

@@ -777,6 +777,11 @@ int CraftingFeats()
nArti = GetLevelByClass(CLASS_TYPE_ARTIFICER),
nBattle = GetLevelByClass(CLASS_TYPE_BATTLESMITH),
nIron = GetLevelByClass(CLASS_TYPE_IRONSOUL_FORGEMASTER);
/*FloatingTextStringOnCreature("Your caster level for crafting feats is: " + IntToString(nCasterLvl), OBJECT_SELF, FALSE);
FloatingTextStringOnCreature("Your manifester level for crafting feats is: " + IntToString(nManifesterLvl), OBJECT_SELF, FALSE);
FloatingTextStringOnCreature("Your invoker level for crafting feats is: " + IntToString(nInvokerLvl), OBJECT_SELF, FALSE);
FloatingTextStringOnCreature("Your max level for crafting feats is: " + IntToString(nMax), OBJECT_SELF, FALSE); */
int bReturn, bFirst = TRUE;
string sError = GetStringByStrRef(16823153) + "\n"; // "Your spellcaster (or manifester) level is not high enough to take the following crafting feats:"

View File

@@ -698,7 +698,7 @@ void PRCFeat_AddCompositeBonuses(object oPC, object oSkin)
{
int nAlignmentGoodEvil = GetAlignmentGoodEvil(oPC);
int nAlignmentLawChaos = GetAlignmentLawChaos(oPC);
if(GetSkillRank(SKILL_JUMP, oPC) > 4)
SetCompositeBonus(oSkin, "SkillJTum", 2, ITEM_PROPERTY_SKILL_BONUS, SKILL_TUMBLE);
@@ -707,6 +707,8 @@ void PRCFeat_AddCompositeBonuses(object oPC, object oSkin)
if(GetHasFeat(FEAT_SAC_VOW, oPC))
SetCompositeBonus(oSkin, "SacredPer", 2, ITEM_PROPERTY_SKILL_BONUS, SKILL_PERSUADE);
if(GetHasFeat(FEAT_VOWOFPOVERTY, oPC)) ExecuteScript("ft_vowofpoverty", oPC);
if(nAlignmentLawChaos == ALIGNMENT_LAWFUL)
{
if(GetHasFeat(FEAT_VOW_OBED, oPC))

View File

@@ -5,9 +5,10 @@
/** @file
This allows you to choose ability to boost.
@author Stratovarius
@date Created - 27.12.2019
@author Stratovarius
@date Created - 27.12.2019
@edited by Stratovarius
@date 24.12.2024
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
@@ -30,6 +31,7 @@ void main()
object oPC = GetPCSpeaker();
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
int nClass = GetPersistantLocalInt(oPC, "ForsakerBoostCheck");
// 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
@@ -50,7 +52,7 @@ void main()
if(nStage == STAGE_SELECT_ABIL)
{
if(DEBUG) DoDebug("prc_forsake_abil: Building maneuver selection");
SetHeader("Choose which ability to boost for this level in Forsaker:");
SetHeader("Choose which ability to boost for Forsaker level " + IntToString(nClass) + ":");
AddChoice("Strength", ABILITY_STRENGTH, oPC);
AddChoice("Dexterity", ABILITY_DEXTERITY, oPC);
AddChoice("Constitution", ABILITY_CONSTITUTION, oPC);
@@ -80,15 +82,16 @@ void main()
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(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));
int nClass = GetLevelByClass(CLASS_TYPE_FORSAKER, oPC);
// +1 because Str is ability 0
SetPersistantLocalInt(oPC, "ForsakerBoost"+IntToString(nClass), nChoice+1);
ApplyEffectToObject(DURATION_TYPE_PERMANENT,UnyieldingEffect(EffectAbilityIncrease(nChoice,1)),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);
}

View File

@@ -1,139 +1,123 @@
//::///////////////////////////////////////////////
//:: Name Forsaker
//:: FileName prc_forsaker.nss
//:: Created By: Stratosvarious
//:: Edited By: Fencas
//:://////////////////////////////////////////////
#include "prc_inc_combat"
#include "inc_dynconv"
itemproperty ForsakerDR(int nClass)
{
itemproperty iDR;
if (nClass >= 30) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_15,IP_CONST_DAMAGESOAK_31_HP);
else if (nClass >= 28) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_14,IP_CONST_DAMAGESOAK_29_HP);
else if (nClass >= 26) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_13,IP_CONST_DAMAGESOAK_27_HP);
else if (nClass >= 24) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_12,IP_CONST_DAMAGESOAK_25_HP);
else if (nClass >= 22) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_11,IP_CONST_DAMAGESOAK_23_HP);
else if (nClass >= 20) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_10,IP_CONST_DAMAGESOAK_21_HP);
else if (nClass >= 18) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_9,IP_CONST_DAMAGESOAK_19_HP);
else if (nClass >= 16) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_8,IP_CONST_DAMAGESOAK_17_HP);
else if (nClass >= 14) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_7,IP_CONST_DAMAGESOAK_15_HP);
else if (nClass >= 12) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_6,IP_CONST_DAMAGESOAK_13_HP);
else if (nClass >= 10) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_5,IP_CONST_DAMAGESOAK_11_HP);
else if (nClass >= 8) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_4,IP_CONST_DAMAGESOAK_9_HP);
else if (nClass >= 6) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_3,IP_CONST_DAMAGESOAK_7_HP);
else if (nClass >= 4) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_2,IP_CONST_DAMAGESOAK_5_HP);
else if (nClass >= 2) iDR = ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_1,IP_CONST_DAMAGESOAK_3_HP);
return iDR;
}
void ForsakerBoost(object oPC, int nClass, object oSkin)
{
int i, nStr, nCon, nDex, nInt, nWis, nCha;
for(i = 0; i <= nClass; i++)
{
int nTest = GetPersistantLocalInt(oPC, "ForsakerBoost"+IntToString(i))-1; // Taking out the -1 here
if (nTest == ABILITY_STRENGTH) nStr++;
else if (nTest == ABILITY_DEXTERITY) nDex++;
else if (nTest == ABILITY_CONSTITUTION) nCon++;
else if (nTest == ABILITY_INTELLIGENCE) nInt++;
else if (nTest == ABILITY_WISDOM) nWis++;
else if (nTest == ABILITY_CHARISMA) nCha++;
}
/*FloatingTextStringOnCreature("Strength = "+IntToString(nStr), oPC, FALSE);
FloatingTextStringOnCreature("Dex = "+IntToString(nDex), oPC, FALSE);
FloatingTextStringOnCreature("Con = "+IntToString(nCon), oPC, FALSE);
FloatingTextStringOnCreature("Int = "+IntToString(nInt), oPC, FALSE);
FloatingTextStringOnCreature("Wis = "+IntToString(nWis), oPC, FALSE);
FloatingTextStringOnCreature("Cha = "+IntToString(nCha), oPC, FALSE);*/
SetCompositeBonus(oSkin, "Forsaker_Str", nStr, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_STR);
SetCompositeBonus(oSkin, "Forsaker_Dex", nDex, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_DEX);
SetCompositeBonus(oSkin, "Forsaker_Con", nCon, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CON);
SetCompositeBonus(oSkin, "Forsaker_Int", nInt, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_INT);
SetCompositeBonus(oSkin, "Forsaker_Wis", nWis, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_WIS);
SetCompositeBonus(oSkin, "Forsaker_Cha", nCha, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CHA);
}
#include "prc_class_const"
#include "prc_alterations"
#include "prc_ipfeat_const"
#include "nw_i0_spells"
void main()
{
int nEvent = GetRunningEvent();
if(DEBUG) DoDebug("prc_forsaker running, event: " + IntToString(nEvent));
// Get the PC. This is event-dependent
object oPC;
switch(nEvent)
{
case EVENT_ITEM_ONHIT: oPC = OBJECT_SELF; break;
case EVENT_ONPLAYEREQUIPITEM: oPC = GetItemLastEquippedBy(); break;
case EVENT_ONPLAYERUNEQUIPITEM: oPC = GetItemLastUnequippedBy(); break;
case EVENT_ONHEARTBEAT: oPC = OBJECT_SELF; break;
default:
oPC = OBJECT_SELF;
}
object oItem;
object oPC = OBJECT_SELF;
object oItem;
object oArmor;
object oShield;
object oSkin = GetPCSkin(oPC);
int nSlot;
int nClass = GetLevelByClass(CLASS_TYPE_FORSAKER, oPC);
int nClassCheck;
int nBonus = nClass/2;
int nRegen = 1 + nClass/4;
int nSR = 10 + nClass;
int nEvent = GetCurrentlyRunningEvent();
//PostString(oPC, "prc_forsaker running, event: " + IntToString(nEvent), 0, 0, SCREEN_ANCHOR_TOP_LEFT, 20.0, 0xFF0000FF, 0x00000000);
// We aren't being called from any event, instead from EvalPRCFeats
if(nEvent == FALSE)
{
if (!GetPersistantLocalInt(oPC, "ForsakerBoost"+IntToString(nClass)))
{
AssignCommand(oPC, ClearAllActions(TRUE));
StartDynamicConversation("prc_forsake_abil", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
}
ForsakerBoost(oPC, nClass, oSkin);
if (nClass >= 2) IPSafeAddItemProperty(oSkin, ForsakerDR(nClass), 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, TRUE, TRUE);
if (nClass >= 3) ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectACIncrease(GetAbilityModifier(ABILITY_CONSTITUTION, oPC), AC_NATURAL_BONUS), oPC);
// Hook in the events, needed from level 1 for Magic Hatred
if(DEBUG) DoDebug("prc_forsaker: Adding eventhooks");
AddEventScript(oPC, EVENT_ONPLAYEREQUIPITEM, "prc_forsaker", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "prc_forsaker", TRUE, FALSE);
}
// We are called from the OnPlayerEquipItem eventhook. Add OnHitCast: Unique Power to oPC's weapon
else if(nEvent == EVENT_ONPLAYEREQUIPITEM)
{
oPC = GetItemLastEquippedBy();
oItem = GetItemLastEquipped();
if(DEBUG) DoDebug("prc_forsaker - OnEquip\n"
+ "oPC = " + DebugObject2Str(oPC) + "\n"
+ "oItem = " + DebugObject2Str(oItem) + "\n"
);
{
//Check if level up bonus has already been chosen and given for any of past Forsaker levels
for(nClassCheck=1; nClassCheck <= nClass; nClassCheck++)
{
if(!GetPersistantLocalInt(oPC, "ForsakerBoost"+IntToString(nClassCheck)))
{
//Level up box for stat bonus
AssignCommand(oPC, ClearAllActions(TRUE));
SetPersistantLocalInt(oPC,"ForsakerBoostCheck",nClassCheck);
StartDynamicConversation("prc_forsake_abil", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
}
}
//Fast healing 1 (+1 each 4 levels)
SetCompositeBonus(oSkin,"ForsakerFH",nRegen,ITEM_PROPERTY_REGENERATION);
//SR = 10 + Forsaker level
IPSafeAddItemProperty(oSkin, ItemPropertyBonusSpellResistance(GetSRByValue(nSR)), 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
//DR starting on level 2 = (level+1)/(Level/2)
if (nClass >=2) ApplyEffectToObject(DURATION_TYPE_PERMANENT,EffectDamageReduction((nClass+1),(nClass/2)),oPC);
// No equipping magical items, and make sure to ignore creature items
if(GetIsItemPropertyValid(GetFirstItemProperty(oItem)) && oItem != GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oPC) && oItem != GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oPC) &&
oItem != GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC) && oItem != GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC))
//Natural AC increase by CON starting on level 3
if (nClass >= 3) ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectACIncrease(GetAbilityModifier(ABILITY_CONSTITUTION, oPC), AC_NATURAL_BONUS), oPC);
// For some reason, EVENT_ONPLAYEREQUIPITEM just works with weapons, so armors and shields should be checked elsewhere
if(!GetHasFeat(FEAT_VOWOFPOVERTY,oPC))
{
for (nSlot=0; nSlot < 13; nSlot++) //All but creatures slots
{
oItem=GetItemInSlot(nSlot, oPC);
if(GetIsItemPropertyValid(GetFirstItemProperty(oItem))) //Check if it is magical (all items but on the hands))
{
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionUnequipItem(oItem));
FloatingTextStringOnCreature(GetName(oItem)+" is a magical item!", oPC, FALSE);
}
}
if(GetIsUnarmed(oPC) && (nClass >= 3)) //If it is unarmed, give DR bypass
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT,EffectAttackIncrease(nBonus),oPC);
ApplyEffectToObject(DURATION_TYPE_PERMANENT,EffectAttackDecrease(nBonus),oPC);
//Remove last weapon(s) bonus
oItem = GetPCItemLastUnequipped();
if((IPGetIsMeleeWeapon(oItem) || GetWeaponRanged(oItem)))
{
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS, -1, -1, 1, "", -1, DURATION_TYPE_TEMPORARY);
RemoveSpecificProperty(oItem, ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER, -1, -1, 1, "", -1, DURATION_TYPE_TEMPORARY);
}
}
}
// Hook in the events
//PostString(oPC, "prc_forsaker: Adding eventhooks", 0, 0, SCREEN_ANCHOR_TOP_LEFT, 20.0, 0xFF0000FF, 0x00000000);
AddEventScript(oPC, EVENT_SCRIPT_MODULE_ON_EQUIP_ITEM, "prc_forsaker", TRUE, FALSE);
}
// We are called from the OnPlayerEquipItem eventhook. Add OnHitCast: Unique Power to oPC's weapon
else if((nEvent == EVENT_SCRIPT_MODULE_ON_EQUIP_ITEM) && (!GetHasFeat(FEAT_VOWOFPOVERTY,oPC)))
{
oItem = GetPCItemLastEquipped();
//Check if weapons are magical
if(GetIsItemPropertyValid(GetFirstItemProperty(oItem)) && (IPGetIsMeleeWeapon(oItem) || GetWeaponRanged(oItem))) //Check if weapon is magical or not on allowed list
{
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionUnequipItem(oItem));
FloatingTextStringOnCreature(GetName(oItem)+" is a magical item!", oPC, FALSE);
}
// Only applies to weapons
if(oItem == GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC) || (oItem == GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC) && !GetIsShield(oItem)))
{
// Penetrate DR
if (nClass >= 3) IPSafeAddItemProperty(oItem, ItemPropertyAttackBonus(nBonus), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
if (nClass >= 3) IPSafeAddItemProperty(oItem, ItemPropertyAttackPenalty(nBonus), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
}
// We are called from the OnPlayerUnEquipItem eventhook. Remove OnHitCast: Unique Power from oPC's weapon
else if(nEvent == EVENT_ONPLAYERUNEQUIPITEM)
{
oPC = GetItemLastUnequippedBy();
oItem = GetItemLastUnequipped();
if(DEBUG) DoDebug("prc_forsaker - OnUnEquip\n"
+ "oPC = " + DebugObject2Str(oPC) + "\n"
+ "oItem = " + DebugObject2Str(oItem) + "\n"
);
// Only applies to weapons
if(IPGetIsMeleeWeapon(oItem) || GetWeaponRanged(oItem))
{
if (nClass >= 3) RemoveSpecificProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS, -1, -1, 1, "", -1, DURATION_TYPE_TEMPORARY);
if (nClass >= 3) RemoveSpecificProperty(oItem, ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER, -1, -1, 1, "", -1, DURATION_TYPE_TEMPORARY);
}
}
else
{
if(nClass>=3)
{
//Give bonus to weapon(s)
IPSafeAddItemProperty(oItem, ItemPropertyAttackBonus(nBonus), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
IPSafeAddItemProperty(oItem, ItemPropertyAttackPenalty(nBonus), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
//Remove unarmed bonus
effect eLoop = GetFirstEffect(oPC);
while(GetIsEffectValid(eLoop))
{
if(GetEffectType(eLoop) == EFFECT_TYPE_ATTACK_INCREASE
|| GetEffectType(eLoop) == EFFECT_TYPE_ATTACK_DECREASE) RemoveEffect(oPC,eLoop);
eLoop = GetNextEffect(oPC);
}
}
}
}
}

View File

@@ -979,6 +979,8 @@ void TomeOfBattle(object oPC = OBJECT_SELF)
nDomain = GetHasFeat(FEAT_DEATH_DOMAIN_POWER, oPC)
+ GetHasFeat(FEAT_MAGIC_DOMAIN_POWER, oPC)
//+ GetHasFeat(FEAT_LAW_DOMAIN_POWER, oPC)
+ GetHasFeat(FEAT_DOMAIN_POWER_PORTAL, oPC)
+ GetHasFeat(FEAT_DOMAIN_POWER_DOMINATION, oPC)
> 1;
}
if(nMove && nStance && nDomain)
@@ -1399,7 +1401,11 @@ void SoulcasterReq(object oPC)
if( GetMaxBindCount(oPC, GetPrimaryIncarnumClass(oPC)) >= 1 && GetTotalSoulmeldCount(oPC) >= 3 &&
((!GetLocalInt(oPC, "PRC_PsiPower2") && GetHasFeat(FEAT_AZURE_TALENT, oPC)) ||
(!GetLocalInt(oPC, "PRC_ArcSpell2") && GetHasFeat(FEAT_INCARNUM_SPELLSHAPING))))
SetLocalInt(oPC, "PRC_PrereqSoulcaster", 0);
SetLocalInt(oPC, "PRC_PrereqSoulcaster", 0);
// If you have both, this class fails
if(!GetLocalInt(oPC, "PRC_PsiPower2") && !GetLocalInt(oPC, "PRC_ArcSpell2"))
SetLocalInt(oPC, "PRC_PrereqSoulcaster", 1);
}
void Ironsoul(object oPC)
@@ -1625,7 +1631,9 @@ void main()
if (nClass == CLASS_TYPE_MONSTROUS && GetRacialType(oPC) == RACIAL_TYPE_REDSPAWN_ARCANISS && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC))
nMonsterCaster = TRUE;
if (nClass == CLASS_TYPE_MONSTROUS && GetRacialType(oPC) == RACIAL_TYPE_MARRUTACT && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC))
nMonsterCaster = TRUE;
nMonsterCaster = TRUE;
if (nClass == CLASS_TYPE_MONSTROUS && GetRacialType(oPC) == RACIAL_TYPE_HOBGOBLIN_WARSOUL && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC))
nMonsterCaster = TRUE;
if (nClass == CLASS_TYPE_FEY && GetRacialType(oPC) == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oPC))
nMonsterCaster = TRUE;

View File

@@ -869,7 +869,7 @@ void main()
sHeader +="\n"+GetStringByStrRef(StringToInt(Get2DACache("classes", "Name", nClass)));
SetHeader(sHeader);
// GetIsCohortChoiceValid(sName, nRace, nClass1, nClass2, nClass3, nOrder, nMoral, nEthran, sKey, nDeleted, oPC);
if(GetIsCohortChoiceValid("", nRace, nClass, CLASS_TYPE_INVALID, CLASS_TYPE_INVALID, nOrder, nMoral, FALSE, sKey, FALSE, oPC))
if(GetIsCohortChoiceValid("", nRace, nClass, CLASS_TYPE_INVALID, CLASS_TYPE_INVALID, CLASS_TYPE_INVALID, CLASS_TYPE_INVALID, CLASS_TYPE_INVALID, CLASS_TYPE_INVALID, CLASS_TYPE_INVALID, nOrder, nMoral, FALSE, sKey, FALSE, oPC))
{
AddChoice("Yes", 1);
AddChoice("Back", CHOICE_RETURN_TO_PREVIOUS);

View File

@@ -0,0 +1,336 @@
//:://////////////////////////////////////////////
//:: Ultimate Magus Spell Knowledge choice script
//:: prc_um_eskcon
//:://////////////////////////////////////////////
/*
@author Stratovarius - 2019.12.29
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "prc_inc_spells"
#include "inc_dynconv"
//////////////////////////////////////////////////
/* Constant definitions */
//////////////////////////////////////////////////
const int STAGE_SELECT_SPELL = 0;
const int STAGE_CONFIRM_SELECTION_SPELL = 1;
const int STAGE_SELECT_SPELL_LEVEL = 2;
const int CHOICE_BACK_TO_LSELECT = -1;
const int STRREF_SELECTED_HEADER1 = 16824209; // "You have selected:"
const int STRREF_SELECTED_HEADER2 = 16824210; // "Is this correct?"
const int LEVEL_STRREF_START = 16824809;
const int STRREF_YES = 4752; // "Yes"
const int STRREF_NO = 4753; // "No"
const int SORT = TRUE; // If the sorting takes too much CPU, set to FALSE
const int DEBUG_LIST = FALSE;
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
void PrintList(object oMagus)
{
string tp = "Printing list:\n";
string s = GetLocalString(oMagus, "PRC_EssentiaConvo_List_Head");
if(s == ""){
tp += "Empty\n";
}
else{
tp += s + "\n";
s = GetLocalString(oMagus, "PRC_EssentiaConvo_List_Next_" + s);
while(s != ""){
tp += "=> " + s + "\n";
s = GetLocalString(oMagus, "PRC_EssentiaConvo_List_Next_" + s);
}
}
DoDebug(tp);
}
/**
* Creates a linked list of entries that is sorted into alphabetical order
* as it is built.
* Assumption: mystery names are unique.
*
* @param oMagus The storage object aka whomever is gaining powers in this conversation
* @param sChoice The choice string
* @param nChoice The choice value
*/
void AddToTempList(object oMagus, string sChoice, int nChoice)
{
if(DEBUG_LIST) DoDebug("\nAdding to temp list: '" + sChoice + "' - " + IntToString(nChoice));
if(DEBUG_LIST) PrintList(oMagus);
// If there is nothing yet
if(!GetLocalInt(oMagus, "PRC_EssentiaConvo_ListInited"))
{
SetLocalString(oMagus, "PRC_EssentiaConvo_List_Head", sChoice);
SetLocalInt(oMagus, "PRC_EssentiaConvo_List_" + sChoice, nChoice);
SetLocalInt(oMagus, "PRC_EssentiaConvo_ListInited", TRUE);
}
else
{
// Find the location to instert into
string sPrev = "", sNext = GetLocalString(oMagus, "PRC_EssentiaConvo_List_Head");
while(sNext != "" && StringCompare(sChoice, sNext) >= 0)
{
if(DEBUG_LIST) DoDebug("Comparison between '" + sChoice + "' and '" + sNext + "' = " + IntToString(StringCompare(sChoice, sNext)));
sPrev = sNext;
sNext = GetLocalString(oMagus, "PRC_EssentiaConvo_List_Next_" + sNext);
}
// Insert the new entry
// Does it replace the head?
if(sPrev == "")
{
if(DEBUG_LIST) DoDebug("New head");
SetLocalString(oMagus, "PRC_EssentiaConvo_List_Head", sChoice);
}
else
{
if(DEBUG_LIST) DoDebug("Inserting into position between '" + sPrev + "' and '" + sNext + "'");
SetLocalString(oMagus, "PRC_EssentiaConvo_List_Next_" + sPrev, sChoice);
}
SetLocalString(oMagus, "PRC_EssentiaConvo_List_Next_" + sChoice, sNext);
SetLocalInt(oMagus, "PRC_EssentiaConvo_List_" + sChoice, nChoice);
}
}
/**
* Reads the linked list built with AddToTempList() to AddChoice() and
* deletes it.
*
* @param oMagus A PC gaining powers at the moment
*/
void TransferTempList(object oMagus)
{
string sChoice = GetLocalString(oMagus, "PRC_EssentiaConvo_List_Head");
int nChoice = GetLocalInt (oMagus, "PRC_EssentiaConvo_List_" + sChoice);
DeleteLocalString(oMagus, "PRC_EssentiaConvo_List_Head");
string sPrev;
if(DEBUG_LIST) DoDebug("Head is: '" + sChoice + "' - " + IntToString(nChoice));
while(sChoice != "")
{
// Add the choice
AddChoice(sChoice, nChoice, oMagus);
// Get next
sChoice = GetLocalString(oMagus, "PRC_EssentiaConvo_List_Next_" + (sPrev = sChoice));
nChoice = GetLocalInt (oMagus, "PRC_EssentiaConvo_List_" + sChoice);
if(DEBUG_LIST) DoDebug("Next is: '" + sChoice + "' - " + IntToString(nChoice) + "; previous = '" + sPrev + "'");
// Delete the already handled data
DeleteLocalString(oMagus, "PRC_EssentiaConvo_List_Next_" + sPrev);
DeleteLocalInt (oMagus, "PRC_EssentiaConvo_List_" + sPrev);
}
DeleteLocalInt(oMagus, "PRC_EssentiaConvo_ListInited");
}
void LearnSpecificSpell(int nClass, int nSpellLevel, int nSpellbookID, object oPC)
{
// get location of persistant storage on the hide
string sSpellbook = GetSpellsKnown_Array(nClass, nSpellLevel);
//object oToken = GetHideToken(oPC);
// Create spells known persistant array if it is missing
int nSize = persistant_array_get_size(oPC, sSpellbook);
if (nSize < 0)
{
persistant_array_create(oPC, sSpellbook);
nSize = 0;
}
// Mark the spell as known (e.g. add it to the end of oPCs spellbook)
persistant_array_set_int(oPC, sSpellbook, nSize, nSpellbookID);
// increment the spells known value in the cache
string sCache = "SKCCCache" + IntToString(nSpellLevel);
int nKnown = GetLocalInt(oPC, sCache);
if (nKnown) SetLocalInt(oPC, sCache, ++nKnown);
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS)
{
// get the associated feat and IPfeat IDs
string sFile = GetNSBDefinitionFileName(nClass);
int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
// Add spell use feats (this also places the bonus feat on the hide, so we can check whether oPC knows this spell by testing for the featID on the hide)
AddSpellUse(oPC, nSpellbookID, nClass, sFile, "NewSpellbookMem_" + IntToString(nClass), SPELLBOOK_TYPE_SPONTANEOUS, GetPCSkin(oPC), nFeatID, nIPFeatID);
}
}
void main()
{
object oMagus = GetPCSpeaker();
int nValue = GetLocalInt(oMagus, DYNCONV_VARIABLE);
int nStage = GetStage(oMagus);
int nLevel = GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oMagus);
// 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
return;
if(nValue == DYNCONV_SETUP_STAGE)
{
if(DEBUG) DoDebug("prc_um_eskcon: Running setup stage for stage " + IntToString(nStage));
// Check if this stage is marked as already set up
// This stops list duplication when scrolling
if(!GetIsStageSetUp(nStage, oMagus))
{
if(DEBUG) DoDebug("prc_um_eskcon: Stage was not set up already");
if(nStage == STAGE_SELECT_SPELL_LEVEL)
{
if(DEBUG) DoDebug("prc_um_eskcon: Building spell level selection");
SetHeader("Choose the level of spell to add to your spontaneous spells known.");
// Set the tokens.
int nType = GetPrimaryArcaneClass(oMagus);
int nMax = GetMaxSpellLevelForCasterLevel(nType, GetLevelByTypeArcane(oMagus));
int nCap = 1; // 2nd level spells learned is capped at 1st level
if (nLevel >= 10) nCap = 5;
else if (nLevel >= 8) nCap = 4;
else if (nLevel >= 6) nCap = 3;
else if (nLevel >= 4) nCap = 2;
// Max spell level to learn
if (nCap > nMax) nMax = nCap;
int i;
for(i = 0; i < nMax; i++){
AddChoice(GetStringByStrRef(LEVEL_STRREF_START - i), // The minus is correct, these are stored in inverse order in the TLK. Whoops
i + 1
);
}
// Set the next, previous and wait tokens to default values
SetDefaultTokens();
// Set the convo quit text to "Abort"
SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(DYNCONV_STRREF_ABORT_CONVO));
}
else if(nStage == STAGE_SELECT_SPELL)
{
if(DEBUG) DoDebug("prc_um_eskcon: Building spell selection");
SetHeader("Choose the spell you wish to learn. It will be added to your Sorcerer's spells known.");
int nType = GetPrimaryArcaneClass(oMagus);
if (nType != CLASS_TYPE_INVALID)
{
//int nMax = GetMaxSpellLevelForCasterLevel(nType, GetLevelByTypeArcane(oMagus));
string sPowerFile = GetFileForClass(nType);
if (nType == CLASS_TYPE_WIZARD) sPowerFile = "cls_spell_sorc";
int nLevelToBrowse = GetLocalInt(oMagus, "UltimateMagusLevel");
int i, nSpellLevel;
string sFeatID;
for(i = 0; i < 550 ; i++)
{
nSpellLevel = StringToInt(Get2DACache(sPowerFile, "Level", i));
if(nSpellLevel < nLevelToBrowse){
continue;
}
//FloatingTextStringOnCreature(IntToString(nSpellLevel)+" "+IntToString(i), oMagus);
//Due to the way the 2das are structured, we know that once
//the level of a read evocation is greater than the maximum castable
//it'll never be lower again. Therefore, we can skip reading the
//evocations that wouldn't be shown anyway.
if(nSpellLevel > nLevelToBrowse){
break;
}
//sFeatID = Get2DACache(sPowerFile, "FeatID", i);
int nSpellId = StringToInt(Get2DACache(sPowerFile, "RealSpellID", i));
if(!PRCGetIsRealSpellKnownByClass(nSpellId, CLASS_TYPE_SORCERER, oMagus) && PRCGetHasSpell(nSpellId, oMagus)) // Must know the spell, but not know it as a sorcerer
{
// Need to use the row number as choice for the NSB system
AddChoice(GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellId))), i, oMagus);
}
}
}
// Set the next, previous and wait tokens to default values
SetDefaultTokens();
// Set the convo quit text to "Abort"
SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(DYNCONV_STRREF_ABORT_CONVO));
}
else if(nStage == STAGE_CONFIRM_SELECTION_SPELL)
{
if(DEBUG) DoDebug("prc_um_eskcon: Building selection confirmation");
// Build the confirmation query
int nSpell = GetLocalInt(oMagus, "nSpell");
string sToken = "You have chosen to learn "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpell)))+"."+ "\n\n";
sToken += GetStringByStrRef(STRREF_SELECTED_HEADER2); // "Is this correct?"
SetHeader(sToken);
AddChoice(GetStringByStrRef(STRREF_YES), TRUE, oMagus); // "Yes"
AddChoice(GetStringByStrRef(STRREF_NO), FALSE, oMagus); // "No"
}
}
// Do token setup
SetupTokens();
}
else if(nValue == DYNCONV_EXITED)
{
if(DEBUG) DoDebug("prc_um_eskcon: Running exit handler");
// End of conversation cleanup
DeleteLocalInt(oMagus, "nSpell");
DeleteLocalInt(oMagus, "UltimateMagusLevel");
}
else if(nValue == DYNCONV_ABORTED)
{
// End of conversation cleanup
DeleteLocalInt(oMagus, "nSpell");
DeleteLocalInt(oMagus, "UltimateMagusLevel");
}
// Handle PC response
else
{
int nChoice = GetChoice(oMagus);
if(DEBUG) DoDebug("prc_um_eskcon: Handling PC response, stage = " + IntToString(nStage) + "; nChoice = " + IntToString(nChoice) + "; choice text = '" + GetChoiceText(oMagus) + "'");
if(nStage == STAGE_SELECT_SPELL_LEVEL)
{
if(DEBUG) DoDebug("prc_um_eskcon: spell level selected");
SetLocalInt(oMagus, "UltimateMagusLevel", nChoice);
nStage = STAGE_SELECT_SPELL;
MarkStageNotSetUp(STAGE_SELECT_SPELL_LEVEL, oMagus);
}
else if(nStage == STAGE_SELECT_SPELL)
{
if(DEBUG) DoDebug("prc_um_eskcon: Spell selected");
SetLocalInt(oMagus, "nSpell", nChoice);
nStage = STAGE_CONFIRM_SELECTION_SPELL;
MarkStageNotSetUp(STAGE_SELECT_SPELL, oMagus);
}
else if(nStage == STAGE_CONFIRM_SELECTION_SPELL)
{
if (nChoice) //Put add spells known here
{
LearnSpecificSpell(CLASS_TYPE_SORCERER, GetLocalInt(oMagus, "UltimateMagusLevel"), GetLocalInt(oMagus, "nSpell"), oMagus);
DeleteLocalInt(oMagus, "nSpell");
DeleteLocalInt(oMagus, "UltimateMagusLevel");
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
}
MarkStageNotSetUp(STAGE_CONFIRM_SELECTION_SPELL, oMagus);
}
if(DEBUG) DoDebug("prc_um_eskcon: New stage: " + IntToString(nStage));
// Store the stage value. If it has been changed, this clears out the choices
SetStage(nStage, oMagus);
}
}