package game import ( "fmt" "log" "strconv" "strings" ) type GameStatus int const ( StatusLobby = iota StatusReady StatusPlaying StatusStop StatusSentinalWin StatusScourgeWin StatusDraw ) const ( SentinalID = 1 ScourgeID = 2 ) func (g GameStatus) String() string { return []string{"Lobby", "Ready", "Playing", "Stopped", "SentinalWin", "ScougeWin", "Draw"}[g] } type Game struct { GameBoard *Board SentinalPlayer *Player ScourgePlayer *Player SentinalDeck *Deck ScourgeDeck *Deck CurrentTurn int CardBuffer *Deck CanDraw bool HasDrawn bool Status GameStatus } func NewGame() *Game { deckA := NewDeck(SentinalID) deckB := NewDeck(ScourgeID) deckA.Shuffle() deckB.Shuffle() return &Game{ GameBoard: NewBoard(), SentinalPlayer: NewPlayer("Sentinal", SentinalID), ScourgePlayer: NewPlayer("Scourge", ScourgeID), SentinalDeck: deckA, ScourgeDeck: deckB, CurrentTurn: 0, //start with no turn CardBuffer: DeckFromCards([]*Card{}), CanDraw: false, HasDrawn: false, Status: StatusLobby, } } func (g *Game) String() string { return fmt.Sprintf("Sen(%v): %v\n\n%v\n\nSco(%v): %v\nStatus:%v Draw:%v Turn:%v\n%v\n", g.SentinalPlayer.Life, g.SentinalPlayer.Hand, g.GameBoard, g.ScourgePlayer.Life, g.ScourgePlayer.Hand, g.Status, g.CanDraw, g.CurrentTurn, g.CardBuffer) } func (g *Game) Parse(cmd *Command) *CommandResult { if g.Status == StatusDraw || g.Status == StatusScourgeWin || g.Status == StatusSentinalWin || g.Status == StatusStop { return &CommandResult{ PlayerID: cmd.PlayerID, ResultType: cmd.Type, StateResult: NewView(cmd.PlayerID, g), ActionResult: nil, DebugResult: g, } } var state_res *GameView var action_res *Deck var debug_res *Game var res_type CmdType if cmd.Type == ActCmd && g.Status == StatusPlaying { action_res = g.PlayerAct(cmd.PlayerID, cmd.Cmd) state_res = nil debug_res = nil res_type = ActCmd } else if cmd.Type == StateCmd { state_res = g.PlayerStateAct(cmd.PlayerID, cmd.Cmd) action_res = nil debug_res = nil res_type = StateCmd } else if cmd.Type == DebugCmd { state_res = nil action_res = nil debug_res = g res_type = DebugCmd } else { state_res = nil action_res = nil debug_res = nil res_type = InvalidCmd } g.StateChanges() return &CommandResult{ PlayerID: cmd.PlayerID, ResultType: res_type, StateResult: state_res, ActionResult: action_res, DebugResult: debug_res, } } func (g *Game) StateChanges() { //check for no actions first if len(g.SentinalPlayer.Hand) == 0 && g.SentinalDeck.Size() == 0 { if g.GameBoard.Empty(SentinalID) { g.Status = StatusScourgeWin } } if len(g.ScourgePlayer.Hand) == 0 && g.ScourgeDeck.Size() == 0 { if g.GameBoard.Empty(ScourgeID) { g.Status = StatusSentinalWin } } //reapply card effects g.GameBoard.ResetCards() for i := 0; i < len(g.GameBoard.Sentinal); i++ { OracleTick(g.GameBoard.Sentinal[i], g) //apply effect stacks first OracleTick(g.GameBoard.Scourge[i], g) } for i := 0; i < len(g.GameBoard.Sentinal); i++ { OracleEffect(g.GameBoard.Sentinal[i], g) //activate effects OracleEffect(g.GameBoard.Scourge[i], g) } //check life //this is second on purpose so that it shadows deck out win conditions //if you use your last action to win the game, you should actually win if g.SentinalPlayer.Life < 0 { g.Status = StatusScourgeWin } if g.ScourgePlayer.Life < 0 { g.Status = StatusSentinalWin } if g.ScourgePlayer.Life < 0 && g.SentinalPlayer.Life < 0 { g.Status = StatusDraw } } func (g *Game) PlayerStateAct(id int, cmd string) *GameView { switch cmd { case "d": Debug(g) case "g": //game state return NewView(id, g) case "b": //begin game if id == SentinalID { g.SentinalPlayer.Ready = true } else if id == ScourgeID { g.ScourgePlayer.Ready = true } if g.SentinalPlayer.Ready && g.ScourgePlayer.Ready && g.Status == StatusLobby { g.Status = StatusReady if id == SentinalID { g.SentinalPlayer.Hand = g.SentinalDeck.Cards[len(g.SentinalDeck.Cards)-5 : len(g.SentinalDeck.Cards)] g.SentinalDeck.Cards = g.SentinalDeck.Cards[0 : len(g.SentinalDeck.Cards)-5] g.ScourgePlayer.Hand = g.ScourgeDeck.Cards[len(g.ScourgeDeck.Cards)-6 : len(g.ScourgeDeck.Cards)] g.ScourgeDeck.Cards = g.ScourgeDeck.Cards[0 : len(g.ScourgeDeck.Cards)-6] g.CurrentTurn = SentinalID } else { g.SentinalPlayer.Hand = g.SentinalDeck.Cards[len(g.SentinalDeck.Cards)-6 : len(g.SentinalDeck.Cards)] g.SentinalDeck.Cards = g.SentinalDeck.Cards[0 : len(g.SentinalDeck.Cards)-6] g.ScourgePlayer.Hand = g.ScourgeDeck.Cards[len(g.ScourgeDeck.Cards)-5 : len(g.ScourgeDeck.Cards)] g.ScourgeDeck.Cards = g.ScourgeDeck.Cards[0 : len(g.ScourgeDeck.Cards)-5] g.CurrentTurn = ScourgeID } } case "s": //start turn if g.Status == StatusReady { //first turn g.Status = StatusPlaying } //skip draw step when 0 life if id == SentinalID && g.SentinalPlayer.Life <= 0 { g.CanDraw = false g.HasDrawn = true } else if id == ScourgeID && g.ScourgePlayer.Life <= 0 { g.CanDraw = false g.HasDrawn = true } else { g.CanDraw = true g.HasDrawn = false } if id != g.CurrentTurn { return nil } if id == SentinalID { for _, v := range g.GameBoard.Sentinal { OracleUpkeep(v, g) } } else { for _, v := range g.GameBoard.Scourge { OracleUpkeep(v, g) } } case "e": //end turn and clean up if id != g.CurrentTurn { return nil } g.CardBuffer = DeckFromCards([]*Card{}) if id == SentinalID { for _, v := range g.GameBoard.Sentinal { OracleEndstep(v, g) } } else { for _, v := range g.GameBoard.Scourge { OracleEndstep(v, g) } } if g.CurrentTurn == SentinalID { g.CurrentTurn = ScourgeID } else { g.CurrentTurn = SentinalID } } return NewView(id, g) } func (g *Game) PlayerAct(id int, cmd string) *Deck { if id != g.CurrentTurn { return nil } var curr *Player var opp *Player var currD *Deck if id == g.SentinalPlayer.Id { curr = g.SentinalPlayer opp = g.ScourgePlayer currD = g.SentinalDeck } else { curr = g.ScourgePlayer opp = g.SentinalPlayer currD = g.ScourgeDeck } cmd_s := strings.Split(cmd, " ") if len(cmd_s) < 1 { return nil } switch cmd_s[0] { case "s": //scry: return scry options off top of deck if !g.CanDraw { return nil } if g.CardBuffer.Size() <= 0 { g.CardBuffer = DeckFromCards(currD.Scry(curr.Life)) } return g.CardBuffer case "d": //draw: return player hand if !g.CanDraw { return nil } if len(cmd_s) != 2 || !g.CanDraw { return nil } if curr.Life == 0 { return DeckFromCards(curr.Hand) } x_i, err := strconv.Atoi(cmd_s[1]) if err != nil { panic(err) } if x_i > 2 || x_i < 0 { return nil } x := g.CardBuffer.Cards[x_i] if x.Owner != g.CurrentTurn { log.Println("drew a card from our deck that isn't our own") } g.CardBuffer.Cards = append(g.CardBuffer.Cards[:x_i], g.CardBuffer.Cards[x_i+1:]...) currD.Bottom(g.CardBuffer.Cards) curr.Hand = append(curr.Hand, x) g.CanDraw = false g.HasDrawn = true return DeckFromCards(curr.Hand) case "m": //move: return player board or [] if invalid if len(cmd_s) != 3 { return nil } if !g.HasDrawn { return nil } x_i, err := strconv.Atoi(cmd_s[1]) if err != nil { log.Println(err) return nil } y_i, err := strconv.Atoi(cmd_s[2]) if err != nil { log.Println(err) } if g.GameBoard.CanMove(g.CurrentTurn, x_i, y_i) { OracleMove(g.GameBoard.GetCard(g.CurrentTurn, x_i), x_i, y_i, g) g.GameBoard.Move(g.CurrentTurn, x_i, y_i) return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) } else { return DeckFromCards([]*Card{}) } case "a": //attack if len(cmd_s) != 3 { return nil } if !g.HasDrawn { return nil } x_i, err := strconv.Atoi(cmd_s[1]) if err != nil { log.Println(err) return nil } y_i, err := strconv.Atoi(cmd_s[2]) if err != nil { log.Println(err) return nil } if g.GameBoard.CanAttack(g.CurrentTurn, x_i, y_i) { OracleAttack(g.GameBoard.GetCard(g.CurrentTurn, x_i), g) res := g.GameBoard.Attack(g.CurrentTurn, x_i, y_i) var aid, did int if id == SentinalID { aid = SentinalID did = ScourgeID } else { aid = ScourgeID did = SentinalID } attacker := g.GameBoard.GetRow(aid)[x_i] defender := g.GameBoard.GetRow(did)[y_i] switch res { case 1: opp.Life = opp.Life - 1 case 2: OracleLeaves(defender, g) g.GameBoard.Remove(defender) case 3: OracleLeaves(attacker, g) g.GameBoard.Remove(attacker) case 4: OracleLeaves(attacker, g) OracleLeaves(defender, g) g.GameBoard.Remove(attacker) g.GameBoard.Remove(defender) } return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) } else { log.Println("can't attack") return DeckFromCards([]*Card{}) } case "p": //play: return player boad or [] if invalid if len(cmd_s) != 3 { fmt.Println("not enough arguments") return nil } if !g.HasDrawn { return nil } x_i, err := strconv.Atoi(cmd_s[1]) if err != nil { log.Println(err) return nil } y_i, err := strconv.Atoi(cmd_s[2]) if err != nil { log.Println(err) return nil } if x_i < 0 || x_i > len(curr.Hand) { return nil } card := curr.Hand[x_i] shouldPlace := true if g.GameBoard.CanPlay(g.CurrentTurn, card, y_i) { shouldPlace = OracleCast(card, g) placed := g.GameBoard.Play(g.CurrentTurn, card, y_i, shouldPlace) if placed { OracleEnters(card, g) } curr.Hand = append(curr.Hand[:x_i], curr.Hand[x_i+1:]...) return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) } else { fmt.Println("couldn't play") return DeckFromCards([]*Card{}) } default: fmt.Println("Invalid act command") return nil } return nil } func Debug(g *Game) { return }