2025/11/25
Added Spell Cancelation tool to end spells early. Made several Exalted feats available generally. Fixed prereqs for several Exalted feats. Fixed typo in Chasing Perfection related itemprops. Grouped Exalted feats under a masterfeat. Moved PRC8 Packages far down the packages.2da so as to not conflict with modules. Updated PRC8 Tester module. Epic Spell: Summon Aberration no longer sucks. Creatures were updated to match PnP and now level with caster. Twinfiend summon now receives the correct number of skill points for their bonus HD. Added LevelUpSummon() function for handling creatures w/ class levels. Further tweaking for the prc_2da_cache creature to prevent NPCs from attacking it. Add paragon & psuedonatural template related json functions. Gated errant debug message in prc_amagsys_gain.nss. Add DM Tool for viewing PC's current character sheet, templates & spell effects. Arrow of Bone shouldn't provide free mundane arrows anymore. Needs testing. Fixed a bunch of minor TLK typos.
This commit is contained in:
67
nwn/nwnprc/trunk/scripts/dm_pc_info_tool.nss
Normal file
67
nwn/nwnprc/trunk/scripts/dm_pc_info_tool.nss
Normal file
@@ -0,0 +1,67 @@
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Jason Stephenson
|
||||
//:: Created On: August 3, 2004
|
||||
//:://////////////////////////////////////////////
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Changed By: Jason Stephenson
|
||||
//:: Changed On: November 24, 2004
|
||||
//:: Note: Changed to use if instead of switch().
|
||||
//:: Also fixed code for X2_ITEM_EVENT_SPELLCAST_AT.
|
||||
//:: Changed On: December 12, 2004
|
||||
//:: Note: Using helper functions from Axe Murderer's example.
|
||||
//:: Click Here
|
||||
//:: Changed On: February 03, 2005
|
||||
//:: Note: Fix Axe Murderer's SetTagBasedScriptExitBehavior function to
|
||||
//:: only clear the variables if the nEndContinue is set to
|
||||
//:: X2_EXECUTE_SCRIPT_END.
|
||||
//:: Changed By: Jaysyn
|
||||
//:: Changed On: 2025-11-25 08:31:43
|
||||
//:: Note: Modified for use with DM info tool
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "x2_inc_switches"
|
||||
int GetTagBasedItemEventNumber()
|
||||
{
|
||||
int nEvent = GetLocalInt(OBJECT_SELF, "X2_L_LAST_ITEM_EVENT");
|
||||
return (nEvent ? nEvent : GetLocalInt(GetModule(), "X2_L_LAST_ITEM_EVENT"));
|
||||
}
|
||||
void SetTagBasedScriptExitBehavior(int nEndContinue)
|
||||
{
|
||||
if (nEndContinue == X2_EXECUTE_SCRIPT_END)
|
||||
{
|
||||
DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_ITEM_EVENT");
|
||||
DeleteLocalInt(GetModule(), "X2_L_LAST_ITEM_EVENT");
|
||||
}
|
||||
SetExecutedScriptReturnValue(nEndContinue);
|
||||
}
|
||||
void main()
|
||||
{
|
||||
//:: Get which event was fired.
|
||||
int nEvent = GetTagBasedItemEventNumber();
|
||||
|
||||
//:: Declare major variables
|
||||
object oPC;
|
||||
object oItem;
|
||||
|
||||
//:: Our unique power was activated.
|
||||
if (nEvent == X2_ITEM_EVENT_ACTIVATE)
|
||||
{
|
||||
oPC = GetItemActivator();
|
||||
oItem = GetItemActivated();
|
||||
object oTarget = GetItemActivatedTarget();
|
||||
|
||||
SetLocalObject(oPC, "EXAMINE_TARGET", oTarget);
|
||||
|
||||
if(!GetIsDM(oPC))
|
||||
{
|
||||
SendMessageToPC(oPC, "This tool is for DM's, not players");
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecuteScript("prc_playerinfo", oPC);
|
||||
}
|
||||
|
||||
}
|
||||
//:: Set the return value, and then fall through.
|
||||
SetTagBasedScriptExitBehavior(X2_EXECUTE_SCRIPT_END);
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
//::////////////////////////////////////////////////////////
|
||||
//:: ;-. ,-. ,-. ,-.
|
||||
//:: | ) | ) / ( )
|
||||
//:: |-' |-< | ;-:
|
||||
//:: | | \ \ ( )
|
||||
//:: ' ' ' `-' `-'
|
||||
//::///////////////////////////////////////////////////////
|
||||
//::
|
||||
/*
|
||||
Impactscript for Shadow Servant.
|
||||
(this is handled in the Familiar script)
|
||||
|
||||
Shadow Servant (Su): At 1st level, your shadow familiar permanently
|
||||
transforms into a Medium shadow elemental. It loses all familiar
|
||||
traits, but gains new abilities as your shadow servant.
|
||||
|
||||
Should your shadow servant die, you can summon a replacement after
|
||||
24 hours pass. Your shadow servant cannot travel farther from you
|
||||
than 30 feet + 10 feet for each of your master of shadow levels
|
||||
(40 feet at 1st level and a maximum of 130 feet at 10th level). If
|
||||
it is forcibly separated from you by more than this distance, the
|
||||
servant dissipates instantly, and you must wait 24 hours to summon
|
||||
a new one.
|
||||
|
||||
|
||||
|
||||
*/
|
||||
//::
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Script: mshadw_shadserv.nss
|
||||
//:: Author: Jaysyn
|
||||
//:: Created: 2025-11-11 19:25:58
|
||||
//:://////////////////////////////////////////////
|
||||
#include "prc_inc_json"
|
||||
#include "prc_inc_spells"
|
||||
|
||||
const string SHADOW_SERVANT_RESREF = "prc_shadow_serv";
|
||||
|
||||
// Watch function: despawns Shadow Servant if master is dead or out of range
|
||||
void ShadowServantWatch(object oShadow, object oPC)
|
||||
{
|
||||
if(DEBUG) DoDebug("mshadw_shadserv >> ShadowServantWatch: Starting function.");
|
||||
|
||||
int nMaster = GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oPC);
|
||||
|
||||
float fRange = 30.0 + (nMaster * 10);
|
||||
|
||||
if (!GetIsObjectValid(oShadow) || !GetIsObjectValid(oPC)) return;
|
||||
|
||||
if (GetIsDead(oPC) ||
|
||||
GetDistanceBetween(oShadow, oPC) > FeetToMeters(fRange))
|
||||
{
|
||||
DestroyObject(oShadow);
|
||||
return;
|
||||
}
|
||||
|
||||
DelayCommand(1.0, ShadowServantWatch(oShadow, oPC));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
|
||||
int nMaster = GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oPC);
|
||||
|
||||
int nDexBonus = (nMaster >= 5 && (nMaster % 2)) ? (nMaster - 3) : 0;
|
||||
|
||||
float fRange = 30.0 + (nMaster * 10);
|
||||
|
||||
// Target location
|
||||
location lTarget = GetSpellTargetLocation();
|
||||
|
||||
// Distance check
|
||||
if (GetDistanceBetweenLocations(GetLocation(oPC), lTarget) > FeetToMeters(fRange))
|
||||
{
|
||||
SendMessageToPC(oPC, "That location is too far away.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Load template
|
||||
json jShadow = TemplateToJson(SHADOW_SERVANT_RESREF, RESTYPE_UTC);
|
||||
if (jShadow == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "mshdw_shadserv: TemplateToJson failed <20> bad resref or resource missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Original HD
|
||||
int nOriginalHD = json_GetCreatureHD(jShadow);
|
||||
if (nOriginalHD <= 0)
|
||||
{
|
||||
SendMessageToPC(oPC, "mshdw_shadserv: json_GetCreatureHD failed <20> template missing HD data.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Add Hit Dice
|
||||
int nHDToAdd = nMaster -1;
|
||||
|
||||
if (nHDToAdd < 0) nHDToAdd = 0;
|
||||
|
||||
jShadow = json_AddHitDice(jShadow, nHDToAdd);
|
||||
|
||||
if (jShadow == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "mshdw_shadserv: json_AddHitDice failed - JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Update feats
|
||||
jShadow = json_AddFeatsFromCreatureVars(jShadow, nOriginalHD);
|
||||
if (jShadow == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "mshdw_shadserv: json_AddFeatsFromCreatureVars failed <20> JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Update stats
|
||||
jShadow = json_ApplyAbilityBoostFromHD(jShadow, nOriginalHD);
|
||||
if (jShadow == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "mshdw_shadserv: json_ApplyAbilityBoostFromHD failed <20> JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Bonus DEX from Shadow Servant class ability
|
||||
jShadow = json_UpdateTemplateStats(jShadow, 0, nDexBonus);
|
||||
|
||||
// Size increase
|
||||
if (nMaster > 2)
|
||||
{
|
||||
jShadow = json_AdjustCreatureSize(jShadow, 1, TRUE);
|
||||
if (jShadow == JSON_NULL)
|
||||
{
|
||||
SendMessageToPC(oPC, "mshdw_shadserv: json_AdjustCreatureSize failed - JSON became invalid.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
object oShadow = JsonToObject(jShadow, lTarget);
|
||||
effect eSummon = ExtraordinaryEffect(EffectSummonCreature("", VFX_FNF_SUMMON_UNDEAD, 0.0, 0, VFX_IMP_UNSUMMON, oShadow));
|
||||
|
||||
ApplyEffectAtLocation(DURATION_TYPE_PERMANENT, eSummon, lTarget);
|
||||
|
||||
if (!GetIsObjectValid(oShadow))
|
||||
{
|
||||
SendMessageToPC(oPC, "mshdw_shadserv: JsonToObject failed - could not create creature from edited template.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set faction to caster<65>s
|
||||
ChangeFaction(oShadow, oPC);
|
||||
SetLocalObject(oShadow, "ANIMATOR", oPC);
|
||||
|
||||
SetCurrentHitPoints(oShadow, GetMaxPossibleHP(oShadow));
|
||||
|
||||
effect eGhost = EffectVisualEffect(VFX_DUR_GHOST_TRANSPARENT);
|
||||
eGhost = UnyieldingEffect(eGhost);
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, oShadow);
|
||||
|
||||
|
||||
// Start watch loop
|
||||
DelayCommand(6.1, ShadowServantWatch(oShadow, oPC));
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "prc_alterations"
|
||||
#include "prc_compan_inc"
|
||||
#include "inc_npc"
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -11,11 +12,13 @@ void main()
|
||||
//:: Used for the Twinfiend Pit Fiend summon
|
||||
int nUltravision = GetLocalInt(oNPC,"INNATE_ULTRAVISION");
|
||||
if(nUltravision)
|
||||
{
|
||||
effect eUltra = EffectUltravision();
|
||||
eUltra = UnyieldingEffect(eUltra);
|
||||
DelayCommand(0.0f, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eUltra, oNPC));
|
||||
}
|
||||
{
|
||||
effect eUltra = EffectUltravision();
|
||||
eUltra = UnyieldingEffect(eUltra);
|
||||
DelayCommand(0.0f, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eUltra, oNPC));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//use companion appearances
|
||||
/*if(GetPRCSwitch(MARKER_PRC_COMPANION))
|
||||
|
||||
406
nwn/nwnprc/trunk/scripts/prc_playerinfo.nss
Normal file
406
nwn/nwnprc/trunk/scripts/prc_playerinfo.nss
Normal file
@@ -0,0 +1,406 @@
|
||||
//::////////////////////////////////////////////////////////
|
||||
//:: ;-. ,-. ,-. ,-.
|
||||
//:: | ) | ) / ( )
|
||||
//:: |-' |-< | ;-:
|
||||
//:: | | \ \ ( )
|
||||
//:: ' ' ' `-' `-'
|
||||
//::////////////////////////////////////////////////////////
|
||||
//:: FileName: "prc_playerinfo"
|
||||
//:: Created By: Jaysyn
|
||||
//:: Last Updated On: 2025-11-25 08:26:22
|
||||
//::
|
||||
//::////////////////////////////////////////////////////////
|
||||
/*
|
||||
|
||||
Displays a lot of relevant PC info in an NUI window
|
||||
|
||||
*/
|
||||
//::////////////////////////////////////////////////////////
|
||||
#include "nw_inc_nui"
|
||||
#include "prc_inc_template"
|
||||
|
||||
const string CHAR_SHEET_WINDOW_ID = "char_sheet_window";
|
||||
|
||||
void ShowCharacterSheet(object oPC, object oTarget)
|
||||
{
|
||||
//:: Close existing window if open
|
||||
int nToken = NuiFindWindow(oPC, CHAR_SHEET_WINDOW_ID);
|
||||
if (nToken > 0)
|
||||
{
|
||||
NuiDestroy(oPC, nToken);
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Build the layout
|
||||
json jCol = JsonArray();
|
||||
|
||||
//:: === CHARACTER NAME & RACE ===
|
||||
json jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Name:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_name"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Race:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_race"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Subrace:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_subrace"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Deity:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_deity"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Templates:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiText(NuiBind("char_templates"), TRUE, NUI_SCROLLBARS_AUTO));
|
||||
jCol = JsonArrayInsert(jCol, NuiHeight(NuiRow(jRow), 60.0));
|
||||
|
||||
//:: === CLASSES ===
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Classes:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiText(NuiBind("char_classes"), TRUE, NUI_SCROLLBARS_AUTO));
|
||||
jCol = JsonArrayInsert(jCol, NuiHeight(NuiRow(jRow), 120.0));
|
||||
|
||||
//:: === LEVEL & EXPERIENCE ===
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Total Level:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_level"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: Only show XP for PCs
|
||||
if (GetIsPC(oTarget))
|
||||
{
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Experience:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_xp"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
}
|
||||
|
||||
//:: === HIT POINTS ===
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Hit Points:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_hp"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: === ABILITY SCORES - Two columns ===
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Ability Scores:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: STR and DEX
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("STR:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_str"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("DEX:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_dex"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: CON and INT
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("CON:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_con"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("INT:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_int"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: WIS and CHA
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("WIS:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_wis"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("CHA:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_cha"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: === ENCUMBRANCE ===
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Encumbrance:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_encumbrance"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: === SAVING THROWS ===
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Saving Throws:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: Fortitude
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Fortitude:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_fort"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: Reflex
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Reflex:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_ref"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: Will
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Will:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_will"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: === ARMOR CLASS ===
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Armor Class:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jRow = JsonArrayInsert(jRow, NuiSpacer());
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(NuiBind("char_ac"), JsonInt(NUI_HALIGN_RIGHT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
//:: === ACTIVE EFFECTS ===
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiLabel(JsonString("Active Spells:"), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE)));
|
||||
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
|
||||
|
||||
jRow = JsonArray();
|
||||
jRow = JsonArrayInsert(jRow, NuiText(NuiBind("char_effects"), TRUE, NUI_SCROLLBARS_AUTO));
|
||||
jCol = JsonArrayInsert(jCol, NuiHeight(NuiRow(jRow), 100.0));
|
||||
|
||||
//:: Create window
|
||||
json jRoot = NuiCol(jCol);
|
||||
|
||||
string sTitle = "Character Sheet: " + GetName(oTarget);
|
||||
json jNui = NuiWindow(
|
||||
jRoot,
|
||||
JsonString(sTitle),
|
||||
NuiBind("geometry"),
|
||||
JsonBool(TRUE),
|
||||
JsonBool(FALSE),
|
||||
JsonBool(TRUE),
|
||||
JsonBool(FALSE),
|
||||
JsonBool(TRUE)
|
||||
);
|
||||
|
||||
nToken = NuiCreate(oPC, jNui, CHAR_SHEET_WINDOW_ID);
|
||||
|
||||
//:: Set geometry
|
||||
NuiSetBind(oPC, nToken, "geometry", NuiRect(100.0, 100.0, 400.0, 850.0));
|
||||
|
||||
//:: === POPULATE DATA ===
|
||||
|
||||
//:: Name
|
||||
NuiSetBind(oPC, nToken, "char_name", JsonString(GetName(oTarget)));
|
||||
|
||||
//:: Race
|
||||
string sRace = GetStringByStrRef(StringToInt(Get2DAString("racialtypes", "Name", GetRacialType(oTarget))));
|
||||
if (sRace == "") sRace = "Unknown";
|
||||
NuiSetBind(oPC, nToken, "char_race", JsonString(sRace));
|
||||
|
||||
//:: Subrace
|
||||
string sSubrace = GetSubRace(oTarget);
|
||||
if (sSubrace == "") sSubrace = "None";
|
||||
NuiSetBind(oPC, nToken, "char_subrace", JsonString(sSubrace));
|
||||
|
||||
//:: Deity
|
||||
string sDeity = GetDeity(oTarget);
|
||||
if (sDeity == "") sDeity = "None";
|
||||
NuiSetBind(oPC, nToken, "char_deity", JsonString(sDeity));
|
||||
|
||||
//:: Templates - Check for persistent local variables named "template_X"
|
||||
string sTemplates = "";
|
||||
int nTemplateCount = 0;
|
||||
int i;
|
||||
int nMaxTemplates = 128;
|
||||
|
||||
for (i = 0; i <= nMaxTemplates; i++)
|
||||
{
|
||||
string sVarName = "template_" + IntToString(i);
|
||||
|
||||
//:: Check if this persistent local variable exists and is TRUE
|
||||
if (GetPersistantLocalInt(oTarget, sVarName))
|
||||
{
|
||||
string sNameEntry = Get2DAString("templates", "Name", i);
|
||||
|
||||
//:: Only process if we got a valid name entry
|
||||
if (sNameEntry != "")
|
||||
{
|
||||
int nNameStrRef = StringToInt(sNameEntry);
|
||||
string sTemplateName = GetStringByStrRef(nNameStrRef);
|
||||
|
||||
if (sTemplateName == "")
|
||||
sTemplateName = "Template " + IntToString(i);
|
||||
|
||||
if (nTemplateCount > 0)
|
||||
sTemplates += "\n";
|
||||
|
||||
sTemplates += sTemplateName;
|
||||
nTemplateCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nTemplateCount == 0)
|
||||
sTemplates = "None";
|
||||
|
||||
NuiSetBind(oPC, nToken, "char_templates", JsonString(sTemplates));
|
||||
|
||||
//:: Classes
|
||||
string sClasses = "";
|
||||
for (i = 1; i <= 8; i++)
|
||||
{
|
||||
int nClass = GetClassByPosition(i, oTarget);
|
||||
if (nClass != CLASS_TYPE_INVALID)
|
||||
{
|
||||
string sClassName = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass)));
|
||||
if (sClassName == "") sClassName = "Class " + IntToString(nClass);
|
||||
|
||||
int nLevel = GetLevelByClass(nClass, oTarget);
|
||||
|
||||
if (sClasses != "")
|
||||
sClasses += "\n";
|
||||
|
||||
sClasses += sClassName + " " + IntToString(nLevel);
|
||||
}
|
||||
}
|
||||
|
||||
if (sClasses == "")
|
||||
sClasses = "No classes found";
|
||||
|
||||
NuiSetBind(oPC, nToken, "char_classes", JsonString(sClasses));
|
||||
|
||||
//:: Level
|
||||
NuiSetBind(oPC, nToken, "char_level", JsonString(IntToString(GetHitDice(oTarget))));
|
||||
|
||||
//:: XP (only for PCs)
|
||||
if (GetIsPC(oTarget))
|
||||
{
|
||||
NuiSetBind(oPC, nToken, "char_xp", JsonString(IntToString(GetXP(oTarget))));
|
||||
}
|
||||
|
||||
//:: Hit Points
|
||||
string sHP = IntToString(GetCurrentHitPoints(oTarget)) + " / " + IntToString(GetMaxHitPoints(oTarget));
|
||||
NuiSetBind(oPC, nToken, "char_hp", JsonString(sHP));
|
||||
|
||||
//:: Ability Scores - Individual binds
|
||||
NuiSetBind(oPC, nToken, "char_str", JsonString(IntToString(GetAbilityScore(oTarget, ABILITY_STRENGTH))));
|
||||
NuiSetBind(oPC, nToken, "char_dex", JsonString(IntToString(GetAbilityScore(oTarget, ABILITY_DEXTERITY))));
|
||||
NuiSetBind(oPC, nToken, "char_con", JsonString(IntToString(GetAbilityScore(oTarget, ABILITY_CONSTITUTION))));
|
||||
NuiSetBind(oPC, nToken, "char_int", JsonString(IntToString(GetAbilityScore(oTarget, ABILITY_INTELLIGENCE))));
|
||||
NuiSetBind(oPC, nToken, "char_wis", JsonString(IntToString(GetAbilityScore(oTarget, ABILITY_WISDOM))));
|
||||
NuiSetBind(oPC, nToken, "char_cha", JsonString(IntToString(GetAbilityScore(oTarget, ABILITY_CHARISMA))));
|
||||
|
||||
//:: Encumbrance
|
||||
int nEncumbrance = GetWeight(oTarget) / 10;
|
||||
string sEncumbrance = IntToString(nEncumbrance) + " lbs";
|
||||
|
||||
//:: Only check for gold bag on PCs
|
||||
if (GetIsPC(oTarget) && GetIsObjectValid(GetItemPossessedBy(oTarget, "NW_IT_MNYBAG01")))
|
||||
{
|
||||
nEncumbrance += GetGold(oTarget) / 50;
|
||||
sEncumbrance += " (+" + IntToString(GetGold(oTarget) / 50) + " gold)";
|
||||
}
|
||||
NuiSetBind(oPC, nToken, "char_encumbrance", JsonString(sEncumbrance));
|
||||
|
||||
//:: Saves - Individual binds
|
||||
NuiSetBind(oPC, nToken, "char_fort", JsonString(IntToString(GetFortitudeSavingThrow(oTarget))));
|
||||
NuiSetBind(oPC, nToken, "char_ref", JsonString(IntToString(GetReflexSavingThrow(oTarget))));
|
||||
NuiSetBind(oPC, nToken, "char_will", JsonString(IntToString(GetWillSavingThrow(oTarget))));
|
||||
|
||||
//:: AC
|
||||
NuiSetBind(oPC, nToken, "char_ac", JsonString(IntToString(GetAC(oTarget))));
|
||||
|
||||
//:: Active Spells - Track unique spell IDs to avoid duplicates
|
||||
string sEffects = "";
|
||||
effect eEffect = GetFirstEffect(oTarget);
|
||||
int nEffectCount = 0;
|
||||
string sTrackedSpells = ""; //:: Use this to track which spells we've already listed
|
||||
|
||||
while (GetIsEffectValid(eEffect))
|
||||
{
|
||||
int nSpellId = GetEffectSpellId(eEffect);
|
||||
|
||||
//:: Only process if this is a valid spell and we haven't already listed it
|
||||
if (nSpellId > 0)
|
||||
{
|
||||
string sSpellIdStr = IntToString(nSpellId);
|
||||
|
||||
//:: Check if we've already processed this spell
|
||||
if (FindSubString(sTrackedSpells, ":" + sSpellIdStr + ":") == -1)
|
||||
{
|
||||
//:: Add to tracked list
|
||||
sTrackedSpells += ":" + sSpellIdStr + ":";
|
||||
|
||||
//:: Get spell name from spells.2da -> TLK
|
||||
int nNameStrRef = StringToInt(Get2DAString("spells", "Name", nSpellId));
|
||||
string sSpellName = GetStringByStrRef(nNameStrRef);
|
||||
|
||||
if (sSpellName == "")
|
||||
sSpellName = "Unknown Spell (ID: " + sSpellIdStr + ")";
|
||||
|
||||
//:: Get duration for this spell effect
|
||||
float fDuration = IntToFloat(GetEffectDurationRemaining(eEffect));
|
||||
string sDuration = "";
|
||||
|
||||
if (fDuration > 0.0)
|
||||
{
|
||||
int nSeconds = FloatToInt(fDuration);
|
||||
int nMinutes = nSeconds / 60;
|
||||
nSeconds = nSeconds % 60;
|
||||
|
||||
if (nMinutes > 0)
|
||||
sDuration = IntToString(nMinutes) + "m " + IntToString(nSeconds) + "s";
|
||||
else
|
||||
sDuration = IntToString(nSeconds) + "s";
|
||||
}
|
||||
else
|
||||
{
|
||||
sDuration = "Permanent";
|
||||
}
|
||||
|
||||
if (nEffectCount > 0)
|
||||
sEffects += "\n";
|
||||
|
||||
sEffects += sSpellName + " (" + sDuration + ")";
|
||||
nEffectCount++;
|
||||
}
|
||||
}
|
||||
|
||||
eEffect = GetNextEffect(oTarget);
|
||||
}
|
||||
|
||||
if (nEffectCount == 0)
|
||||
sEffects = "No active spells";
|
||||
|
||||
NuiSetBind(oPC, nToken, "char_effects", JsonString(sEffects));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
object oTarget = oPC;
|
||||
|
||||
//:: If PC is targeting something else, show that target's sheet instead
|
||||
object oTargeted = GetLocalObject(oPC, "EXAMINE_TARGET");
|
||||
if (GetIsObjectValid(oTargeted) && GetObjectType(oTargeted) == OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
oTarget = oTargeted;
|
||||
}
|
||||
|
||||
//:: Show the window
|
||||
ShowCharacterSheet(oPC, oTarget);
|
||||
}
|
||||
9
nwn/nwnprc/trunk/scripts/prc_remo_spell.nss
Normal file
9
nwn/nwnprc/trunk/scripts/prc_remo_spell.nss
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "inc_dynconv"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
|
||||
StartDynamicConversation("prc_remo_spl_cv", oPC);
|
||||
|
||||
}
|
||||
130
nwn/nwnprc/trunk/scripts/prc_remo_spl_cv.nss
Normal file
130
nwn/nwnprc/trunk/scripts/prc_remo_spl_cv.nss
Normal file
@@ -0,0 +1,130 @@
|
||||
//:://///////////////////////////////////////////////////////////////
|
||||
//:: End Self-Cast Active Spells - DynConv
|
||||
//:: prc_remo_spl_fx.nss
|
||||
//::
|
||||
//:: Created by: Jaysyn
|
||||
//:: Created on: 2025-11-22 15:45:50
|
||||
//:://///////////////////////////////////////////////////////////////
|
||||
/*
|
||||
- Lists all active spell effects on and cast by the PC.
|
||||
- Allows the player to end any of them (removes all effects
|
||||
- from that spell cast by the PC).
|
||||
|
||||
- Start with:
|
||||
- StartDynamicConversation("prc_remo_spl_cv", OBJECT_SELF);
|
||||
*/
|
||||
//:://///////////////////////////////////////////////////////////////
|
||||
#include "prc_effect_inc"
|
||||
#include "inc_dynconv"
|
||||
|
||||
const int STAGE_ENTRY = 0;
|
||||
|
||||
// Get a localized spell name from spells.2da; fallback to "Spell #"
|
||||
string PRCGetSpellName(int nSpell)
|
||||
{
|
||||
string sName = "";
|
||||
string sRef = Get2DAString("spells", "Name", nSpell);
|
||||
if (sRef != "")
|
||||
{
|
||||
int nStrRef = StringToInt(sRef);
|
||||
if (nStrRef > 0)
|
||||
{
|
||||
sName = GetStringByStrRef(nStrRef);
|
||||
}
|
||||
}
|
||||
if (sName == "")
|
||||
{
|
||||
sName = "Spell #" + IntToString(nSpell);
|
||||
}
|
||||
return sName;
|
||||
}
|
||||
|
||||
// Build list of unique self-cast active spells on oPC, one choice per spell id.
|
||||
// Returns count of unique spells found.
|
||||
int BuildSpellChoiceList(object oPC)
|
||||
{
|
||||
int nCount = 0;
|
||||
|
||||
array_create(oPC, "PC_SPELL_LIST");
|
||||
|
||||
effect e = GetFirstEffect(oPC);
|
||||
|
||||
while (GetIsEffectValid(e))
|
||||
{
|
||||
int nSpell = GetEffectSpellId(e);
|
||||
if (nSpell >= 0 && GetEffectCreator(e) == oPC)
|
||||
{
|
||||
if (array_get_int(oPC, "PC_SPELL_LIST", nSpell) == 0)
|
||||
{
|
||||
AddChoice(PRCGetSpellName(nSpell), nSpell, oPC);
|
||||
array_set_int(oPC, "PC_SPELL_LIST", nSpell, 1);
|
||||
nCount++;
|
||||
}
|
||||
}
|
||||
|
||||
e = GetNextEffect(oPC);
|
||||
}
|
||||
array_delete(oPC, "PC_SPELL_LIST");
|
||||
return nCount;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
|
||||
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
|
||||
int nStage = GetStage(oPC);
|
||||
|
||||
if (nValue == 0)
|
||||
return;
|
||||
|
||||
if (nValue == DYNCONV_SETUP_STAGE)
|
||||
{
|
||||
if (!GetIsStageSetUp(nStage, oPC))
|
||||
{
|
||||
if (nStage == STAGE_ENTRY)
|
||||
{
|
||||
int nList = BuildSpellChoiceList(oPC);
|
||||
|
||||
if (nList > 0)
|
||||
{
|
||||
SetHeader("Which of your active spells would you like to end:");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetHeader("You have no self-cast active spells available to end.");
|
||||
}
|
||||
|
||||
MarkStageSetUp(nStage, oPC);
|
||||
SetDefaultTokens();
|
||||
}
|
||||
}
|
||||
|
||||
SetupTokens(oPC);
|
||||
}
|
||||
|
||||
else if (nValue == DYNCONV_EXITED)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
else if (nValue == DYNCONV_ABORTED)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
else
|
||||
{
|
||||
// Player selected a spell id
|
||||
int nSpellId = GetChoice(oPC);
|
||||
|
||||
if (nStage == STAGE_ENTRY)
|
||||
{
|
||||
// End the spell
|
||||
PRCRemoveSpellEffects(nSpellId, oPC, oPC);
|
||||
|
||||
// Rebuild list
|
||||
ClearCurrentStage(oPC);
|
||||
}
|
||||
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ void main()
|
||||
}
|
||||
|
||||
// Target location
|
||||
location lTarget = GetSpellTargetLocation();
|
||||
location lTarget = PRCGetSpellTargetLocation();
|
||||
|
||||
// Distance check
|
||||
if (GetDistanceBetweenLocations(GetLocation(oPC), lTarget) > FeetToMeters(TREE_RANGE_FEET))
|
||||
|
||||
Reference in New Issue
Block a user