2025/08/24 Update

Updated for PRC8 updates.
This commit is contained in:
Jaysyn904 2025-08-24 13:16:35 -04:00
parent 66d0ef278f
commit e76c3a2766
40 changed files with 3767 additions and 737 deletions

View File

@ -1,7 +1,7 @@
[package]
name = "A1-4 Scourge of the Slave Lords [PRC8-CEP3]"
description = "PRC8 version of A1-4 Scourge of the Slave Lords."
version = "4.2prc8"
version = "4.3prc8"
url = "https://discord.gg/ca2ru3KxYd"
author = "Nol Drek"
author = "Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com>"
@ -232,7 +232,10 @@ description = "PRC8 version of A1-4 Scourge of the Slave Lords."
filter = "prc_nui_scd_inc.nss"
filter = "prc_nui_consts.nss"
filter = "nw_inc_nui"
filter = "xchst_inc.nss"
filter = "inc_infusion.nss"
filter = "nw_inc_gff.nss"
filter = "prc_inc_json.nss"
filter = "xchst_inc.nss"
[target.rules]
"*" = "src/module/$ext"

View File

@ -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;
/*

View File

@ -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 != "")

View 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 well 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 (){}

View File

@ -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;
}

View File

@ -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"

View File

@ -720,7 +720,7 @@ void SetDefaultFileEnds()
SetPRCSwitch("PRC_FILE_END_polymorph", 155);
SetPRCSwitch("PRC_FILE_END_portraits", 1300);
SetPRCSwitch("PRC_FILE_END_prc_craft_alchem", 37);
SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 204);
SetPRCSwitch("PRC_FILE_END_prc_craft_gen_it", 253);
SetPRCSwitch("PRC_FILE_END_prc_craft_poison", 62);
SetPRCSwitch("PRC_FILE_END_prc_domains", 59);
SetPRCSwitch("PRC_FILE_END_prc_familiar", 10);
@ -767,7 +767,7 @@ void SetDefaultFileEnds()
SetPRCSwitch("PRC_FILE_END_soundset", 453);
SetPRCSwitch("PRC_FILE_END_soundsettype", 4);
SetPRCSwitch("PRC_FILE_END_soundtypes", 1);
SetPRCSwitch("PRC_FILE_END_spells", 19348);
SetPRCSwitch("PRC_FILE_END_spells", 19400);
//SetPRCSwitch("PRC_FILE_END_spellschools", 9);
SetPRCSwitch("PRC_FILE_END_statescripts", 35);
SetPRCSwitch("PRC_FILE_END_stringtokens", 92);
@ -1069,14 +1069,16 @@ void CreateSwitchNameArray()
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_ROD_CASTER_LEVEL);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFT_STAFF_CASTER_LEVEL);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_BASE_ITEMS);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_MAXLEVEL);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_BREWPOTION_COSTMODIFIER);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_SCRIBESCROLL_COSTMODIFIER);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_MAXLEVEL);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), X2_CI_CRAFTWAND_COSTMODIFIER);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_MAXLEVEL);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_BREWPOTION_COSTMODIFIER);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_SCRIBESCROLL_COSTMODIFIER);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_MAXLEVEL);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CRAFTWAND_COSTMODIFIER);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_X2_CREATEINFUSION_COSTMODIFIER);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_ARBITRARY);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_COST_SCALE);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CRAFTING_TIME_SCALE);
array_set_string(oWP, "Switch_Name", array_get_size(oWP, "Switch_Name"), PRC_CREATE_INFUSION_CASTER_LEVEL);
//spells

View File

@ -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
View 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

View File

@ -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)

View File

@ -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 (){}

View File

@ -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() {}

View File

@ -152,6 +152,9 @@ const int FEAT_EPIC_DIAMOND_DRAGON = 25115;
const int FEAT_EPIC_CRUSADER = 25116;
const int FEAT_EPIC_SWORDSAGE = 25117;
const int FEAT_EPIC_WARBLADE = 25118;
const int FEAT_EPIC_LION_OF_TALISID = 25600;
const int FEAT_EPIC_VERDANT_LORD = 25618;
//:: Vile Martial Strike Expansion
const int FEAT_VILE_MARTIAL_EAGLE_CLAW = 24800;
@ -195,6 +198,28 @@ const int FEAT_CHARMING_THE_ARROW = 25998;
//:: Skill Based Feats
const int FEAT_JUMP = 2884;
//:: Lion of Talisid
const int FEAT_LOT_LIONS_COURAGE = 25614;
const int FEAT_LOT_LIONS_POUNCE = 25615;
const int FEAT_LOT_LIONS_SWIFTNESS = 25616;
const int FEAT_LOT_LEONALS_ROAR = 25617;
//::: Verdant Lord
const int FEAT_VL_EXPERT_INFUSION = 25634;
const int FEAT_VL_SUN_SUSTENANCE = 25635;
const int FEAT_VL_SPONTANEITY = 25636;
const int FEAT_VL_PLANT_FACILITY = 25637;
const int FEAT_VL_WILD_SHAPE_TREANT = 25638;
const int FEAT_VL_ANIMATE_TREE = 25639;
const int FEAT_VL_GAEAS_EMBRACE = 25640;
//:: Masters of the Wild feats
const int FEAT_CREATE_INFUSION = 25960;
const int FEAT_MAGICAL_ARTISAN_CREATE_INFUSION = 25961;
const int FEAT_PLANT_DEFIANCE = 25992;
const int FEAT_PLANT_CONTROL = 25993;
//:: Racial Feats
const int FEAT_WEMIC_JUMP_8 = 4518;
const int FEAT_URDINNIR_STONESKIN = 4644;
@ -782,6 +807,9 @@ const int FEAT_SUEL_IGNORE_SPELL_FAILURE = 2398;
const int FEAT_SUEL_EXTENDED_SPELL = 2399;
const int FEAT_SUEL_DISPELLING_STRIKE = 2400;
//:: Druid
const int FEAT_SPONT_SUMMON = 2372;
//Passive Feats
const int FEAT_ETERNAL_FREEDOM = 4298;
const int FEAT_INTUITIVE_ATTACK = 3166;
@ -1538,18 +1566,19 @@ const int FEAT_SELVETARMS_BLESSING = 2447;
const int FEAT_RANGER_DUAL = 374;
const int FEAT_CAMOUFLAGE = 4486;
//Exalted Feat
const int FEAT_SAC_VOW = 3388;
const int FEAT_VOW_OBED = 3389;
const int FEAT_EXALTED_TURNING = 3168;
const int FEAT_HAND_HEALER = 3167;
const int FEAT_NIMBUSLIGHT = 3165;
const int FEAT_HOLYRADIANCE = 3164;
const int FEAT_STIGMATA = 3163;
const int FEAT_SERVHEAVEN = 3355;
const int FEAT_RANGED_SMITE = 3356;
const int FEAT_VOW_PURITY = 5360;
const int FEAT_VOWOFPOVERTY = 26002;
//:: Exalted Feats
const int FEAT_SAC_VOW = 3388;
const int FEAT_VOW_OBED = 3389;
const int FEAT_EXALTED_TURNING = 3168;
const int FEAT_HAND_HEALER = 3167;
const int FEAT_NIMBUSLIGHT = 3165;
const int FEAT_HOLYRADIANCE = 3164;
const int FEAT_STIGMATA = 3163;
const int FEAT_SERVHEAVEN = 3355;
const int FEAT_RANGED_SMITE = 3356;
const int FEAT_VOW_PURITY = 5360;
const int FEAT_VOWOFPOVERTY = 26002;
const int FEAT_FAV_COMPANIONS = 25994;
//Vile Feat
const int FEAT_LICHLOVED = 3395;
@ -3189,6 +3218,8 @@ const int FEAT_ETHEREAL = 4167;
const int FEAT_TEMPLATE_ARCHLICH_MARKER = 22700;
const int FEAT_TEMPLATE_ARCHLICH_TURN_UNDEAD = 22701;
const int FEAT_TEMPLATE_BAELNORN_MARKER = 22708;
const int FEAT_TEMPLATE_CELESTIAL_SMITE_EVIL = 22601;
const int FEAT_TEMPLATE_CELESTIAL_MARKER = 22602;
const int FEAT_TEMPLATE_FIENDISH_SMITE_GOOD = 22603;
@ -3933,6 +3964,8 @@ const int FEAT_OPPORTUNISTIC_PIETY_HEAL = 5358;
const int FEAT_OPPORTUNISTIC_PIETY_TURN = 5359;
// Combat Maneuver Feats
const int FEAT_CM_CHARGE = 2823;
const int FEAT_CM_GRAPPLE = 3414;
const int FEAT_CURLING_WAVE_STRIKE = 2809;
const int FEAT_SIDESTEP_CHARGE = 3505;
const int FEAT_POWERFUL_CHARGE = 3506;
@ -6203,6 +6236,38 @@ const int FEAT_SHINING_BLADE_SPELLCASTING_VASSAL = 19587;
const int FEAT_SWIFT_WING_SPELLCASTING_VASSAL = 19588;
const int FEAT_WARPRIEST_SPELLCASTING_VASSAL = 19589;
//:: Lion of Talisid marker feats
const int FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST = 25601;
const int FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC = 25602;
const int FEAT_LION_OF_TALISID_SPELLCASTING_DRUID = 25603;
const int FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL = 25604;
const int FEAT_LION_OF_TALISID_SPELLCASTING_HEALER = 25605;
const int FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW = 25606;
const int FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC = 25607;
const int FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER = 25608;
const int FEAT_LION_OF_TALISID_SPELLCASTING_RANGER = 25609;
const int FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN = 25610;
const int FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI = 25611;
const int FEAT_LION_OF_TALISID_SPELLCASTING_SOL = 25612;
const int FEAT_LION_OF_TALISID_SPELLCASTING_SPSHAMAN = 25613;
//:: Verdant Lord marker feats
const int FEAT_VERDANT_LORD_SPELLCASTING_ARCHIVIST = 25619;
const int FEAT_VERDANT_LORD_SPELLCASTING_CLERIC = 25620;
const int FEAT_VERDANT_LORD_SPELLCASTING_DRUID = 25621;
const int FEAT_VERDANT_LORD_SPELLCASTING_FAVOURED_SOUL = 25622;
const int FEAT_VERDANT_LORD_SPELLCASTING_HEALER = 25623;
const int FEAT_VERDANT_LORD_SPELLCASTING_JOWAW = 25624;
const int FEAT_VERDANT_LORD_SPELLCASTING_KOTC = 25625;
const int FEAT_VERDANT_LORD_SPELLCASTING_KOTMC = 25626;
const int FEAT_VERDANT_LORD_SPELLCASTING_NENTYAR_HUNTER = 25627;
const int FEAT_VERDANT_LORD_SPELLCASTING_PALADIN = 25628;
const int FEAT_VERDANT_LORD_SPELLCASTING_RANGER = 25629;
const int FEAT_VERDANT_LORD_SPELLCASTING_OASHAMAN = 25630;
const int FEAT_VERDANT_LORD_SPELLCASTING_SOHEI = 25631;
const int FEAT_VERDANT_LORD_SPELLCASTING_SOL = 25632;
const int FEAT_VERDANT_LORD_SPELLCASTING_SPSHAMAN = 25633;
//:: No spellcasting or invoking marker feats
const int FEAT_ASMODEUS_SPELLCASTING_NONE = 19590;
const int FEAT_TIAMAT_SPELLCASTING_NONE = 19591;

View File

@ -1148,8 +1148,8 @@ int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
if(GetHasFeat(FEAT_DIABOLIST_SPELLCASTING_ASSASSIN, oCaster))
nArcane += GetLevelByClass(CLASS_TYPE_DIABOLIST, oCaster);
if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster))
nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster);
//if(GetHasFeat(FEAT_DHEART_SPELLCASTING_ASSASSIN, oCaster))
//nArcane += GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster);
if(GetHasFeat(FEAT_EKNIGHT_SPELLCASTING_ASSASSIN, oCaster))
nArcane += GetLevelByClass(CLASS_TYPE_ELDRITCH_KNIGHT, oCaster);
@ -3822,6 +3822,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_ARCHIVIST, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_ARCHIVIST, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_ARCHIVIST, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */
@ -4148,7 +4151,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster);
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_CLERIC, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_CLERIC, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_CLERIC, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
@ -4258,7 +4264,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster);
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_DRUID, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_DRUID, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
// if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_DRUID, oCaster))
// nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
@ -4370,10 +4379,13 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster);
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_FAVOURED_SOUL, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_FAVOURED_SOUL, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
// if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster))
// nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_FAVOURED_SOUL, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_FAVOURED_SOUL, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster);
@ -4479,6 +4491,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_HEALER, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_HEALER, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_HEALER, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */
@ -4586,6 +4601,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_JUSTICEWW, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_JOWAW, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
// if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_JUSTICEWW, oCaster))
// nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
@ -4796,6 +4814,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_KOTMC, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_KNIGHT_MIDDLECIRCLE, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */
@ -4901,7 +4922,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_NENTYAR_HUNTER, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_NENTYAR_HUNTER, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_NENTYAR_HUNTER, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */
@ -5212,7 +5236,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster); */
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_RANGER, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_RANGER, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
if(GetHasFeat(FEAT_MORNINGLORD_SPELLCASTING_RANGER, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MORNINGLORD, oCaster);
@ -5316,7 +5343,10 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
nDivine += GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster);
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_OASHAMAN, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_OASHAMAN, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_SHAMAN, oCaster);
if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_OASHAMAN, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
@ -5529,6 +5559,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOHEI, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOHEI, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
// if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOHEI, oCaster))
// nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster);
@ -5636,6 +5669,9 @@ int GetDivinePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
if(GetHasFeat(FEAT_HOSPITALER_SPELLCASTING_SOL, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_HOSPITALER, oCaster);
if(GetHasFeat(FEAT_LION_OF_TALISID_SPELLCASTING_SOL, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_LION_OF_TALISID, oCaster);
/* if(GetHasFeat(FEAT_MASTER_OF_SHROUDS_SPELLCASTING_SOL, oCaster))
nDivine += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster); */

View File

@ -1206,6 +1206,7 @@ int GetIsDoubleSidedWeaponType(int iWeaponType)
return ( iWeaponType == BASE_ITEM_DIREMACE
|| iWeaponType == BASE_ITEM_DOUBLEAXE
|| iWeaponType == BASE_ITEM_TWOBLADEDSWORD
|| iWeaponType == BASE_ITEM_DOUBLE_SCIMITAR
);
}

View File

@ -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

View File

@ -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;

View File

@ -795,7 +795,7 @@ int GetWeaponSize(object oWeapon)
case BASE_ITEM_GREATAXE:
case BASE_ITEM_HEAVYFLAIL:
case BASE_ITEM_QUARTERSTAFF:
case BASE_ITEM_MAGICSTAFF:
//case BASE_ITEM_MAGICSTAFF:
case BASE_ITEM_SCYTHE:
case BASE_ITEM_SHORTSPEAR:
case BASE_ITEM_ELVEN_COURTBLADE:
@ -832,7 +832,7 @@ int PRCLargeWeaponCheck(int iBaseType, int nSize)
case BASE_ITEM_GREATAXE:
case BASE_ITEM_HEAVYFLAIL:
case BASE_ITEM_QUARTERSTAFF:
case BASE_ITEM_MAGICSTAFF:
//case BASE_ITEM_MAGICSTAFF:
case BASE_ITEM_SCYTHE:
case BASE_ITEM_SHORTSPEAR:
case BASE_ITEM_ELVEN_COURTBLADE:

View File

@ -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);

