aboutsummaryrefslogtreecommitdiff
path: root/go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2023-02-20 21:13:47 +0100
committerFlorian Fischer <florian.fischer@muhq.space>2025-01-27 16:43:51 +0100
commit74ae4f091755544906bb2bb38bd360cc4d7b6237 (patch)
tree01dc6ae303daaa671edbc2223091a5ffb64e6f1e /go
parent14f7b0274a20ffc8189d18de5031defcc15e9890 (diff)
downloadmuhqs-game-74ae4f091755544906bb2bb38bd360cc4d7b6237.tar.gz
muhqs-game-74ae4f091755544906bb2bb38bd360cc4d7b6237.zip
implement equip action
Diffstat (limited to 'go')
-rw-r--r--go/TODO1
-rw-r--r--go/client/game.go53
-rw-r--r--go/game/action.go63
-rw-r--r--go/game/cardImplementations.go16
-rw-r--r--go/game/unit.go27
5 files changed, 142 insertions, 18 deletions
diff --git a/go/TODO b/go/TODO
index 201cc37c..a868da71 100644
--- a/go/TODO
+++ b/go/TODO
@@ -4,7 +4,6 @@
* implement artifcat action
* move
* implement equipment actions
- * equip
* drop
* implement target disjunction
* implement Pile UI hint
diff --git a/go/client/game.go b/go/client/game.go
index 5ae2fbe8..f4e0f817 100644
--- a/go/client/game.go
+++ b/go/client/game.go
@@ -10,6 +10,7 @@ import (
"muhq.space/muhqs-game/go/game"
"muhq.space/muhqs-game/go/ui"
+ "muhq.space/muhqs-game/go/utils"
)
const (
@@ -214,14 +215,48 @@ func (g *Game) addPermActionChoice(perm game.Permanent, x, y int) {
p := perms[c.GetChoosen(x, y)]
g.addActionChoice(p, x, y)
}
- g.choice = ui.NewPermChoice(x, y, perms, onClick)
- g.AddWidget(g.choice)
+ g.addChoice(ui.NewPermChoice(x, y, perms, onClick))
} else {
g.selectedObject = perms[0]
g.addActionChoice(perms[0], x, y)
}
}
+func (g *Game) declareOrPromptTargets(a game.Action) {
+ if a.Targets() != nil && a.Targets().RequireSelection() {
+ g.addPrompt(a, fmt.Sprintf("Select targets for %v", a))
+ } else {
+ g.declareAction(a)
+ }
+}
+
+func (g *Game) addActionCostChoice(a game.Action, x, y int) {
+ u := a.Source().(*game.Unit)
+ if u.AvailMoveActions > 0 && u.AvailAttackActions == 0 {
+ game.UseMoveAction(a)
+ } else if u.AvailAttackActions > 0 && u.AvailMoveActions == 0 {
+ game.UseAttackAction(a)
+ }
+
+ if !a.NeedsActionCostChoice() {
+ g.declareOrPromptTargets(a)
+ return
+ }
+
+ choices := []string{"move", "attack"}
+ onClick := func(c *ui.Choice, x, y int) {
+ g.removeChoice()
+ switch choices[c.GetChoosen(x, y)] {
+ case "move":
+ game.UseMoveAction(a)
+ case "attack":
+ game.UseAttackAction(a)
+ }
+ g.declareOrPromptTargets(a)
+ }
+ g.addChoice(ui.NewChoice(x, y, utils.TypedSliceToInterfaceSlice(choices), onClick))
+}
+
func (g *Game) addActionChoice(perm game.Permanent, x, y int) {
actions := perm.CurrentlyAvailActions()
if len(actions) > 0 {
@@ -229,17 +264,21 @@ func (g *Game) addActionChoice(perm game.Permanent, x, y int) {
onClick := func(c *ui.Choice, x, y int) {
g.removeChoice()
a := actions[c.GetChoosen(x, y)]
- if a.Targets() != nil && a.Targets().RequireSelection() {
- g.addPrompt(a, fmt.Sprintf("Select targets for %v", a))
+ if a.NeedsActionCostChoice() {
+ g.addActionCostChoice(a, x, y)
} else {
- g.declareAction(a)
+ g.declareOrPromptTargets(a)
}
}
- g.choice = ui.NewActionChoice(x, y, actions, onClick)
- g.AddWidget(g.choice)
+ g.addChoice(ui.NewActionChoice(x, y, actions, onClick))
}
}
+func (g *Game) addChoice(choice *ui.Choice) {
+ g.choice = choice
+ g.AddWidget(choice)
+}
+
func (g *Game) removeChoice() {
g.RemoveWidget(g.choice)
g.choice = nil
diff --git a/go/game/action.go b/go/game/action.go
index f00c21cd..b8bc8d6e 100644
--- a/go/game/action.go
+++ b/go/game/action.go
@@ -15,6 +15,7 @@ type Action interface {
Targets() *Targets
Target() *Target // Shortcut for to select the first target
+ NeedsActionCostChoice() bool
CheckTargets(*State) error
PayCosts(s *State) bool
resolve(s *State)
@@ -23,14 +24,15 @@ type Action interface {
type PassPriority struct{ player *Player }
-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} }
+func (a *PassPriority) Source() interface{} { return a.player }
+func (*PassPriority) Targets() *Targets { return nil }
+func (*PassPriority) Target() *Target { return nil }
+func (*PassPriority) NeedsActionCostChoice() bool { return false }
+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 TargetSelection struct {
player *Player
@@ -40,6 +42,7 @@ type TargetSelection struct {
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 (*TargetSelection) NeedsActionCostChoice() bool { return false }
func (sel *TargetSelection) CheckTargets(s *State) error { return sel.targets.CheckTargets(s) }
func (*TargetSelection) PayCosts(*State) bool { return true }
func (*TargetSelection) resolve(*State) {}
@@ -206,6 +209,32 @@ func genFullActionCost(u *Unit) ActionCostFunc {
}
}
+type EquipAction struct {
+ ActionBase
+ equipment *Equipment
+}
+
+func NewEquipAction(u *Unit, e *Equipment) *EquipAction {
+ a := &EquipAction{
+ ActionBase{
+ source: u,
+ Card: u.Card(),
+ },
+ e,
+ }
+
+ a.resolveFunc = func(s *State) {
+ u.equip(e)
+ }
+
+ return a
+}
+
+func (a *EquipAction) String() string {
+ u := a.source.(*Unit)
+ return fmt.Sprintf("%s equip %v", u.FmtWController(), a.equipment)
+}
+
type AttackAction struct {
ActionBase
}
@@ -428,3 +457,21 @@ func newUpkeepAction(p *Player) *UpkeepAction {
return a
}
+
+func (a *ActionBase) NeedsActionCostChoice() bool {
+ return a.costFunc == nil
+}
+
+func UseMoveAction(a Action) {
+ switch a := a.(type) {
+ case *EquipAction:
+ a.costFunc = genMoveActionCost(a.Source().(*Unit))
+ }
+}
+
+func UseAttackAction(a Action) {
+ switch a := a.(type) {
+ case *EquipAction:
+ a.costFunc = genAttackActionCost(a.Source().(*Unit))
+ }
+}
diff --git a/go/game/cardImplementations.go b/go/game/cardImplementations.go
index 7055fe03..67b52315 100644
--- a/go/game/cardImplementations.go
+++ b/go/game/cardImplementations.go
@@ -5,8 +5,20 @@ import (
)
func adjustMelee(p Permanent, damage int) {
- if u, ok := p.(*Unit); ok && !INVALID_ATTACK(u.Attack) {
- u.Attack.attacks[0] += damage
+ log.Println("adjusting melee")
+ u, ok := p.(*Unit)
+ if !ok {
+ return
+ }
+
+ if INVALID_ATTACK(u.Attack) {
+ u.Attack.attacks = append(u.Attack.attacks, 1)
+ } else {
+ if u.Attack.attacks[0]+damage == 0 {
+ u.Attack.attacks = nil
+ } else {
+ u.Attack.attacks[0] += damage
+ }
}
}
diff --git a/go/game/unit.go b/go/game/unit.go
index 5b071d7b..99c7c28d 100644
--- a/go/game/unit.go
+++ b/go/game/unit.go
@@ -200,6 +200,24 @@ func (u *Unit) AvailSlowActions() (actions []Action) {
}
}
+ if u.AvailAttackActions > 0 || u.AvailMoveActions > 0 {
+ for _, tile := range TilesInRange(m, u, 1) {
+ if tile.Permanent == nil {
+ continue
+ }
+
+ if equipment, ok := tile.Permanent.(*Equipment); ok {
+ actions = append(actions, NewEquipAction(u, equipment))
+ }
+
+ for _, perm := range tile.Permanent.Pile() {
+ if equipment, ok := perm.(*Equipment); ok {
+ actions = append(actions, NewEquipAction(u, equipment))
+ }
+ }
+ }
+ }
+
return actions
}
@@ -278,3 +296,12 @@ func (u *Unit) addDamage(damage int) {
u.permanentBase.addDamage(damage)
}
+
+func (u *Unit) equip(e *Equipment) {
+ if e.containingPerm != nil {
+ removePermanentFromPile(e.containingPerm, e)
+ } else {
+ leaveTile(e)
+ }
+ addPermanentToPile(u, e)
+}