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:
@@ -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**"));
|
||||
|
203
nwn/nwnprc/trunk/scripts/ft_vowofpoverty.nss
Normal file
203
nwn/nwnprc/trunk/scripts/ft_vowofpoverty.nss
Normal 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
|
||||
}
|
||||
}
|
||||
|
126
nwn/nwnprc/trunk/scripts/ft_vowofpoverty_abil.nss
Normal file
126
nwn/nwnprc/trunk/scripts/ft_vowofpoverty_abil.nss
Normal 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);
|
||||
}
|
||||
}
|
@@ -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");
|
||||
|
@@ -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:"
|
||||
|
@@ -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))
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
|
336
nwn/nwnprc/trunk/scripts/prc_um_eskcon.nss
Normal file
336
nwn/nwnprc/trunk/scripts/prc_um_eskcon.nss
Normal 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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user