From 92fa48882809260a89bfec4ff2262310e9a97cfd Mon Sep 17 00:00:00 2001 From: Vladimir Hodakov Date: Wed, 11 Oct 2017 06:53:50 +0400 Subject: [PATCH] Profiles parsing and saving --- lib/config/config.go | 2 +- lib/dbmappings/leagues.go | 2 +- lib/dbmappings/levels.go | 16 + lib/dbmappings/profiles.go | 2 + lib/dbmappings/profiles_pokememes.go | 18 ++ lib/dbmappings/weapons.go | 17 ++ lib/migrations/10_update_leagues.go | 43 +++ lib/migrations/11_profile_data_additions.go | 84 ++++++ lib/migrations/12_create_profile_relations.go | 36 +++ .../13_create_weapons_and_add_wealth.go | 72 +++++ lib/migrations/migrations.go | 4 + .../parsersinterface/parsersinterface.go | 3 + lib/parsers/profile.go | 282 ++++++++++++++++++ lib/router/router.go | 29 +- lib/talkers/hello.go | 1 + lib/talkers/help.go | 1 + lib/talkers/pokememe_add.go | 2 +- lib/talkers/profile.go | 108 +++++++ lib/talkers/profile_add.go | 31 ++ .../talkersinterface/talkersinterface.go | 3 + 20 files changed, 748 insertions(+), 8 deletions(-) create mode 100644 lib/dbmappings/levels.go create mode 100644 lib/dbmappings/profiles_pokememes.go create mode 100644 lib/dbmappings/weapons.go create mode 100644 lib/migrations/10_update_leagues.go create mode 100644 lib/migrations/11_profile_data_additions.go create mode 100644 lib/migrations/12_create_profile_relations.go create mode 100644 lib/migrations/13_create_weapons_and_add_wealth.go create mode 100644 lib/parsers/profile.go create mode 100644 lib/talkers/profile.go create mode 100644 lib/talkers/profile_add.go diff --git a/lib/config/config.go b/lib/config/config.go index 5d672e4..cbe44b6 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -12,7 +12,7 @@ import ( "gopkg.in/yaml.v2" ) -const VERSION = "0.15" +const VERSION = "0.25" type DatabaseConnection struct { Host string `yaml:"host"` diff --git a/lib/dbmappings/leagues.go b/lib/dbmappings/leagues.go index c959a34..bf4a246 100644 --- a/lib/dbmappings/leagues.go +++ b/lib/dbmappings/leagues.go @@ -11,6 +11,6 @@ import ( type Leagues struct { Id int `db:"id"` Symbol string `db:"symbol"` - Name string `db:"league_id"` + Name string `db:"name"` Created_at *time.Time `db:"created_at"` } diff --git a/lib/dbmappings/levels.go b/lib/dbmappings/levels.go new file mode 100644 index 0000000..cf5a8b1 --- /dev/null +++ b/lib/dbmappings/levels.go @@ -0,0 +1,16 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type Levels struct { + Id int `db:"id"` + Max_exp int `db:"max_exp"` + Max_egg int `db:"max_egg"` + Created_at time.Time `db:"created_at"` +} diff --git a/lib/dbmappings/profiles.go b/lib/dbmappings/profiles.go index f55b7ee..3e5e91d 100644 --- a/lib/dbmappings/profiles.go +++ b/lib/dbmappings/profiles.go @@ -14,6 +14,8 @@ type Profiles struct { Nickname string `db:"nickname"` TelegramNickname string `db:"telegram_nickname"` Level_id int `db:"level_id"` + Pokeballs int `db:"pokeballs"` + Wealth int `db:"wealth"` Exp int `db:"exp"` Egg_exp int `db:"egg_exp"` Power int `db:"power"` diff --git a/lib/dbmappings/profiles_pokememes.go b/lib/dbmappings/profiles_pokememes.go new file mode 100644 index 0000000..6369749 --- /dev/null +++ b/lib/dbmappings/profiles_pokememes.go @@ -0,0 +1,18 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type ProfilesPokememes struct { + Id int `db:"id"` + Profile_id int `db:"profile_id"` + Pokememe_id int `db:"pokememe_id"` + Pokememe_lvl int `db:"pokememe_lvl"` + Pokememe_rarity string `db:"pokememe_rarity"` + Created_at time.Time `db:"created_at"` +} diff --git a/lib/dbmappings/weapons.go b/lib/dbmappings/weapons.go new file mode 100644 index 0000000..e46cb49 --- /dev/null +++ b/lib/dbmappings/weapons.go @@ -0,0 +1,17 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type Weapons struct { + Id int `db:"id"` + Name string `db:"name"` + Power int `db:"power"` + Price int `db:"price"` + Created_at time.Time `db:"created_at"` +} diff --git a/lib/migrations/10_update_leagues.go b/lib/migrations/10_update_leagues.go new file mode 100644 index 0000000..ab26d8c --- /dev/null +++ b/lib/migrations/10_update_leagues.go @@ -0,0 +1,43 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func UpdateLeaguesUp(tx *sql.Tx) error { + _, err := tx.Exec("UPDATE `leagues` SET symbol='🈸' WHERE symbol=':u7533:';") + if err != nil { + return err + } + _, err = tx.Exec("UPDATE `leagues` SET symbol='🈳 ' WHERE symbol=':u6e80';") + if err != nil { + return err + } + _, err = tx.Exec("UPDATE `leagues` SET symbol='🈵' WHERE symbol=':u7a7a:';") + if err != nil { + return err + } + + return nil +} + +func UpdateLeaguesDown(tx *sql.Tx) error { + _, err := tx.Exec("UPDATE `leagues` SET symbol=':u7533:' WHERE symbol='🈸';") + if err != nil { + return err + } + _, err = tx.Exec("UPDATE `leagues` SET symbol=':u6e80' WHERE symbol='🈳 ';") + if err != nil { + return err + } + _, err = tx.Exec("UPDATE `leagues` SET symbol=':u7a7a:' WHERE symbol='🈵';") + if err != nil { + return err + } + + return nil +} diff --git a/lib/migrations/11_profile_data_additions.go b/lib/migrations/11_profile_data_additions.go new file mode 100644 index 0000000..ddaf61b --- /dev/null +++ b/lib/migrations/11_profile_data_additions.go @@ -0,0 +1,84 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func ProfileDataAdditionsUp(tx *sql.Tx) error { + _, err := tx.Exec("ALTER TABLE `profiles` ADD `pokeballs` INT(11) DEFAULT 5 NOT NULL COMMENT 'Покеболы' AFTER `level_id`;") + if err != nil { + return err + } + + create_request := "CREATE TABLE `levels` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID уровня и его номер'," + create_request += "`max_exp` int(11) NOT NULL COMMENT 'Опыт для прохождения уровня'," + create_request += "`max_egg` int(11) NOT NULL COMMENT 'Опыт для открытия яйца'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлен в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `levels_created_at` (`created_at`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Уровни';" + _, err = tx.Exec(create_request) + if err != nil { + return err + } + + // Insert levels + _, err = tx.Exec("INSERT INTO `levels` VALUES(NULL, 200, 6, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `levels` VALUES(NULL, 400, 12, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `levels` VALUES(NULL, 800, 24, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `levels` VALUES(NULL, 1600, 48, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `levels` VALUES(NULL, 3200, 96, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `levels` VALUES(NULL, 6400, 192, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `levels` VALUES(NULL, 12800, 384, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `levels` VALUES(NULL, 25600, 768, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `levels` VALUES(NULL, 51200, 1536, NOW());") + if err != nil { + return err + } + + return nil +} + +func ProfileDataAdditionsDown(tx *sql.Tx) error { + _, err := tx.Exec("ALTER TABLE `profiles` DROP COLUMN `pokeballs`;") + if err != nil { + return err + } + + _, err = tx.Exec("DROP TABLE `levels`;") + if err != nil { + return err + } + + return nil +} diff --git a/lib/migrations/12_create_profile_relations.go b/lib/migrations/12_create_profile_relations.go new file mode 100644 index 0000000..62c72ba --- /dev/null +++ b/lib/migrations/12_create_profile_relations.go @@ -0,0 +1,36 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func CreateProfileRelationsUp(tx *sql.Tx) error { + create_request := "CREATE TABLE `profiles_pokememes` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID связи'," + create_request += "`profile_id` int(11) NOT NULL COMMENT 'ID профиля'," + create_request += "`pokememe_id` int(11) NOT NULL COMMENT 'ID покемема'," + create_request += "`pokememe_lvl` int(11) NOT NULL COMMENT 'Уровень покемема'," + create_request += "`pokememe_rarity` varchar(191) NOT NULL DEFAULT 'common' COMMENT 'Редкость покемема'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлено в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `profiles_pokememes_created_at` (`created_at`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Связь Профили-Покемемы';" + _, err := tx.Exec(create_request) + if err != nil { + return err + } + return nil +} + +func CreateProfileRelationsDown(tx *sql.Tx) error { + _, err := tx.Exec("DROP TABLE `profiles_pokememes`;") + if err != nil { + return err + } + return nil +} diff --git a/lib/migrations/13_create_weapons_and_add_wealth.go b/lib/migrations/13_create_weapons_and_add_wealth.go new file mode 100644 index 0000000..e3227d0 --- /dev/null +++ b/lib/migrations/13_create_weapons_and_add_wealth.go @@ -0,0 +1,72 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func CreateWeaponsAndAddWealthUp(tx *sql.Tx) error { + create_request := "CREATE TABLE `weapons` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID оружия'," + create_request += "`name` varchar(191) NOT NULL COMMENT 'Название оружия'," + create_request += "`power` int(11) NOT NULL COMMENT 'Атака оружия'," + create_request += "`price` int(11) NOT NULL COMMENT 'Цена в магазине'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлено в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `weapons_created_at` (`created_at`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Оружие';" + _, err := tx.Exec(create_request) + if err != nil { + return err + } + + _, err = tx.Exec("INSERT INTO `weapons` VALUES(NULL, 'Бита', 2, 5, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `weapons` VALUES(NULL, 'Стальная бита', 10, 40, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `weapons` VALUES(NULL, 'Чугунная бита ', 200, 500, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `weapons` VALUES(NULL, 'Титановая бита', 2000, 10000, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `weapons` VALUES(NULL, 'Алмазная бита', 10000, 100000, NOW());") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `weapons` VALUES(NULL, 'Криптонитовая бита', 100000, 500000, NOW());") + if err != nil { + return err + } + + _, err = tx.Exec("ALTER TABLE `profiles` ADD COLUMN `wealth` INT(11) NOT NULL COMMENT 'Денег на руках' AFTER `pokeballs`;") + if err != nil { + return err + } + + return nil +} + +func CreateWeaponsAndAddWealthDown(tx *sql.Tx) error { + _, err := tx.Exec("ALTER TABLE `profiles` DROP COLUMN `wealth`;") + if err != nil { + return err + } + + _, err = tx.Exec("DROP TABLE `weapons`;") + if err != nil { + return err + } + + return nil +} diff --git a/lib/migrations/migrations.go b/lib/migrations/migrations.go index 18b7c3d..356f4aa 100644 --- a/lib/migrations/migrations.go +++ b/lib/migrations/migrations.go @@ -24,6 +24,10 @@ func (m *Migrations) Init() { goose.AddNamedMigration("7_create_leagues.go", CreateLeaguesUp, CreateLeaguesDown) goose.AddNamedMigration("8_create_relations.go", CreateRelationsUp, CreateRelationsDown) goose.AddNamedMigration("9_update_locations.go", UpdateLocationsUp, UpdateLocationsDown) + goose.AddNamedMigration("10_update_leagues.go", UpdateLeaguesUp, UpdateLeaguesDown) + goose.AddNamedMigration("11_profile_data_additions.go", ProfileDataAdditionsUp, ProfileDataAdditionsDown) + goose.AddNamedMigration("12_create_profile_relations.go", CreateProfileRelationsUp, CreateProfileRelationsDown) + goose.AddNamedMigration("13_create_weapons_and_add_wealth.go", CreateWeaponsAndAddWealthUp, CreateWeaponsAndAddWealthDown) } func (m *Migrations) Migrate() error { diff --git a/lib/parsers/parsersinterface/parsersinterface.go b/lib/parsers/parsersinterface/parsersinterface.go index 0155f46..c13b1ca 100644 --- a/lib/parsers/parsersinterface/parsersinterface.go +++ b/lib/parsers/parsersinterface/parsersinterface.go @@ -4,6 +4,8 @@ package parsersinterface import ( + // 3rd party + "github.com/go-telegram-bot-api/telegram-bot-api" // local "../../dbmappings" ) @@ -11,5 +13,6 @@ import ( type ParsersInterface interface { ParsePokememe(text string, player_raw dbmappings.Players) string + ParseProfile(update tgbotapi.Update, player_raw dbmappings.Players) string ReturnPoints(points int) string } diff --git a/lib/parsers/profile.go b/lib/parsers/profile.go new file mode 100644 index 0000000..c615d33 --- /dev/null +++ b/lib/parsers/profile.go @@ -0,0 +1,282 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package parsers + +import ( + // stdlib + "log" + "regexp" + "strings" + "strconv" + "time" + // 3rd party + "github.com/go-telegram-bot-api/telegram-bot-api" + // local + "../dbmappings" +) + +// Internal functions + +func (p *Parsers) fillProfilePokememe(profile_id int, meme string, attack string, rarity string) { + spk_raw := dbmappings.Pokememes{} + err := c.Db.Get(&spk_raw, c.Db.Rebind("SELECT * FROM pokememes WHERE name='" + meme + "';")) + if err != nil { + log.Println(err) + } else { + attack_int := p.getPoints(attack) + // Improve it. Game's precision is unstable + orig_attack := float64(spk_raw.Attack) + if rarity == "rare" { + orig_attack = orig_attack * 1.1 + } + level := int(float64(attack_int) / orig_attack) + + ppk := dbmappings.ProfilesPokememes{} + ppk.Profile_id = profile_id + ppk.Pokememe_id = spk_raw.Id + ppk.Pokememe_lvl = level + ppk.Pokememe_rarity = rarity + ppk.Created_at = time.Now().UTC() + _, err2 := c.Db.NamedExec("INSERT INTO `profiles_pokememes` VALUES(NULL, :profile_id, :pokememe_id, :pokememe_lvl, :pokememe_rarity, :created_at)", &ppk) + if err2 != nil { + log.Println(err2) + } + } +} + +// External functions + +func (p *Parsers) ParseProfile(update tgbotapi.Update, player_raw dbmappings.Players) string { + text := update.Message.Text + log.Println(text) + + profile_info_strings := strings.Split(text, "\n") + profile_info_runed_strings := make([][]rune, 0) + for i := range(profile_info_strings) { + profile_info_runed_strings = append(profile_info_runed_strings, []rune(profile_info_strings[i])) + } + + league := dbmappings.Leagues{} + + telegram_nickname := update.Message.From.UserName + nickname := "" + level := "" + level_int := 0 + exp := "" + exp_int := 0 + egg_exp := "" + egg_exp_int := 0 + pokeballs := "" + pokeballs_int := 0 + wealth := "" + wealth_int := 0 + crystalls := "" + crystalls_int := 0 + weapon := "" + pokememes := make(map[string]string) + power_int := 1 + + // Filling information + // We don't know how many strings we got, so we iterating each other + for i := range(profile_info_runed_strings) { + current_string := string(profile_info_runed_strings[i]) + current_runes := profile_info_runed_strings[i] + if strings.HasPrefix(current_string, "🈸") || strings.HasPrefix(current_string, "🈳 ") || strings.HasPrefix(current_string, "🈵") { + err1 := c.Db.Get(&league, c.Db.Rebind("SELECT * FROM leagues WHERE symbol='" + string(current_runes[0]) + "'")) + if err1 != nil { + log.Println(err1) + return "fail" + } + for j := range(current_runes) { + if j > 2 { + nickname += string(current_runes[j]) + } + } + } + if strings.HasPrefix(current_string, "👤Уровень:") { + levelRx := regexp.MustCompile("\\d+") + level_array := levelRx.FindAllString(current_string, -1) + if len(level_array) < 1 { + log.Println("Level string broken") + return "fail" + } + level = level_array[0] + level_int, _ = strconv.Atoi(level) + } + + if strings.HasPrefix(current_string, "🎓Опыт") { + expRx := regexp.MustCompile("\\d+") + exp_array := expRx.FindAllString(current_string, -1) + if len(exp_array) < 4 { + log.Println("Exp string broken") + return "fail" + } + exp = exp_array[0] + exp_int, _ = strconv.Atoi(exp) + egg_exp = exp_array[2] + egg_exp_int, _ = strconv.Atoi(egg_exp) + } + + if strings.HasPrefix(current_string, "⭕Покеболы") { + pkbRx := regexp.MustCompile("\\d+") + pkb_array := pkbRx.FindAllString(current_string, -1) + if len(pkb_array) < 2 { + log.Println("Pokeballs string broken") + return "fail" + } + pokeballs = pkb_array[1] + pokeballs_int, _ = strconv.Atoi(pokeballs) + } + + if strings.HasPrefix(current_string, "💲") { + wealthRx := regexp.MustCompile("(\\d|\\.|K|M)+") + wealth_array := wealthRx.FindAllString(current_string, -1) + if len(wealth_array) < 2 { + log.Println("Wealth string broken") + return "fail" + } + wealth = wealth_array[0] + wealth_int = p.getPoints(wealth) + crystalls =wealth_array[1] + crystalls_int = p.getPoints(crystalls) + } + + if strings.HasPrefix(current_string, "🔫Оружие") { + // We need NEXT string! + weapon_type_string := string(profile_info_runed_strings[i + 1]) + wnRx := regexp.MustCompile("(.+)(ита)") + weapon = wnRx.FindString(weapon_type_string) + } + + if strings.HasPrefix(current_string, "🐱Покемемы: ") { + pkmnumRx := regexp.MustCompile("\\d+") + pk_num_array := pkmnumRx.FindAllString(current_string, -1) + if len(pk_num_array) < 2 { + log.Println("Pokememes count broken") + return "fail" + } + pokememes_count, _ := strconv.Atoi(pk_num_array[0]) + if pokememes_count > 0 { + for pi := 0; pi < pokememes_count; pi++ { + pokememe_string := string(profile_info_runed_strings[i + 1 + pi]) + attackRx := regexp.MustCompile("(\\d|\\.|K|M)+") + pk_points_array := attackRx.FindAllString(pokememe_string, -1) + pk_attack := pk_points_array[1] + pk_name := strings.Split(pokememe_string, "+")[0] + pk_name = strings.Replace(pk_name, " ⭐", "", 1) + pk_name = strings.TrimSuffix(pk_name, " ") + pk_name = strings.Split(pk_name, "⃣ ")[1] + pokememes[pk_name] = pk_attack + power_int += p.getPoints(pk_attack) + } + } + } + } + + log.Printf("Telegram nickname: " + telegram_nickname) + log.Printf("Nickname: " + nickname) + log.Printf("League: " + league.Name) + log.Printf("Level: " + level) + log.Println(level_int) + log.Printf("Exp: " + exp) + log.Println(exp_int) + log.Printf("Egg exp: " + egg_exp) + log.Println(egg_exp_int) + log.Printf("Pokeballs: " + pokeballs) + log.Println(pokeballs_int) + log.Printf("Wealth: " + wealth) + log.Println(wealth_int) + log.Printf("Crystalls: " + crystalls) + log.Println(crystalls_int) + log.Printf("Weapon: " + weapon) + if len(pokememes) > 0 { + for meme, attack := range(pokememes) { + log.Printf(meme + ": " + attack) + } + } else { + log.Printf("Hand is empty.") + } + + // Information is gathered, let's create profile in database! + weapon_raw := dbmappings.Weapons{} + err2 := c.Db.Get(&weapon_raw, c.Db.Rebind("SELECT * FROM weapons WHERE name='" + weapon + "'")) + if err2 != nil { + log.Println(err2) + } + + if player_raw.League_id == 0 { + // Updating player with league + player_raw.League_id = league.Id + if player_raw.Status == "nobody" { + player_raw.Status = "common" + } + _, err4 := c.Db.NamedExec("UPDATE `players` SET league_id=:league_id, status=:status WHERE id=:id", &player_raw) + if err4 != nil { + log.Println(err4) + return "fail" + } + } else if player_raw.League_id != league.Id { + // Duplicate profile: user changed league, beware! + player_raw.League_id = league.Id + player_raw.Squad_id = 0 + player_raw.Status = "league_changed" + player_raw.Created_at = time.Now().UTC() + _, err5 := c.Db.NamedExec("INSERT INTO players VALUES(NULL, :telegram_id, :league_id, :squad_id, :status, :created_at, :updated_at)", &player_raw) + if err5 != nil { + log.Println(err5) + return "fail" + } + err6 := c.Db.Get(&player_raw, c.Db.Rebind("SELECT * FROM players WHERE telegram_id='" + strconv.Itoa(player_raw.Telegram_id) + "' AND league_id='" + strconv.Itoa(league.Id) + "';")) + if err6 != nil { + log.Println(err6) + return "fail" + } + } + + profile_raw := dbmappings.Profiles{} + profile_raw.Player_id = player_raw.Id + profile_raw.Nickname = nickname + profile_raw.TelegramNickname = telegram_nickname + profile_raw.Level_id = level_int + profile_raw.Pokeballs = pokeballs_int + profile_raw.Wealth = wealth_int + profile_raw.Exp = exp_int + profile_raw.Egg_exp = egg_exp_int + profile_raw.Power = power_int + profile_raw.Weapon_id = weapon_raw.Id + profile_raw.Crystalls = crystalls_int + profile_raw.Created_at = time.Now().UTC() + + _, err3 := c.Db.NamedExec("INSERT INTO `profiles` VALUES(NULL, :player_id, :nickname, :telegram_nickname, :level_id, :pokeballs, :wealth, :exp, :egg_exp, :power, :weapon_id, :crystalls, :created_at)", &profile_raw) + if err3 != nil { + log.Println(err3) + return "fail" + } + + err8 := c.Db.Get(&profile_raw, c.Db.Rebind("SELECT * FROM profiles WHERE player_id=? AND created_at=?"), profile_raw.Player_id, profile_raw.Created_at) + if err8 != nil { + log.Println(err8) + log.Printf("Profile isn't added!") + return "fail" + } + + player_raw.Updated_at = time.Now().UTC() + _, err7 := c.Db.NamedExec("UPDATE `players` SET updated_at=:updated_at WHERE id=:id", &player_raw) + if err7 != nil { + log.Println(err7) + return "fail" + } + + + for meme, attack := range(pokememes) { + rarity := "common" + if strings.HasPrefix(meme, "🔸") { + rarity = "rare" + meme = strings.Replace(meme, "🔸", "", 1) + } + p.fillProfilePokememe(profile_raw.Id, meme, attack, rarity) + } + + return "ok" +} diff --git a/lib/router/router.go b/lib/router/router.go index a50f2b0..e91d21f 100644 --- a/lib/router/router.go +++ b/lib/router/router.go @@ -61,17 +61,20 @@ func (r *Router) RouteRequest(update tgbotapi.Update) string { var helloMsg = regexp.MustCompile("/start\\z") var pokedexMsg = regexp.MustCompile("/pokede(x|ks)\\d?\\z") var pokememeInfoMsg = regexp.MustCompile("/pk(\\d+)") + var meMsg = regexp.MustCompile("/me\\z") // Forwards var pokememeMsg = regexp.MustCompile("(Уровень)(.+)(Опыт)(.+)\n(Элементы:)(.+)\n(.+)(💙MP)") + var profileMsg = regexp.MustCompile("(Онлайн: )(\\d+)\n(Турнир Лиг через)(.+)\n\n(.*)\n(Элементы)(.+)\n\n(.+)(Уровень)(.+)\n") if update.Message.ForwardFrom != nil { if update.Message.ForwardFrom.ID != 360402625 { log.Printf("Forward from another user or bot. Ignoring") } else { log.Printf("Forward from PokememBro bot! Processing...") - if pokememeMsg.MatchString(text) { - if player_raw.Id != 0 { + if player_raw.Id != 0 { + switch { + case pokememeMsg.MatchString(text): log.Printf("Pokememe posted!") status := c.Parsers.ParsePokememe(text, player_raw) switch status { @@ -82,11 +85,20 @@ func (r *Router) RouteRequest(update tgbotapi.Update) string { case "fail": c.Talkers.PokememeAddFailureMessage(update) } - } else { - c.Talkers.AnyMessageUnauthorized(update) + case profileMsg.MatchString(text): + log.Printf("Profile posted!") + status := c.Parsers.ParseProfile(update, player_raw) + switch status { + case "ok": + c.Talkers.ProfileAddSuccessMessage(update) + case "fail": + c.Talkers.ProfileAddFailureMessage(update) + } + default: + log.Printf(text) } } else { - log.Printf(text) + c.Talkers.AnyMessageUnauthorized(update) } } } else { @@ -118,6 +130,13 @@ func (r *Router) RouteRequest(update tgbotapi.Update) string { } case pokememeInfoMsg.MatchString(text): c.Talkers.PokememeInfo(update) + // Profile info + case meMsg.MatchString(text): + if player_raw.Id != 0 { + c.Talkers.ProfileMessage(update, player_raw) + } else { + c.Talkers.AnyMessageUnauthorized(update) + } // Easter eggs case huMsg.MatchString(text): c.Talkers.MatMessage(update) diff --git a/lib/talkers/hello.go b/lib/talkers/hello.go index 2a14f5e..a8bc8b6 100644 --- a/lib/talkers/hello.go +++ b/lib/talkers/hello.go @@ -25,6 +25,7 @@ func (t *Talkers) HelloMessageAuthorized(update tgbotapi.Update, player_raw dbma hello_message := "*Бот Инстинкта приветствует тебя. Снова.*\n\n" hello_message += "Привет, " + update.Message.From.FirstName + " " + update.Message.From.LastName + "!\n" hello_message += "Последнее обновление информации о тебе: " + player_raw.Updated_at.Format("02.01.2006 15:04:05 -0700") + hello_message += "\nПосмотреть информацию о себе: /me" msg := tgbotapi.NewMessage(update.Message.Chat.ID, hello_message) msg.ParseMode = "Markdown" diff --git a/lib/talkers/help.go b/lib/talkers/help.go index 2954079..bf065ad 100644 --- a/lib/talkers/help.go +++ b/lib/talkers/help.go @@ -14,6 +14,7 @@ func (t *Talkers) HelpMessage(update tgbotapi.Update) { help_message := "*Бот Инстинкта Enchanched.*\n\n" help_message += "Текущая версия: *" + config.VERSION + "*\n\n" help_message += "Список команд:\n\n" + help_message += "+ /me – посмотреть свой сохраненный профиль в боте\n" help_message += "+ /pokedex – получить список известных боту покемемов\n" help_message += "+ /help – выводит данное сообщение\n" help_message += "\n\n" diff --git a/lib/talkers/pokememe_add.go b/lib/talkers/pokememe_add.go index 8188931..493331b 100644 --- a/lib/talkers/pokememe_add.go +++ b/lib/talkers/pokememe_add.go @@ -31,7 +31,7 @@ func (t *Talkers) PokememeAddDuplicateMessage(update tgbotapi.Update) { func (t *Talkers) PokememeAddFailureMessage(update tgbotapi.Update) { message := "*Неудачно получилось :(*\n\n" - message += "Случилась жуткая ошибка, и мы не смогли записать бота в базу. Напиши @fat0troll, он разбер]тся.\n\n" + message += "Случилась жуткая ошибка, и мы не смогли записать покемема в базу. Напиши @fat0troll, он разберется.\n\n" message += "Посмотреть всех известных боту покемемов можно командой /pokedeks" msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) diff --git a/lib/talkers/profile.go b/lib/talkers/profile.go new file mode 100644 index 0000000..39e5321 --- /dev/null +++ b/lib/talkers/profile.go @@ -0,0 +1,108 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package talkers + +import ( + // stdlib + "log" + "strconv" + // 3rd party + "github.com/go-telegram-bot-api/telegram-bot-api" + // local + "../dbmappings" +) + +func (t *Talkers) ProfileMessage(update tgbotapi.Update, player_raw dbmappings.Players) string { + profile_raw := dbmappings.Profiles{} + err := c.Db.Get(&profile_raw, c.Db.Rebind("SELECT * FROM profiles WHERE player_id=? ORDER BY created_at DESC LIMIT 1"), player_raw.Id) + if err != nil { + log.Println(err) + c.Talkers.AnyMessageUnauthorized(update) + return "fail" + } + league := dbmappings.Leagues{} + err = c.Db.Get(&league, c.Db.Rebind("SELECT * FROM leagues WHERE id=?"), player_raw.League_id) + if err != nil { + log.Println(err) + } + level := dbmappings.Levels{} + err = c.Db.Get(&level, c.Db.Rebind("SELECT * FROM levels WHERE id=?"), profile_raw.Level_id) + if err != nil { + log.Println(err) + } + weapon := dbmappings.Weapons{} + if profile_raw.Weapon_id != 0 { + err = c.Db.Get(&weapon, c.Db.Rebind("SELECT * FROM weapons WHERE id=?"), profile_raw.Weapon_id) + if err != nil { + log.Println(err) + } + } + p_pk := []dbmappings.ProfilesPokememes{} + err = c.Db.Select(&p_pk, c.Db.Rebind("SELECT * FROM profiles_pokememes WHERE profile_id=?"), profile_raw.Id) + if err != nil { + log.Println(err) + } + pokememes := []dbmappings.Pokememes{} + err = c.Db.Select(&pokememes, c.Db.Rebind("SELECT * FROM pokememes")) + if err != nil { + log.Println(err) + } + + attack_pm := 0 + for i := range(p_pk) { + for j := range(pokememes) { + if p_pk[i].Pokememe_id == pokememes[j].Id { + single_attack := float64(pokememes[j].Attack) + single_attack = single_attack * float64(p_pk[i].Pokememe_lvl) + if p_pk[i].Pokememe_rarity == "rare" { + single_attack = single_attack * 1.15 + } + attack_pm += int(single_attack) + } + } + } + + + message := "*Профиль игрока " + message += profile_raw.Nickname + "* (@" + profile_raw.TelegramNickname + ")\n" + message += "\nЛига: " + league.Symbol + league.Name + message += "\n👤 " + strconv.Itoa(profile_raw.Level_id) + message += " | 🎓 " + strconv.Itoa(profile_raw.Exp) + "/" + strconv.Itoa(level.Max_exp) + message += " | 🥚 " + strconv.Itoa(profile_raw.Egg_exp) + "/" + strconv.Itoa(level.Max_egg) + message += "\n💲" + c.Parsers.ReturnPoints(profile_raw.Wealth) + message += " |💎" + strconv.Itoa(profile_raw.Crystalls) + message += " |⭕" + strconv.Itoa(profile_raw.Pokeballs) + message += "\n⚔Атака: 1 + " + c.Parsers.ReturnPoints(weapon.Power) + " + " + c.Parsers.ReturnPoints(attack_pm) + "\n" + + if profile_raw.Weapon_id != 0 { + message += "\n🔫Оружие: " + weapon.Name + " " + c.Parsers.ReturnPoints(weapon.Power) + "⚔" + } + + message += "\n🐱Покемемы:" + for i := range(p_pk) { + for j := range(pokememes) { + if p_pk[i].Pokememe_id == pokememes[j].Id { + single_attack := float64(pokememes[j].Attack) + single_attack = single_attack * float64(p_pk[i].Pokememe_lvl) + if p_pk[i].Pokememe_rarity == "rare" { + single_attack = single_attack * 1.15 + } + + message += "\n" + strconv.Itoa(pokememes[j].Grade) + message += "⃣ " + pokememes[j].Name + message += " +" + c.Parsers.ReturnPoints(int(single_attack)) + "⚔" + } + } + } + message += "\n\n💳" + strconv.Itoa(player_raw.Telegram_id) + message += "\n⏰Последнее обновление профиля: " + profile_raw.Created_at.Format("02.01.2006 15:04:05") + message += "\n\nНе забывай обновляться, это важно для получения актуальной информации." + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) + + return "ok" +} diff --git a/lib/talkers/profile_add.go b/lib/talkers/profile_add.go new file mode 100644 index 0000000..fe1191e --- /dev/null +++ b/lib/talkers/profile_add.go @@ -0,0 +1,31 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package talkers + +import ( + // 3rd party + "github.com/go-telegram-bot-api/telegram-bot-api" +) + +func (t *Talkers) ProfileAddSuccessMessage(update tgbotapi.Update) { + message := "*Профиль успешно обновлен.*\n\n" + message += "Функциональность бота держится на актуальности профилей. Обновляйся почаще, и да пребудет с тобой Рандом!\n" + message += "Сохраненный профиль ты можешь просмотреть командой /me.\n\n" + message += "– почаще – как мощно чаще, но не более 48 раз в сутки." + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) +} + +func (t *Talkers) ProfileAddFailureMessage(update tgbotapi.Update) { + message := "*Неудачно получилось :(*\n\n" + message += "Случилась жуткая ошибка, и мы не смогли записать профиль в базу. Напиши @fat0troll, он разберется." + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) +} diff --git a/lib/talkers/talkersinterface/talkersinterface.go b/lib/talkers/talkersinterface/talkersinterface.go index c7f2b29..77c99cb 100644 --- a/lib/talkers/talkersinterface/talkersinterface.go +++ b/lib/talkers/talkersinterface/talkersinterface.go @@ -23,6 +23,9 @@ type TalkersInterface interface { PokememeAddSuccessMessage(update tgbotapi.Update) PokememeAddDuplicateMessage(update tgbotapi.Update) PokememeAddFailureMessage(update tgbotapi.Update) + ProfileAddSuccessMessage(update tgbotapi.Update) + ProfileAddFailureMessage(update tgbotapi.Update) + ProfileMessage(update tgbotapi.Update, player_raw dbmappings.Players) string // Errors AnyMessageUnauthorized(update tgbotapi.Update)