package game import ( "log" ) type advisorImpl struct{ cardImplementationBase } func (impl *advisorImpl) fullActions(u *Unit) []*FullAction { resolvePrototype := func(a Action) ActionResolveFunc { u := a.Source().(*Unit) return func(s *State) { controller := u.Controller() controller.DrawN(1) cards := controller.PromptHandCardSelection(0, 1) if cards != nil { controller.Deck.MoveCard(cards[0], s.Exile) } } } return []*FullAction{NewFullAction(u, resolvePrototype, "draw 1. exile 1")} } type missionaryImpl struct{ cardImplementationBase } func (impl *missionaryImpl) fullActions(u *Unit) []*FullAction { resolvePrototype := func(a Action) ActionResolveFunc { u := a.Source().(*Unit) target := a.Targets().sel[0].(*Unit) return func(s *State) { target.addMarks(UnitMarks.Faith, 2) if target.Marks(UnitMarks.Faith) > target.Card().BuyCost { target.controller = u.Controller() } } } return []*FullAction{NewFullAction(u, resolvePrototype, "put faith ...")} } type swordImpl struct{ cardImplementationBase } func (*swordImpl) onPile(p Permanent) { if u, ok := p.(*Unit); ok && !INVALID_ATTACK(u.Attack) { u.Attack.attacks[0] += 1 } } func (*swordImpl) onUnpile(p Permanent) { if u, ok := p.(*Unit); ok && !INVALID_ATTACK(u.Attack) { u.Attack.attacks[0] -= 1 } } type tidesChangeImpl struct{ cardImplementation } func (*tidesChangeImpl) onPlay(s *State, _ *Player, _ *Targets) { s.Map.redistributeStoreCards(s.Rand) } type dejaVuImpl struct{ cardImplementation } func (*dejaVuImpl) onPlay(s *State, _ *Player, _ *Targets) { for _, p := range s.Players { if !p.IsKraken() { p.Resource = s.Map.ResourceGain } } } type devourThePoorImpl struct{ cardImplementation } func (*devourThePoorImpl) onPlay(s *State, kraken *Player, _ *Targets) { for _, u := range s.EnemyUnits(kraken) { if u.Card().BuyCost < 7 { s.DestroyPermanent(u) } } } type drownedSailorImpl struct{ cardImplementation } func (*drownedSailorImpl) onPile(containing Permanent) { if u, ok := containing.(*Unit); ok && u.Movement.Swimming { u.Attack.attacks[0] += 1 } } func (*drownedSailorImpl) onUnpile(containing Permanent) { if u, ok := containing.(*Unit); ok && u.Movement.Swimming { u.Attack.attacks[0] -= 1 } } func (*drownedSailorImpl) onDrop(sailor Permanent) { sailor.Controller().gameState.DestroyPermanent(sailor) } // TODO: implement death trigger // TODO: implement hook for the containing permanent on pile type flyingDutchmenImpl struct{ cardImplementation } type frostPylonAoE struct{} func (*frostPylonAoE) onEntering(Permanent) { // TODO: prevent actions and grant new full action } func (*frostPylonAoE) onLeaving(Permanent) { // TODO: remove effect } type frostPylonImpl struct { cardImplementation aoe frostPylonAoE } func (*frostPylonImpl) spawnTiles(s *State, kraken *Player) (spawns []*Tile) { for _, u := range s.EnemyUnits(kraken) { spawns = append(spawns, TilesInRange(s.Map, u, 1)...) } return } func (*frostPylonImpl) stateBasedActions(s *State, p Permanent) { if p.Marks(PermanentMarks.Crack) >= 3 { s.DestroyPermanent(p) } } func (i *frostPylonImpl) onEntering(t *Tile) { s := t.Permanent.Controller().gameState for _, tile := range TilesInRange(s.Map, t.Permanent, 1) { tile.addEffect(&i.aoe) } } func (i *frostPylonImpl) onLeaving(t *Tile) { s := t.Permanent.Controller().gameState for _, tile := range TilesInRange(s.Map, t.Permanent, 1) { tile.removeEffect(&i.aoe) } } type giganticHailImpl struct{ cardImplementation } func (*giganticHailImpl) onPlay(s *State, kraken *Player, _ *Targets) { emptyTiles := s.Map.FreeTiles() choices := len(emptyTiles) for i := 0; i < 3; i++ { if choices == 0 { return } choice := s.Rand.Intn(choices - 1) s.AddNewArtifact(NewCard("kraken/ice_berg"), emptyTiles[choice].Position, kraken) emptyTiles[choice] = emptyTiles[choices-1] choices-- } } type soldOutImpl struct{ cardImplementation } func (*soldOutImpl) onPlay(s *State, kraken *Player, _ *Targets) { nStores := len(s.Map.Stores) storePositions := make([]Position, 0, nStores) for pos := range s.Map.Stores { storePositions = append(storePositions, pos) } storePos := storePositions[s.Rand.Intn(nStores-1)] s.Map.StoreOn(storePos).MoveInto(s.Exile) storeTile := s.Map.TileAt(storePos) storeTile.neutralize() } type supriseImpl struct{ cardImplementation } func (*supriseImpl) onPlay(s *State, kraken *Player, _ *Targets) { kraken.Ctrl.(*KrakenControl).activeSuprise = true } type tentacleSlapImpl struct{ cardImplementation } func (*tentacleSlapImpl) onPlay(s *State, kraken *Player, _ *Targets) { x := 0 for _, p := range s.Players { if p.IsKraken() { continue } x += p.Hand.Size() p.discardHand() } gain := 5 - x if gain > 0 { kraken.gainResource(gain) } } type unholyCannonballImpl struct{ cardImplementation } func (*unholyCannonballImpl) onPlay(s *State, kraken *Player, _ *Targets) { krakenTiles := s.Map.FilterTiles(func(t *Tile) bool { return t.Raw == "the kraken" }) if len(krakenTiles) != 1 { log.Fatal("No kraken tile found in Map") } enemiesInRange2 := []*Unit{} for _, u := range s.EnemyUnits(kraken) { if u.Tile() == nil { continue } if IsPositionInRange(u.Tile().Position, krakenTiles[0].Position, 2) { enemiesInRange2 = append(enemiesInRange2, u) break } } if len(enemiesInRange2) == 0 { kraken.gainResource(5) } else { for _, u := range enemiesInRange2 { u.addMarks(UnitStates.Panic, 1) } } } func init() { cardImplementations = map[string]cardImplementation{ "base/advisor": &advisorImpl{}, "base/missionary": &missionaryImpl{}, "base/sword": &swordImpl{}, "kraken/deja_vu!": &dejaVuImpl{}, "kraken/devour_the_poor!": &devourThePoorImpl{}, "kraken/drowned_sailor": &drownedSailorImpl{}, "kraken/flying_dutchmen": &flyingDutchmenImpl{}, "kraken/frost_pylon": &frostPylonImpl{}, "kraken/gigantic_hail": &giganticHailImpl{}, "kraken/sold_out!": &soldOutImpl{}, "kraken/suprise!": &supriseImpl{}, "kraken/tentacle_slap": &tentacleSlapImpl{}, "kraken/tides_change!": &tidesChangeImpl{}, "kraken/unholy_cannonball": &unholyCannonballImpl{}, } }