Artillery enemy with telegraphed AOE #46

Closed
opened 2026-08-15 11:16:21 +00:00 by metaheavens · 1 comment
Owner

Part of #40. Depends on the enemy-foundation ticket.

one that shot an aoe, pretty slow to arrive but really destructive if not reactive

The whole point is that it is survivable only by reacting, so the telegraph has to be unmistakable and the window generous.

Scope

  1. EnemyArtilleryComponent.tscn + .gd (capability_id = "artillery"), cycle per fire_cooldown (suggest 6 s):
    • Target: the fleet centroid at the moment of firing (Fleet.get_centroid()), within fire_range (suggest 900).
    • Telegraph (~1.8 s): a growing target ring drawn at the impact point in the enemy's colour, plus a countdown-style fill so the remaining time is readable. Reuse the ring idiom from GasBombController._draw_ring.
    • Shell: travels to the impact point at ~180 units/s (slow, visible), trailing like the gas bomb projectile.
    • Impact: AOE radius ~220, damage 3, applied via Ship.take_damage() to every player_ships node inside. Explosion visuals in the style of GasBombController._explode / ExplosionVFXBase.
    • Shield interaction: a shield charge absorbs the hit entirely, matching the existing all-or-nothing shield semantics (VesselShieldComponent.absorb_hit). Document this in the component header rather than inventing partial damage.
  2. Movement: stationary with a slow drift toward the fleet - it is a siege piece, not a chaser. Do not stack a pursuit component on it.
  3. ArtilleryEnemyDefinition.tres - enemy_id = "artillery", max_hp 8, speed ~60, a bulky hull, distinct glow colour.
  4. Register it in EnemyDefinitions so it is placeable from a planet setup.

Acceptance criteria

  • The telegraph is visible for the whole window before any damage lands.
  • A ship that leaves the ring before impact takes no damage; ships still inside take the full damage.
  • A shielded ship inside the blast survives, losing exactly one charge.
  • The impact point is fixed at fire time - it does not home onto the fleet after launch.
  • No type switch; all stats definition-driven.

Tests

tests/test_artillery_enemy.gd (bash tests/run_tests.sh artillery), plus a 720x1280 screenshot of the telegraph ring mid-countdown showing it reads clearly on both surface backgrounds.

