Skip to content

Creative space-platform travel testing mode: indestructible wall, self-fueling thruster, asteroid spawning rate#58

Merged
jodli merged 4 commits into
masterfrom
creative-space-platform-travel-testing-mode
Jun 28, 2026
Merged

Creative space-platform travel testing mode: indestructible wall, self-fueling thruster, asteroid spawning rate#58
jodli merged 4 commits into
masterfrom
creative-space-platform-travel-testing-mode

Conversation

@jodli

@jodli jodli commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Artifacts | Task deep link | PR Walkthrough (alpha)

What problems was I solving

This implements the Creative space-platform travel testing story (US-2.3): as a creative-mode player, I want to test space platforms in flight without managing thruster fuel or losing the platform to asteroid damage, so I can prototype platform layouts and interplanetary routes freely.

In vanilla Space Age, two things make in-transit platform testing tedious:

  • Platforms only move while their thrusters are continuously fed both thruster-fuel and thruster-oxidizer — a whole production chain just to keep something moving while you iterate on a layout.
  • Asteroids damage every platform entity and tile equally (including the hub), so a route test can be interrupted by losing tiles or entities.

There was no built-in way to switch either off. After shipping, a creative player can place a self-fueling thruster to travel with no fuel chain, protect builds with an indestructible wall, and dial asteroid spawning down to zero — all opt-in, with vanilla behavior unchanged when not enabled, and all Space-Age-specific behavior absent/no-op on vanilla.

What user-facing changes did I ship

  • Creative wall — an indestructible red wall. Enemies still target and attack it (and asteroids hit it), but it instantly heals to full and can never be destroyed. Works on any surface, including space platforms; enabled by the normal Creative tools' recipe sweep (not Space-Age-gated).
  • Creative thruster (Space Age only) — a thruster that refuels itself every tick, keeping a platform travelling at vanilla speed with no fuel or oxidizer chain to supply. Marked by a red item icon.
  • Asteroid spawning rate input (Space Age only) — a numeric field in the Game Settings cheats: a global multiplier for how often asteroids spawn. Default 1 (vanilla); set 0 to stop asteroids entirely. Applies game-wide, not per surface.

How I implemented it

Each feature is a thin vertical slice (data prototype + runtime + headless behavior test) reusing the mod's existing creative-entity conventions. See the PR Walkthrough for an interactive top-to-bottom tour with inline diffs.

Phase 1 — Indestructible creative wall (ungated)

  • prototypes/entity.lua — clone base stone-wall, keep destructible = true, bump max_health to 1,000,000 as defense-in-depth, and recursively tint every non-shadow sprite layer red.
  • scripts/events.lua — the mod's single on_entity_damaged handler heals the wall to full on every hit. destructible = false was rejected because it removes the entity from the targeting system entirely.
  • control.lua — register on_entity_damaged with a name event filter and exclude it from the generic filterless loop so it isn't re-registered without filters.
  • prototypes/item.lua / recipe.lua — hidden red item (flags = { "spawnable" }) and zero-ingredient disabled recipe auto-enabled by the existing creative_tools_recipes sweep.

Phase 2 — Self-fueling creative thruster (Space Age only)

  • scripts/creative-thruster.lua (new) — per-tick loop that tops fuel + oxidizer back to capacity (1000 each) via insert_fluid, following the super_boiler convention (storage list, tick(), backwards iteration with self-cleaning of invalid entries).
  • data-final-fixes.lua — clone the vanilla thruster in data-final-fixes (so the base prototype is guaranteed to exist), keeping the vanilla performance curve. The placed thruster keeps vanilla graphics; the creative variant is marked only by its red item icon.
  • scripts/global-util.lua — init storage.creative_mode.creative_thruster and register placed thrusters into it.
  • scripts/events.lua calls creative_thruster.tick(); control.lua requires the module; .luacheckrc whitelists its global. Item + recipe are guarded by if mods["space-age"].

Phase 3 — Asteroid spawning rate (global Game-Settings input)

  • scripts/cheats.lua — a numeric cheat modeled on game_speed that reads/writes game.map_settings.asteroids.spawning_rate, clamps to a non-negative range, and is gated to script.feature_flags["space_travel"]. Essentially free: no on_tick, no per-entity scanning, just a persisted setting write.
  • scripts/gui-menu-cheats.lua — a numeric_apply row next to game_speed.
  • defines.lua (name constants) and locale/en/base.cfg (captions, tooltip, messages, plus entity/item strings for the wall and thruster).

Deviations from the plan

No formal *plan*.md exists for this task — the planning artifact is the structure outline (04-structure-outline-platform-travel.md), which was itself reworked twice during implementation and documents its own resolved decisions. Comparing the final code against that outline:

