feat: Rust combat engine (38k LOC, 1599 tests, full modifier pipelines)#127
Draft
JackSwitzer wants to merge 5 commits intomainfrom
Draft
feat: Rust combat engine (38k LOC, 1599 tests, full modifier pipelines)#127JackSwitzer wants to merge 5 commits intomainfrom
JackSwitzer wants to merge 5 commits intomainfrom
Conversation
Complete Rust engine (packages/engine-rs/) for MCTS-speed Slay the Spire simulation. Squash of 90 commits from fix/phase4-final. Content: - 746 cards (all 4 characters, base + upgraded) - 66 enemies across Acts 1-4 with full AI - 65 combat relics wired with trigger hooks - 38 potions with real effects - 52 events - 220 status effects on FxHashMap<StatusId, i32> Architecture: - Hook dispatch system (powers/hooks.rs) — static tables, auto-wiring - Typed IDs (StatusId, CardId, RelicId) — Copy newtypes - PyO3 bridge (StSEngine, CombatSolver, RustRunEngine) - 480-dim observation encoding - Full run simulation (map, shop, events, campfire, rewards) Tests: 1691 passing, 0 failing Known gaps (from Codex review): - Necronomicon replay not firing - Guardian mode shift incomplete - EchoForm ignores stack count - ~17 enemies unreachable from encounter pools - No Neow phase in RunEngine Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3 Opus 4.6 agents audited trigger system, enemy AI, and architecture. Key findings: - 7 missing trigger hook types (on_attacked, on_hp_loss, on_block_gained, etc.) - Time Eater, Transient, Nemesis have broken enemy-specific mechanics - No minion spawning (Collector, Automaton, Reptomancer, GremlinLeader) - ~400 lines dead code (65 dead fns in buffs.rs alone) - Death-check-fairy pattern duplicated 7 times - Block gain scattered 27 places with no central hook - Run is Act 1 only (no Neow, no act transitions) Full details in docs/research/full-audit-2026-04-02.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…#129) * feat: add v2 core types — Entity, CardInstance, Intent, Combat Engine v2 foundation. Unified entity model where player and enemies share the same Entity struct. CardInstance is 4 bytes (Copy). Intent is a typed enum replacing scattered move_damage/hits/block fields. Combat struct is the MCTS-friendly snapshot. New file: src/combat_types.rs (alongside existing types, no migration yet) 6 new tests passing (1697 total). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add v2 verb functions — centralized mutation pipeline with reactions 14 verb functions, each applies mutation + fires all relevant reactions: - deal_damage: block, Intangible, Thorns/FlameBarrier retaliation, death - apply_hp_loss: bypass-block damage (poison/burn/constricted) - gain_block: Juggernaut (dmg random enemy), Wave of Hand (Weak all) - apply_debuff/buff: Artifact negation, Curl-Up, Sharp Hide, Malleable, Shifting - draw_cards, exhaust_card, discard_card: pile ops with reaction hooks - heal, gain_energy: capped, tracked Overflow status system maps enemy power IDs (>=64) to reserved slots. 38 new tests (1735 total). All reactions verified by test. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: CardRegistry v2 — numeric IDs, O(1) lookup, CardInstance helpers Adds u16 card ID system alongside existing string API: - card_id(&str) -> u16, card_def_by_id(u16) -> &CardDef, card_name(u16) -> &str - make_card/make_card_upgraded for CardInstance construction - is_strike(u16) precomputed bitset for Perfected Strike - Base/upgraded cards get consecutive IDs (Strike_P=N, Strike_P+=N+1) - 741 cards indexed, all existing string methods preserved 10 new tests (1744 total). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: Entity statuses from FxHashMap to [i16; 256] fixed array Direct array indexing eliminates HashMap overhead. 512 bytes per entity, memcpy clone. Removes rustc-hash dependency. All 1744 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: card piles from Vec<String> to Vec<CardInstance> 4-byte Copy struct per card (def_id: u16, cost: i8, flags: u8) replaces heap-allocated strings. O(1) card lookup via def_id index, is_strike() replaces lowercase string search, upgrade_card() replaces string mutation. Added HolyWater card definitions (latent bug from string era). All 1744 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: enemy intents from scattered fields to Intent enum + compact effects Replaces move_damage/move_hits/move_block with typed Intent enum (Copy). Replaces move_effects HashMap<String,i32> with SmallVec<[(u8,i16);4]> using mfx:: constants. Zero heap allocation for enemy moves. Backward-compat methods (move_damage(), set_move()) preserve API surface. All 1744 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: centralized verb pipeline — gain_block, player_lose_hp, hook wiring Centralizes all player block gain through gain_block_player() with Juggernaut and Wave of Hand reactions. Centralizes HP loss through player_lose_hp() with fairy revive, Rupture, and on_hp_loss relics. Wires relics::on_shuffle (Sundial/Abacus), on_enemy_death (Gremlin Horn/Specimen), on_victory (Burning Blood/Black Blood/Meat on Bone). Adds on_enemy_hit reactions (Curl-Up, Malleable, Sharp Hide, Shifting). Deletes dead do_enemy_turns/execute_enemy_move from engine.rs (-157 LOC). All 1744 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: delete 1210 lines of dead code — v2 reference types, combat_verbs, dead powers Removes combat_verbs.rs (893 LOC, superseded by CombatEngine verbs), dead Entity/Combat/StanceV2/EnemyMeta/CombatLine from combat_types.rs, 11 dead functions from buffs.rs and enemy_powers.rs (replaced by hooks dispatch). All 1703 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: wire card replay + 8 missing hooks in play_card/draw_cards Necronomicon replay (2+ cost Attacks), EchoForm stacking fix (first N cards per turn), Unceasing Top (draw on empty hand), Curiosity (enemy Strength on Power play), SkillBurn (damage on Skill play), Forcefield (decrement on card play), Charon's Ashes (damage on exhaust), Evolve (extra draws on Status draw), Fire Breathing (damage on Status/Curse draw). Removes dead replay_pending field. All 1703 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: unified power registry + 4 enemy bug fixes + dead code cleanup Single-source-of-truth PowerRegistryEntry replaces 5-layer hand-wired dispatch (PowerId enum, PowerDef struct, get_power_def(), manual hook tables, scattered install_power match). Net -2577 lines. Bug fixes: Time Eater TIME_WARP_ACTIVE init, Transient FADING init, Nemesis Intangible cycling, boss minion spawning (Collector, Automaton, Reptomancer, GremlinLeader). 9 new integration tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire all relic/power modifiers into the 6 combat pipelines: - Incoming damage: Paper Crane (Weak 0.60), Odd Mushroom (Vuln 1.25) - Debuff application: Ginger blocks Weak, Turnip blocks Frail - Healing: centralized heal_player() with Mark of Bloom (blocks) + Magic Flower (1.5x) - Card cost: Snecko Eye + Snecko Oil set CONFUSION status - Secondary damage: BowlingBash/Ragnarok use calculate_damage_full (pen nib, flight, etc.) - Potion hooks: Toy Ornithopter heals on potion use Cross-enemy effects via new mfx types (BLOCK_ALL_ALLIES, HEAL_LOWEST_ALLY, STRENGTH_ALL_ALLIES) processed in execute_enemy_move: - Centurion Protect gives block to allies - Mystic heals lowest-HP ally - GremlinLeader Encourage buffs minions Fix unreachable enemy moves: - AcidSlime M/L: add Lick to cycle - WrithingMass: MegaDebuff fires once after first BigHit - Repulsor: 5-turn cycle (Daze x4 -> Attack) Cleanup: fix critical match-arm bug where ~70 passive relics set HAS_MARK_OF_BLOOM, remove dead lookup_by_status, fix stale docstrings. 1599 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Relics implemented: - Symbiotic Virus/Cracked Core/Nuclear Battery: channel orbs at combat start via deferred status flags consumed by engine - Runic Capacitor: +3 orb slots at combat start - Ring of the Serpent: +1 draw per turn (every turn, not just turn 1) - Lizard Tail: revive at 50% HP on death (once per run, after Fairy check) - Slaver's Collar: +3 energy in elite/boss fights (flag-based) - WarpedTongs: upgrade random card in hand at turn start (uses engine RNG) - Strange Spoon: 50% chance exhaust -> shuffle into draw pile - Medical Kit: status cards become playable (exhaust on play, cost 0) - Blue Candle: curse cards become playable (1 HP + exhaust, cost 0) Bug fixes: - Frozen Core now channels Frost (was Lightning) - Potion deal_damage_to_enemy now respects Vulnerable, Intangible, Invincible - Discovery potions (Attack/Skill/Power/Colorless) no longer dead code -- early return removed, proxy card implementations now reachable Cleanup: - Fixed 5 stale docstrings in debuffs.rs - Removed dead lookup_by_status from power registry 1599 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Full Rust combat engine for MCTS simulation with complete STS combat parity:
heal_player(),gain_block_player(),player_lose_hp(),deal_damage_to_enemy()Test plan
cargo test)🤖 Generated with Claude Code