Add two design plans
This commit is contained in:
parent
759779b319
commit
541f29d64d
2 changed files with 1660 additions and 0 deletions
182
docs/plans/2026-02-23-single-combat-design.md
Normal file
182
docs/plans/2026-02-23-single-combat-design.md
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
# single combat encounter - design doc
|
||||
|
||||
first playable slice of slaywithfriends. one ironclad player vs one
|
||||
enemy. proves the core card engine works.
|
||||
|
||||
## decisions
|
||||
|
||||
- rendering: html/css with card images (no canvas)
|
||||
- framework: none. vanilla js, es modules, bun serve
|
||||
- networking: client-only. all state in browser
|
||||
- character: ironclad (simplest mechanics)
|
||||
- interaction: two-tap (select card, tap target)
|
||||
- mobile: design for 375px baseline, scales up naturally
|
||||
|
||||
## state model
|
||||
|
||||
single object drives everything. pure functions produce new state.
|
||||
nothing mutates directly.
|
||||
|
||||
state = {
|
||||
player: {
|
||||
hp, maxHp,
|
||||
energy, maxEnergy,
|
||||
block,
|
||||
strength,
|
||||
drawPile: [...cardIds],
|
||||
hand: [...cardIds],
|
||||
discardPile: [...cardIds],
|
||||
exhaustPile: [...cardIds],
|
||||
powers: [...cardIds],
|
||||
},
|
||||
enemy: {
|
||||
id, name, hp, maxHp, block,
|
||||
strength, vulnerable, weak,
|
||||
action,
|
||||
actionTrack: [...],
|
||||
trackPosition,
|
||||
},
|
||||
combat: {
|
||||
turn,
|
||||
phase: 'player_turn' | 'enemy_turn' | 'rewards' | 'ended',
|
||||
dieResult,
|
||||
selectedCard,
|
||||
log: [...],
|
||||
}
|
||||
}
|
||||
|
||||
## card data schema
|
||||
|
||||
cards are json entries keyed by id. effects are typed arrays.
|
||||
|
||||
{
|
||||
"strike_r": {
|
||||
"name": "Strike",
|
||||
"cost": 1,
|
||||
"type": "attack",
|
||||
"effects": [{"type": "hit", "value": 6}],
|
||||
"image": "assets/images/ironclad/starter/0.png",
|
||||
"keywords": [],
|
||||
"description": "Deal 6 damage.",
|
||||
"upgraded": "strike_r+"
|
||||
}
|
||||
}
|
||||
|
||||
effect types for first slice: hit, block, draw, strength, vulnerable,
|
||||
weak, exhaust, lose_hp.
|
||||
|
||||
## enemy data schema
|
||||
|
||||
{
|
||||
"jaw_worm": {
|
||||
"name": "Jaw Worm",
|
||||
"hp": 6,
|
||||
"actionType": "die",
|
||||
"actions": {
|
||||
"1": {"intent": "attack", "effects": [{"type": "hit", "value": 3}]},
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
three action types: single (same every turn), die (keyed to die roll),
|
||||
cube (ordered list with advancing pointer, gray actions don't repeat).
|
||||
|
||||
## rendering layout
|
||||
|
||||
three vertical zones:
|
||||
|
||||
enemy zone (~40%) enemy art, hp bar, block, status tokens, intent
|
||||
info bar (fixed) energy pips, hp bar, block shield, strength, pile counts
|
||||
hand (~35%) cards fan out, overlap if many, selected card lifts
|
||||
|
||||
pile overlays: tap draw/discard count to see scrollable card grid.
|
||||
|
||||
## two-tap interaction
|
||||
|
||||
1. tap card in hand - it lifts and highlights
|
||||
2. enemy zone becomes valid target (highlighted border)
|
||||
3. skills that don't need a target auto-play
|
||||
4. tap enemy - card plays, effects resolve, card animates to discard
|
||||
5. not enough energy - card shakes and drops back
|
||||
6. tap selected card again to deselect
|
||||
|
||||
## combat loop
|
||||
|
||||
player turn:
|
||||
1. reset energy to 3, block to 0
|
||||
2. draw 5 cards (shuffle discard into draw if needed)
|
||||
3. roll die (1-6), determines enemy intent
|
||||
4. resolve start-of-turn triggers
|
||||
5. play phase - player acts freely
|
||||
6. "end turn" button ends play phase
|
||||
7. end-of-turn triggers, discard remaining hand
|
||||
|
||||
enemy turn (auto-resolves):
|
||||
1. remove enemy block
|
||||
2. enemy executes action
|
||||
3. advance cube-action pointer if applicable
|
||||
4. brief pause (~1s) for player to read
|
||||
|
||||
combat ends when enemy hp hits 0 (victory) or player hp hits 0 (defeat).
|
||||
|
||||
## damage formula
|
||||
|
||||
1. start with base hit value
|
||||
2. add attacker strength (+1 per token)
|
||||
3. if target vulnerable, double result
|
||||
4. if attacker weak, subtract 1
|
||||
5. weak AND vulnerable cancel out - skip both
|
||||
6. subtract target block, remainder hits hp
|
||||
7. consume 1 vulnerable from target after attack
|
||||
8. consume 1 weak from attacker after attack
|
||||
9. multi-hit: loop N times, consume tokens only after all hits
|
||||
10. aoe/multi-hit: only 1 weak consumed total
|
||||
|
||||
## enemy ai
|
||||
|
||||
data-driven. each enemy's action is an effects array resolved the
|
||||
same way as card effects. intent displayed as icon + number after
|
||||
die roll so player can plan.
|
||||
|
||||
## project structure
|
||||
|
||||
slaywithfriends/
|
||||
index.html
|
||||
style.css
|
||||
src/
|
||||
main.js entry point, init, render loop
|
||||
state.js state creation, pure action functions
|
||||
effects.js effect resolver
|
||||
combat.js turn flow orchestration
|
||||
enemy-ai.js resolve enemy actions
|
||||
render.js state to dom
|
||||
cards.js load/query card data
|
||||
enemies.js load/query enemy data
|
||||
die.js die roll
|
||||
data/
|
||||
cards.json card database
|
||||
enemies.json enemy database
|
||||
potions.json potion database
|
||||
relics.json relic database
|
||||
assets/ video game card images
|
||||
StS_BG_assets/ board game assets
|
||||
docs/ rules and plans
|
||||
|
||||
## out of scope
|
||||
|
||||
- map / room navigation
|
||||
- deck building / rewards / card selection
|
||||
- merchant / campfire / events
|
||||
- potions and relics
|
||||
- multiplayer / networking
|
||||
- persistent state / save / load
|
||||
- sound
|
||||
- ironclad passive (heal 1 hp end of combat)
|
||||
- tutorial
|
||||
|
||||
## data pipeline
|
||||
|
||||
board game card sheet images being extracted to json by agent.
|
||||
video game wiki data (wiki.gg Module:Cards/data) available as
|
||||
secondary reference. board game values are source of truth.
|
||||
1478
docs/plans/2026-02-23-single-combat-plan.md
Normal file
1478
docs/plans/2026-02-23-single-combat-plan.md
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue