diff --git a/lib/datacache/datacacheinterface/datacacheinterface.go b/lib/datacache/datacacheinterface/datacacheinterface.go index 323d22f..d107f79 100644 --- a/lib/datacache/datacacheinterface/datacacheinterface.go +++ b/lib/datacache/datacacheinterface/datacacheinterface.go @@ -30,5 +30,7 @@ type DataCacheInterface interface { DeletePokememeByID(pokememeID int) error GetLeagueBySymbol(symbol string) (*dbmapping.League, error) + + GetWeaponTypeByID(weaponID int) (*dbmapping.Weapon, error) GetWeaponTypeByName(name string) (*dbmapping.Weapon, error) } diff --git a/lib/datacache/players.go b/lib/datacache/players.go index 9d50dbf..e155eb3 100644 --- a/lib/datacache/players.go +++ b/lib/datacache/players.go @@ -92,8 +92,9 @@ func (dc *DataCache) GetOrCreatePlayerByTelegramID(telegramID int) (*dbmapping.P // GetPlayerByID returns player from datacache by ID func (dc *DataCache) GetPlayerByID(playerID int) (*dbmapping.Player, error) { - c.Log.Info("DataCache: Getting player with ID=", playerID) + c.Log.Info("DataCache: Getting player with ID = ", playerID) if dc.players[playerID] != nil { + c.Log.Debug("DataCache: found player with ID = " + strconv.Itoa(playerID)) return dc.players[playerID], nil } diff --git a/lib/datacache/profiles.go b/lib/datacache/profiles.go index acce95f..f20a735 100644 --- a/lib/datacache/profiles.go +++ b/lib/datacache/profiles.go @@ -111,6 +111,7 @@ func (dc *DataCache) GetProfileByID(profileID int) (*dbmapping.Profile, error) { // GetProfileByPlayerID returns current profile for player func (dc *DataCache) GetProfileByPlayerID(playerID int) (*dbmapping.Profile, error) { if dc.currentProfiles[playerID] != nil { + c.Log.Debug("DataCache: found current profile for player with ID = " + strconv.Itoa(playerID)) return dc.currentProfiles[playerID], nil } diff --git a/lib/datacache/weapons.go b/lib/datacache/weapons.go index 4b03b66..6ff0a5d 100644 --- a/lib/datacache/weapons.go +++ b/lib/datacache/weapons.go @@ -34,6 +34,18 @@ func (dc *DataCache) loadWeapons() { // External functions +// GetWeaponTypeByID returns weapon type from datacache by given ID +func (dc *DataCache) GetWeaponTypeByID(weaponID int) (*dbmapping.Weapon, error) { + dc.weaponsMutex.Lock() + if dc.weapons[weaponID] != nil { + c.Log.Debug("DataCache: found weapon type with ID = " + strconv.Itoa(weaponID)) + dc.weaponsMutex.Unlock() + return dc.weapons[weaponID], nil + } + dc.weaponsMutex.Unlock() + return nil, errors.New("There is no weapon type with ID = " + strconv.Itoa(weaponID)) +} + // GetWeaponTypeByName returns weapon type from datacache by weapon name func (dc *DataCache) GetWeaponTypeByName(name string) (*dbmapping.Weapon, error) { dc.weaponsMutex.Lock() diff --git a/lib/pokedexer/getters.go b/lib/pokedexer/getters.go index 13a71c6..a937809 100644 --- a/lib/pokedexer/getters.go +++ b/lib/pokedexer/getters.go @@ -7,9 +7,11 @@ import ( "git.wtfteam.pro/fat0troll/i2_bot/lib/dbmapping" "sort" "strconv" + "strings" ) -func (p *Pokedexer) getBestPokememes(playerID int) ([]*dbmapping.PokememeFull, bool) { +func (p *Pokedexer) getAdvicePokememes(playerID int, adviceType string) ([]*dbmapping.PokememeFull, bool) { + c.Log.Debug("Getting advice for pokememes...") pokememesArray := make([]*dbmapping.PokememeFull, 0) playerRaw, err := c.DataCache.GetPlayerByID(playerID) @@ -27,31 +29,45 @@ func (p *Pokedexer) getBestPokememes(playerID int) ([]*dbmapping.PokememeFull, b return pokememesArray, false } + weapon, err := c.DataCache.GetWeaponTypeByID(profileRaw.WeaponID) + if err != nil { + c.Log.Debug(err.Error()) + } + + summPower := profileRaw.Power + if weapon != nil { + summPower = summPower + weapon.Power + } + allPokememes := c.DataCache.GetAllPokememes() for i := range allPokememes { - // Adding only affordable pokememes... - if (allPokememes[i].Pokememe.Defence < profileRaw.Power) || allPokememes[i].Pokememe.Purchaseable { - // ...and only of needed grade (+1 until 9) - neededGrade := 0 - if profileRaw.LevelID < 9 { - neededGrade = profileRaw.LevelID + 1 + neededGrade := 0 + if profileRaw.LevelID < 9 { + neededGrade = profileRaw.LevelID + 1 + } else { + neededGrade = 9 + } + if allPokememes[i].Pokememe.Grade == neededGrade { + matchLeague := false + if profileRaw.LevelID < 4 { + matchLeague = true + } else if adviceType == "best_nofilter" || adviceType == "advice_all" { + matchLeague = true } else { - neededGrade = 9 - } - if allPokememes[i].Pokememe.Grade == neededGrade { - // ...and only of our elements if our level past 4 - matchLeague := false - if profileRaw.LevelID < 4 { - matchLeague = true - } else { - for j := range allPokememes[i].Elements { - if allPokememes[i].Elements[j].LeagueID == playerRaw.LeagueID { - matchLeague = true - } + for j := range allPokememes[i].Elements { + if allPokememes[i].Elements[j].LeagueID == playerRaw.LeagueID { + matchLeague = true } } - if matchLeague { + } + if matchLeague { + switch adviceType { + case "best", "advice": + if (allPokememes[i].Pokememe.Defence < summPower) || allPokememes[i].Pokememe.Purchaseable { + pokememesArray = append(pokememesArray, allPokememes[i]) + } + default: pokememesArray = append(pokememesArray, allPokememes[i]) } } @@ -62,84 +78,26 @@ func (p *Pokedexer) getBestPokememes(playerID int) ([]*dbmapping.PokememeFull, b // As we have already filtered this array, we need to sort it and pass to view sort.Slice(pokememesArray, func(i, j int) bool { - return pokememesArray[i].Pokememe.Attack > pokememesArray[j].Pokememe.Attack - }) - - if len(pokememesArray) > 5 { - idx := 0 - - pokememesArrayShorted := make([]*dbmapping.PokememeFull, 0) - - for i := range pokememesArray { - if idx < 5 { - pokememesArrayShorted = append(pokememesArrayShorted, pokememesArray[i]) - } - idx++ + if strings.HasPrefix(adviceType, "best") { + return pokememesArray[i].Pokememe.Attack > pokememesArray[j].Pokememe.Attack } - - pokememesArray = pokememesArrayShorted - } - - return pokememesArray, true -} - -func (p *Pokedexer) getHighPricedPokememes(playerID int) ([]*dbmapping.PokememeFull, bool) { - pokememesArray := make([]*dbmapping.PokememeFull, 0) - - playerRaw, err := c.DataCache.GetPlayerByID(playerID) - if err != nil { - c.Log.Error(err.Error()) - return pokememesArray, false - } - profileRaw, err := c.DataCache.GetProfileByPlayerID(playerRaw.ID) - if err != nil { - c.Log.Error(err.Error()) - return pokememesArray, false - } - - if playerRaw.LeagueID == 0 { - return pokememesArray, false - } - - allPokememes := c.DataCache.GetAllPokememes() - - for i := range allPokememes { - // Adding only affordable pokememes... - // Only by force: who need to buy pokememe for selling? - if allPokememes[i].Pokememe.Defence < profileRaw.Power { - // ...and only of needed grade (+1 until 9) - neededGrade := 0 - if profileRaw.LevelID < 9 { - neededGrade = profileRaw.LevelID + 1 - } else { - neededGrade = 9 - } - if allPokememes[i].Pokememe.Grade == neededGrade { - pokememesArray = append(pokememesArray, allPokememes[i]) - } - } - } - - c.Log.Debug(strconv.Itoa(len(pokememesArray)) + " pokememes passed initial /advice filtration.") - - // As we have already filtered this array, we need to sort it and pass to view - sort.Slice(pokememesArray, func(i, j int) bool { return pokememesArray[i].Pokememe.Price > pokememesArray[j].Pokememe.Price }) - if len(pokememesArray) > 10 { - idx := 0 - - pokememesArrayShorted := make([]*dbmapping.PokememeFull, 0) - - for i := range pokememesArray { - if idx < 10 { - pokememesArrayShorted = append(pokememesArrayShorted, pokememesArray[i]) + switch adviceType { + case "best", "advice", "best_nofilter": + if len(pokememesArray) > 5 { + idx := 0 + pokememesArrayShorted := make([]*dbmapping.PokememeFull, 0) + for i := range pokememesArray { + if idx < 5 { + pokememesArrayShorted = append(pokememesArrayShorted, pokememesArray[i]) + } + idx++ } - idx++ - } - pokememesArray = pokememesArrayShorted + pokememesArray = pokememesArrayShorted + } } return pokememesArray, true diff --git a/lib/pokedexer/responders.go b/lib/pokedexer/responders.go index 97bbe8a..b6214f0 100644 --- a/lib/pokedexer/responders.go +++ b/lib/pokedexer/responders.go @@ -13,21 +13,10 @@ import ( // AdvicePokememesList shows list for catching // It may be list of best or most valuable pokememes func (p *Pokedexer) AdvicePokememesList(update *tgbotapi.Update, playerRaw *dbmapping.Player) string { - pokememes := make([]*dbmapping.PokememeFull, 0) - if update.Message.Command() == "best" { - neededPokememes, ok := p.getBestPokememes(playerRaw.ID) - if !ok { - c.Log.Error("Cannot get pokememes from getter!") - return "fail" - } - pokememes = neededPokememes - } else { - neededPokememes, ok := p.getHighPricedPokememes(playerRaw.ID) - if !ok { - c.Log.Error("Cannot get pokememes from getter!") - return "fail" - } - pokememes = neededPokememes + pokememes, ok := p.getAdvicePokememes(playerRaw.ID, update.Message.Command()) + if !ok { + c.Log.Error("Cannot get pokememes from getter!") + return "fail" } profileRaw, err := c.DataCache.GetProfileByPlayerID(playerRaw.ID) @@ -37,10 +26,17 @@ func (p *Pokedexer) AdvicePokememesList(update *tgbotapi.Update, playerRaw *dbma } message := "" - if update.Message.Command() == "best" { - message += "*Лучшие покемемы для поимки*\n\n" - } else { - message += "*Самые дорогие покемемы для поимки*\n\n" + switch update.Message.Command() { + case "best": + message += "*Пять топовых покемемов для поимки*\n\n" + case "advice": + message += "*Пять самых дорогих покемемов*\n\n" + case "best_all": + message += "*Все топовые покемемы для твоего уровня*\n\n" + case "advice_all": + message += "*Все самые дорогие покемемы для твоего уровня*\n\n" + case "best_nofilter": + message += "*Пять топовых покемемов для поимки без фильтра по элементам*\n\n" } for i := range pokememes { pk := pokememes[i].Pokememe @@ -68,10 +64,10 @@ func (p *Pokedexer) AdvicePokememesList(update *tgbotapi.Update, playerRaw *dbma } else { message += "Нельзя" } - if update.Message.Command() == "advice" { + if update.Message.Command() == "advice" || update.Message.Command() == "advice_all" { message += "\nСтоимость продажи: 💲" + c.Statistics.GetPrintablePoints(pk.Price) } - if len(message) > 3000 { + if len(message) > 4000 { msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) msg.ParseMode = "Markdown" diff --git a/lib/router/private_request.go b/lib/router/private_request.go index 763b66d..7da2c94 100644 --- a/lib/router/private_request.go +++ b/lib/router/private_request.go @@ -94,6 +94,15 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi case update.Message.Command() == "advice": c.Pokedexer.AdvicePokememesList(update, playerRaw) return "ok" + case update.Message.Command() == "best_all": + c.Pokedexer.AdvicePokememesList(update, playerRaw) + return "ok" + case update.Message.Command() == "advice_all": + c.Pokedexer.AdvicePokememesList(update, playerRaw) + return "ok" + case update.Message.Command() == "best_nofilter": + c.Pokedexer.AdvicePokememesList(update, playerRaw) + return "ok" case update.Message.Command() == "reminders": return c.Reminder.AlarmsList(update, playerRaw) diff --git a/lib/talkers/help.go b/lib/talkers/help.go index 8c1db0d..dde3aa6 100644 --- a/lib/talkers/help.go +++ b/lib/talkers/help.go @@ -7,6 +7,7 @@ import ( "git.wtfteam.pro/fat0troll/i2_bot/lib/config" "git.wtfteam.pro/fat0troll/i2_bot/lib/dbmapping" "github.com/go-telegram-bot-api/telegram-bot-api" + "time" ) // AcademyMessage gives user link to Bastion @@ -53,8 +54,13 @@ func (t *Talkers) HelpMessage(update *tgbotapi.Update, playerRaw *dbmapping.Play message += "Текущая версия: *" + config.VERSION + "*\n\n" message += "Список команд\n\n" message += "\\* /me – посмотреть свой сохраненный профиль в боте\n" - message += "\\* /best – посмотреть лучших покемонов для поимки\n" - message += "\\* /advice – посмотреть самых дорогих покемонов для поимки\n" + message += "\\* /best – посмотреть 5 лучших покемонов для поимки\n" + message += "\\* /advice – посмотреть 5 самых дорогих покемонов для поимки\n" + message += "\\* /best\\_all – посмотреть всех лучших покемонов для поимки\n" + message += "\\* /advice\\_all – посмотреть всех самых дорогих покемонов для поимки\n" + if playerRaw.CreatedAt.Before(time.Now().Add(30 * 24 * 60 * 60 * time.Second)) { + message += "\\* /best\\_nofilter – посмотреть пять лучших покемонов для поимки _без фильтра по элементам_ (полезно для сборки максимально топовой руки на высоком уровне)\n" + } message += "\\* /top — топ игроков лиги\n" message += "\\* /top\\_my — топ игроков лиги твоего уровня\n" message += "\\* /pokedeks – получить список известных боту покемемов\n" diff --git a/lib/users/responders.go b/lib/users/responders.go index 7292225..fc9af60 100644 --- a/lib/users/responders.go +++ b/lib/users/responders.go @@ -127,12 +127,10 @@ func (u *Users) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Pla if err != nil { c.Log.Error(err) } - weapon := dbmapping.Weapon{} - if profileRaw.WeaponID != 0 { - err = c.Db.Get(&weapon, c.Db.Rebind("SELECT * FROM weapons WHERE id=?"), profileRaw.WeaponID) - if err != nil { - c.Log.Error(err) - } + weapon, err := c.DataCache.GetWeaponTypeByID(profileRaw.WeaponID) + if err != nil { + // It's non critical + c.Log.Debug(err.Error()) } profilePokememes := []dbmapping.ProfilePokememe{} err = c.Db.Select(&profilePokememes, c.Db.Rebind("SELECT * FROM profiles_pokememes WHERE profile_id=?"), profileRaw.ID)