Design updates
- gameplay draft - core architecture (Python core)
This commit is contained in:
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,3 +1,14 @@
|
||||
# claude artifacts
|
||||
.claude/
|
||||
CLAUDE.md
|
||||
|
||||
# python artifacts
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
|
||||
|
||||
# uv
|
||||
package-lock.json
|
||||
package.json
|
||||
1435
ARCHITECTURE.md
Normal file
1435
ARCHITECTURE.md
Normal file
File diff suppressed because it is too large
Load Diff
11
FILETREE.txt
Normal file
11
FILETREE.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
.
|
||||
|-- .gitignore
|
||||
|-- ARCHITECTURE.md
|
||||
|-- DESIGN.md
|
||||
|-- FILETREE.txt
|
||||
|-- GAMEPLAY.md
|
||||
|-- README.md
|
||||
|-- package-lock.json
|
||||
|-- package.json
|
||||
\-- tools
|
||||
\-- filetree.py
|
||||
703
GAMEPLAY.md
Normal file
703
GAMEPLAY.md
Normal file
@@ -0,0 +1,703 @@
|
||||
# Naval Composition Roguelite — Gameplay Specification
|
||||
|
||||
**Purpose:** Translate DESIGN.md into concrete gameplay mechanics. Half-filled proposals, half-questionnaire. Fill in the `[DECIDE: ...]` sections.
|
||||
|
||||
---
|
||||
|
||||
## 1. Run Start: Fleet Selection
|
||||
|
||||
### What We Know
|
||||
- Player starts with ~3 ships
|
||||
- Meta-progression unlocks options, not power
|
||||
- Choice should set strategic direction
|
||||
|
||||
### Proposed Mechanic
|
||||
|
||||
For the initial concept, player starts with a preset, relatively boring 'default deck' with:
|
||||
- 1 orthodox destroyer
|
||||
- 1 orthodox cruiser (the "scout cruiser" is just a cruiser for MVP - mechanically identical)
|
||||
- 1 orthodox battleship
|
||||
|
||||
Future extension: more presets; cost-based custom presets, etc.
|
||||
But for now, the boring solution is the easiest to implement and will become un-boring if the roguelite part does its job.
|
||||
|
||||
### Unlock Progression
|
||||
Not important in initial version.
|
||||
However, I personally hate grindy grinds, so unlocks should be rather easy, ceremonial, like a breeze; players should be able to fiddle with all possibilities as soon as possible.
|
||||
|
||||
---
|
||||
|
||||
## 2. Map Structure
|
||||
|
||||
### What We Know
|
||||
- Branching paths (think Slay the Spire)
|
||||
- ~50-60% combat, ~40-50% logistics/events
|
||||
- Target runtime: 30 minutes
|
||||
|
||||
### Math Check
|
||||
- 30 min run = ~18-25 nodes total
|
||||
- If 60% combat = ~12-15 fights
|
||||
- Non-combat nodes = ~6-10
|
||||
|
||||
### Between Nodes
|
||||
Player can change equipments on a ship (swap, substitute with inventory items, take off, etc) as long as not in battle or stat check events.
|
||||
Player can also swap ships in/out of the 'sortie slots' of 3 (can have reserve ships), similarly as long as not in battle or stat check.
|
||||
|
||||
|
||||
### Node Types
|
||||
|
||||
#### Starting Node
|
||||
'Home port'.
|
||||
Just a placeholder for picking the starting deck. Does this and only this.
|
||||
Might also do the whale stuff (of Slay the Spire) later but not now.
|
||||
|
||||
#### Combat Node Types
|
||||
**Tributes to KanColle here** (the fancier way of saying 'ripoff')
|
||||
Several kinds of battle, not every comes in PoC/MVP/alpha alpha.
|
||||
- **Normal** - surface-to-surface fights, enemy might have planes but will never have subs.
|
||||
- **ASW** - submarine-only enemy fleet.
|
||||
- **Aerial** - aviation-focussed fights.
|
||||
|
||||
**For MVP, only normal nodes: surface combat nodes.**
|
||||
Add more varieties later if ever. 3 is already a lot.
|
||||
|
||||
**Enemy fleet size**: Always 1 to 3 ships.
|
||||
|
||||
**Enemy composition reveal**: Enemy composition is NOT fully revealed until you lock in your sortie squad and commence battle. You commit to the fight blind (or partially blind).
|
||||
- *Future extension*: More Recon power reveals more enemy info before combat. Tradeoff: Recon specialists are generally weaker in combat (could be compensated with synergies/chemistry).
|
||||
- *For MVP*: Enemy count visible on map node (1/2/3 ships), but not their types or loadouts until battle starts.
|
||||
|
||||
**Loot**: Your classic 'choose 1 equipment from 3'. To streamline things, no concept of 'cash' or 'universal resource'.
|
||||
|
||||
**Battle termination - Tick System**:
|
||||
Battles use a **tick-based system** rather than "turns" (which imply guaranteed action per turn). One action takes multiple ticks.
|
||||
- **Scale reference**: The major battle phase (gunnery) should run ~100 ticks total, supporting ~2 large caliber salvos (~45 ticks per salvo).
|
||||
- Small guns fire more quickly (fewer ticks per salvo), torpedoes slower, etc.
|
||||
- Battle ends when: (1) one side is eliminated, OR (2) tick limit reached (exact limit TBD - probably 200-300 ticks total?)
|
||||
|
||||
**Battle result grading**: Derived from enemy sunk ratios and damage delivered/received. Better battle result yields better loot quality/choice.
|
||||
- **[TODO: ELABORATE VICTORY GRADE FUNCTION]** - Current thinking is too KanColle, will work as stub for now. S/A/B/C/D ranks based on performance.
|
||||
- **Known vulnerability**: Losing spiral - weak fleet → bad results → bad loot → weaker fleet. May need catch-up mechanics (dockyards buff weak fleets, events offer risky power spikes).
|
||||
|
||||
#### Elite Combat Node
|
||||
'Elite' nodes are just combat nodes with 'better'/'stronger' enemies. (optimised compositions or cheating stats by equipments).
|
||||
|
||||
#### Boss Node
|
||||
- Fixed endpoint, no branching after
|
||||
- Two patterns for PoC stage. Like one super battleship (force) and one super carrier (force).
|
||||
With screening ships, but still under the 3-ship threshold.
|
||||
- **Boss structure**
|
||||
- 1 flagship which has a cheating hull (meaty stats by hull, like abnormally high HP/armour/base firepower, or more eq. slots)
|
||||
- Sink flagship to win
|
||||
- Other enemy ships are relatively normal
|
||||
|
||||
#### Refit / Dockyard Node
|
||||
Remember that the game has no 'money', so these nodes are:
|
||||
- free, but some options are conditioned e.g. require specific stats/tags/traits/synergies... or has tradeoff
|
||||
- mostly upgrading (improvement should always be positive at micro)
|
||||
|
||||
**Possible services**, I'm just listing. Not every one should make into the PoC or final game. (if there ever is a final game):
|
||||
- Repair hull damage
|
||||
- Upgrade equipment (a random better one of same type, or stat boost)
|
||||
- New equipment / hull
|
||||
- Trade equipment (no type guarantee, but generally better) **[How to determine 'better'?]**
|
||||
- Apply mod (on the spot, like 'enchant') *this is a strong one, should have some sort of cost*
|
||||
- Remove any mod (positive or negative)
|
||||
- Trade mods
|
||||
|
||||
***Note***: overall number of visitable nodes are relatively low per map. I would like the player to have more freedom to customise, so each dockyard node might offer multiple (2~4?) charges of service.
|
||||
Also that it might be more gameplay if each dockyard node is different and offer a unique set of services. But might as well offer all of them for the first version.
|
||||
|
||||
#### Event Node
|
||||
- Random event from pool
|
||||
- Must force tradeoff (no pure upgrades)
|
||||
- **[DECIDE: Examples?]** (Fill in 3-5 example events with choices and consequences) - Still thinking, might do this later
|
||||
|
||||
Example template:
|
||||
```
|
||||
EVENT: Salvage Drifting Hulk
|
||||
Choice A: Strip for parts → Gain random equipment, -0~20% HP on one ship (represents overwork/risk) (but not deadly)
|
||||
Choice B: Claim as prize → Gain damaged hull
|
||||
Choice C: Ignore → Gain nothing, but also risk nothing
|
||||
```
|
||||
|
||||
```
|
||||
EVENT: Storm
|
||||
Choice A: Take plain damage (all the fleet incl. reserves lose 5% HP)
|
||||
Choice B: (available if RADAR >= 2) Take less or no damage. # Not sure what RADAR could be, but it requires specific deckbuilding
|
||||
```
|
||||
|
||||
**[DECIDE: Fill in 3-5 event examples like above]** - Still thinking, might do this later
|
||||
|
||||
#### Salvage Node
|
||||
Can already get hulls from the Refit/Dockyard node, so this is part of that
|
||||
|
||||
|
||||
### Map Generation
|
||||
- **Depth**: Depending on routes, roughly 8~10 nodes from start to boss (could fluctuate slightly). Boss always visible at end.
|
||||
- **Width per row**: 2~5 paths per row. Includes 'skip' nodes (direct route jumping one row further) and intra-row lateral paths. Generation should guarantee total run length doesn't fluctuate too much (target 8-10 nodes traversed).
|
||||
- **Path/node visibility**:
|
||||
- **For MVP**: Fixed vision of **2 connected nodes** from current position. Boss is always visible (endpoint marker).
|
||||
- *Future extension*: Recon stat/equipment/tags increase visibility range. More scouting = see farther ahead, but scout ships are weaker in combat (balanced via synergies).
|
||||
|
||||
### Known Vulnerability
|
||||
If map is always similar shape (e.g., always 8 rows, always ends at boss), players will plan perfectly. If too random, they'll feel helpless. You probably want consistency in structure, variance in content.
|
||||
|
||||
---
|
||||
|
||||
## 3. Fleet Persistence & Loss
|
||||
|
||||
### The Hard Question
|
||||
**What happens when a ship is destroyed mid-run?**
|
||||
|
||||
- **Ship is lost for the run**
|
||||
- Equipments on sinking ships are lost as well
|
||||
- but certain mechanisms can be used to recover equipments (e.g. planes can emergency rebase to another carrier if certain conditions are met)
|
||||
- Player might or might not have ships in reserve. It's ok to activate reserve ships after the ship-losing battle.
|
||||
- Also, revival mechanisms that can prevent that loss (e.g. emergency repair - just like KanColle)
|
||||
- Still ripping off KanColle, ships above a certain health (not 'heavy damage') won't be sunk in battle but could become heavily damaged. This is a very good guardrail by KanColle in my opinion.
|
||||
|
||||
### KanColle style heavy damage protection
|
||||
Pseudocode here.
|
||||
```python
|
||||
#
|
||||
def getShipDamageLevel(maxShipHp: int, currentShipHp: int):
|
||||
if (currentShipHp <= (maxShipHp * 0.25)):
|
||||
return HEAVY_DAMAGE
|
||||
else:
|
||||
return SAFE_DAMAGE
|
||||
# Actual KanColle has medium damage (0.25 * maxShipHp < currentShipHp <= 0.5 * maxShipHp), light damage (0.5 * maxShipHp < currentShipHp <= 0.75 * maxShipHp), and slight damage (0.75 * maxShipHp <currentShipHp) which has more uses. But currently we might only need this simplest form.
|
||||
```
|
||||
**Sinking Rules:**
|
||||
- Ship enters battle at `HEAVY_DAMAGE` (≤25% HP): **Can be sunk** during that battle (if damage exceeds remaining HP)
|
||||
- Ship enters battle at `SAFE_DAMAGE` (>25% HP): **Cannot be sunk** this battle. Any killing blow is hard capped to leave ship at **1% HP minimum** (non-lethal).
|
||||
- Protection is determined at **battle start**, not recalculated mid-fight. If you enter SAFE, all hits are capped for the entire battle, even if you drop below 25% mid-fight.
|
||||
|
||||
**Implementation note:** "Non-lethal cap" means: if ship is at 30% HP and takes a hit that would deal 29%+ damage, reduce final damage to leave ship at 1% HP. Keeps it simple and dramatic.
|
||||
|
||||
### Damage Persistence
|
||||
**Does hull damage carry between fights?**
|
||||
- YES: Adds attrition strategy, refit nodes become crucial
|
||||
|
||||
**How much can you heal outside refit nodes?**
|
||||
- Equipment/Tag-based healing (repair cranes, damage control, etc.), these check out at different stages. (e.g. DamCon can activate during or outside battle, but repair cranes can only repair outside battles)
|
||||
- Dockyard nodes. Now thinking about it, dockyards should heal (repair) ships unconditionally on entrance.
|
||||
- Event nodes. Requires some good storytelling but as a mechanism this works.
|
||||
|
||||
### Reserve Ships System
|
||||
|
||||
**Core Rules:**
|
||||
- **Max fleet size**: 6 ships total (3 active sortie slots + 3 reserve slots)
|
||||
- **Starting reserves**: 0 - you begin with exactly 3 ships, no reserves
|
||||
- **Acquiring new hulls**: From dockyard/event nodes only
|
||||
- **Hull acquisition philosophy**: Scarce and NOT immediately rewarding
|
||||
|
||||
**The Balance:**
|
||||
When you get a new hull (free at dockyards), it's **just a hull** - no equipment, no mods. It does nothing useful immediately.
|
||||
|
||||
The strategic choice becomes:
|
||||
- **Option A**: Invest resources (equipment, mods) into your existing 3 ships → stronger specialized fleet
|
||||
- **Option B**: Distribute resources across more ships → flexibility, redundancy, but weaker individuals
|
||||
|
||||
Getting a new hull is potential, not power. Equipment scarcity makes specialization vs diversification a real tradeoff.
|
||||
|
||||
**Between-node management:**
|
||||
- Can swap ships in/out of active sortie slots anytime between nodes (not during battle/stat-check events)
|
||||
- Can swap equipment between any ships in fleet (active or reserve)
|
||||
- Reserves can be used to replace losses or adapt to known enemy types (once you have them)
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 4. Combat Resolution - The Actual Rules
|
||||
|
||||
### Pre-Combat
|
||||
**[DECIDE: Formation system]**
|
||||
- Option A: **Simple stance** (Aggressive/Balanced/Defensive)
|
||||
- Aggressive: +damage, -defense
|
||||
- Defensive: -damage, +defense
|
||||
- Balanced: No modifier
|
||||
|
||||
- Option B: **Positioning** (Front/Mid/Back rows)
|
||||
- Front ships targeted first
|
||||
- Back ships safer but may not reach with short-range weapons
|
||||
- Requires UI to show grid
|
||||
|
||||
- Option C: **Named formations** (Line Ahead, Line Abreast, Echelon)
|
||||
- Each has different rules (range mods, targeting priority, etc.)
|
||||
- More flavor, more complexity
|
||||
|
||||
**[DECIDE: Which formation system?]**
|
||||
|
||||
### Phase-by-Phase Resolution
|
||||
|
||||
Each phase needs:
|
||||
1. **Initiative order** (who acts first)
|
||||
2. **Targeting logic** (who shoots whom)
|
||||
3. **Hit resolution** (to-hit calculation)
|
||||
4. **Damage resolution** (how much damage)
|
||||
|
||||
---
|
||||
|
||||
#### PHASE 1: Detection / Initiative
|
||||
|
||||
**Purpose:** Determine turn order and spotting
|
||||
|
||||
**[DECIDE: What happens here?]**
|
||||
Proposed:
|
||||
- Each ship rolls initiative = Base Speed + Equipment Modifier + d20
|
||||
- Order set for this combat
|
||||
- Ships with SCOUT tag grant +1 initiative to fleet?
|
||||
- Failed detection = -hit chance for first strike?
|
||||
|
||||
**[DECIDE: Accept proposal or define differently?]**
|
||||
|
||||
---
|
||||
|
||||
#### PHASE 2: Air Operations
|
||||
|
||||
**Participants:** Ships with AVIATOR tag
|
||||
|
||||
**[DECIDE: How do aircraft work?]**
|
||||
- Option A: **Abstract strike value**
|
||||
- Each AVIATOR ship contributes Air Power
|
||||
- Total Air Power vs Enemy Air Power or AA rating
|
||||
- Winner deals damage to enemy fleet (distributed how?)
|
||||
|
||||
- Option B: **Plane-vs-plane then strike**
|
||||
- If both sides have AVIATOR, planes fight planes (attrition?)
|
||||
- Winner (or side with more) then strikes surface ships
|
||||
|
||||
- Option C: **Direct bombing**
|
||||
- Each carrier selects target
|
||||
- AA defense reduces damage
|
||||
- No air-to-air unless specific equipment
|
||||
|
||||
**[DECIDE: Pick air combat model]**
|
||||
|
||||
**[DECIDE: Can non-aviator ships defend against air?]**
|
||||
- Only if they have AA equipment?
|
||||
- All ships have base AA rating?
|
||||
|
||||
---
|
||||
|
||||
#### PHASE 3: Surface Gunnery
|
||||
|
||||
**Participants:** Ships with gun-type equipment (probably everyone)
|
||||
|
||||
**Initiative:** Use order from Detection phase
|
||||
|
||||
**Targeting:**
|
||||
**[DECIDE: Who shoots whom?]**
|
||||
- Option A: **Automatic priority**
|
||||
- Target lowest HP enemy (focus fire)
|
||||
- Or: Target enemy with most threat (highest damage?)
|
||||
|
||||
- Option B: **Formation-based**
|
||||
- Front-line ships forced to shoot at front-line enemies
|
||||
- Back-line can only be targeted if front is dead
|
||||
|
||||
- Option C: **Random distribution**
|
||||
- Each ship picks random valid target
|
||||
- SCREEN tag makes them more likely to be targeted?
|
||||
|
||||
**[DECIDE: Pick targeting system]**
|
||||
|
||||
**Hit Calculation:**
|
||||
**[DECIDE: To-hit formula?]**
|
||||
|
||||
Proposed:
|
||||
```
|
||||
Hit Chance = Base Accuracy (from gun) + Attacker Bonuses - Target Evasion - Range Penalty
|
||||
Roll d100, hit if <= Hit Chance
|
||||
```
|
||||
|
||||
**[DECIDE: What are Attacker Bonuses and Target Evasion?]**
|
||||
- Fire control equipment gives +accuracy?
|
||||
- Target speed stat = evasion?
|
||||
- ARTILLERY tag gives +X% hit?
|
||||
|
||||
**Damage Calculation:**
|
||||
**[DECIDE: Damage formula?]**
|
||||
|
||||
Proposed:
|
||||
```
|
||||
Damage = Weapon Damage × Penetration vs Armor Factor
|
||||
Penetration Factor = if Pen >= Armor: 1.0, else: (Pen/Armor) × 0.7
|
||||
```
|
||||
|
||||
**[DECIDE: Accept or define differently?]**
|
||||
|
||||
---
|
||||
|
||||
#### PHASE 4: Torpedo Attacks
|
||||
|
||||
**Participants:** Ships with torpedo equipment or TORPEDO_SPECIALIST tag
|
||||
|
||||
**Special Rule (from DESIGN.md):** SCREEN + CAPITAL synergy = screens absorb first torp hit
|
||||
|
||||
**[DECIDE: How does this work mechanically?]**
|
||||
Proposed:
|
||||
- If player fleet has >=1 SCREEN and >=1 CAPITAL:
|
||||
- First torpedo targeting a CAPITAL is redirected to a random SCREEN
|
||||
- SCREEN takes damage or is destroyed
|
||||
- If no SCREEN present:
|
||||
- CAPITAL ships are vulnerable
|
||||
|
||||
**[DECIDE: Accept or modify?]**
|
||||
|
||||
**[DECIDE: Torpedo hit chance - same as gunnery or different?]**
|
||||
- Torpedoes historically lower accuracy, higher damage
|
||||
- Should they auto-hit but be counterable (SCREEN absorbs)?
|
||||
- Or still require hit roll?
|
||||
|
||||
---
|
||||
|
||||
#### PHASE 5: Damage Control / Morale
|
||||
|
||||
**[DECIDE: What actually happens in this phase?]**
|
||||
|
||||
Proposed options:
|
||||
- **Damage Control:** Ships repair X% of damage taken this fight (incentivizes tanky builds?)
|
||||
- **Morale Check:** If fleet lost >50% HP or >1 ship, roll morale check (pass = fight on, fail = retreat?)
|
||||
- **Status Effects:** Fires, flooding, crew casualties affect next fight?
|
||||
- **Nothing:** Phase exists for future expansion, does nothing in MVP
|
||||
|
||||
**[DECIDE: Pick one or define new]**
|
||||
|
||||
---
|
||||
|
||||
### Combat Outcome
|
||||
|
||||
**If Player Wins:**
|
||||
- **[DECIDE: Loot structure?]**
|
||||
- Always 1 equipment piece (random from pool?)
|
||||
- Choose 1 of 3 equipment options
|
||||
- Scrap/currency + shop later?
|
||||
|
||||
**If Player Loses:**
|
||||
- **[DECIDE: Full run loss or ship loss?]** (see section 3)
|
||||
|
||||
---
|
||||
|
||||
## 5. Ship Stats & Equipment - The Numbers
|
||||
|
||||
### Hull Base Stats
|
||||
|
||||
**[DECIDE: Exact stats for MVP's 3 hull types]**
|
||||
|
||||
Template (fill in numbers):
|
||||
```
|
||||
Destroyer:
|
||||
HP: [DECIDE]
|
||||
Speed: [DECIDE] (affects initiative)
|
||||
Armor: [DECIDE] (reduces damage)
|
||||
Evasion: [DECIDE] (reduces hit chance)
|
||||
Equipment Slots: [DECIDE: 2? 3?]
|
||||
Mod Slots: 1 (per design)
|
||||
Starting Tags: [DECIDE: SCREEN? Other?]
|
||||
|
||||
Cruiser:
|
||||
HP: [DECIDE]
|
||||
Speed: [DECIDE]
|
||||
Armor: [DECIDE]
|
||||
Evasion: [DECIDE]
|
||||
Equipment Slots: [DECIDE]
|
||||
Mod Slots: 1
|
||||
Starting Tags: [DECIDE: None? SCREEN? ARTILLERY?]
|
||||
|
||||
Battleship:
|
||||
HP: [DECIDE]
|
||||
Speed: [DECIDE]
|
||||
Armor: [DECIDE]
|
||||
Evasion: [DECIDE]
|
||||
Equipment Slots: [DECIDE]
|
||||
Mod Slots: 1
|
||||
Starting Tags: [DECIDE: CAPITAL? ARTILLERY?]
|
||||
```
|
||||
|
||||
### Equipment Pieces
|
||||
|
||||
**[DECIDE: Define 8-10 equipment items for MVP]**
|
||||
|
||||
Template (fill in 8-10 of these):
|
||||
```
|
||||
[Equipment Name]:
|
||||
Slot Type: [Main Gun / Torpedo / Aircraft / Utility]
|
||||
Stats: [e.g., +20 damage, +15 penetration]
|
||||
Tags Granted: [e.g., ARTILLERY if gun, AVIATOR if aircraft]
|
||||
Special Effect: [e.g., "Fires twice per phase if target HP < 50%"]
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
5-inch Dual Purpose Gun:
|
||||
Slot Type: Main Gun
|
||||
Damage: 15
|
||||
Penetration: 10
|
||||
Accuracy: 75
|
||||
Tags Granted: None
|
||||
Special: Can engage aircraft (contributes +5 AA rating)
|
||||
```
|
||||
|
||||
**[DECIDE: Fill in your 8-10 equipment items]**
|
||||
|
||||
### Mods
|
||||
|
||||
**[DECIDE: Define 5-6 mods for MVP]**
|
||||
|
||||
Template:
|
||||
```
|
||||
[Mod Name]:
|
||||
Effect: [Mechanical change]
|
||||
Tags Granted/Modified: [...]
|
||||
Tradeoff: [What's the cost?]
|
||||
```
|
||||
|
||||
Example from DESIGN.md:
|
||||
```
|
||||
Flight Deck:
|
||||
Effect: +1 Equipment Slot (must be aircraft), +20 HP cost (weight)
|
||||
Tags Granted: Enables AVIATOR if aircraft equipped
|
||||
Tradeoff: Reduces armor by 5 (structural weakness)
|
||||
```
|
||||
|
||||
**[DECIDE: Fill in 5-6 mods]**
|
||||
|
||||
---
|
||||
|
||||
## 6. Tag System - Derivation Rules
|
||||
|
||||
### What We Know
|
||||
- Tags are derived from equipment + mods + hull
|
||||
- Tags must affect >=2 systems
|
||||
- Tags used by combat phases and events
|
||||
|
||||
### Required Tags for MVP (from DESIGN.md)
|
||||
1. AVIATOR
|
||||
2. SCREEN
|
||||
3. CAPITAL
|
||||
4. SCOUT
|
||||
5. TORPEDO_SPECIALIST
|
||||
6. ARTILLERY
|
||||
|
||||
**[DECIDE: Define exact derivation rule for each tag]**
|
||||
|
||||
Template:
|
||||
```
|
||||
Tag: AVIATOR
|
||||
Derived When: [Ship has aircraft equipment AND hull/mod provides flight capacity]
|
||||
Affects:
|
||||
- System 1: [e.g., Participates in Air Phase]
|
||||
- System 2: [e.g., Events may reference "aviator ships"]
|
||||
```
|
||||
|
||||
**[DECIDE: Fill in derivation + effects for all 6 tags]**
|
||||
|
||||
Example:
|
||||
```
|
||||
Tag: SCREEN
|
||||
Derived When: Hull is Destroyer OR ship has "Anti-Torpedo Net" equipment
|
||||
Affects:
|
||||
- System 1: Can intercept torpedoes aimed at CAPITAL ships
|
||||
- System 2: Events may offer "screen-only" upgrades
|
||||
- System 3: Targeted first in gunnery phase (acts as tank)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Fleet Chemistry - Specific Synergies
|
||||
|
||||
### What We Know (from DESIGN.md)
|
||||
- SCREEN + CAPITAL = torpedo protection
|
||||
- No SCREEN = +firepower, +torpedo vulnerability
|
||||
- Multiple AVIATOR = strong air, weak surface
|
||||
|
||||
**[DECIDE: Define exact mechanical effects]**
|
||||
|
||||
Template:
|
||||
```
|
||||
Synergy: [Tag Combo]
|
||||
Condition: [e.g., ">=1 SCREEN and >=1 CAPITAL in fleet"]
|
||||
Effect: [Exact mechanical benefit]
|
||||
Tradeoff: [Any cost or weakness introduced]
|
||||
```
|
||||
|
||||
**[DECIDE: Fill in 4-6 fleet chemistry effects]**
|
||||
|
||||
Example:
|
||||
```
|
||||
Synergy: Carrier Battle Group
|
||||
Condition: >=2 AVIATOR + >=1 SCREEN
|
||||
Effect:
|
||||
- Air Phase attacks deal +25% damage
|
||||
- SCREEN ships provide +10 AA to fleet
|
||||
Tradeoff:
|
||||
- If all AVIATOR ships lost, fleet has -30% surface firepower (over-specialized)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Event Design - Concrete Examples
|
||||
|
||||
### Design Rules (from DESIGN.md)
|
||||
- Must force commitment or introduce risk
|
||||
- No pure free upgrades
|
||||
|
||||
**[DECIDE: Write 5-8 event cards]**
|
||||
|
||||
Template:
|
||||
```
|
||||
EVENT: [Name]
|
||||
Flavor: [1-2 sentences of context]
|
||||
Choice A: [Option] → [Mechanical effect]
|
||||
Choice B: [Option] → [Mechanical effect]
|
||||
Choice C (optional): [Option] → [Mechanical effect]
|
||||
Tag Requirements: [e.g., "Only appears if you have AVIATOR ship"]
|
||||
```
|
||||
|
||||
**[DECIDE: Fill in 5-8 events]**
|
||||
|
||||
Example:
|
||||
```
|
||||
EVENT: Experimental Ammunition
|
||||
Flavor: A supply ship offers prototype shells. Experimental. Unproven. Powerful.
|
||||
Choice A: Load AP Rounds → All guns +5 penetration, but 10% chance to misfire (miss automatically)
|
||||
Choice B: Load HE Rounds → All guns +10 damage vs low-armor targets (<10 armor), -5 damage vs high armor
|
||||
Choice C: Decline → No change
|
||||
Tag Requirements: None
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Boss Design
|
||||
|
||||
**[DECIDE: Define the MVP boss encounter]**
|
||||
|
||||
### Boss Option A: Single Super-Unit
|
||||
```
|
||||
Name: [DECIDE]
|
||||
Hull: [Custom super-hull]
|
||||
HP: [DECIDE: 3x battleship HP?]
|
||||
Special Mechanics: [DECIDE: e.g., "Regenerates 5% HP each phase"]
|
||||
Weakness: [DECIDE: e.g., "Vulnerable to torpedo damage"]
|
||||
```
|
||||
|
||||
### Boss Option B: Elite Fleet
|
||||
```
|
||||
Name: [DECIDE]
|
||||
Composition: [DECIDE: e.g., "2 Cruisers, 2 Destroyers, 1 Battleship"]
|
||||
Special Mechanic: [DECIDE: e.g., "All ships have +1 mod slot filled"]
|
||||
Weakness: [DECIDE: e.g., "No air power"]
|
||||
```
|
||||
|
||||
### Boss Option C: Phased Fight
|
||||
```
|
||||
Name: [DECIDE]
|
||||
Phase 1: [DECIDE: e.g., "3 Destroyers with TORPEDO_SPECIALIST"]
|
||||
Phase 2 (if Phase 1 defeated): [DECIDE: e.g., "1 Battleship + 2 Cruisers"]
|
||||
Special Mechanic: [DECIDE: e.g., "Phase 2 starts with you at current HP"]
|
||||
```
|
||||
|
||||
**[DECIDE: Pick A, B, or C and fill in details]**
|
||||
|
||||
---
|
||||
|
||||
## 10. Meta-Progression
|
||||
|
||||
### What We Know
|
||||
- Unlocks options, not power
|
||||
- No permanent stat buffs
|
||||
|
||||
**[DECIDE: What unlocks after each run?]**
|
||||
|
||||
Proposed structure:
|
||||
- Win Run 1 → Unlock [DECIDE: 1 new hull? 1 new starting fleet? 2 equipment items?]
|
||||
- Win Run 2 → Unlock [DECIDE]
|
||||
- Win Run 3 → Unlock [DECIDE]
|
||||
- Lose Run (any) → Unlock [DECIDE: Nothing? Small consolation prize?]
|
||||
|
||||
**[DECIDE: Fill in unlock tree for first 5 wins]**
|
||||
|
||||
### Unlock Categories
|
||||
Check which categories you want:
|
||||
- [ ] New hulls
|
||||
- [ ] New equipment
|
||||
- [ ] New mods
|
||||
- [ ] New starting fleet options
|
||||
- [ ] New events
|
||||
- [ ] New bosses (variants)
|
||||
- [ ] Cosmetics (ship skins, names, etc.)
|
||||
|
||||
**[DECIDE: Check boxes above]**
|
||||
|
||||
---
|
||||
|
||||
## 11. Victory Condition
|
||||
|
||||
**[DECIDE: What constitutes winning a run?]**
|
||||
|
||||
- Option A: Defeat the boss (regardless of fleet state)
|
||||
- Option B: Defeat the boss with at least X ships remaining
|
||||
- Option C: Reach score threshold (score = enemies defeated × fleet HP remaining?)
|
||||
|
||||
**[DECIDE: Pick one]**
|
||||
|
||||
**[DECIDE: Are there difficulty tiers or modifiers?]** (e.g., Ascension levels like Slay the Spire)
|
||||
- YES → [DECIDE: What do they change?]
|
||||
- NO → Just one difficulty for MVP
|
||||
|
||||
---
|
||||
|
||||
## 12. Known Vulnerabilities Log
|
||||
|
||||
Things that will probably bite later but are acceptable for MVP:
|
||||
|
||||
1. **Combat pacing:** If fights take >2min to watch, 30min promise breaks. Need fast-forward or instant resolve option.
|
||||
|
||||
2. **Balance death spiral:** If one lost ship makes you too weak, runs feel doomed early. Replacement mechanic or careful balance required.
|
||||
|
||||
3. **Tag discovery:** Players won't know what tags do without a codex/help. Either add tutorial or accept confusion for first 2-3 runs.
|
||||
|
||||
4. **Event repetition:** With only 5-8 events, you'll see repeats in same run. Either need more events or smart draw-without-replacement system.
|
||||
|
||||
5. **Solved meta:** With deterministic RNG and small pool, optimal strategies will emerge fast. Plan for balance patches or accept short shelf life.
|
||||
|
||||
6. **Equipment bloat:** If loot drops every fight, inventory management becomes tedious. Either cap inventory size or allow scrapping/selling.
|
||||
|
||||
---
|
||||
|
||||
## 13. Open Questions Not Covered Above
|
||||
|
||||
**[DECIDE: Answer these]**
|
||||
|
||||
1. **Currency system:** Is there scrap/gold/resources, or purely loot-based?
|
||||
|
||||
2. **Ship naming:** Do ships have persistent names/identity, or just "Destroyer #1"?
|
||||
|
||||
3. **RNG seed exposure:** Is seed visible to player (for challenge runs/sharing)?
|
||||
|
||||
4. **Retreat option:** Can you retreat from combat before it starts (see enemy, back out)?
|
||||
|
||||
5. **Save system:** Save between nodes, or full run in one sitting?
|
||||
|
||||
6. **Difficulty indicators:** Does UI show "this fight will be hard" before committing?
|
||||
|
||||
7. **Fleet size limits:** Always exactly 3 ships, or can you have 2-4?
|
||||
|
||||
---
|
||||
|
||||
## Fill-In Instructions
|
||||
|
||||
1. Search for every `[DECIDE: ...]` tag in this document
|
||||
2. Replace with your actual design decision
|
||||
3. Delete options you're NOT using
|
||||
4. If you add new mechanics, document them in same format
|
||||
5. When you've filled it all in, this becomes the gameplay spec
|
||||
|
||||
Don't overthink it - make a decision, document it, test it. Wrong answers are fine; unknown answers will kill the project.
|
||||
|
||||
---
|
||||
|
||||
**Status:** INCOMPLETE - requires design decisions before implementation.
|
||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Fleet builder (working title)
|
||||
|
||||
## Description
|
||||
A 30-minute, composition-first naval roguelite where you act as an admiral. Combat is auto-resolved and phase-based; the core decisions happen before battles through fleet composition, mods, and equipment.
|
||||
Runs are short and final, with meta-progression unlocking options rather than raw power.
|
||||
145
tools/filetree.py
Normal file
145
tools/filetree.py
Normal file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Create an ASCII file tree while respecting .gitignore when possible.
|
||||
|
||||
Usage:
|
||||
python tools/filetree.py [output_path]
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import fnmatch
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Dict, Iterable, List
|
||||
|
||||
|
||||
def find_repo_root(start: str) -> str:
|
||||
cur = os.path.abspath(start)
|
||||
while True:
|
||||
if os.path.isdir(os.path.join(cur, ".git")):
|
||||
return cur
|
||||
parent = os.path.dirname(cur)
|
||||
if parent == cur:
|
||||
return os.path.abspath(start)
|
||||
cur = parent
|
||||
|
||||
|
||||
def git_available() -> bool:
|
||||
try:
|
||||
subprocess.run(["git", "--version"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def list_files_via_git(root: str) -> List[str]:
|
||||
result = subprocess.run(
|
||||
["git", "-C", root, "ls-files", "--others", "--cached", "--exclude-standard"],
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.DEVNULL,
|
||||
text=True,
|
||||
)
|
||||
files = [line.strip() for line in result.stdout.splitlines() if line.strip()]
|
||||
return files
|
||||
|
||||
|
||||
def parse_gitignore(root: str) -> List[str]:
|
||||
path = os.path.join(root, ".gitignore")
|
||||
if not os.path.isfile(path):
|
||||
return []
|
||||
patterns: List[str] = []
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
for raw in f:
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
patterns.append(line)
|
||||
return patterns
|
||||
|
||||
|
||||
def is_ignored(path_rel: str, is_dir: bool, patterns: List[str]) -> bool:
|
||||
# Minimal .gitignore matching: supports *, ?, **, leading /, trailing /
|
||||
path_rel = path_rel.replace(os.sep, "/")
|
||||
ignored = False
|
||||
for pat in patterns:
|
||||
negate = pat.startswith("!")
|
||||
if negate:
|
||||
pat = pat[1:]
|
||||
if pat.startswith("/"):
|
||||
pat = pat[1:]
|
||||
if pat.endswith("/") and not is_dir:
|
||||
continue
|
||||
pat = pat.rstrip("/")
|
||||
if fnmatch.fnmatch(path_rel, pat) or fnmatch.fnmatch(os.path.basename(path_rel), pat):
|
||||
ignored = not negate
|
||||
return ignored
|
||||
|
||||
|
||||
def list_files_with_fallback(root: str) -> List[str]:
|
||||
patterns = parse_gitignore(root)
|
||||
files: List[str] = []
|
||||
for dirpath, dirnames, filenames in os.walk(root):
|
||||
rel_dir = os.path.relpath(dirpath, root)
|
||||
if rel_dir == ".":
|
||||
rel_dir = ""
|
||||
# Prune ignored directories early
|
||||
pruned = []
|
||||
for d in dirnames:
|
||||
rel_path = os.path.join(rel_dir, d) if rel_dir else d
|
||||
if is_ignored(rel_path, True, patterns):
|
||||
continue
|
||||
pruned.append(d)
|
||||
dirnames[:] = pruned
|
||||
for name in filenames:
|
||||
rel_path = os.path.join(rel_dir, name) if rel_dir else name
|
||||
if is_ignored(rel_path, False, patterns):
|
||||
continue
|
||||
files.append(rel_path.replace(os.sep, "/"))
|
||||
return files
|
||||
|
||||
|
||||
def build_tree(paths: Iterable[str]) -> Dict[str, dict]:
|
||||
root: Dict[str, dict] = {}
|
||||
for path in paths:
|
||||
parts = [p for p in path.split("/") if p]
|
||||
node = root
|
||||
for part in parts:
|
||||
node = node.setdefault(part, {})
|
||||
return root
|
||||
|
||||
|
||||
def render_tree(node: Dict[str, dict], prefix: str = "") -> List[str]:
|
||||
lines: List[str] = []
|
||||
entries = sorted(node.keys())
|
||||
for i, name in enumerate(entries):
|
||||
is_last = i == len(entries) - 1
|
||||
connector = "\\-- " if is_last else "|-- "
|
||||
lines.append(f"{prefix}{connector}{name}")
|
||||
child = node[name]
|
||||
if child:
|
||||
extension = " " if is_last else "| "
|
||||
lines.extend(render_tree(child, prefix + extension))
|
||||
return lines
|
||||
|
||||
|
||||
def main() -> int:
|
||||
out_path = sys.argv[1] if len(sys.argv) > 1 else "FILETREE.txt"
|
||||
root = find_repo_root(os.getcwd())
|
||||
if os.path.isdir(os.path.join(root, ".git")) and git_available():
|
||||
files = list_files_via_git(root)
|
||||
else:
|
||||
files = list_files_with_fallback(root)
|
||||
|
||||
tree = build_tree(files)
|
||||
lines = ["."]
|
||||
lines.extend(render_tree(tree))
|
||||
out_abs = os.path.join(root, out_path)
|
||||
with open(out_abs, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(lines) + "\n")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user