Repo notes (read before starting)

  • Godot 4.7.1, portrait 720x1280, touch UI. Project dir: /storage/emulated/0/GodotProjects/SpaceshipTest.
  • After editing any project file, run touch on it. Android FUSE does not bump mtime under ~/storage/shared, and Godot's import cache will silently keep serving the old version, making a correct fix look like it did nothing.
  • Headless tests: bash tests/run_tests.sh <substring>; full suite with no argument. Tests are SceneTree scripts printing TEST_NAME: PASS / TEST_NAME: FAIL (reason) and calling quit(0|1) - copy the shape of tests/test_gas_bomber_cooldowns.gd.
  • Real screenshots: bash tests/screenshot.sh <res://Scene.tscn> <out.png> <frames> 720x1280. Use few frames (~10-20); the software rasterizer is slow. --headless renders nothing at all, so it cannot validate visuals.
  • Drawing goes through NeonDraw / NeonPiece; do not introduce a different visual idiom.
  • The repo deliberately has no type switches left (tickets #31-#35): behaviour comes from *Definition resources plus capability component scenes. Do not add if type == "..." branches.
  • There is no persistence layer (no FileAccess, no user:// anywhere outside this ticket's explicit scope). GameState is an in-memory autoload. Do not invent a save system.
  • Commit each ticket separately and run the full suite before pushing.
Part of #40. Depends on the enemy-foundation ticket. > one that shot an aoe, pretty slow to arrive but really destructive if not reactive The whole point is that it is survivable **only** by reacting, so the telegraph has to be unmistakable and the window generous. ### Scope 1. `EnemyArtilleryComponent.tscn` + `.gd` (`capability_id = "artillery"`), cycle per `fire_cooldown` (suggest 6 s): - **Target**: the fleet centroid at the moment of firing (`Fleet.get_centroid()`), within `fire_range` (suggest 900). - **Telegraph** (~1.8 s): a growing target ring drawn at the impact point in the enemy's colour, plus a countdown-style fill so the remaining time is readable. Reuse the ring idiom from `GasBombController._draw_ring`. - **Shell**: travels to the impact point at ~180 units/s (slow, visible), trailing like the gas bomb projectile. - **Impact**: AOE radius ~220, damage 3, applied via `Ship.take_damage()` to every `player_ships` node inside. Explosion visuals in the style of `GasBombController._explode` / `ExplosionVFXBase`. - **Shield interaction**: a shield charge absorbs the hit entirely, matching the existing all-or-nothing shield semantics (`VesselShieldComponent.absorb_hit`). Document this in the component header rather than inventing partial damage. 2. Movement: stationary with a slow drift toward the fleet - it is a siege piece, not a chaser. Do not stack a pursuit component on it. 3. `ArtilleryEnemyDefinition.tres` - `enemy_id = "artillery"`, `max_hp` 8, `speed` ~60, a bulky hull, distinct glow colour. 4. Register it in `EnemyDefinitions` so it is placeable from a planet setup. ### Acceptance criteria - The telegraph is visible for the whole window before any damage lands. - A ship that leaves the ring before impact takes no damage; ships still inside take the full damage. - A shielded ship inside the blast survives, losing exactly one charge. - The impact point is fixed at fire time - it does not home onto the fleet after launch. - No type switch; all stats definition-driven. ### Tests `tests/test_artillery_enemy.gd` (`bash tests/run_tests.sh artillery`), plus a 720x1280 screenshot of the telegraph ring mid-countdown showing it reads clearly on both surface backgrounds. ### Repo notes (read before starting) - Godot 4.7.1, portrait 720x1280, touch UI. Project dir: `/storage/emulated/0/GodotProjects/SpaceshipTest`. - **After editing any project file, run `touch` on it.** Android FUSE does not bump mtime under `~/storage/shared`, and Godot's import cache will silently keep serving the old version, making a correct fix look like it did nothing. - Headless tests: `bash tests/run_tests.sh <substring>`; full suite with no argument. Tests are `SceneTree` scripts printing `TEST_NAME: PASS` / `TEST_NAME: FAIL (reason)` and calling `quit(0|1)` - copy the shape of `tests/test_gas_bomber_cooldowns.gd`. - Real screenshots: `bash tests/screenshot.sh <res://Scene.tscn> <out.png> <frames> 720x1280`. Use few frames (~10-20); the software rasterizer is slow. `--headless` renders nothing at all, so it cannot validate visuals. - Drawing goes through `NeonDraw` / `NeonPiece`; do not introduce a different visual idiom. - The repo deliberately has **no type switches** left (tickets #31-#35): behaviour comes from `*Definition` resources plus capability component scenes. Do not add `if type == "..."` branches. - There is **no persistence layer** (no `FileAccess`, no `user://` anywhere outside this ticket's explicit scope). `GameState` is an in-memory autoload. Do not invent a save system. - Commit each ticket separately and run the full suite before pushing.
Author
Owner

Implemented and pushed as def2246.

  • EnemyArtilleryComponent is a stationary siege piece (slow drift toward the fleet, deliberately no pursuit component) that fires at the fleet centroid on a long cooldown via a standalone ArtilleryShell: telegraph ring (~1.8s, growing radius plus a filling countdown arc) → slow visible travel → AOE explosion via Ship.take_damage() on every player_ships node inside, same all-or-nothing shield absorption as every other damage source.
  • The shell is independent of the enemy that fired it (added to the tree root, like EnemyProjectile/Projectile), so the shooter dying mid-flight doesn't cancel an already-telegraphed shot, and the impact point is fixed at fire time - verified it does not re-aim at where the fleet moves to afterward.

New test tests/test_artillery_enemy.gd covers the telegraph window being damage-free, in/out-of-radius outcomes, shield absorption, and non-homing. Verified visually at 720x1280 on both the rocky and gas surfaces - the telegraph ring reads clearly against both.

Part of the #40 conquest-mechanic breakdown, alongside #45.

Implemented and pushed as `def2246`. - `EnemyArtilleryComponent` is a stationary siege piece (slow drift toward the fleet, deliberately no pursuit component) that fires at the fleet centroid on a long cooldown via a standalone `ArtilleryShell`: telegraph ring (~1.8s, growing radius plus a filling countdown arc) → slow visible travel → AOE explosion via `Ship.take_damage()` on every `player_ships` node inside, same all-or-nothing shield absorption as every other damage source. - The shell is independent of the enemy that fired it (added to the tree root, like `EnemyProjectile`/`Projectile`), so the shooter dying mid-flight doesn't cancel an already-telegraphed shot, and the impact point is fixed at fire time - verified it does not re-aim at where the fleet moves to afterward. New test `tests/test_artillery_enemy.gd` covers the telegraph window being damage-free, in/out-of-radius outcomes, shield absorption, and non-homing. Verified visually at 720x1280 on both the rocky and gas surfaces - the telegraph ring reads clearly against both. Part of the #40 conquest-mechanic breakdown, alongside #45.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
metaheavens/spaceship#46
No description provided.