Home · Architecture · Combat · Extensions · Known gaps · Source index
Incomplete systems and verified risks
This inventory is based on reachable current code, not comments about intended future behavior. Partial means some implementation is reachable or substantial scaffolding exists; Unwired means no current runtime call path; Risk means reachable behavior can produce incorrect or surprising results.
Highest-impact live risks
| Area | Label | Verified finding |
|---|---|---|
| Kill events | Risk | A damage kill emits EnemyKilled in apply_commands, then death_sweep emits it again |
| Repeated lethal commands | Risk | Damage against an already-dead live entry returns Killed again and emits another event |
| Rewards/VFX | Risk | Every duplicate kill event grants full XP and spawns a death animation |
| Coordinate spaces | Risk | Rendering uses an arena offset of 50; collision/grid use 0–800; spawn and center mix both |
| Crate state | Risk | Simulation continues behind the crate despite pause-oriented comments |
| DPS aging | Risk | Samples are pruned only when new damage arrives, allowing stale nonzero display |
| Arrival radius | Risk | Squared distance is compared with unsquared enemy radius |
| Resistance | Risk | Values above 1 heal; values are not clamped |
| Event cascades | Risk | Events remaining after eight delivery waves are silently discarded |
See CombatPipeline, EnemiesAndWaves, and SpatialGeometryRng.
Ground pools
Unwired. Ground pools have constructors, behavior storage, command support, and a pool_pass, but step_world never calls pool_pass. No current weapon or enemy behavior queues SpawnPool.
| Component | State | Current implementation |
|---|---|---|
GroundPool::acid |
Partial | Radius 1.5, TTL 5, stores AcidTick |
GroundPool::slow |
Partial | Caller radius, TTL 4, stores SlowTick |
pool_pass |
Unwired | Would snapshot enemies, rebuild grid, dispatch pool ticks |
| Acid effect | Unwired | Computes _dmg = potency * dt, iterates targets, queues nothing |
| Slow effect | Unwired | Iterates targets; TODO says a real movement status is missing |
| TTL | Unwired | Never decremented and no retention/removal system exists |
| Rendering | Unwired | Pools are never drawn |
| IDs/despawn | Partial | Pools have no entity ID; generic Despawn does not remove them |
Sources: src/pool.rs, src/pools/acid.rs, src/pools/slow.rs, src/behavior/pool.rs, src/systems.rs.
Tower and firing hooks
Unwired. Two extension layers are declared but not dispatched:
ProjectileBehavior::on_fire(shots, FireContext)
TowerBehavior::{on_fire, on_hit_enemy, on_hit_wall, on_tick, on_expire}
Tower.mods: Vec<Box<dyn TowerBehavior>>
FireContext carries origin, aim, and an optional locked target, but no code constructs it. Tower firing directly creates and pushes one projectile. There is no tower-mod dispatcher and tower.mods is never read.
Consequently, fan shots, multishot, pre-flight targeting modifiers, and TP tower modifications cannot affect play through these hooks.
Sources: src/context.rs, src/behavior/projectile.rs, src/behavior/tower.rs, src/tower.rs, src/systems.rs.
Registries and content abstraction
| Item | Label | Gap |
|---|---|---|
| Damage registry | Partial | IDs are live, but registered DamageBehavior factories are never called in combat |
| Status registry | Unwired | Constructed/stored; Poison Coating constructs PeriodDamage directly |
| Registry priority | Partial | Stored and queryable; firing sorts behavior priority instead |
| Duplicate registration | Risk | Overwrites definition and appends duplicate ID to all |
| Enemy behavior priority | Unwired | Method exists; behavior vectors are not sorted |
| Empty weapon catalog | Risk | Crate modulo/index assumes at least one entry; current seed has two |
The current generic registry comments mention future animation, tower, and drone registries, but none are implemented.
Sources: src/registry.rs, src/behavior/damage.rs, src/weapons/poison.rs.
Projectile lifecycle gaps
| Path | Label | Gap |
|---|---|---|
ExpireReason::Lifetime |
Live | Only expiry reason constructed |
ExpireReason::OutOfBounds |
Unwired | Wall hit has separate handling |
ExpireReason::Consumed |
Unwired | Enemy/wall consumption removes without on_expire |
| Projectile lifetime | Partial | Fixed to 1000 seconds for every tower shot |
| Reflect/steer helpers | Unwired | Helpers exist; no concrete behavior uses them |
| Wall behaviors | Partial | Dispatcher is live, but current Impact/Poison return pass and projectile is consumed |
Sources: src/context.rs, src/systems.rs, src/geometry.rs.
Progression and game-state gaps
| Area | Label | Gap |
|---|---|---|
| WP/XP | Live | Enemy kill XP drives level-up crate credits |
| SP | Unwired | Resource command arm is empty |
| TP | Unwired | Resource command arm is empty |
| Player/tower health | Unwired | Center arrival only despawns an enemy |
| Loss/win conditions | Unwired | No state or transition |
| Pause | Unwired | No pause screen or simulation gating |
| Crate detail | Partial | Names only; no current/new tier or stat descriptions |
| Alternate screens | Unwired | Only Playing and WeaponCrate |
Sources: src/types.rs, src/world.rs, src/main.rs.
Enemy and wave gaps
| Area | Label | Gap |
|---|---|---|
| Wave structure | Partial | One timer repeatedly spawns one blob; no numbered wave/budget/completion |
| Spawn points | Partial | Four are drawn; only (0,400) is used |
| Enemy cap | Risk | Split children bypass cap |
| ZigZag | Unwired | Same behavior as SeekCenter and never registered |
| Enemy attack | Unwired | Arrival causes despawn event only |
| Constants | Partial | ENEMY_SPEED and ENEMY_MAX_HP exist but live blob/movement code does not use them |
Sources: src/systems.rs, src/enemies/movement.rs, src/world.rs.
Rendering/UI gaps
Partial. Macroquad draws all core live entities and a keyboard crate overlay, but pools and statuses have no visualization; there are no mouse controls, health bars, XP/level/wave HUD, loadout panel, pause/game-over screens, or responsive layout. The window is fixed at 900 × 900.
animation_system draws during update before the subsequent clear, then retained animations draw again in the render pass. The unused draw_weapon_crate in animations.rs is separate from the live crate renderer.
See RenderingAndUi.
Unused code and dependencies
The crate root globally allows dead_code, explicitly acknowledging incremental scaffolding. Current source does not reference these declared dependencies:
| Cargo dependency | Source usage |
|---|---|
hecs |
Unused |
mlua |
Unused |
serde |
Unused |
serde_json |
Unused |
strum |
Unused |
macroquad |
Live |
Other dormant items include DamageType, DespawnReason, Damage::{PHYSICAL, ACID}, Acid damage behavior, range_f32, steer, reflect_dir, draw_weapon_crate, and GameEvent::Custom handling that intentionally does nothing.
Sources: Cargo.toml, src/main.rs, src/types.rs, src/behavior/damage.rs, src/rng.rs, src/geometry.rs.
Missing tests and build findings
Unwired verification. No test files or #[test] cases exist. cargo test compiles and reports:
running 0 tests
test result: ok. 0 passed; 0 failed
It also reports unused imports:
PlayerStatusinsrc/main.rsREDandtext::draw_textinsrc/animations.rs
High-value missing coverage includes:
- Exactly-once kill reward, animation, and on-death dispatch.
- Multiple lethal commands and DoT/hit ordering.
- DamageMap increased/more math, resistance bounds, and overkill metering.
- Poison duration, frame-rate independence, stacking, and source attribution.
- Split family counts, child IDs/state, cap behavior, and deterministic placement.
- Wave timer/cap/tier boundary behavior.
- Snapshot/grid nearest, radius, collision, and out-of-bounds behavior.
- RNG known sequences, fork isolation, and replay stability.
- Crate multi-level queue, manual close/reopen, duplicates, and empty registry behavior.
- Coordinate conversion, wall collision, center arrival, and zero-vector geometry.
- Pool ticking, TTL, effects, cleanup, and rendering once wired.
- DPS window aging without new records.
Home · Architecture · Combat · Extensions · Known gaps · Source index