# Events System

## Overview
Advenexus runs automated timed events every **3 hours** with a prize pool. Four event types rotate randomly: Hunt Frenzy, Battle Frenzy, Blackjack Frenzy, and Bounty Hunt. Events are announced server-wide and winners receive prizes from a weighted prize table. The event system persists across server restarts.

---

## Commands

| Command | Description |
|---|---|
| `.event` | Check current event status or time until next event |

---

## Event Schedule

- Events fire every **3 hours** automatically
- **5-minute warning** broadcast before each event starts
- Timer persists in the database (`event_state` table) — survives server restarts
- If the server restarts mid-countdown, the remaining time is calculated from the stored timer
- Push notifications sent to all players when an event starts

---

## Event Types

### 🔥 Hunt Frenzy
- **Duration:** 5 minutes
- **Effect:** Fabled drop rate boosted **+2%** during the event
- **How to win:** No competition — the frenzy benefits all players who hunt during the window
- **No winner declaration** — event ends after 5 minutes

### ⚔️ Battle Frenzy
- **Duration:** 15 minutes
- **Goal:** First player to reach **10 battle wins** wins the grand prize
- **Tracking:** Win count tracked per player in memory (resets each event)
- **Progress broadcasts:** Each win is announced (e.g., "player has 5/10 battle wins!")
- **Leaderboard:** Top 3 shown when using `.event` during the event
- If no one reaches 10 wins in 15 minutes, **no winner** — event ends

### 🃏 Blackjack Frenzy
- **Duration:** 15 minutes
- **Goal:** First player to reach **5 blackjack wins** wins the grand prize
- **Tracking:** Win count tracked per player in memory (resets each event)
- **Progress broadcasts:** Each win is announced
- **Leaderboard:** Top 3 shown when using `.event`
- **If no one reaches 5 wins in 15 minutes**, **no winner**

### 🎯 Bounty Hunt
- **Duration:** 30s Lobby + 30s Head-Start + 2m Active Hunt
- **Lobby Phase:** A 30-second lobby opens where players must type `.join bounty` to participate. A minimum of 3 and a maximum of 6 players can join. If fewer than 3 join, the event is cancelled.
- **Target Selection:** Once the lobby closes, one participant is randomly chosen as the "Target", and the rest become "Hunters". The system attempts to avoid picking recent targets.
- **Head-Start Phase:** The target has 30 seconds to run and hide anywhere on the 6144x6144 world map grid.
- **Active Hunt Phase:** The Hunters must explore the map to find and click the Target. The Target must survive without being clicked for 2 minutes.
- **Commands:** 
  - `.join bounty` - Joins the lobby (only during the lobby phase).
  - `.bounty map` - Sends a full image preview of the map to the chat.
- **Winning:** 
  - If a hunter clicks the target, they win the grand prize immediately.
  - If the 2-minute timer runs out and the target survives, the target wins the grand prize.

### 🛍️ Black Friday Event
- **Duration:** 5 hours
- **Trigger:** Randomly every 8-12 days
- **Effect:** All cosmetic items can be purchased with coins instead of cash
- **Discount:** 10-40% off the converted coin price (200 coins per 1 cash)
- **No competition** — all players benefit during the event window
- Push notifications sent when event starts/ends

---

## Prize Table

Each event rolls a random prize from this weighted table:

| Prize | Weight | Probability |
|---|---|---|
| Mythic Crate | 36.8 | 36.8% |
| Mythic Crate + 3,000 🪙 | 22.1 | 22.1% |
| Mythic Crate + 6,000 🪙 | 22.1 | 22.1% |
| Legendary Crate | 11.0 | 11.0% |
| Legendary Crate + 5,000 🪙 | 7.4 | 7.4% |
| Fabled Crate | 0.7 | 0.7% |

**Total weight:** 100.1

### Prize Award Mechanics

| Prize Type | How It's Given |
|---|---|
| Crate | Crate of specified rarity inserted into winner's inventory |
| Crate + Coins | Crate of specified rarity + bonus coins added to balance |

