Moved PRC8 notes into DevNotes. Updated Eternal Blade TLK to explain abilities better. Updated Werewolf to use "monk" gloves when they exist. Added PRC switch to allow Wildshapes to always merge the arms slot. Clicking on a spell effect now opens the spell effect NUI. (@Rakiov)) Added prc_onplayergui event script for spell effect handling. (@Rakiov) Added prc_nui_sd_event and prc_nui_dur_view to handle displaying spell durations. (@Rakiov) Corrected typo in switch name for PRC_CRAFT_POISON_USE_INGREDIENTS Allowed mindblade to work with Vow of Poverty. Eternal Blade - Island in TIme now has a VFX, looks slightly better. Eternal Blade - Guided Strike now functions. Time Stands Still now has an impact VFX. Added optional PRC_ALLOWED_TO_REMOVE_FRIENDLY_SPELLS and PRC_ALLOWED_TO_SEE_HOSTILE_SPELLS switches for the spell effect view window.
616 lines
18 KiB
Plaintext
616 lines
18 KiB
Plaintext
#include "prc_nui_consts"
|
|
#include "inc_newspellbook"
|
|
#include "psi_inc_psifunc"
|
|
#include "inc_lookups"
|
|
#include "nw_inc_nui"
|
|
#include "tob_inc_tobfunc"
|
|
|
|
//
|
|
// GetCurrentSpellLevel
|
|
// Gets the current spell level the class can achieve at the current
|
|
// caster level (ranging from 0-9)
|
|
//
|
|
// Arguments:
|
|
// nClass:int the ClassID
|
|
// nLevel:int the caster level
|
|
//
|
|
// Returns:
|
|
// int the circle the class can achieve currently
|
|
//
|
|
int GetCurrentSpellLevel(int nClass, int nLevel);
|
|
|
|
//
|
|
// GetMaxSpellLevel
|
|
// Gets the highest possible circle the class can achieve (from 0-9)
|
|
//
|
|
// Arguments:
|
|
// nClass:int the ClassID
|
|
//
|
|
// Returns:
|
|
// int the highest circle that can be achieved
|
|
//
|
|
int GetMaxSpellLevel(int nClass);
|
|
|
|
//
|
|
// GetMinSpellLevel
|
|
// Gets the lowest possible circle the class can achieve (from 0-9)
|
|
//
|
|
// Arguments:
|
|
// nClass:int the ClassID
|
|
//
|
|
// Returns:
|
|
// int the lowest circle that can be achieved
|
|
//
|
|
int GetMinSpellLevel(int nClass);
|
|
|
|
//
|
|
// GetHighestLevelPossibleInClass
|
|
// Given a class Id this will determine what the max level of a class can be
|
|
// achieved
|
|
//
|
|
// Arguments:
|
|
// nClass:int the ClassID
|
|
//
|
|
// Returns:
|
|
// int the highest possible level the class can achieve
|
|
//
|
|
int GetHighestLevelPossibleInClass(int nClass);
|
|
|
|
//
|
|
// GetClassSpellbookFile
|
|
// Gets the class 2da spellbook/ability for the given class Id
|
|
//
|
|
// Arguments:
|
|
// nClass:int the classID
|
|
//
|
|
// Returns:
|
|
// string the 2da file name for the spell/abilities of the ClassID
|
|
//
|
|
string GetClassSpellbookFile(int nClass);
|
|
|
|
//
|
|
// GetBinderSpellToFeatDictionary
|
|
// Sets up the Binder Spell Dictionary that is used to match a binder's vestige
|
|
// to their feat. This is constructed based off the binder's known location of
|
|
// their feat and spell ranges in the base 2das respectivly. After constructing
|
|
// this it will be saved to the player locally as a cached result since we do
|
|
// not need to call this again.
|
|
//
|
|
// Argument:
|
|
// oPlayer:object the player
|
|
//
|
|
// Returns:
|
|
// json:Dictionary<String,Int> a dictionary of mapping between the SpellID
|
|
// and the FeatID of a vestige ability
|
|
//
|
|
json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF);
|
|
|
|
//
|
|
// GetSpellLevelIcon
|
|
// Takes the spell circle int and gets the icon appropriate for it (i.e. 0 turns
|
|
// into "ir_cantrips"
|
|
//
|
|
// Arguments:
|
|
// spellLevel:int the spell level we want the icon for
|
|
//
|
|
// Returns:
|
|
// string the spell level icon
|
|
//
|
|
string GetSpellLevelIcon(int spellLevel);
|
|
|
|
//
|
|
// GetSpellLevelToolTip
|
|
// Gets the spell level tool tip text based on the int spell level provided (i.e.
|
|
// 0 turns into "Cantrips")
|
|
//
|
|
// Arguments:
|
|
// spellLevel:int the spell level we want the tooltip for
|
|
//
|
|
// Returns:
|
|
// string the spell level toop tip
|
|
//
|
|
string GetSpellLevelToolTip(int spellLevel);
|
|
|
|
//
|
|
// GetSpellIcon
|
|
// Gets the spell icon based off the spellId, or featId supplied
|
|
//
|
|
// Arguments:
|
|
// nClass:int the class Id
|
|
// featId:int the featId we can use the icon for
|
|
// spellId:int the spell Id we want the icon for
|
|
//
|
|
// Returns:
|
|
// json:String the string of the icon we want.
|
|
//
|
|
json GetSpellIcon(int spellId, int featId=0, int nClass=0);
|
|
string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0);
|
|
|
|
//
|
|
// GreyOutButton
|
|
// Takes NUI Button along with it's width and height and greys it out it with a drawn
|
|
// colored rectangle to represent it's not been selected or not valid.
|
|
//
|
|
// Arguments:
|
|
// jButton:json the NUI Button
|
|
// w:float the width of the button
|
|
// h:float the height of the button
|
|
//
|
|
// Returns:
|
|
// json the NUI button greyed out
|
|
//
|
|
json GreyOutButton(json jButton, float w, float h);
|
|
|
|
//
|
|
// CreateGreyOutRectangle
|
|
// Creates a grey out rectangle for buttons
|
|
//
|
|
// Arguments:
|
|
// w:float the width of the button
|
|
// h:float the height of the button
|
|
//
|
|
// Returns:
|
|
// json the transparant black rectangle
|
|
//
|
|
json CreateGreyOutRectangle(float w, float h);
|
|
|
|
//
|
|
// GetTrueClassType
|
|
// Gets the true class Id for a provided class Id, mostly for RHD and for
|
|
// ToB prestige classes
|
|
//
|
|
// Arguments:
|
|
// nClass:int classId
|
|
//
|
|
// Returns:
|
|
// int the true classId based off nClass
|
|
//
|
|
int GetTrueClassType(int nClass, object oPC=OBJECT_SELF);
|
|
|
|
void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0);
|
|
|
|
void CallSpellUnlevelScript(object oPC, int nClass, int nLevel);
|
|
void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF);
|
|
void RemoveIPFeat(object oPC, int ipFeatID);
|
|
|
|
void CallSpellUnlevelScript(object oPC, int nClass, int nLevel)
|
|
{
|
|
SetScriptParam("UnLevel_ClassChoice", IntToString(nClass));
|
|
SetScriptParam("UnLevel_LevelChoice", IntToString(nLevel));
|
|
ExecuteScript("prc_unlvl_script", oPC);
|
|
}
|
|
|
|
void RemoveIPFeat(object oPC, int ipFeatID)
|
|
{
|
|
object oSkin = GetPCSkin(oPC);
|
|
itemproperty ipTest = GetFirstItemProperty(oSkin);
|
|
while(GetIsItemPropertyValid(ipTest))
|
|
{
|
|
// Check if the itemproperty is a bonus feat that has been marked for removal
|
|
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_BONUS_FEAT)
|
|
{
|
|
if (GetItemPropertySubType(ipTest) == ipFeatID)
|
|
{
|
|
if(DEBUG) DoDebug("_ManeuverRecurseRemoveArray(): Removing bonus feat itemproperty:\n" + DebugIProp2Str(ipTest));
|
|
// If so, remove it
|
|
RemoveItemProperty(oSkin, ipTest);
|
|
}
|
|
|
|
}
|
|
|
|
ipTest = GetNextItemProperty(oSkin);
|
|
}
|
|
}
|
|
|
|
int GetCurrentSpellLevel(int nClass, int nLevel)
|
|
{
|
|
int currentLevel = nLevel;
|
|
|
|
// ToB doesn't have a concept of spell levels, but still match up to it
|
|
if(nClass == CLASS_TYPE_WARBLADE
|
|
|| nClass == CLASS_TYPE_SWORDSAGE
|
|
|| nClass == CLASS_TYPE_CRUSADER
|
|
|| nClass == CLASS_TYPE_SHADOWCASTER)
|
|
{
|
|
return 9;
|
|
}
|
|
|
|
|
|
// Binders don't really have a concept of spell level
|
|
if (nClass == CLASS_TYPE_BINDER
|
|
|| nClass == CLASS_TYPE_DRAGON_SHAMAN) // they can only reach 1st circle
|
|
return 1;
|
|
|
|
//Shadowsmith has no concept of spell levels
|
|
if (nClass == CLASS_TYPE_SHADOWSMITH)
|
|
return 2;
|
|
|
|
if (nClass == CLASS_TYPE_WARLOCK
|
|
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
|
return 4;
|
|
|
|
// Spont casters have their own function
|
|
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
|
|| nClass == CLASS_TYPE_ARCHIVIST)
|
|
{
|
|
|
|
int maxLevel = GetMaxSpellLevelForCasterLevel(nClass, currentLevel);
|
|
return maxLevel;
|
|
}
|
|
else
|
|
{
|
|
// everyone else uses this
|
|
string spellLevel2da = GetAMSKnownFileName(nClass);
|
|
|
|
currentLevel = nLevel - 1; // Level is 1 off of the row in the 2da
|
|
|
|
if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
|
|| nClass == CLASS_TYPE_PSION
|
|
|| nClass == CLASS_TYPE_PSYWAR
|
|
|| nClass == CLASS_TYPE_WILDER
|
|
|| nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
|
|| nClass == CLASS_TYPE_WARMIND)
|
|
currentLevel = GetManifesterLevel(OBJECT_SELF, nClass, TRUE) - 1;
|
|
|
|
int totalLevel = Get2DARowCount(spellLevel2da);
|
|
|
|
// in case we somehow go over bounds just don't :)
|
|
if (currentLevel >= totalLevel)
|
|
currentLevel = totalLevel - 1;
|
|
|
|
//Psionics have MaxPowerLevel as their column name
|
|
string columnName = "MaxPowerLevel";
|
|
|
|
//Invokers have MaxInvocationLevel
|
|
if (nClass == CLASS_TYPE_WARLOCK
|
|
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|
|
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
|
columnName = "MaxInvocationLevel";
|
|
|
|
// Truenamers have 3 sets of utterances, ranging from 1-6, EvolvingMind covers the entire range
|
|
if (nClass == CLASS_TYPE_TRUENAMER)
|
|
{
|
|
columnName = "EvolvingMind";
|
|
spellLevel2da = "cls_true_maxlvl"; //has a different 2da we want to look at
|
|
}
|
|
|
|
if (nClass == CLASS_TYPE_BINDER)
|
|
{
|
|
columnName = "VestigeLvl";
|
|
spellLevel2da = "cls_bind_binder";
|
|
}
|
|
|
|
// ToB doesn't have a concept of this, but we don't care.
|
|
|
|
int maxLevel = StringToInt(Get2DACache(spellLevel2da, columnName, currentLevel));
|
|
return maxLevel;
|
|
}
|
|
}
|
|
|
|
int GetMinSpellLevel(int nClass)
|
|
{
|
|
// again sponts have their own function
|
|
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
|
|| nClass == CLASS_TYPE_ARCHIVIST)
|
|
{
|
|
return GetMinSpellLevelForCasterLevel(nClass, GetHighestLevelPossibleInClass(nClass));
|
|
}
|
|
else
|
|
{
|
|
if (nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
|
|| nClass == CLASS_TYPE_PSION
|
|
|| nClass == CLASS_TYPE_PSYWAR
|
|
|| nClass == CLASS_TYPE_WILDER
|
|
|| nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
|
|| nClass == CLASS_TYPE_WARMIND
|
|
|| nClass == CLASS_TYPE_WARBLADE
|
|
|| nClass == CLASS_TYPE_SWORDSAGE
|
|
|| nClass == CLASS_TYPE_CRUSADER
|
|
|| nClass == CLASS_TYPE_WARLOCK
|
|
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT
|
|
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|
|
|| nClass == CLASS_TYPE_SHADOWCASTER
|
|
|| nClass == CLASS_TYPE_SHADOWSMITH
|
|
|| nClass == CLASS_TYPE_BINDER)
|
|
return 1;
|
|
|
|
return GetCurrentSpellLevel(nClass, 1);
|
|
}
|
|
|
|
}
|
|
|
|
int GetMaxSpellLevel(int nClass)
|
|
{
|
|
if (nClass == CLASS_TYPE_WILDER
|
|
|| nClass == CLASS_TYPE_PSION)
|
|
return 9;
|
|
if (nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
|
|| nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
|
|| nClass == CLASS_TYPE_WARMIND)
|
|
return 5;
|
|
if (nClass == CLASS_TYPE_PSYWAR)
|
|
return 6;
|
|
|
|
return GetCurrentSpellLevel(nClass, GetHighestLevelPossibleInClass(nClass));
|
|
}
|
|
|
|
int GetHighestLevelPossibleInClass(int nClass)
|
|
{
|
|
string sFile;
|
|
|
|
//sponts have their spells in the classes.2da
|
|
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
|
|| nClass == CLASS_TYPE_ARCHIVIST)
|
|
{
|
|
sFile = Get2DACache("classes", "SpellGainTable", nClass);
|
|
}
|
|
else
|
|
{
|
|
// everyone else uses this
|
|
sFile = GetAMSKnownFileName(nClass);
|
|
|
|
if (nClass == CLASS_TYPE_TRUENAMER)
|
|
{
|
|
sFile = "cls_true_maxlvl"; //has a different 2da we want to look at
|
|
}
|
|
|
|
if (nClass == CLASS_TYPE_BINDER)
|
|
{
|
|
sFile = "cls_bind_binder";
|
|
}
|
|
}
|
|
|
|
return Get2DARowCount(sFile);
|
|
}
|
|
|
|
string GetClassSpellbookFile(int nClass)
|
|
{
|
|
string sFile;
|
|
// Spontaneous casters use a specific file name structure
|
|
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS
|
|
|| nClass == CLASS_TYPE_ARCHIVIST)
|
|
{
|
|
sFile = GetFileForClass(nClass);
|
|
}
|
|
// everyone else uses this structure
|
|
else
|
|
{
|
|
sFile = GetAMSDefinitionFileName(nClass);
|
|
|
|
if (nClass == CLASS_TYPE_BINDER)
|
|
{
|
|
sFile = "vestiges";
|
|
}
|
|
}
|
|
|
|
return sFile;
|
|
}
|
|
|
|
string GetSpellLevelIcon(int spellLevel)
|
|
{
|
|
switch (spellLevel)
|
|
{
|
|
case 0: return "ir_cantrips";
|
|
case 1: return "ir_level1";
|
|
case 2: return "ir_level2";
|
|
case 3: return "ir_level3";
|
|
case 4: return "ir_level4";
|
|
case 5: return "ir_level5";
|
|
case 6: return "ir_level6";
|
|
case 7: return "ir_level789";
|
|
case 8: return "ir_level789";
|
|
case 9: return "ir_level789";
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
string GetSpellLevelToolTip(int spellLevel)
|
|
{
|
|
switch (spellLevel)
|
|
{
|
|
case 0: return "Cantrips";
|
|
case 1: return "Level 1";
|
|
case 2: return "Level 2";
|
|
case 3: return "Level 3";
|
|
case 4: return "Level 4";
|
|
case 5: return "Level 5";
|
|
case 6: return "Level 6";
|
|
case 7: return "Level 7";
|
|
case 8: return "Level 8";
|
|
case 9: return "Level 9";
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
|
|
json GetSpellIcon(int spellId,int featId=0,int nClass=0)
|
|
{
|
|
// Binder's spells don't have the FeatID on the spells.2da, so we have to use
|
|
// the mapping we constructed to get it.
|
|
if (nClass == CLASS_TYPE_BINDER)
|
|
{
|
|
json binderDict = GetBinderSpellToFeatDictionary();
|
|
int nFeatID = JsonGetInt(JsonObjectGet(binderDict, IntToString(spellId)));
|
|
return JsonString(Get2DACache("feat", "Icon", featId));
|
|
}
|
|
|
|
if (featId)
|
|
return JsonString(Get2DACache("feat", "Icon", featId));
|
|
|
|
int masterSpellID = StringToInt(Get2DACache("spells", "Master", spellId));
|
|
|
|
// if this is a sub radial spell, then we use spell's icon instead
|
|
if (masterSpellID)
|
|
return JsonString(Get2DACache("spells", "IconResRef", spellId));
|
|
|
|
// the FeatID holds the accurate spell icon, not the SpellID
|
|
int nFeatID = StringToInt(Get2DACache("spells", "FeatID", spellId));
|
|
// however if no featId was found use the spell's icon instead
|
|
if (!nFeatID)
|
|
return JsonString(Get2DACache("spells", "IconResRef", spellId));
|
|
|
|
return JsonString(Get2DACache("feat", "Icon", nFeatID));
|
|
}
|
|
|
|
string GetSpellName(int spellId, int realSpellID=0, int featId=0, int nClass=0)
|
|
{
|
|
if ((nClass == CLASS_TYPE_SHADOWSMITH
|
|
|| nClass == CLASS_TYPE_SHADOWCASTER) && spellId)
|
|
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId)));
|
|
if (nClass == CLASS_TYPE_TRUENAMER && featId)
|
|
return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId)));
|
|
if (realSpellID)
|
|
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", realSpellID)));
|
|
if (spellId)
|
|
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId)));
|
|
if (featId)
|
|
return GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", featId)));
|
|
|
|
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", spellId)));
|
|
}
|
|
|
|
json GetBinderSpellToFeatDictionary(object oPlayer=OBJECT_SELF)
|
|
{
|
|
// a dictionary of <SpellID, FeatID>
|
|
json binderDict = GetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR);
|
|
// if this hasn't been created, create it now.
|
|
if (binderDict == JsonNull())
|
|
binderDict = JsonObject();
|
|
else
|
|
return binderDict;
|
|
|
|
// the starting row for binder spells
|
|
int spellIndex = 19070;
|
|
// the starting row for binder feats
|
|
int featIndex = 9030;
|
|
//the end of the binder spells/feats
|
|
while (spellIndex <= 19156 && featIndex <= 9104)
|
|
{
|
|
// get the SpellID tied to the feat
|
|
int spellID = StringToInt(Get2DACache("feat", "SPELLID", featIndex));
|
|
// if the spellID matches the current index, then this is the spell
|
|
// attached to the feat
|
|
if (spellID == spellIndex)
|
|
{
|
|
binderDict = JsonObjectSet(binderDict, IntToString(spellID), JsonInt(featIndex));
|
|
|
|
// move to next spell/feat
|
|
featIndex++;
|
|
spellIndex++;
|
|
}
|
|
// else we have reached a subdial spell
|
|
else
|
|
{
|
|
// loop through until we reach back at spellID
|
|
while (spellIndex < spellID)
|
|
{
|
|
int masterSpell = StringToInt(Get2DACache("spells", "Master", spellIndex));
|
|
|
|
// add the sub radial to the dict, tied to the master's FeatID
|
|
int featId = JsonGetInt(JsonObjectGet(binderDict, IntToString(masterSpell)));
|
|
binderDict = JsonObjectSet(binderDict, IntToString(spellIndex), JsonInt(featId));
|
|
|
|
spellIndex++;
|
|
}
|
|
|
|
|
|
// some feats overlap the same FeatID, can cause this to get stuck.
|
|
// if it happens then move on
|
|
if (spellIndex > spellID)
|
|
featIndex++;
|
|
}
|
|
}
|
|
|
|
// cache the result
|
|
SetLocalJson(oPlayer, NUI_SPELLBOOK_BINDER_DICTIONARY_CACHE_VAR, binderDict);
|
|
return binderDict;
|
|
}
|
|
|
|
json GreyOutButton(json jButton, float w, float h)
|
|
{
|
|
json retValue = jButton;
|
|
|
|
json jBorders = JsonArray();
|
|
jBorders = JsonArrayInsert(jBorders, CreateGreyOutRectangle(w, h));
|
|
|
|
return NuiDrawList(jButton, JsonBool(FALSE), jBorders);
|
|
}
|
|
|
|
json CreateGreyOutRectangle(float w, float h)
|
|
{
|
|
// set the points of the button shape
|
|
json jPoints = JsonArray();
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
|
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(h));
|
|
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(w));
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(h));
|
|
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(w));
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
|
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
|
jPoints = JsonArrayInsert(jPoints, JsonFloat(0.0));
|
|
|
|
return NuiDrawListPolyLine(JsonBool(TRUE), NuiColor(0, 0, 0, 127), JsonBool(TRUE), JsonFloat(2.0), jPoints);
|
|
}
|
|
|
|
void CreateSpellDescriptionNUI(object oPlayer, int featID, int spellId=0, int realSpellId=0, int nClass=0)
|
|
{
|
|
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR, featID);
|
|
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR, spellId);
|
|
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR, realSpellId);
|
|
SetLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR, nClass);
|
|
ExecuteScript("prc_nui_dsc_view", oPlayer);
|
|
}
|
|
|
|
void ClearSpellDescriptionNUI(object oPlayer=OBJECT_SELF)
|
|
{
|
|
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_FEATID_VAR);
|
|
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_SPELLID_VAR);
|
|
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_REAL_SPELLID_VAR);
|
|
DeleteLocalInt(oPlayer, NUI_SPELL_DESCRIPTION_CLASSID_VAR);
|
|
}
|
|
|
|
int GetTrueClassType(int nClass, object oPC=OBJECT_SELF)
|
|
{
|
|
if (nClass == CLASS_TYPE_JADE_PHOENIX_MAGE
|
|
|| nClass == CLASS_TYPE_MASTER_OF_NINE
|
|
|| nClass == CLASS_TYPE_DEEPSTONE_SENTINEL
|
|
|| nClass == CLASS_TYPE_BLOODCLAW_MASTER
|
|
|| nClass == CLASS_TYPE_RUBY_VINDICATOR
|
|
|| nClass == CLASS_TYPE_ETERNAL_BLADE
|
|
|| nClass == CLASS_TYPE_SHADOW_SUN_NINJA)
|
|
{
|
|
int trueClass = GetPrimaryBladeMagicClass(oPC);
|
|
return trueClass;
|
|
}
|
|
|
|
if ((nClass == CLASS_TYPE_SHAPECHANGER
|
|
&& GetRacialType(oPC) == RACIAL_TYPE_ARANEA)
|
|
|| (nClass == CLASS_TYPE_OUTSIDER
|
|
&& GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA)
|
|
|| (nClass == CLASS_TYPE_ABERRATION
|
|
&& GetRacialType(oPC) == RACIAL_TYPE_DRIDER)
|
|
|| (nClass == CLASS_TYPE_MONSTROUS
|
|
&& GetRacialType(oPC) == RACIAL_TYPE_ARKAMOI)
|
|
|| (nClass == CLASS_TYPE_MONSTROUS
|
|
&& GetRacialType(oPC) == RACIAL_TYPE_HOBGOBLIN_WARSOUL)
|
|
|| (nClass == CLASS_TYPE_MONSTROUS
|
|
&& GetRacialType(oPC) == RACIAL_TYPE_REDSPAWN_ARCANISS)
|
|
|| (nClass == CLASS_TYPE_MONSTROUS
|
|
&& GetRacialType(oPC) == RACIAL_TYPE_MARRUTACT))
|
|
return CLASS_TYPE_SORCERER;
|
|
if (nClass == CLASS_TYPE_FEY
|
|
&& GetRacialType(oPC) == RACIAL_TYPE_GLOURA)
|
|
return CLASS_TYPE_BARD;
|
|
|
|
return nClass;
|
|
}
|
|
|