135 lines
4.8 KiB
Go
135 lines
4.8 KiB
Go
package game
|
|
|
|
// PlayerView is what any player may know about a seat. Deck contents are
|
|
// only included for the viewer's own seat; opponents see counts.
|
|
type PlayerView struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Seat int `json:"seat"`
|
|
Coins int `json:"coins"`
|
|
Trophies int `json:"trophies"`
|
|
Ready bool `json:"ready"`
|
|
Connected bool `json:"connected"`
|
|
IsBot bool `json:"isBot,omitempty"`
|
|
DeckSize int `json:"deckSize"`
|
|
PetCount int `json:"petCount"`
|
|
// Avocados is the player's set-aside Avocado token count (Golden pack).
|
|
// Public: buying an Avocado is a public shop event.
|
|
Avocados int `json:"avocados,omitempty"`
|
|
// FirstBuyFree / BuysThisRound (Golden pack) are self-only: they'd reveal
|
|
// hidden deck facts (a Manta Ray) to opponents.
|
|
FirstBuyFree bool `json:"firstBuyFree,omitempty"`
|
|
BuysThisRound int `json:"buysThisRound,omitempty"`
|
|
Deck []Card `json:"deck,omitempty"` // self only
|
|
}
|
|
|
|
// View is the full game state as seen by one player.
|
|
type View struct {
|
|
GameID string `json:"gameId"`
|
|
Code string `json:"code"`
|
|
Phase Phase `json:"phase"`
|
|
Round int `json:"round"`
|
|
MaxRounds int `json:"maxRounds"`
|
|
MaxPets int `json:"maxPets"`
|
|
// Pack is the selected card pack; Packs is the catalog of choices for the
|
|
// lobby. HostSeat is the seat that controls the lobby (always 0 for now);
|
|
// MinPlayers is how many seats must be filled before the host can start.
|
|
Pack string `json:"pack"`
|
|
Packs []PackInfo `json:"packs"`
|
|
HostSeat int `json:"hostSeat"`
|
|
MinPlayers int `json:"minPlayers"`
|
|
MaxPlayers int `json:"maxPlayers"`
|
|
YouSeat int `json:"youSeat"`
|
|
Turn int `json:"turn"`
|
|
// PrioritySeat is the seat currently holding the priority token.
|
|
PrioritySeat int `json:"prioritySeat"`
|
|
ShopRow []Card `json:"shopRow"`
|
|
DeckCounts []int `json:"deckCounts"` // remaining shop cards per tier
|
|
Players []PlayerView `json:"players"`
|
|
// Pending is included for everyone so opponents see a trade is in
|
|
// progress, but the revealed options are only shown to the trader.
|
|
Pending *PendingTrade `json:"pending,omitempty"`
|
|
// PendingReveal (Golden pack: Cockatoo) is shown to everyone so opponents
|
|
// see a reveal is in progress; the eligible options are only sent to the
|
|
// buyer (they name the buyer's own hidden pets).
|
|
PendingReveal *PendingReveal `json:"pendingReveal,omitempty"`
|
|
// PendingBattle (Golden pack: Nurse Shark) is a mid-battle decision owed by
|
|
// one seat; public since the battle replay is public.
|
|
PendingBattle *PendingBattleDecision `json:"pendingBattle,omitempty"`
|
|
Battle *BattleResult `json:"battle,omitempty"`
|
|
WinnerSeat int `json:"winnerSeat"`
|
|
// Log is the shared, public event log shown across every phase.
|
|
Log []LogEntry `json:"log,omitempty"`
|
|
// Debug is set by the server when its DEBUG flag is on, unlocking the
|
|
// client's "buy any card" panel. Not part of the pure game state.
|
|
Debug bool `json:"debug,omitempty"`
|
|
}
|
|
|
|
// ViewFor builds the state visible to the given player.
|
|
func (g *Game) ViewFor(playerID string) View {
|
|
v := View{
|
|
GameID: g.ID,
|
|
Code: g.Code,
|
|
Phase: g.Phase,
|
|
Round: g.Round,
|
|
MaxRounds: MaxRounds,
|
|
MaxPets: MaxPets,
|
|
Pack: g.Pack,
|
|
Packs: Packs,
|
|
HostSeat: 0,
|
|
MinPlayers: MinPlayers,
|
|
MaxPlayers: MaxPlayers,
|
|
YouSeat: -1,
|
|
Turn: g.Turn,
|
|
PrioritySeat: g.PrioritySeat,
|
|
ShopRow: g.ShopRow,
|
|
WinnerSeat: g.WinnerSeat,
|
|
Log: g.Log,
|
|
}
|
|
for _, deck := range g.ShopDecks {
|
|
v.DeckCounts = append(v.DeckCounts, len(deck))
|
|
}
|
|
for _, p := range g.Players {
|
|
pv := PlayerView{
|
|
ID: p.ID,
|
|
Name: p.Name,
|
|
Seat: p.Seat,
|
|
Coins: p.Coins,
|
|
Trophies: p.Trophies,
|
|
Ready: p.Ready,
|
|
Connected: p.Connected,
|
|
IsBot: p.IsBot,
|
|
DeckSize: len(p.Deck),
|
|
PetCount: p.PetCount(),
|
|
Avocados: p.Avocados,
|
|
}
|
|
if p.ID == playerID {
|
|
v.YouSeat = p.Seat
|
|
pv.Deck = p.Deck
|
|
pv.FirstBuyFree = p.FirstBuyFree
|
|
pv.BuysThisRound = p.BuysThisRound
|
|
}
|
|
v.Players = append(v.Players, pv)
|
|
}
|
|
if g.Pending != nil {
|
|
pending := *g.Pending
|
|
if pending.PlayerID != playerID {
|
|
pending.Options = [2]Card{} // hide the revealed cards
|
|
}
|
|
v.Pending = &pending
|
|
}
|
|
if g.PendingReveal != nil {
|
|
reveal := *g.PendingReveal
|
|
if reveal.PlayerID != playerID {
|
|
reveal.Options = nil // hide which of the buyer's pets are eligible
|
|
}
|
|
v.PendingReveal = &reveal
|
|
}
|
|
v.PendingBattle = g.PendingBattle
|
|
// Battle results (lineups, events) are public once resolved. Keep the
|
|
// battle around during the following shop phase too, so late joiners /
|
|
// reconnects can still see the last result.
|
|
v.Battle = g.Battle
|
|
return v
|
|
}
|