Script: q_rog_inc
// q_rog_inc.nss -- "The Long Shadow", Rogue class-line I (roadmap: rogue-line-early)
//
// The early nodes (L1 / L8 / L15) of the Rogue line. Fenn the Shade
// (q_rog_fenn), a hooded Bree-lander who watches the Prancing Pony's doorways,
// runs "the Long Shadow" -- a loose net of thieves and watchers who keep tally
// of the Enemy's spies on the roads. He takes the measure of any who move light
// on their feet. Only a Rogue (GetLevelByClass(CLASS_TYPE_ROGUE) >= 1) is
// offered a place in the net; other folk get a wary nod and nothing more.
//
// The arc, one bounded first chunk (the capstone -- Shelob's lair, Cirith Ungol
// and the twin blades -- is LATER-tier content, not built here):
// * Node 1 (L1): Swear into the Long Shadow. Reward: the Shadowmantle
// (q_rog_cloak), a modest +1 Rogue-only cloak.
// * Node 2 (L8): Fenn entrusts a cipher-token (q_rog_token) -- a watchword of
// the net -- and sends the PC out to carry it unseen through
// the wider world and grow into the trade.
// * Node 3 (L15): Grown in the craft, the PC brings the token back; Fenn's
// fence works its hidden steel core into a blade, the
// Nightthorn (q_rog_blade), a +2 Rogue-only short sword.
// Line I done.
//
// Persistence: campaign DB "roguelinedb", per-character (oPC-keyed
// Get/SetCampaignInt -- relog- and restart-safe, mirrors the fighter line).
// Key "shadow_stage": 0 none / 1 sworn / 2 token carried / 3 line done.
// One-off: the stage only advances, so rewards are never farmable.
//
// Fenn is script-spawned at the admin-placed waypoint AP_roguelineearly_1
// (Prancing Pony ground floor, theprancingpo001) by q_rog_spawn, fired from the
// area OnEnter wrapper q_rog_enter. Everything no-ops gracefully until the
// waypoint exists (see the roadmap item manual_steps) and never double-spawns.
// All engine calls used here are base NWScript builtins -- no framework include.
const string ROG_DB = "roguelinedb"; // shared campaign DB
const string ROG_STAGEKEY = "shadow_stage"; // per-character stage int
const string ROG_QUEST = "rog_shadow"; // journal category tag
const string ROG_FENN = "q_rog_fenn"; // giver blueprint + tag
const string ROG_WP_TAG = "AP_roguelineearly_1"; // admin-placed waypoint
const int ROG_LVL_NODE2 = 8; // return for the token at level 8
const int ROG_LVL_NODE3 = 15; // return to reforge at level 15
// ------------------------------------------------------------
// Stage accessors (persistent, per character).
int ROG_GetStage(object oPC)
{
return GetCampaignInt(ROG_DB, ROG_STAGEKEY, oPC);
}
void ROG_SetStage(object oPC, int nStage)
{
SetCampaignInt(ROG_DB, ROG_STAGEKEY, nStage, oPC);
}
// TRUE if oPC has at least one level of Rogue -- the line's entry gate.
int ROG_IsRogue(object oPC)
{
return GetLevelByClass(CLASS_TYPE_ROGUE, oPC) >= 1;
}
// ------------------------------------------------------------
// Node action handlers (called from the conversation reply Scripts, so the
// reward fires the instant the reply is chosen -- escape-closing the following
// line cannot dodge a stage advance or a handed-out prize).
// Node 1: swear into the net. Rogue-gated, one-way (stage 0 -> 1).
void ROG_TakeOath(object oPC)
{
if (!ROG_IsRogue(oPC)) return;
if (ROG_GetStage(oPC) != 0) return;
ROG_SetStage(oPC, 1);
AddJournalQuestEntry(ROG_QUEST, 1, oPC, FALSE, FALSE, TRUE);
CreateItemOnObject("q_rog_cloak", oPC, 1); // Shadowmantle (+1, Rogue)
}
// Node 2: receive the cipher-token (stage 1 -> 2). Level gate is enforced by
// the dialogue StartingConditional; guarded here too against a stale node.
void ROG_TakeToken(object oPC)
{
if (ROG_GetStage(oPC) != 1) return;
if (GetHitDice(oPC) < ROG_LVL_NODE2) return;
ROG_SetStage(oPC, 2);
AddJournalQuestEntry(ROG_QUEST, 2, oPC, FALSE, FALSE, TRUE);
if (!GetIsObjectValid(GetItemPossessedBy(oPC, "q_rog_token")))
CreateItemOnObject("q_rog_token", oPC, 1); // cipher-token (plot)
}
// Node 3: work the token's steel core into the Nightthorn (stage 2 -> 3).
// Consumes the token if the PC still carries it; the reward is given regardless
// so a lost token cannot brick the line at the last step.
void ROG_TakeReturn(object oPC)
{
if (ROG_GetStage(oPC) != 2) return;
if (GetHitDice(oPC) < ROG_LVL_NODE3) return;
ROG_SetStage(oPC, 3);
object oTok = GetItemPossessedBy(oPC, "q_rog_token");
if (GetIsObjectValid(oTok)) DestroyObject(oTok);
AddJournalQuestEntry(ROG_QUEST, 3, oPC, FALSE, FALSE, TRUE);
CreateItemOnObject("q_rog_blade", oPC, 1); // Nightthorn (+2, Rogue)
}
// ------------------------------------------------------------
// Spawn Fenn at the admin-placed waypoint. Graceful no-op until the waypoint
// exists; never double-spawns (module-wide tag guard).
void ROG_SpawnFenn()
{
if (GetIsObjectValid(GetObjectByTag(ROG_FENN))) return;
object oWP = GetWaypointByTag(ROG_WP_TAG);
if (!GetIsObjectValid(oWP)) return;
CreateObject(OBJECT_TYPE_CREATURE, ROG_FENN, GetLocation(oWP));
}