Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
765 lines
32 KiB
Plaintext
765 lines
32 KiB
Plaintext
/**
|
||
* @file
|
||
* PRC functions that are wrappers for functions defined in nwscript.nss
|
||
*/
|
||
const int PRC_SIZEMASK_NONE = 0; // no changes taken into account, same as bio size with fixes for CEP
|
||
const int PRC_SIZEMASK_NORMAL = 1; // normal size changes
|
||
const int PRC_SIZEMASK_NOABIL = 2; // size changes that dont change ability scores
|
||
const int PRC_SIZEMASK_SIMPLE = 4; // 'simple' size changes that have simplified effects (expansion/compression)
|
||
|
||
const int PRC_SIZEMASK_ALL = 7; // PRC_SIZEMASK_NORMAL | PRC_SIZEMASK_NOABIL | PRC_SIZEMASK_SIMPLE
|
||
|
||
//wrapper for biowares GetSpellId()
|
||
//used for actioncastspell
|
||
int PRCGetSpellId(object oCaster = OBJECT_SELF);
|
||
|
||
/**
|
||
* A wrapper for GetSpellTargetObject().
|
||
* Handles effects that redirect spell targeting, currently:
|
||
* - Reddopsi
|
||
* - Casting from runes
|
||
*
|
||
* NOTE: Will probably not return a sensible value outside of a spellscript. Assumes
|
||
* OBJECT_SELF is the object doing the casting.
|
||
*
|
||
* @return The target for the spell whose spellscript is currently being executed.
|
||
*/
|
||
object PRCGetSpellTargetObject(object oCaster = OBJECT_SELF);
|
||
|
||
/**
|
||
* A wrapper for GetSpellCastItem().
|
||
*
|
||
* NOTE: Will probably not return a sensible value outside of a spellscript.
|
||
*
|
||
* @return The item from which the spell was cast.
|
||
*/
|
||
object PRCGetSpellCastItem(object oPC = OBJECT_SELF);
|
||
|
||
/*
|
||
* Caches bonus feat itemproperties rather than creating new ones each time
|
||
*/
|
||
itemproperty PRCItemPropertyBonusFeat(int nBonusFeatID);
|
||
|
||
//Wrapper for GetIsSkillSuccessful(), allows forcing of a particular roll eg. taking 10
|
||
int GetPRCIsSkillSuccessful(object oCreature, int nSkill, int nDifficulty, int nRollOverride = -1);
|
||
|
||
/**
|
||
* Wrapper for GetCreatureSize().
|
||
*
|
||
* Get the size (CREATURE_SIZE_*) of oCreature, including any PRC size modification feats / spells
|
||
*
|
||
* @param oObject Creature whose size to get
|
||
* @param nSizeMask Combination of PRC_SIZEMASK_* constants indicating which types of size changes to return
|
||
* @return CREATURE_SIZE_* constant
|
||
*/
|
||
int PRCGetCreatureSize(object oObject = OBJECT_SELF, int nSizeMask = PRC_SIZEMASK_ALL);
|
||
|
||
/**
|
||
* Returns the total value of essentia invested in the meld
|
||
*
|
||
* @param oMeldshaper The meldshaper
|
||
* @param nMeldId The meld to check
|
||
*
|
||
* @return Invested essentia
|
||
*/
|
||
int GetEssentiaInvested(object oMeldshaper, int nMeld = -1);
|
||
|
||
/**
|
||
* Returns the chakra the meld is bound to, if any
|
||
*
|
||
* @param oMeldshaper The meldshaper
|
||
* @param nMeldId The meld to check
|
||
*
|
||
* @return Chakra constant
|
||
*/
|
||
int GetIsMeldBound(object oMeldshaper, int nMeld = -1);
|
||
|
||
/**
|
||
* Calculates the DC of the soulmeld being currently triggered.
|
||
*
|
||
* @param oMeldshaper The meldshaper
|
||
* @param nClass The class to check
|
||
* @param nMeldId The meld to check
|
||
*
|
||
* @return The DC
|
||
*/
|
||
int GetMeldshaperDC(object oMeldshaper, int nClass, int nMeldId);
|
||
|
||
/**
|
||
* Checks whether meld is a necrocarnum meld
|
||
*
|
||
* @param nMeldId The meld to check
|
||
*
|
||
* @return True/False
|
||
*/
|
||
int GetIsNecrocarnumMeld(int nMeld);
|
||
|
||
/**
|
||
* Returns ability score for Meldshaping DCs
|
||
*
|
||
* @param nClass The class to check
|
||
* @param oMeldshaper The meldshaper
|
||
*
|
||
* @return ABILITY_*
|
||
*/
|
||
int GetMeldshaperAbilityOfClass(int nClass, object oMeldshaper);
|
||
|
||
/**
|
||
* Returns regular chakra when passed a double chakra chakra
|
||
*
|
||
* @param nChakra The chakra to convert
|
||
*
|
||
* @return CHAKRA_DOUBLE_*
|
||
*/
|
||
int DoubleChakraToChakra(int nChakra);
|
||
|
||
/**
|
||
* Returns true if the meldshaper has used all of their expanded soulmeld capacity
|
||
*
|
||
* @param oMeldshaper The meldshaper
|
||
*
|
||
* @return True/False
|
||
*/
|
||
int GetIsSoulmeldCapacityUsed(object oMeldshaper);
|
||
|
||
/**
|
||
* Returns true if the meld has used expanded soulmeld capacity
|
||
*
|
||
* @param oMeldshaper The meldshaper
|
||
* @param nMeld The meld
|
||
*
|
||
* @return True/False
|
||
*/
|
||
int GetExpandedSoulmeld(object oMeldshaper, int nMeld);
|
||
|
||
/**
|
||
* Does what it says
|
||
*
|
||
* @param oMeldshaper Character to check
|
||
*/
|
||
int GetIsIncarnumUser(object oMeldshaper);
|
||
|
||
/**
|
||
* Counts the number of Aberrant feats the PC has
|
||
*
|
||
* @param oPC Character to check
|
||
*/
|
||
int GetAberrantFeatCount(object oPC);
|
||
|
||
//////////////////////
|
||
// Constants
|
||
//////////////////////
|
||
|
||
// This line is here to prevent the bioware toolkit from
|
||
// throwing an exception over the number of constants in PRC
|
||
//const int BIOWARE_INHIBIT = !!0;
|
||
|
||
#include "prc_misc_const"
|
||
#include "prc_spell_const"
|
||
#include "inv_invoc_const"
|
||
#include "psi_power_const"
|
||
#include "prc_inc_racial"
|
||
#include "inc_array"
|
||
#include "moi_meld_const"
|
||
#include "bnd_vestig_const"
|
||
|
||
// colours for log messages (there's not really a sensible place for this while inc_utility is so messy) maybe inc_debug?
|
||
// PRC_TEXT_ prefix to stop clashes with simtools
|
||
// Colors in String messages to PCs
|
||
const string PRC_TEXT_BLUE = "<cf<63><66>>"; // used by saving throws.
|
||
const string PRC_TEXT_DARK_BLUE = "<c f<>>"; // used for electric damage.
|
||
const string PRC_TEXT_GRAY = "<c<><63><EFBFBD>>"; // used for negative damage.
|
||
const string PRC_TEXT_GREEN = "<c <20> >"; // used for acid damage.
|
||
const string PRC_TEXT_LIGHT_BLUE = "<c<><63><EFBFBD>>"; // used for the player's name, and cold damage.
|
||
const string PRC_TEXT_LIGHT_GRAY = "<c<><63><EFBFBD>>"; // used for system messages.
|
||
const string PRC_TEXT_LIGHT_ORANGE = "<c<><63> >"; // used for sonic damage.
|
||
const string PRC_TEXT_LIGHT_PURPLE = "<c̙<63>>"; // used for a target's name.
|
||
const string PRC_TEXT_ORANGE = "<c<>f >"; // used for attack rolls and physical damage.
|
||
const string PRC_TEXT_PURPLE = "<c<>w<EFBFBD>>"; // used for spell casts, as well as magic damage.
|
||
const string PRC_TEXT_RED = "<c<> >"; // used for fire damage.
|
||
const string PRC_TEXT_WHITE = "<c<><63><EFBFBD>>"; // used for positive damage.
|
||
const string PRC_TEXT_YELLOW = "<c<><63> >"; // used for healing, and sent messages.
|
||
|
||
// includes
|
||
#include "inc_2dacache"
|
||
|
||
int PRCGetSpellId(object oCaster = OBJECT_SELF)
|
||
{
|
||
int nID = GetLocalInt(oCaster, PRC_SPELLID_OVERRIDE);
|
||
if(!nID)
|
||
return GetSpellId();
|
||
|
||
if (DEBUG) DoDebug("PRCGetSpellId: found override spell id = "+IntToString(nID)+", original id = "+IntToString(GetSpellId()));
|
||
|
||
if(nID == -1)
|
||
nID = 0;
|
||
return nID;
|
||
}
|
||
|
||
object PRCGetSpellTargetObject(object oCaster = OBJECT_SELF)
|
||
{
|
||
if(GetLocalInt(oCaster, "PRC_EF_ARCANE_FIST"))
|
||
return oCaster;
|
||
|
||
if(GetLocalInt(oCaster, "PsyRogueDanger"))
|
||
return oCaster;
|
||
|
||
object oSpellTarget;
|
||
|
||
// is there an override target on the module? (this is only valid if a local int is set)
|
||
if(GetLocalInt(GetModule(), PRC_SPELL_TARGET_OBJECT_OVERRIDE))
|
||
{
|
||
// this could also be an invalid target (so that the module builder can disable targeting)
|
||
oSpellTarget = GetLocalObject(GetModule(), PRC_SPELL_TARGET_OBJECT_OVERRIDE);
|
||
if (DEBUG) DoDebug("PRCGetSpellTargetObject: module override target = "+GetName(oSpellTarget)+", original target = "+GetName(GetSpellTargetObject()));
|
||
return oSpellTarget;
|
||
}
|
||
|
||
// motu99: added code to put an override target on the caster
|
||
// we might want to change the preference: so far module overrides have higher preference (to give module builders some extra power :-)
|
||
// if we want caster overrides to have higher preference, put this before the module override check
|
||
/* oSpellTarget = GetLocalObject(oCaster, PRC_SPELL_TARGET_OBJECT_OVERRIDE);
|
||
if (GetIsObjectValid(oSpellTarget))
|
||
{
|
||
if (DEBUG) DoDebug("PRCGetSpellTargetObject: caster override target = "+GetName(oSpellTarget)+", original target = "+GetName(GetSpellTargetObject()));
|
||
return oSpellTarget;
|
||
}
|
||
*/
|
||
if(GetLocalInt(oCaster, PRC_SPELL_TARGET_OBJECT_OVERRIDE))
|
||
{
|
||
oSpellTarget = GetLocalObject(oCaster, PRC_SPELL_TARGET_OBJECT_OVERRIDE);
|
||
if (DEBUG) DoDebug("PRCGetSpellTargetObject: caster override target = "+GetName(oSpellTarget)+", original target = "+GetName(GetSpellTargetObject()));
|
||
return oSpellTarget;
|
||
}
|
||
|
||
object oBWTarget = GetSpellTargetObject();
|
||
int nSpellID = PRCGetSpellId(oCaster);
|
||
|
||
// This shifts everything to a random target within 20 feet for a wild mage
|
||
if (GetLocalInt(oBWTarget, "RandomDeflector"))
|
||
{
|
||
object oRandom = GetFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(20.0), GetLocation(oBWTarget), TRUE, OBJECT_TYPE_CREATURE);
|
||
//Cycle through the targets within the spell shape until an invalid object is captured.
|
||
int nCount = 0;
|
||
while (GetIsObjectValid(oRandom))
|
||
{
|
||
array_set_object(oBWTarget, "WildMageTargets", nCount, oRandom);
|
||
nCount++;
|
||
|
||
//Select the next target within the spell shape.
|
||
oRandom = GetNextObjectInShape(SHAPE_SPHERE, FeetToMeters(20.0), GetLocation(oBWTarget), TRUE, OBJECT_TYPE_CREATURE);
|
||
}
|
||
|
||
oBWTarget = array_get_object(oBWTarget, "WildMageTargets", Random(nCount));
|
||
array_delete(oBWTarget, "WildMageTargets");
|
||
}
|
||
|
||
//checking whether spells/powers should rebound on caster - assumes only creatures can have spell turning/reddopsi
|
||
if(GetObjectType(oBWTarget) == OBJECT_TYPE_CREATURE && oCaster != oBWTarget) //if target == caster then we're casting on ourselves or already ran through this code in the same script
|
||
{
|
||
//we only check spells and powers here
|
||
if(nSpellID < 4200 && nSpellID > 16029) //not newspellbook spell or psionic power
|
||
{
|
||
//does not apply to spellscripts triggered by feats
|
||
if(Get2DACache("spells", "FeatID", nSpellID) != "")
|
||
return oBWTarget;
|
||
|
||
//either a feat, or a spell, check to make doubly sure, in the case of monster abilities
|
||
if(
|
||
(Get2DACache("spells", "Wiz_Sorc", nSpellID) == "") &&
|
||
(Get2DACache("spells", "Cleric", nSpellID) == "") &&
|
||
(Get2DACache("spells", "Bard", nSpellID) == "") &&
|
||
(Get2DACache("spells", "Druid", nSpellID) == "") &&
|
||
(Get2DACache("spells", "Paladin", nSpellID) == "") &&
|
||
(Get2DACache("spells", "Ranger", nSpellID) == "")
|
||
)
|
||
return oBWTarget; //we shouldn't be checking feats or other spellbooks
|
||
}
|
||
|
||
// Force missile mage reflects all magic missiles
|
||
if (GetLevelByClass(CLASS_TYPE_FMM, oBWTarget) >= 4 && nSpellID == SPELL_MAGIC_MISSILE)
|
||
return oCaster;
|
||
|
||
int bTouch = GetStringUpperCase(Get2DACache("spells", "Range", nSpellID)) == "T";
|
||
// Reddopsi power causes spells and powers to rebound onto the caster.
|
||
if(GetLocalInt(oBWTarget, "PRC_Power_Reddopsi_Active") && // Reddopsi is active on the target
|
||
!GetLocalInt(oCaster, "PRC_Power_Reddopsi_Active") && // And not on the manifester
|
||
!(nSpellID == SPELL_LESSER_DISPEL || // And the spell/power is not a dispelling one
|
||
nSpellID == SPELL_DISPEL_MAGIC ||
|
||
nSpellID == SPELL_GREATER_DISPELLING ||
|
||
nSpellID == SPELL_MORDENKAINENS_DISJUNCTION ||
|
||
nSpellID == POWER_DISPELPSIONICS
|
||
) &&
|
||
!bTouch // And the spell/power is not touch range
|
||
)
|
||
return oCaster;
|
||
|
||
if(GetLocalInt(oBWTarget, "PRC_SPELL_TURNING") &&
|
||
!(nSpellID == SPELL_LESSER_DISPEL || // And the spell/power is not a dispelling one
|
||
nSpellID == SPELL_DISPEL_MAGIC ||
|
||
nSpellID == SPELL_GREATER_DISPELLING ||
|
||
nSpellID == SPELL_MORDENKAINENS_DISJUNCTION ||
|
||
nSpellID == POWER_DISPELPSIONICS) &&
|
||
!bTouch
|
||
)
|
||
{
|
||
int nSpellLevel = StringToInt(Get2DACache("spells", "Innate", nSpellID));//lookup_spell_innate(nSpellID));
|
||
object oTarget = oBWTarget;
|
||
int nLevels = GetLocalInt(oTarget, "PRC_SPELL_TURNING_LEVELS");
|
||
int bCasterTurning = GetLocalInt(oCaster, "PRC_SPELL_TURNING");
|
||
int nCasterLevels = GetLocalInt(oCaster, "PRC_SPELL_TURNING_LEVELS");
|
||
if(!bCasterTurning)
|
||
{
|
||
if(nSpellLevel > nLevels)
|
||
{
|
||
if((Random(nSpellLevel) + 1) <= nLevels)
|
||
oTarget = oCaster;
|
||
}
|
||
else
|
||
oTarget = oCaster;
|
||
}
|
||
else
|
||
{
|
||
if((Random(nCasterLevels + nLevels) + 1) <= nLevels)
|
||
oTarget = oCaster;
|
||
nCasterLevels -= nSpellLevel;
|
||
if(nCasterLevels < 0) nCasterLevels = 0;
|
||
SetLocalInt(oCaster, "PRC_SPELL_TURNING_LEVELS", nCasterLevels);
|
||
}
|
||
nLevels -= nSpellLevel;
|
||
if(nLevels < 0) nLevels = 0;
|
||
SetLocalInt(oBWTarget, "PRC_SPELL_TURNING_LEVELS", nLevels);
|
||
return oTarget;
|
||
}
|
||
}
|
||
|
||
// 50% chance of this happening
|
||
if(GetHasSpellEffect(SPELL_BLINK, oBWTarget) && d2() == 2)
|
||
return OBJECT_INVALID;
|
||
|
||
// The rune/gem/skull always targets the one who activates it.
|
||
object oItem = PRCGetSpellCastItem(oCaster);
|
||
if(GetIsObjectValid(oItem) && (GetResRef(oItem) == "prc_rune_1" ||
|
||
GetResRef(oItem) == "prc_skulltalis" || GetTag(oItem) == "prc_attunegem"))
|
||
{
|
||
if(DEBUG) DoDebug(GetName(oCaster) + " has cast a spell using a rune");
|
||
// Making sure that the owner of the item is correct
|
||
if (GetIsObjectValid(GetItemPossessor(oItem)))
|
||
{
|
||
if(DEBUG) DoDebug(GetName(oCaster) + " is the owner of the Spellcasting item");
|
||
return GetItemPossessor(oItem);
|
||
}
|
||
}
|
||
|
||
|
||
// return Bioware's target
|
||
return oBWTarget;
|
||
}
|
||
|
||
/**
|
||
* PRCGetSpellCastItem(object oCaster = OBJECT_SELF)
|
||
* wrapper function for GetSpellCastItem()
|
||
*
|
||
* Note that we are giving preference for the local object, "PRC_SPELLCASTITEM_OVERRIDE", stored on oCaster
|
||
* Therefore it is absolutely essential, in order to have this variable not interfere with "normal" spell casting,
|
||
* to delete it *immediately after* the spell script executed. All of this is taken care of in the function
|
||
* ExecuteSpellScript(), which should be used instead of any direct calls to the spell scripts.
|
||
* In particular, NEVER MANUALLY set the overrides. You might ruin the whole spell casting system!
|
||
*
|
||
* Another possibility would have been, to give preference to the GetSpellCastItem() call and only fetch the
|
||
* local object "PRC_SPELLCASTITEM_OVERRIDE" when GetSpellCastItem() returns an invalid object.
|
||
* This is how it is was done in the PRC 3.1c version of prc_onhitcast (lines 58-61), and in psi_sk_onhit, prc_evnt_bonebld, prc_evnt_strmtl
|
||
* [In those scripts the local (override) object was called "PRC_CombatSystem_OnHitCastSpell_Item". In order to be consistent with
|
||
* the naming conventions of the other override variables, I changed the name of the override object to PRC_SPELLCASTITEM_OVERRIDE
|
||
* and provided the wrapper PRCGetSpellCastItem for an easy use of the onhitcast system]
|
||
* However, that approach DOES NOT WORK, because Bioware didn't bother to implement GetSpellCastItem() properly.
|
||
* In a proper implementation GetSpellCastItem() word return OBJECT_INVALID, when called outside of an item spell script,
|
||
* But this is not the case. GetSpellCastItem() will always return the item, from which (according to Bioware's knowledge)
|
||
* the last item spell was cast. As long as the item still exists, the call to GetSpellCastItem() will always return a valid item,
|
||
* even if the item spell long expired and we are casting a completely differnt spell. So GetSpellCastItem() practically
|
||
* NEVER returns an invalid object. [We only get an invalid object, when we didn't yet cast any item spell at all]
|
||
*
|
||
* Possible caveats:
|
||
* You should never cast spells as an action, when the local override object "PRC_SPELLCASTITEM_OVERRIDE"
|
||
* is set (and subsequently deleted) *outside* the action script. This also pertains to other override variables, such as
|
||
* PRC_SPELL_TARGET_OBJECT_OVERRIDE, PRC_METAMAGIC_OVERRIDE, etc.
|
||
* If you set (and delete) a local override (object or int) *within* one single action, thats ok. For instance putting
|
||
* ExecuteSpellScript() into an ActionDoCommand, an AssignCommand or a DelayCommand will work.
|
||
* But (manually) setting "PRC_SPELLCASTITEM_OVERRIDE", then calling ActionCastSpellAt*
|
||
* (which will insert the spell cast action into the action queue) and after that trying to delete the overrides
|
||
* via a DelayCommand or an AssignCommand(), often just guessing how long it takes the spell cast action to run,
|
||
* will most likely break any other spell casting that is done between manually setting the override and deleting it.
|
||
* So please follow the advise to never MANUALLY set the override variables. Use the functions provided here
|
||
* (ExecuteSpellScript, CastSpellAtObject, CastSpellAtLocation, etc. ) or - if you must - build your own
|
||
* functions by using the provided functions either directly or as templates (they show you how to do things right)
|
||
*/
|
||
object PRCGetSpellCastItem(object oCaster = OBJECT_SELF)
|
||
{
|
||
// if the local object "PRC_SPELLCASTITEM_OVERRIDE" is valid, we take it without even looking for anything else
|
||
object oItem = GetLocalObject(oCaster, PRC_SPELLCASTITEM_OVERRIDE);
|
||
if (GetIsObjectValid(oItem))
|
||
{
|
||
// OBJECT_SELF counts as invalid item
|
||
if (oItem == OBJECT_SELF)
|
||
{
|
||
oItem = OBJECT_INVALID;
|
||
}
|
||
|
||
if (DEBUG) DoDebug("PRCGetSpellCastItem: found override spell cast item = "+GetName(oItem)+", original item = " + GetName(GetSpellCastItem()));
|
||
return oItem;
|
||
}
|
||
|
||
// otherwise simply return Bioware's GetSpellCastItem
|
||
oItem = GetSpellCastItem();
|
||
if (DEBUG) DoDebug("PRCGetSpellCastItem: no override, returning bioware spell cast item = "+GetName(oItem));
|
||
return oItem;
|
||
/*
|
||
// motu99: disabled the old stuff; was only used in three scripts (changed them)
|
||
// and couldn't work anyway (because of Bioware's improper implementation of GetSpellCastItem)
|
||
// if Bioware's functions doesn't return a valid object, maybe the scripted combat system will
|
||
if(!GetIsObjectValid(oItem))
|
||
oItem = GetLocalObject(oPC, "PRC_CombatSystem_OnHitCastSpell_Item");
|
||
*/
|
||
}
|
||
|
||
itemproperty PRCItemPropertyBonusFeat(int nBonusFeatID)
|
||
{
|
||
string sTag = "PRC_IPBF_"+IntToString(nBonusFeatID);
|
||
object oTemp = GetObjectByTag(sTag);
|
||
if(!GetIsObjectValid(oTemp))
|
||
{
|
||
if(DEBUG) DoDebug("PRCItemPropertyBonusFeat() : Cache object " + sTag + " is not valid, creating");
|
||
location lLimbo;
|
||
object oLimbo = GetObjectByTag("HEARTOFCHAOS");
|
||
if(GetIsObjectValid(oLimbo))
|
||
lLimbo = GetLocation(oLimbo);
|
||
else
|
||
lLimbo = GetStartingLocation();
|
||
oTemp = CreateObject(OBJECT_TYPE_ITEM, "base_prc_skin", lLimbo, FALSE, sTag);
|
||
}
|
||
itemproperty ipReturn = GetFirstItemProperty(oTemp);
|
||
if(!GetIsItemPropertyValid(ipReturn))
|
||
{
|
||
if(DEBUG) DoDebug("PRCItemPropertyBonusFeat() : Itemproperty was not present on cache object, adding");
|
||
ipReturn = ItemPropertyBonusFeat(nBonusFeatID);
|
||
AddItemProperty(DURATION_TYPE_PERMANENT, ipReturn, oTemp);
|
||
}
|
||
return ipReturn;
|
||
}
|
||
|
||
int GetPRCIsSkillSuccessful(object oCreature, int nSkill, int nDifficulty, int nRollOverride = -1)
|
||
{
|
||
int nRanks = GetSkillRank(nSkill, oCreature);
|
||
if(nRollOverride > 20)
|
||
{
|
||
nRollOverride = 20;
|
||
if(DEBUG) DoDebug("GetPRCIsSkillSuccessful: nRollOverride > 20");
|
||
}
|
||
if(nRollOverride < 0 || (nSkill + nRollOverride) < nDifficulty)
|
||
return GetIsSkillSuccessful(oCreature, nSkill, nDifficulty);
|
||
else
|
||
{ //we're going to fake a skill check here
|
||
SendMessageToPC(oCreature,
|
||
PRC_TEXT_LIGHT_BLUE + GetName(oCreature) + PRC_TEXT_DARK_BLUE + " : " +
|
||
GetStringByStrRef(StringToInt(Get2DACache("skills", "Name", nSkill))) + " : *" +
|
||
(((nRollOverride + nRanks) >= nDifficulty) ? GetStringByStrRef(5352) : ((nDifficulty > nRanks + 20) ? GetStringByStrRef(8101) : GetStringByStrRef(5353))) + "* : " +
|
||
"(" + IntToString(nRollOverride) + " + " + IntToString(nRanks) + " = " + IntToString(nRollOverride + nRanks) + " vs. DC: " + IntToString(nDifficulty) + ")"
|
||
);
|
||
}
|
||
return (nRollOverride + nRanks >= nDifficulty);
|
||
}
|
||
|
||
int PRCGetCreatureSize(object oObject = OBJECT_SELF, int nSizeMask = PRC_SIZEMASK_ALL)
|
||
{
|
||
//int nSize = GetCreatureSize(oObject);
|
||
int nSize = StringToInt(Get2DAString("appearance", "SizeCategory", GetAppearanceType(oObject)));
|
||
if (DEBUG) DoDebug("Appearance-based GetCreatureSize, returning size: "+IntToString(nSize));
|
||
if (DEBUG) DoDebug("Bioware GetCreatureSize, returning size: "+IntToString(GetCreatureSize(oObject)));
|
||
//CEP adds other sizes, take them into account too
|
||
if(nSize == 20)
|
||
nSize = CREATURE_SIZE_DIMINUTIVE;
|
||
else if(nSize == 21)
|
||
nSize = CREATURE_SIZE_FINE;
|
||
else if(nSize == 22)
|
||
nSize = CREATURE_SIZE_GARGANTUAN;
|
||
else if(nSize == 23)
|
||
nSize = CREATURE_SIZE_COLOSSAL;
|
||
|
||
if(nSizeMask & PRC_SIZEMASK_NORMAL)
|
||
{
|
||
if(GetHasFeat(FEAT_SIZE_DECREASE_6, oObject))
|
||
nSize += -6;
|
||
else if(GetHasFeat(FEAT_SIZE_DECREASE_5, oObject))
|
||
nSize += -5;
|
||
else if(GetHasFeat(FEAT_SIZE_DECREASE_4, oObject))
|
||
nSize += -4;
|
||
else if(GetHasFeat(FEAT_SIZE_DECREASE_3, oObject))
|
||
nSize += -3;
|
||
else if(GetHasFeat(FEAT_SIZE_DECREASE_2, oObject))
|
||
nSize += -2;
|
||
else if(GetHasFeat(FEAT_SIZE_DECREASE_1, oObject))
|
||
nSize += -1;
|
||
|
||
if(GetHasFeat(FEAT_SIZE_INCREASE_6, oObject))
|
||
nSize += 6;
|
||
else if(GetHasFeat(FEAT_SIZE_INCREASE_5, oObject))
|
||
nSize += 5;
|
||
else if(GetHasFeat(FEAT_SIZE_INCREASE_4, oObject))
|
||
nSize += 4;
|
||
else if(GetHasFeat(FEAT_SIZE_INCREASE_3, oObject))
|
||
nSize += 3;
|
||
else if(GetHasFeat(FEAT_SIZE_INCREASE_2, oObject))
|
||
nSize += 2;
|
||
else if(GetHasFeat(FEAT_SIZE_INCREASE_1, oObject))
|
||
nSize += 1;
|
||
}
|
||
|
||
if(nSizeMask & PRC_SIZEMASK_NOABIL
|
||
|| ((nSizeMask & PRC_SIZEMASK_NORMAL) && GetPRCSwitch(PRC_DRAGON_DISCIPLE_SIZE_CHANGES)))
|
||
{
|
||
if(GetHasFeat(FEAT_DRACONIC_SIZE_INCREASE_2, oObject))
|
||
nSize += 2;
|
||
else if(GetHasFeat(FEAT_DRACONIC_SIZE_INCREASE_1, oObject))
|
||
nSize += 1;
|
||
}
|
||
|
||
if(nSizeMask & PRC_SIZEMASK_SIMPLE)
|
||
{
|
||
// Size changing powers
|
||
// Compression: Size decreased by one or two categories, depending on augmentation
|
||
if(GetLocalInt(oObject, "PRC_Power_Compression_SizeReduction"))
|
||
nSize -= GetLocalInt(oObject, "PRC_Power_Compression_SizeReduction");
|
||
// Expansion: Size increase by one or two categories, depending on augmentation
|
||
if(GetLocalInt(oObject, "PRC_Power_Expansion_SizeIncrease"))
|
||
nSize += GetLocalInt(oObject, "PRC_Power_Expansion_SizeIncrease");
|
||
}
|
||
|
||
if(nSize < CREATURE_SIZE_FINE)
|
||
nSize = CREATURE_SIZE_FINE;
|
||
if(nSize > CREATURE_SIZE_COLOSSAL)
|
||
nSize = CREATURE_SIZE_COLOSSAL;
|
||
if (DEBUG) DoDebug("PRCGetCreatureSize, returning size: "+IntToString(nSize));
|
||
return nSize;
|
||
}
|
||
|
||
int GetIsChakraBound(object oMeldshaper, int nChakra)
|
||
{
|
||
int nTest = GetLocalInt(oMeldshaper, "BoundMeld"+IntToString(nChakra));
|
||
|
||
if (DEBUG) DoDebug("GetIsChakraBound is "+IntToString(nTest));
|
||
return nTest;
|
||
}
|
||
|
||
int GetMaxEssentiaCapacity(object oMeldshaper, int nClass, int nMeld)
|
||
{
|
||
int nMax = 1; // Always can invest one
|
||
int nHD = GetHitDice(oMeldshaper);
|
||
if (nHD >= 31) nMax = 5;
|
||
else if (nHD >= 18) nMax = 4;
|
||
else if (nHD >= 12) nMax = 3;
|
||
else if (nHD >= 6) nMax = 2;
|
||
|
||
if (nClass == CLASS_TYPE_INCARNATE && GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 3) nMax++;
|
||
if (nClass == CLASS_TYPE_INCARNATE && GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 15) nMax++;
|
||
|
||
if (nClass == CLASS_TYPE_TOTEMIST && GetIsMeldBound(oMeldshaper, nMeld) == CHAKRA_TOTEM) nMax++;
|
||
if (nClass == CLASS_TYPE_TOTEMIST && GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 15 && GetIsMeldBound(oMeldshaper, nMeld) == CHAKRA_TOTEM) nMax++;
|
||
|
||
if (nClass == CLASS_TYPE_TOTEMIST && GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper) >= 10 && GetIsMeldBound(oMeldshaper, nMeld) == CHAKRA_TOTEM) nMax++;
|
||
|
||
if (GetIsNecrocarnumMeld(nMeld) && GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper) >= 9) nMax++;
|
||
if (GetLocalInt(oMeldshaper, "DivineSoultouch")) nMax += 1;
|
||
if (GetLocalInt(oMeldshaper, "IncandescentOverload"))
|
||
{
|
||
if (GetAbilityModifier(ABILITY_CHARISMA, oMeldshaper) > 1)
|
||
nMax += GetAbilityModifier(ABILITY_CHARISMA, oMeldshaper);
|
||
else
|
||
nMax += 1;
|
||
}
|
||
if (GetExpandedSoulmeld(oMeldshaper, nMeld)) nMax += 1;
|
||
|
||
if (DEBUG) DoDebug("GetMaxEssentiaCapacity: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax));
|
||
return nMax;
|
||
}
|
||
|
||
int GetEssentiaInvested(object oMeldshaper, int nMeld = -1)
|
||
{
|
||
if (nMeld == -1) nMeld = PRCGetSpellId();
|
||
|
||
if (GetLocalInt(oMeldshaper, "PerfectMeldshaper")) return GetMaxEssentiaCapacity(oMeldshaper, CLASS_TYPE_INCARNATE, -1);
|
||
|
||
int nReturn = GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(nMeld));
|
||
if (GetLocalInt(oMeldshaper, "TotemEmbodiment") == nMeld) nReturn = nReturn * 2;
|
||
if (GetLocalInt(oMeldshaper, "TotemEmbodiment2") == nMeld) nReturn = nReturn * 2;
|
||
if (DEBUG) DoDebug("GetEssentiaInvested nMeld "+IntToString(nMeld)+" nReturn "+IntToString(nReturn));
|
||
return nReturn;
|
||
}
|
||
|
||
int GetIsMeldBound(object oMeldshaper, int nMeld = -1)
|
||
{
|
||
if (nMeld == -1) nMeld = PRCGetSpellId();
|
||
int i, nBind, nTest;
|
||
for (i = 1; i <= 22; i++)
|
||
{
|
||
nTest = GetLocalInt(oMeldshaper, "BoundMeld"+IntToString(i));
|
||
if (nTest == nMeld) // If it's been marked as bound
|
||
nBind = i;
|
||
}
|
||
//FloatingTextStringOnCreature("GetIsMeldBound: nMeld "+IntToString(nMeld)+" nBind "+IntToString(nBind), oMeldshaper);
|
||
if (DEBUG) DoDebug("GetIsMeldBound is "+IntToString(nBind));
|
||
|
||
return nBind; // Return which Chakra it's bound to
|
||
}
|
||
|
||
int GetMeldshaperAbilityOfClass(int nClass, object oMeldshaper)
|
||
{
|
||
// Incarnates use Wisdom for DC, everyone else uses Con
|
||
if (nClass == CLASS_TYPE_INCARNATE || GetHasFeat(FEAT_UNDEAD_MELDSHAPER, oMeldshaper))
|
||
return ABILITY_WISDOM;
|
||
else
|
||
return ABILITY_CONSTITUTION;
|
||
|
||
// Technically, never gets here but the compiler does not realise that
|
||
return -1;
|
||
}
|
||
|
||
int GetMeldshaperDC(object oMeldshaper, int nClass, int nMeldId)
|
||
{
|
||
int nAbi = GetAbilityModifier(GetMeldshaperAbilityOfClass(nClass, oMeldshaper), oMeldshaper) + GetEssentiaInvested(oMeldshaper, nMeldId);
|
||
|
||
// DC is 10 + ability
|
||
int nDC = 10 + nAbi;
|
||
if (GetIsNecrocarnumMeld(nMeldId) && GetHasFeat(FEAT_NECROCARNUM_ACOLYTE, oMeldshaper)) nDC += 1;
|
||
if (DEBUG) DoDebug("GetMeldshaperDC: nAbi "+IntToString(nAbi)+" nMeldId "+IntToString(nMeldId));
|
||
return nDC;
|
||
}
|
||
|
||
int GetEssentiaInvestedFeat(object oMeldshaper, int nFeat)
|
||
{
|
||
int nReturn = GetLocalInt(oMeldshaper, "FeatEssentia"+IntToString(nFeat));
|
||
if (DEBUG) DoDebug("GetEssentiaInvestedFeat nFeat "+IntToString(nFeat)+" nReturn "+IntToString(nReturn));
|
||
return nReturn;
|
||
}
|
||
|
||
int GetIsNecrocarnumMeld(int nMeld)
|
||
{
|
||
int nReturn = FALSE;
|
||
|
||
if (nMeld == MELD_NECROCARNUM_CIRCLET ||
|
||
nMeld == MELD_NECROCARNUM_MANTLE ||
|
||
nMeld == MELD_NECROCARNUM_SHROUD ||
|
||
nMeld == MELD_NECROCARNUM_TOUCH ||
|
||
nMeld == MELD_NECROCARNUM_VESTMENTS ||
|
||
nMeld == MELD_NECROCARNUM_WEAPON)
|
||
nReturn = TRUE;
|
||
|
||
if (DEBUG) DoDebug("GetIsNecrocarnumMeld nReturn "+IntToString(nReturn));
|
||
return nReturn;
|
||
}
|
||
|
||
int DoubleChakraToChakra(int nChakra)
|
||
{
|
||
if (nChakra == CHAKRA_DOUBLE_CROWN ) return CHAKRA_CROWN;
|
||
if (nChakra == CHAKRA_DOUBLE_FEET ) return CHAKRA_FEET;
|
||
if (nChakra == CHAKRA_DOUBLE_HANDS ) return CHAKRA_HANDS;
|
||
if (nChakra == CHAKRA_DOUBLE_ARMS ) return CHAKRA_ARMS;
|
||
if (nChakra == CHAKRA_DOUBLE_BROW ) return CHAKRA_BROW;
|
||
if (nChakra == CHAKRA_DOUBLE_SHOULDERS) return CHAKRA_SHOULDERS;
|
||
if (nChakra == CHAKRA_DOUBLE_THROAT ) return CHAKRA_THROAT;
|
||
if (nChakra == CHAKRA_DOUBLE_WAIST ) return CHAKRA_WAIST;
|
||
if (nChakra == CHAKRA_DOUBLE_HEART ) return CHAKRA_HEART;
|
||
if (nChakra == CHAKRA_DOUBLE_SOUL ) return CHAKRA_SOUL;
|
||
if (nChakra == CHAKRA_DOUBLE_TOTEM ) return CHAKRA_TOTEM;
|
||
|
||
return nChakra;
|
||
}
|
||
|
||
int GetExpandedSoulmeld(object oMeldshaper, int nMeld)
|
||
{
|
||
int i, nCount, nTest;
|
||
for (i = 1; i <= 5; i++)
|
||
{
|
||
nTest = GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(i));
|
||
if (nTest == nMeld)
|
||
nCount = TRUE;
|
||
}
|
||
if (DEBUG) DoDebug("GetExpandedSoulmeld is "+IntToString(nCount));
|
||
return nCount;
|
||
}
|
||
|
||
int GetIsSoulmeldCapacityUsed(object oMeldshaper)
|
||
{
|
||
// If we have the feat and it's not marked as used
|
||
if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_1, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(1))) return FALSE;
|
||
else if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_2, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(2))) return FALSE;
|
||
else if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_3, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(3))) return FALSE;
|
||
else if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_4, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(4))) return FALSE;
|
||
else if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_5, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(5))) return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
void SetIsSoulmeldCapacityUsed(object oMeldshaper, int nMeld)
|
||
{
|
||
// This is called from a place where we've just checked there was an empty slot
|
||
if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_1, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(1))) SetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(1), nMeld);
|
||
else if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_2, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(2))) SetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(2), nMeld);
|
||
else if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_3, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(3))) SetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(3), nMeld);
|
||
else if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_4, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(4))) SetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(4), nMeld);
|
||
else if (GetHasFeat(FEAT_EXPANDED_SOULMELD_CAPACITY_5, oMeldshaper) && !GetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(5))) SetLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(5), nMeld);
|
||
}
|
||
|
||
int GetIsMeldShaped(object oMeldshaper, int nMeld, int nClass)
|
||
{
|
||
int i, nCount, nTest;
|
||
for (i = 0; i <= 20; i++)
|
||
{
|
||
nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(nClass)+IntToString(i));
|
||
if (nTest == nMeld) // If it's been marked as shaped for that class
|
||
nCount = TRUE;
|
||
}
|
||
if (DEBUG) DoDebug("GetIsMeldShaped is "+IntToString(nCount));
|
||
return nCount;
|
||
}
|
||
|
||
int GetMeldShapedClass(object oMeldshaper, int nMeld)
|
||
{
|
||
int nClass;
|
||
if (GetIsMeldShaped(oMeldshaper, nMeld, CLASS_TYPE_INCARNATE)) nClass = CLASS_TYPE_INCARNATE;
|
||
else if (GetIsMeldShaped(oMeldshaper, nMeld, CLASS_TYPE_SOULBORN)) nClass = CLASS_TYPE_SOULBORN;
|
||
else if (GetIsMeldShaped(oMeldshaper, nMeld, CLASS_TYPE_TOTEMIST)) nClass = CLASS_TYPE_TOTEMIST;
|
||
else if (GetIsMeldShaped(oMeldshaper, nMeld, CLASS_TYPE_SPINEMELD_WARRIOR)) nClass = CLASS_TYPE_SPINEMELD_WARRIOR;
|
||
|
||
return nClass;
|
||
}
|
||
|
||
int GetIsIncarnumUser(object oMeldshaper)
|
||
{
|
||
return !!(GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper)
|
||
|| GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper)
|
||
|| GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper)
|
||
|| GetLevelByClass(CLASS_TYPE_INCANDESCENT_CHAMPION, oMeldshaper)
|
||
|| GetHasFeat(FEAT_HEART_INCARNUM, oMeldshaper)
|
||
|| GetHasFeat(FEAT_INCARNUM_FORTIFIED_BODY, oMeldshaper)
|
||
|| GetHasFeat(FEAT_INVEST_ESSENTIA_CONV, oMeldshaper)
|
||
|| GetLevelByClass(CLASS_TYPE_SPINEMELD_WARRIOR, oMeldshaper));
|
||
}
|
||
|
||
int GetIsBinder(object oBinder)
|
||
{
|
||
return !!(GetLevelByClass(CLASS_TYPE_BINDER, oBinder)
|
||
|| GetHasFeat(FEAT_BIND_VESTIGE, oBinder)
|
||
|| GetRacialType(oBinder) == RACIAL_TYPE_KARSITE);
|
||
}
|
||
|
||
int GetAberrantFeatCount(object oPC)
|
||
{
|
||
int i, nCount;
|
||
for (i = 5387; i <= 5398; i++)
|
||
{
|
||
if (GetHasFeat(i, oPC))
|
||
nCount++;
|
||
}
|
||
if (DEBUG) DoDebug("GetAberrantFeatCount is "+IntToString(nCount));
|
||
return nCount;
|
||
} |