463 lines
No EOL
10 KiB
Markdown
463 lines
No EOL
10 KiB
Markdown
# Battlemap Notation Schema (BMS) - Technical Specification
|
||
|
||
## Schema Version: 1.0
|
||
|
||
## Complete Field Reference
|
||
|
||
### 1. Header Section (Required)
|
||
| Field | Type | Description | Example |
|
||
|-------|------|-------------|---------|
|
||
| `BMS Version` | String | Schema version | `"1.0"` |
|
||
| `Map Name` | String | Map title | `"Goblin Warrens"` |
|
||
| `Grid Size` | String | Width×Height in squares | `"40x30"` |
|
||
| `Grid Unit` | String | Feet per square | `"5ft"` |
|
||
| `Style` | String | Visual theme | `"Stone Cavern"` |
|
||
| `Lighting` | String | Ambient light | `"Dim (torchlight)"` |
|
||
| `Ambient Sound` | String | Background audio | `"Dripping water"` |
|
||
| `Temperature` | String | Environmental temp | `"55°F, damp"` |
|
||
|
||
### 2. Coordinate System
|
||
```
|
||
(0,0)───────→ x (width)
|
||
│
|
||
│
|
||
↓
|
||
y (height)
|
||
|
||
Example: (5,10) = column 6, row 11 (5ft squares)
|
||
Range: (x1,y1)-(x2,y2) defines rectangle
|
||
```
|
||
|
||
### 3. Room Definition
|
||
```yaml
|
||
ROOMS:
|
||
- R1: [Room Name] (x1,y1)-(x2,y2)
|
||
Walls: [Material-Thickness-Style]
|
||
Floor: [Material-Texture]
|
||
Ceiling: [Height-Features]
|
||
Lighting: [Light sources within]
|
||
Features: [Special characteristics]
|
||
```
|
||
|
||
**Wall Types:**
|
||
- `Stone-1ft-Rough`
|
||
- `Wood-6in-Carved`
|
||
- `Iron-2ft-Reinforced`
|
||
- `Masonry-1ft-Smooth`
|
||
- `Natural-Rockface`
|
||
|
||
**Floor Types:**
|
||
- `Rough stone, debris`
|
||
- `Packed earth`
|
||
- `Wooden planks`
|
||
- `Flagstones`
|
||
- `Mosaic tile`
|
||
|
||
### 4. Door Definition
|
||
```yaml
|
||
DOORS:
|
||
- D1: [Door Name]
|
||
Type: [Material-Single/Double-Style]
|
||
Position: (x1,y1)-(x2,y2)
|
||
Connects: [Room1] <-> [Room2]
|
||
State: [Open/Closed]-[Locked/Unlocked]
|
||
Hinges: [Side]
|
||
DC: [Difficulty if locked/trapped]
|
||
```
|
||
|
||
**Door Types:**
|
||
- `Wood-Single-Banded`
|
||
- `Iron-Double-Portcullis`
|
||
- `Stone-Sliding-Secret`
|
||
- `Wood-Double-Ornate`
|
||
|
||
**States:**
|
||
- `Open-Unlocked`
|
||
- `Closed-Locked` (DC15)
|
||
- `Closed-Barred`
|
||
- `Destroyed`
|
||
|
||
### 5. Object Definition
|
||
```yaml
|
||
OBJECTS:
|
||
- O1: [Object Name]
|
||
Type: [Material-Type-Style]
|
||
Position: (x1,y1)-(x2,y2)
|
||
Elevation: [+/- ft from floor]
|
||
State: [Condition]
|
||
Contents: [What's inside]
|
||
Lock: [Lock details if applicable]
|
||
Trapped: [Trap details if applicable]
|
||
```
|
||
|
||
**Object Types:**
|
||
- `Wood-Table-Rough`
|
||
- `Stone-Throne-Ornate`
|
||
- `Iron-Chest-Large`
|
||
- `Wood-Barrel-Sturdy`
|
||
- `Stone-Altar-Carved`
|
||
|
||
### 6. Hazard Definition
|
||
```yaml
|
||
HAZARDS:
|
||
- H1: [Hazard Name]
|
||
Type: [Mechanical/Magical/Environmental]-[Effect]
|
||
Position: (x1,y1)-(x2,y2)
|
||
Trigger: [Activation mechanism]
|
||
DC: [Perception/Disable DCs]
|
||
Save: [Saving throw type & DC]
|
||
Damage: [Damage dice]
|
||
Effect: [Additional effects]
|
||
Reset: [Manual/Automatic]
|
||
```
|
||
|
||
**Hazard Types:**
|
||
- `Mechanical-Pit-20ft`
|
||
- `Magical-Glyph-Fire`
|
||
- `Environmental-Gas-Poison`
|
||
- `Mechanical-Dart-Pressure`
|
||
- `Magical-Fear-Aura`
|
||
|
||
### 7. Lighting Definition
|
||
```yaml
|
||
LIGHTING:
|
||
- L1: [Light Name]
|
||
Type: [Source-Type]
|
||
Position: (x,y)
|
||
Radius: [Bright ft, Dim ft]
|
||
Color: [Light color]
|
||
Fuel: [Duration/Fuel source]
|
||
Special: [Flickering/Steady etc]
|
||
```
|
||
|
||
**Light Types:**
|
||
- `Torch-Wall`
|
||
- `Lantern-Hanging`
|
||
- `Candle-Table`
|
||
- `Magical-Everburning`
|
||
- `Fungi-Bioluminescent`
|
||
|
||
### 8. Connection Graph
|
||
```yaml
|
||
CONNECTIONS:
|
||
[Room1] -- [Door/Passage] --> [Room2]
|
||
[Room2] -- [Tunnel] --> [Room3]
|
||
[Room3] -- [Secret] --> [Room4]
|
||
```
|
||
|
||
**Connection Types:**
|
||
- `-- [Door] -->` (Standard door)
|
||
- `-- [Secret] -->` (Hidden passage)
|
||
- `-- [Tunnel] -->` (Long corridor)
|
||
- `-- [Stairs] -->` (Vertical connection)
|
||
|
||
### 9. Annotation Definition
|
||
```yaml
|
||
ANNOTATIONS:
|
||
- "[Text]" at (x,y)
|
||
- "[Label]" pointing to (x1,y1)-(x2,y2)
|
||
- "DM: [Note]" at (x,y)
|
||
```
|
||
|
||
## Advanced Features
|
||
|
||
### Multi-level Maps
|
||
```yaml
|
||
ELEVATION:
|
||
- Base Level: 0ft
|
||
- Upper Balcony: +15ft
|
||
- Lower Pit: -20ft
|
||
|
||
STAIRS:
|
||
- S1: Spiral Stairs
|
||
Position: (25,15)-(27,17)
|
||
Connects: Level1 -> Level2 (+10ft)
|
||
Steps: 20
|
||
```
|
||
|
||
### Secret/Concealed Features
|
||
```yaml
|
||
SECRETS:
|
||
- S1: Hidden Door
|
||
Position: (14,12)-(14,14)
|
||
Type: Stone-Sliding
|
||
DC: 20 Perception
|
||
Mechanism: Lever at (12,18)
|
||
Revealed: When mechanism activated
|
||
```
|
||
|
||
### Environmental Zones
|
||
```yaml
|
||
ZONES:
|
||
- Z1: Fog Bank
|
||
Position: (10,10)-(20,20)
|
||
Effect: Heavily obscured
|
||
Save: None
|
||
Movement: Normal
|
||
|
||
- Z2: Slippery Ice
|
||
Position: (30,30)-(40,40)
|
||
Effect: Difficult terrain
|
||
Save: DC 10 Acrobatics or fall prone
|
||
```
|
||
|
||
## Visualization Standards
|
||
|
||
### Color Coding (Suggested)
|
||
- **Walls:** Dark gray (#333333)
|
||
- **Doors:** Brown (#8B4513)
|
||
- **Hazards:** Red (#FF0000) with pattern
|
||
- **Objects:** Medium gray (#666666)
|
||
- **Light sources:** Yellow glow (#FFFF00)
|
||
- **Water:** Blue (#0000FF)
|
||
- **Difficult terrain:** Green diagonal lines
|
||
- **Elevation changes:** Contour lines
|
||
|
||
### Icon Standards
|
||
- **Door:** Rectangle with arc
|
||
- **Chest:** Rectangle with curved lid
|
||
- **Table:** Rectangle
|
||
- **Chair/T hrone:** Square with back
|
||
- **Torch:** Small circle with flame above
|
||
- **Pit:** Diagonal hatch pattern
|
||
- **Secret:** Dotted outline
|
||
|
||
## Example: Simple Guard Room
|
||
|
||
```yaml
|
||
BMS Version: 1.0
|
||
Map Name: Guard Room
|
||
Grid Size: 20x15
|
||
Grid Unit: 5ft
|
||
Style: Stone Fortress
|
||
Lighting: Torchlight
|
||
|
||
ROOMS:
|
||
- R1: Guard Room (0,0)-(20,15)
|
||
Walls: Stone-1ft-Smooth
|
||
Floor: Flagstones
|
||
Ceiling: 15ft, wooden beams
|
||
Lighting: Wall torches at (3,0), (17,0)
|
||
|
||
DOORS:
|
||
- D1: Wooden Door (20,6)-(20,9)
|
||
Type: Wood-Single-Reinforced
|
||
Connects: R1 -> Corridor
|
||
State: Closed-Unlocked
|
||
Hinges: East side
|
||
|
||
OBJECTS:
|
||
- O1: Guard Table (5,5)-(9,9)
|
||
Type: Wood-Table-Sturdy
|
||
Contents: Maps, mugs, dice
|
||
|
||
- O2: Weapon Rack (15,5)-(17,10)
|
||
Type: Wood-Rack-Wall
|
||
Contents: 4 spears, 2 swords
|
||
|
||
LIGHTING:
|
||
- L1: Wall Torch (3,0)
|
||
Radius: 20ft bright, 40ft dim
|
||
Color: Orange flickering
|
||
|
||
- L2: Wall Torch (17,0)
|
||
Radius: 20ft bright, 40ft dim
|
||
Color: Orange flickering
|
||
|
||
ANNOTATIONS:
|
||
- "Guard post" at (10,7)
|
||
- "Weapons" pointing to O2
|
||
```
|
||
|
||
## TypeScript Interface Definition
|
||
|
||
```typescript
|
||
// Core BMS Types
|
||
type Coordinate = [number, number]; // (x, y)
|
||
type Rectangle = { from: Coordinate; to: Coordinate };
|
||
|
||
interface BMSHeader {
|
||
bmsVersion: string;
|
||
mapName: string;
|
||
gridSize: { width: number; height: number };
|
||
gridUnit: string;
|
||
style: string;
|
||
lighting: string;
|
||
ambientSound?: string;
|
||
temperature?: string;
|
||
}
|
||
|
||
interface Room {
|
||
id: string; // "R1"
|
||
name: string;
|
||
position: Rectangle;
|
||
walls: string; // "Stone-1ft-Rough"
|
||
floor: string; // "Rough stone, debris"
|
||
ceiling: string; // "15ft, wooden beams"
|
||
lighting?: string;
|
||
features?: string;
|
||
}
|
||
|
||
interface Door {
|
||
id: string; // "D1"
|
||
name: string;
|
||
type: string; // "Wood-Single-Banded"
|
||
position: Rectangle;
|
||
connects: { room1: string; room2: string };
|
||
state: { open: boolean; locked: boolean; dc?: number };
|
||
hinges?: string; // "East side"
|
||
}
|
||
|
||
interface MapObject {
|
||
id: string; // "O1"
|
||
name: string;
|
||
type: string; // "Wood-Table-Rough"
|
||
position: Rectangle;
|
||
elevation?: string; // "+2ft"
|
||
state?: string;
|
||
contents?: string;
|
||
lock?: string;
|
||
trapped?: string;
|
||
}
|
||
|
||
interface Hazard {
|
||
id: string; // "H1"
|
||
name: string;
|
||
type: string; // "Mechanical-Pit-20ft"
|
||
position: Rectangle;
|
||
trigger?: string;
|
||
dc?: { perception?: number; disable?: number };
|
||
save?: { type: string; dc: number };
|
||
damage?: string;
|
||
effect?: string;
|
||
reset?: string;
|
||
}
|
||
|
||
interface LightSource {
|
||
id: string; // "L1"
|
||
name: string;
|
||
type: string; // "Torch-Wall"
|
||
position: Coordinate;
|
||
radius: { bright: number; dim: number };
|
||
color?: string;
|
||
fuel?: string;
|
||
special?: string;
|
||
}
|
||
|
||
interface Connection {
|
||
from: string; // Room ID
|
||
to: string; // Room ID
|
||
type: string; // "Door", "Secret", "Tunnel", "Stairs"
|
||
via?: string; // Door ID if applicable
|
||
}
|
||
|
||
interface Annotation {
|
||
text: string;
|
||
position: Coordinate;
|
||
type?: "label" | "note" | "pointer";
|
||
target?: Rectangle; // For pointer annotations
|
||
}
|
||
|
||
interface BMSSchema extends BMSHeader {
|
||
rooms?: Room[];
|
||
doors?: Door[];
|
||
objects?: MapObject[];
|
||
hazards?: Hazard[];
|
||
lightingSources?: LightSource[];
|
||
connections?: Connection[];
|
||
annotations?: Annotation[];
|
||
|
||
// Advanced features (future)
|
||
elevation?: Elevation[];
|
||
stairs?: Stairs[];
|
||
secrets?: Secret[];
|
||
zones?: Zone[];
|
||
}
|
||
```
|
||
|
||
## Parser Functions
|
||
|
||
### Grid Size Parser
|
||
```typescript
|
||
function parseGridSize(str: string): { width: number; height: number } {
|
||
// "40x30" → { width: 40, height: 30 }
|
||
const match = str.match(/^(\d+)x(\d+)$/);
|
||
if (!match) throw new Error(`Invalid grid size: ${str}`);
|
||
return { width: parseInt(match[1]), height: parseInt(match[2]) };
|
||
}
|
||
```
|
||
|
||
### Coordinate Parser
|
||
```typescript
|
||
function parseCoordinate(str: string): Coordinate {
|
||
// "(5,10)" → [5, 10]
|
||
const match = str.match(/^\((\d+),(\d+)\)$/);
|
||
if (!match) throw new Error(`Invalid coordinate: ${str}`);
|
||
return [parseInt(match[1]), parseInt(match[2])];
|
||
}
|
||
```
|
||
|
||
### Rectangle Parser
|
||
```typescript
|
||
function parseRectangle(str: string): Rectangle {
|
||
// "(0,0)-(20,15)" → { from: [0,0], to: [20,15] }
|
||
const match = str.match(/^\((\d+),(\d+)\)-\((\d+),(\d+)\)$/);
|
||
if (!match) throw new Error(`Invalid rectangle: ${str}`);
|
||
return {
|
||
from: [parseInt(match[1]), parseInt(match[2])],
|
||
to: [parseInt(match[3]), parseInt(match[4])]
|
||
};
|
||
}
|
||
```
|
||
|
||
### Door State Parser
|
||
```typescript
|
||
function parseDoorState(str: string): { open: boolean; locked: boolean; dc?: number } {
|
||
// "Open-Unlocked" → { open: true, locked: false }
|
||
// "Closed-Locked (DC15)" → { open: false, locked: true, dc: 15 }
|
||
const match = str.match(/^(Open|Closed)-(Unlocked|Locked)(?: \(DC(\d+)\))?$/);
|
||
if (!match) throw new Error(`Invalid door state: ${str}`);
|
||
|
||
return {
|
||
open: match[1] === "Open",
|
||
locked: match[2] === "Locked",
|
||
dc: match[3] ? parseInt(match[3]) : undefined
|
||
};
|
||
}
|
||
```
|
||
|
||
## Validation Rules
|
||
|
||
### Required Fields
|
||
1. `BMS Version` must be "1.0"
|
||
2. `Map Name` must be non-empty string
|
||
3. `Grid Size` must match pattern "WxH" where W,H > 0
|
||
4. `Grid Unit` must contain "ft" (e.g., "5ft")
|
||
|
||
### Coordinate Validation
|
||
1. Coordinates must be within grid bounds
|
||
2. Rectangle `from` coordinates must be ≤ `to` coordinates
|
||
3. Room rectangles must not overlap (optional warning)
|
||
|
||
### Door Validation
|
||
1. Door must connect two existing rooms
|
||
2. Door position must be on room boundary
|
||
3. Hinge side must be consistent with door position
|
||
|
||
### Lighting Validation
|
||
1. Light position must be within a room
|
||
2. Bright radius ≤ dim radius
|
||
3. Color must be valid CSS color
|
||
|
||
## Best Practices
|
||
|
||
1. **Start Simple**: Define rooms and connections first
|
||
2. **Be Specific**: Use exact coordinates, not "center of room"
|
||
3. **Consistent Naming**: R1, D1, O1, H1, L1, etc.
|
||
4. **Include DCs**: For all interactive elements
|
||
5. **Visual Notes**: Describe what players SEE
|
||
6. **Mechanical Notes**: Describe what players INTERACT WITH
|
||
7. **Layer Complexity**: Add hazards/objects after base layout
|
||
|
||
---
|
||
*Last Updated: March 19, 2026* |