summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rw-r--r--engine/action.go62
-rw-r--r--engine/card.go (renamed from engine/card/card.go)2
-rw-r--r--engine/card/attack.go26
-rw-r--r--engine/card/damage.go4
-rw-r--r--engine/card/predicate/predicate.go18
-rw-r--r--engine/card/reaction.go7
-rw-r--r--engine/character.go11
-rw-r--r--engine/character/character.go15
-rw-r--r--engine/game.go47
-rw-r--r--engine/game/game.go33
-rw-r--r--engine/interaction.go3
-rw-r--r--engine/play/play.go52
-rw-r--r--engine/player.go42
-rw-r--r--engine/player/action.go12
-rw-r--r--engine/player/player.go34
-rw-r--r--engine/stack.go22
-rw-r--r--engine/vigour.go (renamed from engine/player/vigour.go)2
17 files changed, 293 insertions, 99 deletions
diff --git a/engine/action.go b/engine/action.go
new file mode 100644
index 0000000..2a73982
--- /dev/null
+++ b/engine/action.go
@@ -0,0 +1,62 @@
+package engine
+
+type BaseAction struct {
+ User *Player
+ BaseSource IsCard
+}
+
+func (b *BaseAction) Actor() *Player {
+ return b.User
+}
+
+func (b *BaseAction) Source() IsCard {
+ return b.BaseSource
+}
+
+func (b *BaseAction) Then(g *Game) {
+}
+
+type Action interface {
+ Actor() *Player
+ Source() IsCard
+ Then(g *Game)
+}
+
+func Interactions(a ...Action) map[InteractionID]Action {
+ m := make(map[InteractionID]Action, len(a))
+ for i, ac := range a {
+ m[InteractionID(i)] = ac
+ }
+ return m
+}
+
+type DamageDecision bool
+
+var (
+ Aura DamageDecision = true
+ Life DamageDecision = false
+)
+
+type DesignateDamage struct {
+ Attacker *Player
+ Defender *Player
+ SourceCard *Card
+}
+
+func (d *DesignateDamage) Actor() *Player {
+ return d.Defender
+}
+func (d *DesignateDamage) Instigator() *Player {
+ return d.Attacker
+}
+
+func (d *DesignateDamage) Then(g *Game) {
+}
+
+func (d *DesignateDamage) Source() IsCard {
+ return d.SourceCard
+}
+
+type PlayCard struct {
+ *BaseAction
+}
diff --git a/engine/card/card.go b/engine/card.go
index f2dce83..52d5a6e 100644
--- a/engine/card/card.go
+++ b/engine/card.go
@@ -1,4 +1,4 @@
-package card
+package engine
type Card struct {
Name string
diff --git a/engine/card/attack.go b/engine/card/attack.go
index 19ad196..d05d44a 100644
--- a/engine/card/attack.go
+++ b/engine/card/attack.go
@@ -1,11 +1,31 @@
package card
+import (
+ "sakura/engine"
+ "sakura/engine/pool"
+)
+
type Attack struct {
- *Card
+ *engine.Card
MinDistance RangeValue
MaxDistance RangeValue
- AuraDamage DamageValue
- HealthDamage DamageValue
+ AuraDamage DamageValue
+ LifeDamage DamageValue
+
+ Unreactable bool
+}
+
+func (a *Attack) Attack() *Attack {
+ return a
+}
+
+func (a *Attack) Do(g *engine.Game, to *pool.Pool) {
+}
+
+type IsAttack interface {
+ Attack() *Attack
+ Prepare(g *engine.Game)
+ Do(g *engine.Game, to *pool.Pool)
}
diff --git a/engine/card/damage.go b/engine/card/damage.go
index fccb073..6d7dafd 100644
--- a/engine/card/damage.go
+++ b/engine/card/damage.go
@@ -3,3 +3,7 @@ package card
type DamageValue int
const Unselectable = DamageValue(-1)
+
+func (d DamageValue) Value() int {
+ return int(d)
+}
diff --git a/engine/card/predicate/predicate.go b/engine/card/predicate/predicate.go
new file mode 100644
index 0000000..5770c3d
--- /dev/null
+++ b/engine/card/predicate/predicate.go
@@ -0,0 +1,18 @@
+package predicate
+
+import (
+ "sakura/engine"
+ "sakura/engine/card"
+)
+
+func Reaction(c engine.IsCard) bool {
+ _, ok := c.(card.IsReaction)
+ return ok
+}
+
+func ReactionApplicable(c engine.IsCard) bool {
+ r, isReaction := c.(card.IsReaction)
+ if isReaction {
+ return r.Applicable(c)
+ }
+}
diff --git a/engine/card/reaction.go b/engine/card/reaction.go
new file mode 100644
index 0000000..3eed8c4
--- /dev/null
+++ b/engine/card/reaction.go
@@ -0,0 +1,7 @@
+package card
+
+import "sakura/engine"
+
+type IsReaction interface {
+ Applicable(c engine.IsCard) bool
+}
diff --git a/engine/character.go b/engine/character.go
new file mode 100644
index 0000000..a526501
--- /dev/null
+++ b/engine/character.go
@@ -0,0 +1,11 @@
+package engine
+
+type Character struct {
+ Name string
+ Cards []IsCard
+ Ultimates []IsCard
+}
+
+func (c *Character) String() string {
+ return c.Name
+}
diff --git a/engine/character/character.go b/engine/character/character.go
deleted file mode 100644
index 66671ae..0000000
--- a/engine/character/character.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package character
-
-import (
- "sakura/engine/card"
-)
-
-type Character struct {
- Name string
- Cards []card.IsCard
- Ultimates []card.IsCard
-}
-
-func (c *Character) String() string {
- return c.Name
-}
diff --git a/engine/game.go b/engine/game.go
new file mode 100644
index 0000000..0ed93e2
--- /dev/null
+++ b/engine/game.go
@@ -0,0 +1,47 @@
+package engine
+
+import (
+ "sakura/engine/pool"
+)
+
+type Game struct {
+ Shadow *pool.Pool
+ Distance *pool.Pool
+ Yin *Player
+ Yang *Player
+
+ Stack []IsCard
+
+ Actions map[InteractionID]Action
+}
+
+func (g *Game) propagate() {
+ g.Distance.OverflowsTo = g.Shadow
+}
+
+func NewGame() *Game {
+ g := &Game{
+ Shadow: pool.New(0, pool.Infinite),
+ Distance: pool.New(0, 10),
+ Actions: nil,
+ }
+ g.Yin = NewPlayer(g)
+ g.Yang = NewPlayer(g)
+ g.propagate()
+ return g
+}
+
+var Tie = &Player{}
+
+func (g *Game) Winner() *Player {
+ if g.Yin.Life.Value <= 0 && g.Yang.Life.Value <= 0 {
+ return Tie
+ }
+ if g.Yin.Life.Value <= 0 {
+ return g.Yang
+ }
+ if g.Yang.Life.Value <= 0 {
+ return g.Yin
+ }
+ return nil
+}
diff --git a/engine/game/game.go b/engine/game/game.go
deleted file mode 100644
index 7f3fa76..0000000
--- a/engine/game/game.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package game
-
-import (
- "sakura/engine/player"
- "sakura/engine/pool"
-)
-
-type Game struct {
- Shadow *pool.Pool
- Distance *pool.Pool
- Yin *player.Player
- Yang *player.Player
-
- Must []player.PlayerAction
- May []player.PlayerAction
-}
-
-func (g *Game) propagate() {
- g.Distance.OverflowsTo = g.Shadow
-}
-
-func New() *Game {
- g := &Game{
- Shadow: pool.New(0, pool.Infinite),
- Distance: pool.New(0, 10),
- Must: nil,
- May: nil,
- }
- g.Yin = player.New(g)
- g.Yang = player.New(g)
- g.propagate()
- return g
-}
diff --git a/engine/interaction.go b/engine/interaction.go
new file mode 100644
index 0000000..0c01401
--- /dev/null
+++ b/engine/interaction.go
@@ -0,0 +1,3 @@
+package engine
+
+type InteractionID int
diff --git a/engine/play/play.go b/engine/play/play.go
new file mode 100644
index 0000000..42d9fa3
--- /dev/null
+++ b/engine/play/play.go
@@ -0,0 +1,52 @@
+package play
+
+import (
+ "sakura/engine"
+ "sakura/engine/card"
+ "sakura/engine/card/predicate"
+)
+
+func Card(g *engine.Game, p *engine.Player, anyCard engine.IsCard) {
+ switch c := anyCard.(type) {
+ case card.IsAttack:
+ Attack(g, p, c)
+ }
+ g.Stack = append(g.Stack, anyCard)
+}
+
+func Attack(g *engine.Game, p *engine.Player, a card.IsAttack) {
+ att := a.Attack()
+ opp := p.Opponent(g)
+ if !att.Unreactable && opp.Hand.Contains(predicate.ReactionApplicable) {
+ reactions := opp.Hand.Filter(predicate.ReactionApplicable)
+ acs := make([]engine.Action, len(reactions), len(reactions))
+ for i, r := range reactions {
+ acs[i] = &engine.PlayCard{
+ BaseAction: &engine.BaseAction{
+ User: p,
+ BaseSource: r,
+ },
+ }
+ }
+ g.May = engine.Interactions(acs...)
+ }
+ switch {
+ case att.AuraDamage == card.Unselectable:
+ opp.Life.Subtract(att.LifeDamage.Value())
+ case att.LifeDamage == card.Unselectable:
+ opp.Aura.Subtract(att.AuraDamage.Value())
+ case att.AuraDamage.Value() > opp.Aura.Value:
+ opp.Life.Subtract(att.LifeDamage.Value())
+ default:
+ g.Actions = engine.Interactions(&engine.DesignateDamage{
+ Attacker: p,
+ Defender: opp,
+ SourceCard: a.Attack().Card,
+ })
+ }
+}
+
+func Vigor(g *engine.Game, p *engine.Player, a engine.VigorAction) {
+ a.From(p).Subtract(1)
+ a.To(p).Add(1)
+}
diff --git a/engine/player.go b/engine/player.go
new file mode 100644
index 0000000..5f1d7ca
--- /dev/null
+++ b/engine/player.go
@@ -0,0 +1,42 @@
+package engine
+
+import (
+ "sakura/engine/pool"
+)
+
+type Player struct {
+ Game *Game `json:"-"`
+ Vigour Vigour
+ Life *pool.Pool
+ Aura *pool.Pool
+ Flare *pool.Pool
+ Hand Stack
+ MasterDeck Stack
+ Ultimates []*Card
+}
+
+func (p *Player) Opponent(g *Game) *Player {
+ if p == g.Yin {
+ return g.Yang
+ } else {
+ return g.Yin
+ }
+}
+
+func (p *Player) propagate(g *Game) {
+ p.Game = g
+ p.Aura.SubtractsTo = g.Shadow
+ p.Flare.SubtractsTo = g.Shadow
+ p.Life.SubtractsTo = p.Flare
+}
+
+func NewPlayer(g *Game) *Player {
+ p := &Player{
+ Life: pool.New(pool.Empty, 10),
+ Aura: pool.New(3, 5),
+ Flare: pool.New(pool.Empty, pool.Infinite),
+ Vigour: Vigour(0),
+ }
+ p.propagate(g)
+ return p
+}
diff --git a/engine/player/action.go b/engine/player/action.go
deleted file mode 100644
index 0d8aa58..0000000
--- a/engine/player/action.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package player
-
-type Action int
-
-const (
- _ = iota
-)
-
-type PlayerAction struct {
- Player *Player
- Action Action
-}
diff --git a/engine/player/player.go b/engine/player/player.go
deleted file mode 100644
index 9dece55..0000000
--- a/engine/player/player.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package player
-
-import (
- "sakura/engine/card"
- "sakura/engine/game"
- "sakura/engine/pool"
-)
-
-type Player struct {
- Game *game.Game
- Vigour *Vigour
- Life *pool.Pool
- Aura *pool.Pool
- Flare *pool.Pool
- MasterDeck []*card.Card
- Ultimates []*card.Card
-}
-
-func (p *Player) propagate(g *game.Game) {
- p.Game = g
- p.Aura.SubtractsTo = g.Shadow
- p.Flare.SubtractsTo = g.Shadow
- p.Life.SubtractsTo = p.Flare
-}
-
-func New(g *game.Game) *Player {
- p := &Player{
- Life: pool.New(pool.Empty, 10),
- Aura: pool.New(3, 5),
- Flare: pool.New(pool.Empty, pool.Infinite),
- }
- p.propagate(g)
- return p
-}
diff --git a/engine/stack.go b/engine/stack.go
new file mode 100644
index 0000000..d7fc7be
--- /dev/null
+++ b/engine/stack.go
@@ -0,0 +1,22 @@
+package engine
+
+type Stack []*Card
+
+func (s Stack) Contains(predicate func(c IsCard) bool) bool {
+ for _, c := range s {
+ if predicate(c) {
+ return true
+ }
+ }
+ return false
+}
+
+func (s Stack) Filter(predicate func(c IsCard) bool) Stack {
+ res := make(Stack, 0, len(s))
+ for _, c := range s {
+ if predicate(c) {
+ res = append(res, c)
+ }
+ }
+ return res
+}
diff --git a/engine/player/vigour.go b/engine/vigour.go
index 1d4022e..62ececd 100644
--- a/engine/player/vigour.go
+++ b/engine/vigour.go
@@ -1,4 +1,4 @@
-package player
+package engine
import (
"sakura/engine/pool"