View 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 (){}

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -20,6 +20,11 @@
/* Function prototypes */
//////////////////////////////////////////////////
//:: Calculates total Shield AC bonuses from all sources
int GetTotalShieldACBonus(object oCreature);
//:: Handles psuedo-Foritifcation
void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25);
@ -376,6 +381,36 @@ const int TYPE_DIVINE = -2;
/* Function definitions */
//////////////////////////////////////////////////
// Returns TRUE if nSpellID is a subradial spell, FALSE otherwise
int GetIsSubradialSpell(int nSpellID)
{
string sMaster = Get2DACache("spells", "Master", nSpellID);
// If the Master column is numeric, this spell is a subradial of that master
if (sMaster != "" && sMaster != "****")
{
return TRUE;
}
return FALSE;
}
// Returns the masterspell SpellID for a subradial spell.
int GetMasterSpellFromSubradial(int nSpellID)
{
string sMaster = Get2DAString("spells", "Master", nSpellID);
if (sMaster != "****")
{
return StringToInt(sMaster);
}
return -1; // No master
}
int GetPrCAdjustedClassLevel(int nClass, object oCaster = OBJECT_SELF)
{
int iTemp;
@ -412,7 +447,9 @@ int GetPrCAdjustedCasterLevelByType(int nClassType, object oCaster = OBJECT_SELF
{
int nClassLvl;
int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8;
int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl;
int nClass1Lvl = 0, nClass2Lvl = 0, nClass3Lvl = 0, nClass4Lvl = 0,
nClass5Lvl = 0, nClass6Lvl = 0, nClass7Lvl = 0, nClass8Lvl = 0;
nClass1 = GetClassByPosition(1, oCaster);
nClass2 = GetClassByPosition(2, oCaster);
@ -2223,6 +2260,78 @@ int GetControlledCelestialTotalHD(object oPC = OBJECT_SELF)
return nTotalHD;
}
//:: Calculates total Shield AC bonuses from all sources
int GetTotalShieldACBonus(object oCreature)
{
int nShieldBonus = 0;
object oItem;
// Check left hand for shield
oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature);
if (GetIsObjectValid(oItem))
{
int nBaseItem = GetBaseItemType(oItem);
if (nBaseItem == BASE_ITEM_SMALLSHIELD ||
nBaseItem == BASE_ITEM_LARGESHIELD ||
nBaseItem == BASE_ITEM_TOWERSHIELD)
{
nShieldBonus += GetItemACValue(oItem);
if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC, bonus = " + IntToString(nShieldBonus)+".");
}
}
// Check creature weapon slots for shield AC bonus
oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCreature);
if (GetIsObjectValid(oItem))
nShieldBonus += GetItemACValue(oItem);
oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCreature);
if (GetIsObjectValid(oItem))
nShieldBonus += GetItemACValue(oItem);
oItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCreature);
if (GetIsObjectValid(oItem))
nShieldBonus += GetItemACValue(oItem);
// Add shield AC bonuses from magical effects
effect eEffect = GetFirstEffect(oCreature);
while (GetIsEffectValid(eEffect))
{
int nACType = GetEffectInteger(eEffect, 0);
int nACAmount = GetEffectInteger(eEffect, 1);
if(GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE && nACType == AC_SHIELD_ENCHANTMENT_BONUS)
{
if(DEBUG) DoDebug("prc_inc_spells >> GetTotalShieldACBonus: Found Shield AC effect, bonus = " + IntToString(nACAmount)+".");
nShieldBonus += nACAmount;
}
eEffect = GetNextEffect(oCreature);
}
return nShieldBonus;
}
// Add shield AC bonuses from magical effects
/* effect eEffect = GetFirstEffect(oCreature);
while (GetIsEffectValid(eEffect))
{
if (GetEffectType(eEffect) == EFFECT_TYPE_AC_INCREASE &&
GetEffectInteger(eEffect, 1) == AC_SHIELD_ENCHANTMENT_BONUS)
{
int nMod = GetEffectInteger(eEffect, 0);
int nType = GetEffectInteger(eEffect, 1);
nShieldBonus += GetEffectInteger(eEffect, 0);
string s = "Found AC effect: bonus = " + IntToString(nMod) + ", type = " + IntToString(nType);
SendMessageToPC(GetFirstPC(), s);
}
eEffect = GetNextEffect(oCreature);
}
return nShieldBonus;
}*/
//
//:: Handles psuedo-Foritifcation
void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25)
{
@ -2275,7 +2384,7 @@ void DoFortification(object oPC = OBJECT_SELF, int nFortification = 25)
IPSafeAddItemProperty(oHide, ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB));
}
}
//
// wrapper for DecrementRemainingSpellUses, works for newspellbook 'fake' spells too
// should also find and decrement metamagics for newspellbooks

