Tutorial 2 - Claim a quest room

You don’t always want the player to build a room - sometimes a quest, prefab, or zone mod just needs the engine to treat an existing area as a real room: for room detection, lighting, “are you inside the vault?” checks, and the map.

In this tutorial you’ll claim a hand-picked area as a room when a quest starts, and release it when the quest ends - server-side, persisted, and MP-synced - using RCSF.Rooms. No walls, no UI.

The idea

RCSF.Rooms.assign(rectOrRects, name, opts) creates a real IsoRoom over any area and returns a descriptor you keep. RCSF.Rooms.unassign(...) tears it down. Both are server-authoritative - call them from server-side quest logic.

Step 1 - A quest module (shared)

Create media/lua/shared/VaultQuest/Quest.lua. We’ll keep the active assignment in ModData so it survives a relog mid-quest.

media/lua/shared/VaultQuest/Quest.lua
 1local RCSF = require("RCStructureFramework")
 2
 3local Quest = {}
 4Quest.ROOM_NAME = "VaultQuestRoom"
 5Quest.AREA      = { x = 10600, y = 9420, z = 0, w = 6, h = 5 }   -- your chosen spot
 6
 7---Begin the quest: claim the vault area as a real room. Server/SP only.
 8function Quest.begin()
 9    if isClient() then return end           -- server-authoritative
10    if Quest.isActive() then return end
11
12    local assignment = RCSF.Rooms.assign(Quest.AREA, Quest.ROOM_NAME, { id = "vault_quest" })
13    if assignment then
14        ModData.getOrCreate("VaultQuest").assignment = assignment
15        ModData.transmit("VaultQuest")
16        print("[VaultQuest] vault room claimed")
17    end
18end
19
20---End the quest: release the room. Server/SP only.
21function Quest.finish()
22    if isClient() then return end
23    local data = ModData.getOrCreate("VaultQuest")
24    if not data.assignment then return end
25    RCSF.Rooms.unassign(data.assignment)     -- the descriptor carries id + rects
26    data.assignment = nil
27    ModData.transmit("VaultQuest")
28    print("[VaultQuest] vault room released")
29end
30
31function Quest.isActive()
32    return ModData.getOrCreate("VaultQuest").assignment ~= nil
33end
34
35return Quest

Notice how little there is: assign returns a descriptor, you stash it, and pass it straight back to unassign. The framework handles room creation, persistence, MP sync, and reconstituting the room on a later session.

Step 2 - Trigger it

Hook the quest to whatever should start it - reading a note, entering a trigger zone, a command. Here’s a debug command and a server hook:

media/lua/server/VaultQuest/Triggers.lua
 1local Quest = require("VaultQuest/Quest")
 2
 3-- Example: start the quest the first time the server boots a fresh world.
 4Events.OnServerStarted.Add(function()
 5    if not Quest.isActive() then Quest.begin() end
 6end)
 7
 8-- Example: react to entry. OnRCSFRoomAssigned fires when the room is claimed.
 9Events.OnRCSFRoomAssigned.Add(function(info)
10    if info.id == "vault_quest" then
11        print("[VaultQuest] room " .. info.name .. " is live (" .. #info.rects .. " rect)")
12    end
13end)

Server-authoritative spawners register on OnServerStarted

On a dedicated server, OnGameStart never fires - use OnServerStarted (or OnServerStarted

  • an SP fallback) for anything that must run once on the authoritative side.

Step 3 - Verify

  1. Start a world with the mod enabled (the OnServerStarted hook claims the room).

  2. Walk into the area: open the debug room-info overlay, or place a light switch inside after dark - it lights the room, proving the engine sees a real IsoRoom.

  3. Call Quest.finish() (e.g. from a debug option) and confirm the room is gone.

  4. Relog: the room is still there until you finish the quest - it persisted.

Multi-rect vaults

A bigger vault can be several rectangles; edge-adjacent ones become one building:

Quest.AREA = {
    { x = 10600, y = 9420, z = 0, w = 6, h = 5 },
    { x = 10606, y = 9420, z = 0, w = 4, h = 5 },   -- adjacent → same building
}

Pass it the same way; assign/unassign handle the list.

Next