# Travel between worlds (travel.worlds) ## What it is for `travel.worlds` lets one game hold several worlds (planets, islands, dimensions) and the trip between them. A **destination** is a document of the `destinations` collection: a scene of the engine with an entry, a name, a cost in items, a travel time and an opening condition. A **shuttle** is any entity carrying the component `travel.shuttle`; using it opens the travel screen. A trip takes the cost, lasts its seconds while the game goes on, then sends the player to the destination scene through the scenes of `game.engine`. Each world keeps its own state: what stood in the world left is set aside and put back when the player returns. ## Turn it on ```text gripforge_gamekit_install { project_id: "gkp_…", id: "travel.worlds" } gripforge_gamekit_configure { project_id: "gkp_…", id: "travel.worlds", config: { "carry": ["companion"], "reach": 6 } } ``` It requires `game.engine`. Declare the scenes (with their entries) in the `scenes` collection, then the destinations: ```json { "destinations": [ { "id": "earth", "name": "Earth", "scene": "earth" }, { "id": "moon", "name": "Moon", "scene": "moon", "seconds": 0.1, "cost": [{ "item": "fuel", "count": 2 }] }, { "id": "mars", "name": "Mars", "scene": "mars", "unlocked": false } ] } ``` ## First example With `earth` as the start scene, `moon` reachable and `mars` locked, calling the service `travel.worlds`: ```text travel("mars") -> { ok: false, reason: "locked" } travel("moon") -> { ok: true } travel("earth") -> { ok: false, reason: "busy" } a trip is under way (the trip ends) -> current() is "moon"; a crate left on earth is parked (back on earth) -> the crate is there again, visited("moon") is true ``` The parked entities are part of the saved game. ## Settings and defaults | Setting | Type | Default | Meaning | |---|---|---|---| | `shuttleLabel` | string | `Board {name}` | Prompt of a shuttle; `{name}` is its label. | | `shuttleName` | string | `Shuttle` | Label of a shuttle that has none. | | `reach` | number | `4` | The screen opened from a shuttle closes when the player walks further than this, metres (1 to 30). | | `scoped` | list of strings | `["world.stages", "world.biomes", "life.ecosystem", "resource.nodes"]` | Capabilities whose service keeps a state per world (`scope(id)`); told the live world on arrival, in this order. | | `park` | boolean | `true` | Everything that stood in the world left (but the player, the engine instances and the carried tags) is set aside and put back on return. Off: it stays where it is in every world. | | `carry` | list of strings | `[]` | Tags of entities that travel with the player (a companion, a vehicle); never parked. | A destination has `id`, `name`, `scene` (required), and `description`, `entry` (default: the first entry of the scene), `world` (default: its own id; two destinations with the same `world` are two landing sites of one world, with one state and one park), `cost` (a list of `{ item, count }`, taken when the trip starts), `seconds` (default 0: at once), `unlocked` (`false`: locked until `unlock_destination`), `opensWhen` (a trigger condition such as `{ "type": "stage_reached", "stage": "orbit" }`; the destination stays locked until it holds, then stays open) and `order` (position in the screen). ## Service methods Service `travel.worlds`: - `destinations()`: each destination with `open`, `current`, `affordable`, `missing`, `visited` and `world`. - `current()` and `world()`: the destination and the world the player is in. - `travel(id, opts?)`: answers `{ ok: true }` or `{ ok: false, reason, missing? }`; passing `{ free: true }` skips the cost. - `trip()`: `{ to, left, total }` while a trip is under way, else null. - `unlock(id)` and `visited(id)`. - `open(shuttle?)`, `close()`, `isOpen()`, `shuttle()`: the travel screen. - `placeShuttle(at, yaw?, label?)`: place a shuttle entity from a script and answer its id. ## Verbs, variables, events, hooks - Actions `travel_to { destination }` (no shuttle, no cost; the travel time still applies) and `unlock_destination { destination }`. - Conditions `in_world { destination }` and `world_visited { destination }`. - Variables: `travel.world`, `travel.trip`, `travel.left`, `travel.open`. - Events: `travel.departed { from, to, seconds }`, `travel.arrived { from, to, first }` (also at the start of the game, and when a script loads the scene of another destination), `travel.failed { to, reason }`, `travel.unlocked { destination }`, `travel.opened { shuttle }`, `travel.closed`. - Failure reasons: `unknown`, `locked`, `cost`, `here`, `busy`, `scene`, or the reason of the tap that cancelled it (default `refused`). - Hook `travel.depart` `{ from, to, seconds, free }`: mutable `seconds` and `free`, cancellable. Asked after the checks and before the cost is checked and taken (a faster ship, a free first trip, a storm that grounds the shuttle). - Hook `travel.unlock` `{ destination, by }` (`by` is `call` or `condition`): cancellable; it stays locked. - Hook `travel.open` `{ shuttle }`: cancellable; the screen stays closed and `travel.failed` carries an empty `to` and the reason (default `closed`). ```json { "id": "free_first_trip", "hook": "travel.depart", "match": { "to": "moon" }, "set": { "free": true } } ``` ## Hooks and modding `shuttleLabel`, `shuttleName`, `reach`, `carry` and the `destinations` collection are moddable: a mod adds a destination as a document, or taps the three hooks. ## Engines The rules run on the web and in the native player. The travel screen is an `ui.webui` fragment shared by the page and the engines; the arrival uses the scenes of `game.engine`. ## When it does not do what you expect - `travel` answers `scene`: the engine could not enter the scene of the destination; check the `scenes` collection and the `entry`. - `cost`: the bag lacks items; `missing` lists them. - `here`: the player is already in that world. - A destination never opens: its `opensWhen` does not hold yet. It is checked when the screen opens, on every arrival and when a trip is asked. - Things reappear in the wrong world: the entity carries a tag listed in `carry`, or `park` is off. ## Limits One trip at a time. Per-world state is kept for the `scoped` capabilities and for what parking sets aside. ## Versions Kit version 1.1.1; first release in 1.0.0; the hooks and the moddable settings and destinations in 1.1.0.