From 6cdd436caf9e2103f516442ab6e70a870d4cba04 Mon Sep 17 00:00:00 2001 From: Vaino Kauppila Date: Thu, 30 Jul 2026 11:56:27 +0300 Subject: Mount devices on the strut graph so cutting supports destroys them Implements win-condition path (c): destroy the enemy reactor by cutting its supports so it falls. Previously devices sat at fixed map coordinates, structurally immune to collapse. - BuildGraph gains MountedDevice tracking: mount_device/unmount_device, is_device_alive/get_device_hp/damage_device, nearest_device, with a break_node index-shift fix so mount references stay correct as other geometry on the same fort is destroyed. update_fire now also damages any device mounted on a burning strut. - app.cpp mounts devices onto the nearest strut (within 2 units) at both map-load and interactive placement, and after each tick's structural collapse pass, zeroes a device's HP if its mount didn't survive -- which flows through the existing win-condition/cleanup code unchanged. - tools/device_collapse_test.cpp: 15 headless tests covering collapse, partial support loss, splash/beam/fire-through-mount damage, multiple devices, index stability, and clean unmount. Verified: full test suite passes (15/15), sim_check shows zero regressions across all 3 maps. Co-Authored-By: Claude Sonnet 5 --- src/game/build_graph.hpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src/game/build_graph.hpp') diff --git a/src/game/build_graph.hpp b/src/game/build_graph.hpp index 4452139..cd8dc3d 100644 --- a/src/game/build_graph.hpp +++ b/src/game/build_graph.hpp @@ -67,6 +67,17 @@ struct BuildEdge { struct BuildFace { int node_a, node_b, node_c; }; +// A device mounted on the strut graph via two mount nodes. It is destroyed when +// (a) both mount nodes are removed (fall below ground, snap, break), or +// (b) its HP reaches zero from splash/beam/fire damage. +struct MountedDevice { + int node_a, node_b; // mount-point node indices (-1 if destroyed) + int type; // index into DeviceDefs (from data.hpp) + int team = 0; // team index (0 = player, 1 = enemy) + float hp, max_hp; + bool alive = true; +}; + class BuildGraph { public: // Material table, loaded from Lua at startup (build modes index into it). @@ -133,6 +144,24 @@ public: // e.g. restoring a scenario snapshot). void rebuild() { rebuild_topology(); } + // --- devices mounted on the strut graph ------------------------------ + // Attach a device to two mount nodes (any type from DeviceDefs). + // Returns the device index in the graph's devices vector. + int mount_device(int na, int nb, int device_type, int team, float hp); + + // Remove a device (e.g. when a weapon shot destroys it outright). + // Does NOT shift indices — marks it dead and skips it in queries. + void unmount_device(int device_id); + + bool is_device_alive(int device_id) const; + float get_device_hp(int device_id) const; + const std::vector& get_devices() const { return devices; } + int nearest_device(float x, float y, float radius) const; + + // Deal damage to a device (splash/beam/fire). Returns true if the device + // was alive before and is dead after (for downstream win-condition checks). + bool damage_device(int device_id, float amount); + // --- destruction primitives ------------------------------------------- void break_edge(int edge_id); void break_node(int node_id); @@ -147,6 +176,7 @@ public: std::vector nodes; std::vector edges; std::vector faces; + std::vector devices; struct Destroyed { float x, y; }; std::vector destroyed_events; // drained by the app for FX -- cgit v1.3