View File

@ -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

View File

@ -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

View File

@ -40,13 +40,31 @@ int IsProficient(object oPC, int nBaseItem)
case BASE_ITEM_CLUB:
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC);
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_CLUB, oPC);
case BASE_ITEM_HEAVYCROSSBOW:
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW, oPC);
case BASE_ITEM_LIGHTCROSSBOW:
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW, oPC);
case BASE_ITEM_DAGGER:
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC);
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DAGGER, oPC);
case BASE_ITEM_LONGSWORD:
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oPC)
@ -152,12 +170,14 @@ int IsProficient(object oPC, int nBaseItem)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oPC);
case BASE_ITEM_QUARTERSTAFF:
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF, oPC)
||GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC);
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC);
case BASE_ITEM_MAGICSTAFF:
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
return GetHasFeat(FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF, oPC)
||GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oPC)
|| GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oPC);
@ -300,167 +320,185 @@ int GetWeaponProfFeatByType(int nBaseType)
{
switch(nBaseType)
{
case BASE_ITEM_SHORTSWORD:
return FEAT_WEAPON_PROFICIENCY_SHORTSWORD;
case BASE_ITEM_CLUB:
return FEAT_WEAPON_PROFICIENCY_CLUB;
case BASE_ITEM_QUARTERSTAFF:
return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF;
case BASE_ITEM_LONGSWORD:
return FEAT_WEAPON_PROFICIENCY_LONGSWORD;
case BASE_ITEM_MAGICSTAFF:
return FEAT_WEAPON_PROFICIENCY_QUARTERSTAFF;
case BASE_ITEM_DAGGER:
return FEAT_WEAPON_PROFICIENCY_DAGGER;
case BASE_ITEM_BATTLEAXE:
return FEAT_WEAPON_PROFICIENCY_BATTLEAXE;
case BASE_ITEM_HEAVYCROSSBOW:
return FEAT_WEAPON_PROFICIENCY_HEAVY_XBOW;
case BASE_ITEM_BASTARDSWORD:
return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD;
case BASE_ITEM_LIGHTCROSSBOW:
return FEAT_WEAPON_PROFICIENCY_LIGHT_XBOW;
case BASE_ITEM_SHORTSWORD:
return FEAT_WEAPON_PROFICIENCY_SHORTSWORD;
case BASE_ITEM_LIGHTFLAIL:
return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL;
case BASE_ITEM_LONGSWORD:
return FEAT_WEAPON_PROFICIENCY_LONGSWORD;
case BASE_ITEM_WARHAMMER:
return FEAT_WEAPON_PROFICIENCY_WARHAMMER;
case BASE_ITEM_BATTLEAXE:
return FEAT_WEAPON_PROFICIENCY_BATTLEAXE;
case BASE_ITEM_LONGBOW:
return FEAT_WEAPON_PROFICIENCY_LONGBOW;
case BASE_ITEM_BASTARDSWORD:
return FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD;
case BASE_ITEM_LIGHTMACE:
return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE;
case BASE_ITEM_LIGHTFLAIL:
return FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL;
case BASE_ITEM_HALBERD:
return FEAT_WEAPON_PROFICIENCY_HALBERD;
case BASE_ITEM_WARHAMMER:
return FEAT_WEAPON_PROFICIENCY_WARHAMMER;
case BASE_ITEM_SHORTBOW:
case BASE_ITEM_LONGBOW:
return FEAT_WEAPON_PROFICIENCY_LONGBOW;
case BASE_ITEM_LIGHTMACE:
return FEAT_WEAPON_PROFICIENCY_LIGHT_MACE;
case BASE_ITEM_HALBERD:
return FEAT_WEAPON_PROFICIENCY_HALBERD;
case BASE_ITEM_SHORTBOW:
return FEAT_WEAPON_PROFICIENCY_SHORTBOW;
case BASE_ITEM_TWOBLADEDSWORD:
case BASE_ITEM_TWOBLADEDSWORD:
return FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD;
case BASE_ITEM_GREATSWORD:
case BASE_ITEM_GREATSWORD:
return FEAT_WEAPON_PROFICIENCY_GREATSWORD;
case BASE_ITEM_GREATAXE:
case BASE_ITEM_GREATAXE:
return FEAT_WEAPON_PROFICIENCY_GREATAXE;
case BASE_ITEM_DART:
case BASE_ITEM_DART:
return FEAT_WEAPON_PROFICIENCY_DART;
case BASE_ITEM_DIREMACE:
case BASE_ITEM_DIREMACE:
return FEAT_WEAPON_PROFICIENCY_DIRE_MACE;
case BASE_ITEM_DOUBLEAXE:
case BASE_ITEM_DOUBLEAXE:
return FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE;
case BASE_ITEM_HEAVYFLAIL:
case BASE_ITEM_HEAVYFLAIL:
return FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL;
case BASE_ITEM_LIGHTHAMMER:
case BASE_ITEM_LIGHTHAMMER:
return FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER;
case BASE_ITEM_HANDAXE:
case BASE_ITEM_HANDAXE:
return FEAT_WEAPON_PROFICIENCY_HANDAXE;
case BASE_ITEM_KAMA:
case BASE_ITEM_KAMA:
return FEAT_WEAPON_PROFICIENCY_KAMA;
case BASE_ITEM_KATANA:
case BASE_ITEM_KATANA:
return FEAT_WEAPON_PROFICIENCY_KATANA;
case BASE_ITEM_KUKRI:
case BASE_ITEM_KUKRI:
return FEAT_WEAPON_PROFICIENCY_KUKRI;
case BASE_ITEM_MORNINGSTAR:
case BASE_ITEM_MORNINGSTAR:
return FEAT_WEAPON_PROFICIENCY_MORNINGSTAR;
case BASE_ITEM_RAPIER:
case BASE_ITEM_RAPIER:
return FEAT_WEAPON_PROFICIENCY_RAPIER;
case BASE_ITEM_SCIMITAR:
case BASE_ITEM_SCIMITAR:
return FEAT_WEAPON_PROFICIENCY_SCIMITAR;
case BASE_ITEM_SCYTHE:
case BASE_ITEM_SCYTHE:
return FEAT_WEAPON_PROFICIENCY_SCYTHE;
case BASE_ITEM_SHORTSPEAR:
case BASE_ITEM_SHORTSPEAR:
return FEAT_WEAPON_PROFICIENCY_SHORTSPEAR;
case BASE_ITEM_SHURIKEN:
case BASE_ITEM_SHURIKEN:
return FEAT_WEAPON_PROFICIENCY_SHURIKEN;
case BASE_ITEM_SICKLE:
case BASE_ITEM_SICKLE:
return FEAT_WEAPON_PROFICIENCY_SICKLE;
case BASE_ITEM_SLING:
case BASE_ITEM_SLING:
return FEAT_WEAPON_PROFICIENCY_SLING;
case BASE_ITEM_THROWINGAXE:
case BASE_ITEM_THROWINGAXE:
return FEAT_WEAPON_PROFICIENCY_THROWING_AXE;
case BASE_ITEM_CSLASHWEAPON:
case BASE_ITEM_CSLASHWEAPON:
return FEAT_WEAPON_PROFICIENCY_CREATURE;
case BASE_ITEM_CPIERCWEAPON:
case BASE_ITEM_CPIERCWEAPON:
return FEAT_WEAPON_PROFICIENCY_CREATURE;
case BASE_ITEM_CBLUDGWEAPON:
case BASE_ITEM_CBLUDGWEAPON:
return FEAT_WEAPON_PROFICIENCY_CREATURE;
case BASE_ITEM_CSLSHPRCWEAP:
case BASE_ITEM_CSLSHPRCWEAP:
return FEAT_WEAPON_PROFICIENCY_CREATURE;
case BASE_ITEM_TRIDENT:
case BASE_ITEM_TRIDENT:
return FEAT_WEAPON_PROFICIENCY_TRIDENT;
case BASE_ITEM_DWARVENWARAXE:
case BASE_ITEM_DWARVENWARAXE:
return FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE;
case BASE_ITEM_WHIP:
case BASE_ITEM_WHIP:
return FEAT_WEAPON_PROFICIENCY_WHIP;
case BASE_ITEM_ELVEN_LIGHTBLADE:
case BASE_ITEM_ELVEN_LIGHTBLADE:
return FEAT_WEAPON_PROFICIENCY_ELVEN_LIGHTBLADE;
case BASE_ITEM_ELVEN_THINBLADE:
case BASE_ITEM_ELVEN_THINBLADE:
return FEAT_WEAPON_PROFICIENCY_ELVEN_THINBLADE;
case BASE_ITEM_ELVEN_COURTBLADE:
case BASE_ITEM_ELVEN_COURTBLADE:
return FEAT_WEAPON_PROFICIENCY_ELVEN_COURTBLADE;
case BASE_ITEM_HEAVY_PICK:
case BASE_ITEM_HEAVY_PICK:
return FEAT_WEAPON_PROFICIENCY_HEAVY_PICK;
case BASE_ITEM_LIGHT_PICK:
case BASE_ITEM_LIGHT_PICK:
return FEAT_WEAPON_PROFICIENCY_LIGHT_PICK;
case BASE_ITEM_SAI:
case BASE_ITEM_SAI:
return FEAT_WEAPON_PROFICIENCY_SAI;
case BASE_ITEM_NUNCHAKU:
case BASE_ITEM_NUNCHAKU:
return FEAT_WEAPON_PROFICIENCY_NUNCHAKU;
case BASE_ITEM_FALCHION:
case BASE_ITEM_FALCHION:
return FEAT_WEAPON_PROFICIENCY_FALCHION;
case BASE_ITEM_SAP:
case BASE_ITEM_SAP:
return FEAT_WEAPON_PROFICIENCY_SAP;
case BASE_ITEM_KATAR:
case BASE_ITEM_KATAR:
return FEAT_WEAPON_PROFICIENCY_KATAR;
case BASE_ITEM_HEAVY_MACE:
case BASE_ITEM_HEAVY_MACE:
return FEAT_WEAPON_PROFICIENCY_HEAVY_MACE;
case BASE_ITEM_MAUL:
case BASE_ITEM_MAUL:
return FEAT_WEAPON_PROFICIENCY_MAUL;
case BASE_ITEM_DOUBLE_SCIMITAR:
case BASE_ITEM_DOUBLE_SCIMITAR:
return FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR;
case BASE_ITEM_GOAD:
case BASE_ITEM_GOAD:
return FEAT_WEAPON_PROFICIENCY_GOAD;
case BASE_ITEM_EAGLE_CLAW:
case BASE_ITEM_EAGLE_CLAW:
return FEAT_WEAPON_PROFICIENCY_EAGLE_CLAW;
default:
return FEAT_WEAPON_PROFICIENCY_SIMPLE;
default:
return FEAT_WEAPON_PROFICIENCY_SIMPLE;
}
return 0;

View File

@ -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;

View File

@ -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

View File

@ -2569,7 +2569,8 @@ int HasPreRequisitesForManeuver(int nClass, int spellbookId, object oPC=OBJECT_S
json chosenDisc = JsonObjectGet(discInfo, discipline);
if (chosenDisc != JsonNull())
{
int nManCount = JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER)));
int nManCount = (JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_MANEUVER)))
+ JsonGetInt(JsonObjectGet(chosenDisc, IntToString(MANEUVER_TYPE_STANCE))));
if (nManCount >= prereqs)
return TRUE;
}
@ -3334,3 +3335,5 @@ json GetArchivistNewSpellsList(object oPC=OBJECT_SELF)
SetLocalJson(oPC, NUI_LEVEL_UP_ARCHIVIST_NEW_SPELLS_LIST_VAR, retValue);
return retValue;
}
//:: void main(){}

