added more documentation
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
# ShaiBot Architecture
|
||||
|
||||
This manual describes ShaiBot's implementation structure at a level
|
||||
useful to maintainers. For exact behavior, the current code remains
|
||||
authoritative.
|
||||
|
||||
## Runtime
|
||||
|
||||
`index.js` initializes the Discord client and MongoDB connection,
|
||||
creates the interaction collections, initializes shared systems/indexes,
|
||||
loads handlers, and logs the bot in.
|
||||
|
||||
Interaction modules are discovered into collections such as:
|
||||
|
||||
``` js
|
||||
client.commands
|
||||
client.legacyCommands
|
||||
client.aliases
|
||||
client.buttons
|
||||
client.selectMenus
|
||||
client.modals
|
||||
```
|
||||
|
||||
Before manually wiring a new component into the central router, check
|
||||
whether the filesystem loader already supports it.
|
||||
|
||||
## Preferred Layering
|
||||
|
||||
ShaiBot favors:
|
||||
|
||||
``` text
|
||||
Discord command / button / select menu
|
||||
↓
|
||||
shared utility
|
||||
↓
|
||||
Mongo / economy / profile
|
||||
```
|
||||
|
||||
Discord wrappers should remain thin. Shared rules belong in `utils/`.
|
||||
|
||||
A feature reachable from multiple interfaces should normally have one
|
||||
authoritative implementation.
|
||||
|
||||
## Important Shared Utilities
|
||||
|
||||
Examples include:
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
Utility Responsibility
|
||||
----------------------------------- -----------------------------------
|
||||
`cookieEconomy.js` Cookie balances, transfers,
|
||||
cooldowns, economy primitives
|
||||
|
||||
`crumbCollect.js` Shared Cookie collection
|
||||
|
||||
`crumbSlots.js` Slots
|
||||
|
||||
`crumbBlackjack.js` Blackjack
|
||||
|
||||
`crumbRoulette.js` Roulette
|
||||
|
||||
`cookieHeist.js` Vault Heist
|
||||
|
||||
`bankruptcy.js` Bankruptcy/recovery
|
||||
|
||||
`profileSystem.js` Profiles, achievements, badges,
|
||||
activity
|
||||
|
||||
`profileMaintenance.js` Profile audit/reconciliation
|
||||
|
||||
`interactionSession.js` Shared single-owner interaction
|
||||
sessions
|
||||
|
||||
`permissions.js` Administrator/bot-author checks
|
||||
|
||||
`pokerEngine.js` Pure Hold'em engine
|
||||
|
||||
`crumbPoker.js` Persistent Poker service
|
||||
|
||||
`pokerDiscord.js` Poker Discord rendering/components
|
||||
|
||||
`pokerProfile.js` Poker progression bridge
|
||||
|
||||
`crumbleStrike.js` Cooperative encounter state/combat
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
## MongoDB
|
||||
|
||||
Important collections include:
|
||||
|
||||
``` text
|
||||
items_cookies
|
||||
cooldown_cookies
|
||||
items_games
|
||||
items_special_games
|
||||
stats_profiles
|
||||
items_achievements
|
||||
guild_badges
|
||||
config_achievements
|
||||
```
|
||||
|
||||
Indexes are part of correctness, not only performance.
|
||||
|
||||
ShaiBot intentionally avoids requiring multi-document MongoDB
|
||||
transactions. Depending on the subsystem it instead uses:
|
||||
|
||||
- Atomic filtered updates
|
||||
- Unique indexes
|
||||
- Optimistic version checks
|
||||
- Idempotency markers
|
||||
- Persistent resolution state
|
||||
- Compensating writes
|
||||
|
||||
## Concurrency
|
||||
|
||||
Assume users can double-click, spam controls, act simultaneously, race a
|
||||
timeout, or restart the bot during a transition.
|
||||
|
||||
Stateful systems should answer:
|
||||
|
||||
``` text
|
||||
What is authoritative?
|
||||
Can two interactions both succeed?
|
||||
Can money move twice?
|
||||
What happens if the process stops after the first write?
|
||||
Can the operation safely be retried?
|
||||
```
|
||||
|
||||
Do not rely on process-local flags for correctness that must survive a
|
||||
restart.
|
||||
|
||||
## Discord Interactions
|
||||
|
||||
Button visibility is never authorization.
|
||||
|
||||
For potentially slow stateful interactions, acknowledge Discord early
|
||||
using the response style appropriate to that flow.
|
||||
|
||||
Do not globally defer every interaction from the central router because
|
||||
different modules legitimately use `reply`, `update`, `deferReply`, or
|
||||
`deferUpdate`.
|
||||
|
||||
Critical state should not exist only in an embed/footer.
|
||||
|
||||
## Permissions
|
||||
|
||||
Administrative access is centralized through the shared permission
|
||||
utility.
|
||||
|
||||
Administrative access may include:
|
||||
|
||||
``` text
|
||||
Discord Administrator
|
||||
OR
|
||||
BOT_AUTHOR_ID
|
||||
```
|
||||
|
||||
Do not hard-code administrative Discord IDs.
|
||||
|
||||
## Deployment
|
||||
|
||||
Typical production workflow:
|
||||
|
||||
``` bash
|
||||
node --check path/to/changed-file.js
|
||||
pm2 restart ShaiBot
|
||||
pm2 logs ShaiBot --lines 100
|
||||
```
|
||||
|
||||
Syntax checking is useful, but economy and persistent-state changes
|
||||
still require behavioral testing.
|
||||
|
||||
## Maintainer Checklist
|
||||
|
||||
Before shipping a stateful change:
|
||||
|
||||
- Identify the authoritative state.
|
||||
- Check duplicate-click behavior.
|
||||
- Check simultaneous-user behavior.
|
||||
- Check insufficient-balance behavior.
|
||||
- Check restart/recovery behavior.
|
||||
- Check private/public information boundaries.
|
||||
- Check whether profile tracking can safely fail without corrupting
|
||||
settlement.
|
||||
- Inspect Mongo after a controlled live test.
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
# ShaiBot Cookie Economy
|
||||
|
||||
This manual describes the shared Cookie economy and the rules
|
||||
maintainers should preserve.
|
||||
|
||||
## Source of Truth
|
||||
|
||||
`utils/cookieEconomy.js` is the shared economy utility.
|
||||
|
||||
Game and command modules should not perform independent ad-hoc balance
|
||||
mutations when the shared economy already provides the required
|
||||
operation.
|
||||
|
||||
## Balances
|
||||
|
||||
Cookie balances live in:
|
||||
|
||||
``` text
|
||||
items_cookies
|
||||
```
|
||||
|
||||
Conceptually:
|
||||
|
||||
``` js
|
||||
{
|
||||
userId: "...",
|
||||
cookies: 2500
|
||||
}
|
||||
```
|
||||
|
||||
Negative changes use an atomic balance filter so a player cannot spend
|
||||
more Cookies than are available.
|
||||
|
||||
Expected insufficient-balance failures use:
|
||||
|
||||
``` text
|
||||
INSUFFICIENT_COOKIES
|
||||
```
|
||||
|
||||
Some subsystems carry expected error identifiers in `error.message`,
|
||||
while others may also use `error.code`. User-facing formatters should
|
||||
account for the convention used by that subsystem.
|
||||
|
||||
## Transfers
|
||||
|
||||
Player-to-player transfers do not require MongoDB transactions.
|
||||
|
||||
The safe conceptual sequence is:
|
||||
|
||||
``` text
|
||||
atomic debit source
|
||||
→ credit destination
|
||||
→ compensate source if destination credit fails
|
||||
```
|
||||
|
||||
A critical compensation failure must remain visible in logs.
|
||||
|
||||
## Cooldowns
|
||||
|
||||
Cooldowns live in:
|
||||
|
||||
``` text
|
||||
cooldown_cookies
|
||||
```
|
||||
|
||||
Use the shared cooldown helpers, especially atomic cooldown claiming
|
||||
when double-clicks or simultaneous requests must not both succeed.
|
||||
|
||||
## House Vault
|
||||
|
||||
ShaiBot acts as the general house Cookie vault for supported games.
|
||||
|
||||
Gambling losses and penalties may feed the vault, while wins, heists,
|
||||
and rewards may pay out from it.
|
||||
|
||||
House-funded features should respect their existing liquidity rules.
|
||||
|
||||
## Cookie Collection
|
||||
|
||||
`/cookies collect` and the Crumb Saucer Bakery share
|
||||
`utils/crumbCollect.js`.
|
||||
|
||||
They must share:
|
||||
|
||||
- the same cooldown
|
||||
- the same reward generation
|
||||
- the same balance mutation
|
||||
- the same profile tracking
|
||||
|
||||
Do not create separate collection behavior for the two interfaces.
|
||||
|
||||
## PvP Stealing
|
||||
|
||||
Normal player-to-player stealing is separate from Vault Heist.
|
||||
|
||||
Detailed robbery balancing lives in:
|
||||
|
||||
``` text
|
||||
COOKIE_LOGIC.md
|
||||
```
|
||||
|
||||
The current model includes wealth scaling, victim heat, percentage-based
|
||||
loot, a hard per-hit cap, and an hourly victim exposure budget.
|
||||
|
||||
## Persistent Game Settlement
|
||||
|
||||
For simple house games, settlement should still be protected against
|
||||
repeated resolution.
|
||||
|
||||
For lifecycle-heavy multiplayer games such as Poker, Cookie movement is
|
||||
separated from internal chip movement.
|
||||
|
||||
Poker only crosses the Cookie economy boundary for:
|
||||
|
||||
``` text
|
||||
buy-in
|
||||
cash-out / refund
|
||||
```
|
||||
|
||||
Ordinary Poker betting modifies the table's internal stack state, not
|
||||
`items_cookies`.
|
||||
|
||||
## Idempotent Operations
|
||||
|
||||
Recovery-sensitive economy flows can use operation IDs.
|
||||
|
||||
Poker temporarily stores markers such as:
|
||||
|
||||
``` js
|
||||
appliedCookieOperations: [
|
||||
"poker_buyin:...",
|
||||
"poker_cashout:..."
|
||||
]
|
||||
```
|
||||
|
||||
The purpose is to prevent a retry after a crash from moving money twice.
|
||||
|
||||
Safe lifecycle:
|
||||
|
||||
``` text
|
||||
apply Cookie operation once
|
||||
→ persist authoritative game state
|
||||
→ confirm operation is durably represented
|
||||
→ remove temporary marker
|
||||
```
|
||||
|
||||
Never remove a recovery marker before the surrounding state is safe.
|
||||
|
||||
When the final marker is removed, unset the empty field instead of
|
||||
leaving:
|
||||
|
||||
``` js
|
||||
appliedCookieOperations: []
|
||||
```
|
||||
|
||||
## Economy Invariants
|
||||
|
||||
Every economy change should preserve:
|
||||
|
||||
``` text
|
||||
No Cookie duplication.
|
||||
No unexplained Cookie loss.
|
||||
No duplicate debit.
|
||||
No duplicate payout.
|
||||
No spending below zero.
|
||||
```
|
||||
|
||||
Correctness and recoverability take priority over cosmetic cleanup.
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
# ShaiBot Game Manual
|
||||
|
||||
This document gives maintainers a compact overview of the main game
|
||||
systems. Exact rules remain in the owning utilities.
|
||||
|
||||
# Crumb Saucer
|
||||
|
||||
The Crumb Saucer is ShaiBot's Cookie-powered game hub.
|
||||
|
||||
Shared principle:
|
||||
|
||||
``` text
|
||||
Discord controls
|
||||
→ game utility
|
||||
→ Cookie economy / profile system
|
||||
```
|
||||
|
||||
## Slots
|
||||
|
||||
Core utility:
|
||||
|
||||
``` text
|
||||
utils/crumbSlots.js
|
||||
```
|
||||
|
||||
Features include multiple wagers, symbol payouts, jackpots, All-In
|
||||
tracking, Run It Back, profile statistics, achievements, and guild-first
|
||||
triplet badges.
|
||||
|
||||
Historical replay facts must come from wager-time metadata rather than
|
||||
the player's current Cookie balance.
|
||||
|
||||
## Blackjack
|
||||
|
||||
Core utility:
|
||||
|
||||
``` text
|
||||
utils/crumbBlackjack.js
|
||||
```
|
||||
|
||||
Supports:
|
||||
|
||||
- Hit
|
||||
- Stand
|
||||
- Double
|
||||
- Dealer stands on 17
|
||||
- Natural Blackjack pays 3:2
|
||||
- Push
|
||||
- All-In
|
||||
- Run It Back
|
||||
|
||||
Repeated interactions must never resolve/pay the same hand twice.
|
||||
|
||||
## Roulette
|
||||
|
||||
Core utility:
|
||||
|
||||
``` text
|
||||
utils/crumbRoulette.js
|
||||
```
|
||||
|
||||
European Roulette uses `0–36`.
|
||||
|
||||
Simple bets include Red, Black, Odd, Even, and Zero. Zero loses for
|
||||
Red/Black/Odd/Even.
|
||||
|
||||
Animation uses edits of the same message rather than high-frequency
|
||||
message spam.
|
||||
|
||||
## Vault Heist
|
||||
|
||||
Core utility:
|
||||
|
||||
``` text
|
||||
utils/cookieHeist.js
|
||||
```
|
||||
|
||||
Vault Heist targets ShaiBot's house vault and is separate from PvP
|
||||
stealing.
|
||||
|
||||
Approaches include Sneak, Hack, and Smash and share the same Heist
|
||||
cooldown.
|
||||
|
||||
## Bankruptcy
|
||||
|
||||
Core utility:
|
||||
|
||||
``` text
|
||||
utils/bankruptcy.js
|
||||
```
|
||||
|
||||
Bankruptcy provides a recovery path and tracks post-Bankruptcy
|
||||
rebuilding in profiles.
|
||||
|
||||
Recovery progress should reflect actual balance after Bankruptcy, not
|
||||
merely lifetime Cookie gains.
|
||||
|
||||
## Run It Back
|
||||
|
||||
Supported games can track consecutive replay through the explicit Run It
|
||||
Back action.
|
||||
|
||||
A normal/new wager breaks the chain.
|
||||
|
||||
Win/loss/push does not inherently break it because the streak represents
|
||||
the player's decision to immediately replay.
|
||||
|
||||
Historical All-In and wager state must be preserved at the time the
|
||||
wager occurs.
|
||||
|
||||
# Poker
|
||||
|
||||
Poker is a persistent 2--6 player Texas Hold'em game inside the Crumb
|
||||
Saucer.
|
||||
|
||||
Important files:
|
||||
|
||||
``` text
|
||||
utils/pokerEngine.js
|
||||
utils/crumbPoker.js
|
||||
utils/pokerDiscord.js
|
||||
utils/pokerInteractions.js
|
||||
utils/pokerProfile.js
|
||||
handlers/poker.js
|
||||
buttons/poker/*
|
||||
selectMenus/poker/*
|
||||
```
|
||||
|
||||
Current defaults:
|
||||
|
||||
``` text
|
||||
Buy-in: 1,000 Cookies
|
||||
Blinds: 10 / 20
|
||||
Turn timer: 90 seconds
|
||||
Pot model: single pot
|
||||
```
|
||||
|
||||
Supported actions:
|
||||
|
||||
``` text
|
||||
Fold
|
||||
Check
|
||||
Call
|
||||
Bet
|
||||
Raise
|
||||
All-In
|
||||
```
|
||||
|
||||
## Single-Pot Rule
|
||||
|
||||
Poker intentionally has no side pots.
|
||||
|
||||
At hand start, the maximum amount each participant can commit is limited
|
||||
by the smallest participating starting stack.
|
||||
|
||||
Chips above that cap remain protected for a later hand.
|
||||
|
||||
## Persistence
|
||||
|
||||
MongoDB is authoritative for live/recoverable tables.
|
||||
|
||||
Poker uses temporary state in:
|
||||
|
||||
``` text
|
||||
items_special_games
|
||||
```
|
||||
|
||||
and optimistic versioning for authoritative updates.
|
||||
|
||||
Fully settled games are cleaned up rather than kept permanently as raw
|
||||
history.
|
||||
|
||||
## Economy
|
||||
|
||||
Cookies move only at buy-in and cash-out/refund boundaries.
|
||||
|
||||
Betting moves internal table chips.
|
||||
|
||||
Recovery-sensitive economy operations are idempotent.
|
||||
|
||||
## Privacy
|
||||
|
||||
Hole cards are private.
|
||||
|
||||
The private Cards view may show the requesting player's cards, community
|
||||
cards, turn status, and remaining turn time.
|
||||
|
||||
It must never expose opponent cards.
|
||||
|
||||
A player-facing equity/win-percentage calculator is intentionally
|
||||
excluded from V1 for fairness.
|
||||
|
||||
## Turn / Lobby Behavior
|
||||
|
||||
Active turns have a 90-second deadline.
|
||||
|
||||
Timeout folding uses the same authoritative Fold transition as a normal
|
||||
player action.
|
||||
|
||||
Lobby expiry is disabled while a hand is active and refreshed when a
|
||||
hand ends.
|
||||
|
||||
The internal between-hand state may be called `NEXT_HAND`, but the
|
||||
user-facing UI presents **HAND COMPLETE**.
|
||||
|
||||
## Cancellation / Cleanup
|
||||
|
||||
Host cancellation is allowed outside an active hand.
|
||||
|
||||
Cancellation safely settles players before deleting the table state.
|
||||
|
||||
Confirmation controls should disappear after Confirm or Keep so stale
|
||||
buttons cannot remain usable.
|
||||
|
||||
# Crumble Strike
|
||||
|
||||
Core utility:
|
||||
|
||||
``` text
|
||||
utils/crumbleStrike.js
|
||||
```
|
||||
|
||||
Crumble Strike is a persistent cooperative boss battle.
|
||||
|
||||
Typical flow:
|
||||
|
||||
1. Spawn encounter.
|
||||
2. Recruit players.
|
||||
3. Start once requirements are met.
|
||||
4. Fight within the encounter lifetime.
|
||||
5. Settle success/failure and committed Cookies.
|
||||
|
||||
Combat includes:
|
||||
|
||||
``` text
|
||||
Strike
|
||||
Defend
|
||||
Heal
|
||||
Revive
|
||||
Limit Break
|
||||
```
|
||||
|
||||
Roles include:
|
||||
|
||||
``` text
|
||||
DPS
|
||||
Tank
|
||||
Healer
|
||||
```
|
||||
|
||||
Crumble Strike has more lifecycle complexity than ordinary Saucer games.
|
||||
Do not copy its persistence model into simpler games unless the new
|
||||
feature genuinely requires it.
|
||||
|
||||
# Raid Planner
|
||||
|
||||
Raid planning uses Discord embeds and reactions.
|
||||
|
||||
Participation can count unique users across reactions without forcibly
|
||||
removing reactions.
|
||||
|
||||
Be mindful of Discord partials when changing reaction behavior.
|
||||
@@ -0,0 +1,200 @@
|
||||
# ShaiBot Profiles, Achievements & Badges
|
||||
|
||||
ShaiBot's profile system is the permanent progression layer behind the
|
||||
economy and games.
|
||||
|
||||
## Central Profile System
|
||||
|
||||
`utils/profileSystem.js` owns the main profile/progression behavior.
|
||||
|
||||
Important collections:
|
||||
|
||||
``` text
|
||||
stats_profiles
|
||||
items_achievements
|
||||
guild_badges
|
||||
config_achievements
|
||||
```
|
||||
|
||||
Game modules should integrate with this system instead of creating
|
||||
separate progression databases.
|
||||
|
||||
## Profiles
|
||||
|
||||
Profiles can track:
|
||||
|
||||
- Overall game totals
|
||||
- Per-game statistics
|
||||
- Cookie gains and losses
|
||||
- Giving and stealing
|
||||
- Daily activity
|
||||
- Win/loss streaks
|
||||
- Weekday/time-of-day activity
|
||||
- Social relationships
|
||||
- Run It Back progression
|
||||
- Poker history
|
||||
- Achievement progress
|
||||
- Badge ownership
|
||||
|
||||
Profiles are intended to preserve meaningful long-term history.
|
||||
|
||||
## Profile Events
|
||||
|
||||
Prefer extending established event metadata rather than inventing
|
||||
parallel event systems.
|
||||
|
||||
Common concepts include:
|
||||
|
||||
``` text
|
||||
game_start
|
||||
game_result
|
||||
cookie_gain
|
||||
cookies_given
|
||||
steal_success
|
||||
stolen_from_me
|
||||
```
|
||||
|
||||
New wager metadata should prefer:
|
||||
|
||||
``` text
|
||||
wager
|
||||
```
|
||||
|
||||
Compatibility reads for older `bet`/`previousBet` fields may remain
|
||||
intentionally.
|
||||
|
||||
## Activity
|
||||
|
||||
Profile activity uses a configured timezone.
|
||||
|
||||
Default:
|
||||
|
||||
``` text
|
||||
Europe/Berlin
|
||||
```
|
||||
|
||||
Activity supports daily streaks, weekly participation, weekday counts,
|
||||
and broad time buckets.
|
||||
|
||||
Avoid making ordinary progression depend on excessively narrow
|
||||
late-night windows.
|
||||
|
||||
## Social Progression
|
||||
|
||||
Profiles can store unique relationship sets for gifting and stealing.
|
||||
|
||||
Use set-style updates for unique users rather than appending duplicates.
|
||||
|
||||
Current social progression is intentionally scaled for a relatively
|
||||
small community.
|
||||
|
||||
## Achievements
|
||||
|
||||
Achievements are personal: multiple players can earn the same
|
||||
achievement.
|
||||
|
||||
Supported models include:
|
||||
|
||||
### Stat-backed
|
||||
|
||||
Best for durable lifetime milestones and reconciliation.
|
||||
|
||||
### Composite
|
||||
|
||||
Combines multiple durable conditions.
|
||||
|
||||
### Event-only
|
||||
|
||||
Used when the accomplishment depends on exact event context that cannot
|
||||
reliably be reconstructed later.
|
||||
|
||||
### Hidden
|
||||
|
||||
Used for secret/special challenges.
|
||||
|
||||
Event-only achievements should not be treated as historically
|
||||
backfillable when the necessary event was never stored.
|
||||
|
||||
## Achievement Notifications
|
||||
|
||||
Unlock notification is centralized.
|
||||
|
||||
Individual games should not create competing achievement announcement
|
||||
systems.
|
||||
|
||||
## Global Badges
|
||||
|
||||
Global badges are guild-unique distinctions.
|
||||
|
||||
The common pattern is an atomic claim against an unowned badge:
|
||||
|
||||
``` text
|
||||
guildId
|
||||
badgeId
|
||||
ownerId: null
|
||||
```
|
||||
|
||||
then setting the winner.
|
||||
|
||||
This prevents simultaneous candidates from both owning the same
|
||||
guild-first badge.
|
||||
|
||||
Achievements and badges are intentionally different:
|
||||
|
||||
``` text
|
||||
Achievement → personal; many owners
|
||||
Global badge → guild-unique; one owner
|
||||
```
|
||||
|
||||
## ID Stability
|
||||
|
||||
Once achievement or badge IDs may exist in MongoDB, treat them as
|
||||
persistent database identifiers.
|
||||
|
||||
Prefer retiring an old definition over renaming/deleting an ID that
|
||||
players may already own.
|
||||
|
||||
## Reconciliation & Audit
|
||||
|
||||
Administrative tooling includes:
|
||||
|
||||
``` text
|
||||
/profileadmin audit
|
||||
/profileadmin reconcile dry-run:true
|
||||
```
|
||||
|
||||
Reconciliation can backfill durable/stat-backed accomplishments.
|
||||
|
||||
Event-only achievements may be skipped because historical event context
|
||||
cannot be invented safely.
|
||||
|
||||
When changing progression schemas:
|
||||
|
||||
- use idempotent migrations
|
||||
- preserve existing values
|
||||
- preserve historical IDs
|
||||
- dry-run reconciliation first
|
||||
- do not fabricate data that was never tracked
|
||||
|
||||
## Poker History
|
||||
|
||||
Poker stores permanent statistics in the profile system rather than
|
||||
retaining completed raw table documents.
|
||||
|
||||
Examples include:
|
||||
|
||||
- hands played/won/lost
|
||||
- Cookies won/lost
|
||||
- largest pot
|
||||
- All-Ins
|
||||
- showdowns
|
||||
- action counts
|
||||
- streaks
|
||||
- hand-rank counters
|
||||
- pocket Aces wins
|
||||
- 7-2 wins
|
||||
- fold wins
|
||||
- full-table wins
|
||||
|
||||
Poker profile tracking occurs after authoritative game state succeeds. A
|
||||
profile failure must never corrupt a valid pot/economy settlement.
|
||||
Reference in New Issue
Block a user