---

## Event Lifecycle

```
[3 hours pass] → 5-min warning broadcast → Event starts → Timer runs → Winner or timeout → Prize awarded → Schedule next event
```

1. **Schedule:** Next event time stored in DB
2. **Warning:** 5 minutes before event, broadcast sent to #general
3. **Start:** Random event type selected, prize rolled, broadcast + push notification sent
4. **Active:** Players compete (Battle/Blackjack) or benefit (Hunt Frenzy)
5. **End conditions:**
   - **Battle Frenzy:** first to 10 wins, or 15-minute timeout
   - **Blackjack Frenzy:** first to 5 wins, or 15-minute timeout
   - **Hunt Frenzy:** always runs for full 5 minutes (no winner)
   - **Bounty Hunt:** target claimed by a hunter, or target survives for 2 minutes
6. **Award:** Winner receives prize, celebration broadcast
7. **Reschedule:** Next event scheduled 3 hours from now

---

## Event State API

The server emits `event_state` via WebSocket whenever the event state changes:

**When no event is active:**
```json
{ "active": false, "nextEventTime": 1714500000000, "type": null }
```

**When an event is active:**
```json
{ "active": true, "type": "battle_frenzy", "startTime": ..., "endTime": ..., "prizeName": "a Legendary Weapon" }
```

---

## Hook Integration

The event system hooks into existing command handlers:

| Hook | Source File | When Called |
|---|---|---|
| `onBattleWin(userId, username)` | `battle.js` | After any battle win |
| `onBlackjackWin(userId, username)` | `gambling.js` | After a blackjack stand with win result |
| `isHuntFrenzyActive()` | `hunt.js` | During hunt rarity roll (adds +2% fabled chance) |

---

## Edge Cases

- Only one event can be active at a time
- Battle/Blackjack win counts are stored in memory (Map) — they reset on server restart during an active event
- Hunt Frenzy has no winner — it's a passive buff for everyone
- If nobody wins a Battle/Blackjack Frenzy, the prize is forfeited (not carried over)
- Event broadcasts are persisted to the `messages` table in the `general` channel
- The event system is initialized on server startup with `init(io, pushUtil)`
- Push notifications are sent via `pushUtil.pushToAll()` (service worker push)

---

# Royal Auction System

## Overview
The **Royal Auction** is a live, competitive bidding system where players bid coins on exclusive rewards including rare animals, weapons, evolution stones, crates, and Advenexus Cash. Sessions are manually triggered by administrators and feature 1-3 items auctioned sequentially with break periods between items.

---

## How It Works

