aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2025-09-05 18:28:47 +0200
committerFlorian Fischer <florian.fischer@muhq.space>2025-09-05 18:28:47 +0200
commit034e176110cc0a27cd20bdfe8522fd0dc73d2346 (patch)
treee0198741c94fb3af7777056c031e74100f4f9bb5
parent611c8cd048ca216c16da6744ce2052d9dc000c83 (diff)
downloadmuhqs-game-034e176110cc0a27cd20bdfe8522fd0dc73d2346.tar.gz
muhqs-game-034e176110cc0a27cd20bdfe8522fd0dc73d2346.zip
implement more prompts and exp1/backup!
-rw-r--r--go/game/action.go14
-rw-r--r--go/game/cardImplementations.go21
-rw-r--r--go/game/player.go48
-rw-r--r--go/game/playerControl.go12
4 files changed, 82 insertions, 13 deletions
diff --git a/go/game/action.go b/go/game/action.go
index 0cc0bd0a..ab38f238 100644
--- a/go/game/action.go
+++ b/go/game/action.go
@@ -93,6 +93,20 @@ func newHandCardSelection(p *Player, min, max int) Action {
return a
}
+func newAlliedUnitSelection(p *Player, min, max int) Action {
+ a := &TargetSelection{player: p}
+ targetDesc := TargetDesc{"unit you control", fmt.Sprintf("%d-%d", min, max)}
+ a.targets = newTargets(newTarget(p.gameState, targetDesc, a))
+ return a
+}
+
+func newTileSelection(p *Player, constraint TargetConstraintFunc, min, max int) Action {
+ a := &TargetSelection{player: p}
+ desc := TargetDesc{"tile", fmt.Sprintf("%d-%d", min, max)}
+ a.targets = newTargets(newConstraintTarget(p.gameState, desc, constraint, a))
+ return a
+}
+
type FreeDiscardAction struct {
TargetSelection
}
diff --git a/go/game/cardImplementations.go b/go/game/cardImplementations.go
index ea07ccf4..f7f765d5 100644
--- a/go/game/cardImplementations.go
+++ b/go/game/cardImplementations.go
@@ -728,6 +728,26 @@ func (*unholyCannonballImpl) onPlay(a *PlayAction) {
}
}
+// ====== Exp1 Set ======
+
+type backupImpl struct{ cardImplementationBase }
+
+func (*backupImpl) onPlay(a *PlayAction) {
+ p := a.Controller()
+ units := p.PromptAlliedUnitSelection(0, 1)
+ if len(units) == 0 {
+ return
+ }
+ constraint := conjunction(
+ rangeTargetConstraint(units[0].Tile(), 1),
+ availableTileConstraint(a, NewCard("base/recruit")),
+ )
+ tiles := p.PromptTilesSelection(constraint, 0, 2)
+ for _, tile := range tiles {
+ p.gameState.addNewUnit(NewCard("base/recruit"), tile.Position, p)
+ }
+}
+
type illusionistImpl struct{ cardImplementationBase }
func (*illusionistImpl) fullActions(u *Unit) []*FullAction {
@@ -879,6 +899,7 @@ func init() {
"kraken/tides_change!": &tidesChangeImpl{},
"kraken/unholy_cannonball": &unholyCannonballImpl{},
+ "exp1/backup!": &backupImpl{},
"exp1/illusion": &illusionImpl{},
"exp1/illusionist": &illusionistImpl{},
"exp1/patrician": &patricianImpl{},
diff --git a/go/game/player.go b/go/game/player.go
index a8372040..b3cdfe0f 100644
--- a/go/game/player.go
+++ b/go/game/player.go
@@ -224,37 +224,59 @@ func (p *Player) discardStep() {
}
cards := p.PromptHandCardSelection(0, p.Hand.Size())
- for _, c := range cards {
- p.DiscardCard(c)
- }
+ p.discardCards(cards)
}
-func (p *Player) PromptHandCardSelection(min, max int) []*Card {
- p.Ctrl.SendNotification(newHandCardSelectionPrompt(p, min, max))
+func (p *Player) Prompt(n PlayerNotification) Action {
+ p.Ctrl.SendNotification(n)
_a, err := p.Ctrl.RecvAction()
if err != nil {
// FIXME
}
switch a := _a.(type) {
- case *TargetSelection:
- err := a.CheckTargets(p.gameState)
- if err != nil {
- log.Panicf("Invalid hand card selection: %v", err)
- }
-
- return utils.InterfaceSliceToTypedSlice[*Card](a.Target().sel)
case *PassPriority:
return nil
case *ConcedeAction:
p.concede()
return nil
default:
- log.Panicf("Unexpected response type %T for hand card selection", a)
+ return a
+ }
+}
+
+func PromptSelection[T any](p *Player, n PlayerNotification) []T {
+ _a := p.Prompt(n)
+ if _a == nil {
+ return nil
+ }
+
+ switch a := _a.(type) {
+ case *TargetSelection:
+ err := a.CheckTargets(p.gameState)
+ if err != nil {
+ log.Panicf("Invalid selection: %v", err)
+ }
+
+ return utils.InterfaceSliceToTypedSlice[T](a.Target().sel)
+ default:
+ log.Panicf("Unexpected response type %T for selection", a)
}
return nil
}
+func (p *Player) PromptHandCardSelection(min, max int) []*Card {
+ return PromptSelection[*Card](p, newHandCardSelectionPrompt(p, min, max))
+}
+
+func (p *Player) PromptAlliedUnitSelection(min, max int) []*Unit {
+ return PromptSelection[*Unit](p, newAlliedUnitSelectionPrompt(p, min, max))
+}
+
+func (p *Player) PromptTilesSelection(c TargetConstraintFunc, min, max int) []*Tile {
+ return PromptSelection[*Tile](p, newTileSelectionPrompt(p, c, min, max))
+}
+
func (p *Player) Draw() {
toDraw := p.DrawPerTurn - p.Hand.Size()
if toDraw < 1 {
diff --git a/go/game/playerControl.go b/go/game/playerControl.go
index 5f446106..676d15ce 100644
--- a/go/game/playerControl.go
+++ b/go/game/playerControl.go
@@ -109,6 +109,18 @@ func newHandCardSelectionPrompt(p *Player, min, max int) PlayerNotification {
return newTargetSelectionPrompt(a, desc)
}
+func newAlliedUnitSelectionPrompt(p *Player, min, max int) PlayerNotification {
+ a := newAlliedUnitSelection(p, min, max)
+ desc := fmt.Sprintf("Select between %d and %d allied units", min, max)
+ return newTargetSelectionPrompt(a, desc)
+}
+
+func newTileSelectionPrompt(p *Player, c TargetConstraintFunc, min, max int) PlayerNotification {
+ a := newTileSelection(p, c, min, max)
+ desc := fmt.Sprintf("Select between %d and %d tiles", min, max)
+ return newTargetSelectionPrompt(a, desc)
+}
+
func newDeclareTriggeredActionsPrompt(triggeredActions []*TriggeredAction) PlayerNotification {
return PlayerNotification{DeclareTriggeredActionsPrompt, triggeredActions, nil}
}