# Level editor – objects, scripts, paths, cameras (`editor.tools.objects`) Plugin `ObjectsEditorPlugin` (phase 3, discovered automatically). Parameter decoding and the strat VM: `notes/editor-object-schemas.md`. Tests: `ObjectToolsTest` (needs `-Dllamamod.cd`), screenshot tour `ObjectsTour` (test classes). ![camera zone](img/editor/obj_camera_zone.jpg) ## What it adds | Part | Content | |---|---| | **Objects panel** (left dock) | every placeable type of the base with rendered thumbnail, category filter, search (name + schema summary), favourites (right-click, ★ filter), "parameters decoded" marker; drag into the viewport or click → Place tool. Quick setups: Player start, Checkpoint, Exit, Secret, Coin line, Coin arc | | **Place tool** (P) | click = place on the collision floor under the cursor (snap to floor, grid snap), yaw = camera direction / facing the camera / 0° / type default; click + drag an object = move along the ground (its waypoints move along); drag the yellow knob = rotate (angle snap; a checkpoint's respawn node turns with it). Modes for the setups | | Setups | **Player start** moves the existing player (exactly one) or places a Llama with its chain (camera node 8 cells behind). **Checkpoint** = CheckPointPost + respawn node 0.4 ahead (floor height). **Exit** = LevelDoor in the cell centre + 1×1 FLOOR brush with collision material 16; target picked in the options bar (world/chapter names, "world finished 7,7,7"). **Secret** = Secret with a 3×3 box (2 nodes) | | **Coin tool** (O) | Line: two clicks, coins every *spacing*; Arc: centre + point on the circle, *count* coins over *arc°*; Coin/Coin5, height above floor, follow floor; live preview | | **Waypoint tool** (N) | select an object (or node): click = add node after the selected node / at the chain end (creates the chain if missing), Ctrl+click = insert before, drag = move (keeps height above floor), Backspace/Del = remove and relink; Reverse; orient new nodes along the path | | **Zones & triggers** (J) | handles: 4 corners of box zones (node pairs: Secret, CameraSide/Lift, ObjectDontDropInBox, FallOffNoHurt …), radius knob for RADIUS parameters (CutSceneTrigger, guards, CameraFocusPoint) | | Inspector "Object parameters" | named, typed fields (check boxes, choices, counts, seconds, distances) with doc/range/original-value tooltips, raw hex, inline validation, "Reset to defaults"; LevelDoor target picker with "Leads to: …"; waypoint row (role, node count, Create/Edit path, Unlink, Delete path, Link… to an existing chain, Look through). Undo-aware refresh | | Inspector "Waypoint chain" | node i of n, owner and role, ◀ ▶, select object, delete node, look through | | Viewport layers | *Path directions* (arrows, dashed wrap segment for patrol paths, node yaw ticks), *Zone areas & trigger radii* (boxes for all zone objects, fills for the selection), *Camera frusta* (CameraSide/Lift: computed game camera from height/distance/node yaw; cut-scene cameras: a frustum per node from node yaw/pitch) | | Look through camera (Ctrl+Shift+L, View → Camera) | viewport takes the camera of the selected node / cut-scene camera / camera zone; while active, flying writes back node position + yaw/pitch, or for CameraSide the height/distance params and node yaw (one undo step per pilot session) | | Problems (Level → Check, Build) | chains not stored contiguously (error, Tools → Repair waypoint chains), param count, out-of-range values, missing required waypoints / odd box pairs, types whose originals always have a chain, LevelDoor without material-16 floor in its cell, impossible exit targets and (7,7,7) in TestLevel, far respawn nodes, several player starts | | Copy / paste between levels | Edit → Copy objects (Ctrl+Shift+C) puts JSON (objects + chains + brushes, relative to their centre) on the system clipboard; Paste objects (Ctrl+Shift+V) at the view centre in any level – types are matched by name/variant in the target base (unknown types skipped with a message) | | Prefabs | Tools → Save selection as prefab… / asset browser tab "Prefabs": `/editor/prefabs/.json` + thumbnail; double-click = place at view centre, drag = place under the cursor | | Delete | `edit.delete` is re-registered: a selection of waypoints is removed with the chain relinked | Engine fact used throughout: the MAP loader links waypoint record i to i+1 when "next" ≠ 0, so a chain must be contiguous in the node list (`ChainOps` inserts at the right index and the check / repair action guard it). ## Files `ObjectsEditorPlugin` (registration, actions, waypoint inspector), `Schemas`/`ParamSchema`/ `TypeStats` (+ `type-stats.tsv`), `ParamsSection`, `ObjectChecks`, `PlaceTool`, `Setups`, `ExitTarget`, `CoinTool`, `PathTool`, `ChainOps`, `ZoneTool`, `ObjectOverlays`, `CameraView` (zone camera + pilot), `ObjectPalette`, `ObjectClipboard`, `Prefabs`, `LinkDialog`, `Ground` (floor finder on the collision polygons of tiles + brush preview tiles), `Session`, `Roles`, `Draw` (all game↔render conversions in one place). Shared change: `editor.ui.view.SceneRenderer.brushOutput()` getter (brush preview tiles for the floor finder). Nothing else outside the package. ## Verified UI (Xvfb, `ObjectsTour`): `img/editor/obj_camera_zone.jpg`, `obj_cutscene_frusta.jpg`, `obj_pilot.jpg`, `obj_exit_inspector.jpg`, `obj_place.jpg`, `obj_zone_handles.jpg`, `obj_trigger_radius.jpg`, `obj_problems.jpg`, `obj_newlevel_path.jpg`, `obj_newlevel_camera.jpg`, `obj_coin_arc.jpg`, `obj_newlevel_saved.jpg` (no problems), `obj_beetle_path.jpg`. In game (apptest, display :7, new level on base t1l1m002 as TestLevel chapter 2; island of brushes, coin line + coin arc, checkpoint, exit to Village chapter 2, CameraSide zone at the exit, JumpingBeetleBlue with a 4-node patrol path, CityGuard with a square path): * level loads, coins of line and arc stand where placed (`obj_game_coins.jpg`); * walking through the checkpoint shows "KONTROLLPUNKT"; falling into the sea respawns the llama at the post (`obj_game_checkpoint.jpg`); * entering the camera zone switches to the zone camera (high view, `obj_game_camera_zone.jpg`); * stepping on the exit floor shows the tally "TestLevel Kapitel 2"; Enter → "Dorf Kapitel 2" loads = the chosen chapter (`obj_game_exit.jpg`); * the beetle jumps back and forth along its path (`obj_game_patrol.jpg`). ## Known limits * Parameters are decoded for ~35 common types (confidence per type in the schema doc); the rest shows raw values with the statistics of the originals. * The CityGuard (village-2 base) placed in the open did not show up in game – it probably waits for a scene/event; the patrol test was done with JumpingBeetleBlue. * In 8 original levels the exit check reports "no material 16 in the door cell": the exit floor polygons decode one cell off the door (e.g. village door cell 42,49, floor polygon at 43,48) – original tile collision positions vs. strat positions are not fully understood yet; brush-built exits are correct (verified in game). Snap-to-floor on original levels uses the same polygons. * Zone heights are estimated (+1.2 above the lower node); the engine tests x/z only. * Camera preview of CameraSide assumes the player in the box centre and default distance 2 / height 1 when the parameters are 0; the game's FOV is approximated by 60°. * Look-through of the village cut-scene camera's first node looks into a wall (its first node may be a fly-in start); not compared with the game. * Pasting into another base matches types by name; object models/code are not imported (that is the job of `editor.tools.catalog`).