From 45df9bf319d38db916ca983b8c92bb912f5ce9ee Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Wed, 8 Feb 2023 17:50:10 +0100 Subject: intermediate commit --- go/game/action.go | 194 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 109 insertions(+), 85 deletions(-) (limited to 'go/game/action.go') diff --git a/go/game/action.go b/go/game/action.go index 5002f58a..77e9743f 100644 --- a/go/game/action.go +++ b/go/game/action.go @@ -13,6 +13,7 @@ type ( type Action interface { Source() interface{} Targets() *Targets + Target() *Target // Shortcut for to select the first target CheckTargets(*State) error PayCosts(s *State) bool @@ -20,35 +21,40 @@ type Action interface { String() string } -type PassPriority struct{ source *Player } +type PassPriority struct{ player *Player } -func (a *PassPriority) Source() interface{} { return a.source } +func (a *PassPriority) Source() interface{} { return a.player } func (*PassPriority) Targets() *Targets { return nil } +func (*PassPriority) Target() *Target { 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 } - -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 TargetSelection struct{ targets *Targets } +type TargetSelection struct { + player *Player + targets *Targets +} -func (*TargetSelection) Source() interface{} { return nil } +func (sel *TargetSelection) Source() interface{} { return sel.player } func (sel *TargetSelection) Targets() *Targets { return sel.targets } +func (sel *TargetSelection) Target() *Target { return sel.targets.ts[0] } func (sel *TargetSelection) CheckTargets(s *State) error { return sel.targets.CheckTargets(s) } func (*TargetSelection) PayCosts(*State) bool { return true } func (*TargetSelection) Resolve(*State) {} func (*TargetSelection) String() string { return "target selection" } -func NewTargetSelection(targets *Targets) Action { return &TargetSelection{targets} } + +func newTargetSelection(player *Player, targets *Targets) Action { + return &TargetSelection{player, targets} +} + +func newHandCardSelection(p *Player, min, max int) Action { + a := &TargetSelection{player: p} + targetDesc := TargetDesc{"hand card", fmt.Sprintf("%d-%d", min, max)} + a.targets = newTargets(newTarget(p.gameState, targetDesc, a)) + return a +} type ActionBase struct { source interface{} @@ -58,23 +64,15 @@ type ActionBase struct { costFunc ActionCostFunc } -func (a *ActionBase) Source() interface{} { - return a.source -} - -func (a *ActionBase) Resolve(s *State) { - a.resolveFunc(s) -} - -func (a *ActionBase) PayCosts(s *State) bool { - return a.costFunc(s) -} - -func (a *ActionBase) Targets() *Targets { - return a.targets -} - +func (a *ActionBase) Source() interface{} { return a.source } +func (a *ActionBase) Resolve(s *State) { a.resolveFunc(s) } +func (a *ActionBase) PayCosts(s *State) bool { return a.costFunc(s) } +func (a *ActionBase) Targets() *Targets { return a.targets } +func (a *ActionBase) Target() *Target { return a.targets.ts[0] } func (a *ActionBase) CheckTargets(s *State) error { + if a.targets == nil { + return nil + } return a.targets.CheckTargets(s) } @@ -82,7 +80,7 @@ type PlayAction struct { ActionBase } -const permanentPlayActionTarget = "available spawn tile" +var permanentPlayActionTarget = TargetDesc{"available spawn tile", "1"} func NewPlayAction(p *Player, c *Card, args ...interface{}) *PlayAction { a := &PlayAction{ActionBase{ @@ -110,9 +108,11 @@ func NewPlayAction(p *Player, c *Card, args ...interface{}) *PlayAction { s := p.gameState if c.IsPermanent() { - a.targets = newTargets(s, []string{permanentPlayActionTarget}, a) + a.targets = newTargets(newTarget(s, permanentPlayActionTarget, a)) } else { - a.targets = newTargets(s, []string{}, a) + // TODO: implement parsing targets to play a card + // a.targets = newTargets(s, c.Impl.playTargets(s, p), a) + a.targets = newTargets() } a.resolveFunc = func(s *State) { @@ -124,7 +124,7 @@ func NewPlayAction(p *Player, c *Card, args ...interface{}) *PlayAction { func (a *PlayAction) String() string { p := a.source.(*Player) - if a.targets.RequireTargets() { + if a.targets.RequireSelection() { return fmt.Sprintf(" %s play %s", p.Name, a.Card.Name) } @@ -135,14 +135,15 @@ type MoveAction struct { ActionBase } -const moveActionTargetDesc = "available tile" +var moveActionTargetDesc = TargetDesc{"available tile", "1"} func (a *MoveAction) targetTile() *Tile { - if t, ok := a.targets.sel[0].(*Tile); ok { - return t + t := a.Target() + if tile, ok := t.sel[0].(*Tile); ok { + return tile } - return a.targets.sel[0].(*Unit).Tile() + return t.sel[0].(*Unit).Tile() } func NewMoveAction(u *Unit) *MoveAction { @@ -153,7 +154,7 @@ func NewMoveAction(u *Unit) *MoveAction { }, } - a.targets = newTargets(u.Controller().gameState, []string{moveActionTargetDesc}, a) + a.targets = newTargets(newTarget(u.Controller().gameState, moveActionTargetDesc, a)) a.resolveFunc = func(s *State) { tile := a.targetTile() @@ -173,19 +174,19 @@ func NewMoveAction(u *Unit) *MoveAction { func (a *MoveAction) String() string { u := a.source.(*Unit) - if a.targets.RequireTargets() { + if a.targets.RequireSelection() { return fmt.Sprintf("move %s", u.Movement.String()) } t := a.targetTile() - return fmt.Sprintf("%v: %v -> %v", u.Controller().Name, u.Card().Name, t.Position) + return fmt.Sprintf("%s -> %v", u.FmtWController(), t.Position) } type AttackAction struct { ActionBase } -const attackActionTargetDesc = "attackable enemy permanent" +var attackActionTargetDesc = TargetDesc{"attackable enemy permanent", "1"} func NewAttackAction(u *Unit) *AttackAction { a := &AttackAction{ActionBase{ @@ -193,10 +194,10 @@ func NewAttackAction(u *Unit) *AttackAction { Card: u.Card(), }} - a.targets = newTargets(u.Controller().gameState, []string{attackActionTargetDesc}, a) + a.targets = newTargets(newTarget(u.Controller().gameState, attackActionTargetDesc, a)) a.resolveFunc = func(s *State) { - s.Fight(u, a.targets.sel[0].(Permanent)) + s.Fight(u, a.Target().sel[0].(Permanent)) } a.costFunc = func(*State) bool { @@ -212,13 +213,12 @@ func NewAttackAction(u *Unit) *AttackAction { func (a *AttackAction) String() string { u := a.source.(*Unit) - if a.targets.RequireTargets() { + if a.targets.RequireSelection() { return fmt.Sprintf("attack %v", u.Attack) } - target := a.targets.sel[0].(Permanent) - return fmt.Sprintf("%v: %v x %v", - u.Controller().Name, u.Card().Name, target.Tile().Position) + target := a.Target().sel[0].(Permanent) + return fmt.Sprintf("%s x %v", u.FmtWController(), target.Tile().Position) } type FullAction struct { @@ -255,11 +255,11 @@ func NewFullAction(u *Unit, proto ActionFuncPrototype, desc string) *FullAction func (a *FullAction) String() string { u := a.source.(*Unit) - if a.targets.RequireTargets() { + if a.targets == nil || a.targets.RequireSelection() { return fmt.Sprintf("↻ %s", a.desc) } - return fmt.Sprintf("%s: %s ↻@%v", u.Controller().Name, u.Card().Name, a.targets) + return fmt.Sprintf("%s ↻@%v", u.FmtWController(), a.targets) } type FreeAction struct { @@ -289,80 +289,104 @@ func NewFreeAction(p Permanent, resolveProto ActionFuncPrototype, costFunc Actio func (a *FreeAction) String() string { p := a.source.(Permanent) - if a.targets.RequireTargets() { + if a.targets.RequireSelection() { return fmt.Sprintf("free_action %s", a.desc) } return fmt.Sprintf("%v: %s free_action@%v", p.Controller(), p.Card().Name, a.targets) } -type BuyAction struct { - player *Player - card *Card -} +var buyActionTargetDesc = TargetDesc{"store card", "?"} -func (a *BuyAction) Source() interface{} { - return a.player -} +type BuyAction struct{ TargetSelection } -func (a *BuyAction) Targets() *Targets { - return newTargetsWithSel(a.player.gameState, []string{"store cards"}, a, []interface{}{a.card}) +func (a *BuyAction) card() *Card { + return a.Target().sel[0].(*Card) } func (a *BuyAction) CheckTargets(s *State) error { + err := a.targets.CheckTargets(s) + if err != nil { + return err + } return s.isValidBuy(a) } func (a *BuyAction) Resolve(s *State) { - a.player.Store.MoveCard(a.card, a.player.DiscardPile) + a.player.Store.MoveCard(a.card(), a.player.DiscardPile) } func (a *BuyAction) PayCosts(*State) bool { - if a.card.BuyCost < 0 || a.card.BuyCost > a.player.Resource { + cost := a.card().BuyCost + if cost < 0 || cost > a.player.Resource { return false } - a.player.Resource -= a.card.BuyCost + a.player.Resource -= cost return true } -func (a *BuyAction) String() string { return fmt.Sprintf("%s buy %s", a.player.Name, a.card.Name) } +func (a *BuyAction) String() string { + if !a.Targets().HasSelections() { + return fmt.Sprintf("%s buy", a.player.Name) + } -func NewBuyAction(p *Player, c *Card) *BuyAction { - return &BuyAction{p, c} + return fmt.Sprintf("%s buy %s", a.player.Name, a.card().Name) } -type UpkeepAction struct { - player *Player - unit *Unit - pay bool +func newBuyAction(p *Player) *BuyAction { + a := &BuyAction{TargetSelection{player: p}} + a.targets = newTargets(newTarget(p.gameState, buyActionTargetDesc, a)) + return a } -func (a *UpkeepAction) Resolve(s *State) { - if a.pay { - a.player.Resource -= a.unit.Upkeep - } else { - s.DestroyPermanent(a.unit) - } +var upkeepActionTargetDesc = TargetDesc{"unit you controll", "*"} + +type UpkeepAction struct { + TargetSelection } func (a *UpkeepAction) PayCosts(*State) bool { - if a.unit.Upkeep > a.player.Resource { + costs := 0 + for _, t := range a.Target().sel { + u := t.(*Unit) + costs += u.UpkeepCost() + } + + if a.player.Resource < costs { return false } - a.player.Resource -= a.unit.Upkeep + a.player.Resource -= costs return true } -func (a *UpkeepAction) String() string { - if a.pay { - return fmt.Sprintf("%s keep %v", a.player.Name, a.unit.Tile().Position) +func (a *UpkeepAction) Resolve(*State) { + p := a.player + s := p.gameState + for _, i := range a.Target().sel { + u := i.(*Unit) + s.DestroyPermanent(u) } - return fmt.Sprintf("%s disband %v", a.player.Name, a.unit.Tile().Position) + // Keep and pay for the rest + for _, u := range s.Units { + if u.Controller() != p { + continue + } + + p.Resource -= u.upkeep + u.onUpkeep() + } } -func NewUpkeepAction(p *Player, u *Unit, pay bool) *UpkeepAction { - return &UpkeepAction{p, u, pay} +func (a *UpkeepAction) String() string { + return fmt.Sprintf("upkeep disbanding: %v", a.Target().sel) +} + +func newUpkeepAction(p *Player) *UpkeepAction { + a := &UpkeepAction{TargetSelection{player: p}} + a.targets = newTargets(newTarget(p.gameState, upkeepActionTargetDesc, a)) + + return a } -- cgit v1.2.3