Files
super-auto-pets-board-game/internal/game/view.go
T
Greyson Parrelli b2aa7c5ca3 Add DEBUG-gated panel to buy any card in the shop
When the server's DEBUG env var is on, expose a card catalog endpoint
and a collapsible client panel that drops any pet or food straight into
your deck (free, off-turn). Gated server-side so it is inert in normal
play.
2026-07-23 01:07:14 -04:00

92 lines
2.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"`
DeckSize int `json:"deckSize"`
PetCount int `json:"petCount"`
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"`
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"`
Battle *BattleResult `json:"battle,omitempty"`
WinnerSeat int `json:"winnerSeat"`
// 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,
YouSeat: -1,
Turn: g.Turn,
PrioritySeat: g.PrioritySeat,
ShopRow: g.ShopRow,
WinnerSeat: g.WinnerSeat,
}
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,
DeckSize: len(p.Deck),
PetCount: p.PetCount(),
}
if p.ID == playerID {
v.YouSeat = p.Seat
pv.Deck = p.Deck
}
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
}
// 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
}