generated from Jaysyn/ModuleTemplate
2025/08/24 Update
Updated for PRC8 updates.
This commit is contained in:
parent
2894f5c773
commit
c41f664b12
@ -9,7 +9,7 @@ Repository for the development of the PRC8 version of Endless Nights III, a roug
|
||||
|
||||
2.) [Original module resources](https://neverwintervault.org/project/nwn1/module/endless-nights-iii)
|
||||
|
||||
3.) [PRC8](https://gitea.raptio.us/Jaysyn/PRC8/src/branch/main/Release)
|
||||
3.) [PRC8](https://gitea.raptio.us/Jaysyn/PRC8/releases)
|
||||
|
||||
4.) [CEP3](https://neverwintervault.org/project/nwnee/hakpak/combined/cep-3-community-expansion-pack)
|
||||
|
||||
|
11
nasher.cfg
11
nasher.cfg
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "Endless Nights III [PRC8-CEP3]"
|
||||
description = "PRC8 version of Endless Nights III."
|
||||
version = "1.36prc8"
|
||||
version = "1.37prc8"
|
||||
url = "https://discord.gg/ca2ru3KxYd"
|
||||
author = "Havlen"
|
||||
author = "Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com>"
|
||||
@ -231,5 +231,12 @@ description = "PRC8 version of Endless Nights III."
|
||||
filter = "prc_nui_sc_inc.nss"
|
||||
filter = "prc_nui_scd_inc.nss"
|
||||
filter = "prc_nui_consts.nss"
|
||||
filter = "nw_inc_nui"
|
||||
filter = "prc_nui_sb_inc.nss"
|
||||
filter = "prc_nui_sbd_inc.nss"
|
||||
filter = "prc_nui_lv_inc.nss"
|
||||
filter = "prc_nui_com_inc.nss"
|
||||
filter = "nw_inc_nui.nss"
|
||||
filter = "inc_infusion.nss"
|
||||
filter = "nw_inc_gff.nss"
|
||||
filter = "prc_inc_json.nss"
|
||||
filter = "xchst_inc.nss"
|
@ -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);
|
||||
@ -876,6 +876,8 @@ void CreateSwitchNameArray()
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_HARM);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_NEUTRALIZE_POISON);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIOWARE_REMOVE_DISEASE);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_BIO_UNLEARN);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_UNLEARN_SPELL_MAXNR);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_BIOWARE_DURATION);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_LOCAL);
|
||||
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_TIMESTOP_NO_HOSTILE);
|
||||
@ -1067,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 = 26001;
|
||||
//:: 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;
|
||||
@ -1868,12 +1897,12 @@ const int FEAT_SANCTIFY_MARTIAL_SICKLE = 3169;
|
||||
const int FEAT_SANCTIFY_MARTIAL_MINDBLADE = 3623;
|
||||
const int FEAT_SANCTIFY_MARTIAL_WHIP = 3596;
|
||||
const int FEAT_SANCTIFY_MARTIAL_TRIDENT = 3597;
|
||||
const int FEAT_SANCTIFYKISTRIKE = 26002;
|
||||
const int FEAT_HOLYKISTRIKE = 26003;
|
||||
const int FEAT_FISTOFHEAVENS = 26004;
|
||||
const int FEAT_VOWABSTINENCE = 26005;
|
||||
const int FEAT_VOWCHASTITY = 26006;
|
||||
const int FEAT_GIFTOFFAITH = 26007;
|
||||
const int FEAT_SANCTIFYKISTRIKE = 26003;
|
||||
const int FEAT_HOLYKISTRIKE = 26004;
|
||||
const int FEAT_FISTOFHEAVENS = 26005;
|
||||
const int FEAT_VOWABSTINENCE = 26006;
|
||||
const int FEAT_VOWCHASTITY = 26007;
|
||||
const int FEAT_GIFTOFFAITH = 26008;
|
||||
|
||||
//heartwarder
|
||||
const int FEAT_CHARISMA_INC1 = 3230;
|
||||
@ -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;
|
||||
|
@ -575,8 +575,8 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF)
|
||||
iReturnLevel = GetLevelByClass(CLASS_TYPE_SHAPECHANGER);
|
||||
|
||||
}
|
||||
// Casting as a bard but don't have any levels in the class
|
||||
if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster))
|
||||
// Casting as a bard but don't have any levels in the class //:: Double-dipping?
|
||||
/* if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster))
|
||||
{
|
||||
int nRace = GetRacialType(oCaster);
|
||||
|
||||
@ -584,7 +584,7 @@ int PRCGetCasterLevel(object oCaster = OBJECT_SELF)
|
||||
//otherwise use RHD instead of bard levels
|
||||
if(nRace == RACIAL_TYPE_GLOURA)
|
||||
iReturnLevel = GetLevelByClass(CLASS_TYPE_FEY);
|
||||
}
|
||||
} */
|
||||
|
||||
//Spell Rage ability
|
||||
if(GetHasSpellEffect(SPELL_SPELL_RAGE, oCaster)
|
||||
@ -960,8 +960,10 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
}
|
||||
//:: End Bard Arcane PrC casting calculations
|
||||
|
||||
if(nCastingClass == CLASS_TYPE_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster))
|
||||
if(nCastingClass == CLASS_TYPE_BARD || nCastingClass == CLASS_TYPE_BARD && nRace == RACIAL_TYPE_GLOURA && !GetLevelByClass(CLASS_TYPE_BARD, oCaster))
|
||||
{
|
||||
if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey RHD caster (not bard)");
|
||||
|
||||
if(GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_FEY, oCaster))
|
||||
nArcane += GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oCaster);
|
||||
|
||||
@ -1065,7 +1067,10 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
|
||||
nArcane += GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oCaster);
|
||||
|
||||
if(GetHasFeat(FEAT_VIRTUOSO_SPELLCASTING_FEY, oCaster))
|
||||
{
|
||||
nArcane += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oCaster);
|
||||
if(DEBUG) DoDebug("prc_inc_castlvl >> Found Fey + Virtuoso PrC. Arcane caster level is "+IntToString(nArcane)+".");
|
||||
}
|
||||
|
||||
if(GetHasFeat(FEAT_WWOC_SPELLCASTING_FEY, oCaster))
|
||||
nArcane += GetLevelByClass(CLASS_TYPE_WAR_WIZARD_OF_CORMYR, oCaster);
|
||||
@ -1143,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);
|
||||
@ -3817,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); */
|
||||
|
||||
@ -4143,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);
|
||||
@ -4253,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);
|
||||
@ -4365,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);
|
||||
@ -4474,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); */
|
||||
|
||||
@ -4581,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);
|
||||
|
||||
@ -4791,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); */
|
||||
|
||||
@ -4896,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); */
|
||||
@ -5207,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);
|
||||
@ -5311,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);
|
||||
@ -5524,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);
|
||||
|
||||
@ -5631,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); */
|
||||
|
||||
|
@ -402,6 +402,7 @@ int Vile_Feat(int iTypeWeap)
|
||||
case BASE_ITEM_LONGSWORD: return GetHasFeat(FEAT_VILE_MARTIAL_LONGSWORD);
|
||||
case BASE_ITEM_MORNINGSTAR: return GetHasFeat(FEAT_VILE_MARTIAL_MORNINGSTAR);
|
||||
case BASE_ITEM_QUARTERSTAFF: return GetHasFeat(FEAT_VILE_MARTIAL_QUARTERSTAFF);
|
||||
case BASE_ITEM_MAGICSTAFF: return GetHasFeat(FEAT_VILE_MARTIAL_QUARTERSTAFF);
|
||||
case BASE_ITEM_RAPIER: return GetHasFeat(FEAT_VILE_MARTIAL_RAPIER);
|
||||
case BASE_ITEM_SCIMITAR: return GetHasFeat(FEAT_VILE_MARTIAL_SCIMITAR);
|
||||
case BASE_ITEM_SCYTHE: return GetHasFeat(FEAT_VILE_MARTIAL_SCYTHE);
|
||||
@ -482,6 +483,7 @@ int GetSanctifedMartialFeat(int iTypeWeap)
|
||||
case BASE_ITEM_LONGSWORD: return FEAT_SANCTIFY_MARTIAL_LONGSWORD;
|
||||
case BASE_ITEM_MORNINGSTAR: return FEAT_SANCTIFY_MARTIAL_MORNINGSTAR;
|
||||
case BASE_ITEM_QUARTERSTAFF: return FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF;
|
||||
case BASE_ITEM_MAGICSTAFF: return FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_SANCTIFY_MARTIAL_RAPIER;
|
||||
case BASE_ITEM_SCIMITAR: return FEAT_SANCTIFY_MARTIAL_SCIMITAR;
|
||||
case BASE_ITEM_SCYTHE: return FEAT_SANCTIFY_MARTIAL_SCYTHE;
|
||||
@ -555,6 +557,7 @@ int Sanctify_Feat(int iTypeWeap)
|
||||
case BASE_ITEM_LONGSWORD: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_LONGSWORD);
|
||||
case BASE_ITEM_MORNINGSTAR: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_MORNINGSTAR);
|
||||
case BASE_ITEM_QUARTERSTAFF: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF);
|
||||
case BASE_ITEM_MAGICSTAFF: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF);
|
||||
case BASE_ITEM_RAPIER: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_RAPIER);
|
||||
case BASE_ITEM_SCIMITAR: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SCIMITAR);
|
||||
case BASE_ITEM_SCYTHE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SCYTHE);
|
||||
|
@ -1082,6 +1082,7 @@ int GetIsTwoHandedMeleeWeaponType(int iWeaponType)
|
||||
case BASE_ITEM_HEAVYFLAIL: return TRUE;
|
||||
case BASE_ITEM_SCYTHE: return TRUE;
|
||||
case BASE_ITEM_QUARTERSTAFF: return TRUE;
|
||||
case BASE_ITEM_MAGICSTAFF: return TRUE;
|
||||
case BASE_ITEM_ELVEN_COURTBLADE: return TRUE;
|
||||
case BASE_ITEM_MAUL: return TRUE;
|
||||
case BASE_ITEM_FALCHION: return TRUE;
|
||||
@ -1093,7 +1094,7 @@ int GetIsTwoHandedMeleeWeapon(object oWeap)
|
||||
{
|
||||
return GetIsTwoHandedMeleeWeaponType(GetBaseItemType(oWeap));
|
||||
}
|
||||
|
||||
|
||||
int GetIsCreatureWeaponType(int iWeaponType)
|
||||
{
|
||||
// any of the three creature weapon types that produce bludgeoning, piercing or slashing damage
|
||||
@ -1130,6 +1131,7 @@ int GetIsSimpleWeaponType(int iWeaponType)
|
||||
{
|
||||
case BASE_ITEM_MORNINGSTAR: return 1;
|
||||
case BASE_ITEM_QUARTERSTAFF: return 1;
|
||||
case BASE_ITEM_MAGICSTAFF: return 1;
|
||||
case BASE_ITEM_SHORTSPEAR: return 1;
|
||||
case BASE_ITEM_HEAVYCROSSBOW: return 1;
|
||||
case BASE_ITEM_INVALID: return 1;
|
||||
@ -1204,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
|
||||
);
|
||||
}
|
||||
|
||||
@ -1562,6 +1565,19 @@ struct WeaponFeat GetAllFeatsOfWeaponType(int iWeaponType)
|
||||
sFeat.VileMartialStrike = FEAT_VILE_MARTIAL_QUARTERSTAFF;
|
||||
break;
|
||||
}
|
||||
case BASE_ITEM_MAGICSTAFF: {
|
||||
sFeat.Focus = FEAT_WEAPON_FOCUS_STAFF;
|
||||
sFeat.Specialization = FEAT_WEAPON_SPECIALIZATION_STAFF;
|
||||
sFeat.EpicFocus = FEAT_EPIC_WEAPON_FOCUS_QUARTERSTAFF;
|
||||
sFeat.EpicSpecialization = FEAT_EPIC_WEAPON_SPECIALIZATION_QUARTERSTAFF;
|
||||
sFeat.ImprovedCritical = FEAT_IMPROVED_CRITICAL_STAFF;
|
||||
sFeat.OverwhelmingCritical = FEAT_EPIC_OVERWHELMING_CRITICAL_QUARTERSTAFF;
|
||||
sFeat.DevastatingCritical = FEAT_EPIC_DEVASTATING_CRITICAL_QUARTERSTAFF;
|
||||
sFeat.WeaponOfChoice = FEAT_WEAPON_OF_CHOICE_QUARTERSTAFF;
|
||||
sFeat.SanctifyMartialStrike = FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF;
|
||||
sFeat.VileMartialStrike = FEAT_VILE_MARTIAL_QUARTERSTAFF;
|
||||
break;
|
||||
}
|
||||
case BASE_ITEM_RAPIER: {
|
||||
sFeat.Focus = FEAT_WEAPON_FOCUS_RAPIER;
|
||||
sFeat.Specialization = FEAT_WEAPON_SPECIALIZATION_RAPIER;
|
||||
|
@ -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;
|
||||
|
@ -248,6 +248,7 @@ int GetFocusFeatOfWeaponType(int iWeaponType)
|
||||
case BASE_ITEM_LONGSWORD: return FEAT_WEAPON_FOCUS_LONG_SWORD;
|
||||
case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_FOCUS_MORNING_STAR;
|
||||
case BASE_ITEM_QUARTERSTAFF: return FEAT_WEAPON_FOCUS_STAFF;
|
||||
case BASE_ITEM_MAGICSTAFF: return FEAT_WEAPON_FOCUS_STAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_WEAPON_FOCUS_RAPIER;
|
||||
case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_FOCUS_SCIMITAR;
|
||||
case BASE_ITEM_SCYTHE: return FEAT_WEAPON_FOCUS_SCYTHE;
|
||||
@ -318,6 +319,7 @@ int GetSpecializationFeatOfWeaponType(int iWeaponType)
|
||||
case BASE_ITEM_LONGSWORD: return FEAT_WEAPON_SPECIALIZATION_LONG_SWORD;
|
||||
case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_SPECIALIZATION_MORNING_STAR;
|
||||
case BASE_ITEM_QUARTERSTAFF: return FEAT_WEAPON_SPECIALIZATION_STAFF;
|
||||
case BASE_ITEM_MAGICSTAFF: return FEAT_WEAPON_SPECIALIZATION_STAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_WEAPON_SPECIALIZATION_RAPIER;
|
||||
case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_SPECIALIZATION_SCIMITAR;
|
||||
case BASE_ITEM_SCYTHE: return FEAT_WEAPON_SPECIALIZATION_SCYTHE;
|
||||
@ -388,6 +390,7 @@ int GetEpicFocusFeatOfWeaponType(int iWeaponType)
|
||||
case BASE_ITEM_LONGSWORD: return FEAT_EPIC_WEAPON_FOCUS_LONGSWORD;
|
||||
case BASE_ITEM_MORNINGSTAR: return FEAT_EPIC_WEAPON_FOCUS_MORNINGSTAR;
|
||||
case BASE_ITEM_QUARTERSTAFF: return FEAT_EPIC_WEAPON_FOCUS_QUARTERSTAFF;
|
||||
case BASE_ITEM_MAGICSTAFF: return FEAT_EPIC_WEAPON_FOCUS_QUARTERSTAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_EPIC_WEAPON_FOCUS_RAPIER;
|
||||
case BASE_ITEM_SCIMITAR: return FEAT_EPIC_WEAPON_FOCUS_SCIMITAR;
|
||||
case BASE_ITEM_SCYTHE: return FEAT_EPIC_WEAPON_FOCUS_SCYTHE;
|
||||
@ -458,7 +461,8 @@ int GetEpicSpecializationFeatOfWeaponType(int iWeaponType)
|
||||
case BASE_ITEM_LONGSWORD: return FEAT_EPIC_WEAPON_SPECIALIZATION_LONGSWORD;
|
||||
case BASE_ITEM_MORNINGSTAR: return FEAT_EPIC_WEAPON_SPECIALIZATION_MORNINGSTAR;
|
||||
case BASE_ITEM_QUARTERSTAFF: return FEAT_EPIC_WEAPON_SPECIALIZATION_QUARTERSTAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_EPIC_WEAPON_SPECIALIZATION_RAPIER;
|
||||
case BASE_ITEM_MAGICSTAFF: return FEAT_EPIC_WEAPON_SPECIALIZATION_QUARTERSTAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_EPIC_WEAPON_SPECIALIZATION_RAPIER;
|
||||
case BASE_ITEM_SCIMITAR: return FEAT_EPIC_WEAPON_SPECIALIZATION_SCIMITAR;
|
||||
case BASE_ITEM_SCYTHE: return FEAT_EPIC_WEAPON_SPECIALIZATION_SCYTHE;
|
||||
case BASE_ITEM_SHORTBOW: return FEAT_EPIC_WEAPON_SPECIALIZATION_SHORTBOW;
|
||||
@ -528,6 +532,7 @@ int GetImprovedCriticalFeatOfWeaponType(int iWeaponType)
|
||||
case BASE_ITEM_LONGSWORD: return FEAT_IMPROVED_CRITICAL_LONG_SWORD;
|
||||
case BASE_ITEM_MORNINGSTAR: return FEAT_IMPROVED_CRITICAL_MORNING_STAR;
|
||||
case BASE_ITEM_QUARTERSTAFF: return FEAT_IMPROVED_CRITICAL_STAFF;
|
||||
case BASE_ITEM_MAGICSTAFF: return FEAT_IMPROVED_CRITICAL_STAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_IMPROVED_CRITICAL_RAPIER;
|
||||
case BASE_ITEM_SCIMITAR: return FEAT_IMPROVED_CRITICAL_SCIMITAR;
|
||||
case BASE_ITEM_SCYTHE: return FEAT_IMPROVED_CRITICAL_SCYTHE;
|
||||
@ -598,6 +603,7 @@ int GetOverwhelmingCriticalFeatOfWeaponType(int iWeaponType)
|
||||
case BASE_ITEM_LONGSWORD: return FEAT_EPIC_OVERWHELMING_CRITICAL_LONGSWORD;
|
||||
case BASE_ITEM_MORNINGSTAR: return FEAT_EPIC_OVERWHELMING_CRITICAL_MORNINGSTAR;
|
||||
case BASE_ITEM_QUARTERSTAFF: return FEAT_EPIC_OVERWHELMING_CRITICAL_QUARTERSTAFF;
|
||||
case BASE_ITEM_MAGICSTAFF: return FEAT_EPIC_OVERWHELMING_CRITICAL_QUARTERSTAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_EPIC_OVERWHELMING_CRITICAL_RAPIER;
|
||||
case BASE_ITEM_SCIMITAR: return FEAT_EPIC_OVERWHELMING_CRITICAL_SCIMITAR;
|
||||
case BASE_ITEM_SCYTHE: return FEAT_EPIC_OVERWHELMING_CRITICAL_SCYTHE;
|
||||
@ -668,6 +674,7 @@ int GetDevastatingCriticalFeatOfWeaponType(int iWeaponType)
|
||||
case BASE_ITEM_LONGSWORD: return FEAT_EPIC_DEVASTATING_CRITICAL_LONGSWORD;
|
||||
case BASE_ITEM_MORNINGSTAR: return FEAT_EPIC_DEVASTATING_CRITICAL_MORNINGSTAR;
|
||||
case BASE_ITEM_QUARTERSTAFF: return FEAT_EPIC_DEVASTATING_CRITICAL_QUARTERSTAFF;
|
||||
case BASE_ITEM_MAGICSTAFF: return FEAT_EPIC_DEVASTATING_CRITICAL_QUARTERSTAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_EPIC_DEVASTATING_CRITICAL_RAPIER;
|
||||
case BASE_ITEM_SCIMITAR: return FEAT_EPIC_DEVASTATING_CRITICAL_SCIMITAR;
|
||||
case BASE_ITEM_SCYTHE: return FEAT_EPIC_DEVASTATING_CRITICAL_SCYTHE;
|
||||
@ -729,6 +736,7 @@ int GetWeaponOfChoiceFeatOfWeaponType(int iWeaponType)
|
||||
case BASE_ITEM_LONGSWORD: return FEAT_WEAPON_OF_CHOICE_LONGSWORD;
|
||||
case BASE_ITEM_MORNINGSTAR: return FEAT_WEAPON_OF_CHOICE_MORNINGSTAR;
|
||||
case BASE_ITEM_QUARTERSTAFF: return FEAT_WEAPON_OF_CHOICE_QUARTERSTAFF;
|
||||
case BASE_ITEM_MAGICSTAFF: return FEAT_WEAPON_OF_CHOICE_QUARTERSTAFF;
|
||||
case BASE_ITEM_RAPIER: return FEAT_WEAPON_OF_CHOICE_RAPIER;
|
||||
case BASE_ITEM_SCIMITAR: return FEAT_WEAPON_OF_CHOICE_SCIMITAR;
|
||||
case BASE_ITEM_SCYTHE: return FEAT_WEAPON_OF_CHOICE_SCYTHE;
|
||||
@ -787,6 +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_SCYTHE:
|
||||
case BASE_ITEM_SHORTSPEAR:
|
||||
case BASE_ITEM_ELVEN_COURTBLADE:
|
||||
@ -823,6 +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_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,23 +381,53 @@ 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;
|
||||
// is it arcane, divine or neither?
|
||||
if(GetIsArcaneClass(nClass, oCaster) && nClass != CLASS_TYPE_SUBLIME_CHORD)
|
||||
{
|
||||
if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs
|
||||
if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs
|
||||
iTemp = GetArcanePRCLevels(oCaster, nClass);
|
||||
}
|
||||
else if(GetIsDivineClass(nClass, oCaster))
|
||||
{
|
||||
if (GetPrimaryDivineClass(oCaster) == nClass) // adjust for any PrCs
|
||||
iTemp = GetDivinePRCLevels(oCaster, nClass);
|
||||
if (GetPrimaryDivineClass(oCaster) == nClass) // adjust for any PrCs
|
||||
iTemp = GetDivinePRCLevels(oCaster, nClass);
|
||||
}
|
||||
else // a non-caster class or a PrC
|
||||
{
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
// add the caster class levels
|
||||
return iTemp += GetLevelByClass(nClass, oCaster);
|
||||
@ -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,10 +170,17 @@ 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_QUARTERSTAFF, oPC)
|
||||
||GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC);
|
||||
|
||||
case BASE_ITEM_RAPIER:
|
||||
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_RAPIER, oPC)
|
||||
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oPC)
|
||||
@ -295,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
|
||||
|
530
src/include/prc_nui_com_inc.nss
Normal file
530
src/include/prc_nui_com_inc.nss
Normal file
@ -0,0 +1,530 @@
|
||||
#include "prc_nui_consts"
|
||||
#include "inc_newspellbook"
|
||||
#include "psi_inc_psifunc"
|
||||
#include "inc_lookups"
|
||||
#include "nw_inc_nui"
|
||||
|
||||
//
|
||||
// GetCurrentSpellLevel
|
||||
// Gets the current spell level the class can achieve at the current
|
||||
// caster level (ranging from 0-9)
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
// nLevel:int the caster level
|
||||
//
|
||||
// Returns:
|
||||
// int the circle the class can achieve currently
|
||||
//
|
||||
int GetCurrentSpellLevel(int nClass, int nLevel);
|
||||
|
||||
//
|
||||
// GetMaxSpellLevel
|
||||
// Gets the highest possible circle the class can achieve (from 0-9)
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
//
|
||||
// Returns:
|
||||
// int the highest circle that can be achieved
|
||||
//
|
||||
int GetMaxSpellLevel(int nClass);
|
||||
|
||||
//
|
||||
// GetMinSpellLevel
|
||||
// Gets the lowest possible circle the class can achieve (from 0-9)
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
//
|
||||
// Returns:
|
||||
// int the lowest circle that can be achieved
|
||||
//
|
||||
int GetMinSpellLevel(int nClass);
|
||||
|
||||
//
|
||||
// GetHighestLevelPossibleInClass
|
||||
// Given a class Id this will determine what the max level of a class can be
|
||||
// achieved
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
//
|
||||
// Returns:
|
||||
// int the highest possible level the class can achieve
|
||||
//
|
||||
int GetHighestLevelPossibleInClass(int nClass);
|
||||
|
||||
//
|
||||
// GetClassSpellbookFile
|
||||
// Gets the class 2da spellbook/ability for the given class Id
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the classID
|
||||
//
|
||||
// Returns:
|
||||
// string the 2da file name for the spell/abilities of the ClassID
|
||||
//
|
||||
string GetClassSpellbookFile(int nClass);
|
||||
|
||||
//
|
||||
// GetBinderSpellToFeatDictionary
|
||||
// Sets up the Binder Spell Dictionary that is used to match a binder's vestige
|
||||
// to their feat. This is constructed based off the binder's known location of
|
||||
// their feat and spell ranges in the base 2das respectivly. After constructing
|
||||
// this it will be saved to the player locally as a cached result since we do
|
||||
// not need to call this again.
|
||||
//
|
||||
// Argument:
|
||||
// oPlayer:object the player
|
||||
//
|
||||
// Returns:
|
||||
// json:Dictionary<String,Int> a dictionary of mapping between the SpellID
|
||||
// and the FeatID of a vestige ability
|
||||
//
|
||||
json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF);
|
||||
|
||||
//
|
||||
// GetSpellLevelIcon
|
||||
// Takes the spell circle int and gets the icon appropriate for it (i.e. 0 turns
|
||||
// into "ir_cantrips"
|
||||
//
|
||||
// Arguments:
|
||||
// spellLevel:int the spell level we want the icon for
|
||||
//
|
||||
// Returns:
|
||||
// string the spell level icon
|
||||
//
|
||||
string GetSpellLevelIcon(int spellLevel);
|
||||
|
||||
//
|
||||
// GetSpellLevelToolTip
|
||||
// Gets the spell level tool tip text based on the int spell level provided (i.e.
|
||||
// 0 turns into "Cantrips")
|
||||
//
|
||||
// Arguments:
|
||||
// spellLevel:int the spell level we want the tooltip for
|
||||
//
|
||||
// Returns:
|
||||
// string the spell level toop tip
|
||||
//
|
||||
string GetSpellLevelToolTip(int spellLevel);
|
||||
|
||||
//
|
||||
// GetSpellIcon
|
||||
// Gets the spell icon based off the spellId, or featId supplied
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the class Id
|
||||
// featId:int the featId we can use the icon for
|
||||
// spellId:int the spell Id we want the icon for
|
||||
//
|
||||
// Returns:
|
||||
// json:String the string of the icon we want.
|
||||
//
|
||||
json GetSpellIcon(int spellId, int featId=0, int nClass=0);
|
||||
string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0);
|
||||
|
||||
//
|
||||
// GreyOutButton
|
||||
// Takes NUI Button along with it's width and height and greys it out it with a drawn
|
||||
// colored rectangle to represent it's not been selected or not valid.
|
||||
//
|
||||
// Arguments:
|
||||
// jButton:json the NUI Button
|
||||
// w:float the width of the button
|
||||
// h:float the height of the button
|
||||
//
|
||||
// Returns:
|
||||
// json the NUI button greyed out
|
||||
//
|
||||
json GreyOutButton(json jButton, float w, float h);
|
||||
|
||||
//
|
||||
// CreateGreyOutRectangle
|
||||
// Creates a grey out rectangle for buttons
|
||||
//
|
||||
// Arguments:
|
||||
// w:float the width of the button
|
||||
// h:float the height of the button
|
||||
//
|
||||
// Returns:
|
||||
// json the transparant black rectangle
|
||||
//
|
||||
json CreateGreyOutRectangle(float w, float h);
|
||||
|
||||
void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0);
|
||||
void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF);
|
||||
|
||||
int GetCurrentSpellLevel(int nClass, int nLevel)
|
||||
{
|
||||
int currentLevel = nLevel;
|
||||
|
||||
// ToB doesn't have a concept of spell levels, but still match up to it
|
||||
if(nClass == CLASS_TYPE_WARBLADE
|
||||
|| nClass == CLASS_TYPE_SWORDSAGE
|
||||
|| nClass == CLASS_TYPE_CRUSADER
|
||||
|| nClass == CLASS_TYPE_SHADOWCASTER)
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
|
||||
// Binders don't really have a concept of spell level
|
||||
if (nClass == CLASS_TYPE_BINDER
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle
|
||||
return 1;
|
||||
|
||||
//Shadowsmith has no concept of spell levels
|
||||
if (nClass == CLASS_TYPE_SHADOWSMITH)
|
||||
return 2;
|
||||
|
||||
if (nClass == CLASS_TYPE_WARLOCK
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
||||
return 4;
|
||||
|
||||
// Spont casters have their own function
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
|
||||
int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel);
|
||||
return maxLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
// everyone else uses this
|
||||
string spellLevel2da = GetAMSKnownFileName(nClass);
|
||||
|
||||
currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da
|
||||
|
||||
if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
||||
|| nClass == CLASS_TYPE_PSION
|
||||
|| nClass == CLASS_TYPE_PSYWAR
|
||||
|| nClass == CLASS_TYPE_WILDER
|
||||
|| nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
||||
|| nClass == CLASS_TYPE_WARMIND)
|
||||
currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1;
|
||||
|
||||
int totalLevel = Get2DARowCount(spellLevel2da);
|
||||
|
||||
// in case we somehow go over bounds just don't :)
|
||||
if (currentLevel >= totalLevel)
|
||||
currentLevel = totalLevel - 1;
|
||||
|
||||
//Psionics have MaxPowerLevel as their column name
|
||||
string columnName = "MaxPowerLevel";
|
||||
|
||||
//Invokers have MaxInvocationLevel
|
||||
if (nClass == CLASS_TYPE_WARLOCK
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
||||
columnName = "MaxInvocationLevel";
|
||||
|
||||
// Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range
|
||||
if (nClass == CLASS_TYPE_TRUENAMER)
|
||||
{
|
||||
columnName = "EvolvingMind";
|
||||
spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at
|
||||
}
|
||||
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
columnName = "VestigeLvl";
|
||||
spellLevel2da = "cls_bind_binder";
|
||||
}
|
||||
|
||||
// ToB doesn't have a concept of this, but we don't care.
|
||||
|
||||
int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel));
|
||||
return maxLevel;
|
||||
}
|
||||
}
|
||||
|
||||
int GetMinSpellLevel(int nClass)
|
||||
{
|
||||
// again sponts have their own function
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
||||
|| nClass == CLASS_TYPE_PSION
|
||||
|| nClass == CLASS_TYPE_PSYWAR
|
||||
|| nClass == CLASS_TYPE_WILDER
|
||||
|| nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
||||
|| nClass == CLASS_TYPE_WARMIND
|
||||
|| nClass == CLASS_TYPE_WARBLADE
|
||||
|| nClass == CLASS_TYPE_SWORDSAGE
|
||||
|| nClass == CLASS_TYPE_CRUSADER
|
||||
|| nClass == CLASS_TYPE_WARLOCK
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|
||||
|| nClass == CLASS_TYPE_SHADOWCASTER
|
||||
|| nClass == CLASS_TYPE_SHADOWSMITH
|
||||
|| nClass == CLASS_TYPE_BINDER)
|
||||
return 1;
|
||||
|
||||
return GetCurrentSpellLevel(nClass, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int GetMaxSpellLevel(int nClass)
|
||||
{
|
||||
if (nClass == CLASS_TYPE_WILDER
|
||||
|| nClass == CLASS_TYPE_PSION)
|
||||
return 9;
|
||||
if (nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
||||
|| nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
||||
|| nClass == CLASS_TYPE_WARMIND)
|
||||
return 5;
|
||||
if (nClass == CLASS_TYPE_PSYWAR)
|
||||
return 6;
|
||||
|
||||
return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass));
|
||||
}
|
||||
|
||||
int GetHighestLevelPossibleInClass(int nClass)
|
||||
{
|
||||
string sFile;
|
||||
|
||||
//sponts have their spells in the classes.2da
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
sFile = Get2DACache("classes", "SpellGainTable", nClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// everyone else uses this
|
||||
sFile = GetAMSKnownFileName(nClass);
|
||||
|
||||
if (nClass == CLASS_TYPE_TRUENAMER)
|
||||
{
|
||||
sFile = "cls_true_maxlvl"; //has a different 2da we want to look at
|
||||
}
|
||||
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
sFile = "cls_bind_binder";
|
||||
}
|
||||
}
|
||||
|
||||
return Get2DARowCount(sFile);
|
||||
}
|
||||
|
||||
string GetClassSpellbookFile(int nClass)
|
||||
{
|
||||
string sFile;
|
||||
// Spontaneous casters use a specific file name structure
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
sFile = GetFileForClass(nClass);
|
||||
}
|
||||
// everyone else uses this structure
|
||||
else
|
||||
{
|
||||
sFile = GetAMSDefinitionFileName(nClass);
|
||||
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
sFile = "vestiges";
|
||||
}
|
||||
}
|
||||
|
||||
return sFile;
|
||||
}
|
||||
|
||||
string GetSpellLevelIcon(int spellLevel)
|
||||
{
|
||||
switch (spellLevel)
|
||||
{
|
||||
case 0: return "ir_cantrips";
|
||||
case 1: return "ir_level1";
|
||||
case 2: return "ir_level2";
|
||||
case 3: return "ir_level3";
|
||||
case 4: return "ir_level4";
|
||||
case 5: return "ir_level5";
|
||||
case 6: return "ir_level6";
|
||||
case 7: return "ir_level789";
|
||||
case 8: return "ir_level789";
|
||||
case 9: return "ir_level789";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
string GetSpellLevelToolTip(int spellLevel)
|
||||
{
|
||||
switch (spellLevel)
|
||||
{
|
||||
case 0: return "Cantrips";
|
||||
case 1: return "Level 1";
|
||||
case 2: return "Level 2";
|
||||
case 3: return "Level 3";
|
||||
case 4: return "Level 4";
|
||||
case 5: return "Level 5";
|
||||
case 6: return "Level 6";
|
||||
case 7: return "Level 7";
|
||||
case 8: return "Level 8";
|
||||
case 9: return "Level 9";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
json GetSpellIcon(int spellId,int featId=0,int nClass=0)
|
||||
{
|
||||
// Binder's spells don't have the FeatID on the spells.2da, so we have to use
|
||||
// the mapping we constructed to get it.
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
json binderDict = GetBinderSpellToFeatDictionary();
|
||||
int nFeatID = JsonGetInt(JsonObjectGet(binderDict, IntToString(spellId)));
|
||||
return JsonString(Get2DACache("feat", "Icon", featId));
|
||||
}
|
||||
|
||||
if (featId)
|
||||
return JsonString(Get2DACache("feat", "Icon", featId));
|
||||
|
||||
int masterSpellID = StringToInt(Get2DACache("spells", "Master", spellId));
|
||||
|
||||
// if this is a sub radial spell, then we use spell's icon instead
|
||||
if (masterSpellID)
|
||||
return JsonString(Get2DACache("spells", "IconResRef", spellId));
|
||||
|
||||
// the FeatID holds the accurate spell icon, not the SpellID
|
||||
int nFeatID = StringToInt(Get2DACache("spells", "FeatID", spellId));
|
||||
|
||||
return JsonString(Get2DACache("feat", "Icon", nFeatID));
|
||||
}
|
||||
|
||||
string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0)
|
||||
{
|
||||
if ((nClass == CLASS_TYPE_SHADOWSMITH
|
||||
|| nClass == CLASS_TYPE_SHADOWCASTER) && spellId)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId)));
|
||||
if (nClass == CLASS_TYPE_TRUENAMER && featId)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId)));
|
||||
if (realSpellID)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", realSpellID)));
|
||||
if (spellId)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId)));
|
||||
if (featId)
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId)));
|
||||
|
||||
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId)));
|
||||
}
|
||||
|
||||
json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF)
|
||||
{
|
||||
// a dictionary of <SpellID, FeatID>
|
||||
json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR);
|
||||
// if this hasn't been created, create it now.
|
||||
if (binderDict == JsonNull())
|
||||
binderDict = JsonObject();
|
||||
else
|
||||
return binderDict;
|
||||
|
||||
// the starting row for binder spells
|
||||
int spellIndex = 19070;
|
||||
// the starting row for binder feats
|
||||
int featIndex = 9030;
|
||||
//the end of the binder spells/feats
|
||||
while (spellIndex <= 19156 && featIndex <= 9104)
|
||||
{
|
||||
// get the SpellID tied to the feat
|
||||
int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex));
|
||||
// if the spellID matches the current index, then this is the spell
|
||||
// attached to the feat
|
||||
if (spellID == spellIndex)
|
||||
{
|
||||
binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex));
|
||||
|
||||
// move to next spell/feat
|
||||
featIndex++;
|
||||
spellIndex++;
|
||||
}
|
||||
// else we have reached a subdial spell
|
||||
else
|
||||
{
|
||||
// loop through until we reach back at spellID
|
||||
while (spellIndex < spellID)
|
||||
{
|
||||
int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex));
|
||||
|
||||
// add the sub radial to the dict, tied to the master's FeatID
|
||||
int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell)));
|
||||
binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId));
|
||||
|
||||
spellIndex++;
|
||||
}
|
||||
|
||||
|
||||
// some feats overlap the same FeatID, can cause this to get stuck.
|
||||
// if it happens then move on
|
||||
if (spellIndex > spellID)
|
||||
featIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// cache the result
|
||||
SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict);
|
||||
return binderDict;
|
||||
}
|
||||
|
||||
json GreyOutButton(json jButton, float w, float h)
|
||||
{
|
||||
json retValue = jButton;
|
||||
|
||||
json jBorders = JsonArray();
|
||||
jBorders = JsonArrayInsert(jBorders, CreateGreyOutRectangle(w, h));
|
||||
|
||||
return NuiDrawList(jButton, JsonBool(FALSE), jBorders);
|
||||
}
|
||||
|
||||
json CreateGreyOutRectangle(float w, float h)
|
||||
{
|
||||
// set the points of the button shape
|
||||
json jPoints = JsonArray();
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(h));
|
||||
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(w));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(h));
|
||||
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(w));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
||||
|
||||
return NuiDrawListPolyLine(JsonBool(TRUE), NuiColor(0, 0, 0, 127), JsonBool(TRUE), JsonFloat(2.0), jPoints);
|
||||
}
|
||||
|
||||
void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0)
|
||||
{
|
||||
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR, featID);
|
||||
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR, spellId);
|
||||
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR, realSpellId);
|
||||
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR, nClass);
|
||||
ExecuteScript("prc_nui_dsc_view", oPlayer);
|
||||
}
|
||||
|
||||
void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF)
|
||||
{
|
||||
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR);
|
||||
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR);
|
||||
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR);
|
||||
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR);
|
||||
}
|
||||
|
@ -110,4 +110,49 @@ const string NUI_PRC_PA_TEXT_BIND = "nui_prc_pa_text_bind";
|
||||
// Left Button Enabled Bind for Power Attack NUI
|
||||
const string NUI_PRC_PA_LEFT_BUTTON_ENABLED_BIND = "leftButtonEnabled";
|
||||
// Right Button Enabled Bind for Power Attack NUI
|
||||
const string NUI_PRC_PA_RIGHT_BUTTON_ENABLED_BIND = "rightButtonEnabled";
|
||||
const string NUI_PRC_PA_RIGHT_BUTTON_ENABLED_BIND = "rightButtonEnabled";
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// //
|
||||
// NUI Level Up //
|
||||
// //
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
const string NUI_LEVEL_UP_WINDOW_ID = "prcLevelUpNui";
|
||||
|
||||
const string NUI_LEVEL_UP_SPELL_CIRCLE_BUTTON_BASEID = "NuiLevelUpCircleButton_";
|
||||
const string NUI_LEVEL_UP_SPELL_BUTTON_BASEID = "NuiLevelUpSpellButton_";
|
||||
const string NUI_LEVEL_UP_SPELL_DISABLED_BUTTON_BASEID = "NuiLevelUpDisabledSpellButton_";
|
||||
const string NUI_LEVEL_UP_SPELL_CHOSEN_BUTTON_BASEID = "NuiLevelUpChosenSpellButton_";
|
||||
const string NUI_LEVEL_UP_SPELL_CHOSEN_DISABLED_BUTTON_BASEID = "NuiLevelUpDisabledChosenSpellButton_";
|
||||
const string NUI_LEVEL_UP_DONE_BUTTON = "NuiLevelUpDoneButton";
|
||||
const string NUI_LEVEL_UP_RESET_BUTTON = "NuiLevelUpResetButton";
|
||||
|
||||
const string NUI_LEVEL_UP_SELECTED_CLASS_VAR = "NUILevelUpSelectedClass";
|
||||
const string NUI_LEVEL_UP_SELECTED_CIRCLE_VAR = "NUILevelUpSelectedCircle";
|
||||
const string NUI_LEVEL_UP_KNOWN_SPELLS_VAR = "NUILevelUpKnownSpells";
|
||||
const string NUI_LEVEL_UP_CHOSEN_SPELLS_VAR = "NUILevelUpChosenSpells";
|
||||
const string NUI_LEVEL_UP_EXPANDED_KNOW_LIST_VAR = "NUILevelUpExpKnowList";
|
||||
const string NUI_LEVEL_UP_POWER_LIST_VAR = "NUILevelUpPowerList";
|
||||
const string NUI_LEVEL_UP_DISCIPLINE_INFO_VAR = "GetDisciplineInfoObjectCache_";
|
||||
const string NUI_LEVEL_UP_SPELLID_LIST_VAR = "NUILevelUpSpellIDList_";
|
||||
const string NUI_LEVEL_UP_REMAINING_CHOICES_CACHE_VAR = "NUIRemainingChoicesCache";
|
||||
const string NUI_LEVEL_UP_RELEARN_LIST_VAR = "NUILevelUpRelearnList";
|
||||
const string NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR = "NUILevelUpArchivistNewSpellsList";
|
||||
|
||||
const string NUI_LEVEL_UP_EXPANDED_CHOICES_VAR = "NUIExpandedChoices";
|
||||
const string NUI_LEVEL_UP_EPIC_EXPANDED_CHOICES_VAR = "NUIEpicExpandedChoices";
|
||||
|
||||
const int NUI_LEVEL_UP_MANEUVER_PREREQ_LIMIT = 6;
|
||||
|
||||
const string NUI_LEVEL_UP_MANEUVER_TOTAL = "ManeuverTotal";
|
||||
const string NUI_LEVEL_UP_STANCE_TOTAL = "StanceTotal";
|
||||
|
||||
const string NUI_LEVEL_UP_SPELLBOOK_OBJECT_CACHE_VAR = "GetSpellListObjectCache_";
|
||||
const string NUI_LEVEL_UP_KNOWN_INVOCATIONS_CACHE_VAR = "GetInvokerKnownListObjectCache_";
|
||||
|
||||
const string NUI_SPELL_DESCRIPTION_FEATID_VAR = "NUISpellDescriptionFeatID";
|
||||
const string NUI_SPELL_DESCRIPTION_CLASSID_VAR = "NUISpellDescriptionClassID";
|
||||
const string NUI_SPELL_DESCRIPTION_SPELLID_VAR = "NUISpellDescriptionSpellID";
|
||||
const string NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR = "NUISpellDescriptionRealSpellID";
|
||||
|
||||
|
3339
src/include/prc_nui_lv_inc.nss
Normal file
3339
src/include/prc_nui_lv_inc.nss
Normal file
File diff suppressed because it is too large
Load Diff
@ -10,10 +10,8 @@
|
||||
//:: Created By: Rakiov
|
||||
//:: Created On: 24.05.2005
|
||||
//:://////////////////////////////////////////////
|
||||
#include "inc_newspellbook"
|
||||
#include "psi_inc_psifunc"
|
||||
#include "inc_lookups"
|
||||
#include "prc_nui_consts"
|
||||
|
||||
#include "prc_nui_com_inc"
|
||||
|
||||
//
|
||||
// GetSpellListForCircle
|
||||
@ -43,69 +41,6 @@ json GetSpellListForCircle(object oPlayer, int nClass, int circle);
|
||||
//
|
||||
json GetSupportedNUISpellbookClasses(object oPlayer);
|
||||
|
||||
//
|
||||
// GetCurrentSpellLevel
|
||||
// Gets the current spell level the class can achieve at the current
|
||||
// caster level (ranging from 0-9)
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
// nLevel:int the caster level
|
||||
//
|
||||
// Returns:
|
||||
// int the circle the class can achieve currently
|
||||
//
|
||||
int GetCurrentSpellLevel(int nClass, int nLevel);
|
||||
|
||||
//
|
||||
// GetMaxSpellLevel
|
||||
// Gets the highest possible circle the class can achieve (from 0-9)
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
//
|
||||
// Returns:
|
||||
// int the highest circle that can be achieved
|
||||
//
|
||||
int GetMaxSpellLevel(int nClass);
|
||||
|
||||
//
|
||||
// GetMinSpellLevel
|
||||
// Gets the lowest possible circle the class can achieve (from 0-9)
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
//
|
||||
// Returns:
|
||||
// int the lowest circle that can be achieved
|
||||
//
|
||||
int GetMinSpellLevel(int nClass);
|
||||
|
||||
//
|
||||
// GetHighestLevelPossibleInClass
|
||||
// Given a class Id this will determine what the max level of a class can be
|
||||
// achieved
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the ClassID
|
||||
//
|
||||
// Returns:
|
||||
// int the highest possible level the class can achieve
|
||||
//
|
||||
int GetHighestLevelPossibleInClass(int nClass);
|
||||
|
||||
//
|
||||
// GetClassSpellbookFile
|
||||
// Gets the class 2da spellbook/ability for the given class Id
|
||||
//
|
||||
// Arguments:
|
||||
// nClass:int the classID
|
||||
//
|
||||
// Returns:
|
||||
// string the 2da file name for the spell/abilities of the ClassID
|
||||
//
|
||||
string GetClassSpellbookFile(int nClass);
|
||||
|
||||
//
|
||||
// IsSpellKnown
|
||||
// Returns whether the player with the given class, spell file, and spellbook id
|
||||
@ -234,23 +169,6 @@ json GetMetaMysteryFeatList();
|
||||
//
|
||||
int GetTrueClassIfRHD(object oPlayer, int nClass);
|
||||
|
||||
//
|
||||
// GetBinderSpellToFeatDictionary
|
||||
// Sets up the Binder Spell Dictionary that is used to match a binder's vestige
|
||||
// to their feat. This is constructed based off the binder's known location of
|
||||
// their feat and spell ranges in the base 2das respectivly. After constructing
|
||||
// this it will be saved to the player locally as a cached result since we do
|
||||
// not need to call this again.
|
||||
//
|
||||
// Argument:
|
||||
// oPlayer:object the player
|
||||
//
|
||||
// Returns:
|
||||
// json:Dictionary<String,Int> a dictionary of mapping between the SpellID
|
||||
// and the FeatID of a vestige ability
|
||||
//
|
||||
json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF);
|
||||
|
||||
//
|
||||
// ShouldAddSpell
|
||||
// Given a spellId and a class, determines if the spell should be added to the
|
||||
@ -318,6 +236,18 @@ json GetInvokerEssenceSpellList(int nClass, object oPlayer=OBJECT_SELF);
|
||||
//
|
||||
int JsonArrayContainsInt(json list, int item);
|
||||
|
||||
//
|
||||
// IsSpellbookNUIOpen
|
||||
// Checks to see if the Spellbook NUI is open on a given player.
|
||||
//
|
||||
// Arguments:
|
||||
// oPC:object the player
|
||||
//
|
||||
// Returns:
|
||||
// int:Boolean TRUE if window is open, FALSE otherwise
|
||||
//
|
||||
int IsSpellbookNUIOpen(object oPC);
|
||||
|
||||
json GetSpellListForCircle(object oPlayer, int nClass, int circle)
|
||||
{
|
||||
json retValue = JsonArray();
|
||||
@ -397,86 +327,6 @@ int ShouldAddSpell(int nClass, int spellId, object oPlayer=OBJECT_SELF)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF)
|
||||
{
|
||||
// a dictionary of <SpellID, FeatID>
|
||||
json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR);
|
||||
// if this hasn't been created, create it now.
|
||||
if (binderDict == JsonNull())
|
||||
binderDict = JsonObject();
|
||||
else
|
||||
return binderDict;
|
||||
|
||||
// the starting row for binder spells
|
||||
int spellIndex = 19070;
|
||||
// the starting row for binder feats
|
||||
int featIndex = 9030;
|
||||
//the end of the binder spells/feats
|
||||
while (spellIndex <= 19156 && featIndex <= 9104)
|
||||
{
|
||||
// get the SpellID tied to the feat
|
||||
int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex));
|
||||
// if the spellID matches the current index, then this is the spell
|
||||
// attached to the feat
|
||||
if (spellID == spellIndex)
|
||||
{
|
||||
binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex));
|
||||
|
||||
// move to next spell/feat
|
||||
featIndex++;
|
||||
spellIndex++;
|
||||
}
|
||||
// else we have reached a subdial spell
|
||||
else
|
||||
{
|
||||
// loop through until we reach back at spellID
|
||||
while (spellIndex < spellID)
|
||||
{
|
||||
int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex));
|
||||
|
||||
// add the sub radial to the dict, tied to the master's FeatID
|
||||
int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell)));
|
||||
binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId));
|
||||
|
||||
spellIndex++;
|
||||
}
|
||||
|
||||
|
||||
// some feats overlap the same FeatID, can cause this to get stuck.
|
||||
// if it happens then move on
|
||||
if (spellIndex > spellID)
|
||||
featIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// cache the result
|
||||
SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict);
|
||||
return binderDict;
|
||||
}
|
||||
|
||||
string GetClassSpellbookFile(int nClass)
|
||||
{
|
||||
string sFile;
|
||||
// Spontaneous casters use a specific file name structure
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
sFile = GetFileForClass(nClass);
|
||||
}
|
||||
// everyone else uses this structure
|
||||
else
|
||||
{
|
||||
sFile = GetAMSDefinitionFileName(nClass);
|
||||
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
sFile = "vestiges";
|
||||
}
|
||||
}
|
||||
|
||||
return sFile;
|
||||
}
|
||||
|
||||
json GetSupportedNUISpellbookClasses(object oPlayer)
|
||||
{
|
||||
json retValue = JsonArray();
|
||||
@ -526,167 +376,6 @@ int IsSpellKnown(object oPlayer, int nClass, int spellId)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int GetCurrentSpellLevel(int nClass, int nLevel)
|
||||
{
|
||||
int currentLevel = nLevel;
|
||||
|
||||
// ToB doesn't have a concept of spell levels, but still match up to it
|
||||
if(nClass == CLASS_TYPE_WARBLADE
|
||||
|| nClass == CLASS_TYPE_SWORDSAGE
|
||||
|| nClass == CLASS_TYPE_CRUSADER
|
||||
|| nClass == CLASS_TYPE_SHADOWCASTER)
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
|
||||
// Binders don't really have a concept of spell level
|
||||
if (nClass == CLASS_TYPE_BINDER
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle
|
||||
return 1;
|
||||
|
||||
//Shadowsmith has no concept of spell levels
|
||||
if (nClass == CLASS_TYPE_SHADOWSMITH)
|
||||
return 2;
|
||||
|
||||
if (nClass == CLASS_TYPE_WARLOCK
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
||||
return 4;
|
||||
|
||||
// Spont casters have their own function
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
|
||||
int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel);
|
||||
return maxLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
// everyone else uses this
|
||||
string spellLevel2da = GetAMSKnownFileName(nClass);
|
||||
|
||||
currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da
|
||||
|
||||
if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
||||
|| nClass == CLASS_TYPE_PSION
|
||||
|| nClass == CLASS_TYPE_PSYWAR
|
||||
|| nClass == CLASS_TYPE_WILDER
|
||||
|| nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
||||
|| nClass == CLASS_TYPE_WARMIND)
|
||||
currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1;
|
||||
|
||||
int totalLevel = Get2DARowCount(spellLevel2da);
|
||||
|
||||
// in case we somehow go over bounds just don't :)
|
||||
if (currentLevel >= totalLevel)
|
||||
currentLevel = totalLevel - 1;
|
||||
|
||||
//Psionics have MaxPowerLevel as their column name
|
||||
string columnName = "MaxPowerLevel";
|
||||
|
||||
//Invokers have MaxInvocationLevel
|
||||
if (nClass == CLASS_TYPE_WARLOCK
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
||||
columnName = "MaxInvocationLevel";
|
||||
|
||||
// Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range
|
||||
if (nClass == CLASS_TYPE_TRUENAMER)
|
||||
{
|
||||
columnName = "EvolvingMind";
|
||||
spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at
|
||||
}
|
||||
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
columnName = "VestigeLvl";
|
||||
spellLevel2da = "cls_bind_binder";
|
||||
}
|
||||
|
||||
// ToB doesn't have a concept of this, but we don't care.
|
||||
|
||||
int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel));
|
||||
return maxLevel;
|
||||
}
|
||||
}
|
||||
|
||||
int GetMinSpellLevel(int nClass)
|
||||
{
|
||||
// again sponts have their own function
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
||||
|| nClass == CLASS_TYPE_PSION
|
||||
|| nClass == CLASS_TYPE_PSYWAR
|
||||
|| nClass == CLASS_TYPE_WILDER
|
||||
|| nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
||||
|| nClass == CLASS_TYPE_WARMIND
|
||||
|| nClass == CLASS_TYPE_WARBLADE
|
||||
|| nClass == CLASS_TYPE_SWORDSAGE
|
||||
|| nClass == CLASS_TYPE_CRUSADER
|
||||
|| nClass == CLASS_TYPE_WARLOCK
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|
||||
|| nClass == CLASS_TYPE_SHADOWCASTER
|
||||
|| nClass == CLASS_TYPE_SHADOWSMITH
|
||||
|| nClass == CLASS_TYPE_BINDER)
|
||||
return 1;
|
||||
|
||||
return GetCurrentSpellLevel(nClass, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int GetMaxSpellLevel(int nClass)
|
||||
{
|
||||
if (nClass == CLASS_TYPE_WILDER
|
||||
|| nClass == CLASS_TYPE_PSION)
|
||||
return 9;
|
||||
if (nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
||||
|| nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
||||
|| nClass == CLASS_TYPE_WARMIND)
|
||||
return 5;
|
||||
if (nClass == CLASS_TYPE_PSYWAR)
|
||||
return 6;
|
||||
|
||||
return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass));
|
||||
}
|
||||
|
||||
int GetHighestLevelPossibleInClass(int nClass)
|
||||
{
|
||||
string sFile;
|
||||
|
||||
//sponts have their spells in the classes.2da
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
||||
|| nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
sFile = Get2DACache("classes", "SpellGainTable", nClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// everyone else uses this
|
||||
sFile = GetAMSKnownFileName(nClass);
|
||||
|
||||
if (nClass == CLASS_TYPE_TRUENAMER)
|
||||
{
|
||||
sFile = "cls_true_maxlvl"; //has a different 2da we want to look at
|
||||
}
|
||||
|
||||
if (nClass == CLASS_TYPE_BINDER)
|
||||
{
|
||||
sFile = "cls_bind_binder";
|
||||
}
|
||||
}
|
||||
|
||||
return Get2DARowCount(sFile);
|
||||
}
|
||||
|
||||
int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass)
|
||||
{
|
||||
// This controls who can use the Spellbook NUI, if for some reason you don't
|
||||
@ -698,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
|
||||
@ -817,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
|
||||
@ -838,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
|
||||
@ -1144,5 +830,16 @@ int JsonArrayContainsInt(json list, int item)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int IsSpellbookNUIOpen(object oPC)
|
||||
{
|
||||
int nPreviousToken = NuiFindWindow(oPC, PRC_SPELLBOOK_NUI_WINDOW_ID);
|
||||
if (nPreviousToken != 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: PRC Spellbook Description NUI
|
||||
//:: prc_nui_scd_inc
|
||||
//:: prc_nui_sbd_inc
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
This is the view for the Spell Description NUI
|
@ -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;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ const string _MYSTERY_LIST_MISC_ARRAY = "_MysteriesKnownMiscArray";
|
||||
const string _MYSTERY_LIST_LEVEL_ARRAY = "_MysteriesKnownLevelArray_";
|
||||
const string _MYSTERY_LIST_GENERAL_ARRAY = "_MysteriesKnownGeneralArray";
|
||||
|
||||
#include "shd_inc_shdfunc"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function prototypes */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1154,6 +1154,7 @@ int GetIsDisciplineWeapon(object oWeapon, int nDiscipline)
|
||||
// Invalid is empty handed / Unarmed strike
|
||||
if(nType == BASE_ITEM_INVALID
|
||||
|| nType == BASE_ITEM_QUARTERSTAFF
|
||||
|| nType == BASE_ITEM_MAGICSTAFF
|
||||
|| nType == BASE_ITEM_SHORTSWORD
|
||||
|| nType == BASE_ITEM_NUNCHAKU)
|
||||
return TRUE;
|
||||
|
@ -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
|
||||
@ -1441,8 +1539,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF)
|
||||
if (GetHasFeat(FEAT_WILDMAGE_SPELLCASTING_BARD)) return TRUE;
|
||||
if (GetHasFeat(FEAT_WWOC_SPELLCASTING_BARD)) return TRUE;
|
||||
}
|
||||
else if (bBeguiler)
|
||||
if (bBeguiler)
|
||||
{
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Beguiler", oPC);
|
||||
if (GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_BEGUILER)) return TRUE;
|
||||
if (GetHasFeat(FEAT_AOTS_SPELLCASTING_BEGUILER)) return TRUE;
|
||||
if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_BEGUILER)) return TRUE;
|
||||
@ -1492,8 +1591,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF)
|
||||
|
||||
|
||||
}
|
||||
else if (bDuskblade)
|
||||
if (bDuskblade)
|
||||
{
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Dusblade", oPC);
|
||||
if (GetHasFeat(FEAT_ABCHAMP_SPELLCASTING_DUSKBLADE)) return TRUE;
|
||||
if (GetHasFeat(FEAT_AOTS_SPELLCASTING_DUSKBLADE)) return TRUE;
|
||||
if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_DUSKBLADE)) return TRUE;
|
||||
@ -1540,8 +1640,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF)
|
||||
|
||||
|
||||
}
|
||||
else if (bSorcerer)
|
||||
if (bSorcerer)
|
||||
{
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Sorcerer", oPC);
|
||||
if (GetHasFeat(FEAT_ABERRATION_SPELLCASTING_DRIDER)) return TRUE;
|
||||
if (GetHasFeat(FEAT_MONSTROUS_SPELLCASTING_ARKAMOI)) return TRUE;
|
||||
if (GetHasFeat(FEAT_MONSTROUS_SPELLCASTING_MARRUTACT)) return TRUE;
|
||||
@ -1599,8 +1700,9 @@ int CheckSecondaryPrC(object oPC = OBJECT_SELF)
|
||||
if (GetHasFeat(FEAT_WILDMAGE_SPELLCASTING_SORCERER)) return TRUE;
|
||||
if (GetHasFeat(FEAT_WWOC_SPELLCASTING_SORCERER)) return TRUE;
|
||||
}
|
||||
else if (bWarmage)
|
||||
if (bWarmage)
|
||||
{
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: CheckSecondaryPrC >>> Entering Warmage", oPC);
|
||||
if (GetHasFeat(FEAT_AOTS_SPELLCASTING_WARMAGE)) return TRUE;
|
||||
if (GetHasFeat(FEAT_ALCHEM_SPELLCASTING_WARMAGE)) return TRUE;
|
||||
if (GetHasFeat(FEAT_ANIMA_SPELLCASTING_WARMAGE)) return TRUE;
|
||||
@ -1662,14 +1764,71 @@ int BardSorcPrCCheck(object oCaster, int nCastingClass, object oSpellCastItem)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//check its a sorc spell
|
||||
//check its a sorcerer spell
|
||||
if(nCastingClass == CLASS_TYPE_SORCERER)
|
||||
{
|
||||
if (CheckSecondaryPrC(oCaster) == TRUE)
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> nCastingClass is Sorcerer.", oCaster);
|
||||
//no need to check further if new spellbooks are disabled
|
||||
if(GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK))
|
||||
{
|
||||
if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Sorcerer w/RHD found.", oCaster);
|
||||
if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> PRC_SORC_DISALLOW_NEWSPELLBOOK.", oCaster);
|
||||
return TRUE;
|
||||
}
|
||||
//check they have sorcerer levels
|
||||
if(!GetLevelByClass(CLASS_TYPE_SORCERER, oCaster))
|
||||
{
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Not a sorcerer.", oCaster);
|
||||
return TRUE;
|
||||
}
|
||||
//check if they are casting via new spellbook
|
||||
if(GetLocalInt(oCaster, "NSB_Class") != CLASS_TYPE_SORCERER && GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oCaster))
|
||||
{
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> UltMagus using new spellbook.", oCaster);
|
||||
return FALSE;
|
||||
}
|
||||
//check if they are casting via new spellbook
|
||||
if(GetLocalInt(oCaster, "NSB_Class") == CLASS_TYPE_SORCERER)
|
||||
{
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Using new spellbook.", oCaster);
|
||||
return TRUE;
|
||||
}
|
||||
if(GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oCaster) > 0 && CheckSecondaryPrC(oCaster) == TRUE)
|
||||
{
|
||||
if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Sublime Chord w/RHD found.", oCaster);
|
||||
FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
if (CheckSecondaryPrC(oCaster) == TRUE)
|
||||
{
|
||||
if (DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> Sorcerer w/RHD found.", oCaster);
|
||||
FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
//check they have arcane PrC or Draconic Arcane Grace/Breath
|
||||
if(!(GetArcanePRCLevels(oCaster, nCastingClass) - GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oCaster))
|
||||
&& !(GetHasFeat(FEAT_DRACONIC_GRACE, oCaster) || GetHasFeat(FEAT_DRACONIC_BREATH, oCaster)))
|
||||
{
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> First Sublime Chord check.", oCaster);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//check they have sorcerer in first arcane slot
|
||||
//if(GetPrimaryArcaneClass() != CLASS_TYPE_SORCERER)
|
||||
if(GetPrCAdjustedCasterLevelByType(TYPE_ARCANE, oCaster, TRUE) != GetPrCAdjustedCasterLevelByType(CLASS_TYPE_SORCERER, oCaster, TRUE))
|
||||
{
|
||||
if(DEBUG) DoDebug("x2_inc_spellhook: BardSorcPrCCheck >>> GetPrCAdjustedCasterLevelByType.", oCaster);
|
||||
return TRUE;
|
||||
}
|
||||
//at this point, they must be using the bioware spellbook
|
||||
//from a class that adds to bard
|
||||
FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* //check its a sorc spell
|
||||
if(nCastingClass == CLASS_TYPE_SORCERER)
|
||||
{
|
||||
//no need to check further if new spellbooks are disabled
|
||||
if(GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK))
|
||||
return TRUE;
|
||||
@ -1708,7 +1867,7 @@ int BardSorcPrCCheck(object oCaster, int nCastingClass, object oSpellCastItem)
|
||||
//from a class that adds to sorc
|
||||
FloatingTextStringOnCreature("You must use the new spellbook on the class radial.", oCaster, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
} */
|
||||
|
||||
//check its a bard spell
|
||||
if(nCastingClass == CLASS_TYPE_BARD)
|
||||
@ -3188,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)
|
||||
@ -3338,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
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -35503,7 +35503,7 @@
|
||||
"__struct_id": 0,
|
||||
"CR": {
|
||||
"type": "float",
|
||||
"value": 0.5
|
||||
"value": 0.3333
|
||||
},
|
||||
"FACTION": {
|
||||
"type": "cexostring",
|
||||
|
@ -9,6 +9,159 @@
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
},
|
||||
"EntryList": {
|
||||
"type": "list",
|
||||
"value": [
|
||||
{
|
||||
"__struct_id": 0,
|
||||
"End": {
|
||||
"type": "word",
|
||||
"value": 0
|
||||
},
|
||||
"ID": {
|
||||
"type": "dword",
|
||||
"value": 1
|
||||
},
|
||||
"Text": {
|
||||
"type": "cexolocstring",
|
||||
"value": {
|
||||
"0": "3e D&D Experience Chart\n\nLvl XP Needed\n01 0\n02 1000\n03 3000\n04 6000\n05 10000\n06 15000\n07 21000\n08 28000\n09 36000\n10 45000\n11 55000\n12 66000\n13 78000\n14 91000\n15 105000\n16 120000\n17 136000\n18 153000\n19 171000\n20 190000\n21 210000\n22 231000\n23 253000\n24 276000\n25 300000\n26 325000\n27 351000\n28 378000\n29 406000\n30 435000\n31 465000\n32 496000\n33 528000\n34 561000\n35 595000\n36 630000\n37 666000\n38 703000\n39 741000\n40 780000"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Name": {
|
||||
"type": "cexolocstring",
|
||||
"value": {
|
||||
"0": "| D&D 3e XP Chart |"
|
||||
}
|
||||
},
|
||||
"Picture": {
|
||||
"type": "word",
|
||||
"value": 65535
|
||||
},
|
||||
"Priority": {
|
||||
"type": "dword",
|
||||
"value": 4
|
||||
},
|
||||
"Tag": {
|
||||
"type": "cexostring",
|
||||
"value": "JRNL_XPCHART"
|
||||
},
|
||||
"XP": {
|
||||
"type": "dword",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 1,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
},
|
||||
"EntryList": {
|
||||
"type": "list",
|
||||
"value": [
|
||||
{
|
||||
"__struct_id": 0,
|
||||
"End": {
|
||||
"type": "word",
|
||||
"value": 0
|
||||
},
|
||||
"ID": {
|
||||
"type": "dword",
|
||||
"value": 1
|
||||
},
|
||||
"Text": {
|
||||
"type": "cexolocstring",
|
||||
"value": {
|
||||
"0": "Level Adjustment Buy-off Table\n\nStarting LA / Level\n \n01 / 03\n02 / 06 09\n03 / 09 15 18\n04 / 12 21 27 30\n05 / 15 27 36\n06 / 18 33\n07 / 21 39\n08 / 24\n09 / 27\n10 / 30\n11 / 33\n12 / 36\n13 / 39\n\n(Buy-off dialog will be in the PRC menu when you qualify.)"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Name": {
|
||||
"type": "cexolocstring",
|
||||
"value": {
|
||||
"0": "| LA Buy-off Table |"
|
||||
}
|
||||
},
|
||||
"Picture": {
|
||||
"type": "word",
|
||||
"value": 65535
|
||||
},
|
||||
"Priority": {
|
||||
"type": "dword",
|
||||
"value": 4
|
||||
},
|
||||
"Tag": {
|
||||
"type": "cexostring",
|
||||
"value": "JRNL_LA_BUYOFF"
|
||||
},
|
||||
"XP": {
|
||||
"type": "dword",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 2,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
},
|
||||
"EntryList": {
|
||||
"type": "list",
|
||||
"value": [
|
||||
{
|
||||
"__struct_id": 0,
|
||||
"End": {
|
||||
"type": "word",
|
||||
"value": 0
|
||||
},
|
||||
"ID": {
|
||||
"type": "dword",
|
||||
"value": 1
|
||||
},
|
||||
"Text": {
|
||||
"type": "cexolocstring",
|
||||
"value": {
|
||||
"0": "Visit the PRC8 Discord for ruleset information, as well as other PW servers & dozens of single player PRC8 modules.\n\nhttps://discord.gg/FW9V9RKy5U"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Name": {
|
||||
"type": "cexolocstring",
|
||||
"value": {
|
||||
"0": "| PRC8 Discord |"
|
||||
}
|
||||
},
|
||||
"Picture": {
|
||||
"type": "word",
|
||||
"value": 65535
|
||||
},
|
||||
"Priority": {
|
||||
"type": "dword",
|
||||
"value": 4
|
||||
},
|
||||
"Tag": {
|
||||
"type": "cexostring",
|
||||
"value": "JRNL_PRC8"
|
||||
},
|
||||
"XP": {
|
||||
"type": "dword",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 3,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
},
|
||||
"EntryList": {
|
||||
"type": "list",
|
||||
"value": [
|
||||
@ -72,7 +225,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 1,
|
||||
"__struct_id": 4,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": "Delivery Quest"
|
||||
@ -225,7 +378,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 2,
|
||||
"__struct_id": 5,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
@ -684,7 +837,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 3,
|
||||
"__struct_id": 6,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
@ -752,7 +905,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 4,
|
||||
"__struct_id": 7,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
@ -820,7 +973,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 5,
|
||||
"__struct_id": 8,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
@ -888,7 +1041,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 6,
|
||||
"__struct_id": 9,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
@ -956,7 +1109,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 7,
|
||||
"__struct_id": 10,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
@ -1024,7 +1177,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 8,
|
||||
"__struct_id": 11,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
@ -1075,7 +1228,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 9,
|
||||
"__struct_id": 12,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
@ -1160,7 +1313,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"__struct_id": 10,
|
||||
"__struct_id": 13,
|
||||
"Comment": {
|
||||
"type": "cexostring",
|
||||
"value": ""
|
||||
|
@ -19,12 +19,12 @@ void AddToDynamicMerchant();
|
||||
|
||||
void main()
|
||||
{
|
||||
int iLevel;
|
||||
int iRnd;
|
||||
int iRnd2;
|
||||
int iIndex;
|
||||
object oPC;
|
||||
object oAnimal;
|
||||
int iLevel;
|
||||
int iRnd;
|
||||
int iRnd2;
|
||||
int iIndex;
|
||||
object oPC = GetEnteringObject();
|
||||
object oAnimal;
|
||||
|
||||
int iAnimal = GetLevelByClass(CLASS_TYPE_DRUID, oPC)
|
||||
+ GetLevelByClass(CLASS_TYPE_FACTOTUM, oPC)
|
||||
@ -32,21 +32,25 @@ object oAnimal;
|
||||
+ GetLevelByClass(CLASS_TYPE_RANGER, oPC)
|
||||
+ GetLevelByClass(CLASS_TYPE_SOULBORN, oPC)
|
||||
+ GetLevelByClass(CLASS_TYPE_TOTEMIST, oPC);
|
||||
|
||||
AddJournalQuestEntry("JRNL_XPCHART", 1, oPC, FALSE, FALSE, FALSE);
|
||||
AddJournalQuestEntry("JRNL_LA_BUYOFF", 1, oPC, FALSE, FALSE, FALSE);
|
||||
AddJournalQuestEntry("JRNL_PRC8", 1, oPC, FALSE, FALSE, FALSE);
|
||||
|
||||
SetLocalInt(GetModule(),MODULE_SWITCH_ENABLE_BEBILITH_RUIN_ARMOR,TRUE);
|
||||
SetMaxHenchmen(4);
|
||||
|
||||
//Randomize based on Timer
|
||||
iRnd=GetTimeSecond();
|
||||
iIndex=1;
|
||||
while (iIndex<=iRnd)
|
||||
{
|
||||
iIndex++;
|
||||
iRnd2=Random(100);
|
||||
}
|
||||
|
||||
SetLocalInt(GetModule(),MODULE_SWITCH_ENABLE_BEBILITH_RUIN_ARMOR,TRUE);
|
||||
SetMaxHenchmen(4);
|
||||
|
||||
//Randomize based on Timer
|
||||
iRnd=GetTimeSecond();
|
||||
iIndex=1;
|
||||
while (iIndex<=iRnd)
|
||||
{
|
||||
iIndex++;
|
||||
iRnd2=Random(100);
|
||||
}
|
||||
|
||||
|
||||
oPC = GetEnteringObject();
|
||||
|
||||
/*
|
||||
//This code will start a character with old values and campaign ranking on
|
||||
|
Loading…
x
Reference in New Issue
Block a user