diff options
Diffstat (limited to 'go/game/action.go')
| -rw-r--r-- | go/game/action.go | 303 |
1 files changed, 192 insertions, 111 deletions
diff --git a/go/game/action.go b/go/game/action.go index 0f7a1294..4894d47d 100644 --- a/go/game/action.go +++ b/go/game/action.go @@ -4,40 +4,52 @@ import ( "fmt" ) -type ActionPrototype interface { - Specialize(*State, ...interface{}) Action - String() string -} +type ( + ActionCostFunc func(*State) bool + ActionResolveFunc func(*State) + ActionFuncPrototype func(Action) ActionResolveFunc +) type Action interface { - Resolve(s *State) + Source() interface{} + Targets() *Targets + + CheckTargets(*State) error PayCosts(s *State) bool + Resolve(s *State) String() string } -type PassPriority struct{ Source *Player } +type PassPriority struct{ source *Player } -func (*PassPriority) Resolve(*State) {} -func (*PassPriority) PayCosts(*State) bool { return true } -func (*PassPriority) String() string { return "pass" } -func NewPassPriority(p *Player) Action { return &PassPriority{p} } +func (a *PassPriority) Source() interface{} { return a.source } +func (*PassPriority) Targets() *Targets { return nil } +func (*PassPriority) CheckTargets(*State) error { return nil } +func (*PassPriority) PayCosts(*State) bool { return true } +func (*PassPriority) Resolve(*State) {} +func (*PassPriority) String() string { return "pass" } +func NewPassPriority(p *Player) Action { return &PassPriority{p} } -type HandCardSelection struct { - cards []*Card -} +type HandCardSelection struct{ cards []*Card } -func (*HandCardSelection) Resolve(*State) {} -func (*HandCardSelection) PayCosts(*State) bool { return true } -func (*HandCardSelection) String() string { return "hand card selection" } -func NewHandCardSelection(cards []*Card) Action { return &HandCardSelection{cards} } +func (*HandCardSelection) Source() interface{} { return nil } +func (*HandCardSelection) Targets() *Targets { return nil } +func (*HandCardSelection) CheckTargets(*State) error { return nil } +func (*HandCardSelection) PayCosts(*State) bool { return true } +func (*HandCardSelection) Resolve(*State) {} +func (*HandCardSelection) String() string { return "hand card selection" } +func NewHandCardSelection(cards []*Card) Action { return &HandCardSelection{cards} } type ActionBase struct { - Source interface{} + source interface{} Card *Card - Targets interface{} - resolveFunc func(s *State) - costFunc func(s *State) bool - desc string + targets *Targets + resolveFunc ActionResolveFunc + costFunc ActionCostFunc +} + +func (a *ActionBase) Source() interface{} { + return a.source } func (a *ActionBase) Resolve(s *State) { @@ -48,73 +60,91 @@ func (a *ActionBase) PayCosts(s *State) bool { return a.costFunc(s) } -func (a *ActionBase) String() string { - switch source := a.Source.(type) { - case Permanent: - p := source - return fmt.Sprintf("%s: %s %s", p.Controller().Name, p.Tile().Position.String(), a.desc) - case *Player: - return fmt.Sprintf("%s %s", source.Name, a.desc) - default: - return fmt.Sprintf("%v %s", source, a.desc) - } +func (a *ActionBase) Targets() *Targets { + return a.targets +} + +func (a *ActionBase) CheckTargets(s *State) error { + return a.targets.CheckTargets(s) } type PlayAction struct { ActionBase } -func NewPlayAction(p *Player, c *Card, targets interface{}) Action { - costFunc := func(*State) bool { - cost := c.PlayCosts() +const permanentPlayActionTarget = "available spawn tile" - if p.Resource < cost { - return false +func NewPlayAction(p *Player, c *Card, args ...interface{}) *PlayAction { + a := &PlayAction{ActionBase{ + source: p, + Card: c, + }} + + if len(args) > 0 { + if costFunc, ok := args[0].(ActionCostFunc); ok { + a.costFunc = costFunc } - p.Resource -= cost - return true } - return NewPlayActionWithSpecialCosts(p, c, targets, costFunc) -} -func NewPlayActionWithSpecialCosts(p *Player, c *Card, targets interface{}, - costFunc func(*State) bool, -) Action { + if a.costFunc == nil { + a.costFunc = func(*State) bool { + cost := c.PlayCosts() + + if p.Resource < cost { + return false + } + p.Resource -= cost + return true + } + } + + s := p.gameState + if c.IsPermanent() { + a.targets = newTargets(s, []string{permanentPlayActionTarget}, a) + } else { + a.targets = newTargets(s, []string{}, a) + } + p.Hand.RemoveCard(c) - resolveFunc := func(s *State) { - s.ResolvePlay(p, c, targets) + a.resolveFunc = func(s *State) { + s.resolvePlay(p, c, a.targets) } - desc := fmt.Sprintf("play %s@%v", c.Name, targets) - return &PlayAction{ActionBase{p, c, targets, resolveFunc, costFunc, desc}} + return a } -type MoveAction struct { - ActionBase -} +func (a *PlayAction) String() string { + p := a.source.(*Player) + if a.targets.RequireTargets() { + return fmt.Sprintf(" %s play %s", p.Name, a.Card.Name) + } -type MoveActionPrototype struct { - Unit *Unit + return fmt.Sprintf("%s play %s@%v", p.Name, a.Card.Name, a.targets) } -func NewMoveActionPrototype(u *Unit) *MoveActionPrototype { - return &MoveActionPrototype{u} +type MoveAction struct { + ActionBase } -func (proto *MoveActionPrototype) String() string { - return fmt.Sprintf("move %s", proto.Unit.Movement.String()) -} +const moveActionTargetDesc = "available tile" + +func NewMoveAction(u *Unit) *MoveAction { + a := &MoveAction{ + ActionBase{ + source: u, + Card: u.Card(), + }, + } -func (proto *MoveActionPrototype) Specialize(s *State, args ...interface{}) Action { - target := args[0].(*Tile) - u := proto.Unit + a.targets = newTargets(u.Controller().gameState, []string{moveActionTargetDesc}, a) - resolveFunc := func(s *State) { - u.move(s, target) + a.resolveFunc = func(s *State) { + tile := a.targets.sel[0].(*Tile) + u.move(s, tile) } - costFunc := func(*State) bool { + a.costFunc = func(*State) bool { if u.AvailMoveActions < 1 { return false } @@ -122,35 +152,38 @@ func (proto *MoveActionPrototype) Specialize(s *State, args ...interface{}) Acti return true } - desc := fmt.Sprintf("-> %s", target.Position.String()) - return &MoveAction{ActionBase{u, u.Card(), target, resolveFunc, costFunc, desc}} + return a } -type AttackAction struct { - ActionBase -} +func (a *MoveAction) String() string { + u := a.source.(*Unit) + if a.targets.RequireTargets() { + return fmt.Sprintf("move %s", u.Movement.String()) + } -type AttackActionPrototype struct { - Unit *Unit + t := a.targets.sel[0].(*Tile) + return fmt.Sprintf("%s: %s -> %s", u.Controller().Name, u.Card().Name, t.Position.String()) } -func NewAttackActionPrototype(u *Unit) *AttackActionPrototype { - return &AttackActionPrototype{u} +type AttackAction struct { + ActionBase } -func (proto *AttackActionPrototype) String() string { - return fmt.Sprintf("attack %s", proto.Unit.Attack.String()) -} +const attackActionTargetDesc = "attackable permanent" + +func NewAttackAction(u *Unit) *AttackAction { + a := &AttackAction{ActionBase{ + source: u, + Card: u.Card(), + }} -func (proto *AttackActionPrototype) Specialize(s *State, args ...interface{}) Action { - target := args[0].(Permanent) - u := proto.Unit + a.targets = newTargets(u.Controller().gameState, []string{attackActionTargetDesc}, a) - resolveFunc := func(s *State) { - s.Fight(u, target) + a.resolveFunc = func(s *State) { + s.Fight(u, a.targets.sel[0].(Permanent)) } - costFunc := func(*State) bool { + a.costFunc = func(*State) bool { if u.AvailAttackActions < 1 { return false } @@ -158,27 +191,41 @@ func (proto *AttackActionPrototype) Specialize(s *State, args ...interface{}) Ac return true } - desc := fmt.Sprintf("x %s", target.Tile().Position.String()) - return &AttackAction{ActionBase{u, u.Card(), target, resolveFunc, costFunc, desc}} + return a } -type FullActionPrototype struct { - Unit *Unit - resolveFuncPrototype func(*State, *Unit) func(*State) -} +func (a *AttackAction) String() string { + u := a.source.(*Unit) + if a.targets.RequireTargets() { + return fmt.Sprintf("attack %s", u.Attack.String()) + } -func NewFullActionPrototype(u *Unit, proto func(*State, *Unit) func(*State)) *FullActionPrototype { - return &FullActionPrototype{u, proto} + target := a.targets.sel[0].(Permanent) + return fmt.Sprintf("%s: %s x %s", + u.Controller().Name, u.Card().Name, target.Tile().Position.String()) } -func (proto *FullActionPrototype) String() string { - return "full_action" +type FullAction struct { + ActionBase + desc string } -func (proto *FullActionPrototype) Specialize(s *State, args ...interface{}) Action { - u := proto.Unit - resolveFunc := proto.resolveFuncPrototype(s, u) - costFunc := func(*State) bool { +func NewFullAction(u *Unit, proto ActionFuncPrototype, desc string) *FullAction { + a := &FullAction{ + ActionBase{ + source: u, + Card: u.Card(), + }, + + desc, + } + + a.resolveFunc = func(s *State) { + rf := proto(a) + rf(s) + } + + a.costFunc = func(*State) bool { if u.AvailAttackActions < 1 && u.AvailMoveActions < 1 { return false } @@ -186,28 +233,50 @@ func (proto *FullActionPrototype) Specialize(s *State, args ...interface{}) Acti u.AvailMoveActions-- return true } - desc := "full_action" - return &ActionBase{u, u.Card(), nil, resolveFunc, costFunc, desc} -} - -type FreeActionPrototype struct { - Permanent Permanent + return a } -func (proto *FreeActionPrototype) String() string { - return "free_action" -} +func (a *FullAction) String() string { + u := a.source.(*Unit) + if a.targets.RequireTargets() { + return fmt.Sprintf("↻ %s", a.desc) + } -func (proto *FreeActionPrototype) Specialize(s *State, args ...interface{}) Action { - p := proto.Permanent - resolveFunc := args[0].(func(s *State)) - costFunc := args[1].(func(s *State) bool) - desc := "free_action" - return &FreeAction{ActionBase{p, p.Card(), nil, resolveFunc, costFunc, desc}} + return fmt.Sprintf("%s: %s ↻@%s", u.Controller(), u.Card().Name, a.targets) } type FreeAction struct { ActionBase + desc string +} + +func NewFreeAction(p Permanent, resolveProto ActionFuncPrototype, costFunc ActionCostFunc, + desc string, +) *FreeAction { + a := &FreeAction{ + ActionBase{ + source: p, + Card: p.Card(), + costFunc: costFunc, + }, + desc, + } + + a.resolveFunc = func(s *State) { + rf := resolveProto(a) + rf(s) + } + + return a +} + +func (a *FreeAction) String() string { + p := a.source.(Permanent) + if a.targets.RequireTargets() { + return fmt.Sprintf("free_action %s", a.desc) + } + + return fmt.Sprintf("%s: %s free_action@%s", p.Controller(), p.Card().Name, a.targets) } type BuyAction struct { @@ -215,6 +284,18 @@ type BuyAction struct { card *Card } +func (a *BuyAction) Source() interface{} { + return a.player +} + +func (a *BuyAction) Targets() *Targets { + return newTargetsWithSel(a.player.gameState, []string{"store cards"}, a, []interface{}{a.card}) +} + +func (a *BuyAction) CheckTargets(s *State) error { + return s.isValidBuy(a) +} + func (a *BuyAction) Resolve(s *State) { a.player.Store.MoveCard(a.card, a.player.DiscardPile) } |
