Iso revealed the WHOLE map from move 0: unexplored (dark) cells fell back to the floor tile (_tileUrl(dark) -> tiles.floor) and rendered as floor. Now skip dark cells entirely (unexplored = void), and dim explored tiles by the lightGrid brightness (globalAlpha, floor to 0.16) so the remembered area fades to black with distance — parity with the 2D modes and 3D (which already skips dark + uses THREE distance fog).
Wownerogue
A browser-based roguelike synchronized with Monero (XMR) and Wownero (WOW) block timing. Built with Node.js/Express and Socket.IO for real-time play, optional crypto payments, and automated payouts.
Features
- Provably fair gaming with pre-game hash commitments
- Live spectator mode - watch active games in real-time
- Persistent chat with 30-day history
- Transaction history - view payment and payout records
- Multiple game modes: Free play, per-game payments, or credit bundles
- Real-time multiplayer races: free, prestige-credit, or crypto winner-take-pot races every block
- Configurable difficulty with house edge tuning
- Automatic wallet RPC integration for payments and payouts
Quick Start
git clone <repository-url>
cd wownerogue/src
npm install
cp .env.example .env # Edit with your database/wallet settings
npm run db:create # Initialize PostgreSQL
npm run dev # Start development server
Open http://localhost:3000 to play.
Game Modes
| Mode | Cost | Payout | Description |
|---|---|---|---|
| FREE | None | None | No payments required |
| PAID_SINGLE | 1 WOW/game | 2× escape, 3× with treasure | Per-run payment |
| PAID_CREDITS | 10 credits/5 WOW | Optional | Buy credit bundles |
When both modes are enabled (ALLOW_MIXED_MODE=true), players with credits can start games instantly without the payment modal.
Match Mode (Multiplayer Races)
Optional real-time multiplayer races are available when MATCH_ENABLED=true. A new race starts every
crypto block as long as at least two players are queued. Supported economies:
| Economy | Entry | Payout | Leaderboard |
|---|---|---|---|
| Free | None | None | Pleb |
| Prestige Credits | Credits | None | Prestige |
| Crypto Race | Race-entry ticket | Winner-take-pot minus house fee | Hall of Champions |
See docs/MATCH_MODE.md for full architecture, configuration, and API details.
Difficulty & Pacing
Difficulty has two levers, both keyed to the crypto network so cryptoType actually shapes the
game (it used to be a dead parameter).
Presets (DIFFICULTY_PRESET) — the per-level shape:
| Preset | Dungeon Size | Monster | Target House Win |
|---|---|---|---|
easy |
30×15 | low | ~30% |
normal |
45×22 | medium | ~55% |
hard |
55×28 | high | ~65% |
casino |
70×35 | very high | ~70% |
Defaults to normal for free play, casino for paid. Every knob is env-overridable
(DUNGEON_WIDTH, MONSTER_SPEED, …).
Multi-level depth (levels) — the pacing lever, ∝ block time. A run descends N levels (each a
preset-sized dungeon with a fair monster). Reaching a non-final exit takes the stairs down; only the
final exit escapes; the treasure sits in the vault (final level). Because total run length scales
with the chain's block time, the "race the block" timer provides the house edge — no giant map,
no cheating-fast monster.
| Chain | Block time | Levels |
|---|---|---|
| GRIN | ~1 min | 1 |
| XMR | ~2 min | 2 |
| LTC | ~2.5 min | 2 |
| WOW | ~5 min (measured) | 4 |
| BTC | ~10 min | 8 |
Levels live in NETWORK_TUNING (src/game/difficultyConfig.js); override with DUNGEON_LEVELS,
disable with NETWORK_TUNING_DISABLED=true. The counts are sim-derived starting points — see
docs/BALANCE_SIM.md for how the balance is measured and calibrated.
Note: Wownero's block time is ~5 min (measured on the live daemon), not 2 min as older docs/comments claimed.
Key Features
Provably Fair Gaming
- Server generates a random seed and shows its SHA-256 hash before the game
- The seed deterministically generates the dungeon layout and positions
- After the game, the seed is revealed for verification
- Players can verify
hash(seed) = commitmentto prove no manipulation
Spectator Mode
Click "👁️ Watch Games" to see active games. Spectators receive real-time updates via Socket.IO rooms. Press ESC to exit.
Transaction History
Click "📜 History" to view your payment and payout records. Shows:
- Total received from payouts
- Payment history with status and credits received
- Payout history with multipliers and transaction hashes
Session Persistence
Sessions use an anonymous token stored in localStorage:
- ✅ Persists across refreshes, browser closes, server restarts
- ⚠️ Lost when clearing cookies/localStorage, using incognito mode, or switching browsers/devices
A warning appears if localStorage is unavailable.
API Reference
Public Endpoints
| Endpoint | Description |
|---|---|
GET /health |
Server health, uptime, memory, wallet status |
GET /api/game-modes |
Current modes and pricing |
GET /api/user/:socketId/credits |
User credit balance |
GET /api/user/:socketId/payments |
Payment history (paginated) |
GET /api/user/:socketId/payouts |
Payout history (paginated) |
POST /api/user/:socketId/address |
Set payout address |
GET /verify/:gameId |
Provably fair verification page |
Admin Endpoints
Require X-Admin-Key header matching ADMIN_API_KEY env variable.
| Endpoint | Description |
|---|---|
POST /api/admin/refund/payment |
Refund a payment, deduct credits if applicable |
POST /api/admin/credits/adjust |
Add or remove credits from a user |
GET /api/admin/users/search |
Search users by socket ID or address |
Example: Refund a payment
curl -X POST http://localhost:3000/api/admin/refund/payment \
-H "Content-Type: application/json" \
-H "X-Admin-Key: your-admin-key" \
-d '{"paymentId": 123, "reason": "Customer request", "sendFunds": true}'
Example: Adjust credits
curl -X POST http://localhost:3000/api/admin/credits/adjust \
-H "Content-Type: application/json" \
-H "X-Admin-Key: your-admin-key" \
-d '{"socketId": "abc123", "amount": 5, "reason": "Compensation"}'
Socket.IO Events
Client → Server
| Event | Description |
|---|---|
auto_start |
Start game (uses credits if available) |
player_move |
Move player (direction: 0-3) |
request_payment |
Request payment address |
get_active_games |
List games for spectating |
spectate_game |
Start spectating a game |
Server → Client
| Event | Description |
|---|---|
game_start |
Game initialized with dungeon state |
game_update |
State after movement (incl. depth/maxDepth for multi-level descent) |
game_event |
Discrete event: treasure_found, descend (took the stairs down), escaped |
game_over |
Game ended |
payment_created |
Payment address ready |
credits_update |
Credit balance changed |
spectator_update |
Spectated game state |
Configuration
Key environment variables (see .env.example for full list):
# Core
NODE_ENV=production
PORT=3000
DIFFICULTY_PRESET=casino
# Payments
PAYMENTS_ENABLED=true
PAYMENT_MODES=direct,credits
DIRECT_GAME_PRICE=100000000000 # 1 WOW in atomic units
CREDITS_PACKAGES='[{"id":"small","credits":10,"price":"500000000000","bonus":0}]'
# Payouts
DIRECT_PAYOUT_ESCAPE=2.0
DIRECT_PAYOUT_TREASURE=3.0
# Wallet RPC (required for paid modes)
PRIMARY_WALLET_ENDPOINT=http://127.0.0.1:34570
WALLET_RPC_USER=user
WALLET_RPC_PASSWORD=password
# Database
DB_HOST=localhost
DB_NAME=wownerogue
DB_USER=your_user
DB_PASSWORD=your_password
# Admin API (generate with: openssl rand -hex 32)
ADMIN_API_KEY=your-secure-key
# Network (Monero only - Wownero only has mainnet)
MONERO_NETWORK=mainnet
Amounts use atomic units: 1 WOW = 10^11 atomic units.
Production Deployment
See docs/DEPLOY.md for detailed production deployment instructions including:
- systemd service configuration
- Nginx/reverse proxy setup with WebSocket support
- Database permissions and security hardening
- Multi-instance deployment (running Wownero and Monero on the same server)
Operations
See docs/LOGS_AND_BACKUP.md for:
- Log management with systemd/journald
- PostgreSQL automated backups
- Backup verification procedures
Testing
cd src
npm test
Tests cover payment handlers, wallet RPC, security rules, movement logic, and integration flows.
Project Structure
src/
├── index.js # Entry point
├── config/ # Payment config, validation
├── db/ # PostgreSQL layer
├── game/ # Dungeon, player, monster logic
├── network/ # Socket handlers, chat, queue, spectator
├── payments/ # Wallet RPC, QR codes
└── utils/ # Errors, memory management
html/
├── index.html # Game client
├── admin.html # Admin dashboard
└── js/ # Frontend modules
test/
└── *.test.js # Jest tests
License
See LICENSE file for details.