init game files
This commit is contained in:
270
docs/CARD_FORMAT.md
Normal file
270
docs/CARD_FORMAT.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# Card Data Format Specification
|
||||
|
||||
## Overview
|
||||
|
||||
Card data is stored in `data/cards.json` as a JSON file. This document describes the schema and valid values for card definitions.
|
||||
|
||||
## Schema
|
||||
|
||||
### Root Object
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"cards": [ ... ]
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `version` | string | Yes | Schema version for compatibility |
|
||||
| `cards` | array | Yes | Array of card objects |
|
||||
|
||||
### Card Object
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "1-003C",
|
||||
"name": "Red Mage",
|
||||
"type": "Backup",
|
||||
"element": "Fire",
|
||||
"cost": 2,
|
||||
"power": null,
|
||||
"job": "Standard Unit",
|
||||
"category": "II",
|
||||
"is_generic": false,
|
||||
"has_ex_burst": false,
|
||||
"abilities": [ ... ],
|
||||
"image": "1-003C_eg.jpg"
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `id` | string | Yes | Unique card identifier (e.g., "1-003C") |
|
||||
| `name` | string | Yes | Card name |
|
||||
| `type` | string | Yes | Card type: "Forward", "Backup", "Summon", "Monster" |
|
||||
| `element` | string/array | Yes | Element(s): see Element Values |
|
||||
| `cost` | integer | Yes | CP cost to play (0-10) |
|
||||
| `power` | integer/null | Conditional | Power value (required for Forwards, null otherwise) |
|
||||
| `job` | string | No | Job class (for characters) |
|
||||
| `category` | string | No | Game category (e.g., "II", "VII", "XIV") |
|
||||
| `is_generic` | boolean | No | If true, can have multiple copies on field (default: false) |
|
||||
| `has_ex_burst` | boolean | No | If true, has EX Burst ability (default: false) |
|
||||
| `abilities` | array | No | Array of ability objects |
|
||||
| `image` | string | No | Image filename in assets/cards/ |
|
||||
|
||||
### Element Values
|
||||
|
||||
Single element (string):
|
||||
- `"Fire"` - Red
|
||||
- `"Ice"` - Cyan/Light Blue
|
||||
- `"Wind"` - Green
|
||||
- `"Lightning"` - Purple
|
||||
- `"Water"` - Blue
|
||||
- `"Earth"` - Yellow/Brown
|
||||
- `"Light"` - White
|
||||
- `"Dark"` - Black
|
||||
|
||||
Multi-element (array):
|
||||
```json
|
||||
"element": ["Fire", "Ice"]
|
||||
```
|
||||
|
||||
### Card Types
|
||||
|
||||
| Type | Description | Has Power | Notes |
|
||||
|------|-------------|-----------|-------|
|
||||
| `Forward` | Combat units | Yes | Can attack and block |
|
||||
| `Backup` | Support units | No | Generate CP, max 5 |
|
||||
| `Summon` | One-time effects | No | Goes to Break Zone |
|
||||
| `Monster` | Special characters | Varies | Can have unique rules |
|
||||
|
||||
### Ability Object
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "action",
|
||||
"name": "Cure",
|
||||
"cost": {
|
||||
"fire": 1,
|
||||
"dull": true
|
||||
},
|
||||
"effect": "Choose 1 Forward. It cannot block this turn.",
|
||||
"is_ex_burst": false
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `type` | string | Yes | Ability type (see Ability Types) |
|
||||
| `name` | string | No | Named ability (for Special abilities) |
|
||||
| `cost` | object | Conditional | Cost to activate (for action/special) |
|
||||
| `effect` | string | Yes | Effect text description |
|
||||
| `is_ex_burst` | boolean | No | If true, this is the EX Burst ability |
|
||||
| `trigger` | string | Conditional | Trigger condition (for auto abilities) |
|
||||
|
||||
### Ability Types
|
||||
|
||||
| Type | Description | Has Cost |
|
||||
|------|-------------|----------|
|
||||
| `field` | Always active while on field | No |
|
||||
| `auto` | Triggers on specific events | No (but may have conditions) |
|
||||
| `action` | Activated by paying cost | Yes |
|
||||
| `special` | Named ability requiring card discard | Yes |
|
||||
|
||||
### Cost Object
|
||||
|
||||
```json
|
||||
{
|
||||
"generic": 2,
|
||||
"fire": 1,
|
||||
"ice": 0,
|
||||
"wind": 0,
|
||||
"lightning": 0,
|
||||
"water": 0,
|
||||
"earth": 0,
|
||||
"light": 0,
|
||||
"dark": 0,
|
||||
"dull": false,
|
||||
"discard": 0,
|
||||
"specific_discard": null
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `generic` | integer | 0 | Any element CP |
|
||||
| `fire` | integer | 0 | Fire element CP required |
|
||||
| `ice` | integer | 0 | Ice element CP required |
|
||||
| `wind` | integer | 0 | Wind element CP required |
|
||||
| `lightning` | integer | 0 | Lightning element CP required |
|
||||
| `water` | integer | 0 | Water element CP required |
|
||||
| `earth` | integer | 0 | Earth element CP required |
|
||||
| `light` | integer | 0 | Light element CP required |
|
||||
| `dark` | integer | 0 | Dark element CP required |
|
||||
| `dull` | boolean | false | Requires dulling this card |
|
||||
| `discard` | integer | 0 | Number of cards to discard |
|
||||
| `specific_discard` | string | null | Specific card name to discard |
|
||||
|
||||
## Examples
|
||||
|
||||
### Forward Card
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "1-006H",
|
||||
"name": "Garland",
|
||||
"type": "Forward",
|
||||
"element": "Fire",
|
||||
"cost": 5,
|
||||
"power": 8000,
|
||||
"job": "Knight",
|
||||
"category": "DFF-I",
|
||||
"is_generic": false,
|
||||
"has_ex_burst": false,
|
||||
"abilities": [
|
||||
{
|
||||
"type": "field",
|
||||
"effect": "Brave"
|
||||
},
|
||||
{
|
||||
"type": "auto",
|
||||
"trigger": "When Garland attacks",
|
||||
"effect": "Garland gains +4000 power until the end of the turn."
|
||||
}
|
||||
],
|
||||
"image": "1-006H_eg.jpg"
|
||||
}
|
||||
```
|
||||
|
||||
### Backup Card
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "1-003C",
|
||||
"name": "Red Mage",
|
||||
"type": "Backup",
|
||||
"element": "Fire",
|
||||
"cost": 2,
|
||||
"power": null,
|
||||
"job": "Standard Unit",
|
||||
"category": "II",
|
||||
"is_generic": true,
|
||||
"has_ex_burst": false,
|
||||
"abilities": [
|
||||
{
|
||||
"type": "action",
|
||||
"cost": {
|
||||
"fire": 1,
|
||||
"dull": true
|
||||
},
|
||||
"effect": "Choose 1 Forward. It cannot block this turn."
|
||||
}
|
||||
],
|
||||
"image": "1-003C_eg.jpg"
|
||||
}
|
||||
```
|
||||
|
||||
### Summon Card
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "1-023R",
|
||||
"name": "Ifrit",
|
||||
"type": "Summon",
|
||||
"element": "Fire",
|
||||
"cost": 3,
|
||||
"power": null,
|
||||
"category": "III",
|
||||
"has_ex_burst": true,
|
||||
"abilities": [
|
||||
{
|
||||
"type": "auto",
|
||||
"effect": "If a Fire Forward has entered your field this turn, the cost required to cast Ifrit is reduced by 3. Choose 1 Forward. Deal it 7000 damage.",
|
||||
"is_ex_burst": true
|
||||
}
|
||||
],
|
||||
"image": "1-023R_eg.jpg"
|
||||
}
|
||||
```
|
||||
|
||||
### Multi-Element Card
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "12-001H",
|
||||
"name": "Vaan",
|
||||
"type": "Forward",
|
||||
"element": ["Fire", "Lightning"],
|
||||
"cost": 4,
|
||||
"power": 8000,
|
||||
"job": "Sky Pirate",
|
||||
"category": "XII",
|
||||
"abilities": [
|
||||
{
|
||||
"type": "auto",
|
||||
"trigger": "When Vaan enters the field",
|
||||
"effect": "Choose 1 Forward. Dull it."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Validation Rules
|
||||
|
||||
1. **ID Uniqueness**: Each card must have a unique `id`
|
||||
2. **Power Requirement**: `power` must be set for Forwards, null for others
|
||||
3. **Element Validity**: Elements must be from the valid list
|
||||
4. **Cost Range**: `cost` must be 0-10
|
||||
5. **Power Range**: `power` must be 1000-99000 in increments of 1000
|
||||
6. **Ability Costs**: Action and Special abilities must have a `cost` object
|
||||
|
||||
## Loading Process
|
||||
|
||||
1. Read `data/cards.json`
|
||||
2. Parse JSON
|
||||
3. Validate each card against schema
|
||||
4. Build lookup dictionaries (by ID, by element, by type)
|
||||
5. Pre-load referenced images
|
||||
6. Report any validation errors
|
||||
283
docs/DESIGN.md
Normal file
283
docs/DESIGN.md
Normal file
@@ -0,0 +1,283 @@
|
||||
# FF-TCG Digital - Architecture Design Document
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the software architecture of the FF-TCG Digital implementation.
|
||||
|
||||
## Technology Stack
|
||||
|
||||
- **Game Engine**: Godot 4.2+
|
||||
- **Language**: GDScript
|
||||
- **Target Platform**: Linux Desktop
|
||||
- **Rendering**: Forward+ renderer with 3D isometric view
|
||||
|
||||
## Architecture Principles
|
||||
|
||||
1. **Separation of Concerns**: Game logic is separate from visual presentation
|
||||
2. **Event-Driven**: State changes emit signals for loose coupling
|
||||
3. **Data-Driven**: Card definitions loaded from JSON, not hardcoded
|
||||
4. **Testable**: Core game logic can be tested independently of visuals
|
||||
|
||||
## System Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Main Scene │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Table Scene │ │ UI Layer │ │ Input Handler│ │
|
||||
│ │ (3D View) │ │ (2D Canvas) │ │ │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ Autoload Singletons │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ GameManager │ │ CardDatabase │ │
|
||||
│ └──────────────┘ └──────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ Game State Engine │
|
||||
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────────┐ │
|
||||
│ │ GameState │ │ Player │ │ Zone │ │ TurnManager │ │
|
||||
│ └────────────┘ └────────────┘ └────────────┘ └──────────────┘ │
|
||||
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
|
||||
│ │ CPPool │ │ Combat │ │ Stack │ │
|
||||
│ └────────────┘ └────────────┘ └────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Core Components
|
||||
|
||||
### Autoload Singletons
|
||||
|
||||
#### GameManager (`scripts/autoload/GameManager.gd`)
|
||||
Central coordinator for game flow. Responsibilities:
|
||||
- Initialize new games
|
||||
- Coordinate between game state and visuals
|
||||
- Handle high-level game events
|
||||
- Manage scene transitions
|
||||
|
||||
Signals:
|
||||
- `game_started()`
|
||||
- `game_ended(winner: int)`
|
||||
- `turn_changed(player_index: int)`
|
||||
- `phase_changed(phase: TurnPhase)`
|
||||
|
||||
#### CardDatabase (`scripts/autoload/CardDatabase.gd`)
|
||||
Manages card definitions loaded from JSON. Responsibilities:
|
||||
- Load and parse `data/cards.json`
|
||||
- Provide card lookup by ID
|
||||
- Validate card data on load
|
||||
- Cache card textures
|
||||
|
||||
Methods:
|
||||
- `get_card(id: String) -> CardData`
|
||||
- `get_cards_by_element(element: Element) -> Array[CardData]`
|
||||
- `get_cards_by_type(type: CardType) -> Array[CardData]`
|
||||
|
||||
### Game State Classes
|
||||
|
||||
#### GameState (`scripts/game/GameState.gd`)
|
||||
Master game state container. Holds:
|
||||
- Two Player instances
|
||||
- Shared Stack for ability resolution
|
||||
- Current turn/phase information
|
||||
- Game rules enforcement
|
||||
|
||||
#### Player (`scripts/game/Player.gd`)
|
||||
Individual player state. Contains:
|
||||
- Hand (Zone)
|
||||
- Deck (Zone)
|
||||
- Field - Forwards area (Zone)
|
||||
- Field - Backups area (Zone)
|
||||
- Damage Zone (Zone)
|
||||
- Break Zone (Zone)
|
||||
- Current CP pool
|
||||
|
||||
#### Zone (`scripts/game/Zone.gd`)
|
||||
Base class for card containers. Types:
|
||||
- `DECK` - Hidden, ordered
|
||||
- `HAND` - Hidden from opponent
|
||||
- `FIELD_FORWARDS` - Public
|
||||
- `FIELD_BACKUPS` - Public, max 5
|
||||
- `DAMAGE` - Public, ordered
|
||||
- `BREAK` - Public discard
|
||||
|
||||
Methods:
|
||||
- `add_card(card: CardInstance)`
|
||||
- `remove_card(card: CardInstance)`
|
||||
- `get_cards() -> Array[CardInstance]`
|
||||
- `shuffle()`
|
||||
|
||||
#### TurnManager (`scripts/game/TurnManager.gd`)
|
||||
Handles turn structure and phase progression.
|
||||
|
||||
Phases (enum TurnPhase):
|
||||
1. `ACTIVE` - Activate dull characters
|
||||
2. `DRAW` - Draw cards
|
||||
3. `MAIN_1` - Play cards/abilities
|
||||
4. `ATTACK` - Combat
|
||||
5. `MAIN_2` - Play cards/abilities
|
||||
6. `END` - Cleanup
|
||||
|
||||
#### CPPool (`scripts/game/CPPool.gd`)
|
||||
Tracks generated Crystal Points by element.
|
||||
|
||||
Properties:
|
||||
- `cp: Dictionary` - Element -> count mapping
|
||||
|
||||
Methods:
|
||||
- `add_cp(element: Element, amount: int)`
|
||||
- `spend_cp(cost: Dictionary) -> bool`
|
||||
- `can_afford(cost: Dictionary) -> bool`
|
||||
- `clear()`
|
||||
|
||||
#### Combat (`scripts/game/Combat.gd`)
|
||||
Handles attack phase logic.
|
||||
|
||||
States:
|
||||
- `IDLE`
|
||||
- `DECLARING_ATTACKER`
|
||||
- `WAITING_BLOCKER`
|
||||
- `RESOLVING_DAMAGE`
|
||||
|
||||
### Visual Components
|
||||
|
||||
#### TableCamera (`scripts/visual/TableCamera.gd`)
|
||||
Isometric camera setup:
|
||||
- 45° rotation on Y axis
|
||||
- ~35° tilt down on X axis
|
||||
- Orthographic or perspective projection
|
||||
- Fixed position showing full board
|
||||
|
||||
#### CardVisual (`scripts/visual/CardVisual.gd`)
|
||||
3D card representation:
|
||||
- MeshInstance3D with PlaneMesh
|
||||
- Dynamic texture from card image
|
||||
- States: normal, highlighted, selected, dull
|
||||
- Animation support for movement
|
||||
|
||||
#### ZoneVisual (`scripts/visual/ZoneVisual.gd`)
|
||||
Visual representation of card zones:
|
||||
- Manages card positioning
|
||||
- Handles card enter/exit animations
|
||||
- Supports stacking and spreading
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Playing a Card
|
||||
|
||||
```
|
||||
1. Player clicks card in hand
|
||||
│
|
||||
2. InputHandler detects selection
|
||||
│
|
||||
3. GameManager.request_play_card(card)
|
||||
│
|
||||
4. GameState.validate_play(card)
|
||||
├── Check phase (must be Main Phase)
|
||||
├── Check CP requirements
|
||||
└── Check field limits
|
||||
│
|
||||
5. If valid: GameState.execute_play(card)
|
||||
├── CPPool.spend_cp(card.cost)
|
||||
├── Hand.remove_card(card)
|
||||
└── Field.add_card(card)
|
||||
│
|
||||
6. GameState emits card_played signal
|
||||
│
|
||||
7. Visual layer animates card movement
|
||||
```
|
||||
|
||||
### Combat Flow
|
||||
|
||||
```
|
||||
1. Attack Phase begins
|
||||
│
|
||||
2. Active player selects attacker
|
||||
├── Must be active Forward
|
||||
└── Must be able to attack
|
||||
│
|
||||
3. Attacker is dulled
|
||||
│
|
||||
4. Defending player may select blocker
|
||||
├── Must be active Forward
|
||||
└── Optional
|
||||
│
|
||||
5. Damage resolution
|
||||
├── If blocked: Exchange damage equal to Power
|
||||
└── If unblocked: Deal 1 damage to player
|
||||
│
|
||||
6. Check for broken Forwards
|
||||
│
|
||||
7. Return to step 2 or end Attack Phase
|
||||
```
|
||||
|
||||
## File Organization
|
||||
|
||||
```
|
||||
scripts/
|
||||
├── autoload/
|
||||
│ ├── GameManager.gd # Game flow coordinator
|
||||
│ └── CardDatabase.gd # Card data management
|
||||
├── game/
|
||||
│ ├── GameState.gd # Master game state
|
||||
│ ├── Player.gd # Player state
|
||||
│ ├── Zone.gd # Zone base class
|
||||
│ ├── CardInstance.gd # Runtime card instance
|
||||
│ ├── TurnManager.gd # Turn/phase handling
|
||||
│ ├── CPPool.gd # CP tracking
|
||||
│ ├── Combat.gd # Combat resolution
|
||||
│ └── Enums.gd # Shared enumerations
|
||||
├── visual/
|
||||
│ ├── TableCamera.gd # Isometric camera
|
||||
│ ├── CardVisual.gd # 3D card rendering
|
||||
│ ├── ZoneVisual.gd # Zone rendering
|
||||
│ └── TableSetup.gd # Table scene setup
|
||||
└── ui/
|
||||
├── GameUI.gd # Main UI controller
|
||||
├── CardDetailPanel.gd # Card info popup
|
||||
├── CPDisplay.gd # CP pool display
|
||||
└── TurnIndicator.gd # Turn/phase display
|
||||
```
|
||||
|
||||
## Signals Reference
|
||||
|
||||
### GameManager Signals
|
||||
| Signal | Parameters | Description |
|
||||
|--------|------------|-------------|
|
||||
| `game_started` | none | New game initialized |
|
||||
| `game_ended` | `winner: int` | Game over |
|
||||
| `turn_changed` | `player: int` | Active player changed |
|
||||
| `phase_changed` | `phase: TurnPhase` | Phase advanced |
|
||||
|
||||
### GameState Signals
|
||||
| Signal | Parameters | Description |
|
||||
|--------|------------|-------------|
|
||||
| `card_played` | `card, player` | Card deployed to field |
|
||||
| `card_moved` | `card, from, to` | Card changed zones |
|
||||
| `damage_dealt` | `player, amount` | Player took damage |
|
||||
| `forward_broken` | `card` | Forward destroyed |
|
||||
|
||||
### Player Signals
|
||||
| Signal | Parameters | Description |
|
||||
|--------|------------|-------------|
|
||||
| `hand_changed` | none | Hand contents updated |
|
||||
| `cp_changed` | `pool` | CP pool updated |
|
||||
| `field_changed` | none | Field contents updated |
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- Card data validation
|
||||
- CP calculation
|
||||
- Combat damage resolution
|
||||
- Zone operations
|
||||
|
||||
### Integration Tests
|
||||
- Full turn cycle
|
||||
- Complete game to win condition
|
||||
- Edge cases (deck empty, backup limit)
|
||||
|
||||
### Manual Testing
|
||||
- Visual correctness
|
||||
- Input responsiveness
|
||||
- Animation smoothness
|
||||
Reference in New Issue
Block a user