Adventure Game

Text-based maze crawler with encounters, combat, loot, and stats

Opening / Game Loop Overview

At startup the program builds all core objects (I/O, player, combat, maze, encounters, displays, etc.), asks the player for maze size, generates the maze and encounter grid, shows the intro, then loops until you reach the exit. In each loop iteration you move once and the game checks for an encounter; on exit it shows a success message and your story conclusion.

Opening text screenshot
High-level loop
───────────────
User picks dimensions → Maze & encounters generated → Intro shown
→ while (player not at exit):
     • Read a move (N/E/S/W)
     • Update position
     • Check for encounter (combat or loot)
→ On exit: print success + show story conclusion/stats
      

Systems & Data Flow

The game is split into compact systems: Maze Generation, Traversal, Encounters, Combat, Monster Generation, and Items & Stat Tracking. The Displays class handles narrative / UI text and summaries.

+------------------+     +--------------------+     +------------------+
| Maze Generation  | --> | Maze Traversal     | --> | Encounter System |
+------------------+     +--------------------+     +------------------+
                                  |                         |
                                  v                         v
                        +-----------------+        +------------------+
                        | Player / Stats  | <----> | Combat System    |
                        +-----------------+        +------------------+
                                  ^                         |
                                  |                         v
                        +-----------------+        +------------------+
                        | Items & Loot    | <----> | Monster Gen/Data |
                        +-----------------+        +------------------+
      

Maze Generation

After reading x & y dimensions from the user, the code computes the “with walls” grid (x*2+1 by y*2+1) and calls Maze.create(...) to carve the labyrinth. The carved wall matrix is stored in mazeData.walls.

The creation logic uses a pilot-based carve: when moving the pilot one cell, it also “breaks” the wall between current and next cell to create a passage (N/E/S/W). You can see how walls are removed while moving in movePilotPosition.

A direction is only considered if it’s inside bounds, there is a wall there, and the next cell hasn’t been visited yet. That check is done in isDirectionPossible. Completion is verified by scanning the grid for any unvisited cells.

Code snippet image
Maze generation flow
────────────────────
Input (x, y) → compute (2x+1, 2y+1)
→ place pilot at start
→ while (unvisited cells exist):
     • collect valid directions (have wall & unvisited cell)
     • choose direction
     • break the wall between
     • move pilot
→ save walls to mazeData.walls
      

Traversal (Player Movement)

The game reads a direction (north/east/west/south), prints the narrative line, then updates the player’s mazePos by two grid steps (because walls occupy the tiles between cells). Movement is gated by walls and boundaries.

Move loop (per turn)
────────────────────
• Read direction
• Print narration line
• Update player.mazePos by ±2 on axis
• (Engine ensures walls/edges prevent illegal moves)
      

Encounter System

When the maze is created, an “encounter grid” of the same size is generated. Each open cell gets a chance (percentage) to be marked as an encounter; the exit is marked specially.

Every step, the game calls Encounter.check(...): if the player’s current cell is flagged, the cell is cleared and a random scenario is triggered (loot or combat). A move counter increments as well.

Scenario selection: with a specified loot probability, the engine branches into the loot flow; otherwise, it spins up combat with monsters.

Encounter check
───────────────
On entering a cell:
• If encounters[x][y] == 1 → clear it
• RNG:
    - ≤ lootChance → Loot
    - else → Combat
• Increment moves-taken metric
      

Combat System (Turn-Based)

Combat is turn-based. The Displays class shows the player’s stats, then prompts for an action: Attack, Cast Spell, Move, Consume Potion, or End Turn. After the player acts, monsters act according to speed and status; combat repeats until one side is defeated.

The UI also prints monster stats (HP, damage dice, speed) before you make choices, and exposes helper displays for showing positions in grid-based combat.

Combat round
────────────
1) Displays: player stats, learned spells, potions
2) Player chooses an action (attack/spell/move/potion/end)
3) Apply effects (HP/MP, positions, status)
4) Monsters take their actions
5) Repeat until HP ≤ 0 for a side → resolve (loot/xp/story)
      

Monster Generation / Casting

Enemies are stored in a large “cast” on GameData, and the engine tracks which are “living” in the current fight. This gives you a pool to pull randomized enemies from as encounters trigger.

Each monster has battle stats (HP, attack dice, speed, etc.) printed by the display helpers; the actual combat layer consumes these values to resolve damage and turns.

Monster pipeline
────────────────
Encounter triggers → pick template from GameData.enemiesCast
→ randomize/assign stats & positions → push into living[]
→ Combat loop consumes those stats each round
      

Items, Loot & Stat Tracking

Loot is controlled by a tunable chance (e.g., 60%). If a loot scenario is chosen, the Loot system grants items (potions, etc.) that mutate the Player’s stats/state. The loot chance and enemy/kill bookkeeping live on GameData.

The Displays class prints a final summary at the end (totals for movement, melee attacks, spells, potions, and monsters killed).

Tracking / Summary
──────────────────
• Player: HP, MP, learned spells, potions, combat counters
• GameData: lootChance, enemiesCast[], living[], kill counts
• Displays: per-turn & end-of-run summaries
      

Win Condition

The main loop continues until your player.mazePos matches the maze exit coordinates. When that happens, the game prints a success message and displays the concluding story screen.

while (player not at exit):
    move → check encounter
→ On exit → "You have successfully escaped the labyrinth" + story conclusion