diff --git a/internal/game/board.go b/internal/game/board.go index 33fc8a0..f3ca276 100644 --- a/internal/game/board.go +++ b/internal/game/board.go @@ -2,6 +2,7 @@ package game import ( "fmt" + "log" ) type Board struct { @@ -17,7 +18,7 @@ func NewBoard() *Board { } func (b *Board) String() string { - return fmt.Sprintf("---------\n|%v|%v|%v|%v|\n---------\n|%v|%v|%v|%v|\n---------\n", b.Sentinal[0], b.Sentinal[1], b.Sentinal[2], b.Sentinal[3], b.Scourge[0], b.Scourge[1], b.Scourge[2], b.Scourge[3]) + return fmt.Sprintf("-----------------\n|%v|%v|%v|%v|\n-----------------\n|%v|%v|%v|%v|\n-----------------\n", b.Sentinal[0], b.Sentinal[1], b.Sentinal[2], b.Sentinal[3], b.Scourge[0], b.Scourge[1], b.Scourge[2], b.Scourge[3]) } func (b *Board) GetRow(id int) []*Card { @@ -59,6 +60,9 @@ func (b *Board) Empty(id int) bool { func (b *Board) CanMove(id, src, dest int) bool { brd := b.GetRow(id) + if src < 0 || src > 3 || dest < 0 || dest > 3 { + return false + } if brd[src].Empty() { return false } @@ -72,33 +76,17 @@ func (b *Board) CanMove(id, src, dest int) bool { } func (b *Board) Move(id, src, dest int) bool { - var brd [4]*Card - if id == SentinalID { - brd = b.Sentinal - } else { - brd = b.Scourge - } - if brd[src].Empty() { - return false - } - if !brd[dest].Empty() { - return false - } - if brd[src].Sick { - return false - } + brd := b.GetRow(id) brd[dest] = brd[src] brd[src] = NewEmpty(src) - if id == SentinalID { - b.Sentinal = brd - } else { - b.Scourge = brd - } return true } func (b *Board) CanPlay(id int, c *Card, dest int) bool { brd := b.GetRow(id) + if dest < 0 || dest > 3 { + return false + } if !brd[dest].Empty() && !c.Spell { return false } @@ -118,59 +106,52 @@ func (b *Board) Play(id int, c *Card, dest int, should bool) bool { func (b *Board) CanAttack(id, atk, def int) bool { aBrd := b.GetRow(id) + if atk < 0 || atk > 3 || def < 0 || def > 3 { + return false + } if aBrd[atk].Empty() || aBrd[atk].Sick || atk != def { return false } return true } -func (b *Board) Attack(id int, atk, def int) int { - var aBrd [4]*Card - var dBrd [4]*Card +func (b *Board) Attack(id, atk, def int) int { + var aid, did int if id == SentinalID { - aBrd = b.Sentinal - dBrd = b.Scourge + aid = SentinalID + did = ScourgeID } else { - aBrd = b.Scourge - dBrd = b.Sentinal + aid = ScourgeID + did = SentinalID } - if dBrd[def].Empty() { + attacker := b.GetRow(aid)[atk] + defender := b.GetRow(did)[def] + if defender.Empty() { //health damage - if id == SentinalID { - b.Sentinal = aBrd - b.Scourge = dBrd - } else { - b.Scourge = aBrd - b.Sentinal = dBrd - } return 1 } //Do actual battle math - attacker := aBrd[atk].Power - defender := dBrd[def].Power - if attacker > defender { - dBrd[def] = NewEmpty(def) - if id == SentinalID { - b.Sentinal = aBrd - b.Scourge = dBrd - } else { - b.Scourge = aBrd - b.Sentinal = dBrd - } - return 0 + atkpower := attacker.Power + defpower := defender.Power + log.Printf("Atk:%v v Def: %v", atkpower, defpower) + if atkpower > defpower { + return 2 } - if attacker == defender { - aBrd[atk] = NewEmpty(atk) - dBrd[def] = NewEmpty(def) - if id == 1 { - b.Sentinal = aBrd - b.Scourge = dBrd - } else { - b.Scourge = aBrd - b.Sentinal = dBrd - } - return 0 + if atkpower == defpower { + return 4 + } + if atkpower < defpower { + return 3 } return -1 } + +func (b *Board) ResetCards() { + for _, v := range b.Sentinal { + v.Power = v.BasePower + } + for _, v := range b.Scourge { + v.Power = v.BasePower + } +} diff --git a/internal/game/card.go b/internal/game/card.go index af5c3ea..f684b50 100644 --- a/internal/game/card.go +++ b/internal/game/card.go @@ -16,6 +16,7 @@ type Card struct { Owner int `json:"owner"` Position int `json:"position"` Spell bool `json:"spell"` + Effects []Effect `json:"effects"` } type CardType int @@ -56,6 +57,7 @@ func NewCard(v, o, p int, id uuid.UUID) *Card { Owner: o, Position: p, Spell: OracleSpell(CardType(v), nil), + Effects: []Effect{}, } } @@ -69,6 +71,8 @@ func NewEmpty(p int) *Card { Counters: 0, Owner: -1, Position: p, + Spell: false, + Effects: []Effect{}, } } @@ -77,5 +81,9 @@ func (c *Card) Empty() bool { } func (c *Card) String() string { - return fmt.Sprintf("|%v|", c.Type) + ready := " " + if c.Sick { + ready = "*" + } + return fmt.Sprintf("%v%v%v", c.Type, c.Power, ready) } diff --git a/internal/game/effect.go b/internal/game/effect.go new file mode 100644 index 0000000..23d8178 --- /dev/null +++ b/internal/game/effect.go @@ -0,0 +1,26 @@ +package game + +import "github.com/google/uuid" + +type Effect struct { + Owner uuid.UUID + Target uuid.UUID + ID int +} + +func RemoveEffect(source uuid.UUID, c *Card) { + for i, e := range c.Effects { + if e.Owner == source { + c.Effects = append(c.Effects[:i], c.Effects[i+1:]...) + } + } +} + +func AddEffect(c *Card, e Effect) { + for _, v := range c.Effects { + if v.Owner == e.Owner && v.ID == e.ID { + return + } + } + c.Effects = append(c.Effects, e) +} diff --git a/internal/game/game.go b/internal/game/game.go index fa4c918..c11c62b 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -125,6 +125,16 @@ func (g *Game) StateChanges() { g.Status = StatusSentinalWin } } + //reapply card effects + g.GameBoard.ResetCards() + for _, v := range g.GameBoard.Sentinal { + OracleTick(v, g) //apply effect stacks first + OracleEffect(v, g) //actually activate effects + } + for _, v := range g.GameBoard.Scourge { + OracleTick(v, g) + OracleEffect(v, 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 @@ -222,10 +232,12 @@ func (g *Game) PlayerAct(id int, cmd string) *Deck { switch cmd_s[0] { case "s": //scry: return scry options off top of deck - if !g.CanDraw || g.CardBuffer.Size() > 0 { + if !g.CanDraw { return nil } - g.CardBuffer = DeckFromCards(currD.Scry(curr.Life)) + if g.CardBuffer.Size() <= 0 { + g.CardBuffer = DeckFromCards(currD.Scry(curr.Life)) + } return g.CardBuffer case "d": //draw: return player hand @@ -236,6 +248,9 @@ func (g *Game) PlayerAct(id int, cmd string) *Deck { return nil } x_i, err := strconv.Atoi(cmd_s[1]) + if x_i > 2 || x_i < 0 { + return nil + } if err != nil { panic(err) } @@ -282,12 +297,34 @@ func (g *Game) PlayerAct(id int, cmd string) *Deck { 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) - if res == 1 { - opp.Life = opp.Life - 1 - return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) + var aid, did int + if id == SentinalID { + aid = SentinalID + did = ScourgeID } else { - return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) + 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{}) @@ -306,10 +343,10 @@ func (g *Game) PlayerAct(id int, cmd string) *Deck { card := curr.Hand[x_i] shouldPlace := true if g.GameBoard.CanPlay(g.CurrentTurn, card, y_i) { - shouldPlace = OracleCast(curr.Hand[x_i], g) + shouldPlace = OracleCast(card, g) placed := g.GameBoard.Play(g.CurrentTurn, card, y_i, shouldPlace) if placed { - OracleEnters(curr.Hand[x_i], g) + OracleEnters(card, g) } curr.Hand = append(curr.Hand[:x_i], curr.Hand[x_i+1:]...) return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) diff --git a/internal/game/oracle.go b/internal/game/oracle.go index 4cb7652..391f345 100644 --- a/internal/game/oracle.go +++ b/internal/game/oracle.go @@ -1,7 +1,5 @@ package game -import "log" - func OracleUpkeep(c *Card, g *Game) { switch c.Type { case Eight: @@ -39,78 +37,58 @@ func OracleEnters(c *Card, g *Game) { switch c.Type { case Ace: c.Sick = false + return + case Four: + AddEffect(c, Effect{c.Id, c.Id, 2}) + case Eight: + c.Counters = 0 + } +} + +func OracleTick(c *Card, g *Game) { + row := g.GameBoard.GetRow(c.Owner) + + switch c.Type { case Two: //+1 to all - if c.Owner == SentinalID { - for _, v := range g.GameBoard.Sentinal { - v.Power = v.Power + 1 + for _, v := range row { + if v.Id != c.Id { + v.Effects = append(v.Effects, Effect{c.Id, v.Id, 1}) + AddEffect(v, Effect{c.Id, v.Id, 1}) } - } else if c.Owner == ScourgeID { - for _, v := range g.GameBoard.Scourge { - v.Power = v.Power + 1 - } - } else { - log.Println("Trying to lookup an ETB when card not on field") } case Three: //+1 around it - if c.Owner == SentinalID { - if c.Position-1 >= 0 { - g.GameBoard.Sentinal[c.Position-1].Power = g.GameBoard.Sentinal[c.Position-1].Power + 1 - } - if c.Position+1 <= 3 { - g.GameBoard.Sentinal[c.Position+1].Power = g.GameBoard.Sentinal[c.Position+1].Power + 1 - } + if c.Position-1 >= 0 { + v := row[c.Position-1] + AddEffect(v, Effect{c.Id, v.Id, 1}) } - if c.Owner == ScourgeID { - if c.Position-1 >= 0 { - g.GameBoard.Scourge[c.Position-1].Power = g.GameBoard.Scourge[c.Position-1].Power + 1 - } - if c.Position+1 <= 3 { - g.GameBoard.Scourge[c.Position+1].Power = g.GameBoard.Scourge[c.Position+1].Power + 1 - } + if c.Position+1 <= 3 { + v := row[c.Position+1] + AddEffect(v, Effect{c.Id, v.Id, 1}) } } - return } func OracleLeaves(c *Card, g *Game) { + row := g.GameBoard.GetRow(c.Owner) switch c.Type { case Two: //remove +1 to all - if c.Owner == SentinalID { - for _, v := range g.GameBoard.Sentinal { - v.Power = v.Power - 1 - } - } else if c.Owner == ScourgeID { - for _, v := range g.GameBoard.Scourge { - v.Power = v.Power - 1 - } - } else { - log.Println("Trying to lookup an LTB when card not on field") + for _, v := range row { + RemoveEffect(c.Id, v) } case Three: //+1 around it - if c.Owner == SentinalID { - if c.Position-1 >= 0 { - g.GameBoard.Sentinal[c.Position-1].Power = g.GameBoard.Sentinal[c.Position-1].Power - 1 - } - if c.Position+1 <= 3 { - g.GameBoard.Sentinal[c.Position+1].Power = g.GameBoard.Sentinal[c.Position+1].Power - 1 - } - + if c.Position-1 >= 0 { + RemoveEffect(c.Id, row[c.Position-1]) } - if c.Owner == ScourgeID { - if c.Position-1 >= 0 { - g.GameBoard.Scourge[c.Position-1].Power = g.GameBoard.Scourge[c.Position-1].Power - 1 - } - if c.Position+1 <= 3 { - g.GameBoard.Scourge[c.Position+1].Power = g.GameBoard.Scourge[c.Position+1].Power - 1 - } - + if c.Position+1 <= 3 { + RemoveEffect(c.Id, row[c.Position+1]) } + } return } @@ -132,13 +110,33 @@ func OracleMove(c *Card, src, dest int, g *Game) { switch c.Type { case Three: row := g.GameBoard.GetRow(c.Owner) - row[src-1].Power = row[src-1].Power - 1 - row[src+1].Power = row[src+1].Power - 1 - row[dest-1].Power = row[dest-1].Power + 1 - row[dest+1].Power = row[dest+1].Power + 1 + if src-1 >= 0 { + RemoveEffect(c.Id, row[src-1]) + } + if src+1 <= 3 { + RemoveEffect(c.Id, row[src-1]) + } } } func OracleAttack(c *Card, g *Game) { c.Sick = true } + +func OracleEffect(c *Card, g *Game) { + for _, e := range c.Effects { + switch e.ID { + case 1: + c.Power = c.Power + 1 + case 2: + if c.Owner == SentinalID { + g.CardBuffer = DeckFromCards(g.SentinalDeck.Scry(1)) + } else { + g.CardBuffer = DeckFromCards(g.SentinalDeck.Scry(1)) + } + g.CanDraw = true + g.HasDrawn = false + RemoveEffect(e.Owner, c) + } + } +}