# Seymour Take One - Game & Editor Documentation

A 2D platformer adventure game with an integrated level editor, inspired by classic Dizzy-style games.

## Table of Contents

1. [Game Features](#game-features)
2. [Game Controls](#game-controls)
3. [Editor Features](#editor-features)
4. [Editor Controls](#editor-controls)
5. [Gameplay Systems](#gameplay-systems)
   - [Moving Platform Mechanics](#moving-platform-mechanics)
6. [Editor Systems](#editor-systems)
7. [Trigger System](#trigger-system)
8. [Tips](#tips)
9. [Technical Details](#technical-details)

---

## Game Features

### Core Gameplay

**Player Movement**
- **Walking**: Left/right movement with smooth animation
- **Jumping**: Vertical and horizontal jumping with physics
- **Falling**: Gravity-based falling with collision detection
- **Swimming**: Underwater movement with surface detection and breath mechanics
- **Climbing**: Ladder climbing with back and side orientations
- **One-way Platforms**: Can jump up through platforms, but land on top
- **Step-up Detection**: Automatically steps up small obstacles while walking

**Player States**
- Idle, Walk, Jump, Fall, Swim, Climb
- Side jump/fall animations for horizontal movement in air
- Landing animations when touching ground after side jumps
- Weather-triggered sad face animation (after 10 seconds of rain/snow exposure)

**Character Customization**
- **Color Replacement**: Customize glove and shoe colors (dark and light variants)
- **Idle Face Animations**: Multiple animations that play when player is idle for 3+ seconds
- **Sad Face Animation**: Plays when player is exposed to rain/snow for 10+ seconds
- **Animation System**: Frame-based animations with timing, occurrence rates, and sprite offsets

### Inventory System

**3-Slot FILO (First In, Last Out) Inventory**
- Picking up a new item shifts all existing items to the right
- If inventory is full, the rightmost item is automatically dropped
- **Smooth Animations**: Items scroll in/out with easing functions
- **Drop Animations**: Dropped items fall to safe positions with collision detection
- **Visual Feedback**: Items animate when picked up, dropped, or shifted
- Items can be picked up or dropped via interaction key

### Dialogue Systems

**Traditional Dialogue System**
- Textbox-based dialogue at bottom of screen
- Links between dialogue lines form conversation trees
- Dialogue status tracking per entity
- Supports multiple dialogue owners (NPCs, items, etc.)

**Bubble Dialogue System**
- Speech bubbles that appear above entities or player
- Multiple styles: Speech, Thought, Yell, Narration
- Callout orientation (North, South, NW, NE, SW, SE)
- Positioned relative to speaker entity
- Used for item pickup messages and trigger-based dialogue

### Weather System

**Weather Effects**
- **Rain**: Falling raindrops with splash effects on collision
- **Snow**: Floating snowflakes with accumulation on surfaces
- **Heat**: Heat shimmer distortion effects
- **Cover Detection**: Player is protected when under solid tiles
- **Particle Collision**: Weather particles interact with solid tiles and water
- **Ramp Up/Fade Out**: Weather effects gradually start and end
- **Random Timing**: Weather can trigger randomly based on chance per minute
- **Duration Control**: Configurable minimum and maximum duration

**Weather Impact on Player**
- Rain/snow particles can hit player (tracked for 5 seconds after last hit)
- After 10 seconds of exposure while idle, player shows sad face animation
- Weather respects collision - player under cover is protected

### Entity System

**Entity Types**
- **Items**: Pickable objects that can be added to inventory
- **NPCs**: Non-player characters with dialogue
- **Teleports**: Entities that transport player to different rooms
- **Hazards**: Entities that damage player over time (HurtDps)
- **Moving Platforms**: Animated entities that move along paths and carry the player
- **Animated Entities**: Complex entities with multiple animations and movements

**Entity Properties**
- Position, bounds, room assignment
- Pickable/Droppable flags
- Dialogue status tracking
- Teleport destinations (room, X, Y)
- Damage per second (for hazards)
- Platform data (for moving platforms)
- Sprite and animation support

### Moving Platform System

Moving platforms are animated entities that follow defined paths and can carry the player. They support complex movement patterns including elevators, trams, and cross-room travel.

**Platform Data Properties**
- **Solid**: Whether the platform participates in collision (default: true)
- **OneWay**: If true, player can jump through from below (default: false)
- **Carry**: How the platform carries passengers (`groundedOnly`, `always`, `never`)
- **Collider**: Custom collision rectangle with width, height, and offset

**Path Movement System**
- **Checkpoints**: Global waypoints defined with ID, room, and coordinates
- **Path Segments**: Movement between two points (checkpoint IDs or inline coordinates)
- **Speed or Duration**: Configure movement by speed (units/sec) or explicit duration (ms)
- **Easing Functions**: 30+ easing options for smooth acceleration/deceleration
- **Wait Times**: Configurable delays at segment start and end
- **Trigger Hooks**: Fire triggers on departure and arrival at checkpoints

**Cross-Room Movement**
- Platforms can travel between different rooms
- Room transitions happen automatically at segment completion
- Checkpoints can reference any room in the game
- Platform carries player across room boundaries

**Movement Control**
- **Start Mode**: `idle` (wait for trigger) or `autoStart` (begin immediately)
- **Looping**: No loop, fixed count, or infinite looping
- **Runtime Control**: Start, stop, pause, resume via triggers
- **Target Navigation**: Set destination checkpoint for elevator-style "call" behavior

**Available Easing Functions**
- Linear (no easing)
- Quad, Cubic, Quart, Quint (polynomial)
- Sine, Expo, Circ (mathematical curves)
- Back (overshoot), Elastic (spring), Bounce (bouncing)
- Each with In, Out, and InOut variants (e.g., `InQuad`, `OutQuad`, `InOutQuad`)

### Trigger System

**Event-Driven Automation**
- Responds to game events (player actions, room changes, timers)
- Conditional logic (AND-based conditions)
- Multiple actions per trigger
- Room and entity filtering
- See [Trigger System](#trigger-system) section for full details

### Room System

**Multi-Room World**
- Independent rooms (screens) with neighbor links
- Automatic room transitions when leaving bounds
- Room descriptions displayed in UI
- Room ID displayed in top-left corner
- Each room has its own tilemap and entities

### Collision System

**Tile-Based Collision**
- Layer 2 tiles provide solid collision
- Pixel-perfect collision detection
- One-way platforms (flag 2)
- Moving platforms (flag 3)
- Water tiles for swimming
- Climbable tiles for ladders

### Post-Processing Effects

**Visual Filters** (Toggle with F8-F12)
- **CRT Effect** (F10): Scanlines, curvature, vignette, corner rounding
- **Phosphor Decay** (F11): Persistent glow effect
- **Scale2x** (F9): Pixel art upscaling algorithm
- **VHS Effect** (F12): VHS tape distortion, chroma shift, noise
- **Green Monitor** (F8): Monochrome green terminal effect
- All effects can be toggled independently
- Toggle messages displayed on screen

### Audio System

**Sound Effects**
- Jump sound plays when jumping
- Sound manager loads and plays WAV files from `Data/Audio/`
- Supports volume, pitch, and pan control

### UI Features

**Film Strip Animation** (F5)
- Animated film strip border around gameplay area
- Retracts/extends with smooth animation
- Creates cinematic frame effect

**Screenshot** (F1)
- Saves screenshots as PNG files to `Data/screenshots/` directory with timestamp
- Captures the 480×270 game area

**Version Display**
- Shows version number from `version.txt` in top-left
- Room ID displayed next to version

**Room Description**
- Displays room description text in light blue
- Centered in description area

---

## Game Controls

### Display
- **`Alt + Enter`**: Toggle borderless fullscreen mode

### Keyboard Controls
- **Arrow Keys / `Z` / `X`**: Move left/right
- **`Space` / `Up Arrow`**: Jump
- **`Enter` / `0`**: Interact (pick up items, talk to NPCs, activate teleports, advance dialogue)
- **`Backspace` / `9`**: Drop top item from inventory
- **`Up Arrow`**: Move up (in menus/dialogue, climb ladders, swim up)
- **`Down Arrow`**: Move down (in menus/dialogue, swim down)
- **`Escape`**: Pause
- **`Tab`**: Toggle editor mode
- **`F1`**: Take screenshot (saves as PNG to `Data/screenshots/` directory)
- **`F5`**: Toggle film strip animation (retract/extend)
- **`F8`**: Toggle green monitor effect
- **`F9`**: Toggle Scale2x upscaling
- **`F10`**: Toggle CRT effect
- **`F11`**: Toggle phosphor decay effect
- **`F12`**: Toggle VHS effect

### Gamepad Controls
The game automatically detects and uses the first connected gamepad controller. All keyboard controls are mapped to gamepad:

- **Left Thumbstick**: 
  - **X-axis**: Move left/right
  - **Y-axis up**: Move up (climb, swim up)
  - **Y-axis down**: Move down (swim down/dive)
- **`A` Button**: Jump
- **`X` Button**: Interact
- **`Y` Button**: Drop item
- **D-Pad Up**: Move up (in menus/dialogue, climb, swim up)
- **D-Pad Down**: Move down (in menus/dialogue, swim down)
- **`Start` Button**: Pause
- **`Back` Button**: Toggle editor mode

**Note**: Keyboard and gamepad controls work simultaneously - you can use either input method at any time.

---

## Editor Features

### Editor Modes

The editor supports multiple modes, cycled with the `I` key:

1. **Room**: Unified editor for placing and editing tiles, items, and animated entities
2. **Triggers**: Create event-driven triggers
3. **Weather**: Configure weather effects
4. **Character**: Customize player appearance and animations
5. **Dialogues**: Edit dialogue trees
6. **Presentations**: Edit presentation sequences
7. **General Settings**: Configure general game settings

### Room Editor

The Room Editor is a unified mode that combines tile, item, and animated entity editing into a single workflow. All elements can be placed and edited in the same view.

**Outliner Window**
- Hierarchical list showing all room elements organized by layers
- **Layer 1**: Far background tiles
- **Layer 2**: Collision tiles (behind player)
- **Layer 3**: Gameplay layer with:
  - Tiles
  - Items (in current room)
  - Animated entities (in current room)
- **Layer 4**: Foreground tiles
- Click headers to expand/collapse sections
- Click items in the list to select and focus them on the map
- Color coding: Tiles (green), Items (orange), Animated entities (cyan), Cloud tiles (white)
- Visible only in Room editor mode
- Draggable and resizable window (default position: left side)

**Shape Tools** (for tiles)
- **Rectangle**: Draw rectangular tile areas
- **Ellipse**: Draw elliptical/circular tile areas
- **Bezier Curve**: Draw curved paths with control points
- **Water**: Place water tiles for swimming
- **Climbable**: Place ladder/climbable tiles
- **Horizon**: Place horizon tiles

**Tile Operations**
- **Place tiles**: Select a shape tool (Rect, Ellipse, Bezier, Water, Climb, Horizon) or a tile from the palette, then click and drag on the map to place (release to drop)
- **Select tiles**: Click to select (yellow outline)
- Tiles and animations can be clicked and manipulated from any layer
- Cycle through overlapping tiles with `Q`/`E`
- Move selected tiles with arrow keys (1 pixel) or drag
- Rotate tiles (15° steps)
- Flip tiles horizontally/vertically
- Tile sprites (repeat patterns)
- Delete tiles with `Delete` key or right-click
- Context menu: Send to back, bring to front, send backward, bring forward, copy, paste
- **Modifiable tiles**: Right-click on a tile in the Outliner to toggle "Set modifiable" / "Clear modifiable"
  - Modifiable tiles are displayed in darker green in the Outliner
  - Only modifiable tiles can be targeted by the `set_tile_attributes` trigger action
  - Default state: tiles are not modifiable (modifiable = 0)

**Item Operations**
- **Place items**: Select an item from the palette (items source), then click and drag on the map to place (release to drop)
- **Select items**: Click to select (yellow outline)
- Drag to reposition
- Arrow keys move by 1 pixel
- `Delete` key to remove selected item

**Animated Entity Operations**
- **Place entities**: Enable Place mode in the Animated Entity Editor, then click and drag on the map to place (release to drop)
- **Select entities**: Click to select (yellow outline)
- Drag to reposition
- Arrow keys move by 1 pixel
- `Delete` key to remove selected entity
- Selecting an animated entity opens the Animated Entity Editor panel

**Layers**
- **Layer 1**: Far background (cached for performance)
- **Layer 2**: Behind player (collision layer)
- **Layer 3**: Player layer (same as items/animated entities)
- **Layer 4**: Foreground (in front of player)
- Switch layers with `1`-`4` keys
- Layer switching view: Only tiles from the active layer are selectable (except tiles and animations can be clicked from any layer)

**Selection Behavior**
- Selecting any element (tile, item, or animated entity) also selects it in the Outliner and scrolls to it
- Selecting items in the Outliner focuses them on the map
- Only one element can be selected at a time (selection clears when switching types)

### Animated Entity Editor

**Template System**
- Create reusable entity templates
- Templates saved in `Data/game.json`
- Place template instances in rooms
- Edit templates or individual instances

**Animation System**
- Multiple animations per entity
- Frame-based animations with timing
- Loop control (0 = infinite)
- Sprite composition per frame
- Sprite transformations (offset, flip, rotation, tiling)
- Flag-based sprite visibility

**Movement System**
- Movement paths with keyframes
- Interpolated movement between frames
- Hold, relative move, and absolute position frame types
- Loop control for movements
- Movement and animation can run simultaneously

**Editor Controls**
- Place mode: Toggle to place new entities
- Edit mode: Switch between template and selected entity
- Template management: New, save, update, delete
- Animation editor: Add/remove animations and frames
- Frame editor: Adjust timing, sprites, transformations
- Live preview: See animation playing in real-time

### Trigger Editor

**Trigger Management**
- Create, edit, and delete triggers
- Enable/disable triggers
- Room and entity filtering
- Multiple conditions (AND logic)
- Multiple actions per trigger
- See [Trigger System](#trigger-system) section for full details

### Weather Editor

**Weather Effect Configuration**
- Add rain, snow, or heat effects
- Configure chance per minute (0-100%)
- Set duration range (min/max seconds)
- Adjust intensity (rain/snow: 1-12, heat: 0.0-1.0)
- Enable/disable individual effects
- Test effects immediately
- Stop current weather

**Weather Properties**
- **Rain**: Intensity controls drop count (1-12 scale, 2-960 drops)
- **Snow**: Intensity controls flake count (1-12 scale, 1-640 flakes)
- **Heat**: Intensity controls shimmer strength (0.0-1.0)

### Character Editor

**Color Customization**
- **Glove Colors**: Dark and light variants (RGB controls)
- **Shoe Colors**: Dark and light variants (RGB controls)
- Color preview swatches
- Reset to defaults button

**Idle Face Animations**
- Multiple idle animations
- Each animation has occurrence rate (1-100)
- Frame-based with timing (milliseconds)
- Sprite selection from palette
- Position offset (X, Y) relative to player center
- Live preview with play/pause controls
- Animations play when player is idle for 3+ seconds

**Sad Face Animation**
- Triggered by rain/snow exposure (10+ seconds)
- Same frame-based system as idle animations
- Separate preview and controls
- Create/delete sad animation

---

## Editor Controls

### Editor Toggle & Navigation
- **`Tab`**: Toggle editor mode on/off
- **`I`**: Cycle placement mode (Room → Triggers → Weather → Character → Dialogues → Presentations → General Settings → Room)
- **`1`–`4`**: Switch active layer (1-4) in Room editor
- **Middle mouse drag**: Pan the view
- **`Ctrl` + mouse wheel**: Zoom in/out (range: 0.25x to 4x, proportional steps)
- **Mouse wheel** (without Ctrl): Scroll palette windows, source bar, Outliner, entity lists, or trigger lists

### Selection & Placement (Room Editor)
- **Left click**: Select existing tile/item/entity
- **Click and drag**: With a placement tool active (shape button, item from palette, or entity Place mode), click on the map and drag to place; release to drop
- **Right click**: Remove tile/item/entity at cursor position
- **`Q` / `E`**: Cycle through tiles at cursor position
- **Arrow keys**: 
  - Move selected tile/item/entity by 1 pixel
  - Navigate between rooms (when no tile/item/entity is selected)
- **`Delete`**: Remove selected tile/item/entity

### Outliner Controls
- **Click header**: Expand/collapse section
- **Click item**: Select and focus element on map
- **Mouse wheel**: Scroll Outliner content
- **Drag header**: Move Outliner window
- **Drag resize handle**: Resize Outliner window

### Room Navigation
- When no tile/item/entity is selected, use **arrow keys** to navigate between adjacent rooms
- Rooms are automatically created when navigating to new areas
- Current room ID is displayed in the editor panel

---

## Gameplay Systems

### Interaction System

**Interaction Priority** (when pressing Interact key):
1. **NPC Dialogue**: If near an NPC with dialogue, start conversation
2. **Pickable Items**: If near a pickable item, add to inventory
3. **Teleports**: If near a teleport entity, transport to destination room
4. **Drop Item**: If no other interaction, drop top inventory item

**Line of Sight**
- Items require clear line of sight to pick up
- Checks for solid collision between player and item
- Allows pickup near ramps and slopes

### Collision Detection

**Player Collision**
- Hitbox: 29×20 pixels, offset from sprite center
- Ground snapping: Player snaps to ground when on solid surface
- Penetration resolution: Automatically moves player out of solid tiles
- Step-up: Can step up small obstacles (up to 4 pixels)
- One-way platforms: Can jump up through, but land on top

**Entity Collision**
- Items check collision when dropped
- Items find safe drop positions (avoid solid tiles)
- Hazards damage player on contact
- Teleports activate on contact

### Room Transitions

**Automatic Transitions**
- When player leaves room bounds, transition to adjacent room
- Transitions based on direction (north, south, east, west)
- Player position adjusted based on transition direction
- Room links defined in room data

**Teleport Entities**
- Manual room transitions via teleport entities
- Can set specific X/Y coordinates or keep current position
- Negative coordinates keep current position for that axis

### Inventory Mechanics

**Pickup Process**
1. Item removed from world (RoomId = -1)
2. All existing items shift right
3. New item placed in slot 0
4. If inventory full, rightmost item dropped
5. Animations play for all shifting items

**Drop Process**
1. Top item removed from inventory
2. All remaining items shift left
3. Dropped item placed in world at safe position
4. Item falls to ground with animation

**Safe Drop Position**
- Starts at player center
- Moves down pixel-by-pixel until collision-free
- Finds ground below and positions item just above
- Ensures item doesn't intersect solid tiles

### Dialogue Flow

**Traditional Dialogue**
- Start: Find link with `in == -1` for owner
- Advance: Find link with `in == lastLineId`
- End: No more links or player cancels
- Status: Can set entity dialogue status via links

**Bubble Dialogue**
- Triggered by dialogue IDs
- Positioned relative to speaker
- Multiple styles and orientations
- Advances with Interact or Jump key

### Weather Mechanics

**Weather Spawning**
- Checks every minute for new weather
- Rolls chance per minute for each enabled effect
- Only one weather type active at a time
- Random duration between min and max

**Particle Systems**
- Rain: Drops fall with velocity, create splashes on collision
- Snow: Flakes float down with sway, accumulate on surfaces
- Heat: Shimmers rise with wave distortion
- All particles respect gameplay boundaries
- Particles collide with solid tiles and water

**Cover Detection**
- Checks if solid tile exists above player
- Player protected from rain/snow when under cover
- Weather particles still visible but don't hit player

### Moving Platform Mechanics

Moving platforms are a special type of animated entity that can carry the player along defined paths. They support complex behaviors like elevators, trams, and cross-room transportation.

**Checkpoint System**
- Checkpoints are global waypoints defined at the game level
- Each checkpoint has a unique ID, room ID, and X/Y coordinates
- Platforms reference checkpoints by ID in their path segments
- Example checkpoint: `{ "id": "cp_room0_elevator_top", "roomId": 0, "x": 240, "y": 40 }`

**Path Segments**
- Each segment defines movement from one point to another
- Points can be checkpoint IDs (strings) or inline coordinates
- Inline format: `{ "roomId": 0, "x": 100, "y": 50 }`

**Timing Options**
1. **Speed-based**: Set `speed` in units per second, duration calculated from distance
2. **Duration-based**: Set `durationMs` for explicit timing regardless of distance
3. If neither specified, defaults to 1000ms

**Easing Functions**
Easing controls acceleration/deceleration along the path:
- `Linear` - Constant speed (no easing)
- `InQuad`, `OutQuad`, `InOutQuad` - Quadratic curves
- `InCubic`, `OutCubic`, `InOutCubic` - Cubic curves
- `InSine`, `OutSine`, `InOutSine` - Sinusoidal curves
- `InExpo`, `OutExpo`, `InOutExpo` - Exponential curves
- `InBack`, `OutBack`, `InOutBack` - Overshoot curves
- `InElastic`, `OutElastic`, `InOutElastic` - Spring/elastic curves
- `InBounce`, `OutBounce`, `InOutBounce` - Bouncing curves

**Wait Times**
- `waitMsAtStart`: Pause before starting segment movement
- `waitMsAtEnd`: Pause after completing segment before continuing

**Trigger Integration**
- `onDepart`: Fire trigger when platform starts moving from a checkpoint
- `onArrive`: Fire trigger when platform arrives at a checkpoint
- Triggers are fired by ID and execute associated actions

**Carry Behavior**
When player stands on a moving platform:
- Platform's movement delta is applied to player each frame
- Player moves with platform automatically
- `groundedOnly` (default): Only carry when player is standing on top
- `always`: Carry even when jumping/falling through platform
- `never`: Platform moves but doesn't carry player

**Cross-Room Travel**
- If destination checkpoint is in a different room, platform transitions rooms
- Platform's room ID updates to match destination
- Player riding the platform transitions with it
- Useful for trams, elevators between floors in different rooms

**Movement States**
- `Idle`: Platform is stationary, waiting for start command
- `WaitingAtStart`: Pausing before segment begins
- `Moving`: Actively interpolating position along segment
- `WaitingAtEnd`: Pausing after segment completion
- `Completed`: All segments finished (non-looping paths)

**Platform Collider**
- Platforms have a separate collision rectangle from their sprite
- Collider can be offset from entity origin
- Properties: `w` (width), `h` (height), `offsetX`, `offsetY`
- Example: `{ "w": 32, "h": 8, "offsetX": -16, "offsetY": -4 }`

**Elevator Pattern**
For elevator-style platforms that respond to "call" buttons:
1. Define checkpoints for each floor
2. Create platform with path segments connecting floors
3. Set `startMode: "idle"` so it waits for commands
4. Use `call_elevator` action to set target checkpoint
5. Platform navigates to target and stops

**Example Platform Configuration** (in game.json):
```json
{
  "type": 0,
  "roomId": 0,
  "x": 240,
  "y": 200,
  "platform": {
    "solid": true,
    "oneWay": false,
    "carry": "groundedOnly",
    "collider": { "w": 32, "h": 8, "offsetX": -16, "offsetY": -4 }
  },
  "movements": [{
    "id": "elevator_main",
    "movementFrames": [{
      "type": "path",
      "startMode": "idle",
      "segments": [
        {
          "from": "cp_elevator_bottom",
          "to": "cp_elevator_top",
          "speed": 40,
          "posEasing": "InOutSine",
          "waitMsAtEnd": 500
        }
      ]
    }]
  }]
}
```

### Entity Updates

**Animated Entities**
- Update animations and movements each frame
- Respect loop counts
- Can pause animations
- Movement interpolates between keyframes
- Flag-based sprite visibility

**Moving Platforms**
- Move along defined paths
- Player can ride platforms (carry behavior)
- Collision detection with moving platforms
- Path-based movement with checkpoints
- Speed or duration-based timing
- Easing support for smooth motion
- Cross-room travel capability

**Hazards**
- Damage player continuously while in contact
- Damage per second (HurtDps) property
- Player energy decreases over time

---

## Editor Systems

### Outliner System

**Outliner Window**
- Hierarchical list of all room elements (tiles, items, animated entities)
- Organized by layers with collapsible sections
- Color-coded: Tiles (light green), Modifiable tiles (darker green), Items (orange), Animated entities (cyan), Cloud tiles (white)
- Visible only in Room editor mode
- Default position: Left side of editor
- Draggable and resizable
- Click items to select and focus them on the map
- Selection syncs bidirectionally: selecting on map updates Outliner, selecting in Outliner focuses map
- Right-click on tiles to toggle modifiable status (required for `set_tile_attributes` trigger action)

**Outliner Structure**
- Far background (layer 1) - tiles
- Collision (layer 2) - tiles
- Gameplay (layer 3):
  - Tiles
  - Items (in current room)
  - Animated entities (in current room)
- Foreground (layer 4) - tiles

### Palette System

**Source Bar**
- Horizontal bar at the top of the editor showing all sprite sources
- **Click** a source name to open its palette window
- Open sources are highlighted in yellow
- **Mouse wheel**: Scroll source bar horizontally when hovering over it

**Palette Windows**
- Each window displays sprites from one source
- **Click** a sprite tile to select it for placement
- **Drag** window by header bar to reposition
- **Resize** by dragging the resize handle (bottom-right corner)
- **Close** button (X) in header to close window
- **Mouse wheel**: Scroll palette content when hovering over it
- Multiple palette windows can be open simultaneously
- Windows can be brought to front by clicking on them

**Selecting Sprites**
- Selected sprite is used for placing tiles/items
- In Animated Entity mode, clicking a palette sprite applies it to the current frame sprite
- Selected sprite is highlighted in the palette

### Auto-Save System

**Automatic Saving**
- Changes are automatically saved when:
  - Releasing mouse button after placing/moving tiles/items/entities
  - Moving selected objects with arrow keys
  - Making changes in trigger editor
  - Making changes in weather editor
  - Making changes in character editor
- Room maps are saved immediately after edits
- Game data (triggers, weather, character customization) is saved when modified

### Visual Feedback

**Editor Visuals**
- **Selected tile**: Yellow outline
- **Selected item**: Yellow outline
- **Selected animated entity**: Yellow outline
- **Placement preview**: Semi-transparent preview at cursor position while dragging to place
- **Visible rooms**: Adjacent rooms are shown with reduced opacity
- **Room boundaries**: Outlined rectangles show room edges
- **Current room**: Highlighted, other visible rooms shown at 35% opacity
- **Outliner selection**: Selected items highlighted in the Outliner list

### Zoom & Pan

**Zoom Controls**
- **`Ctrl` + mouse wheel**: Zoom in/out
- Range: 0.25x to 4x
- Proportional steps (zoom speed scales with current zoom level)
- Zoom centers on mouse cursor position
- Smooth zoom with easing

**Pan Controls**
- **Middle mouse drag**: Pan the view
- Pan offset maintained during zoom
- View automatically centers on room

### Room Management

**Room Creation**
- Rooms automatically created when navigating to new areas
- Each room has unique ID
- Room links defined via neighbor system (east, west, north, south)
- Room descriptions can be set per room

**Room Data**
- Room maps saved separately per room
- Room data includes: ID, name, description, neighbor links
- Room maps include: tiles, items, animated entities per layer

---

## Trigger System

The trigger system allows you to create interactive events that respond to game state changes. Triggers consist of an **event** (what causes the trigger), optional **conditions** (requirements that must be met), and **actions** (what happens when the trigger fires).

### How Triggers Work

1. **Event Detection**: The trigger system continuously monitors for events (player actions, room changes, timers, etc.)
2. **Target Matching**: If a trigger has a `TargetEntityId`, it only fires when the event involves that specific entity
3. **Room Filtering**: If a trigger has a `RoomId >= 0`, it only works in that specific room (-1 means any room)
4. **Condition Checking**: All conditions must be met for the trigger to fire (AND logic)
5. **Action Execution**: When all checks pass, all actions are executed in order

### Trigger Editor

When the editor mode is **Triggers**, a dedicated panel appears for editing game triggers.

#### Trigger List
- Click a trigger in the list to select it
- **Add**: Create a new trigger
- **Del**: Delete selected trigger
- **Mouse wheel**: Scroll trigger list when hovering over it

#### Trigger Properties

**Basic Settings**
- **Event < / >**: Cycle trigger event type
- **Target < / >**: Cycle target entity ID (empty = any entity)
- **Enabled**: Toggle trigger on/off
- **Room -/+**: Set room ID (-1 = any room, >= 0 = specific room only)
- **Timer -/+**: Set delay in seconds (0.5s steps) - only used for `on_timer_end` events

**Trigger Rectangle**
- **X-/X+ Y-/Y+**: Adjust rectangle position (for rectangle-based events)
- **W-/W+ H-/H+**: Adjust rectangle width and height
- Required for: `on_enter_rectangle`, `on_exit_rectangle`, `touches_rectangle`

**Conditions**
- **< / >**: Select previous/next condition
- **+ / -**: Add/remove condition
- **Type < / >**: Cycle condition type
- **Value < / >**: Adjust condition value (varies by type)
- All conditions must be true for the trigger to fire (AND logic)

**Actions**
- **< / >**: Select previous/next action
- **+ / -**: Add/remove action
- **Type < / >**: Cycle action type
- **Entity < / >**: Cycle target entity ID (for entity-specific actions)
- **Value < / >**: Adjust action value (varies by type)
- **X-/X+ Y-/Y+**: Adjust action position (for move/kick actions)
- **R-/R+**: Adjust action room ID (for move actions)

### Available Trigger Events

| Event | Description | When It Fires | Requires |
|-------|-------------|---------------|----------|
| `on_game_start` | Game initialization | Once when the game starts | None |
| `on_enter_room` | Room entry | When player enters a room | None |
| `on_exit_room` | Room exit | When player leaves a room | None |
| `on_enter_rectangle` | Enter area | When player first enters the rectangle | `Rect` |
| `on_exit_rectangle` | Exit area | When player first exits the rectangle | `Rect` |
| `touches_rectangle` | Inside area | **Every frame** while player is inside | `Rect` |
| `action_entity` | Interact with entity | When player interacts (Enter key) with an entity | `TargetEntityId` (optional) |
| `approach_entity` | Near entity | When player first gets within 10 pixels of an entity | `TargetEntityId` |
| `player_gets_item` | Item pickup | When player picks up an item | `TargetEntityId` (optional) |
| `player_loses_item` | Item drop | When player drops an item | `TargetEntityId` (optional) |
| `player_has_item` | Item check | When player first obtains a specific item | `TargetEntityId` |
| `on_dialogue_start` | Dialogue begins | When any dialogue starts | `TargetEntityId` (optional) |
| `on_dialogue_end` | Dialogue ends | When any dialogue ends | `TargetEntityId` (optional) |
| `on_timer_end` | Timer expires | After `TimerSeconds` have elapsed | `TimerSeconds > 0` |

**Important Notes:**
- `touches_rectangle` fires **every frame** while inside - use carefully to avoid performance issues
- `on_enter_rectangle` and `on_exit_rectangle` fire only once per entry/exit
- `approach_entity` uses a 10-pixel proximity check (player hitbox inflated by 10 pixels)
- `on_timer_end` timers start counting when the trigger is first checked (in Update loop)

### Available Conditions

| Condition | Description | Value Format | Example |
|-----------|-------------|--------------|---------|
| `player_has_item` | Player must have item | Item entity ID | `"item_1"` |
| `player_lacks_item` | Player must NOT have item | Item entity ID | `"item_1"` |
| `room_id` | Must be in specific room | Room ID (number) | `"0"` |
| `dialogue_id` | Dialogue ID must match | Dialogue ID (number) | `"5"` |
| `entity_id` | Entity ID must match | Entity ID | `"npc_1"` |
| `flag_set` | Flag must be set | Flag ID (number) | `"1"` |

**Condition Logic:**
- All conditions must be true (AND logic)
- If no conditions are specified, the trigger always passes condition checks
- Conditions are checked after target and room matching

### Available Actions

| Action | Description | Parameters | Notes |
|--------|-------------|------------|-------|
| `give_item` | Give item to player | `EntityId`: Item entity ID | Item must exist in world |
| `take_item` | Remove item from player | `EntityId`: Item entity ID | Item is dropped at player position |
| `move_item` | Move entity/player | `EntityId`, `X`, `Y`, `RoomId` | Use `"player"` or `"seymour"` for player |
| `trigger_dialogue` | Start bubble dialogue | `DialogueId`: Dialogue ID | Uses bubble dialogue system |
| `kill_entity` | Remove entity from world | `EntityId` | Sets entity room to -999 |
| `hurt_entity` | Damage entity | `EntityId`, `Value`: damage amount | Default damage: 1.0 |
| `kick_entity` | Push entity | `EntityId`, `X`: delta X, `Y`: delta Y | Default: 8 pixels right |
| `set_entity_animation` | Change entity animation | `EntityId`, `Value`: animation ID | Only works on AnimatedEntity |
| `enable_trigger` | Enable triggers | `EntityId` or `Value`: trigger IDs | Supports single, list, or `*`/`all` |
| `disable_trigger` | Disable triggers | `EntityId` or `Value`: trigger IDs | Supports single or list |
| `platform_start` | Start platform movement | `EntityId`: platform entity ID | Also: `start_platform_movement` |
| `platform_stop` | Stop platform movement | `EntityId`: platform entity ID | Also: `stop_platform_movement` |
| `platform_pause` | Pause platform movement | `EntityId`: platform entity ID | Also: `pause_platform_movement` |
| `platform_resume` | Resume paused movement | `EntityId`: platform entity ID | Also: `resume_platform_movement` |
| `call_elevator` | Navigate to checkpoint | `EntityId`: platform, `Value`: checkpoint ID | Also: `set_platform_target`, `platform_target` |
| `set_tile_attributes` | Modify tile properties | `TileId`: modifiable tile ID, `TileAttributeChanges`: attribute-value pairs, `TimerMs`: interpolation duration | Supports gradual interpolation over time |

**`set_tile_attributes` Action Details:**

This action allows you to modify properties of tiles that have been marked as modifiable. Only tiles marked as modifiable (via right-click context menu in the Outliner) can be targeted by this action.

**Setting Up Modifiable Tiles:**
1. In the Room Editor, open the Outliner window
2. Right-click on any tile in the Outliner
3. Select "Set modifiable" to mark the tile as modifiable (or "Clear modifiable" to remove the flag)
4. Modifiable tiles appear in darker green in the Outliner for easy identification

**Using `set_tile_attributes` in Triggers:**
1. In the Trigger Editor, add a new action and select `set_tile_attributes`
2. Select a modifiable tile from the dropdown (shows all modifiable tiles sorted by room number)
3. Add attribute-value pairs to specify which properties to change:
   - Click "+" to add a new attribute change
   - Select the attribute path (e.g., `color/red`, `color/green`, `color/blue`, `rotation`, `scaleX`, `scaleY`, etc.)
   - Set the target value for that attribute
   - Click "-" to remove an attribute change
4. Set the timer (`TimerMs`):
   - `0` (default): Changes are applied immediately when the trigger fires
   - `> 0`: Changes interpolate gradually from current value to target value over the specified milliseconds (in 50ms increments)

**Supported Tile Attributes:**
The available attributes depend on the tile type:
- **Sprite tiles**: `color/red`, `color/green`, `color/blue`, `color/alpha`, `rotation`, `scaleX`, `scaleY`, `flipX`, `flipY`, `offsetX`, `offsetY`
- **Rectangle tiles**: `color/red`, `color/green`, `color/blue`, `color/alpha`, `width`, `height`
- **Ellipse tiles**: `color/red`, `color/green`, `color/blue`, `color/alpha`, `width`, `height`
- **Bezier tiles**: `color/red`, `color/green`, `color/blue`, `color/alpha`, `thickness`
- Other tile types expose their relevant properties

**Interpolation Behavior:**
When `TimerMs > 0`, the system linearly interpolates each attribute from its current value to the target value over the specified duration. For example, if a tile's `color/red` is currently 0 and you set it to 200 with `TimerMs: 500`, it will smoothly transition from 0 to 200 over 500 milliseconds.

**Action Parameters:**
- `EntityId`: Target entity (empty = use context entity, `"player"` or `"seymour"` = player)
- `X`, `Y`: Position or offset (depending on action)
- `RoomId`: Target room (-1 = current room)
- `Value`: Action-specific value (damage, animation ID, etc.)
- `DialogueId`: Dialogue ID for `trigger_dialogue` action
- `TileId`: Target tile ID (for `set_tile_attributes` - must be a modifiable tile)
- `TileAttributeChanges`: Array of attribute-value pairs (for `set_tile_attributes`)
- `TimerMs`: Interpolation duration in milliseconds (for `set_tile_attributes` - 0 = immediate, >0 = gradual change)

### Trigger Execution Flow

1. **Event Occurs**: An event happens (player enters room, interacts with entity, timer expires, etc.)
2. **Event Matching**: System finds all triggers with matching `TriggerEvent`
3. **Target Matching**: For each trigger, checks if `TargetEntityId` matches (if specified)
4. **Room Filtering**: Checks if trigger's `RoomId` matches current room (if `RoomId >= 0`)
5. **Condition Checking**: Verifies all conditions are met
6. **Action Execution**: Executes all actions in the trigger's action list

### Common Trigger Patterns

**Example 1: Give item when entering area**
```
Event: on_enter_rectangle
Rect: (100, 100, 50, 50)
Actions: give_item (EntityId: "item_1")
```

**Example 2: Start dialogue when interacting with NPC**
```
Event: action_entity
TargetEntityId: "npc_1"
Actions: trigger_dialogue (DialogueId: "5")
```

**Example 3: Conditional trigger (only if player has item)**
```
Event: on_enter_room
RoomId: 1
Conditions: player_has_item (Value: "key_1")
Actions: trigger_dialogue (DialogueId: "10")
```

**Example 4: Timer-based event**
```
Event: on_timer_end
TimerSeconds: 5.0
Actions: trigger_dialogue (DialogueId: "15")
```

**Example 5: Move player to new position**
```
Event: touches_rectangle
Rect: (200, 200, 32, 32)
Actions: move_item (EntityId: "player", X: 300, Y: 100)
```

**Example 6: Call elevator to specific floor**
```
Event: action_entity
TargetEntityId: "elevator_button_floor2"
Actions: call_elevator (EntityId: "elevator_1", Value: "cp_floor2")
```

**Example 7: Start moving platform when player steps on it**
```
Event: on_enter_rectangle
Rect: (platform position)
Actions: platform_start (EntityId: "moving_platform_1")
```

**Example 8: Platform arrival notification**
```
(This is configured in the platform's path segment onArrive property, not as a separate trigger)
Platform segment onArrive: { "triggerId": "platform_arrived_destination" }
Then create trigger with id "platform_arrived_destination":
Event: (fired automatically by platform)
Actions: trigger_dialogue (DialogueId: "arrived_message")
```

**Example 9: Change tile color when entering area (immediate)**
```
Event: on_enter_rectangle
Rect: (100, 100, 50, 50)
Actions: set_tile_attributes (
  TileId: "tile_room0_001",
  TileAttributeChanges: [
    { "attribute": "color/red", "targetValue": 255 },
    { "attribute": "color/green", "targetValue": 128 },
    { "attribute": "color/blue", "targetValue": 64 }
  ],
  TimerMs: 0
)
```

**Example 10: Fade tile color gradually over time**
```
Event: action_entity
TargetEntityId: "light_switch"
Actions: set_tile_attributes (
  TileId: "tile_room1_light",
  TileAttributeChanges: [
    { "attribute": "color/red", "targetValue": 200 },
    { "attribute": "color/green", "targetValue": 200 },
    { "attribute": "color/blue", "targetValue": 200 }
  ],
  TimerMs: 500
)
```
Note: With `TimerMs: 500`, the tile's color attributes will smoothly interpolate from their current values to the target values over 500 milliseconds.

### Important Notes

- **Triggers are saved to game data** (`Data/game.json`), not room maps
- **Changes are saved automatically** when you modify triggers in the editor
- **Trigger rectangles** define activation areas for rectangle-based events
- **Multiple conditions and actions** can be added to a single trigger
- **Room ID -1** means the trigger works in any room
- **Empty TargetEntityId** means the trigger works for any entity
- **`give_item` action requires** the item entity to exist in the world - if the entity doesn't exist, the action fails silently
- **`touches_rectangle` fires every frame** - be careful with actions that should only happen once
- **`enable_trigger` and `disable_trigger` accept lists**: comma/semicolon-separated IDs; `enable_trigger` also supports `*`/`all` to reset all triggers
- **Timer triggers** start counting when first checked in the Update loop, not when created
- **Entity IDs** are case-insensitive
- **Player entity ID** can be `"player"` or `"seymour"` (case-insensitive)
- **`set_tile_attributes` requires modifiable tiles**: Only tiles marked as modifiable (via Outliner context menu) can be targeted by this action
- **`set_tile_attributes` interpolation**: When `TimerMs > 0`, attributes interpolate linearly from current to target values; interpolation runs independently for each attribute
- **Tile modifiable flag**: The modifiable attribute defaults to 0 (not modifiable) for all tiles; setting it to 1 enables the tile for attribute modification via triggers

---

## Tips

### Gameplay Tips
1. **Swimming**: Hold Up/Jump at water surface to jump out of water
2. **Climbing**: Use Up/Down arrows to climb ladders, Jump to exit
3. **Inventory Management**: Drop items before picking up new ones to avoid losing items
4. **Weather Protection**: Stand under solid tiles to avoid rain/snow exposure
5. **Interaction Range**: Get close to items/NPCs for interaction (narrow horizontal, moderate vertical reach)
6. **Moving Platforms**: Stay on top of platforms to be carried along their path
7. **Elevators**: Interact with call buttons to summon elevators to your floor
8. **Cross-Room Platforms**: Ride trams/platforms to travel between distant rooms automatically

### Editor Tips
1. **Unified Room Editor**: All tiles, items, and animated entities can be edited in the same view - no need to switch modes
2. **Placement Control**: Use click-and-drag on the map to place new elements when a placement tool is active; regular click to select existing ones
3. **Outliner Navigation**: Use the Outliner to quickly find and select elements, especially useful in complex rooms
4. **Efficient Tile Placement**: Use `Q`/`E` to cycle through overlapping tiles at the same position
5. **Room Navigation**: Use arrow keys (with no selection) to quickly move between rooms
6. **Palette Organization**: Keep frequently used palette windows open and positioned for easy access
7. **Zoom Levels**: Use `Ctrl` + mouse wheel to zoom in for precise placement or zoom out for overview
8. **Entity Templates**: Build reusable templates in Animated Entity mode, then place multiple instances with click-and-drag on the map
9. **Layer Management**: Use different layers to organize background, midground, and foreground elements
10. **Selection Sync**: Selecting elements on the map automatically scrolls the Outliner to show them
11. **Trigger Testing**: Create triggers with visible rectangles to test activation areas
12. **Weather Testing**: Use the Test button in Weather Editor to immediately see weather effects
13. **Character Preview**: Use the preview windows in Character Editor to see animations in real-time
14. **Shape Tools**: Use Bezier curves for smooth paths, ellipses for circular areas
15. **Moving Platforms**: Configure platform colliders slightly smaller than sprites for better feel
16. **Checkpoint Naming**: Use descriptive IDs like `cp_room0_elevator_top` for easy reference
17. **Easing Selection**: Use `InOutSine` for smooth elevator motion, `Linear` for constant-speed trams
18. **Platform Triggers**: Use `onArrive` triggers to play sounds or show messages when platforms stop
19. **Modifiable Tiles**: Mark tiles as modifiable in the Outliner to enable dynamic property changes via `set_tile_attributes` triggers
20. **Tile Attribute Interpolation**: Use `TimerMs > 0` in `set_tile_attributes` for smooth color transitions, fades, and animated property changes

---

## Technical Details

### Rendering System
- **Virtual Resolution**: 480×270 internal resolution
- **Scaling**: Integer scaling with letterboxing by default, stretch mode available
- **Layers**: 5 render layers (background, behind player, player, foreground, UI)
- **Layer 1 Caching**: Far background layer is cached for performance
- **Post-Processing**: Applied after all layers are composited

### Building on macOS/Linux
- **Version**: Version is updated by `update-version.sh` on Unix and `update-version.ps1` on Windows before each build.
- **Post-processing effects (Bloom, CRT, VHS, Scale2x, Phosphor)**: Shaders are loaded from pre-compiled `.mgfxo` files so the project builds on macOS/Linux without Wine. To generate or update them, on **Windows** run `.\build-effects.ps1` from the repo root, then commit the `Content\*.mgfxo` files. Without these files the game still runs; post-processing effects are simply disabled.

### Data Files
- **`Data/game.json`**: Main game data (rooms, entities, triggers, weather, character customization, checkpoints)
- **`Data/editor.json`**: Editor-specific settings and state
- **`Data/dialogues.json`**: Dialogue lines and links
- **`version.txt`**: Version number displayed in game

### Data Structures

**Checkpoint Data** (in `game.json` → `checkpoints[]`)
```json
{
  "id": "cp_room0_elevator_top",
  "roomId": 0,
  "x": 240,
  "y": 40
}
```

**Platform Data** (in animated entity → `platform`)
```json
{
  "solid": true,
  "oneWay": false,
  "carry": "groundedOnly",
  "collider": { "w": 32, "h": 8, "offsetX": -16, "offsetY": -4 }
}
```

**Path Movement Frame** (in animated entity → `movements[]` → `movementFrames[]`)
```json
{
  "type": "path",
  "startMode": "idle",
  "loop": 0,
  "defaultPosEasing": "Linear",
  "segments": [
    {
      "from": "checkpoint_id_or_object",
      "to": "checkpoint_id_or_object",
      "speed": 40,
      "durationMs": null,
      "posEasing": "InOutSine",
      "waitMsAtStart": 0,
      "waitMsAtEnd": 500,
      "onDepart": { "triggerId": "trigger_id" },
      "onArrive": { "triggerId": "trigger_id" }
    }
  ]
}
```

### Performance
- Layer 1 (far background) is cached and only redrawn when room changes
- Weather particles are optimized with ramp-up/fade-out
- Animated entities update only when in current room
- Post-processing effects can be toggled for performance

---

## Credits

Built with MonoGame framework. Inspired by classic Dizzy-style adventure games.
