Skip to content

Commit b543bcd

Browse files
committed
docs: add combat outcome flavor plan
1 parent ab42838 commit b543bcd

1 file changed

Lines changed: 319 additions & 0 deletions

File tree

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
# Combat Outcome Flavor Implementation Plan
2+
3+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4+
5+
**Goal:** Add distinct miss, evasion, armor-absorb, and penetrating-hit combat log text for both player and enemy attacks in the authoritative raid combat flow.
6+
7+
**Architecture:** Keep the change in the live Supabase SQL combat path. Introduce explicit armor-bonus data and small SQL helpers so attack branches classify outcomes consistently, while preserving the current damage roll and armor DR pipeline on penetrating hits only.
8+
9+
**Tech Stack:** xUnit, .NET test runner, Supabase SQL migrations, PostgreSQL PL/pgSQL
10+
11+
---
12+
13+
### Task 1: Pin the new combat outcome model in migration-content tests
14+
15+
**Files:**
16+
- Modify: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
17+
- Test: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
18+
19+
**Step 1: Write the failing test**
20+
21+
Extend `D20GunDamageMigrationAddsFireModeHelpersAndFullAutoRaidAction` or add a new test that asserts the latest combat migration contains:
22+
23+
```csharp
24+
Assert.Contains("create or replace function game.armor_hit_bonus", migration);
25+
Assert.Contains("attack_total < 10", migration);
26+
Assert.Contains("attack_total < 10 + dodge_bonus", migration);
27+
Assert.Contains("attack_total < 10 + dodge_bonus + armor_bonus", migration);
28+
Assert.Contains("evades your attack", migration);
29+
Assert.Contains("is stopped by armor", migration);
30+
Assert.Contains("armor absorbs", migration);
31+
```
32+
33+
**Step 2: Run test to verify it fails**
34+
35+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
36+
37+
Expected: FAIL because the current migration has no armor-bonus helper and no new combat flavor text.
38+
39+
**Step 3: Write minimal implementation**
40+
41+
Do not change production code yet. Only update the test file with the new assertions and point it at the new latest combat migration path once that filename is chosen.
42+
43+
**Step 4: Run test to verify it still fails for the expected reason**
44+
45+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
46+
47+
Expected: FAIL with missing SQL fragment assertions tied to the new combat flavor model.
48+
49+
**Step 5: Commit**
50+
51+
```bash
52+
git add tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs
53+
git commit -m "test: pin combat outcome flavor migration"
54+
```
55+
56+
### Task 2: Add armor-bonus data and lookup helpers
57+
58+
**Files:**
59+
- Create: `supabase/migrations/2026032402_add_combat_outcome_flavor.sql`
60+
- Modify: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
61+
- Test: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
62+
63+
**Step 1: Write the failing test**
64+
65+
In the migration-content test, add assertions for authored armor bonus support:
66+
67+
```csharp
68+
Assert.Contains("armor_hit_bonus int not null default 0", migration);
69+
Assert.Contains("create or replace function game.armor_hit_bonus(armor_name text)", migration);
70+
Assert.Contains("6B43 Zabralo-Sh body armor", migration);
71+
```
72+
73+
**Step 2: Run test to verify it fails**
74+
75+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
76+
77+
Expected: FAIL because the new migration file or armor-bonus SQL does not exist yet.
78+
79+
**Step 3: Write minimal implementation**
80+
81+
Create `supabase/migrations/2026032402_add_combat_outcome_flavor.sql` that:
82+
83+
- adds `armor_hit_bonus` to `public.item_defs`
84+
- backfills authored armor rows with explicit bonus values
85+
- updates the authored-item seed/upsert path if needed
86+
- defines:
87+
88+
```sql
89+
create or replace function game.armor_hit_bonus(armor_name text)
90+
returns int
91+
language plpgsql
92+
stable
93+
as $$
94+
begin
95+
return coalesce(..., 0);
96+
end;
97+
$$;
98+
```
99+
100+
Choose conservative first-pass armor bonus values that scale with existing armor quality and DR.
101+
102+
**Step 4: Run test to verify it passes**
103+
104+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
105+
106+
Expected: PASS for armor-bonus helper assertions, with remaining failures limited to combat outcome classification/log text.
107+
108+
**Step 5: Commit**
109+
110+
```bash
111+
git add supabase/migrations/2026032402_add_combat_outcome_flavor.sql tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs
112+
git commit -m "feat: add armor bonus lookup for combat outcome flavor"
113+
```
114+
115+
### Task 3: Add reusable SQL helpers for combat outcome classification and log text
116+
117+
**Files:**
118+
- Modify: `supabase/migrations/2026032402_add_combat_outcome_flavor.sql`
119+
- Modify: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
120+
- Test: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
121+
122+
**Step 1: Write the failing test**
123+
124+
Add assertions that the migration defines helpers for classifying attack outcomes and building flavor text:
125+
126+
```csharp
127+
Assert.Contains("create or replace function game.classify_attack_outcome", migration);
128+
Assert.Contains("create or replace function game.describe_player_attack_outcome", migration);
129+
Assert.Contains("create or replace function game.describe_enemy_attack_outcome", migration);
130+
Assert.Contains("when 'miss'", migration);
131+
Assert.Contains("when 'evaded'", migration);
132+
Assert.Contains("when 'armor-absorbed'", migration);
133+
Assert.Contains("when 'hit'", migration);
134+
```
135+
136+
**Step 2: Run test to verify it fails**
137+
138+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
139+
140+
Expected: FAIL because the helper functions are not present yet.
141+
142+
**Step 3: Write minimal implementation**
143+
144+
In the new migration, add helpers shaped like:
145+
146+
```sql
147+
create or replace function game.classify_attack_outcome(
148+
attack_total int,
149+
dodge_bonus int,
150+
armor_bonus int)
151+
returns text
152+
```
153+
154+
Rules:
155+
156+
- `attack_total < 10` => `miss`
157+
- `attack_total < 10 + dodge_bonus` => `evaded`
158+
- `attack_total < 10 + dodge_bonus + armor_bonus` => `armor-absorbed`
159+
- otherwise => `hit`
160+
161+
Add small description helpers that take actor/target names plus absorbed DR and final damage so the player and enemy branches can reuse aligned wording.
162+
163+
**Step 4: Run test to verify it passes**
164+
165+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
166+
167+
Expected: PASS for helper assertions, with remaining failures limited to the still-unwired live combat branches.
168+
169+
**Step 5: Commit**
170+
171+
```bash
172+
git add supabase/migrations/2026032402_add_combat_outcome_flavor.sql tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs
173+
git commit -m "feat: add combat outcome flavor helpers"
174+
```
175+
176+
### Task 4: Wire player attack branches through the new outcome model
177+
178+
**Files:**
179+
- Modify: `supabase/migrations/2026032402_add_combat_outcome_flavor.sql`
180+
- Modify: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
181+
- Test: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
182+
183+
**Step 1: Write the failing test**
184+
185+
Add assertions that the migration text now uses armor bonus and flavor helpers in player attack, burst fire, and full auto sections:
186+
187+
```csharp
188+
Assert.Contains("enemy_armor_bonus", migration);
189+
Assert.Contains("player_attack_total", migration);
190+
Assert.Contains("game.classify_attack_outcome(player_attack_total", migration);
191+
Assert.Contains("game.describe_player_attack_outcome", migration);
192+
```
193+
194+
**Step 2: Run test to verify it fails**
195+
196+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
197+
198+
Expected: FAIL because the player combat branches still log only plain hit-or-miss text.
199+
200+
**Step 3: Write minimal implementation**
201+
202+
Update player attack, burst-fire, and full-auto handling so each branch:
203+
204+
- computes the rolled total once
205+
- computes enemy dodge bonus from DEX mod
206+
- resolves enemy armor bonus from equipped armor
207+
- classifies the outcome with `game.classify_attack_outcome(...)`
208+
- logs:
209+
- miss text for totals under `10`
210+
- evade text for totals in the dodge band
211+
- armor-stop text for totals in the plate band
212+
- hit text with absorbed DR amount when penetrating
213+
214+
Use existing weapon damage and DR helpers only in the `hit` path.
215+
216+
**Step 4: Run test to verify it passes**
217+
218+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
219+
220+
Expected: PASS for player-attack flavor assertions, with remaining failures limited to enemy retaliation paths.
221+
222+
**Step 5: Commit**
223+
224+
```bash
225+
git add supabase/migrations/2026032402_add_combat_outcome_flavor.sql tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs
226+
git commit -m "feat: add player combat outcome flavor text"
227+
```
228+
229+
### Task 5: Wire enemy retaliation and other incoming-attack branches through the new outcome model
230+
231+
**Files:**
232+
- Modify: `supabase/migrations/2026032402_add_combat_outcome_flavor.sql`
233+
- Modify: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
234+
- Test: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
235+
236+
**Step 1: Write the failing test**
237+
238+
Add assertions that all incoming attack branches use the same helper path:
239+
240+
```csharp
241+
Assert.Contains("player_armor_bonus", migration);
242+
Assert.Contains("enemy_attack_total", migration);
243+
Assert.Contains("game.classify_attack_outcome(enemy_attack_total", migration);
244+
Assert.Contains("game.describe_enemy_attack_outcome", migration);
245+
```
246+
247+
**Step 2: Run test to verify it fails**
248+
249+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
250+
251+
Expected: FAIL because enemy retaliation after attacks, medkit, reload, and failed flee still use plain hit-or-miss logs.
252+
253+
**Step 3: Write minimal implementation**
254+
255+
Update each incoming-attack site so enemy attacks:
256+
257+
- use the same `miss` / `evaded` / `armor-absorbed` / `hit` bands
258+
- apply no health loss outside the `hit` band
259+
- preserve current damage roll and DR reduction only on `hit`
260+
- log absorbed DR when armor reduced penetrating damage
261+
262+
Touch the retaliation after:
263+
264+
- player attack loop
265+
- `use-medkit`
266+
- `reload`
267+
- failed `flee`
268+
269+
If extraction ambush combat shares the same combat loop already, no extra branch is needed beyond the existing retaliation flow.
270+
271+
**Step 4: Run test to verify it passes**
272+
273+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
274+
275+
Expected: PASS for the migration-content flavor assertions across both player and enemy combat branches.
276+
277+
**Step 5: Commit**
278+
279+
```bash
280+
git add supabase/migrations/2026032402_add_combat_outcome_flavor.sql tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs
281+
git commit -m "feat: add incoming combat outcome flavor text"
282+
```
283+
284+
### Task 6: Verify the full test suite and review migration diffs
285+
286+
**Files:**
287+
- Modify: `supabase/migrations/2026032402_add_combat_outcome_flavor.sql`
288+
- Modify: `tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
289+
- Modify: `docs/plans/2026-03-24-combat-outcome-flavor-implementation.md`
290+
291+
**Step 1: Run focused tests**
292+
293+
Run: `dotnet test tests/RaidLoop.Core.Tests/RaidLoop.Core.Tests.csproj --filter HomeMarkupBindingTests`
294+
295+
Expected: PASS.
296+
297+
**Step 2: Run the full suite**
298+
299+
Run: `dotnet test RaidLoop.sln`
300+
301+
Expected: PASS with no new failures.
302+
303+
**Step 3: Review the final diff**
304+
305+
Run: `git diff -- supabase/migrations/2026032402_add_combat_outcome_flavor.sql tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs`
306+
307+
Confirm:
308+
309+
- combat outcomes are split into miss, evaded, armor-absorbed, and hit
310+
- player and enemy attacks use the same threshold model
311+
- armor DR still applies only after a penetrating hit
312+
- hit logs mention absorbed DR when relevant
313+
314+
**Step 4: Commit**
315+
316+
```bash
317+
git add supabase/migrations/2026032402_add_combat_outcome_flavor.sql tests/RaidLoop.Core.Tests/HomeMarkupBindingTests.cs docs/plans/2026-03-24-combat-outcome-flavor-implementation.md
318+
git commit -m "feat: add richer combat outcome flavor text"
319+
```

0 commit comments

Comments
 (0)