107 lines
7.4 KiB
Markdown
107 lines
7.4 KiB
Markdown
# Legacy Auctions and Betting
|
|
|
|
This document covers the auction and betting systems: how auctions open/close,
|
|
what resources they trade, and how betting payouts are calculated. References
|
|
include `legacy/hwe/sammo/Auction*.php`, `legacy/hwe/func_auction.php`, and
|
|
`legacy/hwe/sammo/Betting.php`.
|
|
|
|
## Auction Types and Entry Points
|
|
|
|
- `Auction` (base class): shared bid logic and close-date extensions.
|
|
- `AuctionBuyRice`: sell rice for gold.
|
|
- `AuctionSellRice`: sell gold for rice.
|
|
- `AuctionUniqueItem`: bids use inheritance points for unique items.
|
|
- `processAuction()` in `legacy/hwe/func_auction.php` closes finished auctions.
|
|
- `registerAuction()` creates neutral (NPC-hosted) buy/sell auctions.
|
|
|
|
## Auction Data Model
|
|
|
|
Primary tables:
|
|
|
|
- `ng_auction`: auction metadata (type, target, host, close date, detail).
|
|
- `ng_auction_bid`: per-bid rows for each auction.
|
|
|
|
The `AuctionInfo` and `AuctionInfoDetail` DTOs are serialized into
|
|
`ng_auction` columns for structured access.
|
|
|
|
## Core Auction Flow
|
|
|
|
1. **Open**
|
|
- `AuctionBasicResource::openResourceAuction()` validates amounts and
|
|
host resources, then inserts `ng_auction`.
|
|
- `AuctionUniqueItem::openItemAuction()` checks availability, reserves
|
|
unique items, and posts a global history notice.
|
|
2. **Bid**
|
|
- Bids are inserted into `ng_auction_bid` and can extend the close date.
|
|
- Reverse auctions (when `detail->isReverse`) sort by lowest bid.
|
|
3. **Close** (`tryFinish()` from the concrete auction)
|
|
- If no bids: `rollbackAuction()` returns resources to host and logs.
|
|
- With bids: `finishAuction()` transfers resources, logs, and sends messages.
|
|
4. **Processing**
|
|
- `processAuction()` scans auctions past `close_date` and finishes them.
|
|
|
|
## Unique Item Auctions
|
|
|
|
- Currency: inheritance points (`ResourceType::inheritancePoint`).
|
|
- Host identity is obfuscated using `genObfuscatedName()` and a deterministic
|
|
shuffled name pool stored in `game_env.obfuscatedNamePool`.
|
|
- Limits and availability are enforced against `GameConst::$allItems` and
|
|
existing ownership in `general` rows.
|
|
|
|
## Betting System
|
|
|
|
Betting is an independent KV-backed system:
|
|
|
|
- `Betting::openBetting()` stores `BettingInfo` in KV storage (`betting`).
|
|
- `Betting::bet()` inserts or updates `ng_betting` rows and charges either
|
|
gold or inheritance points.
|
|
- `Betting::giveReward()` distributes payouts to winners (exclusive or shared).
|
|
|
|
Event actions controlling lifecycle:
|
|
|
|
- `OpenNationBetting`: opens a nation-strength bet and registers a
|
|
`DESTROY_NATION` event to close it.
|
|
- `FinishNationBetting`: evaluates winners when only N nations remain.
|
|
|
|
## RNG Notes
|
|
|
|
- `Auction::genObfuscatedName()` uses `hiddenSeed + 'obfuscatedNamePool'` to
|
|
shuffle the name pool once and reuse it from `game_env`.
|
|
- `registerAuction()` relies on an injected RNG to randomize neutral auctions.
|
|
|
|
## Open Questions / Follow-ups
|
|
|
|
- `registerAuction()` is called from legacy `func_gamerule.php` after the
|
|
logical month changes. Its RNG is seeded before that change with the previous
|
|
year/month, then consumes one power roll per nation and the conditional
|
|
tournament roll before auction generation.
|
|
- Scenario-specific overrides of unique auction timing have not been found.
|
|
Core2026 currently applies the legacy constants against `tickSeconds`.
|
|
|
|
## core2026 compatibility implementation (2026-07-25)
|
|
|
|
| Contract | core2026 path | Status |
|
|
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
| Resource auction list/open/bid | `game-frontend/AuctionView.vue` → `game-api/router/auction` → `auctionOpen`/`auctionBid` engine commands | Confirmed by integration test |
|
|
| Resource reservation/refund/settlement | opener reserves host gold/rice; bidder reserves and refunds the previous top bid; finalizer transfers or returns resources | Confirmed by integration test |
|
|
| Unique list/detail privacy | API replaces host and bidder identity with deterministic aliases and never returns unique-auction general IDs | Confirmed by API implementation and typecheck |
|
|
| Unique open | engine validates configured quantity, slot ownership, one active host/item auction, and atomically inserts the host's first bid while deducting `inheritance_point.previous` | Confirmed by integration test |
|
|
| Unique bid | row-locked auction, minimum `max(1%, 10)`, conditional point deduction, previous-top-bid refund, slot/top-bid conflict checks | Confirmed by integration test |
|
|
| Unique finalization | requested extension, per-slot and total ownership-limit extension, host neutralization, item inventory update | Confirmed by integration test |
|
|
| Timer/worker | API updates the Redis timer after open/bid; existing scheduler claims due rows and sends durable `auctionFinalize` commands | Confirmed by integration test for timer seed and durable command finalization |
|
|
| Neutral merchant registration | `neutralRegistrar.ts` runs at the month boundary, reproduces the previous-month seed and preceding RNG consumption, and queues host `0` auctions in the same DB transaction as the month state | Confirmed by PHP differential, engine boundary, PostgreSQL idempotency, and full integration tests |
|
|
|
|
Unique auction mutations deliberately run in the turn-engine database
|
|
transaction. Point reads use row locks and deductions use conditional updates,
|
|
so simultaneous requests cannot spend the same previous-season inheritance
|
|
points twice. A failed open command creates neither an auction nor an orphaned
|
|
inheritance request marker.
|
|
|
|
Neutral registration intentionally counts every historical host-`0` resource
|
|
auction, including finished rows, because the legacy probability denominator
|
|
does not filter on `finished`. Average gold/rice includes only generals with
|
|
`npcState < 2` and is clamped to 1,000..20,000. The month marker and generated
|
|
auction rows are persisted together under a PostgreSQL advisory transaction
|
|
lock, preventing the same month from producing duplicate merchant auctions
|
|
during daemon retry.
|