generated from Jaysyn/ModuleTemplate
2025/08/24 Update
Updated for PRC8 updates.
This commit is contained in:
parent
66d0ef278f
commit
e76c3a2766
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "A1-4 Scourge of the Slave Lords [PRC8-CEP3]"
|
||||
description = "PRC8 version of A1-4 Scourge of the Slave Lords."
|
||||
version = "4.2prc8"
|
||||
version = "4.3prc8"
|
||||
url = "https://discord.gg/ca2ru3KxYd"
|
||||
author = "Nol Drek"
|
||||
author = "Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com>"
|
||||
@ -232,7 +232,10 @@ description = "PRC8 version of A1-4 Scourge of the Slave Lords."
|
||||
filter = "prc_nui_scd_inc.nss"
|
||||
filter = "prc_nui_consts.nss"
|
||||
filter = "nw_inc_nui"
|
||||
filter = "xchst_inc.nss"
|
||||
filter = "inc_infusion.nss"
|
||||
filter = "nw_inc_gff.nss"
|
||||
filter = "prc_inc_json.nss"
|
||||
filter = "xchst_inc.nss"
|
||||
|
||||
[target.rules]
|
||||
"*" = "src/module/$ext"
|
@ -47,77 +47,78 @@ const string MES_CONTINGENCIES_YES2 = "The contingencies must expire to allo
|
||||
*/
|
||||
|
||||
//Primogenitors SpellID constants
|
||||
const int SPELL_EPIC_A_STONE = 0;//4007;
|
||||
const int SPELL_EPIC_ACHHEEL = 1;//4000;
|
||||
const int SPELL_EPIC_AL_MART = 2;//4002;
|
||||
const int SPELL_EPIC_ALLHOPE = 3;//4001;
|
||||
const int SPELL_EPIC_ANARCHY = 4;//4003;
|
||||
const int SPELL_EPIC_ANBLAST = 5;//4004;
|
||||
const int SPELL_EPIC_ANBLIZZ = 6;//4005;
|
||||
const int SPELL_EPIC_ARMY_UN = 7;//4006;
|
||||
const int SPELL_EPIC_BATTLEB = 999;//4008;
|
||||
const int SPELL_EPIC_CELCOUN = 8;//4009;
|
||||
const int SPELL_EPIC_CHAMP_V = 9;//4010;
|
||||
const int SPELL_EPIC_CON_RES =10;//4011;
|
||||
const int SPELL_EPIC_CON_REU =11;//4012;
|
||||
const int SPELL_EPIC_DEADEYE =12;//4013;
|
||||
const int SPELL_EPIC_DIREWIN =13;//4015;
|
||||
const int SPELL_EPIC_DREAMSC =14;//4017;
|
||||
const int SPELL_EPIC_DRG_KNI =15;//4016;
|
||||
const int SPELL_EPIC_DTHMARK =1000;//4014;
|
||||
const int SPELL_EPIC_DULBLAD =16;//4018;
|
||||
const int SPELL_EPIC_DWEO_TH =17;//4019;
|
||||
const int SPELL_EPIC_ENSLAVE =18;//4020;
|
||||
const int SPELL_EPIC_EP_M_AR =19;//4021;
|
||||
const int SPELL_EPIC_EP_RPLS =20;//4022;
|
||||
const int SPELL_EPIC_EP_SP_R =21;//4023;
|
||||
const int SPELL_EPIC_EP_WARD =22;//4024;
|
||||
const int SPELL_EPIC_ET_FREE =23;//4025;
|
||||
const int SPELL_EPIC_FIEND_W =24;//4026;
|
||||
const int SPELL_EPIC_FLEETNS =25;//4027;
|
||||
const int SPELL_EPIC_GEMCAGE =26;//4028;
|
||||
const int SPELL_EPIC_GODSMIT =27;//4029;
|
||||
const int SPELL_EPIC_GR_RUIN =28;//4030;
|
||||
const int SPELL_EPIC_GR_SP_RE=29;//4031;
|
||||
const int SPELL_EPIC_GR_TIME =30;//4032;
|
||||
const int SPELL_EPIC_HELBALL =31;//4034;
|
||||
const int SPELL_EPIC_HELSEND =1001;//4033;
|
||||
const int SPELL_EPIC_HERCALL =32;//4035;
|
||||
const int SPELL_EPIC_HERCEMP =33;//4036;
|
||||
const int SPELL_EPIC_IMPENET =34;//4037;
|
||||
const int SPELL_EPIC_LEECH_F =35;//4038;
|
||||
const int SPELL_EPIC_LEG_ART =1002;//4039;
|
||||
const int SPELL_EPIC_LIFE_FT =1003;//4040;
|
||||
const int SPELL_EPIC_MAGMA_B =36;//4041;
|
||||
const int SPELL_EPIC_MASSPEN =37;//4042;
|
||||
const int SPELL_EPIC_MORI = 38;//4043;
|
||||
const int SPELL_EPIC_MUMDUST =39;//4044;
|
||||
const int SPELL_EPIC_NAILSKY =40;//4045;
|
||||
const int SPELL_EPIC_NIGHTSU =1004;//4046;
|
||||
const int SPELL_EPIC_ORDER_R =41;//4047;
|
||||
const int SPELL_EPIC_PATHS_B =42;//4048;
|
||||
const int SPELL_EPIC_PEERPEN =43;//4049;
|
||||
const int SPELL_EPIC_PESTIL = 44;//4050;
|
||||
const int SPELL_EPIC_PIOUS_P =45;//4051;
|
||||
const int SPELL_EPIC_PLANCEL =46;//4052;
|
||||
const int SPELL_EPIC_PSION_S =47;//4053;
|
||||
const int SPELL_EPIC_RAINFIR =48;//4054;
|
||||
const int SPELL_EPIC_RISEN_R =1005;//4055;
|
||||
const int SPELL_EPIC_RUINN = 49;//4056; //NON_STANDARD
|
||||
const int SPELL_EPIC_SINGSUN =50;//4057;
|
||||
const int SPELL_EPIC_SP_WORM =51;//4058;
|
||||
const int SPELL_EPIC_STORM_M =52;//4059;
|
||||
const int SPELL_EPIC_SUMABER =53;//4060;
|
||||
const int SPELL_EPIC_SUP_DIS =54;//4061;
|
||||
const int SPELL_EPIC_SYMRUST =1006;//4062;
|
||||
const int SPELL_EPIC_THEWITH =55;//4063;
|
||||
const int SPELL_EPIC_TOLO_KW =56;//4064;
|
||||
const int SPELL_EPIC_TRANVIT =57;//4065;
|
||||
const int SPELL_EPIC_TWINF = 58;//4066;
|
||||
const int SPELL_EPIC_UNHOLYD =59;//4067;
|
||||
const int SPELL_EPIC_UNIMPIN =60;//4068;
|
||||
const int SPELL_EPIC_UNSEENW =61;//4069;
|
||||
const int SPELL_EPIC_WHIP_SH =62;//4070;
|
||||
const int SPELL_EPIC_A_STONE = 0;//4007;
|
||||
const int SPELL_EPIC_ACHHEEL = 1;//4000;
|
||||
const int SPELL_EPIC_AL_MART = 2;//4002;
|
||||
const int SPELL_EPIC_ALLHOPE = 3;//4001;
|
||||
const int SPELL_EPIC_ANARCHY = 4;//4003;
|
||||
const int SPELL_EPIC_ANBLAST = 5;//4004;
|
||||
const int SPELL_EPIC_ANBLIZZ = 6;//4005;
|
||||
const int SPELL_EPIC_ARMY_UN = 7;//4006;
|
||||
const int SPELL_EPIC_BATTLEB = 999;//4008;
|
||||
const int SPELL_EPIC_CELCOUN = 8;//4009;
|
||||
const int SPELL_EPIC_CHAMP_V = 9;//4010;
|
||||
const int SPELL_EPIC_CON_RES = 10;//4011;
|
||||
const int SPELL_EPIC_CON_REU = 11;//4012;
|
||||
const int SPELL_EPIC_DEADEYE = 12;//4013;
|
||||
const int SPELL_EPIC_DIREWIN = 13;//4015;
|
||||
const int SPELL_EPIC_DREAMSC = 14;//4017;
|
||||
const int SPELL_EPIC_DRG_KNI = 15;//4016;
|
||||
const int SPELL_EPIC_DTHMARK = 1000;//4014;
|
||||
const int SPELL_EPIC_DULBLAD = 16;//4018;
|
||||
const int SPELL_EPIC_DWEO_TH = 17;//4019;
|
||||
const int SPELL_EPIC_ENSLAVE = 18;//4020;
|
||||
const int SPELL_EPIC_EP_M_AR = 19;//4021;
|
||||
const int SPELL_EPIC_EP_RPLS = 20;//4022;
|
||||
const int SPELL_EPIC_EP_SP_R = 21;//4023;
|
||||
const int SPELL_EPIC_EP_WARD = 22;//4024;
|
||||
const int SPELL_EPIC_ET_FREE = 23;//4025;
|
||||
const int SPELL_EPIC_FIEND_W = 24;//4026;
|
||||
const int SPELL_EPIC_FLEETNS = 25;//4027;
|
||||
const int SPELL_EPIC_GEMCAGE = 26;//4028;
|
||||
const int SPELL_EPIC_GODSMIT = 27;//4029;
|
||||
const int SPELL_EPIC_GR_RUIN = 28;//4030;
|
||||
const int SPELL_EPIC_GR_SP_RE = 29;//4031;
|
||||
const int SPELL_EPIC_GR_TIME = 30;//4032;
|
||||
const int SPELL_EPIC_HELBALL = 31;//4034;
|
||||
const int SPELL_EPIC_HELSEND = 1001;//4033;
|
||||
const int SPELL_EPIC_HERCALL = 32;//4035;
|
||||
const int SPELL_EPIC_HERCEMP = 33;//4036;
|
||||
const int SPELL_EPIC_IMPENET = 34;//4037;
|
||||
const int SPELL_EPIC_LEECH_F = 35;//4038;
|
||||
const int SPELL_EPIC_LEG_ART = 1002;//4039;
|
||||
const int SPELL_EPIC_LIFE_FT = 1003;//4040;
|
||||
const int SPELL_EPIC_MAGMA_B = 36;//4041;
|
||||
const int SPELL_EPIC_MASSPEN = 37;//4042;
|
||||
const int SPELL_EPIC_MORI = 38;//4043;
|
||||
const int SPELL_EPIC_MUMDUST = 39;//4044;
|
||||
const int SPELL_EPIC_NAILSKY = 40;//4045;
|
||||
const int SPELL_EPIC_NIGHTSU = 1004;//4046;
|
||||
const int SPELL_EPIC_ORDER_R = 41;//4047;
|
||||
const int SPELL_EPIC_PATHS_B = 42;//4048;
|
||||
const int SPELL_EPIC_PEERPEN = 43;//4049;
|
||||
const int SPELL_EPIC_PESTIL = 44;//4050;
|
||||
const int SPELL_EPIC_PIOUS_P = 45;//4051;
|
||||
const int SPELL_EPIC_PLANCEL = 46;//4052;
|
||||
const int SPELL_EPIC_PSION_S = 47;//4053;
|
||||
const int SPELL_EPIC_RAINFIR = 48;//4054;
|
||||
//const int SPELL_EPIC_RISEN_R =1005;//4055;
|
||||
const int SPELL_EPIC_RISEN_R = 49;//4055;
|
||||
const int SPELL_EPIC_RUINN = 50;//4056; //NON_STANDARD
|
||||
const int SPELL_EPIC_SINGSUN = 51;//4057;
|
||||
const int SPELL_EPIC_SP_WORM = 52;//4058;
|
||||
const int SPELL_EPIC_STORM_M = 53;//4059;
|
||||
const int SPELL_EPIC_SUMABER = 54;//4060;
|
||||
const int SPELL_EPIC_SUP_DIS = 55;//4061;
|
||||
const int SPELL_EPIC_SYMRUST = 1006;//4062;
|
||||
const int SPELL_EPIC_THEWITH = 56;//4063;
|
||||
const int SPELL_EPIC_TOLO_KW = 57;//4064;
|
||||
const int SPELL_EPIC_TRANVIT = 58;//4065;
|
||||
const int SPELL_EPIC_TWINF = 59;//4066;
|
||||
const int SPELL_EPIC_UNHOLYD = 60;//4067;
|
||||
const int SPELL_EPIC_UNIMPIN = 61;//4068;
|
||||
const int SPELL_EPIC_UNSEENW = 62;//4069;
|
||||
const int SPELL_EPIC_WHIP_SH = 63;//4070;
|
||||
|
||||
|
||||
/*
|
||||
|
@ -246,7 +246,7 @@ int GetSpellFromAbrev(string sAbrev)
|
||||
sAbrev = GetStringLowerCase(sAbrev);
|
||||
if(GetStringLeft(sAbrev, 8) == "epic_sp_")
|
||||
sAbrev = GetStringRight(sAbrev, GetStringLength(sAbrev)-8);
|
||||
if(DEBUG) DoDebug("sAbrew to check vs: " + sAbrev);
|
||||
if(DEBUG) DoDebug("sAbrev to check vs: " + sAbrev);
|
||||
int i = 0;
|
||||
string sLabel = GetStringLowerCase(Get2DACache("epicspells", "LABEL", i));
|
||||
while(sLabel != "")
|
||||
|
481
src/include/inc_infusion.nss
Normal file
481
src/include/inc_infusion.nss
Normal file
@ -0,0 +1,481 @@
|
||||
//:://////////////////////////////////////////////
|
||||
//:: ;-. ,-. ,-. ,-.
|
||||
//:: | ) | ) / ( )
|
||||
//:: |-' |-< | ;-:
|
||||
//:: | | \ \ ( )
|
||||
//:: ' ' ' `-' `-'
|
||||
//::///////////////////////////////////////////////
|
||||
//::
|
||||
/*
|
||||
Script: inc_infusion
|
||||
Author: Jaysyn
|
||||
Created: 2025-08-11 17:01:26
|
||||
|
||||
Description:
|
||||
Contains most functions related to the Create
|
||||
Infusion feat.
|
||||
|
||||
*/
|
||||
//::
|
||||
//:://////////////////////////////////////////////
|
||||
#include "prc_inc_spells"
|
||||
|
||||
int GetMaxDivineSpellLevel(object oCaster, int nClass);
|
||||
int GetCastSpellCasterLevelFromItem(object oItem, int nSpellID);
|
||||
int GetIsClassSpell(object oCaster, int nSpellID, int nClass);
|
||||
int GetHasSpellOnClassList(object oCaster, int nSpellID);
|
||||
void InfusionSecondSave(object oUser, int nDC);
|
||||
|
||||
/**
|
||||
* @brief Finds the class index for which the given spell is available to the specified caster.
|
||||
*
|
||||
* This function iterates through all possible classes and returns the first class
|
||||
* index for which the specified spell is on the caster's spell list.
|
||||
*
|
||||
* @param oCaster The creature object to check.
|
||||
* @param nSpellID The spell ID to find the class for.
|
||||
*
|
||||
* @return The class index that has the spell on its class spell list for the caster,
|
||||
* or -1 if no matching class is found.
|
||||
*/
|
||||
int FindSpellCastingClass(object oCaster, int nSpellID)
|
||||
{
|
||||
int i = 0;
|
||||
int nClassFound = -1;
|
||||
int nClass;
|
||||
|
||||
// Only loop through caster's classes
|
||||
for (i = 0; i <= 8; i++)
|
||||
{
|
||||
nClass = GetClassByPosition(i, oCaster);
|
||||
if (nClass == CLASS_TYPE_INVALID) continue;
|
||||
|
||||
if (GetIsClassSpell(oCaster, nSpellID, nClass))
|
||||
{
|
||||
nClassFound = nClass;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nClassFound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Performs validation checks to determine if the caster can use a spell infusion from the specified item.
|
||||
*
|
||||
* This function verifies that the item is a valid infused herb, checks the caster's relevant class and ability scores,
|
||||
* confirms the caster is a divine spellcaster with the necessary caster level, and ensures the spell is on the caster's class spell list.
|
||||
*
|
||||
* @param oCaster The creature attempting to use the infusion.
|
||||
* @param oItem The infused herb item containing the spell.
|
||||
* @param nSpellID The spell ID of the infusion spell being cast.
|
||||
*
|
||||
* @return TRUE if all infusion use checks pass and the caster can use the infusion; FALSE otherwise.
|
||||
*/
|
||||
int DoInfusionUseChecks(object oCaster, object oItem, int nSpellID)
|
||||
{
|
||||
int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS);
|
||||
|
||||
if(GetBaseItemType(oItem) != BASE_ITEM_INFUSED_HERB)
|
||||
{
|
||||
FloatingTextStringOnCreature("Not casting from an Infused Herb", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int nItemSpellLvl = GetCastSpellCasterLevelFromItem(oItem, nSpellID);
|
||||
if (bPnPHerbs && nItemSpellLvl == -1)
|
||||
{
|
||||
FloatingTextStringOnCreature("Item has no spellcaster level.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// **CRITICAL: Find the correct class that actually has the spell on its list**
|
||||
int nClassCaster = FindSpellCastingClass(oCaster, nSpellID);
|
||||
|
||||
if(DEBUG) DoDebug("nClassCaster is: " + IntToString(nClassCaster) + ".");
|
||||
|
||||
// Check for valid class
|
||||
if (nClassCaster == -1)
|
||||
{
|
||||
FloatingTextStringOnCreature("No valid class found for this spell.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(GetMaxDivineSpellLevel(oCaster, nClassCaster) < 1 )
|
||||
{
|
||||
FloatingTextStringOnCreature("You must be a divine spellcaster to activate an infusion.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Must have spell on class list - (This will also double-check via the class)
|
||||
if (!GetHasSpellOnClassList(oCaster, nSpellID))
|
||||
{
|
||||
FloatingTextStringOnCreature("You must have a spell on one of your class spell lists to cast it from an infusion.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Must meet ability requirement: Ability score >= 10 + spell level
|
||||
int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClassCaster);
|
||||
int nClassAbility = GetAbilityScoreForClass(nClassCaster, oCaster);
|
||||
|
||||
if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassCaster is "+IntToString(nClassCaster)+".");
|
||||
if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: Class nSpellLevel is "+IntToString(nSpellLevel)+".");
|
||||
if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassAbility is "+IntToString(nClassAbility)+".");
|
||||
|
||||
if (nClassAbility < 10 + nSpellLevel)
|
||||
{
|
||||
FloatingTextStringOnCreature("You must meet ability score requirement to cast spell from infusion.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Must have a divine caster level at least equal to infusion's caster level
|
||||
int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster);
|
||||
|
||||
if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nDivineLvl is "+IntToString(nDivineLvl)+".");
|
||||
|
||||
if (nDivineLvl < nItemSpellLvl)
|
||||
{
|
||||
FloatingTextStringOnCreature("Your divine caster level is too low to cast this spell from an infusion.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* int DoInfusionUseChecks(object oCaster, object oItem, int nSpellID)
|
||||
{
|
||||
int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS);
|
||||
|
||||
if(GetBaseItemType(oItem) != BASE_ITEM_INFUSED_HERB)
|
||||
{
|
||||
FloatingTextStringOnCreature("Not casting from an Infused Herb", oCaster);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
int nItemSpellLvl = GetCastSpellCasterLevelFromItem(oItem, nSpellID);
|
||||
if (bPnPHerbs && nItemSpellLvl == -1)
|
||||
{
|
||||
FloatingTextStringOnCreature("Item has no spellcaster level.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Find relevant class for the spell
|
||||
int nClassCaster = FindSpellCastingClass(oCaster, nSpellID);
|
||||
|
||||
if(DEBUG) DoDebug("nClassCaster is: "+IntToString(nClassCaster)+".");
|
||||
|
||||
if(GetMaxDivineSpellLevel(oCaster, nClassCaster) < 1 )
|
||||
{
|
||||
FloatingTextStringOnCreature("You must be a divine spellcaster to activate an infusion.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Must have spell on class list
|
||||
if (!GetHasSpellOnClassList(oCaster, nSpellID))
|
||||
{
|
||||
FloatingTextStringOnCreature("You must have a spell on one of your class spell lists to cast it from an infusion.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Must meet ability requirement: Ability score >= 10 + spell level
|
||||
int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClassCaster);
|
||||
int nClassAbility = GetAbilityScoreForClass(nClassCaster, oCaster);
|
||||
|
||||
if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassCaster is "+IntToString(nClassCaster)+".");
|
||||
if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: Class nSpellLevel is "+IntToString(nSpellLevel)+".");
|
||||
if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nClassAbility is "+IntToString(nClassAbility)+".");
|
||||
|
||||
if (nClassAbility < 10 + nSpellLevel)
|
||||
{
|
||||
FloatingTextStringOnCreature("You must meet ability score requirement to cast spell from infusion.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Must have a divine caster level at least equal to infusion's caster level
|
||||
int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster);
|
||||
|
||||
if(DEBUG) DoDebug("inc_infusion >> DoInfusionUseChecks: nDivineLvl is "+IntToString(nDivineLvl)+".");
|
||||
|
||||
if (nDivineLvl < nItemSpellLvl)
|
||||
{
|
||||
FloatingTextStringOnCreature("Your divine caster level is too low to cast this spell from an infusion.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* @brief Retrieves the maximum divine spell level known by the caster for a given class.
|
||||
*
|
||||
* This function checks the caster's local integers named "PRC_DivSpell1" through "PRC_DivSpell9"
|
||||
* in descending order to determine the highest divine spell level available.
|
||||
* It returns the highest spell level for which the corresponding local int is false (zero).
|
||||
*
|
||||
* @param oCaster The creature whose divine spell levels are being checked.
|
||||
* @param nClass The class index for which to check the divine spell level (currently unused).
|
||||
*
|
||||
* @return The highest divine spell level known by the caster (1 to 9).
|
||||
*/
|
||||
int GetMaxDivineSpellLevel(object oCaster, int nClass)
|
||||
{
|
||||
int i = 9;
|
||||
for (i; i > 0; i--)
|
||||
{
|
||||
if(!GetLocalInt(oCaster, "PRC_DivSpell"+IntToString(i)))
|
||||
return i;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves the spell school of an herb based on its resref by looking it up in the craft_infusion.2da file.
|
||||
*
|
||||
* This function searches the "craft_infusion" 2DA for a row matching the herb's resref.
|
||||
* If found, it returns the corresponding spell school as an integer constant.
|
||||
* If not found or the SpellSchool column is missing/invalid, it returns -1.
|
||||
*
|
||||
* @param oHerb The herb object to check.
|
||||
*
|
||||
* @return The spell school constant corresponding to the herb's infusion spell school,
|
||||
* or -1 if the herb is invalid, not found, or the data is missing.
|
||||
*/
|
||||
int GetHerbsSpellSchool(object oHerb)
|
||||
{
|
||||
if (!GetIsObjectValid(oHerb)) return -1;
|
||||
|
||||
string sResref = GetResRef(oHerb);
|
||||
int nRow = 0;
|
||||
string sRowResref;
|
||||
|
||||
while (nRow < 200)
|
||||
{
|
||||
sRowResref = Get2DACache("craft_infusion", "Resref", nRow);
|
||||
if (sRowResref == "") break;
|
||||
if (sRowResref == sResref)
|
||||
{
|
||||
string sHerbSpellSchool = Get2DAString("craft_infusion", "SpellSchool", nRow);
|
||||
|
||||
if (sHerbSpellSchool == "A") return SPELL_SCHOOL_ABJURATION;
|
||||
else if (sHerbSpellSchool == "C") return SPELL_SCHOOL_CONJURATION;
|
||||
else if (sHerbSpellSchool == "D") return SPELL_SCHOOL_DIVINATION;
|
||||
else if (sHerbSpellSchool == "E") return SPELL_SCHOOL_ENCHANTMENT;
|
||||
else if (sHerbSpellSchool == "V") return SPELL_SCHOOL_EVOCATION;
|
||||
else if (sHerbSpellSchool == "I") return SPELL_SCHOOL_ILLUSION;
|
||||
else if (sHerbSpellSchool == "N") return SPELL_SCHOOL_NECROMANCY;
|
||||
else if (sHerbSpellSchool == "T") return SPELL_SCHOOL_TRANSMUTATION;
|
||||
else return SPELL_SCHOOL_GENERAL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
nRow++;
|
||||
}
|
||||
return -1; // Not found
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves the infusion spell level of an herb by matching its resref in the craft_infusion.2da file.
|
||||
*
|
||||
* This function searches the "craft_infusion" 2DA for a row matching the herb's resref.
|
||||
* If found, it returns the spell level from the SpellLevel column as an integer.
|
||||
* If not found or the column is missing, it returns -1.
|
||||
*
|
||||
* @param oHerb The herb object whose infusion spell level is to be retrieved.
|
||||
*
|
||||
* @return The spell level as an integer if found, or -1 if the herb is invalid, not found, or the column is missing.
|
||||
*/
|
||||
int GetHerbsInfusionSpellLevel(object oHerb)
|
||||
{
|
||||
if (!GetIsObjectValid(oHerb)) return -1;
|
||||
|
||||
string sResref = GetResRef(oHerb);
|
||||
int nRow = 0;
|
||||
string sRowResref;
|
||||
|
||||
// Brute-force loop — adjust limit if your 2DA has more than 500 rows
|
||||
while (nRow < 200)
|
||||
{
|
||||
sRowResref = Get2DACache("craft_infusion", "Resref", nRow);
|
||||
if (sRowResref == "") break; // End of valid rows
|
||||
if (sRowResref == sResref)
|
||||
{
|
||||
string sSpellLevelStr = Get2DAString("craft_infusion", "SpellLevel", nRow);
|
||||
return StringToInt(sSpellLevelStr);
|
||||
}
|
||||
nRow++;
|
||||
}
|
||||
return -1; // Not found
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves the caster level of a specific cast-spell item property from an item.
|
||||
*
|
||||
* This function iterates through the item properties of the given item, searching for an
|
||||
* ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL property that matches the specified spell ID.
|
||||
* If found, it returns the caster level value stored in the item property.
|
||||
*
|
||||
* @param oItem The item object to check.
|
||||
* @param nSpellID The spell ID to match against the item property.
|
||||
*
|
||||
* @return The caster level associated with the matching cast-spell item property,
|
||||
* or -1 if no matching property is found.
|
||||
*/
|
||||
int GetCastSpellCasterLevelFromItem(object oItem, int nSpellID)
|
||||
{
|
||||
int nFoundCL = -1;
|
||||
|
||||
itemproperty ip = GetFirstItemProperty(oItem);
|
||||
while (GetIsItemPropertyValid(ip))
|
||||
{
|
||||
int nType = GetItemPropertyType(ip);
|
||||
|
||||
// First preference: PRC's CASTER_LEVEL itemprop
|
||||
if (nType == ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL)
|
||||
{
|
||||
int nSubType = GetItemPropertySubType(ip);
|
||||
string sSpellIDStr = Get2DAString("iprp_spells", "SpellIndex", nSubType);
|
||||
int nSubSpellID = StringToInt(sSpellIDStr);
|
||||
|
||||
if (nSubSpellID == nSpellID)
|
||||
{
|
||||
return GetItemPropertyCostTableValue(ip); // Found exact CL
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: vanilla CAST_SPELL property
|
||||
if (nType == ITEM_PROPERTY_CAST_SPELL && nFoundCL == -1)
|
||||
{
|
||||
int nSubType = GetItemPropertySubType(ip);
|
||||
string sSpellIDStr = Get2DAString("iprp_spells", "SpellIndex", nSubType);
|
||||
int nSubSpellID = StringToInt(sSpellIDStr);
|
||||
|
||||
if (nSubSpellID == nSpellID)
|
||||
{
|
||||
// Vanilla uses CostTableValue for *number of uses*, not CL,
|
||||
// so we’ll assume default caster level = spell level * 2 - 1
|
||||
int nSpellLevel = StringToInt(Get2DAString("spells", "Innate", nSubSpellID));
|
||||
nFoundCL = nSpellLevel * 2 - 1; // default NWN caster level rule
|
||||
}
|
||||
}
|
||||
|
||||
ip = GetNextItemProperty(oItem);
|
||||
}
|
||||
|
||||
return nFoundCL; // -1 if not found
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if a given spell ID is present on the specified class's spell list for the caster.
|
||||
*
|
||||
* This function determines the spell level of the spell for the given class using PRCGetSpellLevelForClass.
|
||||
* If the spell level is -1, the spell is not on the class's spell list.
|
||||
* Otherwise, the spell is considered to be on the class spell list.
|
||||
*
|
||||
* @param oCaster The creature object casting or querying the spell.
|
||||
* @param nSpellID The spell ID to check.
|
||||
* @param nClass The class index to check the spell list against.
|
||||
*
|
||||
* @return TRUE if the spell is on the class's spell list; FALSE otherwise.
|
||||
*/
|
||||
int GetIsClassSpell(object oCaster, int nSpellID, int nClass)
|
||||
{
|
||||
if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: nSpellID is: "+IntToString(nSpellID)+".");
|
||||
if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: nClass is: "+IntToString(nClass)+".");
|
||||
|
||||
int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nClass);
|
||||
if (nSpellLevel == -1)
|
||||
{
|
||||
if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: SpellLevel is "+IntToString(nSpellLevel)+".");
|
||||
if(DEBUG) DoDebug("inc_infusion >> GetIsClassSpell: Spell "+IntToString(nSpellID)+" is not in spelllist of "+IntToString(nClass)+".");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the caster has the specified spell on any of their class spell lists.
|
||||
*
|
||||
* This function iterates through all classes the caster has (up to position 8),
|
||||
* and returns TRUE if the spell is found on any class's spell list.
|
||||
*
|
||||
* @param oCaster The creature object to check.
|
||||
* @param nSpellID The spell ID to search for.
|
||||
*
|
||||
* @return TRUE if the spell is present on at least one of the caster's class spell lists;
|
||||
* FALSE otherwise.
|
||||
*/
|
||||
int GetHasSpellOnClassList(object oCaster, int nSpellID)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= 8; i++)
|
||||
{
|
||||
int nClass = GetClassByPosition(i, oCaster);
|
||||
if (nClass == CLASS_TYPE_INVALID) continue;
|
||||
|
||||
if (GetIsClassSpell(oCaster, nSpellID, nClass))
|
||||
{
|
||||
if(DEBUG) DoDebug("inc_infusion >> GetHasSpellOnClassList: Class spell found.");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if(DEBUG) DoDebug("inc_infusion >> GetHasSpellOnClassList: Class spell not found.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Applies a poison nausea effect to the user when infusion use fails.
|
||||
*
|
||||
* This function performs an immediate Fortitude saving throw against poison DC based on infusion caster level.
|
||||
* If the user fails and is not immune to poison, an infusion nausea effect is applied, replacing any existing one.
|
||||
* A second saving throw is scheduled after 1 minute to attempt to remove the effect.
|
||||
*
|
||||
* @param oUser The creature who used the infusion and may be poisoned.
|
||||
* @param nInfusionCL The caster level of the infusion used, affecting the DC of the saving throw.
|
||||
*/
|
||||
void ApplyInfusionPoison(object oUser, int nInfusionCL)
|
||||
{
|
||||
int nDC = 10 + (nInfusionCL / 2);
|
||||
int bImmune = GetIsImmune(oUser, IMMUNITY_TYPE_POISON);
|
||||
|
||||
// First save immediately
|
||||
if (!bImmune && !PRCMySavingThrow(SAVING_THROW_FORT, oUser, nDC, SAVING_THROW_TYPE_POISON))
|
||||
{
|
||||
// Remove existing infusion poison nausea effect before applying new
|
||||
effect eOld = GetFirstEffect(oUser);
|
||||
while (GetIsEffectValid(eOld))
|
||||
{
|
||||
if (GetEffectTag(eOld) == "INFUSION_POISON_TAG")
|
||||
{
|
||||
RemoveEffect(oUser, eOld);
|
||||
break; // Assuming only one effect with this tag
|
||||
}
|
||||
eOld = GetNextEffect(oUser);
|
||||
}
|
||||
|
||||
effect eNausea = EffectNausea(oUser, 60.0f);
|
||||
|
||||
TagEffect(eNausea, "INFUSION_POISON_TAG");
|
||||
FloatingTextStringOnCreature("The infusion has made you nauseous.", oUser);
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eNausea, oUser, RoundsToSeconds(10));
|
||||
}
|
||||
|
||||
// Second save 1 minute later
|
||||
if (!bImmune)
|
||||
{
|
||||
DelayCommand(60.0, InfusionSecondSave(oUser, nDC));
|
||||
}
|
||||
}
|
||||
|
||||
void InfusionSecondSave(object oUser, int nDC)
|
||||
{
|
||||
if (!PRCMySavingThrow(SAVING_THROW_FORT, oUser, nDC, SAVING_THROW_TYPE_POISON))
|
||||
{
|
||||
FloatingTextStringOnCreature("The infusion has made you nauseous.", oUser);
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectNausea(oUser, 60.0f), oUser, RoundsToSeconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
//:: void main (){}
|
@ -242,25 +242,27 @@ void SetupLookupStage(object oMod, int n)
|
||||
case 11: SetLkupStage(n, oMod, CLASS_TYPE_DRAGON_SHAMAN, "cls_inv_drgshm"); break;
|
||||
case 12: SetLkupStage(n, oMod, CLASS_TYPE_WARLOCK, "cls_inv_warlok"); break;
|
||||
case 13: SetLkupStage(n, oMod, CLASS_TYPE_ARCHIVIST, "cls_spell_archv"); break;
|
||||
case 14: SetLkupStage(n, oMod, CLASS_TYPE_ASSASSIN, "cls_spell_asasin"); break;
|
||||
case 15: SetLkupStage(n, oMod, CLASS_TYPE_BARD, "cls_spell_bard"); break;
|
||||
case 16: SetLkupStage(n, oMod, CLASS_TYPE_BEGUILER, "cls_spell_beguil"); break;
|
||||
case 17: SetLkupStage(n, oMod, CLASS_TYPE_DREAD_NECROMANCER, "cls_spell_dnecro"); break;
|
||||
case 18: SetLkupStage(n, oMod, CLASS_TYPE_DUSKBLADE, "cls_spell_duskbl"); break;
|
||||
case 19: SetLkupStage(n, oMod, CLASS_TYPE_FAVOURED_SOUL, "cls_spell_favsol"); break;
|
||||
case 20: SetLkupStage(n, oMod, CLASS_TYPE_HARPER, "cls_spell_harper"); break;
|
||||
case 21: SetLkupStage(n, oMod, CLASS_TYPE_HEXBLADE, "cls_spell_hexbl"); break;
|
||||
case 22: SetLkupStage(n, oMod, CLASS_TYPE_JUSTICEWW, "cls_spell_justww"); break;
|
||||
case 23: SetLkupStage(n, oMod, CLASS_TYPE_SORCERER, "cls_spell_sorc"); break;
|
||||
case 24: SetLkupStage(n, oMod, CLASS_TYPE_SUBLIME_CHORD, "cls_spell_schord"); break;
|
||||
case 25: SetLkupStage(n, oMod, CLASS_TYPE_SUEL_ARCHANAMACH, "cls_spell_suel"); break;
|
||||
case 26: SetLkupStage(n, oMod, CLASS_TYPE_VIGILANT, "cls_spell_vigil"); break;
|
||||
case 27: SetLkupStage(n, oMod, CLASS_TYPE_WARMAGE, "cls_spell_wrmage"); break;
|
||||
case 28: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_WEAVE, "cls_spell_kngtwv"); break;
|
||||
case 29: SetLkupStage(n, oMod, CLASS_TYPE_PSYCHIC_ROGUE, "cls_psipw_psyrog"); break;
|
||||
case 30: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWCASTER, "cls_myst_shdcst"); break;
|
||||
case 31: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWSMITH, "cls_myst_shdsmt"); break;
|
||||
case 32: SetLkupStage(n, oMod, CLASS_TYPE_CELEBRANT_SHARESS, "cls_spell_sharss"); break;
|
||||
case 14: SetLkupStage(n, oMod, CLASS_TYPE_BARD, "cls_spell_bard"); break;
|
||||
case 15: SetLkupStage(n, oMod, CLASS_TYPE_BEGUILER, "cls_spell_beguil"); break;
|
||||
case 16: SetLkupStage(n, oMod, CLASS_TYPE_DREAD_NECROMANCER, "cls_spell_dnecro"); break;
|
||||
case 17: SetLkupStage(n, oMod, CLASS_TYPE_DUSKBLADE, "cls_spell_duskbl"); break;
|
||||
case 18: SetLkupStage(n, oMod, CLASS_TYPE_FAVOURED_SOUL, "cls_spell_favsol"); break;
|
||||
case 19: SetLkupStage(n, oMod, CLASS_TYPE_HARPER, "cls_spell_harper"); break;
|
||||
case 20: SetLkupStage(n, oMod, CLASS_TYPE_HEXBLADE, "cls_spell_hexbl"); break;
|
||||
case 21: SetLkupStage(n, oMod, CLASS_TYPE_JUSTICEWW, "cls_spell_justww"); break;
|
||||
case 22: SetLkupStage(n, oMod, CLASS_TYPE_SORCERER, "cls_spell_sorc"); break;
|
||||
case 23: SetLkupStage(n, oMod, CLASS_TYPE_SUBLIME_CHORD, "cls_spell_schord"); break;
|
||||
case 24: SetLkupStage(n, oMod, CLASS_TYPE_SUEL_ARCHANAMACH, "cls_spell_suel"); break;
|
||||
case 25: SetLkupStage(n, oMod, CLASS_TYPE_VIGILANT, "cls_spell_vigil"); break;
|
||||
case 26: SetLkupStage(n, oMod, CLASS_TYPE_WARMAGE, "cls_spell_wrmage"); break;
|
||||
case 27: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_WEAVE, "cls_spell_kngtwv"); break;
|
||||
case 28: SetLkupStage(n, oMod, CLASS_TYPE_PSYCHIC_ROGUE, "cls_psipw_psyrog"); break;
|
||||
case 29: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWCASTER, "cls_myst_shdcst"); break;
|
||||
case 30: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWSMITH, "cls_myst_shdsmt"); break;
|
||||
case 31: SetLkupStage(n, oMod, CLASS_TYPE_CELEBRANT_SHARESS, "cls_spell_sharss"); break;
|
||||
|
||||
//:: These were all moved to the Bioware spellbooks -Jaysyn
|
||||
//case 14: SetLkupStage(n, oMod, CLASS_TYPE_ASSASSIN, "cls_spell_asasin"); break;
|
||||
//case 46: SetLkupStage(n, oMod, CLASS_TYPE_CULTIST_SHATTERED_PEAK, "cls_spell_cultst"); break;
|
||||
//case 40: SetLkupStage(n, oMod, CLASS_TYPE_NENTYAR_HUNTER, "cls_spell_hunter"); break;
|
||||
//case 28: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWLORD, "cls_spell_tfshad"); break;
|
||||
@ -528,7 +530,7 @@ int SpellToSpellbookID(int nSpell)
|
||||
int nOutSpellID = GetLocalInt(oWP, /*"PRC_GetRowFromSpellID_" + */IntToString(nSpell));
|
||||
if(nOutSpellID == 0)
|
||||
nOutSpellID = -1;
|
||||
//if(DEBUG) DoDebug("SpellToSpellbookID(" + IntToString(nSpell) + ", " + sFile + ") = " + IntToString(nOutSpellID));
|
||||
if(DEBUG) DoDebug("inc_lookup >> SpellToSpellbookID: (nSpell: " + IntToString(nSpell) + ") = nOutSpellID: " + IntToString(nOutSpellID));
|
||||
return nOutSpellID;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ Make cls_spcr_*.2da
|
||||
Make blank cls_spell_*.2da
|
||||
Add cls_spgn_*.2da to classes.2da
|
||||
Add class entry in prc_classes.2da
|
||||
Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level
|
||||
Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level (not needed for NWN:EE)
|
||||
Add class to PRCGetSpellSaveDC() in prc_add_spell_dc
|
||||
Add class to GetSpellbookTypeForClass() below
|
||||
Add class to GetAbilityScoreForClass() below
|
||||
@ -119,6 +119,7 @@ int GetSpellbookTypeForClass(int nClass)
|
||||
switch(nClass)
|
||||
{
|
||||
case CLASS_TYPE_ARCHIVIST:
|
||||
case CLASS_TYPE_ASSASSIN:
|
||||
case CLASS_TYPE_BLACKGUARD:
|
||||
case CLASS_TYPE_BLIGHTER:
|
||||
case CLASS_TYPE_CLERIC:
|
||||
@ -141,7 +142,6 @@ int GetSpellbookTypeForClass(int nClass)
|
||||
case CLASS_TYPE_VIGILANT:
|
||||
case CLASS_TYPE_WIZARD:
|
||||
return SPELLBOOK_TYPE_PREPARED;
|
||||
case CLASS_TYPE_ASSASSIN:
|
||||
case CLASS_TYPE_BARD:
|
||||
case CLASS_TYPE_BEGUILER:
|
||||
case CLASS_TYPE_CELEBRANT_SHARESS:
|
||||
@ -559,7 +559,7 @@ int bKnowsAllClassSpells(int nClass)
|
||||
{
|
||||
//case CLASS_TYPE_WIZARD:
|
||||
case CLASS_TYPE_ARCHIVIST:
|
||||
case CLASS_TYPE_ASSASSIN:
|
||||
//case CLASS_TYPE_ASSASSIN:
|
||||
case CLASS_TYPE_BARD:
|
||||
case CLASS_TYPE_CELEBRANT_SHARESS:
|
||||
case CLASS_TYPE_CULTIST_SHATTERED_PEAK:
|
||||
@ -580,7 +580,79 @@ int bKnowsAllClassSpells(int nClass)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC)
|
||||
{
|
||||
// If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either
|
||||
if(!GetSlotCount(nLevel, nSpellLevel, GetAbilityScoreForClass(nClass, oPC), nClass))
|
||||
{
|
||||
if(DEBUG) DoDebug("GetSpellKnownMaxCount: No slots available for " + IntToString(nClass) + " level " + IntToString(nLevel) + " circle " + IntToString(nSpellLevel));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nKnown;
|
||||
string sFile = Get2DACache("classes", "SpellKnownTable", nClass);
|
||||
string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1);
|
||||
|
||||
if(DEBUG)
|
||||
{
|
||||
DoDebug("GetSpellKnownMaxCount Details:");
|
||||
DoDebug("- Class: " + IntToString(nClass));
|
||||
DoDebug("- Passed Level: " + IntToString(nLevel));
|
||||
DoDebug("- Base Class Level: " + IntToString(GetLevelByClass(nClass, oPC)));
|
||||
DoDebug("- Effective Level: " + IntToString(GetSpellslotLevel(nClass, oPC)));
|
||||
DoDebug("- Spell Level: " + IntToString(nSpellLevel));
|
||||
DoDebug("- SpellKnownTable: " + sFile);
|
||||
DoDebug("- MaxKnown from 2DA: " + sKnown);
|
||||
}
|
||||
|
||||
if(sKnown == "")
|
||||
{
|
||||
nKnown = -1;
|
||||
if(DEBUG) DoDebug("GetSpellKnownMaxCount: Problem getting known numbers");
|
||||
}
|
||||
else
|
||||
nKnown = StringToInt(sKnown);
|
||||
|
||||
if(nKnown == -1)
|
||||
return 0;
|
||||
|
||||
// COMPLETELY REWROTE THIS SECTION
|
||||
// Bard and Sorcerer logic for prestige class advancement
|
||||
if(nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_BARD)
|
||||
{
|
||||
int baseClassLevel = GetLevelByClass(nClass, oPC);
|
||||
int effectiveLevel = GetSpellslotLevel(nClass, oPC);
|
||||
|
||||
// Debug the values we're checking
|
||||
if(DEBUG)
|
||||
{
|
||||
DoDebug("Spont caster check - Base level: " + IntToString(baseClassLevel) +
|
||||
", Effective level: " + IntToString(effectiveLevel));
|
||||
}
|
||||
|
||||
// If they have prestige class advancement OR special feats, they should get spells
|
||||
if(effectiveLevel > baseClassLevel ||
|
||||
GetHasFeat(FEAT_DRACONIC_GRACE, oPC) ||
|
||||
GetHasFeat(FEAT_DRACONIC_BREATH, oPC))
|
||||
{
|
||||
// Allow them to get spells - do nothing here, return nKnown at the end
|
||||
if(DEBUG) DoDebug("Spontaneous caster eligible for new spells");
|
||||
}
|
||||
else
|
||||
{
|
||||
// No advancement, no special feats - no new spells
|
||||
if(DEBUG) DoDebug("Spontaneous caster NOT eligible for new spells");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("Final spell known count: " + IntToString(nKnown));
|
||||
return nKnown;
|
||||
}
|
||||
|
||||
|
||||
/* int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC)
|
||||
{
|
||||
// If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either
|
||||
// @todo Check rules. There might be cases where this doesn't hold
|
||||
@ -588,22 +660,9 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC)
|
||||
return 0;
|
||||
int nKnown;
|
||||
string sFile;
|
||||
// Bioware casters use their classes.2da-specified tables
|
||||
/*if( nClass == CLASS_TYPE_WIZARD
|
||||
|| nClass == CLASS_TYPE_SORCERER
|
||||
|| nClass == CLASS_TYPE_BARD
|
||||
|| nClass == CLASS_TYPE_CLERIC
|
||||
|| nClass == CLASS_TYPE_DRUID
|
||||
|| nClass == CLASS_TYPE_PALADIN
|
||||
|| nClass == CLASS_TYPE_RANGER)
|
||||
{*/
|
||||
sFile = Get2DACache("classes", "SpellKnownTable", nClass);
|
||||
/*}
|
||||
else
|
||||
{
|
||||
sFile = Get2DACache("classes", "FeatsTable", nClass);
|
||||
sFile = "cls_spkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061231
|
||||
}*/
|
||||
|
||||
sFile = Get2DACache("classes", "SpellKnownTable", nClass);
|
||||
|
||||
|
||||
string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1);
|
||||
if(DEBUG) DoDebug("GetSpellKnownMaxCount(" + IntToString(nLevel) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ", " + GetName(oPC) + ") = " + sKnown);
|
||||
@ -626,6 +685,7 @@ int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC)
|
||||
}
|
||||
return nKnown;
|
||||
}
|
||||
*/
|
||||
|
||||
int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass)
|
||||
{
|
||||
@ -693,6 +753,44 @@ int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass)
|
||||
}
|
||||
|
||||
int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass)
|
||||
{
|
||||
// Get the lookup token created by MakeSpellbookLevelLoop()
|
||||
string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel);
|
||||
object oCache = GetObjectByTag(sTag);
|
||||
if(!GetIsObjectValid(oCache))
|
||||
{
|
||||
if(DEBUG) DoDebug("GetSpellUnknownCurrentCount: " + sTag + " is not valid");
|
||||
|
||||
// Add code to create the missing lookup object
|
||||
if(DEBUG) DoDebug("Attempting to create missing spell lookup token");
|
||||
ExecuteScript("prc_create_spellb", oPC);
|
||||
|
||||
// Try again after creating it
|
||||
oCache = GetObjectByTag(sTag);
|
||||
if(!GetIsObjectValid(oCache))
|
||||
{
|
||||
if(DEBUG) DoDebug("Still couldn't create spell lookup token");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DEBUG) DoDebug("Successfully created spell lookup token");
|
||||
}
|
||||
}
|
||||
|
||||
// Read the total number of spells on the given level and determine how many are already known
|
||||
int nTotal = array_get_size(oCache, "Lkup");
|
||||
int nKnown = GetSpellKnownCurrentCount(oPC, nSpellLevel, nClass);
|
||||
int nUnknown = nTotal - nKnown;
|
||||
|
||||
if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown));
|
||||
if(DEBUG) DoDebug(" Total spells in lookup: " + IntToString(nTotal) + ", Known spells: " + IntToString(nKnown));
|
||||
|
||||
return nUnknown;
|
||||
}
|
||||
|
||||
|
||||
/* int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass)
|
||||
{
|
||||
// Get the lookup token created by MakeSpellbookLevelLoop()
|
||||
string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel);
|
||||
@ -709,7 +807,7 @@ int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass)
|
||||
|
||||
if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown));
|
||||
return nUnknown;
|
||||
}
|
||||
} */
|
||||
|
||||
void AddSpellUse(object oPC, int nSpellbookID, int nClass, string sFile, string sArrayName, int nSpellbookType, object oSkin, int nFeatID, int nIPFeatID, string sIDX = "")
|
||||
{
|
||||
@ -850,7 +948,7 @@ void SetupSpells(object oPC, int nClass)
|
||||
int nAbility = GetAbilityScoreForClass(nClass, oPC);
|
||||
int nSpellbookType = GetSpellbookTypeForClass(nClass);
|
||||
|
||||
if(DEBUG) DoDebug("SetupSpells\n"
|
||||
if(DEBUG) DoDebug("SetupSpells()\n"
|
||||
+ "nClass = " + IntToString(nClass) + "\n"
|
||||
+ "nSpellslotLevel = " + IntToString(nLevel) + "\n"
|
||||
+ "nAbility = " + IntToString(nAbility) + "\n"
|
||||
@ -1178,7 +1276,7 @@ void CastSpontaneousSpell(int nClass, int bInstantSpell = FALSE)
|
||||
else if(GetLocalInt(OBJECT_SELF, "PRC_metamagic_state") == 1)
|
||||
SetLocalInt(OBJECT_SELF, "MetamagicFeatAdjust", 0);
|
||||
}
|
||||
|
||||
if (DEBUG) DoDebug("CastSpontaneousSpell(): nSpellLevel is: "+IntToString(nSpellLevel)+".");
|
||||
CheckSpontSlots(nClass, nSpellID, nSpellLevel);
|
||||
if(GetLocalInt(OBJECT_SELF, "NSB_Cast"))
|
||||
ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE));
|
||||
@ -1330,6 +1428,8 @@ void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGI
|
||||
|
||||
string sFile = GetFileForClass(nClass);
|
||||
int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
|
||||
|
||||
if (DEBUG) DoDebug("inc_newspellbook >> NewSpellbookSpell(): nSpellbookType is: "+IntToString(nSpellbookType)+".");
|
||||
|
||||
// Make sure the caster has uses of this spell remaining
|
||||
// 2009-9-20: Add metamagic feat abilities. -N-S
|
||||
@ -1371,13 +1471,14 @@ void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGI
|
||||
else if(nSpellLevel > 9)//now test the spell level
|
||||
{
|
||||
nMetamagic = METAMAGIC_NONE;
|
||||
ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is to high! Casting spell without metamagic"));
|
||||
ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is too high! Casting spell without metamagic"));
|
||||
nSpellLevel = nSpellSlotLevel;
|
||||
}
|
||||
else if(GetLocalInt(oPC, "PRC_metamagic_state") == 1)
|
||||
SetLocalInt(oPC, "MetamagicFeatAdjust", 0);
|
||||
}
|
||||
|
||||
|
||||
if (DEBUG) DoDebug("inc_newspellbook >> NewSpellbookSpell(): nSpellLevel is: "+IntToString(nSpellLevel)+".");
|
||||
CheckSpontSlots(nClass, nSpellID, nSpellLevel);
|
||||
if(GetLocalInt(oPC, "NSB_Cast"))
|
||||
ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE));
|
||||
@ -1460,7 +1561,7 @@ void CheckPrepSlots(int nClass, int nSpellID, int nSpellbookID, int bIsAction =
|
||||
{
|
||||
DeleteLocalInt(OBJECT_SELF, "NSB_Cast");
|
||||
int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellbookID);
|
||||
if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellbookID) + "] = " + IntToString(nCount));
|
||||
if(DEBUG) DoDebug("NewSpellbookSpell >> CheckPrepSlots: NewSpellbookMem_" + IntToString(nClass) + "[SpellbookID: " + IntToString(nSpellbookID) + "] = " + IntToString(nCount));
|
||||
if(nCount < 1)
|
||||
{
|
||||
string sSpellName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
|
||||
@ -1486,7 +1587,7 @@ void CheckSpontSlots(int nClass, int nSpellID, int nSpellSlotLevel, int bIsActio
|
||||
{
|
||||
DeleteLocalInt(OBJECT_SELF, "NSB_Cast");
|
||||
int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellSlotLevel);
|
||||
if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellSlotLevel) + "] = " + IntToString(nCount));
|
||||
if(DEBUG) DoDebug("NewSpellbookSpell >> CheckSpontSlots: NewSpellbookMem_" + IntToString(nClass) + "[SpellSlotLevel: " + IntToString(nSpellSlotLevel) + "] = " + IntToString(nCount));
|
||||
if(nCount < 1)
|
||||
{
|
||||
// "You have no castings of spells of level " + IntToString(nSpellLevel) + " remaining"
|
||||
|
@ -720,7 +720,7 @@ void SetDefaultFileEnds()
|
||||
SetPRCSwitch("PRC_FILE_END_polymorph", 155);
|
||||
SetPRCSwitch("PRC_FILE_END_portraits", 1300);
|
||||
SetPRCSwitch("PRC_FILE_END_prc_craft_alchem", 37);
|
||||
SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 204);
|
||||
SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 253);
|
||||
SetPRCSwitch("PRC_FILE_END_prc_craft_poison", 62);
|
||||
SetPRCSwitch("PRC_FILE_END_prc_domains", 59);
|
||||
SetPRCSwitch("PRC_FILE_END_prc_familiar", 10);
|
||||
@ -767,7 +767,7 @@ void SetDefaultFileEnds()
|
||||
SetPRCSwitch("PRC_FILE_END_soundset", 453);
|
||||
SetPRCSwitch("PRC_FILE_END_soundsettype", 4);
|
||||
SetPRCSwitch("PRC_FILE_END_soundtypes", 1);
|
||||
SetPRCSwitch("PRC_FILE_END_spells", 19348);
|
||||
SetPRCSwitch("PRC_FILE_END_spells", 19400);
|
||||
//SetPRCSwitch("PRC_FILE_END_spellschools", 9);
|
||||
SetPRCSwitch("PRC_FILE_END_statescripts", 35);
|
||||
SetPRCSwitch("PRC_FILE_END_stringtokens", 92);
|
||||
@ -1069,14 +1069,16 @@ void CreateSwitchNameArray()
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_ROD_CASTER_LEVEL);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_STAFF_CASTER_LEVEL);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_BASE_ITEMS);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_MAXLEVEL);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_COSTMODIFIER);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_SCRIBESCROLL_COSTMODIFIER);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_MAXLEVEL);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_COSTMODIFIER);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_MAXLEVEL);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_COSTMODIFIER);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_SCRIBESCROLL_COSTMODIFIER);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_MAXLEVEL);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_COSTMODIFIER);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CREATEINFUSION_COSTMODIFIER);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_ARBITRARY);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_COST_SCALE);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_TIME_SCALE);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CREATE_INFUSION_CASTER_LEVEL);
|
||||
|
||||
//spells
|
||||
|
||||
|
@ -1182,7 +1182,7 @@ int GetMaxEssentiaCapacityFeat(object oMeldshaper)
|
||||
// Don't allow more than they have
|
||||
if (nMax > GetTotalUsableEssentia(oMeldshaper)) nMax = GetTotalUsableEssentia(oMeldshaper);
|
||||
|
||||
//if (DEBUG) DoDebug("GetMaxEssentiaCapacityFeat: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax));
|
||||
if(DEBUG) DoDebug("GetMaxEssentiaCapacityFeat: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax));
|
||||
return nMax;
|
||||
}
|
||||
|
||||
|
623
src/include/nw_inc_gff.nss
Normal file
623
src/include/nw_inc_gff.nss
Normal file
@ -0,0 +1,623 @@
|
||||
// This is a helper library for advanced use: It allows constructing arbitrary gff data.
|
||||
// You can then spawn your object via JsonToObject().
|
||||
//
|
||||
// The data format is the same as https://github.com/niv/neverwinter.nim@1.4.3+.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// json j = GffCreateObject(OBJECT_TYPE_ITEM);
|
||||
// j = GffAddInt(j, "BaseItem", BASE_ITEM_BELT);
|
||||
// j = GffAddInt(j, "ModelPart1", 12);
|
||||
// j = GffAddLocString(j, "LocalizedName", "hi!");
|
||||
// object belt = JsonToObject(j, GetLocation(OBJECT_SELF));
|
||||
|
||||
|
||||
const string GFF_FIELD_TYPE_STRUCT = "struct";
|
||||
const string GFF_FIELD_TYPE_LIST = "list";
|
||||
const string GFF_FIELD_TYPE_BYTE = "byte";
|
||||
const string GFF_FIELD_TYPE_CHAR = "char";
|
||||
const string GFF_FIELD_TYPE_WORD = "word";
|
||||
const string GFF_FIELD_TYPE_SHORT = "short";
|
||||
const string GFF_FIELD_TYPE_DWORD = "dword";
|
||||
const string GFF_FIELD_TYPE_INT = "int";
|
||||
const string GFF_FIELD_TYPE_DWORD64 = "dword64";
|
||||
const string GFF_FIELD_TYPE_INT64 = "int64";
|
||||
const string GFF_FIELD_TYPE_FLOAT = "float";
|
||||
const string GFF_FIELD_TYPE_DOUBLE = "double";
|
||||
const string GFF_FIELD_TYPE_RESREF = "resref";
|
||||
const string GFF_FIELD_TYPE_STRING = "cexostring";
|
||||
const string GFF_FIELD_TYPE_LOC_STRING = "cexolocstring";
|
||||
|
||||
|
||||
// Create a empty object of the given type. You need to manually fill in all
|
||||
// GFF data with GffAddXXX. This will require understanding of the GFF file format
|
||||
// and what data fields each object type requires.
|
||||
json GffCreateObject(int nObjectType);
|
||||
// Create a combined area format(CAF) object. You need to manually create the ARE and GIT objects with their required data fields.
|
||||
json GffCreateArea(json jARE, json jGIT);
|
||||
|
||||
// Returns the OBJECT_TYPE_* of jGff.
|
||||
// Note: Will return 0 for invalid object types, including areas.
|
||||
int GffGetObjectType(json jGff);
|
||||
// Returns TRUE if jGff is a combined area format(CAF) object.
|
||||
int GffGetIsArea(json jGff);
|
||||
|
||||
// Returns TRUE if a field named sLabel of sType exists in jGff.
|
||||
// * sLabel: Can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details.
|
||||
// * sType: An optional GFF_FIELD_TYPE_*, leave empty to check if sLabel exists regardless of type.
|
||||
int GffGetFieldExists(json jGff, string sLabel, string sType = "");
|
||||
|
||||
|
||||
// Add a new field, will overwrite any existing fields with the same label even if the type is different.
|
||||
// Returns a json null value on error with GetJsonError() filled in.
|
||||
//
|
||||
// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details.
|
||||
// For example, to add the tag of an area to an empty combined area format(CAF) object you can do the following:
|
||||
// json jArea = GffCreateArea(JsonObject(), JsonObject());
|
||||
// jArea = GffAddString(jArea, "ARE/value/Tag", "AREA_TAG");
|
||||
|
||||
json GffAddStruct(json jGff, string sLabel, json jStruct, int nType = -1);
|
||||
json GffAddList(json jGff, string sLabel, json jList);
|
||||
json GffAddByte(json jGff, string sLabel, int v);
|
||||
json GffAddChar(json jGff, string sLabel, int v);
|
||||
json GffAddWord(json jGff, string sLabel, int v);
|
||||
json GffAddShort(json jGff, string sLabel, int v);
|
||||
// Note: Only data of type int32 will fit, because that's all that NWScript supports.
|
||||
json GffAddDword(json jGff, string sLabel, int v);
|
||||
json GffAddInt(json jGff, string sLabel, int v);
|
||||
// Note: Only data of type int32 will fit, because that's all that NWScript supports.
|
||||
json GffAddDword64(json jGff, string sLabel, int v);
|
||||
// Note: Only data of type int32 will fit, because that's all that NWScript supports.
|
||||
json GffAddInt64(json jGff, string sLabel, int v);
|
||||
json GffAddFloat(json jGff, string sLabel, float v);
|
||||
// Note: Only data of type float will fit, because that's all that NWScript supports.
|
||||
json GffAddDouble(json jGff, string sLabel, float v);
|
||||
json GffAddResRef(json jGff, string sLabel, string v);
|
||||
json GffAddString(json jGff, string sLabel, string v);
|
||||
json GffAddLocString(json jGff, string sLabel, string v, int nStrRef = -1);
|
||||
|
||||
|
||||
// Replace a field, the type must match and the field must exist.
|
||||
// Returns a json null value on error with GetJsonError() filled in.
|
||||
//
|
||||
// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details.
|
||||
// For example, to replace the name of an area in a combined area format(CAF) object you can do the following:
|
||||
// json jArea = ObjectToStruct(GetFirstArea());
|
||||
// jArea = GffReplaceLocString(jArea, "ARE/value/Name", "New Area Name");
|
||||
|
||||
json GffReplaceStruct(json jGff, string sLabel, json jStruct);
|
||||
json GffReplaceList(json jGff, string sLabel, json jList);
|
||||
json GffReplaceByte(json jGff, string sLabel, int v);
|
||||
json GffReplaceChar(json jGff, string sLabel, int v);
|
||||
json GffReplaceWord(json jGff, string sLabel, int v);
|
||||
json GffReplaceShort(json jGff, string sLabel, int v);
|
||||
// Note: Only data of type int32 will fit, because that's all that NWScript supports.
|
||||
json GffReplaceDword(json jGff, string sLabel, int v);
|
||||
json GffReplaceInt(json jGff, string sLabel, int v);
|
||||
// Note: Only data of type int32 will fit, because that's all that NWScript supports.
|
||||
json GffReplaceDword64(json jGff, string sLabel, int v);
|
||||
// Note: Only data of type int32 will fit, because that's all that NWScript supports.
|
||||
json GffReplaceInt64(json jGff, string sLabel, int v);
|
||||
json GffReplaceFloat(json jGff, string sLabel, float v);
|
||||
// Note: Only data of type float will fit, because that's all that NWScript supports.
|
||||
json GffReplaceDouble(json jGff, string sLabel, float v);
|
||||
json GffReplaceResRef(json jGff, string sLabel, string v);
|
||||
json GffReplaceString(json jGff, string sLabel, string v);
|
||||
json GffReplaceLocString(json jGff, string sLabel, string v, int nStrRef = -1);
|
||||
|
||||
|
||||
// Remove a field, the type must match and the field must exist.
|
||||
// Returns a json null value on error with GetJsonError() filled in.
|
||||
//
|
||||
// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details.
|
||||
// For example, to remove all placeables from an area in a combined area format(CAF) object you can do the following:
|
||||
// json jArea = ObjectToStruct(GetFirstArea());
|
||||
// jArea = GffRemoveList(jArea, "GIT/value/Placeable List");
|
||||
|
||||
json GffRemoveStruct(json jGff, string sLabel);
|
||||
json GffRemoveList(json jGff, string sLabel);
|
||||
json GffRemoveByte(json jGff, string sLabel);
|
||||
json GffRemoveChar(json jGff, string sLabel);
|
||||
json GffRemoveWord(json jGff, string sLabel);
|
||||
json GffRemoveShort(json jGff, string sLabel);
|
||||
json GffRemoveDword(json jGff, string sLabel);
|
||||
json GffRemoveInt(json jGff, string sLabel);
|
||||
json GffRemoveDword64(json jGff, string sLabel);
|
||||
json GffRemoveInt64(json jGff, string sLabel);
|
||||
json GffRemoveFloat(json jGff, string sLabel);
|
||||
json GffRemoveDouble(json jGff, string sLabel);
|
||||
json GffRemoveResRef(json jGff, string sLabel);
|
||||
json GffRemoveString(json jGff, string sLabel);
|
||||
json GffRemoveLocString(json jGff, string sLabel);
|
||||
|
||||
|
||||
// Get a field's value as json object.
|
||||
// Returns a json null value on error with GetJsonError() filled in.
|
||||
//
|
||||
// Note: Json types do not implicitly convert between types, this means you cannot convert a JsonInt to a string with JsonGetString(), etc.
|
||||
// You may need to check the type with JsonGetType() and then do the appropriate cast yourself.
|
||||
// For GffGet*() functions the json type returned is noted in the function description.
|
||||
//
|
||||
// Example:
|
||||
// INCORRECT: string s = JsonGetString(GffGetInt());
|
||||
// CORRECT: string s = IntToString(JsonGetInt(GffGetInt()));
|
||||
//
|
||||
// sLabel can be a json pointer(path) without the starting /, see the documentation of JsonPointer() for details.
|
||||
// For example, to get the resref of an area in a combined area format(CAF) object you can do the following:
|
||||
// json jResRef = GffGetResRef(ObjectToStruct(GetFirstArea()), "ARE/value/ResRef");
|
||||
// if (jResRef != JsonNull())
|
||||
// {
|
||||
// string sResRef = JsonGetString(jResRef);
|
||||
// }
|
||||
// else
|
||||
// WriteTimestampedLogEntry("Failed to get area ResRef: " + JsonGetError(jResRef));
|
||||
|
||||
// Returns the struct as JsonObject() on success.
|
||||
json GffGetStruct(json jGff, string sLabel);
|
||||
// Returns a JsonArray() with all the list elements on success.
|
||||
json GffGetList(json jGff, string sLabel);
|
||||
// Returns a JsonInt() on success.
|
||||
json GffGetByte(json jGff, string sLabel);
|
||||
// Returns a JsonInt() on success.
|
||||
json GffGetChar(json jGff, string sLabel);
|
||||
// Returns a JsonInt() on success.
|
||||
json GffGetWord(json jGff, string sLabel);
|
||||
// Returns a JsonInt() on success.
|
||||
json GffGetShort(json jGff, string sLabel);
|
||||
// Returns a JsonInt() on success.
|
||||
json GffGetDword(json jGff, string sLabel);
|
||||
// Returns a JsonInt() on success.
|
||||
json GffGetInt(json jGff, string sLabel);
|
||||
// Returns a JsonInt() on success.
|
||||
json GffGetDword64(json jGff, string sLabel);
|
||||
// Returns a JsonInt() on success.
|
||||
json GffGetInt64(json jGff, string sLabel);
|
||||
// Returns a JsonFloat() on success.
|
||||
json GffGetFloat(json jGff, string sLabel);
|
||||
// Returns a JsonFloat() on success.
|
||||
json GffGetDouble(json jGff, string sLabel);
|
||||
// Returns a JsonString() on success.
|
||||
json GffGetResRef(json jGff, string sLabel);
|
||||
// Returns a JsonString() on success.
|
||||
json GffGetString(json jGff, string sLabel);
|
||||
// Returns a JsonObject() on success.
|
||||
// Key "0" will have a JsonString() with the string, if set.
|
||||
// Key "id" will have a JsonInt() with the strref, if set.
|
||||
json GffGetLocString(json jGff, string sLabel);
|
||||
|
||||
|
||||
// *** Internal Helper Functions
|
||||
json AddPatchOperation(json jPatchArray, string sOp, string sPath, json jValue)
|
||||
{
|
||||
json jOperation = JsonObject();
|
||||
jOperation = JsonObjectSet(jOperation, "op", JsonString(sOp));
|
||||
jOperation = JsonObjectSet(jOperation, "path", JsonString(sPath));
|
||||
jOperation = JsonObjectSet(jOperation, "value", jValue);
|
||||
return JsonArrayInsert(jPatchArray, jOperation);
|
||||
}
|
||||
|
||||
json GffAddField(json jGff, string sLabel, string sType, json jValue, int nType = -1)
|
||||
{
|
||||
json jField = JsonObject();
|
||||
jField = JsonObjectSet(jField, "type", JsonString(sType));
|
||||
jField = JsonObjectSet(jField, "value", jValue);
|
||||
if (sType == GFF_FIELD_TYPE_STRUCT && nType != -1)
|
||||
jField = JsonObjectSet(jField, "__struct_id", JsonInt(nType));
|
||||
|
||||
return JsonPatch(jGff, AddPatchOperation(JsonArray(), "add", "/" + sLabel, jField));
|
||||
}
|
||||
|
||||
json GffReplaceField(json jGff, string sLabel, string sType, json jValue)
|
||||
{
|
||||
json jPatch = JsonArray();
|
||||
jPatch = AddPatchOperation(jPatch, "test", "/" + sLabel + "/type", JsonString(sType));
|
||||
jPatch = AddPatchOperation(jPatch, "replace", "/" + sLabel + "/value", jValue);
|
||||
return JsonPatch(jGff, jPatch);
|
||||
}
|
||||
|
||||
json GffRemoveField(json jGff, string sLabel, string sType)
|
||||
{
|
||||
json jPatch = JsonArray();
|
||||
jPatch = AddPatchOperation(jPatch, "test", "/" + sLabel + "/type", JsonString(sType));
|
||||
jPatch = AddPatchOperation(jPatch, "remove", "/" + sLabel, JsonNull());
|
||||
return JsonPatch(jGff, jPatch);
|
||||
}
|
||||
|
||||
json GffGetFieldType(json jGff, string sLabel)
|
||||
{
|
||||
return JsonPointer(jGff, "/" + sLabel + "/type");
|
||||
}
|
||||
|
||||
json GffGetFieldValue(json jGff, string sLabel)
|
||||
{
|
||||
return JsonPointer(jGff, "/" + sLabel + "/value");
|
||||
}
|
||||
|
||||
json GffGetField(json jGff, string sLabel, string sType)
|
||||
{
|
||||
json jType = GffGetFieldType(jGff, sLabel);
|
||||
if (jType == JsonNull())
|
||||
return jType;
|
||||
else if (jType != JsonString(sType))
|
||||
return JsonNull("field type does not match");
|
||||
else
|
||||
return GffGetFieldValue(jGff, sLabel);
|
||||
}
|
||||
|
||||
json GffLocString(string v, int nStrRef = -1)
|
||||
{
|
||||
json jLocString = JsonObject();
|
||||
if (v != "")
|
||||
jLocString = JsonObjectSet(jLocString, "0", JsonString(v)); // english/any
|
||||
if (nStrRef != -1)
|
||||
jLocString = JsonObjectSet(jLocString, "id", JsonInt(nStrRef));
|
||||
|
||||
return jLocString;
|
||||
}
|
||||
//***
|
||||
|
||||
json GffCreateObject(int nObjectType)
|
||||
{
|
||||
string ot;
|
||||
if (nObjectType == OBJECT_TYPE_CREATURE) ot = "UTC ";
|
||||
else if (nObjectType == OBJECT_TYPE_ITEM) ot = "UTI ";
|
||||
else if (nObjectType == OBJECT_TYPE_TRIGGER) ot = "UTT ";
|
||||
else if (nObjectType == OBJECT_TYPE_DOOR) ot = "UTD ";
|
||||
else if (nObjectType == OBJECT_TYPE_WAYPOINT) ot = "UTW ";
|
||||
else if (nObjectType == OBJECT_TYPE_PLACEABLE) ot = "UTP ";
|
||||
else if (nObjectType == OBJECT_TYPE_STORE) ot = "UTM ";
|
||||
else if (nObjectType == OBJECT_TYPE_ENCOUNTER) ot = "UTE ";
|
||||
|
||||
if (ot == "") return JsonNull("invalid object type");
|
||||
|
||||
json ret = JsonObject();
|
||||
ret = JsonObjectSet(ret, "__data_type", JsonString(ot));
|
||||
return ret;
|
||||
}
|
||||
|
||||
json GffCreateArea(json jARE, json jGIT)
|
||||
{
|
||||
json jCAF = JsonObject();
|
||||
jCAF = JsonObjectSet(jCAF, "__data_type", JsonString("CAF "));
|
||||
jCAF = GffAddStruct(jCAF, "ARE", jARE, 0);
|
||||
jCAF = GffAddStruct(jCAF, "GIT", jGIT, 1);
|
||||
return jCAF;
|
||||
}
|
||||
|
||||
|
||||
int GffGetObjectType(json jGff)
|
||||
{
|
||||
json jDataType = JsonObjectGet(jGff, "__data_type");
|
||||
if (jDataType == JsonNull())
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
string sObjectType = JsonGetString(jDataType);
|
||||
|
||||
if (sObjectType == "UTC ") return OBJECT_TYPE_CREATURE;
|
||||
else if (sObjectType == "UTI ") return OBJECT_TYPE_ITEM;
|
||||
else if (sObjectType == "UTT ") return OBJECT_TYPE_TRIGGER;
|
||||
else if (sObjectType == "UTD ") return OBJECT_TYPE_DOOR;
|
||||
else if (sObjectType == "UTW ") return OBJECT_TYPE_WAYPOINT;
|
||||
else if (sObjectType == "UTP ") return OBJECT_TYPE_PLACEABLE;
|
||||
else if (sObjectType == "UTM ") return OBJECT_TYPE_STORE;
|
||||
else if (sObjectType == "UTE ") return OBJECT_TYPE_ENCOUNTER;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GffGetIsArea(json jGff)
|
||||
{
|
||||
return JsonObjectGet(jGff, "__data_type") == JsonString("CAF ");
|
||||
}
|
||||
|
||||
int GffGetFieldExists(json jGff, string sLabel, string sType = "")
|
||||
{
|
||||
json jFieldType = GffGetFieldType(jGff, sLabel);
|
||||
return sType == "" ? jFieldType != JsonNull() : jFieldType == JsonString(sType);
|
||||
}
|
||||
|
||||
|
||||
json GffAddStruct(json jGff, string sLabel, json jStruct, int nType = -1)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT, jStruct, nType);
|
||||
}
|
||||
|
||||
json GffAddList(json jGff, string sLabel, json jList)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_LIST, jList);
|
||||
}
|
||||
|
||||
json GffAddByte(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_BYTE, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffAddChar(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_CHAR, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffAddWord(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_WORD, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffAddShort(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_SHORT, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffAddDword(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DWORD, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffAddInt(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_INT, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffAddDword64(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffAddInt64(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_INT64, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffAddFloat(json jGff, string sLabel, float v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT, JsonFloat(v));
|
||||
}
|
||||
|
||||
json GffAddDouble(json jGff, string sLabel, float v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE, JsonFloat(v));
|
||||
}
|
||||
|
||||
json GffAddResRef(json jGff, string sLabel, string v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_RESREF, JsonString(v));
|
||||
}
|
||||
|
||||
json GffAddString(json jGff, string sLabel, string v)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_STRING, JsonString(v));
|
||||
}
|
||||
|
||||
json GffAddLocString(json jGff, string sLabel, string v, int nStrRef = -1)
|
||||
{
|
||||
return GffAddField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING, GffLocString(v, nStrRef));
|
||||
}
|
||||
|
||||
|
||||
json GffReplaceStruct(json jGff, string sLabel, json jStruct)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT, jStruct);
|
||||
}
|
||||
|
||||
json GffReplaceList(json jGff, string sLabel, json jList)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_LIST, jList);
|
||||
}
|
||||
|
||||
json GffReplaceByte(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_BYTE, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffReplaceChar(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_CHAR, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffReplaceWord(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_WORD, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffReplaceShort(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_SHORT, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffReplaceDword(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DWORD, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffReplaceInt(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_INT, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffReplaceDword64(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffReplaceInt64(json jGff, string sLabel, int v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_INT64, JsonInt(v));
|
||||
}
|
||||
|
||||
json GffReplaceFloat(json jGff, string sLabel, float v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT, JsonFloat(v));
|
||||
}
|
||||
|
||||
json GffReplaceDouble(json jGff, string sLabel, float v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE, JsonFloat(v));
|
||||
}
|
||||
|
||||
json GffReplaceResRef(json jGff, string sLabel, string v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_RESREF, JsonString(v));
|
||||
}
|
||||
|
||||
json GffReplaceString(json jGff, string sLabel, string v)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_STRING, JsonString(v));
|
||||
}
|
||||
|
||||
json GffReplaceLocString(json jGff, string sLabel, string v, int nStrRef = -1)
|
||||
{
|
||||
return GffReplaceField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING, GffLocString(v, nStrRef));
|
||||
}
|
||||
|
||||
|
||||
json GffRemoveStruct(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT);
|
||||
}
|
||||
|
||||
json GffRemoveList(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_LIST);
|
||||
}
|
||||
|
||||
json GffRemoveByte(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_BYTE);
|
||||
}
|
||||
|
||||
json GffRemoveChar(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_CHAR);
|
||||
}
|
||||
|
||||
json GffRemoveWord(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_WORD);
|
||||
}
|
||||
|
||||
json GffRemoveShort(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_SHORT);
|
||||
}
|
||||
|
||||
json GffRemoveDword(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DWORD);
|
||||
}
|
||||
|
||||
json GffRemoveInt(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_INT);
|
||||
}
|
||||
|
||||
json GffRemoveDword64(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64);
|
||||
}
|
||||
|
||||
json GffRemoveInt64(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_INT64);
|
||||
}
|
||||
|
||||
json GffRemoveFloat(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT);
|
||||
}
|
||||
|
||||
json GffRemoveDouble(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE);
|
||||
}
|
||||
|
||||
json GffRemoveResRef(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_RESREF);
|
||||
}
|
||||
|
||||
json GffRemoveString(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_STRING);
|
||||
}
|
||||
|
||||
json GffRemoveLocString(json jGff, string sLabel)
|
||||
{
|
||||
return GffRemoveField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING);
|
||||
}
|
||||
|
||||
|
||||
json GffGetStruct(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_STRUCT);
|
||||
}
|
||||
|
||||
json GffGetList(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_LIST);
|
||||
}
|
||||
|
||||
json GffGetByte(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_BYTE);
|
||||
}
|
||||
|
||||
json GffGetChar(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_CHAR);
|
||||
}
|
||||
|
||||
json GffGetWord(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_WORD);
|
||||
}
|
||||
|
||||
json GffGetShort(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_SHORT);
|
||||
}
|
||||
|
||||
json GffGetDword(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DWORD);
|
||||
}
|
||||
|
||||
json GffGetInt(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_INT);
|
||||
}
|
||||
|
||||
json GffGetDword64(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DWORD64);
|
||||
}
|
||||
|
||||
json GffGetInt64(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_INT64);
|
||||
}
|
||||
|
||||
json GffGetFloat(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_FLOAT);
|
||||
}
|
||||
|
||||
json GffGetDouble(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_DOUBLE);
|
||||
}
|
||||
|
||||
json GffGetResRef(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_RESREF);
|
||||
}
|
||||
|
||||
json GffGetString(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_STRING);
|
||||
}
|
||||
|
||||
json GffGetLocString(json jGff, string sLabel)
|
||||
{
|
||||
return GffGetField(jGff, sLabel, GFF_FIELD_TYPE_LOC_STRING);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -513,6 +513,8 @@ int PRCGetSpellSaveDC(int nSpellID = -1, int nSchool = -1, object oCaster = OBJE
|
||||
|
||||
if(nClass == CLASS_TYPE_BARD)
|
||||
nDC += StringToInt(Get2DACache("Spells", "Bard", nSpellID));
|
||||
else if(nClass == CLASS_TYPE_ASSASSIN)
|
||||
nDC += StringToInt(Get2DACache("Spells", "Assassin", nSpellID));
|
||||
else if(nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_UR_PRIEST || nClass == CLASS_TYPE_OCULAR)
|
||||
nDC += StringToInt(Get2DACache("Spells", "Cleric", nSpellID));
|
||||
else if(nClass == CLASS_TYPE_DRUID)
|
||||
|
@ -143,7 +143,7 @@ const int CLASS_TYPE_MASTER_HARPER = 176;
|
||||
const int CLASS_TYPE_FRE_BERSERKER = 177;
|
||||
const int CLASS_TYPE_TEMPEST = 178;
|
||||
const int CLASS_TYPE_FOE_HUNTER = 179;
|
||||
//:: Free = 180
|
||||
const int CLASS_TYPE_VERDANT_LORD = 180;
|
||||
const int CLASS_TYPE_ORC_WARLORD = 181;
|
||||
const int CLASS_TYPE_THRALL_OF_GRAZZT_A = 182;
|
||||
const int CLASS_TYPE_NECROCARNATE = 183;
|
||||
@ -162,7 +162,7 @@ const int CLASS_TYPE_MASTER_OF_NINE = 195;
|
||||
const int CLASS_TYPE_ETERNAL_BLADE = 196;
|
||||
const int CLASS_TYPE_SHADOW_SUN_NINJA = 197;
|
||||
const int CLASS_TYPE_WITCHBORN_BINDER = 198;
|
||||
const int CLASS_TYPE_BAELNORN = 199;
|
||||
const int CLASS_TYPE_LION_OF_TALISID = 199;
|
||||
const int CLASS_TYPE_DISCIPLE_OF_MEPH = 200;
|
||||
const int CLASS_TYPE_SOUL_EATER = 201;
|
||||
const int CLASS_TYPE_HENSHIN_MYSTIC = 202;
|
||||
@ -236,6 +236,7 @@ const int CLASS_TYPE_WITCH = -1;
|
||||
const int CLASS_TYPE_TEMPLAR = -1;
|
||||
const int CLASS_TYPE_MYSTIC = -1;
|
||||
const int CLASS_TYPE_NOBLE = -1;
|
||||
const int CLASS_TYPE_BAELNORN = -2;
|
||||
|
||||
|
||||
//void main (){}
|
@ -75,6 +75,13 @@ void DeathlessFrenzyCheck(object oTarget);
|
||||
// * PRC Version of a Bioware function to disable include loops
|
||||
void PRCRemoveSpellEffects(int nSpell_ID, object oCaster, object oTarget);
|
||||
|
||||
/**
|
||||
* Target is immune to gaze attacks
|
||||
*
|
||||
* @return the Dazzle effect
|
||||
*/
|
||||
effect EffectGazeImmune();
|
||||
|
||||
/**
|
||||
* Dazzles the target: -1 Attack, Search, Spot, and VFX
|
||||
*
|
||||
@ -583,7 +590,8 @@ effect PRCEffectHeal(int nHP, object oTarget)
|
||||
return EffectHeal(nHP);
|
||||
}
|
||||
|
||||
effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1){
|
||||
effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1)
|
||||
{
|
||||
effect eReturn;
|
||||
switch(iAbility)
|
||||
{
|
||||
@ -639,7 +647,8 @@ effect EffectAbilityBasedSkillIncrease(int iAbility, int iIncrease = 1){
|
||||
return eReturn;
|
||||
}
|
||||
|
||||
effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1){
|
||||
effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1)
|
||||
{
|
||||
effect eReturn;
|
||||
switch(iAbility)
|
||||
{
|
||||
@ -695,7 +704,8 @@ effect EffectAbilityBasedSkillDecrease(int iAbility, int iDecrease = 1){
|
||||
return eReturn;
|
||||
}
|
||||
|
||||
effect EffectDamageImmunityAll(){
|
||||
effect EffectDamageImmunityAll()
|
||||
{
|
||||
effect eReturn = EffectDamageImmunityIncrease(DAMAGE_TYPE_ACID, 100);
|
||||
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, 100));
|
||||
eReturn = EffectLinkEffects(eReturn, EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, 100));
|
||||
@ -712,7 +722,8 @@ effect EffectDamageImmunityAll(){
|
||||
return eReturn;
|
||||
}
|
||||
|
||||
effect EffectImmunityMiscAll(){
|
||||
effect EffectImmunityMiscAll()
|
||||
{
|
||||
effect eReturn = EffectImmunity(IMMUNITY_TYPE_ABILITY_DECREASE);
|
||||
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_BLINDNESS));
|
||||
eReturn = EffectLinkEffects(eReturn, EffectImmunity(IMMUNITY_TYPE_DEAFNESS));
|
||||
@ -732,6 +743,31 @@ effect EffectImmunityMiscAll(){
|
||||
return eReturn;
|
||||
}
|
||||
|
||||
//:: Immunity to all gaze attacks
|
||||
effect EffectGazeImmune()
|
||||
{
|
||||
effect eBlank;
|
||||
|
||||
effect eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_CHARM);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_CONFUSION);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DAZE);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DEATH);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_CHAOS);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_EVIL);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_GOOD);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DESTROY_LAW);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DOMINATE);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_DOOM);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_FEAR);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_PARALYSIS);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_PETRIFY);
|
||||
eReturn = EffectSpellImmunity(SPELLABILITY_GAZE_STUNNED);
|
||||
|
||||
eReturn = TagEffect(eReturn, "PRCGazeImmune");
|
||||
|
||||
return eReturn;
|
||||
}
|
||||
|
||||
int GetIsShaken(object oTarget)
|
||||
{
|
||||
effect eEffect = GetFirstEffect(oTarget);
|
||||
@ -747,4 +783,7 @@ int GetIsShaken(object oTarget)
|
||||
eEffect = GetNextEffect(oTarget);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//:: Test void
|
||||
//:: void main() {}
|
@ -152,6 +152,9 @@ const int FEAT_EPIC_DIAMOND_DRAGON = 25115;
|
||||
const int FEAT_EPIC_CRUSADER = 25116;
|
||||
const int FEAT_EPIC_SWORDSAGE = 25117;
|
||||
const int FEAT_EPIC_WARBLADE = 25118;
|
||||
const int FEAT_EPIC_LION_OF_TALISID = 25600;
|
||||
const int FEAT_EPIC_VERDANT_LORD = 25618;
|
||||
|
||||
|
||||
//:: Vile Martial Strike Expansion
|
||||
const int FEAT_VILE_MARTIAL_EAGLE_CLAW = 24800;
|
||||
@ -195,6 +198,28 @@ const int FEAT_CHARMING_THE_ARROW = 25998;
|
||||
//:: Skill Based Feats
|
||||
const int FEAT_JUMP = 2884;
|
||||
|
||||
//:: Lion of Talisid
|
||||
const int FEAT_LOT_LIONS_COURAGE = 25614;
|
||||
const int FEAT_LOT_LIONS_POUNCE = 25615;
|
||||
const int FEAT_LOT_LIONS_SWIFTNESS = 25616;
|
||||
const int FEAT_LOT_LEONALS_ROAR = 25617;
|
||||
|
||||
//::: Verdant Lord
|
||||
const int FEAT_VL_EXPERT_INFUSION = 25634;
|
||||
const int FEAT_VL_SUN_SUSTENANCE = 25635;
|
||||
const int FEAT_VL_SPONTANEITY = 25636;
|
||||
const int FEAT_VL_PLANT_FACILITY = 25637;
|
||||
const int FEAT_VL_WILD_SHAPE_TREANT = 25638;
|
||||
const int FEAT_VL_ANIMATE_TREE = 25639;
|
||||
const int FEAT_VL_GAEAS_EMBRACE = 25640;
|
||||
|
||||
//:: Masters of the Wild feats
|
||||
const int FEAT_CREATE_INFUSION = 25960;
|
||||
const int FEAT_MAGICAL_ARTISAN_CREATE_INFUSION = 25961;
|
||||
const int FEAT_PLANT_DEFIANCE = 25992;
|
||||
const int FEAT_PLANT_CONTROL = 25993;
|
||||
|
||||
|
||||
//:: Racial Feats
|
||||
const int FEAT_WEMIC_JUMP_8 = 4518;
|
||||
const int FEAT_URDINNIR_STONESKIN = 4644;
|
||||
@ -782,6 +807,9 @@ const int FEAT_SUEL_IGNORE_SPELL_FAILURE = 2398;
|
||||
const int FEAT_SUEL_EXTENDED_SPELL = 2399;
|
||||
const int FEAT_SUEL_DISPELLING_STRIKE = 2400;
|
||||
|
||||
//:: Druid
|
||||
const int FEAT_SPONT_SUMMON = 2372;
|
||||
|
||||
//Passive Feats
|
||||
const int FEAT_ETERNAL_FREEDOM = 4298;
|
||||
const int FEAT_INTUITIVE_ATTACK = 3166;
|
||||
@ -1538,18 +1566,19 @@ const int FEAT_SELVETARMS_BLESSING = 2447;
|
||||
const int FEAT_RANGER_DUAL = 374;
|
||||
const int FEAT_CAMOUFLAGE = 4486;
|
||||
|
||||
//Exalted Feat
|
||||
const int FEAT_SAC_VOW = 3388;
|
||||
const int FEAT_VOW_OBED = 3389;
|
||||
const int FEAT_EXALTED_TURNING = 3168;
|
||||
const int FEAT_HAND_HEALER = 3167;
|
||||
const int FEAT_NIMBUSLIGHT = 3165;
|
||||
const int FEAT_HOLYRADIANCE = 3164;
|
||||
const int FEAT_STIGMATA = 3163;
|
||||
const int FEAT_SERVHEAVEN = 3355;
|
||||
const int FEAT_RANGED_SMITE = 3356;
|
||||
const int FEAT_VOW_PURITY = 5360;
|
||||
const int FEAT_VOWOFPOVERTY = 26002;
|
||||
//:: Exalted Feats
|
||||
const int FEAT_SAC_VOW = 3388;
|
||||
const int FEAT_VOW_OBED = 3389;
|
||||
const int FEAT_EXALTED_TURNING = 3168;
|
||||
const int FEAT_HAND_HEALER = 3167;
|
||||
const int FEAT_NIMBUSLIGHT = 3165;
|
||||
const int FEAT_HOLYRADIANCE = 3164;
|
||||
const int FEAT_STIGMATA = 3163;
|
||||
const int FEAT_SERVHEAVEN = 3355;
|
||||
const int FEAT_RANGED_SMITE = 3356;
|
||||
const int FEAT_VOW_PURITY = 5360;
|
||||
const int FEAT_VOWOFPOVERTY = 26002;
|
||||
const int FEAT_FAV_COMPANIONS = 25994;
|
||||
|
||||
//Vile Feat
|
||||
const int FEAT_LICHLOVED = 3395;
|
||||
@ -3189,6 +3218,8 @@ const int FEAT_ETHEREAL = 4167;
|
||||
const int FEAT_TEMPLATE_ARCHLICH_MARKER = 22700;
|
||||
const int FEAT_TEMPLATE_ARCHLICH_TURN_UNDEAD = 22701;
|
||||
|
||||
const int FEAT_TEMPLATE_BAELNORN_MARKER = 22708;
|
||||
|
||||
const int FEAT_TEMPLATE_CELESTIAL_SMITE_EVIL = 22601;
|
||||
const int FEAT_TEMPLATE_CELESTIAL_MARKER = 22602;
|
||||
const int FEAT_TEMPLATE_FIENDISH_SMITE_GOOD = 22603;
|
||||
@ -3933,6 +3964,8 @@ const int FEAT_OPPORTUNISTIC_PIETY_HEAL = 5358;
|
||||
const int FEAT_OPPORTUNISTIC_PIETY_TURN = 5359;
|
||||
|
||||
// Combat Maneuver Feats
|
||||
const int FEAT_CM_CHARGE = 2823;
|
||||
const int FEAT_CM_GRAPPLE = 3414;
|
||||
const int FEAT_CURLING_WAVE_STRIKE = 2809;
|
||||
const int FEAT_SIDESTEP_CHARGE = 3505;
|
||||
const int FEAT_POWERFUL_CHARGE = 3506;
|
||||
@ -6203,6 +6236,38 @@ const int FEAT_SHINING_BLADE_SPELLCASTING_VASSAL = 19587;
|
||||
const int FEAT_SWIFT_WING_SPELLCASTING_VASSAL = 19588;
|
||||
const int FEAT_WARPRIEST_SPELLCASTING_VASSAL = 19589;
|
||||
|
||||
//:: Lion of Talisid marker feats
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST = 25601;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC = 25602;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_DRUID = 25603;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL = 25604;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_HEALER = 25605;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW = 25606;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC = 25607;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER = 25608;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_RANGER = 25609;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN = 25610;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI = 25611;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_SOL = 25612;
|
||||
const int FEAT_LION_OF_TALISID_SPELLCASTING_SPSHAMAN = 25613;
|
||||
|
||||
//:: Verdant Lord marker feats
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_ARCHIVIST = 25619;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_CLERIC = 25620;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_DRUID = 25621;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_FAVOURED_SOUL = 25622;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_HEALER = 25623;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_JOWAW = 25624;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_KOTC = 25625;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_KOTMC = 25626;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_NENTYAR_HUNTER = 25627;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_PALADIN = 25628;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_RANGER = 25629;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_OASHAMAN = 25630;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_SOHEI = 25631;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_SOL = 25632;
|
||||
const int FEAT_VERDANT_LORD_SPELLCASTING_SPSHAMAN = 25633;
|
||||
|
||||
//:: No spellcasting or invoking marker feats
|
||||
const int FEAT_ASMODEUS_SPELLCASTING_NONE = 19590;
|
||||
const int FEAT_TIAMAT_SPELLCASTING_NONE = 19591;
|
||||
|
@ -1148,8 +1148,8 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
if(GetHasFeat(FEAT_DIABOLIST_SPELLCASTING_ASSASSIN, oCaster))
|
||||
nArcane += GetLevelByClass(CLASS_TYPE_DIABOLIST, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster))
|
||||
nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster);
|
||||
//if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster))
|
||||
//nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_EKNIGHT_SPELLCASTING_ASSASSIN, oCaster))
|
||||
nArcane += GetLevelByClass(CLASS_TYPE_ELDRITCH_KNIGHT, oCaster);
|
||||
@ -3822,6 +3822,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_ARCHIVIST, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_ARCHIVIST, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */
|
||||
|
||||
@ -4148,7 +4151,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_CLERIC, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_CLERIC, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
|
||||
@ -4258,7 +4264,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_DRUID, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_DRUID, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
// if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_DRUID, oCaster))
|
||||
// nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
|
||||
@ -4370,10 +4379,13 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_FAVOURED_SOUL, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
// if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster))
|
||||
// nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
|
||||
if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_FAVOURED_SOUL, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster);
|
||||
@ -4479,6 +4491,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_HEALER, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_HEALER, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_HEALER, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */
|
||||
|
||||
@ -4586,6 +4601,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_JUSTICEWW, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
// if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_JUSTICEWW, oCaster))
|
||||
// nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
|
||||
|
||||
@ -4796,6 +4814,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */
|
||||
|
||||
@ -4901,7 +4922,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */
|
||||
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_NENTYAR_HUNTER, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_NENTYAR_HUNTER, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */
|
||||
@ -5212,7 +5236,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */
|
||||
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_RANGER, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_RANGER, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_RANGER, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster);
|
||||
@ -5316,7 +5343,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_OASHAMAN, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_SHAMAN, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_OASHAMAN, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
|
||||
@ -5529,6 +5559,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOHEI, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
// if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOHEI, oCaster))
|
||||
// nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
|
||||
|
||||
@ -5636,6 +5669,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOL, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOL, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
|
||||
|
||||
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOL, oCaster))
|
||||
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */
|
||||
|
||||
|
@ -1206,6 +1206,7 @@ int GetIsDoubleSidedWeaponType(int iWeaponType)
|
||||
return ( iWeaponType == BASE_ITEM_DIREMACE
|
||||
|| iWeaponType == BASE_ITEM_DOUBLEAXE
|
||||
|| iWeaponType == BASE_ITEM_TWOBLADEDSWORD
|
||||
|| iWeaponType == BASE_ITEM_DOUBLE_SCIMITAR
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1140,6 +1140,9 @@ void DoCharge(object oPC, object oTarget, int nDoAttack = TRUE, int nGenerateAoO
|
||||
nPounce = TRUE;
|
||||
if (GetHasSpellEffect(VESTIGE_CHUPOCLOPS, oPC) && GetLocalInt(oPC, "ExploitVestige") != VESTIGE_CHUPOCLOPS_POUNCE)
|
||||
nPounce = TRUE;
|
||||
//:: Lion of Talisid
|
||||
if(GetHasFeat(FEAT_LOT_LIONS_POUNCE, oPC))
|
||||
nPounce = TRUE;
|
||||
|
||||
// Checks for a White Raven Stance
|
||||
// If it exists, +1 damage/initiator level
|
||||
@ -2312,7 +2315,10 @@ void DoShieldCharge(object oPC, object oTarget, int nSlam = FALSE)
|
||||
if(GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC) >= 5)
|
||||
nPounce = TRUE;
|
||||
if(GetRacialType(oPC) == RACIAL_TYPE_MARRUSAULT)
|
||||
nPounce = TRUE;
|
||||
nPounce = TRUE;
|
||||
//:: Lion of Talisid
|
||||
if(GetHasFeat(FEAT_LOT_LIONS_POUNCE, oPC))
|
||||
nPounce = TRUE;
|
||||
|
||||
// Checks for a White Raven Stance
|
||||
// If it exists, +1 damage/initiator level
|
||||
|
@ -462,7 +462,7 @@ int PRCGetSpellLevelForClass(int nSpell, int nClass)
|
||||
return nSpellLevel;
|
||||
}
|
||||
|
||||
// returns the spelllevel of nSpell as it can be cast by oCreature
|
||||
// returns the spell circle level of nSpell as it can be cast by oCreature
|
||||
int PRCGetSpellLevel(object oCreature, int nSpell)
|
||||
{
|
||||
/*if (!PRCGetHasSpell(nSpell, oCreature))
|
||||
@ -605,7 +605,7 @@ int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF)
|
||||
if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
|
||||
{
|
||||
nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), j);
|
||||
if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
|
||||
if(DEBUG) DoDebug("prc_inc_core >> PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
|
||||
if(nCount > 0)
|
||||
{
|
||||
nUses += nCount;
|
||||
@ -615,7 +615,7 @@ int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF)
|
||||
{
|
||||
nSpellLevel = StringToInt(Get2DACache(sFile, "Level", j));
|
||||
nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel);
|
||||
if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
|
||||
if(DEBUG) DoDebug("prc_inc_core >> PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
|
||||
if(nCount > 0)
|
||||
{
|
||||
nUses += nCount;
|
||||
|
@ -795,7 +795,7 @@ int GetWeaponSize(object oWeapon)
|
||||
case BASE_ITEM_GREATAXE:
|
||||
case BASE_ITEM_HEAVYFLAIL:
|
||||
case BASE_ITEM_QUARTERSTAFF:
|
||||
case BASE_ITEM_MAGICSTAFF:
|
||||
//case BASE_ITEM_MAGICSTAFF:
|
||||
case BASE_ITEM_SCYTHE:
|
||||
case BASE_ITEM_SHORTSPEAR:
|
||||
case BASE_ITEM_ELVEN_COURTBLADE:
|
||||
@ -832,7 +832,7 @@ int PRCLargeWeaponCheck(int iBaseType, int nSize)
|
||||
case BASE_ITEM_GREATAXE:
|
||||
case BASE_ITEM_HEAVYFLAIL:
|
||||
case BASE_ITEM_QUARTERSTAFF:
|
||||
case BASE_ITEM_MAGICSTAFF:
|
||||
//case BASE_ITEM_MAGICSTAFF:
|
||||
case BASE_ITEM_SCYTHE:
|
||||
case BASE_ITEM_SHORTSPEAR:
|
||||
case BASE_ITEM_ELVEN_COURTBLADE:
|
||||
|
@ -108,8 +108,8 @@ void SetupCharacterData(object oPC)
|
||||
case CLASS_TYPE_ALIENIST: sScript = "prc_alienist"; break;
|
||||
case CLASS_TYPE_ARCANE_DUELIST: sScript = "prc_arcduel"; break;
|
||||
case CLASS_TYPE_ARCHIVIST: sScript = "prc_archivist"; iData |= 0x01; break;
|
||||
case CLASS_TYPE_ASSASSIN: iData |= 0x03; break;
|
||||
case CLASS_TYPE_BAELNORN: sScript = "prc_baelnorn"; break;
|
||||
case CLASS_TYPE_ASSASSIN: break;
|
||||
//case CLASS_TYPE_BAELNORN: sScript = "prc_baelnorn"; break;
|
||||
case CLASS_TYPE_BARD: iData |= 0x07; break;
|
||||
case CLASS_TYPE_BATTLESMITH: sScript = "prc_battlesmith"; break;
|
||||
case CLASS_TYPE_BEGUILER: iData |= 0x03; break;
|
||||
@ -121,7 +121,7 @@ void SetupCharacterData(object oPC)
|
||||
case CLASS_TYPE_BLIGHTLORD: sScript = "prc_blightlord"; break;
|
||||
case CLASS_TYPE_BLOODCLAW_MASTER: sScript = "tob_bloodclaw"; break;
|
||||
case CLASS_TYPE_BONDED_SUMMONNER: sScript = "prc_bondedsumm"; break;
|
||||
case CLASS_TYPE_CELEBRANT_SHARESS: iData |= 0x03; break;
|
||||
case CLASS_TYPE_CELEBRANT_SHARESS: iData |= 0x07; break;
|
||||
case CLASS_TYPE_CHILD_OF_NIGHT: sScript = "shd_childnight"; break;
|
||||
case CLASS_TYPE_COC: sScript = "prc_coc"; break;
|
||||
case CLASS_TYPE_COMBAT_MEDIC: sScript = "prc_cbtmed"; break;
|
||||
@ -180,6 +180,7 @@ void SetupCharacterData(object oPC)
|
||||
case CLASS_TYPE_LASHER: sScript = "prc_lasher"; break;
|
||||
case CLASS_TYPE_LEGENDARY_DREADNOUGHT: sScript = "prc_legendread"; break;
|
||||
case CLASS_TYPE_LICH: sScript = "pnp_lich_level"; break;
|
||||
case CLASS_TYPE_LION_OF_TALISID: sScript = "prc_lot"; break;
|
||||
case CLASS_TYPE_MAGEKILLER: sScript = "prc_magekill"; break;
|
||||
case CLASS_TYPE_MASTER_HARPER: sScript = "prc_masterh"; break;
|
||||
case CLASS_TYPE_MASTER_OF_NINE: sScript = "tob_masterofnine"; break;
|
||||
@ -245,6 +246,7 @@ void SetupCharacterData(object oPC)
|
||||
case CLASS_TYPE_TOTEM_RAGER: sScript = "moi_totemrager"; break;
|
||||
case CLASS_TYPE_TRUENAMER: sScript = "true_truenamer"; iData |= 0x01; break;
|
||||
case CLASS_TYPE_VASSAL: sScript = "prc_vassal"; break;
|
||||
case CLASS_TYPE_VERDANT_LORD: sScript = "prc_verdantlord"; break;
|
||||
case CLASS_TYPE_VIGILANT: sScript = "prc_vigilant"; break;
|
||||
case CLASS_TYPE_WARBLADE: sScript = "tob_warblade"; iData |= 0x01; break;
|
||||
case CLASS_TYPE_WARCHIEF: sScript = "prc_warchief"; break;
|
||||
@ -2264,6 +2266,8 @@ void FeatSpecialUsePerDay(object oPC)
|
||||
FeatUsePerDay(oPC, FEAT_FM_FOREST_DOMINION, ABILITY_CHARISMA, 3);
|
||||
FeatUsePerDay(oPC, FEAT_SOD_DEATH_TOUCH, -1, (GetLevelByClass(CLASS_TYPE_SLAYER_OF_DOMIEL, oPC)+4)/4);
|
||||
FeatUsePerDay(oPC, FEAT_SUEL_DISPELLING_STRIKE, -1, (GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oPC) + 2) / 4);
|
||||
FeatUsePerDay(oPC, FEAT_PLANT_CONTROL, ABILITY_CHARISMA, 3);
|
||||
FeatUsePerDay(oPC, FEAT_PLANT_DEFIANCE, ABILITY_CHARISMA, 3);
|
||||
FeatDiabolist(oPC);
|
||||
FeatAlaghar(oPC);
|
||||
ShadowShieldUses(oPC);
|
||||
|
750
src/include/prc_inc_json.nss
Normal file
750
src/include/prc_inc_json.nss
Normal file
@ -0,0 +1,750 @@
|
||||
//:://////////////////////////////////////////////
|
||||
//:: ;-. ,-. ,-. ,-.
|
||||
//:: | ) | ) / ( )
|
||||
//:: |-' |-< | ;-:
|
||||
//:: | | \ \ ( )
|
||||
//:: ' ' ' `-' `-'
|
||||
//:://////////////////////////////////////////////
|
||||
//::
|
||||
/*
|
||||
Library for json related functions.
|
||||
|
||||
*/
|
||||
//::
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Script: prc_inc_json.nss
|
||||
//:: Author: Jaysyn
|
||||
//:: Created: 2025-08-14 12:52:32
|
||||
//:://////////////////////////////////////////////
|
||||
#include "nw_inc_gff"
|
||||
#include "inc_debug"
|
||||
|
||||
|
||||
//::---------------------------------------------|
|
||||
//:: Helper functions |
|
||||
//::---------------------------------------------|
|
||||
|
||||
//:: Function to calculate the maximum possible hitpoints for oCreature
|
||||
int GetMaxPossibleHP(object oCreature)
|
||||
{
|
||||
int nMaxHP = 0; // Stores the total maximum hitpoints
|
||||
int i = 1; // Initialize position for class index
|
||||
int nConb = GetAbilityModifier(ABILITY_CONSTITUTION, oCreature);
|
||||
|
||||
// Loop through each class position the creature may have, checking each class in turn
|
||||
while (TRUE)
|
||||
{
|
||||
// Get the class ID at position i
|
||||
int nClassID = GetClassByPosition(i, oCreature);
|
||||
|
||||
// If class is invalid (no more classes to check), break out of loop
|
||||
if (nClassID == CLASS_TYPE_INVALID)
|
||||
break;
|
||||
|
||||
// Get the number of levels in this class
|
||||
int nClassLevels = GetLevelByClass(nClassID, oCreature);
|
||||
|
||||
// Get the row index of the class in classes.2da by using class ID as the row index
|
||||
int nHitDie = StringToInt(Get2DAString("classes", "HitDie", nClassID));
|
||||
|
||||
// Add maximum HP for this class (Hit Die * number of levels in this class)
|
||||
nMaxHP += nClassLevels * nHitDie;
|
||||
|
||||
// Move to the next class position
|
||||
i++;
|
||||
}
|
||||
|
||||
nMaxHP += nConb * GetHitDice(oCreature);
|
||||
|
||||
return nMaxHP;
|
||||
}
|
||||
|
||||
// Returns how many feats a creature should gain when its HD increases
|
||||
int CalculateFeatsFromHD(int nOriginalHD, int nNewHD)
|
||||
{
|
||||
// HD increase
|
||||
int nHDIncrease = nNewHD - nOriginalHD;
|
||||
|
||||
if (nHDIncrease <= 0)
|
||||
return 0; // No new feats if HD did not increase
|
||||
|
||||
// D&D 3E: 1 feat per 3 HD
|
||||
int nBonusFeats = nHDIncrease / 3;
|
||||
|
||||
return nBonusFeats;
|
||||
}
|
||||
|
||||
// Returns how many stat boosts a creature needs based on its HD
|
||||
int GetStatBoostsFromHD(int nCreatureHD, int nModiferCap)
|
||||
{
|
||||
// Make sure we don't get negative boosts
|
||||
int nBoosts = (40 - nCreatureHD) / 4;
|
||||
if (nBoosts < 0)
|
||||
{
|
||||
nBoosts = 0;
|
||||
}
|
||||
return nBoosts;
|
||||
}
|
||||
|
||||
// Struct to hold size modifiers
|
||||
struct SizeModifiers
|
||||
{
|
||||
int strMod;
|
||||
int dexMod;
|
||||
int conMod;
|
||||
int naturalAC;
|
||||
int attackBonus;
|
||||
int dexSkillMod;
|
||||
};
|
||||
|
||||
//::---------------------------------------------|
|
||||
//:: JSON functions |
|
||||
//::---------------------------------------------|
|
||||
|
||||
//:: Returns the integer value of a VarTable entry named sVarName, or 0 if not found.
|
||||
int json_GetLocalIntFromVarTable(json jCreature, string sVarName)
|
||||
{
|
||||
json jVarTable = GffGetList(jCreature, "VarTable");
|
||||
if (jVarTable == JsonNull())
|
||||
return 0;
|
||||
|
||||
int nCount = JsonGetLength(jVarTable);
|
||||
int i;
|
||||
for (i = 0; i < nCount; i++)
|
||||
{
|
||||
json jEntry = JsonArrayGet(jVarTable, i);
|
||||
if (jEntry == JsonNull()) continue;
|
||||
|
||||
// Get the Name field using GFF functions
|
||||
json jName = GffGetString(jEntry, "Name");
|
||||
if (jName == JsonNull()) continue;
|
||||
string sName = JsonGetString(jName);
|
||||
|
||||
if (sName == sVarName)
|
||||
{
|
||||
// Get the Type field to verify it's an integer
|
||||
json jType = GffGetDword(jEntry, "Type");
|
||||
if (jType != JsonNull())
|
||||
{
|
||||
int nType = JsonGetInt(jType);
|
||||
if (nType == 1) // Type 1 = integer
|
||||
{
|
||||
// Get the Value field using GFF functions
|
||||
json jValue = GffGetInt(jEntry, "Value");
|
||||
if (jValue == JsonNull()) return 0;
|
||||
return JsonGetInt(jValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//:: Returns the total Hit Dice from a JSON creature GFF.
|
||||
int json_GetCreatureHD(json jGff)
|
||||
{
|
||||
int nHD = 0;
|
||||
|
||||
json jClasses = GffGetList(jGff, "ClassList");
|
||||
if (jClasses == JsonNull())
|
||||
return 0;
|
||||
|
||||
int nCount = JsonGetLength(jClasses);
|
||||
int i;
|
||||
for (i = 0; i < nCount; i = i + 1)
|
||||
{
|
||||
json jClass = JsonArrayGet(jClasses, i);
|
||||
if (jClass == JsonNull())
|
||||
continue;
|
||||
|
||||
json jLevel = GffGetShort(jClass, "ClassLevel"); // Use GffGetShort, not GffGetField
|
||||
if (jLevel != JsonNull())
|
||||
{
|
||||
int nLevel = JsonGetInt(jLevel);
|
||||
nHD += nLevel;
|
||||
}
|
||||
}
|
||||
|
||||
if (nHD <= 0) nHD = 1;
|
||||
return nHD;
|
||||
}
|
||||
|
||||
//:: Reads ABILITY_TO_INCREASE from creature's VarTable and applies stat boosts based on increased HD
|
||||
json json_ApplyAbilityBoostFromHD(json jCreature, int nOriginalHD, int nModifierCap)
|
||||
{
|
||||
if (jCreature == JsonNull())
|
||||
return jCreature;
|
||||
|
||||
// Get the ability to increase from VarTable
|
||||
int nAbilityToIncrease = json_GetLocalIntFromVarTable(jCreature, "ABILITY_TO_INCREASE");
|
||||
if (nAbilityToIncrease < 0 || nAbilityToIncrease > 5)
|
||||
{
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Invalid ABILITY_TO_INCREASE value: " + IntToString(nAbilityToIncrease));
|
||||
return jCreature; // Invalid ability index
|
||||
}
|
||||
|
||||
// Calculate total current HD from ClassList
|
||||
json jClassList = GffGetList(jCreature, "ClassList");
|
||||
if (jClassList == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to get ClassList");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
int nCurrentTotalHD = 0;
|
||||
int nClassCount = JsonGetLength(jClassList);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nClassCount; i++)
|
||||
{
|
||||
json jClass = JsonArrayGet(jClassList, i);
|
||||
if (jClass != JsonNull())
|
||||
{
|
||||
json jClassLevel = GffGetShort(jClass, "ClassLevel");
|
||||
if (jClassLevel != JsonNull())
|
||||
{
|
||||
nCurrentTotalHD += JsonGetInt(jClassLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nCurrentTotalHD <= 0)
|
||||
{
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: No valid Hit Dice found");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
// Calculate stat boosts based on crossing level thresholds
|
||||
// Characters get stat boosts at levels 4, 8, 12, 16, 20, etc.
|
||||
int nOriginalBoosts = nOriginalHD / 4; // How many boosts they already had
|
||||
int nCurrentBoosts = nCurrentTotalHD / 4; // How many they should have now
|
||||
int nBoosts = nCurrentBoosts - nOriginalBoosts; // Additional boosts to apply
|
||||
|
||||
if (nBoosts <= 0)
|
||||
{
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: No boosts needed (Original boosts: " + IntToString(nOriginalBoosts) + ", Current boosts: " + IntToString(nCurrentBoosts) + ")");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Applying " + IntToString(nBoosts) + " boosts to ability " + IntToString(nAbilityToIncrease) + " for HD increase from " + IntToString(nOriginalHD) + " to " + IntToString(nCurrentTotalHD));
|
||||
|
||||
// Determine which ability to boost and apply the increases
|
||||
string sAbilityField;
|
||||
switch (nAbilityToIncrease)
|
||||
{
|
||||
case 0: sAbilityField = "Str"; break;
|
||||
case 1: sAbilityField = "Dex"; break;
|
||||
case 2: sAbilityField = "Con"; break;
|
||||
case 3: sAbilityField = "Int"; break;
|
||||
case 4: sAbilityField = "Wis"; break;
|
||||
case 5: sAbilityField = "Cha"; break;
|
||||
default:
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Unknown ability index: " + IntToString(nAbilityToIncrease));
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
// Get current ability score
|
||||
json jCurrentAbility = GffGetByte(jCreature, sAbilityField);
|
||||
if (jCurrentAbility == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to get " + sAbilityField + " score");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
int nCurrentScore = JsonGetInt(jCurrentAbility);
|
||||
int nNewScore = nCurrentScore + nBoosts;
|
||||
|
||||
// Clamp to valid byte range
|
||||
if (nNewScore < 1) nNewScore = 1;
|
||||
if (nNewScore > 255) nNewScore = 255;
|
||||
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Increasing " + sAbilityField + " from " + IntToString(nCurrentScore) + " to " + IntToString(nNewScore));
|
||||
|
||||
// Apply the ability score increase
|
||||
jCreature = GffReplaceByte(jCreature, sAbilityField, nNewScore);
|
||||
if (jCreature == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Failed to update " + sAbilityField);
|
||||
return JsonNull();
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("json_ApplyAbilityBoostFromHD: Successfully applied ability boosts");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
//:: Adjust a skill by its ID (more efficient than name lookup)
|
||||
json json_AdjustCreatureSkillByID(json jCreature, int nSkillID, int nMod)
|
||||
{
|
||||
// Get the SkillList
|
||||
json jSkillList = GffGetList(jCreature, "SkillList");
|
||||
if (jSkillList == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get SkillList");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
// Check if we have enough skills in the list
|
||||
int nSkillCount = JsonGetLength(jSkillList);
|
||||
if (nSkillID >= nSkillCount)
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Skill ID " + IntToString(nSkillID) + " exceeds skill list length " + IntToString(nSkillCount));
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
// Get the skill struct at the correct index
|
||||
json jSkill = JsonArrayGet(jSkillList, nSkillID);
|
||||
if (jSkill == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get skill at index " + IntToString(nSkillID));
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
// Get current rank
|
||||
json jRank = GffGetByte(jSkill, "Rank");
|
||||
if (jRank == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to get Rank for skill ID " + IntToString(nSkillID));
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
int nCurrentRank = JsonGetInt(jRank);
|
||||
int nNewRank = nCurrentRank + nMod;
|
||||
|
||||
// Clamp to valid range
|
||||
if (nNewRank < 0) nNewRank = 0;
|
||||
if (nNewRank > 255) nNewRank = 255;
|
||||
|
||||
// Update the rank in the skill struct
|
||||
jSkill = GffReplaceByte(jSkill, "Rank", nNewRank);
|
||||
if (jSkill == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AdjustCreatureSkillByID: Failed to replace Rank for skill ID " + IntToString(nSkillID));
|
||||
return JsonNull();
|
||||
}
|
||||
|
||||
// Replace the skill in the array
|
||||
jSkillList = JsonArraySet(jSkillList, nSkillID, jSkill);
|
||||
|
||||
// Replace the SkillList in the creature
|
||||
jCreature = GffReplaceList(jCreature, "SkillList", jSkillList);
|
||||
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
//:: Reads FutureFeat1..FutureFeatN from the template's VarTable and appends them to FeatList if missing.
|
||||
json json_AddFeatsFromCreatureVars(json jCreature, int nOriginalHD)
|
||||
{
|
||||
if (jCreature == JsonNull())
|
||||
return jCreature;
|
||||
|
||||
// Calculate current total HD
|
||||
int nCurrentHD = json_GetCreatureHD(jCreature);
|
||||
int nAddedHD = nCurrentHD - nOriginalHD;
|
||||
|
||||
if (nAddedHD <= 0)
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: No additional HD to process (Current: " + IntToString(nCurrentHD) + ", Original: " + IntToString(nOriginalHD) + ")");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
// Calculate how many feats the creature should get based on added HD
|
||||
// Characters get a feat at levels 1, 3, 6, 9, 12, 15, 18, etc.
|
||||
// For added levels, we need to check what feat levels they cross
|
||||
int nOriginalFeats = (nOriginalHD + 2) / 3; // Feats from original HD
|
||||
int nCurrentFeats = (nCurrentHD + 2) / 3; // Feats from current HD
|
||||
int nNumFeats = nCurrentFeats - nOriginalFeats; // Additional feats earned
|
||||
|
||||
if (nNumFeats <= 0)
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: No additional feats earned from " + IntToString(nAddedHD) + " added HD");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Processing " + IntToString(nNumFeats) + " feats for " + IntToString(nAddedHD) + " added HD (Original: " + IntToString(nOriginalHD) + ", Current: " + IntToString(nCurrentHD) + ")");
|
||||
|
||||
// Get or create FeatList
|
||||
json jFeatArray = GffGetList(jCreature, "FeatList");
|
||||
if (jFeatArray == JsonNull())
|
||||
jFeatArray = JsonArray();
|
||||
|
||||
int nOriginalFeatCount = JsonGetLength(jFeatArray);
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Original feat count: " + IntToString(nOriginalFeatCount));
|
||||
|
||||
int nAdded = 0;
|
||||
int i = 1;
|
||||
int nMaxIterations = 100; // Safety valve
|
||||
int nIterations = 0;
|
||||
|
||||
while (nAdded < nNumFeats && nIterations < nMaxIterations)
|
||||
{
|
||||
nIterations++;
|
||||
string sVarName = "FutureFeat" + IntToString(i);
|
||||
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Checking " + sVarName);
|
||||
|
||||
int nFeat = json_GetLocalIntFromVarTable(jCreature, sVarName);
|
||||
|
||||
if (nFeat <= 0)
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: " + sVarName + " not found or invalid");
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Found " + sVarName + " = " + IntToString(nFeat));
|
||||
|
||||
// Check if feat already exists
|
||||
int bHasFeat = FALSE;
|
||||
int nFeatCount = JsonGetLength(jFeatArray);
|
||||
int j;
|
||||
|
||||
for (j = 0; j < nFeatCount; j++)
|
||||
{
|
||||
json jFeatStruct = JsonArrayGet(jFeatArray, j);
|
||||
if (jFeatStruct != JsonNull())
|
||||
{
|
||||
json jFeatValue = GffGetWord(jFeatStruct, "Feat");
|
||||
if (jFeatValue != JsonNull() && JsonGetInt(jFeatValue) == nFeat)
|
||||
{
|
||||
bHasFeat = TRUE;
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Feat " + IntToString(nFeat) + " already exists");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert if missing
|
||||
if (!bHasFeat)
|
||||
{
|
||||
json jNewFeat = JsonObject();
|
||||
jNewFeat = JsonObjectSet(jNewFeat, "__struct_id", JsonInt(1));
|
||||
jNewFeat = GffAddWord(jNewFeat, "Feat", nFeat);
|
||||
|
||||
if (jNewFeat == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Failed to create feat struct for feat " + IntToString(nFeat));
|
||||
break;
|
||||
}
|
||||
|
||||
jFeatArray = JsonArrayInsert(jFeatArray, jNewFeat);
|
||||
nAdded++;
|
||||
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Added feat " + IntToString(nFeat) + " (" + IntToString(nAdded) + "/" + IntToString(nNumFeats) + ")");
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
// Safety break if we've checked too many variables
|
||||
if (i > 100)
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Safety break - checked too many FutureFeat variables");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Completed. Added " + IntToString(nAdded) + " feats in " + IntToString(nIterations) + " iterations");
|
||||
|
||||
// Save back the modified FeatList only if we added something
|
||||
if (nAdded > 0)
|
||||
{
|
||||
jCreature = GffReplaceList(jCreature, "FeatList", jFeatArray);
|
||||
if (jCreature == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("json_AddFeatsFromCreatureVars: Failed to replace FeatList");
|
||||
return JsonNull();
|
||||
}
|
||||
}
|
||||
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
//:: Get the size of a JSON array
|
||||
int json_GetArraySize(json jArray)
|
||||
{
|
||||
int iSize = 0;
|
||||
while (JsonArrayGet(jArray, iSize) != JsonNull())
|
||||
{
|
||||
iSize++;
|
||||
}
|
||||
return iSize;
|
||||
}
|
||||
|
||||
//:: Directly modifies oCreature's Base Natural AC if iNewAC is higher.
|
||||
//::
|
||||
json json_UpdateBaseAC(json jCreature, int iNewAC)
|
||||
{
|
||||
//json jBaseAC = GffGetByte(jCreature, "Creature/value/NaturalAC/value");
|
||||
json jBaseAC = GffGetByte(jCreature, "NaturalAC");
|
||||
|
||||
if (jBaseAC == JsonNull())
|
||||
{
|
||||
return JsonNull();
|
||||
}
|
||||
else if (JsonGetInt(jBaseAC) > iNewAC)
|
||||
{
|
||||
return jCreature;
|
||||
}
|
||||
else
|
||||
{
|
||||
jCreature = GffReplaceByte(jCreature, "NaturalAC", iNewAC);
|
||||
|
||||
return jCreature;
|
||||
}
|
||||
}
|
||||
|
||||
//:: Directly modifies jCreature's Challenge Rating.
|
||||
//:: This is useful for most XP calculations.
|
||||
json json_UpdateCR(json jCreature, int nBaseCR, int nCRMod)
|
||||
{
|
||||
int nNewCR;
|
||||
|
||||
//:: Add CRMod to current CR
|
||||
nNewCR = nBaseCR + nCRMod;
|
||||
|
||||
//:: Modify Challenge Rating
|
||||
jCreature = GffReplaceFloat(jCreature, "ChallengeRating", IntToFloat(nNewCR));
|
||||
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
//:: Directly modifies ability scores in a creature's JSON GFF.
|
||||
//::
|
||||
json json_UpdateTemplateStats(json jCreature, int iModStr = 0, int iModDex = 0, int iModCon = 0,
|
||||
int iModInt = 0, int iModWis = 0, int iModCha = 0)
|
||||
{
|
||||
int iCurrent;
|
||||
|
||||
// STR
|
||||
if (!GffGetFieldExists(jCreature, "Str", GFF_FIELD_TYPE_BYTE))
|
||||
jCreature = GffAddByte(jCreature, "Str", 10);
|
||||
iCurrent = JsonGetInt(GffGetByte(jCreature, "Str"));
|
||||
jCreature = GffReplaceByte(jCreature, "Str", iCurrent + iModStr);
|
||||
|
||||
// DEX
|
||||
if (!GffGetFieldExists(jCreature, "Dex", GFF_FIELD_TYPE_BYTE))
|
||||
jCreature = GffAddByte(jCreature, "Dex", 10);
|
||||
iCurrent = JsonGetInt(GffGetByte(jCreature, "Dex"));
|
||||
jCreature = GffReplaceByte(jCreature, "Dex", iCurrent + iModDex);
|
||||
|
||||
// CON
|
||||
if (!GffGetFieldExists(jCreature, "Con", GFF_FIELD_TYPE_BYTE))
|
||||
jCreature = GffAddByte(jCreature, "Con", 10);
|
||||
iCurrent = JsonGetInt(GffGetByte(jCreature, "Con"));
|
||||
jCreature = GffReplaceByte(jCreature, "Con", iCurrent + iModCon);
|
||||
|
||||
// INT
|
||||
if (!GffGetFieldExists(jCreature, "Int", GFF_FIELD_TYPE_BYTE))
|
||||
jCreature = GffAddByte(jCreature, "Int", 10);
|
||||
iCurrent = JsonGetInt(GffGetByte(jCreature, "Int"));
|
||||
jCreature = GffReplaceByte(jCreature, "Int", iCurrent + iModInt);
|
||||
|
||||
// WIS
|
||||
if (!GffGetFieldExists(jCreature, "Wis", GFF_FIELD_TYPE_BYTE))
|
||||
jCreature = GffAddByte(jCreature, "Wis", 10);
|
||||
iCurrent = JsonGetInt(GffGetByte(jCreature, "Wis"));
|
||||
jCreature = GffReplaceByte(jCreature, "Wis", iCurrent + iModWis);
|
||||
|
||||
// CHA
|
||||
if (!GffGetFieldExists(jCreature, "Cha", GFF_FIELD_TYPE_BYTE))
|
||||
jCreature = GffAddByte(jCreature, "Cha", 10);
|
||||
iCurrent = JsonGetInt(GffGetByte(jCreature, "Cha"));
|
||||
jCreature = GffReplaceByte(jCreature, "Cha", iCurrent + iModCha);
|
||||
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
//:: Directly modifies oCreature's ability scores.
|
||||
//::
|
||||
json json_UpdateCreatureStats(json jCreature, object oBaseCreature, int iModStr = 0, int iModDex = 0, int iModCon = 0, int iModInt = 0, int iModWis = 0, int iModCha = 0)
|
||||
{
|
||||
//:: Retrieve and modify ability scores
|
||||
int iCurrentStr = GetAbilityScore(oBaseCreature, ABILITY_STRENGTH);
|
||||
int iCurrentDex = GetAbilityScore(oBaseCreature, ABILITY_DEXTERITY);
|
||||
int iCurrentCon = GetAbilityScore(oBaseCreature, ABILITY_CONSTITUTION);
|
||||
int iCurrentInt = GetAbilityScore(oBaseCreature, ABILITY_INTELLIGENCE);
|
||||
int iCurrentWis = GetAbilityScore(oBaseCreature, ABILITY_WISDOM);
|
||||
int iCurrentCha = GetAbilityScore(oBaseCreature, ABILITY_CHARISMA);
|
||||
|
||||
jCreature = GffReplaceByte(jCreature, "Str", iCurrentStr + iModStr);
|
||||
jCreature = GffReplaceByte(jCreature, "Dex", iCurrentDex + iModDex);
|
||||
jCreature = GffReplaceByte(jCreature, "Con", iCurrentCon + iModCon);
|
||||
jCreature = GffReplaceByte(jCreature, "Int", iCurrentInt + iModInt);
|
||||
jCreature = GffReplaceByte(jCreature, "Wis", iCurrentWis + iModWis);
|
||||
jCreature = GffReplaceByte(jCreature, "Cha", iCurrentCha + iModCha);
|
||||
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
//:: Increases a creature's Hit Dice in its JSON GFF data by nAmount
|
||||
json json_AddHitDice(json jCreature, int nAmount)
|
||||
{
|
||||
if (jCreature == JsonNull() || nAmount <= 0)
|
||||
return jCreature;
|
||||
|
||||
// Get the ClassList
|
||||
json jClasses = GffGetList(jCreature, "ClassList");
|
||||
if (jClasses == JsonNull() || JsonGetLength(jClasses) == 0)
|
||||
return jCreature;
|
||||
|
||||
// Grab the first class entry
|
||||
json jFirstClass = JsonArrayGet(jClasses, 0);
|
||||
|
||||
// Only touch ClassLevel; do NOT modify Class type
|
||||
json jCurrentLevel = GffGetShort(jFirstClass, "ClassLevel");
|
||||
int nCurrentLevel = JsonGetInt(jCurrentLevel);
|
||||
int nNewLevel = nCurrentLevel + nAmount;
|
||||
|
||||
// Replace ClassLevel only
|
||||
jFirstClass = GffReplaceShort(jFirstClass, "ClassLevel", nNewLevel);
|
||||
|
||||
// Put modified class back into the array
|
||||
jClasses = JsonArraySet(jClasses, 0, jFirstClass);
|
||||
|
||||
// Replace ClassList in the creature JSON
|
||||
jCreature = GffReplaceList(jCreature, "ClassList", jClasses);
|
||||
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
//:: Adjusts a creature's size by nSizeChange (-4 to +4) and updates ability scores accordingly.
|
||||
json json_AdjustCreatureSize(json jCreature, int nSizeDelta)
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Entering function. nSizeDelta=" + IntToString(nSizeDelta));
|
||||
|
||||
if (jCreature == JsonNull() || nSizeDelta == 0)
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Exiting: jCreature is null or nSizeDelta is 0");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
// Get Appearance_Type using GFF functions
|
||||
json jAppearanceType = GffGetWord(jCreature, "Appearance_Type");
|
||||
if (jAppearanceType == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to get Appearance_Type");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
int nAppearance = JsonGetInt(jAppearanceType);
|
||||
int nCurrentSize = StringToInt(Get2DAString("appearances", "Size", nAppearance));
|
||||
|
||||
// Default to Medium (4) if invalid
|
||||
if (nCurrentSize < 0 || nCurrentSize > 8) nCurrentSize = 4;
|
||||
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Appearance_Type =" + IntToString(nAppearance) + ", Size =" + IntToString(nCurrentSize));
|
||||
|
||||
int nSteps = nSizeDelta;
|
||||
|
||||
// Calculate modifiers based on size change
|
||||
int strMod = nSteps * 4;
|
||||
int dexMod = nSteps * -1;
|
||||
int conMod = nSteps * 2;
|
||||
int naturalAC = nSteps * 1;
|
||||
int dexSkillMod = nSteps * -2;
|
||||
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Applying stat modifiers: STR=" + IntToString(strMod) +
|
||||
" DEX=" + IntToString(dexMod) +
|
||||
" CON=" + IntToString(conMod));
|
||||
|
||||
// Update ability scores using GFF functions with error checking
|
||||
json jStr = GffGetByte(jCreature, "Str");
|
||||
if (jStr != JsonNull())
|
||||
{
|
||||
int nNewStr = JsonGetInt(jStr) + strMod;
|
||||
if (nNewStr < 1) nNewStr = 1;
|
||||
if (nNewStr > 255) nNewStr = 255;
|
||||
|
||||
jCreature = GffReplaceByte(jCreature, "Str", nNewStr);
|
||||
if (jCreature == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Str");
|
||||
return JsonNull();
|
||||
}
|
||||
}
|
||||
|
||||
json jDex = GffGetByte(jCreature, "Dex");
|
||||
if (jDex != JsonNull())
|
||||
{
|
||||
int nNewDex = JsonGetInt(jDex) + dexMod;
|
||||
if (nNewDex < 1) nNewDex = 1;
|
||||
if (nNewDex > 255) nNewDex = 255;
|
||||
|
||||
jCreature = GffReplaceByte(jCreature, "Dex", nNewDex);
|
||||
if (jCreature == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Dex");
|
||||
return JsonNull();
|
||||
}
|
||||
}
|
||||
|
||||
json jCon = GffGetByte(jCreature, "Con");
|
||||
if (jCon != JsonNull())
|
||||
{
|
||||
int nNewCon = JsonGetInt(jCon) + conMod;
|
||||
if (nNewCon < 1) nNewCon = 1;
|
||||
if (nNewCon > 255) nNewCon = 255;
|
||||
|
||||
jCreature = GffReplaceByte(jCreature, "Con", nNewCon);
|
||||
if (jCreature == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update Con");
|
||||
return JsonNull();
|
||||
}
|
||||
}
|
||||
|
||||
// Update Natural AC
|
||||
json jNaturalAC = GffGetByte(jCreature, "NaturalAC");
|
||||
if (jNaturalAC != JsonNull())
|
||||
{
|
||||
int nCurrentNA = JsonGetInt(jNaturalAC);
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Current NaturalAC: " + IntToString(nCurrentNA));
|
||||
|
||||
int nNewNA = nCurrentNA + naturalAC;
|
||||
if (nNewNA < 0) nNewNA = 0;
|
||||
if (nNewNA > 255) nNewNA = 255;
|
||||
|
||||
jCreature = GffReplaceByte(jCreature, "NaturalAC", nNewNA);
|
||||
if (jCreature == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed to update NaturalAC");
|
||||
return JsonNull();
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust all Dexterity-based skills by finding them in skills.2da
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Adjusting DEX-based skills");
|
||||
|
||||
int nSkillID = 0;
|
||||
while (TRUE)
|
||||
{
|
||||
string sKeyAbility = Get2DAString("skills", "KeyAbility", nSkillID);
|
||||
|
||||
// Break when we've reached the end of skills
|
||||
if (sKeyAbility == "")
|
||||
break;
|
||||
|
||||
// If this skill uses Dexterity, adjust it
|
||||
if (sKeyAbility == "DEX")
|
||||
{
|
||||
string sSkillLabel = Get2DAString("skills", "Label", nSkillID);
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Adjusting DEX skill: " + sSkillLabel + " (ID: " + IntToString(nSkillID) + ")");
|
||||
|
||||
jCreature = json_AdjustCreatureSkillByID(jCreature, nSkillID, dexSkillMod);
|
||||
if (jCreature == JsonNull())
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_json >> json_AdjustCreatureSize: Failed adjusting skill ID " + IntToString(nSkillID));
|
||||
return JsonNull();
|
||||
}
|
||||
}
|
||||
|
||||
nSkillID++;
|
||||
}
|
||||
|
||||
if(DEBUG) DoDebug("json_AdjustCreatureSize completed successfully");
|
||||
return jCreature;
|
||||
}
|
||||
|
||||
|
||||
//:: Test void
|
||||
//:: void main (){}
|
@ -16,26 +16,28 @@ const int MATERIAL_TYPE_UNKNOWN = 0;
|
||||
const int MATERIAL_TYPE_BONE = 1;
|
||||
const int MATERIAL_TYPE_CERAMIC = 2;
|
||||
const int MATERIAL_TYPE_CRYSTAL = 3;
|
||||
const int MATERIAL_TYPE_FABRIC = 4;
|
||||
const int MATERIAL_TYPE_FIBER = 4;
|
||||
const int MATERIAL_TYPE_LEATHER = 5;
|
||||
const int MATERIAL_TYPE_METAL = 6;
|
||||
const int MATERIAL_TYPE_PAPER = 7;
|
||||
const int MATERIAL_TYPE_ROPE = 8;
|
||||
const int MATERIAL_TYPE_STONE = 9;
|
||||
const int MATERIAL_TYPE_WOOD = 10;
|
||||
const int MATERIAL_TYPE_BOTANICAL = 11;
|
||||
|
||||
const string MATERIAL_TYPE_NAME_INVALID = "";
|
||||
const string MATERIAL_TYPE_NAME_UNKNOWN = "Unknown";
|
||||
const string MATERIAL_TYPE_NAME_BONE = "Bone";
|
||||
const string MATERIAL_TYPE_NAME_CERAMIC = "Ceramic";
|
||||
const string MATERIAL_TYPE_NAME_CRYSTAL = "Crystal";
|
||||
const string MATERIAL_TYPE_NAME_FABRIC = "Fabric";
|
||||
const string MATERIAL_TYPE_NAME_FIBER = "Fiber";
|
||||
const string MATERIAL_TYPE_NAME_LEATHER = "Leather";
|
||||
const string MATERIAL_TYPE_NAME_METAL = "Metal";
|
||||
const string MATERIAL_TYPE_NAME_PAPER = "Paper";
|
||||
const string MATERIAL_TYPE_NAME_ROPE = "Rope";
|
||||
const string MATERIAL_TYPE_NAME_STONE = "Stone";
|
||||
const string MATERIAL_TYPE_NAME_WOOD = "Wood";
|
||||
const string MATERIAL_TYPE_NAME_BOTANICAL = "Bontanical";
|
||||
|
||||
//:: Material Itemproperty Constants
|
||||
//::////////////////////////////////////////////////////////////////////////////////
|
||||
@ -163,7 +165,8 @@ const int IP_MATERIAL_OBSIDIAN = 140;
|
||||
const int IP_MATERIAL_BAMBOO = 141;
|
||||
const int IP_MATERIAL_POTTERY = 142;
|
||||
const int IP_MATERIAL_GLASSTEEL = 143;
|
||||
const int IP_NUM_MATERIALS = 143;
|
||||
const int IP_MATERIAL_HERB = 144;
|
||||
const int IP_NUM_MATERIALS = 144;
|
||||
|
||||
const string IP_MATERIAL_NAME_INVALID = "";
|
||||
const string IP_MATERIAL_NAME_UNKNOWN = "Unknown";
|
||||
@ -288,6 +291,7 @@ const string IP_MATERIAL_NAME_OBSIDIAN = "Obsidian";
|
||||
const string IP_MATERIAL_NAME_BAMBOO = "Bamboo";
|
||||
const string IP_MATERIAL_NAME_POTTERY = "Pottery";
|
||||
const string IP_MATERIAL_NAME_GLASSTEEL = "Glassteel";
|
||||
const string IP_MATERIAL_NAME_HERB = "Herbs";
|
||||
|
||||
//::///////////////////////////////////////////////////////////////
|
||||
// GetMaterialName( int iMaterialType, int bLowerCase = FALSE)
|
||||
@ -428,6 +432,7 @@ string GetMaterialName( int iMaterialType, int bLowerCase = FALSE)
|
||||
case IP_MATERIAL_BAMBOO: sName = IP_MATERIAL_NAME_BAMBOO; break;
|
||||
case IP_MATERIAL_POTTERY: sName = IP_MATERIAL_NAME_POTTERY; break;
|
||||
case IP_MATERIAL_GLASSTEEL: sName = IP_MATERIAL_NAME_GLASSTEEL; break;
|
||||
case IP_MATERIAL_HERB: sName = IP_MATERIAL_NAME_HERB; break;
|
||||
|
||||
default: return "";
|
||||
}
|
||||
@ -573,6 +578,7 @@ int GetIPMaterial( string sMaterialName)
|
||||
else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_BAMBOO)) return IP_MATERIAL_BAMBOO;
|
||||
else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_POTTERY)) return IP_MATERIAL_POTTERY;
|
||||
else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_GLASSTEEL)) return IP_MATERIAL_GLASSTEEL;
|
||||
else if( sMaterialName == GetStringUpperCase(IP_MATERIAL_NAME_HERB)) return IP_MATERIAL_HERB;
|
||||
|
||||
return IP_MATERIAL_INVALID;
|
||||
}
|
||||
@ -806,6 +812,9 @@ int GetMaterialType(int nMaterial)
|
||||
|| nMaterial == IP_MATERIAL_DRAKE_IVORY )
|
||||
return MATERIAL_TYPE_BONE;
|
||||
|
||||
else if ( nMaterial == IP_MATERIAL_HERB )
|
||||
return MATERIAL_TYPE_BOTANICAL;
|
||||
|
||||
else if ( nMaterial == IP_MATERIAL_ELUKIAN_CLAY
|
||||
|| nMaterial == IP_MATERIAL_POTTERY )
|
||||
return MATERIAL_TYPE_CERAMIC;
|
||||
@ -814,7 +823,7 @@ int GetMaterialType(int nMaterial)
|
||||
|| nMaterial == IP_MATERIAL_COTTON
|
||||
|| nMaterial == IP_MATERIAL_SILK
|
||||
|| nMaterial == IP_MATERIAL_WOOL )
|
||||
return MATERIAL_TYPE_FABRIC;
|
||||
return MATERIAL_TYPE_FIBER;
|
||||
|
||||
else if ( nMaterial == IP_MATERIAL_GEM
|
||||
|| nMaterial == IP_MATERIAL_GEM_ALEXANDRITE
|
||||
|
@ -808,7 +808,24 @@ int GetIsOnHitCastSpell(object oSpellTarget = OBJECT_INVALID, object oSpellCastI
|
||||
if (DEBUG) DoDebug("GetIsOnHitCastSpell: item "+GetName(oSpellCastItem)+" is armor; attacker = "+GetName(oAttacker)+", defender = "+GetName(oDefender));
|
||||
}
|
||||
// is the spell type item a weapon?
|
||||
else if (iWeaponType == StringToInt(Get2DACache("baseitems", "WeaponType", iBaseType)))
|
||||
int nWT = StringToInt(Get2DACache("baseitems", "WeaponType", iBaseType));
|
||||
if (nWT > 0)
|
||||
{
|
||||
if (oSpellTarget == OBJECT_INVALID)
|
||||
oSpellTarget = PRCGetSpellTargetObject(oSpellOrigin);
|
||||
|
||||
oAttacker = oSpellOrigin;
|
||||
oDefender = oSpellTarget;
|
||||
|
||||
if (DEBUG) DoDebug("GetIsOnHitCastSpell: item "+GetName(oSpellCastItem)+" is weapon [WT="+IntToString(nWT)+"]; attacker="+GetName(oAttacker)+", defender="+GetName(oDefender));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DEBUG) DoDebug("GetIsOnHitCastSpell: item "+GetName(oSpellCastItem)+" is neither weapon nor armor; returning FALSE");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* else if (iWeaponType == StringToInt(Get2DACache("baseitems", "WeaponType", iBaseType)))
|
||||
{
|
||||
// determine the target, if not already given
|
||||
if (oSpellTarget == OBJECT_INVALID)
|
||||
@ -823,7 +840,7 @@ int GetIsOnHitCastSpell(object oSpellTarget = OBJECT_INVALID, object oSpellCastI
|
||||
{
|
||||
if (DEBUG) DoDebug("GetIsOnHitCastSpell: item "+GetName(oSpellCastItem)+" is neither weapon nor armor; returning FALSE");
|
||||
return FALSE;
|
||||
}
|
||||
} */
|
||||
|
||||
|
||||
// the spell origin must possess the item that cast the spell (at least for the aurora engine, in prc_inc_combat that may differ)
|
||||
|
@ -115,11 +115,11 @@ int PerformJump(object oPC, location lLoc, int bDoKnockDown = TRUE)
|
||||
iBonus = 4;
|
||||
}
|
||||
}
|
||||
/*if (GetHasSpellEffect(MOVE_TC_LEAPING_DRAGON, oPC))
|
||||
if (GetHasSpellEffect(MOVE_TC_LEAPING_DRAGON, oPC))
|
||||
{
|
||||
bIsRunningJump = TRUE;
|
||||
iBonus = 10;
|
||||
} */
|
||||
//iBonus = 10; //:: This is granted in the stance.
|
||||
}
|
||||
// PnP rules are height * 6 for run and height * 2 for jump.
|
||||
// I can't get height so that is assumed to be 6.
|
||||
// Changed maxed jump distance because the NwN distance is rather short
|
||||
@ -374,6 +374,12 @@ int PRCIsFlying(object oCreature)
|
||||
|
||||
if(GetRacialType(oCreature) == RACIAL_TYPE_GLOURA)
|
||||
bFlying = TRUE;
|
||||
|
||||
if(GetRacialType(oCreature) == RACIAL_TYPE_AVARIEL)
|
||||
bFlying = TRUE;
|
||||
|
||||
if(GetRacialType(oCreature) == RACIAL_TYPE_FEYRI)
|
||||
bFlying = TRUE;
|
||||
|
||||
if(GetRacialType(oCreature) == RACIAL_TYPE_SPIRETOPDRAGON)
|
||||
bFlying = TRUE;
|
||||
|
@ -20,6 +20,11 @@
|
||||
/* Function prototypes */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
//:: Calculates total Shield AC bonuses from all sources
|
||||
int GetTotalShieldACBonus(object oCreature);
|
||||
|
||||
//:: Handles psuedo-Foritifcation
|
||||
void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25);
|
||||
|
||||
@ -376,6 +381,36 @@ const int TYPE_DIVINE = -2;
|
||||
/* Function definitions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Returns TRUE if nSpellID is a subradial spell, FALSE otherwise
|
||||
int GetIsSubradialSpell(int nSpellID)
|
||||
{
|
||||
string sMaster = Get2DACache("spells", "Master", nSpellID);
|
||||
|
||||
// If the Master column is numeric, this spell is a subradial of that master
|
||||
if (sMaster != "" && sMaster != "****")
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Returns the masterspell SpellID for a subradial spell.
|
||||
int GetMasterSpellFromSubradial(int nSpellID)
|
||||
{
|
||||
string sMaster = Get2DAString("spells", "Master", nSpellID);
|
||||
|
||||
if (sMaster != "****")
|
||||
{
|
||||
return StringToInt(sMaster);
|
||||
}
|
||||
|
||||
return -1; // No master
|
||||
}
|
||||
|
||||
|
||||
|
||||
int GetPrCAdjustedClassLevel(int nClass, object oCaster = OBJECT_SELF)
|
||||
{
|
||||
int iTemp;
|
||||
@ -412,7 +447,9 @@ int GetPrCAdjustedCasterLevelByType(int nClassType, object oCaster = OBJECT_SELF
|
||||
{
|
||||
int nClassLvl;
|
||||
int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8;
|
||||
int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl;
|
||||
int nClass1Lvl = 0, nClass2Lvl = 0, nClass3Lvl = 0, nClass4Lvl = 0,
|
||||
nClass5Lvl = 0, nClass6Lvl = 0, nClass7Lvl = 0, nClass8Lvl = 0;
|
||||
|
||||
|
||||
nClass1 = GetClassByPosition(1, oCaster);
|
||||
nClass2 = GetClassByPosition(2, oCaster);
|
||||
@ -2223,6 +2260,78 @@ int GetControlledCelestialTotalHD(object oPC = OBJECT_SELF)
|
||||
return nTotalHD;
|
||||
}
|
||||
|
||||
//:: Calculates total Shield AC bonuses from all sources
|
||||
int GetTotalShieldACBonus(object oCreature)
|
||||
{
|
||||
int nShieldBonus = 0;
|
||||
object oItem;
|
||||
|
||||
// Check left hand for shield
|
||||
oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature);
|
||||
if (GetIsObjectValid(oItem))
|
||||
{
|
||||
int nBaseItem = GetBaseItemType(oItem);
|
||||
if (nBaseItem == BASE_ITEM_SMALLSHIELD ||
|
||||
nBaseItem == BASE_ITEM_LARGESHIELD ||
|
||||
nBaseItem == BASE_ITEM_TOWERSHIELD)
|
||||
{
|
||||
nShieldBonus += GetItemACValue(oItem);
|
||||
if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC, bonus = " + IntToString(nShieldBonus)+".");
|
||||
}
|
||||
}
|
||||
|
||||
// Check creature weapon slots for shield AC bonus
|
||||
oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCreature);
|
||||
if (GetIsObjectValid(oItem))
|
||||
nShieldBonus += GetItemACValue(oItem);
|
||||
|
||||
oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCreature);
|
||||
if (GetIsObjectValid(oItem))
|
||||
nShieldBonus += GetItemACValue(oItem);
|
||||
|
||||
oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCreature);
|
||||
if (GetIsObjectValid(oItem))
|
||||
nShieldBonus += GetItemACValue(oItem);
|
||||
|
||||
// Add shield AC bonuses from magical effects
|
||||
effect eEffect = GetFirstEffect(oCreature);
|
||||
while (GetIsEffectValid(eEffect))
|
||||
{
|
||||
int nACType = GetEffectInteger(eEffect, 0);
|
||||
int nACAmount = GetEffectInteger(eEffect, 1);
|
||||
|
||||
if(GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE && nACType == AC_SHIELD_ENCHANTMENT_BONUS)
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC effect, bonus = " + IntToString(nACAmount)+".");
|
||||
nShieldBonus += nACAmount;
|
||||
}
|
||||
|
||||
eEffect = GetNextEffect(oCreature);
|
||||
}
|
||||
return nShieldBonus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Add shield AC bonuses from magical effects
|
||||
/* effect eEffect = GetFirstEffect(oCreature);
|
||||
while (GetIsEffectValid(eEffect))
|
||||
{
|
||||
if (GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE &&
|
||||
GetEffectInteger(eEffect, 1) == AC_SHIELD_ENCHANTMENT_BONUS)
|
||||
{
|
||||
int nMod = GetEffectInteger(eEffect, 0);
|
||||
int nType = GetEffectInteger(eEffect, 1);
|
||||
nShieldBonus += GetEffectInteger(eEffect, 0);
|
||||
string s = "Found AC effect: bonus = " + IntToString(nMod) + ", type = " + IntToString(nType);
|
||||
SendMessageToPC(GetFirstPC(), s);
|
||||
}
|
||||
eEffect = GetNextEffect(oCreature);
|
||||
}
|
||||
|
||||
return nShieldBonus;
|
||||
}*/
|
||||
//
|
||||
//:: Handles psuedo-Foritifcation
|
||||
void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25)
|
||||
{
|
||||
@ -2275,7 +2384,7 @@ void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25)
|
||||
IPSafeAddItemProperty(oHide, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// wrapper for DecrementRemainingSpellUses, works for newspellbook 'fake' spells too
|
||||
// should also find and decrement metamagics for newspellbooks
|
||||
|
@ -70,6 +70,8 @@
|
||||
43 PRC_CRAFTING_BASE_ITEMS int 1
|
||||
44 PRC_XP_USE_SIMPLE_LA int 1
|
||||
45 PRC_XP_USE_SIMPLE_RACIAL_HD int 1
|
||||
46 PRC_CREATE_INFUSION_CASTER_LEVEL int 1
|
||||
47 PRC_CREATE_INFUSION_OPTIONAL_HERBS int 0
|
||||
*/
|
||||
|
||||
/* This variable MUST be updated with every new version of the PRC!!! */
|
||||
@ -1952,6 +1954,18 @@ const string PRC_CRAFT_ROD_CASTER_LEVEL = "PRC_CRAFT_ROD_CASTER_LEVE
|
||||
*/
|
||||
const string PRC_CRAFT_STAFF_CASTER_LEVEL = "PRC_CRAFT_STAFF_CASTER_LEVEL";
|
||||
|
||||
/*
|
||||
* As above, except it applies to herbal infusions
|
||||
*/
|
||||
const string PRC_CREATE_INFUSION_CASTER_LEVEL = "PRC_CREATE_INFUSION_CASTER_LEVEL";
|
||||
|
||||
/*
|
||||
* Builder's Option: Enables the optional PnP herbs for creating infusions.
|
||||
* Each herb is keyed to a spell circle level & spell school as shown on pg. 33
|
||||
* of the Master's of the Wild sourcebook.
|
||||
*/
|
||||
const string PRC_CREATE_INFUSION_OPTIONAL_HERBS = "PRC_CREATE_INFUSION_OPTIONAL_HERBS";
|
||||
|
||||
/*
|
||||
* Characters with a crafting feat always have the appropriate base item in their inventory
|
||||
*/
|
||||
@ -1961,45 +1975,52 @@ const string PRC_CRAFTING_BASE_ITEMS = "PRC_CRAFTING_BASE_ITEMS";
|
||||
* Max level of spells brewed into potions
|
||||
* defaults to 3
|
||||
*/
|
||||
const string X2_CI_BREWPOTION_MAXLEVEL = "X2_CI_BREWPOTION_MAXLEVEL";
|
||||
//const string X2_CI_BREWPOTION_MAXLEVEL = "X2_CI_BREWPOTION_MAXLEVEL";
|
||||
const string PRC_X2_BREWPOTION_MAXLEVEL = "PRC_X2_BREWPOTION_MAXLEVEL";
|
||||
|
||||
/*
|
||||
* cost modifier of spells brewed into poitions
|
||||
* defaults to 50
|
||||
*/
|
||||
const string X2_CI_BREWPOTION_COSTMODIFIER = "X2_CI_BREWPOTION_COSTMODIFIER";
|
||||
const string PRC_X2_BREWPOTION_COSTMODIFIER = "PRC_X2_BREWPOTION_COSTMODIFIER";
|
||||
|
||||
/*
|
||||
* cost modifier of spells scribed into scrolls
|
||||
* defaults to 25
|
||||
*/
|
||||
const string X2_CI_SCRIBESCROLL_COSTMODIFIER = "X2_CI_SCRIBESCROLL_COSTMODIFIER";
|
||||
const string PRC_X2_SCRIBESCROLL_COSTMODIFIER = "PRC_X2_SCRIBESCROLL_COSTMODIFIER";
|
||||
|
||||
/*
|
||||
* cost modifier of spells infused into herbs
|
||||
* defaults to 25
|
||||
*/
|
||||
const string PRC_X2_CREATEINFUSION_COSTMODIFIER = "PRC_X2_CREATEINFUSION_COSTMODIFIER";
|
||||
|
||||
/*
|
||||
* Max level of spells crafted into wands
|
||||
* defaults to 4
|
||||
*/
|
||||
const string X2_CI_CRAFTWAND_MAXLEVEL = "X2_CI_CRAFTWAND_MAXLEVEL";
|
||||
const string PRC_X2_CRAFTWAND_MAXLEVEL = "PRC_X2_CRAFTWAND_MAXLEVEL";
|
||||
|
||||
/*
|
||||
* cost modifier of spells crafted into wands
|
||||
* defaults to 750
|
||||
*/
|
||||
const string X2_CI_CRAFTWAND_COSTMODIFIER = "X2_CI_CRAFTWAND_COSTMODIFIER";
|
||||
const string PRC_X2_CRAFTWAND_COSTMODIFIER = "PRC_X2_CRAFTWAND_COSTMODIFIER";
|
||||
|
||||
/*
|
||||
* cost modifier of spells crafted into rods
|
||||
* note that adding a second spell costs 75% and 3 or more costs 50%
|
||||
* defaults to 750
|
||||
*/
|
||||
const string X2_CI_CRAFTROD_COSTMODIFIER = "X2_CI_CRAFTROD_COSTMODIFIER";
|
||||
const string PRC_X2_CRAFTROD_COSTMODIFIER = "PRC_X2_CRAFTROD_COSTMODIFIER";
|
||||
|
||||
/*
|
||||
* cost modifier of spells crafted into staffs
|
||||
* note that adding a second spell costs 75% and 3 or more costs 50%
|
||||
* defaults to 750
|
||||
*/
|
||||
const string X2_CI_CRAFTSTAFF_COSTMODIFIER = "X2_CI_CRAFTSTAFF_COSTMODIFIER";
|
||||
const string PRC_X2_CRAFTSTAFF_COSTMODIFIER = "PRC_X2_CRAFTSTAFF_COSTMODIFIER";
|
||||
|
||||
/**
|
||||
* Allows the use of arbitrary itemproperties and uses NWN item costs
|
||||
|
@ -14,17 +14,6 @@
|
||||
/* Function prototypes */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//gets the number of class levels that count for turning
|
||||
int GetTurningClassLevel(object oCaster = OBJECT_SELF, int nTurnType = SPELL_TURN_UNDEAD);
|
||||
|
||||
@ -191,6 +180,20 @@ int GetIsTurnOrRebuke(object oTarget, int nTurnType, int nTargetRace)
|
||||
|
||||
break;
|
||||
}
|
||||
case SPELL_PLANT_DEFIANCE:
|
||||
{
|
||||
if(nTargetRace == RACIAL_TYPE_PLANT)
|
||||
nReturn = ACTION_TURN;
|
||||
|
||||
break;
|
||||
}
|
||||
case SPELL_PLANT_CONTROL:
|
||||
{
|
||||
if(nTargetRace == RACIAL_TYPE_PLANT)
|
||||
nReturn = ACTION_REBUKE;
|
||||
|
||||
break;
|
||||
}
|
||||
case SPELL_TURN_PLANT:
|
||||
{
|
||||
// Plant domain rebukes or commands plants
|
||||
@ -383,6 +386,13 @@ int GetTurningClassLevel(object oCaster = OBJECT_SELF, int nTurnType = SPELL_TUR
|
||||
|
||||
if (nTurnType == SPELL_OPPORTUNISTIC_PIETY_TURN)
|
||||
return GetLevelByClass(CLASS_TYPE_FACTOTUM, oCaster);
|
||||
|
||||
if (nTurnType == SPELL_PLANT_DEFIANCE || nTurnType == SPELL_PLANT_CONTROL)
|
||||
{
|
||||
int nDivineLvl = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster);
|
||||
|
||||
return nDivineLvl;
|
||||
}
|
||||
|
||||
//Baelnorn & Archlich adds all class levels.
|
||||
if(GetLevelByClass(CLASS_TYPE_BAELNORN, oCaster) || GetHasFeat(FEAT_TEMPLATE_ARCHLICH_MARKER, oCaster)) //:: Archlich
|
||||
|
@ -40,13 +40,31 @@ int IsProficient(object oPC, int nBaseItem)
|
||||
|
||||
case BASE_ITEM_CLUB:
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC);
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC);
|
||||
|
||||
case BASE_ITEM_HEAVYCROSSBOW:
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW, oPC);
|
||||
|
||||
case BASE_ITEM_LIGHTCROSSBOW:
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW, oPC);
|
||||
|
||||
case BASE_ITEM_DAGGER:
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC);
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC);
|
||||
|
||||
case BASE_ITEM_LONGSWORD:
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oPC)
|
||||
@ -152,12 +170,14 @@ int IsProficient(object oPC, int nBaseItem)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC);
|
||||
|
||||
case BASE_ITEM_QUARTERSTAFF:
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF, oPC)
|
||||
||GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC);
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC);
|
||||
|
||||
case BASE_ITEM_MAGICSTAFF:
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF, oPC)
|
||||
||GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC);
|
||||
|
||||
@ -300,167 +320,185 @@ int GetWeaponProfFeatByType(int nBaseType)
|
||||
{
|
||||
switch(nBaseType)
|
||||
{
|
||||
case BASE_ITEM_SHORTSWORD:
|
||||
return FEAT_WEAPON_PROFICIENCY_SHORTSWORD;
|
||||
case BASE_ITEM_CLUB:
|
||||
return FEAT_WEAPON_PROFICIENCY_CLUB;
|
||||
|
||||
case BASE_ITEM_QUARTERSTAFF:
|
||||
return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF;
|
||||
|
||||
case BASE_ITEM_LONGSWORD:
|
||||
return FEAT_WEAPON_PROFICIENCY_LONGSWORD;
|
||||
case BASE_ITEM_MAGICSTAFF:
|
||||
return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF;
|
||||
|
||||
case BASE_ITEM_DAGGER:
|
||||
return FEAT_WEAPON_PROFICIENCY_DAGGER;
|
||||
|
||||
case BASE_ITEM_BATTLEAXE:
|
||||
return FEAT_WEAPON_PROFICIENCY_BATTLEAXE;
|
||||
case BASE_ITEM_HEAVYCROSSBOW:
|
||||
return FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW;
|
||||
|
||||
case BASE_ITEM_BASTARDSWORD:
|
||||
return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD;
|
||||
case BASE_ITEM_LIGHTCROSSBOW:
|
||||
return FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW;
|
||||
|
||||
case BASE_ITEM_SHORTSWORD:
|
||||
return FEAT_WEAPON_PROFICIENCY_SHORTSWORD;
|
||||
|
||||
case BASE_ITEM_LIGHTFLAIL:
|
||||
return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL;
|
||||
case BASE_ITEM_LONGSWORD:
|
||||
return FEAT_WEAPON_PROFICIENCY_LONGSWORD;
|
||||
|
||||
case BASE_ITEM_WARHAMMER:
|
||||
return FEAT_WEAPON_PROFICIENCY_WARHAMMER;
|
||||
case BASE_ITEM_BATTLEAXE:
|
||||
return FEAT_WEAPON_PROFICIENCY_BATTLEAXE;
|
||||
|
||||
case BASE_ITEM_LONGBOW:
|
||||
return FEAT_WEAPON_PROFICIENCY_LONGBOW;
|
||||
case BASE_ITEM_BASTARDSWORD:
|
||||
return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD;
|
||||
|
||||
case BASE_ITEM_LIGHTMACE:
|
||||
return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE;
|
||||
case BASE_ITEM_LIGHTFLAIL:
|
||||
return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL;
|
||||
|
||||
case BASE_ITEM_HALBERD:
|
||||
return FEAT_WEAPON_PROFICIENCY_HALBERD;
|
||||
case BASE_ITEM_WARHAMMER:
|
||||
return FEAT_WEAPON_PROFICIENCY_WARHAMMER;
|
||||
|
||||
case BASE_ITEM_SHORTBOW:
|
||||
case BASE_ITEM_LONGBOW:
|
||||
return FEAT_WEAPON_PROFICIENCY_LONGBOW;
|
||||
|
||||
case BASE_ITEM_LIGHTMACE:
|
||||
return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE;
|
||||
|
||||
case BASE_ITEM_HALBERD:
|
||||
return FEAT_WEAPON_PROFICIENCY_HALBERD;
|
||||
|
||||
case BASE_ITEM_SHORTBOW:
|
||||
return FEAT_WEAPON_PROFICIENCY_SHORTBOW;
|
||||
|
||||
case BASE_ITEM_TWOBLADEDSWORD:
|
||||
case BASE_ITEM_TWOBLADEDSWORD:
|
||||
return FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD;
|
||||
|
||||
case BASE_ITEM_GREATSWORD:
|
||||
case BASE_ITEM_GREATSWORD:
|
||||
return FEAT_WEAPON_PROFICIENCY_GREATSWORD;
|
||||
|
||||
case BASE_ITEM_GREATAXE:
|
||||
case BASE_ITEM_GREATAXE:
|
||||
return FEAT_WEAPON_PROFICIENCY_GREATAXE;
|
||||
|
||||
case BASE_ITEM_DART:
|
||||
case BASE_ITEM_DART:
|
||||
return FEAT_WEAPON_PROFICIENCY_DART;
|
||||
|
||||
case BASE_ITEM_DIREMACE:
|
||||
case BASE_ITEM_DIREMACE:
|
||||
return FEAT_WEAPON_PROFICIENCY_DIRE_MACE;
|
||||
|
||||
case BASE_ITEM_DOUBLEAXE:
|
||||
case BASE_ITEM_DOUBLEAXE:
|
||||
return FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE;
|
||||
|
||||
case BASE_ITEM_HEAVYFLAIL:
|
||||
case BASE_ITEM_HEAVYFLAIL:
|
||||
return FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL;
|
||||
|
||||
case BASE_ITEM_LIGHTHAMMER:
|
||||
case BASE_ITEM_LIGHTHAMMER:
|
||||
return FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER;
|
||||
|
||||
case BASE_ITEM_HANDAXE:
|
||||
case BASE_ITEM_HANDAXE:
|
||||
return FEAT_WEAPON_PROFICIENCY_HANDAXE;
|
||||
|
||||
case BASE_ITEM_KAMA:
|
||||
case BASE_ITEM_KAMA:
|
||||
return FEAT_WEAPON_PROFICIENCY_KAMA;
|
||||
|
||||
case BASE_ITEM_KATANA:
|
||||
case BASE_ITEM_KATANA:
|
||||
return FEAT_WEAPON_PROFICIENCY_KATANA;
|
||||
|
||||
case BASE_ITEM_KUKRI:
|
||||
case BASE_ITEM_KUKRI:
|
||||
return FEAT_WEAPON_PROFICIENCY_KUKRI;
|
||||
|
||||
case BASE_ITEM_MORNINGSTAR:
|
||||
case BASE_ITEM_MORNINGSTAR:
|
||||
return FEAT_WEAPON_PROFICIENCY_MORNINGSTAR;
|
||||
|
||||
case BASE_ITEM_RAPIER:
|
||||
case BASE_ITEM_RAPIER:
|
||||
return FEAT_WEAPON_PROFICIENCY_RAPIER;
|
||||
|
||||
case BASE_ITEM_SCIMITAR:
|
||||
case BASE_ITEM_SCIMITAR:
|
||||
return FEAT_WEAPON_PROFICIENCY_SCIMITAR;
|
||||
|
||||
case BASE_ITEM_SCYTHE:
|
||||
case BASE_ITEM_SCYTHE:
|
||||
return FEAT_WEAPON_PROFICIENCY_SCYTHE;
|
||||
|
||||
case BASE_ITEM_SHORTSPEAR:
|
||||
case BASE_ITEM_SHORTSPEAR:
|
||||
return FEAT_WEAPON_PROFICIENCY_SHORTSPEAR;
|
||||
|
||||
case BASE_ITEM_SHURIKEN:
|
||||
case BASE_ITEM_SHURIKEN:
|
||||
return FEAT_WEAPON_PROFICIENCY_SHURIKEN;
|
||||
|
||||
case BASE_ITEM_SICKLE:
|
||||
case BASE_ITEM_SICKLE:
|
||||
return FEAT_WEAPON_PROFICIENCY_SICKLE;
|
||||
|
||||
case BASE_ITEM_SLING:
|
||||
case BASE_ITEM_SLING:
|
||||
return FEAT_WEAPON_PROFICIENCY_SLING;
|
||||
|
||||
case BASE_ITEM_THROWINGAXE:
|
||||
case BASE_ITEM_THROWINGAXE:
|
||||
return FEAT_WEAPON_PROFICIENCY_THROWING_AXE;
|
||||
|
||||
case BASE_ITEM_CSLASHWEAPON:
|
||||
case BASE_ITEM_CSLASHWEAPON:
|
||||
return FEAT_WEAPON_PROFICIENCY_CREATURE;
|
||||
|
||||
case BASE_ITEM_CPIERCWEAPON:
|
||||
case BASE_ITEM_CPIERCWEAPON:
|
||||
return FEAT_WEAPON_PROFICIENCY_CREATURE;
|
||||
|
||||
case BASE_ITEM_CBLUDGWEAPON:
|
||||
case BASE_ITEM_CBLUDGWEAPON:
|
||||
return FEAT_WEAPON_PROFICIENCY_CREATURE;
|
||||
|
||||
case BASE_ITEM_CSLSHPRCWEAP:
|
||||
case BASE_ITEM_CSLSHPRCWEAP:
|
||||
return FEAT_WEAPON_PROFICIENCY_CREATURE;
|
||||
|
||||
case BASE_ITEM_TRIDENT:
|
||||
case BASE_ITEM_TRIDENT:
|
||||
return FEAT_WEAPON_PROFICIENCY_TRIDENT;
|
||||
|
||||
case BASE_ITEM_DWARVENWARAXE:
|
||||
case BASE_ITEM_DWARVENWARAXE:
|
||||
return FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE;
|
||||
|
||||
case BASE_ITEM_WHIP:
|
||||
case BASE_ITEM_WHIP:
|
||||
return FEAT_WEAPON_PROFICIENCY_WHIP;
|
||||
|
||||
case BASE_ITEM_ELVEN_LIGHTBLADE:
|
||||
case BASE_ITEM_ELVEN_LIGHTBLADE:
|
||||
return FEAT_WEAPON_PROFICIENCY_ELVEN_LIGHTBLADE;
|
||||
|
||||
case BASE_ITEM_ELVEN_THINBLADE:
|
||||
case BASE_ITEM_ELVEN_THINBLADE:
|
||||
return FEAT_WEAPON_PROFICIENCY_ELVEN_THINBLADE;
|
||||
|
||||
case BASE_ITEM_ELVEN_COURTBLADE:
|
||||
case BASE_ITEM_ELVEN_COURTBLADE:
|
||||
return FEAT_WEAPON_PROFICIENCY_ELVEN_COURTBLADE;
|
||||
|
||||
case BASE_ITEM_HEAVY_PICK:
|
||||
case BASE_ITEM_HEAVY_PICK:
|
||||
return FEAT_WEAPON_PROFICIENCY_HEAVY_PICK;
|
||||
|
||||
case BASE_ITEM_LIGHT_PICK:
|
||||
case BASE_ITEM_LIGHT_PICK:
|
||||
return FEAT_WEAPON_PROFICIENCY_LIGHT_PICK;
|
||||
|
||||
case BASE_ITEM_SAI:
|
||||
case BASE_ITEM_SAI:
|
||||
return FEAT_WEAPON_PROFICIENCY_SAI;
|
||||
|
||||
case BASE_ITEM_NUNCHAKU:
|
||||
case BASE_ITEM_NUNCHAKU:
|
||||
return FEAT_WEAPON_PROFICIENCY_NUNCHAKU;
|
||||
|
||||
case BASE_ITEM_FALCHION:
|
||||
case BASE_ITEM_FALCHION:
|
||||
return FEAT_WEAPON_PROFICIENCY_FALCHION;
|
||||
|
||||
case BASE_ITEM_SAP:
|
||||
case BASE_ITEM_SAP:
|
||||
return FEAT_WEAPON_PROFICIENCY_SAP;
|
||||
|
||||
case BASE_ITEM_KATAR:
|
||||
case BASE_ITEM_KATAR:
|
||||
return FEAT_WEAPON_PROFICIENCY_KATAR;
|
||||
|
||||
case BASE_ITEM_HEAVY_MACE:
|
||||
case BASE_ITEM_HEAVY_MACE:
|
||||
return FEAT_WEAPON_PROFICIENCY_HEAVY_MACE;
|
||||
|
||||
case BASE_ITEM_MAUL:
|
||||
case BASE_ITEM_MAUL:
|
||||
return FEAT_WEAPON_PROFICIENCY_MAUL;
|
||||
|
||||
case BASE_ITEM_DOUBLE_SCIMITAR:
|
||||
case BASE_ITEM_DOUBLE_SCIMITAR:
|
||||
return FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR;
|
||||
|
||||
case BASE_ITEM_GOAD:
|
||||
case BASE_ITEM_GOAD:
|
||||
return FEAT_WEAPON_PROFICIENCY_GOAD;
|
||||
|
||||
case BASE_ITEM_EAGLE_CLAW:
|
||||
case BASE_ITEM_EAGLE_CLAW:
|
||||
return FEAT_WEAPON_PROFICIENCY_EAGLE_CLAW;
|
||||
|
||||
default:
|
||||
return FEAT_WEAPON_PROFICIENCY_SIMPLE;
|
||||
default:
|
||||
return FEAT_WEAPON_PROFICIENCY_SIMPLE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1206,11 +1206,12 @@ const int IP_CONST_FEAT_REGENERATION_5 = 24820;
|
||||
const int IP_CONST_FEAT_SCENT = 24821;
|
||||
const int IP_CONST_FEAT_GIANT_RACIAL_TYPE = 24822;
|
||||
|
||||
const int IP_CONST_FEAT_TEMPLATE_ARCHLICH_MARKER = 16401; //:: Archlich
|
||||
const int IP_CONST_FEAT_TEMPLATE_TURN_UNDEAD = 16402;
|
||||
const int IP_CONST_FEAT_TEMPLATE_PROJECTION = 24823;
|
||||
const int IP_CONST_FEAT_TEMPLATE_END_PROJECTION = 24824;
|
||||
const int IP_CONST_FEAT_TEMPLATE_ANIMATE_DEAD = 24825;
|
||||
const int IP_CONST_FEAT_TEMPLATE_ARCHLICH_MARKER = 16401; //:: Archlich
|
||||
const int IP_CONST_FEAT_TEMPLATE_TURN_UNDEAD = 16402;
|
||||
const int IP_CONST_FEAT_TEMPLATE_BAELNORN_MARKER = 16409; //:: Baelnorn
|
||||
const int IP_CONST_FEAT_TEMPLATE_PROJECTION = 24823;
|
||||
const int IP_CONST_FEAT_TEMPLATE_END_PROJECTION = 24824;
|
||||
const int IP_CONST_FEAT_TEMPLATE_ANIMATE_DEAD = 24825;
|
||||
const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_BLESS = 16403; //:: Saint
|
||||
//const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_GUIDANCE = 16404;
|
||||
const int IP_CONST_FEAT_TEMPLATE_SAINT_SLA_RESISTANCE = 16405;
|
||||
|
@ -29,6 +29,10 @@ const int BASE_ITEM_CRAFTED_STAFF = 201;
|
||||
const int BASE_ITEM_ELVEN_LIGHTBLADE = 202;
|
||||
const int BASE_ITEM_ELVEN_THINBLADE = 203;
|
||||
const int BASE_ITEM_ELVEN_COURTBLADE = 204;
|
||||
const int BASE_ITEM_CRAFT_SCEPTER = 249;
|
||||
const int BASE_ITEM_MAGIC_SCEPTER = 250;
|
||||
const int BASE_ITEM_MUNDANE_HERB = 252;
|
||||
const int BASE_ITEM_INFUSED_HERB = 253;
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Player Health Const
|
||||
|
@ -2569,7 +2569,8 @@ int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_S
|
||||
json chosenDisc = JsonObjectGet(discInfo, discipline);
|
||||
if (chosenDisc != JsonNull())
|
||||
{
|
||||
int nManCount = JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER)));
|
||||
int nManCount = (JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER)))
|
||||
+ JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE))));
|
||||
if (nManCount >= prereqs)
|
||||
return TRUE;
|
||||
}
|
||||
@ -3334,3 +3335,5 @@ json GetArchivistNewSpellsList(object oPC=OBJECT_SELF)
|
||||
SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, retValue);
|
||||
return retValue;
|
||||
}
|
||||
|
||||
//:: void main(){}
|
@ -387,8 +387,7 @@ int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass)
|
||||
return TRUE;
|
||||
|
||||
// Arcane Spont
|
||||
if (nClass == CLASS_TYPE_ASSASSIN
|
||||
|| nClass == CLASS_TYPE_BEGUILER
|
||||
if (nClass == CLASS_TYPE_BEGUILER
|
||||
|| nClass == CLASS_TYPE_CELEBRANT_SHARESS
|
||||
|| nClass == CLASS_TYPE_DREAD_NECROMANCER
|
||||
|| nClass == CLASS_TYPE_DUSKBLADE
|
||||
@ -506,8 +505,7 @@ int CanClassUseMetamagicFeats(int nClass)
|
||||
// I don't want to spend the time looping through each class's
|
||||
// feat 2da so this is the list of all classes that are allowed to use the
|
||||
// Spellbook NUI and can use Metamagic
|
||||
return (nClass == CLASS_TYPE_ASSASSIN
|
||||
|| nClass == CLASS_TYPE_BARD
|
||||
return (nClass == CLASS_TYPE_BARD
|
||||
|| nClass == CLASS_TYPE_SORCERER
|
||||
|| nClass == CLASS_TYPE_BEGUILER
|
||||
|| nClass == CLASS_TYPE_DREAD_NECROMANCER
|
||||
@ -527,7 +525,6 @@ int CanClassUseSuddenMetamagicFeats(int nClass)
|
||||
// Spellbook NUI and can use Sudden Metamagic
|
||||
return (nClass == CLASS_TYPE_SHADOWLORD
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST
|
||||
|| nClass == CLASS_TYPE_ASSASSIN
|
||||
|| nClass == CLASS_TYPE_BARD
|
||||
|| nClass == CLASS_TYPE_BEGUILER
|
||||
|| nClass == CLASS_TYPE_DREAD_NECROMANCER
|
||||
@ -845,4 +842,4 @@ int IsSpellbookNUIOpen(object oPC)
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
@ -22,6 +22,9 @@ const int SPELL_BCM_RENDING_CLAWS = 17997;
|
||||
//:: Complete Warrior
|
||||
const int SPELL_RANGED_DISARM = 3493;
|
||||
|
||||
//:: Tome of Battle
|
||||
const int SPELL_TOB_SNAP_KICK = 3794;
|
||||
|
||||
//marshal
|
||||
const int SPELL_MINAUR_DEMFORT = 3500;
|
||||
const int SPELL_MINAUR_FORCEWILL = 3501;
|
||||
@ -1289,6 +1292,69 @@ const int SPELL_SUMMON_CREATURE_IX_WATER = 3200;
|
||||
//:: Player's Handbook Spells
|
||||
const int SPELL_SPIRITUAL_WEAPON = 17249;
|
||||
|
||||
const int SPELL_SUMMON_NATURES_ALLY_1 = 17000;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_1_DIREBADGER = 17001;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_1_DIRERAT = 17002;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_1_DOG = 17003;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_1_HAWK = 17004;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_1_TINY_VIPER = 17005;
|
||||
|
||||
const int SPELL_SUMMON_NATURES_ALLY_2 = 17010;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_2_DIREBOAR = 17011;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_2_COOSHEE = 17012;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_2_WOLF = 17013;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_2_SMALL_VIPER = 17014;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_2_BLACKBEAR = 17015;
|
||||
|
||||
const int SPELL_SUMMON_NATURES_ALLY_3 = 17020;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_3_BROWNBEAR = 17021;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_3_DIREWOLK = 17022;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_3_LARGE_VIPER = 17023;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_3_LEOPARD = 17024;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_3_SATYR = 17025;
|
||||
|
||||
const int SPELL_SUMMON_NATURES_ALLY_4 = 17030;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_4_LION = 17031;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_4_POLAR_BEAR = 17032;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_4_DIRE_SPIDER = 17033;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_4_HUGE_VIPER = 17034;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_4_WEREBOAR = 17035;
|
||||
|
||||
const int SPELL_SUMMON_NATURES_ALLY_5 = 17040;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_5_MED_AIR = 17041;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_5_MED_EARTH = 17042;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_5_MED_FIRE = 17043;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_5_MED_WATER = 17044;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_5_DIRE_BEAR = 17045;
|
||||
|
||||
const int SPELL_SUMMON_NATURES_ALLY_6 = 17050;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_6_LG_AIR = 17051;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_6_LG_EARTH = 17052;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_6_LG_FIRE = 17053;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_6_LG_WATER = 17054;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_6_DIRETIGER = 17055;
|
||||
|
||||
const int SPELL_SUMMON_NATURES_ALLY_7 = 17060;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_7_BULETTE = 17061;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_7_INVSTALKER = 17062;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_7_PIXIE = 17063;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_7_GORGON = 17064;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_7_MANTICORE = 17065;
|
||||
|
||||
const int SPELL_SUMMON_NATURES_ALLY_8 = 17070;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_8_GR_AIR = 17071;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_8_GR_EARTH = 17072;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_8_GR_FIRE = 17073;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_8_GR_WATER = 17074;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_8_NYMPH = 17075;
|
||||
|
||||
const int SPELL_SUMMON_NATURES_ALLY_9 = 17080;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_9_ELD_AIR = 17081;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_9_ELD_EARTH = 17082;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_9_ELD_FIRE = 17083;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_9_ELD_WATER = 17084;
|
||||
const int SPELL_SUMMON_NATURES_ALLY_9_ARANEA = 17085;
|
||||
|
||||
//:: Player's Handbook II Spells
|
||||
const int SPELL_CHASING_PERFECTION = 2479;
|
||||
|
||||
@ -1297,12 +1363,34 @@ const int SPELL_SPIRIT_WORM = 17248;
|
||||
const int SPELL_FORCE_MISSILES = 2480;
|
||||
|
||||
//:: Masters of the Wild Spells
|
||||
const int SPELL_FORESTFOLD = 17090;
|
||||
const int SPELL_CREEPING_COLD = 17091;
|
||||
const int SPELL_GREATER_CREEPING_COLD = 17092;
|
||||
const int SPELL_CONTROL_PLANTS = 17237;
|
||||
const int SPELL_ADRENALINE_SURGE = 17238;
|
||||
const int SPELL_INVULNERABILITY_TO_ELEMENTS = 17239;
|
||||
const int SPELL_REGEN_RING = 17241;
|
||||
const int SPELL_REGEN_CIRCLE = 17242;
|
||||
const int SPELL_REGEN_LIGHT_WOUNDS = 17243;
|
||||
const int SPELL_REGEN_MODERATE_WOUNDS = 17244;
|
||||
const int SPELL_REGEN_SERIOUS_WOUNDS = 17245;
|
||||
const int SPELL_REGEN_CRITICAL_WOUNDS = 17246;
|
||||
const int SPELL_SPEED_WIND = 17247;
|
||||
const int SPELL_TORTISE_SHELL = 17250;
|
||||
const int SPELL_TORTISE_SHELL = 17250;
|
||||
|
||||
//:: Book of Exalted Deeds Spells
|
||||
const int SPELL_LEONALS_ROAR = 17240;
|
||||
|
||||
//:: Master of the Wild Feats
|
||||
const int SPELL_VL_WILD_SHAPE_TREANT = 17989;
|
||||
const int SPELL_VL_ANIMATE_TREE = 17990;
|
||||
const int SPELL_PLANT_DEFIANCE = 17991;
|
||||
const int SPELL_PLANT_CONTROL = 17992;
|
||||
|
||||
//:: Book of Exalted Deeds Feats
|
||||
const int SPELL_FOT_LEONALS_ROAR = 17993;
|
||||
const int SPELL_FOT_LIONS_SWIFTNESS = 17994;
|
||||
const int SPELL_FAVORED_OF_THE_COMPANIONS = 17995;
|
||||
|
||||
//x
|
||||
const int SPELL_TENSERS_FLOATING_DISK = 3849;
|
||||
|
@ -299,6 +299,7 @@ int SpellfireDrainItem(object oPC, object oItem, int bCharged = TRUE, int bSingl
|
||||
{
|
||||
|
||||
if((nBase == BASE_ITEM_POTIONS) ||
|
||||
(nBase == BASE_ITEM_INFUSED_HERB) ||
|
||||
(nBase == BASE_ITEM_SCROLL) ||
|
||||
(nBase == BASE_ITEM_SPELLSCROLL) ||
|
||||
(nBase == BASE_ITEM_BLANK_POTION) ||
|
||||
@ -382,6 +383,7 @@ void SpellfireDrain(object oPC, object oTarget, int bCharged = TRUE, int bExempt
|
||||
if(GetPRCSwitch(PRC_SPELLFIRE_DISALLOW_DRAIN_SCROLL_POTION) &&
|
||||
((nBase == BASE_ITEM_POTIONS) ||
|
||||
(nBase == BASE_ITEM_SCROLL) ||
|
||||
(nBase == BASE_ITEM_INFUSED_HERB) ||
|
||||
(nBase == BASE_ITEM_BLANK_POTION) ||
|
||||
(nBase == BASE_ITEM_BLANK_SCROLL)
|
||||
)
|
||||
@ -525,3 +527,4 @@ void SpellfireCrown(object oPC)
|
||||
}
|
||||
}
|
||||
|
||||
//:: void main() {}
|
@ -18,6 +18,7 @@ const int TEMPLATE_CURST = 26;
|
||||
const int TEMPLATE_GRAVETOUCHED_GHOUL = 29;
|
||||
const int TEMPLATE_CRYPTSPAWN = 30;
|
||||
const int TEMPLATE_ARCHLICH = 99;
|
||||
const int TEMPLATE_BAELNORN = 100;
|
||||
const int TEMPLATE_LICH = 101;
|
||||
const int TEMPLATE_DEMILICH = 102;
|
||||
const int TEMPLATE_NECROPOLITAN = 105;
|
||||
|
@ -13,7 +13,7 @@
|
||||
//:: Created On: 2003-05-09
|
||||
//:: Last Updated On: 2003-10-14
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "prc_x2_itemprop"
|
||||
|
||||
struct craft_struct
|
||||
{
|
||||
@ -44,22 +44,24 @@ const string X2_CI_CRAFTSKILL_CONV ="x2_p_craftskills";
|
||||
/* moved to be code switches
|
||||
|
||||
const int X2_CI_BREWPOTION_MAXLEVEL = 3; // Max Level for potions
|
||||
const int X2_CI_BREWPOTION_COSTMODIFIER = 50; // gp Brew Potion XPCost Modifier
|
||||
const int PRC_X2_BREWPOTION_COSTMODIFIER = 50; // gp Brew Potion XPCost Modifier
|
||||
|
||||
// Scribe Scroll related constants
|
||||
const int X2_CI_SCRIBESCROLL_COSTMODIFIER = 25; // Scribescroll Cost Modifier
|
||||
const int PRC_X2_SCRIBESCROLL_COSTMODIFIER = 25; // Scribescroll Cost Modifier
|
||||
|
||||
// Craft Wand related constants
|
||||
const int X2_CI_CRAFTWAND_MAXLEVEL = 4;
|
||||
const int X2_CI_CRAFTWAND_COSTMODIFIER = 750;
|
||||
const int PRC_X2_CRAFTWAND_MAXLEVEL = 4;
|
||||
const int PRC_X2_CRAFTWAND_COSTMODIFIER = 750;
|
||||
*/
|
||||
const int X2_CI_BREWPOTION_FEAT_ID = 944; // Brew Potion feat simulation
|
||||
const int X2_CI_SCRIBESCROLL_FEAT_ID = 945;
|
||||
const int X2_CI_CRAFTWAND_FEAT_ID = 946;
|
||||
const int X2_CI_CRAFTROD_FEAT_ID = 2927;
|
||||
const int X2_CI_CRAFTROD_EPIC_FEAT_ID = 3490;
|
||||
const int X2_CI_CRAFTSTAFF_FEAT_ID = 2928;
|
||||
const int X2_CI_CRAFTSTAFF_EPIC_FEAT_ID = 3491;
|
||||
const int X2_CI_BREWPOTION_FEAT_ID = 944; // Brew Potion feat simulation
|
||||
const int X2_CI_SCRIBESCROLL_FEAT_ID = 945;
|
||||
const int X2_CI_CRAFTWAND_FEAT_ID = 946;
|
||||
const int X2_CI_CRAFTROD_FEAT_ID = 2927;
|
||||
const int X2_CI_CRAFTROD_EPIC_FEAT_ID = 3490;
|
||||
const int X2_CI_CRAFTSTAFF_FEAT_ID = 2928;
|
||||
const int X2_CI_CRAFTSTAFF_EPIC_FEAT_ID = 3491;
|
||||
const int X2_CI_CREATEINFUSION_FEAT_ID = 25960;
|
||||
|
||||
const string X2_CI_BREWPOTION_NEWITEM_RESREF = "x2_it_pcpotion"; // ResRef for new potion item
|
||||
const string X2_CI_SCRIBESCROLL_NEWITEM_RESREF = "x2_it_pcscroll"; // ResRef for new scroll item
|
||||
const string X2_CI_CRAFTWAND_NEWITEM_RESREF = "x2_it_pcwand";
|
||||
@ -185,6 +187,17 @@ int CheckAlternativeCrafting(object oPC, int nSpell, struct craft_cost_struct co
|
||||
// Returns the maximum of caster level used and other effective levels from emulating spells
|
||||
int GetAlternativeCasterLevel(object oPC, int nLevel);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Create and Return an herbal infusion with an item property
|
||||
// matching nSpellID.
|
||||
// -----------------------------------------------------------------------------
|
||||
object CICreateInfusion(object oCreator, int nSpellID);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Returns TRUE if the player successfully performed Create Infusion
|
||||
// -----------------------------------------------------------------------------
|
||||
int CICraftCheckCreateInfusion(object oSpellTarget, object oCaster, int nID = 0);
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Include section */
|
||||
//////////////////////////////////////////////////
|
||||
@ -194,6 +207,7 @@ int GetAlternativeCasterLevel(object oPC, int nLevel);
|
||||
#include "prc_inc_newip"
|
||||
#include "prc_inc_spells"
|
||||
#include "prc_add_spell_dc"
|
||||
#include "inc_infusion"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function definitions */
|
||||
@ -261,7 +275,8 @@ int CIGetIsCraftFeatBaseItem(object oItem)
|
||||
nBt == BASE_ITEM_BLANK_SCROLL ||
|
||||
nBt == BASE_ITEM_BLANK_WAND ||
|
||||
nBt == BASE_ITEM_CRAFTED_ROD ||
|
||||
nBt == BASE_ITEM_CRAFTED_STAFF)
|
||||
nBt == BASE_ITEM_CRAFTED_STAFF ||
|
||||
nBt == BASE_ITEM_MUNDANE_HERB)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
@ -453,11 +468,158 @@ object CICraftCraftWand(object oCreator, int nSpellID )
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Georg, 2003-06-12
|
||||
// Create and Return a magic wand with an item property
|
||||
// matching nSpellID. Charges are set to d20 + casterlevel
|
||||
// capped at 50 max
|
||||
// Create and Return a magic scroll with an item property
|
||||
// matching nSpellID.
|
||||
// -----------------------------------------------------------------------------
|
||||
object CICraftScribeScroll(object oCreator, int nSpellID)
|
||||
{
|
||||
if (DEBUG) DoDebug("CICraftScribeScroll: Enter (nSpellID=" + IntToString(nSpellID) + ")");
|
||||
|
||||
// Keep original and compute one-step master (if subradial)
|
||||
int nSpellOriginal = nSpellID;
|
||||
int nSpellMaster = nSpellOriginal;
|
||||
if (GetIsSubradialSpell(nSpellOriginal))
|
||||
{
|
||||
nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal);
|
||||
if (DEBUG) DoDebug("CICraftScribeScroll: subradial detected original=" + IntToString(nSpellOriginal) + " master=" + IntToString(nSpellMaster));
|
||||
}
|
||||
|
||||
// Prefer iprp mapping for the original, fallback to master
|
||||
int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal);
|
||||
int nSpellUsedForIP = nSpellOriginal;
|
||||
if (nPropID < 0)
|
||||
{
|
||||
if (DEBUG) DoDebug("CICraftScribeScroll: no iprp for original " + IntToString(nSpellOriginal) + ", trying master " + IntToString(nSpellMaster));
|
||||
nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster);
|
||||
nSpellUsedForIP = nSpellMaster;
|
||||
}
|
||||
|
||||
// If neither original nor master has an iprp row, we can still try templates,
|
||||
// but most templates expect a matching iprp. Bail out now if nothing found.
|
||||
if (nPropID < 0)
|
||||
{
|
||||
if (DEBUG) DoDebug("CICraftScribeScroll: no iprp_spells entry for original/master -> aborting");
|
||||
FloatingTextStringOnCreature("This spell cannot be scribed (no item property mapping).", oCreator, FALSE);
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
if (DEBUG) DoDebug("CICraftScribeScroll: using spell " + IntToString(nSpellUsedForIP) + " (iprp row " + IntToString(nPropID) + ") for item property");
|
||||
|
||||
// Material component check (based on resolved iprp row)
|
||||
string sMat = GetMaterialComponentTag(nPropID);
|
||||
if (sMat != "")
|
||||
{
|
||||
object oMat = GetItemPossessedBy(oCreator, sMat);
|
||||
if (oMat == OBJECT_INVALID)
|
||||
{
|
||||
FloatingTextStrRefOnCreature(83374, oCreator); // Missing material component
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyObject(oMat);
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve class and scroll template
|
||||
int nClass = PRCGetLastSpellCastClass();
|
||||
string sClass = "";
|
||||
switch (nClass)
|
||||
{
|
||||
case CLASS_TYPE_WIZARD:
|
||||
case CLASS_TYPE_SORCERER: sClass = "Wiz_Sorc"; break;
|
||||
case CLASS_TYPE_CLERIC:
|
||||
case CLASS_TYPE_UR_PRIEST: sClass = "Cleric"; break;
|
||||
case CLASS_TYPE_PALADIN: sClass = "Paladin"; break;
|
||||
case CLASS_TYPE_DRUID:
|
||||
case CLASS_TYPE_BLIGHTER: sClass = "Druid"; break;
|
||||
case CLASS_TYPE_RANGER: sClass = "Ranger"; break;
|
||||
case CLASS_TYPE_BARD: sClass = "Bard"; break;
|
||||
case CLASS_TYPE_ASSASSIN: sClass = "Assassin"; break;
|
||||
}
|
||||
|
||||
object oTarget = OBJECT_INVALID;
|
||||
string sResRef = "";
|
||||
|
||||
// Try to find a class-specific scroll template.
|
||||
if (sClass != "")
|
||||
{
|
||||
// Try original first (so if you made a subradial-specific template it will be used)
|
||||
sResRef = Get2DACache(X2_CI_2DA_SCROLLS, sClass, nSpellOriginal);
|
||||
if (sResRef == "")
|
||||
{
|
||||
// fallback to the spell that matched an iprp row (master or original)
|
||||
sResRef = Get2DACache(X2_CI_2DA_SCROLLS, sClass, nSpellUsedForIP);
|
||||
}
|
||||
if (sResRef != "")
|
||||
{
|
||||
oTarget = CreateItemOnObject(sResRef, oCreator);
|
||||
if (DEBUG) DoDebug("CICraftScribeScroll: created template " + sResRef + " for class " + sClass);
|
||||
// Ensure template uses the correct cast-spell property: replace the template's cast-spell IP with ours
|
||||
if (oTarget != OBJECT_INVALID)
|
||||
{
|
||||
itemproperty ipIter = GetFirstItemProperty(oTarget);
|
||||
while (GetIsItemPropertyValid(ipIter))
|
||||
{
|
||||
if (GetItemPropertyType(ipIter) == ITEM_PROPERTY_CAST_SPELL)
|
||||
{
|
||||
RemoveItemProperty(oTarget, ipIter);
|
||||
break;
|
||||
}
|
||||
ipIter = GetNextItemProperty(oTarget);
|
||||
}
|
||||
itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE);
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no template or sClass was empty, create generic scroll and add itemprop.
|
||||
if (oTarget == OBJECT_INVALID)
|
||||
{
|
||||
sResRef = "craft_scroll";
|
||||
oTarget = CreateItemOnObject(sResRef, oCreator);
|
||||
if (oTarget == OBJECT_INVALID)
|
||||
{
|
||||
WriteTimestampedLogEntry("CICraftScribeScroll: failed to create craft_scroll template.");
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
// Remove existing default IP and add correct one
|
||||
itemproperty ipFirst = GetFirstItemProperty(oTarget);
|
||||
if (GetIsItemPropertyValid(ipFirst))
|
||||
RemoveItemProperty(oTarget, ipFirst);
|
||||
|
||||
itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE);
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget);
|
||||
}
|
||||
|
||||
// Add PRC metadata (use the same spell that matched the iprp row so metadata and IP line up)
|
||||
if (GetPRCSwitch(PRC_SCRIBE_SCROLL_CASTER_LEVEL))
|
||||
{
|
||||
int nCasterLevel = GetAlternativeCasterLevel(oCreator, PRCGetCasterLevel(oCreator));
|
||||
itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpellUsedForIP, nCasterLevel);
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipLevel, oTarget);
|
||||
|
||||
itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpellUsedForIP, PRCGetMetaMagicFeat());
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipMeta, oTarget);
|
||||
|
||||
int nDC = PRCGetSpellSaveDC(nSpellUsedForIP, GetSpellSchool(nSpellUsedForIP), OBJECT_SELF);
|
||||
itemproperty ipDC = ItemPropertyCastSpellDC(nSpellUsedForIP, nDC);
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipDC, oTarget);
|
||||
}
|
||||
|
||||
if (oTarget == OBJECT_INVALID)
|
||||
{
|
||||
WriteTimestampedLogEntry("prc_x2_craft::CICraftScribeScroll failed - Resref: " + sResRef + " Class: " + sClass + "(" + IntToString(nClass) + ") " + " SpellID " + IntToString(nSpellID));
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
if (DEBUG) DoDebug("CICraftScribeScroll: Success - created scroll " + sResRef + " for spell " + IntToString(nSpellUsedForIP));
|
||||
return oTarget;
|
||||
}
|
||||
|
||||
|
||||
/* object CICraftScribeScroll(object oCreator, int nSpellID)
|
||||
{
|
||||
int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellID);
|
||||
object oTarget;
|
||||
@ -491,6 +653,7 @@ object CICraftScribeScroll(object oCreator, int nSpellID)
|
||||
break;
|
||||
case CLASS_TYPE_CLERIC:
|
||||
case CLASS_TYPE_UR_PRIEST:
|
||||
case CLASS_TYPE_OCULAR:
|
||||
sClass = "Cleric";
|
||||
break;
|
||||
case CLASS_TYPE_PALADIN:
|
||||
@ -506,6 +669,9 @@ object CICraftScribeScroll(object oCreator, int nSpellID)
|
||||
case CLASS_TYPE_BARD:
|
||||
sClass = "Bard";
|
||||
break;
|
||||
case CLASS_TYPE_ASSASSIN:
|
||||
sClass = "Assassin";
|
||||
break;
|
||||
}
|
||||
string sResRef;
|
||||
if (sClass != "")
|
||||
@ -542,7 +708,7 @@ object CICraftScribeScroll(object oCreator, int nSpellID)
|
||||
}
|
||||
return oTarget;
|
||||
}
|
||||
|
||||
*/
|
||||
// -----------------------------------------------------------------------------
|
||||
// Returns TRUE if the player used the last spell to brew a potion
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -593,7 +759,7 @@ These dont work as IPs since they are hardcoded */
|
||||
// -------------------------------------------------------------------------
|
||||
// check if spell is below maxlevel for brew potions
|
||||
// -------------------------------------------------------------------------
|
||||
int nPotionMaxLevel = GetPRCSwitch(X2_CI_BREWPOTION_MAXLEVEL);
|
||||
int nPotionMaxLevel = GetPRCSwitch(PRC_X2_BREWPOTION_MAXLEVEL);
|
||||
if(nPotionMaxLevel == 0)
|
||||
nPotionMaxLevel = 3;
|
||||
|
||||
@ -624,7 +790,7 @@ These dont work as IPs since they are hardcoded */
|
||||
// -------------------------------------------------------------------------
|
||||
// XP/GP Cost Calculation
|
||||
// -------------------------------------------------------------------------
|
||||
int nCostModifier = GetPRCSwitch(X2_CI_BREWPOTION_COSTMODIFIER);
|
||||
int nCostModifier = GetPRCSwitch(PRC_X2_BREWPOTION_COSTMODIFIER);
|
||||
if(nCostModifier == 0)
|
||||
nCostModifier = 50;
|
||||
int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_BREW_POTION_CASTER_LEVEL);
|
||||
@ -728,7 +894,7 @@ int CICraftCheckScribeScroll(object oSpellTarget, object oCaster, int nID = 0)
|
||||
// XP/GP Cost Calculation
|
||||
// -------------------------------------------------------------------------
|
||||
int nLevel = CIGetSpellInnateLevel(nID,TRUE);
|
||||
int nCostModifier = GetPRCSwitch(X2_CI_SCRIBESCROLL_COSTMODIFIER);
|
||||
int nCostModifier = GetPRCSwitch(PRC_X2_SCRIBESCROLL_COSTMODIFIER);
|
||||
if(nCostModifier == 0)
|
||||
nCostModifier = 25;
|
||||
int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_SCRIBE_SCROLL_CASTER_LEVEL);
|
||||
@ -884,7 +1050,7 @@ These dont work as IPs since they are hardcoded */
|
||||
// -------------------------------------------------------------------------
|
||||
// check if spell is below maxlevel for craft want
|
||||
// -------------------------------------------------------------------------
|
||||
int nMaxLevel = GetPRCSwitch(X2_CI_CRAFTWAND_MAXLEVEL);
|
||||
int nMaxLevel = GetPRCSwitch(PRC_X2_CRAFTWAND_MAXLEVEL);
|
||||
if(nMaxLevel == 0)
|
||||
nMaxLevel = 4;
|
||||
if (nLevel > nMaxLevel)
|
||||
@ -896,7 +1062,7 @@ These dont work as IPs since they are hardcoded */
|
||||
// -------------------------------------------------------------------------
|
||||
// XP/GP Cost Calculation
|
||||
// -------------------------------------------------------------------------
|
||||
int nCostMod = GetPRCSwitch(X2_CI_CRAFTWAND_COSTMODIFIER);
|
||||
int nCostMod = GetPRCSwitch(PRC_X2_CRAFTWAND_COSTMODIFIER);
|
||||
if(nCostMod == 0)
|
||||
nCostMod = 750;
|
||||
int nCost = CIGetCraftGPCost(nLevel, nCostMod, PRC_CRAFT_WAND_CASTER_LEVEL);
|
||||
@ -1027,7 +1193,7 @@ int CICraftCheckCraftStaff(object oSpellTarget, object oCaster, int nSpellID = 0
|
||||
These dont work as IPs since they are hardcoded */
|
||||
}
|
||||
}
|
||||
int nCostMod = GetPRCSwitch(X2_CI_CRAFTSTAFF_COSTMODIFIER);
|
||||
int nCostMod = GetPRCSwitch(PRC_X2_CRAFTSTAFF_COSTMODIFIER);
|
||||
if(!nCostMod) nCostMod = 750;
|
||||
int nLvlRow = IPGetIPConstCastSpellFromSpellID(nSpellID);
|
||||
int nCLevel = StringToInt(Get2DACache("iprp_spells","CasterLvl",nLvlRow));
|
||||
@ -1175,7 +1341,7 @@ int CICraftCheckCraftRod(object oSpellTarget, object oCaster, int nSpellID = 0)
|
||||
These dont work as IPs since they are hardcoded */
|
||||
}
|
||||
}
|
||||
int nCostMod = GetPRCSwitch(X2_CI_CRAFTROD_COSTMODIFIER);
|
||||
int nCostMod = GetPRCSwitch(PRC_X2_CRAFTROD_COSTMODIFIER);
|
||||
if(!nCostMod) nCostMod = 750;
|
||||
int nLvlRow = IPGetIPConstCastSpellFromSpellID(nSpellID);
|
||||
int nCLevel = StringToInt(Get2DACache("iprp_spells","CasterLvl",nLvlRow));
|
||||
@ -1544,7 +1710,7 @@ int AttuneGem(object oTarget = OBJECT_INVALID, object oCaster = OBJECT_INVALID,
|
||||
// No point scribing Gems from items, and its not allowed.
|
||||
if (oItem != OBJECT_INVALID)
|
||||
{
|
||||
FloatingTextStringOnCreature("You cannot scribe a Gem from an item.", oCaster, FALSE);
|
||||
FloatingTextStringOnCreature("You cannot attune a Gem from an item.", oCaster, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
// oTarget here should be the gem. If it's not, fail.
|
||||
@ -1951,7 +2117,13 @@ int CIGetSpellWasUsedForItemCreation(object oSpellTarget)
|
||||
// -------------------------------------------------
|
||||
nRet = CICraftCheckCraftStaff(oSpellTarget,oCaster);
|
||||
break;
|
||||
|
||||
|
||||
case BASE_ITEM_MUNDANE_HERB :
|
||||
// -------------------------------------------------
|
||||
// Create Infusion
|
||||
// -------------------------------------------------
|
||||
nRet = CICraftCheckCreateInfusion(oSpellTarget,oCaster);
|
||||
break;
|
||||
// you could add more crafting basetypes here....
|
||||
}
|
||||
|
||||
@ -2740,6 +2912,11 @@ int GetMagicalArtisanFeat(int nCraftingFeat)
|
||||
nReturn = FEAT_MAGICAL_ARTISAN_CRAFT_SKULL_TALISMAN;
|
||||
break;
|
||||
}
|
||||
case FEAT_CREATE_INFUSION:
|
||||
{
|
||||
nReturn = FEAT_MAGICAL_ARTISAN_CREATE_INFUSION;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if(DEBUG) DoDebug("GetMagicalArtisanFeat: invalid crafting feat");
|
||||
@ -2941,6 +3118,306 @@ int GetAlternativeCasterLevel(object oPC, int nLevel)
|
||||
return nLevel;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Returns TRUE if the player successfully performed Create Infusion
|
||||
// -----------------------------------------------------------------------------
|
||||
int CICraftCheckCreateInfusion(object oSpellTarget, object oCaster, int nID = 0)
|
||||
{
|
||||
if (nID == 0) nID = PRCGetSpellId();
|
||||
|
||||
int bIsSubradial = GetIsSubradialSpell(nID);
|
||||
|
||||
if(bIsSubradial)
|
||||
{
|
||||
nID = GetMasterSpellFromSubradial(nID);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if the caster has the Create Infusion feat
|
||||
// -------------------------------------------------------------------------
|
||||
if (!GetHasFeat(FEAT_CREATE_INFUSION, oCaster))
|
||||
{
|
||||
FloatingTextStrRefOnCreature(40487, oCaster); // Missing feat
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Divine spellcasters only
|
||||
// -------------------------------------------------------------------------
|
||||
int nClass = PRCGetLastSpellCastClass();
|
||||
if (!GetIsDivineClass(nClass))
|
||||
{
|
||||
FloatingTextStringOnCreature("Only divine casters can create infusions.", oCaster, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if spell is restricted for Create Infusion
|
||||
// -------------------------------------------------------------------------
|
||||
if (CIGetIsSpellRestrictedFromCraftFeat(nID, X2_CI_CREATEINFUSION_FEAT_ID))
|
||||
{
|
||||
FloatingTextStrRefOnCreature(83451, oCaster); // Spell not allowed
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Optional PnP Herb check
|
||||
// -------------------------------------------------------------------------
|
||||
int bPnPHerbs = GetPRCSwitch(PRC_CREATE_INFUSION_OPTIONAL_HERBS);
|
||||
if(bPnPHerbs)
|
||||
{
|
||||
int nSpellschool = GetSpellSchool(nID);
|
||||
int nHerbSchool = GetHerbsSpellSchool(oSpellTarget);
|
||||
|
||||
int nSpellLevel = PRCGetSpellLevelForClass(nID, nClass);
|
||||
int nHerbLevel = GetHerbsInfusionSpellLevel(oSpellTarget);
|
||||
|
||||
if(nSpellschool != nHerbSchool)
|
||||
{
|
||||
// Herb is for wrong spellschool
|
||||
FloatingTextStringOnCreature("This herb isn't appropriate for this spell school", oCaster);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if(nSpellLevel > nHerbLevel)
|
||||
{
|
||||
// Herb spell circle level too low
|
||||
FloatingTextStringOnCreature("This herb isn't appropriate for this spell level", oCaster);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XP/GP Cost Calculation
|
||||
// -------------------------------------------------------------------------
|
||||
int nLevel = CIGetSpellInnateLevel(nID, TRUE);
|
||||
int nCostModifier = GetPRCSwitch(PRC_X2_CREATEINFUSION_COSTMODIFIER);
|
||||
if (nCostModifier == 0)
|
||||
nCostModifier = 25;
|
||||
|
||||
int nCost = CIGetCraftGPCost(nLevel, nCostModifier, PRC_CREATE_INFUSION_CASTER_LEVEL);
|
||||
struct craft_cost_struct costs = GetModifiedCostsFromBase(nCost, oCaster, FEAT_CREATE_INFUSION, FALSE);
|
||||
|
||||
// Adjust level for metamagic
|
||||
if (GetPRCSwitch(PRC_CREATE_INFUSION_CASTER_LEVEL))
|
||||
{
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
switch(nMetaMagic)
|
||||
{
|
||||
case METAMAGIC_EMPOWER: nLevel += 2; break;
|
||||
case METAMAGIC_EXTEND: nLevel += 1; break;
|
||||
case METAMAGIC_MAXIMIZE: nLevel += 3; break;
|
||||
// Unsupported metamagic IPs not added
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Check Gold
|
||||
// -------------------------------------------------------------------------
|
||||
if (!GetHasGPToSpend(oCaster, costs.nGoldCost))
|
||||
{
|
||||
FloatingTextStrRefOnCreature(3786, oCaster); // Not enough gold
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Check XP
|
||||
// -------------------------------------------------------------------------
|
||||
if (!GetHasXPToSpend(oCaster, costs.nXPCost))
|
||||
{
|
||||
FloatingTextStrRefOnCreature(3785, oCaster); // Not enough XP
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Check alternative spell emulation requirements
|
||||
// -------------------------------------------------------------------------
|
||||
if (!CheckAlternativeCrafting(oCaster, nID, costs))
|
||||
{
|
||||
FloatingTextStringOnCreature("*Crafting failed!*", oCaster, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Create the infused herb item
|
||||
// -------------------------------------------------------------------------
|
||||
object oInfusion = CICreateInfusion(oCaster, nID);
|
||||
|
||||
if (GetIsObjectValid(oInfusion))
|
||||
{
|
||||
// Get the spell's display name from spells.2da via TLK
|
||||
int nNameStrRef = StringToInt(Get2DAString("spells", "Name", nID));
|
||||
string sSpellName = GetStringByStrRef(nNameStrRef);
|
||||
|
||||
// Rename the item
|
||||
string sNewName = "Infusion of " + sSpellName;
|
||||
SetName(oInfusion, sNewName);
|
||||
|
||||
// Post-creation actions
|
||||
SetIdentified(oInfusion, TRUE);
|
||||
ActionPlayAnimation(ANIMATION_FIREFORGET_READ, 1.0);
|
||||
SpendXP(oCaster, costs.nXPCost);
|
||||
SpendGP(oCaster, costs.nGoldCost);
|
||||
DestroyObject(oSpellTarget);
|
||||
FloatingTextStrRefOnCreature(8502, oCaster); // Item creation successful
|
||||
|
||||
if (!costs.nTimeCost) costs.nTimeCost = 1;
|
||||
AdvanceTimeForPlayer(oCaster, RoundsToSeconds(costs.nTimeCost));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatingTextStringOnCreature("Infusion creation failed", oCaster); // Item creation failed
|
||||
FloatingTextStrRefOnCreature(76417, oCaster); // Item creation failed
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* // -------------------------------------------------------------------------
|
||||
// Create the infused herb item
|
||||
// -------------------------------------------------------------------------
|
||||
object oInfusion = CICreateInfusion(oCaster, nID);
|
||||
|
||||
if (GetIsObjectValid(oInfusion))
|
||||
{
|
||||
SetIdentified(oInfusion, TRUE);
|
||||
ActionPlayAnimation(ANIMATION_FIREFORGET_READ, 1.0);
|
||||
SpendXP(oCaster, costs.nXPCost);
|
||||
SpendGP(oCaster, costs.nGoldCost);
|
||||
DestroyObject(oSpellTarget);
|
||||
FloatingTextStrRefOnCreature(8502, oCaster); // Item creation successful
|
||||
|
||||
if (!costs.nTimeCost) costs.nTimeCost = 1;
|
||||
AdvanceTimeForPlayer(oCaster, RoundsToSeconds(costs.nTimeCost));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatingTextStringOnCreature("Infusion creation failed", oCaster); // Item creation failed
|
||||
FloatingTextStrRefOnCreature(76417, oCaster); // Item creation failed
|
||||
return TRUE;
|
||||
} */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Create and return an herbal infusion with an item property matching nSpellID
|
||||
// -----------------------------------------------------------------------------
|
||||
object CICreateInfusion(object oCreator, int nSpellID)
|
||||
{
|
||||
if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: Entering function");
|
||||
|
||||
// Keep the original spell id the engine gave us (may be a subradial)
|
||||
int nSpellOriginal = nSpellID;
|
||||
if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellOriginal is "+IntToString(nSpellOriginal)+".");
|
||||
|
||||
// Compute the master if this is a subradial. Keep original intact.
|
||||
int nSpellMaster = nSpellOriginal;
|
||||
if (GetIsSubradialSpell(nSpellOriginal))
|
||||
{
|
||||
nSpellMaster = GetMasterSpellFromSubradial(nSpellOriginal);
|
||||
if (DEBUG) DoDebug("CICreateInfusion: detected subradial " + IntToString(nSpellOriginal) + " master -> " + IntToString(nSpellMaster));
|
||||
}
|
||||
if (DEBUG) DoDebug("prc_x2_craft >> CICreateInfusion: nSpellMaster is "+IntToString(nSpellMaster)+".");
|
||||
|
||||
// Try to find an iprp_spells row for the original subradial first (preferred).
|
||||
int nPropID = IPGetIPConstCastSpellFromSpellID(nSpellOriginal);
|
||||
int nSpellUsedForIP = nSpellOriginal;
|
||||
|
||||
// If not found for original, fall back to the master/base spell.
|
||||
if (nPropID < 0)
|
||||
{
|
||||
if (DEBUG) DoDebug("CICreateInfusion: no iprp row for original " + IntToString(nSpellOriginal) + ", trying master " + IntToString(nSpellMaster));
|
||||
nPropID = IPGetIPConstCastSpellFromSpellID(nSpellMaster);
|
||||
nSpellUsedForIP = nSpellMaster;
|
||||
}
|
||||
|
||||
// If still invalid, bail out with a helpful message
|
||||
if (nPropID < 0)
|
||||
{
|
||||
if (DEBUG) DoDebug("CICreateInfusion: No iprp_spells entry for either original " + IntToString(nSpellOriginal) + " or master " + IntToString(nSpellMaster));
|
||||
FloatingTextStringOnCreature("This spell cannot be infused (no item property mapping).", oCreator, FALSE);
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
if (DEBUG) DoDebug("CICreateInfusion: using spell " + IntToString(nSpellUsedForIP) + " (iprp row " + IntToString(nPropID) + ") for item property");
|
||||
|
||||
// Optional: check for material component (use the resolved iprp row)
|
||||
string sMat = GetMaterialComponentTag(nPropID);
|
||||
if (sMat != "")
|
||||
{
|
||||
object oMat = GetItemPossessedBy(oCreator, sMat);
|
||||
if (oMat == OBJECT_INVALID)
|
||||
{
|
||||
FloatingTextStrRefOnCreature(83374, oCreator); // Missing material component
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyObject(oMat);
|
||||
}
|
||||
}
|
||||
|
||||
// Only allow divine spellcasters
|
||||
int nClass = PRCGetLastSpellCastClass();
|
||||
if (!GetIsDivineClass(nClass))
|
||||
{
|
||||
FloatingTextStringOnCreature("Only divine casters can use Create Infusion.", oCreator, FALSE);
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
// Create base infusion item (herb)
|
||||
string sResRef = "prc_infusion_000";
|
||||
object oTarget = CreateItemOnObject(sResRef, oCreator);
|
||||
if (oTarget == OBJECT_INVALID)
|
||||
{
|
||||
WriteTimestampedLogEntry("Create Infusion failed: couldn't create item with resref " + sResRef);
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
// Confirm that the item is a herb
|
||||
int nBaseItem = GetBaseItemType(oTarget);
|
||||
if (nBaseItem != BASE_ITEM_INFUSED_HERB)
|
||||
{
|
||||
FloatingTextStringOnCreature("Only herbs may be infused.", oCreator, FALSE);
|
||||
DestroyObject(oTarget);
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
// Remove all non-material item properties from the herb
|
||||
itemproperty ipRemove = GetFirstItemProperty(oTarget);
|
||||
while (GetIsItemPropertyValid(ipRemove))
|
||||
{
|
||||
itemproperty ipNext = GetNextItemProperty(oTarget);
|
||||
if (GetItemPropertyType(ipRemove) != ITEM_PROPERTY_MATERIAL)
|
||||
RemoveItemProperty(oTarget, ipRemove);
|
||||
ipRemove = ipNext;
|
||||
}
|
||||
|
||||
// Add the cast-spell itemproperty using the iprp row we resolved
|
||||
itemproperty ipSpell = ItemPropertyCastSpell(nPropID, IP_CONST_CASTSPELL_NUMUSES_SINGLE_USE);
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipSpell, oTarget);
|
||||
|
||||
// Optional PRC casting metadata: use the SAME spell id that matched the iprp row
|
||||
// so caster level/DC/meta line up with the actual cast property on the item.
|
||||
if (GetPRCSwitch(PRC_CREATE_INFUSION_CASTER_LEVEL))
|
||||
{
|
||||
int nCasterLevel = GetAlternativeCasterLevel(oCreator, PRCGetCasterLevel(oCreator));
|
||||
// nSpellUsedForIP is either original (if that had an iprp row) or the master (fallback)
|
||||
itemproperty ipLevel = ItemPropertyCastSpellCasterLevel(nSpellUsedForIP, nCasterLevel);
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipLevel, oTarget);
|
||||
|
||||
itemproperty ipMeta = ItemPropertyCastSpellMetamagic(nSpellUsedForIP, PRCGetMetaMagicFeat());
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipMeta, oTarget);
|
||||
|
||||
int nDC = PRCGetSpellSaveDC(nSpellUsedForIP, GetSpellSchool(nSpellUsedForIP), OBJECT_SELF);
|
||||
itemproperty ipDC = ItemPropertyCastSpellDC(nSpellUsedForIP, nDC);
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipDC, oTarget);
|
||||
}
|
||||
|
||||
return oTarget;
|
||||
}
|
||||
|
||||
|
||||
// Test main
|
||||
//void main(){}
|
||||
// void main(){}
|
||||
|
@ -768,7 +768,6 @@ int IPGetIsBludgeoningWeapon(object oItem)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Return the IP_CONST_CASTSPELL_* ID matching to the SPELL_* constant given
|
||||
// in nSPELL_ID.
|
||||
// This uses Get2DAstring, so it is slow. Avoid using in loops!
|
||||
// returns -1 if there is no matching property for a spell
|
||||
// ----------------------------------------------------------------------------
|
||||
int IPGetIPConstCastSpellFromSpellID(int nSpellID)
|
||||
@ -1883,7 +1882,7 @@ int IPDamageConstant(int nDamBon)
|
||||
case 49: nIPBonus = IP_CONST_DAMAGEBONUS_49; break;
|
||||
case 50: nIPBonus = IP_CONST_DAMAGEBONUS_50; break;
|
||||
}
|
||||
if (nDamBon > 20) nIPBonus = IP_CONST_DAMAGEBONUS_50;
|
||||
if (nDamBon > 50) nIPBonus = IP_CONST_DAMAGEBONUS_50;
|
||||
|
||||
return nIPBonus;
|
||||
}
|
||||
|
@ -236,12 +236,12 @@ int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLAS
|
||||
// For when you want to assign the caster level.
|
||||
if(nLevel)
|
||||
{
|
||||
if(DEBUG) SendMessageToPC(oShadow, "GetShadowcasterLevel(): Forced-level shadowcasting at level " + IntToString(nLevel));
|
||||
if(DEBUG) DoDebug("GetShadowcasterLevel(): Forced-level shadowcasting at level " + IntToString(nLevel));
|
||||
//DelayCommand(1.0, DeleteLocalInt(oShadow, PRC_CASTERLEVEL_OVERRIDE));
|
||||
return nLevel + nAdjust;
|
||||
}
|
||||
|
||||
if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: "+GetName(oShadow)+" is a "+IntToString(nSpecificClass), oShadow);
|
||||
if (DEBUG) DoDebug("GetShadowcasterLevel: "+GetName(oShadow)+" is a "+IntToString(nSpecificClass), oShadow);
|
||||
// The function user needs to know the character's Shadowcaster level in a specific class
|
||||
// instead of whatever the character last shadowcast a mystery as
|
||||
if(nSpecificClass != CLASS_TYPE_INVALID)
|
||||
@ -288,7 +288,7 @@ int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLAS
|
||||
nLevel -= 4;
|
||||
}
|
||||
|
||||
if(DEBUG) FloatingTextStringOnCreature("Shadowcaster Level: " + IntToString(nLevel), oShadow, FALSE);
|
||||
if(DEBUG) DoDebug("Shadowcaster Level: " + IntToString(nLevel));
|
||||
|
||||
return nLevel + nAdjust;
|
||||
}
|
||||
|
@ -144,8 +144,103 @@ int PRCGetUserSpecificSpellScriptFinished();
|
||||
#include "pnp_shft_main"
|
||||
#include "inc_dynconv"
|
||||
#include "inc_npc"
|
||||
#include "inc_infusion"
|
||||
#include "prc_add_spell_dc"
|
||||
|
||||
|
||||
int Spontaneity(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel)
|
||||
{
|
||||
if(GetLocalInt(oCaster, "PRC_SpontRegen"))
|
||||
{
|
||||
DeleteLocalInt(oCaster, "PRC_SpontRegen");
|
||||
|
||||
int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here
|
||||
nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nCastingClass);
|
||||
nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic);
|
||||
|
||||
int nRegenSpell;
|
||||
|
||||
if(nCastingClass == CLASS_TYPE_DRUID)
|
||||
{
|
||||
switch(nSpellLevel)
|
||||
{
|
||||
case 0: return TRUE;
|
||||
case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break;
|
||||
case 2: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break;
|
||||
case 3: nRegenSpell = SPELL_REGEN_RING; break;
|
||||
case 4: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break;
|
||||
case 5: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break;
|
||||
case 6: nRegenSpell = SPELL_REGEN_CIRCLE; break;
|
||||
case 7: nRegenSpell = SPELL_REGEN_CIRCLE; break;
|
||||
case 8: nRegenSpell = SPELL_REGEN_CIRCLE; break;
|
||||
case 9: nRegenSpell = SPELL_REGENERATE; break;
|
||||
}
|
||||
ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, CLASS_TYPE_DRUID);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(nSpellLevel)
|
||||
{
|
||||
case 0: return TRUE;
|
||||
case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break;
|
||||
case 2: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break;
|
||||
case 3: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break;
|
||||
case 4: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break;
|
||||
case 5: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break;
|
||||
case 6: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break;
|
||||
case 7: nRegenSpell = SPELL_REGENERATE; break;
|
||||
case 8: nRegenSpell = SPELL_REGENERATE; break;
|
||||
case 9: nRegenSpell = SPELL_REGENERATE; break;
|
||||
}
|
||||
|
||||
ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, nCastingClass);
|
||||
}
|
||||
//Don't cast original spell
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel)
|
||||
{
|
||||
if(nCastingClass != CLASS_TYPE_DRUID)
|
||||
return TRUE;
|
||||
|
||||
if(GetLocalInt(oCaster, "PRC_SpontSummon"))
|
||||
{
|
||||
DeleteLocalInt(oCaster, "PRC_SpontSummon");
|
||||
int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here
|
||||
int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, CLASS_TYPE_DRUID);
|
||||
nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic);
|
||||
int nSummonSpell;
|
||||
switch(nSpellLevel)
|
||||
{
|
||||
case 0: return TRUE;
|
||||
case 1: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_1; break;
|
||||
case 2: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_2; break;
|
||||
case 3: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_3; break;
|
||||
case 4: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_4; break;
|
||||
case 5: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_5; break;
|
||||
case 6: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_6; break;
|
||||
case 7: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_7; break;
|
||||
case 8: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_8; break;
|
||||
case 9: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_9; break;
|
||||
}
|
||||
|
||||
//:: All SNA spells are subradial spells
|
||||
SetLocalInt(oCaster, "DomainOrigSpell", nSummonSpell);
|
||||
SetLocalInt(oCaster, "DomainCastLevel", nSpellLevel);
|
||||
SetLocalInt(oCaster, "DomainCastClass", CLASS_TYPE_DRUID);
|
||||
StartDynamicConversation("prc_domain_conv", oCaster, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oCaster);
|
||||
|
||||
//Don't cast original spell
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel)
|
||||
{
|
||||
if(nCastingClass != CLASS_TYPE_DRUID)
|
||||
return TRUE;
|
||||
@ -191,6 +286,8 @@ int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpell
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
int ArcaneSpellFailure(object oCaster, int nCastingClass, int nSpellLevel, int nMetamagic, string sComponents)
|
||||
{
|
||||
if(!GetIsArcaneClass(nCastingClass))
|
||||
@ -904,7 +1001,8 @@ int ShifterCasting(object oCaster, object oSpellCastItem, int nSpellLevel, int n
|
||||
{
|
||||
// Potion drinking is not restricted
|
||||
if(GetBaseItemType(oSpellCastItem) == BASE_ITEM_ENCHANTED_POTION
|
||||
|| GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS)
|
||||
|| GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS
|
||||
|| GetBaseItemType(oSpellCastItem) == BASE_ITEM_INFUSED_HERB)
|
||||
return TRUE;
|
||||
|
||||
//OnHit properties on equipped items not restricted
|
||||
@ -3249,6 +3347,28 @@ int X2PreSpellCastCode2()
|
||||
X2BreakConcentrationSpells();
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Herbal Infusion Use check
|
||||
//---------------------------------------------------------------------------
|
||||
if(nContinue && (GetBaseItemType(oSpellCastItem) == BASE_ITEM_INFUSED_HERB))
|
||||
{
|
||||
int bIsSubradial = GetIsSubradialSpell(nSpellID);
|
||||
|
||||
if(bIsSubradial)
|
||||
{
|
||||
nSpellID = GetMasterSpellFromSubradial(nSpellID);
|
||||
}
|
||||
int nItemCL = GetCastSpellCasterLevelFromItem(oSpellCastItem, nSpellID);
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook >> X2PreSpellCastCode2: Item Spellcaster Level: "+IntToString(nItemCL)+".");
|
||||
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook >> X2PreSpellCastCode2: Herbal Infusion Found");
|
||||
if(!DoInfusionUseChecks(oCaster, oSpellCastItem, nSpellID))
|
||||
{
|
||||
ApplyInfusionPoison(oCaster, nItemCL);
|
||||
nContinue = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// No casting while using expertise
|
||||
//---------------------------------------------------------------------------
|
||||
if(nContinue)
|
||||
@ -3399,6 +3519,12 @@ int X2PreSpellCastCode2()
|
||||
if (nContinue)
|
||||
nContinue = SpellAlignmentRestrictions(oCaster, nSpellID, nCastingClass);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Verdant Lord Spontaneous Regernate
|
||||
//---------------------------------------------------------------------------
|
||||
if(nContinue)
|
||||
Spontaneity(oCaster, nCastingClass, nSpellID, nSpellLevel);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Druid spontaneous summoning
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -2894,5 +2894,3 @@ void main()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user