← Back to Index

Terminal Micro Engine

Abyssal Run Template – Advanced Features vs Basic Horror Template

This guide explains the new systems and improvements introduced in the Abyssal Run template compared to the basic horror template (Derelict Outpost A-13). It is meant to help you build more complex projects with the same JSON-based engine.

You do not need to write JavaScript: you only edit the GAME_DATA object in game_data.js.


1. Two Templates, Same Engine

Both use the same general structure:

{
  "title": "...",
  "startRoom": "...",
  "viewport": { ... },
  "flags": { ... },
  "rooms": { ... },
  "events": [ ... ]
}

This guide focuses on what Abyssal Run adds or changes, not on the basics (which are covered in the previous general user guide). :contentReference[oaicite:2]{index=2}


2. Viewport: from Single Image to Multi-Camera + Map

2.1 Old way (Derelict Outpost)

In the basic template, the viewport uses a single image or tileset:

"viewport": {
  "image": "assets/viewport_idle.png",
  "frameWidth": 160,
  "frameHeight": 90,
  "fps": 6,
  "mode": "tileset"
}

2.2 New way (Abyssal Run): images[] + index

In Abyssal Run, the viewport is a list of images with a numeric index:

"viewport": {
  "images": [
    "assets/map.png",
    "assets/cam_shallow.png",
    "assets/cam_rockpass.png",
    "assets/cam_trench.png",
    "assets/cam_kelp.png",
    "assets/cam_ruins.png",
    "assets/cam_trenchside.png",
    "assets/cam_signal.png"
  ],
  "current": 0,
  "frameWidth": 350,
  "frameHeight": 350,
  "fps": 0,
  "mode": "still"
}

In this template, the images are used like this:

2.3 Changing image with setViewport index

Instead of changing the viewport by passing a full URL every time, the template uses indexes into the images array:

"cam": {
  "text": "External camera activated.",
  "actions": [
    { "type": "flag", "set": { "cam_active": true } },
    { "type": "flag", "add": { "battery": -10 } },
    { "type": "setViewport", "index": 1 }
  ]
}

Here:

2.4 How to load your own images

  1. Put your PNGs in the assets/ folder (for example assets/cam_lab.png).
  2. In viewport.images, replace or add URLs:
    "images": [
      "assets/my_map.png",
      "assets/cam_lab.png",
      "assets/cam_hangar.png"
    ]
    
  3. In room actions, use setViewport with the correct index:
    { "type": "setViewport", "index": 2 }
  4. Remember: indexes start at 0.

This system makes it easy to have many cameras and maps without repeating long image URLs everywhere.


3. New Global Flags: Battery, Pressure, Blackbox, Camera

Compared to the simple power_online / creature_alert flags in the basic template, Abyssal Run introduces a more complex “submarine status” system in flags: :contentReference[oaicite:5]{index=5}

"flags": {
  "pressure_alert": 0,
  "battery": 100,
  "has_blackbox": false,
  "cam_active": false
}

Local room actions add or remove values using type: "flag". For example, many commands consume battery:

"sonar ping": {
  "text": "Echo returns clean and stable.",
  "actions": [
    { "type": "flag", "add": { "battery": -5 } }
  ]
}

In deeper or unstable sectors, some actions also increase pressure:

"sonar ping": {
  "text": "Delayed echo from deep void.",
  "actions": [
    { "type": "flag", "add": { "pressure_alert": 1 } },
    { "type": "flag", "add": { "battery": -5 } }
  ]
}

The “camera” action sets cam_active to true and consumes more battery:

"cam": {
  "text": "Camera engaged.",
  "actions": [
    { "type": "flag", "add": { "battery": -10 } },
    { "type": "flag", "set": { "cam_active": true } },
    { "type": "setViewport", "index": 2 }
  ]
}

You can use this pattern in your games: treat numeric flags as resources or meters (oxygen, sanity, temperature, etc.).


4. Global Status Commands (briefing / status / environment / map)

In the basic horror template, most events are local to rooms or simple onCommand/timer events. Abyssal Run introduces a set of global commands that always work, no matter which room you are in: :contentReference[oaicite:6]{index=6}

4.1 Example: status command

{
  "trigger": "onCommand",
  "command": "status",
  "actions": [
    { "type": "log", "text": "STATUS:" },
    { "type": "log", "text": "Battery: drains with sonar, camera and adjustments." },
    { "type": "log", "text": "Pressure: increases in deep or unstable sectors." },
    { "type": "log", "text": "Blackbox: retrieve at signal source sector." }
  ]
}

