-
Notifications
You must be signed in to change notification settings - Fork 2
Tutorial 08 Quest
Goal. Build a multi-map fetch quest: an NPC asks for an item, private state tracks progress across saves, and completion plays a scripted cutscene.
Prerequisites. Tutorials 06–07; Concepts: Save Model; Reference: Script Commands.
Files created.
mods/tutorial_08_quest/
├── manifest.json
└── main.lua
-
Quest state in
mod.save, not global flags. Flags are a shared namespace every mod and the story can see;mod.saveis yours alone and survives saves. Script rows reach it throughset_fieldwith themod:prefix:-- stage 0 = not started, 1 = asked, 2 = done -
The quest giver. A talk script in Pallet Town that branches on stage — reading state via a check the script sets up:
return function(mod) mod.content.map_scripts:register("PALLET_TOWN", { talk = { TEXT_TUT8_GIVER = { { "check_flag", "TUT8_DONE" }, { "jump_if_true", "thanks" }, { "check_item", "NUGGET" }, { "jump_if_true", "complete" }, { "show_text", "Fetch me a NUGGET\nfrom MODROUTE!" }, { "jump", "end" }, { "label", "complete" }, { "take_item", "NUGGET", 1 }, { "set_flag", "TUT8_DONE" }, { "jump", "cutscene" }, { "label", "thanks" }, { "show_text", "Thanks again!" }, { "jump", "end" }, { "label", "cutscene" }, { "play_music", "Music_Surfing", { keep = false } }, { "emote", "player", "happy", 40 }, { "walk_npc", "player", { "down", "down" } }, { "fade", "out", 30 }, { "warp", "PALLET_TOWN", 10, 8, "down" }, { "fade", "in", 30 }, { "show_text", "You did it!\nQuest complete!" }, }, }, }) mod.content.maps:patch("PALLET_TOWN", { objects = { __append = { { index = 92, x = 12, y = 8, sprite = "SPRITE_SCIENTIST", movement = "STAY", range = "NONE", text = "TEXT_TUT8_GIVER" }, } }, }) end
Outcome: the giver asks, acknowledges the fetched item, runs a cutscene in pure command rows — no raw Lua — and thanks you ever after. (The quest flag here is a story flag so the talk rows can branch on it; keep bulk private state in
mod.save.) -
The item on the far map. Hide a Nugget on tutorial 07's MODROUTE through the
fielddeep registry:mod.content.field:patch("hiddenItems", { MODROUTE = { { x = 4, y = 2, item = "NUGGET" } }, })
Outcome: pressing A on that cell finds the Nugget.
-
An
onStepnudge. A compose contribution can add a step trigger beside the map's own scripts:mod.content.map_scripts:register("MODROUTE", { onStep = function(game, ow, x, y) if x == 4 and y == 2 and not game.save.flags.TUT8_HINTED then game.save.flags.TUT8_HINTED = true end -- return true to consume the step (stop later handlers) end, })
The handler is
onStep(game, overworld, cellX, cellY); contributions chain with first-truthy-return-consumes semantics (src/script/MapScripts.lua). Outcome: stepping on the spot marks a hint flag once — and the map's ownonStep(if any) still runs, because compose contributions stack instead of replacing. -
A migration for the future. When v1.1 renames its state, old saves upgrade themselves:
mod.migrations:add("1.1.0", function(save) local bucket = save.modData[mod.id] if bucket and bucket.stage == nil then bucket.stage = 0 end end)
Outcome: a save written by mod 1.0.0 loads cleanly under 1.1.0 (Save Model).
Fresh game: giver asks → find the Nugget on MODROUTE → return → cutscene plays → subsequent talks thank you. Save and reload at each stage; the quest resumes where it stood. Disable the mod: Pallet Town and the flags' effects are gone, and the save loads clean.
-
Global flags for private state. Another mod's
TUT8_DONEcollides with yours; prefix flags with your mod id, or better, keep state inmod.saveand use flags only where script rows must branch. -
Blocking verbs in parallel scripts.
run_parallelscripts may not use foreground commands (show_text, ...) or move the player — the runner errors, attributed to your mod. -
Two cutscenes at once. Queued scripts are FIFO through
mod.world:queueScript; a secondqueueScriptwhile one runs returns an error rather than interleaving.
Next: Tutorial 09 — Custom Music.
Engine 1.0.0 · mod API 2 · repository · Discord
This project ships no ROM data. All game content is decoded on the player's machine from their own verified Pokemon Red ROM; mods ship recipes and original assets, never extracted content.
Start here
Concepts
Tutorials
- The ladder
- 01 Sprite and Text Tweak
- 02 Balance Patch
- 03 New Species
- 04 New Item and Ball
- 05 New Move
- 06 NPC and Dialogue
- 07 New Map
- 08 Quest
- 09 Custom Music
- 10 New Mechanic
- 11 Custom UI Screen
- 12 Mini Total Conversion
Reference
Guides
Playing