### Session Structure
- **Manual trigger:** Admins create and start auction sessions (not on a timer)
- **1-3 items per session:** Each session auctions between 1 and 3 exclusive items
- **Sequential auctions:** Items are auctioned one at a time
- **Break periods:** 3-minute breaks between items to allow players to prepare for the next auction
- **Push notifications:** All players receive a push notification when an auction session starts (respects user's `push_events` preference)

### Item Auction Flow
1. **Item goes live:** Timer starts (typically 2-5 minutes per item)
2. **Players bid:** Minimum bid is the starting price or current highest bid + 1 coin
3. **Final phase:** Last 30 seconds marked as "FINAL" with red pulsing timer
4. **Anti-sniping:** Any bid in the final 30 seconds extends the timer by 30 seconds
5. **Item ends:** Highest bidder wins and receives the reward
6. **Break or end:** 3-minute break before next item (or session ends if no more items)

---

## Bidding Mechanics

### How to Bid
- **Widget UI:** A draggable widget appears on screen when an auction is active
- **Expand widget:** Click the collapsed pill to open the full auction interface
- **Enter bid:** Type your bid amount in gold coins
- **+10% button:** Quick button to bid 10% above current highest bid
- **Submit:** Click "Place Bid" to submit your bid

### Bid Requirements
- **Minimum bid:** Must be at least the starting price OR current highest bid + 1 coin or more
- **Sufficient balance:** You must have enough gold coins in your balance
- **Active auction:** Can only bid while the item status is "active" or "final"
- **Not leading:** Cannot bid if you're already the highest bidder

### Escrow System
- **Immediate deduction:** When you place a bid, coins are immediately removed from your balance and held in escrow
- **Outbid refund:** If someone outbids you, your previous bid is automatically refunded
- **Winner payment:** If you win, your escrowed coins are **destroyed** (removed from the economy as a gold sink)
- **Incremental bidding:** If you bid again on the same item, only the additional amount is deducted
  - Example: You bid 10,000 → someone bids 15,000 → you bid 20,000 → only 10,000 additional coins are deducted

### Anti-Sniping Protection
- **Final phase:** When the timer reaches 30 seconds or less, the auction enters "FINAL" phase
- **Timer extension:** Any bid placed during the final phase resets the timer to 30 seconds
- **Fair competition:** This prevents last-second sniping and gives all players a chance to respond
- **Visual indicator:** Timer turns red and pulses during final phase

---

## Reward Types

The auction can feature any of these reward categories:

| Reward Type | Description | Example |
|---|---|---|
| **Animals** | Rare or evolved animals at specific stages | Frost Revenant (Stage 1), Mythic rarity animals |
| **Weapons** | High-rarity weapons | Legendary or Fabled weapons |
| **Evolution Stones** | Premium evolution stones | 1x Fabled Stone, 2x Gods Stone |
| **Crates** | Premium crates | 1x Legendary Crate, 3x Mythic Crate |
| **Advenexus Cash** | Premium currency | 100 Cash, 500 Cash |

### Reward Delivery
- **Instant delivery:** Winners receive rewards immediately upon auction end
- **Animals:** Added directly to your zoo with `auction_generated` flag
- **Weapons:** Added to your weapons inventory with full durability
- **Stones/Crates:** Added to your inventory (use `.inv` to access)
- **Cash:** Added to your cash balance (visible in wallet)

---

## Widget Interface

### Collapsed State
- **Pill indicator:** Shows "LIVE AUCTION", "ON BREAK", or "AUCTION ENDED"
- **Color coding:**
  - Yellow pulsing: Active auction
  - Blue: Break period
  - Gray: Ended
- **Click to expand:** Click the pill to open the full interface

### Expanded State
- **Draggable:** Click and drag the header to reposition the widget
- **Item display:** Shows the current item image and details
- **Current bid:** Displays highest bid in gold coins
- **Leader:** Shows username of current highest bidder (or "No bids")
- **Timer:** Countdown showing time remaining
- **Top bidders:** List of top 3 bidders with their bid amounts
- **Bid input:** Text field to enter your bid amount
- **Activity log:** Recent bid updates and announcements
- **Minimize button:** Click "−" to collapse back to pill

### Break Period Display
- **Break timer:** Shows time until next item starts
- **Results so far:** Lists winners of previous items in the session
- **Next item preview:** Indicates which item number is coming next

### Session End Display
- **Final results:** Complete list of all winners and their winning bids
- **Reward details:** Shows what each winner received
- **30-minute cooldown:** Widget remains visible for 30 minutes after session ends, then auto-hides

---

## Leading Status

### When You're Leading
- **Green indicator:** "You Are Leading" button displayed in green
- **Cannot bid:** Place Bid button is disabled while you're the highest bidder
- **Outbid notification:** You'll receive a real-time notification if someone outbids you
- **Your escrow amount:** Your bid is held in escrow until auction ends or you're outbid

### When Outbid
- **Socket notification:** Receive `auction:you_were_outbid` event
- **Automatic refund:** Your previous bid is instantly refunded to your balance
- **Bid again:** You can immediately place a new, higher bid

---

## Session States

| State | Description | Duration |
|---|---|---|
| **Pending** | Session created but not started yet | Until admin starts |
| **Active** | Item auction is live, accepting bids | 2-5 minutes per item |
| **Final** | Last 30 seconds of auction, anti-sniping active | 30+ seconds |
| **Break** | Pause between items | 3 minutes |
| **Ended** | All items auctioned, session complete | 30-minute cooldown |
| **Cancelled** | Admin cancelled the session, all bids refunded | Immediate |

---

## Economy Impact

### Gold Sink
- **Winning bids destroyed:** All gold coins from winning bids are permanently removed from the economy
- **Deflation mechanism:** Helps control inflation by removing coins from circulation
- **High-value sink:** Typically removes millions of coins per session

### Escrow Tracking
- **Database table:** `auction_escrow` tracks all escrowed coins
- **Per-item, per-user:** Each player's escrow is tracked separately per item
- **Refund safety:** If auction is cancelled, all escrow is automatically refunded
- **Ledger entries:** All transactions logged in `ledger` table for transparency

---

## Tips & Strategy

### Bidding Strategy
- **Watch the timer:** Don't bid too early — wait for the final phase to gauge competition
- **Use +10% wisely:** Quick way to stay ahead without manually calculating
- **Set a limit:** Decide your maximum bid beforehand to avoid overspending
- **Monitor top bidders:** Check who you're competing against

### When to Bid
- **Early bird:** Bid early to establish presence and deter competition
- **Last minute:** Wait until final phase to avoid driving price up prematurely
- **Counter-bid:** Respond immediately when outbid to show you're serious

### Risk Management
- **Check your balance:** Ensure you have enough coins before the auction starts
- **Multiple items:** Consider which items you want most if there are multiple in a session
- **Break periods:** Use breaks to assess your strategy for upcoming items

---

## Notifications & Broadcasts

### Push Notifications
- **Session start:** "Royal Auction Started! A new Royal Auction has begun with X exclusive items! Place your bids now!"
- **Controlled by settings:** Respects user's `push_events` preference setting

### Socket Events (Real-time)
- `auction:session_start` — New auction session begins
- `auction:item_start` — New item goes live for bidding
- `auction:bid_update` — Someone placed a bid (updates highest bid, leader, timer)
- `auction:final_phase` — Item entered final 30 seconds
- `auction:item_ended` — Item auction concluded, winner announced
- `auction:break_start` — Break period begins before next item
- `auction:session_end` — All items finished, session complete
- `auction:cancelled` — Admin cancelled the session
- `auction:you_were_outbid` — Personal notification when outbid (includes refund amount)
- `auction:you_are_leading` — Confirmation that your bid is now the highest
- `auction:bid_rejected` — Your bid was rejected (shows reason)
- `auction:reward_delivered` — Personal notification of your won reward

### Broadcast Announcements
- **Server-wide:** Winner announcements broadcast to all players in #general
- **Format:** "🏛️ [winner] won the Royal Auction for [amount] gold!"

---

## Technical Details

### Database Tables
- `auction_sessions` — Session records (id, status, item_order, timestamps)
- `auction_items` — Item records (reward data, starting price, duration, winner, bids)
- `auction_bids` — Bid history (bidder, amount, timestamp, status)
- `auction_escrow` — Active escrow amounts per user per item

### Item Duration
- **Configurable:** Each item can have a different auction duration
- **Range:** 120-300 seconds (2-5 minutes)
- **Default:** 180 seconds (3 minutes)

### Session Limits
- **Max items:** 3 items per session
- **One at a time:** Only one auction session can be active at any given time
- **No timer:** Sessions are manually triggered by admins, not automated

### Crash Recovery
- **State persistence:** Session state saved in database
- **Timer recovery:** If server restarts during auction, timer is recalculated from database
- **Active item resume:** Current item auction continues from where it left off
- **Break recovery:** Break timers are restored and continue counting down

---

## Edge Cases

- Only one auction session can be active at a time
- Cannot bid if you're already the highest bidder
- If an item receives no bids, it ends with no winner (reward not distributed)
- All escrow is automatically refunded if a session is cancelled or reset
- Widget persists for 30 minutes after session ends to show final results
- Widget position is saved to localStorage and restored on page reload