Implemented as planned

  • Phase 1 creative wall: four-part definition, heal-on-damage via name-filtered on_entity_damaged, red tint, destructible = false explicitly rejected, ungated/available on vanilla.
  • Phase 2 thruster: super_boiler-style storage list + tick() self-cleaning loop, Space-Age-guarded item/recipe, red item icon only.
  • Phase 3 asteroid rate: numeric numeric_apply cheat over game.map_settings.asteroids.spawning_rate in Game Settings, gated to space_travel, no runtime handler or stored state.

Deviations/surprises

  • Thruster prototype lives in data-final-fixes.lua, not prototypes/entity.lua. The outline placed the if mods["space-age"] clone in prototypes/entity.lua; the implementation moved it to data-final-fixes so the vanilla thruster prototype is guaranteed to exist before cloning.
  • Refill mechanism differs. The outline's tick() read entity.fluidbox.get_filter(i) and assigned fluidbox[i] = {...}. The shipped code uses a hardcoded { fuel, oxidizer } table and insert_fluid (the thruster exposes no writable fluidbox property).
  • Thruster entity flags were set explicitly (placeable-neutral, placeable-player, player-creation, not-rotatable) and fast_replaceable_group cleared, rather than reusing the vanilla flags as the outline implied.

Additions not in plan

  • .luacheckrc gained a creative_thruster global whitelist entry (required by luacheck for the new module).

Items planned but not implemented (intentionally)

  • The Phase-3 per-surface asteroid-protection on_entity_damaged heal / impact damage-type filter was dropped. Playtesting showed asteroid survival is already covered by creative walls + "kill all enemies", so the asteroid spawning-rate setting replaced it. The wall heal is now the only on_entity_damaged use; the "Phase 3 will OR an impact damage-type filter" comments in control.lua/events.lua are historical.

How to verify it

git fetch origin
git worktree add ../creativemod-pr58 creative-space-platform-travel-testing-mode
cd ../creativemod-pr58
uv run verify.py all

Manual Testing

  • Creative wall: enable Creative Mode, place a creative wall (red), confirm biters target and attack it but it is never destroyed; confirm asteroids on a platform likewise can't destroy it.
  • Creative thruster (Space Age): create a platform, place the creative thruster, set a route schedule, confirm the platform travels toward its destination at vanilla speed with no fuel/oxidizer supplied.
  • Asteroid spawning rate (Space Age): Cheats → Game Settings, set "Asteroid spawning rate" to 0, fly a route (use "kill all enemies" once to clear any in flight), confirm no new asteroids appear; set it back to 1 and confirm they resume.
  • Vanilla (no Space Age): confirm the creative wall is craftable, and that the creative thruster recipe and the asteroid-rate row are both absent.

Automated Tests

uv run verify.py static    # luacheck + stylua
uv run verify.py load      # data + control load gate
uv run verify.py behavior  # creative_wall_indestructible, creative_thruster_placed,
                           # creative_thruster_refuels, asteroid_spawning_rate_set_zero/_restore

Description for the changelog

Add three opt-in creative space-platform travel aids: an indestructible creative wall, a self-fueling creative thruster (Space Age), and a global asteroid spawning-rate input (Space Age).

jodli added 4 commits June 28, 2026 23:04
The creative wall stays a normal destructible target (biters path to it,
asteroids hit it) but is healed to full on every hit via a name-filtered
on_entity_damaged handler, so it can never be destroyed. max_health is bumped
high as defense-in-depth. The wall and its item icon are tinted red to match
the mod's other creative entities. Not Space-Age gated.

The on_entity_damaged handler is registered with event filters and excluded
from the generic filterless event loop; Phase 3 (asteroid protection) will
extend this same handler rather than registering a second one.
A clone of the vanilla thruster that keeps the normal performance curve but has
its fuel + oxidizer topped off every tick by script, so a space platform travels
at vanilla speed with no fuel chain to supply. Defined only when Space Age is
present (its fluids are space-age-only); the entity is cloned in data-final-fixes
where the vanilla thruster prototype is guaranteed to exist.

The body and item icon are tinted red to match the mod's other creative
(spawn/source) entities; exhaust flames/glow are left natural.
…on only

The thruster's animated body doesn't take a flat tint cleanly (only the
integration patch picked it up, leaving a half-red look). The creative variant
is now distinguished solely by its red item icon.
Add an 'Asteroid spawning rate' numeric input to the Game Settings cheats
submenu, exposing game.map_settings.asteroids.spawning_rate directly (a float
multiplier, default 1; set 0 to stop all asteroid spawning). Modeled on the
existing game_speed numeric cheat and clamped to >= 0. Applies game-wide with
zero runtime cost - no event handler, no per-tick work. Gated to Space Age via
get_player_can_access_function, so the row is hidden on vanilla.

Replaces the originally planned per-surface on_entity_damaged asteroid-protection
toggle, which playtesting showed was redundant (creative walls block asteroids
fully; remove/kill all enemies clear them).
@jodli jodli merged commit d4b39ab into master Jun 28, 2026
2 checks passed
@jodli jodli deleted the creative-space-platform-travel-testing-mode branch June 28, 2026 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant