aboutsummaryrefslogtreecommitdiff
path: root/go/game/cardImplementations.go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2023-02-25 23:08:47 +0100
committerFlorian Fischer <florian.fischer@muhq.space>2025-08-20 15:57:06 +0200
commit3d36d1d0254b8aeecc889a2a49cbcced458cbe9c (patch)
tree38dd0851d8eaa6535d05b97f29f65fc35655a5ef /go/game/cardImplementations.go
parent19fb1a7e5c5883f49e944b6499fa1ced207a3e39 (diff)
downloadmuhqs-game-3d36d1d0254b8aeecc889a2a49cbcced458cbe9c.tar.gz
muhqs-game-3d36d1d0254b8aeecc889a2a49cbcced458cbe9c.zip
intermediate commit
* Implement move artifact action * Fix widget update memory leak * update the highlights not during on each frame * do not update the unchanged label of a button * Allow to exit the game by pressing 'q' * Implement some cards from the magic set * Improve permanent formatting * Some tweaks to UnitAI code
Diffstat (limited to 'go/game/cardImplementations.go')
-rw-r--r--go/game/cardImplementations.go204
1 files changed, 197 insertions, 7 deletions
diff --git a/go/game/cardImplementations.go b/go/game/cardImplementations.go
index 1c4d07a5..66c77b18 100644
--- a/go/game/cardImplementations.go
+++ b/go/game/cardImplementations.go
@@ -2,6 +2,8 @@ package game
import (
"log"
+
+ "muhq.space/muhqs-game/go/utils"
)
func adjustMelee(p Permanent, damage int) {
@@ -21,6 +23,35 @@ func adjustMelee(p Permanent, damage int) {
}
}
+func adjustAttack(p Permanent, damage int) {
+ u, ok := p.(*Unit)
+ if !ok {
+ return
+ }
+
+ if INVALID_ATTACK(u.Attack) {
+ u.Attack.attacks = append(u.Attack.attacks, damage)
+ } else {
+ // TODO: remove 0 attacks
+ for i := range u.Attack.attacks {
+ u.Attack.attacks[i] += damage
+ }
+ }
+}
+
+func adjustMovement(p Permanent, delta int) {
+ u, ok := p.(*Unit)
+ if !ok {
+ return
+ }
+
+ if u.Movement == INVALID_MOVEMENT() && delta > 0 {
+ u.Movement.Range = delta
+ } else {
+ u.Movement.Range += delta
+ }
+}
+
func adjustHealth(p Permanent, delta int) {
if u, ok := p.(*Unit); ok {
u.Health += delta
@@ -39,7 +70,7 @@ func (*advisorImpl) fullActions(u *Unit) []*FullAction {
controller.DrawN(1)
cards := controller.PromptHandCardSelection(0, 1)
if cards != nil {
- controller.Deck.MoveCard(cards[0], s.Exile)
+ controller.Hand.MoveCard(cards[0], s.Exile)
}
}
}
@@ -172,11 +203,59 @@ func (*wormtongueImpl) fullActions(u *Unit) []*FullAction {
// ====== Magic Set ======
+type attackImpl struct{ cardImplementationBase }
+
+func (*attackImpl) playTargets() TargetDesc {
+ return TargetDesc{"unit", "0-2"}
+}
+
+func (*attackImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
+ sel := t.Cur().sel
+ switch len(sel) {
+ case 1:
+ s.addEotEffect(newAttackModificationEffect(sel[0].(*Unit), 2))
+ case 2:
+ s.addEotEffect(newAttackModificationEffect(sel[0].(*Unit), 1))
+ s.addEotEffect(newAttackModificationEffect(sel[1].(*Unit), 1))
+ }
+}
+
+type healImpl struct{ cardImplementationBase }
+
+func (*healImpl) playTargets() TargetDesc {
+ return newTargetDesc("unit")
+}
+
+func (*healImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
+ u := t.Cur().sel[0].(*Unit)
+ // TODO: prompt damage or poison choice
+ u.adjustDamage(-2)
+}
+
type dieImpl struct{ cardImplementationBase }
-func (*dieImpl) playTargets() *TargetDesc {
- desc := newTargetDesc("unit")
- return &desc
+func (*dieImpl) playTargets() TargetDesc {
+ return newTargetDesc("unit")
+}
+
+type moreImpl struct{ cardImplementationBase }
+
+func (*moreImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
+ p.DrawN(2)
+}
+
+type mineImpl struct{ cardImplementationBase }
+
+func (*mineImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
+ stolen := 0
+ for _, player := range s.Players {
+ if p == player || !p.IsEnemy(player) {
+ continue
+ }
+ player.reduceResource(2)
+ stolen += 2
+ }
+ p.gainResource(stolen)
}
func (*dieImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
@@ -189,6 +268,67 @@ func (*ritualImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
p.gainResource(3)
}
+type rushImpl struct{ cardImplementationBase }
+
+func (*rushImpl) playTargets() TargetDesc {
+ return TargetDesc{"unit", "0-2"}
+}
+
+func (*rushImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
+ sel := t.Cur().sel
+ switch len(sel) {
+ case 1:
+ s.addEotEffect(newMovementModificationEffect(sel[0].(*Unit), 2))
+ case 2:
+ s.addEotEffect(newMovementModificationEffect(sel[0].(*Unit), 1))
+ s.addEotEffect(newMovementModificationEffect(sel[1].(*Unit), 1))
+ }
+}
+
+type selectImpl struct{ cardImplementationBase }
+
+func (*selectImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
+ p.DrawN(1)
+ cards := p.PromptHandCardSelection(0, 1)
+ if cards != nil {
+ p.Hand.MoveCard(cards[0], s.Exile)
+ }
+}
+
+type shroudImpl struct{ cardImplementationBase }
+
+func (*shroudImpl) playTargets() TargetDesc {
+ return newTargetDesc("unit")
+}
+
+func (*shroudImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
+ u := t.Cur().sel[0].(*Unit)
+ s.addEotEffect(newTmpEffect(u, "shroud"))
+}
+
+type switchImpl struct{ cardImplementationBase }
+
+func (*switchImpl) playTargets() TargetDesc {
+ return TargetDesc{"permanent", "2"}
+}
+
+func (*switchImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
+ perms := utils.InterfaceSliceToTypedSlice[Permanent](t.Cur().sel)
+ s.switchPermanents(perms[0], perms[1])
+}
+
+type transmuteImpl struct{ cardImplementationBase }
+
+func (*transmuteImpl) playTargets() TargetDesc {
+ return newTargetDesc("store card")
+}
+
+func (*transmuteImpl) onPlay(s *State, c *Card, p *Player, t *Targets) {
+ storeCard := t.Cur().sel[0].(*Card)
+ p.Store.MoveCard(storeCard, p.Hand)
+ s.Exile.AddCard(c)
+}
+
// ====== Nautics Set ======
var fishTrapAoE areaEffect = newGrantFullActionEffect("nautics/fisher",
@@ -290,6 +430,40 @@ func (*devourThePoorImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets)
}
}
+type dolphinImpl struct{ cardImplementationBase }
+
+func (*dolphinImpl) fullActions(u *Unit) []*FullAction {
+ s := u.Controller().gameState
+ resolvePrototype := func(a Action) ActionResolveFunc {
+ return func(s *State) {
+ t := a.Target().sel[0].(*Unit)
+
+ // 1. +1 Attack
+ // 2. +1 Armor
+ // 3. +2 Movement
+ // 4. +1 Action
+ // 5. +2 Pierce
+ // 6. All
+ choice := s.Rand.Intn(5) + 1
+ switch choice {
+ case 1:
+ s.addEotEffect(newAttackModificationEffect(t, 1))
+ case 2:
+ case 3:
+ s.addEotEffect(newMovementModificationEffect(t, 1))
+ case 4:
+ case 5:
+ case 6:
+ }
+
+ // TODO: implement eot effects
+ }
+ }
+ a := newFullAction(u, resolvePrototype, "random dolphin buff")
+ a.targets = newTargets(newTarget(s, newTargetDesc("adjacent akkied unit"), a))
+ return []*FullAction{a}
+}
+
type drownedSailorImpl struct {
cardImplementation
sailorImpl
@@ -348,7 +522,11 @@ func (i *frostPylonImpl) onLeaving(t *Tile) {
}
}
-type giganticHailImpl struct{ cardImplementation }
+type giganticHailImpl struct {
+ cardImplementation
+}
+
+func (*giganticHailImpl) playTargets() TargetDesc { return INVALID_TARGET_DESC }
func (*giganticHailImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
emptyTiles := s.Map.FreeTiles()
@@ -408,6 +586,8 @@ func (*tentacleSlapImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
type unholyCannonballImpl struct{ cardImplementation }
+func (*unholyCannonballImpl) playTargets() TargetDesc { return INVALID_TARGET_DESC }
+
func (*unholyCannonballImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
krakenTiles := s.Map.FilterTiles(func(t *Tile) bool { return t.Raw == "the kraken" })
if len(krakenTiles) != 1 {
@@ -449,8 +629,17 @@ func init() {
"base/tower_shield": &towerShieldImpl{},
"base/wormtongue": &wormtongueImpl{},
- "magic/die!": &dieImpl{},
- "magic/ritual!": &ritualImpl{},
+ "magic/attack!": &attackImpl{},
+ "magic/die!": &dieImpl{},
+ "magic/heal!": &healImpl{},
+ "magic/more!": &moreImpl{},
+ "magic/mine!": &mineImpl{},
+ "magic/ritual!": &ritualImpl{},
+ "magic/rush!": &rushImpl{},
+ "magic/select!": &selectImpl{},
+ "magic/shroud!": &shroudImpl{},
+ "magic/switch!": &switchImpl{},
+ "magic/transmute!": &transmuteImpl{},
"nautics/captain": &captainImpl{},
"nautics/fish_trap": &fishTrapImpl{aoe: fishTrapAoE},
@@ -459,6 +648,7 @@ func init() {
"kraken/deja_vu!": &dejaVuImpl{},
"kraken/devour_the_poor!": &devourThePoorImpl{},
+ "kraken/dolphin": &dolphinImpl{},
"kraken/drowned_sailor": &drownedSailorImpl{},
"kraken/flying_dutchmen": &flyingDutchmenImpl{},
"kraken/frost_pylon": &frostPylonImpl{},