Add pokememes info, convert it to new format and drop unnecessary database tables
This commit introduces pokememes information storage in source code (because they're rarely changed and I always update them manually). All information about pokememes updated after nerf of 25 April. Also, added buttons to /pokedeks command for changing pages (there are 21 pages already!), and limited one page to 35 pokememes.
This commit is contained in:
@@ -45,18 +45,21 @@ type DataCacheInterface interface {
|
||||
GetProfileByID(profileID int) (*dbmapping.Profile, error)
|
||||
GetProfileByPlayerID(playerID int) (*dbmapping.Profile, error)
|
||||
|
||||
AddPokememe(pokememeData map[string]string, pokememeLocations map[string]string, pokememeElements map[string]string) (int, error)
|
||||
GetAllPokememes() map[int]*dbmapping.PokememeFull
|
||||
GetPokememeByID(pokememeID int) (*dbmapping.PokememeFull, error)
|
||||
GetPokememeByName(name string) (*dbmapping.PokememeFull, error)
|
||||
DeletePokememeByID(pokememeID int) error
|
||||
UpdatePokememe(pokememeData map[string]string, pokememeLocations map[string]string, pokememeElements map[string]string) (int, error)
|
||||
|
||||
GetElementByID(elementID int) (*datamapping.Element, error)
|
||||
FindElementIDBySymbol(symbol string) (int, error)
|
||||
|
||||
GetLeagueByID(leagueID int) (*datamapping.League, error)
|
||||
GetLeagueBySymbol(symbol string) (*datamapping.League, error)
|
||||
|
||||
GetLevelByID(levelID int) (*datamapping.Level, error)
|
||||
|
||||
FindLocationIDByName(name string) (int, error)
|
||||
|
||||
GetAllPokememes() map[int]*datamapping.PokememeFull
|
||||
GetPokememeByID(pokememeID int) (*datamapping.PokememeFull, error)
|
||||
GetPokememeByName(name string) (*datamapping.PokememeFull, error)
|
||||
GetPokememesCountByGradeAndLocation(grade int, locationID int) int
|
||||
|
||||
GetWeaponTypeByID(weaponID int) (*datamapping.Weapon, error)
|
||||
GetWeaponTypeByName(name string) (*datamapping.Weapon, error)
|
||||
}
|
||||
|
@@ -44,16 +44,6 @@ func (dc *DataCache) getElements() []datamapping.Element {
|
||||
return elements
|
||||
}
|
||||
|
||||
func (dc *DataCache) findElementIDBySymbol(symbol string) (int, error) {
|
||||
for i := range dc.elements {
|
||||
if dc.elements[i].Symbol == symbol {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, errors.New("There is no element with symbol = " + symbol)
|
||||
}
|
||||
|
||||
// External functions
|
||||
|
||||
// GetElementByID returns element with given ID
|
||||
@@ -64,3 +54,14 @@ func (dc *DataCache) GetElementByID(elementID int) (*datamapping.Element, error)
|
||||
|
||||
return nil, errors.New("There is no element with ID = " + strconv.Itoa(elementID))
|
||||
}
|
||||
|
||||
// FindElementIDBySymbol returns element ID for given symbol
|
||||
func (dc *DataCache) FindElementIDBySymbol(symbol string) (int, error) {
|
||||
for i := range dc.elements {
|
||||
if dc.elements[i].Symbol == symbol {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, errors.New("There is no element with symbol = " + symbol)
|
||||
}
|
||||
|
@@ -28,12 +28,6 @@ type DataCache struct {
|
||||
// Note: int in this array for player ID, not for profile ID
|
||||
currentProfiles map[int]*dbmapping.Profile
|
||||
currentProfilesMutex sync.Mutex
|
||||
// Pokememes
|
||||
pokememes map[int]*dbmapping.Pokememe
|
||||
pokememesMutex sync.Mutex
|
||||
// Pokememes with all supported data
|
||||
fullPokememes map[int]*dbmapping.PokememeFull
|
||||
fullPokememesMutex sync.Mutex
|
||||
|
||||
// Chats
|
||||
chats map[int]*dbmapping.Chat
|
||||
@@ -45,13 +39,19 @@ type DataCache struct {
|
||||
squadPlayers map[int]map[int]*dbmapping.SquadPlayerFull
|
||||
squadsMutex sync.Mutex
|
||||
|
||||
// Non-database data
|
||||
// Rarely changing data
|
||||
// Elements
|
||||
elements map[int]*datamapping.Element
|
||||
// Leagues
|
||||
leagues map[int]*datamapping.League
|
||||
// Levels
|
||||
levels map[int]*datamapping.Level
|
||||
// Locations
|
||||
locations map[int]*datamapping.Location
|
||||
// Pokememes
|
||||
pokememes map[int]*datamapping.Pokememe
|
||||
fullPokememes map[int]*datamapping.PokememeFull
|
||||
pokememesGradeLocation map[int]map[int]int
|
||||
// Weapons
|
||||
weapons map[int]*datamapping.Weapon
|
||||
}
|
||||
@@ -75,6 +75,8 @@ func (dc *DataCache) Init() {
|
||||
dc.loadLocations()
|
||||
dc.initWeapons()
|
||||
dc.loadWeapons()
|
||||
dc.initLevels()
|
||||
dc.loadLevels()
|
||||
dc.initPokememes()
|
||||
dc.loadPokememes()
|
||||
dc.initPlayers()
|
||||
|
56
lib/datacache/levels.go
Normal file
56
lib/datacache/levels.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2018 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package datacache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gopkg.in/yaml.v2"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/datamapping"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/static"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (dc *DataCache) initLevels() {
|
||||
c.Log.Info("Initializing Levels storage...")
|
||||
dc.levels = make(map[int]*datamapping.Level)
|
||||
}
|
||||
|
||||
func (dc *DataCache) loadLevels() {
|
||||
c.Log.Info("Load current Levels data to DataCache...")
|
||||
levels := dc.getLevels()
|
||||
|
||||
for i := range levels {
|
||||
dc.levels[levels[i].ID] = &levels[i]
|
||||
}
|
||||
c.Log.Info("Loaded levels in DataCache: " + strconv.Itoa(len(dc.levels)))
|
||||
}
|
||||
|
||||
func (dc *DataCache) getLevels() []datamapping.Level {
|
||||
levels := []datamapping.Level{}
|
||||
|
||||
yamlFile, err := static.ReadFile("levels.yml")
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
c.Log.Fatal("Can't read levels data file")
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(yamlFile, &levels)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
c.Log.Fatal("Can't parse levels data file")
|
||||
}
|
||||
|
||||
return levels
|
||||
}
|
||||
|
||||
// External functions
|
||||
|
||||
// GetLevelByID returns level data by ID
|
||||
func (dc *DataCache) GetLevelByID(levelID int) (*datamapping.Level, error) {
|
||||
if dc.levels[levelID] != nil {
|
||||
return dc.levels[levelID], nil
|
||||
}
|
||||
|
||||
return nil, errors.New("There is no level with ID = " + strconv.Itoa(levelID))
|
||||
}
|
@@ -44,7 +44,18 @@ func (dc *DataCache) getLocations() []datamapping.Location {
|
||||
return locations
|
||||
}
|
||||
|
||||
func (dc *DataCache) findLocationIDByName(name string) (int, error) {
|
||||
func (dc *DataCache) getLocationByID(locationID int) (*datamapping.Location, error) {
|
||||
if dc.locations[locationID] != nil {
|
||||
return dc.locations[locationID], nil
|
||||
}
|
||||
|
||||
return nil, errors.New("There is no localtion with ID = " + strconv.Itoa(locationID))
|
||||
}
|
||||
|
||||
// External functions
|
||||
|
||||
// FindLocationIDByName returns location ID for given location name
|
||||
func (dc *DataCache) FindLocationIDByName(name string) (int, error) {
|
||||
for i := range dc.locations {
|
||||
if dc.locations[i].Name == name {
|
||||
return i, nil
|
||||
|
@@ -5,445 +5,133 @@ package datacache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"gopkg.in/yaml.v2"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/datamapping"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/static"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (dc *DataCache) initPokememes() {
|
||||
c.Log.Info("Initializing Pokememes storage...")
|
||||
dc.pokememes = make(map[int]*dbmapping.Pokememe)
|
||||
dc.fullPokememes = make(map[int]*dbmapping.PokememeFull)
|
||||
dc.pokememes = make(map[int]*datamapping.Pokememe)
|
||||
dc.fullPokememes = make(map[int]*datamapping.PokememeFull)
|
||||
dc.pokememesGradeLocation = make(map[int]map[int]int)
|
||||
}
|
||||
|
||||
func (dc *DataCache) loadPokememes() {
|
||||
c.Log.Info("Load current Pokememes data from database to DataCache...")
|
||||
pokememes := []dbmapping.Pokememe{}
|
||||
err := c.Db.Select(&pokememes, "SELECT * FROM pokememes WHERE is_active=1")
|
||||
if err != nil {
|
||||
// This is critical error and we need to stop immediately!
|
||||
c.Log.Fatal(err.Error())
|
||||
}
|
||||
pokememesElements := []dbmapping.PokememeElement{}
|
||||
err = c.Db.Select(&pokememesElements, "SELECT * FROM pokememes_elements")
|
||||
if err != nil {
|
||||
// This is critical error and we need to stop immediately!
|
||||
c.Log.Fatal(err)
|
||||
}
|
||||
pokememesLocations := []dbmapping.PokememeLocation{}
|
||||
err = c.Db.Select(&pokememesLocations, "SELECT * FROM pokememes_locations")
|
||||
if err != nil {
|
||||
// This is critical error and we need to stop immediately!
|
||||
c.Log.Fatal(err)
|
||||
}
|
||||
c.Log.Info("Load current Pokememes data to DataCache...")
|
||||
|
||||
pokememes := dc.getPokememes()
|
||||
|
||||
dc.pokememesMutex.Lock()
|
||||
dc.fullPokememesMutex.Lock()
|
||||
for i := range pokememes {
|
||||
c.Log.Debug("Loading pokememe with name: " + pokememes[i].Name)
|
||||
dc.pokememes[pokememes[i].ID] = &pokememes[i]
|
||||
|
||||
// Filling fullPokememes
|
||||
fullPokememe := dbmapping.PokememeFull{}
|
||||
elementsListed := []datamapping.Element{}
|
||||
locationsListed := []datamapping.Location{}
|
||||
|
||||
for j := range pokememesLocations {
|
||||
if pokememesLocations[j].PokememeID == pokememes[i].ID {
|
||||
for l := range dc.locations {
|
||||
if pokememesLocations[j].LocationID == dc.locations[l].ID {
|
||||
locationsListed = append(locationsListed, *dc.locations[l])
|
||||
}
|
||||
}
|
||||
}
|
||||
if dc.pokememesGradeLocation[pokememes[i].Grade] == nil {
|
||||
dc.pokememesGradeLocation[pokememes[i].Grade] = make(map[int]int)
|
||||
}
|
||||
|
||||
for k := range pokememesElements {
|
||||
if pokememesElements[k].PokememeID == pokememes[i].ID {
|
||||
for e := range dc.elements {
|
||||
if pokememesElements[k].ElementID == dc.elements[e].ID {
|
||||
elementsListed = append(elementsListed, *dc.elements[e])
|
||||
}
|
||||
}
|
||||
pokememeFull := datamapping.PokememeFull{}
|
||||
pokememeFullElements := []datamapping.Element{}
|
||||
pokememeFullLocations := []datamapping.Location{}
|
||||
pokememeFull.Pokememe = pokememes[i]
|
||||
for ii := range pokememes[i].Elements {
|
||||
element, err := dc.GetElementByID(pokememes[i].Elements[ii])
|
||||
if err != nil {
|
||||
// This is critical
|
||||
c.Log.Fatal(err.Error())
|
||||
}
|
||||
pokememeFullElements = append(pokememeFullElements, *element)
|
||||
}
|
||||
for ii := range pokememes[i].Locations {
|
||||
location, err := dc.getLocationByID(pokememes[i].Locations[ii])
|
||||
if err != nil {
|
||||
// This is critical
|
||||
c.Log.Fatal(err.Error())
|
||||
}
|
||||
pokememeFullLocations = append(pokememeFullLocations, *location)
|
||||
dc.pokememesGradeLocation[pokememes[i].Grade][location.ID]++
|
||||
}
|
||||
|
||||
fullPokememe.Pokememe = pokememes[i]
|
||||
fullPokememe.Elements = elementsListed
|
||||
fullPokememe.Locations = locationsListed
|
||||
|
||||
dc.fullPokememes[pokememes[i].ID] = &fullPokememe
|
||||
pokememeFull.Elements = pokememeFullElements
|
||||
pokememeFull.Locations = pokememeFullLocations
|
||||
dc.fullPokememes[pokememes[i].ID] = &pokememeFull
|
||||
}
|
||||
c.Log.Info("Loaded pokememes with all additional information in DataCache: " + strconv.Itoa(len(dc.fullPokememes)))
|
||||
dc.pokememesMutex.Unlock()
|
||||
dc.fullPokememesMutex.Unlock()
|
||||
|
||||
c.Log.Info("Loaded pokememes in DataCache: " + strconv.Itoa(len(dc.fullPokememes)))
|
||||
}
|
||||
|
||||
func (dc *DataCache) getPokememes() []datamapping.Pokememe {
|
||||
pokememes := []datamapping.Pokememe{}
|
||||
|
||||
allPokememesFiles, err := static.WalkDirs("pokememes", false)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
c.Log.Fatal("Can't read directory with pokememes information")
|
||||
}
|
||||
|
||||
var pokememesData []byte
|
||||
|
||||
for i := range allPokememesFiles {
|
||||
yamlFile, err := static.ReadFile(allPokememesFiles[i])
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
c.Log.Fatal("Can't read pokememes data file: " + allPokememesFiles[i])
|
||||
}
|
||||
|
||||
for ii := range yamlFile {
|
||||
pokememesData = append(pokememesData, yamlFile[ii])
|
||||
}
|
||||
pokememesData = append(pokememesData, '\n')
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(pokememesData, &pokememes)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
c.Log.Fatal("Can't parse merged pokememes data")
|
||||
}
|
||||
|
||||
return pokememes
|
||||
}
|
||||
|
||||
// External functions
|
||||
|
||||
// AddPokememe adds pokememe from parser
|
||||
func (dc *DataCache) AddPokememe(pokememeData map[string]string, pokememeLocations map[string]string, pokememeElements map[string]string) (int, error) {
|
||||
_, noerr := dc.GetPokememeByName(pokememeData["name"])
|
||||
if noerr == nil {
|
||||
return 0, errors.New("This pokememe already exists")
|
||||
}
|
||||
|
||||
gradeInt := c.Statistics.GetPoints(pokememeData["grade"])
|
||||
attackInt := c.Statistics.GetPoints(pokememeData["attack"])
|
||||
hpInt := c.Statistics.GetPoints(pokememeData["hp"])
|
||||
mpInt := c.Statistics.GetPoints(pokememeData["mp"])
|
||||
defenceInt := attackInt
|
||||
if pokememeData["defence"] != "" {
|
||||
defenceInt = c.Statistics.GetPoints(pokememeData["defence"])
|
||||
}
|
||||
priceInt := c.Statistics.GetPoints(pokememeData["price"])
|
||||
creatorID := c.Statistics.GetPoints(pokememeData["creator_id"])
|
||||
|
||||
if !(gradeInt != 0 && attackInt != 0 && hpInt != 0 && mpInt != 0 && defenceInt != 0 && priceInt != 0 && creatorID != 0) {
|
||||
return 0, errors.New("Some of the required numerical values are empty")
|
||||
}
|
||||
|
||||
pokememe := dbmapping.Pokememe{}
|
||||
pokememe.Grade = gradeInt
|
||||
pokememe.Name = pokememeData["name"]
|
||||
pokememe.Description = pokememeData["description"]
|
||||
pokememe.Attack = attackInt
|
||||
pokememe.HP = hpInt
|
||||
pokememe.MP = mpInt
|
||||
pokememe.Defence = defenceInt
|
||||
pokememe.Price = priceInt
|
||||
if pokememeData["purchaseable"] == "true" {
|
||||
pokememe.Purchaseable = true
|
||||
} else {
|
||||
pokememe.Purchaseable = false
|
||||
}
|
||||
pokememe.ImageURL = pokememeData["image"]
|
||||
pokememe.PlayerID = creatorID
|
||||
pokememe.IsActive = 1
|
||||
pokememe.CreatedAt = time.Now().UTC()
|
||||
|
||||
locations := []datamapping.Location{}
|
||||
elements := []datamapping.Element{}
|
||||
|
||||
for i := range pokememeLocations {
|
||||
locationID, err := dc.findLocationIDByName(pokememeLocations[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
locations = append(locations, *dc.locations[locationID])
|
||||
}
|
||||
|
||||
for i := range pokememeElements {
|
||||
elementID, err := dc.findElementIDBySymbol(pokememeElements[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
elements = append(elements, *dc.elements[elementID])
|
||||
}
|
||||
|
||||
// All objects are prepared, let's fill database with it!
|
||||
c.Log.Debug("Filling pokememe...")
|
||||
_, err := c.Db.NamedExec("INSERT INTO pokememes VALUES(NULL, :grade, :name, :description, :attack, :hp, :mp, :defence, :price, :purchaseable, :image_url, :player_id, :is_active, :created_at)", &pokememe)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
c.Log.Debug("Finding newly added pokememe...")
|
||||
insertedPokememe := dbmapping.Pokememe{}
|
||||
err = c.Db.Get(&insertedPokememe, c.Db.Rebind("SELECT * FROM pokememes WHERE grade=? AND name=?"), pokememe.Grade, pokememe.Name)
|
||||
if err != nil {
|
||||
c.Log.Debug("Can't find newly added pokememe!")
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Now we creating locations and elements links
|
||||
locationsAndElementsFilledSuccessfully := true
|
||||
c.Log.Debug("Filling locations...")
|
||||
for i := range locations {
|
||||
link := dbmapping.PokememeLocation{}
|
||||
link.PokememeID = insertedPokememe.ID
|
||||
link.LocationID = locations[i].ID
|
||||
link.CreatedAt = time.Now().UTC()
|
||||
|
||||
_, err := c.Db.NamedExec("INSERT INTO pokememes_locations VALUES(NULL, :pokememe_id, :location_id, :created_at)", &link)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
locationsAndElementsFilledSuccessfully = false
|
||||
}
|
||||
}
|
||||
|
||||
c.Log.Debug("Filling elements...")
|
||||
for i := range elements {
|
||||
link := dbmapping.PokememeElement{}
|
||||
link.PokememeID = insertedPokememe.ID
|
||||
link.ElementID = elements[i].ID
|
||||
link.CreatedAt = time.Now().UTC()
|
||||
|
||||
_, err := c.Db.NamedExec("INSERT INTO pokememes_elements VALUES(NULL, :pokememe_id, :element_id, :created_at)", &link)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
locationsAndElementsFilledSuccessfully = false
|
||||
}
|
||||
}
|
||||
|
||||
if !locationsAndElementsFilledSuccessfully {
|
||||
c.Log.Debug("All fucked up, removing what we have already added...")
|
||||
// There is something fucked up. In normal state we're should never reach this code
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes_locations WHERE pokememe_id=:id", &insertedPokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
}
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes_elements WHERE pokememe_id=:id", &insertedPokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
}
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes where id=:id", &insertedPokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
}
|
||||
return 0, errors.New("Failed to add pokememe to database")
|
||||
}
|
||||
|
||||
fullPokememe := dbmapping.PokememeFull{}
|
||||
fullPokememe.Pokememe = insertedPokememe
|
||||
fullPokememe.Locations = locations
|
||||
fullPokememe.Elements = elements
|
||||
|
||||
// Filling data cache
|
||||
dc.pokememesMutex.Lock()
|
||||
dc.fullPokememesMutex.Lock()
|
||||
dc.pokememes[insertedPokememe.ID] = &insertedPokememe
|
||||
dc.fullPokememes[insertedPokememe.ID] = &fullPokememe
|
||||
dc.pokememesMutex.Unlock()
|
||||
dc.fullPokememesMutex.Unlock()
|
||||
|
||||
return insertedPokememe.ID, nil
|
||||
}
|
||||
|
||||
// GetAllPokememes returns all pokememes
|
||||
// Index in resulted map counts all pokememes ordered by grade and alphabetically
|
||||
func (dc *DataCache) GetAllPokememes() map[int]*dbmapping.PokememeFull {
|
||||
pokememes := make(map[int]*dbmapping.PokememeFull)
|
||||
dc.fullPokememesMutex.Lock()
|
||||
func (dc *DataCache) GetAllPokememes() map[int]*datamapping.PokememeFull {
|
||||
pokememes := make(map[int]*datamapping.PokememeFull)
|
||||
|
||||
var keys []string
|
||||
keysToIDs := make(map[string]int)
|
||||
for i := range dc.fullPokememes {
|
||||
gradeKey := ""
|
||||
if dc.fullPokememes[i].Pokememe.Grade == 0 {
|
||||
gradeKey += "Z"
|
||||
} else {
|
||||
gradeKey += string(rune('A' - 1 + dc.fullPokememes[i].Pokememe.Grade))
|
||||
}
|
||||
keys = append(keys, gradeKey+"_"+strconv.Itoa(dc.fullPokememes[i].Pokememe.Attack+100000000000000)+"_"+dc.fullPokememes[i].Pokememe.Name)
|
||||
keysToIDs[gradeKey+"_"+strconv.Itoa(dc.fullPokememes[i].Pokememe.Attack+100000000000000)+"_"+dc.fullPokememes[i].Pokememe.Name] = i
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
idx := 0
|
||||
for _, k := range keys {
|
||||
pokememes[idx] = dc.fullPokememes[keysToIDs[k]]
|
||||
idx++
|
||||
pokememes[dc.fullPokememes[i].Pokememe.ID] = dc.fullPokememes[i]
|
||||
}
|
||||
|
||||
dc.fullPokememesMutex.Unlock()
|
||||
return pokememes
|
||||
}
|
||||
|
||||
// GetPokememeByID returns pokememe with additional information by ID
|
||||
func (dc *DataCache) GetPokememeByID(pokememeID int) (*dbmapping.PokememeFull, error) {
|
||||
dc.fullPokememesMutex.Lock()
|
||||
func (dc *DataCache) GetPokememeByID(pokememeID int) (*datamapping.PokememeFull, error) {
|
||||
if dc.fullPokememes[pokememeID] != nil {
|
||||
dc.fullPokememesMutex.Unlock()
|
||||
return dc.fullPokememes[pokememeID], nil
|
||||
}
|
||||
dc.fullPokememesMutex.Unlock()
|
||||
|
||||
return nil, errors.New("There is no pokememe with ID = " + strconv.Itoa(pokememeID))
|
||||
}
|
||||
|
||||
// GetPokememeByName returns pokememe from datacache by name
|
||||
func (dc *DataCache) GetPokememeByName(name string) (*dbmapping.PokememeFull, error) {
|
||||
dc.fullPokememesMutex.Lock()
|
||||
// GetPokememeByName returns pokememe with additional information by name
|
||||
func (dc *DataCache) GetPokememeByName(pokememeName string) (*datamapping.PokememeFull, error) {
|
||||
for i := range dc.fullPokememes {
|
||||
if strings.HasPrefix(dc.fullPokememes[i].Pokememe.Name, name) {
|
||||
dc.fullPokememesMutex.Unlock()
|
||||
if strings.Contains(dc.fullPokememes[i].Pokememe.Name, pokememeName) {
|
||||
return dc.fullPokememes[i], nil
|
||||
}
|
||||
}
|
||||
dc.fullPokememesMutex.Unlock()
|
||||
return nil, errors.New("There is no pokememe with name = " + name)
|
||||
|
||||
return nil, errors.New("There is no pokememe with name = " + pokememeName)
|
||||
}
|
||||
|
||||
// DeletePokememeByID removes pokememe from database
|
||||
func (dc *DataCache) DeletePokememeByID(pokememeID int) error {
|
||||
pokememe, err := dc.GetPokememeByID(pokememeID)
|
||||
if err != nil {
|
||||
return err
|
||||
// GetPokememesCountByGradeAndLocation returns pokememes count with given grade on given location
|
||||
func (dc *DataCache) GetPokememesCountByGradeAndLocation(grade int, locationID int) int {
|
||||
if dc.pokememesGradeLocation[grade] == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes_locations WHERE pokememe_id=:id", &pokememe.Pokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
}
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes_elements WHERE pokememe_id=:id", &pokememe.Pokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
}
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes where id=:id", &pokememe.Pokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
}
|
||||
|
||||
dc.pokememesMutex.Lock()
|
||||
dc.fullPokememesMutex.Lock()
|
||||
delete(dc.pokememes, pokememe.Pokememe.ID)
|
||||
delete(dc.fullPokememes, pokememe.Pokememe.ID)
|
||||
dc.pokememesMutex.Unlock()
|
||||
dc.fullPokememesMutex.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatePokememe updates existing pokememes in database and datacache
|
||||
func (dc *DataCache) UpdatePokememe(pokememeData map[string]string, pokememeLocations map[string]string, pokememeElements map[string]string) (int, error) {
|
||||
knownPokememe, err := dc.GetPokememeByName(pokememeData["name"])
|
||||
if err != nil {
|
||||
// This should never happen, but who knows?
|
||||
return 0, errors.New("This pokememe doesn't exist. We should add it instead")
|
||||
}
|
||||
|
||||
gradeInt := c.Statistics.GetPoints(pokememeData["grade"])
|
||||
attackInt := c.Statistics.GetPoints(pokememeData["attack"])
|
||||
hpInt := c.Statistics.GetPoints(pokememeData["hp"])
|
||||
mpInt := c.Statistics.GetPoints(pokememeData["mp"])
|
||||
defenceInt := attackInt
|
||||
if pokememeData["defence"] != "" {
|
||||
defenceInt = c.Statistics.GetPoints(pokememeData["defence"])
|
||||
}
|
||||
priceInt := c.Statistics.GetPoints(pokememeData["price"])
|
||||
creatorID := c.Statistics.GetPoints(pokememeData["creator_id"])
|
||||
|
||||
if !(gradeInt != 0 && attackInt != 0 && hpInt != 0 && mpInt != 0 && defenceInt != 0 && priceInt != 0 && creatorID != 0) {
|
||||
return 0, errors.New("Some of the required numerical values are empty")
|
||||
}
|
||||
|
||||
pokememe := knownPokememe.Pokememe
|
||||
pokememe.Grade = gradeInt
|
||||
pokememe.Name = pokememeData["name"]
|
||||
pokememe.Description = pokememeData["description"]
|
||||
pokememe.Attack = attackInt
|
||||
pokememe.HP = hpInt
|
||||
pokememe.MP = mpInt
|
||||
pokememe.Defence = defenceInt
|
||||
pokememe.Price = priceInt
|
||||
if pokememeData["purchaseable"] == "true" {
|
||||
pokememe.Purchaseable = true
|
||||
} else {
|
||||
pokememe.Purchaseable = false
|
||||
}
|
||||
pokememe.ImageURL = pokememeData["image"]
|
||||
pokememe.PlayerID = creatorID
|
||||
pokememe.CreatedAt = time.Now().UTC()
|
||||
|
||||
locations := []datamapping.Location{}
|
||||
elements := []datamapping.Element{}
|
||||
|
||||
for i := range pokememeLocations {
|
||||
locationID, err := dc.findLocationIDByName(pokememeLocations[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
locations = append(locations, *dc.locations[locationID])
|
||||
}
|
||||
|
||||
for i := range pokememeElements {
|
||||
elementID, err := dc.findElementIDBySymbol(pokememeElements[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
elements = append(elements, *dc.elements[elementID])
|
||||
}
|
||||
|
||||
// All objects are prepared, let's fill database with it!
|
||||
c.Log.Debug("Updating existing pokememe...")
|
||||
_, err = c.Db.NamedExec("UPDATE pokememes SET grade=:grade, name=:name, description=:description, attack=:attack, hp=:hp, mp=:mp, defence=:defence, price=:price, purchaseable=:purchaseable, image_url=:image_url, player_id=:player_id, created_at=:created_at WHERE id=:id", &pokememe)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Now we creating locations and elements links
|
||||
locationsAndElementsFilledSuccessfully := true
|
||||
c.Log.Debug("Destroying old relations...")
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes_locations WHERE pokememe_id=:id", &pokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
locationsAndElementsFilledSuccessfully = false
|
||||
}
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes_elements WHERE pokememe_id=:id", &pokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
locationsAndElementsFilledSuccessfully = false
|
||||
}
|
||||
c.Log.Debug("Filling locations...")
|
||||
for i := range locations {
|
||||
link := dbmapping.PokememeLocation{}
|
||||
link.PokememeID = pokememe.ID
|
||||
link.LocationID = locations[i].ID
|
||||
link.CreatedAt = time.Now().UTC()
|
||||
|
||||
_, err := c.Db.NamedExec("INSERT INTO pokememes_locations VALUES(NULL, :pokememe_id, :location_id, :created_at)", &link)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
locationsAndElementsFilledSuccessfully = false
|
||||
}
|
||||
}
|
||||
|
||||
c.Log.Debug("Filling elements...")
|
||||
for i := range elements {
|
||||
link := dbmapping.PokememeElement{}
|
||||
link.PokememeID = pokememe.ID
|
||||
link.ElementID = elements[i].ID
|
||||
link.CreatedAt = time.Now().UTC()
|
||||
|
||||
_, err := c.Db.NamedExec("INSERT INTO pokememes_elements VALUES(NULL, :pokememe_id, :element_id, :created_at)", &link)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
locationsAndElementsFilledSuccessfully = false
|
||||
}
|
||||
}
|
||||
|
||||
if !locationsAndElementsFilledSuccessfully {
|
||||
c.Log.Debug("All fucked up, removing what we have already added...")
|
||||
// There is something fucked up. In normal state we're should never reach this code
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes_locations WHERE pokememe_id=:id", &pokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
}
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes_elements WHERE pokememe_id=:id", &pokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
}
|
||||
_, err = c.Db.NamedExec("DELETE FROM pokememes where id=:id", &pokememe)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
}
|
||||
return 0, errors.New("Failed to add pokememe to database")
|
||||
}
|
||||
|
||||
fullPokememe := dbmapping.PokememeFull{}
|
||||
fullPokememe.Pokememe = pokememe
|
||||
fullPokememe.Locations = locations
|
||||
fullPokememe.Elements = elements
|
||||
|
||||
// Filling data cache
|
||||
dc.pokememesMutex.Lock()
|
||||
dc.fullPokememesMutex.Lock()
|
||||
dc.pokememes[pokememe.ID] = &pokememe
|
||||
dc.fullPokememes[pokememe.ID] = &fullPokememe
|
||||
dc.pokememesMutex.Unlock()
|
||||
dc.fullPokememesMutex.Unlock()
|
||||
|
||||
return pokememe.ID, nil
|
||||
return dc.pokememesGradeLocation[grade][locationID]
|
||||
}
|
||||
|
12
lib/datamapping/levels.go
Normal file
12
lib/datamapping/levels.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package datamapping
|
||||
|
||||
// Level is a struct, which represents level data
|
||||
type Level struct {
|
||||
ID int `yaml:"id"`
|
||||
MaxExp int `yaml:"max_exp"`
|
||||
MaxEgg int `yaml:"max_egg"`
|
||||
LevelStart int `yaml:"level_start"`
|
||||
}
|
28
lib/datamapping/pokememes.go
Normal file
28
lib/datamapping/pokememes.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017-2018 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package datamapping
|
||||
|
||||
// Pokememe is a struct, which represents pokememes item data
|
||||
type Pokememe struct {
|
||||
ID int `yaml:"id"`
|
||||
Grade int `yaml:"grade"`
|
||||
Name string `yaml:"name"`
|
||||
Description string `yaml:"description"`
|
||||
Attack int `yaml:"attack"`
|
||||
HP int `yaml:"health"`
|
||||
MP int `yaml:"mana"`
|
||||
Defence int `db:"defence"`
|
||||
Price int `yaml:"cost"`
|
||||
Purchaseable bool `yaml:"purchaseable"`
|
||||
ImageURL string `yaml:"image"`
|
||||
Elements []int `yaml:"elements"`
|
||||
Locations []int `yaml:"locations"`
|
||||
}
|
||||
|
||||
// PokememeFull is a struct for handling pokememe with all informations about locations and elements
|
||||
type PokememeFull struct {
|
||||
Pokememe Pokememe
|
||||
Locations []Location
|
||||
Elements []Element
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package dbmapping
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Level is a struct, which represents `levels` table item in databse.
|
||||
type Level struct {
|
||||
ID int `db:"id"`
|
||||
MaxExp int `db:"max_exp"`
|
||||
MaxEgg int `db:"max_egg"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package dbmapping
|
||||
|
||||
import (
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/datamapping"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Pokememe is a struct, which represents `pokememes` table item in databse.
|
||||
type Pokememe struct {
|
||||
ID int `db:"id"`
|
||||
Grade int `db:"grade"`
|
||||
Name string `db:"name"`
|
||||
Description string `db:"description"`
|
||||
Attack int `db:"attack"`
|
||||
HP int `db:"hp"`
|
||||
MP int `db:"mp"`
|
||||
Defence int `db:"defence"`
|
||||
Price int `db:"price"`
|
||||
Purchaseable bool `db:"purchaseable"`
|
||||
ImageURL string `db:"image_url"`
|
||||
PlayerID int `db:"player_id"`
|
||||
IsActive int `db:"is_active"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
// PokememeFull is a struct for handling pokememe with all informations about locations and elements
|
||||
type PokememeFull struct {
|
||||
Pokememe Pokememe
|
||||
Locations []datamapping.Location
|
||||
Elements []datamapping.Element
|
||||
}
|
@@ -13,7 +13,7 @@ import (
|
||||
func (f *Forwarder) ProcessForward(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
|
||||
text := update.Message.Text
|
||||
// Forwards
|
||||
var pokememeMsg = regexp.MustCompile("(Уровень)(.+)(Опыт)(.+)\n(Элементы:)(.+)\n(.+)(💙MP)")
|
||||
var pokememeMsg = regexp.MustCompile(`Dex(.+)\nGrade(.+)\nName(.+)`)
|
||||
var profileMsg = regexp.MustCompile(`(Онлайн: )(\d+)(| Турнир: )(.+)\n(.+)\n(.+)\n(👤Уровень)(.+)\n`)
|
||||
var profileWithEffectsMsg = regexp.MustCompile(`(Онлайн: )(\d+)(| Турнир: )(.+)\n(.+)\n(.+)\n(.+)\n(👤Уровень)(.+)\n`)
|
||||
|
||||
|
38
lib/migrations/34_delete_pokememes_tables.go
Normal file
38
lib/migrations/34_delete_pokememes_tables.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017-2018 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// DeletePokememesTablesUp drops `pokememes`, `pokememes_elements` and `pokememes_locations` tables
|
||||
// These tables data is rarely changed, so I decided to hold such data in source code
|
||||
func DeletePokememesTablesUp(tx *sql.Tx) error {
|
||||
request := "DROP TABLE IF EXISTS `pokememes`"
|
||||
_, err := tx.Exec(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
request = "DROP TABLE IF EXISTS `pokememes_elements`"
|
||||
_, err = tx.Exec(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
request = "DROP TABLE IF EXISTS `pokememes_locations`"
|
||||
_, err = tx.Exec(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletePokememesTablesDown does nothing, because after nerf old information isn't needed at all
|
||||
func DeletePokememesTablesDown(tx *sql.Tx) error {
|
||||
return errors.New("This migration is irreversible, as nerf itself")
|
||||
}
|
@@ -44,6 +44,7 @@ func (m *Migrations) Init() {
|
||||
goose.AddNamedMigration("31_change_squads_table.go", ChangeSquadsTableUp, ChangeSquadsTableDown)
|
||||
goose.AddNamedMigration("32_add_is_active_to_pokememes.go", AddIsActiveToPokememesUp, AddIsActiveToPokememesDown)
|
||||
goose.AddNamedMigration("33_delete_datamapped_tables.go", DeleteDataMappedTablesUp, DeleteDataMappedTablesDown)
|
||||
goose.AddNamedMigration("34_delete_pokememes_tables.go", DeletePokememesTablesUp, DeletePokememesTablesDown)
|
||||
}
|
||||
|
||||
// Migrate migrates database to current version
|
||||
|
@@ -1,32 +0,0 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package pokedexer
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// DeletePokememe deletes pokememe by its ID
|
||||
func (p *Pokedexer) DeletePokememe(update *tgbotapi.Update) string {
|
||||
pokememeNum, _ := strconv.Atoi(update.Message.CommandArguments())
|
||||
if pokememeNum == 0 {
|
||||
return "fail"
|
||||
}
|
||||
|
||||
err := c.DataCache.DeletePokememeByID(pokememeNum)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
return "fail"
|
||||
}
|
||||
|
||||
message := "Покемем удалён."
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
|
||||
c.Bot.Send(msg)
|
||||
|
||||
return "ok"
|
||||
}
|
@@ -5,14 +5,14 @@ package pokedexer
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/datamapping"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (p *Pokedexer) getAdvicePokememes(playerID int, adviceType string) ([]*dbmapping.PokememeFull, bool) {
|
||||
func (p *Pokedexer) getAdvicePokememes(playerID int, adviceType string) ([]*datamapping.PokememeFull, bool) {
|
||||
c.Log.Debug("Getting advice for pokememes...")
|
||||
pokememesArray := make([]*dbmapping.PokememeFull, 0)
|
||||
pokememesArray := make([]*datamapping.PokememeFull, 0)
|
||||
|
||||
playerRaw, err := c.DataCache.GetPlayerByID(playerID)
|
||||
if err != nil {
|
||||
@@ -90,7 +90,7 @@ func (p *Pokedexer) getAdvicePokememes(playerID int, adviceType string) ([]*dbma
|
||||
case "best", "advice", "best_nofilter":
|
||||
if len(pokememesArray) > 5 {
|
||||
idx := 0
|
||||
pokememesArrayShorted := make([]*dbmapping.PokememeFull, 0)
|
||||
pokememesArrayShorted := make([]*datamapping.PokememeFull, 0)
|
||||
for i := range pokememesArray {
|
||||
if idx < 5 {
|
||||
pokememesArrayShorted = append(pokememesArrayShorted, pokememesArray[i])
|
||||
|
@@ -5,15 +5,14 @@ package pokedexer
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"regexp"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping"
|
||||
"strconv"
|
||||
"strings"
|
||||
// "time"
|
||||
)
|
||||
|
||||
// ParsePokememe parses pokememe, forwarded from PokememeBroBot, to database
|
||||
func (p *Pokedexer) ParsePokememe(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
|
||||
c.Log.Info("Starting pokememe parsing...")
|
||||
pokememeStringsArray := strings.Split(update.Message.Text, "\n")
|
||||
pokememeRunesArray := make([][]rune, 0)
|
||||
for i := range pokememeStringsArray {
|
||||
@@ -21,149 +20,55 @@ func (p *Pokedexer) ParsePokememe(update *tgbotapi.Update, playerRaw *dbmapping.
|
||||
}
|
||||
|
||||
pokememeData := make(map[string]string)
|
||||
pokememeLocations := make(map[string]string)
|
||||
pokememeElements := make(map[string]string)
|
||||
|
||||
hitPointsRx := regexp.MustCompile("(\\d|\\.)+(K|M)?")
|
||||
|
||||
for i := range pokememeStringsArray {
|
||||
c.Log.Debug("Processing string: " + pokememeStringsArray[i])
|
||||
if strings.Contains(pokememeStringsArray[i], "⃣") {
|
||||
// Strings with name and grade
|
||||
splitGradeAndName := strings.Split(string(pokememeRunesArray[i]), " ")
|
||||
gradeNumberRegexp := regexp.MustCompile("[0-9]+")
|
||||
pokememeData["grade"] = strings.Join(gradeNumberRegexp.FindAllString(splitGradeAndName[0], -1), "")
|
||||
pokememeData["name"] = strings.Join(splitGradeAndName[1:], " ")
|
||||
}
|
||||
|
||||
// Special case: "10" emoji
|
||||
if strings.Contains(pokememeStringsArray[i], "🔟") {
|
||||
// Strings with name and grade
|
||||
pokememeData["grade"] = "10"
|
||||
pokememeData["name"] = string(pokememeStringsArray[i][5:])
|
||||
}
|
||||
|
||||
if i == 1 {
|
||||
pokememeData["description"] = string(pokememeRunesArray[i])
|
||||
}
|
||||
|
||||
if strings.HasPrefix(pokememeStringsArray[i], "Обитает: ") {
|
||||
// Elements
|
||||
locationsString := strings.TrimPrefix(pokememeStringsArray[i], "Обитает: ")
|
||||
locationsArray := strings.Split(locationsString, ", ")
|
||||
for i := range locationsArray {
|
||||
pokememeLocations[strconv.Itoa(i)] = locationsArray[i]
|
||||
infoString := pokememeStringsArray[i]
|
||||
c.Log.Debug("Processing string: " + infoString)
|
||||
if strings.HasPrefix(infoString, "Elements ") {
|
||||
infoString = strings.Replace(infoString, "Elements ", "", -1)
|
||||
elements := strings.Split(infoString, " ")
|
||||
elementsIDs := make([]string, 0)
|
||||
for ii := range elements {
|
||||
element, _ := c.DataCache.FindElementIDBySymbol(elements[ii])
|
||||
elementsIDs = append(elementsIDs, strconv.Itoa(element))
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(pokememeStringsArray[i], "Элементы: ") {
|
||||
// Elements
|
||||
elementsString := strings.TrimPrefix(pokememeStringsArray[i], "Элементы: ")
|
||||
elementsArray := strings.Split(elementsString, " ")
|
||||
for i := range elementsArray {
|
||||
pokememeElements[strconv.Itoa(i)] = elementsArray[i]
|
||||
pokememeData["elements"] = "\\[" + strings.Join(elementsIDs, ", ") + "]"
|
||||
} else if strings.HasPrefix(infoString, "Place ") {
|
||||
infoString = strings.Replace(infoString, "Place ", "", -1)
|
||||
places := strings.Split(infoString, ",")
|
||||
locationIDs := make([]string, 0)
|
||||
for ii := range places {
|
||||
locationID, _ := c.DataCache.FindLocationIDByName(places[ii])
|
||||
locationIDs = append(locationIDs, strconv.Itoa(locationID))
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(pokememeStringsArray[i], "⚔Атака: ") {
|
||||
// Attack, HP, MP
|
||||
hitPoints := hitPointsRx.FindAllString(string(pokememeRunesArray[i]), -1)
|
||||
if len(hitPoints) != 3 {
|
||||
c.Log.Error("Can't parse hitpoints!")
|
||||
c.Log.Debug("Points string was: " + string(pokememeRunesArray[i]))
|
||||
p.pokememeAddFailureMessage(update)
|
||||
return "fail"
|
||||
}
|
||||
pokememeData["attack"] = hitPoints[0]
|
||||
pokememeData["hp"] = hitPoints[1]
|
||||
pokememeData["mp"] = hitPoints[2]
|
||||
}
|
||||
|
||||
if strings.HasPrefix(pokememeStringsArray[i], "🛡Защита ") {
|
||||
// Defence for top-level pokememes
|
||||
defence := hitPointsRx.FindAllString(string(pokememeRunesArray[i]), -1)
|
||||
if len(defence) != 1 {
|
||||
c.Log.Error("Can't parse defence!")
|
||||
c.Log.Debug("Defence string was: " + string(pokememeRunesArray[i]))
|
||||
p.pokememeAddFailureMessage(update)
|
||||
return "fail"
|
||||
}
|
||||
pokememeData["defence"] = defence[0]
|
||||
}
|
||||
|
||||
if strings.HasPrefix(pokememeStringsArray[i], "Стоимость :") {
|
||||
// Price
|
||||
price := hitPointsRx.FindAllString(string(pokememeRunesArray[i]), -1)
|
||||
if len(price) != 1 {
|
||||
c.Log.Error("Can't parse price!")
|
||||
c.Log.Debug("Price string was: " + string(pokememeRunesArray[i]))
|
||||
p.pokememeAddFailureMessage(update)
|
||||
return "fail"
|
||||
}
|
||||
pokememeData["price"] = price[0]
|
||||
}
|
||||
|
||||
if strings.HasPrefix(pokememeStringsArray[i], "Купить: ") {
|
||||
// Purchaseability
|
||||
pokememeData["locations"] = "\\[" + strings.Join(locationIDs, ", ") + "]"
|
||||
} else if strings.HasPrefix(infoString, "Buyable ") {
|
||||
pokememeData["purchaseable"] = "false"
|
||||
if strings.Contains(pokememeStringsArray[i], "Можно") {
|
||||
if strings.HasSuffix(infoString, "Yes") {
|
||||
pokememeData["purchaseable"] = "true"
|
||||
}
|
||||
} else {
|
||||
pokememeData[strings.Split(infoString, " ")[0]] = strings.Join(strings.Split(infoString, " ")[1:], " ")
|
||||
}
|
||||
}
|
||||
|
||||
// Image
|
||||
for _, entity := range *update.Message.Entities {
|
||||
if entity.Type == "text_link" && entity.URL != "" {
|
||||
pokememeData["image"] = entity.URL
|
||||
}
|
||||
}
|
||||
|
||||
// Checking grade to be integer
|
||||
_, err := strconv.Atoi(pokememeData["grade"])
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
p.pokememeAddFailureMessage(update)
|
||||
return "fail"
|
||||
}
|
||||
|
||||
pokememeData["creator_id"] = strconv.Itoa(playerRaw.ID)
|
||||
|
||||
c.Log.Debugln("Pokememe data: ", pokememeData)
|
||||
c.Log.Debugln("Elements: ", pokememeElements)
|
||||
c.Log.Debugln("Locations: ", pokememeLocations)
|
||||
|
||||
if len(pokememeElements) == 0 {
|
||||
p.pokememeAddFailureMessage(update)
|
||||
return "fail"
|
||||
}
|
||||
message := "- id: " + pokememeData["Dex"]
|
||||
message += "\n grade: " + pokememeData["Grade"]
|
||||
message += "\n name: \"" + pokememeData["Name"] + "\""
|
||||
message += "\n description: \"" + pokememeData["Description"] + "\""
|
||||
message += "\n attack: " + pokememeData["Attack"]
|
||||
message += "\n defence: " + pokememeData["Def"]
|
||||
message += "\n health: " + pokememeData["HP"]
|
||||
message += "\n mana: " + pokememeData["MP"]
|
||||
message += "\n cost: " + pokememeData["Cost"]
|
||||
message += "\n purchaseable: " + pokememeData["purchaseable"]
|
||||
message += "\n image: \"" + pokememeData["Image"] + "\""
|
||||
message += "\n elements: " + pokememeData["elements"]
|
||||
message += "\n locations: " + pokememeData["locations"]
|
||||
|
||||
if len(pokememeLocations) == 0 {
|
||||
p.pokememeAddFailureMessage(update)
|
||||
return "fail"
|
||||
}
|
||||
c.Sender.SendMarkdownAnswer(update, message)
|
||||
|
||||
_, err = c.DataCache.GetPokememeByName(pokememeData["name"])
|
||||
if err == nil {
|
||||
// There is already a pokememe with such name, updating
|
||||
pokememeID, err := c.DataCache.UpdatePokememe(pokememeData, pokememeLocations, pokememeElements)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
p.pokememeAddFailureMessage(update)
|
||||
return "fail"
|
||||
}
|
||||
|
||||
p.pokememeAddDuplicateMessage(update, pokememeID)
|
||||
return "ok"
|
||||
}
|
||||
|
||||
newPokememeID, err := c.DataCache.AddPokememe(pokememeData, pokememeLocations, pokememeElements)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
p.pokememeAddFailureMessage(update)
|
||||
return "fail"
|
||||
}
|
||||
|
||||
p.pokememeAddSuccessMessage(update, newPokememeID)
|
||||
return "ok"
|
||||
}
|
||||
|
@@ -6,22 +6,13 @@ package pokedexer
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"sort"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/datamapping"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (p *Pokedexer) pokememesListing(update *tgbotapi.Update, page int, pokememesArray map[int]*dbmapping.PokememeFull) {
|
||||
message := "*Известные боту покемемы*\n"
|
||||
message += "Список отсортирован по грейду и алфавиту.\n"
|
||||
message += "Покедекс: " + strconv.Itoa(len(pokememesArray)) + " / 296\n"
|
||||
message += "Отображаем покемемов с " + strconv.Itoa(((page-1)*50)+1) + " по " + strconv.Itoa(page*50) + "\n"
|
||||
if len(pokememesArray) > page*50 {
|
||||
message += "Переход на следующую страницу: /pokedeks" + strconv.Itoa(page+1)
|
||||
}
|
||||
if page > 1 {
|
||||
message += "\nПереход на предыдущую страницу: /pokedeks" + strconv.Itoa(page-1)
|
||||
}
|
||||
message += "\n\n"
|
||||
func (p *Pokedexer) pokememesListingMessage(update *tgbotapi.Update, page int, pokememesArray map[int]*datamapping.PokememeFull) string {
|
||||
message := "📕*Покедекс: " + strconv.Itoa(len(pokememesArray)) + " / 733*\n"
|
||||
message += "```\nВсе виды покемемов, которые известны боту. [" + strconv.Itoa(page) + "] (" + strconv.Itoa(((page-1)*35)+1) + "-" + strconv.Itoa(page*35) + ")```"
|
||||
|
||||
var keys []int
|
||||
for i := range pokememesArray {
|
||||
@@ -30,13 +21,13 @@ func (p *Pokedexer) pokememesListing(update *tgbotapi.Update, page int, pokememe
|
||||
sort.Ints(keys)
|
||||
|
||||
for _, i := range keys {
|
||||
if (i+1 > 50*(page-1)) && (i+1 < (50*page)+1) {
|
||||
if (i > 35*(page-1)) && (i < (35*page)+1) {
|
||||
pk := pokememesArray[i].Pokememe
|
||||
pkE := pokememesArray[i].Elements
|
||||
message += strconv.Itoa(i+1) + ". *[" + strconv.Itoa(pk.Grade)
|
||||
message += strconv.Itoa(pk.ID) + ". *[" + strconv.Itoa(pk.Grade)
|
||||
message += "]* *" + pk.Name
|
||||
message += "* (" + c.Statistics.GetPrintablePoints(pk.HP) + "-" + c.Statistics.GetPrintablePoints(pk.MP) + ") ⚔️ *"
|
||||
message += c.Statistics.GetPrintablePoints(pk.Attack) + "* \\["
|
||||
message += "* ❤️" + c.Statistics.GetPrintablePoints(pk.HP) + " ⚔️ "
|
||||
message += c.Statistics.GetPrintablePoints(pk.Attack) + " 🛡" + c.Statistics.GetPrintablePoints(pk.Defence) + " \\["
|
||||
for j := range pkE {
|
||||
message += pkE[j].Symbol
|
||||
}
|
||||
@@ -45,49 +36,47 @@ func (p *Pokedexer) pokememesListing(update *tgbotapi.Update, page int, pokememe
|
||||
}
|
||||
}
|
||||
|
||||
if len(pokememesArray) > page*50 {
|
||||
message += "\n"
|
||||
message += "Переход на следующую страницу: /pokedeks" + strconv.Itoa(page+1)
|
||||
return message
|
||||
}
|
||||
|
||||
func (p *Pokedexer) pokememesListingKeyboard(pokememesArray map[int]*datamapping.PokememeFull) *tgbotapi.InlineKeyboardMarkup {
|
||||
keyboard := tgbotapi.InlineKeyboardMarkup{}
|
||||
rows := make(map[int][]tgbotapi.InlineKeyboardButton)
|
||||
rows[0] = []tgbotapi.InlineKeyboardButton{}
|
||||
if len(pokememesArray) > 35*7 {
|
||||
rows[1] = []tgbotapi.InlineKeyboardButton{}
|
||||
}
|
||||
if page > 1 {
|
||||
message += "\nПереход на предыдущую страницу: /pokedeks" + strconv.Itoa(page-1)
|
||||
if len(pokememesArray) > 35*14 {
|
||||
rows[2] = []tgbotapi.InlineKeyboardButton{}
|
||||
}
|
||||
totalPages := int(len(pokememesArray)/35) + 1
|
||||
for i := 1; i <= totalPages; i++ {
|
||||
btn := tgbotapi.NewInlineKeyboardButtonData(strconv.Itoa(i), "pokedeks"+strconv.Itoa(i))
|
||||
rows[(i-1)/7] = append(rows[(i-1)/7], btn)
|
||||
}
|
||||
for i := range rows {
|
||||
keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, rows[i])
|
||||
}
|
||||
|
||||
return &keyboard
|
||||
}
|
||||
|
||||
func (p *Pokedexer) pokememesListing(update *tgbotapi.Update, page int, pokememesArray map[int]*datamapping.PokememeFull) {
|
||||
message := p.pokememesListingMessage(update, page, pokememesArray)
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
msg.ReplyMarkup = p.pokememesListingKeyboard(pokememesArray)
|
||||
|
||||
c.Bot.Send(msg)
|
||||
}
|
||||
|
||||
func (p *Pokedexer) pokememeAddSuccessMessage(update *tgbotapi.Update, newPokememeID int) {
|
||||
message := "*Покемем успешно добавлен.*\n\n"
|
||||
message += "Посмотреть всех известных боту покемемов можно командой /pokedeks\n"
|
||||
message += "Посмотреть свежедобавленного покемема можно командой /pk" + strconv.Itoa(newPokememeID)
|
||||
func (p *Pokedexer) pokememesListingUpdate(update *tgbotapi.Update, page int, pokememesArray map[int]*datamapping.PokememeFull) {
|
||||
message := p.pokememesListingMessage(update, page, pokememesArray)
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
messageUpdate := tgbotapi.NewEditMessageText(update.CallbackQuery.Message.Chat.ID, update.CallbackQuery.Message.MessageID, message)
|
||||
messageUpdate.ParseMode = "Markdown"
|
||||
messageUpdate.ReplyMarkup = p.pokememesListingKeyboard(pokememesArray)
|
||||
|
||||
c.Bot.Send(msg)
|
||||
}
|
||||
|
||||
func (p *Pokedexer) pokememeAddDuplicateMessage(update *tgbotapi.Update, pokememeID int) {
|
||||
message := "*Покемем успешно обновлён.*\n\n"
|
||||
message += "Посмотреть всех известных боту покемемов можно командой /pokedeks\n"
|
||||
message += "Посмотреть свежеобновлённого покемема можно командой /pk" + strconv.Itoa(pokememeID)
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
|
||||
c.Bot.Send(msg)
|
||||
}
|
||||
|
||||
func (p *Pokedexer) pokememeAddFailureMessage(update *tgbotapi.Update) {
|
||||
message := "*Неудачно получилось :(*\n\n"
|
||||
message += "Случилась жуткая ошибка, и мы не смогли записать покемема в базу. Напиши @fat0troll, он разберется.\n\n"
|
||||
message += "Посмотреть всех известных боту покемемов можно командой /pokedeks"
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
|
||||
c.Bot.Send(msg)
|
||||
c.Bot.Send(messageUpdate)
|
||||
}
|
||||
|
@@ -4,8 +4,8 @@
|
||||
package pokedexerinterface
|
||||
|
||||
import (
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping"
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping"
|
||||
)
|
||||
|
||||
// PokedexerInterface implements Pokedexer for importing via appcontext.
|
||||
@@ -13,8 +13,7 @@ type PokedexerInterface interface {
|
||||
ParsePokememe(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
|
||||
|
||||
PokememesList(update *tgbotapi.Update)
|
||||
PokememesListUpdater(update *tgbotapi.Update) string
|
||||
PokememeInfo(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
|
||||
AdvicePokememesList(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
|
||||
|
||||
DeletePokememe(update *tgbotapi.Update) string
|
||||
}
|
||||
|
@@ -99,6 +99,19 @@ func (p *Pokedexer) PokememesList(update *tgbotapi.Update) {
|
||||
p.pokememesListing(update, page, pokememesArray)
|
||||
}
|
||||
|
||||
// PokememesListUpdater updates page in pokedeks message
|
||||
func (p *Pokedexer) PokememesListUpdater(update *tgbotapi.Update) string {
|
||||
pageNumber := strings.Replace(update.CallbackQuery.Data, "pokedeks", "", 1)
|
||||
page, _ := strconv.Atoi(pageNumber)
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
pokememesArray := c.DataCache.GetAllPokememes()
|
||||
p.pokememesListingUpdate(update, page, pokememesArray)
|
||||
|
||||
return "ok"
|
||||
}
|
||||
|
||||
// PokememeInfo shows information about single pokememe based on internal ID
|
||||
func (p *Pokedexer) PokememeInfo(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
|
||||
pokememeNumber := strings.Replace(update.Message.Text, "/pk", "", 1)
|
||||
@@ -150,7 +163,7 @@ func (p *Pokedexer) PokememeInfo(update *tgbotapi.Update, playerRaw *dbmapping.P
|
||||
if c.Users.PlayerBetterThan(playerRaw, "academic") {
|
||||
message += "\nВероятность поимки:"
|
||||
idx := 1
|
||||
for idx < 10 {
|
||||
for idx < 23 {
|
||||
levelHeaderPosted := false
|
||||
for i := range pokememe.Locations {
|
||||
percentile, pokeballs := c.Statistics.PossibilityRequiredPokeballs(pokememe.Locations[i].ID, pk.Grade, idx)
|
||||
@@ -183,6 +196,7 @@ 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)
|
||||
|
@@ -23,12 +23,15 @@ func (r *Router) RouteCallback(update tgbotapi.Update) string {
|
||||
|
||||
var enableAlarmCallback = regexp.MustCompile("enable_reminder_(\\d+)\\z")
|
||||
var disableAlarmCallback = regexp.MustCompile("disable_reminder_(\\d+)\\z")
|
||||
var pokedeksPageCallback = regexp.MustCompile("pokedeks(\\d+)\\z")
|
||||
|
||||
switch {
|
||||
case enableAlarmCallback.MatchString(update.CallbackQuery.Data):
|
||||
return c.Reminder.CreateAlarmSetting(&update, playerRaw)
|
||||
case disableAlarmCallback.MatchString(update.CallbackQuery.Data):
|
||||
return c.Reminder.DestroyAlarmSetting(&update, playerRaw)
|
||||
case pokedeksPageCallback.MatchString(update.CallbackQuery.Data):
|
||||
return c.Pokedexer.PokememesListUpdater(&update)
|
||||
}
|
||||
|
||||
return "ok"
|
||||
|
@@ -4,10 +4,10 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"regexp"
|
||||
"source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *Router) routePrivateRequest(update tgbotapi.Update, playerRaw *dbmapping.Player, chatRaw *dbmapping.Chat) string {
|
||||
@@ -26,15 +26,23 @@ func (r *Router) routePrivateRequest(update tgbotapi.Update, playerRaw *dbmappin
|
||||
}
|
||||
|
||||
if update.Message.ForwardFrom != nil {
|
||||
if update.Message.ForwardFrom.ID != 360402625 {
|
||||
c.Log.Info("Forward from another user or bot. Ignoring")
|
||||
} else {
|
||||
if update.Message.ForwardFrom.ID == 360402625 {
|
||||
c.Log.Info("Forward from PokememBro bot! Processing...")
|
||||
if playerRaw.ID != 0 {
|
||||
c.Forwarder.ProcessForward(&update, playerRaw)
|
||||
} else {
|
||||
return c.Talkers.AnyMessageUnauthorized(&update)
|
||||
}
|
||||
} else if update.Message.ForwardFrom.ID == 392622454 {
|
||||
// Pokememes test bot with actual pokedeks
|
||||
c.Log.Info("Forward from PokememBro test bot! Processing...")
|
||||
if playerRaw.ID != 0 {
|
||||
c.Forwarder.ProcessForward(&update, playerRaw)
|
||||
} else {
|
||||
return c.Talkers.AnyMessageUnauthorized(&update)
|
||||
}
|
||||
} else {
|
||||
c.Log.Info("Forward from another user or bot (" + strconv.Itoa(update.Message.ForwardFrom.ID) + "). Ignoring")
|
||||
}
|
||||
} else {
|
||||
if update.Message.IsCommand() {
|
||||
@@ -74,12 +82,7 @@ func (r *Router) routePrivateRequest(update tgbotapi.Update, playerRaw *dbmappin
|
||||
case pokememeInfoMsg.MatchString(text):
|
||||
c.Pokedexer.PokememeInfo(&update, playerRaw)
|
||||
return "ok"
|
||||
case update.Message.Command() == "delete_pokememe":
|
||||
if c.Users.PlayerBetterThan(playerRaw, "owner") {
|
||||
return c.Pokedexer.DeletePokememe(&update)
|
||||
}
|
||||
|
||||
return c.Talkers.AnyMessageUnauthorized(&update)
|
||||
case update.Message.Command() == "me":
|
||||
if playerRaw.ID != 0 {
|
||||
c.Users.ProfileMessage(&update, playerRaw)
|
||||
|
@@ -60,12 +60,7 @@ func (s *Statistics) PossibilityRequiredPokeballs(location int, grade int, lvl i
|
||||
}
|
||||
}
|
||||
|
||||
var pokememesCount int
|
||||
|
||||
err := c.Db.Get(&pokememesCount, c.Db.Rebind("SELECT count(*) FROM pokememes p, pokememes_locations pl WHERE p.grade = ? AND pl.location_id = ? AND pl.pokememe_id = p.id;"), grade, location)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
}
|
||||
pokememesCount := c.DataCache.GetPokememesCountByGradeAndLocation(grade, location)
|
||||
|
||||
if basePossibility != 0 && pokememesCount != 0 {
|
||||
percentile = basePossibility * 100.0 / float64(pokememesCount)
|
||||
|
@@ -122,8 +122,7 @@ func (u *Users) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Pla
|
||||
c.Log.Error(err.Error())
|
||||
return c.Talkers.BotError(update)
|
||||
}
|
||||
level := dbmapping.Level{}
|
||||
err = c.Db.Get(&level, c.Db.Rebind("SELECT * FROM levels WHERE id=?"), profileRaw.LevelID)
|
||||
level, err := c.DataCache.GetLevelByID(profileRaw.LevelID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
}
|
||||
@@ -137,16 +136,12 @@ func (u *Users) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Pla
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
}
|
||||
pokememes := []dbmapping.Pokememe{}
|
||||
err = c.Db.Select(&pokememes, c.Db.Rebind("SELECT * FROM pokememes"))
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
}
|
||||
pokememes := c.DataCache.GetAllPokememes()
|
||||
|
||||
attackPokememes := 0
|
||||
for i := range profilePokememes {
|
||||
for j := range pokememes {
|
||||
if profilePokememes[i].PokememeID == pokememes[j].ID {
|
||||
if profilePokememes[i].PokememeID == pokememes[j].Pokememe.ID {
|
||||
singleAttack := profilePokememes[i].PokememeAttack
|
||||
attackPokememes += singleAttack
|
||||
}
|
||||
@@ -178,9 +173,9 @@ func (u *Users) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Pla
|
||||
message += "\n🐱Покемемы:"
|
||||
for i := range profilePokememes {
|
||||
for j := range pokememes {
|
||||
if profilePokememes[i].PokememeID == pokememes[j].ID {
|
||||
message += "\n *[" + strconv.Itoa(pokememes[j].Grade)
|
||||
message += "]* " + pokememes[j].Name
|
||||
if profilePokememes[i].PokememeID == pokememes[j].Pokememe.ID {
|
||||
message += "\n *[" + strconv.Itoa(pokememes[j].Pokememe.Grade)
|
||||
message += "]* " + pokememes[j].Pokememe.Name
|
||||
message += " +" + c.Statistics.GetPrintablePoints(profilePokememes[i].PokememeAttack) + "⚔"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user