Shops and quests
Giving an NPC a shop or quests, and adding your own kinds of quest task.
The Interactable NPC tool (Q menu > Tools > RPG X) gives a spawn point's NPC a role players talk to by pressing E on it: a shop or a quest giver. Its statues show like the Enemy Spawns tool's.
| On the toolgun | Does |
|---|---|
| Left click | Give the aimed-at point (its statue, or its live NPC) the role set up in the menu. After Set waypoint, sets the waypoint instead. |
| Right click | Copy the point's role into the menu (for a quest giver: which quests it hands out). |
| Reload | Take the role away: a plain enemy again. |
The role stays when the point's enemy settings are changed with the Enemy Spawns tool; deleting the point deletes it (its quests stay). The menu remembers the role, shop items and ticked quests between sessions.
The NPC isn't made friendly: pick "Hostile to players" off on its point if it should be.
Shop: tick the weapons it hands out (every spawnable SWEP, searchable). Players see each one with its icon and name, like in the inventory. Free for now; Take puts one in your inventory.
Quest giver: hands out some of the server's quests. Quests aren't a giver's or a map's: they're kept in the database, the same on every map, and on every server that shares the database (see Database). Givers are spawn points, so they're per map; any number of givers, on any maps, can hand out the same quest, and one giver up to 255.
With the quest giver role picked, the menu lists every quest on the server. The checkbox in a quest's title bar says whether this giver hands it out; tick the ones it should, then left click the point. Click a quest's title to open it and edit it. Edits are saved for everyone a moment after you make them, givers already handing the quest out included; players keep their progress in tasks that are still there. Add quest makes a new one (ticked and opened), Delete quest deletes one for good: every giver stops handing it out and players lose their progress in it. Each quest has:
- a name, a minimum player level (default 1; see Levels and skills), repeatable (can be taken again after turning it in), and for a repeatable one a cooldown (minutes after turning it in before the same player can take it again; 0 = right away; up to 30 days, typed in),
- rewards on turn-in, any of: a weapon (into the inventory; there must be room), XP, and levels of a skill (given for free, whatever the skill needs, up to its level cap; the rest is lost if it's already there),
- quests it needs finished first: any other quest on the server (quests waiting on each other in a circle are refused),
- tasks (up to 32). A task can wait for earlier tasks of the same quest ("go to the yard" before "kill 5 zombies"); until then nothing counts towards it.
Quests made before the list was the server's (when each giver had its own) were moved into it automatically, still handed out by the same givers.
Built-in task types:
| Type | Options | Done when |
|---|---|---|
| Kill X | Enemies that count (any NPC of those types, not just spawn point ones), how many, each (that many of every one picked; off: in total) | Enough are killed |
| Go to | A waypoint (Set waypoint closes the menu; your next left click is the spot), a radius, an optional place name | You're inside the radius, on the waypoint's map |
A waypoint is a place on the map it was set on: on other maps it isn't shown and can't be reached (so a quest with one belongs on givers on that map). Waypoints set before quests were the server's have no map and count on any map; set them again to fix that. While the tool is out, the waypoints of the ticked and opened quests show as blue spheres. Players press E on the giver for a window with each quest's status (available, locked and why, in progress, ready to turn in, done, or not yet with the cooldown counting down), its tasks and progress, and Accept, Abandon and Turn in buttons. With a quest in progress, progress pops up as it's made. Abandoning resets a quest's progress.
The quest journal is the inventory's Quests tab (I): every accepted quest, who gave it, whether it's in progress or ready to turn in (and where to), its reward, and each task with its progress (✔ done, • open, ○ after an earlier task). One quest at a time is tracked (Track / Stop tracking): it shows on the HUD on the right with its tasks and progress, and the places of its open Go to tasks are marked on screen with the distance. Accepting a quest with nothing tracked tracks it; turning in or abandoning the tracked one leaves nothing tracked. The tracked quest is saved with the player's quests.
Task types from addons #
Quests are built from task types, and addons add their own the same way the built-in ones are
made (gamemode/sh_tasktypes.lua is the example):
hook.Add( "RPGXTaskTypes", "MyAddon", function( register )
register( "spin", {
name = "Turn in circles",
Defaults = function() return { turns = 3 } end,
Sanitize = function( data ) return { turns = math.Clamp( tonumber( data.turns ) or 3, 1, 50 ) } end,
Describe = function( data ) return "Turn around " .. data.turns .. " times" end,
Done = function( data, progress ) return ( progress.turns or 0 ) >= data.turns end,
ProgressText = function( data, progress ) return ( progress.turns or 0 ) .. " / " .. data.turns end,
Events = {
spun = function( data, progress, ply ) progress.turns = ( progress.turns or 0 ) + 1 return true end,
},
BuildEditor = function( parent, data, changed, tools )
local turns = parent:NumSlider( "Turns", nil, 1, 50, 0 )
turns:SetValue( data.turns )
turns.OnValueChanged = function( _, v ) data.turns = math.floor( v ) changed() end
end,
} )
end )
-- and wherever the addon notices a full turn (server):
GAMEMODE:QuestEvent( ply, "spun" )
Register on both realms. Events return true when they changed the progress; built-in events are
npc_killed( npc, npcName ) and think (twice a second). Optional: Waypoint( data ) -> pos, radius
marks a spot on the player's screen. A task type's options and a player's progress are stored as
JSON, so a new type needs no tables. A task type that errors is logged once and skipped, never
breaking the rest.