diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2023-02-15 15:49:50 +0100 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2025-08-20 15:50:10 +0200 |
| commit | b810c024c301fdbe3d0833422bd18449d66d276a (patch) | |
| tree | 9fe207e1dc0c74c8670a9a86d9bda0eb88ed6b07 | |
| parent | 259b2f2b2af8f23bc2fe193838e7f7ecfc61c23a (diff) | |
| download | muhqs-game-b810c024c301fdbe3d0833422bd18449d66d276a.tar.gz muhqs-game-b810c024c301fdbe3d0833422bd18449d66d276a.zip | |
implement the basics of the rest of the base cards
* Add more TODOs
* Implement permanents granting more spawn tiles
| -rw-r--r-- | go/TODO | 8 | ||||
| -rw-r--r-- | go/game/card.go | 18 | ||||
| -rw-r--r-- | go/game/cardImplementations.go | 102 | ||||
| -rw-r--r-- | go/game/cardParsing.go | 22 | ||||
| -rw-r--r-- | go/game/state.go | 12 | ||||
| -rw-r--r-- | go/game/tile.go | 4 |
6 files changed, 156 insertions, 10 deletions
@@ -1,3 +1,11 @@ +* implement pile dropping +* implement artifcat action + * move + * switch +* implement equipment actions + * equip + * drop +* implement target disjunction * implement Pile UI hint * implement spell target parsing / selection * implement triggers diff --git a/go/game/card.go b/go/game/card.go index 031b95bf..7701b5f2 100644 --- a/go/game/card.go +++ b/go/game/card.go @@ -71,6 +71,15 @@ var CardTypeNames = map[string]CardType{ "intention": intentionType, } +func (ct CardType) IsPermanent() bool { + switch ct { + case CardTypes.Unit, CardTypes.Artifact, CardTypes.Equipment, CardTypes.Potion: + return true + default: + return false + } +} + type cardImplementation interface { spawnTiles(*State, *Player) []*Tile fullActions(*Unit) []*FullAction @@ -78,6 +87,8 @@ type cardImplementation interface { stateBasedActions(*State, Permanent) + additionalSpawnsFor(Permanent, CardType) []*Tile + onEntering(*Tile) onLeaving(*Tile) onPlay(*State, *Card, *Player, *Targets) @@ -98,6 +109,8 @@ func (*cardImplementationBase) freeActions(Permanent) []*FreeAction { return nil func (*cardImplementationBase) stateBasedActions(*State, Permanent) {} +func (*cardImplementationBase) additionalSpawnsFor(Permanent, CardType) []*Tile { return nil } + func (*cardImplementationBase) onEntering(*Tile) {} func (*cardImplementationBase) onLeaving(*Tile) {} func (*cardImplementationBase) onPlay(*State, *Card, *Player, *Targets) {} @@ -306,10 +319,7 @@ func (c *Card) Path() string { } func (c *Card) IsPermanent() bool { - return c.Type == CardTypes.Unit || - c.Type == CardTypes.Artifact || - c.Type == CardTypes.Equipment || - c.Type == CardTypes.Potion + return c.Type.IsPermanent() } func (c *Card) IsToken() bool { diff --git a/go/game/cardImplementations.go b/go/game/cardImplementations.go index 038ce2d6..32208f09 100644 --- a/go/game/cardImplementations.go +++ b/go/game/cardImplementations.go @@ -10,6 +10,12 @@ func adjustMelee(p Permanent, damage int) { } } +func adjustHealth(p Permanent, delta int) { + if u, ok := p.(*Unit); ok { + u.Health += delta + } +} + // ====== Base Set ====== type advisorImpl struct{ cardImplementationBase } @@ -64,6 +70,96 @@ func (*misinformationImpl) onPlay(s *State, c *Card, _ *Player, _ *Targets) { s.Exile.AddCard(c) } +type pioneerImpl struct{ cardImplementationBase } + +func (*pioneerImpl) fullActions(u *Unit) []*FullAction { + resolvePrototype := func(a Action) ActionResolveFunc { + return func(s *State) { + target := a.Target().sel[0] + if artifact, ok := target.(*Artifact); ok { + s.DestroyPermanent(artifact) + } else { + tile := target.(*Tile) + tile.neutralize() + } + } + } + + s := u.Controller().gameState + a := NewFullAction(u, resolvePrototype, "neutralize tile or artifact") + // TODO: add target disjunktion 'or' + a.targets = newTargets(newTarget(s, newTargetDesc("adjacent tile or artifcat"), a)) + return []*FullAction{a} +} + +type recruiterImpl struct{ cardImplementationBase } + +func (*recruiterImpl) fullActions(u *Unit) []*FullAction { + resolvePrototype := func(a Action) ActionResolveFunc { + u := a.Source().(*Unit) + return func(s *State) { + t := a.Target().sel[0].(*Tile) + s.AddNewUnit(NewCard("base/recruit"), t.Position, u.Controller()) + } + } + + s := u.Controller().gameState + a := NewFullAction(u, resolvePrototype, "create recruit") + a.targets = newTargets(newTarget(s, newTargetDesc("adjacent tile"), a)) + return []*FullAction{a} +} + +func (*recruiterImpl) additionalSpawnsFor(p Permanent, ct CardType) []*Tile { + if ct != CardTypes.Unit { + return nil + } + + s := p.Controller().gameState + return TilesInRange(s.Map, p, 1) +} + +type shieldImpl struct{ cardImplementationBase } + +func (*shieldImpl) onPile(p Permanent) { adjustHealth(p, 1) } +func (*shieldImpl) onUnpile(p Permanent) { adjustHealth(p, -1) } + +type taxCollectorImpl struct{ cardImplementationBase } + +func (*taxCollectorImpl) fullActions(u *Unit) []*FullAction { + resolvePrototype := func(a Action) ActionResolveFunc { + u := a.Source().(*Unit) + return func(s *State) { + controller := u.Controller() + controller.gainResource(2) + } + } + + a := NewFullAction(u, resolvePrototype, "gain 2") + return []*FullAction{a} +} + +type towerShieldImpl struct{ cardImplementationBase } + +func (*towerShieldImpl) onPile(p Permanent) { adjustHealth(p, 2) } +func (*towerShieldImpl) onUnpile(p Permanent) { adjustHealth(p, -2) } + +type wormtongueImpl struct{ cardImplementationBase } + +func (*wormtongueImpl) fullActions(u *Unit) []*FullAction { + resolvePrototype := func(a Action) ActionResolveFunc { + return func(s *State) { + t := a.Target().sel[0].(*Player) + t.DiscardPile.AddCard(NewCard("base/misinformation")) + } + } + + s := u.Controller().gameState + a := NewFullAction(u, resolvePrototype, "misinform") + // TODO: implement player targeting + a.targets = newTargets(newTarget(s, newTargetDesc("opponent"), a)) + return []*FullAction{a} +} + // ====== Nautics Set ====== var fishTrapAoE areaEffect = newGrantFullActionEffect("nautics/fisher", @@ -316,6 +412,12 @@ func init() { "base/sword": &swordImpl{}, "base/greatsword": &greatSwordImpl{}, "base/misinformation": &misinformationImpl{}, + "base/pioneer": &pioneerImpl{}, + "base/recruiter": &recruiterImpl{}, + "base/shield": &shieldImpl{}, + "base/tax_collector": &taxCollectorImpl{}, + "base/tower_shield": &towerShieldImpl{}, + "base/wormtongue": &wormtongueImpl{}, "nautics/captain": &captainImpl{}, "nautics/fish_trap": &fishTrapImpl{aoe: fishTrapAoE}, diff --git a/go/game/cardParsing.go b/go/game/cardParsing.go index 315de293..ad231fd2 100644 --- a/go/game/cardParsing.go +++ b/go/game/cardParsing.go @@ -14,12 +14,15 @@ type dynamicCardImplementation struct { genFreeActions func(Permanent) []*FreeAction _stateBasedActions func(*State, Permanent) - _onEntering func(*Tile) - _onLeaving func(*Tile) - _onPlay func(*State, *Card, *Player, *Targets) - _onPile func(Permanent) - _onUnpile func(Permanent) - _onDrop func(Permanent) + + _additionalSpawnsFor func(Permanent, CardType) []*Tile + + _onEntering func(*Tile) + _onLeaving func(*Tile) + _onPlay func(*State, *Card, *Player, *Targets) + _onPile func(Permanent) + _onUnpile func(Permanent) + _onDrop func(Permanent) } func (impl *dynamicCardImplementation) spawnTiles(s *State, p *Player) []*Tile { @@ -49,6 +52,13 @@ func (impl *dynamicCardImplementation) stateBasedActions(s *State, p Permanent) } } +func (impl *dynamicCardImplementation) additionalSpawnsFor(p Permanent, ct CardType) []*Tile { + if impl._additionalSpawnsFor != nil { + return impl._additionalSpawnsFor(p, ct) + } + return nil +} + func (impl *dynamicCardImplementation) onEntering(t *Tile) { if impl._onEntering != nil { impl._onEntering(t) diff --git a/go/game/state.go b/go/game/state.go index 5c2fd053..a5a9de82 100644 --- a/go/game/state.go +++ b/go/game/state.go @@ -409,6 +409,16 @@ func (s *State) resolvePlay(p *Player, c *Card, targets *Targets) { } } +func (s *State) additionalSpawnsFor(p *Player, cType CardType) (spawns []*Tile) { + for _, perm := range s.Permanents { + if perm.Controller() != p { + continue + } + spawns = append(spawns, perm.Card().Impl.additionalSpawnsFor(perm, cType)...) + } + return +} + func (s *State) SpawnTiles(p *Player) []*Tile { spawns := s.Map.FilterTiles(func(t *Tile) bool { if t.Type != TileTypes.Spawn { @@ -459,6 +469,8 @@ func (s *State) AvailableSpawnTiles(p *Player, c *Card) []*Tile { } else { candidates = s.SpawnTiles(p) } + + candidates = append(candidates, s.additionalSpawnsFor(p, c.Type)...) } tiles := []*Tile{} diff --git a/go/game/tile.go b/go/game/tile.go index ce7518cb..9034203d 100644 --- a/go/game/tile.go +++ b/go/game/tile.go @@ -197,6 +197,10 @@ func (t *Tile) removeEffect(effect areaEffect) { } func (t *Tile) neutralize() { + if t.Type == TileTypes.Farm { + t.removeEffect(farmEffect) + } + t.Type = TileTypes.Neutral t.Water = false } |