View File

@ -387,8 +387,7 @@ int IsClassAllowedToUseNUISpellbook(object oPlayer, int nClass)
return TRUE;
// Arcane Spont
if (nClass == CLASS_TYPE_ASSASSIN
|| nClass == CLASS_TYPE_BEGUILER
if (nClass == CLASS_TYPE_BEGUILER
|| nClass == CLASS_TYPE_CELEBRANT_SHARESS
|| nClass == CLASS_TYPE_DREAD_NECROMANCER
|| nClass == CLASS_TYPE_DUSKBLADE
@ -506,8 +505,7 @@ int CanClassUseMetamagicFeats(int nClass)
// I don't want to spend the time looping through each class's
// feat 2da so this is the list of all classes that are allowed to use the
// Spellbook NUI and can use Metamagic
return (nClass == CLASS_TYPE_ASSASSIN
|| nClass == CLASS_TYPE_BARD
return (nClass == CLASS_TYPE_BARD
|| nClass == CLASS_TYPE_SORCERER
|| nClass == CLASS_TYPE_BEGUILER
|| nClass == CLASS_TYPE_DREAD_NECROMANCER
@ -527,7 +525,6 @@ int CanClassUseSuddenMetamagicFeats(int nClass)
// Spellbook NUI and can use Sudden Metamagic
return (nClass == CLASS_TYPE_SHADOWLORD
|| nClass == CLASS_TYPE_ARCHIVIST
|| nClass == CLASS_TYPE_ASSASSIN
|| nClass == CLASS_TYPE_BARD
|| nClass == CLASS_TYPE_BEGUILER
|| nClass == CLASS_TYPE_DREAD_NECROMANCER
@ -845,4 +842,4 @@ int IsSpellbookNUIOpen(object oPC)
}
return FALSE;
}
}

View File

@ -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;

View File

@ -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() {}

View File

@ -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;

View File

@ -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(){}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -144,8 +144,103 @@ int PRCGetUserSpecificSpellScriptFinished();
#include "pnp_shft_main"
#include "inc_dynconv"
#include "inc_npc"
#include "inc_infusion"
#include "prc_add_spell_dc"
int Spontaneity(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel)
{
if(GetLocalInt(oCaster, "PRC_SpontRegen"))
{
DeleteLocalInt(oCaster, "PRC_SpontRegen");
int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here
nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nCastingClass);
nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic);
int nRegenSpell;
if(nCastingClass == CLASS_TYPE_DRUID)
{
switch(nSpellLevel)
{
case 0: return TRUE;
case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break;
case 2: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break;
case 3: nRegenSpell = SPELL_REGEN_RING; break;
case 4: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break;
case 5: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break;
case 6: nRegenSpell = SPELL_REGEN_CIRCLE; break;
case 7: nRegenSpell = SPELL_REGEN_CIRCLE; break;
case 8: nRegenSpell = SPELL_REGEN_CIRCLE; break;
case 9: nRegenSpell = SPELL_REGENERATE; break;
}
ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, CLASS_TYPE_DRUID);
}
else
{
switch(nSpellLevel)
{
case 0: return TRUE;
case 1: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break;
case 2: nRegenSpell = SPELL_REGEN_LIGHT_WOUNDS; break;
case 3: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break;
case 4: nRegenSpell = SPELL_REGEN_MODERATE_WOUNDS; break;
case 5: nRegenSpell = SPELL_REGEN_SERIOUS_WOUNDS; break;
case 6: nRegenSpell = SPELL_REGEN_CRITICAL_WOUNDS; break;
case 7: nRegenSpell = SPELL_REGENERATE; break;
case 8: nRegenSpell = SPELL_REGENERATE; break;
case 9: nRegenSpell = SPELL_REGENERATE; break;
}
ActionCastSpell(nRegenSpell, 0, 0, 0, METAMAGIC_NONE, nCastingClass);
}
//Don't cast original spell
return FALSE;
}
return TRUE;
}
int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel)
{
if(nCastingClass != CLASS_TYPE_DRUID)
return TRUE;
if(GetLocalInt(oCaster, "PRC_SpontSummon"))
{
DeleteLocalInt(oCaster, "PRC_SpontSummon");
int nMetamagic = GetMetaMagicFeat();//we need bioware metamagic here
int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, CLASS_TYPE_DRUID);
nSpellLevel += GetMetaMagicSpellLevelAdjustment(nMetamagic);
int nSummonSpell;
switch(nSpellLevel)
{
case 0: return TRUE;
case 1: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_1; break;
case 2: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_2; break;
case 3: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_3; break;
case 4: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_4; break;
case 5: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_5; break;
case 6: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_6; break;
case 7: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_7; break;
case 8: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_8; break;
case 9: nSummonSpell = SPELL_SUMMON_NATURES_ALLY_9; break;
}
//:: All SNA spells are subradial spells
SetLocalInt(oCaster, "DomainOrigSpell", nSummonSpell);
SetLocalInt(oCaster, "DomainCastLevel", nSpellLevel);
SetLocalInt(oCaster, "DomainCastClass", CLASS_TYPE_DRUID);
StartDynamicConversation("prc_domain_conv", oCaster, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oCaster);
//Don't cast original spell
return FALSE;
}
return TRUE;
}
/* int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpellLevel)
{
if(nCastingClass != CLASS_TYPE_DRUID)
return TRUE;
@ -191,6 +286,8 @@ int DruidSpontSummon(object oCaster, int nCastingClass, int nSpellID, int nSpell
return TRUE;
}
*/
int ArcaneSpellFailure(object oCaster, int nCastingClass, int nSpellLevel, int nMetamagic, string sComponents)
{
if(!GetIsArcaneClass(nCastingClass))
@ -904,7 +1001,8 @@ int ShifterCasting(object oCaster, object oSpellCastItem, int nSpellLevel, int n
{
// Potion drinking is not restricted
if(GetBaseItemType(oSpellCastItem) == BASE_ITEM_ENCHANTED_POTION
|| GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS)
|| GetBaseItemType(oSpellCastItem) == BASE_ITEM_POTIONS
|| GetBaseItemType(oSpellCastItem) == BASE_ITEM_INFUSED_HERB)
return TRUE;
//OnHit properties on equipped items not restricted
@ -3249,6 +3347,28 @@ int X2PreSpellCastCode2()
X2BreakConcentrationSpells();
//---------------------------------------------------------------------------
// Herbal Infusion Use check
//---------------------------------------------------------------------------
if(nContinue && (GetBaseItemType(oSpellCastItem) == BASE_ITEM_INFUSED_HERB))
{
int bIsSubradial = GetIsSubradialSpell(nSpellID);
if(bIsSubradial)
{
nSpellID = GetMasterSpellFromSubradial(nSpellID);
}
int nItemCL = GetCastSpellCasterLevelFromItem(oSpellCastItem, nSpellID);
if(DEBUG) DoDebug("x2_inc_spellhook >> X2PreSpellCastCode2: Item Spellcaster Level: "+IntToString(nItemCL)+".");
if(DEBUG) DoDebug("x2_inc_spellhook >> X2PreSpellCastCode2: Herbal Infusion Found");
if(!DoInfusionUseChecks(oCaster, oSpellCastItem, nSpellID))
{
ApplyInfusionPoison(oCaster, nItemCL);
nContinue = FALSE;
}
}
//---------------------------------------------------------------------------
// No casting while using expertise
//---------------------------------------------------------------------------
if(nContinue)
@ -3399,6 +3519,12 @@ int X2PreSpellCastCode2()
if (nContinue)
nContinue = SpellAlignmentRestrictions(oCaster, nSpellID, nCastingClass);
//---------------------------------------------------------------------------
// Verdant Lord Spontaneous Regernate
//---------------------------------------------------------------------------
if(nContinue)
Spontaneity(oCaster, nCastingClass, nSpellID, nSpellLevel);
//---------------------------------------------------------------------------
// Druid spontaneous summoning
//---------------------------------------------------------------------------

View File

@ -2894,5 +2894,3 @@ void main()
}
}
}