Script: q_pass_inc
// q_pass_inc.nss — "Pass the Pass" Misty Mountains escort (roadmap: pass-the-pass)
//
// T2 (L10+) daily escort quest, journal tag "pass_pass". A caravan-master
// waits at the western foot of the High Pass (Foothills of the Misty
// Mountains) and hires the PC to see his wagons across to the eastern
// waystation (the far Misty Mountains ledge). The PC picks a difficulty at
// dialogue; the reward scales as nDiff * QPASS_GOLD_PER gold plus nDiff *
// QPASS_XP_PER XP. On the hardest run a Stone-Giant (q_pass_gnt, a plot-safe
// CR-25 clone of the ordinary Misty Mountains giant "mgiant") ambushes the
// caravan mid-pass. One escort per real calendar day (quest_cd_inc:
// QCD_IsDoneToday gates the offer, QCD_Stamp fires on turn-in).
//
// BOUNDED (no walking-companion escort AI): accept at the giver, an ambush
// scaled by difficulty spawns at waypoint AP_passthepass_2 mid-pass, and the
// quartermaster on the far side pays out when reached. Reaching the far side
// is the whole objective; the ambush is the danger, not a hard fail-state.
//
// Waypoint tags (hyphen-less roadmap id; MUST match the admin-action entries):
// AP_passthepass_1 giver spawn (Foothills of the Misty Mountains)
// AP_passthepass_2 ambush spawn (The Misty Mountains, mistymountainsa)
// AP_passthepass_3 quartermaster spawn(The Misty Mountains, mistymountainsb)
// Everything no-ops gracefully until the admin places the waypoints, so the
// module ships and compiles before any placement exists.
//
// Session state (locals on the PC, set at accept, cleared at turn-in):
// QPASS_ACTIVE 1 while an escort is in progress (blocks re-accept, gates turn-in)
// QPASS_DIFF the chosen difficulty 1..3 (drives payout + ambush composition)
//
// Custom token: 6395 = "come back tomorrow" countdown on the giver.
#include "quest_cd_inc"
const string QPASS_QUEST = "pass_pass"; // questcddb key + journal tag
const int QPASS_GOLD_PER = 200; // gold reward = nDiff * this
const int QPASS_XP_PER = 150; // xp reward = nDiff * this
const int QPASS_MAXDIFF = 3; // hardest tier (Stone-Giant ambush)
// ------------------------------------------------------------
// Small accessors.
int QPASS_Diff(object oPC) { return GetLocalInt(oPC, "QPASS_DIFF"); }
int QPASS_Active(object oPC) { return GetLocalInt(oPC, "QPASS_ACTIVE"); }
// Seconds until the next UTC midnight (when QCD_IsDoneToday flips back). From
// SQLite so there is no game-clock drift, matching QCD_IsDoneToday's date().
int QPASS_SecsToTomorrow()
{
sqlquery q = SqlPrepareQueryCampaign(QCD_DB,
"SELECT CAST(strftime('%s', date('now','+1 day')) AS INTEGER)"
+ " - CAST(strftime('%s','now') AS INTEGER)");
return SqlStep(q) ? SqlGetInt(q, 0) : 0;
}
// ------------------------------------------------------------
// Ambush. Spawns a difficulty-scaled warband at AP_passthepass_2 (mid-pass).
// No-ops when the waypoint is unplaced. Rate is limited naturally: a PC can
// only accept once per day and cannot re-accept while an escort is active, so
// each player triggers at most one ambush per day.
void QPASS_Mob(string sResRef, location lLoc)
{
object oM = CreateObject(OBJECT_TYPE_CREATURE, sResRef, lLoc);
if (GetIsObjectValid(oM))
SetLocalInt(oM, "QPASS_AMBUSH", 1); // tag for later cleanup/inspection
}
void QPASS_SpawnAmbush(int nDiff)
{
object oWP = GetWaypointByTag("AP_passthepass_2");
if (!GetIsObjectValid(oWP)) return; // no-op until the admin places it
location lLoc = GetLocation(oWP);
int i;
if (nDiff <= 1)
{
// Easy: a rabble of goblin-kin.
for (i = 0; i < 3; i++) QPASS_Mob("bugbeara001", lLoc);
}
else if (nDiff == 2)
{
// Normal: goblin soldiers led by a bigger brute.
for (i = 0; i < 3; i++) QPASS_Mob("bugchiefa001", lLoc);
QPASS_Mob("bugbearboss001", lLoc);
}
else
{
// Hard: soldiers, wargs, and a Stone-Giant of the High Pass.
for (i = 0; i < 4; i++) QPASS_Mob("bugchiefa001", lLoc);
for (i = 0; i < 2; i++) QPASS_Mob("q_brn_warg", lLoc);
QPASS_Mob("q_pass_gnt", lLoc);
}
}
// ------------------------------------------------------------
// Accept (ActionTaken from the difficulty replies q_pass_d1/d2/d3).
void QPASS_Begin(object oPC, int nDiff)
{
if (QCD_IsDoneToday(oPC, QPASS_QUEST)) return; // already ran today
if (QPASS_Active(oPC)) return; // already escorting
if (nDiff < 1) nDiff = 1;
if (nDiff > QPASS_MAXDIFF) nDiff = QPASS_MAXDIFF;
SetLocalInt(oPC, "QPASS_ACTIVE", 1);
SetLocalInt(oPC, "QPASS_DIFF", nDiff);
AddJournalQuestEntry(QPASS_QUEST, 1, oPC, FALSE, FALSE, TRUE);
QPASS_SpawnAmbush(nDiff);
FloatingTextStringOnCreature(
"The caravan sets out. Cross the high pass to the eastern waystation.",
oPC, FALSE);
}
// ------------------------------------------------------------
// Turn-in (ActionTaken from the quartermaster's accepting reply q_pass_pay).
// Guarded so it can never pay twice in a day or without an active escort.
void QPASS_TurnIn(object oPC)
{
if (!QPASS_Active(oPC)) return;
int nDiff = QPASS_Diff(oPC);
if (nDiff < 1) nDiff = 1;
DeleteLocalInt(oPC, "QPASS_ACTIVE");
DeleteLocalInt(oPC, "QPASS_DIFF");
if (QCD_IsDoneToday(oPC, QPASS_QUEST)) return; // paranoid double-pay guard
QCD_Stamp(oPC, QPASS_QUEST);
GiveGoldToCreature(oPC, nDiff * QPASS_GOLD_PER);
GiveXPToCreature(oPC, nDiff * QPASS_XP_PER);
AddJournalQuestEntry(QPASS_QUEST, 2, oPC, FALSE, FALSE, TRUE);
FloatingTextStringOnCreature(
"The caravan is safe across the pass. The quartermaster counts out your pay.",
oPC, FALSE);
}