package game import ( "math/rand" "muhq.space/muhqs-game/go/log" ) func prepState(playerName string, m *Map) *LocalState { s := NewLocalState() s.SetMap(m) // Prepare the players s.AddNewPlayer(playerName, NewDeck()) // Add Opponent ai := s.AddNewPlayer("opponent", NewDeck()) ai.Ctrl = NewSimpleAiControl(ai) return s } func NewRandomChallenge(name string) *LocalState { maps := []string{"2P-ring-street", "2P-river-king"} var m *Map n := rand.Intn(len(maps) + 1) switch n { case 0, 1: m, _ = GetMap(maps[rand.Intn(len(maps))]) case 2: seed := rand.Int63() log.Info("create random map", "seed", seed) m = RandomMap(seed, 2) } s := prepState(name, m) switch rand.Intn(3) { // Cavalry Archer Challenge case 0: return prepCavArcherChallenge(s) case 1: return prepMissionaryChallenge(s) // Random Base Challenge default: return prepBaseChallenge(s) } } func prepCavArcherChallenge(s *LocalState) *LocalState { // Override old Prepare to prevent Kings from beeing spawned s._map.Prepare = func(*LocalState) { u := NewCard("base/cavalry_archer") tiles := s._map.AvailableTilesFor(u) tile := tiles[rand.Intn(len(tiles))] p := s.PlayerById(1) p.Deck = NewDeck() s.addNewUnit(u, tile.Position, p) // Prepare the opponent's units nUnits := rand.Intn(3) + 2 // add support equipment if nUnits > 3 { candidates := []string{ "base/shield", "base/tower_shield", "equipments/armor", "equipments/gear", "equipments/mace", // "equipments/poison_dagger", } e := NewCard(candidates[rand.Intn(len(candidates))]) tiles := s._map.AvailableTilesFor(e) tile := tiles[rand.Intn(len(tiles))] s.addNewEquipment(e, tile.Position, p) } units := make([]*Card, 0, nUnits) ai := s.PlayerById(2) // Only use Melee Units candidates := NewDeckFromCardPaths(Sets.Base.CardPaths()).FilterCards(func(c *Card) bool { if c.Type != CardTypes.Unit { return false } // Disallow armor since the cavalry archer can not penetrate it. if _, err := c.getXEffect("armor"); err == nil { return false } var attack Attack if attackDesc, found := c.Values["attack"]; found { attack = parseAttack(attackDesc) return attack.MaxRange() == 1 } return false }) for range nUnits { units = append(units, NewCard(candidates[rand.Intn(len(candidates))].Path())) } for _, u := range units { tiles := s._map.AvailableTilesFor(u) tile := tiles[rand.Intn(len(tiles))] s.addNewUnit(u, tile.Position, ai) } s._map.WinCondition = DeathMatch } return s } func NewCavArcherChallenge(playerName string) *LocalState { maps := []string{"2P-ring-street", "2P-river-king"} m, _ := GetMap(maps[rand.Intn(len(maps))]) return prepCavArcherChallenge(prepState(playerName, m)) } func prepMissionaryChallenge(s *LocalState) *LocalState { // Override old Prepare to prevent Kings from beeing spawned s._map.Prepare = func(*LocalState) { u := NewCard("base/missionary") tiles := s._map.AvailableTilesFor(u) tile := tiles[rand.Intn(len(tiles))] p := s.PlayerById(1) p.Deck = NewDeck() s.addNewUnit(u, tile.Position, p) // Prepare the opponent's units nUnits := rand.Intn(2) + 2 units := make([]*Card, 0, nUnits) ai := s.PlayerById(2) // Only spawn aggressive Units candidates := NewDeckFromCardPaths(Sets.Base.CardPaths()).FilterCards(func(c *Card) bool { if c.Type != CardTypes.Unit { return false } _, found := c.Values["attack"] return found }) for range nUnits { units = append(units, NewCard(candidates[rand.Intn(len(candidates))].Path())) } for _, u := range units { tiles := s._map.AvailableTilesFor(u) tile := tiles[rand.Intn(len(tiles))] s.addNewUnit(u, tile.Position, ai) } s._map.WinCondition = DeathMatch } return s } func NewMissionaryChallenge(playerName string) *LocalState { maps := []string{"2P-ring-street", "2P-river-king"} m, _ := GetMap(maps[rand.Intn(len(maps))]) return prepMissionaryChallenge(prepState(playerName, m)) } func prepBaseChallenge(s *LocalState) *LocalState { p := s.PlayerById(1) nCards := rand.Intn(6) nCards = nCards + 3 d := NewRandomDeck(nCards, []SetIdentifier{Sets.Base, Sets.Magic, Sets.Equipments}) p.Store.AddCards(d.FilterCards(func(c *Card) bool { return c.IsBuyable() })) ai := s.PlayerById(2) ai.Deck = NewRandomDeck(nCards, []SetIdentifier{Sets.Base}) return s }