This event does not directly read the numeric values, but it explains to the player how the system behaves. You could also add more advanced logs if you want.

4.2 Example: map command

{
  "trigger": "onCommand",
  "command": "map",
  "actions": [
    { "type": "log", "text": "NAVIGATION MAP:" },
    { "type": "log", "text": "        [06]" },
    { "type": "log", "text": "         │" },
    { "type": "log", "text": "        [07]" },
    ...
  ]
}

This shows a simple ASCII map in the terminal, helping the player understand the structure of rooms/sectors.

4.3 Example: cam command (already active)

There is also a global event for cam that triggers only if the camera is already active:

{
  "trigger": "onCommand",
  "command": "cam",
  "conditions": [ "flags.cam_active === true" ],
  "actions": [
    { "type": "warn", "text": "Camera already active." }
  ]
}

This is a good pattern: use onCommand + conditions to create global feedback for your “systems” flags.


5. Endings and Mission Flow

The basic horror template already showed endings via: { "type": "end", "text": "..." } in actions and events. :contentReference[oaicite:7]{index=7}

Abyssal Run expands this with a mission objective (blackbox) and multiple possible endings:

5.1 Retrieving the blackbox

In the sector_signal_07 room, the player can retrieve the blackbox:

"retrieve object": {
  "conditions": [ "flags.has_blackbox === false" ],
  "text": "Blackbox secured.",
  "actions": [
    { "type": "flag", "set": { "has_blackbox": true } },
    { "type": "flag", "add": { "battery": -5 } }
  ]
}

This sets has_blackbox to true and slightly reduces battery.

5.2 Surface (success ending)

The success ending is triggered with a global surface command, but only if:

{
  "trigger": "onCommand",
  "command": "surface",
  "conditions": [
    "flags.has_blackbox === true",
    "state.currentRoomId === 'sector_shallow_01'"
  ],
  "actions": [
    { "type": "log", "text": "Surface ascent initiated." },
    { "type": "end", "text": "ENDING: RECOVERY COMPLETE" }
  ]
}

This pattern is very useful: you can require both a flag and a specific room to unlock the ending.

5.3 Timer-based failure endings

Two timers watch the pressure_alert and battery flags:

{
  "trigger": "timer",
  "delay": 24,
  "repeat": true,
  "conditions": [ "flags.pressure_alert >= 5" ],
  "actions": [
    { "type": "err", "text": "Critical hull stress detected." },
    { "type": "end", "text": "ENDING: HULL IMPLOSION" }
  ]
}
{
  "trigger": "timer",
  "delay": 30,
  "repeat": true,
  "conditions": [ "flags.battery <= 0" ],
  "actions": [
    { "type": "err", "text": "Battery depleted. Systems shutting down." },
    { "type": "end", "text": "ENDING: POWER FAILURE" }
  ]
}

You can reuse this technique for any kind of “slow failure” system: sanity, infection, fuel, etc.

5.4 Secret ending (no disturbance)

There is also a one-shot timer that checks if pressure_alert remains 0 for a long time:

{
  "trigger": "timer",
  "delay": 180,
  "repeat": false,
  "conditions": [ "flags.pressure_alert === 0" ],
  "actions": [
    { "type": "log", "text": "Silent drift detected. Water conditions unusually calm." },
    { "type": "end", "text": "SECRET ENDING: NO DISTURBANCE DETECTED" }
  ]
}

This shows how you can reward “careful” play with a hidden ending.


6. How to Build Your Own Complex Project

Here is a simple workflow to use Abyssal Run as a base for your own complex game:

  1. Start from Abyssal Run JSON.
    Rename the title, change room names and descriptions, but keep the structure (flags, events) as a reference.
  2. Define your global systems as flags.
    For example: oxygen, sanity, temperature, infection. Initialize them in the flags object.
  3. Use local room actions to modify these flags.
    Consume resources for powerful actions, increase danger in risky areas, etc. Use type: "flag" with add and set.
  4. Create a global status command.
    Copy the idea of the status event and adjust the text to describe your systems to the player.
  5. Use a viewport.images[] list.
    Decide an index for each area/camera. Keep index 0 for a global map if you like. Use setViewport with index in room actions.
  6. Add timer events for failure/success.
    Watch your main flags with timer events. If a flag is too high or too low for too long, trigger an ending.
  7. Add at least one secret ending.
    Use a timer with repeat: false and a special condition (for example, “never triggered alarm”, or “never used weapon”).

7. Summary of Improvements in Abyssal Run

You can mix and match these patterns to design your own advanced games while still working only inside the GAME_DATA JSON file.