From ca516481105fc5ed100a7a0f1029fcc5bf0ad888 Mon Sep 17 00:00:00 2001 From: Vladimir Hodakov Date: Wed, 2 May 2018 08:48:22 +0400 Subject: [PATCH] Add profile updates via statistics After nerf update there is machine-readable command /me in PokememBroBot. It can be used for gathering useful information about users. --- .../datacacheinterface/datacacheinterface.go | 2 + lib/datacache/leagues.go | 12 + lib/datacache/weapons.go | 11 + lib/pokedexer/getters.go | 12 +- lib/pokedexer/responders.go | 1 - lib/router/inline.go | 41 ++- lib/users/parsers.go | 311 ++++++++---------- lib/welcomer/responders.go | 13 +- lib/welcomer/welcomer.go | 9 +- 9 files changed, 201 insertions(+), 211 deletions(-) diff --git a/lib/datacache/datacacheinterface/datacacheinterface.go b/lib/datacache/datacacheinterface/datacacheinterface.go index 3142507..c6e1bb4 100644 --- a/lib/datacache/datacacheinterface/datacacheinterface.go +++ b/lib/datacache/datacacheinterface/datacacheinterface.go @@ -49,6 +49,7 @@ type DataCacheInterface interface { FindElementIDBySymbol(symbol string) (int, error) GetLeagueByID(leagueID int) (*datamapping.League, error) + GetLeagueByName(name string) (*datamapping.League, error) GetLeagueBySymbol(symbol string) (*datamapping.League, error) GetLevelByID(levelID int) (*datamapping.Level, error) @@ -60,6 +61,7 @@ type DataCacheInterface interface { GetPokememeByName(name string) (*datamapping.PokememeFull, error) GetPokememesCountByGradeAndLocation(grade int, locationID int) int + GetWeaponTypeByAttack(attack int) (*datamapping.Weapon, error) GetWeaponTypeByID(weaponID int) (*datamapping.Weapon, error) GetWeaponTypeByName(name string) (*datamapping.Weapon, error) } diff --git a/lib/datacache/leagues.go b/lib/datacache/leagues.go index 5273322..241600d 100644 --- a/lib/datacache/leagues.go +++ b/lib/datacache/leagues.go @@ -6,6 +6,7 @@ package datacache import ( "errors" "strconv" + "strings" "gopkg.in/yaml.v2" "source.wtfteam.pro/i2_bot/i2_bot/lib/datamapping" @@ -56,6 +57,17 @@ func (dc *DataCache) GetLeagueByID(leagueID int) (*datamapping.League, error) { return nil, errors.New("There is no league with ID = " + strconv.Itoa(leagueID)) } +// GetLeagueByName returns league from datacache by name +func (dc *DataCache) GetLeagueByName(name string) (*datamapping.League, error) { + for i := range dc.leagues { + if strings.Contains(dc.leagues[i].Name, name) { + return dc.leagues[i], nil + } + } + + return nil, errors.New("There is no league with name = " + name) +} + // GetLeagueBySymbol returns league from datacache by emoji func (dc *DataCache) GetLeagueBySymbol(symbol string) (*datamapping.League, error) { for i := range dc.leagues { diff --git a/lib/datacache/weapons.go b/lib/datacache/weapons.go index e5edeec..8e92817 100644 --- a/lib/datacache/weapons.go +++ b/lib/datacache/weapons.go @@ -48,6 +48,17 @@ func (dc *DataCache) getWeapons() []datamapping.Weapon { // External functions +// GetWeaponTypeByAttack returns weapon type from datacache by given attack +func (dc *DataCache) GetWeaponTypeByAttack(attack int) (*datamapping.Weapon, error) { + for i := range dc.weapons { + if dc.weapons[i].Power == attack { + return dc.weapons[i], nil + } + } + + return nil, errors.New("There is no weapon type with attack = " + strconv.Itoa(attack)) +} + // GetWeaponTypeByID returns weapon type from datacache by given ID func (dc *DataCache) GetWeaponTypeByID(weaponID int) (*datamapping.Weapon, error) { if dc.weapons[weaponID] != nil { diff --git a/lib/pokedexer/getters.go b/lib/pokedexer/getters.go index 78250de..0fe0c0c 100644 --- a/lib/pokedexer/getters.go +++ b/lib/pokedexer/getters.go @@ -42,10 +42,10 @@ func (p *Pokedexer) getAdvicePokememes(playerID int, adviceType string) ([]*data allPokememes := c.DataCache.GetAllPokememes() neededGrade := 0 - if profileRaw.LevelID < 10 { + if profileRaw.LevelID < 19 { neededGrade = profileRaw.LevelID + 1 } else { - neededGrade = 10 + neededGrade = 19 } c.Log.Debug("This player will search for grade: " + strconv.Itoa(neededGrade)) @@ -90,13 +90,9 @@ func (p *Pokedexer) getAdvicePokememes(playerID int, adviceType string) ([]*data switch adviceType { case "best", "advice", "best_nofilter": if len(pokememesArray) > 5 { - idx := 0 pokememesArrayShorted := make([]*datamapping.PokememeFull, 0) - for i := range pokememesArray { - if idx < 5 { - pokememesArrayShorted = append(pokememesArrayShorted, pokememesArray[i]) - } - idx++ + for i := 0; i < 5; i++ { + pokememesArrayShorted = append(pokememesArrayShorted, pokememesArray[i]) } pokememesArray = pokememesArrayShorted diff --git a/lib/pokedexer/responders.go b/lib/pokedexer/responders.go index 9deb059..bbc4bf7 100644 --- a/lib/pokedexer/responders.go +++ b/lib/pokedexer/responders.go @@ -197,7 +197,6 @@ func (p *Pokedexer) PokememeInfo(update *tgbotapi.Update, playerRaw *dbmapping.P msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) keyboard := tgbotapi.InlineKeyboardMarkup{} for i := range pokememe.Locations { - c.Log.Info("wow, location") var row []tgbotapi.InlineKeyboardButton btn := tgbotapi.NewInlineKeyboardButtonSwitch(pokememe.Locations[i].Symbol+pokememe.Locations[i].Name, pokememe.Locations[i].Symbol+pokememe.Locations[i].Name) row = append(row, btn) diff --git a/lib/router/inline.go b/lib/router/inline.go index 8cd13fb..7694db2 100644 --- a/lib/router/inline.go +++ b/lib/router/inline.go @@ -21,8 +21,8 @@ func (r *Router) RouteInline(update tgbotapi.Update) string { results := make([]interface{}, 0) if (playerRaw.LeagueID != 1) || (playerRaw.Status == "banned") { - article := tgbotapi.NewInlineQueryResultArticle("0", "Команда боту @PokememBroBot:", "👤Герой") - article.Description = "👤Герой" + article := tgbotapi.NewInlineQueryResultArticle("0", "Команда боту @PokememBroBot:", "/me") + article.Description = "Получить статистику" results = append(results, article) } else { @@ -45,23 +45,30 @@ func (r *Router) RouteInline(update tgbotapi.Update) string { results = append(results, article) } else { - availableCommands := make(map[string]string) - availableCommands["10"] = "🌲Лес" - availableCommands["11"] = "⛰Горы" - availableCommands["12"] = "🚣Озеро" - availableCommands["13"] = "🏙Город" - availableCommands["14"] = "🏛Катакомбы" - availableCommands["15"] = "⛪️Кладбище" - outputCommands := make(map[string]string) - for i, value := range availableCommands { - if strings.Contains(value, update.InlineQuery.Query) { - outputCommands[i] = value + if update.InlineQuery.Query != "Статы" { + availableCommands := make(map[string]string) + availableCommands["10"] = "🌲Лес" + availableCommands["11"] = "⛰Горы" + availableCommands["12"] = "🚣Озеро" + availableCommands["13"] = "🏙Город" + availableCommands["14"] = "🏛Катакомбы" + availableCommands["15"] = "⛪️Кладбище" + outputCommands := make(map[string]string) + for i, value := range availableCommands { + if strings.Contains(value, update.InlineQuery.Query) { + outputCommands[i] = value + } } - } - for i, value := range outputCommands { - article := tgbotapi.NewInlineQueryResultArticle(i, "Команда боту @PokememBroBot:", value) - article.Description = value + for i, value := range outputCommands { + article := tgbotapi.NewInlineQueryResultArticle(i, "Команда боту @PokememBroBot:", value) + article.Description = value + + results = append(results, article) + } + } else { + article := tgbotapi.NewInlineQueryResultArticle("0", "Команда боту @PokememBroBot:", "/me") + article.Description = "Получить статистику" results = append(results, article) } diff --git a/lib/users/parsers.go b/lib/users/parsers.go index 1e56922..2aaeea8 100644 --- a/lib/users/parsers.go +++ b/lib/users/parsers.go @@ -4,20 +4,19 @@ package users import ( - "regexp" + "fmt" "strconv" "strings" "time" "github.com/go-telegram-bot-api/telegram-bot-api" - "source.wtfteam.pro/i2_bot/i2_bot/lib/datamapping" "source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping" ) // Internal functions -func (u *Users) fillProfilePokememe(profileID int, meme string, attack string, rarity string) { - spkRaw, err := c.DataCache.GetPokememeByName(meme) +func (u *Users) fillProfilePokememe(profileID int, pokememeID int, attack string, rarity string) { + spkRaw, err := c.DataCache.GetPokememeByID(pokememeID) if err != nil { c.Log.Error(err.Error()) } else { @@ -43,158 +42,104 @@ func (u *Users) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Playe c.Log.Info(text) profileStringsArray := strings.Split(text, "\n") - profileRunesArray := make([][]rune, 0) - for i := range profileStringsArray { - profileRunesArray = append(profileRunesArray, []rune(profileStringsArray[i])) - } - - league := datamapping.League{} telegramNickname := update.Message.From.UserName - nickname := "" - level := "" - levelInt := 0 - exp := "" - expInt := 0 - eggexp := "" - eggexpInt := 0 - pokeballs := "" - pokeballsInt := 0 - wealth := "" - wealthInt := 0 - pokememesWealth := "" - pokememesWealthInt := 0 - crystals := "" - crystalsInt := 0 - weapon := "" - pokememes := make(map[string]string) - powerInt := 0 + rawProfileData := make(map[string]string) + rawCurrentHandData := make(map[string]string) + currentHand := 0 + profilePower := 0 - // Filling information - // We don't know how many strings we got, so we iterating each other - for i := range profileRunesArray { - currentString := string(profileRunesArray[i]) - currentRunes := profileRunesArray[i] - if strings.HasPrefix(currentString, "🈸") || strings.HasPrefix(currentString, "🈳 ") || strings.HasPrefix(currentString, "🈵") { - leagueRaw, err := c.DataCache.GetLeagueBySymbol(string(currentRunes[0])) + // Not using range here, because range is picking elements in random order + for i := 0; i < len(profileStringsArray); i++ { + infoString := profileStringsArray[i] + c.Log.Debug("Processing string: " + infoString) + if strings.HasPrefix(infoString, "CurrentHand ") { + currentHandNumber := strings.Split(infoString, " ")[1] + currentHandInt, err := strconv.Atoi(currentHandNumber) if err != nil { c.Log.Error(err.Error()) u.profileAddFailureMessage(update) return "fail" } - league = *leagueRaw - for j := range currentRunes { - if j > 1 { - nickname += string(currentRunes[j]) - } - } - } - if strings.HasPrefix(currentString, "id: ") { - realUserID := strings.TrimPrefix(currentString, "id: ") - c.Log.Debug("Profile user ID: " + realUserID) - realUID, _ := strconv.Atoi(realUserID) - if realUID != playerRaw.TelegramID { - return "fail" - } - } - if strings.HasPrefix(currentString, "👤Уровень:") { - levelRx := regexp.MustCompile("\\d+") - levelArray := levelRx.FindAllString(currentString, -1) - if len(levelArray) < 1 { - c.Log.Error("Level string broken") - u.profileAddFailureMessage(update) - return "fail" - } - level = levelArray[0] - levelInt, _ = strconv.Atoi(level) - } - - if strings.HasPrefix(currentString, "🎓Опыт") { - expRx := regexp.MustCompile("\\d+") - expArray := expRx.FindAllString(currentString, -1) - if len(expArray) < 4 { - c.Log.Error("Exp string broken") - u.profileAddFailureMessage(update) - return "fail" - } - exp = expArray[0] - expInt, _ = strconv.Atoi(exp) - eggexp = expArray[2] - eggexpInt, _ = strconv.Atoi(eggexp) - } - - if strings.HasPrefix(currentString, "⭕Покеболы") { - pkbRx := regexp.MustCompile("\\d+") - pkbArray := pkbRx.FindAllString(currentString, -1) - if len(pkbArray) < 2 { - c.Log.Error("Pokeballs string broken") - u.profileAddFailureMessage(update) - return "fail" - } - pokeballs = pkbArray[1] - pokeballsInt, _ = strconv.Atoi(pokeballs) - } - - if strings.HasPrefix(currentString, "💲") { - wealthRx := regexp.MustCompile("(\\d|\\.|K|M)+") - wealthArray := wealthRx.FindAllString(currentString, -1) - if len(wealthArray) < 2 { - c.Log.Error("Wealth string broken") - u.profileAddFailureMessage(update) - return "fail" - } - wealth = wealthArray[0] - wealthInt = c.Statistics.GetPoints(wealth) - crystals = wealthArray[1] - crystalsInt = c.Statistics.GetPoints(crystals) - } - - if strings.HasPrefix(currentString, "🔫") { - // We need NEXT string! - weaponType := strings.Replace(currentString, "🔫 ", "", 1) - wnRx := regexp.MustCompile("(.+)(ита|ёры)") - weapon = wnRx.FindString(weaponType) - } - - if strings.HasPrefix(currentString, "🐱Покемемы: ") { - pkmnumRx := regexp.MustCompile(`(\d|\.|K|M)+`) - pkNumArray := pkmnumRx.FindAllString(currentString, -1) - if len(pkNumArray) < 3 { - c.Log.Error("Pokememes count broken") - u.profileAddFailureMessage(update) - return "fail" - } - pokememesCount, _ := strconv.Atoi(pkNumArray[0]) - pokememesWealth = pkNumArray[2] - pokememesWealthInt = c.Statistics.GetPoints(pokememesWealth) - if pokememesCount > 0 { - for pi := 0; pi < pokememesCount; pi++ { - pokememeString := string(profileRunesArray[i+1+pi]) - attackRx := regexp.MustCompile("(\\d|\\.|K|M)+") - pkPointsArray := attackRx.FindAllString(pokememeString, -1) - pkAttack := "" - if strings.Contains(pokememeString, "🔟") { - pkAttack = pkPointsArray[0] - } else if strings.Contains(pokememeString, "⃣") { - pkAttack = pkPointsArray[1] - } else { - // Something went wrong - return c.Talkers.BotError(update) - } - pkName := strings.Split(pokememeString, "+")[0] - pkName = strings.Replace(pkName, " ⭐", "", 1) - if strings.Contains(pkName, "🔟") { - pkName = strings.Split(pkName, "🔟 ")[1] - } else { - pkName = strings.Split(pkName, "⃣ ")[1] - } - pokememes[strconv.Itoa(pi)+"_"+pkName] = pkAttack - powerInt += c.Statistics.GetPoints(pkAttack) - } + currentHand = currentHandInt + } else if strings.HasPrefix(infoString, ("Hand" + strconv.Itoa(currentHand))) { + if strings.HasPrefix(infoString, ("Hand"+strconv.Itoa(currentHand))+" Attack") { + rawProfileData["currentHandAttack"] = strings.Join(strings.Split(infoString, " ")[2:], " ") + } else { + rawCurrentHandData[strconv.Itoa(len(rawCurrentHandData))] = strings.Join(strings.Split(infoString, " ")[1:], " ") } + } else { + rawProfileData[strings.Split(infoString, " ")[0]] = strings.Join(strings.Split(infoString, " ")[1:], " ") } } + fmt.Println(rawProfileData) + + nickname := rawProfileData["Name"] + league, err := c.DataCache.GetLeagueByName(rawProfileData["Team"]) + if err != nil { + c.Log.Error(err.Error()) + u.profileAddFailureMessage(update) + return "fail" + } + level := rawProfileData["Lvl"] + levelInt, err := strconv.Atoi(level) + if err != nil { + c.Log.Error(err.Error()) + u.profileAddFailureMessage(update) + return "fail" + } + exp := rawProfileData["Exp"] + expInt, err := strconv.Atoi(exp) + if err != nil { + c.Log.Error(err.Error()) + u.profileAddFailureMessage(update) + return "fail" + } + eggexp := strings.Split(rawProfileData["Eggs"], "/")[0] + eggexpInt, err := strconv.Atoi(eggexp) + if err != nil { + c.Log.Error(err.Error()) + u.profileAddFailureMessage(update) + return "fail" + } + pokeballs := rawProfileData["BallsMax"] + pokeballsInt, err := strconv.Atoi(pokeballs) + if err != nil { + c.Log.Error(err.Error()) + u.profileAddFailureMessage(update) + return "fail" + } + wealth := rawProfileData["Money"] + wealthInt, err := strconv.Atoi(wealth) + if err != nil { + c.Log.Error(err.Error()) + u.profileAddFailureMessage(update) + return "fail" + } + crystals := rawProfileData["Crystalls"] + crystalsInt, err := strconv.Atoi(crystals) + if err != nil { + c.Log.Error(err.Error()) + u.profileAddFailureMessage(update) + return "fail" + } + weapon := rawProfileData["Weapon"] + weaponAttack, err := strconv.Atoi(weapon) + if err != nil { + c.Log.Error(err.Error()) + u.profileAddFailureMessage(update) + return "fail" + } + currentHandAttack := rawProfileData["currentHandAttack"] + currentHandAttackInt, err := strconv.Atoi(currentHandAttack) + if err != nil { + c.Log.Error(err.Error()) + u.profileAddFailureMessage(update) + return "fail" + } + profilePower = weaponAttack + currentHandAttackInt + c.Log.Debug("Telegram nickname: " + telegramNickname) c.Log.Debug("Nickname: " + nickname) c.Log.Debug("League: " + league.Name) @@ -208,25 +153,32 @@ func (u *Users) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Playe c.Log.Debugln(pokeballsInt) c.Log.Debug("Wealth: " + wealth) c.Log.Debugln(wealthInt) - c.Log.Debug("crystals: " + crystals) + c.Log.Debug("Crystals: " + crystals) c.Log.Debugln(crystalsInt) - c.Log.Debug("Weapon: " + weapon) - if len(pokememes) > 0 { - c.Log.Debug("Hand cost: " + pokememesWealth) - c.Log.Debugln(pokememesWealthInt) - for meme, attack := range pokememes { - c.Log.Debug(meme + ": " + attack) + c.Log.Debug("Weapon attack: " + weapon) + c.Log.Debugln(weaponAttack) + c.Log.Debug("Current hand attack: " + currentHandAttack) + c.Log.Debugln(currentHandAttackInt) + if len(rawCurrentHandData) > 0 { + for i := range rawCurrentHandData { + c.Log.Debug(rawCurrentHandData[i]) } } else { c.Log.Debug("Hand is empty.") } // Information is gathered, let's create profile in database! - weaponRaw, err := c.DataCache.GetWeaponTypeByName(weapon) + weaponRaw, err := c.DataCache.GetWeaponTypeByAttack(weaponAttack) if err != nil { c.Log.Error(err.Error()) } + if weaponRaw != nil { + c.Log.Debug("Got weapon: " + weaponRaw.Name) + } else { + c.Log.Debug("This profile contains no weapon") + } + if playerRaw.LeagueID == 0 { // Updating player with league playerRaw.LeagueID = league.ID @@ -256,10 +208,11 @@ func (u *Users) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Playe profileRaw.LevelID = levelInt profileRaw.Pokeballs = pokeballsInt profileRaw.Wealth = wealthInt - profileRaw.PokememesWealth = pokememesWealthInt + // TODO: count pokememes wealth + profileRaw.PokememesWealth = 0 profileRaw.Exp = expInt profileRaw.EggExp = eggexpInt - profileRaw.Power = powerInt + profileRaw.Power = profilePower if weaponRaw != nil { profileRaw.WeaponID = weaponRaw.ID } else { @@ -288,35 +241,31 @@ func (u *Users) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Playe return "fail" } - for nMeme, attack := range pokememes { - memeAry := strings.Split(nMeme, "_") - meme := memeAry[1] - rarity := "common" - if strings.HasPrefix(meme, "🔸") { - rarity = "rare" - meme = strings.Replace(meme, "🔸", "", 1) + for i := range rawCurrentHandData { + pokememeInfoArray := strings.Split(rawCurrentHandData[i], " ") + pokememePokedexNumber := pokememeInfoArray[1] + pokememePokedexID, err := strconv.Atoi(pokememePokedexNumber) + if err != nil { + c.Log.Error(err.Error()) } - if strings.HasPrefix(meme, "🔶") { - rarity = "super rare" - meme = strings.Replace(meme, "🔶", "", 1) + pokememeRarityName := "common" + pokememeRarity := pokememeInfoArray[3] + pokememeAttack := pokememeInfoArray[7] + switch pokememeRarity { + case "1": + pokememeRarityName = "rare" + case "2": + pokememeRarityName = "super rare" + case "3": + pokememeRarityName = "liber" + case "4": + pokememeRarityName = "super liber" + case "7": + pokememeRarityName = "new year" + case "8": + pokememeRarityName = "valentine" } - if strings.HasPrefix(meme, "🔹") { - rarity = "liber" - meme = strings.Replace(meme, "🔹", "", 1) - } - if strings.HasPrefix(meme, "🔷") { - rarity = "super liber" - meme = strings.Replace(meme, "🔷", "", 1) - } - if strings.HasPrefix(meme, "❄") { - rarity = "new year" - meme = strings.Replace(meme, "❄", "", 1) - } - if strings.HasPrefix(meme, "❤") { - rarity = "valentine" - meme = strings.Replace(meme, "❤", "", 1) - } - u.fillProfilePokememe(newProfileID, meme, attack, rarity) + u.fillProfilePokememe(newProfileID, pokememePokedexID, pokememeAttack, pokememeRarityName) } u.profileAddSuccessMessage(update, league.ID, profileRaw.LevelID) diff --git a/lib/welcomer/responders.go b/lib/welcomer/responders.go index f6a4348..6d01d29 100644 --- a/lib/welcomer/responders.go +++ b/lib/welcomer/responders.go @@ -13,13 +13,20 @@ import ( // PrivateWelcomeMessageUnauthorized tell new user what to do. func (w *Welcomer) PrivateWelcomeMessageUnauthorized(update *tgbotapi.Update) { message := "*Бот Инстинкта приветствует тебя!*\n\n" - message += "Для начала работы с ботом, пожалуйста, перешли от бота игры @PokememBroBot профиль героя.\n" - message += "Все дальнейшие действия с ботом возможны лишь при наличии профиля игрока.\n\n" + message += "Для начала работы с ботом, пожалуйста, перешли от бота игры @PokememBroBot свою статистику.\n" + message += "Все дальнейшие действия с ботом возможны лишь при наличии профиля игрока внутри его базы данных.\n\n" - message += "Как переслать профиль: перейди в @okemembrobot, нажми там кнопку 👤Герой. Щелкни на полученном сообщении с твоим уровнем, атакой, опытом и так далее правой кнопкой мыши (или просто тапни, если ты с телефона), в появившемся меню нажми Переслать и выбери @i2\\_bot, то есть меня, в появившемся списке чатов, а затем отправь мне это сообщение.\n" + message += "_Нажми на кнопку, получишь результат\nИ твоя мечта осуществится\nНажми на кнопку…_\n" msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) msg.ParseMode = "Markdown" + keyboard := tgbotapi.InlineKeyboardMarkup{} + var row []tgbotapi.InlineKeyboardButton + btn := tgbotapi.NewInlineKeyboardButtonSwitch("Отправить команду @PokememBroBot", "Статы") + row = append(row, btn) + keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, row) + + msg.ReplyMarkup = keyboard c.Bot.Send(msg) } diff --git a/lib/welcomer/welcomer.go b/lib/welcomer/welcomer.go index 6884fbc..2a7f2d5 100644 --- a/lib/welcomer/welcomer.go +++ b/lib/welcomer/welcomer.go @@ -32,10 +32,17 @@ func (w *Welcomer) groupWelcomeUser(update *tgbotapi.Update, newUser *tgbotapi.U w.alertUserWithoutProfile(update, newUser) } - message += "Приветствую тебя, гость лиги Инстинкт! Для регистрации в Лиге и получения доступа к ее ресурсам и чатам напиши скорее мне, @i2\\_bot, в личку и скинь свой профиль Герой.\n\nГайд для игроков Инстинкта: http://telegra.ph/Dobro-pozhalovat-v-Instinkt-11-22" + message += "Приветствую тебя, гость лиги Инстинкт! Для регистрации в Лиге и получения доступа к ее ресурсам и чатам напиши скорее мне, @i2\\_bot, в личку и скинь свою статистику.\n\nГайд для игроков Инстинкта: http://telegra.ph/Dobro-pozhalovat-v-Instinkt-11-22" msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) msg.ParseMode = "Markdown" + keyboard := tgbotapi.InlineKeyboardMarkup{} + var row []tgbotapi.InlineKeyboardButton + btn := tgbotapi.NewInlineKeyboardButtonSwitch("Получить статистику у @PokememBroBot", "Статы") + row = append(row, btn) + keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, row) + + msg.ReplyMarkup = keyboard c.Bot.Send(msg)