From 30baff46db3eddc1cbb3cc20fb7fde625f986feb Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 10 Mar 2022 14:48:18 +0200 Subject: [PATCH 001/367] Latest translations --- core/lang/pokemon_moves.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/lang/pokemon_moves.json b/core/lang/pokemon_moves.json index e9078e0a..8764d514 100644 --- a/core/lang/pokemon_moves.json +++ b/core/lang/pokemon_moves.json @@ -3848,16 +3848,16 @@ "ES": "Fuego Sagrado++" }, "pokemon_move_364": { - "PT-BR": "Acrobatics", + "PT-BR": "Acrobático", "EN": "Acrobatics", "FI": "Acrobatics", "NL": "Acrobatics", "NO": "Acrobatics", "PL": "Acrobatics", - "FR": "Acrobatics", - "DE": "Acrobatics", - "IT": "Acrobatics", + "FR": "Acrobatie", + "DE": "Akrobatik", + "IT": "Acrobazia", "RU": "Акробатика", - "ES": "Acrobatics" + "ES": "Acróbata" } } \ No newline at end of file From a9b16abc9a82cfcbd608654bfaa013cfd2fac780 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 12 Mar 2022 22:31:41 +0200 Subject: [PATCH 002/367] Added WEBHOOK_CHATS_BY_POKEMON --- commands/raid_from_webhook.php | 11 ++++++++++- config/defaults-config.json | 1 + docs/config.rst | 22 +++++++++++++++++++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index e527d823..71a8c1b3 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -345,7 +345,16 @@ function isPointInsidePolygon($point, $vertices) { if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); } - $chats = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats); + + $chats_by_pokemon = []; + foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { + info_log(print_r($rule,true)); + if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { + $chats_by_pokemon = $rule['chats']; + } + } + + $chats = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats, $chats_by_pokemon); require_once(LOGIC_PATH .'/send_raid_poll.php'); if ($metrics){ diff --git a/config/defaults-config.json b/config/defaults-config.json index 8c7f7b6d..51c72229 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -126,6 +126,7 @@ "WEBHOOK_CHATS_LEVEL_3_1":"", "WEBHOOK_CHATS_LEVEL_2_1":"", "WEBHOOK_CHATS_LEVEL_1_1":"", + "WEBHOOK_CHATS_BY_POKEMON" : [], "WEBHOOK_EXCLUDE_UNKNOWN": false, "WEBHOOK_EXCLUDE_RAID_LEVEL":"1,2,3", "WEBHOOK_EXCLUDE_POKEMON":"", diff --git a/docs/config.rst b/docs/config.rst index 49476b55..c8abc0ab 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -47,7 +47,6 @@ it's already prepended to the right length. .. code-block:: - { *snip* "chat": { "id": -1002233445566, @@ -395,6 +394,25 @@ For that you need to setup ``WEBHOOK_CREATOR``\ , and to automatically share rai or by Raidlevel ``"WEBHOOK_CHATS_LEVEL_5":"-100444555666"`` All incoming raids will be published in these chats. +If you only want to automatically share a specific Pokemon, you can do that by editing the ``WEBHOOK_CHATS_BY_POKEMON`` json array: + + +.. code-block:: + + "WEBHOOK_CHATS_BY_POKEMON" : [ + { + "pokemon_id": 744, + "chats":[chat_id_1, chat_id_2] + }, + { + "pokemon_id": 25, + "form_id": 2678, + "chats":[chat_id_3] + } + ], + +``pokemon_id`` and ``chats`` are required objects, ``form_id`` is optional. + Filter Raids from Webhook / geoconfig.json ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1074,6 +1092,8 @@ Config reference - List of Telegram chat IDs to autoshare raids of level 5 * - WEBHOOK_CHATS_ALL_LEVELS - List of Telegram chat IDs to autoshare raids of any level + * - WEBHOOK_CHATS_BY_POKEMON + - Automatically share only specific Pokemon to set chats. See above for further details. * - WEBHOOK_CREATE_ONLY - Bool, only create raids, don't autoshare them to any chat * - WEBHOOK_CREATOR From eac926dab46413a15a67246291f697bec826e9aa Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Mar 2022 09:17:09 +0200 Subject: [PATCH 003/367] Minor WEBHOOK_CHATS_BY_POKEMON documentation fix --- docs/config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.rst b/docs/config.rst index c8abc0ab..4b7cd7e4 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -1093,7 +1093,7 @@ Config reference * - WEBHOOK_CHATS_ALL_LEVELS - List of Telegram chat IDs to autoshare raids of any level * - WEBHOOK_CHATS_BY_POKEMON - - Automatically share only specific Pokemon to set chats. See above for further details. + - Automatically share only specific Pokemon to set chats. See `Raids from Webhook`_ for further details. * - WEBHOOK_CREATE_ONLY - Bool, only create raids, don't autoshare them to any chat * - WEBHOOK_CREATOR From deeb91fa0dc5ca5e899240cdc0154f966c0d50b8 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Mar 2022 09:18:01 +0200 Subject: [PATCH 004/367] Reworked raid posting from webhooks to acommodate WEBHOOK_CHATS_BY_POKEMON --- commands/raid_from_webhook.php | 89 ++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 71a8c1b3..c41a6e5d 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -33,6 +33,25 @@ function isPointInsidePolygon($point, $vertices) { } } +$cleanup_data = []; +if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0])) { + // Fetch cleanup info for later use + try { + $query_cleanup = 'SELECT raid_id, chat_id FROM cleanup'; + $statement_cleanup = $dbh->prepare($query_cleanup); + $statement_cleanup->execute(); + $cleanup_table = $statement_cleanup->fetchAll(); + foreach($cleanup_table as $row) { + $cleanup_data[$row['raid_id']][] = $row['chat_id']; + } + } + catch (PDOException $exception) { + error_log($exception->getMessage()); + $dbh = null; + exit; + } +} + // Telegram JSON array. $tg_json = []; debug_log(count($update),"Received raids:"); @@ -315,51 +334,57 @@ function isPointInsidePolygon($point, $vertices) { } if($send_updates == true) { require_once(LOGIC_PATH .'/update_raid_poll.php'); - $update = update_raid_poll($raid_id, $raid, false, $tg_json, false); // update_raid_poll() will return false if the raid isn't shared to any chat - if($update != false) $tg_json = $update; - }else { - // Get chats to share to by raid level and geofence id - $chats_geofence = []; - if($geofences != false) { - foreach ($inside_geofences as $geofence_id) { - $const_geofence = 'WEBHOOK_CHATS_LEVEL_' . $level . '_' . $geofence_id; - $const_geofence_chats = $config->{$const_geofence}; + $tg_json = update_raid_poll($raid_id, $raid, false, $tg_json, false); + } + // Get chats to share to by raid level and geofence id + $chats_geofence = []; + if($geofences != false) { + foreach ($inside_geofences as $geofence_id) { + $const_geofence = 'WEBHOOK_CHATS_LEVEL_' . $level . '_' . $geofence_id; + $const_geofence_chats = $config->{$const_geofence}; - if(!empty($const_geofence_chats)) { - $chats_geofence = explode(',', $const_geofence_chats); - } + if(!empty($const_geofence_chats)) { + $chats_geofence = explode(',', $const_geofence_chats); } } + } - // Get chats to share to by raid level - $const = 'WEBHOOK_CHATS_LEVEL_' . $level; - $const_chats = $config->{$const}; + // Get chats to share to by raid level + $const = 'WEBHOOK_CHATS_LEVEL_' . $level; + $const_chats = $config->{$const}; - $chats_raidlevel =[]; - if(!empty($const_chats)) { - $chats_raidlevel = explode(',', $const_chats); - } + $chats_raidlevel =[]; + if(!empty($const_chats)) { + $chats_raidlevel = explode(',', $const_chats); + } - // Get chats - $webhook_chats = []; - if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { - $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); - } + // Get chats + $webhook_chats = []; + if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { + $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); + } - $chats_by_pokemon = []; + $chats_by_pokemon = []; + if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0])) { foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { - info_log(print_r($rule,true)); if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { - $chats_by_pokemon = $rule['chats']; + foreach($rule['chats'] as $rule_chat) { + // If the raid isn't already posted to the chats specified in WEBHOOK_CHATS_BY_POKEMON, we add it to the array + if(!isset($cleanup_data[$raid_id]) or !in_array($rule_chat, $cleanup_data[$raid_id])) { + $chats_by_pokemon[] = $rule_chat; + } + } } } + } - $chats = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats, $chats_by_pokemon); + $chats = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats, $chats_by_pokemon); - require_once(LOGIC_PATH .'/send_raid_poll.php'); - if ($metrics){ - $webhook_raids_posted_total->inc(); - } + require_once(LOGIC_PATH .'/send_raid_poll.php'); + if ($metrics){ + $webhook_raids_posted_total->inc(); + } + if(count($chats) > 0) { $tg_json = send_raid_poll($raid_id, $chats, $raid, $tg_json); } } From 208e5ce2071808867440e886c6b638b8e474bf9b Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Mar 2022 10:33:12 +0200 Subject: [PATCH 005/367] Fixed webhook posting not respecting WEBHOOK_CREATE_ONLY --- commands/raid_from_webhook.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index c41a6e5d..a4a5a465 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -52,6 +52,9 @@ function isPointInsidePolygon($point, $vertices) { } } +// Skip posting if create only -mode is set or raid time is greater than value set in config +$no_auto_posting = ($config->WEBHOOK_CREATE_ONLY or ($raid['message']['end']-$raid['message']['start']) > ($config->WEBHOOK_EXCLUDE_AUTOSHARE_DURATION * 60)); + // Telegram JSON array. $tg_json = []; debug_log(count($update),"Received raids:"); @@ -269,8 +272,7 @@ function isPointInsidePolygon($point, $vertices) { $webhook_raids_accepted_total->inc(); } - // Skip posting if create only -mode is set or raid time is greater than value set in config - if ($config->WEBHOOK_CREATE_ONLY or ($raid['message']['end']-$raid['message']['start']) > ($config->WEBHOOK_EXCLUDE_AUTOSHARE_DURATION * 60) ) { + if ($no_auto_posting) { debug_log($gym_name,'Not autoposting raid, WEBHOOK_CREATE_ONLY is set to true or raids duration is over the WEBHOOK_EXCLUDE_AUTOSHARE_DURATION threshold:'); continue; } @@ -336,6 +338,9 @@ function isPointInsidePolygon($point, $vertices) { require_once(LOGIC_PATH .'/update_raid_poll.php'); $tg_json = update_raid_poll($raid_id, $raid, false, $tg_json, false); } + + if($no_auto_posting) continue; + // Get chats to share to by raid level and geofence id $chats_geofence = []; if($geofences != false) { From c97272386e14f7107f3e8af16ad969cd753a2b4e Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Mar 2022 10:34:50 +0200 Subject: [PATCH 006/367] Tried fixing timezone mess with import upcoming bosses Might work, might not. We'll see in a year Also edited the date display of scheduled bosses under pokedex --- logic/read_upcoming_bosses.php | 22 +++++++++------------- mods/import_future_bosses.php | 5 +++-- mods/pokedex_list_raids.php | 4 ++-- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index 09c0670c..17714d08 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -6,13 +6,10 @@ * @return string */ function read_upcoming_bosses($return_sql = false) { - global $config; $link = curl_get_contents('https://fight.pokebattler.com/raids'); $pb = json_decode($link,true); - $now = new dateTimeZone($config->TIMEZONE); - $transitions = ( $now->getTransitions()[0]['isdst'] ? 0 : 1 ); - $tz_offset = (-7 - $transitions)*60*60; + $pb_timezone = new dateTimeZone('America/Phoenix'); $count = 0; $sql = $list = $prev_start = $prev_rl = ''; foreach($pb['breakingNews'] as $news) { @@ -20,8 +17,11 @@ function read_upcoming_bosses($return_sql = false) { $rl = str_replace('RAID_LEVEL_','', $news['tier']); if($rl == "MEGA") $raid_level_id = 6; else $raid_level_id = $rl; if($raid_level_id != '5' and $raid_level_id != '6') break; // Limit scheduling to tier 5 and mega only - $starttime = new DateTime("@".(substr($news['startDate'],0,10) + $tz_offset), new dateTimeZone('UTC')); - $endtime = new DateTime("@".(substr($news['endDate'],0,10) + $tz_offset), new dateTimeZone('UTC')); + $starttime = new DateTime("@".(substr($news['startDate'],0,10)), new dateTimeZone('UTC')); + $endtime = new DateTime("@".(substr($news['endDate'],0,10)), new dateTimeZone('UTC')); + + $starttime->setTimezone($pb_timezone); + $endtime->setTimezone($pb_timezone); // If the boss only appears for an hour, the eggs most likely start to spawn 20 minutes prior to the time. $diff = $starttime->diff($endtime); @@ -30,16 +30,12 @@ function read_upcoming_bosses($return_sql = false) { } $date_start = $starttime->format('Y-m-d H:i:s'); - if($endtime->format('H') == '11') { - // Usually the switch happens at 10. Pokebattler sets the end time to 11, so we must manually set it to 10 - $date_end = $endtime->format('Y-m-d').' 10:00:00'; - }else { - $date_end = $endtime->format('Y-m-d H:i:s'); - } + $date_end = $endtime->format('Y-m-d H:i:s'); $dex_id_form = explode('-',resolve_boss_name_to_ids($news['pokemon']),2); if($prev_start != $date_start) { - $list.= CR . '' . $date_start . ' - ' . $date_end . ':' . CR; + $list.= CR . EMOJI_CLOCK . ' ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; + $prev_rl = ''; } if($prev_rl != $raid_level_id) { $list.= '' . getTranslation($raid_level_id . 'stars') .':' . CR; diff --git a/mods/import_future_bosses.php b/mods/import_future_bosses.php index ac2b1e9a..beac26a4 100644 --- a/mods/import_future_bosses.php +++ b/mods/import_future_bosses.php @@ -32,7 +32,7 @@ if(!empty($list)) { $now = new DateTime('now', new DateTimeZone($config->TIMEZONE)); $query = my_query(" - SELECT * FROM raid_bosses + SELECT id, pokedex_id, pokemon_form_id, raid_level, scheduled, DATE_FORMAT(date_start, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_start, DATE_FORMAT(date_end, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_end FROM raid_bosses WHERE date_end > '" . $now->format('Y-m-d H:i:s') . "' AND scheduled = 1 ORDER BY date_start, raid_level, pokedex_id, pokemon_form_id @@ -41,7 +41,8 @@ $msg = '' . getTranslation('current_scheduled_bosses') . ':'; foreach($query->fetchAll() as $result) { if($prev_start != $result['date_start']) { - $msg.= CR . '' . $result['date_start'] . ' - ' . $result['date_end'] . ':' . CR; + $msg.= CR . EMOJI_CLOCK . ' ' . $result['date_start'] . ' — ' . $result['date_end'] . ':' . CR; + $prev_rl = ''; } if($prev_rl != $result['raid_level']) { $msg.= '' . getTranslation($result['raid_level'] . 'stars') .':' . CR; diff --git a/mods/pokedex_list_raids.php b/mods/pokedex_list_raids.php index cad3b361..45f12c7b 100644 --- a/mods/pokedex_list_raids.php +++ b/mods/pokedex_list_raids.php @@ -12,7 +12,7 @@ // Get all pokemon with raid levels from database. $rs = my_query( " - SELECT raid_bosses.id, raid_bosses.pokedex_id, raid_bosses.pokemon_form_id, raid_bosses.raid_level, raid_bosses.date_start, raid_bosses.date_end, raid_bosses.scheduled + SELECT raid_bosses.id, raid_bosses.pokedex_id, raid_bosses.pokemon_form_id, raid_bosses.raid_level, DATE_FORMAT(date_start, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_start, DATE_FORMAT(date_end, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_end, raid_bosses.scheduled FROM raid_bosses LEFT JOIN pokemon ON raid_bosses.pokedex_id = pokemon.pokedex_id @@ -44,7 +44,7 @@ if($pokemon['scheduled'] == 0) { $msg .= '' . getTranslation('unscheduled_bosses') . ':' . CR; }else { - $msg .= EMOJI_CLOCK . ' ' . $pokemon['date_start'] . ' - ' . $pokemon['date_end'] . ':' . CR ; + $msg .= EMOJI_CLOCK . ' ' . $pokemon['date_start'] . ' — ' . $pokemon['date_end'] . ':' . CR ; } $previous_level = 'FIRST_RUN'; } From d4975d13f98a4b5f23798f2400e86179d5bdd9fa Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Mar 2022 20:41:59 +0200 Subject: [PATCH 007/367] Fix --- mods/vote_time.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/vote_time.php b/mods/vote_time.php index 07dbec89..69fafdf4 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -64,7 +64,7 @@ } // Vote time in the future or Raid anytime? -if($now <= $attend_time_compare || $vote_time == 0) { +if($vote_time == 0 || $now <= $attend_time_compare) { // If user is attending remotely, get the number of remote users already attending if (!is_array($answer) or !in_array('remote', $answer) or $answer['remote'] == 0){ $remote_users = 0; From cbce7d0bd5d6bd4dd88f3a8d1101bfbe3b293596 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Mar 2022 20:48:55 +0200 Subject: [PATCH 008/367] Changed user_id column in user_input table to bigint This is overflowing with newer Telegram users --- VERSION | 2 +- sql/pokemon-raid-bot.sql | 2 +- sql/upgrade/5.sql | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 sql/upgrade/5.sql diff --git a/VERSION b/VERSION index b8626c4c..7ed6ff82 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4 +5 diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 6d3ec13f..76773f30 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -120,7 +120,7 @@ CREATE TABLE `trainerinfo` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `user_input` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `user_id` int(11) DEFAULT NULL, + `user_id` bigint(20) DEFAULT NULL, `handler` varchar(45) DEFAULT NULL, `modifiers` text DEFAULT NULL, PRIMARY KEY (`id`) diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql new file mode 100644 index 00000000..c8fd9c68 --- /dev/null +++ b/sql/upgrade/5.sql @@ -0,0 +1 @@ +ALTER TABLE user_input CHANGE COLUMN IF EXISTS `user_id` `user_id` BIGINT(20) DEFAULT NULL AFTER `id`; From 53b44f475f64333df09d32f7dd27414b4ae98a29 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sat, 19 Mar 2022 16:42:42 +0200 Subject: [PATCH 009/367] Collect metrics on Telegram responses to API calls Example metrics after a while of normal running: ``` pokemonraidbot_tg_response_count{code="200",method="answerCallbackQuery",description=""} 16 pokemonraidbot_tg_response_count{code="200",method="deleteMessage",description=""} 38 pokemonraidbot_tg_response_count{code="200",method="editMessageCaption",description=""} 30 pokemonraidbot_tg_response_count{code="200",method="editMessageMedia",description=""} 20 pokemonraidbot_tg_response_count{code="200",method="editMessageText",description=""} 209 pokemonraidbot_tg_response_count{code="200",method="sendPhoto",description=""} 40 pokemonraidbot_tg_response_count{code="400",method="deleteMessage",description="Bad Request: message to delete not found"} 1 ``` --- logic/curl_json_response.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/logic/curl_json_response.php b/logic/curl_json_response.php index 7c0855e8..67592461 100644 --- a/logic/curl_json_response.php +++ b/logic/curl_json_response.php @@ -1,4 +1,9 @@ registerCounter($namespace, 'tg_response_count', 'Counters of response codes from Telegram', ['code', 'method', 'description']); +} + /** * Process response from telegram api. * @param string $json_response Json response from Telegram @@ -8,12 +13,24 @@ */ function curl_json_response($json_response, $json, $identifier = false) { - global $config; + global $config, $metrics, $tg_response_code; // Write to log. debug_log_incoming($json_response, '<-'); - // Decode json response. + // Decode json objects + $request = json_decode($json, true); $response = json_decode($json_response, true); + if ($metrics){ + $code = 200; + $method = $request['method']; + $description = null; + if (isset($response['error_code'])) { + $code = $response['error_code']; + # We have to also include the description because TG overloads error codes + $description = $response['description']; + } + $tg_response_code->inc([$code, $method, $description]); + } // Validate response. if ((isset($response['ok']) && $response['ok'] != true) || isset($response['update_id'])) { info_log("{$json} -> {$json_response}", 'ERROR:'); From 98d261f7f113245f0a65c09940d82810f5f988fe Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 20 Mar 2022 10:19:45 +0200 Subject: [PATCH 010/367] Another webhook autopost fix --- commands/raid_from_webhook.php | 71 ++++++++++++++++------------------ 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index a4a5a465..e7e819f1 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -334,52 +334,47 @@ function isPointInsidePolygon($point, $vertices) { $dbh = null; exit; } + $chats_geofence = $chats_raidlevel = $webhook_chats = $chats_by_pokemon = []; if($send_updates == true) { require_once(LOGIC_PATH .'/update_raid_poll.php'); $tg_json = update_raid_poll($raid_id, $raid, false, $tg_json, false); - } - - if($no_auto_posting) continue; - - // Get chats to share to by raid level and geofence id - $chats_geofence = []; - if($geofences != false) { - foreach ($inside_geofences as $geofence_id) { - $const_geofence = 'WEBHOOK_CHATS_LEVEL_' . $level . '_' . $geofence_id; - $const_geofence_chats = $config->{$const_geofence}; - - if(!empty($const_geofence_chats)) { - $chats_geofence = explode(',', $const_geofence_chats); + if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0]) && !$no_auto_posting) { + foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { + if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { + foreach($rule['chats'] as $rule_chat) { + // If the raid isn't already posted to the chats specified in WEBHOOK_CHATS_BY_POKEMON, we add it to the array + if(!isset($cleanup_data[$raid_id]) or !in_array($rule_chat, $cleanup_data[$raid_id])) { + $chats_by_pokemon[] = $rule_chat; + } + } + } + } + } + if(empty($chats_by_pokemon)) continue; + }else { + // Get chats to share to by raid level and geofence id + if($geofences != false) { + foreach ($inside_geofences as $geofence_id) { + $const_geofence = 'WEBHOOK_CHATS_LEVEL_' . $level . '_' . $geofence_id; + $const_geofence_chats = $config->{$const_geofence}; + + if(!empty($const_geofence_chats)) { + $chats_geofence = explode(',', $const_geofence_chats); + } } } - } - - // Get chats to share to by raid level - $const = 'WEBHOOK_CHATS_LEVEL_' . $level; - $const_chats = $config->{$const}; - $chats_raidlevel =[]; - if(!empty($const_chats)) { - $chats_raidlevel = explode(',', $const_chats); - } + // Get chats to share to by raid level + $const = 'WEBHOOK_CHATS_LEVEL_' . $level; + $const_chats = $config->{$const}; - // Get chats - $webhook_chats = []; - if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { - $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); - } + if(!empty($const_chats)) { + $chats_raidlevel = explode(',', $const_chats); + } - $chats_by_pokemon = []; - if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0])) { - foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { - if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { - foreach($rule['chats'] as $rule_chat) { - // If the raid isn't already posted to the chats specified in WEBHOOK_CHATS_BY_POKEMON, we add it to the array - if(!isset($cleanup_data[$raid_id]) or !in_array($rule_chat, $cleanup_data[$raid_id])) { - $chats_by_pokemon[] = $rule_chat; - } - } - } + // Get chats + if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { + $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); } } From 894cc6fa602d64386769838dc0a1e08e8a6d73a0 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 23 Mar 2022 19:22:39 +0200 Subject: [PATCH 011/367] Added new RAID_PICTURE_SEND_METHOD If this config value is set to something else than `url`, bot pushes raidpicture instead of have TG fetch it from an url Hopefully this mitigates some issues related to TG fetching the raidpicture from an url. Requires PHP version 8+. TODO: Handle errors if TG rejects file_unique_id we're sending them. Might happen since we have no idea how long TG stores the images. We'll do this when it actually happens and we know what the specific error message for this is. --- commands/help.php | 2 +- commands/raid_from_webhook.php | 1 + commands/start.php | 2 +- commands/tutorial.php | 2 +- config/defaults-config.json | 1 + core/bot/cleanup_run.php | 2 + core/bot/logic/sql_utils.php | 4 +- core/telegram/functions.php | 125 +++---- logic/curl_json_response.php | 34 +- logic/get_raid.php | 3 +- logic/insert_cleanup.php | 24 +- logic/keys_vote.php | 14 +- logic/raid_level.php | 2 +- logic/raid_picture.php | 653 ++++++++++++++++++++++++++++++++- logic/send_raid_poll.php | 13 +- logic/show_raid_poll.php | 4 +- logic/update_raid_poll.php | 72 ++-- mods/end_remote_raid.php | 2 +- mods/raid_set_poke.php | 2 +- mods/refresh_polls.php | 10 +- mods/tutorial.php | 2 +- mods/vote_refresh.php | 2 +- raidpicture.php | 640 +++----------------------------- sql/pokemon-raid-bot.sql | 15 +- sql/upgrade/5.sql | 4 + 25 files changed, 884 insertions(+), 751 deletions(-) diff --git a/commands/help.php b/commands/help.php index 66f08396..77d37835 100644 --- a/commands/help.php +++ b/commands/help.php @@ -69,7 +69,7 @@ ] ]; $photo = $tutorial[0]['photo']; - send_photo($update['message']['from']['id'],$photo, $msg, $keys, ['disable_web_page_preview' => 'true']); + send_photo($update['message']['from']['id'],$photo, false, $msg, $keys, ['disable_web_page_preview' => 'true']); exit(); // No help for the user. diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index e7e819f1..96008fb5 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -327,6 +327,7 @@ function isPointInsidePolygon($point, $vertices) { 'event_raid_duration' => NULL, 'event_hide_raid_picture' => NULL, 'event_poll_template' => NULL, + 'raid_ended' => 0, ]); } catch (PDOException $exception) { diff --git a/commands/start.php b/commands/start.php index 23816ba8..d2463f0c 100644 --- a/commands/start.php +++ b/commands/start.php @@ -28,7 +28,7 @@ ] ]; $photo = $tutorial[0]['photo']; - send_photo($update['message']['from']['id'], $photo, $msg, $keys, ['disable_web_page_preview' => 'true'],false); + send_photo($update['message']['from']['id'], $photo, false, $msg, $keys, ['disable_web_page_preview' => 'true'],false); }else { // Trim away everything before "/start " $searchterm = $update['message']['text']; diff --git a/commands/tutorial.php b/commands/tutorial.php index 3b8b7695..207a002c 100644 --- a/commands/tutorial.php +++ b/commands/tutorial.php @@ -28,5 +28,5 @@ ] ]; $photo = $tutorial[0]['photo']; -send_photo($update['message']['from']['id'], $photo, $msg, $keys, ['disable_web_page_preview' => 'true'],false); +send_photo($update['message']['from']['id'], $photo, false, $msg, $keys, ['disable_web_page_preview' => 'true'],false); ?> \ No newline at end of file diff --git a/config/defaults-config.json b/config/defaults-config.json index 51c72229..233d00dc 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -58,6 +58,7 @@ "RAID_PICTURE": false, "RAID_PICTURE_AUTOEXTEND": false, "RAID_AUTOMATIC_ALARM": false, + "RAID_PICTURE_SEND_METHOD": "url", "RAID_PICTURE_HIDE_LEVEL":"", "RAID_PICTURE_HIDE_POKEMON":"", "RAID_PICTURE_BG_COLOR":"0,0,0", diff --git a/core/bot/cleanup_run.php b/core/bot/cleanup_run.php index fb9598b6..36d4af37 100644 --- a/core/bot/cleanup_run.php +++ b/core/bot/cleanup_run.php @@ -91,8 +91,10 @@ function perform_cleanup(){ } $q_a = my_query('DELETE FROM attendance WHERE raid_id IN (SELECT id FROM raids WHERE raids.end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_DB.' MINUTE))'); $q_r = my_query('DELETE FROM raids WHERE end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_DB.' MINUTE)'); + $q_p = my_query('DELETE photo_cache FROM photo_cache LEFT JOIN raids ON photo_cache.raid_id = raids.id WHERE photo_cache.ended = 0 AND raids.id IS NULL'); cleanup_log('Cleaned ' . $q_a->rowCount() . ' rows from attendance table'); cleanup_log('Cleaned ' . $q_r->rowCount() . ' rows from raids table'); + cleanup_log('Cleaned ' . $q_p->rowCount() . ' rows from photo_cache table'); if ($metrics){ $cleanup_total->incBy($q_a->rowCount(), ['db_attendance']); $cleanup_total->incBy($q_r->rowCount(), ['db_raids']); diff --git a/core/bot/logic/sql_utils.php b/core/bot/logic/sql_utils.php index c95c1218..327e17eb 100644 --- a/core/bot/logic/sql_utils.php +++ b/core/bot/logic/sql_utils.php @@ -42,12 +42,12 @@ function my_query($query, $binds=null) } catch (PDOException $exception) { // The message will be output in the global handler, we just need to extract the failing query error_log('The following query failed:'); - log_query($stmt, $binds, 'error_log'); + log_query($stmt, print_r($binds, true), 'error_log'); throw $exception; } finally { debug_log_sql('Query success', '$'); if($config->DEBUG_SQL) { - log_query($stmt, $binds, 'debug_log_sql'); + log_query($stmt, print_r($binds, true), 'debug_log_sql'); } } return $stmt; diff --git a/core/telegram/functions.php b/core/telegram/functions.php index 6a10d0a0..8cdfddbe 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -591,147 +591,139 @@ function get_chatmember($chat_id, $user_id, $multicurl = false) /** * Send photo. * @param $chat_id - * @param $photo_url + * @param string $media_content content of the media file. + * @param bool $content_type true = photo file, false = file_id * @param array $text * @param mixed $inline_keyboard * @param array $merge_args * @param array $multicurl * @param int $identifier */ -function send_photo($chat_id, $photo_url, $text = array(), $inline_keyboard = false, $merge_args = [], $multicurl = false, $identifier = false) +function send_photo($chat_id, $media_content, $content_type, $text = '', $inline_keyboard = false, $merge_args = [], $multicurl = false, $identifier = false) { // Create response content array. - $reply_content = [ - 'method' => 'sendPhoto', - 'chat_id' => $chat_id, - 'photo' => $photo_url, - 'parse_mode' => 'HTML', - 'caption' => $text + $post_contents = [ + 'method' => 'sendPhoto', + 'chat_id' => $chat_id, + 'reply_markup' => json_encode(['inline_keyboard' => $inline_keyboard]), ]; + if($text != '') { + $post_contents['caption'] = $text; + $post_contents['parse_mode'] = 'HTML'; + } if(!is_valid_target($chat_id, null, false, true)){ info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); - info_log($reply_content, 'ERROR: data would have been:'); + info_log(print_r($post_contents, true), 'ERROR: data would have been:'); exit(); } - debug_log($inline_keyboard, 'KEYS:'); + $post_contents['photo'] = ($content_type) ? new CURLStringFile($media_content, 'photo') : $media_content; - if (isset($inline_keyboard)) { - $reply_content['reply_markup'] = ['inline_keyboard' => $inline_keyboard]; - } + debug_log($inline_keyboard, 'KEYS:'); if (is_array($merge_args) && count($merge_args)) { - $reply_content = array_merge_recursive($reply_content, $merge_args); + $post_contents = array_merge_recursive($post_contents, $merge_args); } - // Encode data to json. - $reply_json = json_encode($reply_content); - header('Content-Type: application/json'); - - debug_log($reply_json, '>'); + debug_log(print_r($post_contents, true), '>'); // Send request to telegram api. - return curl_request($reply_json, $multicurl, $identifier); + return curl_request($post_contents, $multicurl, $identifier); } /** * Edit message media and text. * @param $id_val * @param $text_val - * @param $url + * @param string $media_content content of the media file. + * @param bool $content_type true = photo file, false = file_id/url * @param $markup_val * @param null $chat_id * @param mixed $merge_args * @param $multicurl */ -function editMessageMedia($id_val, $text_val, $url, $markup_val, $chat_id = NULL, $merge_args = false, $multicurl = false) +function editMessageMedia($id_val, $text_val, $media_content, $content_type, $inline_keyboard = false, $chat_id = NULL, $merge_args = false, $multicurl = false, $identifier = false) { // Create response array. - $response = [ + $post_contents = [ 'method' => 'editMessageMedia', 'media' => [ 'type' => 'photo', - 'media' => $url, 'caption' => $text_val, 'parse_mode'=> 'HTML' - ], - 'reply_markup' => [ - 'inline_keyboard' => $markup_val ] ]; - if ($markup_val == false) { - unset($response['reply_markup']); - $response['remove_keyboard'] = true; + if ($inline_keyboard !== false) { + $post_contents['reply_markup'] = json_encode(['inline_keyboard' => $inline_keyboard]); + }else { + $post_contents['remove_keyboard'] = true; } if ($chat_id != null) { - $response['chat_id'] = $chat_id; - $response['message_id'] = $id_val; + $post_contents['chat_id'] = $chat_id; + $post_contents['message_id'] = $id_val; } else { - $response['inline_message_id'] = $id_val; + $post_contents['inline_message_id'] = $id_val; } if (is_array($merge_args) && count($merge_args)) { - $response = array_merge_recursive($response, $merge_args); + $post_contents = array_merge_recursive($post_contents, $merge_args); } if(!is_valid_target($chat_id, $id_val, true, false)){ info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit media of invalid chat/message id:'); - info_log($response, 'ERROR: data would have been:'); + info_log(print_r($post_contents, true), 'ERROR: data would have been:'); exit(); } // Encode response to json format. - $json_response = json_encode($response); - debug_log($response, '<-'); + if($content_type) { + $post_contents['photo'] = new CURLStringFile($media_content, 'photo'); + $post_contents['media']['media'] = 'attach://photo'; + } else { + $post_contents['media']['media'] = $media_content; + } + $post_contents['media'] = json_encode($post_contents['media']); + debug_log(print_r($post_contents, true), '->'); // Send request to telegram api. - return curl_request($json_response, $multicurl); + return curl_request($post_contents, $multicurl, $identifier); } /** * Send request to telegram api - single or multi?. - * @param $json + * @param $post_contents * @param $multicurl * @param $identifier * @return mixed */ -function curl_request($json, $multicurl = false, $identifier = false) +function curl_request($post_contents, $multicurl = false, $identifier = false) { // Send request to telegram api. if($multicurl == true) { - return ['json' => $json, 'identifier' => $identifier]; + return ['post_contents' => $post_contents, 'identifier' => $identifier]; } else { - return curl_json_request($json, $identifier); + return curl_json_request($post_contents, $identifier); } } /** * Send request to telegram api. - * @param $json + * @param $post_contents * @param $identifier * @return mixed */ -function curl_json_request($json, $identifier) +function curl_json_request($post_contents, $identifier) { global $config; - // Bridge mode? - if($config->BRIDGE_MODE) { - // Add bot folder name to callback data - debug_log('Adding bot folder name "' . basename(ROOT_PATH) . '" to callback data'); - $search = '"callback_data":"'; - $replace = $search . basename(ROOT_PATH) . ':'; - $json = str_replace($search,$replace,$json); - } // Telegram $URL = 'https://api.telegram.org/bot' . API_KEY . '/'; $curl = curl_init($URL); - curl_setopt($curl, CURLOPT_HEADER, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json")); + if(!is_array($post_contents)) curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json")); curl_setopt($curl, CURLOPT_POST, true); - curl_setopt($curl, CURLOPT_POSTFIELDS, $json); + curl_setopt($curl, CURLOPT_POSTFIELDS, $post_contents); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($curl, CURLOPT_TIMEOUT, 10); @@ -741,7 +733,8 @@ function curl_json_request($json, $identifier) } // Write to log. - debug_log($json, '->'); + if(is_array($post_contents)) debug_log(print_r($post_contents,true), '->'); + else debug_log($post_contents, '->'); // Execute curl request. $json_response = curl_exec($curl); @@ -754,7 +747,7 @@ function curl_json_request($json, $identifier) curl_close($curl); // Process response from telegram api. - $response = curl_json_response($json_response, $json, $identifier); + $response = curl_json_response($json_response, $post_contents, $identifier); // Return response. return $response; @@ -788,7 +781,7 @@ function curl_json_multi_request($json) // Curl options. curl_setopt($curly[$id], CURLOPT_URL, $URL); curl_setopt($curly[$id], CURLOPT_HEADER, false); - curl_setopt($curly[$id], CURLOPT_HTTPHEADER, array("Content-type: application/json")); + if(!is_array($data['post_contents'])) curl_setopt($curly[$id], CURLOPT_HTTPHEADER, array("Content-type: application/json")); curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, true); curl_setopt($curly[$id], CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($curly[$id], CURLOPT_TIMEOUT, 10); @@ -798,24 +791,16 @@ function curl_json_multi_request($json) curl_setopt($curly[$id], CURLOPT_PROXY, $config->CURL_PROXYSERVER); } - // Bridge mode? - if($config->BRIDGE_MODE) { - // Add bot folder name to callback data - debug_log('Adding bot folder name "' . basename(ROOT_PATH) . '" to callback data'); - $search = '"callback_data":"'; - $replace = $search . basename(ROOT_PATH) . ':'; - array_push($data['json'], str_replace($search,$replace,$data['json'])); - } - // Curl post. curl_setopt($curly[$id], CURLOPT_POST, true); - curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $data['json']); + curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $data['post_contents']); // Add multi handle. curl_multi_add_handle($mh, $curly[$id]); // Write to log. - debug_log($data['json'], '->'); + if(is_array($data['post_contents'])) debug_log(print_r($data['post_contents'],true), '->'); + else debug_log($data['post_contents'], '->'); } // Execute the handles. @@ -837,7 +822,7 @@ function curl_json_multi_request($json) // Process response from telegram api. foreach($response as $id => $json_response) { - $response[$id] = curl_json_response($response[$id], $json[$id]['json'], $json[$id]['identifier']); + $response[$id] = curl_json_response($response[$id], $json[$id]['post_contents'], $json[$id]['identifier']); debug_log_incoming($json_response, '<-'); } diff --git a/logic/curl_json_response.php b/logic/curl_json_response.php index 67592461..28c4bf26 100644 --- a/logic/curl_json_response.php +++ b/logic/curl_json_response.php @@ -8,7 +8,7 @@ * Process response from telegram api. * @param string $json_response Json response from Telegram * @param string $json Json sent to Telegram - * @param int|string $identifier + * @param array|int|string $identifier raid array from get_raid, raid id or [overview/trainer] * @return mixed */ function curl_json_response($json_response, $json, $identifier = false) @@ -33,6 +33,7 @@ function curl_json_response($json_response, $json, $identifier = false) } // Validate response. if ((isset($response['ok']) && $response['ok'] != true) || isset($response['update_id'])) { + if(is_array($json)) $json = json_encode($json); info_log("{$json} -> {$json_response}", 'ERROR:'); } else { if($identifier != false) { @@ -40,7 +41,7 @@ function curl_json_response($json_response, $json, $identifier = false) // Set chat and message_id $chat_id = $response['result']['chat']['id']; $message_id = $response['result']['message_id']; - debug_log('Return data: Chat id: '.$chat_id.', message_id: '.$message_id.', type: '.$identifier); + debug_log('Return data: Chat id: '.$chat_id.', message_id: '.$message_id.', type: '.(is_array($identifier) ? print_r($identifier,true) : $identifier)); if($identifier == 'trainer') { debug_log('Adding trainermessage info to database now!'); insert_trainerinfo($chat_id, $message_id); @@ -60,7 +61,34 @@ function curl_json_response($json_response, $json, $identifier = false) }else if(isset($response['result']['photo']) && !isset($response['result']['caption'])) { $type = 'photo'; } - insert_cleanup($chat_id, $message_id, $identifier, $type); + $save_id = $unique_id = false; + if(isset($response['result']['photo'])) { + $largest_size = 0; + foreach($response['result']['photo'] as $photo) { + if($photo['file_size'] > $largest_size) { + $largest_size = $photo['file_size']; + $save_id = $photo['file_id']; + $unique_id = $photo['file_unique_id']; + } + } + $standalone_photo = (array_key_exists('standalone_photo', $identifier) && $identifier['standalone_photo'] === true) ? true : false; + my_query(" + REPLACE INTO photo_cache + VALUES (:id, :unique_id, :pokedex_id, :form_id, :raid_id, :ended, :gym_id, :standalone) + ",[ + ':id' => $save_id, + ':unique_id' => $unique_id, + ':pokedex_id' => $identifier['pokemon'], + ':form_id' => $identifier['pokemon_form'], + ':raid_id' => ($identifier['raid_ended'] ? 0 : $identifier['id']), // No need to save raid id if raid has ended + ':ended' => $identifier['raid_ended'], + ':gym_id' => $identifier['gym_id'], + ':standalone' => $standalone_photo, + ] + ); + } + $raid_id = is_array($identifier) ? $identifier['id'] : $identifier; + insert_cleanup($chat_id, $message_id, $raid_id, $type, $unique_id); } } } diff --git a/logic/get_raid.php b/logic/get_raid.php index d4f3e352..2c76107e 100644 --- a/logic/get_raid.php +++ b/logic/get_raid.php @@ -18,7 +18,8 @@ function get_raid($raid_id) gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, gyms.gym_note, users.name, users.trainername, users.nick, events.name as event_name, events.description as event_description, events.vote_key_mode as event_vote_key_mode, events.time_slots as event_time_slots, events.raid_duration as event_raid_duration, events.hide_raid_picture as event_hide_raid_picture, events.poll_template as event_poll_template, - TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left + TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left, + IF(UTC_TIMESTAMP() > end_time, 1, 0) as raid_ended FROM raids LEFT JOIN gyms ON raids.gym_id = gyms.id diff --git a/logic/insert_cleanup.php b/logic/insert_cleanup.php index b77b6fdc..827fffac 100644 --- a/logic/insert_cleanup.php +++ b/logic/insert_cleanup.php @@ -5,8 +5,9 @@ * @param $message_id * @param $raid_id * @param $type + * @param $photo_id */ -function insert_cleanup($chat_id, $message_id, $raid_id, $type) +function insert_cleanup($chat_id, $message_id, $raid_id, $type, $photo_id = NULL) { // Log ID's of raid, chat and message debug_log('Raid_ID: ' . $raid_id); @@ -17,14 +18,21 @@ function insert_cleanup($chat_id, $message_id, $raid_id, $type) if ((is_numeric($chat_id)) && (is_numeric($message_id)) && (is_numeric($raid_id)) && ($raid_id > 0)) { // Build query for cleanup table to add cleanup info to database debug_log('Adding cleanup info to database:'); - $rs = my_query( - " - INSERT INTO cleanup - SET raid_id = '{$raid_id}', - chat_id = '{$chat_id}', - message_id = '{$message_id}', - type = '{$type}' + my_query( " + REPLACE INTO cleanup + SET raid_id = :raid_id, + chat_id = :chat_id, + message_id = :message_id, + type = :type, + media_unique_id = :media_unique_id + ", [ + ':raid_id' => $raid_id, + ':chat_id' => $chat_id, + ':message_id' => $message_id, + ':type' => $type, + ':media_unique_id' => $photo_id, + ] ); } else { debug_log('Invalid input for cleanup preparation!'); diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 6d9baf1b..219fe6d9 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -21,11 +21,11 @@ function keys_vote($raid) debug_log($start_time, 'UTC START:'); // Raid ended already. - if ($end_time < $now) { + if ($raid['raid_ended']) { if($config->RAID_ENDED_HIDE_KEYS) { - $keys = []; + return []; }else { - $keys = [ + return [ [ [ 'text' => getPublicTranslation('raid_done'), @@ -50,7 +50,7 @@ function keys_vote($raid) // Show buttons to users? if(in_array($raid_level, $hide_buttons_raid_level) || in_array(($raid_pokemon_id . "-" . get_pokemon_form_name($raid_pokemon_id,$raid_pokemon_form_id)), $hide_buttons_pokemon) || in_array($raid_pokemon_id, $hide_buttons_pokemon)) { - $keys = []; + return []; } else { // Extra Keys $buttons_alone = [ @@ -566,11 +566,11 @@ function keys_vote($raid) if(!empty($keys[$r][0])) $r++; } } + + // Return the keys. + return $keys; } } - - // Return the keys. - return $keys; } ?> diff --git a/logic/raid_level.php b/logic/raid_level.php index a46d0f9a..bfb73652 100644 --- a/logic/raid_level.php +++ b/logic/raid_level.php @@ -37,7 +37,7 @@ function get_raid_level($pokedex_id, $pokemon_form_id) * Get active raid bosses at a certain time. * @param $time - string, datetime, local time * @param $raid_level - ENUM('1', '2', '3', '4', '5', '6', 'X') - * @return string + * @return array */ function get_raid_bosses($time, $raid_level) { diff --git a/logic/raid_picture.php b/logic/raid_picture.php index bee70152..9424ec64 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -22,15 +22,666 @@ function raid_picture_url($raid, $standalone = false) // We'll set raid start and end times to 0 to get a new image for when the raid has ended. // Setting thetimes to 0 also makes it so TG can cache the raid ended -images and reuse them $start_time = $end_time = 0; + $raid_id = ''; }else { $start_time = strtotime($raid['start_time']); $end_time = strtotime($raid['end_time']); + $raid_id = 'raid='.$raid['id'].'&'; } if($raid['event'] == EVENT_ID_EX) $ex_raid = '1'; else $ex_raid = '0'; - $picture_url = "{$config->RAID_PICTURE_URL}?pokemon={$raid['pokemon']}&pokemon_form={$raid['pokemon_form']}&gym_id={$raid['gym_id']}&start_time={$start_time}&end_time={$end_time}&ex_raid={$ex_raid}"; + $picture_url = "{$config->RAID_PICTURE_URL}?{$raid_id}pokemon={$raid['pokemon']}&pokemon_form={$raid['pokemon_form']}&gym_id={$raid['gym_id']}&start_time={$start_time}&end_time={$end_time}&ex_raid={$ex_raid}"; if($standalone) $picture_url .= '&sa=1'; if($raid['costume'] != 0) $picture_url .= '&costume='.$raid['costume']; debug_log('raid_picture_url: ' . $picture_url); return $picture_url; } + +/** + * Returns photo contents to post to Telegram. File_id, url or photo file contents + * @param array $raid Raid array from get_raid() + * @param bool $standalone_photo Clear the bottom right corner of the photo from text + * @param bool $debug Add debug features to the photo + * @return array [true/false if returned content is photo file, content, cached unique_id for editMessageMedia] + */ +function get_raid_picture($raid, $standalone_photo = false) { + global $config; + // Has raid ended? + $binds = [ + ':raid_id' => $raid['id'], + ':gym_id' => $raid['gym_id'], + ':pokedex_id' => $raid['pokemon'], + ':pokemon_form' => $raid['pokemon_form'], + ':standalone' => $standalone_photo, + ':ended' => $raid['raid_ended'], + ]; + if($config->RAID_PICTURE_SEND_METHOD == 'url') return [false, raid_picture_url($raid, $standalone_photo)]; + $query_cache = my_query(" + SELECT id, unique_id + FROM photo_cache + WHERE raid_id = :raid_id + AND gym_id = :gym_id + AND pokedex_id = :pokedex_id + AND form_id = :pokemon_form + AND ended = :ended + AND standalone = :standalone + LIMIT 1", $binds + ); + + if($query_cache->rowCount() > 0) { + $result = $query_cache->fetch(); + return [false, $result['id'], $result['unique_id']]; + }else { + return [true, create_raid_picture($raid, $standalone_photo)]; + } +} + +/** + * Create a raid picture and return it as a string + * @param array $raid Raid array from get_raid() + * @param bool $standalone_photo Clear the bottom right corner of the photo from text + * @param bool $debug Add debug features to the photo + * @return string + */ +function create_raid_picture($raid, $standalone_photo = false, $debug = false) { + global $config; + if ($GLOBALS['metrics']){ + $GLOBALS['requests_total']->inc(['raidpicture']); + } + + if(utcnow() > $raid['end_time']) $raid_ongoing = false; + else $raid_ongoing = true; + + // Query missing raid info + $q_pokemon_info = my_query(" + SELECT + pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, asset_suffix, type, type2, + (SELECT img_url FROM gyms WHERE id='".$raid['gym_id']."' LIMIT 1) as img_url + FROM pokemon + WHERE pokedex_id = '".$raid['pokemon']."' + AND pokemon_form_id = '".$raid['pokemon_form']."' LIMIT 1"); + if($q_pokemon_info->rowCount() == 0) { + info_log("Something wrong with the raid data provided!"); + info_log(print_r($raid,true)); + exit(); + } + $raid = array_merge($raid, $q_pokemon_info->fetch()); + + // Fonts + $font_gym = FONTS_PATH . '/' . $config->RAID_PICTURE_FONT_GYM; + $font_text = FONTS_PATH . '/' . $config->RAID_PICTURE_FONT_TEXT; + $font_ex_gym = FONTS_PATH . '/' . $config->RAID_PICTURE_FONT_EX_GYM; + + // Canvas size + $canvas_width = 700; + $canvas_height = 356; + + // Creating an empty canvas + $canvas = imagecreatetruecolor($canvas_width,$canvas_height); + imagesavealpha($canvas,true); + + // Background color + // Default: White + $bg_rgb = [255,255,255]; + $config_bg_color = explode(',',$config->RAID_PICTURE_BG_COLOR); + if(count($config_bg_color) == 3) { + $bg_rgb = $config_bg_color; + } else { + info_log($config->RAID_PICTURE_BG_COLOR, 'Invalid value RAID_PICTURE_BG_COLOR:'); + } + $bg_color = imagecolorallocate($canvas,$bg_rgb[0],$bg_rgb[1], $bg_rgb[2]); + imagefill($canvas, 0, 0, $bg_color); + + // Text / Font color + // Default: Black + $font_rgb = [0,0,0]; + $config_font_color = explode(',',$config->RAID_PICTURE_TEXT_COLOR); + if(count($config_font_color) == 3) { + $font_rgb = $config_font_color; + } else { + info_log($config->RAID_PICTURE_TEXT_COLOR, 'Invalid value RAID_PICTURE_TEXT_COLOR:'); + } + $font_color = imagecolorallocate($canvas,$font_rgb[0],$font_rgb[1],$font_rgb[2]); + + // Defining RBG values that are used to create transparent color + // Should be different from RAID_PICTURE_BG_COLOR and RAID_PICTURE_TEXT_COLOR + $transparent_rgb = [0,255,0]; + + // Gym image + $gym_url = $raid['img_url']; + if($config->RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY && !empty($gym_url)) { + if(substr($gym_url, 0, 7) == 'file://') { + $gym_image_path = $gym_url; + debug_log($gym_image_path, 'Found an image imported via a portal bot: '); + }else { + $file_name = explode('/', $gym_url)[3]; + $gym_image_path = PORTAL_IMAGES_PATH .'/'. $file_name.'.png'; + debug_log($gym_image_path, 'Attempting to use locally stored gym image'); + if(!file_exists($gym_image_path)) { + debug_log($gym_url, 'Gym image not found, attempting to downloading it from: '); + if(is_writable(PORTAL_IMAGES_PATH)) { + download_Portal_Image($gym_url, PORTAL_IMAGES_PATH, $file_name . '.png'); + }else { + $gym_image_path = $gym_url; + info_log(PORTAL_IMAGES_PATH, 'Failed to write new gym image, incorrect permissions in directory '); + } + } + } + }else { + $img_gym = false; + if (!empty($gym_url)) { + $gym_image_path = $gym_url; + } + } + $img_gym = grab_img($gym_image_path); + if($img_gym == false) { + info_log($gym_image_path, 'Loading the gym image failed, using default gym image'); + if(is_file($config->RAID_DEFAULT_PICTURE)) { + $img_gym = grab_img($config->RAID_DEFAULT_PICTURE); + } else { + info_log($config->RAID_DEFAULT_PICTURE, 'Cannot read default gym image:'); + $img_gym = grab_img(IMAGES_PATH . "/gym_default.png"); + } + } + + // Get the width and height of the gym picture + $gym_w = imagesx($img_gym); + $gym_h = imagesy($img_gym); + + // Crop gym image + if($gym_w > $gym_h) { + $size = $gym_h; + $crop_x = floor((($gym_w/2)-($gym_h/2))); + $crop_y = 0; + } else { + $size = $gym_w; + $crop_x = 0; + $crop_y = floor((($gym_h/2)-($gym_w/2))); + } + + // Create mask + $new_w = 300; + $new_h = 300; + $mask = imagecreatetruecolor($new_w,$new_h); + + // Fill the mask with background color + $bg = imagecolorallocate($mask,$bg_rgb[0],$bg_rgb[1], $bg_rgb[1]); + imagefill($mask,0,0,$bg); + + // Define transparent color for the mask + $transparent = imagecolorallocate($mask,$transparent_rgb[0],$transparent_rgb[1],$transparent_rgb[2]); + imagecolortransparent($mask,$transparent); + + // Creating the orange circle around the gym photo + $color_ellipse = imagecolorallocate($mask,254,193,161); + imagefilledellipse($mask,$new_w/2,$new_h/2,$new_w-9,$new_h-9,$color_ellipse); + imagefilledellipse($mask,$new_w/2,$new_h/2,$new_w-16,$new_h-16,$bg); + + // Creating a circle that is filled with transparent color + imagefilledellipse($mask,$new_w/2,$new_h/2,$new_w-30,$new_h-30,$transparent); + + // Merging the desired part of the gym picture with canvas + imagecopyresampled($canvas,$img_gym,0,0,$crop_x,$crop_y,$new_w,$new_h, $size,$size); + + // Merging the mask with a circular cutout to the canvas + imagecopymerge($canvas, $mask, 0, 0, 0, 0, $new_w, $new_h, 100); + + + + // Is ex gym? + if($raid['ex_gym'] == 1) { + $ex_text_size = 20; + $ex_text_angle = 0; + $corner = 16; // Roundness of the corners + $extra = $ex_text_size/5+1; // Some extra height + + $ex_mark_bg_color = [94,169,190]; + $ex_mark_text_color = [255,255,255]; + + // Get the text with local translation for EX Raid gym + $ex_raid_gym_text = strtoupper(getPublicTranslation('ex_gym')); + // Finding out the size of text + $ex_text_box = imagettfbbox($ex_text_size,$ex_text_angle,$font_ex_gym,$ex_raid_gym_text); + + $ex_logo_width = $ex_text_box[2]+($corner); + $ex_logo_height = $ex_text_size+$extra; + + + // Create the canvas for EX RAID indicator + $ex_logo = imagecreatetruecolor($ex_logo_width,$ex_logo_height); + // Defining the transparent color + $ex_transparent = imagecolorallocate($ex_logo,$transparent_rgb[0],$transparent_rgb[1],$transparent_rgb[2]); + imagecolortransparent($ex_logo,$ex_transparent); + // Defining background color + $ex_logo_bg = imagecolorallocate($mask,$ex_mark_bg_color[0],$ex_mark_bg_color[1], $ex_mark_bg_color[2]); + $ex_text_color = imagecolorallocate($ex_logo,$ex_mark_text_color[0],$ex_mark_text_color[1],$ex_mark_text_color[2]); + + //Filling the canvas with transparent color + imagefill($ex_logo,0,0,$ex_transparent); + + // Creating 4 balls, one in each corner + imagefilledellipse($ex_logo,$corner/2,$corner/2,$corner,$corner,$ex_logo_bg); + imagefilledellipse($ex_logo,$corner/2,$ex_logo_height-$corner/2,$corner,$corner,$ex_logo_bg); + imagefilledellipse($ex_logo,$ex_logo_width-$corner/2,$corner/2,$corner,$corner,$ex_logo_bg); + imagefilledellipse($ex_logo,$ex_logo_width-$corner/2,$ex_logo_height-$corner/2,$corner,$corner,$ex_logo_bg); + // And two rectangles to fill the rest + imagefilledrectangle($ex_logo,$corner/2,0,$ex_logo_width-($corner/2),$ex_logo_height,$ex_logo_bg); + imagefilledrectangle($ex_logo,0,$corner/2,$ex_logo_width,$ex_logo_height-($corner/2),$ex_logo_bg); + + // Draw the text + imagettftext($ex_logo,$ex_text_size,$ex_text_angle,$corner/2,$ex_text_size+1,$ex_text_color,$font_ex_gym,$ex_raid_gym_text); + + // Copy icon into canvas + imagecopy($canvas,$ex_logo,20,20,0,0,$ex_logo_width,$ex_logo_height); + } + + + $show_boss_pokemon_types = false; + // Raid running + if($raid_ongoing) { + if(strlen($raid['asset_suffix']) > 2) { + $icon_suffix = $raid['asset_suffix']; + }else { + $pad_zeroes = ''; + for ($o=3-strlen($raid['pokemon']);$o>0;$o--) { + $pad_zeroes .= 0; + } + $icon_suffix = $pad_zeroes.$raid['pokemon'] . "_" . $raid['asset_suffix']; + } + + // Raid Egg + if($raid['pokemon'] > 9990) { + // Getting the actual icon + $img_pokemon = grab_img(IMAGES_PATH . "/raid_eggs/pokemon_icon_" . $raid['pokemon'] . "_00.png"); + + // Position and size of the picture + $dst_x = $dst_y = 150; + $dst_w = $dst_h = 200; + $src_w = $src_h = 128; + + //Pokemon + } else { + // Check pokemon icon source and create image + $img_file = null; + $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); + + $addressable_icon = 'pm'.$raid['pokemon']; + if($raid['pokemon_form_name'] != 'normal') $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); + + // Getting the actual icon filename + $p_icon = "pokemon_icon_" . $icon_suffix; + if($raid['costume'] != 0) { + $p_icon .= '_' . str_pad($raid['costume'], 2, '0', STR_PAD_LEFT); + + $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); + $addressable_icon .= '.c' . array_search($raid['costume'],$costume); + } + if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { + $p_icon = $p_icon . "_shiny"; + $addressable_icon .= '.s'; + $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); + } + $addressable_icon .= '.icon.png'; + $p_icon = $p_icon . ".png"; + + foreach($p_sources as $p_dir) { + // Set pokemon icon dir + $p_img = IMAGES_PATH . "/pokemon_" . $p_dir . "/" . $p_icon; + $p_add_img = IMAGES_PATH . "/pokemon_" . $p_dir . "/Addressable_Assets/" . $addressable_icon; + + // Icon dir named 'pokemon'? Then change path to not add '_repo-owner' to icon folder name + if($p_dir == 'pokemon') { + $p_img = IMAGES_PATH . "/pokemon/" . $p_icon; + $p_add_img = IMAGES_PATH . "/pokemon/Addressable_Assets" . $addressable_icon; + } + // Check if file exists in this collection + // Prioritize addressable asset file + if(file_exists($p_add_img) && filesize($p_add_img) > 0) { + $img_file = $p_add_img; + break; + }else if(file_exists($p_img) && filesize($p_img) > 0) { + $img_file = $p_img; + break; + } + } + + // If no image was found, substitute with a fallback + if($img_file === null) { + info_log($p_icon, 'Failed to find an image in any pokemon image collection for:'); + $img_fallback_file = null; + // If we know the raid level, fallback to egg image + if(array_key_exists('level', $raid) && $raid['level'] !== null && $raid['level'] != 0) { + $img_fallback_file = IMAGES_PATH . "/raid_eggs/pokemon_icon_999" . $raid['level'] . "_00.png"; + } else { + info_log('Unknown raid level, using fallback icon.'); + $img_fallback_file = $config->RAID_PICTURE_POKEMON_FALLBACK; + } + $img_file = $img_fallback_file; + } + + $img_pokemon = grab_img($img_file); + + // Position and size of the picture + $dst_x = $dst_y = 100; + $dst_w = $dst_h = $src_w = $src_h = 256; + + if($raid['type'] != '') $show_boss_pokemon_types = true; + } + + // Raid ended + } else { + // Raid won image + $img_pokemon = grab_img(IMAGES_PATH . "/raidwon.png"); + + // Position and size of the picture + $dst_x = $dst_y = 172; + $src_w = 444; + $src_h = 512; + $dst_w = 160; + $dst_h = floor($dst_w/$src_w*$src_h); + } + + // Create pokemon image. + imagesavealpha($img_pokemon,true); + + // Debug - Add border around pokemon image + if($debug) { + $im = imagecreate($src_w,$src_h); + $black = imagecolorallocate($im,0,0,0); + imagerectangle($img_pokemon,0,0,$src_w-1,$src_h-1,$black); + } + + // Add pokemon to image + imagecopyresampled($canvas,$img_pokemon,$dst_x,$dst_y,0,0,$dst_w,$dst_h,$src_w,$src_h); + + // Add pokemon types + if($config->RAID_PICTURE_POKEMON_TYPES && $show_boss_pokemon_types) { + $img_type = grab_img(IMAGES_PATH . "/types/".$raid['type'].".png"); + $type1_x = 300; + imagesavealpha($img_type, true); + if($raid['type2'] != '') { + $img_type2 = grab_img(IMAGES_PATH . "/types/".$raid['type2'].".png"); + imagesavealpha($img_type2, true); + imagecopyresampled($canvas,$img_type2,300,300,0,0,40,40,64,64); + $type1_x -= 50; + } + imagecopyresampled($canvas,$img_type,$type1_x,300,0,0,40,40,64,64); + } + if(isset($shiny_icon)) { + imagesavealpha($shiny_icon,true); + $light_white = imagecolorallocatealpha($canvas, 255,255,255,50); + imagefilledellipse($canvas, $type1_x-35 ,320,40,40,$light_white); + imagecopyresampled($canvas,$shiny_icon,$type1_x-52,301,0,0,35,35,100,100); + } + + // Ex-Raid? + if($raid['event'] == EVENT_ID_EX) { + $img_expass = grab_img(IMAGES_PATH . "/expass.png"); + imagesavealpha($img_expass,true); + + // Debug - Add border around expass image + if($debug) { + $im = imagecreate(256,256); + $black = imagecolorallocate($im,0,0,0); + imagerectangle($img_expass,0,0,255,255,$black); + } + imagecopyresampled($canvas,$img_expass,0,225,0,0,100,100,256,256); + } + + + + // Adding the gym name to the image + $text_size = 23; // Font size of additional text + $text_size_cp_weather = 20;// Font size of weather cp text + $left_after_poke = 356; // First left position behind the pokemon icon. + $angle = 0; // Angle of the text + $spacing = 10; // Spacing between lines + $spacing_right = 10; // Empty space on the right for weather icons and CP text + + + + // Gym name + // Largest gym name we found so far for testing: + //$gym_name = 'Zentrum für Junge Erwachsene der Kirche Jesu Christi der Heiligen der Letzten Tage Pfahl Düsseldorf'; + $gym_name = $raid['gym_name']; + + // Get length, the shortest and largest word of the gym name + $gym_name_words = explode(SP, $gym_name); + $gym_name_word_lengths = array_map('strlen', array_map('utf8_decode', $gym_name_words)); + $gym_name_word_largest = max($gym_name_word_lengths); + $gym_name_total_chars = strlen(utf8_decode($gym_name)); + + // Number of rows based on number of words or total chars + $gym_name_rows = 1; + if(count($gym_name_words) > 1 && $gym_name_total_chars >= 18 && $gym_name_total_chars <= 50) { + $gym_name_rows = 2; + } else if($gym_name_total_chars > 50) { + $gym_name_rows = 3; + } + + // Wrap gym name to multiple lines if too long + $gym_name_lines = explode(PHP_EOL,wordwrap(trim($gym_name),floor(($gym_name_total_chars+$gym_name_word_largest)/$gym_name_rows),PHP_EOL)); + + debug_log($gym_name_total_chars, 'Gym name length:'); + debug_log($gym_name_lines, 'Gym name lines:'); + + // Target width and height + $targetWidth = imagesx($canvas) - imagesx($mask) - $spacing_right; + $targetHeight = 95; + $rowHeight = $targetHeight/$gym_name_rows; + + // Get largest possible fontsize for each gym name line + $fontsize_gym = 0; + for($l=0; $l= $targetWidth || $height >= $rowHeight){ + break; + } + } + + // Gym name font size and spacing + if($l == 0 || $targetsize < $fontsize_gym) { + $fontsize_gym = $targetsize; + $spacing_gym = $height * 0.30; + } + } + + // Add gym name to image + for($y=0;$y 20) { + $pokemon_text_lines = explode(SP,$pokemon_name); + if(count($pokemon_text_lines) == 1) { + // Wrapping the time text if too long (to 20 letters) + $pokemon_text_lines = explode(PHP_EOL,wordwrap(trim($pokemon_name),20,PHP_EOL)); + } + } + $num_pokemon_lines = count($pokemon_text_lines); + + // Target width and height + $targetWidth = imagesx($canvas) - $left_after_poke - (strlen($raid['weather']) * 42) - $spacing_right; + $targetHeight = 80; + + // Get largest possible fontsize for each pokemon name and form line + $fontsize_poke = 0; + for($p=0; $p<($num_pokemon_lines); $p++) { + for($s=1; $s<40; $s=$s+0.5){ + $box = imagettfbbox($s, 0, $font_text, $pokemon_text_lines[$p]); + $min_x = min(array($box[0], $box[2], $box[4], $box[6])); + $max_x = max(array($box[0], $box[2], $box[4], $box[6])); + $min_y = min(array($box[1], $box[3], $box[5], $box[7])); + $max_y = max(array($box[1], $box[3], $box[5], $box[7])); + $width = ($max_x - $min_x); + $height = ($max_y - $min_y); + $targetsize = $s; + // Exit once we exceed width or height + if($width >= $targetWidth || $height >= $targetHeight){ + break; + } + } + + // Gym name font size and spacing + if($p == 0 || $targetsize < $fontsize_poke) { + $fontsize_poke = $targetsize; + } + } + + // Pokemon name (and form) in 1 row + $poke_text_top = 310; + + // Pokemon name and form in one or two lines? + if($num_pokemon_lines > 1) { + $poke_text_top = 272; + } + + // If the photo is sent without caption, we want to keep the bottom right corcer clear of text because Telegram covers it with a timestamp + if($standalone_photo) $poke_text_top -= 50; + + // Add pokemon name to image + for($pa=0;$pa<$num_pokemon_lines;$pa++){ + // Get text width and height + $textwidth = ($max_x - $min_x); + $textheight = ($max_y - $min_y); + // Position from top + $poke_text_top = ($poke_text_top+($pa*($fontsize_poke+$spacing))); + imagettftext($canvas,$fontsize_poke,$angle,$left_after_poke,$poke_text_top,$font_color,$font_text,$pokemon_text_lines[$pa]); + } + + // Pokemon CP + if($raid['pokemon'] < 9990) { + $cp_text_top = $poke_text_top+$text_size+$spacing; + $cp_text = $raid['min_cp']." - ".$raid['max_cp']; + $cp_text2 = "(".$raid['min_weather_cp']."-".$raid['max_weather_cp'].")"; + + imagettftext($canvas,$text_size,$angle,$left_after_poke,$cp_text_top,$font_color,$font_text,$cp_text); + $cp_weather_text_box = imagettfbbox($text_size_cp_weather,$angle,$font_text,$cp_text2); + imagettftext($canvas,$text_size_cp_weather,$angle,($canvas_width-$cp_weather_text_box[2]-$spacing_right),$cp_text_top,$font_color,$font_text,$cp_text2); + + $count_weather = strlen($raid['weather']); + for($i=0;$i<$count_weather;$i++) { + $we = substr($raid['weather'],$i,1); + $weather_icon_path = IMAGES_PATH . "/weather/"; + // Use white icons? + if($config->RAID_PICTURE_ICONS_WHITE) { + $weather_icon_path = IMAGES_PATH . "/weather_white/"; + } + $weather_icon = grab_img($weather_icon_path . $we . ".png"); // 64x64 + imagecopyresampled($canvas,$weather_icon,$canvas_width-$spacing_right-($count_weather-$i)*40,$poke_text_top-30,0,0,38,38,64,64); + } + } + + ob_start(); + // Define and print picture + // PNG + if($config->RAID_PICTURE_FILE_FORMAT == 'png') { + imagepng($canvas); + + // JPEG + } else if($config->RAID_PICTURE_FILE_FORMAT == 'jpeg' || $config->RAID_PICTURE_FILE_FORMAT == 'jpg') { + imagejpeg($canvas, NULL, 90); + + // Use GIF as default - smallest file size without compression + } else { + imagegif($canvas); + } + return ob_get_clean(); + +} + +/** + * Create GD image object from given URI regardless of file type + * @param string $uri Image uri + * @return object + */ +function grab_img($uri) { + $img = imagecreatefromstring(file_get_contents($uri)); + if ($img === false) { + info_log($uri, 'Failed to get image:'); + return false; + } + return $img; +} + ?> diff --git a/logic/send_raid_poll.php b/logic/send_raid_poll.php index c6dd53fb..6607be1f 100644 --- a/logic/send_raid_poll.php +++ b/logic/send_raid_poll.php @@ -35,12 +35,6 @@ function send_raid_poll($raid_id, $chats, $raid = false, $tg_json = false) { // Telegram JSON array. if($tg_json == false) $tg_json = []; - // Raid picture - if($config->RAID_PICTURE) { - require_once(LOGIC_PATH . '/raid_picture.php'); - $picture_url = raid_picture_url($raid, $config->RAID_PICTURE_AUTOEXTEND); - } - // Send the message. $raid_picture_hide_level = explode(",",$config->RAID_PICTURE_HIDE_LEVEL); $raid_picture_hide_pokemon = explode(",",$config->RAID_PICTURE_HIDE_POKEMON); @@ -62,11 +56,14 @@ function send_raid_poll($raid_id, $chats, $raid = false, $tg_json = false) { send_message($chat_id, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); }else { if($config->RAID_PICTURE && $raid['event_hide_raid_picture'] == 0 && !in_array($raid_level, $raid_picture_hide_level) && !in_array($raid_pokemon, $raid_picture_hide_pokemon) && !in_array($raid_pokemon_id, $raid_picture_hide_pokemon)) { + require_once(LOGIC_PATH . '/raid_picture.php'); + $media_content = get_raid_picture($raid, $config->RAID_PICTURE_AUTOEXTEND); if(($config->RAID_PICTURE_AUTOEXTEND && !in_array($raid['level'], $raid_poll_hide_buttons_levels)) or $post_text) { - send_photo($chat_id, $picture_url, '', [], [], false, $raid_id); + $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache + send_photo($chat_id, $media_content[1], $media_content[0], '', [], [], false, $raid); send_message($chat_id, $text['short'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); } else { - $tg_json[] = send_photo($chat_id, $picture_url, $text['short'], $keys, ['disable_web_page_preview' => 'true'], true, $raid_id); + $tg_json[] = send_photo($chat_id, $media_content[1], $media_content[0], $text['short'], $keys, ['disable_web_page_preview' => 'true'], true, $raid); } } else { $tg_json[] = send_message($chat_id, $text['full'], $keys, ['disable_web_page_preview' => 'true'], true, $raid_id); diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index f8c15cae..e1cbebcf 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -270,7 +270,7 @@ function show_raid_poll($raid, $inline = false) // Raid has started and has participants if($time_now > $raid['start_time']) { // Add raid is done message. - if($time_now > $raid['end_time']) { + if($raid['raid_ended']) { $msg = raid_poll_message($msg, '' . getPublicTranslation('raid_done') . '' . CR); // Add time left message. } else { @@ -469,7 +469,7 @@ function show_raid_poll($raid, $inline = false) // Add update time and raid id to message. $msg = raid_poll_message($msg, CR . '' . getPublicTranslation('updated') . ': ' . dt2time('now', 'H:i:s') . ''); - if($inline && ($buttons_hidden or ($raid['end_time'] < $time_now && $config->RAID_ENDED_HIDE_KEYS))) { + if($inline && ($buttons_hidden or ($raid['raid_ended'] && $config->RAID_ENDED_HIDE_KEYS))) { // Only case this is needed anymore is a poll shared via inline that has no vote keys $msg = raid_poll_message($msg, SP . SP . substr(strtoupper($config->BOT_ID), 0, 1) . '-ID = ' . $raid['id']); } diff --git a/logic/update_raid_poll.php b/logic/update_raid_poll.php index b1420f64..8a9d1cc7 100644 --- a/logic/update_raid_poll.php +++ b/logic/update_raid_poll.php @@ -6,11 +6,10 @@ * @param array|false $raid Array received from get_raid() (optional). * @param array|false $update * @param array|false $tg_json Multicurl array. - * @param bool $skip_picture_update Bool, Skip updating raid picture on refresh after raid has ended * @return array|false tg_json multicurl array */ -function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = false, $skip_picture_update = true) +function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = false) { global $config; $chat_and_message = []; @@ -23,22 +22,18 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f ]; // For updating a poll }else if(isset($update['push'])) { - $chat_and_message[] = [ - 'chat_id' => $update['push']['chat_id'], - 'message_id' => $update['push']['message_id'], - 'type' => $update['push']['type'], - ]; + $chat_and_message[] = $update['push']; } // If neither of the methods above yielded results, or update came from a inline poll, check cleanup table for chat messages to update if(empty($chat_and_message) or isset($update['callback_query']['inline_message_id'])) { $rs_chann = my_query(' - SELECT chat_id, message_id, type + SELECT chat_id, message_id, type, media_unique_id FROM cleanup WHERE raid_id = ' . $raid_id ); if ($rs_chann->rowCount() > 0) { while($chat = $rs_chann->fetch()) { - $chat_and_message[] = ['chat_id' => $chat['chat_id'], 'message_id' => $chat['message_id'], 'type' => $chat['type']]; + $chat_and_message[] = $chat; } }else { if(is_array($tg_json)) return $tg_json; @@ -67,35 +62,12 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f // Telegram JSON array. if($tg_json == false) $tg_json = []; - if($config->RAID_PICTURE) { - require_once(LOGIC_PATH . '/raid_picture.php'); - } foreach($chat_and_message as $chat_id_msg_id) { $chat = $chat_id_msg_id['chat_id']; $message = $chat_id_msg_id['message_id']; $type = $chat_id_msg_id['type']; - if($type == 'poll_photo') { - $picture_url = raid_picture_url($raid); - // If the poll message gets too long, we'll replace it with regular text based poll - if($post_text == true) { - // Delete raid picture and caption. - $tg_json[] = delete_message($chat, $message, true); - my_query("DELETE FROM cleanup WHERE chat_id = '{$chat}' AND message_id = '{$message}'"); - - // Resend raid poll as text message. - send_photo($chat, $picture_url, '', [], [], false, $raid_id); - send_message($chat, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); - } else { - // Edit the picture and caption - if(!$skip_picture_update) { - $tg_json[] = editMessageMedia($message, $text['short'], $picture_url, $keys, $chat, ['disable_web_page_preview' => 'true'], true); - }else { - // Edit the caption. - $tg_json[] = editMessageCaption($message, $text['short'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); - } - } - }else if ($type == 'poll_text') { + if ($type == 'poll_text') { $raid_picture_hide_level = explode(",",$config->RAID_PICTURE_HIDE_LEVEL); $raid_picture_hide_pokemon = explode(",",$config->RAID_PICTURE_HIDE_POKEMON); @@ -106,9 +78,37 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f }else { $tg_json[] = editMessageText($message, $text['full'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); } - }else if ($type == 'photo' && !$skip_picture_update) { - $picture_url = raid_picture_url($raid, 1); - $tg_json[] = editMessageMedia($message, '', $picture_url, '', $chat, [], true); + }else { + require_once(LOGIC_PATH . '/raid_picture.php'); + if($type == 'poll_photo') { + // If the poll message gets too long, we'll replace it with regular text based poll + if($post_text == true) { + // Delete raid picture and caption. + $tg_json[] = delete_message($chat, $message, true); + my_query("DELETE FROM cleanup WHERE chat_id = '{$chat}' AND message_id = '{$message}'"); + + $media_content = get_raid_picture($raid, true); + $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache + // Resend raid poll as text message. + send_photo($chat, $media_content[1], $media_content[0], '', [], [], false, $raid); + send_message($chat, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); + } else { + $media_content = get_raid_picture($raid); + // Edit the picture and caption + if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { + $tg_json[] = editMessageMedia($message, $text['short'], $media_content[1], $media_content[0], $keys, $chat, ['disable_web_page_preview' => 'true'], true, $raid); + }else { + // Edit the caption. + $tg_json[] = editMessageCaption($message, $text['short'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); + } + } + }else if ($type == 'photo') { + $media_content = get_raid_picture($raid, 1); + $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache + if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { + $tg_json[] = editMessageMedia($message, '', $media_content[1], $media_content[0], false, $chat, false, true, $raid); + } + } } } return $tg_json; diff --git a/mods/end_remote_raid.php b/mods/end_remote_raid.php index 31c78416..428f5485 100644 --- a/mods/end_remote_raid.php +++ b/mods/end_remote_raid.php @@ -5,7 +5,7 @@ my_query('UPDATE raids SET end_time = date_sub(UTC_TIMESTAMP(),interval 1 minute) WHERE id = \'' . $raid_id . '\''); require_once(LOGIC_PATH . '/update_raid_poll.php'); -$tg_json = update_raid_poll($raid_id, false, $update, false, false); +$tg_json = update_raid_poll($raid_id, false, $update, false); $tg_json[] = edit_message($update, getTranslation('raid_done'), [], false, true); $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation("remote_raid_marked_ended"), true); diff --git a/mods/raid_set_poke.php b/mods/raid_set_poke.php index 0bd7f9ee..d8f05a32 100644 --- a/mods/raid_set_poke.php +++ b/mods/raid_set_poke.php @@ -48,7 +48,7 @@ // Update the shared raid polls. require_once(LOGIC_PATH .'/update_raid_poll.php'); -$tg_json = update_raid_poll($id, $raid, false, $tg_json, false); +$tg_json = update_raid_poll($id, $raid, false, $tg_json); // Alert users. $tg_json = alarm($raid, $update['callback_query']['from']['id'], 'new_boss', '', $tg_json); diff --git a/mods/refresh_polls.php b/mods/refresh_polls.php index d3d58f73..5da202cf 100644 --- a/mods/refresh_polls.php +++ b/mods/refresh_polls.php @@ -5,12 +5,12 @@ if(strlen($data['id']) > 5) $where_chat = 'chat_id = '.$data['id']; else $where_chat = 'chat_id != 0'; if(!empty($config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL)) $level_exclude = 'AND raids.level NOT IN ('.$config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL.')'; else $level_exclude = ''; $query_messages = my_query(" - SELECT cleanup.* + SELECT cleanup.raid_id, cleanup.chat_id, cleanup.message_id, cleanup.type, cleanup.media_unique_id FROM cleanup LEFT JOIN raids ON cleanup.raid_id = raids.id WHERE {$where_chat} - AND cleanup.type IN ('poll_text', 'poll_photo') + AND cleanup.type IN ('poll_text', 'poll_photo', 'photo') AND raids.start_time <= UTC_TIMESTAMP() AND raids.end_time > DATE_SUB(UTC_TIMESTAMP(), INTERVAL 1 MINUTE) AND message_id != 0 @@ -25,12 +25,10 @@ debug_log("chat id: ".$res_messages['chat_id']); debug_log("raid id: ".$res_messages['raid_id']); - $data_poll['push']['message_id']=$res_messages['message_id']; - $data_poll['push']['chat_id']=$res_messages['chat_id']; - $data_poll['push']['type']=$res_messages['type']; + $data_poll['push'] = $res_messages; require_once(LOGIC_PATH . '/update_raid_poll.php'); - $tg_json = update_raid_poll($res_messages['raid_id'], false, $data_poll, $tg_json, false); + $tg_json = update_raid_poll($res_messages['raid_id'], get_raid($res_messages['raid_id']), $data_poll, $tg_json); } curl_json_multi_request($tg_json); }else { diff --git a/mods/tutorial.php b/mods/tutorial.php index 088f9db2..94a1e48b 100644 --- a/mods/tutorial.php +++ b/mods/tutorial.php @@ -112,5 +112,5 @@ } } answerCallbackQuery($update['callback_query']['id'], "OK!"); -editMessageMedia($update['callback_query']['message']['message_id'], $msg, $photo, $keys, $update['callback_query']['message']['chat']['id'], ['disable_web_page_preview' => 'true']); +editMessageMedia($update['callback_query']['message']['message_id'], $msg, $photo, false, $keys, $update['callback_query']['message']['chat']['id'], ['disable_web_page_preview' => 'true']); ?> \ No newline at end of file diff --git a/mods/vote_refresh.php b/mods/vote_refresh.php index 315cbdce..22ebad3d 100644 --- a/mods/vote_refresh.php +++ b/mods/vote_refresh.php @@ -1,7 +1,7 @@ inc(['raidpicture']); -} -// Create GD image object from given URI regardless of file type -function grab_img($uri){ - try { - $img = imagecreatefromstring(file_get_contents($uri)); - } catch (Exception $e) { - info_log($uri, 'Failed to get image:'); - info_log($e->getMessage(), 'Reason: '); - return false; - } - return $img; + $requests_total->inc(['raidpicture']); } + if(isset($_GET['sa']) && $_GET['sa'] == 1) $standalone_photo = true; else $standalone_photo = false; // Debug switch $debug = false; if(isset($_GET['debug']) && $_GET['debug'] == 1) { $debug = true; -} -$required_parameters = ['pokemon', 'pokemon_form', 'start_time', 'end_time', 'gym_id', 'ex_raid']; -$failed = []; -// Raid info -foreach($required_parameters as $required) { - if(!array_key_exists($required, $_GET)) { - $failed[] = $required; - } -} -if(count($failed) > 0) { - info_log('Raidpicture called without '.join(', ',$failed).', ending execution'); - exit(); -} -$raid = []; -$raid['pokemon'] = preg_replace("/\D/","",$_GET['pokemon']); -$raid['gym_id'] = preg_replace("/\D/","",$_GET['gym_id']); -$raid['raid_costume'] = false; -if($_GET['start_time'] == 0) { - $raid_ongoing = false; -}else { - $raid_ongoing = true; - $raid['start_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['start_time'])); - $raid['end_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['end_time'])); -} -if(in_array($_GET['pokemon_form'], ['-1','-2','-3'])) { - $raid['pokemon_form'] = $_GET['pokemon_form']; -}else { - $raid['pokemon_form'] = preg_replace("/\D/","",$_GET['pokemon_form']); -} -$raid['costume'] = 0; -if(array_key_exists('costume', $_GET) && $_GET['costume'] != '') { - $raid['costume'] = preg_replace("/\D/","",$_GET['costume']); -} -$q_pokemon_info = my_query(" - SELECT - pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, asset_suffix, type, type2 - FROM pokemon - WHERE pokedex_id = '".$raid['pokemon']."' - AND pokemon_form_id = '".$raid['pokemon_form']."' LIMIT 1")->fetch(); -$q_gym_info = my_query("SELECT img_url, gym_name, ex_gym FROM gyms WHERE id='".$raid['gym_id']."'")->fetch(); -$raid = array_merge($raid, $q_pokemon_info, $q_gym_info); - -// Fonts -$font_gym = FONTS_PATH . '/' . $config->RAID_PICTURE_FONT_GYM; -$font_text = FONTS_PATH . '/' . $config->RAID_PICTURE_FONT_TEXT; -$font_ex_gym = FONTS_PATH . '/' . $config->RAID_PICTURE_FONT_EX_GYM; - - -// Canvas size -$canvas_width = 700; -$canvas_height = 356; - -// Creating an empty canvas -$canvas = imagecreatetruecolor($canvas_width,$canvas_height); -imagesavealpha($canvas,true); - -// Background color -// Default: White -$bg_rgb = [255,255,255]; -$config_bg_color = explode(',',$config->RAID_PICTURE_BG_COLOR); -if(count($config_bg_color) == 3) { - $bg_rgb = $config_bg_color; + $raid_id = preg_replace("/\D/","",$_GET['raid']); + if(preg_match("^[0-9]+$^",$raid_id)) $raid = get_raid($raid_id); + else die("Invalid raid id!"); } else { - info_log($config->RAID_PICTURE_BG_COLOR, 'Invalid value RAID_PICTURE_BG_COLOR:'); -} -$bg_color = imagecolorallocate($canvas,$bg_rgb[0],$bg_rgb[1], $bg_rgb[2]); -imagefill($canvas, 0, 0, $bg_color); - -// Text / Font color -// Default: Black -$font_rgb = [0,0,0]; -$config_font_color = explode(',',$config->RAID_PICTURE_TEXT_COLOR); -if(count($config_font_color) == 3) { - $font_rgb = $config_font_color; -} else { - info_log($config->RAID_PICTURE_TEXT_COLOR, 'Invalid value RAID_PICTURE_TEXT_COLOR:'); -} -$font_color = imagecolorallocate($canvas,$font_rgb[0],$font_rgb[1],$font_rgb[2]); - -// Defining RBG values that are used to create transparent color -// Should be different from RAID_PICTURE_BG_COLOR and RAID_PICTURE_TEXT_COLOR -$transparent_rgb = [0,255,0]; - -// Gym image -$gym_url = $raid['img_url']; -if($config->RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY && !empty($gym_url)) { - if(substr($gym_url, 0, 7) == 'file://') { - $gym_image_path = $gym_url; - debug_log($gym_image_path, 'Found an image imported via a portal bot: '); - }else { - $file_name = explode('/', $gym_url)[3]; - $gym_image_path = PORTAL_IMAGES_PATH .'/'. $file_name.'.png'; - debug_log($gym_image_path, 'Attempting to use locally stored gym image'); - if(!file_exists($gym_image_path)) { - debug_log($gym_url, 'Gym image not found, attempting to downloading it from: '); - if(is_writable(PORTAL_IMAGES_PATH)) { - download_Portal_Image($gym_url, PORTAL_IMAGES_PATH, $file_name . '.png'); - }else { - $gym_image_path = $gym_url; - info_log(PORTAL_IMAGES_PATH, 'Failed to write new gym image, incorrect permissions in directory '); - } + $required_parameters = ['pokemon', 'pokemon_form', 'start_time', 'end_time', 'gym_id', 'ex_raid']; + $failed = []; + // Raid info + foreach($required_parameters as $required) { + if(!array_key_exists($required, $_GET)) { + $failed[] = $required; } } -}else { - $img_gym = false; - if (!empty($gym_url)) { - $gym_image_path = $gym_url; - } -} -$img_gym = grab_img($gym_image_path); -if($img_gym == false) { - info_log($gym_image_path, 'Loading the gym image failed, using default gym image'); - if(is_file($config->RAID_DEFAULT_PICTURE)) { - $img_gym = grab_img($config->RAID_DEFAULT_PICTURE); - } else { - info_log($config->RAID_DEFAULT_PICTURE, 'Cannot read default gym image:'); - $img_gym = grab_img(IMAGES_PATH . "/gym_default.png"); + if(count($failed) > 0) { + info_log('Raidpicture called without '.join(', ',$failed).', ending execution'); + exit(); } -} - -// Get the width and height of the gym picture -$gym_w = imagesx($img_gym); -$gym_h = imagesy($img_gym); - -// Crop gym image -if($gym_w > $gym_h) { - $size = $gym_h; - $crop_x = floor((($gym_w/2)-($gym_h/2))); - $crop_y = 0; -} else { - $size = $gym_w; - $crop_x = 0; - $crop_y = floor((($gym_h/2)-($gym_w/2))); -} - -// Create mask -$new_w = 300; -$new_h = 300; -$mask = imagecreatetruecolor($new_w,$new_h); - -// Fill the mask with background color -$bg = imagecolorallocate($mask,$bg_rgb[0],$bg_rgb[1], $bg_rgb[1]); -imagefill($mask,0,0,$bg); - -// Define transparent color for the mask -$transparent = imagecolorallocate($mask,$transparent_rgb[0],$transparent_rgb[1],$transparent_rgb[2]); -imagecolortransparent($mask,$transparent); - -// Creating the orange circle around the gym photo -$color_ellipse = imagecolorallocate($mask,254,193,161); -imagefilledellipse($mask,$new_w/2,$new_h/2,$new_w-9,$new_h-9,$color_ellipse); -imagefilledellipse($mask,$new_w/2,$new_h/2,$new_w-16,$new_h-16,$bg); - -// Creating a circle that is filled with transparent color -imagefilledellipse($mask,$new_w/2,$new_h/2,$new_w-30,$new_h-30,$transparent); - -// Merging the desired part of the gym picture with canvas -imagecopyresampled($canvas,$img_gym,0,0,$crop_x,$crop_y,$new_w,$new_h, $size,$size); - -// Merging the mask with a circular cutout to the canvas -imagecopymerge($canvas, $mask, 0, 0, 0, 0, $new_w, $new_h, 100); - - - -// Is ex gym? -if($raid['ex_gym'] == 1) { - $ex_text_size = 20; - $ex_text_angle = 0; - $corner = 16; // Roundness of the corners - $extra = $ex_text_size/5+1; // Some extra height - - $ex_mark_bg_color = [94,169,190]; - $ex_mark_text_color = [255,255,255]; - - // Get the text with local translation for EX Raid gym - $ex_raid_gym_text = strtoupper(getPublicTranslation('ex_gym')); - // Finding out the size of text - $ex_text_box = imagettfbbox($ex_text_size,$ex_text_angle,$font_ex_gym,$ex_raid_gym_text); - - $ex_logo_width = $ex_text_box[2]+($corner); - $ex_logo_height = $ex_text_size+$extra; - - - // Create the canvas for EX RAID indicator - $ex_logo = imagecreatetruecolor($ex_logo_width,$ex_logo_height); - // Defining the transparent color - $ex_transparent = imagecolorallocate($ex_logo,$transparent_rgb[0],$transparent_rgb[1],$transparent_rgb[2]); - imagecolortransparent($ex_logo,$ex_transparent); - // Defining background color - $ex_logo_bg = imagecolorallocate($mask,$ex_mark_bg_color[0],$ex_mark_bg_color[1], $ex_mark_bg_color[2]); - $ex_text_color = imagecolorallocate($ex_logo,$ex_mark_text_color[0],$ex_mark_text_color[1],$ex_mark_text_color[2]); - - //Filling the canvas with transparent color - imagefill($ex_logo,0,0,$ex_transparent); - - // Creating 4 balls, one in each corner - imagefilledellipse($ex_logo,$corner/2,$corner/2,$corner,$corner,$ex_logo_bg); - imagefilledellipse($ex_logo,$corner/2,$ex_logo_height-$corner/2,$corner,$corner,$ex_logo_bg); - imagefilledellipse($ex_logo,$ex_logo_width-$corner/2,$corner/2,$corner,$corner,$ex_logo_bg); - imagefilledellipse($ex_logo,$ex_logo_width-$corner/2,$ex_logo_height-$corner/2,$corner,$corner,$ex_logo_bg); - // And two rectangles to fill the rest - imagefilledrectangle($ex_logo,$corner/2,0,$ex_logo_width-($corner/2),$ex_logo_height,$ex_logo_bg); - imagefilledrectangle($ex_logo,0,$corner/2,$ex_logo_width,$ex_logo_height-($corner/2),$ex_logo_bg); - - // Draw the text - imagettftext($ex_logo,$ex_text_size,$ex_text_angle,$corner/2,$ex_text_size+1,$ex_text_color,$font_ex_gym,$ex_raid_gym_text); - - // Copy icon into canvas - imagecopy($canvas,$ex_logo,20,20,0,0,$ex_logo_width,$ex_logo_height); -} - - -$show_boss_pokemon_types = false; -// Raid running -if($raid_ongoing) { - if(strlen($raid['asset_suffix']) > 2) { - $icon_suffix = $raid['asset_suffix']; + $raid = []; + $raid['pokemon'] = preg_replace("/\D/","",$_GET['pokemon']); + $raid['gym_id'] = preg_replace("/\D/","",$_GET['gym_id']); + $raid['raid_costume'] = false; + $raid['event'] = ($_GET['ex_raid'] == 1) ? EVENT_ID_EX : 0; + if($_GET['start_time'] == 0) { + $raid_ongoing = false; }else { - $pad_zeroes = ''; - for ($o=3-strlen($raid['pokemon']);$o>0;$o--) { - $pad_zeroes .= 0; - } - $icon_suffix = $pad_zeroes.$raid['pokemon'] . "_" . $raid['asset_suffix']; + $raid_ongoing = true; + $raid['start_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['start_time'])); + $raid['end_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['end_time'])); } - - // Raid Egg - if($raid['pokemon'] > 9990) { - // Getting the actual icon - $img_pokemon = grab_img(IMAGES_PATH . "/raid_eggs/pokemon_icon_" . $raid['pokemon'] . "_00.png"); - - // Position and size of the picture - $dst_x = $dst_y = 150; - $dst_w = $dst_h = 200; - $src_w = $src_h = 128; - - //Pokemon - } else { - // Formatting the id from 1 digit to 3 digit (1 -> 001) - $pokemon_id = str_pad($raid['pokemon'], 3, '0', STR_PAD_LEFT); - - // Check pokemon icon source and create image - $img_file = null; - $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); - - $addressable_icon = 'pm'.$raid['pokemon']; - if($raid['pokemon_form_name'] != 'normal') $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); - - // Getting the actual icon filename - $p_icon = "pokemon_icon_" . $icon_suffix; - if($raid['costume'] != 0) { - $p_icon .= '_' . str_pad($raid['costume'], 2, '0', STR_PAD_LEFT); - - $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); - $addressable_icon .= '.c' . array_search($raid['costume'],$costume); - } - if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { - $p_icon = $p_icon . "_shiny"; - $addressable_icon .= '.s'; - $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); - } - $addressable_icon .= '.icon.png'; - $p_icon = $p_icon . ".png"; - - foreach($p_sources as $p_dir) { - // Set pokemon icon dir - $p_img = IMAGES_PATH . "/pokemon_" . $p_dir . "/" . $p_icon; - $p_add_img = IMAGES_PATH . "/pokemon_" . $p_dir . "/Addressable_Assets/" . $addressable_icon; - - // Icon dir named 'pokemon'? Then change path to not add '_repo-owner' to icon folder name - if($p_dir == 'pokemon') { - $p_img = IMAGES_PATH . "/pokemon/" . $p_icon; - $p_add_img = IMAGES_PATH . "/pokemon/Addressable_Assets" . $addressable_icon; - } - // Check if file exists in this collection - // Prioritize addressable asset file - if(file_exists($p_add_img) && filesize($p_add_img) > 0) { - $img_file = $p_add_img; - break; - }else if(file_exists($p_img) && filesize($p_img) > 0) { - $img_file = $p_img; - break; - } - } - - // If no image was found, substitute with a fallback - if($img_file === null) { - info_log($p_icon, 'Failed to find an image in any pokemon image collection for:'); - $img_fallback_file = null; - // If we know the raid level, fallback to egg image - if(array_key_exists('level', $raid) && $raid['level'] !== null && $raid['level'] != 0) { - $img_fallback_file = IMAGES_PATH . "/raid_eggs/pokemon_icon_999" . $raid['level'] . "_00.png"; - } else { - info_log('Unknown raid level, using fallback icon.'); - $img_fallback_file = $config->RAID_PICTURE_POKEMON_FALLBACK; - } - $img_file = $img_fallback_file; - } - - $img_pokemon = grab_img($img_file); - - // Position and size of the picture - $dst_x = $dst_y = 100; - $dst_w = $dst_h = $src_w = $src_h = 256; - - if($raid['type'] != '') $show_boss_pokemon_types = true; - } - -// Raid ended -} else { - // Raid won image - $img_pokemon = grab_img(IMAGES_PATH . "/raidwon.png"); - - // Position and size of the picture - $dst_x = $dst_y = 172; - $src_w = 444; - $src_h = 512; - $dst_w = 160; - $dst_h = floor($dst_w/$src_w*$src_h); -} - -// Create pokemon image. -imagesavealpha($img_pokemon,true); - -// Debug - Add border around pokemon image -if($debug) { - $im = imagecreate($src_w,$src_h); - $black = imagecolorallocate($im,0,0,0); - imagerectangle($img_pokemon,0,0,$src_w-1,$src_h-1,$black); -} - -// Add pokemon to image -imagecopyresampled($canvas,$img_pokemon,$dst_x,$dst_y,0,0,$dst_w,$dst_h,$src_w,$src_h); - -// Add pokemon types -if($config->RAID_PICTURE_POKEMON_TYPES && $show_boss_pokemon_types) { - $img_type = grab_img(IMAGES_PATH . "/types/".$raid['type'].".png"); - $type1_x = 300; - imagesavealpha($img_type, true); - if($raid['type2'] != '') { - $img_type2 = grab_img(IMAGES_PATH . "/types/".$raid['type2'].".png"); - imagesavealpha($img_type2, true); - imagecopyresampled($canvas,$img_type2,300,300,0,0,40,40,64,64); - $type1_x -= 50; - } - imagecopyresampled($canvas,$img_type,$type1_x,300,0,0,40,40,64,64); -} -if(isset($shiny_icon)) { - imagesavealpha($shiny_icon,true); - $light_white = imagecolorallocatealpha($canvas, 255,255,255,50); - imagefilledellipse($canvas, $type1_x-35 ,320,40,40,$light_white); - imagecopyresampled($canvas,$shiny_icon,$type1_x-52,301,0,0,35,35,100,100); -} - -// Ex-Raid? -if($_GET['ex_raid'] == '1') { - $img_expass = grab_img(IMAGES_PATH . "/expass.png"); - imagesavealpha($img_expass,true); - - // Debug - Add border around expass image - if($debug) { - $im = imagecreate(256,256); - $black = imagecolorallocate($im,0,0,0); - imagerectangle($img_expass,0,0,255,255,$black); - } - imagecopyresampled($canvas,$img_expass,0,225,0,0,100,100,256,256); -} - - - -// Adding the gym name to the image -$text_size = 23; // Font size of additional text -$text_size_cp_weather = 20;// Font size of weather cp text -$left_after_poke = 356; // First left position behind the pokemon icon. -$angle = 0; // Angle of the text -$spacing = 10; // Spacing between lines -$spacing_right = 10; // Empty space on the right for weather icons and CP text - - - -// Gym name -// Largest gym name we found so far for testing: -//$gym_name = 'Zentrum für Junge Erwachsene der Kirche Jesu Christi der Heiligen der Letzten Tage Pfahl Düsseldorf'; -$gym_name = $raid['gym_name']; - -// Get length, the shortest and largest word of the gym name -$gym_name_words = explode(SP, $gym_name); -$gym_name_word_lengths = array_map('strlen', array_map('utf8_decode', $gym_name_words)); -$gym_name_word_largest = max($gym_name_word_lengths); -$gym_name_word_shortest = min($gym_name_word_lengths); -$gym_name_total_chars = strlen(utf8_decode($gym_name)); - -// Number of rows based on number of words or total chars -$gym_name_rows = 1; -if(count($gym_name_words) > 1 && $gym_name_total_chars >= 18 && $gym_name_total_chars <= 50) { - $gym_name_rows = 2; -} else if($gym_name_total_chars > 50) { - $gym_name_rows = 3; -} - -// Wrap gym name to multiple lines if too long -$gym_name_lines = explode(PHP_EOL,wordwrap(trim($gym_name),floor(($gym_name_total_chars+$gym_name_word_largest)/$gym_name_rows),PHP_EOL)); - -debug_log($gym_name_total_chars, 'Gym name length:'); -debug_log($gym_name_lines, 'Gym name lines:'); - -// Target width and height -$targetWidth = imagesx($canvas) - imagesx($mask) - $spacing_right; -$targetHeight = 95; -$targetHeight = $targetHeight/$gym_name_rows; - -// Get largest possible fontsize for each gym name line -for($l=0; $l= $targetWidth || $height >= $targetHeight){ - break; - } - } - - // Gym name font size and spacing - if($l == 0 || $targetsize < $fontsize_gym) { - $fontsize_gym = $targetsize; - $spacing_gym = $height * 0.30; - } -} - -// Add gym name to image -for($y=0;$y 20) { - $pokemon_text_lines = explode(SP,$pokemon_name); - if(count($pokemon_text_lines) == 1) { - // Wrapping the time text if too long (to 20 letters) - $pokemon_text_lines = explode(PHP_EOL,wordwrap(trim($pokemon_name),20,PHP_EOL)); - } -} -$num_pokemon_lines = count($pokemon_text_lines); - -// Target width and height -$targetWidth = imagesx($canvas) - $left_after_poke - (strlen($raid['weather']) * 42) - $spacing_right; -$targetHeight = 80; - -// Get largest possible fontsize for each pokemon name and form line -for($p=0; $p<($num_pokemon_lines); $p++) { - for($s=1; $s<40; $s=$s+0.5){ - $box = imagettfbbox($s, 0, $font_text, $pokemon_text_lines[$p]); - $min_x = min(array($box[0], $box[2], $box[4], $box[6])); - $max_x = max(array($box[0], $box[2], $box[4], $box[6])); - $min_y = min(array($box[1], $box[3], $box[5], $box[7])); - $max_y = max(array($box[1], $box[3], $box[5], $box[7])); - $width = ($max_x - $min_x); - $height = ($max_y - $min_y); - $targetsize = $s; - // Exit once we exceed width or height - if($width >= $targetWidth || $height >= $targetHeight){ - break; - } + if(in_array($_GET['pokemon_form'], ['-1','-2','-3'])) { + $raid['pokemon_form'] = $_GET['pokemon_form']; + }else { + $raid['pokemon_form'] = preg_replace("/\D/","",$_GET['pokemon_form']); } - - // Gym name font size and spacing - if($p == 0 || $targetsize < $fontsize_poke) { - $fontsize_poke = $targetsize; + $raid['costume'] = 0; + if(array_key_exists('costume', $_GET) && $_GET['costume'] != '') { + $raid['costume'] = preg_replace("/\D/","",$_GET['costume']); } + $q_pokemon_info = my_query(" + SELECT + pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, asset_suffix, type, type2 + FROM pokemon + WHERE pokedex_id = '".$raid['pokemon']."' + AND pokemon_form_id = '".$raid['pokemon_form']."' LIMIT 1")->fetch(); + $q_gym_info = my_query("SELECT img_url, gym_name, ex_gym FROM gyms WHERE id='".$raid['gym_id']."'")->fetch(); + $raid = array_merge($raid, $q_pokemon_info, $q_gym_info); } -// Pokemon name (and form) in 1 row -$poke_text_top = 310; - -// Pokemon name and form in one or two lines? -if($num_pokemon_lines > 1) { - $poke_text_top = 272; -} - -// If the photo is sent without caption, we want to keep the bottom right corcer clear of text because Telegram covers it with a timestamp -if($standalone_photo) $poke_text_top -= 50; - -// Add pokemon name to image -for($pa=0;$pa<$num_pokemon_lines;$pa++){ - // Get text width and height - $textwidth = ($max_x - $min_x); - $textheight = ($max_y - $min_y); - // Position from top - $poke_text_top = ($poke_text_top+($pa*($fontsize_poke+$spacing))); - imagettftext($canvas,$fontsize_poke,$angle,$left_after_poke,$poke_text_top,$font_color,$font_text,$pokemon_text_lines[$pa]); -} - -// Pokemon CP -if($raid['pokemon'] < 9990) { - $cp_text_top = $poke_text_top+$text_size+$spacing; - $cp_text = $raid['min_cp']." - ".$raid['max_cp']; - $cp_text2 = "(".$raid['min_weather_cp']."-".$raid['max_weather_cp'].")"; - - imagettftext($canvas,$text_size,$angle,$left_after_poke,$cp_text_top,$font_color,$font_text,$cp_text); - $cp_weather_text_box = imagettfbbox($text_size_cp_weather,$angle,$font_text,$cp_text2); - imagettftext($canvas,$text_size_cp_weather,$angle,($canvas_width-$cp_weather_text_box[2]-$spacing_right),$cp_text_top,$font_color,$font_text,$cp_text2); - - $count_weather = strlen($raid['weather']); - for($i=0;$i<$count_weather;$i++) { - $we = substr($raid['weather'],$i,1); - $weather_icon_path = IMAGES_PATH . "/weather/"; - // Use white icons? - if($config->RAID_PICTURE_ICONS_WHITE) { - $weather_icon_path = IMAGES_PATH . "/weather_white/"; - } - $weather_icon = grab_img($weather_icon_path . $we . ".png"); // 64x64 - imagecopyresampled($canvas,$weather_icon,$canvas_width-$spacing_right-($count_weather-$i)*40,$poke_text_top-30,0,0,38,38,64,64); - } -} - - - // Define and print picture // PNG if($config->RAID_PICTURE_FILE_FORMAT == 'png') { header("Content-type: image/png"); - imagepng($canvas); // JPEG } else if($config->RAID_PICTURE_FILE_FORMAT == 'jpeg' || $config->RAID_PICTURE_FILE_FORMAT == 'jpg') { header("Content-type: image/jpeg"); - imagejpeg($canvas, NULL, 90); // Use GIF as default - smallest file size without compression } else { header("Content-type: image/gif"); - imagegif($canvas); } +echo create_raid_picture($raid, $standalone_photo, $debug); + ?> diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 76773f30..74b8d20e 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -25,7 +25,9 @@ CREATE TABLE `cleanup` ( `message_id` bigint(20) unsigned NOT NULL, `type` VARCHAR(20) NULL, `date_of_posting` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) + `media_unique_id` varchar(45) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `unique_chat_msg` (`chat_id`,`message_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `events` ( `id` int(3) unsigned NOT NULL AUTO_INCREMENT, @@ -63,6 +65,17 @@ CREATE TABLE `overview` ( `updated` date DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +CREATE TABLE `photo_cache` ( + `id` varchar(100) NOT NULL, + `unique_id` varchar(45) NOT NULL, + `pokedex_id` int(10) DEFAULT NULL, + `form_id` int(4) DEFAULT NULL, + `raid_id` int(10) unsigned DEFAULT NULL, + `ended` tinyint(1) DEFAULT NULL, + `gym_id` int(10) unsigned DEFAULT NULL, + `standalone` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`unique_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `pokemon` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `pokedex_id` int(10) unsigned NOT NULL, diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index c8fd9c68..4ff94df7 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -1 +1,5 @@ ALTER TABLE user_input CHANGE COLUMN IF EXISTS `user_id` `user_id` BIGINT(20) DEFAULT NULL AFTER `id`; + +CREATE TABLE `photo_cache` (`id` varchar(100) NOT NULL, `unique_id` varchar(45) NOT NULL, `pokedex_id` int(10) DEFAULT NULL, `form_id` int(4) DEFAULT NULL, `raid_id` int(10) unsigned DEFAULT NULL, `ended` tinyint(1) DEFAULT NULL, `gym_id` int(10) unsigned DEFAULT NULL, `standalone` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`unique_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; +CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); From af90b2dfeb89fbafb1880b0c8b17a0233fc2b919 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 23 Mar 2022 19:36:21 +0200 Subject: [PATCH 012/367] Cleaned up curl request mess --- logic/curl_json_response.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/logic/curl_json_response.php b/logic/curl_json_response.php index 28c4bf26..8e898f2d 100644 --- a/logic/curl_json_response.php +++ b/logic/curl_json_response.php @@ -7,22 +7,22 @@ /** * Process response from telegram api. * @param string $json_response Json response from Telegram - * @param string $json Json sent to Telegram + * @param string $request Request sent to Telegram * @param array|int|string $identifier raid array from get_raid, raid id or [overview/trainer] * @return mixed */ -function curl_json_response($json_response, $json, $identifier = false) +function curl_json_response($json_response, $request, $identifier = false) { - global $config, $metrics, $tg_response_code; + global $metrics, $tg_response_code; // Write to log. debug_log_incoming($json_response, '<-'); // Decode json objects - $request = json_decode($json, true); + $request_array = is_array($request) ? $request : json_decode($request, true); $response = json_decode($json_response, true); if ($metrics){ $code = 200; - $method = $request['method']; + $method = $request_array['method']; $description = null; if (isset($response['error_code'])) { $code = $response['error_code']; @@ -33,7 +33,7 @@ function curl_json_response($json_response, $json, $identifier = false) } // Validate response. if ((isset($response['ok']) && $response['ok'] != true) || isset($response['update_id'])) { - if(is_array($json)) $json = json_encode($json); + if(is_array($request)) $json = json_encode($request); else $json = $request; info_log("{$json} -> {$json_response}", 'ERROR:'); } else { if($identifier != false) { From ae8ee4999ceaf877fb0e683cd51248a3980d3570 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 24 Mar 2022 18:06:58 +0200 Subject: [PATCH 013/367] Importal fixes - Fixed portalmapbot message parsing - Fixed a couple of php errors --- core/bot/importal.php | 25 +++++++++++++++---------- mods/importal.php | 5 +++-- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/core/bot/importal.php b/core/bot/importal.php index 996d316c..456c4e63 100644 --- a/core/bot/importal.php +++ b/core/bot/importal.php @@ -8,13 +8,24 @@ $msg_to_rows = explode(PHP_EOL, $update['message']['text']); + $supported_bots = ['Ingressportalbot', 'PortalMapBot']; + if(isset($update['message']['via_bot']) && in_array($update['message']['via_bot']['username'], $supported_bots)) { + $parse_bot = $update['message']['via_bot']['username']; + }else { + // Invalid input or unknown bot - send message and end. + $msg = '' . getTranslation('invalid_input') . ''; + $msg .= CR . CR . getTranslation('not_supported') . SP . getTranslation('or') . SP . getTranslation('internal_error'); + send_message($update['message']['from']['id'], $msg); + exit(); + } + // Ingressportalbot - if(strpos($update['message']['text'], $icon . 'Portal:') === 0) { + if($parse_bot == 'Ingressportalbot') { // Set portal bot name. $botname = '@Ingressportalbot'; // Get portal name. - $portal = trim(str_replace($icon . 'Portal:', '', strtok($update['message']['text'], PHP_EOL))); + $portal = trim(str_replace($icon . 'Portal:', '', $msg_to_rows[0])); // Get portal address. $address = trim(explode(':', $msg_to_rows[1], 2)[1]); @@ -40,12 +51,12 @@ $portal_image = $update['message']['entities']['0']['url']; // PortalMapBot - } else if(substr_compare(strtok($update['message']['text'], PHP_EOL), '(Intel)', -strlen('(Intel)')) === 0) { + } else if($parse_bot == 'PortalMapBot') { // Set portal bot name. $botname = '@PortalMapBot'; // Get portal name. - $portal = trim(substr(strtok($update['message']['text'], PHP_EOL), 0, -strlen('(Intel)'))); + $portal = trim(str_replace('(Intel)','', str_replace('(Scanner)','',$msg_to_rows[0]))); // Check for strange characters at the beginn of the portal name: â<81>£ // â = 0x00E2 @@ -70,12 +81,6 @@ // Portal image $portal_image = $update['message']['entities']['0']['url']; - } else { - // Invalid input or unknown bot - send message and end. - $msg = '' . getTranslation('invalid_input') . ''; - $msg .= CR . CR . getTranslation('not_supported') . SP . getTranslation('or') . SP . getTranslation('internal_error'); - send_message($update['message']['from']['id'], $msg); - exit(); } // Empty address? Try lookup. diff --git a/mods/importal.php b/mods/importal.php index fa589151..80d7ecaa 100644 --- a/mods/importal.php +++ b/mods/importal.php @@ -82,6 +82,7 @@ function escape($value){ UPDATE gyms SET lat = :lat, lon = :lon, + gym_name = :gym_name, address = :address, ' . $update_values . ' img_url = :gym_image @@ -94,7 +95,7 @@ function escape($value){ // Insert / Update. $statement = $dbh->prepare($query); $statement->execute([ - 'gym_name' => $gym_name, + 'gym_name' => $gym_name_no_spec, 'lat' => $lat, 'lon' => $lon, 'address' => $address, @@ -119,7 +120,7 @@ function escape($value){ } // Gym photo. - if($gym_image) { + if($config->RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY && $gym_image) { $msg .= EMOJI_CAMERA . SP . $no_spaces_gym_name; } From 15696403f6cbd5885f6b0ecd43ba067b3913f52d Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 26 Mar 2022 10:44:01 +0200 Subject: [PATCH 014/367] fix to /list with gymareas enabled --- logic/raid_edit_gyms_first_letter_keys.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/logic/raid_edit_gyms_first_letter_keys.php b/logic/raid_edit_gyms_first_letter_keys.php index c5c02206..573397fa 100644 --- a/logic/raid_edit_gyms_first_letter_keys.php +++ b/logic/raid_edit_gyms_first_letter_keys.php @@ -143,10 +143,17 @@ function raid_edit_gyms_first_letter_keys($action = 'raid_by_gym', $hidden = fal if ($active_raid > 0) { $gym_name = EMOJI_WARN . SP . $gym_name; } - $keys[] = array( - 'text' => $gym_name, - 'callback_data' => 'gl' . $gymarea_id . ':' . $gym_name_action . ':' . $gym['id'] - ); + if($gym_name_action == 'list_raid') { + $keys[] = array( + 'text' => $gym_name, + 'callback_data' => '0:' . $gym_name_action . ':' . $gym['id'] + ); + }else { + $keys[] = array( + 'text' => $gym_name, + 'callback_data' => 'gl' . $gymarea_id . ':' . $gym_name_action . ':' . $gym['id'] + ); + } } } From 1eae7c24c516ed3b9d13846290ce2f3255a21e5d Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 1 Apr 2022 22:07:10 +0300 Subject: [PATCH 015/367] Raid picture fixes If you're using `RAID_PICTURE_AUTOEXTEND true`, `RAID_PICTURE_SEND_METHOD url` and scheduled bosses together with webhook posted/updated raids, you'll probably still get spammed with TG errors when the egg hatches. I'm not fixing that, it'll go away when we get rid of url method for passing raid pictures --- commands/raid_from_webhook.php | 2 +- logic/raid_picture.php | 7 ++----- logic/update_raid_poll.php | 9 ++++++--- mods/raid_set_poke.php | 2 +- raidpicture.php | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 96008fb5..a086cb27 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -338,7 +338,7 @@ function isPointInsidePolygon($point, $vertices) { $chats_geofence = $chats_raidlevel = $webhook_chats = $chats_by_pokemon = []; if($send_updates == true) { require_once(LOGIC_PATH .'/update_raid_poll.php'); - $tg_json = update_raid_poll($raid_id, $raid, false, $tg_json, false); + $tg_json = update_raid_poll($raid_id, $raid, false, $tg_json, true); if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0]) && !$no_auto_posting) { foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 9424ec64..f16f4e6f 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -88,9 +88,6 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $GLOBALS['requests_total']->inc(['raidpicture']); } - if(utcnow() > $raid['end_time']) $raid_ongoing = false; - else $raid_ongoing = true; - // Query missing raid info $q_pokemon_info = my_query(" SELECT @@ -277,7 +274,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $show_boss_pokemon_types = false; // Raid running - if($raid_ongoing) { + if(!$raid['raid_ended']) { if(strlen($raid['asset_suffix']) > 2) { $icon_suffix = $raid['asset_suffix']; }else { @@ -515,7 +512,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Raid times - if($raid_ongoing) { + if(!$raid['raid_ended']) { $time_text = get_raid_times($raid, true, true); } else { $time_text = getPublicTranslation('raid_done'); diff --git a/logic/update_raid_poll.php b/logic/update_raid_poll.php index 8a9d1cc7..45a74575 100644 --- a/logic/update_raid_poll.php +++ b/logic/update_raid_poll.php @@ -6,10 +6,11 @@ * @param array|false $raid Array received from get_raid() (optional). * @param array|false $update * @param array|false $tg_json Multicurl array. + * @param bool $update_photo Update the raid photo. * @return array|false tg_json multicurl array */ -function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = false) +function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = false, $update_photo = false) { global $config; $chat_and_message = []; @@ -26,10 +27,12 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f } // If neither of the methods above yielded results, or update came from a inline poll, check cleanup table for chat messages to update if(empty($chat_and_message) or isset($update['callback_query']['inline_message_id'])) { + if($update_photo) $photo_query = 'AND type = \'photo\''; else $photo_query = ''; $rs_chann = my_query(' SELECT chat_id, message_id, type, media_unique_id FROM cleanup - WHERE raid_id = ' . $raid_id + WHERE raid_id = ' . $raid_id . ' + ' . $photo_query ); if ($rs_chann->rowCount() > 0) { while($chat = $rs_chann->fetch()) { @@ -102,7 +105,7 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f $tg_json[] = editMessageCaption($message, $text['short'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); } } - }else if ($type == 'photo') { + }else if ($type == 'photo' && $update_photo) { $media_content = get_raid_picture($raid, 1); $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { diff --git a/mods/raid_set_poke.php b/mods/raid_set_poke.php index d8f05a32..f936b614 100644 --- a/mods/raid_set_poke.php +++ b/mods/raid_set_poke.php @@ -48,7 +48,7 @@ // Update the shared raid polls. require_once(LOGIC_PATH .'/update_raid_poll.php'); -$tg_json = update_raid_poll($id, $raid, false, $tg_json); +$tg_json = update_raid_poll($id, $raid, false, $tg_json, true); // Alert users. $tg_json = alarm($raid, $update['callback_query']['from']['id'], 'new_boss', '', $tg_json); diff --git a/raidpicture.php b/raidpicture.php index 124cd9cf..fa415594 100644 --- a/raidpicture.php +++ b/raidpicture.php @@ -36,9 +36,9 @@ $raid['raid_costume'] = false; $raid['event'] = ($_GET['ex_raid'] == 1) ? EVENT_ID_EX : 0; if($_GET['start_time'] == 0) { - $raid_ongoing = false; + $raid['raid_ended'] = true; }else { - $raid_ongoing = true; + $raid['raid_ended'] = false; $raid['start_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['start_time'])); $raid['end_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['end_time'])); } From 2a61a573889a097f4352678057c53081e4679a95 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 2 Apr 2022 15:45:23 +0300 Subject: [PATCH 016/367] Proper format --- logic/curl_json_response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/curl_json_response.php b/logic/curl_json_response.php index 8e898f2d..1b2038e1 100644 --- a/logic/curl_json_response.php +++ b/logic/curl_json_response.php @@ -71,7 +71,7 @@ function curl_json_response($json_response, $request, $identifier = false) $unique_id = $photo['file_unique_id']; } } - $standalone_photo = (array_key_exists('standalone_photo', $identifier) && $identifier['standalone_photo'] === true) ? true : false; + $standalone_photo = (array_key_exists('standalone_photo', $identifier) && $identifier['standalone_photo'] === true) ? 1 : 0; my_query(" REPLACE INTO photo_cache VALUES (:id, :unique_id, :pokedex_id, :form_id, :raid_id, :ended, :gym_id, :standalone) From 4ca3a79417e4d64254d60dd80aa40af5df7e2ce7 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 27 Apr 2022 20:47:23 +0300 Subject: [PATCH 017/367] getdb fix --- mods/getdb.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/getdb.php b/mods/getdb.php index f2d80b19..1cf7f41c 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -44,7 +44,7 @@ $pokemon_id = $id; foreach($forms as $form=>$data) { // Check that data is set, if not the mon is probably not in the game yet and there's no point in having them in a broken state - if(isset($data['weather']) && isset($data['min_cp']) && isset($data['max_cp']) && isset($data['min_weather_cp']) && isset($data['max_weather_cp'])) { + if(isset($data['weather']) && isset($data['min_cp']) && isset($data['max_cp']) && isset($data['min_weather_cp']) && isset($data['max_weather_cp']) && isset($data['pokemon_name'])) { $poke_form = $form; $poke_name = $data['pokemon_name']; From cc70b742c57cfdfc5d8b0d7bd51c7ae779b0177f Mon Sep 17 00:00:00 2001 From: Artanicus Date: Fri, 29 Apr 2022 16:30:34 +0300 Subject: [PATCH 018/367] Fail pokemon form name resolutions with a useful error --- logic/get_pokemon_form_name.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/logic/get_pokemon_form_name.php b/logic/get_pokemon_form_name.php index 64e81bd7..075e742b 100644 --- a/logic/get_pokemon_form_name.php +++ b/logic/get_pokemon_form_name.php @@ -24,8 +24,12 @@ function get_pokemon_form_name($pokedex_id, $pokemon_form_id) ); $level = $rs->fetch(); - $pokemon_form_name = $level['pokemon_form_name']; - + if($level) { + $pokemon_form_name = $level['pokemon_form_name']; + } else { + $error = "pokemon_form_name unknown for pokedex_id: {$pokedex_id}, pokemon_form_id: {$pokemon_form_id}"; + throw new Exception($error); + } debug_log($pokemon_form_name, 'Per db, level is:'); } else { debug_log('Faulty dex_id or form_id, defaulting to normal.'); From b7fdc62646b4653eeb223510b4dbd26b4f87e603 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 29 Apr 2022 17:10:37 +0300 Subject: [PATCH 019/367] Fixed getdb to support the new mega system in game master --- mods/getdb.php | 50 ++++++++++++++------------------------------------ 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 1cf7f41c..900de408 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -176,6 +176,7 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { // Using negative to prevent mixup with actual form ID's // Collected from pogoprotos (hoping they won't change, so hard coding them here) $mega_ids = array('MEGA'=>-1,'MEGA_X'=>-2,'MEGA_Y'=>-3); + $mega_asset_suffixes = array('MEGA'=>51,'MEGA_X'=>51,'MEGA_Y'=>52); $weatherboost_table = array( 'POKEMON_TYPE_BUG' => '3', @@ -245,34 +246,6 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { } } - }else if($part[0] == 'TEMPORARY' && $part[1] == 'EVOLUTION') { - // Found Mega pokemon data - // Get pokemon ID - $pokemon_id = ltrim(str_replace('V','',$part[2]),'0'); - unset($part[0]); - unset($part[1]); - unset($part[2]); - unset($part[3]); - - // Pokemon name - $pokemon_name = implode("_",$part); - $form_data = $row['data']['temporaryEvolutionSettings']['temporaryEvolutions']; - foreach($form_data as $form) { - // Nidoran - $poke_name = ucfirst(strtolower(str_replace(["_FEMALE","_MALE"],["♀","♂"],$pokemon_name))); - // Ho-oh - $poke_name = str_replace("_","-",$poke_name); - - $form_name = str_replace("TEMP_EVOLUTION_","",$form['temporaryEvolutionId']); - $form_asset_suffix = $form['assetBundleValue']; - $form_id = $mega_ids[$form_name]; - - $pokemon_array[$pokemon_id][$form_name] = [ "pokemon_name"=>$poke_name, - "pokemon_form_name"=>$form_name, - "pokemon_form_id"=>$form_id, - "asset_suffix"=>$form_asset_suffix - ]; - } }else if ($part[1] == "POKEMON" && $part[0][0] == "V" && isset($row['data']['pokemonSettings'])) { // Found Pokemon data $pokemon_id = (int)str_replace("V","",$part[0]); @@ -328,7 +301,7 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { if(isset($row['data']['pokemonSettings']['tempEvoOverrides'])) { foreach($row['data']['pokemonSettings']['tempEvoOverrides'] as $temp_evolution) { if(isset($temp_evolution['tempEvoId'])) { - $form_name = str_replace('TEMP_EVOLUTION_','',$temp_evolution['tempEvoId']); + $mega_evolution_name = str_replace('TEMP_EVOLUTION_','',$temp_evolution['tempEvoId']); // We only override the types for megas // weather info is used to display boosts for caught mons, which often are different from mega's typing $typeOverride = strtolower(str_replace('POKEMON_TYPE_','', $temp_evolution['typeOverride1'])); @@ -337,13 +310,18 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { if(isset($temp_evolution['typeOverride2'])) { $typeOverride2 = strtolower(str_replace('POKEMON_TYPE_','', $temp_evolution['typeOverride2'])); } - $pokemon_array[$pokemon_id][$form_name]['min_cp'] = $min_cp; - $pokemon_array[$pokemon_id][$form_name]['max_cp'] = $max_cp; - $pokemon_array[$pokemon_id][$form_name]['min_weather_cp'] = $min_weather_cp; - $pokemon_array[$pokemon_id][$form_name]['max_weather_cp'] = $max_weather_cp; - $pokemon_array[$pokemon_id][$form_name]['weather'] = $weather; - $pokemon_array[$pokemon_id][$form_name]['type'] = $typeOverride; - $pokemon_array[$pokemon_id][$form_name]['type2'] = $typeOverride2; + $pokemon_array[$pokemon_id][$mega_evolution_name] = [ 'pokemon_name' => $pokemon_array[$pokemon_id][$form_name]['pokemon_name'], + 'pokemon_form_name' => $mega_evolution_name, + 'pokemon_form_id' => $mega_ids[$mega_evolution_name], + 'asset_suffix' => $mega_asset_suffixes[$mega_evolution_name], + 'min_cp' => $min_cp, + 'max_cp' => $max_cp, + 'min_weather_cp' => $min_weather_cp, + 'max_weather_cp' => $max_weather_cp, + 'weather' => $weather, + 'type' => $typeOverride, + 'type2' => $typeOverride2, + ]; } } } From 2745bf3e384e4ecbba48e8ab2e45363b6f602437 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 29 Apr 2022 17:11:19 +0300 Subject: [PATCH 020/367] New translations --- core/lang/pokemon.json | 1 - core/lang/pokemon_moves.json | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/lang/pokemon.json b/core/lang/pokemon.json index b1470fd8..913d424c 100644 --- a/core/lang/pokemon.json +++ b/core/lang/pokemon.json @@ -4139,7 +4139,6 @@ "RU": "Крабаминабл" }, "pokemon_id_741": { - "PT-BR": "Oricório", "EN": "Oricorio", "FR": "Plumeline", "DE": "Choreogel", diff --git a/core/lang/pokemon_moves.json b/core/lang/pokemon_moves.json index 8764d514..d12c7d79 100644 --- a/core/lang/pokemon_moves.json +++ b/core/lang/pokemon_moves.json @@ -3859,5 +3859,31 @@ "IT": "Acrobazia", "RU": "Акробатика", "ES": "Acróbata" + }, + "pokemon_move_365": { + "PT-BR": "Purga de Esplendor", + "EN": "Luster Purge", + "FI": "Luster Purge", + "NL": "Luster Purge", + "NO": "Luster Purge", + "PL": "Luster Purge", + "FR": "Lumi-Éclat", + "DE": "Scheinwerfer", + "IT": "Abbagliante", + "RU": "Генеральная Чистка", + "ES": "Resplandor" + }, + "pokemon_move_366": { + "PT-BR": "Bola de Névoa", + "EN": "Mist Ball", + "FI": "Mist Ball", + "NL": "Mist Ball", + "NO": "Mist Ball", + "PL": "Mist Ball", + "FR": "Ball’Brume", + "DE": "Nebelball", + "IT": "Foschisfera", + "RU": "Шар Тумана", + "ES": "Bola Neblina" } } \ No newline at end of file From 7a4e802e7433cccc1c7786bfaecbb2c1e5fce688 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Tue, 3 May 2022 14:20:34 +0300 Subject: [PATCH 021/367] Add default config values for level 7 raids, i.e. legendary megas Lack of these causes crashes but this does not add full support for them, just avoids some of the crashes. --- config/defaults-config.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/defaults-config.json b/config/defaults-config.json index 233d00dc..890f002e 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -100,6 +100,7 @@ "TRAINER_CHATS":"", "SHARE_CHATS":"", "SHARE_CHATS_LEVEL_X":"", + "SHARE_CHATS_LEVEL_7":"", "SHARE_CHATS_LEVEL_6":"", "SHARE_CHATS_LEVEL_5":"", "SHARE_CHATS_LEVEL_4":"", @@ -109,18 +110,21 @@ "WEBHOOK_CREATOR":"bot_or_user_id", "WEBHOOK_CREATE_ONLY": false, "WEBHOOK_CHATS_ALL_LEVELS":"", + "WEBHOOK_CHATS_LEVEL_7":"", "WEBHOOK_CHATS_LEVEL_6":"", "WEBHOOK_CHATS_LEVEL_5":"", "WEBHOOK_CHATS_LEVEL_4":"", "WEBHOOK_CHATS_LEVEL_3":"", "WEBHOOK_CHATS_LEVEL_2":"", "WEBHOOK_CHATS_LEVEL_1":"", + "WEBHOOK_CHATS_LEVEL_7_0":"", "WEBHOOK_CHATS_LEVEL_6_0":"", "WEBHOOK_CHATS_LEVEL_5_0":"", "WEBHOOK_CHATS_LEVEL_4_0":"", "WEBHOOK_CHATS_LEVEL_3_0":"", "WEBHOOK_CHATS_LEVEL_2_0":"", "WEBHOOK_CHATS_LEVEL_1_0":"", + "WEBHOOK_CHATS_LEVEL_7_1":"", "WEBHOOK_CHATS_LEVEL_6_1":"", "WEBHOOK_CHATS_LEVEL_5_1":"", "WEBHOOK_CHATS_LEVEL_4_1":"", From 156667c0dac8e946dd7cf65e8f1ead183c5070f9 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 3 May 2022 17:39:26 +0300 Subject: [PATCH 022/367] Legendary mega support I might have missed something, let's see --- constants.php | 1 + images/raid_eggs/pokemon_icon_9997_00.png | Bin 0 -> 21087 bytes lang/language.json | 26 ++++++++++++++++++++++ logic/raid_picture.php | 2 +- logic/read_upcoming_bosses.php | 4 ++-- mods/getdb.php | 2 +- mods/pokebattler.php | 13 ++++++----- mods/pokedex_set_raid_level.php | 2 +- sql/pokemon-raid-bot.sql | 4 ++-- sql/upgrade/5.sql | 3 +++ 10 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 images/raid_eggs/pokemon_icon_9997_00.png diff --git a/constants.php b/constants.php index eedf0507..ceb64dac 100644 --- a/constants.php +++ b/constants.php @@ -72,6 +72,7 @@ // Raid eggs. $eggs = array( + '9997', // Level 7 / Legendary Mega '9996', // Level 6 / Mega '9995', // Level 5 '9994', // Level 4 diff --git a/images/raid_eggs/pokemon_icon_9997_00.png b/images/raid_eggs/pokemon_icon_9997_00.png new file mode 100644 index 0000000000000000000000000000000000000000..bdd08eedd319d0a1df34db81b88ea808be7b829d GIT binary patch literal 21087 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 zo>8e(setTimezone($ph); @@ -144,7 +147,7 @@ debug_log('Processing received pokebattler raid bosses for each raid level'); foreach($pb_data['tiers'] as $tier) { $rl = str_replace('RAID_LEVEL_','', $tier['tier']); - if($rl == "MEGA") $raid_level_id = 6; else $raid_level_id = $rl; + if($rl == "MEGA") $raid_level_id = 6; elseif($rl == 'MEGA_5') $raid_level_id = 7; else $raid_level_id = $rl; // Skip this raid level if the boss data was already collected from breaking news or raid level doesn't interest us if(!in_array($tier['tier'], $raidlevels) or isset($levels_processed[$raid_level_id])) { continue; @@ -164,7 +167,7 @@ $count = count($get_levels)-1; for($i=$count;$i>=0;$i--) { $raid_level_id = $get_levels[$i]; - if($raid_level_id == 6) $rl = "MEGA"; else $rl = $raid_level_id; + if($raid_level_id == 6) $rl = "MEGA"; elseif($raid_level_id == 7) $rl = "Legendary MEGA"; else $rl = $raid_level_id; $msg .= '' . getTranslation('pokedex_raid_level') . SP . $rl . ':' . CR; foreach($bosses[$raid_level_id] as $dex_id_form) { $dex_id = explode('-', $dex_id_form['id'], 2)[0]; diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index 4812bc4c..6a0f473b 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -22,7 +22,7 @@ // Set raid level or show raid levels? if($data['arg'] == "setlevel") { - $raid_levels = [0,1,3,5,6,'X']; + $raid_levels = [0,1,3,5,6,7,'X']; // Init empty keys array. $keys = []; diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 74b8d20e..3a6e8ab3 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -100,7 +100,7 @@ CREATE TABLE `raid_bosses` ( `pokemon_form_id` int(4) DEFAULT NULL, `date_start` datetime NOT NULL DEFAULT '1970-01-01 00:00:01', `date_end` datetime NOT NULL DEFAULT '2038-01-19 03:14:07', - `raid_level` enum('1','2','3','4','5','6','X') DEFAULT NULL, + `raid_level` enum('1','2','3','4','5','6','7','X') DEFAULT NULL, `scheduled` TINYINT(1) NULL DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -114,7 +114,7 @@ CREATE TABLE `raids` ( `end_time` datetime DEFAULT NULL, `gym_team` enum('mystic','valor','instinct') DEFAULT NULL, `gym_id` int(10) unsigned NOT NULL, - `level` enum('1','2','3','4','5','6','X') DEFAULT NULL, + `level` enum('1','2','3','4','5','6','7','X') DEFAULT NULL, `move1` varchar(255) DEFAULT NULL, `move2` varchar(255) DEFAULT NULL, `gender` varchar(255) DEFAULT NULL, diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index 4ff94df7..a20c253f 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -3,3 +3,6 @@ ALTER TABLE user_input CHANGE COLUMN IF EXISTS `user_id` `user_id` BIGINT(20) DE CREATE TABLE `photo_cache` (`id` varchar(100) NOT NULL, `unique_id` varchar(45) NOT NULL, `pokedex_id` int(10) DEFAULT NULL, `form_id` int(4) DEFAULT NULL, `raid_id` int(10) unsigned DEFAULT NULL, `ended` tinyint(1) DEFAULT NULL, `gym_id` int(10) unsigned DEFAULT NULL, `standalone` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`unique_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); + +ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','X') DEFAULT NULL; +ALTER TABLE `raid_bosses` MODIFY `raid_level` enum('1','2','3','4','5','6','7','X') DEFAULT NULL; From d80ae9a619233ba2eec6ec29f340c8de03734d06 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 4 May 2022 17:01:32 +0300 Subject: [PATCH 023/367] Raidpicture update fix --- logic/update_raid_poll.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/update_raid_poll.php b/logic/update_raid_poll.php index 45a74575..3c0ccfd5 100644 --- a/logic/update_raid_poll.php +++ b/logic/update_raid_poll.php @@ -27,7 +27,7 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f } // If neither of the methods above yielded results, or update came from a inline poll, check cleanup table for chat messages to update if(empty($chat_and_message) or isset($update['callback_query']['inline_message_id'])) { - if($update_photo) $photo_query = 'AND type = \'photo\''; else $photo_query = ''; + if($update_photo) $photo_query = 'AND (type = \'photo\' OR type = \'poll_photo\')'; else $photo_query = ''; $rs_chann = my_query(' SELECT chat_id, message_id, type, media_unique_id FROM cleanup From d23fcd293c1544b9afa81d846705b4bdf4b6109d Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 4 May 2022 19:27:33 +0300 Subject: [PATCH 024/367] Autopost raid timelimit fix --- commands/raid_from_webhook.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index a086cb27..18a64a1a 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -52,9 +52,6 @@ function isPointInsidePolygon($point, $vertices) { } } -// Skip posting if create only -mode is set or raid time is greater than value set in config -$no_auto_posting = ($config->WEBHOOK_CREATE_ONLY or ($raid['message']['end']-$raid['message']['start']) > ($config->WEBHOOK_EXCLUDE_AUTOSHARE_DURATION * 60)); - // Telegram JSON array. $tg_json = []; debug_log(count($update),"Received raids:"); @@ -62,6 +59,9 @@ function isPointInsidePolygon($point, $vertices) { $webhook_raids_received_total->incBy(count($update)); } foreach ($update as $raid) { + // Skip posting if create only -mode is set or raid time is greater than value set in config + $no_auto_posting = ($config->WEBHOOK_CREATE_ONLY or ($raid['message']['end']-$raid['message']['start']) > ($config->WEBHOOK_EXCLUDE_AUTOSHARE_DURATION * 60)); + $level = $raid['message']['level']; $pokemon = $raid['message']['pokemon_id']; $exclude_raid_levels = explode(',', $config->WEBHOOK_EXCLUDE_RAID_LEVEL); From 8f5827d902caa904b27cc7dbf529d832f10d16d0 Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 4 May 2022 20:11:50 +0300 Subject: [PATCH 025/367] Raid level 7 --- constants.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constants.php b/constants.php index ceb64dac..0b96542f 100644 --- a/constants.php +++ b/constants.php @@ -3,7 +3,7 @@ define('PORTAL_IMAGES_PATH', IMAGES_PATH . '/gyms'); // raid level constants -define('RAID_LEVEL_ALL', '654321'); +define('RAID_LEVEL_ALL', '7654321'); // Value used for denoting anytime attendance define('ANYTIME', '1970-01-01 00:00:00'); From e70523d8656d3652cc66e1295b10d131992b8b9d Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 5 May 2022 19:55:13 +0300 Subject: [PATCH 026/367] Moved all stuff regarding raid level control to constants.php Should make adding/removing raid levels easier. I also made the webhook autoposting more failproof for unsupported raid levels/missing chat config values --- commands/raid_from_webhook.php | 4 +-- constants.php | 41 +++++++++++++++------- lang/language.json | 26 ++++++++++++++ logic/read_upcoming_bosses.php | 5 +-- mods/getdb.php | 6 ++-- mods/pokebattler.php | 61 +++++++++++---------------------- mods/pokedex_disable_raids.php | 16 ++++----- mods/pokedex_set_raid_level.php | 2 +- 8 files changed, 90 insertions(+), 71 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 18a64a1a..afdc3c8b 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -357,7 +357,7 @@ function isPointInsidePolygon($point, $vertices) { if($geofences != false) { foreach ($inside_geofences as $geofence_id) { $const_geofence = 'WEBHOOK_CHATS_LEVEL_' . $level . '_' . $geofence_id; - $const_geofence_chats = $config->{$const_geofence}; + $const_geofence_chats = $config->{$const_geofence} ?? []; if(!empty($const_geofence_chats)) { $chats_geofence = explode(',', $const_geofence_chats); @@ -367,7 +367,7 @@ function isPointInsidePolygon($point, $vertices) { // Get chats to share to by raid level $const = 'WEBHOOK_CHATS_LEVEL_' . $level; - $const_chats = $config->{$const}; + $const_chats = $config->{$const} ?? []; if(!empty($const_chats)) { $chats_raidlevel = explode(',', $const_chats); diff --git a/constants.php b/constants.php index 0b96542f..2ff8075f 100644 --- a/constants.php +++ b/constants.php @@ -2,8 +2,34 @@ // Paths. define('PORTAL_IMAGES_PATH', IMAGES_PATH . '/gyms'); -// raid level constants -define('RAID_LEVEL_ALL', '7654321'); +// raid levels constant +define('RAID_LEVEL_ALL', 'X76531'); + +// Raid eggs. +$eggs = array( + '9997', // Level 7 / Legendary Mega + '9996', // Level 6 / Mega + '9995', // Level 5 + '9994', // Level 4 + '9993', // Level 3 + '9992', // Level 2 + '9991' // Level 1 +); + +// Levels available for import at PokeBattler +$pokebattler_levels = array('7', '6', '5', '3', '1'); + +// Map our raid levels to tier names PokeBattler uses +$pokebattler_level_map = [ + '1' => 1, + '3' => 3, + '5' => 5, + '6' => 'MEGA', + '7' => 'MEGA_5', +]; + +// Limit the tiers of upcoming raid bosses imported from PokeBattler to legendary and mega +$pokebattler_import_future_tiers = [5, 6, 7]; // Value used for denoting anytime attendance define('ANYTIME', '1970-01-01 00:00:00'); @@ -69,14 +95,3 @@ 'unknown' => TEAM_UNKNOWN, 'cancel' => TEAM_CANCEL ); - -// Raid eggs. -$eggs = array( - '9997', // Level 7 / Legendary Mega - '9996', // Level 6 / Mega - '9995', // Level 5 - '9994', // Level 4 - '9993', // Level 3 - '9992', // Level 2 - '9991' // Level 1 -); diff --git a/lang/language.json b/lang/language.json index 8ccf3c51..a6110523 100644 --- a/lang/language.json +++ b/lang/language.json @@ -38,6 +38,19 @@ "FI": "Legendaarinen Mega-Raidi", "ES": "TRANSLATE" }, + "7stars_short": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Lege Mega", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Lege Mega", + "ES": "TRANSLATE" + }, "6stars": { "NL": "Mega-Raid", "DE": "Mega-Raid", @@ -51,6 +64,19 @@ "FI": "Mega-Raidi", "ES": "Mega Incursión" }, + "6stars_short": { + "NL": "Mega", + "DE": "Mega", + "EN": "Mega", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Mega", + "ES": "Mega" + }, "5stars": { "NL": "5 Sterren", "DE": "5 Sterne", diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index 900e522a..4ff96a27 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -6,6 +6,7 @@ * @return string */ function read_upcoming_bosses($return_sql = false) { + global $pokebattler_import_future_tiers, $pokebattler_level_map; $link = curl_get_contents('https://fight.pokebattler.com/raids'); $pb = json_decode($link,true); @@ -15,8 +16,8 @@ function read_upcoming_bosses($return_sql = false) { foreach($pb['breakingNews'] as $news) { if($news['type'] == 'RAID_TYPE_RAID') { $rl = str_replace('RAID_LEVEL_','', $news['tier']); - if($rl == 'MEGA') $raid_level_id = 6; elseif($rl == 'MEGA_5') $raid_level_id = 7; else $raid_level_id = $rl; - if($raid_level_id != '5' and $raid_level_id != '6' and $raid_level_id != '7') break; // Limit scheduling to tier 5 and mega only + $raid_level_id = array_search($rl, $pokebattler_level_map); + if(!in_array($raid_level_id,$pokebattler_import_future_tiers)) break; // Limit scheduling to tier 5 and mega only $starttime = new DateTime("@".(substr($news['startDate'],0,10)), new dateTimeZone('UTC')); $endtime = new DateTime("@".(substr($news['endDate'],0,10)), new dateTimeZone('UTC')); diff --git a/mods/getdb.php b/mods/getdb.php index 21677cd8..1b858885 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -19,10 +19,10 @@ } else { $PRE = 'INSERT INTO `pokemon`' . PHP_EOL; $PRE .= '(pokedex_id, pokemon_name, pokemon_form_name, pokemon_form_id, asset_suffix, min_cp, max_cp, min_weather_cp, max_weather_cp, type, type2, weather) VALUES'; - for($e = 1; $e <= 7; $e++) { - $pokemon_id = '999'.$e; + foreach($eggs as $egg) { + $pokemon_id = $egg; $form_name = 'normal'; - $pokemon_name = 'Level '. $e .' Egg'; + $pokemon_name = 'Level '. $egg[3] .' Egg'; $pokemon_array[$pokemon_id][$form_name] = [ 'pokemon_name'=>$pokemon_name, 'pokemon_form_name'=>$form_name, 'pokemon_form_id'=>0, diff --git a/mods/pokebattler.php b/mods/pokebattler.php index 9a584d06..20f7112b 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -10,9 +10,6 @@ bot_access_check($update, 'pokedex'); include(LOGIC_PATH . '/resolve_boss_name_to_ids.php'); -// Levels available for import at PokeBattler -$levels = array('7', '6', '5', '3', '1'); - // Get raid levels $id = $data['id']; @@ -31,11 +28,11 @@ // All raid level keys. $keys[][] = array( 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => RAID_LEVEL_ALL . ':pokebattler:ex#0,0,0' + 'callback_data' => implode(",", $pokebattler_levels) . ':pokebattler:ex#0,0,0' ); // Add key for each raid level - foreach($levels as $l) { + foreach($pokebattler_levels as $l) { $keys[][] = array( 'text' => getTranslation($l . 'stars'), 'callback_data' => $l . ':pokebattler:ex#0,0,0' @@ -69,14 +66,8 @@ $pb_data = curl_get_contents($link); $pb_data = json_decode($pb_data,true); - // All raid levels? - if($id == RAID_LEVEL_ALL) { - $get_levels = $levels; - $clear = "'7','6','5','3','1'"; - } else { - $get_levels = explode(",", $id); - $clear = $id; - } + $get_levels = explode(",", $id); + $clear = $id; // Prefix for exclusion. $prefix = 'ex#'; @@ -112,13 +103,7 @@ debug_log('Processing the following raid levels:'); $raidlevels = array(); foreach($get_levels as $level) { - if($level == 6) { - $level = 'MEGA'; // PB uses RAID_LEVEL_MEGA instead of RAID_LEVEL_6 - } - if($level == 7) { - $level = 'MEGA_5'; // PB uses RAID_LEVEL_MEGA_5 instead of RAID_LEVEL_7 - } - $raidlevels[] = 'RAID_LEVEL_' . $level; + $raidlevels[] = 'RAID_LEVEL_' . $pokebattler_level_map[$level]; } debug_log($raidlevels); $levels_processed = []; @@ -129,7 +114,7 @@ foreach($pb_data['breakingNews'] as $news) { if($news['type'] == 'RAID_TYPE_RAID') { $rl = str_replace('RAID_LEVEL_','', $news['tier']); - if($rl == "MEGA") $raid_level_id = 6; elseif($rl == 'MEGA_5') $raid_level_id = 7; else $raid_level_id = $rl; + $raid_level_id = array_search($rl, $pokebattler_level_map); $starttime = new DateTime("@".substr($news['startDate'],0,10)); $endtime = new DateTime("@".substr($news['endDate'],0,10)); $starttime->setTimezone($ph); @@ -142,12 +127,11 @@ } } } - // Process raid tier(s) debug_log('Processing received pokebattler raid bosses for each raid level'); foreach($pb_data['tiers'] as $tier) { $rl = str_replace('RAID_LEVEL_','', $tier['tier']); - if($rl == "MEGA") $raid_level_id = 6; elseif($rl == 'MEGA_5') $raid_level_id = 7; else $raid_level_id = $rl; + $raid_level_id = array_search($rl, $pokebattler_level_map); // Skip this raid level if the boss data was already collected from breaking news or raid level doesn't interest us if(!in_array($tier['tier'], $raidlevels) or isset($levels_processed[$raid_level_id])) { continue; @@ -164,11 +148,10 @@ } } - $count = count($get_levels)-1; - for($i=$count;$i>=0;$i--) { - $raid_level_id = $get_levels[$i]; - if($raid_level_id == 6) $rl = "MEGA"; elseif($raid_level_id == 7) $rl = "Legendary MEGA"; else $rl = $raid_level_id; - $msg .= '' . getTranslation('pokedex_raid_level') . SP . $rl . ':' . CR; + foreach($get_levels as $raid_level_id) { + if($raid_level_id > 5) $raid_level_text = getTranslation($raid_level_id . 'stars_short'); else $raid_level_text = $raid_level_id; + if(!isset($bosses[$raid_level_id])) continue; + $msg .= '' . getTranslation('pokedex_raid_level') . SP . $raid_level_text . ':' . CR; foreach($bosses[$raid_level_id] as $dex_id_form) { $dex_id = explode('-', $dex_id_form['id'], 2)[0]; $dex_form = explode('-', $dex_id_form['id'], 2)[1]; @@ -235,20 +218,16 @@ // Are 3 raid bosses already selected? if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { - // Add raid level to pokemon name - if($id == RAID_LEVEL_ALL) { - // Add key to exclude pokemon from import. - $keys[] = array( - 'text' => '[' . ($rl) . ']' . SP . $local_pokemon, - 'callback_data' => $id . ':pokebattler:' . $new_arg - ); - } else { - // Add key to exclude pokemon from import. - $keys[] = array( - 'text' => $local_pokemon, - 'callback_data' => $id . ':pokebattler:' . $new_arg - ); + // Add key to exclude pokemon from import. + $button_text_prefix = ''; + if($id == implode(",", $pokebattler_levels)) { + // Add raid level to pokemon name + $button_text_prefix = '[' . ($raid_level_text) . ']'; } + $keys[] = array( + 'text' => $button_text_prefix . SP . $local_pokemon, + 'callback_data' => $id . ':pokebattler:' . $new_arg + ); } } } diff --git a/mods/pokedex_disable_raids.php b/mods/pokedex_disable_raids.php index 0e4db6a6..f5238b32 100644 --- a/mods/pokedex_disable_raids.php +++ b/mods/pokedex_disable_raids.php @@ -15,18 +15,16 @@ // Get argument. $arg = $data['arg']; +// Specify raid levels. +$levels = str_split(RAID_LEVEL_ALL); + // All raid levels? -if($id == 'X' . RAID_LEVEL_ALL) { - // TODO(artanicus): get this from somewhere instead of hardcoded - $clear = "'X','6','5','3','1'"; +if($id == RAID_LEVEL_ALL) { + $clear = "'" . implode("','", $levels) . "'"; } else { $clear = "'" . $id . "'"; } -// Specify raid levels. -// TODO(artanicus): get this from somewhere instead of hardcoded -$levels = array('X', '6', '5', '3', '1'); - // Raid level selection if($arg == 0) { // Set message. @@ -38,7 +36,7 @@ // All raid level keys. $keys[] = array( 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => 'X' . RAID_LEVEL_ALL . ':pokedex_disable_raids:1' + 'callback_data' => RAID_LEVEL_ALL . ':pokedex_disable_raids:1' ); // Add key for each raid level @@ -124,7 +122,7 @@ $msg = '' . getTranslation('disabled_raid_level') . ':' . CR; // All levels - if($id == 'X' . RAID_LEVEL_ALL) { + if($id == RAID_LEVEL_ALL) { foreach($levels as $lv) { $msg .= getTranslation($lv . 'stars') . CR; } diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index 6a0f473b..473aa65e 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -22,7 +22,7 @@ // Set raid level or show raid levels? if($data['arg'] == "setlevel") { - $raid_levels = [0,1,3,5,6,7,'X']; + $raid_levels = str_split('0' . RAID_LEVEL_ALL); // Init empty keys array. $keys = []; From 7a706e45403bc3a9d48fa97610a08cde20096147 Mon Sep 17 00:00:00 2001 From: klablabla <30940278+klablabla@users.noreply.github.com> Date: Sat, 7 May 2022 15:26:42 +0200 Subject: [PATCH 027/367] Added dutch translation --- lang/language.json | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lang/language.json b/lang/language.json index a6110523..f7077baa 100644 --- a/lang/language.json +++ b/lang/language.json @@ -26,7 +26,7 @@ "ES": "Incursión EX" }, "7stars": { - "NL": "TRANSLATE", + "NL": "Legendary Mega-Raid", "DE": "TRANSLATE", "EN": "Legendary Mega-Raid", "IT": "TRANSLATE", @@ -39,7 +39,7 @@ "ES": "TRANSLATE" }, "7stars_short": { - "NL": "TRANSLATE", + "NL": "Lege Mega", "DE": "TRANSLATE", "EN": "Lege Mega", "IT": "TRANSLATE", @@ -156,7 +156,7 @@ "ES": "Desactivado" }, "egg_7": { - "NL": "TRANSLATE", + "NL": "Legendary Mega-Raid Ei", "DE": "TRANSLATE", "EN": "Legendary Mega-Raid Egg", "IT": "TRANSLATE", @@ -260,7 +260,7 @@ "ES": "Huevo Incursión" }, "upcoming": { - "NL": "TRANSLATE", + "NL": "geplande", "DE": "TRANSLATE", "EN": "upcoming", "IT": "TRANSLATE", @@ -273,7 +273,7 @@ "ES": "próximo" }, "upcoming_bosses_not_found": { - "NL": "TRANSLATE", + "NL": "Geen informatie gevonden voor geplande raid bazen!", "DE": "TRANSLATE", "EN": "No info of upcoming bosses was found!", "IT": "TRANSLATE", @@ -286,7 +286,7 @@ "ES": "¡No se encontró información de los próximos jefes!" }, "current_scheduled_bosses": { - "NL": "TRANSLATE", + "NL": "Geplande raid bazen van de database", "DE": "TRANSLATE", "EN": "Scheduled raid bosses from database", "IT": "TRANSLATE", @@ -299,7 +299,7 @@ "ES": "Jefes de incursión programados de la base de datos" }, "unscheduled_bosses": { - "NL": "TRANSLATE", + "NL": "Ongeplande bazen", "DE": "TRANSLATE", "EN": "Unscheduled bosses", "IT": "TRANSLATE", @@ -312,7 +312,7 @@ "ES": "Jefes no programados" }, "delete_scheduled_confirmation": { - "NL": "TRANSLATE", + "NL": "Wil je de geplande baas verwijderen?", "DE": "TRANSLATE", "EN": "Do you want to delete this scheduled entry?", "IT": "TRANSLATE", @@ -325,7 +325,7 @@ "ES": "¿Quieres eliminar esta entrada programada?" }, "found_upcoming_bosses": { - "NL": "TRANSLATE", + "NL": "Volgende geplande raid bazen gevonden", "DE": "TRANSLATE", "EN": "Found following upcoming bosses", "IT": "TRANSLATE", @@ -338,7 +338,7 @@ "ES": "Próximos jefes encontrado" }, "confirm_replace_upcoming": { - "NL": "TRANSLATE", + "NL": "Wil je de data vervangen met wat we gevonden hebben?", "DE": "TRANSLATE", "EN": "Would you like to replace the current data with what we found?", "IT": "TRANSLATE", @@ -637,7 +637,7 @@ "ES": "Importar" }, "update_pokemon_table": { - "NL": "TRANSLATE", + "NL": "Update Pokemon tabel", "DE": "TRANSLATE", "EN": "Update Pokemon table", "IT": "TRANSLATE", @@ -819,7 +819,7 @@ "ES": "Incursión remota" }, "remote_raids": { - "NL": "TRANSLATE", + "NL": "Remote raids", "DE": "TRANSLATE", "EN": "Remote raids", "IT": "TRANSLATE", @@ -871,7 +871,7 @@ "ES": "Has participado en la incursión remota que creaste. ¿Quieres eliminar el anuncio de la incursión?" }, "delete_remote_raid_cancel": { - "NL": "TRANSLATE", + "NL": "Je hebt je aanwezigheid bij de remote raid afgezegd. Kunnen we het raid overzicht verwijderen?", "DE": "TRANSLATE", "EN": "You have canceled your attendance to the remote raid you created. Can we delete the raid poll?", "IT": "TRANSLATE", @@ -988,7 +988,7 @@ "ES": "Por favor, selecciona la primera letra del gimnasio:" }, "select_gym_first_letter_or_gym_area": { - "NL": "TRANSLATE", + "NL": "Selecteer de eerste letter van de gym of gym gebied:", "DE": "TRANSLATE", "EN": "Please select the first letter of the gym or gym area:", "IT": "TRANSLATE", @@ -1001,7 +1001,7 @@ "ES": "Seleccione la primera letra del gimnasio o la zona del gimnasio:" }, "select_gym_name_or_gym_area": { - "NL": "TRANSLATE", + "NL": "Selecteer gym of gym gebied:", "DE": "TRANSLATE", "EN": "Please select gym or gym area:", "IT": "TRANSLATE", @@ -1014,7 +1014,7 @@ "ES": "Seleccione gimnasio o zona de gimnasio:" }, "select_gym_area": { - "NL": "TRANSLATE", + "NL": "Selecteer gym gebied:", "DE": "TRANSLATE", "EN": "Please select the gymarea:", "IT": "TRANSLATE", @@ -3393,7 +3393,7 @@ "ES": "¡Alertas de incursión activadas!" }, "switch_alarm_on": { - "NL": "TRANSLATE", + "NL": "Zet automatische raid alarm aan", "DE": "TRANSLATE", "EN": "Enable automatic raid alerts", "IT": "TRANSLATE", @@ -3406,7 +3406,7 @@ "ES": "Activar alertas automáticas de incursiones" }, "switch_alarm_off": { - "NL": "TRANSLATE", + "NL": "Zet automatisch raid alarm uit", "DE": "TRANSLATE", "EN": "Disable automatic raid alerts", "IT": "TRANSLATE", @@ -3848,7 +3848,7 @@ "ES": "¡No se encontraron incursiones con los asistentes!" }, "date": { - "NL": "TRANSLATE", + "NL": "Datum", "DE": "Datum", "EN": "Date", "IT": "TRANSLATE", @@ -3861,7 +3861,7 @@ "ES": "Fecha" }, "current_gymarea": { - "NL": "TRANSLATE", + "NL": "Gym gebied", "DE": "TRANSLATE", "EN": "Current gymarea", "IT": "TRANSLATE", @@ -3873,4 +3873,4 @@ "FI": "Salit alueelta", "ES": "Zona de gimnasio actual" } -} \ No newline at end of file +} From 1450b9f7f8bb71942bcef0b7945d4053ca1c6999 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sat, 7 May 2022 17:17:18 +0300 Subject: [PATCH 028/367] Fail gracefully on not finding weather --- logic/get_pokemon_weather.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/logic/get_pokemon_weather.php b/logic/get_pokemon_weather.php index fa4a95b5..1835b8dc 100644 --- a/logic/get_pokemon_weather.php +++ b/logic/get_pokemon_weather.php @@ -18,10 +18,13 @@ function get_pokemon_weather($pokemon_id, $pokemon_form_id) " ); - // Fetch the row. $ww = $rs->fetch(); - return $ww['weather']; + if($ww) { + return $ww['weather']; + } else { + throw new Exception("Failed to find pokemon {$pokemon_id}_{$pokemon_form_id} weather."); + } } else { return 0; } From 8a5f2ca4561d90ff4a6aaa9a32eeeb3e6d5abd65 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sat, 7 May 2022 17:23:19 +0300 Subject: [PATCH 029/367] Use new global eggs data --- mods/getdb.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/getdb.php b/mods/getdb.php index 1b858885..7a9dbfb3 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -6,7 +6,7 @@ // Read the form ids from protos if($protos = get_protos($proto_url)) { - global $dbh; + global $dbh, $eggs; $form_ids = $protos[0]; $costume = $protos[1]; From d7fe915003a5e1205e3bbb8db95832872f9c71ff Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 21 May 2022 20:05:34 +0300 Subject: [PATCH 030/367] New move translations --- core/lang/pokemon_moves.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/core/lang/pokemon_moves.json b/core/lang/pokemon_moves.json index d12c7d79..55a1489b 100644 --- a/core/lang/pokemon_moves.json +++ b/core/lang/pokemon_moves.json @@ -3885,5 +3885,31 @@ "IT": "Foschisfera", "RU": "Шар Тумана", "ES": "Bola Neblina" + }, + "pokemon_move_368": { + "PT-BR": "Rolagem", + "EN": "Rollout", + "FI": "Rollout", + "NL": "Rollout", + "NO": "Rollout", + "PL": "Rollout", + "FR": "Roulade", + "DE": "Walzer", + "IT": "Rotolamento", + "RU": "Перекат", + "ES": "Desenrollar" + }, + "pokemon_move_369": { + "PT-BR": "Semente Ofuscante", + "EN": "Seed Flare", + "FI": "Seed Flare", + "NL": "Seed Flare", + "NO": "Seed Flare", + "PL": "Seed Flare", + "FR": "Fulmigraine", + "DE": "Schocksamen", + "IT": "Infuriaseme", + "RU": "Сияние Семени", + "ES": "Fogonazo" } } \ No newline at end of file From 5b5bc7860b37989b008e9192f58acc9710e5716e Mon Sep 17 00:00:00 2001 From: Ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 21 May 2022 22:06:51 +0300 Subject: [PATCH 031/367] Prepared raidpicture for the full transition to using new asset naming format As announced, PokeMiners is about to move all the pokemon icon files from Addressable Assets folder to the parent directory. You can prepare your image folder for the transition by removing the `pokemon_icon_*` files from `pokemon(_PokeMiners)` folder and moving every file from `Addressable_Assets` folder to the parent directory and then removing the `Addressable_Assets` folder. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Old file structure: pokemon(_PokeMiners)/ ├─ Addressable_Assets/ │ ├─ pm1.icon.png │ ├─ pm2.icon.png │ ├─ pm3.icon.png ├─ pokemon_icon_001_00.png ├─ pokemon_icon_002_00.png ├─ pokemon_icon_003_00.png New file structure: pokemon(_PokeMiners)/ ├─ pm1.icon.png ├─ pm2.icon.png ├─ pm3.icon.png --- logic/raid_picture.php | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 4a20b215..2c6161c1 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -321,24 +321,23 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $p_icon = $p_icon . ".png"; foreach($p_sources as $p_dir) { + // Icon dir named 'pokemon'? Then change path to not add '_repo-owner' to icon folder name + if($p_dir == 'pokemon') $asset_dir = 'pokemon'; else $asset_dir = 'pokemon_' . $p_dir; // Set pokemon icon dir - $p_img = IMAGES_PATH . "/pokemon_" . $p_dir . "/" . $p_icon; - $p_add_img = IMAGES_PATH . "/pokemon_" . $p_dir . "/Addressable_Assets/" . $addressable_icon; + $p_img_base_path = IMAGES_PATH . "/" . $asset_dir; - // Icon dir named 'pokemon'? Then change path to not add '_repo-owner' to icon folder name - if($p_dir == 'pokemon') { - $p_img = IMAGES_PATH . "/pokemon/" . $p_icon; - $p_add_img = IMAGES_PATH . "/pokemon/Addressable_Assets" . $addressable_icon; - } // Check if file exists in this collection // Prioritize addressable asset file - if(file_exists($p_add_img) && filesize($p_add_img) > 0) { - $img_file = $p_add_img; - break; - }else if(file_exists($p_img) && filesize($p_img) > 0) { - $img_file = $p_img; - break; + if(file_exists($p_img_base_path . "/" . $addressable_icon) && filesize($p_img_base_path . "/" . $addressable_icon) > 0) { + $img_file = $p_img_base_path . "/" . $addressable_icon; + + // These elseifs become redundant after PokeMiners move the files from Addressable Assets folder to the parent directory on 1.6.2022 + }else if(file_exists($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) && filesize($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) > 0) { + $img_file = $p_img_base_path . "/Addressable_Assets/" . $addressable_icon; + }else if(file_exists($p_img_base_path . "/" . $p_icon) && filesize($p_img_base_path . "/" . $p_icon) > 0) { + $img_file = $p_img_base_path . "/" . $p_icon; } + break; } // If no image was found, substitute with a fallback From c08e91ad3c87f0923f1bd3b2ff5a04238e00759f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 3 Jun 2022 19:27:01 +0300 Subject: [PATCH 032/367] RDM support for webhooks Support incoming raid webhooks from RDM --- commands/raid_from_webhook.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index afdc3c8b..36eda590 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -71,7 +71,7 @@ function isPointInsidePolygon($point, $vertices) { continue; } - $gym_name = $raid['message']['name']; + $gym_name = isset($raid['message']['name']) ? $raid['message']['name'] : $raid['message']['gym_name']; if ($config->WEBHOOK_EXCLUDE_UNKNOWN && $gym_name === 'unknown') { debug_log($raid['message']['gym_id'],'Ignoring raid, the gym name is unknown and WEBHOOK_EXCLUDE_UNKNOWN says to ignore. id:'); continue; @@ -79,8 +79,8 @@ function isPointInsidePolygon($point, $vertices) { $gym_lat = $raid['message']['latitude']; $gym_lon = $raid['message']['longitude']; $gym_id = $raid['message']['gym_id']; - $gym_img_url = $raid['message']['url']; - $gym_is_ex = ( $raid['message']['is_ex_raid_eligible'] ? 1 : 0 ); + $gym_img_url = isset($raid['message']['url']) ? $raid['message']['url'] : $raid['message']['gym_url']; + $gym_is_ex = isset($raid['message']['is_ex_raid_eligible']) ? ( $raid['message']['is_ex_raid_eligible'] ? 1 : 0 ) : ( $raid['message']['ex_raid_eligible'] ? 1 : 0 ); $gym_internal_id = 0; // Check geofence, if available, and skip current raid if not inside any fence From 80171fbc722538251e02ddcea0df85fd2878bfaa Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 3 Jun 2022 19:28:00 +0300 Subject: [PATCH 033/367] Fixed asset image selector --- logic/raid_picture.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 2c6161c1..209ab152 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -330,14 +330,15 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Prioritize addressable asset file if(file_exists($p_img_base_path . "/" . $addressable_icon) && filesize($p_img_base_path . "/" . $addressable_icon) > 0) { $img_file = $p_img_base_path . "/" . $addressable_icon; - + break; // These elseifs become redundant after PokeMiners move the files from Addressable Assets folder to the parent directory on 1.6.2022 }else if(file_exists($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) && filesize($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) > 0) { $img_file = $p_img_base_path . "/Addressable_Assets/" . $addressable_icon; + break; }else if(file_exists($p_img_base_path . "/" . $p_icon) && filesize($p_img_base_path . "/" . $p_icon) > 0) { $img_file = $p_img_base_path . "/" . $p_icon; + break; } - break; } // If no image was found, substitute with a fallback From 5f8c5fc39c869fb444faadf06cb7eb6ff324e32f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 3 Jun 2022 19:28:27 +0300 Subject: [PATCH 034/367] New translations --- core/lang/pokemon.json | 1 + core/lang/pokemon_moves.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/lang/pokemon.json b/core/lang/pokemon.json index 913d424c..b1470fd8 100644 --- a/core/lang/pokemon.json +++ b/core/lang/pokemon.json @@ -4139,6 +4139,7 @@ "RU": "Крабаминабл" }, "pokemon_id_741": { + "PT-BR": "Oricório", "EN": "Oricorio", "FR": "Plumeline", "DE": "Choreogel", diff --git a/core/lang/pokemon_moves.json b/core/lang/pokemon_moves.json index 55a1489b..374fa029 100644 --- a/core/lang/pokemon_moves.json +++ b/core/lang/pokemon_moves.json @@ -3724,7 +3724,7 @@ "NL": "Psychic Fangs", "NO": "Psychic Fangs", "PL": "Psychic Fangs", - "FR": "Psychic Fangs", + "FR": "Psycho-Croc", "DE": "Psychobeißer", "IT": "Psicozanna", "RU": "Психоклыки", From b849495dc7b156768bab3a5c8d74d9f9fde35aa5 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 3 Jun 2022 19:41:29 +0300 Subject: [PATCH 035/367] Ultra wormhole support Support for raid level 8 --- config/defaults-config.json | 2 ++ constants.php | 8 ++++--- images/raid_eggs/pokemon_icon_9998_00.png | Bin 0 -> 24848 bytes lang/language.json | 26 ++++++++++++++++++++++ sql/pokemon-raid-bot.sql | 2 +- sql/upgrade/5.sql | 2 +- 6 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 images/raid_eggs/pokemon_icon_9998_00.png diff --git a/config/defaults-config.json b/config/defaults-config.json index 890f002e..7834c4e5 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -110,6 +110,7 @@ "WEBHOOK_CREATOR":"bot_or_user_id", "WEBHOOK_CREATE_ONLY": false, "WEBHOOK_CHATS_ALL_LEVELS":"", + "WEBHOOK_CHATS_LEVEL_8":"", "WEBHOOK_CHATS_LEVEL_7":"", "WEBHOOK_CHATS_LEVEL_6":"", "WEBHOOK_CHATS_LEVEL_5":"", @@ -117,6 +118,7 @@ "WEBHOOK_CHATS_LEVEL_3":"", "WEBHOOK_CHATS_LEVEL_2":"", "WEBHOOK_CHATS_LEVEL_1":"", + "WEBHOOK_CHATS_LEVEL_8_0":"", "WEBHOOK_CHATS_LEVEL_7_0":"", "WEBHOOK_CHATS_LEVEL_6_0":"", "WEBHOOK_CHATS_LEVEL_5_0":"", diff --git a/constants.php b/constants.php index 2ff8075f..b0ecdf99 100644 --- a/constants.php +++ b/constants.php @@ -3,10 +3,11 @@ define('PORTAL_IMAGES_PATH', IMAGES_PATH . '/gyms'); // raid levels constant -define('RAID_LEVEL_ALL', 'X76531'); +define('RAID_LEVEL_ALL', 'X876531'); // Raid eggs. $eggs = array( + '9998', // Level 8 / Ultra beast '9997', // Level 7 / Legendary Mega '9996', // Level 6 / Mega '9995', // Level 5 @@ -17,7 +18,7 @@ ); // Levels available for import at PokeBattler -$pokebattler_levels = array('7', '6', '5', '3', '1'); +$pokebattler_levels = array('8', '7', '6', '5', '3', '1'); // Map our raid levels to tier names PokeBattler uses $pokebattler_level_map = [ @@ -26,10 +27,11 @@ '5' => 5, '6' => 'MEGA', '7' => 'MEGA_5', + '8' => 'ULTRA_BEAST', ]; // Limit the tiers of upcoming raid bosses imported from PokeBattler to legendary and mega -$pokebattler_import_future_tiers = [5, 6, 7]; +$pokebattler_import_future_tiers = [5, 6, 7, 8]; // Value used for denoting anytime attendance define('ANYTIME', '1970-01-01 00:00:00'); diff --git a/images/raid_eggs/pokemon_icon_9998_00.png b/images/raid_eggs/pokemon_icon_9998_00.png new file mode 100644 index 0000000000000000000000000000000000000000..8df11e880dfe8af66fe94bcc20b985c662267100 GIT binary patch literal 24848 zcmX_nWmp_d)AjDMi!APo1Shx?LV`O45AN;+4Q`8Tupq$~2*EW3m&FNwBLRXt!QJKM z`SE>oT|GVhXQr#VYwA?>sc1D7Icz976aWBVE67WKeCgr;Yv`yi_a0HR;g=5R{!va6 zP&G#R?_~hCkx-TZ0BRF3AIu;xV+Ar{{kSIN)4j2>_TDDM(9bdK(|+pc#Jk zdK%cMc-1ib*L8Nk+*s;-ST0lE%=1=t`p2WnE(p)Loq=G%b%4 znf#=5X@zc|I#-YzGD?Sav&+x%9m@f^VX)+#^QVBI6>0`mLC~8A&J(umje`d1=o>jZ zZT1jr8A)4XnwlP0Sz2mA9{(w+?ps+E1_F)-mu?vn6^8DCylV??dy4Km_-=KgK(j<_#bf|BW&+))%fflM9MGtsJOIZDPot!M-FV-;#k1G>PcUl_1zGV)UtI^05b+I|oYM6DoF9>)>(`Doq>xSk>6Gls$ zp2R=wH>;NQ|;)RNOg5#9;>sW{u8X7nR5}qCGRE8Vi`;K)r zYh}+6ZY9)s8lrS&0f-zk7BA2Z!*6NhXH$pbvfcc71^2RC)j_#fxg1}6_`;ix|NjfA zobqaq-v)O-zXR0}s5!62^&?HBa_ttMM zChF$I4^4ZAeOL?nae6rRO41KiR219D1-T!9fs?!+fEzy1-aI)_y=f2A+`yTGE0*Z8 zf!&Un3Y>|ymuVZFx)@N^`{!r}U7X)XavC7&2+E3hRs`D`>WiX2#c_TC31dAs;?Z>Q z_^*rELruBd`vi(tZM~pZ=+1bIAA5T4Y0P;X=}@ByGP5d)zGb~J6cAwA)RoZX{r=~V zI-NV4jr2JOWm>8{!^)&1gn+(5z=YNwz9be5v>ZBl$KpsCJ=y=eXve_LA=aO!qUJHR z*p~UZ>6z=qbIjIvH3)0(0Hqx!q#j5hq(h?P>cmmKLz!E+R?#zIG4NZ^q5myj?C4i5dC(l8m)?%Nb3dC{MT}wQC1FV6h&VQOK zmKQUM&m~}<@J6hJ7~$6p6xf}xE8{*SoIb0-dGXUcPzA%=P_x5TC!j!|B11bL$a4V2 zcgCgh1dN&#XIohU!*pH!uK*sHXA@yy89*^C0doTOlqHOPAq&)}9krXbVDuLJR6AZx zbWJw@4EFX0WOj=pfABx~-Hnn%p7AB=gkOs@NE!(E(F7F zeS{;8MiH{TJ)F4p1tcvHf9GOpMF@nRzBAvYrWe6W?}sAswI+f6F%gZw<(i|PF(zPi ze)Bw^<%V3R1?jq(4rl_}2o2i*H}m39xrZBgq$ zo(WfX(DA;YF*iJ@msosq1iiYABbWTk1Z2KZODgT7ORC)xuC1MMtj+hBI*FE|b060D zXuH)jE7lK7I@J@iY#W@j2CZ}Pix9#`Rt@yQnCu)Rh2Ss?Lizl+@&1`0ThWPY&Aw>>y4r>u zb^E(1blLm&ib3D0>wxdR;U0>NX?H%s^!_%4y47=G4OIsPxSdZD%;aD^aRfl9L*+pCl5!9+b-Pl=C(204gR=*`9$Ziz!SIC2fzxl3qIXC z_4(zD(_-+b@+>rS?4NKk@W{{>PmDbLJX0QjpyX};1;yd%8dIuU`p*+e9lI7DVIQ;o3NrSo-R3$U)AYZ1^prtM|8f>D9keJ0pEdeD zfqEP9VaX4S?k9M5DES|0j#OWs*O$clV-mLe?*s2|#pI!A!0tp0UF>CA+0=heVZwZA z<<9tnQ;q0-TK&+ZS_nps9$=K^B8$MbFInMSjH>t<2D}mMe4-3=05Usn zzn|I)y!NQR>RDa-SibW49U`!CKxONmUSRlHz`1<={J5ugr6nw?1uwuQ=*^3+PJU5$ z#?qVIqqFXII4|j&9`r;1Yb<&4*i6MQY9aL> z{ya|b6V~&S0V%^%uhcVPmuF@54u>GJ`8gfx@^*YAgBP*dX#giE`ma&xQ-)G{>zeJc zr{wvcMnA1%4@0(FzkA|t)xTWkf5$ONTm8jSSB9CSStju@Dxg z$Kk5h)zS`qvxrdq`V|ce_rcoS4K@>S?gS&<|Ii@JCc5g?nfZA49qEAkCD+F}{+(ka z>xlvSYJ}N+%huBsND%Wvp#~^4$?rd~AI6$VnosuFCATP#Q5Rn;%#g|BE(x=6|Nh09 z(?z$yJwL#gQ)wv$(@4}1HyhW+MeMW2Ao-1+=pm*}a^6)>TOxax0@+6}%RdP7Hl!&yuF6t%en9DKSw-4;m zrC*x$EL(nB+I&*FK4q=Oc~pa|Gb8;a#yNQ=t9^TacO2A8-9|6?jAm&#&DOW7JNejQ z@}gwW)OQGC>M+-9G6IvOtyLnX?><9LZpVocWTO9R3lj?uJ0rA!qW=}eMgJs$L|Kk- zNRdtPb;X@#tSJR#Io%UG*L|M$E#O_P0poe|=-H<6Saat8|$pqeR7ld3~K0 zaf_YKPR6H6AelaH#AEz>w4MmeRe^E5{)6&h{l^8OY$A|gynTcJ$2ch;tdWZZv-Nth zz_#=5^VY%uFLt$z6`Ap?R13!)E%U&6P9RjgGwSba-g!t9Ypt6+Ivq)I<3RT_7d~7n zf8%R_HX>vvQ6Su#OfKMD3q9>oTktNg?~?%$qSBx$OUt1%O>!?@}un+Awu z6n?mpu;qJ6)$>ZgU+}H%Cil@nZGcr**H9L0`O39CqxlIB+$cjRdsX-!X{)qWv6WzY#9@*zVTfUy)P1L@wC$zIR-i&*8hl zmL>tx$}+=-={w3KzLiT43oTVKxEdw%Ix@Q|z;E!&ofxhJzJCqD&0DC;2gkJoag4c> zycmGRb0`E+mrze+aYIMkrdHO_-WFZkpg;0WAHsc?_9EJV{fSLB=;L;hKWUa*WMMB3K*jSevgVnCUL1RJZT!6-S11F{#|t|!;Zfr;Unw8RERqa zr~n;Ll`y@)HuvX@EEhE`z!}-m;w5{n#hcb^@NAA)le}MFQk?wYxV*F{eHLCz+~Qx$ z5qjI{Jflj*R!ZkVOPr81`KYIhq^`TEHQ+DTVBidGuoL!8>!#|3xFH@v7j-#YOdDwE z+SJ5OawU$r1fFyno>em}*vpo4Qo1cdxbkVn+ITb4##k zmk>BF@orl!@upK7t9vo_7n-YnNEFz5SiHlWmArU6nMQGBElc5k{^#3=vyEVuzfig( zcrzw|?)PLEi z!-WIaZBKdcZox)BKJBb2jmK|fa4n3R|7|phK9C;cJq(@lIJ72$@LuwQkkb8?66?pMU{>7{CyBO#DVg2(J?QXzhDRY2ovhSK~U+ zMSqD27U*S36#hKVA6V`D8vX7X#!2~iR*L^md81`!LL|4PPn7*a>BeQ_WEDAP)oY5n zDknb6BCfZKt&QE^a)_;12NQVG(|QeV7CA_GyqM&_1<(*up%$UzPl_53tYAPx6u>?{ zAbB+$Vq6HbkfZkIYx0bXH+RAWYi_myccq9H#Viud*IYSe@=@9Oe`PDOOFvw^;>7y* zHk<4}4~Fwcoj|1>uF!AQ@2gBZ4w_)>j@$O}d4{N#R7R94J5l2GMFQMvi1aAN7`v4J@iSZdZ z{mWNrM9Bo^NKo6cH5 zZ!6?bJJq|f@}oC8(fS4=IVS=-PgatW1O9aYGZuxC3q|ICj9F7mSQUlRv|3i~P`zP0 z_sRgzFT`zW;yYDO+E6D{wAR14jj#r^^x5n$Sq8N>G1ZoRC2J!iPoZST#wcW7>0L_K z&Y*8qE7H71Mg&@UO}S-(HiIIM!(UxDnGoQeT7pGw{j7JP*rKrXb|+Gb?&lyzaV=tD zf+xECU_Shv->y0if*MZK4SKGfPd%F-rv}+T!}hI!M|Jp9NFdQujcD>eLbPGYodgXh zT^`xgCfCgE!L@J?9nJv+z)u|>i%40n*ZMs+UuHFsDAhoIi(kU{or(Lz9ihGmf8Y0M zV#rxC2P?@KP?_W26hu%~RNB-Iyo=$_lJQ^GA6Bikl@IF{d9A*zLN7*mA1*|JrB`nS zLBC3`%n*)=hVdj~9IRxWK2^QtL)^RcSNd^pY!k5D_B*8CQFrO=Jy9l=2C;yOL!;cz z`KH1nNb=1sVr`>Ko9T&!hY2A!m6_uIGv=27jYyQ|!2HeW&^NX>&TB-g4FU$#Aybk! ztB`d#u&0kO;-Wuk#ejtTpwy6*7$I8o>BD98=DbJxSj6t6vkb+#TZ5kWh^yL=lliVr zzP2l5F9lX{M(Ku%(t-Mm0L%C@?&oeaQ@m}sdLpLm(JStGg@H!{(;DaF(B?f(_+G>) zbEo-C5;_A=J3BEK@V2pZ$Nu>}&@ZIcr=L_FU{3N#tKjI%+)cmsObR`*i!9vJS(z*M{x$qN z=1CWN?KC=V2sK6+%B_tbS1#ghm5SE95qJN0;BR!dr50eVpHfT1HfCtt*2ik?xv?17 zU6y88XSeBoOi2Kj2^hA1je*Wsg{OPg zxVA*A^Jj0e@CP>wrvJCYuOb=f$D$)x)qx`n)oUZ)S84h^4$RecW_9(L(m$02wPaWM zEI=4fHunuwh+z6p=D@&mEx^5Oya}d>jB~m#<=xM1tJ-Kn1LJ`VBmJetYTfe+8#5V$ zSuBnL51lPP&uxXy#*Hqexa@-EjP?aXCCV?8#>OIrZpXn}zjk;@Bm%FX%q+&3!pkIh z7}p_^Zdj}-I^yL`kjuJO#MkW*2}7`~`nzv8^8iM90k>*Ae0nWFI{%mg3rbTk5sj7i zeck6xI`|nuOe*xvhiuN?-v|~3u!o8;b9Mh8k-49Uv(Juj|AB0??vmdqw~A55#)i*9 zSX)=Oy;%#b4(!*%$Jg%9|8j>OC(b38D89yyj-yWbA0r8ZpDyj*wKVip|7pAsEZOp| z5Pxm|&RDd2dn1vC0ZT8IfzE)mM9`pk_#FmeQ8v0WzD;Vvx1VpshobXJ>ZQ2U-NRl* zDc^cQPlTZp zIn-#oz<~n$8Z%AGRRPQ8mO_GA36ycetSLWc&W$V1)w3GzW4cNlTKgRw2VoX>0*dS7 zBby1}8(RQ0Mu49twwZG&nr^X!B!@Uba)_Z8iZIe%f-c2W27eh`c|d-JM~cw)$0`f+ zL!5QV2I$#aDw8YVz16Dq`v?1dr)S)aPJrkUKbi>gcD?_MzIydpZ|rfq)oAgG0k9T8 zm>%u#pjZr|>^gZ%qgbEqq|wJ=h|JrRj+y~`g=+Glj}z(U zV>1i*&s2yRsq1xGrx41Rbo%oRngXZ{%mCuTfpuBqec<;02XuT=kxJd<9lL~ycH+fZ zS(y&)gx&^&*~y?a%j;&}{NYA)a4?H_1&F4gfc9W&2B0nr2i%ZK_`=mJU)2#q=0h9j zO)y;ea4&EZlPM=+Yx5F~`iwXDr@8$`Sd-zbUC}jr4hGg`IN@<5)t49BWAqsBvDbZr zgtPbmm_ZwD(qT@;)C4p!4&Ho%a?e9yS(oEqIy6^&H0R>2u}qx)LW&y7Hm`Hg2tpR|8t?WxfH~(sT9)=$$O1-|1!t*ybY2*SEdA^>`>zG z=819gx5c+b-sf$27>#f3g&csCNUyyviR0@-K_jm?Od2iQ+}uYlVnnVc^K6GUsL`Tt z7;L}mo^3@+a0~>@GnVwcRvqt5SX?`3kJ$7b6RJBZDVvhOZs~X;qk+S) zR|e61*5y{?#@=}XM|q3nRM+>~#cyVXO|c!+Lpf*v07r?cvTlA}Seu^5c;&kjLd|>a zKR^egJOOQQ#%~&DiXs~6KVS#x^-gt?vrlyL%39mMty6ohn^iuHeN52qobXfZ`?*9< zJnqe|?S5xEf4w{2sE8+|J)&@f53FJGBlH<91$_2RDF#w_Yoxh4ypzzqlOxp{>QIwu-PR|pe~Ssv=*E<;Pgy6&CKo3 z62aAf)DGTxK2VylF(qzd2cO#!t;)ZO_a{X9TE3H9QysVsqEi6^8_A=(2|9_3QT}@V zg--a0z!yY`)_CFLDDYEBKu`)39H@aF(W!#*2ZdP@^$E+23^pU@_+C4tTe>icK@e8( zu8{%W>hM?4Df`;?h#B zWUg<7NVMy^8qK;^pMxKWrGnD1pYeg(X5OkOHfw|m{;!y_4HlrGL4o3CeTqxxTGd{I zS`QvQ^Lwrg$X@RvG{|^2)J0S!-P0kKXCEI}B`H$%?{e-mt9Ra%*z`I#a;?}5(gY`7 ztwA3V;x4(duQ}{iZ^zIJ4O^F|jx1bwRFRrvFXROD{w5FGZ3AFPJ^=1UA?U&(Zl+SZ zASCuGpw#6r>Kss{3 zVN?^K^y#d2{*tsxj_k4 zrbr>z=?FF+VamgNm_H~vN}49nyA|gY_Ml`577Jn-av!#p`rWBL(|S?qx~s=*w4wsGqEqbW;Vr zt1?OXHTtYD3`{cq%0JXn<7Qd*1Qe zqxd7qZq>4()u695oDKFQ@*R9ZM-`E9?n)&P_z(8L0z?WJZdZ1nkec1%*7KutlgnKL z46#R~=xU~`yN&{nv?j(xLMg@9C0c!nHBEFeha4is(>zJOUvq}uNRUUpKn!j!3h;cN zTEIEgbgn3F%jUiswFz{_EL9CZY-)(=q1lTM7*+~ufD1uIs|I=AZjN%MI+*hx0a)PdB@jj7X1dJOSIrba3$E#4MzE#DO0WwiT#-avVSW?v>vsn||_6 z{rtyK>vrzRZqGLp_pXEF;k>n9dQwF>fm!GD`9f#) zVDwajtZ_UFgM_VFvDqD`OEx21*5xA@B(R&GeSMREAmp${P zQ6bm%2Em01U_223iUv5soC?NAY}%rSlBS8}$He)syK?TAMLKoZ zRuC)a{atq7Ernv>Kp()!RfQVPXhvt8OANUzFF?Gud!uQr0+I23Kgbs=K4bwOhze#( zmTHzq*;@29jZs1tJJ$YXtNF(45{y7fR3qo5YjGgxl0fUVx2m-7-gz^Ap!rZce^c!E zr(UH0E_A=1_`hNP^-{hRD`s&$)21_l2&bkbr?O_3B{ld08Z$DrTT(EAfgWSf9z;ES zb5D1oL>z38j3;XHg$@Be>_2G|zesZNVU$f~>nGcouj;=^jf;F+fUS0SA z%BuRw4Ehsn5gmWy?NA4TKO8Z6*PbWCn-*UWtBA^hi9^0$rR;6^xFbD{}Tha-1HW8Z?#%}Ee{_S!F7d=(6(k32zChzNKSKY)C%tq>2EEt9hf0TGqW|;V0N)TBR zSB3I+d8)}@OQb%4rzcHrZ?1tui690Mid8|XgGy#3)NqF|wifM#?Pst_F19tzxf`+x z<6VMQ$XxV2_{r}}j=wZYrrRs#l=t`YHr#R*Z8ZI>wLbxifHH6i5yIHBLLh4t=Sb|~ zgOg_5W=kqs8->#D{7hJ)66|2tQui@*kHZpiY}dR zVw5BeZoUsVt&<~ks8EB(p6vx0TbR6N6`NKStj~< zp=7n`mQ|21;^f_a|L=DO52*X5FuTHEGEdK?Q z%eBJ0Z6L^puqHJ%Q)-2^4b+p|u0_}#y$O-+zqk7JvijOE2J&2DhT z8)cq8fv^Vuw4W_0^cgH|Fgza!OHDKnBkR=p@0f05dTcL_vyD>S0$m@M9$?IzihvGo z49&?NW~2-eO`!xFM5*_$S+L*)aEu3(w$T513ZJU}Wb@l`;y9bQW8OMgHT~OKERPxw zp;R6|>I~m&@vRS=chC}+Ic#!T&P)F5{1JcZx?s!*T6haniBiI`w@W z)A32sK&CiBMSqY7mf~*||2A_hlK{eUU=`6vRsA^EX#K5=xuH6Ivlzoh$fRGM(w2!k zMRk*4p!QZ*&B@XX83>N>TS*viqv>XZ-ip%Ml5jL_LvcsV9L^1wS6& zgfp&sC%IY<{>!{_8YTxL{_E^l?bj2zQa2xX00g=TscO9dgBsAqaE0?Mo8FUCBeQFy zGt+776cM*6GhaAZmr%EM$JAxC&mq6%VDb>TbBGeX3x>J?A@WkdItnmC<(|A@b)Z&g zA6T@Bpr|aKJS-gqz5xn`l}J#&H&+LNMrjN8>F>pTQZ0qyhlv{*l}ll z)Esr?txXTO*Rfbm2zV2CpH!`n739aEqAZv|DXuVcqsvxfPrL|d@))yTa7U^UW~y)}rJB1hdaf;0+w+beadMVuPVrd+ z*rA&M0%sm*AV-W4ISqiaw0!VDErDgP1cx$E>pGw4$l@d_7t@CyvTCIH@!vpj+^1K< z*&7t+fd}QM3kd;B-9q!BTb8&g>RVAn<=SKd;nOJDg4UCj%f`hBR-_7wQ!FuQWO%tM zYOm&zLER5)i%HbSNkxj$;0KK>C^uGdh^Qdsvoc5MxIDZlCUYF^wDuwonUqi%lvsV1 zQPlA!uew|PkZ6S(aeA+61po1}@=eyZ)BpL9ddVGWBGd5sW$>5~`0~8wfQg2T8ATn@14W?l z2whK!8bxx1E$3f|J=l-j*H-sC3q7`kD@IvjJ>z_gIPa{h#rSS#Iv^ULb@PK9LqWVL zoQ)F)Lpz6xuXg=pv2S_ZIb53qkfaUmyMqqSYD@4e7ZLDP%21I#c5d$ze5e6rX;DdF zn-Qp(DQFM(F%*ijmTJGMsrtBHEC0JbZ_x1gz4B*Yq~ZLsf*G;FAE)U`#dqjD*BUe> zn{+oROYp#XueJRR+|{o|J||T=neiLHDnmBjgpZRQ>h)ttOD4)(q<5Jhr|=LQPgxx> ze>CXx-Ag<<$aPu!Bm;kS3bF8 zy{)lgmDnlmR%+Bs&Y~w_{fMHYNu{5IP@L;rsAI>5AWi16L!MN5W$SmXg zH6~4mMs@hPvAVK+y2OgtLeO+)8QS2dLt_e9p^O zWvR~~X?trhkn}UR=H)RU|#S-~rz@$^wP2Hbs9a`Y)IIYAfW`M!d z%Q@_?l1bOL4Omzt8|gOe3Vh#{mTLLtSaouyYEH9|oUoF_>?T}l`!`SyK@V{OPrgZA$X?&xt0S2j=bBh|HZsCcn+ z(Nt41_-dc|GZ78oHaGS@D^MPezWwtD$T7>%9FEW1MiV+BKlWH;yNjT%H8fx zFmtb!slMpgvmnH=r&n8`!!Z^NiwAil088?4J!Wy;M=4-8ig=JPxXexGy%Nw$O`9#U zZtwl7T^y1Lc;Zx(>fZvAS1(;czhqZ(4F&f_I{u+(9gXX11ddIzz`H$x!kLhu6 zKhtHR-s9cdDQD+5w8yL*iyO$c3O#6>s2Fmj1|Lh1^2u9 zrW!|r6q*>er)x9M?PfoF>3x_D)oogO8Zt?}VV%a96xWF-TJyb=rRA*l24wNn+B(iN zKd7U(?-mYIfrYw(gUk#MRJ+kPAnxS~G>S1Q@l6Nuauz^vGdM;Zbi1w3+vq(o7ng4rvFRkGn@Zc@GVsAXO?qhCfZbw02?DR7ZPhAlQ6ZYf_e|DFv%jOjK^$zcC}~@ z%*2(3rH%Ji6Q&&^zqGV2orn=H9)19t9y|&$&Q8z(v{x$PxKMv>iL(;xi`w@WuDL$} z*wE?VJJubpjgR+36GMnYfEq5m(;VoLLpkme0klM{?i=~~`T)0{Pt3JTVW5YE7fU6k z_>;OK3%Dy-!E$2$IS;L?)IQbwTIyfj{#|upd8N#zip|n>SIR(Qi@%i*}YJ%eXj@e4$P)l)Tr}7+3U=JU}Cs&Q5_uIgaB3> z5`L#?ZVCccFOarr5m8ZcLQS}}D9PSwQRPwUdGKi#>Cf6fwj33)KOfb1$q* z!Gz`B#PLFKqes}^Gbj6Mf5BQ>#t2;F|D1CBT*qHYiscyKj( zl)!Lc*k9k(b>74$bm=cN3MZO@6oY|D0C(;OMP0~HRo3XFWhgC^dUYopB+XI2rkqnQ zIyq}nx4OV1SZ_E$T5}=v&Nn1*FHcH&E_cP3MQMI#NBq;U|XMM%25Ji>@*F zuVa8*ruNNdFc|#_^Z?_Rf-@6fQ97hIktqqZM%U}D7!;-tg~;6QxHfHZ+PKz31BdVZpEIVo!Wx0kP<|_Jwm`|4H^Z`QQ86kzbK=wT+Q% zKW)dj|3z?oWlJ#8`##!4Z8o^mpG9Ux$BcoG+HVO@3(U#W3lNEZolJniYIhtZRR`o6f0W~@EWFkgWZRHF7!P~&Qjzl7oJEJ%FIT|Rqkn)t zXN(;F*YneRj{EJ?q`2zuzurNY`O~)^jYkpt?uvghhpiSI-3Y{$xX=^_@MA%n7K2wN zsHs55E;|}ZIc*JKhsY#Nuo2v`WIhi&LUG=7%+!TN9<&J1lb}ME=|l2Oepm%U)gIIU z6^vK2D8iLoSzS<)Djar2R%9La?;(`-LV%pLT~*)RZ!aY(WZsGzcj2w)DD!SZQgt$<*Q zAgAu?V4qAA$&od^QNte@%3)aXpzkAuQU}bDOU}m(qKB#&*d?R2noUPlRNC*e4mDfq8 zpO?`(q{}{MOPmC#BSgG}!j%k#YclzI@0t#zfH>&2xJaltNRS`_!R85!3Tssp^CQ&s zxkS^d5Suo_23b)FWEOlymMcUOyi!5oCx&UM>3>4is>G?u1w2|M{s4vC0oRMGaOM^a zPN-q7;pziZ5{JSZx^J`80aUQmxy27x!LQxllu+R#u^})x2+Ij?wN)ynamiV$Q}VbJ zajiY!$4)6_lb@ZL8*os3rn{iM622uNQ?uZr@0c*`^U#T zNv1JcLf2p78t?^swGoxDviUV;q$!apeOnzHGI<)&c z+&mLXo+XKGF0M3~@R<3nLr#rQVb}FymNgF1VGKEgf8=(YE(Cn!W;vE01JIknrJ%OGAIaOQPyJk|E$|B3xl^dX3OU3?-xH+J*u zf0&OAU;r^B;W?a_otR-1+eM@33e|n8#jnSNTZxhu!-a|frA;9De)B`vgIib*=m3Nz z1&l`kqS7g#tEe8)5(s5%&>LmQzb%^K>5%Vgn3Ag!Kj>jiaBz)&rT!v0zOM(j0y5r( z1e#+kXfJWl_4Z>dHiBHP^8!HtJI+EZ!L?{G?*Ue{SHRC7*(yLRie*QRS%vS(*SX>| zgpMEiN zAc6)~>tba~w&fzyL;uT?&1T2WqOElOC*P@LPpIW&zoGR#DC!>7&Tm#GF1Gyb#@Znp zG<%E5i1>}V&xxA+QW2(lODiscl9iPZJMXDzmaGSQx%g{XxFI(t8*-=;Z2^V7xalm^ z@?as9CylX5tegbFrGgv4g>qqncH(M^GBy6R@76@Ye02ow8x4sN!>Qe^l1Sru#aoHH zTJ?+Qi2O}rX%87%Y}^>x%?4FqK2V##D-1U@WI%xU%#|viZ-o0FF%5JDRsYy=;*$l^ z8x7y6k7^ZNlcZpkjII85;Eye5Rf5)$ag!RQh!1U0{&mb5(k>}^{KrA5xAWxTofw29 zBNvWXrT_oa5nns zM+!L=l-nh8-J+4WTZIA1O}+O0w*{kOx{4aZ5wuDq;C0*6)gyNQM>(J+#FQX4IGPLW zo)2UH$6J%F17{=?x-XgmnCW7Ztgl@sApl+!ARDRTLvq7+69T8`%s5sd>mxoXrd$y# zHy>!VfJ8GQaLRL$Cg-8>dveCj4Wm>$Y^3cd&BR~vu&!ZzYz(+q{Dk>eI3JoO1)vO1 znOK}Be^M$MLDJO7K$Gi^hqcUTT7#*Eidtd&Cb>}U_Y$NmPViHpo3xd^W0e2Grouyb z4^z78p-}7efJ4U3`C4=tZdNXh4x>E*8Wt zL~t6Q%Id^oY+(RX{L>N!LOugCX2gYvhK#5i#H_O^>3S$KIAbjpFNxI`@)8%a(P$W8 zzGIdQ{u3iPCmsQsHpNg|O<${rIGuSP73|W5XJU%ZQGCX-BC_wD0onLaw{iWS#M3CKCz0>j@KK+0X)4`HzgS z7^!rQd+?#gjWiaN+kuuj?F+as?GzzM8UvCJ3GpKW_r27;X@pdikoQ74i71YGP(I-p z&bqBNXamXqlD9d+&9QQx+VVoh>Hx8-cE7McuyQ0;3rJ|^OmAQCrJhnIHEGzNH8g& zgsuW%v9)xTJHe;Wh)y&;xoUjmf2vw=Um!HcR8EvlnmhjKpWvR2PcR+j{2SupP&_qD z6F^_6qnapQXq_6Azz#pz<&6cUlvE?wv|e?2tHu3qUCwEJ_&=B2jI z_a*}B$<+z~ABe;w=uO}nz#Q@;&WLgCU|Zr4GeXA`$D0GqRX=i~*d!zkn4V0lXlelT2(b`LIBe(}fDa_yiSn18c2;QE)3OHl!l8*6VAs@pViV$pg} zfR!i|i6R?B2vvOr?#upV3TvdQSes*GAEyocy9)VZGB3KZuZ zs&1a=XV81!Z*M^j6g!5lLTbAI#G9r}Bp<~xCxMvME!Wt4&|39vx20DFqMSFqcVH$r zPnx3!oD`aQE#TOe&#$^X2DT8_B~Ru~2;z10O7Yi|bu z@oF$UbuogYH7}&Am?8MW9L9;+10Rn?p*rS1Ia*7RD8Xlz0f~$fUrmqFT5iqPEF;Pz6YJjM9B6TS16K5i6ABxoQvb5n7XSWsiqfzfn zPR8!~Z|{2CZmYB9p+=)>+ruE-Z_K=n-_vJh)=nK_jNm3wB91mMC-1hb0OQ#TC2I!> zkRa+fK|F4v=@&+Pc{mT_w!kCjpZ5PeZ2II@B0hBd6VAO3NXQNE36uwPxvD8vNmL4x z#wDO90u#02z!<;_HevBb{L7KL7|!3C%T3UjL#Vb8w@^y}|L7lp@Sb)kLYU%LKS|N& z`;M}gEWW`=A!Q2Qw1!1FQK2Ro!G+a`)`lc(^!^XSp9Vnn)JDbaC~nrJIV0bG^Dwo=038Re;bquJFgTfzVtUve%>V zJ0C)XfE&N&;R&i1uL>s13-uGbr^6FU(vlXH)U5Sb)d{B zoT~8!kxf^(Vpuy<-maK2!pZ>@7%n8#D*;c1pv`L3qu=k|=xp?tUX7mMRl0duSYN{i zZ$6XvUp)EepAc#T#tWD*#s7yw;rqUhSJ`SI`vEqqZ7YjOh6mX4pcn2PkvB||K93c6 z7)cX+V=24Jzv@|a#AWohRPAQz|o+Mjss0f6-X1egCcQ0D9&Tga1lAOyg`6-2S9UfF=#eV zh1!HfsNExmng#Ko^I8PjWf@@hxeO*6{WEanZ_t441~#chC65Y_y9!E^gR0L*`6zZw zau=@X(}$Vfbr3VWBYhmrQqjk(0KaiLtcyd|-I7`_bxmIO3YF+e7YaF)&wT#ij3mi{P>4VGaApkEM8tFVDrvF%~t6h2!G zh$;I)J8>J-PmF{5g&Uz}%~`12%LipBE*V27f+F4*6kAb%t-C;R7OO%+C^I zjlZ;aKW1|0!Hj2zkxbVwS4jTO3NWHn-{wC~0KN*IEypc2fzF^8H_S$Sh1Qn6uGPQR zb+6_F*Kk=U3jX#kL#E_{OuM zD*}qx2GHBF0rX~EIz>xAVg>LnGd%N~3E(W`pF1-w)m^*0&QMUi)x?+V zv8t;MftC>50}F$cBgL6u&CUT^29C7L*ca@_s<0NT!y@dy=U^qEcN5bqh^JTDplgX0 zx}LQ_*Ij1ly4D0=O)=V;d(r}@P!`$}GgCmvav1+DLHpi|Q66N@HGrweN6P@ZqDOYGuRSwn<4~rb~YHK>DFphx~*P)+oltqw^kIMv!E|fzDcJ!ywNfB|s`)u%wrP38yE$G}T%yOSRQV&seL=4q2pkwwm*f zM;k7X04&=N8n*kaQ23AlZYV&%E1LHQmFe1zlp5PkK^BM%FUDeMPZOu1{u~?yXd1o~ z0laDS)0WEx4iSdY6QQrx^vI%qj6boXfRP3TEKoZC?xdeLgZ7>O_5}*L3nE+`h!A%t4Itp+BNBw>z6r00P9WD^0lzv=8bD3ZEokFL%Up-{%~Lk4-53@@XPUuo&+z1aG%q zYd>YZHC+VefFJo*qs^{W-7#I18U}6reHu_Owso z??Toi3mU^G+8<@!@3evc&+ZEa-?&c`_4b}988O*UHf7!@#hNu!D|YW&Saardxc0`K zIDKBh786gn8PwvvP$fNS|42BU2rB{g1tdTYmgX!8z#SZ!m*fB`$VRaZ)?oQxiJ>n; zLP-j&3^5oy&HW_60Ga|CanA-5VW0aO_lXe?8cr3v7JG{rlxY@jqie8&;HW<$1@mPL zKbsFGCI<|a7olFd-&)O2vZ~6GEZE#yM3*)i)7MX`-!a3za)zI~%5Si{Y_R(niM#t6 zBvs;`cDwrRa}R3&vcIIh-5#O-rFez$g-DzNa#T3jo+3^|{W(zhv~?Cf;UEA7Zx5d! z0chk?_#^>a0ova{0g_RGHG*&YE);#|IZf>0?I#&AexPK@B41^E!VJy9q;gD2AE8$yZ$Rj84>bDerRpgd`i){RKERP*S`H>Du2i%spp_h374T z^IMI#qP(^7jsm!PV-K(ddw}iO1DvV&Xv)3Xza~ozFQ#GeEY3pwHE>EK7~s#KSc1Vi zz%J{`qg{1fh?H%R=rW zmvEVQ1V=BOYjC3)U>{b3^%&qv44i&*IFG>nd3fDi442-67=zIMTpaClaSB<4B|Zx0 z`b~IwH*OCqzXm zb8uYCJK`8_Q@ApCrRjAHLLadn+V~0E4+RigUmTxje0}T{?fc^oSO0S|N-#A<;yPrE zaO$wZ!WrWRh!%&9lJ3|rQFdx?kmA;*SZxMLP`2MJBmrb6Z54I_GQlE2ga{A8ieM>1 z^0EOkaD_ncFrxDf9zp?5qX7GBv3yqntiicF60Zx#?XpUMqg!^B941eM}vK zJ;iDae2WGw2X)x#*MjxD7))1-!H}B+*5dovhuj5|1d(0_t@tpgDEz#Q*0R$p>Tm2_ zRCDIwlG^k8Luyi=B!EwG{fkq%`Zn|UhE^-Y##S*>QwwL|6VAdXoQ3WPr%VPv3uoaI z&TdOI4W6ZG1z?%3gy-j#TV4*&F}@Ls63p9E*cfIeM>J`z@Z6PJkTVB}|j373gxI&B-hzu-Pj z5jTqgZeZBAQGl}wtO{7dcZwU{bg~|arEN7zf&%QoQNInP*oU{-Ck5DB4#pD_oa-yW za$5zK2Rtz5=YpP_31;C<{Mi^heX5!G3{(pbfTDPdjiFIb!LOOF-Ww61+T4Zs`N}<_KQvoDu+Y@mb+LLe=KH==P zgtPDoXWxnN^50EmLSSgNrKWMS}G z7;FYE=jekY>5Si}aeEA>iDW*8jo&+iBmXE?gQF?=Yv|q>h{=OW{x!Cj- z<7E^~C&ZF3rO!7?0gd<+X!tn#xw}AiKi*t;K1!Fib*|=U$awjN30}f5pF#W(5`Z}M zz#5itRp;vPYsX1U-_Aq%L)`lbCXDDKoH=!nIAW!rB9R2R zy+N0qu}PozV4I=1Xpf2EZ2_4e36$akP$4@3)$+?wuRsY{0jNnV#&*J2F!spQ87s&~`eKde75`1@X^lkMeyf}#(FPZA_&nCHb_ ztn-}17+%Lw|KcKnp+%U;$f5Ap${rWs$EE;hp*!L)n}fMu1ljW z^#ld+ATCV+34bfd#JfOA9~ZBn4}5GCfWcmX!651U@N}7b2f?bq#pPW|77BqpK#EX+ zBD_seAwri?lp+*^ivkF+>62jivNABzpQmM4K&!-tPj(QLA{_N42_VRg$Gb;PE!SS7 z(m!vkG;Z>6QAAS#sQgblsQQ4W1F8tes;r$8RhGX+ijB`X6Tor)|F;V8b19YC>~Iw} zPPwXK-+o!@oI;WP4<0S%3XCmh2n?-!`TABKd|hkzRQS+6rn-}RSfz`5psc&QJJ+3< z8Kw-`f2#K6jukb@JEqqpr{KIw+=|lY6vmqw7TIfg2_Nnun$gcgIHsqEV2F!1;e!8+K!F_EZMAH8NH=)L)ff}*oZL|aoeX=AJ`vU zd-BBM+UqwWby*p!3Mm zx(6vCwbypf)TD$3$`1sMm&W;w5YPAU6isyX6b$R^$?xYfNzln9O#08R+m-M4JX86X zfe&h4o`C|a5kR|C8GQ3V3GNttxBnLc&?}1aSs3S#04Gp@coZNE1)xgcj}kl-fY@XB z)LsdYm{XM-Cxyso`HqxLp4?wCC(N@VcJt)wJ)5Ri96h|S=JJK*+6)q)c)eLbl*L2Suuu!%VF9(#}?FF-WphOGscs{Lqq>X`^#6PW)0G|lJrAqj>W`y;L|NSnV^M$wJmAC#;7=)1=)}{27b}6Y z@Cj$(6V5_+#A#?x6Gs8^FklvE;S(gl8Vo;NU}_nGkOVVPfPGx}D3=SaTrRjfvhz{};uBCQ!Y*EfatM!uMtBS~f@G)=q9h~*&h<62L)hu>2bCEA zjrbyx0jk0{QyGPSWM1_}3O{PBd`Ivw@j5>bamY|lQDDCjSo(bhL%trz@7;bP(I1Akor=dMfeu)4Zgyt4; zC;@FrhFFBcKF)MUTL5evOJOnG2 zj*)HMKC|*<^8D(H#F?dax34eP-+Zvum{)ezBIIARDwxAoId_{yEZhcSVIoKbJ3%VI z?p=UF2v7*&DX7BBD!~p=3buiQDuC!VR)!={@$vR$TYxFq3FRfnkgHHmqkr#g&6)K9 zs)NgYWZPzXidK*9!z}ai5KZmph2eYSygz~8=Zo3=?(M@Em+$tf-udo$#a{=eRk!ml zs(aBN!>1{L6@Z|TkGzBujK@%iVc>5g&-}j?-~dhm$&Kt1nw!&<2Y}Bgpt`aYccMu0kEbjRAf^3>4pwfy|7x zkdd(oNrVh)`qufY_AebR-7;gaFviD?7uvr|>8!pULZ6;PapaHU_x@rszx(IQnXc_O zGcNruYhEY3a%*3rkv|=wCeVohY!C202KzbE389Mc4npt2pts^RqtG337P=#kE$5y# zWf(qDiu?8+fZqVU(Zm@76|{5)+W*0BypI694S|jegd;}|7x?@2<ql^gdjt37@DggGbw5-^#&ti?wowHGs^ zjfKw0-wsTE7!rphBj*sjE^V0Lbn4!gZ1{v@*v@bo+S7y;fJ+}< zsQee~dk>pZE{EoPCA46J7gs_nc@4D2z}w!z2Ygat=hO2__C`*ydz zRe%3txx7=Ch0&UPKEsiVamKqBgN=7@ZZPNE+-J_YxB)MR8}A;QQ+IVw zP|ca0)2mMrYXU0v%<_@0qTu(OFr>_#$X(+-nmeV-5Uwi;@K5jZ?j8J@&J=#<80jb9 z?Nhzm?`qYn!*c7N8(XSxGnsFAW{$|zYO&DVGEzWi0{Kw^9-%RC3ZG8(_s0^T;Umo- z#aZ|SgW>a4{}Mo`Zjb;4pixhd3_Xs?;Vr5J6GYY*2j!Vw?S_@$3#61_T;gRx~s>w>aOmX+HiTpl*)rKlhnJyCn&cp_LFa* z@co7h7t@GelU%bZ;fQuK3D996_e+wXV<7*VuR=r}yTr-d-Y#m3f4g_agk82(xToeSs}3Gf(>VLQWVXit-$D*#Uc&FvC2RDp*gI0*0-@^M}T zv?c+9l<@p0L4yQtm+RjecTW3G#Ob>C#>C0~-hYLp)7Nvwy+4~O8vHFz3B7!UV@CRy zPa8Q9>0Lf;=6Lb)P3txLBWEc$&K@OQy>N^ye(5;HW&)>*#0`NJ2Ui5Ex33tb-oATd z-I@K{wdYp*Rqk2grQW_^tSpW~pW-bJr{KN4`18DmFf-kTaR>Js&K!soj55qrO`R4&?H7|Q|>z|z<)VB!~8C%cA(jS50$71+#I92}J1ZevA z{ihB#bl*rZ5ZzAn31%Daaa}5_+Ks-BOgCZU+=? zyKRxZ^(|I|&!eTEeS#Ii#XsM}&S1nf-=oj)VxPzZ%8fMoJ>8i(J$sh<_jfCwF}NRZ z7U4093G(R91g(y(+_V3r_S}k9>g^sbOb~_soqO5%E`3XU9AO2Z(8p{QeG;-qJ<)%= z#Dy9@_Z!viJRa1(G`L9n{7{juH8D+MY#oZ>uf*^j`S%IXc)eil(sCvv5Mfda)_nv zhwfZ=;_pLvecDeJb@?nv;zH2LuR1Lg{If%p=pS7Yq#yVmtN6>J>ox5X@G*|XM$e1U zx1sG^0hWDaDc{HmN9etij-S%r^n)Gvcns`dsLn!n7Vb~MX$Ze3tN`?T1LEQ3e+lq% zsSsMxnM;TRQfqVKn9SPzfx^~or^M2NB$!%kYBRdX*v2#0@Z7-L+CRBps(sb{Z1wAX zb}HU=StI>>r!euSUn~)Q)(IJkoJIAsdS+;z;km(=D%$lt zSMgf6eag4K*(!g(6EYMzdtWuW=UQd^F2SPCj&z)y|6NnA6j)bX;2GSp$#d_xNdCo_ z;mY=3uc`P)=j~PR_1>#|yEg{!hQar{r+vviyS{DzLjChJ@@HV+iDGlhLntW;L2MA3 zIL`R57N8iz=Q)H=2(TJ7(w0tM#nSY=galQDjTrngiLLo8oEH2MKiv025k_ZKKi?ne zbEWc?o~PBXcR@xYm-B1;_ugOi{&xxLPaJVsUG`;Dy6xuwlLR=Ht8?Fzu66HzO#4R9 zl=|0trRrYkf4=IqLFsib55>?&@{Dc#_{KH?$ioqj6<`+%dI=w65k1cz;9=lR`EM0~ zo%4}44*O08$iOOaS!!#(5kn6VSzF9Q=AsaDQGmem+EzZu$by<@hvZa0HvkDlZj>0i z_dQ$pXSZWDZ#mNAsPH3ablFw?4oOgGw7K^ywKeOLV`=@}6~jxOS@kcD#PG*p=##{z z*3*$Wh@${R6!M1|5H=kaushlgWkjN{cYp(sbvQDJe}2@ePhcg40}8hh|EUjA&U^Uu`LsgtLS22#o?X zm4F0@!tjaZSOqBjLYa+oPiA}Otit55_YN@V0Xqp1J{2|&FE z%l`y;ia0*mpM-+|juMans~Ta$C-^7;%X;hus2?Dlg-`rI_>Txc{7-;y5E310~n54bJNR&v-|!jI1S3E&9`~E374dM61 z@t`%u@d-Z!pM*2$_Kx8fW5|TF@CgdLSOm>5@TNGG;0Xc{Q~~}cz%Rk^pgoC)PadCy zGida46&S8V_&+9qGgtwdO5p5Z5{-|K!e_Bx=j^tGV~D>7XZQV6a2mqz346eP3ic|Q37WNlW=%^{}bSsz#g#2z@?lsoE;2;hu6VY7WVNuyX_wVry=~FJQBJiO@n7?{C?8||3?ylaCX~20!~BtJz)>n zV>At(#o;!N2mX&D0E@HR{t<8*!taS=ppVcrcot{3MMwaGPD=TR1Wv*y{wKg61ZQE| maSYuNXSYTEC%{huIR6LH8fGA>uSc~20000 Date: Fri, 3 Jun 2022 21:26:17 +0300 Subject: [PATCH 036/367] RDM unknown gym name fix --- commands/raid_from_webhook.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 36eda590..d6c26725 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -72,7 +72,7 @@ function isPointInsidePolygon($point, $vertices) { } $gym_name = isset($raid['message']['name']) ? $raid['message']['name'] : $raid['message']['gym_name']; - if ($config->WEBHOOK_EXCLUDE_UNKNOWN && $gym_name === 'unknown') { + if ($config->WEBHOOK_EXCLUDE_UNKNOWN && ($gym_name === 'unknown' || $gym_name === 'Unknown')) { debug_log($raid['message']['gym_id'],'Ignoring raid, the gym name is unknown and WEBHOOK_EXCLUDE_UNKNOWN says to ignore. id:'); continue; } From d8fc400d06d0da91c98c2537f614f9e812990097 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 4 Jun 2022 22:16:01 +0300 Subject: [PATCH 037/367] Raid level 8 sql upgrade fixes --- sql/pokemon-raid-bot.sql | 2 +- sql/upgrade/5.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 6520768c..df6fc0f9 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -114,7 +114,7 @@ CREATE TABLE `raids` ( `end_time` datetime DEFAULT NULL, `gym_team` enum('mystic','valor','instinct') DEFAULT NULL, `gym_id` int(10) unsigned NOT NULL, - `level` enum('1','2','3','4','5','6','7','X') DEFAULT NULL, + `level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL, `move1` varchar(255) DEFAULT NULL, `move2` varchar(255) DEFAULT NULL, `gender` varchar(255) DEFAULT NULL, diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index 0a7613bf..394c476f 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -4,5 +4,5 @@ CREATE TABLE `photo_cache` (`id` varchar(100) NOT NULL, `unique_id` varchar(45) ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); -ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','X') DEFAULT NULL; +ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL; ALTER TABLE `raid_bosses` MODIFY `raid_level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL; From 00db1194243b2e2253571202615343a7070af54a Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 5 Jun 2022 07:07:28 +0300 Subject: [PATCH 038/367] Added level 8 to share chats --- config/defaults-config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/config/defaults-config.json b/config/defaults-config.json index 7834c4e5..0d56f597 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -100,6 +100,7 @@ "TRAINER_CHATS":"", "SHARE_CHATS":"", "SHARE_CHATS_LEVEL_X":"", + "SHARE_CHATS_LEVEL_8":"", "SHARE_CHATS_LEVEL_7":"", "SHARE_CHATS_LEVEL_6":"", "SHARE_CHATS_LEVEL_5":"", From dd41e505d26ed222db4af6a05073a6c2cf153173 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 5 Jun 2022 07:11:51 +0300 Subject: [PATCH 039/367] Added missing translation --- lang/language.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lang/language.json b/lang/language.json index 0d3e0fe5..03a4375b 100644 --- a/lang/language.json +++ b/lang/language.json @@ -38,6 +38,19 @@ "FI": "Ultramadonreikä", "ES": "Ultraumbral" }, + "8stars_short": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Ultra", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "TRANSLATE", + "ES": "TRANSLATE" + }, "7stars": { "NL": "Legendary Mega-Raid", "DE": "TRANSLATE", From e073daf5cae053c54b20a9c28f3e1ec5d6b9c838 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 29 Jun 2022 20:14:46 +0300 Subject: [PATCH 040/367] Updated translations --- core/lang/pokemon.json | 22 +++++++++++++++++++++- core/lang/pokemon_moves.json | 13 +++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/core/lang/pokemon.json b/core/lang/pokemon.json index b1470fd8..f32bb1c3 100644 --- a/core/lang/pokemon.json +++ b/core/lang/pokemon.json @@ -4139,7 +4139,6 @@ "RU": "Крабаминабл" }, "pokemon_id_741": { - "PT-BR": "Oricório", "EN": "Oricorio", "FR": "Plumeline", "DE": "Choreogel", @@ -5059,5 +5058,26 @@ "FR": "Sylveroy", "DE": "Coronospa", "RU": "Калирекс" + }, + "pokemon_id_899": { + "EN": "Wyrdeer" + }, + "pokemon_id_900": { + "EN": "Kleavor" + }, + "pokemon_id_901": { + "EN": "Ursaluna" + }, + "pokemon_id_902": { + "EN": "Basculegion" + }, + "pokemon_id_903": { + "EN": "Sneasler" + }, + "pokemon_id_904": { + "EN": "Overqwil" + }, + "pokemon_id_905": { + "EN": "Enamorus" } } \ No newline at end of file diff --git a/core/lang/pokemon_moves.json b/core/lang/pokemon_moves.json index 374fa029..cefd670c 100644 --- a/core/lang/pokemon_moves.json +++ b/core/lang/pokemon_moves.json @@ -3886,6 +3886,19 @@ "RU": "Шар Тумана", "ES": "Bola Neblina" }, + "pokemon_move_367": { + "PT-BR": "Balanço Violento", + "EN": "Brutal Swing", + "FI": "Brutal Swing", + "NL": "Brutal Swing", + "NO": "Brutal Swing", + "PL": "Brutal Swing", + "FR": "Centrifugifle", + "DE": "Wirbler", + "IT": "Vorticolpo", + "RU": "Резкий Поворот", + "ES": "Giro Vil" + }, "pokemon_move_368": { "PT-BR": "Rolagem", "EN": "Rollout", From 905b0b574dd56f0445ea33c4ca942a643cc3ff52 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 29 Jun 2022 20:15:26 +0300 Subject: [PATCH 041/367] Re-enabled raid level 4 and updated the egg image --- constants.php | 5 +++-- images/raid_eggs/pokemon_icon_9994_00.png | Bin 16776 -> 19452 bytes 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/constants.php b/constants.php index b0ecdf99..4dc72846 100644 --- a/constants.php +++ b/constants.php @@ -3,7 +3,7 @@ define('PORTAL_IMAGES_PATH', IMAGES_PATH . '/gyms'); // raid levels constant -define('RAID_LEVEL_ALL', 'X876531'); +define('RAID_LEVEL_ALL', 'X8765431'); // Raid eggs. $eggs = array( @@ -18,12 +18,13 @@ ); // Levels available for import at PokeBattler -$pokebattler_levels = array('8', '7', '6', '5', '3', '1'); +$pokebattler_levels = array('8', '7', '6', '5', '4', '3', '1'); // Map our raid levels to tier names PokeBattler uses $pokebattler_level_map = [ '1' => 1, '3' => 3, + '4' => 4, '5' => 5, '6' => 'MEGA', '7' => 'MEGA_5', diff --git a/images/raid_eggs/pokemon_icon_9994_00.png b/images/raid_eggs/pokemon_icon_9994_00.png index 747b9d577844ac22a0c33dbb1725fef3caa53b45..0e36e2159b4bf800f38e8c99bfaf64d1741fc1c0 100644 GIT binary patch literal 19452 zcmV*!Ks&#QP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>DOOZ)LK~#8N?Y#$d zlv$dl*|RgV+dI2+re=H2cFj!h>7K4WUENugmc$Er0|*bo3J~(%
xPrUaYB#b~v zfROjz3wakt3V9NfkXe=0-@f0C|Au}AK_*FMS7lY_J?A;UQ7BOSPrTp#t`rgc#h>bk zBl`DhZrADm>UNucZtTFo%G|zT;6z z)3rw>EkYg>U#_9JqGlma3X} zayvUaW3^iC|AS@3zn3Tv;ot5!pY-_Lo@>>#{Zb_zylIrk+tUekbpCz=olUH#eb=jL z$Hhwe?0m&Ac^fX3Q+!FsI}2o3o+W`&qDiEZP&7Ji`1k(HPXaMMJ5}AZ`Ah||zj`A~z9_TQ)xWpv}Ia2$v6V+*S^v&1(^sL`9Z!1trG?QmS zc}V|u#i#Ko+NF#o-bmY~6`cT6Ls^q7M~Q#Qq{7%M!MmvuXP7JX(CDh{Dd7 z(w>AGx|Y*ObvlC}rAbSP4H_!#=oATj)r;i^gh`PSO9B~7@)$HV^~yv0^B*Dm3SvSJ z6jCIT^I1ZhVEx$&irim9;hz_a?TRC1g0Ou>6n(UWA|Q_UC8384DQI5-1??@MfZh4z zw=+-d^EMdrqEJ>hq|{MNMgy%+uA}u?b+igZf~f3zT3^sW+lm`0AB~Cl{VCA*qO2

j8bz{Dmc`Qix93yP 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 anOPZ`Lp1E^)ZYZuz~JfX=d#Wzp$Pz_BE7!= From 251e0b26f019cb95a06bc8527f76b37a9e3c2f8b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 4 Jul 2022 19:08:43 +0300 Subject: [PATCH 042/367] Moved all gym management features under `/gym` Implemented suggestions from issue #276 - Removed the commands `/addgym`, `/gymaddress`, `/gymgps` and `/gymnote` - Added their functionalities under `/gym` together with gym name editing `/gymname` is apparently still used by something else also, so I left that in for now. --- commands/addgym.php | 161 ------------------- commands/gym.php | 9 ++ commands/gymaddress.php | 95 ----------- commands/gymgps.php | 101 ------------ commands/gymnote.php | 98 ------------ constants.php | 3 + docs/config.rst | 15 +- lang/help.json | 65 -------- lang/language.json | 323 +++++++++++--------------------------- logic.php | 1 + logic/edit_gym_keys.php | 97 ++++++++++++ logic/get_gym_details.php | 19 +-- mods/gym_create.php | 103 ++++++++++++ mods/gym_delete.php | 2 +- mods/gym_details.php | 47 +----- mods/gym_edit_details.php | 122 +++++++------- mods/save_gym_info.php | 56 +++++++ 17 files changed, 439 insertions(+), 878 deletions(-) delete mode 100644 commands/addgym.php delete mode 100644 commands/gymaddress.php delete mode 100644 commands/gymgps.php delete mode 100644 commands/gymnote.php create mode 100644 logic/edit_gym_keys.php create mode 100644 mods/gym_create.php create mode 100644 mods/save_gym_info.php diff --git a/commands/addgym.php b/commands/addgym.php deleted file mode 100644 index 460b8cd6..00000000 --- a/commands/addgym.php +++ /dev/null @@ -1,161 +0,0 @@ -' . getTranslation('invalid_input') . '' . CR . CR; - $msg .= getTranslation('gym_coordinates_format_error') . CR; - $msg .= getTranslation('gym_coordinates_format_example'); - send_message($update['message']['chat']['id'], $msg); - exit(); -} - -// Set gym name. -$gym_name = '#' . $update['message']['from']['id']; - -// Get address. -$addr = get_address($lat, $lon); -$address = format_address($addr); - -// Insert / update gym. -try { - - global $dbh; - - // Build query to check if gym is already in database or not - $rs = my_query(" - SELECT COUNT(*) AS count - FROM gyms - WHERE gym_name = '{$gym_name}' - "); - - $row = $rs->fetch(); - - // Gym already in database or new - if (empty($row['count'])) { - // insert gym in table. - debug_log('Gym not found in database gym list! Inserting gym "' . $gym_name . '" now.'); - $query = ' - INSERT INTO gyms (gym_name, lat, lon, address, show_gym) - VALUES (:gym_name, :lat, :lon, :address, 0) - '; - $msg = getTranslation('gym_added'); - } else { - // Get gym by temporary name. - $gym = get_gym_by_telegram_id($gym_name); - - // If gym is already in the database, make sure no raid is active before continuing! - if($gym) { - debug_log('Gym found in the database! Checking for active raid now!'); - $gym_id = $gym['id']; - - // Check for duplicate raid - $duplicate_id = 0; - $duplicate_id = active_raid_duplication_check($gym_id); - - // Continue with raid creation - if($duplicate_id > 0) { - debug_log('Active raid is in progress!'); - debug_log('Tell user to update the gymname and exit!'); - - // Show message that a raid is active on that gym. - $raid_id = $duplicate_id; - $raid = get_raid($raid_id); - - // Build message. - $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); - - // Tell user to update the gymname first to create another raid by location - $msg .= getTranslation('gymname_then_location'); - $keys = []; - - // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); - - exit(); - } else { - debug_log('No active raid found! Continuing now ...'); - } - } else { - // Set gym_id to 0 - $gym_id = 0; - debug_log('No gym found in the database! Continuing now ...'); - } - - // Update gyms table to reflect gym changes. - debug_log('Gym found in database gym list! Updating gym "' . $gym_name . '" now.'); - $query = ' - UPDATE gyms - SET lat = :lat, - lon = :lon, - address = :address - WHERE gym_name = :gym_name - '; - $msg = getTranslation('gym_updated'); - } - - $statement = $dbh->prepare($query); - $statement->execute([ - 'gym_name' => $gym_name, - 'lat' => $lat, - 'lon' => $lon, - 'address' => $address - ]); - - // Get last insert id. - if (empty($row['count'])) { - $gym_id = $dbh->lastInsertId(); - } - - // Gym details. - if($gym_id > 0) { - $gym = get_gym($gym_id); - $msg .= CR . CR . get_gym_details($gym); - $msg .= CR . getTranslation('gym_instructions'); - $msg .= CR . getTranslation('help_gym-edit'); - $msg .= CR . getTranslation('help_gym-name'); - $msg .= CR . getTranslation('help_gym-address'); - $msg .= CR . getTranslation('help_gym-note'); - $msg .= CR . getTranslation('help_gym-delete'); - } -} catch (PDOException $exception) { - - error_log($exception->getMessage()); - $dbh = null; - exit(); -} - -// Set keys. -$keys = []; - -// Send the message. -send_message($update['message']['chat']['id'], $msg, $keys, ['disable_web_page_preview' => 'true']); - -?> diff --git a/commands/gym.php b/commands/gym.php index 3dfad347..70e481c3 100644 --- a/commands/gym.php +++ b/commands/gym.php @@ -51,6 +51,15 @@ // Merge keys. $keys = array_merge($h_keys, $keys); +if(bot_access_check($update, 'gym-add')) { + $keys[] = [ + [ + 'text' => getTranslation('gym_create'), + 'callback_data' => '0:gym_create:0' + ] + ]; +} + $keys[] = [ [ 'text' => getTranslation('abort'), diff --git a/commands/gymaddress.php b/commands/gymaddress.php deleted file mode 100644 index 9dc2a31d..00000000 --- a/commands/gymaddress.php +++ /dev/null @@ -1,95 +0,0 @@ -' . getTranslation('gym_id_address_missing') . ''; - $msg .= CR . CR . getTranslation('gym_address_instructions'); - $msg .= CR . getTranslation('gym_address_example'); - $msg .= CR . CR . getTranslation('gym_address_reset'); - $msg .= CR . getTranslation('gym_address_reset_example'); - $msg .= CR . CR . getTranslation('gym_get_id_details'); - - // Set keys. - $keys = []; -} else { - // Set keys. - $keys = []; - - // Get gym id. - $split_id_info = explode(',', $id_info,2); - $id = $split_id_info[0]; - $info = $split_id_info[1]; - $info = trim($info); - - // Make sure we have a valid gym id. - $gym = false; - if(is_numeric($id)) { - $gym = get_gym($id); - } - - // Update gym info. - if($gym && !empty($info) && strtolower($info) == 'reset') { - debug_log('Deleting address for gym with ID: ' . $id); - my_query( - " - UPDATE gyms - SET address = NULL - WHERE id = {$id} - " - ); - - // Set message. - $msg = get_gym_details($gym); - $msg .= CR . '' . getTranslation('gym_address_deleted') . ''; - } else if($gym && !empty($info)) { - debug_log('Adding address for gym with ID: ' . $id); - debug_log('Gym note: ' . $info); - $stmt = $dbh->prepare( - " - UPDATE gyms - SET address = :info - WHERE id = :id - " - ); - $stmt->execute(['info' => $info, 'id' => $id]); - - // Set message. - $msg = get_gym_details($gym); - $msg .= EMOJI_NEW . SP . $info; - $msg .= CR . CR . '' . getTranslation('gym_address_added') . ''; - } else if($gym && empty($info)) { - debug_log('Missing gym address!'); - // Set message. - $msg .= CR . '' . getTranslation('gym_id_address_missing') . ''; - $msg .= CR . CR . getTranslation('gym_address_instructions'); - $msg .= CR . getTranslation('gym_address_example'); - $msg .= CR . CR . getTranslation('gym_address_reset'); - $msg .= CR . getTranslation('gym_address_reset_example'); - $msg .= CR . CR . getTranslation('gym_get_id_details'); - } else { - // Set message. - $msg .= getTranslation('invalid_input'); - } -} - -// Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); - -?> diff --git a/commands/gymgps.php b/commands/gymgps.php deleted file mode 100644 index 7a76007f..00000000 --- a/commands/gymgps.php +++ /dev/null @@ -1,101 +0,0 @@ -' . getTranslation('gym_id_gps_missing') . ''; - $msg .= CR . CR . getTranslation('gym_gps_instructions'); - $msg .= CR . getTranslation('gym_gps_example'); - - // Set keys. - $keys = []; -} else { - // Set keys. - $keys = []; - - // Get gym id. - $split_id_info = explode(',', $id_info,2); - $id = $split_id_info[0]; - $info = $split_id_info[1]; - $info = trim($info); - - // Count commas given in info. - $count = substr_count($info, ","); - - // 1 comma as it should be? - // E.g. 52.5145434,13.3501189 - if($count == 1) { - $lat_lon = explode(',', $info); - $lat = $lat_lon[0]; - $lon = $lat_lon[1]; - - // Lat and lon with comma instead of dot? - // E.g. 52,5145434,13,3501189 - } else if($count == 3) { - $lat_lon = explode(',', $info); - $lat = $lat_lon[0] . '.' . $lat_lon[1]; - $lon = $lat_lon[2] . '.' . $lat_lon[3]; - } else { - // Invalid input - send the message and exit. - $msg = '' . getTranslation('invalid_input') . '' . CR . CR; - $msg .= getTranslation('gym_gps_coordinates_format_error') . CR; - $msg .= getTranslation('gym_gps_example'); - send_message($update['message']['chat']['id'], $msg); - exit(); - } - - // Make sure we have a valid gym id. - $gym = false; - if(is_numeric($id)) { - $gym = get_gym($id); - } - - if($gym && !empty($info)) { - debug_log('Updating gps coordinates for gym with ID: ' . $id); - debug_log('Gym latitude: ' . $lat); - debug_log('Gym longitude: ' . $lon); - my_query( - " - UPDATE gyms - SET lat = {$lat}, - lon = {$lon} - WHERE id = {$id} - " - ); - - // Set message. - $msg = get_gym_details($gym); - $msg .= EMOJI_NEW . SP . $info; - $msg .= CR . CR . '' . getTranslation('gym_gps_added') . ''; - } else if($gym && empty($info)) { - debug_log('Missing gym coordinates!'); - // Set message. - $msg .= CR . '' . getTranslation('gym_id_gps_missing') . ''; - $msg .= CR . CR . getTranslation('gym_gps_instructions'); - $msg .= CR . getTranslation('gym_gps_example'); - } else { - // Set message. - $msg .= getTranslation('invalid_input'); - } -} - -// Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); - -?> diff --git a/commands/gymnote.php b/commands/gymnote.php deleted file mode 100644 index f5652dd0..00000000 --- a/commands/gymnote.php +++ /dev/null @@ -1,98 +0,0 @@ -' . getTranslation('gym_id_note_missing') . ''; - $msg .= CR . CR . getTranslation('gym_note_instructions'); - $msg .= CR . getTranslation('gym_note_example'); - $msg .= CR . CR . getTranslation('gym_note_reset'); - $msg .= CR . getTranslation('gym_note_reset_example'); - $msg .= CR . CR . getTranslation('gym_get_id_details'); - - // Set keys. - $keys = []; -} else { - // Set keys. - $keys = []; - - // Get gym id. - $split_id_info = explode(',', $id_info,2); - $id = $split_id_info[0]; - $info = $split_id_info[1]; - $info = trim($info); - - // Make sure we have a valid gym id. - $gym = false; - if(is_numeric($id)) { - $gym = get_gym($id); - } - - // Update gym info. - if($gym && !empty($info) && strtolower($info) == 'reset') { - debug_log('Deleting gym note for gym with ID: ' . $id); - my_query( - " - UPDATE gyms - SET gym_note = NULL - WHERE id = {$id} - " - ); - - // Set message. - $msg = get_gym_details($gym); - $msg .= CR . '' . getTranslation('gym_note_deleted') . ''; - } else if($gym && !empty($info)) { - debug_log('Adding gym note for gym with ID: ' . $id); - debug_log('Gym note: ' . $info); - $stmt = $dbh->prepare( - " - UPDATE gyms - SET gym_note = :info - WHERE id = :id - " - ); - $stmt->execute([ - 'info' => $info, - 'id' => $id - ]); - - // Set message. - $msg = get_gym_details($gym); - $msg .= CR . CR . '' . getTranslation('gym_note_new') . '' . CR . EMOJI_INFO . SP . $info; - $msg .= CR . CR . '' . getTranslation('gym_note_added') . ''; - } else if($gym && empty($info)) { - debug_log('Missing gym note!'); - // Set message. - $msg .= CR . '' . getTranslation('gym_id_note_missing') . ''; - $msg .= CR . CR . getTranslation('gym_note_instructions'); - $msg .= CR . getTranslation('gym_note_example'); - $msg .= CR . CR . getTranslation('gym_note_reset'); - $msg .= CR . getTranslation('gym_note_reset_example'); - $msg .= CR . CR . getTranslation('gym_get_id_details'); - } else { - // Set message. - $msg .= getTranslation('invalid_input'); - } -} - -// Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); - -?> diff --git a/constants.php b/constants.php index 4dc72846..69e01c13 100644 --- a/constants.php +++ b/constants.php @@ -57,6 +57,9 @@ defined('EMOJI_STAR') or define('EMOJI_STAR', iconv('UCS-4LE', 'UTF-8', pack('V', 0x2B50))); defined('EMOJI_INVITE') or define('EMOJI_INVITE', iconv('UCS-4LE', 'UTF-8', pack('V', 0x2709))); defined('EMOJI_INFO') or define('EMOJI_INFO', iconv('UCS-4LE', 'UTF-8', pack('V', 0x2139))); +defined('EMOJI_DELETE') or define('EMOJI_DELETE', iconv('UCS-4LE', 'UTF-8', pack('V', 0x274C))); +defined('EMOJI_MAP') or define('EMOJI_MAP', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F5FA))); +defined('EMOJI_PENCIL') or define('EMOJI_PENCIL', iconv('UCS-4LE', 'UTF-8', pack('V', 0x270F))); defined('EMOJI_EGG') or define('EMOJI_EGG', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F95A))); defined('EMOJI_CLOCK') or define('EMOJI_CLOCK', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F551))); defined('EMOJI_CAMERA') or define('EMOJI_CAMERA', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F4F7))); diff --git a/docs/config.rst b/docs/config.rst index 4b7cd7e4..4b51d21b 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -690,19 +690,10 @@ A few examples for access files can be found below the permission overview table - Edit extended gym details ``/gym`` - ``gym-edit`` * - - - Edit gym name ``/gymname`` - - ``gym-name`` + - Delete a gym ``/gym`` + - ``gym-delete`` * - - - Edit gym address ``/gymaddress`` - - ``gym-address`` - * - - - Edit gym gps coordinates ``/gymgps`` - - ``gym-gps`` - * - - - Edit gym note ``/gymnote`` - - ``gym-note`` - * - - - Add a gym ``/addgym`` + - Add a gym ``/gym`` - ``gym-add`` * - - diff --git a/lang/help.json b/lang/help.json index 5a4d61b7..001e2391 100644 --- a/lang/help.json +++ b/lang/help.json @@ -181,71 +181,6 @@ "FI": "/gym - Muuta salin lisätietoja", "ES": "/gym - Editar detalles extendidos del gimnasio" }, - "help_gym-name": { - "NL": "/gymname - Verander de gym naam", - "DE": "/gymname - Arena-Namen bearbeiten", - "EN": "/gymname - Edit gym name", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "/gymname - Muuta salin nimeä", - "ES": "/gymname - Editar nombre del gimnasio" - }, - "help_gym-address": { - "NL": "/gymaddress - Verander gym adres", - "DE": "/gymaddress - Arena-Adresse bearbeiten", - "EN": "/gymaddress - Edit gym address", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "/gymaddress - Muuta salin osoitetta", - "ES": "/gymaddress - Editar dirección del gimnasio" - }, - "help_gym-gps": { - "NL": "/gymgps - Verander gym coordinaten", - "DE": "/gymgps - Arena-Koordinaten bearbeiten", - "EN": "/gymgps - Edit gym coordinates", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "/gymgps - Muuta salin koordinaatteja", - "ES": "/gymgps - Editar coordenadas del gimnasio" - }, - "help_gym-note": { - "NL": "/gymnote - Verander extra gym informatie", - "DE": "/gymnote - Arena-Notiz bearbeiten", - "EN": "/gymnote - Edit gym note", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "/gymnote - Muuta salin muistiinpanoja", - "ES": "/gymnote - Editar nota del gimnasio" - }, - "help_gym-add": { - "NL": "/addgym - Gym toevoegen", - "DE": "/addgym - Arena hinzufügen", - "EN": "/addgym - Add a gym", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "/addgym - Lisää sali", - "ES": "/addgym - Añadir gimnasio" - }, "help_portal-import": { "NL": "@Ingressportalbot - Importeer gym", "DE": "@Ingressportalbot - Arena importieren", diff --git a/lang/language.json b/lang/language.json index 03a4375b..48dfe267 100644 --- a/lang/language.json +++ b/lang/language.json @@ -1793,6 +1793,32 @@ "FI": "Virhe! Salia ei löytynyt!", "ES": "¡Error! ¡Gimnasio no encontrado!" }, + "gym_coordinates": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Coordinates", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Koordinaatit", + "ES": "TRANSLATE" + }, + "gym_edit_coordinates": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Edit coordinates", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Muokkaa koordinaatteja", + "ES": "TRANSLATE" + }, "gym_coordinates_format_error": { "NL": "Error! Stuur de coordinaten in het volgende formaat Latitude,Longitude om de nieuwe gym toe te voegen!", "DE": "Fehler! Bitte übermittle die Koordinaten im Format Breitengrad,Längengrad zum Hinzufügen einer neuen Arena!", @@ -1829,60 +1855,34 @@ "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Virhe! Virhe! Anna koordinaatit seuraavassa muodossa: Leveysaste,Pituusaste", + "FI": "Virhe! Anna koordinaatit seuraavassa muodossa: Leveysaste,Pituusaste", "ES": "¡Error! Envía las coordenadas en el siguiente formato: latitud,longitud" }, "gym_gps_instructions": { - "NL": "Om de gym coordinaten te veranderen stuur /gymgps gym id, nieuwe gym coordinaten!", - "DE": "Zum Ändern der Arena-Koordinaten bitte /gymgps Arena-ID, neue Arena-Koordinaten eingeben!", - "EN": "To change the coordinates of a gym please enter /gymgps gym id, new gym coordinates!", + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Send me the gym coordinates in the following format: Latitude,Longitude", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Muuttaaksesi salin koordinaatteja komenna gymgps salin id, uudet koordinaatit!", - "ES": "¡Para cambiar las coordenadas de un gimnasio, ingresa /gymgps gym id, nuevas coordenadas de gimnasio!" + "FI": "Lähetä minulle salin koordinaatit muodossa: Leveysaste,Pituusaste", + "ES": "TRANSLATE" }, "gym_gps_example": { - "NL": "Als voorbeeld: /gymgps 34, 51.516263,4.377755", - "DE": "Zum Beispiel: /gymgps 34, 52.516263,13.377755", - "EN": "For example: /gymgps 34, 52.516263,13.377755", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Esimerkiksi: /gymgps 34, 52.516263,13.377755", - "ES": "Por ejemplo: /gymgps 34, 52.516263,13.377755" - }, - "gym_gps_added": { - "NL": "Gym coordinaten succesvol toegevoegd!", - "DE": "Arena-Koordinaten erfolgreich hinzugefügt!", - "EN": "Gym coordinates successfully added!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Salin koordinaatit lisätty onnistuneesti!", - "ES": "¡Se agregaron con éxito las coordenadas del gimnasio!" - }, - "gym_id_gps_missing": { - "NL": "Error! gym id of coordinaten mist!", - "DE": "Fehler! Arena-ID oder Koordinaten fehlen!", - "EN": "Error! Gym id or coordinates are missing!", + "NL": "Als voorbeeld: 51.516263,4.377755", + "DE": "Zum Beispiel: 52.516263,13.377755", + "EN": "For example: 52.516263,13.377755", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Virhe! Salin id tai koordinaatit puuttuvat!", - "ES": "¡Error! ¡Faltan el gym id o las coordenadas!" + "FI": "Esimerkiksi: 52.516263,13.377755", + "ES": "Por ejemplo: 52.516263,13.377755" }, "gymname_then_location": { "NL": "Gebruik het commando /gymname Naam van de gym om deze aan de coordinaten vast te zetten. Daarna kan je weer een locatie delen!", @@ -1910,6 +1910,19 @@ "FI": "Sali lisätty onnistuneesti!", "ES": "¡Se agregó con éxito el gimnasio!" }, + "gym_create": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Create a new gym", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Luo uusi sali", + "ES": "TRANSLATE" + }, "gym_updated": { "NL": "De gym is succesvol aangepast!", "DE": "Arena erfolgreich aktualisiert!", @@ -1988,200 +2001,70 @@ "FI": "Näytä salin yksityiskohdat", "ES": "Ver detalles del gimnasio" }, - "gym_note_added": { - "NL": "Gym info toegevoegd!", - "DE": "Arena-Notiz erfolgreich hinzugefügt!", - "EN": "Gym note successfully added!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Salin muistiinpano tallennettu onnistuneesti!", - "ES": "¡Nota del gimnasio añadida con éxito!" - }, - "gym_note_deleted": { - "NL": "Gym info verwijderd!", - "DE": "Arena-Notiz erfolgreich gelöscht!", - "EN": "Gym note successfully deleted!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "alin muistiinpano poistettu onnistuneesti!", - "ES": "¡Nota del gimnasio eliminada con éxito!" - }, - "gym_note_new": { - "NL": "Nieuwe gym info:", - "DE": "Neue Arena-Notiz:", - "EN": "New gym note:", + "gym_edit_text_too_long": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Error! The maximum text length is 255 characters!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Uusi sali muistiinpano:", - "ES": "Nueva nota del gimnasio:" + "FI": "Virhe! Tekstin enimmäispituus on 255 merkkiä!", + "ES": "TRANSLATE" }, - "gym_id_note_missing": { - "NL": "Error! Gym id of info mist!", - "DE": "Fehler! Arena-ID oder Notiz fehlt!", - "EN": "Error! Gym id or note is missing!", + "gym_add_edit_note": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "gym note", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Virhe! Salin id tai muistiinpano puuttuu!", - "ES": "¡Error! ¡Faltan gym id o nota!" + "FI": "lisätietoja", + "ES": "TRANSLATE" }, "gym_note_instructions": { - "NL": "Om de gym info te veranderen stuur /gymnote gym id, nieuwe gym info!", - "DE": "Zum Ändern einer Arena-Notiz bitte /gymnote Arena-ID, neue Arena-Notiz eingeben!", - "EN": "To change the note of a gym please enter /gymnote gym id, new gym note!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Vaihtaaksesi salin muistiinpanoa komenna /gymnote salin id, uusi muistiinpano!", - "ES": "¡Para cambiar la nota de un gimnasio, escribe /gymnote gym id, nueva nota de gimnasio!" - }, - "gym_note_example": { - "NL": "Als voorbeeld: /gymnote 34, ontmoetingsplek: achter het gebouw!", - "DE": "Zum Beispiel: /gymnote 34, Treffpunkt: Hinter dem Gebäude", - "EN": "For example: /gymnote 34, Meeting point: Behind the building!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Esimerkiksi: /gymnote 34, Tapaamispiste: Rakennuksen takana!", - "ES": "Por ejemplo: /gymnote 34, Meeting point: Behind the building" - }, - "gym_note_reset": { - "NL": "Om de gym info te verwijderen stuur /gymnote gym id, reset.", - "DE": "Zum Löschen einer Arena-Notiz /gymnote Arena-ID, reset eingeben.", - "EN": "To delete a gym note enter /gymnote gym id, reset.", + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Send me the new gym note (max 255 characters):", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Poistaaksesi salin muistiinpanon komenna /gymnote salin id, reset.", - "ES": "Para eliminar la nota de un gimnasio, escribe /gymnote gym id, reset." + "FI": "Lähetä minulle salin uudet lisätiedot (max 255 merkkiä):", + "ES": "TRANSLATE" }, - "gym_note_reset_example": { - "NL": "Als voorbeeld: /gymnote 34, reset.", - "DE": "Zum Beispiel: /gymnote 34, reset", - "EN": "For example: /gymnote 34, reset", + "gym_address": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "gym address", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Esimerkiksi: /gymnote 34, reset", - "ES": "Por ejemplo: /gymnote 34, reset" + "FI": "salin osoite", + "ES": "TRANSLATE" }, "gym_address_instructions": { - "NL": "Om het adres aan te passen stuur /gymaddress gym id, het nieuwe gym adres!", - "DE": "Zum Ändern einer Arena-Adresse bitte /gymaddress Arena-ID, neue Arena-Adresse eingeben!", - "EN": "To change the address of a gym please enter /gymaddress gym id, new gym address!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Vaihtaaksesi salin osoitetta komenna /gymaddress salin id, uusi salin osoite!", - "ES": "¡Para cambiar la dirección de un gimnasio, escribe /gymaddress gym id, nueva dirección de gimnasio!" - }, - "gym_address_example": { - "NL": "Als voorbeeld /gymaddress 34, Markt 61, 3131 CR Vlaardingen !", - "DE": "Zum Beispiel: /gymaddress 34, Großer Stern, 10557 Berlin", - "EN": "For example: /gymaddress 34, Großer Stern, 10557 Berlin!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Esimeriksi: /gymaddress 34, Mannerheiminkatu, 49400 Hamina!", - "ES": "Por ejemplo: /gymaddress 34, Großer Stern, 10557 Berlin" - }, - "gym_address_reset": { - "NL": "Om het gym adres te verwijderen stuur /gymaddress gym id, reset.", - "DE": "Zum Löschen einer Arena-Adresse /gymaddress Arena-ID, reset eingeben.", - "EN": "To delete a gym address enter /gymaddress gym id, reset.", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Poistaaksesi salin osoitteen komenna /gymaddress salin id, reset.", - "ES": "Para eliminar la dirección de un gimnasio, escribe /gymaddress gym id, reset." - }, - "gym_address_reset_example": { - "NL": "Als voorbeeld /gymaddress 34, reset", - "DE": "Zum Beispiel: /gymaddress 34, reset", - "EN": "For example: /gymaddress 34, reset", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Esimerkiksi: /gymaddress 34, reset", - "ES": "Por ejemplo: /gymaddress 34, reset" - }, - "gym_address_added": { - "NL": "Gym adres succesvol toegevoegd!", - "DE": "Arena-Adresse erfolgreich hinzugefügt!", - "EN": "Gym address successfully added!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Salin osoite tallennettu onnistuneesti!", - "ES": "¡Dirección del gimnasio añadida con éxito!" - }, - "gym_id_address_missing": { - "NL": "Error! gym id of adres mist!", - "DE": "Fehler! Arena-ID oder Adresse fehlt!", - "EN": "Error! Gym id or address is missing!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Virhe! Salin id tai osoite puuttuu!", - "ES": "¡Error! Faltan gym id o dirreción!" - }, - "gym_address_deleted": { - "NL": "Gym adres succesvol verwijderd!", - "DE": "Arena-Adresse erfolgreich gelöscht!", - "EN": "Gym address successfully deleted!", + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Send me the new gym address:", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Salin osoite poistettu onnistuneesti!", - "ES": "¡Dirección del gimnasio eliminada con éxito!" + "FI": "Lähetä minulle salin uusi osoite:", + "ES": "TRANSLATE" }, "select_raid_boss": { "NL": "Selecteer Raid baas", @@ -3145,57 +3028,31 @@ "FI": "Saataksesi salin id numeron tai muita tietoja, käytä /gym -komentoa.", "ES": "Para obtener la identificación y más detalles del gimnasio, usa el comando /gym." }, - "gym_name_instructions": { - "NL": "Om de gym naam aan te passen stuur /gymname gym id, nieuwe gym naam!", - "DE": "Zum Ändern eines Arena-Namen bitte /gymname Arena-ID, neuer Arena-Name eingeben!", - "EN": "To change the name of a gym please enter /gymname gym id, new gym name!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Vaihtaaksesi salin nimeä komenna /gymname salin id, uusi salin nimi!", - "ES": "Para cambiar el nombre de un gimnasio, escribe /gymname gym id, nuevo nombre de gimnasio." - }, - "gym_name_example": { - "NL": "Als voorbeeld: /gymname 34, Markt 61, 3131 CR Vlaardingen ", - "DE": "Zum Beispiel: /gymname 34, Wasserfall im Park", - "EN": "For example: /gymname 34, Waterfall in the park!", + "gym_name_edit": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Edit gym name", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Esimerkiksi: /gymname 34, Vapauden Muistomerkki!", - "ES": "Por ejemplo: /gymname 34, Waterfall in the park" + "FI": "Muokkaa salin nimeä", + "ES": "TRANSLATE" }, - "gym_id_name_missing": { - "NL": "Error! Gym id of naam mist!", - "DE": "Fehler! Arena-ID oder Name fehlt!", - "EN": "Error! Gym id or name is missing!", + "gym_name_instructions": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Send me the gym name:", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Virhe! Salin id numero tai nimi puuttuu!", - "ES": "¡Error! ¡Faltan gym id o nombre!" - }, - "gym_name_updated": { - "NL": "Gym naam aangepast.", - "DE": "Der Arena-Name wurde aktualisiert.", - "EN": "Gym name updated.", - "IT": "Nome della Palestra aggiornato.", - "PT-BR": "Nome do ginásio atualizado.", - "RU": "Название гима обновлено.", - "NO": "Gym navn oppdatert.", - "FR": "Nom de l'arène mis à jour", - "PL": "Nazwa Areny zaktualizowana", - "FI": "Salin nimi päivitetty.", - "ES": "Nombre del gimnasio actualizado." + "FI": "Lähetä minulle salin nimi:", + "ES": "TRANSLATE" }, "overview_share": { "NL": "Overzicht delen", diff --git a/logic.php b/logic.php index 35d4c6f4..afe4206d 100644 --- a/logic.php +++ b/logic.php @@ -12,6 +12,7 @@ include('logic/delete_raid.php'); include('logic/delete_trainerinfo.php'); include('logic/disable_raid_level.php'); +include('logic/edit_gym_keys.php'); include('logic/edit_pokedex_keys.php'); include('logic/get_chat_title_username.php'); include('logic/get_formatted_pokemon_cp.php'); diff --git a/logic/edit_gym_keys.php b/logic/edit_gym_keys.php new file mode 100644 index 00000000..4b8947a5 --- /dev/null +++ b/logic/edit_gym_keys.php @@ -0,0 +1,97 @@ + $text_show_button, + 'callback_data' => $gym_id . ':gym_edit_details:show-' . $arg_show + ], + [ + 'text' => $text_ex_button, + 'callback_data' => $gym_id . ':gym_edit_details:ex-' . $arg_ex + ] + ]; + if(bot_access_check($update, 'gym-name', true)) { + $keys[] = [ + [ + 'text' => EMOJI_PENCIL . ' ' . getTranslation("gym_name_edit"), + 'callback_data' => $gym_id . ':gym_edit_details:name' + ] + ]; + } + if(bot_access_check($update, 'gym-note', true)) { + $keys[] = [ + [ + 'text' => EMOJI_INFO . ' ' . (!empty($gym_note) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_add_edit_note"), + 'callback_data' => $gym_id . ':gym_edit_details:note' + ] + ]; + } + if(bot_access_check($update, 'gym-address', true)) { + $keys[] = [ + [ + 'text' => EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("forest")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), + 'callback_data' => $gym_id . ':gym_edit_details:addr' + ] + ]; + } + if(bot_access_check($update, 'gym-gps', true)) { + $keys[] = [ + [ + 'text' => EMOJI_HERE . ' ' . getTranslation("gym_edit_coordinates"), + 'callback_data' => $gym_id . ':gym_edit_details:gps' + ] + ]; + } + if(bot_access_check($update, 'gym-delete', true)) { + $keys[] = [ + [ + 'text' => EMOJI_DELETE . ' ' . getTranslation("gym_delete"), + 'callback_data' => '0:gym_delete:'.$gym_id.'-delete' + ] + ]; + } + $keys[] = [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ]; + + return $keys; +} +?> diff --git a/logic/get_gym_details.php b/logic/get_gym_details.php index 3ecdc4a0..19d0cd81 100644 --- a/logic/get_gym_details.php +++ b/logic/get_gym_details.php @@ -35,23 +35,24 @@ function get_gym_details($gym, $extended = false) // Add or hide gym note. if(!empty($gym['gym_note'])) { - $msg .= EMOJI_INFO . SP . $gym['gym_note']; + $msg .= EMOJI_INFO . SP . $gym['gym_note'] . CR; } // Get extended gym details? if($extended == true) { $msg .= CR . '' . getTranslation('extended_gym_details') . ''; - // Normal gym? - if($gym['ex_gym'] == 1) { - $msg .= CR . '-' . SP . getTranslation('ex_gym'); - } - // Hidden gym? - if($gym['show_gym'] == 1 && $gym['ex_gym'] == 0) { - $msg .= CR . '-' . SP . getTranslation('normal_gym'); - } else if($gym['show_gym'] == 0) { + if($gym['show_gym'] == 0) { $msg .= CR . '-' . SP . getTranslation('hidden_gym'); + }else { + // Normal gym? + if($gym['ex_gym'] == 1) { + $msg .= CR . '-' . SP . getTranslation('ex_gym'); + }else { + $msg .= CR . '-' . SP . getTranslation('normal_gym'); + } } + $msg .= CR . '-' . SP . getTranslation('gym_coordinates') . ': ' . (float)$gym['lat'] . ',' . (float)$gym['lon'].''; } return $msg; diff --git a/mods/gym_create.php b/mods/gym_create.php new file mode 100644 index 00000000..c82f52b8 --- /dev/null +++ b/mods/gym_create.php @@ -0,0 +1,103 @@ + $stage + 1, "oldMessageId" => $oldMessageId]; + if($gymId !== 0) $modifierArray['gymId'] = $gymId; + $modifiers = json_encode($modifierArray); + $handler = "gym_create"; + + my_query("INSERT INTO user_input SET user_id = :userId, modifiers = :modifiers, handler = :handler", [':userId' => $userId, ':modifiers' => $modifiers, ':handler' => $handler]); + return $dbh->lastInsertId(); +} +function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [], $sendMsg = '', $sendKeys = [], $callbackMsg = '', $callbackId = 0) { + if($callbackId != 0) answerCallbackQuery($callbackId, $callbackMsg); + if($editMsg != '') editMessageText($oldMessageId, $editMsg, $editKeys, $userId, ['disable_web_page_preview' => 'true']); + if($sendMsg != '') send_message($userId, $sendMsg, $sendKeys, ['disable_web_page_preview' => 'true']); +} +if(isset($data['arg'])) { + // Split the arg. + $split_arg = explode('-', $data['arg']); + $action = $split_arg[0] ?? false; + $deleteId = $split_arg[1] ?? false; +} +// Set keys. +$keys = []; + +$stage = $modifiers['stage'] ?? 1; + +if(isset($action) && $action == 'abort') { + my_query("DELETE FROM user_input WHERE id = :deleteId", ['deleteId' => $deleteId]); + $msg = getTranslation("action_aborted"); + editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['from']['id']); +}else { + if($stage == 1) { + $callbackResponse = getTranslation('here_we_go'); + $callbackId = $update['callback_query']['id']; + + $userId = $update['callback_query']['from']['id']; + $oldMessageId = $update['callback_query']['message']['message_id']; + + $userInputId = insertUserInput($userId, $stage, $oldMessageId); + + $editMsg = getTranslation("gym_create") . ':'; + $editKeys[0][] = [ + 'text' => getTranslation("abort"), + 'callback_data' => '0:gym_create:abort-' . $userInputId + ]; + $sendMsg = EMOJI_HERE . getTranslation('gym_gps_instructions') . CR; + $sendMsg .= getTranslation('gym_gps_example'); + respondToUser($userId, $oldMessageId, $editMsg, $editKeys, $sendMsg, [], $callbackResponse, $callbackId); + }else { + $userId = $update['message']['from']['id']; + $oldMessageId = $modifiers['oldMessageId']; + + if($stage == 2) { + $input = $update['message']['text']; + $reg_exp_coordinates = '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$^'; + if(preg_match($reg_exp_coordinates, $input)) { + [$lat,$lon] = explode(',', $input, 2); + my_query("INSERT INTO gyms (gym_name, lat, lon) VALUES ('unknown', :lat, :lon)", [':lat' => $lat, ':lon' => $lon]); + $gymId = $dbh->lastInsertId(); + + $userInputId = insertUserInput($userId, $stage, $oldMessageId, $gymId); + $msg = EMOJI_PENCIL . getTranslation('gym_name_instructions'); + respondToUser($userId, 0, '', [], $msg); + }else { + $msg = getTranslation('gym_gps_coordinates_format_error'); + respondToUser($userId, 0, '', [], $msg); + exit(); + } + + }elseif($stage == 3) { + $input = trim($update['message']['text']); + if(strlen($input) <= 255) { + $gymId = $modifiers['gymId']; + my_query("UPDATE gyms SET gym_name = :gym_name WHERE id = :gymId", [':gym_name' => $input, ':gymId' => $gymId]); + + $msg = getTranslation('gym_added'); + $keys[] = [ + [ + 'text' => getTranslation('show_gym_details'), + 'callback_data' => 'N:gym_details:' . $gymId + ] + ]; + respondToUser($userId, $oldMessageId, 'OK', [], $msg, $keys); + }else { + $msg = getTranslation('gym_edit_text_too_long'); + respondToUser($userId, 0, '', [], $msg); + exit(); + } + } + } +} diff --git a/mods/gym_delete.php b/mods/gym_delete.php index ae2c5a31..d74c6d3f 100644 --- a/mods/gym_delete.php +++ b/mods/gym_delete.php @@ -46,7 +46,7 @@ [ [ 'text' => getTranslation('no'), - 'callback_data' => '0:exit:0' + 'callback_data' => $new_arg . ':gym_edit_details:' ] ] ]; diff --git a/mods/gym_details.php b/mods/gym_details.php index 58279cba..a81b81f6 100644 --- a/mods/gym_details.php +++ b/mods/gym_details.php @@ -57,53 +57,8 @@ } else { $gym = get_gym($arg); $msg = get_gym_details($gym, true); - $msg .= CR . CR . '' . getTranslation('change_extended_gym_details') . ''; - // Hide gym? - if($gym['show_gym'] == 1) { - $text_show_button = getTranslation('hide_gym'); - $arg_show = 0; - - // Show gym? - } else { - $text_show_button = getTranslation('show_gym'); - $arg_show = 1; - } - - // Normal gym? - if($gym['ex_gym'] == 1) { - $text_ex_button = getTranslation('normal_gym'); - $arg_ex = 0; - - // Ex-raid gym? - } else { - $text_ex_button = getTranslation('ex_gym'); - $arg_ex = 1; - } - - // Add buttons to show/hide the gym and add/remove ex-raid flag - $keys = []; - $keys[] = array( - 'text' => $text_show_button, - 'callback_data' => $arg . ':gym_edit_details:show-' . $arg_show - ); - $keys[] = array( - 'text' => $text_ex_button, - 'callback_data' => $arg . ':gym_edit_details:ex-' . $arg_ex - ); - if(bot_access_check($update, 'gym-delete', true)) { - $keys[] = array( - 'text' => getTranslation("gym_delete"), - 'callback_data' => '0:gym_delete:'.$arg.'-delete' - ); - } - $keys[] = array( - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ); - - // Get the inline key array. - $keys = inline_key_array($keys, 1); + $keys = edit_gym_keys($update, $arg, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); } // Build callback message string. diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index 20842d7f..c4fda88a 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -10,7 +10,7 @@ bot_access_check($update, 'gym-edit'); // Get the id. -$id = $data['id']; +$gym_id = $data['id']; // Get the arg. $arg = $data['arg']; @@ -18,69 +18,77 @@ // Split the arg. $split_arg = explode('-', $arg); $action = $split_arg[0]; -$value = $split_arg[1]; +$value = $split_arg[1] ?? false; +$delete_id = $split_arg[2] ?? false; // Set keys. $keys = []; -// Update gym info. -if($action == 'show' || $action == 'ex') { - $gym = get_gym($id); - - // Set message - $msg = get_gym_details($gym, true); - $msg .= CR . CR . '' . getTranslation('new_extended_gym_detail') . ''; - - // New extended gym detail. - if($action == 'show' && $value == 0) { - $msg .= CR . '-' . SP . getTranslation('hide_gym'); - } else if($action == 'show' && $value == 1) { - $msg .= CR . '-' . SP . getTranslation('show_gym'); - } else if($action == 'ex' && $value == 0) { - $msg .= CR . '-' . SP . getTranslation('normal_gym'); - } else if($action == 'ex' && $value == 1) { - $msg .= CR . '-' . SP . getTranslation('ex_gym'); +debug_log('Changing the details for the gym with ID ' . $gym_id); + +$gym = get_gym($gym_id); + +// Did we receive a call to edit some gym data that requires a text input +if(in_array($action, ['name','note','gps','addr'])) { + if($value == 'd') { + my_query("DELETE FROM user_input WHERE id=:delete_id'", ['delete_id' => $delete_id]); + if($action == 'note') { + $query = 'UPDATE gyms SET gym_note = NULL WHERE id = :id'; + $binds = [ + ':id' => $gym_id, + ]; + // Update the event note to raid table + $prepare = $dbh->prepare($query); + $prepare->execute($binds); + $gym['gym_note'] = ''; + } + $msg = get_gym_details($gym, true); + $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); + }else { + // Create an entry to user_input table + $userid = $update['callback_query']['from']['id']; + $modifiers = json_encode(array("id" => $gym_id, "value" => $action, "old_message_id" => $update['callback_query']['message']['message_id'])); + $handler = "save_gym_info"; + + my_query("INSERT INTO user_input SET user_id = :userid, modifiers = :modifiers, handler = :handler", [':userid' => $userid, ':modifiers' => $modifiers, ':handler' => $handler]); + + $msg = get_gym_details($gym, true); + if($action == 'addr') $instructions = 'gym_address_instructions'; else $instructions = 'gym_'.$action.'_instructions'; + $msg .= CR . CR . '' . getTranslation($instructions) . ''; + if($action == 'gps') $msg .= CR. getTranslation('gym_gps_example'); + + $keys[0][] = [ + 'text' => getTranslation("abort"), + 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() + ]; + if($action == 'note' && !empty($gym['note'])) { + $keys[0][] = [ + 'text' => getTranslation("delete"), + 'callback_data' => $gym_id.':gym_edit_details:note-d-'.$dbh->lastInsertId() + ]; + } } - $msg .= CR . CR . '' . getTranslation('change_extended_gym_details') . ''; - - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => $id . ':gym_edit_details:' . 'confirm' . $action . '-' . $value - ] - ], - [ - [ - 'text' => getTranslation('no'), - 'callback_data' => '0:exit:0' - ] - ] - ]; - -} else if($action == 'confirmshow' || $action == 'confirmex') { - debug_log('Changing the details for the gym with ID ' . $id); - // Show or ex? - $table = 'show_gym'; - if($action == 'confirmex') { +}else { + if($action == 'show') { + $gym['show_gym'] = $value; + $table = 'show_gym'; + }else if($action == 'ex') { + $gym['ex_gym'] = $value; $table = 'ex_gym'; + }else if($action == 'abort') { + my_query("DELETE FROM user_input WHERE id = :value", ['value' => $value]); } - - my_query( - " - UPDATE gyms - SET $table = $value - WHERE id = {$id} - " - ); - - // Get gym. - $gym = get_gym($id); - - // Set message. - $msg = '' . getTranslation('gym_saved') . ''; - $msg .= CR . get_gym_details($gym, true); + if(isset($table)) { + my_query( + " + UPDATE gyms + SET $table = $value + WHERE id = {$gym_id} + " + ); + } + $msg = get_gym_details($gym, true); + $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); } // Build callback message string. diff --git a/mods/save_gym_info.php b/mods/save_gym_info.php new file mode 100644 index 00000000..8c5327e1 --- /dev/null +++ b/mods/save_gym_info.php @@ -0,0 +1,56 @@ + $lat, + ':lon' => $lon, + ':id' => $gym_id, + ]; + $gym['lat'] = $lat; + $gym['lon'] = $lon; + }else { + send_message($user_id, getTranslation("gym_gps_coordinates_format_error") . CR . getTranslation("gym_coordinates_format_example")); + exit(); + } +}else if(in_array($action, ['addr','name','note'])) { + $column_map = ['addr' => 'address', 'name' => 'gym_name', 'note' => 'gym_note']; + if(strlen($input) <= 255) { + $query = 'UPDATE gyms SET '.$column_map[$action].'=:value WHERE id = :id'; + $binds = [ + ':value' => $input, + ':id' => $gym_id, + ]; + $gym[$column_map[$action]] = $input; + }else { + send_message($user_id, getTranslation("gym_edit_text_too_long")); + exit(); + } +} +if($query !== false) { + $prepare = $dbh->prepare($query); + $prepare->execute($binds); + + $msg = get_gym_details($gym, true); + $msg .= CR . CR . getTranslation("gym_saved"); + $update['callback_query']['from']['id'] = $user_id; + $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); +} +// Remove back button from previous message to avoid confusion +editMessageText($modifiers['old_message_id'], $msg, $keys, $user_id, ['disable_web_page_preview' => 'true']); +if($error) exit(); From 2c28d985275afe8d694ae1b941290ea1d65ff13f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 4 Jul 2022 19:19:04 +0300 Subject: [PATCH 043/367] Minor fixes to `/get` and `/set`, and documented them issue #271 --- core/commands/set.php | 4 ++-- core/lang/language.json | 15 ++++++++++++++- docs/config.rst | 18 +++++++++++++++++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/core/commands/set.php b/core/commands/set.php index 693ff218..353cc978 100644 --- a/core/commands/set.php +++ b/core/commands/set.php @@ -89,7 +89,7 @@ if(in_array($config_name, $allowed)) { // Only bool? if(in_array($config_name, $allowed_bool)) { - if(strcasecmp($config_value, true) == 0 || strcasecmp($config_value, false) == 0) { + if(strcasecmp($config_value, 'true') == 0 || strcasecmp($config_value, 'false') == 0) { $config_value = strtolower($config_value); $restrict = 'no'; } else if($config_value == 0 || $config_value == 1) { @@ -144,7 +144,7 @@ $msg .= '' . getTranslation('config') . ':' . CR; // Any configs allowed? if(!empty($config->ALLOWED_TELEGRAM_CONFIG)) { - $msg .= '/setconfig' . SP . getTranslation('option_value') . '' . CR; + $msg .= '/set [' . getTranslation("config_option") . '] [' . getTranslation('option_value') . ']' . CR; foreach($json as $cfg_name => $cfg_value) { // Only allowed configs if(in_array($cfg_name, $allowed)) { diff --git a/core/lang/language.json b/core/lang/language.json index 153b90f3..6898eaa7 100644 --- a/core/lang/language.json +++ b/core/lang/language.json @@ -626,7 +626,7 @@ "option_value": { "NL": "Configuratie optie waarde", "DE": "Konfigurationsoption Wert", - "EN": "Configurationoption value", + "EN": "Configuration option value", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", @@ -636,6 +636,19 @@ "FI": "Asetuksen arvo", "ES": "Valor de la opción de configuración" }, + "config_option": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Configuration option", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Asetuksen nimi", + "ES": "TRANSLATE" + }, "no_value": { "NL": "Geen waarde", "DE": "Kein Wert", diff --git a/docs/config.rst b/docs/config.rst index 4b51d21b..19a545dd 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -272,6 +272,13 @@ Set ``RAID_EX_GYM_MARKER`` to set the marker for ex-raid gyms. You can use a pre Set ``RAID_CREATION_EX_GYM_MARKER`` to true to show the marker for ex-raid gyms during raid creation. +Manage bot configuration values via Telegram +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For bot admins to easily manage specific bot settings you can create a config file ``config/telegram.json`` containing the configuration values you want to be able to edit. Example file is located in ``config/defaults-telegram.json``. + +Users with the right permissions can then use the commands ``/get`` and ``/set`` to manage those configuration values. + Automatically refreshing raid polls ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -698,6 +705,15 @@ A few examples for access files can be found below the permission overview table * - - - + * - Settings + - Read the value of a specific setting in bot config ``/get`` + - ``config-get`` + * - + - Set the value of a specific setting in bot config ``/set`` + - ``config-set`` + * - + - + - * - Trainer - Set trainer data ``/trainer`` - ``trainer`` @@ -717,7 +733,7 @@ A few examples for access files can be found below the permission overview table - - * - Pokedex - - Manage raid pokemon ``/pokedex`` + - Manage raid Pokemon ``/pokedex`` - ``pokedex`` * - - From 9b749b442a75fc613aa73cba30ea3ecd58d2420c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 4 Jul 2022 20:00:45 +0300 Subject: [PATCH 044/367] Added `pokemon_title` column in `events` table Makes it configurable how the Pokemon name is displayed for this event. Issue #277 --- docs/config.rst | 5 +++++ lang/language.json | 13 +++++++++++++ logic/get_raid.php | 2 +- logic/show_raid_poll.php | 22 ++++++++++++++-------- sql/pokemon-raid-bot.sql | 1 + sql/upgrade/5.sql | 2 ++ 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index 19a545dd..a7a82484 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -448,6 +448,11 @@ With ``time_slots`` you can set event secific time slots for vote keys when ``vo ``hide_raid_picture`` hides the raid picture from these event polls even if ``RAID_PICTURE`` is set to ``true``. +``pokemon_title`` select how the Pokemon name is displayed for this event. +``0`` = hide Pokemon name +``1`` = Raid boss: Kyogre +``2`` = Featured Pokemon: Kyogre + Trainer settings ---------------- diff --git a/lang/language.json b/lang/language.json index 48dfe267..914caa7d 100644 --- a/lang/language.json +++ b/lang/language.json @@ -2105,6 +2105,19 @@ "FI": "Raidi tallennettu:", "ES": "Incursión guardada:" }, + "featured_pokemon": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Featured Pokemon", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tapahtuman Pokemon", + "ES": "TRANSLATE" + }, "raid_boss": { "NL": "Raid baas", "DE": "Raid-Boss", diff --git a/logic/get_raid.php b/logic/get_raid.php index 2c76107e..f8b9dc67 100644 --- a/logic/get_raid.php +++ b/logic/get_raid.php @@ -17,7 +17,7 @@ function get_raid($raid_id) SELECT raids.pokemon, raids.pokemon_form, raids.id, raids.user_id, raids.spawn, raids.start_time, raids.end_time, raids.gym_team, raids.gym_id, raids.level, raids.move1, raids.move2, raids.gender, raids.event, raids.costume, raids.event_note, gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, gyms.gym_note, users.name, users.trainername, users.nick, - events.name as event_name, events.description as event_description, events.vote_key_mode as event_vote_key_mode, events.time_slots as event_time_slots, events.raid_duration as event_raid_duration, events.hide_raid_picture as event_hide_raid_picture, events.poll_template as event_poll_template, + events.name as event_name, events.description as event_description, events.vote_key_mode as event_vote_key_mode, events.time_slots as event_time_slots, events.raid_duration as event_raid_duration, events.hide_raid_picture as event_hide_raid_picture, events.pokemon_title as event_pokemon_title, events.poll_template as event_poll_template, TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left, IF(UTC_TIMESTAMP() > end_time, 1, 0) as raid_ended FROM raids diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index e1cbebcf..a5605538 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -26,7 +26,7 @@ function show_raid_poll($raid, $inline = false) } // Get raid times. - $msg = raid_poll_message($msg, get_raid_times($raid), true); + $msg = raid_poll_message($msg, get_raid_times($raid, false, ($raid['event_pokemon_title'] == 0 ? true : false)), true); // Get current time and time left. $time_now = utcnow(); @@ -74,13 +74,19 @@ function show_raid_poll($raid, $inline = false) } } - // Display raid boss name. - $msg = raid_poll_message($msg, getPublicTranslation('raid_boss') . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . '', true); - - // Display raid boss weather. - $pokemon_weather = get_pokemon_weather($raid_pokemon_id, $raid_pokemon_form_id); - $msg = raid_poll_message($msg, ($pokemon_weather != 0) ? (' ' . get_weather_icons($pokemon_weather)) : '', true); - $msg = raid_poll_message($msg, CR, true); + // Display raid boss name and boss' weather unless hidden for a specific event + if($raid['event_pokemon_title'] != 0) { + // Display raid boss name. + if($raid['event_pokemon_title'] == 1) $title = getPublicTranslation('raid_boss'); + elseif($raid['event_pokemon_title'] == 2) $title = getPublicTranslation('featured_pokemon'); + else $title = getPublicTranslation('raid_boss'); + $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . '', true); + + // Display raid boss weather. + $pokemon_weather = get_pokemon_weather($raid_pokemon_id, $raid_pokemon_form_id); + $msg = raid_poll_message($msg, ($pokemon_weather != 0) ? (' ' . get_weather_icons($pokemon_weather)) : '', true); + $msg = raid_poll_message($msg, CR, true); + } // Display attacks. if ($raid['move1'] > 1 && $raid['move2'] > 2 ) { diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index df6fc0f9..4fedbe12 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -37,6 +37,7 @@ CREATE TABLE `events` ( `time_slots` int(3) DEFAULT NULL, `raid_duration` int(3) unsigned NOT NULL DEFAULT 0, `hide_raid_picture` tinyint(1) DEFAULT 0, + `pokemon_title` tinyint(1) NULL DEFAULT 1, `poll_template` VARCHAR(200) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index 394c476f..cbf6a3a9 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -6,3 +6,5 @@ CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, messa ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL; ALTER TABLE `raid_bosses` MODIFY `raid_level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL; + +ALTER TABLE `events` ADD COLUMN `pokemon_title` TINYINT(1) NULL DEFAULT 1 AFTER `hide_raid_picture`; From aabf7e444feec4a74293427d56f8396300794014 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 4 Jul 2022 20:04:40 +0300 Subject: [PATCH 045/367] PHP error fix --- logic/raid_picture.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 209ab152..97c3461a 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -145,6 +145,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Gym image $gym_url = $raid['img_url']; + $gym_image_path = ''; if($config->RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY && !empty($gym_url)) { if(substr($gym_url, 0, 7) == 'file://') { $gym_image_path = $gym_url; @@ -169,7 +170,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $gym_image_path = $gym_url; } } - $img_gym = grab_img($gym_image_path); + $img_gym = $gym_image_path != '' ? grab_img($gym_image_path) : false; if($img_gym == false) { info_log($gym_image_path, 'Loading the gym image failed, using default gym image'); if(is_file($config->RAID_DEFAULT_PICTURE)) { From 54129d7caad410ed3bf64150010cbe2246794d52 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 4 Jul 2022 20:16:58 +0300 Subject: [PATCH 046/367] Modified how timestamp is stored when voting `Participate` on an event raid Votes work now even if `RAID_ANYTIME` is set to `false`. And as an added bonus the raid alarms make a bit more sense now --- logic/keys_vote.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 219fe6d9..03c94b44 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -168,7 +168,7 @@ function keys_vote($raid) $keys_time = [ [ 'text' => getPublicTranslation("Participate"), - 'callback_data' => $raid['id'] . ':vote_time:0' + 'callback_data' => $raid['id'] . ':vote_time:' . utctime($raid['start_time'], 'YmdHis') ] ]; }else { From 11d2ca582a00c45a302224fed3e262eefd515716 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 6 Jul 2022 18:54:17 +0300 Subject: [PATCH 047/367] Fixed raid picture Current megas have a costume, so it broke things. I tried to fix it --- logic/raid_picture.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 97c3461a..b08baf87 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -303,11 +303,14 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); $addressable_icon = 'pm'.$raid['pokemon']; + if($raid['pokemon_form_name'] != 'normal') $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); // Getting the actual icon filename $p_icon = "pokemon_icon_" . $icon_suffix; - if($raid['costume'] != 0) { + + // Add costume info for every mon except megas + if($raid['costume'] != 0 && $raid['pokemon_form'] >= 0) { $p_icon .= '_' . str_pad($raid['costume'], 2, '0', STR_PAD_LEFT); $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); @@ -344,7 +347,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // If no image was found, substitute with a fallback if($img_file === null) { - info_log($p_icon, 'Failed to find an image in any pokemon image collection for:'); + info_log($p_icon . ' ' . $addressable_icon, 'Failed to find an image in any pokemon image collection for:'); $img_fallback_file = null; // If we know the raid level, fallback to egg image if(array_key_exists('level', $raid) && $raid['level'] !== null && $raid['level'] != 0) { From 8c0eba795ebc531d3297a15e66052d63ccb142c5 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 6 Jul 2022 19:02:25 +0300 Subject: [PATCH 048/367] Fixed webhook raid polls --- commands/raid_from_webhook.php | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index d6c26725..c3038c48 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -326,6 +326,7 @@ function isPointInsidePolygon($point, $vertices) { 'event_time_slots' => NULL, 'event_raid_duration' => NULL, 'event_hide_raid_picture' => NULL, + 'event_pokemon_title' => NULL, 'event_poll_template' => NULL, 'raid_ended' => 0, ]); From 703b28603384d0e0091421e889e67fca40bda392 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 7 Jul 2022 19:46:43 +0300 Subject: [PATCH 049/367] Fixed raid timer translation --- logic/show_raid_poll.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index a5605538..c59d1cde 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -26,7 +26,7 @@ function show_raid_poll($raid, $inline = false) } // Get raid times. - $msg = raid_poll_message($msg, get_raid_times($raid, false, ($raid['event_pokemon_title'] == 0 ? true : false)), true); + $msg = raid_poll_message($msg, get_raid_times($raid, true, ($raid['event_pokemon_title'] == 0 ? true : false)), true); // Get current time and time left. $time_now = utcnow(); From 2362a6e2006f494da9a545494695c55f88d8a583 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 7 Jul 2022 20:00:14 +0300 Subject: [PATCH 050/367] Remove duplicate raid bosses --- logic/raid_level.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/logic/raid_level.php b/logic/raid_level.php index bfb73652..0353395a 100644 --- a/logic/raid_level.php +++ b/logic/raid_level.php @@ -44,10 +44,10 @@ function get_raid_bosses($time, $raid_level) // Get raid level from database $rs = my_query( ' - SELECT pokedex_id, pokemon_form_id - FROM raid_bosses - WHERE \''.$time.'\' BETWEEN date_start AND date_end - AND raid_level = \''.$raid_level.'\' + SELECT DISTINCT pokedex_id, pokemon_form_id + FROM raid_bosses + WHERE \''.$time.'\' BETWEEN date_start AND date_end + AND raid_level = \''.$raid_level.'\' '); debug_log('Checking active raid bosses for raid level '.$raid_level.' at '.$time.':'); $raid_bosses = []; From 5f9cf1ef7c5c703dc1351cc2d080b1d4cb378a2a Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 7 Jul 2022 20:01:15 +0300 Subject: [PATCH 051/367] Fixed php errors if failed to retrieve expected data --- logic/read_upcoming_bosses.php | 70 +++++++++++++++++----------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index 4ff96a27..966e1c64 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -13,48 +13,50 @@ function read_upcoming_bosses($return_sql = false) { $pb_timezone = new dateTimeZone('America/Phoenix'); $count = 0; $sql = $list = $prev_start = $prev_rl = ''; - foreach($pb['breakingNews'] as $news) { - if($news['type'] == 'RAID_TYPE_RAID') { - $rl = str_replace('RAID_LEVEL_','', $news['tier']); - $raid_level_id = array_search($rl, $pokebattler_level_map); - if(!in_array($raid_level_id,$pokebattler_import_future_tiers)) break; // Limit scheduling to tier 5 and mega only - $starttime = new DateTime("@".(substr($news['startDate'],0,10)), new dateTimeZone('UTC')); - $endtime = new DateTime("@".(substr($news['endDate'],0,10)), new dateTimeZone('UTC')); + if(isset($pb['breakingNews'])) { + foreach($pb['breakingNews'] as $news) { + if($news['type'] == 'RAID_TYPE_RAID') { + $rl = str_replace('RAID_LEVEL_','', $news['tier']); + $raid_level_id = array_search($rl, $pokebattler_level_map); + if(!in_array($raid_level_id,$pokebattler_import_future_tiers)) break; // Limit scheduling to tier 5 and mega only + $starttime = new DateTime("@".(substr($news['startDate'],0,10)), new dateTimeZone('UTC')); + $endtime = new DateTime("@".(substr($news['endDate'],0,10)), new dateTimeZone('UTC')); - $starttime->setTimezone($pb_timezone); - $endtime->setTimezone($pb_timezone); + $starttime->setTimezone($pb_timezone); + $endtime->setTimezone($pb_timezone); - // If the boss only appears for an hour, the eggs most likely start to spawn 20 minutes prior to the time. - $diff = $starttime->diff($endtime); - if($diff->format('%h') == 1) { - $starttime->sub(new DateInterval('PT20M')); - } - $date_start = $starttime->format('Y-m-d H:i:s'); + // If the boss only appears for an hour, the eggs most likely start to spawn 20 minutes prior to the time. + $diff = $starttime->diff($endtime); + if($diff->format('%h') == 1) { + $starttime->sub(new DateInterval('PT20M')); + } + $date_start = $starttime->format('Y-m-d H:i:s'); - $date_end = $endtime->format('Y-m-d H:i:s'); + $date_end = $endtime->format('Y-m-d H:i:s'); - $dex_id_form = explode('-',resolve_boss_name_to_ids($news['pokemon']),2); - if($prev_start != $date_start) { - $list.= CR . EMOJI_CLOCK . ' ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; - $prev_rl = ''; - } - if($prev_rl != $raid_level_id) { - $list.= '' . getTranslation($raid_level_id . 'stars') .':' . CR; - } - $list.= get_local_pokemon_name($dex_id_form[0], $dex_id_form[1]) . CR; - $prev_start = $date_start; - $prev_rl = $raid_level_id; + $dex_id_form = explode('-',resolve_boss_name_to_ids($news['pokemon']),2); + if($prev_start != $date_start) { + $list.= CR . EMOJI_CLOCK . ' ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; + $prev_rl = ''; + } + if($prev_rl != $raid_level_id) { + $list.= '' . getTranslation($raid_level_id . 'stars') .':' . CR; + } + $list.= get_local_pokemon_name($dex_id_form[0], $dex_id_form[1]) . CR; + $prev_start = $date_start; + $prev_rl = $raid_level_id; - if($count == 0) { - $count++; - $sql .= 'INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, date_start, date_end, raid_level, scheduled) VALUES '; - $sql .= '("'.$dex_id_form[0].'","'.$dex_id_form[1].'","'.$date_start.'","'.$date_end.'","'.$raid_level_id.'", 1)'; - }else { - $sql .= ',("'.$dex_id_form[0].'","'.$dex_id_form[1].'","'.$date_start.'","'.$date_end.'","'.$raid_level_id.'", 1)'; + if($count == 0) { + $count++; + $sql .= 'INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, date_start, date_end, raid_level, scheduled) VALUES '; + $sql .= '("'.$dex_id_form[0].'","'.$dex_id_form[1].'","'.$date_start.'","'.$date_end.'","'.$raid_level_id.'", 1)'; + }else { + $sql .= ',("'.$dex_id_form[0].'","'.$dex_id_form[1].'","'.$date_start.'","'.$date_end.'","'.$raid_level_id.'", 1)'; + } } } + if($count > 0) $sql.=';'; } - if($count > 0) $sql.=';'; if($return_sql) return $sql; else return $list; } From 7ee61ebabd727fe5fbd92823d44178296ebf47a3 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 9 Jul 2022 10:22:33 +0300 Subject: [PATCH 052/367] Fix duplicate bosses --- logic/resolve_raid_boss.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/logic/resolve_raid_boss.php b/logic/resolve_raid_boss.php index 405dfaea..5e68b6d7 100644 --- a/logic/resolve_raid_boss.php +++ b/logic/resolve_raid_boss.php @@ -10,11 +10,11 @@ function resolve_raid_boss($pokemon, $pokemon_form, $spawn, $raid_level) { if($pokemon == 0) { $tz_diff = tz_diff(); - $query = my_query(' SELECT pokedex_id, pokemon_form_id - FROM raid_bosses - WHERE raid_level = "' . $raid_level . '" - AND scheduled = 1 - AND convert_tz("' . $spawn . '","+00:00","'.$tz_diff.'") BETWEEN date_start AND date_end'); + $query = my_query(' SELECT DISTINCT pokedex_id, pokemon_form_id + FROM raid_bosses + WHERE raid_level = "' . $raid_level . '" + AND scheduled = 1 + AND convert_tz("' . $spawn . '","+00:00","'.$tz_diff.'") BETWEEN date_start AND date_end'); if($query->rowCount() == 1) { $row = $query->fetch(); // Return active boss From b563d7822fa523ab373fb7e075446495d238ca21 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sun, 17 Jul 2022 15:04:10 +0300 Subject: [PATCH 053/367] Execute DB upgrades more reliably, surfacing errors better In some environments a $statement->execute() without reading results or manually closing the statement can result in the statement never being executed. With a direct $dbh->exec() this is not an issue. --- core/bot/logic/sql_utils.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/bot/logic/sql_utils.php b/core/bot/logic/sql_utils.php index 327e17eb..33eeebb7 100644 --- a/core/bot/logic/sql_utils.php +++ b/core/bot/logic/sql_utils.php @@ -12,8 +12,7 @@ function run_sql_file($file) { } try { $query = file_get_contents($file); - $statement = $dbh->prepare( $query ); - $statement->execute(); + $dbh->exec( $query ); } catch (PDOException $exception) { info_log('DB upgrade failed: ' . $exception->getMessage()); From 83dc3179990a780a29007fff3d63930ffc004d67 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sun, 17 Jul 2022 15:07:47 +0300 Subject: [PATCH 054/367] Fix idempotence of v5 DB schema upgrade i.e. don't attempt to create photo_cache if it already exists. --- sql/upgrade/5.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index cbf6a3a9..a5529dbe 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -1,6 +1,6 @@ ALTER TABLE user_input CHANGE COLUMN IF EXISTS `user_id` `user_id` BIGINT(20) DEFAULT NULL AFTER `id`; -CREATE TABLE `photo_cache` (`id` varchar(100) NOT NULL, `unique_id` varchar(45) NOT NULL, `pokedex_id` int(10) DEFAULT NULL, `form_id` int(4) DEFAULT NULL, `raid_id` int(10) unsigned DEFAULT NULL, `ended` tinyint(1) DEFAULT NULL, `gym_id` int(10) unsigned DEFAULT NULL, `standalone` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`unique_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +CREATE TABLE IF NOT EXISTS `photo_cache` (`id` varchar(100) NOT NULL, `unique_id` varchar(45) NOT NULL, `pokedex_id` int(10) DEFAULT NULL, `form_id` int(4) DEFAULT NULL, `raid_id` int(10) unsigned DEFAULT NULL, `ended` tinyint(1) DEFAULT NULL, `gym_id` int(10) unsigned DEFAULT NULL, `standalone` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`unique_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); From d42cdb5492576ae4844ef98ac0123325e92b9b07 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sun, 17 Jul 2022 15:22:34 +0300 Subject: [PATCH 055/367] Also fix the other ALTER that was not idempotent. --- sql/upgrade/5.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index a5529dbe..4429e10c 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -7,4 +7,4 @@ CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, messa ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL; ALTER TABLE `raid_bosses` MODIFY `raid_level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL; -ALTER TABLE `events` ADD COLUMN `pokemon_title` TINYINT(1) NULL DEFAULT 1 AFTER `hide_raid_picture`; +ALTER TABLE `events` ADD COLUMN IF NOT EXISTS `pokemon_title` TINYINT(1) NULL DEFAULT 1 AFTER `hide_raid_picture`; From cf5c4a59d4f522d35e5b8b05149ddb3eb9050b1e Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 27 Jul 2022 21:39:08 +0300 Subject: [PATCH 056/367] fixed raid boss list formating --- logic/read_upcoming_bosses.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index 966e1c64..ac299dd0 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -12,7 +12,7 @@ function read_upcoming_bosses($return_sql = false) { $pb_timezone = new dateTimeZone('America/Phoenix'); $count = 0; - $sql = $list = $prev_start = $prev_rl = ''; + $sql = $list = $prev_start = $prev_end = $prev_rl = ''; if(isset($pb['breakingNews'])) { foreach($pb['breakingNews'] as $news) { if($news['type'] == 'RAID_TYPE_RAID') { @@ -35,7 +35,7 @@ function read_upcoming_bosses($return_sql = false) { $date_end = $endtime->format('Y-m-d H:i:s'); $dex_id_form = explode('-',resolve_boss_name_to_ids($news['pokemon']),2); - if($prev_start != $date_start) { + if($prev_start != $date_start or $prev_end != $date_end) { $list.= CR . EMOJI_CLOCK . ' ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; $prev_rl = ''; } @@ -44,6 +44,7 @@ function read_upcoming_bosses($return_sql = false) { } $list.= get_local_pokemon_name($dex_id_form[0], $dex_id_form[1]) . CR; $prev_start = $date_start; + $prev_end = $date_end; $prev_rl = $raid_level_id; if($count == 0) { From dd085f3afc9ebe729d429306595727e6ca4f91b5 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 29 Jul 2022 18:26:38 +0300 Subject: [PATCH 057/367] Added another map to interpret Pokebattler's Pokemon names to ours Should fix importing of future bosses. Might have to apply the same fix to regular pokebattler import, we'll see. --- constants.php | 5 +++++ logic/read_upcoming_bosses.php | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/constants.php b/constants.php index 69e01c13..447e759b 100644 --- a/constants.php +++ b/constants.php @@ -31,6 +31,11 @@ '8' => 'ULTRA_BEAST', ]; +$pokebattler_pokemon_map = [ + 'ZACIAN' => 'ZACIAN_HERO_FORM', + 'ZAMAZENTA' => 'ZAMAZENTA_HERO_FORM', +]; + // Limit the tiers of upcoming raid bosses imported from PokeBattler to legendary and mega $pokebattler_import_future_tiers = [5, 6, 7, 8]; diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index ac299dd0..cf5a981b 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -6,7 +6,7 @@ * @return string */ function read_upcoming_bosses($return_sql = false) { - global $pokebattler_import_future_tiers, $pokebattler_level_map; + global $pokebattler_import_future_tiers, $pokebattler_level_map, $pokebattler_pokemon_map; $link = curl_get_contents('https://fight.pokebattler.com/raids'); $pb = json_decode($link,true); @@ -34,7 +34,11 @@ function read_upcoming_bosses($return_sql = false) { $date_end = $endtime->format('Y-m-d H:i:s'); - $dex_id_form = explode('-',resolve_boss_name_to_ids($news['pokemon']),2); + $boss = $news['pokemon']; + if(in_array($news['pokemon'], array_keys($pokebattler_pokemon_map))) { + $boss = $pokebattler_pokemon_map[$news['pokemon']]; + } + $dex_id_form = explode('-',resolve_boss_name_to_ids($boss),2); if($prev_start != $date_start or $prev_end != $date_end) { $list.= CR . EMOJI_CLOCK . ' ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; $prev_rl = ''; From 0db7439c0b0ac104f7aef2c2d0f35560319d50a1 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 17 Sep 2022 20:52:45 +0300 Subject: [PATCH 058/367] Translations --- core/lang/pokemon.json | 34 ++++++++++++++++++----- core/lang/pokemon_moves.json | 52 ++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/core/lang/pokemon.json b/core/lang/pokemon.json index f32bb1c3..551858bd 100644 --- a/core/lang/pokemon.json +++ b/core/lang/pokemon.json @@ -5060,24 +5060,44 @@ "RU": "Калирекс" }, "pokemon_id_899": { - "EN": "Wyrdeer" + "EN": "Wyrdeer", + "FR": "Cerbyllin", + "DE": "Damythir", + "RU": "Вирдир" }, "pokemon_id_900": { - "EN": "Kleavor" + "EN": "Kleavor", + "FR": "Hachécateur", + "DE": "Axantor", + "RU": "Кливор" }, "pokemon_id_901": { - "EN": "Ursaluna" + "EN": "Ursaluna", + "FR": "Ursaking", + "RU": "Урсалуна" }, "pokemon_id_902": { - "EN": "Basculegion" + "EN": "Basculegion", + "FR": "Paragruel", + "DE": "Salmagnis", + "RU": "Баскулиджен" }, "pokemon_id_903": { - "EN": "Sneasler" + "EN": "Sneasler", + "FR": "Farfurex", + "DE": "Snieboss", + "RU": "Снизлер" }, "pokemon_id_904": { - "EN": "Overqwil" + "EN": "Overqwil", + "FR": "Qwilpik", + "DE": "Myriador", + "RU": "Оверквил" }, "pokemon_id_905": { - "EN": "Enamorus" + "EN": "Enamorus", + "FR": "Amovénus", + "DE": "Cupidos", + "RU": "Энаморус" } } \ No newline at end of file diff --git a/core/lang/pokemon_moves.json b/core/lang/pokemon_moves.json index cefd670c..6a623ae8 100644 --- a/core/lang/pokemon_moves.json +++ b/core/lang/pokemon_moves.json @@ -3924,5 +3924,57 @@ "IT": "Infuriaseme", "RU": "Сияние Семени", "ES": "Fogonazo" + }, + "pokemon_move_350": { + "PT-BR": "Vento de Fada", + "EN": "Fairy Wind", + "FI": "Fairy Wind", + "NL": "Fairy Wind", + "NO": "Fairy Wind", + "PL": "Fairy Wind", + "FR": "Vent Féérique", + "DE": "Feenbrise", + "IT": "Vento di Fata", + "RU": "Ветер Феи", + "ES": "Viento Feérico" + }, + "pokemon_move_356": { + "PT-BR": "Chute Duplo", + "EN": "Double Kick", + "FI": "Double Kick", + "NL": "Double Kick", + "NO": "Double Kick", + "PL": "Double Kick", + "FR": "Double Pied", + "DE": "Doppelkick", + "IT": "Doppiocalcio", + "RU": "Двойной Пинок", + "ES": "Doble Patada" + }, + "pokemon_move_370": { + "PT-BR": "Obstruir", + "EN": "Obstruct", + "FI": "Obstruct", + "NL": "Obstruct", + "NO": "Obstruct", + "PL": "Obstruct", + "FR": "Blocage", + "DE": "Abblocker", + "IT": "Sbarramento", + "RU": "Преграда", + "ES": "Obstrucción" + }, + "pokemon_move_372": { + "PT-BR": "Raio Meteórico", + "EN": "Meteor Beam", + "FI": "Meteor Beam", + "NL": "Meteor Beam", + "NO": "Meteor Beam", + "PL": "Meteor Beam", + "FR": "Laser Météore", + "DE": "Meteorstrahl", + "IT": "Raggiometeora", + "RU": "Метеоритный Луч", + "ES": "Rayo Meteórico" } } \ No newline at end of file From 8da9078c56cb57824b251ae1d16d144b945587fa Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 15 Oct 2022 06:16:46 +0300 Subject: [PATCH 059/367] Translations --- core/lang/pokemon_moves.json | 76 ++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/core/lang/pokemon_moves.json b/core/lang/pokemon_moves.json index 6a623ae8..71657405 100644 --- a/core/lang/pokemon_moves.json +++ b/core/lang/pokemon_moves.json @@ -3704,6 +3704,19 @@ "RU": "Танец с Перьями", "ES": "Danza Pluma" }, + "pokemon_move_350": { + "PT-BR": "Vento de Fada", + "EN": "Fairy Wind", + "FI": "Fairy Wind", + "NL": "Fairy Wind", + "NO": "Fairy Wind", + "PL": "Fairy Wind", + "FR": "Vent Féérique", + "DE": "Feenbrise", + "IT": "Vento di Fata", + "RU": "Ветер Феи", + "ES": "Viento Feérico" + }, "pokemon_move_352": { "PT-BR": "Esfera Climática", "EN": "Weather Ball", @@ -3756,6 +3769,19 @@ "RU": "Гиперпространственная Дыра", "ES": "Paso Dimensional" }, + "pokemon_move_356": { + "PT-BR": "Chute Duplo", + "EN": "Double Kick", + "FI": "Double Kick", + "NL": "Double Kick", + "NO": "Double Kick", + "PL": "Double Kick", + "FR": "Double Pied", + "DE": "Doppelkick", + "IT": "Doppiocalcio", + "RU": "Двойной Пинок", + "ES": "Doble Patada" + }, "pokemon_move_357": { "PT-BR": "Folha Mágica", "EN": "Magical Leaf", @@ -3925,32 +3951,6 @@ "RU": "Сияние Семени", "ES": "Fogonazo" }, - "pokemon_move_350": { - "PT-BR": "Vento de Fada", - "EN": "Fairy Wind", - "FI": "Fairy Wind", - "NL": "Fairy Wind", - "NO": "Fairy Wind", - "PL": "Fairy Wind", - "FR": "Vent Féérique", - "DE": "Feenbrise", - "IT": "Vento di Fata", - "RU": "Ветер Феи", - "ES": "Viento Feérico" - }, - "pokemon_move_356": { - "PT-BR": "Chute Duplo", - "EN": "Double Kick", - "FI": "Double Kick", - "NL": "Double Kick", - "NO": "Double Kick", - "PL": "Double Kick", - "FR": "Double Pied", - "DE": "Doppelkick", - "IT": "Doppiocalcio", - "RU": "Двойной Пинок", - "ES": "Doble Patada" - }, "pokemon_move_370": { "PT-BR": "Obstruir", "EN": "Obstruct", @@ -3976,5 +3976,29 @@ "IT": "Raggiometeora", "RU": "Метеоритный Луч", "ES": "Rayo Meteórico" + }, + "pokemon_move_371": { + "PT-BR": "Força das Sombras", + "EN": "Shadow Force", + "FI": "Shadow Force", + "NL": "Shadow Force", + "NO": "Shadow Force", + "PL": "Shadow Force", + "FR": "Revenant", + "DE": "Schemenkraft", + "RU": "Сумеречная Сила", + "ES": "Golpe Umbrío" + }, + "pokemon_move_376": { + "PT-BR": "Poltergeist", + "EN": "Poltergeist", + "FI": "Poltergeist", + "NL": "Poltergeist", + "NO": "Poltergeist", + "PL": "Poltergeist", + "FR": "Esprit Frappeur", + "DE": "Poltergeist", + "RU": "Полтергейст", + "ES": "Poltergeist" } } \ No newline at end of file From 16e9e236f4bd375e5086e65b82c26b0770c71f2a Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 15 Oct 2022 06:19:47 +0300 Subject: [PATCH 060/367] Elite raid support - Database update - Relevant constants and translations - Date selection for elite raid start time - New hint to raid polls for raids that don't allow remote participants - Hide remote participation vote keys for raid levels 4 and 9 --- config/defaults-config.json | 5 +++ constants.php | 6 ++- images/raid_eggs/pokemon_icon_9999_00.png | Bin 0 -> 22837 bytes lang/language.json | 52 ++++++++++++++++++++++ logic/keys_vote.php | 47 +++++++++++-------- logic/show_raid_poll.php | 11 ++++- mods/edit_starttime.php | 7 +-- mods/edit_time.php | 15 +++++-- sql/pokemon-raid-bot.sql | 4 +- sql/upgrade/5.sql | 4 +- 10 files changed, 118 insertions(+), 33 deletions(-) create mode 100644 images/raid_eggs/pokemon_icon_9999_00.png diff --git a/config/defaults-config.json b/config/defaults-config.json index 0d56f597..44e74ac4 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -38,7 +38,9 @@ "RAID_VIA_LOCATION": true, "RAID_VIA_LOCATION_FUNCTION": "create", "RAID_EGG_DURATION":"60", + "RAID_EGG_DURATION_ELITE":"1440", "RAID_DURATION":"45", + "RAID_DURATION_ELITE":"30", "RAID_DURATION_CLOCK_STYLE": true, "RAID_CUSTOM_GYM_LETTERS":"", "RAID_EXCLUDE_EXRAID_DUPLICATION": true, @@ -100,6 +102,7 @@ "TRAINER_CHATS":"", "SHARE_CHATS":"", "SHARE_CHATS_LEVEL_X":"", + "SHARE_CHATS_LEVEL_9":"", "SHARE_CHATS_LEVEL_8":"", "SHARE_CHATS_LEVEL_7":"", "SHARE_CHATS_LEVEL_6":"", @@ -111,6 +114,7 @@ "WEBHOOK_CREATOR":"bot_or_user_id", "WEBHOOK_CREATE_ONLY": false, "WEBHOOK_CHATS_ALL_LEVELS":"", + "WEBHOOK_CHATS_LEVEL_9":"", "WEBHOOK_CHATS_LEVEL_8":"", "WEBHOOK_CHATS_LEVEL_7":"", "WEBHOOK_CHATS_LEVEL_6":"", @@ -119,6 +123,7 @@ "WEBHOOK_CHATS_LEVEL_3":"", "WEBHOOK_CHATS_LEVEL_2":"", "WEBHOOK_CHATS_LEVEL_1":"", + "WEBHOOK_CHATS_LEVEL_9_0":"", "WEBHOOK_CHATS_LEVEL_8_0":"", "WEBHOOK_CHATS_LEVEL_7_0":"", "WEBHOOK_CHATS_LEVEL_6_0":"", diff --git a/constants.php b/constants.php index 447e759b..a9c0b28b 100644 --- a/constants.php +++ b/constants.php @@ -3,10 +3,11 @@ define('PORTAL_IMAGES_PATH', IMAGES_PATH . '/gyms'); // raid levels constant -define('RAID_LEVEL_ALL', 'X8765431'); +define('RAID_LEVEL_ALL', 'X98765431'); // Raid eggs. $eggs = array( + '9999', // Level 9 / Elite raid '9998', // Level 8 / Ultra beast '9997', // Level 7 / Legendary Mega '9996', // Level 6 / Mega @@ -17,6 +18,9 @@ '9991' // Level 1 ); +// Raid levels limited to local players only +define('RAID_LEVEL_LOCAL_ONLY', [4, 9]); + // Levels available for import at PokeBattler $pokebattler_levels = array('8', '7', '6', '5', '4', '3', '1'); diff --git a/images/raid_eggs/pokemon_icon_9999_00.png b/images/raid_eggs/pokemon_icon_9999_00.png new file mode 100644 index 0000000000000000000000000000000000000000..5146a1e2324b84c941638464c264c077f1e5b45e GIT binary patch literal 22837 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 $hide_buttons_pokemon = explode(',', $config->RAID_POLL_HIDE_BUTTONS_POKEMON); @@ -61,28 +64,34 @@ function keys_vote($raid) 'text' => '+ ' . EMOJI_IN_PERSON, 'callback_data' => $raid['id'] . ':vote_extra:in_person' ]; - $buttons_extra_alien = [ - 'text' => '+ ' . EMOJI_ALIEN, - 'callback_data' => $raid['id'] . ':vote_extra:alien' - ]; - // Can invite key - $buttons_can_inv = [ - 'text' => EMOJI_CAN_INVITE, - 'callback_data' => $raid['id'] . ':vote_can_invite:0' - ]; + // Show buttons regarding remote participation only if raid level allows it + if(!$raid_local_only) { + $buttons_extra_alien = [ + 'text' => '+ ' . EMOJI_ALIEN, + 'callback_data' => $raid['id'] . ':vote_extra:alien' + ]; - // Remote Raid Pass key - $buttons_remote = [ - 'text' => EMOJI_REMOTE, - 'callback_data' => $raid['id'] . ':vote_remote:0' - ]; + // Can invite key + $buttons_can_inv = [ + 'text' => EMOJI_CAN_INVITE, + 'callback_data' => $raid['id'] . ':vote_can_invite:0' + ]; - // Want invite key - $buttons_inv_plz = [ - 'text' => EMOJI_WANT_INVITE, - 'callback_data' => $raid['id'] . ':vote_want_invite:0' - ]; + // Remote Raid Pass key + $buttons_remote = [ + 'text' => EMOJI_REMOTE, + 'callback_data' => $raid['id'] . ':vote_remote:0' + ]; + + // Want invite key + $buttons_inv_plz = [ + 'text' => EMOJI_WANT_INVITE, + 'callback_data' => $raid['id'] . ':vote_want_invite:0' + ]; + }else { + $buttons_extra_alien = $buttons_can_inv = $buttons_remote = $buttons_inv_plz = []; + } // Team and level keys. $buttons_teamlvl = [ diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index c59d1cde..9a6064d8 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -21,6 +21,9 @@ function show_raid_poll($raid, $inline = false) // Get raid level $raid_level = $raid['level']; + // Are remote players allowed for this raid? + $raid_local_only = in_array($raid_level, RAID_LEVEL_LOCAL_ONLY); + if($raid['event_name'] != NULL && $raid['event_name'] != "") { $msg = raid_poll_message($msg, "".$raid['event_name']."".CR, true); } @@ -303,6 +306,10 @@ function show_raid_poll($raid, $inline = false) if($raid['event'] == EVENT_ID_EX) { $msg = raid_poll_message($msg, CR . EMOJI_WARN . ' ' . getPublicTranslation('exraid_pass') . ' ' . EMOJI_WARN . CR); } + // Add hint that remote participation is not possible + if($raid_local_only) { + $msg = raid_poll_message($msg, CR . EMOJI_WARN . SP . getPublicTranslation('no_remote_parcipants') . CR); + } // Add event description if($raid['event_description'] != NULL && $raid['event_description'] != "") { @@ -321,12 +328,12 @@ function show_raid_poll($raid, $inline = false) $previous_pokemon = 'FIRST_RUN'; // Add hint for remote attendances. - if($cnt_remote > 0 || $cnt_want_invite > 0 || $cnt_extra_alien > 0) { + if(!$raid_local_only && ($cnt_remote > 0 || $cnt_want_invite > 0 || $cnt_extra_alien > 0)) { $remote_max_msg = str_replace('REMOTE_MAX_USERS', $config->RAID_REMOTEPASS_USERS_LIMIT, getPublicTranslation('remote_participants_max')); $msg = raid_poll_message($msg, CR . ($cnt_remote > 0 ? EMOJI_REMOTE : '') . ($cnt_extra_alien > 0 ? EMOJI_ALIEN : '') . ($cnt_want_invite > 0 ? EMOJI_WANT_INVITE : '') . SP . getPublicTranslation('remote_participants') . SP . '' . $remote_max_msg . '' . CR); } // Add hint for attendees that only invite. - if($cnt_can_invite > 0) { + if(!$raid_local_only && $cnt_can_invite > 0) { $msg = raid_poll_message($msg, CR . EMOJI_CAN_INVITE . SP . getPublicTranslation('alert_can_invite') . CR); } // Add start raid message diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index 8de3c303..c9e439e3 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -26,7 +26,7 @@ $gym_id = explode(',', $data['id'])[0]; // Are we creating an event? -if($event_id != 'N') { +if($event_id != 'N' or $raid_level == 9) { // Init empty keys array. $keys = []; @@ -35,8 +35,9 @@ $tz = $config->TIMEZONE; $today = new DateTimeImmutable('now', new DateTimeZone($tz)); - // Next 14 days. - for ($d = 0; $d <= 14; $d = $d + 1) { + // Create date buttons. Two days for Elite Raids, 15 days for EX raids. + $days = ($raid_level == 9) ? 1 : 14; + for ($d = 0; $d <= $days; $d++) { // Add day to today. $today_plus_d = $today->add(new DateInterval("P".$d."D")); diff --git a/mods/edit_time.php b/mods/edit_time.php index a6bd203b..b2d5b3d8 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -63,17 +63,23 @@ debug_log('Formatting the raid time properly now.'); $arg_time = str_replace('-', ':', $starttime); - // Event Raid or normal/EX raid? - if($event_id == 'X') { + // Ex and elite raids + if($event_id == 'X' or $raid_level == 9) { debug_log('Ex-Raid time :D ... Setting raid date to ' . $arg_time); $start_date_time = $arg_time; - $duration = $config->RAID_DURATION; + $duration = ($raid_level == 9) ? $config->RAID_DURATION_ELITE : $config->RAID_DURATION; + $egg_duration = ($raid_level == 9) ? $config->RAID_EGG_DURATION_ELITE : $config->RAID_EGG_DURATION; + + // Event raids }elseif($event_id != 'N') { debug_log('Event time :D ... Setting raid date to ' . $arg_time); $start_date_time = $arg_time; $query = my_query("SELECT raid_duration FROM events WHERE id = '{$event_id}' LIMIT 1"); $result = $query->fetch(); $duration = $result['raid_duration']; + $egg_duration = $config->RAID_EGG_DURATION; + + // Normal raids } else { // Current date $current_date = date('Y-m-d', strtotime('now')); @@ -82,6 +88,7 @@ $start_date_time = $current_date . ' ' . $arg_time . ':00'; debug_log('Received the following time for the raid: ' . $start_date_time); $duration = $config->RAID_DURATION; + $egg_duration = $config->RAID_EGG_DURATION; } // Check for duplicate raid @@ -112,7 +119,7 @@ pokemon = '{$pokemon_id_formid['pokedex_id']}', pokemon_form = '{$pokemon_id_formid['pokemon_form_id']}', start_time = '{$start_date_time}', - spawn = DATE_SUB(start_time, INTERVAL ".$config->RAID_EGG_DURATION." MINUTE), + spawn = DATE_SUB(start_time, INTERVAL ".$egg_duration." MINUTE), end_time = DATE_ADD(start_time, INTERVAL {$duration} MINUTE), gym_id = '{$gym_id}', level = '{$raid_level}', diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 4fedbe12..eb30c025 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -101,7 +101,7 @@ CREATE TABLE `raid_bosses` ( `pokemon_form_id` int(4) DEFAULT NULL, `date_start` datetime NOT NULL DEFAULT '1970-01-01 00:00:01', `date_end` datetime NOT NULL DEFAULT '2038-01-19 03:14:07', - `raid_level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL, + `raid_level` enum('1','2','3','4','5','6','7','8','9','X') DEFAULT NULL, `scheduled` TINYINT(1) NULL DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -115,7 +115,7 @@ CREATE TABLE `raids` ( `end_time` datetime DEFAULT NULL, `gym_team` enum('mystic','valor','instinct') DEFAULT NULL, `gym_id` int(10) unsigned NOT NULL, - `level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL, + `level` enum('1','2','3','4','5','6','7','8','9','X') DEFAULT NULL, `move1` varchar(255) DEFAULT NULL, `move2` varchar(255) DEFAULT NULL, `gender` varchar(255) DEFAULT NULL, diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index 4429e10c..32f2c968 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS `photo_cache` (`id` varchar(100) NOT NULL, `unique_id ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); -ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL; -ALTER TABLE `raid_bosses` MODIFY `raid_level` enum('1','2','3','4','5','6','7','8','X') DEFAULT NULL; +ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','8','9','X') DEFAULT NULL; +ALTER TABLE `raid_bosses` MODIFY `raid_level` enum('1','2','3','4','5','6','7','8','9','X') DEFAULT NULL; ALTER TABLE `events` ADD COLUMN IF NOT EXISTS `pokemon_title` TINYINT(1) NULL DEFAULT 1 AFTER `hide_raid_picture`; From ecd2a52c617c586d1cafa6113bccd506cb54c1d2 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sat, 15 Oct 2022 18:52:35 +0300 Subject: [PATCH 061/367] Improve debug logging for raid_from_webhook duplication checks --- commands/raid_from_webhook.php | 4 +++- logic/active_raid_duplication_check.php | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index c3038c48..f24b4382 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -195,6 +195,7 @@ function isPointInsidePolygon($point, $vertices) { // Raid exists, do updates! if ( $raid_id > 0 ) { + debug_log($gym_name, 'Raid already in DB for gym:'); // Update database try { $query = ' @@ -233,11 +234,12 @@ function isPointInsidePolygon($point, $vertices) { $send_updates = true; debug_log($raid_id, 'Raid updated:'); }else { - debug_log($gym_name,'Nothing was updated, moving on:'); + debug_log($gym_name,'Nothing had changed for raid at gym:'); continue; } }else { // Create Raid and send messages + debug_log($gym_name, 'Raid not in DB yet, creating for gym:'); try { $query = ' INSERT INTO raids (pokemon, pokemon_form, user_id, spawn, start_time, end_time, gym_team, gym_id, level, move1, move2, gender, costume) diff --git a/logic/active_raid_duplication_check.php b/logic/active_raid_duplication_check.php index 9f6ee6dc..9a2b5a46 100644 --- a/logic/active_raid_duplication_check.php +++ b/logic/active_raid_duplication_check.php @@ -20,9 +20,11 @@ function active_raid_duplication_check($gym_id) ); $active = 0; while($raid = $rs->fetch()) { + # TODO: Should document why this check happens / the logic if($config->RAID_EXCLUDE_EXRAID_DUPLICATION && $raid['event'] == EVENT_ID_EX) { continue; } + # TODO: Should document why this check happens / the logic if($config->RAID_EXCLUDE_EVENT_DUPLICATION && $raid['event'] !== NULL && $raid['event'] != EVENT_ID_EX) { continue; } From c7167294547d4a065c7e71c0084f91e6d40d0b8d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 16 Oct 2022 09:21:01 +0300 Subject: [PATCH 062/367] Changed access level from ex-raid to create so normal users can create elite raids --- mods/edit_date.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/edit_date.php b/mods/edit_date.php index 90acab81..88cb52e6 100644 --- a/mods/edit_date.php +++ b/mods/edit_date.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'ex-raids'); +bot_access_check($update, 'create'); // Set the id. $id = $data['id']; From a584606dcdb794a1511f41a86e63907f9f7871ad Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 16 Oct 2022 13:14:03 +0300 Subject: [PATCH 063/367] Fixed raid boss name display logic --- logic/show_raid_poll.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index 9a6064d8..3c3f22e7 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -78,7 +78,7 @@ function show_raid_poll($raid, $inline = false) } // Display raid boss name and boss' weather unless hidden for a specific event - if($raid['event_pokemon_title'] != 0) { + if($raid['event_pokemon_title'] != 0 or $raid['event_pokemon_title'] == NULL) { // Display raid boss name. if($raid['event_pokemon_title'] == 1) $title = getPublicTranslation('raid_boss'); elseif($raid['event_pokemon_title'] == 2) $title = getPublicTranslation('featured_pokemon'); From 4ce710c2eb21acb5f1597909896845410f1d61ce Mon Sep 17 00:00:00 2001 From: klablabla <30940278+klablabla@users.noreply.github.com> Date: Sun, 16 Oct 2022 22:07:32 +0200 Subject: [PATCH 064/367] Added NL translation Added NL translation. --- lang/language.json | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lang/language.json b/lang/language.json index f49fa2af..1c2fb08d 100644 --- a/lang/language.json +++ b/lang/language.json @@ -26,7 +26,7 @@ "ES": "Incursión EX" }, "9stars": { - "NL": "TRANSLATE", + "NL": "Elite raid", "DE": "TRANSLATE", "EN": "Elite raid", "IT": "TRANSLATE", @@ -39,7 +39,7 @@ "ES": "TRANSLATE" }, "9stars_short": { - "NL": "TRANSLATE", + "NL": "Elite", "DE": "TRANSLATE", "EN": "Elite", "IT": "TRANSLATE", @@ -52,7 +52,7 @@ "ES": "TRANSLATE" }, "8stars": { - "NL": "TRANSLATE", + "NL": "Ultra Wormhole", "DE": "Ultrapforte", "EN": "Ultra Wormhole", "IT": "Ultravarco", @@ -65,7 +65,7 @@ "ES": "Ultraumbral" }, "8stars_short": { - "NL": "TRANSLATE", + "NL": "Ultra", "DE": "TRANSLATE", "EN": "Ultra", "IT": "TRANSLATE", @@ -208,7 +208,7 @@ "ES": "Desactivado" }, "egg_9": { - "NL": "TRANSLATE", + "NL": "Elite raid egg", "DE": "TRANSLATE", "EN": "Elite raid egg", "IT": "TRANSLATE", @@ -221,7 +221,7 @@ "ES": "TRANSLATE" }, "egg_8": { - "NL": "TRANSLATE", + "NL": "Ultra Wormhole", "DE": "Ultrapforte", "EN": "Ultra Wormhole", "IT": "Ultravarco", @@ -689,7 +689,7 @@ "ES": "PARTICIPACIÓN SOLO ES POSIBLE CON PASE EX" }, "no_remote_parcipants": { - "NL": "TRANSLATE", + "NL": "Deze raid kan alleen lokaal gespeeld worden!", "DE": "TRANSLATE", "EN": "This raid can not be participated using a Remote Raid Pass!", "IT": "TRANSLATE", @@ -1846,7 +1846,7 @@ "ES": "¡Error! ¡Gimnasio no encontrado!" }, "gym_coordinates": { - "NL": "TRANSLATE", + "NL": "Coordinaten", "DE": "TRANSLATE", "EN": "Coordinates", "IT": "TRANSLATE", @@ -1859,7 +1859,7 @@ "ES": "TRANSLATE" }, "gym_edit_coordinates": { - "NL": "TRANSLATE", + "NL": "Wijzig coordinaten", "DE": "TRANSLATE", "EN": "Edit coordinates", "IT": "TRANSLATE", @@ -1911,7 +1911,7 @@ "ES": "¡Error! Envía las coordenadas en el siguiente formato: latitud,longitud" }, "gym_gps_instructions": { - "NL": "TRANSLATE", + "NL": "Stuur me de gym coordinaten in de volgende format: Latitude,Longitude", "DE": "TRANSLATE", "EN": "Send me the gym coordinates in the following format: Latitude,Longitude", "IT": "TRANSLATE", @@ -1963,7 +1963,7 @@ "ES": "¡Se agregó con éxito el gimnasio!" }, "gym_create": { - "NL": "TRANSLATE", + "NL": "Maak een nieuwe gym", "DE": "TRANSLATE", "EN": "Create a new gym", "IT": "TRANSLATE", @@ -2054,7 +2054,7 @@ "ES": "Ver detalles del gimnasio" }, "gym_edit_text_too_long": { - "NL": "TRANSLATE", + "NL": "Error! niet meer dan 255 tekens!", "DE": "TRANSLATE", "EN": "Error! The maximum text length is 255 characters!", "IT": "TRANSLATE", @@ -2067,7 +2067,7 @@ "ES": "TRANSLATE" }, "gym_add_edit_note": { - "NL": "TRANSLATE", + "NL": "gym note", "DE": "TRANSLATE", "EN": "gym note", "IT": "TRANSLATE", @@ -2080,7 +2080,7 @@ "ES": "TRANSLATE" }, "gym_note_instructions": { - "NL": "TRANSLATE", + "NL": "Stuur me een nieuwe gym notitie (maximaal 255 tekens):", "DE": "TRANSLATE", "EN": "Send me the new gym note (max 255 characters):", "IT": "TRANSLATE", @@ -2093,7 +2093,7 @@ "ES": "TRANSLATE" }, "gym_address": { - "NL": "TRANSLATE", + "NL": "Gym adres", "DE": "TRANSLATE", "EN": "gym address", "IT": "TRANSLATE", @@ -2106,7 +2106,7 @@ "ES": "TRANSLATE" }, "gym_address_instructions": { - "NL": "TRANSLATE", + "NL": "Stuur me het nieuwe gym adres:", "DE": "TRANSLATE", "EN": "Send me the new gym address:", "IT": "TRANSLATE", @@ -2158,7 +2158,7 @@ "ES": "Incursión guardada:" }, "featured_pokemon": { - "NL": "TRANSLATE", + "NL": "Pokemon", "DE": "TRANSLATE", "EN": "Featured Pokemon", "IT": "TRANSLATE", @@ -3094,7 +3094,7 @@ "ES": "Para obtener la identificación y más detalles del gimnasio, usa el comando /gym." }, "gym_name_edit": { - "NL": "TRANSLATE", + "NL": "Gym naam aanpassen", "DE": "TRANSLATE", "EN": "Edit gym name", "IT": "TRANSLATE", @@ -3107,7 +3107,7 @@ "ES": "TRANSLATE" }, "gym_name_instructions": { - "NL": "TRANSLATE", + "NL": "Stuur me de gym naam:", "DE": "TRANSLATE", "EN": "Send me the gym name:", "IT": "TRANSLATE", From 79f293f77ac0fc93c875f5f64046ef2ebba071a4 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Mon, 17 Oct 2022 13:40:11 +0300 Subject: [PATCH 065/367] Drop non-repeatable 2->3 sql schema upgrade for the raid_bosses table --- sql/upgrade/3.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/upgrade/3.sql b/sql/upgrade/3.sql index b3a3b6b8..e16145ea 100644 --- a/sql/upgrade/3.sql +++ b/sql/upgrade/3.sql @@ -12,7 +12,6 @@ ADD COLUMN IF NOT EXISTS `event` int(3) unsigned DEFAULT NULL AFTER `gender`, ADD COLUMN IF NOT EXISTS `event_note` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL AFTER `event`; CREATE TABLE IF NOT EXISTS `raid_bosses` (`id` int(11) NOT NULL AUTO_INCREMENT,`pokedex_id` int(10) DEFAULT NULL,`pokemon_form_id` int(4) DEFAULT NULL,`date_start` datetime NOT NULL DEFAULT '1970-01-01 00:00:01',`date_end` datetime NOT NULL DEFAULT '2038-01-19 03:14:07',`raid_level` enum('1','2','3','4','5','6','X') DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -INSERT INTO `raid_bosses` (`pokedex_id`,`pokemon_form_id`,`raid_level`) SELECT `pokedex_id`,`pokemon_form_id`,`raid_level` FROM pokemon WHERE raid_level != '0'; ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `trainername` varchar(200) CHARACTER SET utf8mb4 DEFAULT NULL AFTER `name`, From e331a01373eb9f3814dfd3c96c454126e4bff694 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Mon, 17 Oct 2022 19:08:28 +0300 Subject: [PATCH 066/367] Throw an error if all default config files are missing. This is a decent indicator that someone has mounted over the entire `config` dir or manually removed the defaults values. Both will cause weird failures if done unintentionally. --- core/bot/config.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/bot/config.php b/core/bot/config.php index ecbfc1d6..348c425d 100644 --- a/core/bot/config.php +++ b/core/bot/config.php @@ -58,6 +58,9 @@ function migrate_config($config, $file){ function build_config() { // Get default config files without their full path, e.g. 'defaults-config.json' $default_configs = str_replace(CONFIG_PATH . '/', '', glob(CONFIG_PATH . '/defaults-*.json')); + if(!$default_configs){ + error_log('No config defaults found, make sure you have not destroyed config/defaults-config.json. Things will break unless your custom config sets every possible option.'); + } // Collection point for individual configfile arrays, will eventually be converted to a json object $config = Array(); From 59ba7adc797da75b81b6a5cbe6d66014ca177059 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 18 Oct 2022 17:35:17 +0300 Subject: [PATCH 067/367] Fetch protos from another source --- mods/getdb.php | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 7a9dbfb3..a983907c 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -1,5 +1,5 @@ = $data_start_line) { + $data = explode(':', $line, 2); // End of pokemon data, no need to loop further - if(trim($data[0]) == '}') { + if(trim($data[0]) == ']') { $data_array = false; + $data_start_line = 0; if(count($form_ids) > 0 && count($costume) > 0) { // We found what we needed so we can stop looping through proto file and exit break; } - }else if(count($data) == 2) { - ${$data_array}[trim($data[0])] = trim($data[1]); + continue; + } + $value = explode('"', $data[1]); + if(strlen($value[1]) > 0) { + ${$data_array}[trim($value[1])] = trim($data[0]); } }else { - if($line == 'enum Costume {') { + if($line == 'extension PokemonDisplayProto.Costume: SwiftProtobuf._ProtoNameProviding {') { $data_array = 'costume'; + $data_start_line = $i+2; } - if($line == 'enum Form {') { + if($line == 'extension PokemonDisplayProto.Form: SwiftProtobuf._ProtoNameProviding {') { $data_array = 'form_ids'; + $data_start_line = $i+2; } } } From 1666184484b243464a428ca0273a4debc2fcd036 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 19 Oct 2022 17:12:42 +0300 Subject: [PATCH 068/367] Do nothing if user votes for time they already voted --- mods/vote_time.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mods/vote_time.php b/mods/vote_time.php index 69fafdf4..1d58c49b 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -27,7 +27,7 @@ if($count_att > 0){ $rs = my_query( " - SELECT user_id, remote, (1 + extra_in_person + extra_alien) as user_count + SELECT user_id, remote, attend_time, (1 + extra_in_person + extra_alien) as user_count FROM attendance WHERE raid_id = {$data['id']} AND user_id = {$update['callback_query']['from']['id']} @@ -63,6 +63,13 @@ $now = $now->format('Y-m-d H:i') . ':00'; } +// Exit if user is voting for the same time again +if(is_array($answer) && array_key_exists('attend_time', $answer) && $attend_time_save == $answer['attend_time']) { + answerCallbackQuery($update['callback_query']['id'], 'OK'); + $dbh = null; + exit(); +} + // Vote time in the future or Raid anytime? if($vote_time == 0 || $now <= $attend_time_compare) { // If user is attending remotely, get the number of remote users already attending From 0061ff437083f21c9971e0ff54e16d6a02114e2e Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 21 Oct 2022 15:14:44 +0300 Subject: [PATCH 069/367] Support elite raids in Pokebattler import --- constants.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/constants.php b/constants.php index a9c0b28b..debab865 100644 --- a/constants.php +++ b/constants.php @@ -22,7 +22,7 @@ define('RAID_LEVEL_LOCAL_ONLY', [4, 9]); // Levels available for import at PokeBattler -$pokebattler_levels = array('8', '7', '6', '5', '4', '3', '1'); +$pokebattler_levels = array('9', '8', '7', '6', '5', '4', '3', '1'); // Map our raid levels to tier names PokeBattler uses $pokebattler_level_map = [ @@ -33,6 +33,7 @@ '6' => 'MEGA', '7' => 'MEGA_5', '8' => 'ULTRA_BEAST', + '9' => 'ELITE', ]; $pokebattler_pokemon_map = [ @@ -41,7 +42,7 @@ ]; // Limit the tiers of upcoming raid bosses imported from PokeBattler to legendary and mega -$pokebattler_import_future_tiers = [5, 6, 7, 8]; +$pokebattler_import_future_tiers = [5, 6, 7, 8, 9]; // Value used for denoting anytime attendance define('ANYTIME', '1970-01-01 00:00:00'); From 3a4bcf6a3b2a644fb60db3d13287284065e98210 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sat, 15 Oct 2022 20:10:45 +0300 Subject: [PATCH 070/367] Make getdb standalone capable in a pinch with direct includes --- core/bot/logic/sql_utils.php | 1 + mods/getdb.php | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/core/bot/logic/sql_utils.php b/core/bot/logic/sql_utils.php index 33eeebb7..74bad175 100644 --- a/core/bot/logic/sql_utils.php +++ b/core/bot/logic/sql_utils.php @@ -34,6 +34,7 @@ function my_query($query, $binds=null) { global $dbh; global $config; + require_once(CORE_BOT_PATH . '/logic/debug.php'); try { $stmt = $dbh->prepare($query); diff --git a/mods/getdb.php b/mods/getdb.php index a983907c..9dc4248c 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -1,4 +1,12 @@ Date: Sat, 15 Oct 2022 20:49:07 +0300 Subject: [PATCH 071/367] Info log getdb results if no callback is set. --- mods/getdb.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 9dc4248c..9040972b 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -133,6 +133,8 @@ // Exit. $dbh = null; exit(); +} else { + info_log($msg); } function calculate_cps($base_stats) { @@ -377,5 +379,3 @@ function getProtoURL() { } return $url; } - -?> From e7c3b82f78a0189d5a6205e18f9aa053d1b33220 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sat, 22 Oct 2022 14:39:05 +0300 Subject: [PATCH 072/367] Ensure log directories exist. Otherwise it can be very confusing if logs can't be created. It's still very possible the log dir creation fails due to a lack of permissions, but at least we try! If APCu is not available some cycles are wasted on the check, so if that's a thing you care about, enable APCu in your PHP installation. Official Docker images enable it. --- core/bot/is_init.php | 5 +++++ core/bot/logic/debug.php | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/core/bot/is_init.php b/core/bot/is_init.php index baa4ce5b..f74fe7af 100644 --- a/core/bot/is_init.php +++ b/core/bot/is_init.php @@ -3,6 +3,7 @@ /* If we're able to, detect the first time this PHP context is initialized. * - **Optional** QoL things can be gated to be run only on this init round. * - Use IS_INIT to gate those things. + * - **Mandatory** code that should get run, but ideally only once should be gated by IS_INIT_OR_WHATEVER instead. * */ @@ -10,10 +11,14 @@ if (!apcu_exists($namespace)){ apcu_store($namespace, time()); define('IS_INIT', true); + define('IS_INIT_OR_WHATEVER', true); } else { define('IS_INIT', false); + define('IS_INIT_OR_WHATEVER', false); } } else { // If APCu becomes more widely used in the codebase we could flip the default to be the other way around eventually. define('IS_INIT', false); + // In the meanwhile code that should be run anyway, but can be optimized away with APCu should be gated by this. + define('IS_INIT_OR_WHATEVER', true); } diff --git a/core/bot/logic/debug.php b/core/bot/logic/debug.php index af5e4b1f..caa1e6e7 100644 --- a/core/bot/logic/debug.php +++ b/core/bot/logic/debug.php @@ -1,4 +1,35 @@ DEBUG_LOGFILE, + $config->LOGGING_INFO_LOGFILE, + $config->DEBUG_LOGFILE, + $config->DEBUG_INCOMING_LOGFILE, + $config->DEBUG_SQL_LOGFILE, + $config->CLEANUP_LOGFILE, + ]; + + # Collect unique paths that house logfiles + $paths = []; + foreach($logfiles as $logfile){ + $dirname = pathinfo($logfile, PATHINFO_DIRNAME); + if(!in_array($dirname, $paths)){ + $paths[] = $dirname; + } + } + + # Create the necessary paths + foreach($paths as $path){ + if (!file_exists($path)) { + mkdir($path, 770, true); + } + } +} /** * Write any log level. * @param $val From cc561a518e901fde3de28e4aa3a6719c9bc12300 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 22 Oct 2022 22:55:47 +0300 Subject: [PATCH 073/367] Refactored user access check Moved access checking logic into a class and cleaned up the code a bit. --- commands/delete.php | 4 +- commands/exreport.php | 2 +- commands/friendsearch.php | 2 +- commands/gym.php | 4 +- commands/gymname.php | 2 +- commands/help.php | 12 +- commands/history.php | 2 +- commands/list.php | 4 +- commands/listall.php | 2 +- commands/overview.php | 2 +- commands/pokedex.php | 2 +- commands/pokemon.php | 2 +- commands/start.php | 6 +- commands/trainer.php | 6 +- commands/tutorial.php | 2 +- core/bot/logic.php | 1 - core/bot/logic/bot_access_check.php | 277 ---------------------------- core/bot/logic/key_util.php | 4 +- core/bot/requirements.php | 3 + core/bot/user.php | 179 ++++++++++++++++++ core/commands/get.php | 2 +- core/commands/set.php | 2 +- index.php | 4 + logic/edit_gym_keys.php | 11 +- logic/raid_access_check.php | 9 +- mods/bot_lang.php | 2 +- mods/code.php | 2 +- mods/code_start.php | 2 +- mods/delete_scheduled_entry.php | 2 +- mods/edit_date.php | 2 +- mods/edit_event.php | 2 +- mods/edit_event_raidlevel.php | 4 +- mods/edit_pokemon.php | 2 +- mods/edit_raidlevel.php | 6 +- mods/edit_save.php | 4 +- mods/edit_starttime.php | 2 +- mods/edit_time.php | 2 +- mods/gym_create.php | 2 +- mods/gym_delete.php | 2 +- mods/gym_details.php | 2 +- mods/gym_edit_details.php | 2 +- mods/gym_hidden_letter.php | 4 +- mods/gym_letter.php | 4 +- mods/history.php | 2 +- mods/history_gyms.php | 2 +- mods/history_raid.php | 2 +- mods/history_raids.php | 2 +- mods/import_future_bosses.php | 2 +- mods/import_shinyinfo.php | 2 +- mods/importal.php | 2 +- mods/list_by_gym.php | 2 +- mods/list_by_gym_letter.php | 2 +- mods/list_raid.php | 2 +- mods/listall.php | 2 +- mods/overview_delete.php | 2 +- mods/overview_share.php | 2 +- mods/pogoinfo.php | 2 +- mods/pokebattler.php | 2 +- mods/pokedex.php | 2 +- mods/pokedex_disable_raids.php | 2 +- mods/pokedex_edit_pokemon.php | 2 +- mods/pokedex_import.php | 2 +- mods/pokedex_list_raids.php | 2 +- mods/pokedex_set_cp.php | 2 +- mods/pokedex_set_raid_level.php | 2 +- mods/pokedex_set_shiny.php | 2 +- mods/pokedex_set_weather.php | 2 +- mods/raid_by_gym.php | 2 +- mods/raid_by_gym_letter.php | 2 +- mods/raid_by_location.php | 2 +- mods/raids_list.php | 2 +- mods/share_raid_by_location.php | 2 +- mods/trainer.php | 6 +- mods/trainer_add.php | 2 +- mods/trainer_code.php | 2 +- mods/trainer_delete.php | 2 +- mods/trainer_level.php | 2 +- mods/trainer_name.php | 2 +- mods/trainer_share.php | 2 +- mods/trainer_team.php | 2 +- mods/tutorial.php | 2 +- 81 files changed, 291 insertions(+), 383 deletions(-) delete mode 100644 core/bot/logic/bot_access_check.php create mode 100644 core/bot/user.php diff --git a/commands/delete.php b/commands/delete.php index df04936a..2a1729b7 100644 --- a/commands/delete.php +++ b/commands/delete.php @@ -7,13 +7,13 @@ //debug_log($data); // Check access. -bot_access_check($update, 'access-bot'); +$botUser->accessCheck($update, 'access-bot'); // Count results. $count = 0; $own_sql = ""; $own_arr = []; -if(!bot_access_check($update, 'delete', true) && bot_access_check($update,'delete-own',true)) { +if(!$botUser->accessCheck($update, 'delete', true) && $botUser->accessCheck($update,'delete-own',true)) { $own_sql = "AND users.user_id = :user_id"; $own_arr = [":user_id"=>$update['message']['from']['id']]; } diff --git a/commands/exreport.php b/commands/exreport.php index 7d793ed7..827d37b1 100644 --- a/commands/exreport.php +++ b/commands/exreport.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'ex-report'); +$botUser->accessCheck($update, 'ex-report'); // Init empty keys array. $keys = []; diff --git a/commands/friendsearch.php b/commands/friendsearch.php index fe740994..67ec7486 100644 --- a/commands/friendsearch.php +++ b/commands/friendsearch.php @@ -6,7 +6,7 @@ //debug_log($update); //debug_log($data); -bot_access_check($update, 'friendsearch'); +$botUser->accessCheck($update, 'friendsearch'); // Trim away everything before "/FRIENDSEARCH" $searchterm = $update['message']['text']; diff --git a/commands/gym.php b/commands/gym.php index 70e481c3..06083133 100644 --- a/commands/gym.php +++ b/commands/gym.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'gym-details'); +$botUser->accessCheck($update, 'gym-details'); // Set keys. $keys_and_gymarea = raid_edit_gyms_first_letter_keys('gym_details', false, false, 'gym_letter'); @@ -51,7 +51,7 @@ // Merge keys. $keys = array_merge($h_keys, $keys); -if(bot_access_check($update, 'gym-add')) { +if($botUser->accessCheck($update, 'gym-add')) { $keys[] = [ [ 'text' => getTranslation('gym_create'), diff --git a/commands/gymname.php b/commands/gymname.php index d6f0a7e2..18b7d9eb 100644 --- a/commands/gymname.php +++ b/commands/gymname.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'gym-name'); +$botUser->accessCheck($update, 'gym-name'); // Get gym by name. // Trim away everything before "/gymname " diff --git a/commands/help.php b/commands/help.php index 77d37835..488f697a 100644 --- a/commands/help.php +++ b/commands/help.php @@ -1,12 +1,10 @@ accessCheck($update, 'help', true); // Display help for each permission -if($access && (is_file(ROOT_PATH . '/access/' . $access) || $access == 'BOT_ADMINS')) { - // Get permissions from file. - - if($access == 'BOT_ADMINS') { +if($access) { + if($botUser->userPrivileges['grantedBy'] == 'BOT_ADMINS') { $permissions = array(); $permissions[] = 'access-bot'; $permissions[] = 'create'; @@ -31,8 +29,8 @@ $permissions[] = 'pokedex'; $permissions[] = 'help'; } else { - // Get permissions from file. - $permissions = file(ROOT_PATH . '/access/' . $access, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + // Get permissions. + $permissions = $botUser->userPrivileges['privileges']; } // Write to log. diff --git a/commands/history.php b/commands/history.php index edd09dc3..fa6d8e8f 100644 --- a/commands/history.php +++ b/commands/history.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'history'); +$botUser->accessCheck($update, 'history'); require_once(LOGIC_PATH .'/history.php'); diff --git a/commands/list.php b/commands/list.php index 59545550..ef9f6510 100644 --- a/commands/list.php +++ b/commands/list.php @@ -8,13 +8,13 @@ //debug_log($data); // Check access. -bot_access_check($update, 'list'); +$botUser->accessCheck($update, 'list'); // Init text and keys. $text = ''; $keys = []; -$event_permissions = bot_access_check($update, 'event',true); +$event_permissions = $botUser->accessCheck($update, 'event',true); // Get last 12 active raids data. $rs = my_query( diff --git a/commands/listall.php b/commands/listall.php index e109fcae..37553e88 100644 --- a/commands/listall.php +++ b/commands/listall.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -if(!isset($skip_access) or $skip_access != true) bot_access_check($update, 'list'); +if(!isset($skip_access) or $skip_access != true) $botUser->accessCheck($update, 'list'); // Set keys. $keys_and_gymarea = raid_edit_gyms_first_letter_keys('list_by_gym', false, false, 'listall', 'list_raid'); diff --git a/commands/overview.php b/commands/overview.php index 6d2fbac5..d7396d70 100644 --- a/commands/overview.php +++ b/commands/overview.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'overview'); +$botUser->accessCheck($update, 'overview'); // Init empty keys array. $keys = []; diff --git a/commands/pokedex.php b/commands/pokedex.php index b8a05fd4..12f9d0f1 100644 --- a/commands/pokedex.php +++ b/commands/pokedex.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Get pokemon name or dex id. $pokemon = trim(substr($update['message']['text'], 8)); diff --git a/commands/pokemon.php b/commands/pokemon.php index 7058f2b2..24d83ada 100644 --- a/commands/pokemon.php +++ b/commands/pokemon.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'access-bot'); +$botUser->accessCheck($update, 'access-bot'); // Count results. $count = 0; diff --git a/commands/start.php b/commands/start.php index d2463f0c..cd2e63dc 100644 --- a/commands/start.php +++ b/commands/start.php @@ -7,13 +7,13 @@ //debug_log($data); $new_user = new_user($update['message']['from']['id']); -$access = bot_access_check($update, 'create', true, true, $new_user); -if(!$access && bot_access_check($update, 'list', true) && !$new_user){ +$access = $botUser->accessCheck($update, 'create', true, $new_user); +if(!$access && $botUser->accessCheck($update, 'list', true) && !$new_user){ debug_log('No access to create, will do a list instead'); require('list.php'); exit; } -if($config->TUTORIAL_MODE && $new_user && (!$access or $access == 'BOT_ADMINS')) { +if($new_user && !$access) { // Tutorial if(is_file(ROOT_PATH . '/config/tutorial.php')) { require_once(ROOT_PATH . '/config/tutorial.php'); diff --git a/commands/trainer.php b/commands/trainer.php index f6eeef33..06dbfbb4 100644 --- a/commands/trainer.php +++ b/commands/trainer.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'trainer'); +$botUser->accessCheck($update, 'trainer'); // Set message. $msg = '' . getTranslation('trainerinfo_set_yours') . ''; @@ -62,10 +62,10 @@ } // Check access. -$access = bot_access_check($update, 'trainer-share', true, true); +$access = $botUser->accessCheck($update, 'trainer-share', true); // Display sharing options for admins and users with trainer-share permissions -if($access && (is_file(ROOT_PATH . '/access/' . $access) || $access == 'BOT_ADMINS')) { +if($access) { // Add sharing keys. $share_keys = []; $share_keys[] = universal_inner_key($keys, '0', 'trainer_add', '0', getTranslation('trainer_message_share')); diff --git a/commands/tutorial.php b/commands/tutorial.php index 207a002c..8802908c 100644 --- a/commands/tutorial.php +++ b/commands/tutorial.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'tutorial'); +$botUser->accessCheck($update, 'tutorial'); // Tutorial if(is_file(ROOT_PATH . '/config/tutorial.php')) { diff --git a/core/bot/logic.php b/core/bot/logic.php index e5bed5df..06463d80 100644 --- a/core/bot/logic.php +++ b/core/bot/logic.php @@ -4,7 +4,6 @@ // No new logic functions should through it, // instead require_once them directy! -require_once('logic/bot_access_check.php'); require_once('logic/date_util.php'); require_once('logic/download_Portal_Image.php'); require_once('logic/geo_api.php'); diff --git a/core/bot/logic/bot_access_check.php b/core/bot/logic/bot_access_check.php deleted file mode 100644 index 6a17f93e..00000000 --- a/core/bot/logic/bot_access_check.php +++ /dev/null @@ -1,277 +0,0 @@ -BOT_ADMINS)) { - debug_log('Bot access is not restricted! Allowing access for user: ' . CR . $user_id); - $allow_access = true; - $access_granted_by = 'NOT_RESTRICTED'; - }else { - // Admin? - $admins = explode(',', $config->BOT_ADMINS); - if(in_array($user_id,$admins)) { - debug_log('Positive result on access check for Bot Admins'); - debug_log('Bot Admins: ' . $config->BOT_ADMINS); - debug_log('user_id: ' . $user_id); - $access_granted_by = 'BOT_ADMINS'; - debug_log('Allowing access to the bot for user:' . CR . $user_id); - $allow_access = true; - } - } - if($allow_access) { - if($return_access) { - return $access_granted_by; - } else { - return true; - } - } - - // Get all chat files for groups/channels like -100111222333 - // Creators - $creator_chats = array(); - $creator_chats = str_replace(ACCESS_PATH . '/creator','',glob(ACCESS_PATH . '/creator-*')); - - // Admins - $admin_chats = array(); - $admin_chats = str_replace(ACCESS_PATH . '/admins','',glob(ACCESS_PATH . '/admins-*')); - - // Members - $member_chats = array(); - $member_chats = str_replace(ACCESS_PATH . '/members','',glob(ACCESS_PATH . '/members-*')); - - // Restricted - $restricted_chats = array(); - $restricted_chats = str_replace(ACCESS_PATH . '/restricted','',glob(ACCESS_PATH . '/restricted-*')); - - // Kicked - $kicked_chats = array(); - $kicked_chats = str_replace(ACCESS_PATH . '/kicked','',glob(ACCESS_PATH . '/kicked-*')); - - // Access chats - $access_chats = array(); - $access_chats = str_replace(ACCESS_PATH . '/access','',glob(ACCESS_PATH . '/access-*')); - $access_chats = array_merge($access_chats, $creator_chats, $admin_chats, $member_chats, $restricted_chats, $kicked_chats); - - // Add user_id - if (is_file(ACCESS_PATH . '/access' . $user_id)) { - $access_chats[] = $user_id; - } - // Delete duplicates - $access_chats = array_unique($access_chats); - - // Get count of access files. - $access_count = count($access_chats); - - // Check each chat - debug_log('Checking these chats:'); - debug_log($access_chats); - debug_log($access_count, 'Chat count:'); - - // Record why access was granted - $access_granted_by = false; - - $access_file = $afile = "UNDEFINED"; - - // Check access files, otherwise check only BOT_ADMINS as no access files are existing yet. - if($access_count > 0) { - // Check access and permission - foreach($access_chats as $chat) { - // Get chat object - remove comments from filename - // This way some kind of comment like the channel name can be added to the end of the filename, e.g. creator-100123456789-MyPokemonChannel to easily differ between access files :) - // Source: php.net/manual/en/function.intval.php#7707 - preg_match_all('/-?\d+/', $chat, $tg_chat); - $tg_chat=$tg_chat[0][0]; - debug_log("Getting chat object for '$tg_chat'"); - - // Group/channel? - if($chat[0] == '-') { - // Get chat member object and check status - debug_log("Getting user from chat '$tg_chat'"); - $chat_obj = get_chatmember($tg_chat, $user_id); - - // Make sure we get a proper response - if($chat_obj['ok'] == true) { - debug_log('Proper chat object received, continuing with access check.'); - - // Get access file based on user status/role. - debug_log('Role of user ' . $chat_obj['result']['user']['id'] . ' : ' . $chat_obj['result']['status']); - - // Creator - if($chat_obj['result']['status'] == 'creator' && is_file(ROOT_PATH . '/access/creator' . $chat)) { - $access_file = file(ROOT_PATH . '/access/creator' . $chat, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $afile = 'creator' . $chat; - - // Admin - } else if($chat_obj['result']['status'] == 'administrator' && is_file(ROOT_PATH . '/access/admins' . $chat)) { - $access_file = file(ROOT_PATH . '/access/admins' . $chat, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $afile = 'admins' . $chat; - - // Member - } else if($chat_obj['result']['status'] == 'member' && is_file(ROOT_PATH . '/access/members' . $chat)) { - $access_file = file(ROOT_PATH . '/access/members' . $chat, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $afile = 'members' . $chat; - - // Restricted - } else if($chat_obj['result']['status'] == 'restricted' && is_file(ROOT_PATH . '/access/restricted' . $chat)) { - $access_file = file(ROOT_PATH . '/access/restricted' . $chat, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $afile = 'restricted' . $chat; - - // Kicked - } else if($chat_obj['result']['status'] == 'kicked' && is_file(ROOT_PATH . '/access/kicked' . $chat)) { - $access_file = file(ROOT_PATH . '/access/kicked' . $chat, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $afile = 'kicked' . $chat; - - // Any other user status/role except "left" - } else if($chat_obj['result']['status'] != 'left' && is_file(ROOT_PATH . '/access/access' . $chat)) { - $access_file = file(ROOT_PATH . '/access/access' . $chat, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $afile = 'access' . $chat; - - // Ignore "Restricted"? - if($chat_obj['result']['status'] == 'restricted' && in_array('ignore-restricted', $access_file)) { - // Reset access file. - $access_file = NULL; - } - - // Ignore "kicked"? - if($chat_obj['result']['status'] == 'kicked' && in_array('ignore-kicked', $access_file)) { - // Reset access file. - $access_file = NULL; - } - } - - // Debug. - debug_log('Access file:'); - debug_log($access_file); - - // If a config file matching users status was found, check if tutorial is forced - if(is_array($access_file) && $config->TUTORIAL_MODE && $access_granted_by != 'BOT_ADMINS' && $new_user && in_array("force-tutorial",$access_file)) { - $access_file = NULL; - } - - // Check user status/role and permission to access the function - if($chat_obj['result']['user']['id'] == $user_id && is_array($access_file) && in_array($permission,$access_file)) { - debug_log($afile, 'Positive result on access check in file:'); - debug_log($tg_chat, 'Positive result on access check from chat:'); - $allow_access = true; - $access_granted_by = $afile; - break; - } else { - // Deny access - debug_log($afile, 'Negative result on access check in file:'); - debug_log('Continuing with next chat...'); - continue; - } - } else { - // Invalid chat - debug_log('Chat ' . $tg_chat . ' does not exist! Continuing with next chat...'); - continue; - } - // Private chat - } else { - // Get chat object - debug_log("Getting chat object for '$tg_chat'"); - $chat_obj = get_chat($tg_chat); - - // Check chat object for proper response. - if($chat_obj['ok'] == true) { - debug_log('Proper chat object received, continuing with access check.'); - - // Get access file - if(is_file(ROOT_PATH . '/access/access' . $chat)) { - $access_file = file(ROOT_PATH . '/access/access' . $chat, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - } - $afile = 'access' . $chat; - - // ID matching $chat, private chat type and permission to access the function - if($chat_obj['result']['id'] == $user_id && $chat_obj['result']['type'] == 'private' && is_array($access_file) && in_array($permission,$access_file)) { - debug_log($afile, 'Positive result on access check in file:'); - debug_log($user_id, 'Positive result on access check for user:'); - $allow_access = true; - $access_granted_by = $afile; - break; - } else if($chat_obj['result']['type'] == 'private') { - // Result was ok, but access not granted. Continue with next chat if type is private. - debug_log($afile, 'Negative result on access check in file:'); - debug_log('Continuing with next chat...'); - continue; - } - } else { - // Invalid chat - debug_log('Chat ' . $tg_chat . ' does not exist! Continuing with next chat...'); - continue; - } - } - } - } - - // Result of access check? - // Prepare logging of id, username and/or first_name - $msg = ''; - $msg .= !empty($update[$update_type]['from']['id']) ? 'Id: ' . $update[$update_type]['from']['id'] . CR : ''; - $msg .= !empty($update[$update_type]['from']['username']) ? 'Username: ' . $update[$update_type]['from']['username'] . CR : ''; - $msg .= !empty($update[$update_type]['from']['first_name']) ? 'First Name: ' . $update[$update_type]['from']['first_name'] . CR : ''; - - // Allow or deny access to the bot and log result - if ($allow_access && !$return_result) { - debug_log('Allowing access to the bot for user:' . CR . $msg); - // Return access (BOT_ADMINS or access_file) - if($return_access) { - return $access_granted_by; - } - } else if ($allow_access && $return_result) { - debug_log('Allowing access to the bot for user:' . CR . $msg); - return $allow_access; - } else if (!$allow_access && $return_result) { - debug_log('Denying access to the bot for user:' . CR . $msg); - return $allow_access; - } else { - debug_log('Denying access to the bot for user:' . CR . $msg); - $response_msg = '' . getTranslation('bot_access_denied') . ''; - // Edit message or send new message based on value of $update_type - if ($update_type == 'callback_query') { - // Empty keys. - $keys = []; - - // Telegram JSON array. - $tg_json = array(); - - // Edit message. - $tg_json[] = edit_message($update, $response_msg, $keys, false, true); - - // Answer the callback. - $tg_json[] = answerCallbackQuery($update[$update_type]['id'], getTranslation('bot_access_denied'), true); - - // Telegram multicurl request. - curl_json_multi_request($tg_json); - } else { - send_message($update[$update_type]['from']['id'], $response_msg); - } - exit; - } -} - -?> diff --git a/core/bot/logic/key_util.php b/core/bot/logic/key_util.php index 16b06321..1ddfd20c 100644 --- a/core/bot/logic/key_util.php +++ b/core/bot/logic/key_util.php @@ -83,9 +83,9 @@ function universal_key($keys, $id, $action, $arg, $text = '0') */ function share_keys($id, $action, $update, $chats = '', $prefix_text = '', $hide = false, $level = '') { - global $config; + global $config, $botUser; // Check access. - $share_access = bot_access_check($update, 'share-any-chat', true); + $share_access = $botUser->accessCheck($update, 'share-any-chat', true); // Add share button if not restricted to allow sharing to any chat. if ($share_access == true && $hide == false) { diff --git a/core/bot/requirements.php b/core/bot/requirements.php index 6c8517ed..c3122cea 100644 --- a/core/bot/requirements.php +++ b/core/bot/requirements.php @@ -55,6 +55,9 @@ // Core Logic require_once(CORE_BOT_PATH . '/logic.php'); +// User logic +require_once(CORE_BOT_PATH . '/user.php'); + // Telegram Core require_once(CORE_TG_PATH . '/functions.php'); diff --git a/core/bot/user.php b/core/bot/user.php new file mode 100644 index 00000000..ea669d0f --- /dev/null +++ b/core/bot/user.php @@ -0,0 +1,179 @@ + [], + 'grantedBy' => '', + ]; + + /** + * Run privilege check for Telegram user and save them for later use. + * @param $update Update array from Telegram + */ + public function privilegeCheck($update) { + global $config; + // Get Telegram user ID to check access from $update - either message, callback_query or inline_query + $update_type = ''; + $update_type = !empty($update['message']['from']['id']) ? 'message' : $update_type; + $update_type = (empty($update_type) && !empty($update['callback_query']['from']['id'])) ? 'callback_query' : $update_type; + $update_type = (empty($update_type) && !empty($update['inline_query']['from']['id'])) ? 'inline_query' : $update_type; + if(empty($update_type)) return; // If no update type was found, the call probably didn't come from Telegram and privileges don't need to be checked + $user_id = $update[$update_type]['from']['id']; + + // Write to log. + debug_log('Telegram message type: ' . $update_type); + debug_log('Checking access for ID: ' . $user_id); + + // Public access? + if(empty($config->BOT_ADMINS)) { + debug_log('Bot access is not restricted! Allowing access for user: ' . CR . $user_id); + $this->userPrivileges['grantedBy'] = 'NOT_RESTRICTED'; + return; + }else { + // Admin? + $admins = explode(',', $config->BOT_ADMINS); + if(in_array($user_id,$admins)) { + debug_log('Positive result on access check for Bot Admins'); + debug_log('Bot Admins: ' . $config->BOT_ADMINS); + debug_log('user_id: ' . $user_id); + $this->userPrivileges['grantedBy'] = 'BOT_ADMINS'; + return; + } + } + + $telegramRoles = ['creator', 'admins', 'members', 'restricted', 'kicked']; + + // If user specific permissions are found, use them instead of group based + if (is_file(ACCESS_PATH . '/access' . $user_id)) { + $accessChats = [$user_id => null]; + }else { + $chatIds = []; + foreach($telegramRoles as $roleToCheck) { + $chatFiles = str_replace(ACCESS_PATH . '/' . $roleToCheck, '', glob(ACCESS_PATH . '/' . $roleToCheck . '-*')); + $chatIds = array_merge($chatIds, $chatFiles); + } + // Delete duplicates + $chatsToCheck = array_unique($chatIds); + $tg_json = []; + // Check access and permission + foreach($chatsToCheck as $chat) { + // Get chat object - remove comments from filename + // This way some kind of comment like the channel name can be added to the end of the filename, e.g. creator-100123456789-MyPokemonChannel to easily differ between access files :) + // Source: php.net/manual/en/function.intval.php#7707 + preg_match_all('/-?\d+/', $chat, $tg_chat); + $tg_chat = $tg_chat[0][0]; + debug_log("Getting chat object for '$tg_chat'"); + + // Group/channel? + if($tg_chat[0] == '-') { + // Get chat member object and check status + debug_log("Getting user from chat '$tg_chat'"); + $tg_json[$tg_chat] = get_chatmember($tg_chat, $user_id, true); + } + } + $accessChats = curl_json_multi_request($tg_json); + } + // Loop through different chats + foreach($accessChats as $chatId => $chatObj) { + // Object contains response from Telegram + if(isset($chatObj['ok'])) { + if($chatObj['ok'] == true) { + debug_log('Proper chat object received, continuing with access check.'); + + // Get access file based on user status/role. + debug_log('Role of user ' . $chatObj['result']['user']['id'] . ' : ' . $chatObj['result']['status']); + + if(in_array($chatObj['result']['status'], $telegramRoles) && is_file(ACCESS_PATH . '/' . $chatObj['result']['status'] . $chatId)) { + $privilegeList = file(ACCESS_PATH . '/' . $chatObj['result']['status'] . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $accessFile = $chatObj['result']['status'] . $chatId; + + // Any other user status/role except "left" + } else if($chatObj['result']['status'] != 'left' && is_file(ACCESS_PATH . '/access' . $chatId)) { + $privilegeList = file(ACCESS_PATH . '/access' . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $accessFile = 'access' . $chatId; + + // Ignore "Restricted"? + if($chatObj['result']['status'] == 'restricted' && in_array('ignore-restricted', $privilegeList)) { + // Reset access file. + $privilegeList = NULL; + } + + // Ignore "kicked"? + if($chatObj['result']['status'] == 'kicked' && in_array('ignore-kicked', $privilegeList)) { + // Reset access file. + $privilegeList = NULL; + } + } + + // Debug. + debug_log('Access file:'); + debug_log($privilegeList); + } else { + // Invalid chat + debug_log('Chat ' . $chatId . ' does not exist! Continuing with next chat...'); + continue; + } + // Process user specific access file + }else { + if(is_file(ACCESS_PATH . '/access' . $chatId)) { + $privilegeList = file(ACCESS_PATH . '/access' . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $accessFile = 'access' . $chatId; + } + } + + // Save privileges if found + if(is_array($privilegeList)) { + debug_log($accessFile, 'Positive result on access check in file:'); + $this->userPrivileges = [ + 'privileges' => $privilegeList, + 'grantedBy' => $accessFile, + ]; + break; + } + // Deny access + debug_log($chat, 'Negative result on access check for chat:'); + debug_log('Continuing with next chat...'); + } + } + + /** + * Check users privileges for a specific action. Exits by default if access is denied. + * @param $update Update array from Telegram + * @param $permission Permission to check + * @param $return_result Return the result of privilege check + * @param $new_user Has user completed tutorial or not + * @return bool|string + */ + public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { + if(in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { + // If a config file matching users status was found, check if tutorial is forced + if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED')) { + return false; + } + return true; + }else { + debug_log('Denying access to the bot for user'); + + if($return_result) + return false; + + $response_msg = '' . getTranslation('bot_access_denied') . ''; + // Edit message or send new message based on type of received call + if (isset($update['callback_query'])) { + $keys = []; + + // Telegram JSON array. + $tg_json = array(); + $tg_json[] = edit_message($update, $response_msg, $keys, false, true); + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('bot_access_denied'), true); + + curl_json_multi_request($tg_json); + } else { + send_message($update['message']['from']['id'], $response_msg); + } + exit; + } + } +} +?> \ No newline at end of file diff --git a/core/commands/get.php b/core/commands/get.php index 473c8b6b..b16e3734 100644 --- a/core/commands/get.php +++ b/core/commands/get.php @@ -7,7 +7,7 @@ // debug_log($data); // Check access. -bot_access_check($update, 'config-get'); +$botUser->accessCheck($update, 'config-get'); // Get all allowed configs. $allowed = explode(',', $config->ALLOWED_TELEGRAM_CONFIG); diff --git a/core/commands/set.php b/core/commands/set.php index 353cc978..b58fc9a3 100644 --- a/core/commands/set.php +++ b/core/commands/set.php @@ -7,7 +7,7 @@ // debug_log($data); // Check access. -bot_access_check($update, 'config-set'); +$botUser->accessCheck($update, 'config-set'); // Get config name and value. $input = trim(substr($update['message']['text'], 4)); diff --git a/index.php b/index.php index 49fa1cea..6efd4e7a 100644 --- a/index.php +++ b/index.php @@ -7,6 +7,8 @@ $requests_total->inc(['/']); } +$botUser = new botUser; + // Start logging. debug_log("RAID-BOT '" . $config->BOT_ID . "'"); @@ -66,6 +68,8 @@ // Get language include_once(CORE_BOT_PATH . '/userlanguage.php'); +$botUser->privilegeCheck($update); + // Run cleanup if requested if (isset($update['cleanup'])) { include_once(CORE_BOT_PATH . '/cleanup_run.php'); diff --git a/logic/edit_gym_keys.php b/logic/edit_gym_keys.php index 4b8947a5..9024ed50 100644 --- a/logic/edit_gym_keys.php +++ b/logic/edit_gym_keys.php @@ -11,6 +11,7 @@ */ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_address) { + global $botUser; // Hide gym? if($show_gym == 1) { $text_show_button = getTranslation('hide_gym'); @@ -45,7 +46,7 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add 'callback_data' => $gym_id . ':gym_edit_details:ex-' . $arg_ex ] ]; - if(bot_access_check($update, 'gym-name', true)) { + if($botUser->accessCheck($update, 'gym-name', true)) { $keys[] = [ [ 'text' => EMOJI_PENCIL . ' ' . getTranslation("gym_name_edit"), @@ -53,7 +54,7 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add ] ]; } - if(bot_access_check($update, 'gym-note', true)) { + if($botUser->accessCheck($update, 'gym-note', true)) { $keys[] = [ [ 'text' => EMOJI_INFO . ' ' . (!empty($gym_note) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_add_edit_note"), @@ -61,7 +62,7 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add ] ]; } - if(bot_access_check($update, 'gym-address', true)) { + if($botUser->accessCheck($update, 'gym-address', true)) { $keys[] = [ [ 'text' => EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("forest")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), @@ -69,7 +70,7 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add ] ]; } - if(bot_access_check($update, 'gym-gps', true)) { + if($botUser->accessCheck($update, 'gym-gps', true)) { $keys[] = [ [ 'text' => EMOJI_HERE . ' ' . getTranslation("gym_edit_coordinates"), @@ -77,7 +78,7 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add ] ]; } - if(bot_access_check($update, 'gym-delete', true)) { + if($botUser->accessCheck($update, 'gym-delete', true)) { $keys[] = [ [ 'text' => EMOJI_DELETE . ' ' . getTranslation("gym_delete"), diff --git a/logic/raid_access_check.php b/logic/raid_access_check.php index 203a0dad..252d2cf9 100644 --- a/logic/raid_access_check.php +++ b/logic/raid_access_check.php @@ -7,6 +7,7 @@ */ function raid_access_check($update, $data, $permission, $return_result = false) { + global $botUser; // Default: Deny access to raids $raid_access = false; @@ -26,22 +27,22 @@ function raid_access_check($update, $data, $permission, $return_result = false) // Check "-all" permission debug_log('Checking permission:' . $permission . '-all'); $permission = $permission . '-all'; - $raid_access = bot_access_check($update, $permission, $return_result); + $raid_access = $botUser->accessCheck($update, $permission, $return_result); } else { // Check "-own" permission debug_log('Checking permission:' . $permission . '-own'); $permission_own = $permission . '-own'; $permission_all = $permission . '-all'; - $raid_access = bot_access_check($update, $permission_own, true); + $raid_access = $botUser->accessCheck($update, $permission_own, true); // Check "-all" permission if we get "access denied" // Maybe necessary if user has only "-all" configured, but not "-own" if(!$raid_access) { debug_log('Permission check for ' . $permission_own . ' failed! Maybe the access is just granted via ' . $permission . '-all ?'); debug_log('Checking permission:' . $permission_all); - $raid_access = bot_access_check($update, $permission_all, $return_result); + $raid_access = $botUser->accessCheck($update, $permission_all, $return_result); } else { - $raid_access = bot_access_check($update, $permission_own, $return_result); + $raid_access = $botUser->accessCheck($update, $permission_own, $return_result); } } diff --git a/mods/bot_lang.php b/mods/bot_lang.php index 15d3ec64..083feeaa 100644 --- a/mods/bot_lang.php +++ b/mods/bot_lang.php @@ -7,7 +7,7 @@ //debug_log($data); // Access check. -bot_access_check($update, 'trainer'); +$botUser->accessCheck($update, 'trainer'); $keys = []; diff --git a/mods/code.php b/mods/code.php index 407905e2..25ae1f44 100644 --- a/mods/code.php +++ b/mods/code.php @@ -8,7 +8,7 @@ // Allow anyone to use /code // Check access. -//bot_access_check($update, 'list'); +//$botUser->accessCheck($update, 'list'); // Set the raid id. $raid_id = $data['id']; diff --git a/mods/code_start.php b/mods/code_start.php index 73b88923..8a8b8540 100644 --- a/mods/code_start.php +++ b/mods/code_start.php @@ -8,7 +8,7 @@ // Allow anyone to use /code // Check access. -//bot_access_check($update, 'list'); +//$botUser->accessCheck($update, 'list'); // Get raid $raid = get_raid($code_raid_id); diff --git a/mods/delete_scheduled_entry.php b/mods/delete_scheduled_entry.php index 012bf1d0..6166880e 100644 --- a/mods/delete_scheduled_entry.php +++ b/mods/delete_scheduled_entry.php @@ -3,7 +3,7 @@ debug_log('delete_scheduled_entry()'); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); $arg = $data['arg']; $id = $data['id']; diff --git a/mods/edit_date.php b/mods/edit_date.php index 88cb52e6..6084c4d6 100644 --- a/mods/edit_date.php +++ b/mods/edit_date.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'create'); +$botUser->accessCheck($update, 'create'); // Set the id. $id = $data['id']; diff --git a/mods/edit_event.php b/mods/edit_event.php index 256da3fe..2dd92863 100644 --- a/mods/edit_event.php +++ b/mods/edit_event.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'event-raids'); +$botUser->accessCheck($update, 'event-raids'); // Set the id. $gym_id_plus_letter = $data['id']; diff --git a/mods/edit_event_raidlevel.php b/mods/edit_event_raidlevel.php index f952d0e3..c0af0801 100644 --- a/mods/edit_event_raidlevel.php +++ b/mods/edit_event_raidlevel.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'event-raids'); +$botUser->accessCheck($update, 'event-raids'); // Get gym data via ID $id_data = explode(",", $data['id']); @@ -29,7 +29,7 @@ //Initiate admin rights table [ ex-raid , raid-event ] $admin_access = [false,1]; // Check access - user must be admin for raid_level X -$admin_access[0] = bot_access_check($update, 'ex-raids', true); +$admin_access[0] = $botUser->accessCheck($update, 'ex-raids', true); // Get the keys. $keys = raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access, $event_id); diff --git a/mods/edit_pokemon.php b/mods/edit_pokemon.php index 28d21453..f9ee421e 100644 --- a/mods/edit_pokemon.php +++ b/mods/edit_pokemon.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'create'); +$botUser->accessCheck($update, 'create'); // Set the id. $gym_id_plus_letter = $data['id']; diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index 71015904..ca4ac5c1 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'create'); +$botUser->accessCheck($update, 'create'); // Get gym data via ID in arg $gym_id = $data['arg']; @@ -73,9 +73,9 @@ //Initialize admin rights table [ ex-raid , raid-event ] $admin_access = [false,false]; // Check access - user must be admin for raid_level X -$admin_access[0] = bot_access_check($update, 'ex-raids', true); +$admin_access[0] = $botUser->accessCheck($update, 'ex-raids', true); // Check access - user must be admin for raid event creation -$admin_access[1] = bot_access_check($update, 'event-raids', true); +$admin_access[1] = $botUser->accessCheck($update, 'event-raids', true); // Get the keys. $keys = raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access); diff --git a/mods/edit_save.php b/mods/edit_save.php index 0c55b065..4f320358 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'create'); +$botUser->accessCheck($update, 'create'); // Set the id and arg. if(substr_count($data['id'], ',') == 1) { @@ -87,7 +87,7 @@ ]; // Check access level prior allowing to change raid time -$admin_access = bot_access_check($update, 'raid-duration', true); +$admin_access = $botUser->accessCheck($update, 'raid-duration', true); if($admin_access) { // Add time change to keys. $keys_time = [ diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index c9e439e3..964069b2 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'create'); +$botUser->accessCheck($update, 'create'); // Get the argument. $arg_data = explode(",", $data['arg']); diff --git a/mods/edit_time.php b/mods/edit_time.php index b2d5b3d8..5f191ae0 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'create'); +$botUser->accessCheck($update, 'create'); // Get count of ID and argument. $count_id = substr_count($data['id'], ','); diff --git a/mods/gym_create.php b/mods/gym_create.php index c82f52b8..9bc3b20b 100644 --- a/mods/gym_create.php +++ b/mods/gym_create.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'gym-edit'); +$botUser->accessCheck($update, 'gym-edit'); function insertUserInput($userId, $stage, $oldMessageId, $gymId = 0) { global $dbh; diff --git a/mods/gym_delete.php b/mods/gym_delete.php index d74c6d3f..03b076e6 100644 --- a/mods/gym_delete.php +++ b/mods/gym_delete.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'gym-delete'); +$botUser->accessCheck($update, 'gym-delete'); // Get the arg. $arg = $data['arg']; diff --git a/mods/gym_details.php b/mods/gym_details.php index a81b81f6..1d328815 100644 --- a/mods/gym_details.php +++ b/mods/gym_details.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'gym-details'); +$botUser->accessCheck($update, 'gym-details'); // Get the arg. $args = explode(',',$data['arg'],2); diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index c4fda88a..ede761ea 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'gym-edit'); +$botUser->accessCheck($update, 'gym-edit'); // Get the id. $gym_id = $data['id']; diff --git a/mods/gym_hidden_letter.php b/mods/gym_hidden_letter.php index 716fc069..97bb6ef0 100644 --- a/mods/gym_hidden_letter.php +++ b/mods/gym_hidden_letter.php @@ -12,7 +12,7 @@ // Check access, show message and set keys based on arg. if($arg == 'gym_delete') { // Check access. - bot_access_check($update, 'gym-delete'); + $botUser->accessCheck($update, 'gym-delete'); // Set message. $msg = '' . getTranslation('gym_delete') . SP . '—' . SP . getTranslation('select_gym_first_letter') . ''; @@ -21,7 +21,7 @@ $arg = 'gym_details'; // Check access. - bot_access_check($update, 'gym-details'); + $botUser->accessCheck($update, 'gym-details'); // Set message. $msg = '' . getTranslation('show_gym_details') . SP . '—' . SP . getTranslation('select_gym_first_letter') . ''; diff --git a/mods/gym_letter.php b/mods/gym_letter.php index 1bb15303..cb9bcf4b 100644 --- a/mods/gym_letter.php +++ b/mods/gym_letter.php @@ -16,7 +16,7 @@ // Check access, show message and set keys based on arg. if($arg == 'gym_delete') { // Check access. - bot_access_check($update, 'gym-delete'); + $botUser->accessCheck($update, 'gym-delete'); // Set message. $msg = '' . getTranslation('gym_delete') . CR . getTranslation('select_gym_first_letter') . ''; @@ -26,7 +26,7 @@ $arg = 'gym_details'; // Check access. - bot_access_check($update, 'gym-details'); + $botUser->accessCheck($update, 'gym-details'); // Set message. $msg = '' . getTranslation('show_gym_details') . CR . getTranslation('select_gym_first_letter') . ''; diff --git a/mods/history.php b/mods/history.php index a895c989..1d17404a 100644 --- a/mods/history.php +++ b/mods/history.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'history'); +$botUser->accessCheck($update, 'history'); // Expected callback data: [Day number (0-31), DD]:history:[Year and month, YYYY-MM] diff --git a/mods/history_gyms.php b/mods/history_gyms.php index 10c3e701..4dec71d2 100644 --- a/mods/history_gyms.php +++ b/mods/history_gyms.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'history'); +$botUser->accessCheck($update, 'history'); // Expected callback data: [Date, YYYY-MM-DD]:history_gyms:[GYM_LETTER] diff --git a/mods/history_raid.php b/mods/history_raid.php index 5b518abe..90f925f1 100644 --- a/mods/history_raid.php +++ b/mods/history_raid.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'history'); +$botUser->accessCheck($update, 'history'); // Expected callback data: [Date, YYYY-MM-DD]/[GYM_LETTER]:history_raid:[GYM_ID]/[RAID_ID] diff --git a/mods/history_raids.php b/mods/history_raids.php index 42cb6c27..f75e73c3 100644 --- a/mods/history_raids.php +++ b/mods/history_raids.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'history'); +$botUser->accessCheck($update, 'history'); // Expected callback data: [Date, YYYY-MM-DD]/[GYM_LETTER]:history_raids:[GYM_ID] diff --git a/mods/import_future_bosses.php b/mods/import_future_bosses.php index beac26a4..03dbbd29 100644 --- a/mods/import_future_bosses.php +++ b/mods/import_future_bosses.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); require_once(LOGIC_PATH . '/read_upcoming_bosses.php'); $id = $data['id']; diff --git a/mods/import_shinyinfo.php b/mods/import_shinyinfo.php index bc5c1217..c6e3586d 100644 --- a/mods/import_shinyinfo.php +++ b/mods/import_shinyinfo.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Get raid levels $id = $data['id']; diff --git a/mods/importal.php b/mods/importal.php index 80d7ecaa..4eabb6cc 100644 --- a/mods/importal.php +++ b/mods/importal.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'portal-import'); +$botUser->accessCheck($update, 'portal-import'); function escape($value){ diff --git a/mods/list_by_gym.php b/mods/list_by_gym.php index cac040a2..4a73be46 100644 --- a/mods/list_by_gym.php +++ b/mods/list_by_gym.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'list'); +$botUser->accessCheck($update, 'list'); // Get the first letter $args = explode(',',$data['arg'],2); diff --git a/mods/list_by_gym_letter.php b/mods/list_by_gym_letter.php index 24a703ad..e310824a 100644 --- a/mods/list_by_gym_letter.php +++ b/mods/list_by_gym_letter.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'list'); +$botUser->accessCheck($update, 'list'); // Get the keys. $keys_and_gymarea = raid_edit_gyms_first_letter_keys('list_by_gym', false, ($data['id'] == 'n' ? false : $data['id']), 'list_by_gym_letter'); diff --git a/mods/list_raid.php b/mods/list_raid.php index e675a827..f7942485 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'list'); +$botUser->accessCheck($update, 'list'); // Get gym ID. $gym_id = $data['arg']; diff --git a/mods/listall.php b/mods/listall.php index 480eef17..87885b56 100644 --- a/mods/listall.php +++ b/mods/listall.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'list'); +$botUser->accessCheck($update, 'list'); // Get the keys. $keys_and_gymarea = raid_edit_gyms_first_letter_keys('list_by_gym', false, ($data['id'] == 'n' ? false : $data['id']), 'listall', 'list_raid'); diff --git a/mods/overview_delete.php b/mods/overview_delete.php index 9c600bfe..dd92e87d 100644 --- a/mods/overview_delete.php +++ b/mods/overview_delete.php @@ -11,7 +11,7 @@ $chat_id = $data['arg']; // Check access. -bot_access_check($update, 'overview'); +$botUser->accessCheck($update, 'overview'); // Telegram JSON array. $tg_json = array(); diff --git a/mods/overview_share.php b/mods/overview_share.php index 2e4aedf6..2cc58ef7 100644 --- a/mods/overview_share.php +++ b/mods/overview_share.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'overview'); +$botUser->accessCheck($update, 'overview'); // Get chat ID from data $chat_id = 0; diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index 47f1c840..6d84ea57 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Levels available for import $levels = array('6', '5', '3', '1'); diff --git a/mods/pokebattler.php b/mods/pokebattler.php index 20f7112b..8f23125a 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); include(LOGIC_PATH . '/resolve_boss_name_to_ids.php'); // Get raid levels diff --git a/mods/pokedex.php b/mods/pokedex.php index ed05d4dd..7a2c4a00 100644 --- a/mods/pokedex.php +++ b/mods/pokedex.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Get the limit. $limit = $data['id']; diff --git a/mods/pokedex_disable_raids.php b/mods/pokedex_disable_raids.php index f5238b32..9bd87b41 100644 --- a/mods/pokedex_disable_raids.php +++ b/mods/pokedex_disable_raids.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Get raid levels. $id = $data['id']; diff --git a/mods/pokedex_edit_pokemon.php b/mods/pokedex_edit_pokemon.php index 59156f5f..778e5fb8 100644 --- a/mods/pokedex_edit_pokemon.php +++ b/mods/pokedex_edit_pokemon.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Set the id. $poke_id_form = $data['id']; diff --git a/mods/pokedex_import.php b/mods/pokedex_import.php index a500a65f..fc700b83 100644 --- a/mods/pokedex_import.php +++ b/mods/pokedex_import.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); $id = $data['id']; $arg = $data['arg']; diff --git a/mods/pokedex_list_raids.php b/mods/pokedex_list_raids.php index 45f12c7b..065d47cb 100644 --- a/mods/pokedex_list_raids.php +++ b/mods/pokedex_list_raids.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Get all pokemon with raid levels from database. $rs = my_query( diff --git a/mods/pokedex_set_cp.php b/mods/pokedex_set_cp.php index 7421ee8a..bc3d4365 100644 --- a/mods/pokedex_set_cp.php +++ b/mods/pokedex_set_cp.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Set the id. $pokedex_id = $data['id']; diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index 473aa65e..f35bde65 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Set the id. $pokedex_id = $data['id']; diff --git a/mods/pokedex_set_shiny.php b/mods/pokedex_set_shiny.php index f3a74f4d..9a091554 100644 --- a/mods/pokedex_set_shiny.php +++ b/mods/pokedex_set_shiny.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Set the id. $pokedex_id = $data['id']; diff --git a/mods/pokedex_set_weather.php b/mods/pokedex_set_weather.php index d671aa4e..2bf5ee27 100644 --- a/mods/pokedex_set_weather.php +++ b/mods/pokedex_set_weather.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'pokedex'); +$botUser->accessCheck($update, 'pokedex'); // Set the id. $pokedex_id = $data['id']; diff --git a/mods/raid_by_gym.php b/mods/raid_by_gym.php index 58916693..fa4b66db 100644 --- a/mods/raid_by_gym.php +++ b/mods/raid_by_gym.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'create'); +$botUser->accessCheck($update, 'create'); // Get the first letter $args = explode(',',$data['arg'],2); diff --git a/mods/raid_by_gym_letter.php b/mods/raid_by_gym_letter.php index a8be56b7..02299807 100644 --- a/mods/raid_by_gym_letter.php +++ b/mods/raid_by_gym_letter.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'create'); +$botUser->accessCheck($update, 'create'); // Back key id, action and arg $back_id = 'n'; diff --git a/mods/raid_by_location.php b/mods/raid_by_location.php index a7ddf3df..e2e45065 100644 --- a/mods/raid_by_location.php +++ b/mods/raid_by_location.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'create'); +$botUser->accessCheck($update, 'create'); // Enabled? if(!$config->RAID_VIA_LOCATION) { diff --git a/mods/raids_list.php b/mods/raids_list.php index a247e7a1..5047bff8 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'list'); +$botUser->accessCheck($update, 'list'); // Get ID. $id = $data['id']; diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 2f542ee0..1e7c4ac5 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'share-all'); +$botUser->accessCheck($update, 'share-all'); if(isset($data['arg']) && $data['arg'] == 1) { $raid_id = $data['id']; diff --git a/mods/trainer.php b/mods/trainer.php index fb3187b9..151b6ea1 100644 --- a/mods/trainer.php +++ b/mods/trainer.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'trainer'); +$botUser->accessCheck($update, 'trainer'); $user_id = $update['callback_query']['from']['id']; if($data['arg'] == "a") { @@ -66,10 +66,10 @@ } // Check access. -$access = bot_access_check($update, 'trainer-share', true, true); +$access = $botUser->accessCheck($update, 'trainer-share', true); // Display sharing options for admins and users with trainer-share permissions -if($access && (is_file(ROOT_PATH . '/access/' . $access) || $access == 'BOT_ADMINS')) { +if($access) { // Add sharing keys. $share_keys = []; $share_keys[] = universal_inner_key($keys, '0', 'trainer_add', '0', getTranslation('trainer_message_share')); diff --git a/mods/trainer_add.php b/mods/trainer_add.php index baf1b208..55b83556 100644 --- a/mods/trainer_add.php +++ b/mods/trainer_add.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'trainer-share'); +$botUser->accessCheck($update, 'trainer-share'); // Init keys and chat list. $keys = []; diff --git a/mods/trainer_code.php b/mods/trainer_code.php index 0ced1b15..dac90e8a 100644 --- a/mods/trainer_code.php +++ b/mods/trainer_code.php @@ -7,7 +7,7 @@ //debug_log($data); // Access check. -bot_access_check($update, 'trainer'); +$botUser->accessCheck($update, 'trainer'); // Mode and action $mode = $data['id']; diff --git a/mods/trainer_delete.php b/mods/trainer_delete.php index f02deadf..f338a4e0 100644 --- a/mods/trainer_delete.php +++ b/mods/trainer_delete.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'trainer-delete'); +$botUser->accessCheck($update, 'trainer-delete'); // Init keys and chat list. $keys = []; diff --git a/mods/trainer_level.php b/mods/trainer_level.php index 49ebf21b..f9502448 100644 --- a/mods/trainer_level.php +++ b/mods/trainer_level.php @@ -7,7 +7,7 @@ //debug_log($data); // Access check. -bot_access_check($update, 'trainer'); +$botUser->accessCheck($update, 'trainer'); // Confirmation and level $confirm = $data['id']; diff --git a/mods/trainer_name.php b/mods/trainer_name.php index 105a7a99..cb0985f4 100644 --- a/mods/trainer_name.php +++ b/mods/trainer_name.php @@ -7,7 +7,7 @@ //debug_log($data); // Access check. -bot_access_check($update, 'trainer'); +$botUser->accessCheck($update, 'trainer'); // Mode and action $mode = $data['id']; diff --git a/mods/trainer_share.php b/mods/trainer_share.php index d2a9a900..db812bd0 100644 --- a/mods/trainer_share.php +++ b/mods/trainer_share.php @@ -7,7 +7,7 @@ //debug_log($data); // Access check. -bot_access_check($update, 'trainer-share'); +$botUser->accessCheck($update, 'trainer-share'); // Get chat id. $chat = $data['arg']; diff --git a/mods/trainer_team.php b/mods/trainer_team.php index 02f4a7c2..93cf5ee2 100644 --- a/mods/trainer_team.php +++ b/mods/trainer_team.php @@ -7,7 +7,7 @@ //debug_log($data); // Access check. -bot_access_check($update, 'trainer'); +$botUser->accessCheck($update, 'trainer'); // Confirmation and level $confirm = $data['id']; diff --git a/mods/tutorial.php b/mods/tutorial.php index 94a1e48b..abe0a216 100644 --- a/mods/tutorial.php +++ b/mods/tutorial.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -bot_access_check($update, 'tutorial'); +$botUser->accessCheck($update, 'tutorial'); // Tutorial if(is_file(ROOT_PATH . '/config/tutorial.php')) { From cc88f9882d001eace2ed6f8ef7ad01c97f64ec0f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 25 Oct 2022 20:20:58 +0300 Subject: [PATCH 074/367] Reworked raid share buttons - Chat specific button is now left out if raid is already shared to that chat - Unified the behavior when raid level specific share chat is configured. `SHARE_CHATS_LEVEL_X` will now always override `SHARE_CHATS` --- core/bot/logic/key_util.php | 48 ++++++++++++++++++++++----------- mods/edit_raidlevel.php | 19 +++---------- mods/edit_save.php | 16 +---------- mods/edit_time.php | 24 +++-------------- mods/list_raid.php | 8 +++--- mods/raids_list.php | 8 +++--- mods/save_event_note.php | 5 ++-- mods/share_raid_by_location.php | 8 +++--- mods/trainer_add.php | 2 +- 9 files changed, 53 insertions(+), 85 deletions(-) diff --git a/core/bot/logic/key_util.php b/core/bot/logic/key_util.php index 16b06321..6f7f1b34 100644 --- a/core/bot/logic/key_util.php +++ b/core/bot/logic/key_util.php @@ -72,23 +72,24 @@ function universal_key($keys, $id, $action, $arg, $text = '0') /** - * Share keys. - * @param $id - * @param $action - * @param $update - * @param $chats - * @param $prefix_text - * @param $hide + * Share keys. Has own logic for fetching chat id's if used to generate share keys for raids. + * @param $id Id to pass to callback query + * @param $action Action to pass to callback query + * @param $update Update from Telegram + * @param $raidLevel Raid level if sharing a raid + * @param $chats List of chats if using alternative list + * @param $hideGeneralShare Leave out the general share button * @return array */ -function share_keys($id, $action, $update, $chats = '', $prefix_text = '', $hide = false, $level = '') +function share_keys($id, $action, $update, $raidLevel = '', $chats = '', $hideGeneralShare = false) { global $config; + $keys = []; // Check access. $share_access = bot_access_check($update, 'share-any-chat', true); // Add share button if not restricted to allow sharing to any chat. - if ($share_access == true && $hide == false) { + if ($share_access == true && $hideGeneralShare == false) { debug_log('Adding general share key to inline keys'); // Set the keys. $keys[] = [ @@ -105,17 +106,17 @@ function share_keys($id, $action, $update, $chats = '', $prefix_text = '', $hide debug_log($chats, 'Got specific chats to share to:'); $chats = explode(',', $chats); } else { - if(!empty($level)) { + if(!empty($raidLevel)) { // find chats to share ourselves, if we can - debug_log($level, 'Did not get specific chats to share to, checking level specific for: '); - $level_chat = 'SHARE_CHATS_LEVEL_' . $level; + debug_log($raidLevel, 'Did not get specific chats to share to, checking level specific for: '); + $level_chat = 'SHARE_CHATS_LEVEL_' . $raidLevel; if(!empty($config->{$level_chat})) { $chats = explode(',', $config->{$level_chat}); debug_log($chats, 'Found level specific chats to share to: '); } else { - $chats = explode(',', $config->SHARE_CHATS); - debug_log($chats, 'Chats not specified for level, sharing to globals: '); - } + $chats = explode(',', $config->SHARE_CHATS); + debug_log($chats, 'Chats not specified for level, sharing to globals: '); + } } else { $chats = explode(',', $config->SHARE_CHATS); debug_log($chats, 'Level not given, sharing to globals: '); @@ -123,7 +124,20 @@ function share_keys($id, $action, $update, $chats = '', $prefix_text = '', $hide } // Add keys for each chat. if(!empty($chats)){ + if($raidLevel == '') { + // If raid level is not set we are sharing something else than a raid. + $sharedChats = []; + } else { + $queryShared = my_query(" + SELECT DISTINCT chat_id + FROM cleanup + WHERE raid_id=?", + [ $id ] + ); + $sharedChats = $queryShared->fetchAll(PDO::FETCH_COLUMN, 0); + } foreach($chats as $chat) { + if(in_array($chat, $sharedChats)) continue; // Get chat object debug_log("Getting chat object for '" . $chat . "'"); $chat_obj = get_chat($chat); @@ -133,10 +147,12 @@ function share_keys($id, $action, $update, $chats = '', $prefix_text = '', $hide debug_log('Proper chat object received, continuing to add key for this chat: ' . $chat_obj['result']['title']); $keys[] = [ [ - 'text' => $prefix_text . getTranslation('share_with') . ' ' . $chat_obj['result']['title'], + 'text' => getTranslation('share_with') . ' ' . $chat_obj['result']['title'], 'callback_data' => $id . ':' . $action . ':' . $chat ] ]; + } else { + info_log($chat, 'Invalid chat id in your configuration:'); } } } else { diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index 71015904..eab68a2a 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -36,25 +36,12 @@ $raid = get_raid($raid_id); $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); - // Check if the raid was already shared. - $rs_share = my_query( - " - SELECT COUNT(*) AS raid_count - FROM cleanup - WHERE raid_id = '{$raid_id}' - " - ); - - $shared = $rs_share->fetch(); + $keys = share_keys($raid_id, 'raid_share', $update, $raid['level']); // Add keys for sharing the raid. - if($shared['raid_count'] == 0) { - $keys = share_keys($raid_id, 'raid_share', $update); - + if(!empty($keys)) { // Exit key - $empty_exit_key = []; - $key_exit = universal_key($empty_exit_key, '0', 'exit', '0', getTranslation('abort')); - $keys = array_merge($keys, $key_exit); + $keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); } // Answer callback. diff --git a/mods/edit_save.php b/mods/edit_save.php index 0c55b065..953f0fd6 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -106,20 +106,6 @@ // Get raid level. $raid_level = $raid['level']; -$const = 'SHARE_CHATS_LEVEL_' . $raid_level; -$const_chats = $config->{$const}; - -// Debug. -//debug_log($const,'CONSTANT NAME:'); -//debug_log(constant($const),'CONSTANT VALUE:'); - -// Special sharing keys for raid level? -if(!empty($const_chats)) { - $chats = $const_chats; - debug_log('Special sharing keys detected for raid level ' . $raid_level); -} else { - $chats = ''; -} if($raid['event']!==NULL) { if($raid['event_note']==NULL) { @@ -139,7 +125,7 @@ } // Add keys to share. -$keys_share = share_keys($id, 'raid_share', $update, $chats); +$keys_share = share_keys($id, 'raid_share', $update, $raid_level); $keys = array_merge($keys, $keys_share); // Build message string. diff --git a/mods/edit_time.php b/mods/edit_time.php index b2d5b3d8..bc326a90 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -92,10 +92,7 @@ } // Check for duplicate raid - $duplicate_id = 0; - if($raid_id == 0) { - $duplicate_id = active_raid_duplication_check($gym_id); - } + $duplicate_id = active_raid_duplication_check($gym_id); // Continue with raid creation if($duplicate_id == 0) { @@ -140,25 +137,12 @@ $raid = get_raid($raid_id); $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); - // Check if the raid was already shared. - $rs_share = my_query( - " - SELECT COUNT(*) AS raid_count - FROM cleanup - WHERE raid_id = '{$raid_id}' - " - ); - - $shared = $rs_share->fetch(); + $keys = share_keys($raid_id, 'raid_share', $update, $raid['level']); // Add keys for sharing the raid. - if($shared['raid_count'] == 0) { - $keys = share_keys($raid_id, 'raid_share', $update); - + if(!empty($keys)) { // Exit key - $empty_exit_key = []; - $key_exit = universal_key($empty_exit_key, '0', 'exit', '0', getTranslation('abort')); - $keys = array_merge($keys, $key_exit); + $keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); } // Answer callback. diff --git a/mods/list_raid.php b/mods/list_raid.php index e675a827..4dfbc70a 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -63,16 +63,14 @@ // Add keys to share. debug_log($raid, 'raw raid data for share: '); - $keys_share = share_keys($raid['id'], 'raid_share', $update, '', '', false, $raid['level']); - if(is_array($keys_share)) { + $keys_share = share_keys($raid['id'], 'raid_share', $update, $raid['level']); + if(!empty($keys_share)) { $keys = array_merge($keys, $keys_share); } else { debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key - $empty_exit_key = []; - $key_exit = universal_key($empty_exit_key, '0', 'exit', '1', getTranslation('done')); - $keys = array_merge($keys, $key_exit); + $keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); // Get message. $msg = show_raid_poll_small($raid); diff --git a/mods/raids_list.php b/mods/raids_list.php index a247e7a1..8c85ca0f 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -39,16 +39,14 @@ // Add keys to share. debug_log($raid, 'raw raid data for share: '); -$keys_share = share_keys($raid['id'], 'raid_share', $update, '', '', false, $raid['level']); -if(is_array($keys_share)) { +$keys_share = share_keys($raid['id'], 'raid_share', $update, $raid['level']); +if(!empty($keys_share)) { $keys = array_merge($keys, $keys_share); } else { debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key -$empty_exit_key = []; -$key_exit = universal_key($empty_exit_key, '0', 'exit', '1', getTranslation('done')); -$keys = array_merge($keys, $key_exit); +$keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); // Get message. $msg = show_raid_poll_small($raid); diff --git a/mods/save_event_note.php b/mods/save_event_note.php index f00cb97f..76ee6def 100644 --- a/mods/save_event_note.php +++ b/mods/save_event_note.php @@ -15,10 +15,11 @@ edit_message_keyboard($modifiers['old_message_id'], [], $user_id); // Return message to user +$raid = get_raid($raid_id); $msg = ''; $msg .= getTranslation('raid_saved') . CR; $msg .= CR.getTranslation('event_note').': '.$update['message']['text'].CR2; -$msg .= show_raid_poll_small(get_raid($raid_id)) . CR; +$msg .= show_raid_poll_small($raid) . CR; debug_log($msg); $keys = [ @@ -35,7 +36,7 @@ ] ] ]; -$keys_share = share_keys($raid_id, 'raid_share', $update, $chats); +$keys_share = share_keys($raid_id, 'raid_share', $update, $raid['level']); $keys = array_merge($keys, $keys_share); debug_log($keys); diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 2f542ee0..ed86d487 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -19,16 +19,14 @@ // Add keys to share. debug_log($raid, 'raw raid data for share: '); - $keys_share = share_keys($raid['id'], 'raid_share', $update, '', '', false, $raid['level']); - if(is_array($keys_share)) { + $keys_share = share_keys($raid['id'], 'raid_share', $update, $raid['level']); + if(!empty($keys_share)) { $keys = array_merge($keys, $keys_share); } else { debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key - $empty_exit_key = []; - $key_exit = universal_key($empty_exit_key, '0', 'exit', '1', getTranslation('done')); - $keys = array_merge($keys, $key_exit); + $keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); // Get message. $msg = show_raid_poll_small($raid); diff --git a/mods/trainer_add.php b/mods/trainer_add.php index baf1b208..312e925e 100644 --- a/mods/trainer_add.php +++ b/mods/trainer_add.php @@ -81,7 +81,7 @@ // Create keys. if(!empty($chats)) { - $keys = share_keys('0', 'trainer_share', $update, $chats, '', true); + $keys = share_keys('0', 'trainer_share', $update, '', $chats, true); } // Add abort key. From 0e4ba5ddaeea211e0db1fd64c14356f8a715ba7f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 25 Oct 2022 21:50:39 +0300 Subject: [PATCH 075/367] Moved more stuff under botUser class Moved/added functions raidAccessCheck, updateUser, defineUserLanguage, updateUserdb under botUser class. Also added botUser->userLanguage variable and got rid of the old constant --- core/bot/logic.php | 2 - core/bot/logic/language.php | 4 +- core/bot/logic/update_user.php | 21 ---- core/bot/logic/update_userdb.php | 80 ------------- core/bot/user.php | 186 ++++++++++++++++++++++++++++++- core/bot/userlanguage.php | 38 ------- index.php | 16 +-- logic.php | 1 - logic/get_pokemon_id_by_name.php | 4 +- logic/raid_access_check.php | 54 --------- mods/list_raid.php | 28 +++-- mods/raid_edit_poke.php | 6 +- mods/raid_set_poke.php | 11 +- mods/raid_share.php | 10 +- mods/raids_delete.php | 16 +-- mods/raids_list.php | 36 +++--- 16 files changed, 254 insertions(+), 259 deletions(-) delete mode 100644 core/bot/logic/update_user.php delete mode 100644 core/bot/logic/update_userdb.php delete mode 100644 core/bot/userlanguage.php delete mode 100644 logic/raid_access_check.php diff --git a/core/bot/logic.php b/core/bot/logic.php index 06463d80..f2c33105 100644 --- a/core/bot/logic.php +++ b/core/bot/logic.php @@ -9,7 +9,5 @@ require_once('logic/geo_api.php'); require_once('logic/key_util.php'); require_once('logic/language.php'); -require_once('logic/update_userdb.php'); -require_once('logic/update_user.php'); ?> diff --git a/core/bot/logic/language.php b/core/bot/logic/language.php index e1c5038d..995029bc 100644 --- a/core/bot/logic/language.php +++ b/core/bot/logic/language.php @@ -21,7 +21,7 @@ function getPublicTranslation($text) */ function getTranslation($text, $override = false, $override_language = '') { - global $config; + global $config, $botUser; debug_log($text,'T:'); $translation = ''; $text = trim($text); @@ -31,7 +31,7 @@ function getTranslation($text, $override = false, $override_language = '') if($override == true && $override_language != '') { $language = $override_language; } else { - $language = USERLANGUAGE; + $language = $botUser->userLanguage; } // Pokemon name? diff --git a/core/bot/logic/update_user.php b/core/bot/logic/update_user.php deleted file mode 100644 index 8ee02996..00000000 --- a/core/bot/logic/update_user.php +++ /dev/null @@ -1,21 +0,0 @@ - diff --git a/core/bot/logic/update_userdb.php b/core/bot/logic/update_userdb.php deleted file mode 100644 index ce73e2ae..00000000 --- a/core/bot/logic/update_userdb.php +++ /dev/null @@ -1,80 +0,0 @@ -prepare( - " - INSERT INTO users - SET user_id = :id, - nick = :nick, - name = :name, - lang = :lang, - auto_alarm = :auto_alarm - ON DUPLICATE KEY - UPDATE nick = :nick, - name = :name, - lang = IF(lang_manual = 1, lang, :lang), - auto_alarm = IF(:auto_alarm = 1, 1, auto_alarm) - " - ); - $alarm_setting = ($config->RAID_AUTOMATIC_ALARM ? 1 : 0); - $stmt->bindParam(':id', $id); - $stmt->bindParam(':nick', $nick); - $stmt->bindParam(':name', $name); - $stmt->bindParam(':lang', $lang); - $stmt->bindParam(':auto_alarm', $alarm_setting); - $stmt->execute(); - - return 'Updated user ' . $nick; -} -?> diff --git a/core/bot/user.php b/core/bot/user.php index ea669d0f..22f90fc9 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -6,6 +6,7 @@ class botUser 'privileges' => [], 'grantedBy' => '', ]; + public $userLanguage = ''; /** * Run privilege check for Telegram user and save them for later use. @@ -95,13 +96,11 @@ public function privilegeCheck($update) { // Ignore "Restricted"? if($chatObj['result']['status'] == 'restricted' && in_array('ignore-restricted', $privilegeList)) { - // Reset access file. $privilegeList = NULL; } // Ignore "kicked"? if($chatObj['result']['status'] == 'kicked' && in_array('ignore-kicked', $privilegeList)) { - // Reset access file. $privilegeList = NULL; } } @@ -175,5 +174,188 @@ public function accessCheck($update, $permission = 'access-bot', $return_result exit; } } + + /** + * Raid access check. + * @param $update + * @param $data + * @return bool + */ + public function raidAccessCheck($update, $raidId, $permission, $return_result = false) + { + global $botUser; + // Default: Deny access to raids + $raid_access = false; + + // Build query. + $rs = my_query( + " + SELECT user_id + FROM raids + WHERE id = {$raidId} + " + ); + + $raid = $rs->fetch(); + + // Check permissions + if ($rs->rowCount() == 0 or $update['callback_query']['from']['id'] != $raid['user_id']) { + // Check "-all" permission + debug_log('Checking permission:' . $permission . '-all'); + $permission = $permission . '-all'; + $raid_access = $botUser->accessCheck($update, $permission, $return_result); + } else { + // Check "-own" permission + debug_log('Checking permission:' . $permission . '-own'); + $permission_own = $permission . '-own'; + $permission_all = $permission . '-all'; + $raid_access = $botUser->accessCheck($update, $permission_own, true); + + // Check "-all" permission if we get "access denied" + // Maybe necessary if user has only "-all" configured, but not "-own" + if(!$raid_access) { + debug_log('Permission check for ' . $permission_own . ' failed! Maybe the access is just granted via ' . $permission . '-all ?'); + debug_log('Checking permission:' . $permission_all); + $raid_access = $botUser->accessCheck($update, $permission_all, $return_result); + } else { + $raid_access = $botUser->accessCheck($update, $permission_own, $return_result); + } + } + + // Return result + return $raid_access; + } + + /** + * Update users info if allowed + * @param $update + * @return bool|mysqli_result + */ + public function updateUser($update) + { + global $ddos_count; + + // Check DDOS count + if ($ddos_count < 2) { + // Update the user. + $userUpdate = $this->updateUserdb($update); + + // Write to log. + debug_log('Update user: ' . $userUpdate); + } + } + + /** + * Define userlanguage + * @param $update + * @return bool|mysqli_result + */ + public function defineUserLanguage($update) { + global $config; + // Write to log. + debug_log('Language Check'); + + // Get language from user - otherwise use language from config. + if ($config->LANGUAGE_PRIVATE == '') { + // Message or callback? + if(isset($update['message']['from'])) { + $from = $update['message']['from']; + } else if(isset($update['callback_query']['from'])) { + $from = $update['callback_query']['from']; + } else if(isset($update['inline_query']['from'])) { + $from = $update['inline_query']['from']; + } + if(isset($from)) { + $q = my_query("SELECT lang FROM users WHERE user_id='".$from['id']."' LIMIT 1"); + $res = $q->fetch(); + $language_code = $res['lang']; + }else { + $language_code = ''; + } + + // Get and define userlanguage. + $languages = $GLOBALS['languages']; + + // Get languages from normal translation. + if(array_key_exists($language_code, $languages)) { + $userlanguage = $languages[$language_code]; + } else { + $userlanguage = DEFAULT_LANGUAGE; + } + + debug_log('User language: ' . $userlanguage); + $this->userLanguage = $userlanguage; + } else { + // Set user language to language from config. + $this->userLanguage = $config->LANGUAGE_PRIVATE; + } + } + + /** + * Update users info into database. + * @param $update + * @return bool|mysqli_result + */ + private function updateUserdb($update) + { + global $dbh, $config; + + if (isset($update['message']['from'])) { + $msg = $update['message']['from']; + } else if (isset($update['callback_query']['from'])) { + $msg = $update['callback_query']['from']; + } else if (isset($update['inline_query']['from'])) { + $msg = $update['inline_query']['from']; + } + + if (empty($msg['id'])) { + debug_log('No id', '!'); + debug_log($update, '!'); + return false; + } + $id = $msg['id']; + + $name = ''; + $sep = ''; + + if (isset($msg['first_name'])) { + $name = $msg['first_name']; + $sep = ' '; + } + + if (isset($msg['last_name'])) { + $name .= $sep . $msg['last_name']; + } + + $nick = (isset($msg['username'])) ? $msg['username'] : ''; + + $lang = (isset($msg['language_code'])) ? $msg['language_code'] : ''; + + // Create or update the user. + $stmt = $dbh->prepare( + ' + INSERT INTO users + SET user_id = :id, + nick = :nick, + name = :name, + lang = :lang, + auto_alarm = :auto_alarm + ON DUPLICATE KEY + UPDATE nick = :nick, + name = :name, + lang = IF(lang_manual = 1, lang, :lang), + auto_alarm = IF(:auto_alarm = 1, 1, auto_alarm) + ' + ); + $alarm_setting = ($config->RAID_AUTOMATIC_ALARM ? 1 : 0); + $stmt->bindParam(':id', $id); + $stmt->bindParam(':nick', $nick); + $stmt->bindParam(':name', $name); + $stmt->bindParam(':lang', $lang); + $stmt->bindParam(':auto_alarm', $alarm_setting); + $stmt->execute(); + + return 'Updated user ' . $nick; + } } ?> \ No newline at end of file diff --git a/core/bot/userlanguage.php b/core/bot/userlanguage.php deleted file mode 100644 index 48f21ee5..00000000 --- a/core/bot/userlanguage.php +++ /dev/null @@ -1,38 +0,0 @@ -LANGUAGE_PRIVATE == '') { - // Message or callback? - if(isset($update['message']['from'])) { - $from = $update['message']['from']; - } else if(isset($update['callback_query']['from'])) { - $from = $update['callback_query']['from']; - } else if(isset($update['inline_query']['from'])) { - $from = $update['inline_query']['from']; - } - if(isset($from)) { - $q = my_query("SELECT lang FROM users WHERE user_id='".$from['id']."' LIMIT 1"); - $res = $q->fetch(); - $language_code = $res['lang']; - }else { - $language_code = ''; - } - - // Get and define userlanguage. - $languages = $GLOBALS['languages']; - - // Get languages from normal translation. - if(array_key_exists($language_code, $languages)) { - $userlanguage = $languages[$language_code]; - } else { - $userlanguage = DEFAULT_LANGUAGE; - } - - debug_log('User language: ' . $userlanguage); - define('USERLANGUAGE', $userlanguage); -} else { - // Set user language to language from config. - define('USERLANGUAGE', $config->LANGUAGE_PRIVATE); -} diff --git a/index.php b/index.php index 6efd4e7a..dda9f0ac 100644 --- a/index.php +++ b/index.php @@ -57,25 +57,25 @@ $data['arg'] = $splitData[2]; } +// Run cleanup if requested +if (isset($update['cleanup'])) { + include_once(CORE_BOT_PATH . '/cleanup_run.php'); + cleanup_auth_and_run($update); +} + // DDOS protection if($config->ENABLE_DDOS_PROTECTION) { include_once(CORE_BOT_PATH . '/ddos.php'); } // Update the user -update_user($update); +$botUser->updateUser($update); // Get language -include_once(CORE_BOT_PATH . '/userlanguage.php'); +$botUser->defineUserLanguage($update); $botUser->privilegeCheck($update); -// Run cleanup if requested -if (isset($update['cleanup'])) { - include_once(CORE_BOT_PATH . '/cleanup_run.php'); - cleanup_auth_and_run($update); -} - // Callback query received. if (isset($update['callback_query'])) { // Logic to get the module diff --git a/logic.php b/logic.php index afe4206d..eeef688b 100644 --- a/logic.php +++ b/logic.php @@ -43,7 +43,6 @@ include('logic/mapslink.php'); include('logic/new_user.php'); include('logic/pokemon_keys.php'); -include('logic/raid_access_check.php'); include('logic/raid_edit_gym_keys.php'); include('logic/raid_edit_gyms_first_letter_keys.php'); include('logic/raid_edit_raidlevel_keys.php'); diff --git a/logic/get_pokemon_id_by_name.php b/logic/get_pokemon_id_by_name.php index d828f0e7..e8d4e807 100644 --- a/logic/get_pokemon_id_by_name.php +++ b/logic/get_pokemon_id_by_name.php @@ -7,7 +7,7 @@ */ function get_pokemon_id_by_name($pokemon_name, $get_from_db = false) { - global $dbh; + global $dbh, $botUser; debug_log($pokemon_name,'P:'); // Explode pokemon name in case we have a form too. @@ -38,7 +38,7 @@ function get_pokemon_id_by_name($pokemon_name, $get_from_db = false) $pokemon_form = ($poke_form!="")?$poke_form:"normal"; // Set language - $language = USERLANGUAGE; + $language = $botUser->userLanguage; if($get_from_db) { // Fetch Pokemon form ID from database $stmt = $dbh->prepare(" diff --git a/logic/raid_access_check.php b/logic/raid_access_check.php deleted file mode 100644 index 252d2cf9..00000000 --- a/logic/raid_access_check.php +++ /dev/null @@ -1,54 +0,0 @@ -fetch(); - - // Check permissions - if ($rs->rowCount() == 0 or $update['callback_query']['from']['id'] != $raid['user_id']) { - // Check "-all" permission - debug_log('Checking permission:' . $permission . '-all'); - $permission = $permission . '-all'; - $raid_access = $botUser->accessCheck($update, $permission, $return_result); - } else { - // Check "-own" permission - debug_log('Checking permission:' . $permission . '-own'); - $permission_own = $permission . '-own'; - $permission_all = $permission . '-all'; - $raid_access = $botUser->accessCheck($update, $permission_own, true); - - // Check "-all" permission if we get "access denied" - // Maybe necessary if user has only "-all" configured, but not "-own" - if(!$raid_access) { - debug_log('Permission check for ' . $permission_own . ' failed! Maybe the access is just granted via ' . $permission . '-all ?'); - debug_log('Checking permission:' . $permission_all); - $raid_access = $botUser->accessCheck($update, $permission_all, $return_result); - } else { - $raid_access = $botUser->accessCheck($update, $permission_own, $return_result); - } - } - - // Return result - return $raid_access; -} - - -?> diff --git a/mods/list_raid.php b/mods/list_raid.php index e234f908..ea44fecb 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -46,20 +46,24 @@ 'text' => getTranslation('expand'), 'callback_data' => $raid['id'] . ':vote_refresh:0', ] - ], - [ - [ - 'text' => getTranslation('update_pokemon'), - 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], - ] - ], - [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => $raid['id'] . ':raids_delete:0' - ] ] ]; + if($botUser->raidAccessCheck($update, $raid_id, 'pokemon', true)) { + $keys[] = [ + [ + 'text' => getTranslation('update_pokemon'), + 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], + ] + ]; + } + if($botUser->raidAccessCheck($update, $raid_id, 'delete', true)) { + $keys[] = [ + [ + 'text' => getTranslation('delete'), + 'callback_data' => $raid['id'] . ':raids_delete:0' + ] + ]; + } // Add keys to share. debug_log($raid, 'raw raid data for share: '); diff --git a/mods/raid_edit_poke.php b/mods/raid_edit_poke.php index 546f1833..c717f8fd 100644 --- a/mods/raid_edit_poke.php +++ b/mods/raid_edit_poke.php @@ -6,12 +6,12 @@ //debug_log($update); //debug_log($data); -// Access check. -raid_access_check($update, $data, 'pokemon'); - // Set the id. $raid_id = $data['id']; +// Access check. +$botUser->raidAccessCheck($update, $raid_id, 'pokemon'); + // Get raid level $raid_level = $data['arg']; diff --git a/mods/raid_set_poke.php b/mods/raid_set_poke.php index f936b614..d2c9a170 100644 --- a/mods/raid_set_poke.php +++ b/mods/raid_set_poke.php @@ -6,11 +6,12 @@ //debug_log($update); //debug_log($data); +// Set the id. +$raidId = $data['id']; + // Access check. -raid_access_check($update, $data, 'pokemon'); +$botUser->raidAccessCheck($update, $raidId, 'pokemon'); -// Set the id. -$id = $data['id']; $pokemon_id_form = get_pokemon_by_table_id($data['arg']); // Update pokemon in the raid table. @@ -19,12 +20,12 @@ UPDATE raids SET pokemon = '{$pokemon_id_form['pokedex_id']}', pokemon_form = '{$pokemon_id_form['pokemon_form_id']}' - WHERE id = {$id} + WHERE id = {$raidId} " ); // Get raid times. -$raid = get_raid($data['id']); +$raid = get_raid($raidId); // Create the keys. $keys = []; diff --git a/mods/raid_share.php b/mods/raid_share.php index d8bd51be..6aaa398a 100644 --- a/mods/raid_share.php +++ b/mods/raid_share.php @@ -7,16 +7,16 @@ //debug_log($update); //debug_log($data); -// Access check. -raid_access_check($update, $data, 'share'); - // Get raid id. -$id = $data['id']; +$raidId = $data['id']; + +// Access check. +$botUser->raidAccessCheck($update, $raidId, 'share'); // Get chat id. $chat = $data['arg']; -$tg_json = send_raid_poll($id, $chat); +$tg_json = send_raid_poll($raidId, $chat); // Set callback keys and message $callback_msg = getTranslation('successfully_shared'); diff --git a/mods/raids_delete.php b/mods/raids_delete.php index a6d377f2..18e9086b 100644 --- a/mods/raids_delete.php +++ b/mods/raids_delete.php @@ -6,9 +6,6 @@ //debug_log($update); //debug_log($data); -// Access check. -raid_access_check($update, $data, 'delete'); - // Get the action. // 0 -> Confirmation required // 1 -> Cancel deletion @@ -16,12 +13,15 @@ $action = $data['arg']; // Get the raid id. -$id = $data['id']; +$raidId = $data['id']; + +// Access check. +$botUser->raidAccessCheck($update, $raidId, 'delete'); // Execute the action. if ($action == 0) { // Get raid. - $raid = get_raid($id); + $raid = get_raid($raidId); // Write to log. debug_log('Asking for confirmation to delete the following raid:'); @@ -45,14 +45,14 @@ $msg = EMOJI_WARN . ' ' . getTranslation('delete_this_raid') . ' ' . EMOJI_WARN . CR . CR; $msg .= show_raid_poll_small($raid); } else if ($action == 1) { - debug_log('Raid deletion for ' . $id . ' was canceled!'); + debug_log('Raid deletion for ' . $raidId . ' was canceled!'); // Set message. $msg = '' . getTranslation('raid_deletion_was_canceled') . ''; // Set keys. $keys = []; } else if ($action == 2) { - debug_log('Confirmation to delete raid ' . $id . ' was received!'); + debug_log('Confirmation to delete raid ' . $raidId . ' was received!'); // Set message. $msg = getTranslation('raid_successfully_deleted'); @@ -60,7 +60,7 @@ $keys = []; // Delete raid from database. - delete_raid($id); + delete_raid($raidId); } // Build callback message string. diff --git a/mods/raids_list.php b/mods/raids_list.php index d3c7c18a..3328ee50 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -6,14 +6,14 @@ //debug_log($update); //debug_log($data); +// Get ID. +$raidId = $data['id']; + // Check access. $botUser->accessCheck($update, 'list'); -// Get ID. -$id = $data['id']; - // Get raid details. -$raid = get_raid($id); +$raid = get_raid($raidId); // Create keys array. $keys = [ @@ -22,20 +22,24 @@ 'text' => getTranslation('expand'), 'callback_data' => $raid['id'] . ':vote_refresh:0', ] - ], - [ - [ - 'text' => getTranslation('update_pokemon'), - 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], - ] - ], - [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => $raid['id'] . ':raids_delete:0' - ] ] ]; +if($botUser->raidAccessCheck($update, $raidId, 'pokemon', true)) { + $keys[] = [ + [ + 'text' => getTranslation('update_pokemon'), + 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], + ] + ]; +} +if($botUser->raidAccessCheck($update, $raidId, 'delete', true)) { + $keys[] = [ + [ + 'text' => getTranslation('delete'), + 'callback_data' => $raid['id'] . ':raids_delete:0' + ] + ]; +} // Add keys to share. debug_log($raid, 'raw raid data for share: '); From 3505fbaa5e612fa92468107ce61e77c681a2a1de Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 26 Oct 2022 20:06:46 +0300 Subject: [PATCH 076/367] Match privilege names with the ones in documentation --- commands/help.php | 4 ---- core/bot/user.php | 2 ++ logic/edit_gym_keys.php | 6 +----- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/commands/help.php b/commands/help.php index 488f697a..3204789b 100644 --- a/commands/help.php +++ b/commands/help.php @@ -18,10 +18,6 @@ $permissions[] = 'trainer'; $permissions[] = 'gym-details'; $permissions[] = 'gym-edit'; - $permissions[] = 'gym-name'; - $permissions[] = 'gym-address'; - $permissions[] = 'gym-gps'; - $permissions[] = 'gym-note'; $permissions[] = 'gym-add'; $permissions[] = 'portal-import'; $permissions[] = 'config-get'; diff --git a/core/bot/user.php b/core/bot/user.php index 22f90fc9..4d0fceb2 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -103,6 +103,8 @@ public function privilegeCheck($update) { if($chatObj['result']['status'] == 'kicked' && in_array('ignore-kicked', $privilegeList)) { $privilegeList = NULL; } + } else { + continue; } // Debug. diff --git a/logic/edit_gym_keys.php b/logic/edit_gym_keys.php index 9024ed50..751c9cfc 100644 --- a/logic/edit_gym_keys.php +++ b/logic/edit_gym_keys.php @@ -54,23 +54,19 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add ] ]; } - if($botUser->accessCheck($update, 'gym-note', true)) { + if($botUser->accessCheck($update, 'gym-edit', true)) { $keys[] = [ [ 'text' => EMOJI_INFO . ' ' . (!empty($gym_note) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_add_edit_note"), 'callback_data' => $gym_id . ':gym_edit_details:note' ] ]; - } - if($botUser->accessCheck($update, 'gym-address', true)) { $keys[] = [ [ 'text' => EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("forest")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), 'callback_data' => $gym_id . ':gym_edit_details:addr' ] ]; - } - if($botUser->accessCheck($update, 'gym-gps', true)) { $keys[] = [ [ 'text' => EMOJI_HERE . ' ' . getTranslation("gym_edit_coordinates"), From c470fe2915a1b1204ee4eafc7e22e513d28a7d7d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 26 Oct 2022 21:40:47 +0300 Subject: [PATCH 077/367] Added more fallbacks for district in OSM reverse lookup --- core/bot/logic/geo_api.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/bot/logic/geo_api.php b/core/bot/logic/geo_api.php index 94e0383c..80f2cad1 100644 --- a/core/bot/logic/geo_api.php +++ b/core/bot/logic/geo_api.php @@ -179,6 +179,10 @@ function get_address($lat, $lon) $location['district'] = $data['address']['village']; }elseif(isset($data['address']['county']) && !empty($data['address']['county'])) { $location['district'] = $data['address']['county']; + }elseif(isset($data['address']['country']) && !empty($data['address']['country'])) { + $location['district'] = $data['address']['country']; + }else { + $location['district'] = 'Unknown'; } // No valid data received. } else { From 1c1fd214f703de962b80f1e55f41a61042e06912 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 28 Oct 2022 17:09:55 +0300 Subject: [PATCH 078/367] Fixed `access` not working for groups Fixed also `/start` not returning access denied --- commands/start.php | 11 ++++++++--- core/bot/user.php | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/commands/start.php b/commands/start.php index cd2e63dc..107b789a 100644 --- a/commands/start.php +++ b/commands/start.php @@ -8,9 +8,14 @@ $new_user = new_user($update['message']['from']['id']); $access = $botUser->accessCheck($update, 'create', true, $new_user); -if(!$access && $botUser->accessCheck($update, 'list', true) && !$new_user){ - debug_log('No access to create, will do a list instead'); - require('list.php'); +if(!$access && !$new_user) { + if($botUser->accessCheck($update, 'list', true)){ + debug_log('No access to create, will do a list instead'); + require('list.php'); + }else { + $response_msg = '' . getTranslation('bot_access_denied') . ''; + send_message($update['message']['from']['id'], $response_msg); + } exit; } if($new_user && !$access) { diff --git a/core/bot/user.php b/core/bot/user.php index 4d0fceb2..9e0fe7b3 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -50,7 +50,9 @@ public function privilegeCheck($update) { $accessChats = [$user_id => null]; }else { $chatIds = []; - foreach($telegramRoles as $roleToCheck) { + $rolesToCheck = $telegramRoles; + $rolesToCheck[] = 'access'; + foreach($rolesToCheck as $roleToCheck) { $chatFiles = str_replace(ACCESS_PATH . '/' . $roleToCheck, '', glob(ACCESS_PATH . '/' . $roleToCheck . '-*')); $chatIds = array_merge($chatIds, $chatFiles); } From 5da9db6c806ee007a217f52f3b422037757c70ad Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 31 Oct 2022 15:34:57 +0200 Subject: [PATCH 079/367] Refactored code for translation - Refactored for performance and (hopefully) cleaner code - Got rid of the core language directory as there really is no reason to have that anymore - Renamed a couple of translation titles --- core/bot/logic/geo_api.php | 4 +- core/bot/logic/language.php | 231 +++---- core/bot/paths.php | 2 - core/lang/help.json | 80 --- core/lang/language.json | 795 ------------------------- core/lang/requirements.txt | 1 - core/lang/translate.py | 58 -- getTranslations.php | 5 +- lang/help.json | 52 ++ lang/language.json | 793 ++++++++++++++++++++++++ {core/lang => lang}/pokemon.json | 0 {core/lang => lang}/pokemon_forms.json | 0 {core/lang => lang}/pokemon_moves.json | 0 logic/edit_gym_keys.php | 2 +- 14 files changed, 924 insertions(+), 1099 deletions(-) delete mode 100644 core/lang/help.json delete mode 100644 core/lang/language.json delete mode 100644 core/lang/requirements.txt delete mode 100644 core/lang/translate.py rename {core/lang => lang}/pokemon.json (100%) rename {core/lang => lang}/pokemon_forms.json (100%) rename {core/lang => lang}/pokemon_moves.json (100%) diff --git a/core/bot/logic/geo_api.php b/core/bot/logic/geo_api.php index 80f2cad1..93c79aae 100644 --- a/core/bot/logic/geo_api.php +++ b/core/bot/logic/geo_api.php @@ -114,7 +114,7 @@ function get_address($lat, $lon) // Rename street responses. switch ($location['street']) { case 'Unnamed Road': - $location['street'] = getPublicTranslation('forest'); + $location['street'] = getPublicTranslation('directions'); break; } @@ -241,7 +241,7 @@ function format_address($address) } else if(!empty($helper) && empty($formatted)) { $return = $helper; } else { - $return = getPublicTranslation('forest'); + $return = getPublicTranslation('directions'); } return $return; diff --git a/core/bot/logic/language.php b/core/bot/logic/language.php index e1c5038d..7a9d7c6f 100644 --- a/core/bot/logic/language.php +++ b/core/bot/logic/language.php @@ -1,4 +1,52 @@ false, + 'pokemonNames' => false, + 'pokemonMoves' => false, + 'pokemonForms' => false, + 'botHelp' => false, + 'custom' => false, + ]; + static $fileMap = [ + 'botLang' => 'language', + 'pokemonNames' => 'pokemon', + 'pokemonMoves' => 'pokemon_moves', + 'pokemonForms' => 'pokemon_forms', + 'botHelp' => 'help', + ]; + $translation = $savedTranslations[$translationTitle]; + + // Return translation if it's in memory already + if($translation !== false) return $translation; + + // Load translations from this file + $fileContents = file_get_contents(BOT_LANG_PATH . '/' . $fileMap[$translationTitle] . '.json'); + $translation = json_decode($fileContents, true); + + // Has custom translation already been processed? + if($savedTranslations['custom'] === false) { + $savedTranslations['custom'] = []; + // Load custom language file if it exists + if(is_file(CUSTOM_PATH . '/language.json')) { + $customContents = file_get_contents(CUSTOM_PATH . '/language.json'); + $savedTranslations['custom'] = json_decode($customContents, true); + } + } + + foreach($savedTranslations['custom'] as $title => $translation) { + if(key_exists($title, $json)) { + debug_log($title, 'Found custom translation for'); + $json[$title] = $translation; + unset($savedTranslations['custom'][$title]); + } + } + $savedTranslations[$translationTitle] = $translation; + + return $translation; +} + /** * Call the translation function with override parameters. * @param string $text @@ -6,177 +54,46 @@ */ function getPublicTranslation($text) { - global $config; - $translation = getTranslation($text, true, $config->LANGUAGE_PUBLIC); - - return $translation; + global $config; + return getTranslation($text, $config->LANGUAGE_PUBLIC); } /** * Gets a table translation out of the json file. * @param string $text - * @param bool $override * @param string $override_language * @return string translation */ -function getTranslation($text, $override = false, $override_language = '') +function getTranslation($text, $language = USERLANGUAGE) { - global $config; - debug_log($text,'T:'); - $translation = ''; - $text = trim($text); - - $language = ''; - // Override language? - if($override == true && $override_language != '') { - $language = $override_language; - } else { - $language = USERLANGUAGE; - } - - // Pokemon name? - if(strpos($text, 'pokemon_id_') === 0) { - // Translation filename - $tfile = CORE_LANG_PATH . '/pokemon.json'; + debug_log($text,'T:'); + $text = trim($text); - // Get ID from string - e.g. 150 from pokemon_id_150 - $pokemon_id = substr($text, strrpos($text, '_') + 1); + $tfile = 'botLang'; + // Pokemon name? + if(strpos($text, 'pokemon_id_') === 0) $tfile = 'pokemonNames'; - // Make sure we have a valid id. - if(is_numeric($pokemon_id) && $pokemon_id > 0) { - $str = file_get_contents($tfile); + // Pokemon form? + if(strpos($text, 'pokemon_form_') === 0) $tfile = 'pokemonForms'; - $json = json_decode($str, true); - if(!isset($json[$text][$language])) { - // If translation wasn't found, try to use english as fallback - $language = DEFAULT_LANGUAGE; - } - if(!isset($json[$text][$language])) { - $translation = false; - }else { - $translation = $json[$text][$language]; - } + // Pokemon moves? + if(strpos($text, 'pokemon_move_') === 0) $tfile = 'pokemonMoves'; - // Return false - } else { - debug_log($pokemon_id,'T: Received invalid pokemon id for translation:'); - $translation = false; - } + // Pokemon moves? + if(strpos($text, 'help_') === 0) $tfile = 'botHelp'; - // Pokemon form? - } else if(strpos($text, 'pokemon_form_') === 0) { - // Translation filename - $tfile = CORE_LANG_PATH . '/pokemon_forms.json'; + // Debug log translation file + debug_log($tfile,'T:'); - $str = file_get_contents($tfile); - $json = json_decode($str, true); + $translations = getTranslationFile($tfile); - // Pokemon moves? - } else if(strpos($text, 'pokemon_move_') === 0) { - // Translation filename - $tfile = CORE_LANG_PATH . '/pokemon_moves.json'; - - $str = file_get_contents($tfile); - $json = json_decode($str, true); - - // Custom language file. - } else if(is_file(CUSTOM_PATH . '/language.json')) { - $tfile = CUSTOM_PATH . '/language.json'; - - $str = file_get_contents($tfile); - $json = json_decode($str, true); - } - - // Other translation - if(!(isset($json[$text]))){ - // Specific translation file? - // E.g. Translation = hello_world_123, then check if hello_world.json exists. - if(is_file(BOT_LANG_PATH . '/' . substr($text, 0, strrpos($text, '_')) . '.json')) { - // Translation filename - $tfile = BOT_LANG_PATH . '/' . substr($text, 0, strrpos($text, '_')) . '.json'; - - $str = file_get_contents($tfile); - $json = json_decode($str, true); - - // Core language file. - if(!(isset($json[$text]))){ - // Translation filename - $tfile = CORE_LANG_PATH . '/language.json'; - - // Make sure file exists. - if(is_file($tfile)) { - $str = file_get_contents($tfile); - $json = json_decode($str, true); - } - } - } - - // Bot language file. - if(!(isset($json[$text]))){ - // Translation filename - $tfile = BOT_LANG_PATH . '/language.json'; - - // Make sure file exists. - if(is_file($tfile)) { - $str = file_get_contents($tfile); - $json = json_decode($str, true); - } - } - - // Translation not in core or bot language file? - Try other core files. - if(!(isset($json[$text]))){ - // Get all bot specific language files - $langfiles = glob(CORE_LANG_PATH . '/*.json'); - - // Find translation in the right file - foreach($langfiles as $file) { - $tfile = $file; - $str = file_get_contents($file); - $json = json_decode($str, true); - // Exit foreach once found - if(isset($json[$text])) { - break; - } - } - } - - // Translation not in core or bot language file? - Try other bot files. - if(!(isset($json[$text]))){ - // Get all bot specific language files - $langfiles = glob(BOT_LANG_PATH . '/*.json'); - - // Find translation in the right file - foreach($langfiles as $file) { - $tfile = $file; - $str = file_get_contents($file); - $json = json_decode($str, true); - // Exit foreach once found - if(isset($json[$text])) { - break; - } - } - } - } - - // Debug log translation file - debug_log($tfile,'T:'); - - // Return pokemon name or translation - if(strpos($text, 'pokemon_id_') === 0) { - return $translation; - } else { - // Fallback to English when there is no language key or translation is not yet done. - if(isset($json[$text][$language]) && $json[$text][$language] != 'TRANSLATE'){ - $translation = $json[$text][$language]; - } else { - $language = DEFAULT_LANGUAGE; - if(isset($json[$text][$language])){ - $translation = $json[$text][$language]; - }else { - $translation = ''; - } - } - //debug_log($translation,'T:'); - return $translation; - } + // Fallback to English when there is no language key or translation is not yet done. + if(isset($translations[$text][$language]) && $translations[$text][$language] != 'TRANSLATE') + $translation = $translations[$text][$language]; + elseif(isset($translations[$text][DEFAULT_LANGUAGE])) + $translation = $translations[$text][DEFAULT_LANGUAGE]; + else + $translation = $text; + debug_log($translation,'T:'); + return $translation; } diff --git a/core/bot/paths.php b/core/bot/paths.php index 6fcf4ca9..82dd84fc 100644 --- a/core/bot/paths.php +++ b/core/bot/paths.php @@ -5,9 +5,7 @@ // Core Paths define('CORE_TG_PATH', CORE_PATH . '/telegram'); define('CORE_BOT_PATH', CORE_PATH . '/bot'); -define('CORE_LANG_PATH', CORE_PATH . '/lang'); define('CORE_COMMANDS_PATH', CORE_PATH . '/commands'); -define('CORE_CLASS_PATH', CORE_PATH . '/class'); // Bot Paths define('CONFIG_PATH', ROOT_PATH . '/config'); diff --git a/core/lang/help.json b/core/lang/help.json deleted file mode 100644 index 55218974..00000000 --- a/core/lang/help.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "help_config-get": { - "NL": "/get - laat bot configuratie zien", - "DE": "/get - Bot-Konfiguration anzeigen", - "EN": "/get - Show bot configuration", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "/get - Näytä botin asetukset", - "ES": "/get - Ver configuración del bot" - }, - "help_config-set": { - "NL": "/set - Verander bot configuratie", - "DE": "/set - Bot-Konfiguration bearbeiten", - "EN": "/set - Edit bot configuration", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "/set - Muokkaa botin asetuksia", - "ES": "/set - Editar configuración del bot" - }, - "help_only_bool": { - "NL": "Alleen true/false of 0/1", - "DE": "nur true/false oder 0/1", - "EN": "only true/false or 0/1", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "vain true/false tai 0/1", - "ES": "solo true/false o 0/1" - }, - "help_only_numbers": { - "NL": "Alleen nummers", - "DE": "nur Zahlen", - "EN": "only numbers", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "vain numeroita", - "ES": "solo números" - }, - "help_bool_expected": { - "NL": "Toegestaande waarde: true/false of 0/1", - "DE": "Zulässige Werte: true/false oder 0/1", - "EN": "Allowed values: true/false or 0/1", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Sallitut arvot: true/false tai 0/1", - "ES": "Valores validos: true/false o 0/1" - }, - "help_number_expected": { - "NL": "Toegestaande waarde: Nummers groter dan 0", - "DE": "Zulässiger Wert: Zahlen größer 0", - "EN": "Allowed value: Numbers greater than 0", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Sallittu arvo: 0 suuremmat luvut", - "ES": "Valores validos: Números mayores que 0" - } -} diff --git a/core/lang/language.json b/core/lang/language.json deleted file mode 100644 index 6898eaa7..00000000 --- a/core/lang/language.json +++ /dev/null @@ -1,795 +0,0 @@ -{ - "lang_name": { - "NL": "Nederlands", - "DE": "Deutsch", - "EN": "English", - "IT": "Italiano", - "PT-BR": "Português", - "RU": "Русский", - "NO": "Norsk", - "FR": "Français", - "PL": "Polski", - "FI": "Suomi", - "ES": "Español" - }, - "weekday_1": { - "NL": "Maandag", - "DE": "Montag", - "EN": "Monday", - "IT": "Lunedì", - "PT-BR": "segunda-feira", - "RU": "Понедельник", - "NO": "Mandag", - "FR": "Lundi", - "PL": "Poniedziałek", - "FI": "Maanantai", - "ES": "Lunes" - }, - "weekday_2": { - "NL": "Dinsdag", - "DE": "Dienstag", - "EN": "Tuesday", - "IT": "Martedì", - "PT-BR": "terça-feira", - "RU": "Вторник", - "NO": "Tirsdag", - "FR": "Mardi", - "PL": "Wtorek", - "FI": "Tiistai", - "ES": "Martes" - }, - "weekday_3": { - "NL": "Woensdag", - "DE": "Mittwoch", - "EN": "Wednesday", - "IT": "Mercoledì", - "PT-BR": "quarta-feira", - "RU": "Среда", - "NO": "Onsdag", - "FR": "Mercredi", - "PL": "Środa", - "FI": "Keskiviikko", - "ES": "Miércoles" - }, - "weekday_4": { - "NL": "Donderdag", - "DE": "Donnerstag", - "EN": "Thursday", - "IT": "Giovedì", - "PT-BR": "quinta-feira", - "RU": "Четверг", - "NO": "Torsdag", - "FR": "Jeudi", - "PL": "Czwartek", - "FI": "Torstai", - "ES": "Jueves" - }, - "weekday_5": { - "NL": "Vrijdag", - "DE": "Freitag", - "EN": "Friday", - "IT": "Venerdì", - "PT-BR": "sexta-feira", - "RU": "Пятница", - "NO": "Fredag", - "FR": "Vendredi", - "PL": "Piątek", - "FI": "Perjantai", - "ES": "Viernes" - }, - "weekday_6": { - "NL": "Zaterdag", - "DE": "Samstag", - "EN": "Saturday", - "IT": "Sabato", - "PT-BR": "sábado", - "RU": "Суббота", - "NO": "Lørdag", - "FR": "Samedi", - "PL": "Sobota", - "FI": "Lauantai", - "ES": "Sábado" - }, - "weekday_7": { - "NL": "Zondag", - "DE": "Sonntag", - "EN": "Sunday", - "IT": "Domenica", - "PT-BR": "domingo", - "RU": "Воскресение", - "NO": "Søndag", - "FR": "Dimanche", - "PL": "Niedziela", - "FI": "Sunnuntai", - "ES": "Domingo" - }, - "month_01": { - "NL": "Januari", - "DE": "Januar", - "EN": "January", - "IT": "Gennaio", - "PT-BR": "Janeiro", - "RU": "Январь", - "NO": "Januar", - "FR": "Janvier", - "PL": "Styczeń", - "FI": "Tammikuu", - "ES": "Enero" - }, - "month_02": { - "NL": "Februari", - "DE": "Februar", - "EN": "February", - "IT": "Febbraio", - "PT-BR": "Fevereiro", - "RU": "Февраль", - "NO": "Februar", - "FR": "Février", - "PL": "Luty", - "FI": "Helmikuu", - "ES": "Febrero" - }, - "month_03": { - "NL": "Maart", - "DE": "März", - "EN": "March", - "IT": "Marzo", - "PT-BR": "Março", - "RU": "Март", - "NO": "Mars", - "FR": "Mars", - "PL": "Marzec", - "FI": "Maaliskuu", - "ES": "Marzo" - }, - "month_04": { - "NL": "April", - "DE": "April", - "EN": "April", - "IT": "Aprile", - "PT-BR": "Abril", - "RU": "Апрель", - "NO": "April", - "FR": "Avril", - "PL": "Kwiecień", - "FI": "Huhtikuu", - "ES": "Abril" - }, - "month_05": { - "NL": "Mei", - "DE": "Mai", - "EN": "May", - "IT": "Maggio", - "PT-BR": "Maio", - "RU": "Май", - "NO": "Mai", - "FR": "Mai", - "PL": "Maj", - "FI": "Toukokuu", - "ES": "Mayo" - }, - "month_06": { - "NL": "Juni", - "DE": "Juni", - "EN": "June", - "IT": "Giugno", - "PT-BR": "Junho", - "RU": "Июнь", - "NO": "Juni", - "FR": "Juin", - "PL": "Czerwiec", - "FI": "Kesäkuu", - "ES": "Junio" - }, - "month_07": { - "NL": "Juli", - "DE": "Juli", - "EN": "July", - "IT": "Luglio", - "PT-BR": "Julho", - "RU": "Июль", - "NO": "Juli", - "FR": "Juillet", - "PL": "Lipiec", - "FI": "Heinäkuu", - "ES": "Julio" - }, - "month_08": { - "NL": "Augustus", - "DE": "August", - "EN": "August", - "IT": "Agosto", - "PT-BR": "Agosto", - "RU": "Август", - "NO": "August", - "FR": "Août", - "PL": "Sierpień", - "FI": "Elokuu", - "ES": "Agosto" - }, - "month_09": { - "NL": "September", - "DE": "September", - "EN": "September", - "IT": "Settembre", - "PT-BR": "Setembro", - "RU": "Сентябрь", - "NO": "September", - "FR": "Septembre", - "PL": "Wrzesień", - "FI": "Syyskuu", - "ES": "Septiembre" - }, - "month_10": { - "NL": "Oktober", - "DE": "Oktober", - "EN": "October", - "IT": "Ottobre", - "PT-BR": "Outubro", - "RU": "Октябрь", - "NO": "Oktober", - "FR": "Octobre", - "PL": "Październik", - "FI": "Lokakuu", - "ES": "Octubre" - }, - "month_11": { - "NL": "November", - "DE": "November", - "EN": "November", - "IT": "Novembre", - "PT-BR": "Novembro", - "RU": "Ноябрь", - "NO": "November", - "FR": "Novembre", - "PL": "Listopad", - "FI": "Marraskuu", - "ES": "Noviembre" - }, - "month_12": { - "NL": "December", - "DE": "Dezember", - "EN": "December", - "IT": "Dicembre", - "PT-BR": "Dezembro", - "RU": "Декабрь", - "NO": "Desember", - "FR": "Décembre", - "PL": "Grudzień", - "FI": "Joulukuu", - "ES": "Diciembre" - }, - "bot_access_denied": { - "NL": "Je hebt geen toegang tot deze functie of bot!", - "DE": "Sie haben keine Berechtigung diesen Befehl oder Bot zu nutzen!", - "EN": "You are not allowed to use this command or bot!", - "IT": "Non hai i permessi necessari per usare questo comando o bot!", - "PT-BR": "Você não tem permissão para utilizar esse comando ou bot!", - "RU": "Вы не можете использовать эту команду или бота!", - "NO": "Du har ikke tillatelse til å bruke denne kommandoen eller boten!", - "FR": "Tu n'es pas autorisé à utiliser cette commande !", - "PL": "Nie masz uprawnień do korzystania z tej komendy lub bota!", - "FI": "Sinulla ei ole oikeutta tähän komentoon tai bottiin!", - "ES": "¡No está autorizado a utilizar este comando o bot!" - }, - "forest": { - "NL": "Routebeschrijving", - "DE": "Wegbeschreibung", - "EN": "Directions", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Reittiohje", - "ES": "Abrir mapa" - }, - "pokemon": { - "NL": "Pokemon", - "DE": "Pokemon", - "EN": "Pokemon", - "IT": "Pokemon", - "PT-BR": "Pokemon", - "RU": "Pokemon", - "NO": "Pokemon", - "FR": "Pokemon", - "PL": "Pokemon", - "FI": "Pokemon", - "ES": "Pokémon" - }, - "pokemon_types": { - "NL": "Pokemon Types", - "DE": "Pokemon-Typen", - "EN": "Pokemon Types", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Pokemon Tyypit", - "ES": "Tipos de Pokémon" - }, - "yes": { - "NL": "Ja", - "DE": "Ja", - "EN": "Yes", - "IT": "Sì", - "PT-BR": "Sim", - "RU": "Да", - "NO": "Ja", - "FR": "Oui", - "PL": "Tak", - "FI": "Kyllä", - "ES": "Si" - }, - "no": { - "NL": "Nee", - "DE": "Nein", - "EN": "No", - "IT": "No", - "PT-BR": "Não", - "RU": "Нет", - "NO": "Nei", - "FR": "Non", - "PL": "Nie", - "FI": "Ei", - "ES": "No" - }, - "or": { - "NL": "of", - "DE": "oder", - "EN": "or", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "tai", - "ES": "o" - }, - "not_supported": { - "NL": "Niet ondersteund", - "DE": "Nicht unterstützt", - "EN": "Not supported", - "IT": "Non compatibile", - "PT-BR": "Não compatível", - "RU": "Не поддерживается", - "NO": "Ikke støttet", - "FR": "Non compatible", - "PL": "Nieobsługiwane", - "FI": "Ei tuettu", - "ES": "No soportado" - }, - "abort": { - "NL": "Afbreken", - "DE": "Abbrechen", - "EN": "Abort", - "IT": "Cancella", - "PT-BR": "Abortar", - "RU": "Прервать", - "NO": "Avbryt", - "FR": "Abandonner", - "PL": "Anuluj", - "FI": "Peruuta", - "ES": "Cancelar" - }, - "action_aborted": { - "NL": "Het proces is afgebroken!", - "DE": "Der Vorgang wurde abgebrochen!", - "EN": "The process was aborted!", - "IT": "Il processo è stato cancellato!", - "PT-BR": "O processo foi abortado!", - "RU": "Процесс был прерван!", - "NO": "Handlingen ble avbrutt!", - "FR": "Le processus à échoué !", - "PL": "Zadanie zostało anulowane", - "FI": "Prosessi peruutettiin!", - "ES": "¡El proceso fue cancelado!" - }, - "select_action": { - "NL": "Selecteer actie:", - "DE": "Aktion auswählen:", - "EN": "Select action:", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Valitse toiminto:", - "ES": "Selecciona la acción:" - }, - "back": { - "NL": "Terug", - "DE": "Zurück", - "EN": "Back", - "IT": "Precedente", - "PT-BR": "Voltar", - "RU": "Назад", - "NO": "Tilbake", - "FR": "Retour", - "PL": "Wstecz", - "FI": "Takaisin", - "ES": "Volver" - }, - "next": { - "NL": "Volgende", - "DE": "Weiter", - "EN": "Next", - "IT": "Successivo", - "PT-BR": "Próximo", - "RU": "Вперед", - "NO": "Neste", - "FR": "Suivant", - "PL": "Dalej", - "FI": "Seuraava", - "ES": "Siguiente" - }, - "done": { - "NL": "Klaar", - "DE": "Fertig", - "EN": "Done", - "IT": "Completato", - "PT-BR": "Feito", - "RU": "Готово", - "NO": "Ferdig", - "FR": "Terminé", - "PL": "Zrobione", - "FI": "Valmis", - "ES": "Hecho" - }, - "add": { - "NL": "Toevoegen", - "DE": "Hinzufügen", - "EN": "Add", - "IT": "Aggiungi", - "PT-BR": "Adicionar", - "RU": "Добавить", - "NO": "Legg til", - "FR": "Ajouter", - "PL": "Dodaj", - "FI": "Lisää", - "ES": "Añadir" - }, - "replace": { - "NL": "TRANSLATE", - "DE": "TRANSLATE", - "EN": "Replace", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Korvaa", - "ES": "Reemplazar" - }, - "delete": { - "NL": "Verwijder", - "DE": "Löschen", - "EN": "Delete", - "IT": "Elimina", - "PT-BR": "Deletar", - "RU": "Удалить", - "NO": "Slett", - "FR": "Supprimer", - "PL": "Usuń", - "FI": "Poista", - "ES": "Borrar" - }, - "edit": { - "NL": "Bewerken", - "DE": "Bearbeiten", - "EN": "Edit", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Muokkaa", - "ES": "Editar" - }, - "list": { - "NL": "Lijst", - "DE": "Anzeigen", - "EN": "List", - "IT": "Lista", - "PT-BR": "Lista", - "RU": "Список", - "NO": "List", - "FR": "Liste", - "PL": "Pokaż", - "FI": "Listaa", - "ES": "Lista" - }, - "reset": { - "NL": "Reset", - "DE": "Reset", - "EN": "Reset", - "IT": "Reset", - "PT-BR": "Resetar", - "RU": "Сброс", - "NO": "Reset", - "FR": "Remise à zéro", - "PL": "Resetuj", - "FI": "Resetoi", - "ES": "Reiniciar" - }, - "created_by": { - "NL": "Aangemaakt door", - "DE": "Erstellt von", - "EN": "Created by", - "IT": "Creato da", - "PT-BR": "Criada por", - "RU": "Создано", - "NO": "Postet av", - "FR": "Créé par", - "PL": "Stworzone przez", - "FI": "Luonut", - "ES": "Creado por" - }, - "updated": { - "NL": "Bijgewerkt", - "DE": "Aktualisiert", - "EN": "Updated", - "IT": "Aggiornato", - "PT-BR": "Atualizada", - "RU": "Обновлено", - "NO": "Oppdatert", - "FR": "Mis à jour", - "PL": "Zaktualizowano", - "FI": "Päivitetty", - "ES": "Actualizado" - }, - "share": { - "NL": "Delen", - "DE": "Teilen", - "EN": "Share", - "IT": "Condividi", - "PT-BR": "Compartilhar", - "RU": "Поделиться", - "NO": "Del", - "FR": "Partager", - "PL": "Udostępnij", - "FI": "Jaa", - "ES": "Compartir" - }, - "share_with": { - "NL": "Delen met", - "DE": "Teilen mit", - "EN": "Share with", - "IT": "Condividi con", - "PT-BR": "Compartilhar com", - "RU": "Поделиться с", - "NO": "Del med", - "FR": "Partager avec", - "PL": "Przekaż dalej", - "FI": "Jaa ryhmään", - "ES": "Compartir con" - }, - "successfully_shared": { - "NL": "Succesvol gedeeld!", - "DE": "Erfolgreich geteilt!", - "EN": "Successfully shared!", - "IT": "Condiviso con successo!", - "PT-BR": "Compartilhado com sucesso!", - "RU": "Успешно отправлено!", - "NO": "Deling velykket!", - "FR": "Partagé avec succès !", - "PL": "Pomyślnie udostępniono", - "FI": "Jaettu onnistuneesti!", - "ES": "¡Compartido con éxito!" - }, - "config": { - "NL": "Configuratie", - "DE": "Konfiguration", - "EN": "Configuration", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Asetukset", - "ES": "Configuración" - }, - "config_updated": { - "NL": "Configuratie ge-update", - "DE": "Konfiguration aktualisiert", - "EN": "Configuration updated", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Asetukset päivitetty", - "ES": "Configuración actualizada" - }, - "resetted": { - "NL": "Gereset", - "DE": "Zurückgesetzt", - "EN": "Resetted", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Resetoitu", - "ES": "Reiniciado" - }, - "option_value": { - "NL": "Configuratie optie waarde", - "DE": "Konfigurationsoption Wert", - "EN": "Configuration option value", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Asetuksen arvo", - "ES": "Valor de la opción de configuración" - }, - "config_option": { - "NL": "TRANSLATE", - "DE": "TRANSLATE", - "EN": "Configuration option", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Asetuksen nimi", - "ES": "TRANSLATE" - }, - "no_value": { - "NL": "Geen waarde", - "DE": "Kein Wert", - "EN": "No value", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Ei arvoa", - "ES": "Sin valor" - }, - "new_value": { - "NL": "Nieuwe waarde:", - "DE": "Neuer Wert:", - "EN": "New value:", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Uusi arvo:", - "ES": "Nuevo valor:" - }, - "old_value": { - "NL": "Oude waarde:", - "DE": "Alter Wert:", - "EN": "Old value:", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Vanha arvo:", - "ES": "Antiguo valor:" - }, - "personal_help": { - "NL": "Alle commando's voor de bot:", - "DE": "Deine persönliche Bot-Hilfe:", - "EN": "Your personal bot help:", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Henkilökohtainen bottiapu:", - "ES": "Tu bot personal ayuda:" - }, - "invalid_input": { - "NL": "Ongeldige input!", - "DE": "Ungültige Eingabe!", - "EN": "Invalid input!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Epäkelpo arvo!", - "ES": "¡Entrada inválida!" - }, - "internal_error": { - "NL": "Internal error!", - "DE": "Interner Fehler!", - "EN": "Internal error!", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Sisäinen virhe!", - "ES": "¡Error interno!" - }, - "expand": { - "NL": "Uitklappen", - "DE": "Ausklappen", - "EN": "Expand", - "IT": "Espandi", - "PT-BR": "Expandir", - "RU": "Развернуть", - "NO": "Flere valg", - "FR": "Agrandir", - "PL": "Rozwiń", - "FI": "Laajenna", - "ES": "Expandir" - }, - "none": { - "NL": "Geen", - "DE": "Keine", - "EN": "None", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "ei mitään", - "ES": "Nada" - }, - "other": { - "NL": "Anders", - "DE": "Sonstiges", - "EN": "Other", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Muu", - "ES": "Otro" - }, - "tutorial_vote_failed": { - "NL": "Je kan niet meedoen voordat je de tutorial hebt doorlopen.", - "DE": "TRANSLATE", - "EN": "You can't vote before going through the tutorial.", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Et voi äänestää ennen kuin olet käynyt ohjeen läpi.", - "ES": "No puedes votar antes de seguir el tutorial." - }, - "tutorial_command_failed": { - "NL": "Je kan dit commando niet gebruiken voordat je de tutorial hebt doorlopen.", - "DE": "TRANSLATE", - "EN": "You can't use this command before going through the tutorial.", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Et voi käyttää tätä käskyä ennen kuin olet käynyt ohjeen läpi.", - "ES": "No puede usar este comando antes de seguir el tutorial." - } -} diff --git a/core/lang/requirements.txt b/core/lang/requirements.txt deleted file mode 100644 index b998a06a..00000000 --- a/core/lang/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -absl-py diff --git a/core/lang/translate.py b/core/lang/translate.py deleted file mode 100644 index 465b3e98..00000000 --- a/core/lang/translate.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 - -from absl import flags, app, logging -import json - -FLAGS = flags.FLAGS - -flags.DEFINE_string('from_language', 'EN', 'Language to use as translation hint') -flags.DEFINE_string('to', None, 'Language to translate into') -flags.DEFINE_string('input', 'language.json', 'File to read base translation from.') -flags.DEFINE_string('output', 'language.json', 'File to keep saving changes to.') -flags.DEFINE_boolean('incremental', True, 'Update only strings missing translations.') -flags.DEFINE_boolean('sort_keys', False, 'Whether to output sorted or not.') -flags.mark_flag_as_required('to') - - -def main(argv): - with open(FLAGS.input, encoding='utf8') as f: - trans = json.load(f) - - logging.info('Creating placeholders for missing strings for language {0}'.format(FLAGS.to)) - for key in trans.keys(): - if FLAGS.to not in trans[key]: - trans[key][FLAGS.to] = 'TRANSLATE' - flush(trans) - print('Press ^D or ^C to stop. Leave a translation empty to skip.') - - - if FLAGS.incremental: - logging.info('Iterating over strings that have not been translated to language {0}'.format(FLAGS.to)) - for key in trans.keys(): - if trans[key][FLAGS.to] == 'TRANSLATE': - translate(trans, key) - flush(trans) - - else: - logging.info('Iterating over all strings of language {0}'.format(FLAGS.to)) - for key in trans.keys(): - translate(trans, key) - flush(trans) - -# Flush current changes to output file to avoid losing changes -def flush(trans): - logging.debug('flushing into {0}'.format(FLAGS.output)) - with open(FLAGS.output, 'w', encoding='utf8') as f: - # We dump without ASCII ensurance to get unicode output for example for Russian - json.dump(trans, f, indent=2, sort_keys=FLAGS.sort_keys, ensure_ascii=False) - -# Print from string, request to string and update it to trans -def translate(trans, key): - print('{0}[{1}]: {2}'.format(key, FLAGS.from_language, trans[key][FLAGS.from_language])) - translation = input('{0}[{1}]: '.format(key, FLAGS.to)) - if translation: - trans[key][FLAGS.to] = translation - - -if __name__ == '__main__': - app.run(main) diff --git a/getTranslations.php b/getTranslations.php index dc641662..e5f77abf 100644 --- a/getTranslations.php +++ b/getTranslations.php @@ -1,6 +1,5 @@ EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("forest")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), + 'text' => EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("directions")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), 'callback_data' => $gym_id . ':gym_edit_details:addr' ] ]; From c362a8bfe2e1a784b202b1099adf84153fdb73e7 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 31 Oct 2022 17:54:04 +0200 Subject: [PATCH 080/367] Fixed custom translations not working --- core/bot/logic/language.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/bot/logic/language.php b/core/bot/logic/language.php index 7a9d7c6f..12d80bcf 100644 --- a/core/bot/logic/language.php +++ b/core/bot/logic/language.php @@ -35,10 +35,10 @@ function getTranslationFile($translationTitle) { } } - foreach($savedTranslations['custom'] as $title => $translation) { - if(key_exists($title, $json)) { + foreach($savedTranslations['custom'] as $title => $value) { + if(key_exists($title, $translation)) { debug_log($title, 'Found custom translation for'); - $json[$title] = $translation; + $translation[$title] = $value; unset($savedTranslations['custom'][$title]); } } From e39e9aaf27299abc299b056846ef034298fe1057 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 31 Oct 2022 18:11:26 +0200 Subject: [PATCH 081/367] Fixes --- core/bot/logic/language.php | 4 ++++ logic/alarm.php | 42 ++++++++++++++++++------------------- mods/bot_lang.php | 8 +++---- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/core/bot/logic/language.php b/core/bot/logic/language.php index 12d80bcf..64d030b6 100644 --- a/core/bot/logic/language.php +++ b/core/bot/logic/language.php @@ -92,6 +92,10 @@ function getTranslation($text, $language = USERLANGUAGE) $translation = $translations[$text][$language]; elseif(isset($translations[$text][DEFAULT_LANGUAGE])) $translation = $translations[$text][DEFAULT_LANGUAGE]; + + // No translation found + elseif($tfile == 'botHelp') + $translation = false; else $translation = $text; debug_log($translation,'T:'); diff --git a/logic/alarm.php b/logic/alarm.php index c13f1641..1ff223f2 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -79,9 +79,9 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) // Sending message if($info == 'alien') { - $msg_text = '' . getTranslation('alert_add_alien_trainer', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_add_alien_trainer', $recipient_language) . '' . CR; }else { - $msg_text = '' . getTranslation('alert_add_trainer', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_add_trainer', $recipient_language) . '' . CR; } $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . SP . '+' . $icons[$info] . CR; @@ -94,14 +94,14 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) if($info == 'late') { debug_log('Alarm late: ' . $info); // Send message. - $msg_text = '' . getTranslation('alert_later', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_later', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); $msg_text .= create_traincode_msg($trainercode); } else if($info == 'cancel') { debug_log('Alarm cancel: ' . $info); - $msg_text = '' . getTranslation('alert_cancel', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_cancel', $recipient_language) . '' . CR; $msg_text .= TEAM_CANCEL . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); @@ -115,14 +115,14 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) if($info != '0') { $pokemon = explode("-",$info,2); $poke_name = get_local_pokemon_name($pokemon[0],$pokemon[1]); - $msg_text = '' . getTranslation('alert_individual_poke', true, $recipient_language) . SP . $poke_name . '' . CR; + $msg_text = '' . getTranslation('alert_individual_poke', $recipient_language) . SP . $poke_name . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); $msg_text .= create_traincode_msg($trainercode); // Any pokemon } else { - $msg_text = '' . getTranslation('alert_every_poke', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_every_poke', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); @@ -134,7 +134,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) debug_log('Alarm Pokemon: ' . $info); $pokemon = explode("-",$info,2); $poke_name = get_local_pokemon_name($pokemon[0],$pokemon[1]); - $msg_text = '' . getTranslation('alert_cancel_individual_poke', true, $recipient_language) . SP . $poke_name . '' . CR; + $msg_text = '' . getTranslation('alert_cancel_individual_poke', $recipient_language) . SP . $poke_name . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); @@ -149,7 +149,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) } else if($action == "new_att") { debug_log('Alarm new attendance: ' . $info); // Will Attend - $msg_text = '' . getTranslation('alert_new_att', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_new_att', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . check_time($info); @@ -159,7 +159,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) } else if($action == "change_time") { debug_log('Alarm changed attendance time: ' . $info); // Changes Time - $msg_text = '' . getTranslation('alert_change_time', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_change_time', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . '' . check_time($info) . ''; @@ -169,7 +169,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) } else if($action == "remote") { debug_log('Alarm remote attendance changed: ' . $info); // Changes Time - $msg_text = '' . getTranslation('alert_remote', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_remote', $recipient_language) . '' . CR; $msg_text .= EMOJI_REMOTE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; @@ -179,7 +179,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) } else if($action == "no_remote") { debug_log('Alarm remote attendance changed: ' . $info); // Changes Time - $msg_text = '' . getTranslation('alert_no_remote', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_no_remote', $recipient_language) . '' . CR; $msg_text .= EMOJI_REMOTE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; @@ -187,7 +187,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) // No additional trainer } else if($action == "extra_alone") { debug_log('Alarm no additional trainers: ' . $info); - $msg_text = '' . getTranslation('alert_extra_alone', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_extra_alone', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); @@ -196,8 +196,8 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) // Group code public } else if($action == "group_code_public") { debug_log('Alarm for group code: ' . $info); - $msg_text = '' . getTranslation('alert_raid_starts_now', true, $recipient_language) . CR . getTranslation('alert_raid_get_in', true, $recipient_language) . '' . CR . CR; - $msg_text .= '' . getTranslation('alert_public_group', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_raid_starts_now', $recipient_language) . CR . getTranslation('alert_raid_get_in', $recipient_language) . '' . CR . CR; + $msg_text .= '' . getTranslation('alert_public_group', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_REMOTE . SP . $info; @@ -205,8 +205,8 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) // Group code private } else if($action == "group_code_private") { debug_log('Alarm for group code: ' . $info); - $msg_text = '' . getTranslation('alert_raid_starts_now', true, $recipient_language) . CR . getTranslation('alert_raid_get_in', true, $recipient_language) . '' . CR . CR; - $msg_text .= '' . getTranslation('alert_private_group', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_raid_starts_now', $recipient_language) . CR . getTranslation('alert_raid_get_in', $recipient_language) . '' . CR . CR; + $msg_text .= '' . getTranslation('alert_private_group', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; @@ -217,12 +217,12 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) // Send message to local raiders if($answer['remote'] == 0) { - $msg_text .= EMOJI_REMOTE . SP . '' . getTranslation('group_code_only_for_remote_raiders', true, $recipient_language) . ''; + $msg_text .= EMOJI_REMOTE . SP . '' . getTranslation('group_code_only_for_remote_raiders', $recipient_language) . ''; } // Attendance from remote } else if($action == "want_invite") { debug_log('Alarm invite begging changed: ' . $info); - $msg_text = '' . getTranslation('alert_want_invite', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_want_invite', $recipient_language) . '' . CR; $msg_text .= EMOJI_WANT_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; @@ -231,7 +231,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) // Attendance no longer from remote } else if($action == "no_want_invite") { debug_log('Alarm invite begging changed: ' . $info); - $msg_text = '' . getTranslation('alert_no_want_invite', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_no_want_invite', $recipient_language) . '' . CR; $msg_text .= EMOJI_WANT_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; @@ -240,7 +240,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) // Let others know you are not playing, but can invite others } else if($action == "can_invite") { debug_log('Alarm: ' . $action); - $msg_text = '' . getTranslation('alert_can_invite', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_can_invite', $recipient_language) . '' . CR; $msg_text .= EMOJI_CAN_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; @@ -249,7 +249,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) // Let others know you are not longer able to invite them } else if($action == "no_can_invite") { debug_log('Alarm: ' . $action); - $msg_text = '' . getTranslation('alert_no_can_invite', true, $recipient_language) . '' . CR; + $msg_text = '' . getTranslation('alert_no_can_invite', $recipient_language) . '' . CR; $msg_text .= EMOJI_CAN_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; diff --git a/mods/bot_lang.php b/mods/bot_lang.php index 15d3ec64..8bac0f4d 100644 --- a/mods/bot_lang.php +++ b/mods/bot_lang.php @@ -25,14 +25,14 @@ 'user_id' => $update['callback_query']['from']['id'] ]); $new_lang_internal = $languages[$data['arg']]; - $msg = getTranslation('new_lang_saved', true, $new_lang_internal); + $msg = getTranslation('new_lang_saved', $new_lang_internal); $keys[] = [ [ - 'text' => getTranslation('back', true, $new_lang_internal), + 'text' => getTranslation('back', $new_lang_internal), 'callback_data' => '0:trainer:0' ], [ - 'text' => getTranslation('done', true, $new_lang_internal), + 'text' => getTranslation('done', $new_lang_internal), 'callback_data' => '0:exit:1' ] ]; @@ -40,7 +40,7 @@ } else { foreach($languages as $lang_tg => $lang_internal) { $keys[][] = [ - 'text' => getTranslation('lang_name', true, $lang_internal), + 'text' => getTranslation('lang_name', $lang_internal), 'callback_data' => '0:bot_lang:'.$lang_tg ]; } From 3bb803bb15187c0382a9acc10a87f0a7afdc06b7 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 31 Oct 2022 18:31:31 +0200 Subject: [PATCH 082/367] Fixed alarms not using user's language --- logic/alarm.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/logic/alarm.php b/logic/alarm.php index c13f1641..dcfdbc41 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -51,7 +51,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $request = my_query(" SELECT DISTINCT attendance.user_id, attendance.remote, users.lang FROM attendance LEFT JOIN users - ON users.id = attendance.user_id + ON users.user_id = attendance.user_id WHERE raid_id = {$raid_id} AND attend_time = (SELECT attend_time from attendance WHERE raid_id = {$raid_id} AND user_id = {$user_id}) "); @@ -59,7 +59,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $request = my_query(" SELECT DISTINCT attendance.user_id, users.lang FROM attendance LEFT JOIN users - ON users.id = attendance.user_id + ON users.user_id = attendance.user_id WHERE raid_id = {$raid_id} AND attendance.user_id != {$user_id} AND cancel = 0 @@ -71,7 +71,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) while($answer = $request->fetch()) { if(!isset($answer['lang']) or empty($answer['lang'])) $recipient_language = $config->LANGUAGE_PUBLIC; - else $recipient_language = $answer['lang']; + else $recipient_language = $GLOBALS['languages'][$answer['lang']]; // Adding a guest if($action == "extra") { debug_log('Alarm additional trainer: ' . $info); From 504a3b6af0cbb241a70c6b1ee13d8f718813f2da Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 31 Oct 2022 21:01:48 +0200 Subject: [PATCH 083/367] Only overwrite the translation with custom values for the specified languages --- core/bot/logic/language.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/bot/logic/language.php b/core/bot/logic/language.php index 64d030b6..d4ae8b3a 100644 --- a/core/bot/logic/language.php +++ b/core/bot/logic/language.php @@ -38,7 +38,10 @@ function getTranslationFile($translationTitle) { foreach($savedTranslations['custom'] as $title => $value) { if(key_exists($title, $translation)) { debug_log($title, 'Found custom translation for'); - $translation[$title] = $value; + // Only overwrite the translation for languages that are present + foreach($value as $lang => $newValue) { + $translation[$title][$lang] = $newValue; + } unset($savedTranslations['custom'][$title]); } } From 06d61cedd007dd04c0f5bc92d17a3850de418414 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 2 Nov 2022 12:42:34 +0200 Subject: [PATCH 084/367] Fix --- core/bot/logic/language.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/bot/logic/language.php b/core/bot/logic/language.php index d4ae8b3a..d7c40cee 100644 --- a/core/bot/logic/language.php +++ b/core/bot/logic/language.php @@ -67,8 +67,10 @@ function getPublicTranslation($text) * @param string $override_language * @return string translation */ -function getTranslation($text, $language = USERLANGUAGE) +function getTranslation($text, $language = false) { + global $botUser; + if($language === false) $language = $botUser->userLanguage; debug_log($text,'T:'); $text = trim($text); From b981bf0d1a69788f1a6735db2b96ecfa0e7ee3b8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 2 Nov 2022 17:27:56 +0200 Subject: [PATCH 085/367] Fixed a bug where duplicate raids were created --- core/tools/automate_raid_hour_creation/raid_hour_creator.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/tools/automate_raid_hour_creation/raid_hour_creator.php b/core/tools/automate_raid_hour_creation/raid_hour_creator.php index c7aa6695..08836de4 100644 --- a/core/tools/automate_raid_hour_creation/raid_hour_creator.php +++ b/core/tools/automate_raid_hour_creation/raid_hour_creator.php @@ -25,6 +25,7 @@ $offset = date('Z'); $interval = DateInterval::createFromDateString($offset.' seconds'); $raid_to_create = []; +$datesToCreate = []; $data = json_decode($data,true); if($data !== false) { $now = new DateTime('18:00'); @@ -68,9 +69,10 @@ $pokemon_form = $mon[1]; } $raid_to_create[] = [$pokemon, $pokemon_form,$event_start,$event_end]; + $datesToCreate[] = $event_start; } } - if($now->format('w') == 3 && !in_array($now->format('Y-m-d H:i:s'),$raids_res)) { + if($now->format('w') == 3 && !in_array($now->format('Y-m-d H:i:s'), $raids_res) && !in_array($now->format('Y-m-d H:i:s'), $datesToCreate)) { $start_time = gmdate('Y-m-d H:i:s',mktime(18,0,0)); $end_time = gmdate('Y-m-d H:i:s',mktime(19,0,0)); $mon = get_current_bosses($start_time); From 5d7b3ae4798a5e457bf18af2bca8ecef98aa4ff0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 3 Nov 2022 15:47:03 +0200 Subject: [PATCH 086/367] Vote fixes - Fixed a bug where canceled user couldn't uncancel by voting on the same time they originally attended - Fixed the limiter that doesn't allow signing up more than the configured ammount of remote players - Moved multiple sql queries to use `my_query()` - General code cleanups --- logic/get_remote_users_count.php | 70 ++++--- mods/vote_can_invite.php | 113 +++++------ mods/vote_extra.php | 147 +++++++------- mods/vote_remote.php | 96 ++++----- mods/vote_time.php | 322 +++++++++++++++---------------- mods/vote_want_invite.php | 111 +++++------ 6 files changed, 423 insertions(+), 436 deletions(-) diff --git a/logic/get_remote_users_count.php b/logic/get_remote_users_count.php index 1ab72065..2863e3c7 100644 --- a/logic/get_remote_users_count.php +++ b/logic/get_remote_users_count.php @@ -6,44 +6,50 @@ * @param $attend_time * @return int */ -function get_remote_users_count($raid_id, $user_id, $attend_time = false) +function get_remote_users_count($raidId, $userId, $attendTime = false) { - global $config; + global $config; - if(!$attend_time) { - // If attend time is not given, get the one user has already voted for from database - $att_sql = "( - SELECT attend_time - FROM attendance - WHERE raid_id = {$raid_id} - AND user_id = {$user_id} - LIMIT 1 - )"; - }else { - // Use given attend time (needed when voting for new time) - $att_sql = "'{$attend_time}'"; - } + $attBinds['userId'] = $userId; + if($attendTime) { + $attSql = ':attTime'; + $attBinds['attTime'] = $attendTime; + }else { + // If attend time is not given, get the one user has already voted for from database + $attSql = '( + SELECT attend_time + FROM attendance + WHERE raid_id = :raidId + AND user_id = :userId + LIMIT 1 + )'; + $attBinds['raidId'] = $raidId; + $attBinds['userId'] = $userId; + } - // Check if max remote users limit is already reached! - // Ignore max limit if attend time is 'Anytime' - $rs = my_query( - " - SELECT IF(attend_time = '" . ANYTIME . "', 0, sum(1 + extra_in_person)) AS remote_users - FROM (SELECT DISTINCT user_id, extra_in_person, attend_time FROM attendance WHERE remote = 1 AND cancel = 0 AND raid_done = 0) as T - WHERE attend_time = {$att_sql} - GROUP BY attend_time - " - ); + // Check if max remote users limit is already reached! + // Ignore max limit if attend time is 'Anytime' + $rs = my_query( + ' + SELECT CASE WHEN attend_time = \'' . ANYTIME . '\' + THEN 0 + ELSE + sum(CASE WHEN remote = 1 THEN 1 + extra_in_person ELSE 0 END + extra_alien) END AS remote_users + FROM (SELECT DISTINCT user_id, extra_in_person, extra_alien, remote, attend_time FROM attendance WHERE (remote = 1 or extra_alien > 0) AND cancel = 0 AND raid_done = 0 and user_id != :userId) as T + WHERE attend_time = ' . $attSql . ' + GROUP BY attend_time + ', $attBinds + ); - // Get the answer. - $answer = $rs->fetch(); - $remote_users = empty($answer) ? 0 : $answer['remote_users']; + // Get the answer. + $answer = $rs->fetch(); + $remoteUsers = empty($answer) ? 0 : $answer['remote_users']; - // Write to log. - debug_log($remote_users, 'Remote participants so far:'); - debug_log($config->RAID_REMOTEPASS_USERS_LIMIT, 'Maximum remote participants:'); + // Write to log. + debug_log($remoteUsers, 'Remote participants so far:'); + debug_log($config->RAID_REMOTEPASS_USERS_LIMIT, 'Maximum remote participants:'); - return $remote_users; + return $remoteUsers; } ?> diff --git a/mods/vote_can_invite.php b/mods/vote_can_invite.php index ea4c5a66..7b1a483f 100644 --- a/mods/vote_can_invite.php +++ b/mods/vote_can_invite.php @@ -6,69 +6,52 @@ //debug_log($update); //debug_log($data); -try { - $query_select = " - SELECT can_invite - FROM attendance - WHERE raid_id = :raid_id - AND user_id = :user_id - LIMIT 1 - "; - $statement_select = $dbh->prepare( $query_select ); - $statement_select->execute([ - 'raid_id' => $data['id'], - 'user_id' => $update['callback_query']['from']['id'] - ]); - $res = $statement_select->fetch(); - if($statement_select->rowCount() > 0) { - $query = " - UPDATE attendance - SET can_invite = CASE - WHEN can_invite = '0' THEN '1' - ELSE '0' - END, - late = 0, - arrived = 0, - remote = 0, - want_invite = 0, - extra_alien = 0, - extra_in_person = 0 - WHERE raid_id = :raid_id - AND user_id = :user_id - "; - $statement = $dbh->prepare( $query ); - $statement->execute([ - 'raid_id' => $data['id'], - 'user_id' => $update['callback_query']['from']['id'] - ]); - } +$raidId = $data['id']; + +$query_select = my_query(' + SELECT can_invite, CASE WHEN cancel = 1 or raid_done = 1 THEN 1 ELSE 0 END as cancelOrDone + FROM attendance + WHERE raid_id = :raid_id + AND user_id = :user_id + LIMIT 1 + ', + [ + 'raid_id' => $raidId, + 'user_id' => $update['callback_query']['from']['id'], + ]); +$res = $query_select->fetch(); +if($query_select->rowCount() == 0 or $res['cancelOrDone'] == 1) { + // Send vote time first. + send_vote_time_first($update); + exit; } -catch (PDOException $exception) { - - error_log($exception->getMessage()); - $dbh = null; - exit; -} -if($statement_select->rowCount() > 0) { - if($res['can_invite'] == 0) { - $alarm_action = 'can_invite'; - } else { - $alarm_action = 'no_can_invite'; - } - // Send vote response. - require_once(LOGIC_PATH . '/update_raid_poll.php'); - - $tg_json = update_raid_poll($data['id'], false, $update); - - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'], $alarm_action, '', $tg_json); - - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); - - curl_json_multi_request($tg_json); -} else { - // Send vote time first. - send_vote_time_first($update); -} - -$dbh = null; -exit(); +my_query(' + UPDATE attendance + SET can_invite = CASE + WHEN can_invite = 0 THEN 1 + ELSE 0 + END, + late = 0, + arrived = 0, + remote = 0, + want_invite = 0, + extra_alien = 0, + extra_in_person = 0 + WHERE raid_id = :raid_id + AND user_id = :user_id + ', + [ + 'raid_id' => $raidId, + 'user_id' => $update['callback_query']['from']['id'], + ]); +// Send vote response. +require_once(LOGIC_PATH . '/update_raid_poll.php'); + +$tg_json = update_raid_poll($raidId, false, $update); + +$alarm_action = ($res['can_invite'] == 0) ? 'can_invite' : 'no_can_invite'; +$tg_json = alarm($raidId,$update['callback_query']['from']['id'], $alarm_action, '', $tg_json); + +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); + +curl_json_multi_request($tg_json); diff --git a/mods/vote_extra.php b/mods/vote_extra.php index b982686c..b25663a8 100644 --- a/mods/vote_extra.php +++ b/mods/vote_extra.php @@ -6,14 +6,21 @@ //debug_log($update); //debug_log($data); +$raidId = $data['id']; + // Check if the user has voted for this raid before and check if they are attending remotely. $rs = my_query( - " - SELECT user_id, remote, want_invite, can_invite, (1 + extra_in_person) as user_count - FROM attendance - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " + ' + SELECT user_id, remote, want_invite, can_invite, attend_time, (CASE WHEN remote = 1 THEN 1 + extra_in_person ELSE 0 END + extra_alien) as user_count, CASE WHEN cancel = 1 or raid_done = 1 THEN 1 ELSE 0 END as cancelOrDone + FROM attendance + WHERE raid_id = :raidId + AND user_id = :userId + LIMIT 1 + ', + [ + 'raidId' => $raidId, + 'userId' => $update['callback_query']['from']['id'], + ] ); // Get the answer. @@ -25,72 +32,76 @@ // Write to log. debug_log($answer); -// User has voted before. -if (!empty($answer)) { - if($data['arg'] == '0') - { - // Reset team extra people. - my_query( - " - UPDATE attendance - SET extra_in_person = 0, - extra_alien = 0 - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " - ); - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'extra_alone',$data['arg'], $tg_json); - } else if($answer['can_invite'] == 1 ) { - // People who are only inviting others can't add extras - $msg = getTranslation('vote_status_not_allowed'); +// User has not voted before. +if (empty($answer) or $answer['cancelOrDone'] == 1) { + // Send vote time first. + send_vote_time_first($update); + exit; +} - // Answer the callback. - answerCallbackQuery($update['callback_query']['id'], $msg); +if($data['arg'] == '0') { + // Reset team extra people. + my_query( + ' + UPDATE attendance + SET extra_in_person = 0, + extra_alien = 0 + WHERE raid_id = :raidId + AND user_id = :userId + ', + [ + 'raidId' => $raidId, + 'userId' => $update['callback_query']['from']['id'], + ] + ); + $tg_json = alarm($raidId, $update['callback_query']['from']['id'], 'extra_alone', $data['arg'], $tg_json); +} else if($answer['can_invite'] == 1 ) { + // People who are only inviting others can't add extras + $msg = getTranslation('vote_status_not_allowed'); - $dbh = null; - exit(); - } else { - // Check if max remote users limit is already reached! - $remote_users = get_remote_users_count($data['id'], $update['callback_query']['from']['id']); - // Skip remote user limit check if user is not attending remotely. - // If they are, check if attend time already has max number of remote users. - // Also prevent user from adding more than max number of remote players even if 'Anytime' is selected - if ($answer['remote'] == 0 or ($remote_users < $config->RAID_REMOTEPASS_USERS_LIMIT && $answer['user_count'] < $config->RAID_REMOTEPASS_USERS_LIMIT)) { - if($answer['want_invite'] == 1 && $data['arg'] == 'alien') { - // Force invite beggars to user extra_in_person even if they vote +alien - $data['arg'] = 'in_person'; - } - $team = 'extra_' . $data['arg']; - // Increase team extra people. - my_query( - " - UPDATE attendance - SET {$team} = {$team}+1 - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " - ); - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'extra',$data['arg'], $tg_json); - } else { - // Send max remote users reached. - send_vote_remote_users_limit_reached($update); - $dbh = null; - exit(); - } - } + // Answer the callback. + answerCallbackQuery($update['callback_query']['id'], $msg); - // Send vote response. - require_once(LOGIC_PATH . '/update_raid_poll.php'); + exit; +} else { + // Check if max remote users limit is already reached! + $remote_users = get_remote_users_count($raidId, $update['callback_query']['from']['id']); + // Skip remote user limit check if user is not attending remotely. + // If they are, check if attend time already has max number of remote users. + if (($answer['remote'] == 1 or $data['arg'] == 'alien') && ($remote_users >= $config->RAID_REMOTEPASS_USERS_LIMIT or $answer['user_count'] >= $config->RAID_REMOTEPASS_USERS_LIMIT)) { + // Send max remote users reached. + send_vote_remote_users_limit_reached($update); + exit; + } + // Force invite beggars to user extra_in_person even if they vote +alien + if($answer['want_invite'] == 1 && $data['arg'] == 'alien') $data['arg'] = 'in_person'; - $tg_json = update_raid_poll($data['id'], false, $update, $tg_json); + if(!in_array($data['arg'], ['in_person', 'alien'])) { + error_log('Invalid vote variable: ' . $data['arg']); + exit; + } + $team = 'extra_' . $data['arg']; + // Increase team extra people. + my_query( + ' + UPDATE attendance + SET ' . $team . ' = ' . $team . ' + 1 + WHERE raid_id = :raidId + AND user_id = :userId + ', + [ + 'raidId' => $raidId, + 'userId' => $update['callback_query']['from']['id'], + ] + ); + $tg_json = alarm($raidId, $update['callback_query']['from']['id'], 'extra', $data['arg'], $tg_json); +} - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); +// Send vote response. +require_once(LOGIC_PATH . '/update_raid_poll.php'); - curl_json_multi_request($tg_json); -} else { - // Send vote time first. - send_vote_time_first($update); -} +$tg_json = update_raid_poll($raidId, false, $update, $tg_json); + +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); -$dbh = null; -exit(); +curl_json_multi_request($tg_json); diff --git a/mods/vote_remote.php b/mods/vote_remote.php index 128b4939..24bbef32 100644 --- a/mods/vote_remote.php +++ b/mods/vote_remote.php @@ -6,63 +6,67 @@ //debug_log($update); //debug_log($data); +$raidId = $data['id']; + // Get current remote status of user $rs = my_query( - " - SELECT remote, (1 + extra_in_person + extra_alien) as user_count - FROM attendance - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " + ' + SELECT remote, (1 + extra_in_person + extra_alien) as user_count, CASE WHEN cancel = 1 or raid_done = 1 THEN 1 ELSE 0 END as cancelOrDone + FROM attendance + WHERE raid_id = :raidId + AND user_id = :userId + ', + [ + 'raidId' => $raidId, + 'userId' => $update['callback_query']['from']['id'], + ] ); // Get remote value. $remote = $rs->fetch(); -$remote_status = isset($remote['remote']) ? $remote['remote'] : 0; -$user_remote_count = isset($remote['user_count']) ? $remote['user_count'] : 0; -// Check if max remote users limit is already reached! -$remote_users = get_remote_users_count($data['id'], $update['callback_query']['from']['id']); +if($rs->rowCount() == 0 or $remote['cancelOrDone'] == 1) { + // Send vote time first. + send_vote_time_first($update); + exit; +} -if($rs->rowCount() > 0) { - // Ignore max users reached when switching from remote to local otherwise check if max users reached? - if ($remote_users + $user_remote_count <= $config->RAID_REMOTEPASS_USERS_LIMIT || $remote_status == 1) { - // Update users table. - my_query( - " - UPDATE attendance - SET remote = CASE - WHEN remote = '0' THEN '1' - ELSE '0' - END, - want_invite = 0, - can_invite = 0 - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " - ); +$remote_status = $remote['remote']; - if($remote_status == 0) { - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'remote'); - } else { - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'no_remote'); - } +// Check if max remote users limit is already reached! +$remote_users = get_remote_users_count($raidId, $update['callback_query']['from']['id']); +// Ignore max users reached when switching from remote to local otherwise check if max users reached? +if($remote_status == 0 && $config->RAID_REMOTEPASS_USERS_LIMIT < $remote_users + $remote['user_count']) { + // Send max remote users reached. + send_vote_remote_users_limit_reached($update); + exit; +} +// Update users table. +my_query( + ' + UPDATE attendance + SET remote = CASE + WHEN remote = 0 THEN 1 + ELSE 0 + END, + want_invite = 0, + can_invite = 0 + WHERE raid_id = :raidId + AND user_id = :userId + ', + [ + 'raidId' => $raidId, + 'userId' => $update['callback_query']['from']['id'], + ] +); - // Send vote response. - require_once(LOGIC_PATH . '/update_raid_poll.php'); +$tg_json = alarm($raidId, $update['callback_query']['from']['id'], ($remote_status == 0 ? 'remote' : 'no_remote')); - $tg_json = update_raid_poll($data['id'], false, $update, $tg_json); +// Send vote response. +require_once(LOGIC_PATH . '/update_raid_poll.php'); - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); +$tg_json = update_raid_poll($raidId, false, $update, $tg_json); - curl_json_multi_request($tg_json); - } else { - // Send max remote users reached. - send_vote_remote_users_limit_reached($update); - } -} else { - // Send vote time first. - send_vote_time_first($update); -} +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); -exit(); +curl_json_multi_request($tg_json); diff --git a/mods/vote_time.php b/mods/vote_time.php index 1d58c49b..6c65a67d 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -6,183 +6,183 @@ //debug_log($update); //debug_log($data); -// Check if someone has voted for this raid before. -$rs_count = my_query( - " - SELECT count(attend_time) AS count - FROM attendance - WHERE raid_id = {$data['id']} - "); -// Get the answer. -$answer_count = $rs_count->fetch(); -// Get number of participants, if 0 -> raid has no participant at all -$count_att = $answer_count['count']; -// Write to log. -debug_log($answer_count, 'Anyone Voted: '); +$raidId = $data['id']; + +$vote_time = $data['arg']; +// Raid anytime? +$attend_time_save = $attend_time_compare = ANYTIME; +if($vote_time != 0) { + // Normal raid time - convert data arg to UTC time. + $dt = new DateTime(); + $dt_attend = $dt->createFromFormat('YmdHis', $vote_time, new DateTimeZone('UTC')); + $attend_time_compare = $dt_attend->format('Y-m-d H:i:s'); + $attend_time_save = $dt_attend->format('Y-m-d H:i') . ':00'; + + // Get current time. + $now = new DateTime('now', new DateTimeZone('UTC')); + $now = $now->format('Y-m-d H:i') . ':00'; +} + +// Vote time in the future? +if($attend_time_compare != ANYTIME && $now >= $attend_time_compare) { + // Send vote time first. + send_vote_time_future($update); + exit; +} // Request Raid and Gym - Infos -$raid = get_raid($data['id']); +$raid = get_raid($raidId); // Check if the user has voted for this raid before. -if($count_att > 0){ - $rs = my_query( - " - SELECT user_id, remote, attend_time, (1 + extra_in_person + extra_alien) as user_count - FROM attendance - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - LIMIT 1 - " - ); - - // Get the answer. - $answer = $rs->fetch(); - - // Write to log. - debug_log($answer); -}else{ - $answer = []; -} +$rs = my_query( + ' + SELECT count(attendance.attend_time) AS count, userInfo.* + FROM attendance + LEFT JOIN ( + SELECT raid_id, user_id, remote, attend_time, extra_alien, + (CASE WHEN remote = 1 THEN 1 + extra_in_person ELSE 0 END + extra_alien) as user_count, + CASE WHEN cancel = 1 or raid_done = 1 THEN 1 ELSE 0 END as cancelOrDone + FROM attendance + WHERE raid_id = :raidId + AND user_id = :userId + LIMIT 1 + ) as userInfo + ON userInfo.raid_id = attendance.raid_id + WHERE attendance.raid_id = :raidId + ', + [ + 'raidId' => $raidId, + 'userId' => $update['callback_query']['from']['id'], + ] +); -$tg_json = []; +// Get the answer. +$answer = $rs->fetch(); +// Get number of participants, if 0 -> raid has no participant at all +$count_att = $answer['count'] ?? 0; -$vote_time = $data['arg']; -// Raid anytime? -if($vote_time == 0) { - // Raid anytime. - $attend_time_save = $attend_time_compare = ANYTIME; -} else { - // Normal raid time - convert data arg to UTC time. - $dt = new DateTime(); - $dt_attend = $dt->createFromFormat('YmdHis', $vote_time, new DateTimeZone('UTC')); - $attend_time_compare = $dt_attend->format('Y-m-d H:i:s'); - $attend_time_save = $dt_attend->format('Y-m-d H:i') . ':00'; - - // Get current time. - $now = new DateTime('now', new DateTimeZone('UTC')); - $now = $now->format('Y-m-d H:i') . ':00'; -} +// Write to log. +debug_log($count_att, 'Anyone Voted: '); +debug_log($answer); -// Exit if user is voting for the same time again -if(is_array($answer) && array_key_exists('attend_time', $answer) && $attend_time_save == $answer['attend_time']) { +$tg_json = []; + +// User has voted before. +if ($answer['user_count'] != NULL) { + // Exit if user is voting for the same time again unless they are done/canceled + if(array_key_exists('attend_time', $answer) && $answer['cancelOrDone'] == 0 && $attend_time_save == $answer['attend_time']) { answerCallbackQuery($update['callback_query']['id'], 'OK'); + exit; + } + // If user voted something else than 'Anytime', get the number of remote users already attending + $remote_users = ($vote_time == 0) ? 0 : get_remote_users_count($raidId, $update['callback_query']['from']['id'], $attend_time_save); + + // Check if max remote users limit is already reached, unless voting for 'Anytime' + if(($answer['remote'] != 0 or $answer['extra_alien'] > 0) && $vote_time != 0 && $config->RAID_REMOTEPASS_USERS_LIMIT < ($remote_users + $answer['user_count'])) { + // Send max remote users reached. + send_vote_remote_users_limit_reached($update); $dbh = null; - exit(); -} - -// Vote time in the future or Raid anytime? -if($vote_time == 0 || $now <= $attend_time_compare) { - // If user is attending remotely, get the number of remote users already attending - if (!is_array($answer) or !in_array('remote', $answer) or $answer['remote'] == 0){ - $remote_users = 0; - } else { - $remote_users = get_remote_users_count($data['id'], $update['callback_query']['from']['id'], $attend_time); - } - // Check if max remote users limit is already reached, unless voting for 'Anytime' - if ((!empty($answer) && ($answer['remote'] == 0 || $remote_users + $answer['user_count'])) <= $config->RAID_REMOTEPASS_USERS_LIMIT || $vote_time == 0) { - // User has voted before. - if (!empty($answer)) { - // Update attendance. - $update_pokemon_sql = ''; - if(!in_array($raid['pokemon'], $eggs)) { - // If raid egg has hatched - // -> clean up attendance table from votes for other pokemon - // -> leave one entry remaining and set the pokemon to 0 there - my_query(" - DELETE a1 - FROM attendance a1 - INNER JOIN attendance a2 - WHERE a1.id < a2.id - AND a1.user_id = a2.user_id - AND a2.raid_id = {$raid['id']} - AND a1.raid_id = {$raid['id']} - "); - $update_pokemon_sql = 'pokemon = \'0\','; - } - my_query( - " - UPDATE attendance - SET attend_time = '{$attend_time_save}', - cancel = 0, - arrived = 0, - raid_done = 0, - {$update_pokemon_sql} - late = 0 - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " - ); - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'change_time', $attend_time_save, $tg_json); - - // User has not voted before. - } else { - $q_user = my_query("SELECT auto_alarm FROM users WHERE user_id ='" . $update['callback_query']['from']['id'] . "' LIMIT 1"); - $user_alarm = $q_user->fetch()['auto_alarm']; - if($config->RAID_AUTOMATIC_ALARM) { - $set_alarm = true; - }else { - $set_alarm = ($user_alarm == 1 ? true : false); - } - // Create attendance. - // Save attandence to DB + Set Auto-Alarm on/off according to config - $insert_sql="INSERT INTO attendance SET - raid_id = :raid_id, - user_id = :user_id, - attend_time = :attend_time, - alarm = :alarm"; - $dbh->prepare($insert_sql)->execute([ - 'raid_id' => $data['id'], - 'user_id' => $update['callback_query']['from']['id'], - 'attend_time' => $attend_time_save, - 'alarm' => ($set_alarm ? 1 : 0) - ]); - // Send Alarm. - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'new_att', $attend_time_save, $tg_json); - - // Enable alerts message. -> only if alert is on - if($set_alarm) { - // Inform User about active alert - sendAlertOnOffNotice($data['id'], $update['callback_query']['from']['id'], 1, $raid); - } - } - // Check if RAID has no participants AND Raid should be shared to another chat at first participant - // AND target chat was set in config AND Raid was not shared to target chat before - if($count_att == 0 && $config->SHARE_AFTER_ATTENDANCE && !empty($config->SHARE_CHATS_AFTER_ATTENDANCE)){ - // Check if Raid has been posted to target chat - $rs_chann = my_query( - " - SELECT * - FROM cleanup - WHERE raid_id = {$data['id']} - AND chat_id = {$config->SHARE_CHATS_AFTER_ATTENDANCE} - "); - // IF raid was not shared to target chat, we want to share it - if ($rs_chann->rowCount() == 0) { - // Send the message. - require_once(LOGIC_PATH . '/send_raid_poll.php'); - $tg_json = send_raid_poll($data['id'], $config->SHARE_CHATS_AFTER_ATTENDANCE, $raid, $tg_json); - } - } - } else { - // Send max remote users reached. - send_vote_remote_users_limit_reached($update); - $dbh = null; - exit(); - } - + exit; + } + + // Update attendance. + $update_pokemon_sql = ''; + if(!in_array($raid['pokemon'], $eggs)) { + // If raid egg has hatched + // -> clean up attendance table from votes for other pokemon + // -> leave one entry remaining and set the pokemon to 0 there + my_query(' + DELETE a1 + FROM attendance a1 + INNER JOIN attendance a2 + WHERE a1.id < a2.id + AND a1.user_id = a2.user_id + AND a2.raid_id = :raid_id + AND a1.raid_id = :raid_id + ', + [ + 'raid_id' => $raid['id'], + ]); + $update_pokemon_sql = 'pokemon = \'0\','; + } + my_query( + ' + UPDATE attendance + SET attend_time = :attendTimeSave, + cancel = 0, + arrived = 0, + raid_done = 0, + ' . $update_pokemon_sql . ' + late = 0 + WHERE raid_id = :raidId + AND user_id = :userId + ', + [ + 'attendTimeSave' => $attend_time_save, + 'raidId' => $raidId, + 'userId' => $update['callback_query']['from']['id'], + ] + ); + $tg_json = alarm($raidId, $update['callback_query']['from']['id'], 'change_time', $attend_time_save, $tg_json); + +// User has not voted before. } else { - // Send vote time first. - send_vote_time_future($update); + $q_user = my_query("SELECT auto_alarm FROM users WHERE user_id ='" . $update['callback_query']['from']['id'] . "' LIMIT 1"); + $set_alarm = (!$config->RAID_AUTOMATIC_ALARM) ? $q_user->fetch()['auto_alarm'] : 1; + + // Create attendance. + // Save attandence to DB + Set Auto-Alarm on/off according to config + $insert_sql = my_query(' + INSERT INTO attendance SET + raid_id = :raidId, + user_id = :userId, + attend_time = :attendTime, + alarm = :alarm + ', + [ + 'raidId' => $raidId, + 'userId' => $update['callback_query']['from']['id'], + 'attendTime' => $attend_time_save, + 'alarm' => $set_alarm, + ]); + // Send Alarm. + $tg_json = alarm($raidId,$update['callback_query']['from']['id'],'new_att', $attend_time_save, $tg_json); + + // Enable alerts message. -> only if alert is on + if($set_alarm == 1) { + // Inform User about active alert + sendAlertOnOffNotice($raidId, $update['callback_query']['from']['id'], 1, $raid); + } + + // Check if RAID has no participants AND Raid should be shared to another chat at first participant + // AND target chat was set in config AND Raid was not shared to target chat before + if($count_att == 0 && $config->SHARE_AFTER_ATTENDANCE && !empty($config->SHARE_CHATS_AFTER_ATTENDANCE)){ + // Check if Raid has been posted to target chat + $rs_chann = my_query( + ' + SELECT * + FROM cleanup + WHERE raid_id = :raidId + AND chat_id = :chatId + ', + [ + 'raidId' => $raidId, + 'chatId' => $config->SHARE_CHATS_AFTER_ATTENDANCE, + ]); + // IF raid was not shared to target chat, we want to share it + if ($rs_chann->rowCount() == 0) { + // Send the message. + require_once(LOGIC_PATH . '/send_raid_poll.php'); + $tg_json = send_raid_poll($raidId, $config->SHARE_CHATS_AFTER_ATTENDANCE, $raid, $tg_json); + } + } } // Send vote response. require_once(LOGIC_PATH . '/update_raid_poll.php'); -$tg_json = update_raid_poll($data['id'], $raid, $update, $tg_json); +$tg_json = update_raid_poll($raidId, $raid, $update, $tg_json); $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); curl_json_multi_request($tg_json); - -$dbh = null; -exit(); \ No newline at end of file diff --git a/mods/vote_want_invite.php b/mods/vote_want_invite.php index 6599220d..6c7363f1 100644 --- a/mods/vote_want_invite.php +++ b/mods/vote_want_invite.php @@ -6,68 +6,51 @@ //debug_log($update); //debug_log($data); -try { - $query_select = " - SELECT want_invite - FROM attendance - WHERE raid_id = :raid_id - AND user_id = :user_id - LIMIT 1 - "; - $statement_select = $dbh->prepare( $query_select ); - $statement_select->execute([ - 'raid_id' => $data['id'], - 'user_id' => $update['callback_query']['from']['id'] - ]); - $res = $statement_select->fetch(); - if($statement_select->rowCount() > 0) { - $query = " - UPDATE attendance - SET want_invite = CASE - WHEN want_invite = '0' THEN '1' - ELSE '0' - END, - late = 0, - arrived = 0, - remote = 0, - extra_alien = 0, - can_invite = 0 - WHERE raid_id = :raid_id - AND user_id = :user_id - "; - $statement = $dbh->prepare( $query ); - $statement->execute([ - 'raid_id' => $data['id'], - 'user_id' => $update['callback_query']['from']['id'] - ]); - } +$raidId = $data['id']; + +$query_select = my_query(' + SELECT want_invite, CASE WHEN cancel = 1 or raid_done = 1 THEN 1 ELSE 0 END as cancelOrDone + FROM attendance + WHERE raid_id = :raid_id + AND user_id = :user_id + LIMIT 1 + ', + [ + 'raid_id' => $raidId, + 'user_id' => $update['callback_query']['from']['id'], + ]); +$res = $query_select->fetch(); +if($query_select->rowCount() == 0 or $res['cancelOrDone'] == 1) { + // Send vote time first. + send_vote_time_first($update); + exit; } -catch (PDOException $exception) { - - error_log($exception->getMessage()); - $dbh = null; - exit; -} -if($statement_select->rowCount() > 0) { - if($res['want_invite'] == 0) { - $alarm_action = 'want_invite'; - } else { - $alarm_action = 'no_want_invite'; - } - // Send vote response. - require_once(LOGIC_PATH . '/update_raid_poll.php'); - - $tg_json = update_raid_poll($data['id'], false, $update); - - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],$alarm_action, '', $tg_json); - - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); - - curl_json_multi_request($tg_json); -} else { - // Send vote time first. - send_vote_time_first($update); -} - -$dbh = null; -exit(); +my_query(' + UPDATE attendance + SET want_invite = CASE + WHEN want_invite = 0 THEN 1 + ELSE 0 + END, + late = 0, + arrived = 0, + remote = 0, + extra_alien = 0, + can_invite = 0 + WHERE raid_id = :raid_id + AND user_id = :user_id + ', + [ + 'raid_id' => $raidId, + 'user_id' => $update['callback_query']['from']['id'] + ]); +// Send vote response. +require_once(LOGIC_PATH . '/update_raid_poll.php'); + +$tg_json = update_raid_poll($raidId, false, $update); + +$alarm_action = ($res['want_invite'] == 0) ? 'want_invite' : $alarm_action = 'no_want_invite'; +$tg_json = alarm($raidId, $update['callback_query']['from']['id'], $alarm_action, '', $tg_json); + +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); + +curl_json_multi_request($tg_json); From 793fe502b15bd20a3ef3fa5ee2c80254f63fc9ff Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 3 Nov 2022 20:20:49 +0200 Subject: [PATCH 087/367] Fixed english language code --- core/bot/constants.php | 1 + 1 file changed, 1 insertion(+) diff --git a/core/bot/constants.php b/core/bot/constants.php index 9d5e3101..73813dd7 100644 --- a/core/bot/constants.php +++ b/core/bot/constants.php @@ -14,6 +14,7 @@ 'nl' => 'NL', 'de' => 'DE', 'en-US' => 'EN', + 'en' => 'EN', 'it' => 'IT', 'pt' => 'PT-BR', 'ru' => 'RU', From 62be5df222c8e81252ba83294f51ef576df3280f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 5 Nov 2022 22:22:41 +0200 Subject: [PATCH 088/367] Fixed php warning --- core/bot/is_init.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/bot/is_init.php b/core/bot/is_init.php index f74fe7af..4f6308b5 100644 --- a/core/bot/is_init.php +++ b/core/bot/is_init.php @@ -8,7 +8,7 @@ if(extension_loaded('apcu') && apcu_enabled()){ - if (!apcu_exists($namespace)){ + if (isset($namespace) && !apcu_exists($namespace)){ apcu_store($namespace, time()); define('IS_INIT', true); define('IS_INIT_OR_WHATEVER', true); From a8326047a1fdd4471a0a21d85e89a3b54cbfdc9d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 5 Nov 2022 22:30:20 +0200 Subject: [PATCH 089/367] Added error handling to Telegram errors - Added sleep and retry logic if TG rate limits are hit - Clear database entry of poll/overview/trainerinfo message if it's been deleted --- core/telegram/functions.php | 110 +++++++++++++++++++++++++++++++---- logic.php | 2 +- logic/collectCleanup.php | 72 +++++++++++++++++++++++ logic/curl_json_response.php | 101 -------------------------------- 4 files changed, 171 insertions(+), 114 deletions(-) create mode 100644 logic/collectCleanup.php delete mode 100644 logic/curl_json_response.php diff --git a/core/telegram/functions.php b/core/telegram/functions.php index 8cdfddbe..b572b44c 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -747,10 +747,12 @@ function curl_json_request($post_contents, $identifier) curl_close($curl); // Process response from telegram api. - $response = curl_json_response($json_response, $post_contents, $identifier); + responseHandler($json_response, $post_contents); + + collectCleanup($json_response, $post_contents, $identifier); // Return response. - return $response; + return $json_response; } /** @@ -803,30 +805,114 @@ function curl_json_multi_request($json) else debug_log($data['post_contents'], '->'); } - // Execute the handles. - $running = null; + // Get content and remove handles. + $retry = false; + $maxRetries = 3; + $retryCount = 0; + $sleep = 0; do { - curl_multi_select($mh); + // On the second pass and onwards sleep before executing curls + if($retry === true) { + $retry = false; + $sleep = 0; + $retryCount++; + debug_log('Retrying in '.$sleep.' seconds'); + sleep($sleep); + debug_log('Retry count: '.($retryCount).'...'); + } + + // Execute the handles. + $running = null; + do { $status = curl_multi_exec($mh, $running); - } while($running > 0 && $status === CURLM_OK); + curl_multi_select($mh); + } while($running > 0 && $status === CURLM_OK); - if ($status != CURLM_OK) { + if ($status != CURLM_OK) { info_log(curl_multi_strerror($status)); - } + } - // Get content and remove handles. - foreach($curly as $id => $content) { + foreach($curly as $id => $content) { $response[$id] = curl_multi_getcontent($content); curl_multi_remove_handle($mh, $content); - } + $responseResults = responseHandler($response[$id], $json[$id]['post_contents']); + // Handle errors + if(is_array($responseResults) && $responseResults[0] === 'retry') { + $retry = true; + // Use the highest sleep value returned by TG + $sleep = $responseResults[1] > $sleep ? $responseResults[1] : $sleep; + // Re-add this handle with the same info + curl_multi_add_handle($mh, $curly[$id]); + continue; + } + + unset($curly[$id]); + } + }while($retry === true && $retryCount < $maxRetries); // Process response from telegram api. foreach($response as $id => $json_response) { - $response[$id] = curl_json_response($response[$id], $json[$id]['post_contents'], $json[$id]['identifier']); + collectCleanup($response[$id], $json[$id]['post_contents'], $json[$id]['identifier']); debug_log_incoming($json_response, '<-'); } // Return response. return $response; } +if($metrics) { + $tg_response_code = $metrics->registerCounter($namespace, 'tg_response_count', 'Counters of response codes from Telegram', ['code', 'method', 'description']); +} +/** + * Process response from Telegram. + * @param $jsonResponse JSON string returned by Telegram + * @param $request The request we sent to Telegram + * @return mixed + */ +function responseHandler($jsonResponse, $request) { + global $metrics, $tg_response_code; + // Write to log. + debug_log_incoming($jsonResponse, '<-'); + + // Decode json objects + $request_array = is_array($request) ? $request : json_decode($request, true); + $response = json_decode($jsonResponse, true); + if ($metrics){ + $code = 200; + $method = $request_array['method']; + $description = null; + if (isset($response['error_code'])) { + $code = $response['error_code']; + # We have to also include the description because TG overloads error codes + $description = $response['description']; + } + $tg_response_code->inc([$code, $method, $description]); + } + // Validate response. + if ((isset($response['ok']) && $response['ok'] != true) || isset($response['update_id'])) { + if(is_array($request)) $json = json_encode($request); else $json = $request; + // Handle some specific errors + if($response['description'] == 'Bad Request: message to edit not found' || $response['description'] == 'Bad Request: message to delete not found') { + // Loop through tables where we store sent messages + $table = ['cleanup', 'overview', 'trainerinfo']; + $i = 0; + do { + $q = my_query('DELETE FROM '.$table[$i].' WHERE chat_id = :chatId AND message_id = :messageId',['chatId' => $request_array['chat_id'], ':messageId' => $request_array['message_id']]); + $i++; + } while($q->rowCount() == 0 && $i < count($table)); + info_log($table[$i-1], 'A message was deleted by someone else than us. Deleting info from database table:'); + info_log($chatId, 'chat_id:'); + info_log($messageId, 'message_id:'); + return true; + } + if(substr($response['description'], 0, 30) == 'Too Many Requests: retry after') { + return [ 'retry', + ($response['parameters']['retry_after'] + 1), + ]; + } + info_log("{$json} -> {$jsonResponse}", 'ERROR:'); + // Log unhandled errors + return false; + } + return true; +} diff --git a/logic.php b/logic.php index eeef688b..c6fde260 100644 --- a/logic.php +++ b/logic.php @@ -8,7 +8,7 @@ include('logic/alarm.php'); include('logic/check_time.php'); include('logic/cp_keys.php'); -include('logic/curl_json_response.php'); +include('logic/collectCleanup.php'); include('logic/delete_raid.php'); include('logic/delete_trainerinfo.php'); include('logic/disable_raid_level.php'); diff --git a/logic/collectCleanup.php b/logic/collectCleanup.php new file mode 100644 index 00000000..43a0fb84 --- /dev/null +++ b/logic/collectCleanup.php @@ -0,0 +1,72 @@ + $largest_size) { + $largest_size = $photo['file_size']; + $save_id = $photo['file_id']; + $unique_id = $photo['file_unique_id']; + } + } + $standalone_photo = (array_key_exists('standalone_photo', $identifier) && $identifier['standalone_photo'] === true) ? 1 : 0; + my_query(" + REPLACE INTO photo_cache + VALUES (:id, :unique_id, :pokedex_id, :form_id, :raid_id, :ended, :gym_id, :standalone) + ",[ + ':id' => $save_id, + ':unique_id' => $unique_id, + ':pokedex_id' => $identifier['pokemon'], + ':form_id' => $identifier['pokemon_form'], + ':raid_id' => ($identifier['raid_ended'] ? 0 : $identifier['id']), // No need to save raid id if raid has ended + ':ended' => $identifier['raid_ended'], + ':gym_id' => $identifier['gym_id'], + ':standalone' => $standalone_photo, + ] + ); + } + $raid_id = is_array($identifier) ? $identifier['id'] : $identifier; + insert_cleanup($chat_id, $message_id, $raid_id, $type, $unique_id); + } + // Return response. + return $response; +} + +?> diff --git a/logic/curl_json_response.php b/logic/curl_json_response.php deleted file mode 100644 index 1b2038e1..00000000 --- a/logic/curl_json_response.php +++ /dev/null @@ -1,101 +0,0 @@ -registerCounter($namespace, 'tg_response_count', 'Counters of response codes from Telegram', ['code', 'method', 'description']); -} - -/** - * Process response from telegram api. - * @param string $json_response Json response from Telegram - * @param string $request Request sent to Telegram - * @param array|int|string $identifier raid array from get_raid, raid id or [overview/trainer] - * @return mixed - */ -function curl_json_response($json_response, $request, $identifier = false) -{ - global $metrics, $tg_response_code; - // Write to log. - debug_log_incoming($json_response, '<-'); - - // Decode json objects - $request_array = is_array($request) ? $request : json_decode($request, true); - $response = json_decode($json_response, true); - if ($metrics){ - $code = 200; - $method = $request_array['method']; - $description = null; - if (isset($response['error_code'])) { - $code = $response['error_code']; - # We have to also include the description because TG overloads error codes - $description = $response['description']; - } - $tg_response_code->inc([$code, $method, $description]); - } - // Validate response. - if ((isset($response['ok']) && $response['ok'] != true) || isset($response['update_id'])) { - if(is_array($request)) $json = json_encode($request); else $json = $request; - info_log("{$json} -> {$json_response}", 'ERROR:'); - } else { - if($identifier != false) { - if (isset($response['result']['chat']['type']) && in_array($response['result']['chat']['type'], ['channel','group','supergroup'])) { - // Set chat and message_id - $chat_id = $response['result']['chat']['id']; - $message_id = $response['result']['message_id']; - debug_log('Return data: Chat id: '.$chat_id.', message_id: '.$message_id.', type: '.(is_array($identifier) ? print_r($identifier,true) : $identifier)); - if($identifier == 'trainer') { - debug_log('Adding trainermessage info to database now!'); - insert_trainerinfo($chat_id, $message_id); - }else if ($identifier == 'overview') { - debug_log('Adding overview info to database now!'); - $chat_title = $response['result']['chat']['title']; - $chat_username = isset($response['result']['chat']['username']) ? $response['result']['chat']['username'] : ''; - - insert_overview($chat_id, $message_id, $chat_title, $chat_username); - }else { - if(isset($response['result']['text']) && !empty($response['result']['text'])) { - $type = 'poll_text'; - } else if(isset($response['result']['caption']) && !empty($response['result']['caption'])) { - $type = 'poll_photo'; - } else if(isset($response['result']['venue']) && !empty($response['result']['venue'])) { - $type = 'poll_venue'; - }else if(isset($response['result']['photo']) && !isset($response['result']['caption'])) { - $type = 'photo'; - } - $save_id = $unique_id = false; - if(isset($response['result']['photo'])) { - $largest_size = 0; - foreach($response['result']['photo'] as $photo) { - if($photo['file_size'] > $largest_size) { - $largest_size = $photo['file_size']; - $save_id = $photo['file_id']; - $unique_id = $photo['file_unique_id']; - } - } - $standalone_photo = (array_key_exists('standalone_photo', $identifier) && $identifier['standalone_photo'] === true) ? 1 : 0; - my_query(" - REPLACE INTO photo_cache - VALUES (:id, :unique_id, :pokedex_id, :form_id, :raid_id, :ended, :gym_id, :standalone) - ",[ - ':id' => $save_id, - ':unique_id' => $unique_id, - ':pokedex_id' => $identifier['pokemon'], - ':form_id' => $identifier['pokemon_form'], - ':raid_id' => ($identifier['raid_ended'] ? 0 : $identifier['id']), // No need to save raid id if raid has ended - ':ended' => $identifier['raid_ended'], - ':gym_id' => $identifier['gym_id'], - ':standalone' => $standalone_photo, - ] - ); - } - $raid_id = is_array($identifier) ? $identifier['id'] : $identifier; - insert_cleanup($chat_id, $message_id, $raid_id, $type, $unique_id); - } - } - } - } - - // Return response. - return $response; -} - -?> From ecbd4a2ff6bda3e659514c755403c23525b36ed8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 6 Nov 2022 11:32:50 +0200 Subject: [PATCH 090/367] Fixed Pokemon form translation fallback --- core/bot/logic/language.php | 2 +- lang/pokemon_moves.json | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/core/bot/logic/language.php b/core/bot/logic/language.php index d7c40cee..753e4680 100644 --- a/core/bot/logic/language.php +++ b/core/bot/logic/language.php @@ -99,7 +99,7 @@ function getTranslation($text, $language = false) $translation = $translations[$text][DEFAULT_LANGUAGE]; // No translation found - elseif($tfile == 'botHelp') + elseif($tfile == 'botHelp' or $tfile == 'pokemonForms') $translation = false; else $translation = $text; diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index 71657405..cc69948a 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -3964,6 +3964,19 @@ "RU": "Преграда", "ES": "Obstrucción" }, + "pokemon_move_371": { + "PT-BR": "Força das Sombras", + "EN": "Shadow Force", + "FI": "Shadow Force", + "NL": "Shadow Force", + "NO": "Shadow Force", + "PL": "Shadow Force", + "FR": "Revenant", + "DE": "Schemenkraft", + "IT": "Oscurotuffo", + "RU": "Сумеречная Сила", + "ES": "Golpe Umbrío" + }, "pokemon_move_372": { "PT-BR": "Raio Meteórico", "EN": "Meteor Beam", @@ -3977,18 +3990,6 @@ "RU": "Метеоритный Луч", "ES": "Rayo Meteórico" }, - "pokemon_move_371": { - "PT-BR": "Força das Sombras", - "EN": "Shadow Force", - "FI": "Shadow Force", - "NL": "Shadow Force", - "NO": "Shadow Force", - "PL": "Shadow Force", - "FR": "Revenant", - "DE": "Schemenkraft", - "RU": "Сумеречная Сила", - "ES": "Golpe Umbrío" - }, "pokemon_move_376": { "PT-BR": "Poltergeist", "EN": "Poltergeist", @@ -3998,6 +3999,7 @@ "PL": "Poltergeist", "FR": "Esprit Frappeur", "DE": "Poltergeist", + "IT": "Poltergeist", "RU": "Полтергейст", "ES": "Poltergeist" } From 2125513e0cd81a3d1b1488aa0856aff0446970d5 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 6 Nov 2022 18:02:47 +0200 Subject: [PATCH 091/367] Fixed response format --- core/telegram/functions.php | 12 +++++++----- logic/collectCleanup.php | 5 ++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/telegram/functions.php b/core/telegram/functions.php index b572b44c..1fb09915 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -749,10 +749,11 @@ function curl_json_request($post_contents, $identifier) // Process response from telegram api. responseHandler($json_response, $post_contents); - collectCleanup($json_response, $post_contents, $identifier); + $responseArray = json_decode($json_response, true); + collectCleanup($responseArray, $post_contents, $identifier); // Return response. - return $json_response; + return $responseArray; } /** @@ -850,14 +851,15 @@ function curl_json_multi_request($json) } }while($retry === true && $retryCount < $maxRetries); + $responseArrays = []; // Process response from telegram api. foreach($response as $id => $json_response) { - collectCleanup($response[$id], $json[$id]['post_contents'], $json[$id]['identifier']); - debug_log_incoming($json_response, '<-'); + $responseArrays[$id] = json_decode($response[$id], true); + collectCleanup($responseArrays[$id], $json[$id]['post_contents'], $json[$id]['identifier']); } // Return response. - return $response; + return $responseArrays; } if($metrics) { $tg_response_code = $metrics->registerCounter($namespace, 'tg_response_count', 'Counters of response codes from Telegram', ['code', 'method', 'description']); diff --git a/logic/collectCleanup.php b/logic/collectCleanup.php index 43a0fb84..53274d71 100644 --- a/logic/collectCleanup.php +++ b/logic/collectCleanup.php @@ -2,14 +2,13 @@ /** * Process response from telegram api. - * @param string $json_response Json response from Telegram + * @param string $response Decoded json response from Telegram * @param string $request Request sent to Telegram * @param array|int|string $identifier raid array from get_raid, raid id or [overview/trainer] * @return mixed */ -function collectCleanup($json_response, $request, $identifier = false) +function collectCleanup($response, $request, $identifier = false) { - $response = json_decode($json_response, true); if($identifier == false) return $response; if(!isset($response['result']['chat']['type']) or !in_array($response['result']['chat']['type'], ['channel','group','supergroup'])) return $response; From f38e2a7a0eabc6a4370dba6338ad8faa1251497d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 6 Nov 2022 19:20:42 +0200 Subject: [PATCH 092/367] One more check to prevent sharing a raid twice to a chat --- logic/send_raid_poll.php | 24 +++++++++++++++++++----- mods/vote_time.php | 21 +++------------------ 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/logic/send_raid_poll.php b/logic/send_raid_poll.php index 6607be1f..79989dc0 100644 --- a/logic/send_raid_poll.php +++ b/logic/send_raid_poll.php @@ -2,14 +2,31 @@ /** * Post a raid poll to all relevant chats * @param int $raid_id ID of the raid - * @param int|array $chats chat ID or array of IDs + * @param int|array $shareChats chat ID or array of IDs * @param array|false $raid Array received from get_raid() (optional). * @param array|false $tg_json multicurl array * @return array multicurl array */ -function send_raid_poll($raid_id, $chats, $raid = false, $tg_json = false) { +function send_raid_poll($raid_id, $shareChats, $raid = false, $tg_json = false) { global $config; + // Telegram JSON array. + if($tg_json == false) $tg_json = []; + if(!is_array($shareChats)) $shareChats = [$shareChats]; + // Check if Raid has been posted to target chat + $resultChats = my_query( + ' + SELECT DISTINCT chat_id + FROM cleanup + WHERE raid_id = :raidId + AND chat_id IN ("' . implode('","',$shareChats) . '") + ', + [ + 'raidId' => $raid_id, + ]); + $chatsAlreadySharedTo = $resultChats->fetchAll(PDO::FETCH_COLUMN, 0); + $chats = array_diff($shareChats, $chatsAlreadySharedTo); + if(count($chats) == 0) return $tg_json; // Get raid data. if($raid == false) $raid = get_raid($raid_id); @@ -32,8 +49,6 @@ function send_raid_poll($raid_id, $chats, $raid = false, $tg_json = false) { $post_text = true; } - // Telegram JSON array. - if($tg_json == false) $tg_json = []; // Send the message. $raid_picture_hide_level = explode(",",$config->RAID_PICTURE_HIDE_LEVEL); @@ -45,7 +60,6 @@ function send_raid_poll($raid_id, $chats, $raid = false, $tg_json = false) { $raid_pokemon_form_name = get_pokemon_form_name($raid_pokemon_id,$raid['pokemon_form']); $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_name; - if(!is_array($chats)) $chats = [$chats]; foreach($chats as $chat_id) { // Send location. if ($config->RAID_LOCATION) { diff --git a/mods/vote_time.php b/mods/vote_time.php index 6c65a67d..9081d361 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -157,24 +157,9 @@ // Check if RAID has no participants AND Raid should be shared to another chat at first participant // AND target chat was set in config AND Raid was not shared to target chat before if($count_att == 0 && $config->SHARE_AFTER_ATTENDANCE && !empty($config->SHARE_CHATS_AFTER_ATTENDANCE)){ - // Check if Raid has been posted to target chat - $rs_chann = my_query( - ' - SELECT * - FROM cleanup - WHERE raid_id = :raidId - AND chat_id = :chatId - ', - [ - 'raidId' => $raidId, - 'chatId' => $config->SHARE_CHATS_AFTER_ATTENDANCE, - ]); - // IF raid was not shared to target chat, we want to share it - if ($rs_chann->rowCount() == 0) { - // Send the message. - require_once(LOGIC_PATH . '/send_raid_poll.php'); - $tg_json = send_raid_poll($raidId, $config->SHARE_CHATS_AFTER_ATTENDANCE, $raid, $tg_json); - } + // Send the message. + require_once(LOGIC_PATH . '/send_raid_poll.php'); + $tg_json = send_raid_poll($raidId, $config->SHARE_CHATS_AFTER_ATTENDANCE, $raid, $tg_json); } } From cb9a36a57b37d8cd08e7673f44f2234bb715d94c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 8 Nov 2022 16:58:53 +0200 Subject: [PATCH 093/367] Another attempt at getting the timezone right --- logic/read_upcoming_bosses.php | 103 +++++++++++++++++---------------- mods/update_bosses.php | 6 +- 2 files changed, 56 insertions(+), 53 deletions(-) diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index cf5a981b..951e796e 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -6,63 +6,64 @@ * @return string */ function read_upcoming_bosses($return_sql = false) { - global $pokebattler_import_future_tiers, $pokebattler_level_map, $pokebattler_pokemon_map; - $link = curl_get_contents('https://fight.pokebattler.com/raids'); - $pb = json_decode($link,true); + global $pokebattler_import_future_tiers, $pokebattler_level_map, $pokebattler_pokemon_map; + $link = curl_get_contents('https://fight.pokebattler.com/raids'); + $pb = json_decode($link, true); + if(!isset($pb['breakingNews'])) return ''; - $pb_timezone = new dateTimeZone('America/Phoenix'); - $count = 0; - $sql = $list = $prev_start = $prev_end = $prev_rl = ''; - if(isset($pb['breakingNews'])) { - foreach($pb['breakingNews'] as $news) { - if($news['type'] == 'RAID_TYPE_RAID') { - $rl = str_replace('RAID_LEVEL_','', $news['tier']); - $raid_level_id = array_search($rl, $pokebattler_level_map); - if(!in_array($raid_level_id,$pokebattler_import_future_tiers)) break; // Limit scheduling to tier 5 and mega only - $starttime = new DateTime("@".(substr($news['startDate'],0,10)), new dateTimeZone('UTC')); - $endtime = new DateTime("@".(substr($news['endDate'],0,10)), new dateTimeZone('UTC')); + $pb_timezone = new dateTimeZone('America/Los_Angeles'); + $standardTimezone = new dateTimeZone('UTC'); + $count = 0; + $sql = $list = $prev_start = $prev_end = $prev_rl = ''; + foreach($pb['breakingNews'] as $news) { + if($news['type'] != 'RAID_TYPE_RAID') continue; - $starttime->setTimezone($pb_timezone); - $endtime->setTimezone($pb_timezone); + $rl = str_replace('RAID_LEVEL_','', $news['tier']); + $raid_level_id = array_search($rl, $pokebattler_level_map); + if(!in_array($raid_level_id, $pokebattler_import_future_tiers)) continue; // Limit scheduling to tier 5 and higher only + $starttime = new DateTime("@".(substr($news['startDate'],0,10)), $standardTimezone); + $endtime = new DateTime("@".(substr($news['endDate'],0,10)), $standardTimezone); - // If the boss only appears for an hour, the eggs most likely start to spawn 20 minutes prior to the time. - $diff = $starttime->diff($endtime); - if($diff->format('%h') == 1) { - $starttime->sub(new DateInterval('PT20M')); - } - $date_start = $starttime->format('Y-m-d H:i:s'); + $starttime->setTimezone($pb_timezone); + $endtime->setTimezone($pb_timezone); - $date_end = $endtime->format('Y-m-d H:i:s'); + // If the boss only appears for an hour, the eggs most likely start to spawn 20 minutes prior to the time. + $diff = $starttime->diff($endtime); + if($diff->format('%h') == 1) { + $starttime->sub(new DateInterval('PT20M')); + } + + $date_start = $starttime->format('Y-m-d H:i:s'); + $date_end = $endtime->format('Y-m-d H:i:s'); - $boss = $news['pokemon']; - if(in_array($news['pokemon'], array_keys($pokebattler_pokemon_map))) { - $boss = $pokebattler_pokemon_map[$news['pokemon']]; - } - $dex_id_form = explode('-',resolve_boss_name_to_ids($boss),2); - if($prev_start != $date_start or $prev_end != $date_end) { - $list.= CR . EMOJI_CLOCK . ' ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; - $prev_rl = ''; - } - if($prev_rl != $raid_level_id) { - $list.= '' . getTranslation($raid_level_id . 'stars') .':' . CR; - } - $list.= get_local_pokemon_name($dex_id_form[0], $dex_id_form[1]) . CR; - $prev_start = $date_start; - $prev_end = $date_end; - $prev_rl = $raid_level_id; + $boss = $news['pokemon']; + if(in_array($news['pokemon'], array_keys($pokebattler_pokemon_map))) { + $boss = $pokebattler_pokemon_map[$news['pokemon']]; + } + $dex_id_form = explode('-',resolve_boss_name_to_ids($boss),2); + if($prev_start != $date_start or $prev_end != $date_end) { + $list.= CR . EMOJI_CLOCK . ' ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; + $prev_rl = ''; + } + if($prev_rl != $raid_level_id) { + $list.= '' . getTranslation($raid_level_id . 'stars') .':' . CR; + } + $list.= get_local_pokemon_name($dex_id_form[0], $dex_id_form[1]) . CR; + $prev_start = $date_start; + $prev_end = $date_end; + $prev_rl = $raid_level_id; - if($count == 0) { - $count++; - $sql .= 'INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, date_start, date_end, raid_level, scheduled) VALUES '; - $sql .= '("'.$dex_id_form[0].'","'.$dex_id_form[1].'","'.$date_start.'","'.$date_end.'","'.$raid_level_id.'", 1)'; - }else { - $sql .= ',("'.$dex_id_form[0].'","'.$dex_id_form[1].'","'.$date_start.'","'.$date_end.'","'.$raid_level_id.'", 1)'; - } - } - } - if($count > 0) $sql.=';'; + if($count == 0) { + $count++; + $sql .= 'INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, date_start, date_end, raid_level, scheduled) VALUES '; + $sql .= '("'.$dex_id_form[0].'","'.$dex_id_form[1].'","'.$date_start.'","'.$date_end.'","'.$raid_level_id.'", 1)'; + }else { + $sql .= ',("'.$dex_id_form[0].'","'.$dex_id_form[1].'","'.$date_start.'","'.$date_end.'","'.$raid_level_id.'", 1)'; } - if($return_sql) return $sql; - else return $list; + } + if($count > 0) $sql.=';'; + + if($return_sql) return $sql; + else return $list; } ?> \ No newline at end of file diff --git a/mods/update_bosses.php b/mods/update_bosses.php index 9cd1cc3e..71f85808 100644 --- a/mods/update_bosses.php +++ b/mods/update_bosses.php @@ -4,7 +4,7 @@ if(!$config->ENABLE_BOSS_AUTO_UPDATE) { exit; } $levels = $data['id']; -$source = $data ['arg']; +$source = $data['arg']; $add_mons = []; if($levels != 'scheduled') { $get_levels = explode(",",$levels); @@ -54,8 +54,10 @@ } }elseif($levels == 'scheduled') { require_once(LOGIC_PATH . '/read_upcoming_bosses.php'); + $data = read_upcoming_bosses(true); + if(empty($data)) exit; $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1;'; - $sql .= read_upcoming_bosses(true); + $sql .= $data; }else { info_log("Invalid argumens supplied to update_bosses!"); exit(); From 85527c01dbe1288999342ee8eaec99c7139e20c4 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 8 Nov 2022 17:07:50 +0200 Subject: [PATCH 094/367] Only save lang code if it's known --- core/bot/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/bot/user.php b/core/bot/user.php index 9e0fe7b3..09f485fd 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -333,7 +333,7 @@ private function updateUserdb($update) $nick = (isset($msg['username'])) ? $msg['username'] : ''; - $lang = (isset($msg['language_code'])) ? $msg['language_code'] : ''; + $lang = (isset($msg['language_code']) && array_key_exists($msg['language_code'], $GLOBALS['languages'])) ? $msg['language_code'] : 'en'; // Create or update the user. $stmt = $dbh->prepare( From 646aa17fccb61e2d6f55c0fd6383aae7e4025476 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 8 Nov 2022 19:19:04 +0200 Subject: [PATCH 095/367] Added OSM_CUSTOM_ADDRESS Ability to set address for custom nominatim server --- config/defaults-config.json | 1 + core/bot/logic/geo_api.php | 2 +- docs/config.rst | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config/defaults-config.json b/config/defaults-config.json index 44e74ac4..540a2e21 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -30,6 +30,7 @@ "MAPS_LOOKUP": false, "MAPS_API_KEY":"", "OSM_LOOKUP": false, + "OSM_CUSTOM_ADDRESS": "", "AUTO_REFRESH_POLLS":false, "ENABLE_BOSS_AUTO_UPDATE": true, "CUSTOM_TRAINERNAME": true, diff --git a/core/bot/logic/geo_api.php b/core/bot/logic/geo_api.php index 93c79aae..7300eae5 100644 --- a/core/bot/logic/geo_api.php +++ b/core/bot/logic/geo_api.php @@ -138,7 +138,7 @@ function get_address($lat, $lon) // Set maps geocode url. $language = strtolower($config->LANGUAGE_PUBLIC); $MapsApiKey = $config->MAPS_API_KEY; - $url = 'https://nominatim.openstreetmap.org/reverse?lat=' . $lat . '&lon=' . $lon . '&format=json&accept-language=' . $language; + $url = ((isset($config->OSM_CUSTOM_ADDRESS) && $config->OSM_CUSTOM_ADDRESS != '') ? $config->OSM_CUSTOM_ADDRESS : 'https://nominatim.openstreetmap.org') . '/reverse?lat=' . $lat . '&lon=' . $lon . '&format=json&accept-language=' . $language; // Curl request. $curl = curl_init($url); diff --git a/docs/config.rst b/docs/config.rst index a7a82484..b66f7537 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -193,6 +193,8 @@ OpenStreetMap API To use OpenStreetMap's Nominatim API to lookup addresses of gyms, set ``OSM_LOOKUP`` to ``true`` and ``MAPS_LOOKUP`` to ``false``. +You can set a custom nominatim server address in ``OSM_CUSTOM_ADDRESS``, e.g. ``http://localhost:8090``. + Quote from `Nominatim documentation `_\ : ``The reverse geocoding API does not exactly compute the address for the coordinate it receives. It works by finding the closest suitable OSM object and returning its address information. This may occasionally lead to unexpected results.`` @@ -940,6 +942,8 @@ Config reference - Boolean, resolve missing gym addresses via Google Maps * - OSM_LOOKUP - Boolean, resolve missing gym addresses via OpenStreetMap + * - OSM_CUSTOM_ADDRESS + - String, if OSM lookup is enabled, you can set private server address here. e.g. ``http://localhost:8090`` * - MAP_URL - URL to your map. This is displayed under every raid poll. * - CUSTOM_TRAINERNAME From cbf933fbc28a962a5baba78a6ca3c4561a9d2d8e Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 8 Nov 2022 21:59:56 +0200 Subject: [PATCH 096/367] Renamed OSM_CUSTOM_ADDRESS to OSM_URL --- config/defaults-config.json | 2 +- core/bot/logic/geo_api.php | 3 +-- docs/config.rst | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/config/defaults-config.json b/config/defaults-config.json index 540a2e21..1aca962a 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -30,7 +30,7 @@ "MAPS_LOOKUP": false, "MAPS_API_KEY":"", "OSM_LOOKUP": false, - "OSM_CUSTOM_ADDRESS": "", + "OSM_URL": "https://nominatim.openstreetmap.org", "AUTO_REFRESH_POLLS":false, "ENABLE_BOSS_AUTO_UPDATE": true, "CUSTOM_TRAINERNAME": true, diff --git a/core/bot/logic/geo_api.php b/core/bot/logic/geo_api.php index 7300eae5..98d94fa3 100644 --- a/core/bot/logic/geo_api.php +++ b/core/bot/logic/geo_api.php @@ -137,8 +137,7 @@ function get_address($lat, $lon) // Set maps geocode url. $language = strtolower($config->LANGUAGE_PUBLIC); - $MapsApiKey = $config->MAPS_API_KEY; - $url = ((isset($config->OSM_CUSTOM_ADDRESS) && $config->OSM_CUSTOM_ADDRESS != '') ? $config->OSM_CUSTOM_ADDRESS : 'https://nominatim.openstreetmap.org') . '/reverse?lat=' . $lat . '&lon=' . $lon . '&format=json&accept-language=' . $language; + $url = $config->OSM_URL . '/reverse?lat=' . $lat . '&lon=' . $lon . '&format=json&accept-language=' . $language; // Curl request. $curl = curl_init($url); diff --git a/docs/config.rst b/docs/config.rst index b66f7537..089f4e35 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -193,7 +193,7 @@ OpenStreetMap API To use OpenStreetMap's Nominatim API to lookup addresses of gyms, set ``OSM_LOOKUP`` to ``true`` and ``MAPS_LOOKUP`` to ``false``. -You can set a custom nominatim server address in ``OSM_CUSTOM_ADDRESS``, e.g. ``http://localhost:8090``. +You can set a custom nominatim server address in ``OSM_URL``, e.g. ``http://localhost:8090``. Quote from `Nominatim documentation `_\ : @@ -942,7 +942,7 @@ Config reference - Boolean, resolve missing gym addresses via Google Maps * - OSM_LOOKUP - Boolean, resolve missing gym addresses via OpenStreetMap - * - OSM_CUSTOM_ADDRESS + * - OSM_URL - String, if OSM lookup is enabled, you can set private server address here. e.g. ``http://localhost:8090`` * - MAP_URL - URL to your map. This is displayed under every raid poll. From 39dc8509d1b1f046d3192a0f193ddb1efcc287d6 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 9 Nov 2022 10:19:53 +0200 Subject: [PATCH 097/367] Extend raid boss check to raid level 8 also --- .../raid_hour_creator.php | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/core/tools/automate_raid_hour_creation/raid_hour_creator.php b/core/tools/automate_raid_hour_creation/raid_hour_creator.php index 08836de4..18db249c 100644 --- a/core/tools/automate_raid_hour_creation/raid_hour_creator.php +++ b/core/tools/automate_raid_hour_creation/raid_hour_creator.php @@ -110,18 +110,21 @@ $dbh = null; function get_current_bosses($spawn) { global $dbh; - $pk = $dbh->prepare('SELECT pokedex_id,pokemon_form_id FROM raid_bosses WHERE raid_level = \'5\' AND \''.$spawn.'\' BETWEEN date_start AND date_end'); - $pk->execute(); - $res = $pk->fetch(); - if($pk->rowCount()==1) { - $pokemon = $res['pokedex_id']; - $pokemon_form = $res['pokemon_form_id']; - }elseif($pk->rowCount()>1) { - $pokemon = 9995; - $pokemon_form = 0; - }else { - return false; - } + $i = 0; + $levels = [5, 8]; // Search potential raid hour bosses from these raid levels + do { + $pk = $dbh->prepare('SELECT pokedex_id,pokemon_form_id FROM raid_bosses WHERE raid_level = ? AND ? BETWEEN date_start AND date_end'); + $pk->execute([$levels[$i], $spawn]); + $res = $pk->fetch(); + if($pk->rowCount() == 1) { + $pokemon = $res['pokedex_id']; + $pokemon_form = $res['pokemon_form_id']; + }elseif($pk->rowCount() > 1) { + $pokemon = 999 . $levels[$i]; + $pokemon_form = 0; + } + $i++; + } while($pk->rowcount() > 0 or $i < 1); return [$pokemon,$pokemon_form]; } function curl_get_contents($url) From 3d9e2ee4fa03e8fe6976de9d5a1f11404fb03f7e Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 9 Nov 2022 10:38:48 +0200 Subject: [PATCH 098/367] Maybe now this works --- core/tools/automate_raid_hour_creation/raid_hour_creator.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/tools/automate_raid_hour_creation/raid_hour_creator.php b/core/tools/automate_raid_hour_creation/raid_hour_creator.php index 18db249c..b6ba37a8 100644 --- a/core/tools/automate_raid_hour_creation/raid_hour_creator.php +++ b/core/tools/automate_raid_hour_creation/raid_hour_creator.php @@ -112,6 +112,7 @@ function get_current_bosses($spawn) { global $dbh; $i = 0; $levels = [5, 8]; // Search potential raid hour bosses from these raid levels + $pokemon = $pokemon_form = false; do { $pk = $dbh->prepare('SELECT pokedex_id,pokemon_form_id FROM raid_bosses WHERE raid_level = ? AND ? BETWEEN date_start AND date_end'); $pk->execute([$levels[$i], $spawn]); @@ -124,7 +125,8 @@ function get_current_bosses($spawn) { $pokemon_form = 0; } $i++; - } while($pk->rowcount() > 0 or $i < 1); + } while($pk->rowcount() > 0 or $i <= 1); + if($pokemon === false) return false; return [$pokemon,$pokemon_form]; } function curl_get_contents($url) From ad2fbf3ae40ab15207e858538639e66a63faf2ec Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 9 Nov 2022 21:06:03 +0200 Subject: [PATCH 099/367] Fixed grab_img error handling --- logic/raid_picture.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index b08baf87..1f87b0af 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -677,8 +677,9 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { * @return object */ function grab_img($uri) { - $img = imagecreatefromstring(file_get_contents($uri)); - if ($img === false) { + try { + $img = imagecreatefromstring(file_get_contents($uri)); + }catch(Exception $e) { info_log($uri, 'Failed to get image:'); return false; } From a3b60e015eb0803aba898a42e5f38469333b2856 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 10 Nov 2022 11:58:07 +0200 Subject: [PATCH 100/367] Change the raid picture send method Removed RAID_PICTURE_URL and RAID_PICTURE_SEND_METHOD. The picture is now by default sent along with rest of the message data instead of having Telegram fetch it from our raidpicture.php. Minimum PHP version for this is 8.1. --- config/config.json.example | 1 - config/defaults-config.json | 2 -- logic/raid_picture.php | 44 ++----------------------------------- 3 files changed, 2 insertions(+), 45 deletions(-) diff --git a/config/config.json.example b/config/config.json.example index 7e2e5ea9..8114a7f4 100644 --- a/config/config.json.example +++ b/config/config.json.example @@ -19,6 +19,5 @@ "RAID_PICTURE": false, "RAID_PICTURE_AUTOEXTEND": false, "RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY": true, - "RAID_PICTURE_URL":"https://example.com/raid/raidpicture.php", "RAID_POLL_UI_TEMPLATE":[["alone","extra","extra_alien","remote","inv_plz","can_inv","ex_inv"],["teamlvl"],["time"],["pokemon"],["refresh","alarm","here","late","done","cancel"]] } diff --git a/config/defaults-config.json b/config/defaults-config.json index 1aca962a..5aa4d805 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -61,7 +61,6 @@ "RAID_PICTURE": false, "RAID_PICTURE_AUTOEXTEND": false, "RAID_AUTOMATIC_ALARM": false, - "RAID_PICTURE_SEND_METHOD": "url", "RAID_PICTURE_HIDE_LEVEL":"", "RAID_PICTURE_HIDE_POKEMON":"", "RAID_PICTURE_BG_COLOR":"0,0,0", @@ -71,7 +70,6 @@ "RAID_PICTURE_SHOW_SHINY": true, "RAID_DEFAULT_PICTURE":"images/gym_default.png", "RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY": true, - "RAID_PICTURE_URL":"https://example.com/raid/raidpicture.php", "RAID_PICTURE_FONT_GYM":"NotoSans-Bold.ttf", "RAID_PICTURE_FONT_EX_GYM":"NotoSans-Regular.ttf", "RAID_PICTURE_FONT_TEXT":"NotoSans-Regular.ttf", diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 1f87b0af..4be08320 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -1,51 +1,13 @@ $raid['end_time']) { - // We'll set raid start and end times to 0 to get a new image for when the raid has ended. - // Setting thetimes to 0 also makes it so TG can cache the raid ended -images and reuse them - $start_time = $end_time = 0; - $raid_id = ''; - }else { - $start_time = strtotime($raid['start_time']); - $end_time = strtotime($raid['end_time']); - $raid_id = 'raid='.$raid['id'].'&'; - } - if($raid['event'] == EVENT_ID_EX) $ex_raid = '1'; else $ex_raid = '0'; - $picture_url = "{$config->RAID_PICTURE_URL}?{$raid_id}pokemon={$raid['pokemon']}&pokemon_form={$raid['pokemon_form']}&gym_id={$raid['gym_id']}&start_time={$start_time}&end_time={$end_time}&ex_raid={$ex_raid}"; - if($standalone) $picture_url .= '&sa=1'; - if($raid['costume'] != 0) $picture_url .= '&costume='.$raid['costume']; - debug_log('raid_picture_url: ' . $picture_url); - return $picture_url; -} - -/** - * Returns photo contents to post to Telegram. File_id, url or photo file contents + * Returns photo contents to post to Telegram. File_id or photo file contents * @param array $raid Raid array from get_raid() * @param bool $standalone_photo Clear the bottom right corner of the photo from text * @param bool $debug Add debug features to the photo * @return array [true/false if returned content is photo file, content, cached unique_id for editMessageMedia] */ function get_raid_picture($raid, $standalone_photo = false) { - global $config; - // Has raid ended? $binds = [ ':raid_id' => $raid['id'], ':gym_id' => $raid['gym_id'], @@ -54,7 +16,6 @@ function get_raid_picture($raid, $standalone_photo = false) { ':standalone' => $standalone_photo, ':ended' => $raid['raid_ended'], ]; - if($config->RAID_PICTURE_SEND_METHOD == 'url') return [false, raid_picture_url($raid, $standalone_photo)]; $query_cache = my_query(" SELECT id, unique_id FROM photo_cache @@ -70,9 +31,8 @@ function get_raid_picture($raid, $standalone_photo = false) { if($query_cache->rowCount() > 0) { $result = $query_cache->fetch(); return [false, $result['id'], $result['unique_id']]; - }else { - return [true, create_raid_picture($raid, $standalone_photo)]; } + return [true, create_raid_picture($raid, $standalone_photo)]; } /** From 68338294ddb4141616499869638b1e1cd6fc671c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 10 Nov 2022 13:01:39 +0200 Subject: [PATCH 101/367] Fixed new user logic --- core/bot/user.php | 2 +- logic/new_user.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/bot/user.php b/core/bot/user.php index 09f485fd..13e82a5c 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -151,7 +151,7 @@ public function privilegeCheck($update) { public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { if(in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { // If a config file matching users status was found, check if tutorial is forced - if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED')) { + if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) && $this->userPrivileges['grantedBy'] !== 'BOT_ADMINS' && $this->userPrivileges['grantedBy'] !== 'NOT_RESTRICTED')) { return false; } return true; diff --git a/logic/new_user.php b/logic/new_user.php index b42867ab..e1b33289 100644 --- a/logic/new_user.php +++ b/logic/new_user.php @@ -6,7 +6,7 @@ */ function new_user($user_id) { global $config; - if(!$config->TUTORIAL_MODE || user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; + if($config->TUTORIAL_MODE && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; else return false; } ?> \ No newline at end of file From 6b02dc9ed502b8de5ce80daab8d5f8ad82fab76b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 10 Nov 2022 18:00:03 +0200 Subject: [PATCH 102/367] Map telegram roles to correct access files --- core/bot/user.php | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/core/bot/user.php b/core/bot/user.php index 13e82a5c..ef41bcda 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -43,7 +43,14 @@ public function privilegeCheck($update) { } } - $telegramRoles = ['creator', 'admins', 'members', 'restricted', 'kicked']; + // Map telegram roles to access file names + $telegramRoles = [ + 'creator' => 'creator', + 'administrator' => 'admins', + 'member' => 'members', + 'restricted' => 'restricted', + 'kicked' => 'kicked', + ]; // If user specific permissions are found, use them instead of group based if (is_file(ACCESS_PATH . '/access' . $user_id)) { @@ -52,7 +59,7 @@ public function privilegeCheck($update) { $chatIds = []; $rolesToCheck = $telegramRoles; $rolesToCheck[] = 'access'; - foreach($rolesToCheck as $roleToCheck) { + foreach($rolesToCheck as $tgRole => $roleToCheck) { $chatFiles = str_replace(ACCESS_PATH . '/' . $roleToCheck, '', glob(ACCESS_PATH . '/' . $roleToCheck . '-*')); $chatIds = array_merge($chatIds, $chatFiles); } @@ -87,22 +94,24 @@ public function privilegeCheck($update) { // Get access file based on user status/role. debug_log('Role of user ' . $chatObj['result']['user']['id'] . ' : ' . $chatObj['result']['status']); - if(in_array($chatObj['result']['status'], $telegramRoles) && is_file(ACCESS_PATH . '/' . $chatObj['result']['status'] . $chatId)) { - $privilegeList = file(ACCESS_PATH . '/' . $chatObj['result']['status'] . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $accessFile = $chatObj['result']['status'] . $chatId; + $userStatus = $chatObj['result']['status']; + + if(array_key_exists($userStatus, $telegramRoles) && is_file(ACCESS_PATH . '/' . $telegramRoles[$userStatus] . $chatId)) { + $privilegeList = file(ACCESS_PATH . '/' . $telegramRoles[$userStatus] . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $accessFile = $userStatus . $chatId; // Any other user status/role except "left" - } else if($chatObj['result']['status'] != 'left' && is_file(ACCESS_PATH . '/access' . $chatId)) { + } else if($userStatus != 'left' && is_file(ACCESS_PATH . '/access' . $chatId)) { $privilegeList = file(ACCESS_PATH . '/access' . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $accessFile = 'access' . $chatId; // Ignore "Restricted"? - if($chatObj['result']['status'] == 'restricted' && in_array('ignore-restricted', $privilegeList)) { + if($userStatus == 'restricted' && in_array('ignore-restricted', $privilegeList)) { $privilegeList = NULL; } // Ignore "kicked"? - if($chatObj['result']['status'] == 'kicked' && in_array('ignore-kicked', $privilegeList)) { + if($userStatus == 'kicked' && in_array('ignore-kicked', $privilegeList)) { $privilegeList = NULL; } } else { From d7fc3b3b383c8a6705614c0729ddcce4fa124433 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:11:30 +0200 Subject: [PATCH 103/367] Added `/history` to help --- lang/help.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lang/help.json b/lang/help.json index 58a1ecac..c5466870 100644 --- a/lang/help.json +++ b/lang/help.json @@ -297,5 +297,18 @@ "PL": "TRANSLATE", "FI": "/help - Näytä ohjeet", "ES": "/help - Ver ayuda" + }, + "help_history": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "/history - View history of raids that had attendees", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "/history - Listaa päättyneet raidit joissa oli osallistujia", + "ES": "TRANSLATE" } } From ecdd76a2cfc968b7c94d2a1c99877b6b9ed7cd71 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 18:16:47 +0200 Subject: [PATCH 104/367] Fixed updating raid pokemon manually --- mods/raid_set_poke.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/raid_set_poke.php b/mods/raid_set_poke.php index d2c9a170..ea3b864f 100644 --- a/mods/raid_set_poke.php +++ b/mods/raid_set_poke.php @@ -49,7 +49,7 @@ // Update the shared raid polls. require_once(LOGIC_PATH .'/update_raid_poll.php'); -$tg_json = update_raid_poll($id, $raid, false, $tg_json, true); +$tg_json = update_raid_poll($raidId, $raid, false, $tg_json, true); // Alert users. $tg_json = alarm($raid, $update['callback_query']['from']['id'], 'new_boss', '', $tg_json); From 754cdd39a075ba30297772a2d1feec4aaa26c799 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 19:12:51 +0200 Subject: [PATCH 105/367] Cosmetic changes to `list` and fixed `listall` permission that didn't previously do anything --- commands/list.php | 153 ++++++++++++++++++++++--------------------- commands/listall.php | 2 +- 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/commands/list.php b/commands/list.php index ef9f6510..308d302b 100644 --- a/commands/list.php +++ b/commands/list.php @@ -10,25 +10,30 @@ // Check access. $botUser->accessCheck($update, 'list'); -// Init text and keys. -$text = ''; -$keys = []; - -$event_permissions = $botUser->accessCheck($update, 'event',true); +$event_sql = 'event IS NULL'; +if($botUser->accessCheck($update, 'ex-raids', true)) { + if($botUser->accessCheck($update, 'event-raids', true)) + $event_sql = ''; + else + $event_sql .= ' OR event = ' . EVENT_ID_EX; +}elseif($botUser->accessCheck($update, 'event-raids', true)) { + $event_sql = 'event != ' . EVENT_ID_EX .' OR event IS NULL'; +} // Get last 12 active raids data. $rs = my_query( ' - SELECT raids.pokemon, raids.pokemon_form, raids.id, raids.user_id, raids.spawn, raids.start_time, raids.end_time, raids.gym_team, raids.gym_id, raids.level, raids.move1, raids.move2, raids.gender, raids.event, raids.event_note, - gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, gyms.gym_note, - start_time, end_time, - TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left, - (SELECT COUNT(*) FROM raids WHERE end_time>UTC_TIMESTAMP()) AS r_active + SELECT raids.pokemon, raids.pokemon_form, raids.id, raids.spawn, raids.start_time, raids.end_time, raids.level, raids.event, + gyms.gym_name, gyms.ex_gym, + events.name as event_name, + (SELECT COUNT(*) FROM raids WHERE end_time>UTC_TIMESTAMP() ' . ($event_sql == '' ? '' : 'AND ('.$event_sql.')') . ') as r_active FROM raids LEFT JOIN gyms ON raids.gym_id = gyms.id + LEFT JOIN events + ON events.id = raids.event WHERE end_time>UTC_TIMESTAMP() - ' . ($event_permissions ? '' : 'AND event IS NULL' ) . ' + ' . ($event_sql == '' ? '' : 'AND ('.$event_sql.')') . ' ORDER BY end_time ASC LIMIT 12 ' @@ -40,72 +45,70 @@ debug_log($raids); // Did we get any raids? -if(isset($raids[0]['r_active'])) { - debug_log($raids[0]['r_active'], 'Active raids:'); - - // More raids as we like? - if($raids[0]['r_active'] > 12) { - // Forward to /listall - debug_log('Too much raids, forwarding to /listall'); - $skip_access = true; - include_once(ROOT_PATH . '/commands/listall.php'); - exit(); - - // Just enough raids to display at once - } else { - //while ($raid = $rs->fetch()) { - foreach($raids as $raid) { - // Set text and keys. - $gym_name = $raid['gym_name']; - if(empty($gym_name)) { - $gym_name = ''; - } - $resolved_boss = resolve_raid_boss($raid['pokemon'], $raid['pokemon_form'], $raid['spawn'], $raid['level']); - - $text .= $gym_name . CR; - $raid_day = dt2date($raid['start_time']); - $now = utcnow(); - $today = dt2date($now); - $start = dt2time($raid['start_time']); - $end = dt2time($raid['end_time']); - $text .= get_local_pokemon_name($resolved_boss['pokedex_id'], $resolved_boss['pokemon_form_id']) . SP . '-' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; - - // Pokemon is an egg? - $eggs = $GLOBALS['eggs']; - if(in_array($resolved_boss['pokedex_id'], $eggs)) { - $keys_text = EMOJI_EGG . SP . $gym_name; - } else { - $keys_text = $gym_name; - } - - $keys[] = array( - 'text' => $keys_text, - 'callback_data' => $raid['id'] . ':raids_list:0' - ); - } - - // Get the inline key array. - $keys = inline_key_array($keys, 1); - - // Add exit key. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - - // Build message. - $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; - $msg .= $text; - $msg .= '' . getTranslation('select_gym_name') . '' . CR; - } - -// No active raids -} else { - $msg = '' . getTranslation('no_active_raids_found') . ''; +if($raids[0]['r_active'] == 0) { + $msg = '' . getTranslation('no_active_raids_found') . ''; + send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + exit(); +} + +debug_log($raids[0]['r_active'], 'Active raids:'); +// More raids as we like? +if($raids[0]['r_active'] > 12 && $botUser->accessCheck($update, 'listall', true)) { + // Forward to /listall + debug_log('Too much raids, forwarding to /listall'); + $skip_access = true; + include_once(ROOT_PATH . '/commands/listall.php'); + exit(); } +// Just enough raids to display at once +$text = ''; +foreach($raids as $raid) { + // Set text and keys. + $gym_name = $raid['gym_name']; + if(empty($gym_name)) { + $gym_name = ''; + } + $resolved_boss = resolve_raid_boss($raid['pokemon'], $raid['pokemon_form'], $raid['spawn'], $raid['level']); + + $text .= ($raid['ex_gym'] === 1 ? EMOJI_STAR . SP : '') . $gym_name . CR; + $raid_day = dt2date($raid['start_time']); + $now = utcnow(); + $today = dt2date($now); + $start = dt2time($raid['start_time']); + $end = dt2time($raid['end_time']); + $text .= (!empty($raid['event_name']) ? $raid['event_name'] . CR : '' ); + $text .= get_local_pokemon_name($resolved_boss['pokedex_id'], $resolved_boss['pokemon_form_id']) . SP . '-' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; + + // Pokemon is an egg? + $keys_text = ''; + if(in_array($resolved_boss['pokedex_id'], $GLOBALS['eggs'])) { + $keys_text = EMOJI_EGG . SP; + } + $keys_text .= ($raid['ex_gym'] === 1 ? EMOJI_STAR . SP : '') . $gym_name; + + $keys[] = array( + 'text' => $keys_text, + 'callback_data' => $raid['id'] . ':raids_list:0' + ); +} + +// Get the inline key array. +$keys = inline_key_array($keys, 1); + +// Add exit key. +$keys[] = [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] +]; + +// Build message. +$msg = '' . getTranslation('list_all_active_raids') . ':' . CR; +$msg .= $text; +$msg .= '' . getTranslation('select_gym_name') . '' . CR; + // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); ?> diff --git a/commands/listall.php b/commands/listall.php index 37553e88..35f8f95b 100644 --- a/commands/listall.php +++ b/commands/listall.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -if(!isset($skip_access) or $skip_access != true) $botUser->accessCheck($update, 'list'); +if(!isset($skip_access) or $skip_access != true) $botUser->accessCheck($update, 'listall'); // Set keys. $keys_and_gymarea = raid_edit_gyms_first_letter_keys('list_by_gym', false, false, 'listall', 'list_raid'); From 232b5d31f90d795ea71bf1923248c0b6405c1322 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 19:39:55 +0200 Subject: [PATCH 106/367] Fixed access rights and menus for ex raid creation --- logic/keys_event.php | 30 ++++++++++++++++++------------ logic/raid_edit_raidlevel_keys.php | 5 +++-- mods/edit_event.php | 12 ++++++++---- mods/edit_event_raidlevel.php | 9 ++++----- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/logic/keys_event.php b/logic/keys_event.php index 388cb409..944a29fa 100644 --- a/logic/keys_event.php +++ b/logic/keys_event.php @@ -3,9 +3,12 @@ * Event keys. * @param $gym_id_plus_letter * @param $action + * @param $admin_access array of access rights [ex-raids, event-raids] * @return array */ -function keys_event($gym_id_plus_letter, $action) { +function keys_event($gym_id_plus_letter, $action, $admin_access = [false,false]) { + $keys = []; + if($admin_access[1] === true) { $q = my_query(" SELECT id, name @@ -13,22 +16,25 @@ function keys_event($gym_id_plus_letter, $action) { WHERE id != 999 "); while($event = $q->fetch()) { - if(!empty($event['name'])) { - $keys[] = array( - 'text' => $event['name'], - 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . $event['id'] - ); - }else { - info_log('Invalid event name on event '. $event['id']); - } + if(!empty($event['name'])) { + $keys[] = array( + 'text' => $event['name'], + 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . $event['id'] + ); + }else { + info_log('Invalid event name on event '. $event['id']); + } } + } + if($admin_access[0] === true) { $keys[] = array( 'text' => getTranslation("Xstars"), 'callback_data' => $gym_id_plus_letter . ':' . $action . ':X' ); - // Get the inline key array. - $keys = inline_key_array($keys, 1); + } + // Get the inline key array. + $keys = inline_key_array($keys, 1); - return $keys; + return $keys; } ?> \ No newline at end of file diff --git a/logic/raid_edit_raidlevel_keys.php b/logic/raid_edit_raidlevel_keys.php index f06d0cab..d1e93f25 100644 --- a/logic/raid_edit_raidlevel_keys.php +++ b/logic/raid_edit_raidlevel_keys.php @@ -19,7 +19,8 @@ function raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access = [f $query_event = 'AND raid_bosses.raid_level != \'X\''; }else { $event_id = $event; - $query_event = ''; + if($admin_access[0] === true) $query_event = ''; + else $query_event = 'AND raid_bosses.raid_level != \'X\''; } $query_counts = ' SELECT raid_level, COUNT(*) AS raid_level_count @@ -74,7 +75,7 @@ function raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access = [f } } // Add key for raid event if user allowed to create event raids - if($admin_access[1] === true && $event === false) { + if(($admin_access[1] === true or $admin_access[0] === true) && $event === false) { $keys[] = array( 'text' => getTranslation('event'), 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_event:0' diff --git a/mods/edit_event.php b/mods/edit_event.php index 2dd92863..b6aa75b5 100644 --- a/mods/edit_event.php +++ b/mods/edit_event.php @@ -6,14 +6,18 @@ //debug_log($update); //debug_log($data); -// Check access. -$botUser->accessCheck($update, 'event-raids'); - // Set the id. $gym_id_plus_letter = $data['id']; +//Initialize admin rights table [ ex-raid , raid-event ] +$admin_access = [false, false]; +// Check access - user must be admin for raid_level X +$admin_access[0] = $botUser->accessCheck($update, 'ex-raids', true); +// Check access - user must be admin for raid event creation +$admin_access[1] = $botUser->accessCheck($update, 'event-raids', true); + // Get the keys. -$keys = keys_event($gym_id_plus_letter, "edit_event_raidlevel"); +$keys = keys_event($gym_id_plus_letter, "edit_event_raidlevel", $admin_access); // No keys found. if (!$keys) { diff --git a/mods/edit_event_raidlevel.php b/mods/edit_event_raidlevel.php index c0af0801..69156d4a 100644 --- a/mods/edit_event_raidlevel.php +++ b/mods/edit_event_raidlevel.php @@ -6,9 +6,6 @@ //debug_log($update); //debug_log($data); -// Check access. -$botUser->accessCheck($update, 'event-raids'); - // Get gym data via ID $id_data = explode(",", $data['id']); $gym_id = $id_data[0]; @@ -26,10 +23,12 @@ // Telegram JSON array. $tg_json = array(); -//Initiate admin rights table [ ex-raid , raid-event ] -$admin_access = [false,1]; +//Initialize admin rights table [ ex-raid , raid-event ] +$admin_access = [false, false]; // Check access - user must be admin for raid_level X $admin_access[0] = $botUser->accessCheck($update, 'ex-raids', true); +// Check access - user must be admin for raid event creation +$admin_access[1] = $botUser->accessCheck($update, 'event-raids', true); // Get the keys. $keys = raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access, $event_id); From 29a5b801c99fccab4d314ada47606e16930d6730 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 20:02:12 +0200 Subject: [PATCH 107/367] Event settings should override everything --- mods/edit_time.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mods/edit_time.php b/mods/edit_time.php index 397b2907..3d0d8477 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -63,22 +63,22 @@ debug_log('Formatting the raid time properly now.'); $arg_time = str_replace('-', ':', $starttime); - // Ex and elite raids - if($event_id == 'X' or $raid_level == 9) { - debug_log('Ex-Raid time :D ... Setting raid date to ' . $arg_time); - $start_date_time = $arg_time; - $duration = ($raid_level == 9) ? $config->RAID_DURATION_ELITE : $config->RAID_DURATION; - $egg_duration = ($raid_level == 9) ? $config->RAID_EGG_DURATION_ELITE : $config->RAID_EGG_DURATION; - // Event raids - }elseif($event_id != 'N') { + if($event_id != 'N') { debug_log('Event time :D ... Setting raid date to ' . $arg_time); $start_date_time = $arg_time; $query = my_query("SELECT raid_duration FROM events WHERE id = '{$event_id}' LIMIT 1"); $result = $query->fetch(); - $duration = $result['raid_duration']; + $duration = $result['raid_duration'] ?? $config->RAID_DURATION; $egg_duration = $config->RAID_EGG_DURATION; + // Elite raids + }elseif($raid_level == 9) { + debug_log('Elite Raid time :D ... Setting raid date to ' . $arg_time); + $start_date_time = $arg_time; + $duration = $config->RAID_DURATION_ELITE; + $egg_duration = $config->RAID_EGG_DURATION_ELITE; + // Normal raids } else { // Current date From 4cc19d7cdf75b2fb8f9e1f703f3a611f798c4f82 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 23:08:44 +0200 Subject: [PATCH 108/367] Tutorial fix --- core/bot/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/bot/user.php b/core/bot/user.php index ef41bcda..162a0eee 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -160,7 +160,7 @@ public function privilegeCheck($update) { public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { if(in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { // If a config file matching users status was found, check if tutorial is forced - if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) && $this->userPrivileges['grantedBy'] !== 'BOT_ADMINS' && $this->userPrivileges['grantedBy'] !== 'NOT_RESTRICTED')) { + if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) || $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' || $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED')) { return false; } return true; From f78b8044cfe45d3f9d6d7eb0ad30b01c7008a399 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 12 Nov 2022 00:19:10 +0200 Subject: [PATCH 109/367] Fixed force-tutorial logic --- core/bot/commands.php | 2 +- core/bot/modules.php | 2 +- core/bot/user.php | 39 +++++++++++++++++---------------------- logic/new_user.php | 4 ++-- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/core/bot/commands.php b/core/bot/commands.php index ecc6d8c0..ff25936d 100644 --- a/core/bot/commands.php +++ b/core/bot/commands.php @@ -14,7 +14,7 @@ $altcom = 'start'; } - if($config->TUTORIAL_MODE && isset($update['message']['chat']['id']) && new_user($update['message']['chat']['id']) && $com != 'start' && $com != 'tutorial') { + if(isset($update['message']['chat']['id']) && new_user($update['message']['chat']['id']) && $com != 'start' && $com != 'tutorial') { send_message($update['message']['chat']['id'], getTranslation("tutorial_command_failed")); $dbh = null; exit(); diff --git a/core/bot/modules.php b/core/bot/modules.php index 7aac7a9b..4322211f 100644 --- a/core/bot/modules.php +++ b/core/bot/modules.php @@ -1,7 +1,7 @@ TUTORIAL_MODE && isset($update['callback_query']['from']['id']) && new_user($update['callback_query']['from']['id']) && $data['action'] != "tutorial") { +if(isset($update['callback_query']['from']['id']) && new_user($update['callback_query']['from']['id']) && $data['action'] != "tutorial") { answerCallbackQuery($update['callback_query']['id'], getTranslation("tutorial_vote_failed")); $dbh = null; exit(); diff --git a/core/bot/user.php b/core/bot/user.php index 162a0eee..89556590 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -158,34 +158,29 @@ public function privilegeCheck($update) { * @return bool|string */ public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { - if(in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { - // If a config file matching users status was found, check if tutorial is forced - if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) || $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' || $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED')) { - return false; - } + if(!$new_user && in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { return true; - }else { - debug_log('Denying access to the bot for user'); + } + debug_log('Denying access to the bot for user'); - if($return_result) - return false; + if($return_result) + return false; - $response_msg = '' . getTranslation('bot_access_denied') . ''; - // Edit message or send new message based on type of received call - if (isset($update['callback_query'])) { - $keys = []; + $response_msg = '' . getTranslation('bot_access_denied') . ''; + // Edit message or send new message based on type of received call + if (isset($update['callback_query'])) { + $keys = []; - // Telegram JSON array. - $tg_json = array(); - $tg_json[] = edit_message($update, $response_msg, $keys, false, true); - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('bot_access_denied'), true); + // Telegram JSON array. + $tg_json = array(); + $tg_json[] = edit_message($update, $response_msg, $keys, false, true); + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('bot_access_denied'), true); - curl_json_multi_request($tg_json); - } else { - send_message($update['message']['from']['id'], $response_msg); - } - exit; + curl_json_multi_request($tg_json); + } else { + send_message($update['message']['from']['id'], $response_msg); } + exit; } /** diff --git a/logic/new_user.php b/logic/new_user.php index e1b33289..2cbe7a92 100644 --- a/logic/new_user.php +++ b/logic/new_user.php @@ -5,8 +5,8 @@ * @return bool */ function new_user($user_id) { - global $config; - if($config->TUTORIAL_MODE && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; + global $config, $botUser; + if($config->TUTORIAL_MODE && in_array("force-tutorial", $botUser->userPrivileges['privileges']) && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; else return false; } ?> \ No newline at end of file From 8e85c257387f767dbbfcc6897cd7c3ad4abd665d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 12 Nov 2022 00:37:08 +0200 Subject: [PATCH 110/367] Fixed error message when there are no active raids in database --- commands/list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/list.php b/commands/list.php index 308d302b..31023618 100644 --- a/commands/list.php +++ b/commands/list.php @@ -45,7 +45,7 @@ debug_log($raids); // Did we get any raids? -if($raids[0]['r_active'] == 0) { +if(count($raids) == 0) { $msg = '' . getTranslation('no_active_raids_found') . ''; send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); exit(); From 80495d68cec7cc8f4de0a387e459c0e7707eeb2d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 12 Nov 2022 11:32:22 +0200 Subject: [PATCH 111/367] Removed `/team` command, brounght back missing translations and improved documentation --- commands/team.php | 47 ------------------------------------- docs/config.rst | 3 ++- docs/index.rst | 1 + docs/usage.rst | 50 +++++++-------------------------------- lang/language.json | 52 ++++++++++++++++++++++++++++++----------- logic.php | 1 - logic/new_user.php | 23 +++++++++++++++--- logic/user_tutorial.php | 25 -------------------- 8 files changed, 71 insertions(+), 131 deletions(-) delete mode 100644 commands/team.php delete mode 100644 logic/user_tutorial.php diff --git a/commands/team.php b/commands/team.php deleted file mode 100644 index 30489775..00000000 --- a/commands/team.php +++ /dev/null @@ -1,47 +0,0 @@ - 'mystic', - 'instinct' => 'instinct', - 'valor' => 'valor', - getTranslation('red') => 'valor', - getTranslation('blue') => 'mystic', - getTranslation('yellow') => 'instinct', - 'r' => 'valor', - 'b' => 'mystic', - 'y' => 'instinct', - 'g' => 'instinct' -); - -// Valid team name. -if (!empty($gym_team) && $teams[$gym_team]) { - // Update team in raids table. - my_query( - " - UPDATE raids - SET gym_team = '{$teams[$gym_team]}' - WHERE user_id = {$update['message']['from']['id']} - ORDER BY id DESC LIMIT 1 - " - ); - - // Send the message. - send_message($update['message']['chat']['id'], getTranslation('gym_team_set_to') . ' ' . ucfirst($teams[$gym_team])); - -// Invalid team name. -} else { - // Send the message. - send_message($update['message']['chat']['id'], getTranslation('invalid_team')); -} - -?> diff --git a/docs/config.rst b/docs/config.rst index 089f4e35..23ecfae1 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -137,6 +137,7 @@ You can set several languages for the bot. Available languages are (A-Z): * DE (German) * EN (English) +* ES (Spanish) * FI (Finnish) * FR (French) * IT (Italian) @@ -501,7 +502,7 @@ Cleanup The bot features an automatic cleanup of Telegram raid poll messages as well as cleanup of the database (attendance and raids tables). -To activate cleanup you need to `make sure your groups are Supergroups or Channels <#which-group-type-should-i-use--how-do-i-make-a-group-a-supergroup>`_\ , make your bot an admin in this chat, enable cleanup in the config and create a cronjob to trigger the cleanup process. +To activate cleanup you need to `make sure your groups are Supergroups or Channels <#referring-to-groups-channels-and-users>`_\ , make your bot an admin in this chat, enable cleanup in the config and create a cronjob to trigger the cleanup process. #. Set the ``CLEANUP`` in the config to ``true`` and define a cleanup secret/passphrase under ``CLEANUP_SECRET``. diff --git a/docs/index.rst b/docs/index.rst index ff768754..ebad472f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -52,6 +52,7 @@ You can submit translations to expand our list of lanuages! For more information * DE (German) * EN (English) +* ES (Spanish) * FI (Finnish) * FR (French) * IT (Italian) diff --git a/docs/usage.rst b/docs/usage.rst index f9d1138c..d8ad110e 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -4,11 +4,11 @@ PokemonRaidBot usage Send your location to the bot ----------------------------- -If ``RAID_LOCATION`` is set to ``true`` (default), the bot will guide you through the creation of a raid poll based on the settings in the config file. +If ``RAID_LOCATION`` is set to ``true`` (default), the bot will guide you through the creation of a raid poll based on the settings in the config file. ``RAID_VIA_LOCATION_FUNCTION`` determines the actions taken after location is received. -In case of a raid poll the bot will ask you for the raid level, the pokemon raid boss, the time until the raids starts and the time left for the raid. Afterwards you can set the gym name and gym team by using the /gym and /team commands. +By default the bot will ask you for the raid level, the pokemon raid boss, the time until the raids starts and the time left for the raid. Afterwards you can set the gym name by using the /gym or /gymname commands. -If ``LIST_BY_LOCATION`` is set to ``true``\ , the bot will instead list all nearby saved raids. +For further details please refer to :doc:`config#raid-creation-options` Using inline search of @PortalMapBot or @Ingressportalbot --------------------------------------------------------- @@ -264,17 +264,17 @@ Delete an existing raid poll with the ``/delete`` command: :alt: Command: /delete -Command: /team -^^^^^^^^^^^^^^ +Command: /trainer +^^^^^^^^^^^^^^^^^ -The bot will set the team to Mystic/Valor/Instinct for the last created raid based on your input. +Users can use this command to set their trainer name, friend code, team, level and if configured, personal bot settings (private language and automatic raid alarms). -Example input: ``/team Mystic`` +For users with proper access rights the bot will also give you a list of chats to share the trainer message which allows users to set team and level+/- data. You can also delete the shared trainer messages via the ``/trainer`` command. -Command: /trainer +Command: /history ^^^^^^^^^^^^^^^^^ -The bot will give you a list of chats to share the trainer message which allows users to set team and level+/- data. You can also delete the shared trainer messages via the ``/trainer`` command. +Tool for admins to view history of raids that had at least one person signed up for it. Command: /gym ^^^^^^^^^^^^^ @@ -283,13 +283,6 @@ The bot will show the details of each gym. Additionally you can change the exten Example input: ``/gym`` -Command: /addgym -^^^^^^^^^^^^^^^^ - -The bot will add a gym under the coordinates you're submitting. First latitude, then longitude. The gym is added under the name '#YourTelegramID' (e.g. '#111555777') and you need to change the name afterwards using the ``/gymname`` command. You cannot submit a second gym unless you changed the name of the first gym. In case you submit a second gym without changing the name of the previously submitted gym, the first gym coordinates will be overwritten! - -Example input: ``/addgym 52.5145434,13.3501189`` - Command: /gymname ^^^^^^^^^^^^^^^^^ @@ -298,28 +291,3 @@ The bot will set the name of gym to your input. If you submitted a gym via locat Example input: ``/gymname Siegessäule`` Example input with gym id: ``/gymname 34, Siegessäule`` - -Command: /gymaddress -^^^^^^^^^^^^^^^^^^^^ - -The bot will set the address of gym to your input. The id of the gym is required. You can delete the gym address using the keyword 'reset'. - -Example input: ``/gymaddress 34, Großer Stern, 10557 Berlin`` - -Example input to delete the gym address: ``/gymaddress 34, reset`` - -Command: /gymgps -^^^^^^^^^^^^^^^^ - -The bot will set the gps coordinates of gym to your input. The id of the gym is required. - -Example input: ``/gymgps 34, 52.5145434,13.3501189`` - -Command: /gymnote -^^^^^^^^^^^^^^^^^ - -The bot will set the note for gym to your input. The id of the gym is required. You can delete the gym note using the keyword 'reset'. - -Example input: ``/gymnote 34, Meeting point: Behind the building`` - -Example input to delete the gym note: ``/gymnote 34, reset`` diff --git a/lang/language.json b/lang/language.json index 1963c481..af0c2879 100644 --- a/lang/language.json +++ b/lang/language.json @@ -3080,19 +3080,6 @@ "FI": "Valinnainen - aseta sali ja joukkue", "ES": "Opcional - Poner gimnasio y equipo" }, - "set_gym_team_command": { - "NL": "/team Mystic/Valor/Instinct/Blauw/Rood/Geel", - "DE": "/team Mystic/Valor/Instinct/Blau/Rot/Gelb", - "EN": "/team Mystic/Valor/Instinct/Blue/Red/Yellow", - "IT": "/team Saggezza/Valore/Istinto/Blu/Rosso/Giallo", - "PT-BR": "/team Mystic/Valor/Instinct/Azul/Vermelho/Amarelo", - "RU": "/team Mystic/Valor/Instinct/Синий/Красный/Желтый", - "NO": "/team Mystic/Valor/Instinct/Blue/Red/Yellow", - "FR": "/team Sagesse/Bravoure/Intuition/Bleu/Rouge/Jaune", - "PL": "/team Niebieski/Czerowny/Żółty", - "FI": "/team Mystic/Valor/Instinct/Blue/Red/Yellow", - "ES": "/team Sabiduría/Valor/Instinto/Azul/Rojo/Amarillo" - }, "mystic": { "NL": "Mystic/Blauw", "DE": "Weisheit/Blau", @@ -3886,6 +3873,45 @@ "FI": "Saataksesi salin id numeron tai muita tietoja, käytä /gym -komentoa.", "ES": "Para obtener la identificación y más detalles del gimnasio, usa el comando /gym." }, + "gym_name_example": { + "NL": "Als voorbeeld: /gymname 34, Markt 61, 3131 CR Vlaardingen ", + "DE": "Zum Beispiel: /gymname 34, Wasserfall im Park", + "EN": "For example: /gymname 34, Waterfall in the park!", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Esimerkiksi: /gymname 34, Vapauden Muistomerkki!", + "ES": "Por ejemplo: /gymname 34, Waterfall in the park" + }, + "gym_id_name_missing": { + "NL": "Error! Gym id of naam mist!", + "DE": "Fehler! Arena-ID oder Name fehlt!", + "EN": "Error! Gym id or name is missing!", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Virhe! Salin id numero tai nimi puuttuu!", + "ES": "¡Error! ¡Faltan gym id o nombre!" + }, + "gym_name_updated": { + "NL": "Gym naam aangepast.", + "DE": "Der Arena-Name wurde aktualisiert.", + "EN": "Gym name updated.", + "IT": "Nome della Palestra aggiornato.", + "PT-BR": "Nome do ginásio atualizado.", + "RU": "Название гима обновлено.", + "NO": "Gym navn oppdatert.", + "FR": "Nom de l'arène mis à jour", + "PL": "Nazwa Areny zaktualizowana", + "FI": "Salin nimi päivitetty.", + "ES": "Nombre del gimnasio actualizado." + }, "gym_name_edit": { "NL": "Gym naam aanpassen", "DE": "TRANSLATE", diff --git a/logic.php b/logic.php index c6fde260..75f7dbe4 100644 --- a/logic.php +++ b/logic.php @@ -58,7 +58,6 @@ include('logic/show_raid_poll.php'); include('logic/show_raid_poll_small.php'); include('logic/show_trainerinfo.php'); -include('logic/user_tutorial.php'); include('logic/weather_keys.php'); include('logic/curl_get_contents.php'); ?> diff --git a/logic/new_user.php b/logic/new_user.php index 2cbe7a92..8b2e239a 100644 --- a/logic/new_user.php +++ b/logic/new_user.php @@ -5,8 +5,25 @@ * @return bool */ function new_user($user_id) { - global $config, $botUser; - if($config->TUTORIAL_MODE && in_array("force-tutorial", $botUser->userPrivileges['privileges']) && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; - else return false; + global $config, $botUser; + if($config->TUTORIAL_MODE && in_array("force-tutorial", $botUser->userPrivileges['privileges']) && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) + return true; + return false; } + +/** + * Return the tutorial value from users table + * @param $user_id + * @return int + */ +function user_tutorial($user_id) { + debug_log("Reading user's tutorial value: ".$user_id); + $query = my_query("SELECT tutorial FROM users WHERE user_id = :user_id LIMIT 1", [":user_id"=>$user_id]); + $res = $query->fetch(); + $result = 0; + if($query->rowCount() > 0) $result = $res['tutorial']; + debug_log("Result: ".$result); + return $result; +} + ?> \ No newline at end of file diff --git a/logic/user_tutorial.php b/logic/user_tutorial.php deleted file mode 100644 index 8548bcd1..00000000 --- a/logic/user_tutorial.php +++ /dev/null @@ -1,25 +0,0 @@ -prepare( $query ); - $statement->execute([":user_id"=>$user_id]); - $res = $statement->fetch(); - if($statement->rowCount() > 0) $result = $res['tutorial']; - else $result = 0; - debug_log("Result: ".$result); - return $result; - } catch (PDOException $exception) { - error_log($exception->getMessage()); - $dbh = null; - exit; - } -} -?> \ No newline at end of file From 2d7ee31a3553d47e0a768783a7e6e075b4bc6f31 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 12 Nov 2022 16:56:25 +0200 Subject: [PATCH 112/367] Improved documentation --- docs/config.rst | 33 ++++++++++++--------------------- docs/development.rst | 2 +- docs/maintenance.rst | 2 +- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index 23ecfae1..a4b37643 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -213,18 +213,6 @@ Set ``RAID_EGG_DURATION`` to the maximum amount of minutes a user can select for Set ``RAID_DURATION`` to the maximum amount of minutes a user can select as raid duration for already running/active raids. -Set ``RAID_HOUR`` to true to enable the raid hour. Enabling the raid hour superseds the normal raid duration. Note that the raid hour takes precedence over the raid day. Make sure to disable the raid hour to get the raid day. - -Set ``RAID_HOUR_DURATION`` to the maximum amount of minutes a user can select as raid duration if the ``RAID_HOUR`` is enabled. Per default max. 60 minutes. - -Set ``RAID_HOUR_CREATION_LIMIT`` to the maximum amount of raids a user can create if the ``RAID_HOUR`` is enabled. Per default 1 raid. - -Set ``RAID_DAY`` to true to enable the raid day. Enabling the raid day superseds the normal raid duration. Note that the raid hour takes precedence over the raid day. Make sure to disable the raid hour to get the raid day. - -Set ``RAID_DAY_DURATION`` to the maximum amount of minutes a user can select as raid duration if the ``RAID_DAY`` is enabled. Per default max. 180 minutes. - -Set ``RAID_DAY_CREATION_LIMIT`` to the maximum amount of raids a user can create if the ``RAID_DAY`` is enabled. Per default 1 raid. - Set ``RAID_DURATION_CLOCK_STYLE`` to customize the default style for the raid start time selection. Set to true, the bot will show the time in clocktime style, e.g. "18:34" as selection when the raid will start. Set to false the bot will show the time until the raid starts in minutes, e.g. "0:16" (similar to the countdown in the gyms). Users can switch between both style in the raid creation process. Set ``RAID_CUSTOM_GYM_LETTERS`` to further split gyms by their first letter. For example if you have a lot of gyms starting with 'St' as there are a lot of churches like St. Helen, St. Jospeh, etc. in your area and the gym list under the letter 'S' is too long, you can tell the bot to put the gyms starting with 'St' under 'St' and exclude them from the letter 'S'. There is no limitation in length, so even 'Berlin' would work to split gyms, but the recommendation is to use as less chars as possible to split the gyms. You can add multiple custom gym letters, just separate them by comma. Example: ``"RAID_CUSTOM_GYM_LETTERS":"Ber,Sch,St,Wi"`` @@ -398,7 +386,7 @@ Predefine sharing all raids to the chats -100111222333 and -100444555666, except Raids from Webhook ~~~~~~~~~~~~~~~~~~ -You can receive Raids from a mapping system such as MAD via Webhook. +You can receive Raids from a mapping systems such as MAD and RDM via Webhook. For that you need to setup ``WEBHOOK_CREATOR``\ , and to automatically share raids to chats, ``"WEBHOOK_CHATS_ALL_LEVELS":"-100444555666"`` or by Raidlevel ``"WEBHOOK_CHATS_LEVEL_5":"-100444555666"`` @@ -443,7 +431,7 @@ Event raids Users with the proper access rights can choose to create event raids. These can be handy for example on raid hours and raid days. These special raid polls have event specific name, description and poll settings that need to be set in database. Example of a few settings is in ``sql/event-table-example.sql``. -``vote_key_mode`` currently supports 2 modes, 0 and 1. 0 is the standard mode where users vote for a time when they are attending. 1 is a mode with no timeslots, just a button for 'attending'. +``vote_key_mode`` currently supports two modes, 0 and 1. 0 is the standard mode where users vote for a time when they are attending. 1 is a mode with no timeslots, just a button for 'attending'. With ``time_slots`` you can set event secific time slots for vote keys when ``vote_key_mode`` 0 is selected. @@ -527,7 +515,7 @@ Access permissions Public access ^^^^^^^^^^^^^ -When no Telegram id, group, supergroup or channel is specified in ``BOT_ADMINS`` the bot will allow everyone to use it (public access). +When no Telegram id is specified in ``BOT_ADMINS`` the bot will allow everyone to use it (public access). Example for public access: ``"BOT_ADMINS":""`` @@ -536,11 +524,11 @@ Access and permissions The ``MAINTAINER_ID`` is not able to access the bot nor has any permissions as that id is only contacted in case of errors and issues with the bot configuration. -The ``BOT_ADMINS`` have all permissions and can use any feature of the bot. +The ``BOT_ADMINS`` have all permissions and can use any feature of the bot. No restrictions specified in access files apply to these users. Telegram Users can only vote on raid polls, but have no access to other bot functions (unless you configured it). -In order to allow Telegram chats to access the bot and use commands/features, you need to create an access file. +In order to allow members of Telegram chats to access the bot and use commands/features, you need to create an access file. It does not matter if a chat is a user, group, supergroup or channel - any kind of chat is supported as every chat has a chat id! @@ -645,7 +633,7 @@ A few examples for access files can be found below the permission overview table - Vote on shared raid poll - Not required! * - - - Create raids ``/start``\ , ``/raid`` + - Create raids ``/start`` - ``create`` * - - Create ex-raids ``/start`` @@ -658,7 +646,7 @@ A few examples for access files can be found below the permission overview table - ``raid-duration`` * - - List all raids ``/list`` and ``/listall`` - - ``list`` + - ``list`` and ``listall`` * - - Manage overview ``/overview`` - ``overview`` @@ -710,6 +698,9 @@ A few examples for access files can be found below the permission overview table * - - Add a gym ``/gym`` - ``gym-add`` + * - + - Edit gym name after creating a gym with ``RAID_VIA_LOCATION`` + - ``gym-name`` * - - - @@ -804,7 +795,7 @@ To enable this feature: * Create ``tutorial.php`` in config folder. Use ``tutorial.php.example`` as reference * Set ``TUTORIAL_MODE`` to ``true`` in ``config.json`` * ``tutorial`` in access config file(s) -* ``force-tutorial`` in access config file(s) to force users to go through the tutorial before they're able to use the bot. +* ``force-tutorial`` in access config file(s) to force users to go through the tutorial before they're able to use the bot. Does not apply to users specified in ``BOT_ADMINS``. Customization ------------- @@ -836,7 +827,7 @@ To change translations you can do the following: * Create a file named ``language.json`` in the custom folder -* Find the translation name/id by searching the core and bot language.php files (\ ``core/lang/language.php`` and ``lang/language.php``\ ) +* Find the translation name/id by searching the bot language.json files (\ ``lang/*.json``\ ) * Set your own translation in your custom language.json * For example to change the translation of 'Friday' to a shorter 'Fri' put the following in your ``custom/language.json``\ : diff --git a/docs/development.rst b/docs/development.rst index dd3da3a9..865506a0 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -32,7 +32,7 @@ the schema version is final and immutable and any schema changes need to happen Translations ------------ -Translations are stored in ``lang/language.json`` and ``core/lang/language.json``. Any string marked as ``TRANSLATE`` hasn't been translated yet. These can be changed by hand but if you want to add a new language or do large scale translation, using translate.py is recommended. +Translations are stored in ``lang/language.json``. Any string marked as ``TRANSLATE`` hasn't been translated yet. These can be changed by hand but if you want to add a new language or do large scale translation, using translate.py is recommended. translate.py ^^^^^^^^^^^^ diff --git a/docs/maintenance.rst b/docs/maintenance.rst index 92195ff1..130c372a 100644 --- a/docs/maintenance.rst +++ b/docs/maintenance.rst @@ -28,7 +28,7 @@ To automatically keep the raid boss data somewhat up to date, you can schedule t ``curl -k -d '{"callback_query":{"data":"LEVELS:update_bosses:SOURCE"}}' https://localhost/botdir/index.php?apikey=111111111:AABBccddEEFFggHHiijjKKLLmmnn`` -Currently supported arguments for LEVELS are raid levels ``1, 3, 5, 6`` in comma separated string, and ``scheduled`` to execute import of scheduled info for tier 5 and 6 raids. +Currently supported arguments for LEVELS are raid levels ``1, 3, 5, 6`` in comma separated string, and ``scheduled`` to execute import of scheduled info for tier 5 and higher raids. Currently supported arguments for SOURCE are ``pogoinfo``, which is only used when importing specific levels. From 0ecfe2429e0b5fff8042fa97f01b1929c8404704 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Nov 2022 21:49:28 +0200 Subject: [PATCH 113/367] Fixed lang path --- logic/get_pokemon_id_by_name.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/get_pokemon_id_by_name.php b/logic/get_pokemon_id_by_name.php index e8d4e807..de36b538 100644 --- a/logic/get_pokemon_id_by_name.php +++ b/logic/get_pokemon_id_by_name.php @@ -58,7 +58,7 @@ function get_pokemon_id_by_name($pokemon_name, $get_from_db = false) } }else { // Get translation file - $str = file_get_contents(CORE_LANG_PATH . '/pokemon.json'); + $str = file_get_contents(BOT_LANG_PATH . '/pokemon.json'); $json = json_decode($str, true); $search_result = ""; foreach($json as $title => $translations) { @@ -88,7 +88,7 @@ function get_pokemon_id_by_name($pokemon_name, $get_from_db = false) debug_log('Searching for pokemon form: ' . $poke_form); // Get forms translation file - $str_form = file_get_contents(CORE_LANG_PATH . '/pokemon_forms.json'); + $str_form = file_get_contents(BOT_LANG_PATH . '/pokemon_forms.json'); $json_form = json_decode($str_form, true); // Search pokemon form in json From 57ced64d535b5abba9d56b42de61728da49cfb9c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Nov 2022 21:49:47 +0200 Subject: [PATCH 114/367] Simple uicons support If you have an uicons repo stored on your server already you can just link the pokemon folder from there to images/pokemon in raidbot --- logic/raid_picture.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 1f87b0af..213ea8ef 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -300,11 +300,16 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { } else { // Check pokemon icon source and create image $img_file = null; + $uicons = false; $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); $addressable_icon = 'pm'.$raid['pokemon']; + $uicons_icon = $raid['pokemon']; - if($raid['pokemon_form_name'] != 'normal') $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); + if($raid['pokemon_form_name'] != 'normal') { + $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); + $uicons_icon .= '_f'.$raid['pokemon_form']; + } // Getting the actual icon filename $p_icon = "pokemon_icon_" . $icon_suffix; @@ -315,14 +320,18 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); $addressable_icon .= '.c' . array_search($raid['costume'],$costume); + + $uicons_icon .= '_c'.$raid['costume']; } if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { $p_icon = $p_icon . "_shiny"; $addressable_icon .= '.s'; + $uicons_icon .= '_s'; $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); } $addressable_icon .= '.icon.png'; $p_icon = $p_icon . ".png"; + $uicons_icon .= '.png'; foreach($p_sources as $p_dir) { // Icon dir named 'pokemon'? Then change path to not add '_repo-owner' to icon folder name @@ -342,6 +351,10 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { }else if(file_exists($p_img_base_path . "/" . $p_icon) && filesize($p_img_base_path . "/" . $p_icon) > 0) { $img_file = $p_img_base_path . "/" . $p_icon; break; + }else if(file_exists($p_img_base_path . "/" . $uicons_icon) && filesize($p_img_base_path . "/" . $uicons_icon) > 0) { + $img_file = $p_img_base_path . "/" . $uicons_icon; + $uicons = true; + break; } } @@ -363,7 +376,9 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Position and size of the picture $dst_x = $dst_y = 100; - $dst_w = $dst_h = $src_w = $src_h = 256; + $dst_w = $dst_h = 256; + $src_w = $src_h = $dst_w; + if($uicons === true) $src_w = $src_h = 128; if($raid['type'] != '') $show_boss_pokemon_types = true; } From 92dda6ab53aa79facd1c4db2d0f69728b0791aea Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Nov 2022 22:24:17 +0200 Subject: [PATCH 115/367] Minor translation fix --- lang/language.json | 13 ------------- mods/edit_save.php | 5 +---- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/lang/language.json b/lang/language.json index af0c2879..4b611e0d 100644 --- a/lang/language.json +++ b/lang/language.json @@ -3067,19 +3067,6 @@ "FI": "/gymname Salin nimi", "ES": "/gymname Nombre del gimnasio" }, - "set_gym_team": { - "NL": "Optioneel - zet Gym en Team", - "DE": "Optional - Arena Team setzen", - "EN": "Optional - set Gym and Team", - "IT": "Opzionale - imposta Palestra e Team", - "PT-BR": "Opcional - escolha o gínasio e time", - "RU": "Опционально - указать Гим и Команду", - "NO": "Valgfri - Fortell hvilken Gym og Team", - "FR": "Optionnel - choisir la couleur de l'arène", - "PL": "Opcjonalnie - Wybierz kolor Areny", - "FI": "Valinnainen - aseta sali ja joukkue", - "ES": "Opcional - Poner gimnasio y equipo" - }, "mystic": { "NL": "Mystic/Blauw", "DE": "Weisheit/Blau", diff --git a/mods/edit_save.php b/mods/edit_save.php index b71c3e29..ca3a67c4 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -137,13 +137,10 @@ $user_id_tag = '#' . $update['callback_query']['from']['id']; // Gym Name -if(!empty($raid['gym_name']) && ($raid['gym_name'] != $user_id_tag)) { -$msg .= getTranslation('set_gym_team') . CR2; -} else { +if(!empty($raid['gym_name']) && ($raid['gym_name'] == $user_id_tag)) { $msg .= getTranslation('set_gym_name_and_team') . CR2; $msg .= getTranslation('set_gym_name_command') . CR; } -$msg .= getTranslation('set_gym_team_command'); // Build callback message string. if($arg == 0) { From 99cab0d52740db3807467f90f30fe4fffcc11b01 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Nov 2022 22:24:27 +0200 Subject: [PATCH 116/367] Detect UICONS source size automagically --- logic/raid_picture.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 213ea8ef..8e325452 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -378,7 +378,9 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $dst_x = $dst_y = 100; $dst_w = $dst_h = 256; $src_w = $src_h = $dst_w; - if($uicons === true) $src_w = $src_h = 128; + if($uicons === true) { + [$src_w, $src_h] = getimagesize($img_file); + } if($raid['type'] != '') $show_boss_pokemon_types = true; } From ee57930f2df4dfd288ad6ead620caf7ec4c3c9c3 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:14:16 +0200 Subject: [PATCH 117/367] Added RAID_EXCLUDE_ELITE_DUPLICATION and made duplicate raid check raid level specific for raids received via webhook --- commands/raid_from_webhook.php | 54 ++++++++++++------------- config/defaults-config.json | 1 + docs/config.rst | 4 ++ logic/active_raid_duplication_check.php | 31 ++++++++------ 4 files changed, 50 insertions(+), 40 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index f24b4382..9d0d5d7c 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -189,7 +189,7 @@ function isPointInsidePolygon($point, $vertices) { } // Insert new raid or update existing raid/ex-raid? - $raid_id = active_raid_duplication_check($gym_internal_id); + $raid_id = active_raid_duplication_check($gym_internal_id, $level); $send_updates = false; @@ -306,32 +306,32 @@ function isPointInsidePolygon($point, $vertices) { // Combine resulting data with stuff received from webhook to create a complete raid array $raid = array_merge($missing_raid_data, [ - 'id' => $raid_id, - 'user_id' => $config->WEBHOOK_CREATOR, - 'spawn' => $spawn, - 'pokemon' => $resolved_boss['pokedex_id'], - 'pokemon_form' => $resolved_boss['pokemon_form_id'], - 'start_time' => $start, - 'end_time' => $end, - 'gym_team' => $team, - 'gym_id' => $gym_internal_id, - 'level' => $level, - 'move1' => $move_1, - 'move2' => $move_2, - 'gender' => $gender, - 'costume' => $costume, - 'event' => NULL, - 'event_note' => NULL, - 'event_name' => NULL, - 'event_description' => NULL, - 'event_vote_key_mode' => NULL, - 'event_time_slots' => NULL, - 'event_raid_duration' => NULL, - 'event_hide_raid_picture' => NULL, - 'event_pokemon_title' => NULL, - 'event_poll_template' => NULL, - 'raid_ended' => 0, - ]); + 'id' => $raid_id, + 'user_id' => $config->WEBHOOK_CREATOR, + 'spawn' => $spawn, + 'pokemon' => $resolved_boss['pokedex_id'], + 'pokemon_form' => $resolved_boss['pokemon_form_id'], + 'start_time' => $start, + 'end_time' => $end, + 'gym_team' => $team, + 'gym_id' => $gym_internal_id, + 'level' => $level, + 'move1' => $move_1, + 'move2' => $move_2, + 'gender' => $gender, + 'costume' => $costume, + 'event' => NULL, + 'event_note' => NULL, + 'event_name' => NULL, + 'event_description' => NULL, + 'event_vote_key_mode' => NULL, + 'event_time_slots' => NULL, + 'event_raid_duration' => NULL, + 'event_hide_raid_picture' => NULL, + 'event_pokemon_title' => NULL, + 'event_poll_template' => NULL, + 'raid_ended' => 0, + ]); } catch (PDOException $exception) { error_log($exception->getMessage()); diff --git a/config/defaults-config.json b/config/defaults-config.json index 1aca962a..dc03d17c 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -45,6 +45,7 @@ "RAID_DURATION_CLOCK_STYLE": true, "RAID_CUSTOM_GYM_LETTERS":"", "RAID_EXCLUDE_EXRAID_DUPLICATION": true, + "RAID_EXCLUDE_ELITE_DUPLICATION": true, "RAID_EXCLUDE_EVENT_DUPLICATION": true, "RAID_LOCATION": false, "RAID_SLOTS":"15", diff --git a/docs/config.rst b/docs/config.rst index a4b37643..63e075fe 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -968,6 +968,10 @@ Config reference - In minutes the maximum length of the egg phase a user is allowed to give. * - RAID_EXCLUDE_EXRAID_DUPLICATION - Bool, true to exclude ex-raids from the duplication check which allows to create an ex-raid and a normal raid at the same gym + * - RAID_EXCLUDE_EVENT_DUPLICATION + - Bool, true to exclude event raids from the duplication check which allows to create an event and a normal raid at the same gym + * - RAID_EXCLUDE_ELITE_DUPLICATION + - Bool, true to exclude elite raids from the duplication check which allows to create an elite raid and a normal raid at the same gym * - RAID_EX_GYM_MARKER - Enum, "icon" (default value, a star icon) or a custom text/icon to indicate an ex-raid gym in the raid polls * - RAID_FIRST_START diff --git a/logic/active_raid_duplication_check.php b/logic/active_raid_duplication_check.php index 9a2b5a46..33a253db 100644 --- a/logic/active_raid_duplication_check.php +++ b/logic/active_raid_duplication_check.php @@ -4,28 +4,33 @@ * @param $gym_id * @return string */ -function active_raid_duplication_check($gym_id) +function active_raid_duplication_check($gym_id, $level = false) { global $config; - + $levelSql = ''; + $args = [$gym_id]; + if($level !== false) { + $levelSql = 'AND level = ?'; + $args[] = $level; + } // Build query. $rs = my_query( - " - SELECT id, event + ' + SELECT id, event, level FROM raids WHERE end_time > (UTC_TIMESTAMP() - INTERVAL 5 MINUTE) - AND gym_id = {$gym_id} - ORDER BY event IS NOT NULL - " + AND gym_id = ? + ' . $levelSql . ' + ORDER BY end_time, event IS NOT NULL + ', $args ); $active = 0; while($raid = $rs->fetch()) { - # TODO: Should document why this check happens / the logic - if($config->RAID_EXCLUDE_EXRAID_DUPLICATION && $raid['event'] == EVENT_ID_EX) { - continue; - } - # TODO: Should document why this check happens / the logic - if($config->RAID_EXCLUDE_EVENT_DUPLICATION && $raid['event'] !== NULL && $raid['event'] != EVENT_ID_EX) { + // In some cases (ex-raids, event raids and elite raids) gyms can have multiple raids saved to them. + // We ignore these raids when performing the duplication check. + if( ($config->RAID_EXCLUDE_EXRAID_DUPLICATION && $raid['event'] == EVENT_ID_EX) + or ($level != 9 && $config->RAID_EXCLUDE_ELITE_DUPLICATION && $raid['level'] == 9) + or ($config->RAID_EXCLUDE_EVENT_DUPLICATION && $raid['event'] !== NULL && $raid['event'] != EVENT_ID_EX)) { continue; } $active = $raid['id']; From d417e8d4826717c485913c3c5d3bc28b165994ac Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:31:12 +0200 Subject: [PATCH 118/367] Documented instructions for using UICONS in raid picture --- docs/config.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/config.rst b/docs/config.rst index 63e075fe..cb088122 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -296,6 +296,8 @@ To enable raid announcements as images set ``RAID_PICTURE`` to true and set the You also need to get the Pokemon sprites from known sources and put them in either images/pokemon/ or the images/pokemon_REPO-OWNER/ folder. The images/pokemon/ directory needs to be created manually, the images/pokemon_REPO-OWNER/ folders will be created automatically when by running the special download script mentioned below. +If you have an UICONS repo stored on your server already you can softlink the ``pokemon`` folder from there to ``images/pokemon/`` in raidbot directory. + Pokemon Icons / Sprites: Link: https://github.com/PokeMiners/pogo_assets/tree/master/Images/Pokemon%20-%20256x256 From 1d52c2a25ac92153729a16a5320a36c4bb7411f6 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:32:19 +0200 Subject: [PATCH 119/367] Removed the part with `RAID_PICTURE_URL` from documentation --- docs/config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.rst b/docs/config.rst index 089f4e35..0324be89 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -303,7 +303,7 @@ For a specific chat: Raid Picture mode ^^^^^^^^^^^^^^^^^ -To enable raid announcements as images set ``RAID_PICTURE`` to true and set the url in ``RAID_PICTURE_URL`` to the location of raidpicture.php. +To enable raid announcements as images set ``RAID_PICTURE`` to true. You also need to get the Pokemon sprites from known sources and put them in either images/pokemon/ or the images/pokemon_REPO-OWNER/ folder. The images/pokemon/ directory needs to be created manually, the images/pokemon_REPO-OWNER/ folders will be created automatically when by running the special download script mentioned below. From 8b6eb63f182adba342e5434ce69de2d63f81b64d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 15 Nov 2022 23:06:14 +0200 Subject: [PATCH 120/367] Comments in access file names should now work as advertised in documentation Also streamlined the privilege check code a bit --- core/bot/user.php | 128 +++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 74 deletions(-) diff --git a/core/bot/user.php b/core/bot/user.php index 89556590..2638f864 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -52,86 +52,66 @@ public function privilegeCheck($update) { 'kicked' => 'kicked', ]; - // If user specific permissions are found, use them instead of group based - if (is_file(ACCESS_PATH . '/access' . $user_id)) { - $accessChats = [$user_id => null]; - }else { - $chatIds = []; - $rolesToCheck = $telegramRoles; - $rolesToCheck[] = 'access'; - foreach($rolesToCheck as $tgRole => $roleToCheck) { - $chatFiles = str_replace(ACCESS_PATH . '/' . $roleToCheck, '', glob(ACCESS_PATH . '/' . $roleToCheck . '-*')); - $chatIds = array_merge($chatIds, $chatFiles); - } - // Delete duplicates - $chatsToCheck = array_unique($chatIds); - $tg_json = []; - // Check access and permission - foreach($chatsToCheck as $chat) { - // Get chat object - remove comments from filename - // This way some kind of comment like the channel name can be added to the end of the filename, e.g. creator-100123456789-MyPokemonChannel to easily differ between access files :) - // Source: php.net/manual/en/function.intval.php#7707 - preg_match_all('/-?\d+/', $chat, $tg_chat); - $tg_chat = $tg_chat[0][0]; - debug_log("Getting chat object for '$tg_chat'"); - - // Group/channel? - if($tg_chat[0] == '-') { - // Get chat member object and check status - debug_log("Getting user from chat '$tg_chat'"); - $tg_json[$tg_chat] = get_chatmember($tg_chat, $user_id, true); - } + $accessFilesList = $tg_json = $chatIds = []; + foreach(glob(ACCESS_PATH . '/*') as $filePath) { + $filename = str_replace(ACCESS_PATH . '/', '', $filePath); + // Get chat object - remove comments from filename + // This way some kind of comment like the channel name can be added to the end of the filename, e.g. creator-100123456789-MyPokemonChannel to easily differ between access files :) + preg_match('/(access)('.$user_id.')|(access|creator|admins|members|restricted|kicked)(-[0-9]+)/', '-' . $filename, $result); + if(empty($result[0])) continue; + // User specific access file found? + if(!empty($result[1])) { + $privilegeList = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + debug_log($filename, 'Positive result on access check in file:'); + $this->userPrivileges = [ + 'privileges' => $privilegeList, + 'grantedBy' => $filename, + ]; + return; } - $accessChats = curl_json_multi_request($tg_json); + // Group/channel? + $role = $result[3]; + $tg_chat = $result[4]; + $chatIds[] = $tg_chat; + // Save the full filename (with possible comments) to an array for later use + $accessFilesList[$role.$tg_chat] = $filename; + debug_log("Asking Telegram if user is a member of chat '$tg_chat'"); + if(!isset($tg_json[$tg_chat])) $tg_json[$tg_chat] = get_chatmember($tg_chat, $user_id, true); // Get chat member object and check status } + $accessChats = curl_json_multi_request($tg_json); + // Loop through different chats foreach($accessChats as $chatId => $chatObj) { + $userStatus = $chatObj['result']['status']; + if(!isset($chatObj['ok']) or $chatObj['ok'] != true or $userStatus == 'left' or !array_key_exists($userStatus, $telegramRoles)){ + // Deny access + debug_log($chatId, 'Negative result on access check for chat:'); + debug_log('Continuing with next chat...'); + continue; + } // Object contains response from Telegram - if(isset($chatObj['ok'])) { - if($chatObj['ok'] == true) { - debug_log('Proper chat object received, continuing with access check.'); - - // Get access file based on user status/role. - debug_log('Role of user ' . $chatObj['result']['user']['id'] . ' : ' . $chatObj['result']['status']); - - $userStatus = $chatObj['result']['status']; - - if(array_key_exists($userStatus, $telegramRoles) && is_file(ACCESS_PATH . '/' . $telegramRoles[$userStatus] . $chatId)) { - $privilegeList = file(ACCESS_PATH . '/' . $telegramRoles[$userStatus] . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $accessFile = $userStatus . $chatId; - - // Any other user status/role except "left" - } else if($userStatus != 'left' && is_file(ACCESS_PATH . '/access' . $chatId)) { - $privilegeList = file(ACCESS_PATH . '/access' . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $accessFile = 'access' . $chatId; - - // Ignore "Restricted"? - if($userStatus == 'restricted' && in_array('ignore-restricted', $privilegeList)) { - $privilegeList = NULL; - } - - // Ignore "kicked"? - if($userStatus == 'kicked' && in_array('ignore-kicked', $privilegeList)) { - $privilegeList = NULL; - } - } else { - continue; - } - - // Debug. - debug_log('Access file:'); - debug_log($privilegeList); - } else { - // Invalid chat - debug_log('Chat ' . $chatId . ' does not exist! Continuing with next chat...'); - continue; - } - // Process user specific access file - }else { - if(is_file(ACCESS_PATH . '/access' . $chatId)) { - $privilegeList = file(ACCESS_PATH . '/access' . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $accessFile = 'access' . $chatId; + debug_log('Proper chat object received, continuing with access check.'); + debug_log('Role of user ' . $chatObj['result']['user']['id'] . ' : ' . $chatObj['result']['status']); + + // Get access file based on user status/role. + $roleAndChat = $telegramRoles[$userStatus] . $chatId; + if(array_key_exists($roleAndChat, $accessFilesList)) { + $privilegeList = file(ACCESS_PATH . '/' . $accessFilesList[$roleAndChat], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $accessFile = $accessFilesList[$roleAndChat]; + + // Any other user status/role except "left" + } else if(array_key_exists('access' . $chatId, $accessFilesList)) { + $privilegeList = file(ACCESS_PATH . '/' . $accessFilesList['access' . $chatId], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $accessFile = $accessFilesList['access' . $chatId]; + + // Ignore "Restricted" or "kicked"? + if( ($userStatus == 'restricted' && in_array('ignore-restricted', $privilegeList)) + or ($userStatus == 'kicked' && in_array('ignore-kicked', $privilegeList))) { + $privilegeList = NULL; } + // Debug. + debug_log('Access file:'); + debug_log($privilegeList); } // Save privileges if found From cccbf0518db851be51b0e02711c0376b96b34703 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 14:30:26 +0200 Subject: [PATCH 121/367] Cleaned up pokedex code --- constants.php | 1 + logic.php | 5 --- logic/get_formatted_pokemon_cp.php | 32 ++++---------- logic/get_pokemon_cp.php | 25 ----------- logic/get_pokemon_info.php | 40 ++++++++--------- logic/get_pokemon_shiny_status.php | 31 ------------- logic/get_pokemon_weather.php | 33 -------------- logic/get_raid.php | 4 +- logic/raid_level.php | 64 --------------------------- logic/show_raid_poll.php | 14 +++--- mods/pokedex_edit_pokemon.php | 48 +++++++++----------- mods/pokedex_set_cp.php | 40 ++++++----------- mods/pokedex_set_raid_level.php | 38 ++++++++-------- mods/pokedex_set_shiny.php | 70 ++++++++++++------------------ mods/pokedex_set_weather.php | 18 ++++---- 15 files changed, 123 insertions(+), 340 deletions(-) delete mode 100644 logic/get_pokemon_cp.php delete mode 100644 logic/get_pokemon_shiny_status.php delete mode 100644 logic/get_pokemon_weather.php delete mode 100644 logic/raid_level.php diff --git a/constants.php b/constants.php index debab865..c0204b55 100644 --- a/constants.php +++ b/constants.php @@ -80,6 +80,7 @@ defined('EMOJI_IN_PERSON') or define('EMOJI_IN_PERSON', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F9E1))); defined('EMOJI_ALIEN') or define('EMOJI_ALIEN', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F47D))); defined('EMOJI_CAN_INVITE')or define('EMOJI_CAN_INVITE', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F695))); +defined('EMOJI_SHINY') or define('EMOJI_SHINY', iconv('UCS-4LE', 'UTF-8', pack('V', 0x2728))); // Weather Icons. defined('EMOJI_W_SUNNY') or define('EMOJI_W_SUNNY', iconv('UCS-4LE', 'UTF-8', pack('V', 0x2600))); diff --git a/logic.php b/logic.php index 75f7dbe4..6c8d681d 100644 --- a/logic.php +++ b/logic.php @@ -22,12 +22,8 @@ include('logic/get_local_pokemon_name.php'); include('logic/get_overview.php'); include('logic/get_pokemon_by_table_id.php'); -include('logic/get_pokemon_cp.php'); include('logic/get_pokemon_form_name.php'); include('logic/get_pokemon_id_by_name.php'); -include('logic/get_pokemon_info.php'); -include('logic/get_pokemon_weather.php'); -include('logic/get_pokemon_shiny_status.php'); include('logic/get_raid.php'); include('logic/get_raid_times.php'); include('logic/get_remote_users_count.php'); @@ -47,7 +43,6 @@ include('logic/raid_edit_gyms_first_letter_keys.php'); include('logic/raid_edit_raidlevel_keys.php'); include('logic/raid_get_gyms_list_keys.php'); -include('logic/raid_level.php'); include('logic/raid_list.php'); include('logic/raid_poll_message.php'); include('logic/sendalarmnotice.php'); diff --git a/logic/get_formatted_pokemon_cp.php b/logic/get_formatted_pokemon_cp.php index a447c68d..053d97f6 100644 --- a/logic/get_formatted_pokemon_cp.php +++ b/logic/get_formatted_pokemon_cp.php @@ -1,39 +1,23 @@ 0) ? $row['min_cp'] : ''; + $cp20 .= (!empty($cp20) && $cp20 > 0) ? ('/' . $row['max_cp']) : ($row['max_cp']); - while($row = $rs->fetch()) { - // CP - $cp20 .= ($row['min_cp'] > 0) ? $row['min_cp'] : ''; - $cp20 .= (!empty($cp20) && $cp20 > 0) ? ('/' . $row['max_cp']) : ($row['max_cp']); - - // Weather boosted CP - $cp25 .= ($row['min_weather_cp'] > 0) ? $row['min_weather_cp'] : ''; - $cp25 .= (!empty($cp25) && $cp25 > 0) ? ('/' . $row['max_weather_cp']) : ($row['max_weather_cp']); - } - } + // Weather boosted CP + $cp25 .= ($row['min_weather_cp'] > 0) ? $row['min_weather_cp'] : ''; + $cp25 .= (!empty($cp25) && $cp25 > 0) ? ('/' . $row['max_weather_cp']) : ($row['max_weather_cp']); // Combine CP and weather boosted CP $text = ($override_language == true) ? (getPublicTranslation('pokedex_cp')) : (getTranslation('pokedex_cp')); diff --git a/logic/get_pokemon_cp.php b/logic/get_pokemon_cp.php deleted file mode 100644 index 0e496fd0..00000000 --- a/logic/get_pokemon_cp.php +++ /dev/null @@ -1,25 +0,0 @@ -fetch(); - - return $cp; -} - -?> diff --git a/logic/get_pokemon_info.php b/logic/get_pokemon_info.php index 19c575aa..b72e6b3f 100644 --- a/logic/get_pokemon_info.php +++ b/logic/get_pokemon_info.php @@ -5,26 +5,24 @@ * @param $pokemon_form_id * @return array */ -function get_pokemon_info($pokemon_id, $pokemon_form_id) +function get_pokemon_info($pokedex_id, $pokemon_form_id) { - /** Example: - * Raid boss: Mewtwo (#ID) - * Weather: Icons - * CP: CP values (Boosted CP values) - * Shiny: Shiny - */ - $info = ''; - $info .= getTranslation('raid_boss') . ': ' . get_local_pokemon_name($pokemon_id, $pokemon_form_id) . ' (#' . $pokemon_id . ')' . CR . CR; - $poke_raid_level = get_raid_level($pokemon_id, $pokemon_form_id); - $poke_cp = get_formatted_pokemon_cp($pokemon_id, $pokemon_form_id); - $poke_weather = get_pokemon_weather($pokemon_id, $pokemon_form_id); - $poke_shiny = get_pokemon_shiny_status($pokemon_id, $pokemon_form_id); - $info .= getTranslation('pokedex_raid_level') . ': ' . getTranslation($poke_raid_level . 'stars') . CR; - $info .= (empty($poke_cp)) ? (getTranslation('pokedex_cp') . CR) : $poke_cp . CR; - $info .= getTranslation('pokedex_weather') . ': ' . get_weather_icons($poke_weather) . CR; - $info .= (($poke_shiny == 1) ? (getTranslation('shiny')) : (getTranslation('not_shiny'))) . CR . CR; - - return $info; + $query = my_query(' + SELECT id, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, + (SELECT raid_level + FROM raid_bosses + WHERE pokedex_id = :pokedex_id + AND pokemon_form_id = :pokemon_form_id + AND scheduled = 0) as raid_level + FROM pokemon + WHERE pokedex_id = :pokedex_id + AND pokemon_form_id = :pokemon_form_id + LIMIT 1 + ', [ + 'pokedex_id' => $pokedex_id, + 'pokemon_form_id' => $pokemon_form_id + ]); + $result = $query->fetch(); + if($result['raid_level'] == NULL) $result['raid_level'] = 0; + return $result; } - -?> diff --git a/logic/get_pokemon_shiny_status.php b/logic/get_pokemon_shiny_status.php deleted file mode 100644 index 0c2c9527..00000000 --- a/logic/get_pokemon_shiny_status.php +++ /dev/null @@ -1,31 +0,0 @@ -fetch(); - debug_log($shiny, 'Per db, shiny status is:'); - - return $shiny['shiny']; - } else { - return 0; - } -} - -?> diff --git a/logic/get_pokemon_weather.php b/logic/get_pokemon_weather.php deleted file mode 100644 index 1835b8dc..00000000 --- a/logic/get_pokemon_weather.php +++ /dev/null @@ -1,33 +0,0 @@ -fetch(); - - if($ww) { - return $ww['weather']; - } else { - throw new Exception("Failed to find pokemon {$pokemon_id}_{$pokemon_form_id} weather."); - } - } else { - return 0; - } -} - -?> diff --git a/logic/get_raid.php b/logic/get_raid.php index f8b9dc67..0bf38024 100644 --- a/logic/get_raid.php +++ b/logic/get_raid.php @@ -27,9 +27,9 @@ function get_raid($raid_id) ON raids.user_id = users.user_id LEFT JOIN events ON events.id = raids.event - WHERE raids.id = '.$raidid.' + WHERE raids.id = ? LIMIT 1 - ' + ', [$raidid] ); // Get the row. $raid = $rs->fetch(); diff --git a/logic/raid_level.php b/logic/raid_level.php deleted file mode 100644 index 0353395a..00000000 --- a/logic/raid_level.php +++ /dev/null @@ -1,64 +0,0 @@ -fetch()) { - $raid_level = $level['raid_level']; - } - debug_log("Resolved level of {$pokedex_id}({$pokemon_form_id}) to {$raid_level}"); - } else { - info_log("Could not resolve level of {$pokedex_id}({$pokemon_form_id}), defaulting to 0!"); - $raid_level = '0'; - } - - return $raid_level; -} - -/** - * Get active raid bosses at a certain time. - * @param $time - string, datetime, local time - * @param $raid_level - ENUM('1', '2', '3', '4', '5', '6', 'X') - * @return array - */ -function get_raid_bosses($time, $raid_level) -{ - // Get raid level from database - $rs = my_query( - ' - SELECT DISTINCT pokedex_id, pokemon_form_id - FROM raid_bosses - WHERE \''.$time.'\' BETWEEN date_start AND date_end - AND raid_level = \''.$raid_level.'\' - '); - debug_log('Checking active raid bosses for raid level '.$raid_level.' at '.$time.':'); - $raid_bosses = []; - $egg_found = false; - while ($result = $rs->fetch()) { - $raid_bosses[] = $result; - if($result['pokedex_id'] == '999'.$raid_level) $egg_found = true; - debug_log('Pokedex id: '.$result['pokedex_id'].' | Form id: '.$result['pokemon_form_id']); - } - if(!$egg_found) $raid_bosses[] = ['pokedex_id' => '999'.$raid_level, 'pokemon_form_id' => 0]; // Add egg if it wasn't found from db - return $raid_bosses; -} - -?> diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index 3c3f22e7..dd2623ab 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -17,6 +17,8 @@ function show_raid_poll($raid, $inline = false) $raid_pokemon_form_id = $raid['pokemon_form']; $raid_pokemon_form_name = ($raid_pokemon_form_id != 0) ? get_pokemon_form_name($raid_pokemon_id, $raid_pokemon_form_id) : ''; $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_id; + require_once(LOGIC_PATH . '/get_pokemon_info.php'); + $raid_pokemon_info = get_pokemon_info($raid_pokemon_id, $raid_pokemon_form_id); // Get raid level $raid_level = $raid['level']; @@ -62,12 +64,11 @@ function show_raid_poll($raid, $inline = false) //Only store address if not empty if(!empty($address)) { my_query( - " + ' UPDATE gyms SET address = ? - WHERE id = '{$raid['gym_id']}' - ", - [$address] + WHERE id = ? + ', [$address, $raid['gym_id']] ); //Use new address $msg = raid_poll_message($msg, ($config->RAID_PICTURE ? $raid['gym_name'].': ' : ''). mapslink($raid,$address) . CR); @@ -86,8 +87,7 @@ function show_raid_poll($raid, $inline = false) $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . '', true); // Display raid boss weather. - $pokemon_weather = get_pokemon_weather($raid_pokemon_id, $raid_pokemon_form_id); - $msg = raid_poll_message($msg, ($pokemon_weather != 0) ? (' ' . get_weather_icons($pokemon_weather)) : '', true); + $msg = raid_poll_message($msg, ($raid_pokemon_info['weather'] != 0) ? (' ' . get_weather_icons($raid_pokemon_info['weather'])) : '', true); $msg = raid_poll_message($msg, CR, true); } @@ -287,7 +287,7 @@ function show_raid_poll($raid, $inline = false) } if($cnt_all > 0 || $buttons_hidden) { // Display raid boss CP values. - $pokemon_cp = get_formatted_pokemon_cp($raid_pokemon_id, $raid_pokemon_form_id, true); + $pokemon_cp = get_formatted_pokemon_cp($raid_pokemon_info, true); $msg = raid_poll_message($msg, (!empty($pokemon_cp)) ? ($pokemon_cp . CR) : '', true); } } diff --git a/mods/pokedex_edit_pokemon.php b/mods/pokedex_edit_pokemon.php index 778e5fb8..4dd18b0f 100644 --- a/mods/pokedex_edit_pokemon.php +++ b/mods/pokedex_edit_pokemon.php @@ -8,21 +8,22 @@ // Check access. $botUser->accessCheck($update, 'pokedex'); - +require_once(LOGIC_PATH . '/get_pokemon_info.php'); // Set the id. $poke_id_form = $data['id']; -$dex_id_form = explode('-',$data['id'],2); -$pokedex_id = $dex_id_form[0]; -$pokemon_form = $dex_id_form[1]; +[$pokedex_id, $pokemon_form_id] = explode('-',$data['id'],2); // Set the arg. $arg = $data['arg']; -// Init empty keys array. -$keys = []; - // Set the message. -$msg = get_pokemon_info($pokedex_id, $pokemon_form); +$pokemon = get_pokemon_info($pokedex_id, $pokemon_form_id); +$poke_cp = get_formatted_pokemon_cp($pokemon); +$msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($pokedex_id, $pokemon_form_id) . ' (#' . $pokedex_id . ')' . CR . CR; +$msg .= getTranslation('pokedex_raid_level') . ': ' . getTranslation($pokemon['raid_level'] . 'stars') . CR; +$msg .= (empty($poke_cp)) ? (getTranslation('pokedex_cp') . CR) : $poke_cp . CR; +$msg .= getTranslation('pokedex_weather') . ': ' . get_weather_icons($pokemon['weather']) . CR; +$msg .= (($pokemon['shiny'] == 1) ? (EMOJI_SHINY . SP . getTranslation('shiny')) : (getTranslation('not_shiny'))) . CR . CR; $msg .= '' . getTranslation('pokedex_select_action') . ''; // Create keys array. @@ -36,8 +37,7 @@ ]; // Raid-Egg? Hide specific options! -$eggs = $GLOBALS['eggs']; -if(!in_array($pokedex_id, $eggs)) { +if(!in_array($pokedex_id, $GLOBALS['eggs'])) { $keys_cp_weather = [ [ [ @@ -92,28 +92,20 @@ ] ]; -// Send message. -if($arg == 'id-or-name') { - // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); - -// Edit message. -} else { - // Build callback message string. - $callback_response = 'OK'; +// Build callback message string. +$callback_response = 'OK'; - // Telegram JSON array. - $tg_json = array(); +// Telegram JSON array. +$tg_json = array(); - // Answer callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); +// Answer callback. +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - // Edit message. - $tg_json[] = edit_message($update, $msg, $keys, false, true); +// Edit message. +$tg_json[] = edit_message($update, $msg, $keys, false, true); - // Telegram multicurl request. - curl_json_multi_request($tg_json); -} +// Telegram multicurl request. +curl_json_multi_request($tg_json); // Exit. exit(); diff --git a/mods/pokedex_set_cp.php b/mods/pokedex_set_cp.php index bc3d4365..edfc506c 100644 --- a/mods/pokedex_set_cp.php +++ b/mods/pokedex_set_cp.php @@ -25,18 +25,15 @@ $cp_value = $data[3]; // Set boosted string -if($cp_level == 25) { - $boosted = '_weather_cp'; -} else { - $boosted = '_cp'; -} +$boosted = ($cp_level == 25) ? '_weather_cp' : '_cp'; // Action to do: Save or add digits to cp $action = $data[2]; // Get current CP values -$cp_old = get_pokemon_cp($dex_id, $dex_form); -$current_cp = $cp_old[$cp_type . $boosted]; +require_once(LOGIC_PATH . '/get_pokemon_info.php'); +$pokemon = get_pokemon_info($dex_id, $dex_form); +$current_cp = $pokemon[$cp_type . $boosted]; // Log debug_log('New CP Type: ' . $cp_type); @@ -75,28 +72,17 @@ // Save cp to database } else if($action == 'save') { - // Set IV level for database - if($cp_level == 25) { - $weather = 'weather_cp'; - } else { - $weather = 'cp'; - } - // Set column name. - $cp_column = $cp_type . '_' . $weather; + $cp_column = $cp_type . $boosted; // Update cp of pokemon. - $rs = my_query( - " - UPDATE pokemon - SET $cp_column = {$cp_value} - WHERE pokedex_id = {$dex_id} - AND pokemon_form_id = '{$dex_form}' - " - ); - - // Init empty keys array. - $keys = []; + $rs = my_query(' + UPDATE pokemon + SET ' . $cp_column . ' = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$cp_value, $dex_id, $dex_form] + ); // Back to pokemon and done keys. $keys = [ @@ -113,7 +99,7 @@ ]; // Build callback message string. - $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($pokedex_id); + $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); // Set the message. $msg = getTranslation('pokemon_saved') . CR; diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index f35bde65..93d025cd 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -20,6 +20,9 @@ $dex_id = $dex_id_form[0]; $dex_form = $dex_id_form[1]; +require_once(LOGIC_PATH . '/get_pokemon_info.php'); +$pokemon = get_pokemon_info($dex_id, $dex_form); + // Set raid level or show raid levels? if($data['arg'] == "setlevel") { $raid_levels = str_split('0' . RAID_LEVEL_ALL); @@ -54,32 +57,25 @@ // Set the message. $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; - $old_raid_level = get_raid_level($dex_id, $dex_form); - $msg .= getTranslation('pokedex_current_raid_level') . ' ' . getTranslation($old_raid_level . 'stars') . CR . CR; + $msg .= getTranslation('pokedex_current_raid_level') . ' ' . getTranslation($pokemon['raid_level'] . 'stars') . CR . CR; $msg .= '' . getTranslation('pokedex_new_raid_level') . ':'; } else { // Update raid level of pokemon. - if($arg == 0 && get_raid_level($dex_id, $dex_form) != 0) { - $rs = my_query( - " - DELETE FROM raid_bosses - WHERE pokedex_id = '{$dex_id}' - AND pokemon_form_id = '{$dex_form}' - AND scheduled = 0 - " - ); - }else { - $rs = my_query( - " - INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) - VALUES ('{$dex_id}', '{$dex_form}', '{$arg}') - " - ); + my_query(' + DELETE FROM raid_bosses + WHERE pokedex_id = ? + AND pokemon_form_id = ? + AND scheduled = 0 + ', [$dex_id, $dex_form] + ); + if($arg != 0) { + my_query(' + INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) + VALUES (?, ?, ?) + ',[$dex_id, $dex_form, $arg] + ); } - // Init empty keys array. - $keys = []; - // Back to pokemon and done keys. $keys = [ [ diff --git a/mods/pokedex_set_shiny.php b/mods/pokedex_set_shiny.php index 9a091554..2aa11d08 100644 --- a/mods/pokedex_set_shiny.php +++ b/mods/pokedex_set_shiny.php @@ -21,44 +21,32 @@ $dex_form = $dex_id_form[1]; // Set shiny or ask to set? -if($data['arg'] == "setshiny") { +if($data['arg'] == 'setshiny') { // Get current shiny status from database. - $shiny = get_pokemon_shiny_status($dex_id, $dex_form); - - // Init empty keys array. - $keys = []; - - // Create keys array. - if($shiny == 0) { - // Enable shiny. - $old_shiny_status = getTranslation('not_shiny'); - $keys[] = [ - array( - 'text' => getTranslation('shiny'), - 'callback_data' => $pokedex_id . ':pokedex_set_shiny:1' - ) - ]; - - } else { - // Disable shiny. - $old_shiny_status = getTranslation('shiny'); - $keys[] = [ - array( - 'text' => getTranslation('not_shiny'), - 'callback_data' => $pokedex_id . ':pokedex_set_shiny:0' - ) - ]; - } + require_once(LOGIC_PATH . '/get_pokemon_info.php'); + $pokemon = get_pokemon_info($dex_id, $dex_form); + + $shinyText = ($pokemon['shiny'] == 0) ? 'shiny' : 'not_shiny'; + $old_shiny_status = ($pokemon['shiny'] == 0) ? getTranslation('not_shiny') : EMOJI_SHINY . SP . getTranslation('shiny'); + $newShinyValue = ($pokemon['shiny'] == 0) ? 1 : 0; // Back and abort. - $keys[] = [ + $keys = [ [ - 'text' => getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + [ + 'text' => getTranslation($shinyText), + 'callback_data' => $pokedex_id . ':pokedex_set_shiny:' . $newShinyValue + ] ], [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + [ + 'text' => getTranslation('back'), + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] ] ]; @@ -71,17 +59,13 @@ $msg .= '' . getTranslation('pokedex_new_status') . ':'; } else { // Update shiny status of pokemon. - $rs = my_query( - " - UPDATE pokemon - SET shiny = '{$arg}' - WHERE pokedex_id = {$dex_id} - AND pokemon_form_id = '{$dex_form}' - " - ); - - // Init empty keys array. - $keys = []; + $rs = my_query(' + UPDATE pokemon + SET shiny = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$arg, $dex_id, $dex_form] + ); // Back to pokemon and done keys. $keys = [ diff --git a/mods/pokedex_set_weather.php b/mods/pokedex_set_weather.php index 2bf5ee27..f0aacfa9 100644 --- a/mods/pokedex_set_weather.php +++ b/mods/pokedex_set_weather.php @@ -22,7 +22,10 @@ $data = explode("-", $arg); $action = $data[0]; $new_weather = $data[1]; -$old_weather = get_pokemon_weather($dex_id, $dex_form); + +require_once(LOGIC_PATH . '/get_pokemon_info.php'); +$pokemon = get_pokemon_info($dex_id, $dex_form); +$old_weather = $pokemon['weather']; // Log debug_log('Action: ' . $action); @@ -61,17 +64,14 @@ } else if($action == 'save') { // Update weather of pokemon. $rs = my_query( - " + ' UPDATE pokemon - SET weather = {$new_weather} - WHERE pokedex_id = {$dex_id} - AND pokemon_form_id = '{$dex_form}' - " + SET weather = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$new_weather, $dex_id, $dex_form] ); - // Init empty keys array. - $keys = []; - // Back to pokemon and done keys. $keys = [ [ From fefa0b38af77e1ac60a0ba7b50d0b19f967d7930 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 15:25:35 +0200 Subject: [PATCH 122/367] Cleaned up keys_vote code Also refactored the time slot key logic. Hopefully didn't break it --- logic/keys_vote.php | 979 ++++++++++++++++++-------------------------- 1 file changed, 408 insertions(+), 571 deletions(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index bbd72a1b..8859f58f 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -6,580 +6,417 @@ */ function keys_vote($raid) { - global $config; - // Init keys_time array. - $keys_time = []; - - // Get current UTC time and raid UTC times. - $now = utcnow(); - $end_time = $raid['end_time']; - $start_time = $raid['start_time']; - - // Write to log. - debug_log($now, 'UTC NOW:'); - debug_log($end_time, 'UTC END:'); - debug_log($start_time, 'UTC START:'); - - // Raid ended already. - if ($raid['raid_ended']) { - if($config->RAID_ENDED_HIDE_KEYS) { - return []; - }else { - return [ - [ - [ - 'text' => getPublicTranslation('raid_done'), - 'callback_data' => $raid['id'] . ':vote_refresh:1' - ] - ] - ]; - } - // Raid is still running. + global $config; + // Init keys_time array. + $keys_time = []; + + // Get current UTC time and raid UTC times. + $now = utcnow(); + + // Write to log. + debug_log($now, 'UTC NOW:'); + debug_log($raid['end_time'], 'UTC END:'); + debug_log($raid['start_time'], 'UTC START:'); + + // Raid ended already. + if ($raid['raid_ended']) { + if($config->RAID_ENDED_HIDE_KEYS) return []; + return [ + [ + [ + 'text' => getPublicTranslation('raid_done'), + 'callback_data' => $raid['id'] . ':vote_refresh:1' + ] + ] + ]; + } + // Raid is still running. + // Get current pokemon + $raid_pokemon_id = $raid['pokemon']; + $raid_pokemon_form_id = $raid['pokemon_form']; + $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_id; + + // Get raid level + $raid_level = $raid['level']; + + // Are remote players allowed for this raid? + $raid_local_only = in_array($raid_level, RAID_LEVEL_LOCAL_ONLY); + + // Hide buttons for raid levels and pokemon + $hide_buttons_raid_level = explode(',', $config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL); + $hide_buttons_pokemon = explode(',', $config->RAID_POLL_HIDE_BUTTONS_POKEMON); + + // Show buttons to users? + if(in_array($raid_level, $hide_buttons_raid_level) || in_array(($raid_pokemon_id . "-" . get_pokemon_form_name($raid_pokemon_id,$raid_pokemon_form_id)), $hide_buttons_pokemon) || in_array($raid_pokemon_id, $hide_buttons_pokemon)) { + return []; + } + // Extra Keys + $buttons['alone'] = [ + 'text' => EMOJI_SINGLE, + 'callback_data' => $raid['id'] . ':vote_extra:0' + ]; + $buttons['extra'] = [ + 'text' => '+ ' . EMOJI_IN_PERSON, + 'callback_data' => $raid['id'] . ':vote_extra:in_person' + ]; + + // Show buttons regarding remote participation only if raid level allows it + $buttons['extra_alien'] = $buttons['can_inv'] = $buttons['remote'] = $buttons['inv_plz'] = []; + if(!$raid_local_only) { + $buttons['extra_alien'] = [ + 'text' => '+ ' . EMOJI_ALIEN, + 'callback_data' => $raid['id'] . ':vote_extra:alien' + ]; + + // Can invite key + $buttons['can_inv'] = [ + 'text' => EMOJI_CAN_INVITE, + 'callback_data' => $raid['id'] . ':vote_can_invite:0' + ]; + + // Remote Raid Pass key + $buttons['remote'] = [ + 'text' => EMOJI_REMOTE, + 'callback_data' => $raid['id'] . ':vote_remote:0' + ]; + + // Want invite key + $buttons['inv_plz'] = [ + 'text' => EMOJI_WANT_INVITE, + 'callback_data' => $raid['id'] . ':vote_want_invite:0' + ]; + } + + // Team and level keys. + $buttons['teamlvl'] = [ + [ + [ + 'text' => 'Team', + 'callback_data' => $raid['id'] . ':vote_team:0' + ], + [ + 'text' => 'Lvl +', + 'callback_data' => $raid['id'] . ':vote_level:up' + ], + [ + 'text' => 'Lvl -', + 'callback_data' => $raid['id'] . ':vote_level:down' + ] + ] + ]; + + // Ex-Raid Invite key + $buttons['ex_inv'] = []; + if ($raid['event'] == EVENT_ID_EX) { + $buttons['ex_inv'] = [ + 'text' => EMOJI_INVITE, + 'callback_data' => $raid['id'] . ':vote_invite:0' + ]; + } + + // Show icon, icon + text or just text. + // Icon. + if($config->RAID_VOTE_ICONS && !$config->RAID_VOTE_TEXT) { + $text_here = EMOJI_HERE; + $text_late = EMOJI_LATE; + $text_done = TEAM_DONE; + $text_cancel = TEAM_CANCEL; + // Icon + text. + } else if($config->RAID_VOTE_ICONS && $config->RAID_VOTE_TEXT) { + $text_here = EMOJI_HERE . getPublicTranslation('here'); + $text_late = EMOJI_LATE . getPublicTranslation('late'); + $text_done = TEAM_DONE . getPublicTranslation('done'); + $text_cancel = TEAM_CANCEL . getPublicTranslation('cancellation'); + // Text. + } else { + $text_here = getPublicTranslation('here'); + $text_late = getPublicTranslation('late'); + $text_done = getPublicTranslation('done'); + $text_cancel = getPublicTranslation('cancellation'); + } + + // Status keys. + $buttons['alarm'] = [ + 'text' => EMOJI_ALARM, + 'callback_data' => $raid['id'] . ':vote_status:alarm' + ]; + $buttons['here'] = [ + 'text' => $text_here, + 'callback_data' => $raid['id'] . ':vote_status:arrived' + ]; + $buttons['late'] = [ + 'text' => $text_late, + 'callback_data' => $raid['id'] . ':vote_status:late' + ]; + $buttons['done'] = [ + 'text' => $text_done, + 'callback_data' => $raid['id'] . ':vote_status:raid_done' + ]; + $buttons['cancel'] = [ + 'text' => $text_cancel, + 'callback_data' => $raid['id'] . ':vote_status:cancel' + ]; + + $buttons['refresh'] = []; + if(!$config->AUTO_REFRESH_POLLS) { + $buttons['refresh'] = [ + 'text' => EMOJI_REFRESH, + 'callback_data' => $raid['id'] . ':vote_refresh:0' + ]; + } + + if($raid['event_vote_key_mode'] == 1) { + $keys_time = [ + [ + 'text' => getPublicTranslation("Participate"), + 'callback_data' => $raid['id'] . ':vote_time:' . utctime($raid['start_time'], 'YmdHis') + ] + ]; + }else { + $RAID_SLOTS = ($raid['event_time_slots'] > 0) ? $raid['event_time_slots'] : $config->RAID_SLOTS; + $keys_time = generateTimeslotKeys($RAID_SLOTS, $raid); + } + // Add time keys. + $buttons['time'] = inline_key_array($keys_time, 4); + + // Hidden participants? + $hide_users_sql = ''; + if($config->RAID_POLL_HIDE_USERS_TIME > 0) { + if($config->RAID_ANYTIME) { + $hide_users_sql = 'AND (attend_time > (UTC_TIMESTAMP() - INTERVAL ' . $config->RAID_POLL_HIDE_USERS_TIME . ' MINUTE) OR attend_time = \''.ANYTIME.'\')'; } else { - // Get current pokemon - $raid_pokemon_id = $raid['pokemon']; - $raid_pokemon_form_id = $raid['pokemon_form']; - $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_id; - - // Get raid level - $raid_level = $raid['level']; - - // Are remote players allowed for this raid? - $raid_local_only = in_array($raid_level, RAID_LEVEL_LOCAL_ONLY); - - // Hide buttons for raid levels and pokemon - $hide_buttons_raid_level = explode(',', $config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL); - $hide_buttons_pokemon = explode(',', $config->RAID_POLL_HIDE_BUTTONS_POKEMON); - - // Show buttons to users? - if(in_array($raid_level, $hide_buttons_raid_level) || in_array(($raid_pokemon_id . "-" . get_pokemon_form_name($raid_pokemon_id,$raid_pokemon_form_id)), $hide_buttons_pokemon) || in_array($raid_pokemon_id, $hide_buttons_pokemon)) { - return []; - } else { - // Extra Keys - $buttons_alone = [ - 'text' => EMOJI_SINGLE, - 'callback_data' => $raid['id'] . ':vote_extra:0' - ]; - $buttons_extra = [ - 'text' => '+ ' . EMOJI_IN_PERSON, - 'callback_data' => $raid['id'] . ':vote_extra:in_person' - ]; - - // Show buttons regarding remote participation only if raid level allows it - if(!$raid_local_only) { - $buttons_extra_alien = [ - 'text' => '+ ' . EMOJI_ALIEN, - 'callback_data' => $raid['id'] . ':vote_extra:alien' - ]; - - // Can invite key - $buttons_can_inv = [ - 'text' => EMOJI_CAN_INVITE, - 'callback_data' => $raid['id'] . ':vote_can_invite:0' - ]; - - // Remote Raid Pass key - $buttons_remote = [ - 'text' => EMOJI_REMOTE, - 'callback_data' => $raid['id'] . ':vote_remote:0' - ]; - - // Want invite key - $buttons_inv_plz = [ - 'text' => EMOJI_WANT_INVITE, - 'callback_data' => $raid['id'] . ':vote_want_invite:0' - ]; - }else { - $buttons_extra_alien = $buttons_can_inv = $buttons_remote = $buttons_inv_plz = []; - } - - // Team and level keys. - $buttons_teamlvl = [ - [ - [ - 'text' => 'Team', - 'callback_data' => $raid['id'] . ':vote_team:0' - ], - [ - 'text' => 'Lvl +', - 'callback_data' => $raid['id'] . ':vote_level:up' - ], - [ - 'text' => 'Lvl -', - 'callback_data' => $raid['id'] . ':vote_level:down' - ] - ] - ]; - - // Ex-Raid Invite key - if ($raid['event'] == EVENT_ID_EX) { - $buttons_ex_inv = [ - 'text' => EMOJI_INVITE, - 'callback_data' => $raid['id'] . ':vote_invite:0' - ]; - }else { - $buttons_ex_inv = []; - } - - // Show icon, icon + text or just text. - // Icon. - if($config->RAID_VOTE_ICONS && !$config->RAID_VOTE_TEXT) { - $text_here = EMOJI_HERE; - $text_late = EMOJI_LATE; - $text_done = TEAM_DONE; - $text_cancel = TEAM_CANCEL; - // Icon + text. - } else if($config->RAID_VOTE_ICONS && $config->RAID_VOTE_TEXT) { - $text_here = EMOJI_HERE . getPublicTranslation('here'); - $text_late = EMOJI_LATE . getPublicTranslation('late'); - $text_done = TEAM_DONE . getPublicTranslation('done'); - $text_cancel = TEAM_CANCEL . getPublicTranslation('cancellation'); - // Text. - } else { - $text_here = getPublicTranslation('here'); - $text_late = getPublicTranslation('late'); - $text_done = getPublicTranslation('done'); - $text_cancel = getPublicTranslation('cancellation'); - } - - // Status keys. - $buttons_alarm = [ - 'text' => EMOJI_ALARM, - 'callback_data' => $raid['id'] . ':vote_status:alarm' - ]; - $buttons_here = [ - 'text' => $text_here, - 'callback_data' => $raid['id'] . ':vote_status:arrived' - ]; - $buttons_late = [ - 'text' => $text_late, - 'callback_data' => $raid['id'] . ':vote_status:late' - ]; - $buttons_done = [ - 'text' => $text_done, - 'callback_data' => $raid['id'] . ':vote_status:raid_done' - ]; - $buttons_cancel = [ - 'text' => $text_cancel, - 'callback_data' => $raid['id'] . ':vote_status:cancel' - ]; - - if(!$config->AUTO_REFRESH_POLLS) { - $buttons_refresh = [ - 'text' => EMOJI_REFRESH, - 'callback_data' => $raid['id'] . ':vote_refresh:0' - ]; - }else { - $buttons_refresh = []; - } - - if($raid['event_vote_key_mode'] == 1) { - $keys_time = [ - [ - 'text' => getPublicTranslation("Participate"), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($raid['start_time'], 'YmdHis') - ] - ]; - }else { - if($raid['event_time_slots'] > 0) { - $RAID_SLOTS = $raid['event_time_slots']; - }else { - $RAID_SLOTS = $config->RAID_SLOTS; - } - // Get current time. - $now_helper = new DateTimeImmutable('now', new DateTimeZone('UTC')); - $now_helper = $now_helper->format('Y-m-d H:i') . ':00'; - $dt_now = new DateTimeImmutable($now_helper, new DateTimeZone('UTC')); - - // Get direct start slot - $direct_slot = new DateTimeImmutable($start_time, new DateTimeZone('UTC')); - - // Get first raidslot rounded up to the next 5 minutes - // Get minute and convert modulo raidslot - $five_slot = new DateTimeImmutable($start_time, new DateTimeZone('UTC')); - $minute = $five_slot->format("i"); - $minute = $minute % 5; - - // Count minutes to next 5 multiple minutes if necessary - if($minute != 0) - { - // Count difference - $diff = 5 - $minute; - // Add difference - $five_slot = $five_slot->add(new DateInterval("PT".$diff."M")); - } - - // Add $config->RAID_FIRST_START minutes to five minutes slot - //$five_plus_slot = new DateTime($five_slot, new DateTimeZone('UTC')); - $five_plus_slot = $five_slot; - $five_plus_slot = $five_plus_slot->add(new DateInterval("PT".$config->RAID_FIRST_START."M")); - - // Get first regular raidslot - // Get minute and convert modulo raidslot - $first_slot = new DateTimeImmutable($start_time, new DateTimeZone('UTC')); - $minute = $first_slot->format("i"); - $minute = $minute % $config->RAID_SLOTS; - - // Count minutes to next raidslot multiple minutes if necessary - if($minute != 0) - { - // Count difference - $diff = $config->RAID_SLOTS - $minute; - // Add difference - $first_slot = $first_slot->add(new DateInterval("PT".$diff."M")); - } - - // Compare times slots to add them to keys. - // Example Scenarios: - // Raid 1: Start = 17:45, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 2: Start = 17:36, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 3: Start = 17:35, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 4: Start = 17:31, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 5: Start = 17:40, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 6: Start = 17:32, $config->RAID_FIRST_START = 5, $config->RAID_SLOTS = 5 - - // Write slots to log. - debug_log($direct_slot, 'Direct start slot:'); - debug_log($five_slot, 'Next 5 Minute slot:'); - debug_log($first_slot, 'First regular slot:'); - - // Add first slot only, as all slot times are identical - if($direct_slot == $five_slot && $direct_slot == $first_slot) { - // Raid 1: 17:45 (17:45 == 17:45 && 17:45 == 17:45) - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - // Add either five and first slot or only first slot based on RAID_FIRST_START - } else if($direct_slot == $five_slot && $five_slot < $first_slot) { - // Raid 3: 17:35 == 17:35 && 17:35 < 17:45 - // Raid 5: 17:40 == 17:40 && 17:40 < 17:45 - - // Add next five minutes slot and first regular slot - if($five_plus_slot <= $first_slot) { - // Raid 3: 17:35, 17:45 (17:35 + 10min <= 17:45) - - // Add five minutes slot - if($five_slot >= $dt_now) { - $slot = $five_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - // Add only first regular slot - } else { - // Raid 5: 17:45 - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Add direct slot and first slot - } else if($direct_slot < $five_slot && $five_slot == $first_slot) { - // Raid 6: 17:32 < 17:35 && 17:35 == 17:35 - // Some kind of special case for a low value of RAID_SLOTS - - // Add direct slot? - if($config->RAID_DIRECT_START) { - if($direct_slot >= $dt_now) { - $slot = $direct_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - - // Add either all 3 slots (direct slot, five minutes slot and first regular slot) or - // 2 slots (direct slot and first slot) as $config->RAID_FIRST_START does not allow the five minutes slot to be added - } else if($direct_slot < $five_slot && $five_slot < $first_slot) { - // Raid 2: 17:36 < 17:40 && 17:40 < 17:45 - // Raid 4: 17:31 < 17:35 && 17:35 < 17:45 - - // Add all 3 slots - if($five_plus_slot <= $first_slot) { - // Raid 4: 17:31, 17:35, 17:45 - - // Add direct slot? - if($config->RAID_DIRECT_START) { - if($direct_slot >= $dt_now) { - $slot = $direct_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Add five minutes slot - if($five_slot >= $dt_now) { - $slot = $five_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - // Add direct slot and first regular slot - } else { - // Raid 2: 17:36, 17:45 - - // Add direct slot? - if($config->RAID_DIRECT_START) { - if($direct_slot >= $dt_now) { - $slot = $direct_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // We missed all possible cases or forgot to include them in future else-if-clauses :D - // Try to add at least the direct slot. - } else { - // Add direct slot? - if($config->RAID_DIRECT_START) { - if($first_slot >= $dt_now) { - $slot = $direct_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - } - - - // Init last slot time. - $last_slot = new DateTimeImmutable($start_time, new DateTimeZone('UTC')); - - // Get regular slots - // Start with second slot as first slot is already added to keys. - $second_slot = $first_slot->add(new DateInterval("PT".$RAID_SLOTS."M")); - $dt_end = new DateTimeImmutable($end_time, new DateTimeZone('UTC')); - $regular_slots = new DatePeriod($second_slot, new DateInterval('PT'.$RAID_SLOTS.'M'), $dt_end); - - // Add regular slots. - foreach($regular_slots as $slot){ - $slot_end = $slot->add(new DateInterval('PT'.$config->RAID_LAST_START.'M')); - // Slot + $config->RAID_LAST_START before end_time? - if($slot_end < $dt_end) { - debug_log($slot, 'Regular slot:'); - // Add regular slot. - if($slot >= $dt_now) { - $slot = $slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - - // Set last slot for later. - $last_slot = new DateTimeImmutable($slot, new DateTimeZone('UTC')); - } else { - // Set last slot for later. - $slot = $slot->format('Y-m-d H:i:s'); - $last_slot = new DateTimeImmutable($slot, new DateTimeZone('UTC')); - } - } - } - - // Add raid last start slot - // Set end_time to last extra slot, subtract $config->RAID_LAST_START minutes and round down to earlier 5 minutes. - $last_extra_slot = $dt_end; - $last_extra_slot = $last_extra_slot->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')); - $s = 5 * 60; - $last_extra_slot = $last_extra_slot->setTimestamp($s * floor($last_extra_slot->getTimestamp() / $s)); - //$time_to_last_slot = $last_extra_slot->diff($last_slot)->format("%a"); - - // Last extra slot not conflicting with last slot and time to last regular slot larger than RAID_LAST_START? - //if($last_extra_slot > $last_slot && $time_to_last_slot > $config->RAID_LAST_START) - - // Log last and last extra slot. - debug_log($last_slot, 'Last slot:'); - debug_log($last_extra_slot, 'Last extra slot:'); - - // Last extra slot not conflicting with last slot - if($last_extra_slot > $last_slot) { - // Add last extra slot - if($last_extra_slot >= $dt_now) { - $slot = $last_extra_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Attend raid at any time - if($config->RAID_ANYTIME) - { - $keys_time[] = array( - 'text' => getPublicTranslation('anytime'), - 'callback_data' => $raid['id'] . ':vote_time:0' - ); - } - } - // Add time keys. - $buttons_time = inline_key_array($keys_time, 4); - - // Hidden participants? - if($config->RAID_POLL_HIDE_USERS_TIME > 0) { - if($config->RAID_ANYTIME) { - $hide_users_sql = "AND (attend_time > (UTC_TIMESTAMP() - INTERVAL " . $config->RAID_POLL_HIDE_USERS_TIME . " MINUTE) OR attend_time = '".ANYTIME."')"; - } else { - $hide_users_sql = "AND attend_time > (UTC_TIMESTAMP() - INTERVAL " . $config->RAID_POLL_HIDE_USERS_TIME . " MINUTE)"; - } - } else { - $hide_users_sql = ""; - } - - // Get participants - $rs = my_query( - " - SELECT count(attend_time) AS count, - sum(pokemon = '0') AS count_any_pokemon, - sum(pokemon = '{$raid_pokemon}') AS count_raid_pokemon - FROM attendance - WHERE raid_id = {$raid['id']} - $hide_users_sql - AND attend_time IS NOT NULL - AND raid_done != 1 - AND cancel != 1 - " - ); - - $row = $rs->fetch(); - - // Count participants and participants by pokemon - $count_pp = $row['count']; - $count_any_pokemon = $row['count_any_pokemon']; - $count_raid_pokemon = $row['count_raid_pokemon']; - - // Write to log. - debug_log('Participants for raid with ID ' . $raid['id'] . ': ' . $count_pp); - debug_log('Participants who voted for any pokemon: ' . $count_any_pokemon); - debug_log('Participants who voted for ' . $raid_pokemon . ': ' . $count_raid_pokemon); - - // Zero Participants? Show only time buttons! - if($count_pp == 0) { - $keys = $buttons_time; - } else { - // Init keys pokemon array. - $buttons_pokemon = []; - - // Show pokemon keys only if the raid boss is an egg - if(in_array($raid_pokemon_id, $GLOBALS['eggs'])) { - // Get pokemon from database - $raid_spawn = dt2time($raid['spawn'], 'Y-m-d H:i'); // Convert utc spawntime to local time - $raid_bosses = get_raid_bosses($raid_spawn, $raid_level); - - // Get eggs. - $eggs = $GLOBALS['eggs']; - - if(count($raid_bosses) > 2) { - // Add key for each raid level - foreach($raid_bosses as $pokemon) { - if(in_array($pokemon['pokedex_id'], $eggs)) continue; - $buttons_pokemon[] = array( - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), - 'callback_data' => $raid['id'] . ':vote_pokemon:' . $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] - ); - } - - // Add button if raid boss does not matter - $buttons_pokemon[] = array( - 'text' => getPublicTranslation('any_pokemon'), - 'callback_data' => $raid['id'] . ':vote_pokemon:0' - ); - - // Finally add pokemon to keys - $buttons_pokemon = inline_key_array($buttons_pokemon, 2); - } - } - - // Init keys array - $keys = []; - - if($raid['event_poll_template'] != null) $template = json_decode($raid['event_poll_template']); - else $template = $config->RAID_POLL_UI_TEMPLATE; - $r=0; - foreach($template as $row) { - foreach($row as $key) { - $v_name = 'buttons_'.$key; - if($key == 'teamlvl' or $key == 'pokemon' or $key == 'time') { - // Some button variables are "blocks" of keys, process them here - if(empty(${$v_name})) continue; - foreach(${$v_name} as $teamlvl) { - if(!isset($keys[$r])) $keys[$r] = []; - $keys[$r] = array_merge($keys[$r],$teamlvl); - $r++; - } - $r--; - }else { - if(empty(${$v_name})) continue; - $keys[$r][] = ${$v_name}; - } - } - if(!empty($keys[$r][0])) $r++; - } - } - - // Return the keys. - return $keys; + $hide_users_sql = 'AND attend_time > (UTC_TIMESTAMP() - INTERVAL ' . $config->RAID_POLL_HIDE_USERS_TIME . ' MINUTE)'; + } + } + + // Get participants + $rs = my_query( + ' + SELECT count(attend_time) AS count, + sum(pokemon = 0) AS count_any_pokemon, + sum(pokemon = ?) AS count_raid_pokemon + FROM attendance + WHERE raid_id = ? + ' . $hide_users_sql . ' + AND attend_time IS NOT NULL + AND raid_done != 1 + AND cancel != 1 + ', [$raid_pokemon, $raid['id']] + ); + + $row = $rs->fetch(); + + // Count participants and participants by pokemon + $count_pp = $row['count']; + $count_any_pokemon = $row['count_any_pokemon']; + $count_raid_pokemon = $row['count_raid_pokemon']; + + // Write to log. + debug_log('Participants for raid with ID ' . $raid['id'] . ': ' . $count_pp); + debug_log('Participants who voted for any pokemon: ' . $count_any_pokemon); + debug_log('Participants who voted for ' . $raid_pokemon . ': ' . $count_raid_pokemon); + + // Zero Participants? Show only time buttons! + if($row['count'] == 0) { + return $buttons['time']; + } + + // Init keys pokemon array. + $buttons['pokemon'] = []; + // Show pokemon keys only if the raid boss is an egg + if(in_array($raid_pokemon_id, $GLOBALS['eggs'])) { + // Get pokemon from database + $raid_spawn = dt2time($raid['spawn'], 'Y-m-d H:i'); // Convert utc spawntime to local time + $raid_bosses = get_raid_bosses($raid_spawn, $raid_level); + + if(count($raid_bosses) > 2) { + // Add key for each raid level + foreach($raid_bosses as $pokemon) { + if(in_array($pokemon['pokedex_id'], $GLOBALS['eggs'])) continue; + $buttons['pokemon'][] = array( + 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), + 'callback_data' => $raid['id'] . ':vote_pokemon:' . $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] + ); + } + + // Add button if raid boss does not matter + $buttons['pokemon'][] = array( + 'text' => getPublicTranslation('any_pokemon'), + 'callback_data' => $raid['id'] . ':vote_pokemon:0' + ); + + // Finally add pokemon to keys + $buttons['pokemon'] = inline_key_array($buttons['pokemon'], 2); + } + } + + // Init keys array + $keys = []; + + $template = $config->RAID_POLL_UI_TEMPLATE; + if($raid['event_poll_template'] != null) $template = json_decode($raid['event_poll_template']); + $r = 0; + foreach($template as $row) { + foreach($row as $key) { + $v_name = 'buttons_'.$key; + if(!isset($buttons[$key]) or empty($buttons[$key])) continue; + if($key == 'teamlvl' or $key == 'pokemon' or $key == 'time') { + // Some button variables are "blocks" of keys, process them here + foreach($buttons[$key] as $teamlvl) { + if(!isset($keys[$r])) $keys[$r] = []; + $keys[$r] = array_merge($keys[$r],$teamlvl); + $r++; } + $r--; + continue; + } + $keys[$r][] = $buttons[$key]; + } + if(!empty($keys[$r][0])) $r++; + } + + // Return the keys. + return $keys; +} + +/** + * Get active raid bosses at a certain time. + * @param $time - string, datetime, local time + * @param $raid_level - ENUM('1', '2', '3', '4', '5', '6', 'X') + * @return array + */ +function get_raid_bosses($time, $raid_level) +{ + // Get raid level from database + $rs = my_query( + ' + SELECT DISTINCT pokedex_id, pokemon_form_id + FROM raid_bosses + WHERE ? BETWEEN date_start AND date_end + AND raid_level = ? + ', [$time, $raid_level]); + debug_log('Checking active raid bosses for raid level '.$raid_level.' at '.$time.':'); + $raid_bosses = []; + $egg_found = false; + while ($result = $rs->fetch()) { + $raid_bosses[] = $result; + if($result['pokedex_id'] == '999'.$raid_level) $egg_found = true; + debug_log('Pokedex id: '.$result['pokedex_id'].' | Form id: '.$result['pokemon_form_id']); + } + if(!$egg_found) $raid_bosses[] = ['pokedex_id' => '999'.$raid_level, 'pokemon_form_id' => 0]; // Add egg if it wasn't found from db + return $raid_bosses; +} + +/** + * Get active raid bosses at a certain time. + * @param $RAID_SLOTS - int, length of the timeslot + * @param $raid + * @return array + */ +function generateTimeslotKeys($RAID_SLOTS, $raid) { + global $config; + // Get current time. + $now_helper = new DateTimeImmutable('now', new DateTimeZone('UTC')); + $now_helper = $now_helper->format('Y-m-d H:i') . ':00'; + $dt_now = new DateTimeImmutable($now_helper, new DateTimeZone('UTC')); + + // Get direct start slot + $direct_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); + $directStartMinutes = $direct_slot->format('i'); + + // Get first raidslot rounded up to the next 5 minutes + $five_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); + $minute = $directStartMinutes % 5; + $diff = ($minute != 0) ? 5 - $minute : 5; + $five_slot = $five_slot->add(new DateInterval('PT'.$diff.'M')); + + // Get first regular raidslot + $first_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); + $minute = $directStartMinutes % $RAID_SLOTS; + + // Count minutes to next raidslot multiple minutes if necessary + if($minute != 0) { + $diff = $RAID_SLOTS - $minute; + $first_slot = $first_slot->add(new DateInterval('PT'.$diff.'M')); + } + + // Write slots to log. + debug_log($direct_slot, 'Direct start slot:'); + debug_log($five_slot, 'Next 5 Minute slot:'); + debug_log($first_slot, 'First regular slot:'); + $keys_time = []; + // Add button for when raid starts time + if($config->RAID_DIRECT_START && $direct_slot >= $dt_now) { + $keys_time[] = array( + 'text' => dt2time($direct_slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $direct_slot->format('YmdHis') + ); + } + // Add five minutes slot + if($five_slot >= $dt_now && (empty($keys_time) || (!empty($keys_time) && $direct_slot != $five_slot))) { + $keys_time[] = array( + 'text' => dt2time($five_slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $five_slot->format('YmdHis') + ); + } + // Add the first normal slot + if($first_slot >= $dt_now && $first_slot != $five_slot) { + $keys_time[] = array( + 'text' => dt2time($first_slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $first_slot->format('YmdHis') + ); + } + + // Init last slot time. + $last_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); + + // Get regular slots + // Start with second slot as first slot is already added to keys. + $dt_end = new DateTimeImmutable($raid['end_time'], new DateTimeZone('UTC')); + $regular_slots = new DatePeriod($first_slot, new DateInterval('PT'.$RAID_SLOTS.'M'), $dt_end->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')), DatePeriod::EXCLUDE_START_DATE); + info_log($regular_slots); + // Add regular slots. + foreach($regular_slots as $slot){ + debug_log($slot, 'Regular slot:'); + // Add regular slot. + if($slot >= $dt_now) { + $keys_time[] = array( + 'text' => dt2time($slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $slot->format('YmdHis') + ); } + // Set last slot for later. + $last_slot = $slot; + } + + // Add raid last start slot + // Set end_time to last extra slot, subtract $config->RAID_LAST_START minutes and round down to earlier 5 minutes. + $last_extra_slot = $dt_end; + $last_extra_slot = $last_extra_slot->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')); + $s = 5 * 60; + $last_extra_slot = $last_extra_slot->setTimestamp($s * floor($last_extra_slot->getTimestamp() / $s)); + + // Log last and last extra slot. + debug_log($last_slot, 'Last slot:'); + debug_log($last_extra_slot, 'Last extra slot:'); + + // Last extra slot not conflicting with last slot + if($last_extra_slot > $last_slot && $last_extra_slot >= $dt_now) { + // Add last extra slot + $keys_time[] = array( + 'text' => dt2time($last_extra_slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $last_extra_slot->format('YmdHis') + ); + } + + // Attend raid at any time + if($config->RAID_ANYTIME) { + $keys_time[] = array( + 'text' => getPublicTranslation('anytime'), + 'callback_data' => $raid['id'] . ':vote_time:0' + ); + } + return $keys_time; } ?> From f4fa8ea3e89f6a91b0006ede5ea9b31e47840335 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 15:35:18 +0200 Subject: [PATCH 123/367] Forgot to remove this --- logic/keys_vote.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 8859f58f..8a68fe47 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -374,7 +374,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { // Start with second slot as first slot is already added to keys. $dt_end = new DateTimeImmutable($raid['end_time'], new DateTimeZone('UTC')); $regular_slots = new DatePeriod($first_slot, new DateInterval('PT'.$RAID_SLOTS.'M'), $dt_end->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')), DatePeriod::EXCLUDE_START_DATE); - info_log($regular_slots); + // Add regular slots. foreach($regular_slots as $slot){ debug_log($slot, 'Regular slot:'); From 588607f17e1ddc158f663cb9186a83644fe7f825 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 21:16:05 +0200 Subject: [PATCH 124/367] Fixed gym note deletion feature --- mods/gym_edit_details.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index ede761ea..9d107e3f 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -31,15 +31,9 @@ // Did we receive a call to edit some gym data that requires a text input if(in_array($action, ['name','note','gps','addr'])) { if($value == 'd') { - my_query("DELETE FROM user_input WHERE id=:delete_id'", ['delete_id' => $delete_id]); + my_query("DELETE FROM user_input WHERE id = ?", [$delete_id]); if($action == 'note') { - $query = 'UPDATE gyms SET gym_note = NULL WHERE id = :id'; - $binds = [ - ':id' => $gym_id, - ]; - // Update the event note to raid table - $prepare = $dbh->prepare($query); - $prepare->execute($binds); + my_query('UPDATE gyms SET gym_note = NULL WHERE id = ?', [$gym_id]); $gym['gym_note'] = ''; } $msg = get_gym_details($gym, true); @@ -61,7 +55,7 @@ 'text' => getTranslation("abort"), 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() ]; - if($action == 'note' && !empty($gym['note'])) { + if($action == 'note' && !empty($gym['gym_note'])) { $keys[0][] = [ 'text' => getTranslation("delete"), 'callback_data' => $gym_id.':gym_edit_details:note-d-'.$dbh->lastInsertId() From 952f5fa4628bedab83f49a46bd39e22d409b9c00 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 22:04:22 +0200 Subject: [PATCH 125/367] Only display each language once --- mods/bot_lang.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mods/bot_lang.php b/mods/bot_lang.php index d06bc214..020e6bce 100644 --- a/mods/bot_lang.php +++ b/mods/bot_lang.php @@ -38,11 +38,14 @@ ]; $callback_msg = $msg; } else { + $displayedLanguages = []; foreach($languages as $lang_tg => $lang_internal) { + if(in_array($lang_internal, $displayedLanguages)) continue; $keys[][] = [ 'text' => getTranslation('lang_name', $lang_internal), 'callback_data' => '0:bot_lang:'.$lang_tg ]; + $displayedLanguages[] = $lang_internal; } $keys[] = [ [ From 724d6c4ca267eb4b16109e5d9ebe8fa824455c9a Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 22:05:07 +0200 Subject: [PATCH 126/367] Added feature under `gym` for saving gym address from OSM/Google lookup --- lang/language.json | 39 ++++++++++++++++++++++++++++++++++ logic/get_gym_details.php | 36 +++++++++++++++++++------------- mods/gym_edit_details.php | 44 ++++++++++++++++++++++++++------------- 3 files changed, 89 insertions(+), 30 deletions(-) diff --git a/lang/language.json b/lang/language.json index 4b611e0d..dfbeb7e4 100644 --- a/lang/language.json +++ b/lang/language.json @@ -2898,6 +2898,19 @@ "FI": "salin osoite", "ES": "TRANSLATE" }, + "gym_stored_address": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Stored address", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tallennettu osoite", + "ES": "TRANSLATE" + }, "gym_address_instructions": { "NL": "Stuur me het nieuwe gym adres:", "DE": "TRANSLATE", @@ -2911,6 +2924,32 @@ "FI": "Lähetä minulle salin uusi osoite:", "ES": "TRANSLATE" }, + "gym_address_lookup_result": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Address lookup result", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Osoitehaun tulos", + "ES": "TRANSLATE" + }, + "gym_save_lookup_result": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Save lookup result", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tallenna osoitehaun tulos", + "ES": "TRANSLATE" + }, "select_raid_boss": { "NL": "Selecteer Raid baas", "DE": "Raid-Boss auswählen", diff --git a/logic/get_gym_details.php b/logic/get_gym_details.php index 19d0cd81..7833787a 100644 --- a/logic/get_gym_details.php +++ b/logic/get_gym_details.php @@ -10,27 +10,33 @@ function get_gym_details($gym, $extended = false) global $config; // Add gym name to message. $msg = '' . getTranslation('gym_details') . ':' . CR . CR; - $msg .= 'ID = ' . $gym['id'] . '' . CR; $msg .= getTranslation('gym') . ':' . SP; $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : '' . $config->RAID_EX_GYM_MARKER . ''; $msg .= ($gym['ex_gym'] ? $ex_raid_gym_marker . SP : '') . '' . $gym['gym_name'] . ''; $msg .= CR; + if($extended) $msg .= getTranslation('gym_stored_address') . CR; // Add maps link to message. - if (!empty($gym['address'])) { - $msg .= mapslink($gym) . CR; - } else { - // Get the address. - $addr = get_address($gym['lat'], $gym['lon']); - $address = format_address($addr); + $address = ''; + $lookupAddress = format_address(get_address($gym['lat'], $gym['lon'])); + if(!empty($gym['address'])) { + $address = $gym['address']; + } elseif(!$extended) { + $address = $lookupAddress; + } - //Only store address if not empty - if(!empty($address)) { - //Use new address - $msg .= mapslink($gym,$address) . CR; - } else { - //If no address is found show maps link - $msg .= mapslink($gym,'1') . CR; - } + //Only store address if not empty + if(!empty($address)) { + //Use new address + $msg .= mapslink($gym, $address) . CR; + } elseif(!$extended) { + //If no address is found show maps link + $msg .= mapslink($gym, '1') . CR; + }else { + $msg .= getTranslation('none') . CR; + } + if($extended) { + $msg .= getTranslation('gym_address_lookup_result') . ': ' . CR; + $msg .= mapslink($gym, $lookupAddress) . CR; } // Add or hide gym note. diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index 9d107e3f..01aa286b 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -31,20 +31,29 @@ // Did we receive a call to edit some gym data that requires a text input if(in_array($action, ['name','note','gps','addr'])) { if($value == 'd') { - my_query("DELETE FROM user_input WHERE id = ?", [$delete_id]); + my_query('DELETE FROM user_input WHERE id = :id', ['id' => $delete_id]); if($action == 'note') { - my_query('UPDATE gyms SET gym_note = NULL WHERE id = ?', [$gym_id]); + my_query('UPDATE gyms SET gym_note = NULL WHERE id = :id', ['id' => $gym_id]); $gym['gym_note'] = ''; } $msg = get_gym_details($gym, true); $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); + }elseif($value == 'e') { + my_query('DELETE FROM user_input WHERE id = ?', [$delete_id]); + if($action == 'addr') { + $addr = format_address(get_address($gym['lat'], $gym['lon'])); + my_query('UPDATE gyms SET address = :addr WHERE id = :id', ['addr' => $addr, 'id' => $gym_id]); + $gym['address'] = $addr; + } + $msg = get_gym_details($gym, true); + $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); }else { // Create an entry to user_input table $userid = $update['callback_query']['from']['id']; $modifiers = json_encode(array("id" => $gym_id, "value" => $action, "old_message_id" => $update['callback_query']['message']['message_id'])); $handler = "save_gym_info"; - my_query("INSERT INTO user_input SET user_id = :userid, modifiers = :modifiers, handler = :handler", [':userid' => $userid, ':modifiers' => $modifiers, ':handler' => $handler]); + my_query('INSERT INTO user_input SET user_id = :userid, modifiers = :modifiers, handler = :handler', [':userid' => $userid, ':modifiers' => $modifiers, ':handler' => $handler]); $msg = get_gym_details($gym, true); if($action == 'addr') $instructions = 'gym_address_instructions'; else $instructions = 'gym_'.$action.'_instructions'; @@ -52,34 +61,39 @@ if($action == 'gps') $msg .= CR. getTranslation('gym_gps_example'); $keys[0][] = [ - 'text' => getTranslation("abort"), - 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() - ]; + 'text' => getTranslation('abort'), + 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() + ]; if($action == 'note' && !empty($gym['gym_note'])) { $keys[0][] = [ - 'text' => getTranslation("delete"), + 'text' => getTranslation('delete'), 'callback_data' => $gym_id.':gym_edit_details:note-d-'.$dbh->lastInsertId() - ]; + ]; + } + if($action == 'addr') { + $keys[0][] = [ + 'text' => getTranslation('gym_save_lookup_result'), + 'callback_data' => $gym_id.':gym_edit_details:addr-e-'.$dbh->lastInsertId() + ]; } } }else { if($action == 'show') { - $gym['show_gym'] = $value; $table = 'show_gym'; }else if($action == 'ex') { - $gym['ex_gym'] = $value; $table = 'ex_gym'; }else if($action == 'abort') { - my_query("DELETE FROM user_input WHERE id = :value", ['value' => $value]); + my_query('DELETE FROM user_input WHERE id = :value', ['value' => $value]); } if(isset($table)) { my_query( - " + ' UPDATE gyms - SET $table = $value - WHERE id = {$gym_id} - " + SET ' . $table . ' = :value + WHERE id = :gym_id + ', ['value' => $value, 'gym_id' => $gym_id] ); + $gym[$table] = $value; } $msg = get_gym_details($gym, true); $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); From 7fb5f42adead3c11729b3b73000e086500fa884e Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 17 Nov 2022 23:39:59 +0200 Subject: [PATCH 127/367] Added `events` command Simple Telegram UI for managing the settings in `events`-table in database. This feature probably sees so little use it's not worth making translations and explanations for the values --- commands/events.php | 43 +++++++++ commands/help.php | 2 + docs/config.rst | 6 ++ docs/usage.rst | 5 ++ lang/help.json | 14 +++ lang/language.json | 143 +++++++++++++++++++++++++++++ mods/events.php | 52 +++++++++++ mods/events_add.php | 72 +++++++++++++++ mods/events_manage.php | 200 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 537 insertions(+) create mode 100644 commands/events.php create mode 100644 mods/events.php create mode 100644 mods/events_add.php create mode 100644 mods/events_manage.php diff --git a/commands/events.php b/commands/events.php new file mode 100644 index 00000000..db1d5281 --- /dev/null +++ b/commands/events.php @@ -0,0 +1,43 @@ +accessCheck($update, 'event-manage'); + +$q = my_query('SELECT * FROM events'); + +$msg = '' . getTranslation('events_manage') . '' . CR; + +foreach($q->fetchAll() as $event) { + if($event['id'] == EVENT_ID_EX) $event['name'] = getTranslation('Xstars'); + if(empty($event['description'])) $event['description'] = '' . getTranslation('events_no_description') . ''; + $msg .= '' . $event['name'] . '' . CR; + $msg .= $event['description'] . CR . CR; +} + +$keys = []; +$keys[] = [ + [ + 'text' => getTranslation('events_manage'), + 'callback_data' => '0:events:0', + ] +]; +$keys[] = [ + [ + 'text' => getTranslation('events_create'), + 'callback_data' => '0:events_add:0', + ] +]; +$keys[] = [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1', + ] +]; +// Send message. +send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/help.php b/commands/help.php index 3204789b..f6fb1f4a 100644 --- a/commands/help.php +++ b/commands/help.php @@ -23,6 +23,8 @@ $permissions[] = 'config-get'; $permissions[] = 'config-set'; $permissions[] = 'pokedex'; + $permissions[] = 'history'; + $permissions[] = 'event-manage'; $permissions[] = 'help'; } else { // Get permissions. diff --git a/docs/config.rst b/docs/config.rst index cb088122..e3ff436a 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -745,6 +745,12 @@ A few examples for access files can be found below the permission overview table * - - - + * - Events + - Show help ``/events`` + - ``event-manage`` + * - + - + - * - Tutorial - Allow users to access tutorial - ``tutorial`` diff --git a/docs/usage.rst b/docs/usage.rst index d8ad110e..6cd017c7 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -276,6 +276,11 @@ Command: /history Tool for admins to view history of raids that had at least one person signed up for it. +Command: /events +^^^^^^^^^^^^^^^^ + +Tool for admins to edit raid events. The UI is very simple and for some stuff you need to refer to this documentation. + Command: /gym ^^^^^^^^^^^^^ diff --git a/lang/help.json b/lang/help.json index c5466870..3485edf9 100644 --- a/lang/help.json +++ b/lang/help.json @@ -310,5 +310,19 @@ "PL": "TRANSLATE", "FI": "/history - Listaa päättyneet raidit joissa oli osallistujia", "ES": "TRANSLATE" + }, + "help_event-manage": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "/events - Manage raid events", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "/events - Hallitse raiditapahtumia", + "ES": "TRANSLATE" } + } diff --git a/lang/language.json b/lang/language.json index dfbeb7e4..abc17c92 100644 --- a/lang/language.json +++ b/lang/language.json @@ -4562,6 +4562,149 @@ "FI": "Lisää ilmoituskohtaisia lisätietoja tapahtumaan liittyen. (esim. reitti)", "ES": "Agrega más información para este anuncio específico sobre el evento. (por ejemplo: ruta)" }, + "events_manage": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Manage events", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Hallitse tapahtumia", + "ES": "TRANSLATE" + }, + "events_create": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Create a new event", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Luo uusi tapahtuma", + "ES": "TRANSLATE" + }, + "events_created": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Event created succesfully!", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tapahtuma luotu onnistuneesti!", + "ES": "TRANSLATE" + }, + "events_give_name": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Give the event a name", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Anna tapahtuman nimi", + "ES": "TRANSLATE" + }, + "events_give_description": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Give the event a description", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Anna tapahtuman lisätiedot", + "ES": "TRANSLATE" + }, + "events_no_description": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "No description", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Ei kuvausta", + "ES": "TRANSLATE" + }, + "events_edit_name": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Edit event name", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Muokkaa tapahtuman nimeä", + "ES": "TRANSLATE" + }, + "events_edit_description": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Edit event description", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Muokkaa tapahtuman kuvausta", + "ES": "TRANSLATE" + }, + "events_edit_raid_poll": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Edit event raid poll", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Muokkaa tapahtuman raidi-ilmoitusta", + "ES": "TRANSLATE" + }, + "events_delete": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Delete event", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Poista tapahtuma", + "ES": "TRANSLATE" + }, + "events_delete_confirmation": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Do you really want to delete this event?", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Haluatko varmasti poistaa tämän tapahtuman?", + "ES": "TRANSLATE" + }, "Participate": { "NL": "Deelnemer", "DE": "Teilnehmen", diff --git a/mods/events.php b/mods/events.php new file mode 100644 index 00000000..39ffcf90 --- /dev/null +++ b/mods/events.php @@ -0,0 +1,52 @@ +accessCheck($update, 'event-manage'); + +$id = $data['id']; +$arg = $data['arg']; + +$keys = []; +$callback_response = 'OK'; + +// Manage events +$q = my_query('SELECT * FROM events'); +$msg = '' . getTranslation('events_manage') . '' . CR; +foreach($q->fetchAll() as $event) { + if($event['id'] == EVENT_ID_EX) $event['name'] = getTranslation('Xstars'); + if(empty($event['description'])) $event['description'] = '' . getTranslation('events_no_description') . ''; + $msg .= '' . $event['name'] . '' . CR; + $msg .= $event['description'] . CR . CR; + $keys[] = [ + [ + 'text' => $event['name'], + 'callback_data' => $event['id'] . ':events_manage:0', + ] + ]; +} +$keys[] = [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1', + ] +]; + +$tg_json = []; + +// Answer callback. +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + +// Edit the message. +$tg_json[] = edit_message($update, $msg, $keys, false, true); + +// Telegram multicurl request. +curl_json_multi_request($tg_json); + +// Exit. +exit(); diff --git a/mods/events_add.php b/mods/events_add.php new file mode 100644 index 00000000..567fe5ee --- /dev/null +++ b/mods/events_add.php @@ -0,0 +1,72 @@ +accessCheck($update, 'event-manage'); + +$keys = []; +$callback_response = 'OK'; +$userId = $update['callback_query']['from']['id'] ?? $update['message']['from']['id']; + +if(isset($modifiers)) { + $value = htmlspecialchars(trim($update['message']['text'])); + my_query('INSERT INTO events SET name=?',[$value]); + $eventId = $dbh->lastInsertId(); + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + $callback_response = getTranslation('done'); + editMessageText($modifiers['old_message_id'], getTranslation('events_created'), [], $userId); + $msg = '' . getTranslation('events_created') . '' . CR; + $msg .= $value; + $keys[] = [ + [ + 'text' => getTranslation('next'), + 'callback_data' => $eventId . ':events_manage:0', + ] + ]; +}else { + if($data['arg'] == 0) { + // Add a new event + $msg = '' . getTranslation('events_create') . '' . CR; + $msg .= getTranslation('events_give_name') . ':'; + + $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id']]); + $userId = $update['callback_query']['from']['id']; + + // Data for handling response from the user + my_query('INSERT INTO user_input SET user_id=?, handler=\'events_add\', modifiers=?', [$userId, $modifiers]); + + $keys[] = [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:events_add:a', + ] + ]; + }elseif($data['arg'] == 'a') { + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + answerCallbackQuery($update['callback_query']['id'], 'OK'); + editMessageText($update['callback_query']['message']['message_id'], getTranslation('action_aborted'), [], $userId); + exit; + } +} + +$tg_json = []; + +if(isset($update['callback_query'])) { + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + // Edit the message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); +}else { + $tg_json[] = send_message($update['message']['chat']['id'], $msg, $keys, false, true); +} + +// Telegram multicurl request. +curl_json_multi_request($tg_json); + +// Exit. +exit(); diff --git a/mods/events_manage.php b/mods/events_manage.php new file mode 100644 index 00000000..932b1918 --- /dev/null +++ b/mods/events_manage.php @@ -0,0 +1,200 @@ +accessCheck($update, 'event-manage'); + +$columnSettings = [ + 'vote_key_mode' => ['allowed' => [0,1], 'default' => 0, 'nullable' => false], + 'hide_raid_picture' => ['allowed' => [0,1], 'default' => 0, 'nullable' => false], + 'pokemon_title' => ['allowed' => [0,1,2], 'default' => 1, 'nullable' => false], + 'time_slots' => ['nullable' => true], + 'raid_duration' => ['nullable' => false], + 'poll_template' => ['nullable' => true], +]; + +$eventId = $data['id'] ?? false; +$arg = $data['arg'] ?? false; +$subArg = ($arg !== false) ? explode('-', $arg) : []; +$keys = []; +$callback_response = 'OK'; +$userId = $update['callback_query']['from']['id'] ?? $update['message']['from']['id']; + +// Process user input +if(isset($modifiers) && isset($modifiers['action'])) { + $value = htmlspecialchars(trim($update['message']['text'])); + if($modifiers['action'] == 1) { + // User input is new event name + $column = 'name'; + $arg = 0; + }else if($modifiers['action'] == 2) { + // User input is new description + $column = 'description'; + $arg = 0; + }else if($modifiers['action'] == 3) { + // User input is raid poll settings + $column = $modifiers['column']; + // Validate input + if($columnSettings[$column]['nullable'] && strtolower($value) == 'null') { + $value = NULL; + } + if(in_array($column, ['vote_key_mode','time_slots','raid_duration','hide_raid_picture','pokemon_title']) && $value != NULL) { + $value = preg_replace('/\D/', '', $value); + if(isset($columnSettings[$column]['allowed']) && !in_array($value, $columnSettings[$column]['allowed'])) $value = $columnSettings[$column]['default']; + }elseif($column == 'poll_template' && $value != NULL) { + $rows = preg_split("/\r\n|\n|\r/", $value); + $inputArray = []; + $i = 0; + // Convert input into json array + foreach($rows as $row) { + $buttons = explode(',', $row); + foreach($buttons as $button) { + $button = trim($button); + if(in_array($button, ['alone', 'extra', 'extra_alien', 'remote', 'inv_plz', 'can_inv', 'ex_inv', 'teamlvl', 'time', 'pokemon', 'refresh', 'alarm', 'here', 'late', 'done', 'cancel'])) { + $inputArray[$i][] = $button; + } + } + $i++; + } + $value = (strtolower($value) == 'null' ? NULL : json_encode($inputArray)); + } + $arg = 3; + } + $eventId = $modifiers['eventId']; + my_query('UPDATE events SET ' . $column . ' = ? WHERE id=?', [$value, $eventId]); + $callback_response = getTranslation('done'); + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + editMessageText($modifiers['old_message_id'], getTranslation('updated'), [], $userId); +} + +$q = my_query('SELECT * FROM events where id = ?', [$eventId]); +$event = $q->fetch(); +if($eventId == EVENT_ID_EX) { + $event['name'] = getTranslation('Xstars'); +} +if(empty($event['description'])) $event['description'] = '' . getTranslation('events_no_description') . ''; + +$msg = '' . getTranslation('events_manage') . '' . CR . CR; +$msg .= '' . $event['name'] . '' . CR; +$msg .= $event['description'] . CR . CR; + +if($arg == 0 || $arg == 'a') { + if($arg == 'a') { + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + $callback_response = getTranslation('action_aborted'); + } + if($eventId != EVENT_ID_EX) + $keys = universal_key($keys, $eventId, 'events_manage', '1', getTranslation('events_edit_name')); + $keys = universal_key($keys, $eventId, 'events_manage', '2', getTranslation('events_edit_description')); + $keys = universal_key($keys, $eventId, 'events_manage', '3', getTranslation('events_edit_raid_poll')); + if($eventId != EVENT_ID_EX) + $keys = universal_key($keys, $eventId, 'events_manage', '4', getTranslation('events_delete')); + + $keys[] = [ + universal_inner_key($keys, '0', 'events', '0', getTranslation('back')), + universal_inner_key($keys, '0', 'exit', '0', getTranslation('done')) + ]; + +// Edit event name +}else if($arg == 1) { + $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id'],'action'=>1,'eventId'=>$eventId]); + my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); + + $msg .= '' . getTranslation('events_edit_name') . '' . CR; + $msg .= getTranslation('events_give_name') . ':' . CR; + $keys = universal_key($keys, $eventId, 'events_manage', 'a', getTranslation('abort')); + +// Edit event description +}else if($arg == 2) { + $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id'],'action'=>2,'eventId'=>$eventId]); + my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); + $msg .= '' . getTranslation('events_edit_description') . '' . CR; + $msg .= getTranslation('events_give_description') . ':'; + $keys = universal_key($keys, $eventId, 'events_manage', 'a', getTranslation('abort')); + +// Edt event raid poll settings +}else if($arg == 3) { + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + $templateArray = ($event['poll_template'] == NULL) ? $config->RAID_POLL_UI_TEMPLATE : json_decode($event['poll_template'], true); + $event['poll_template'] = templateJsonToString($templateArray); + $printColumns = ['vote_key_mode','time_slots','raid_duration','hide_raid_picture','pokemon_title','poll_template']; + + $msg .= 'https://pokemonraidbot.readthedocs.io/en/latest/config.html#event-raids' . CR; + $msg .= 'https://pokemonraidbot.readthedocs.io/en/latest/config.html#raid-poll-design-and-layout' . CR . CR; + foreach($printColumns as $column) { + $msg .= $column . ': '; + $msg .= ($column == 'poll_template' ? CR : ''); + $msg .= '' . ($event[$column] === NULL ? 'NULL' : $event[$column]) . '' . CR; + $keys = universal_key($keys, $eventId, 'events_manage', 'e-'.$column, $column); + } + $keys[] = [ + universal_inner_key($keys, $eventId, 'events_manage', '0', getTranslation('back')), + universal_inner_key($keys, '0', 'exit', '1', getTranslation('done')) + ]; + +// Delete event confirmation +}else if($arg == 4) { + $msg .= '' . getTranslation('events_delete_confirmation') . '' . CR; + $keys[] = [ + universal_inner_key($keys, $eventId, 'events_manage', 'd', getTranslation('yes')), + universal_inner_key($keys, $eventId, 'events_manage', '0', getTranslation('no')) + ]; + +// Delete event +}else if($arg == 'd') { + if($eventId != EVENT_ID_EX) my_query('DELETE FROM events WHERE id=?', [$eventId]); + $data['id'] = $data['arg'] = 0; + include(ROOT_PATH . '/mods/events.php'); + exit; + +// Prompt for raid poll value editing +}else if($subArg[0] == 'e') { + $valueToEdit = $subArg[1]; + $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id'],'action'=>3,'column'=>$valueToEdit,'eventId'=>$eventId]); + my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); + + if($valueToEdit == 'poll_template') { + $templateArray = ($event['poll_template'] == NULL) ? $config->RAID_POLL_UI_TEMPLATE : json_decode($event['poll_template'], true); + $event['poll_template'] = templateJsonToString($templateArray); + } + + $msg .= $valueToEdit . CR; + $msg .= getTranslation('old_value') . CR; + $msg .= '' . ($event[$valueToEdit] === NULL ? 'NULL' : $event[$valueToEdit]) . '' . CR . CR; + $msg .= getTranslation('new_value'); + $keys = universal_key($keys, $eventId, 'events_manage', '3', getTranslation('back')); + +} + +$tg_json = []; + +if(isset($update['callback_query'])) { + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + // Edit the message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); +}else { + $tg_json[] = send_message($update['message']['chat']['id'], $msg, $keys, false, true); +} + +// Telegram multicurl request. +curl_json_multi_request($tg_json); + +function templateJsonToString($templateArray) { + $templateString = ''; + foreach($templateArray as $line) { + foreach($line as $button) { + $templateString .= $button; + $templateString .= ','; + } + $templateString = rtrim($templateString, ',') . CR; + } + return $templateString; +} +// Exit. +exit(); From 2c04732df67f20d6efa87e88f38bb8ff5755dc69 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 18 Nov 2022 20:01:51 +0200 Subject: [PATCH 128/367] Time vote key fixes --- logic/keys_vote.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 8a68fe47..58684919 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -332,11 +332,11 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { // Get first regular raidslot $first_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); - $minute = $directStartMinutes % $RAID_SLOTS; + $first_minute = $directStartMinutes % $RAID_SLOTS; // Count minutes to next raidslot multiple minutes if necessary - if($minute != 0) { - $diff = $RAID_SLOTS - $minute; + if($first_minute != 0) { + $diff = $RAID_SLOTS - $first_minute; $first_slot = $first_slot->add(new DateInterval('PT'.$diff.'M')); } @@ -346,21 +346,21 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { debug_log($first_slot, 'First regular slot:'); $keys_time = []; // Add button for when raid starts time - if($config->RAID_DIRECT_START && $direct_slot >= $dt_now) { + if(($config->RAID_DIRECT_START or $first_minute == 0) && $direct_slot >= $dt_now) { $keys_time[] = array( 'text' => dt2time($direct_slot->format('Y-m-d H:i:s')), 'callback_data' => $raid['id'] . ':vote_time:' . $direct_slot->format('YmdHis') ); } // Add five minutes slot - if($five_slot >= $dt_now && (empty($keys_time) || (!empty($keys_time) && $direct_slot != $five_slot))) { + if($five_slot >= $dt_now && ($five_slot < $first_slot || $five_slot == $first_slot)) { $keys_time[] = array( 'text' => dt2time($five_slot->format('Y-m-d H:i:s')), 'callback_data' => $raid['id'] . ':vote_time:' . $five_slot->format('YmdHis') ); } // Add the first normal slot - if($first_slot >= $dt_now && $first_slot != $five_slot) { + if($first_slot >= $dt_now && $first_slot > $five_slot && $first_slot > $direct_slot) { $keys_time[] = array( 'text' => dt2time($first_slot->format('Y-m-d H:i:s')), 'callback_data' => $raid['id'] . ':vote_time:' . $first_slot->format('YmdHis') From b397274ce9ccf0b6717498fc878f3cfb55298043 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 10 Nov 2022 13:01:39 +0200 Subject: [PATCH 129/367] Fixed new user logic --- core/bot/user.php | 2 +- logic/new_user.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/bot/user.php b/core/bot/user.php index 09f485fd..13e82a5c 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -151,7 +151,7 @@ public function privilegeCheck($update) { public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { if(in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { // If a config file matching users status was found, check if tutorial is forced - if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED')) { + if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) && $this->userPrivileges['grantedBy'] !== 'BOT_ADMINS' && $this->userPrivileges['grantedBy'] !== 'NOT_RESTRICTED')) { return false; } return true; diff --git a/logic/new_user.php b/logic/new_user.php index b42867ab..e1b33289 100644 --- a/logic/new_user.php +++ b/logic/new_user.php @@ -6,7 +6,7 @@ */ function new_user($user_id) { global $config; - if(!$config->TUTORIAL_MODE || user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; + if($config->TUTORIAL_MODE && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; else return false; } ?> \ No newline at end of file From e3fd064181e1eb0cdfd94ecb73b0d35959c489bf Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 10 Nov 2022 18:00:03 +0200 Subject: [PATCH 130/367] Map telegram roles to correct access files --- core/bot/user.php | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/core/bot/user.php b/core/bot/user.php index 13e82a5c..ef41bcda 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -43,7 +43,14 @@ public function privilegeCheck($update) { } } - $telegramRoles = ['creator', 'admins', 'members', 'restricted', 'kicked']; + // Map telegram roles to access file names + $telegramRoles = [ + 'creator' => 'creator', + 'administrator' => 'admins', + 'member' => 'members', + 'restricted' => 'restricted', + 'kicked' => 'kicked', + ]; // If user specific permissions are found, use them instead of group based if (is_file(ACCESS_PATH . '/access' . $user_id)) { @@ -52,7 +59,7 @@ public function privilegeCheck($update) { $chatIds = []; $rolesToCheck = $telegramRoles; $rolesToCheck[] = 'access'; - foreach($rolesToCheck as $roleToCheck) { + foreach($rolesToCheck as $tgRole => $roleToCheck) { $chatFiles = str_replace(ACCESS_PATH . '/' . $roleToCheck, '', glob(ACCESS_PATH . '/' . $roleToCheck . '-*')); $chatIds = array_merge($chatIds, $chatFiles); } @@ -87,22 +94,24 @@ public function privilegeCheck($update) { // Get access file based on user status/role. debug_log('Role of user ' . $chatObj['result']['user']['id'] . ' : ' . $chatObj['result']['status']); - if(in_array($chatObj['result']['status'], $telegramRoles) && is_file(ACCESS_PATH . '/' . $chatObj['result']['status'] . $chatId)) { - $privilegeList = file(ACCESS_PATH . '/' . $chatObj['result']['status'] . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $accessFile = $chatObj['result']['status'] . $chatId; + $userStatus = $chatObj['result']['status']; + + if(array_key_exists($userStatus, $telegramRoles) && is_file(ACCESS_PATH . '/' . $telegramRoles[$userStatus] . $chatId)) { + $privilegeList = file(ACCESS_PATH . '/' . $telegramRoles[$userStatus] . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $accessFile = $userStatus . $chatId; // Any other user status/role except "left" - } else if($chatObj['result']['status'] != 'left' && is_file(ACCESS_PATH . '/access' . $chatId)) { + } else if($userStatus != 'left' && is_file(ACCESS_PATH . '/access' . $chatId)) { $privilegeList = file(ACCESS_PATH . '/access' . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $accessFile = 'access' . $chatId; // Ignore "Restricted"? - if($chatObj['result']['status'] == 'restricted' && in_array('ignore-restricted', $privilegeList)) { + if($userStatus == 'restricted' && in_array('ignore-restricted', $privilegeList)) { $privilegeList = NULL; } // Ignore "kicked"? - if($chatObj['result']['status'] == 'kicked' && in_array('ignore-kicked', $privilegeList)) { + if($userStatus == 'kicked' && in_array('ignore-kicked', $privilegeList)) { $privilegeList = NULL; } } else { From 28bb86679381925630ea576c99e2587d4447d735 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:11:30 +0200 Subject: [PATCH 131/367] Added `/history` to help --- lang/help.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lang/help.json b/lang/help.json index 58a1ecac..c5466870 100644 --- a/lang/help.json +++ b/lang/help.json @@ -297,5 +297,18 @@ "PL": "TRANSLATE", "FI": "/help - Näytä ohjeet", "ES": "/help - Ver ayuda" + }, + "help_history": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "/history - View history of raids that had attendees", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "/history - Listaa päättyneet raidit joissa oli osallistujia", + "ES": "TRANSLATE" } } From a1b2da96be0466e8dcd023b826410f5576bcbc48 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 18:16:47 +0200 Subject: [PATCH 132/367] Fixed updating raid pokemon manually --- mods/raid_set_poke.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/raid_set_poke.php b/mods/raid_set_poke.php index d2c9a170..ea3b864f 100644 --- a/mods/raid_set_poke.php +++ b/mods/raid_set_poke.php @@ -49,7 +49,7 @@ // Update the shared raid polls. require_once(LOGIC_PATH .'/update_raid_poll.php'); -$tg_json = update_raid_poll($id, $raid, false, $tg_json, true); +$tg_json = update_raid_poll($raidId, $raid, false, $tg_json, true); // Alert users. $tg_json = alarm($raid, $update['callback_query']['from']['id'], 'new_boss', '', $tg_json); From 0d257b6725eb897c00aa8ed7ec406af74e0b5a15 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 19:12:51 +0200 Subject: [PATCH 133/367] Cosmetic changes to `list` and fixed `listall` permission that didn't previously do anything --- commands/list.php | 153 ++++++++++++++++++++++--------------------- commands/listall.php | 2 +- 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/commands/list.php b/commands/list.php index ef9f6510..308d302b 100644 --- a/commands/list.php +++ b/commands/list.php @@ -10,25 +10,30 @@ // Check access. $botUser->accessCheck($update, 'list'); -// Init text and keys. -$text = ''; -$keys = []; - -$event_permissions = $botUser->accessCheck($update, 'event',true); +$event_sql = 'event IS NULL'; +if($botUser->accessCheck($update, 'ex-raids', true)) { + if($botUser->accessCheck($update, 'event-raids', true)) + $event_sql = ''; + else + $event_sql .= ' OR event = ' . EVENT_ID_EX; +}elseif($botUser->accessCheck($update, 'event-raids', true)) { + $event_sql = 'event != ' . EVENT_ID_EX .' OR event IS NULL'; +} // Get last 12 active raids data. $rs = my_query( ' - SELECT raids.pokemon, raids.pokemon_form, raids.id, raids.user_id, raids.spawn, raids.start_time, raids.end_time, raids.gym_team, raids.gym_id, raids.level, raids.move1, raids.move2, raids.gender, raids.event, raids.event_note, - gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, gyms.gym_note, - start_time, end_time, - TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left, - (SELECT COUNT(*) FROM raids WHERE end_time>UTC_TIMESTAMP()) AS r_active + SELECT raids.pokemon, raids.pokemon_form, raids.id, raids.spawn, raids.start_time, raids.end_time, raids.level, raids.event, + gyms.gym_name, gyms.ex_gym, + events.name as event_name, + (SELECT COUNT(*) FROM raids WHERE end_time>UTC_TIMESTAMP() ' . ($event_sql == '' ? '' : 'AND ('.$event_sql.')') . ') as r_active FROM raids LEFT JOIN gyms ON raids.gym_id = gyms.id + LEFT JOIN events + ON events.id = raids.event WHERE end_time>UTC_TIMESTAMP() - ' . ($event_permissions ? '' : 'AND event IS NULL' ) . ' + ' . ($event_sql == '' ? '' : 'AND ('.$event_sql.')') . ' ORDER BY end_time ASC LIMIT 12 ' @@ -40,72 +45,70 @@ debug_log($raids); // Did we get any raids? -if(isset($raids[0]['r_active'])) { - debug_log($raids[0]['r_active'], 'Active raids:'); - - // More raids as we like? - if($raids[0]['r_active'] > 12) { - // Forward to /listall - debug_log('Too much raids, forwarding to /listall'); - $skip_access = true; - include_once(ROOT_PATH . '/commands/listall.php'); - exit(); - - // Just enough raids to display at once - } else { - //while ($raid = $rs->fetch()) { - foreach($raids as $raid) { - // Set text and keys. - $gym_name = $raid['gym_name']; - if(empty($gym_name)) { - $gym_name = ''; - } - $resolved_boss = resolve_raid_boss($raid['pokemon'], $raid['pokemon_form'], $raid['spawn'], $raid['level']); - - $text .= $gym_name . CR; - $raid_day = dt2date($raid['start_time']); - $now = utcnow(); - $today = dt2date($now); - $start = dt2time($raid['start_time']); - $end = dt2time($raid['end_time']); - $text .= get_local_pokemon_name($resolved_boss['pokedex_id'], $resolved_boss['pokemon_form_id']) . SP . '-' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; - - // Pokemon is an egg? - $eggs = $GLOBALS['eggs']; - if(in_array($resolved_boss['pokedex_id'], $eggs)) { - $keys_text = EMOJI_EGG . SP . $gym_name; - } else { - $keys_text = $gym_name; - } - - $keys[] = array( - 'text' => $keys_text, - 'callback_data' => $raid['id'] . ':raids_list:0' - ); - } - - // Get the inline key array. - $keys = inline_key_array($keys, 1); - - // Add exit key. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - - // Build message. - $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; - $msg .= $text; - $msg .= '' . getTranslation('select_gym_name') . '' . CR; - } - -// No active raids -} else { - $msg = '' . getTranslation('no_active_raids_found') . ''; +if($raids[0]['r_active'] == 0) { + $msg = '' . getTranslation('no_active_raids_found') . ''; + send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + exit(); +} + +debug_log($raids[0]['r_active'], 'Active raids:'); +// More raids as we like? +if($raids[0]['r_active'] > 12 && $botUser->accessCheck($update, 'listall', true)) { + // Forward to /listall + debug_log('Too much raids, forwarding to /listall'); + $skip_access = true; + include_once(ROOT_PATH . '/commands/listall.php'); + exit(); } +// Just enough raids to display at once +$text = ''; +foreach($raids as $raid) { + // Set text and keys. + $gym_name = $raid['gym_name']; + if(empty($gym_name)) { + $gym_name = ''; + } + $resolved_boss = resolve_raid_boss($raid['pokemon'], $raid['pokemon_form'], $raid['spawn'], $raid['level']); + + $text .= ($raid['ex_gym'] === 1 ? EMOJI_STAR . SP : '') . $gym_name . CR; + $raid_day = dt2date($raid['start_time']); + $now = utcnow(); + $today = dt2date($now); + $start = dt2time($raid['start_time']); + $end = dt2time($raid['end_time']); + $text .= (!empty($raid['event_name']) ? $raid['event_name'] . CR : '' ); + $text .= get_local_pokemon_name($resolved_boss['pokedex_id'], $resolved_boss['pokemon_form_id']) . SP . '-' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; + + // Pokemon is an egg? + $keys_text = ''; + if(in_array($resolved_boss['pokedex_id'], $GLOBALS['eggs'])) { + $keys_text = EMOJI_EGG . SP; + } + $keys_text .= ($raid['ex_gym'] === 1 ? EMOJI_STAR . SP : '') . $gym_name; + + $keys[] = array( + 'text' => $keys_text, + 'callback_data' => $raid['id'] . ':raids_list:0' + ); +} + +// Get the inline key array. +$keys = inline_key_array($keys, 1); + +// Add exit key. +$keys[] = [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] +]; + +// Build message. +$msg = '' . getTranslation('list_all_active_raids') . ':' . CR; +$msg .= $text; +$msg .= '' . getTranslation('select_gym_name') . '' . CR; + // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); ?> diff --git a/commands/listall.php b/commands/listall.php index 37553e88..35f8f95b 100644 --- a/commands/listall.php +++ b/commands/listall.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -if(!isset($skip_access) or $skip_access != true) $botUser->accessCheck($update, 'list'); +if(!isset($skip_access) or $skip_access != true) $botUser->accessCheck($update, 'listall'); // Set keys. $keys_and_gymarea = raid_edit_gyms_first_letter_keys('list_by_gym', false, false, 'listall', 'list_raid'); From e9d70be250fe4ebf9300e5a9f8f801cbc2c324b8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 19:39:55 +0200 Subject: [PATCH 134/367] Fixed access rights and menus for ex raid creation --- logic/keys_event.php | 30 ++++++++++++++++++------------ logic/raid_edit_raidlevel_keys.php | 5 +++-- mods/edit_event.php | 12 ++++++++---- mods/edit_event_raidlevel.php | 9 ++++----- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/logic/keys_event.php b/logic/keys_event.php index 388cb409..944a29fa 100644 --- a/logic/keys_event.php +++ b/logic/keys_event.php @@ -3,9 +3,12 @@ * Event keys. * @param $gym_id_plus_letter * @param $action + * @param $admin_access array of access rights [ex-raids, event-raids] * @return array */ -function keys_event($gym_id_plus_letter, $action) { +function keys_event($gym_id_plus_letter, $action, $admin_access = [false,false]) { + $keys = []; + if($admin_access[1] === true) { $q = my_query(" SELECT id, name @@ -13,22 +16,25 @@ function keys_event($gym_id_plus_letter, $action) { WHERE id != 999 "); while($event = $q->fetch()) { - if(!empty($event['name'])) { - $keys[] = array( - 'text' => $event['name'], - 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . $event['id'] - ); - }else { - info_log('Invalid event name on event '. $event['id']); - } + if(!empty($event['name'])) { + $keys[] = array( + 'text' => $event['name'], + 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . $event['id'] + ); + }else { + info_log('Invalid event name on event '. $event['id']); + } } + } + if($admin_access[0] === true) { $keys[] = array( 'text' => getTranslation("Xstars"), 'callback_data' => $gym_id_plus_letter . ':' . $action . ':X' ); - // Get the inline key array. - $keys = inline_key_array($keys, 1); + } + // Get the inline key array. + $keys = inline_key_array($keys, 1); - return $keys; + return $keys; } ?> \ No newline at end of file diff --git a/logic/raid_edit_raidlevel_keys.php b/logic/raid_edit_raidlevel_keys.php index f06d0cab..d1e93f25 100644 --- a/logic/raid_edit_raidlevel_keys.php +++ b/logic/raid_edit_raidlevel_keys.php @@ -19,7 +19,8 @@ function raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access = [f $query_event = 'AND raid_bosses.raid_level != \'X\''; }else { $event_id = $event; - $query_event = ''; + if($admin_access[0] === true) $query_event = ''; + else $query_event = 'AND raid_bosses.raid_level != \'X\''; } $query_counts = ' SELECT raid_level, COUNT(*) AS raid_level_count @@ -74,7 +75,7 @@ function raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access = [f } } // Add key for raid event if user allowed to create event raids - if($admin_access[1] === true && $event === false) { + if(($admin_access[1] === true or $admin_access[0] === true) && $event === false) { $keys[] = array( 'text' => getTranslation('event'), 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_event:0' diff --git a/mods/edit_event.php b/mods/edit_event.php index 2dd92863..b6aa75b5 100644 --- a/mods/edit_event.php +++ b/mods/edit_event.php @@ -6,14 +6,18 @@ //debug_log($update); //debug_log($data); -// Check access. -$botUser->accessCheck($update, 'event-raids'); - // Set the id. $gym_id_plus_letter = $data['id']; +//Initialize admin rights table [ ex-raid , raid-event ] +$admin_access = [false, false]; +// Check access - user must be admin for raid_level X +$admin_access[0] = $botUser->accessCheck($update, 'ex-raids', true); +// Check access - user must be admin for raid event creation +$admin_access[1] = $botUser->accessCheck($update, 'event-raids', true); + // Get the keys. -$keys = keys_event($gym_id_plus_letter, "edit_event_raidlevel"); +$keys = keys_event($gym_id_plus_letter, "edit_event_raidlevel", $admin_access); // No keys found. if (!$keys) { diff --git a/mods/edit_event_raidlevel.php b/mods/edit_event_raidlevel.php index c0af0801..69156d4a 100644 --- a/mods/edit_event_raidlevel.php +++ b/mods/edit_event_raidlevel.php @@ -6,9 +6,6 @@ //debug_log($update); //debug_log($data); -// Check access. -$botUser->accessCheck($update, 'event-raids'); - // Get gym data via ID $id_data = explode(",", $data['id']); $gym_id = $id_data[0]; @@ -26,10 +23,12 @@ // Telegram JSON array. $tg_json = array(); -//Initiate admin rights table [ ex-raid , raid-event ] -$admin_access = [false,1]; +//Initialize admin rights table [ ex-raid , raid-event ] +$admin_access = [false, false]; // Check access - user must be admin for raid_level X $admin_access[0] = $botUser->accessCheck($update, 'ex-raids', true); +// Check access - user must be admin for raid event creation +$admin_access[1] = $botUser->accessCheck($update, 'event-raids', true); // Get the keys. $keys = raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access, $event_id); From 6c5b3c813f948b058d5d5aa08f989ae4b6e7864d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 20:02:12 +0200 Subject: [PATCH 135/367] Event settings should override everything --- mods/edit_time.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mods/edit_time.php b/mods/edit_time.php index 397b2907..3d0d8477 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -63,22 +63,22 @@ debug_log('Formatting the raid time properly now.'); $arg_time = str_replace('-', ':', $starttime); - // Ex and elite raids - if($event_id == 'X' or $raid_level == 9) { - debug_log('Ex-Raid time :D ... Setting raid date to ' . $arg_time); - $start_date_time = $arg_time; - $duration = ($raid_level == 9) ? $config->RAID_DURATION_ELITE : $config->RAID_DURATION; - $egg_duration = ($raid_level == 9) ? $config->RAID_EGG_DURATION_ELITE : $config->RAID_EGG_DURATION; - // Event raids - }elseif($event_id != 'N') { + if($event_id != 'N') { debug_log('Event time :D ... Setting raid date to ' . $arg_time); $start_date_time = $arg_time; $query = my_query("SELECT raid_duration FROM events WHERE id = '{$event_id}' LIMIT 1"); $result = $query->fetch(); - $duration = $result['raid_duration']; + $duration = $result['raid_duration'] ?? $config->RAID_DURATION; $egg_duration = $config->RAID_EGG_DURATION; + // Elite raids + }elseif($raid_level == 9) { + debug_log('Elite Raid time :D ... Setting raid date to ' . $arg_time); + $start_date_time = $arg_time; + $duration = $config->RAID_DURATION_ELITE; + $egg_duration = $config->RAID_EGG_DURATION_ELITE; + // Normal raids } else { // Current date From e1c03e6c2f58714c2af23b634736672e911db1a1 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 11 Nov 2022 23:08:44 +0200 Subject: [PATCH 136/367] Tutorial fix --- core/bot/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/bot/user.php b/core/bot/user.php index ef41bcda..162a0eee 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -160,7 +160,7 @@ public function privilegeCheck($update) { public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { if(in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { // If a config file matching users status was found, check if tutorial is forced - if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) && $this->userPrivileges['grantedBy'] !== 'BOT_ADMINS' && $this->userPrivileges['grantedBy'] !== 'NOT_RESTRICTED')) { + if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) || $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' || $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED')) { return false; } return true; From 071995ecaf9d8bad156275058509a8007bc15c1d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 12 Nov 2022 00:19:10 +0200 Subject: [PATCH 137/367] Fixed force-tutorial logic --- core/bot/commands.php | 2 +- core/bot/modules.php | 2 +- core/bot/user.php | 39 +++++++++++++++++---------------------- logic/new_user.php | 4 ++-- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/core/bot/commands.php b/core/bot/commands.php index ecc6d8c0..ff25936d 100644 --- a/core/bot/commands.php +++ b/core/bot/commands.php @@ -14,7 +14,7 @@ $altcom = 'start'; } - if($config->TUTORIAL_MODE && isset($update['message']['chat']['id']) && new_user($update['message']['chat']['id']) && $com != 'start' && $com != 'tutorial') { + if(isset($update['message']['chat']['id']) && new_user($update['message']['chat']['id']) && $com != 'start' && $com != 'tutorial') { send_message($update['message']['chat']['id'], getTranslation("tutorial_command_failed")); $dbh = null; exit(); diff --git a/core/bot/modules.php b/core/bot/modules.php index 7aac7a9b..4322211f 100644 --- a/core/bot/modules.php +++ b/core/bot/modules.php @@ -1,7 +1,7 @@ TUTORIAL_MODE && isset($update['callback_query']['from']['id']) && new_user($update['callback_query']['from']['id']) && $data['action'] != "tutorial") { +if(isset($update['callback_query']['from']['id']) && new_user($update['callback_query']['from']['id']) && $data['action'] != "tutorial") { answerCallbackQuery($update['callback_query']['id'], getTranslation("tutorial_vote_failed")); $dbh = null; exit(); diff --git a/core/bot/user.php b/core/bot/user.php index 162a0eee..89556590 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -158,34 +158,29 @@ public function privilegeCheck($update) { * @return bool|string */ public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { - if(in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { - // If a config file matching users status was found, check if tutorial is forced - if($new_user && (in_array("force-tutorial", $this->userPrivileges['privileges']) || $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' || $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED')) { - return false; - } + if(!$new_user && in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { return true; - }else { - debug_log('Denying access to the bot for user'); + } + debug_log('Denying access to the bot for user'); - if($return_result) - return false; + if($return_result) + return false; - $response_msg = '' . getTranslation('bot_access_denied') . ''; - // Edit message or send new message based on type of received call - if (isset($update['callback_query'])) { - $keys = []; + $response_msg = '' . getTranslation('bot_access_denied') . ''; + // Edit message or send new message based on type of received call + if (isset($update['callback_query'])) { + $keys = []; - // Telegram JSON array. - $tg_json = array(); - $tg_json[] = edit_message($update, $response_msg, $keys, false, true); - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('bot_access_denied'), true); + // Telegram JSON array. + $tg_json = array(); + $tg_json[] = edit_message($update, $response_msg, $keys, false, true); + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('bot_access_denied'), true); - curl_json_multi_request($tg_json); - } else { - send_message($update['message']['from']['id'], $response_msg); - } - exit; + curl_json_multi_request($tg_json); + } else { + send_message($update['message']['from']['id'], $response_msg); } + exit; } /** diff --git a/logic/new_user.php b/logic/new_user.php index e1b33289..2cbe7a92 100644 --- a/logic/new_user.php +++ b/logic/new_user.php @@ -5,8 +5,8 @@ * @return bool */ function new_user($user_id) { - global $config; - if($config->TUTORIAL_MODE && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; + global $config, $botUser; + if($config->TUTORIAL_MODE && in_array("force-tutorial", $botUser->userPrivileges['privileges']) && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; else return false; } ?> \ No newline at end of file From 47c82e59bc2083d08acb9698bbc446355a7bc711 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 12 Nov 2022 00:37:08 +0200 Subject: [PATCH 138/367] Fixed error message when there are no active raids in database --- commands/list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/list.php b/commands/list.php index 308d302b..31023618 100644 --- a/commands/list.php +++ b/commands/list.php @@ -45,7 +45,7 @@ debug_log($raids); // Did we get any raids? -if($raids[0]['r_active'] == 0) { +if(count($raids) == 0) { $msg = '' . getTranslation('no_active_raids_found') . ''; send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); exit(); From fa6d3caeccc450098e388d17cfb33ff395bc3263 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 12 Nov 2022 11:32:22 +0200 Subject: [PATCH 139/367] Removed `/team` command, brounght back missing translations and improved documentation --- commands/team.php | 47 ------------------------------------- docs/config.rst | 3 ++- docs/index.rst | 1 + docs/usage.rst | 50 +++++++-------------------------------- lang/language.json | 52 ++++++++++++++++++++++++++++++----------- logic.php | 1 - logic/new_user.php | 23 +++++++++++++++--- logic/user_tutorial.php | 25 -------------------- 8 files changed, 71 insertions(+), 131 deletions(-) delete mode 100644 commands/team.php delete mode 100644 logic/user_tutorial.php diff --git a/commands/team.php b/commands/team.php deleted file mode 100644 index 30489775..00000000 --- a/commands/team.php +++ /dev/null @@ -1,47 +0,0 @@ - 'mystic', - 'instinct' => 'instinct', - 'valor' => 'valor', - getTranslation('red') => 'valor', - getTranslation('blue') => 'mystic', - getTranslation('yellow') => 'instinct', - 'r' => 'valor', - 'b' => 'mystic', - 'y' => 'instinct', - 'g' => 'instinct' -); - -// Valid team name. -if (!empty($gym_team) && $teams[$gym_team]) { - // Update team in raids table. - my_query( - " - UPDATE raids - SET gym_team = '{$teams[$gym_team]}' - WHERE user_id = {$update['message']['from']['id']} - ORDER BY id DESC LIMIT 1 - " - ); - - // Send the message. - send_message($update['message']['chat']['id'], getTranslation('gym_team_set_to') . ' ' . ucfirst($teams[$gym_team])); - -// Invalid team name. -} else { - // Send the message. - send_message($update['message']['chat']['id'], getTranslation('invalid_team')); -} - -?> diff --git a/docs/config.rst b/docs/config.rst index 0324be89..8f95902b 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -137,6 +137,7 @@ You can set several languages for the bot. Available languages are (A-Z): * DE (German) * EN (English) +* ES (Spanish) * FI (Finnish) * FR (French) * IT (Italian) @@ -501,7 +502,7 @@ Cleanup The bot features an automatic cleanup of Telegram raid poll messages as well as cleanup of the database (attendance and raids tables). -To activate cleanup you need to `make sure your groups are Supergroups or Channels <#which-group-type-should-i-use--how-do-i-make-a-group-a-supergroup>`_\ , make your bot an admin in this chat, enable cleanup in the config and create a cronjob to trigger the cleanup process. +To activate cleanup you need to `make sure your groups are Supergroups or Channels <#referring-to-groups-channels-and-users>`_\ , make your bot an admin in this chat, enable cleanup in the config and create a cronjob to trigger the cleanup process. #. Set the ``CLEANUP`` in the config to ``true`` and define a cleanup secret/passphrase under ``CLEANUP_SECRET``. diff --git a/docs/index.rst b/docs/index.rst index ff768754..ebad472f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -52,6 +52,7 @@ You can submit translations to expand our list of lanuages! For more information * DE (German) * EN (English) +* ES (Spanish) * FI (Finnish) * FR (French) * IT (Italian) diff --git a/docs/usage.rst b/docs/usage.rst index f9d1138c..d8ad110e 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -4,11 +4,11 @@ PokemonRaidBot usage Send your location to the bot ----------------------------- -If ``RAID_LOCATION`` is set to ``true`` (default), the bot will guide you through the creation of a raid poll based on the settings in the config file. +If ``RAID_LOCATION`` is set to ``true`` (default), the bot will guide you through the creation of a raid poll based on the settings in the config file. ``RAID_VIA_LOCATION_FUNCTION`` determines the actions taken after location is received. -In case of a raid poll the bot will ask you for the raid level, the pokemon raid boss, the time until the raids starts and the time left for the raid. Afterwards you can set the gym name and gym team by using the /gym and /team commands. +By default the bot will ask you for the raid level, the pokemon raid boss, the time until the raids starts and the time left for the raid. Afterwards you can set the gym name by using the /gym or /gymname commands. -If ``LIST_BY_LOCATION`` is set to ``true``\ , the bot will instead list all nearby saved raids. +For further details please refer to :doc:`config#raid-creation-options` Using inline search of @PortalMapBot or @Ingressportalbot --------------------------------------------------------- @@ -264,17 +264,17 @@ Delete an existing raid poll with the ``/delete`` command: :alt: Command: /delete -Command: /team -^^^^^^^^^^^^^^ +Command: /trainer +^^^^^^^^^^^^^^^^^ -The bot will set the team to Mystic/Valor/Instinct for the last created raid based on your input. +Users can use this command to set their trainer name, friend code, team, level and if configured, personal bot settings (private language and automatic raid alarms). -Example input: ``/team Mystic`` +For users with proper access rights the bot will also give you a list of chats to share the trainer message which allows users to set team and level+/- data. You can also delete the shared trainer messages via the ``/trainer`` command. -Command: /trainer +Command: /history ^^^^^^^^^^^^^^^^^ -The bot will give you a list of chats to share the trainer message which allows users to set team and level+/- data. You can also delete the shared trainer messages via the ``/trainer`` command. +Tool for admins to view history of raids that had at least one person signed up for it. Command: /gym ^^^^^^^^^^^^^ @@ -283,13 +283,6 @@ The bot will show the details of each gym. Additionally you can change the exten Example input: ``/gym`` -Command: /addgym -^^^^^^^^^^^^^^^^ - -The bot will add a gym under the coordinates you're submitting. First latitude, then longitude. The gym is added under the name '#YourTelegramID' (e.g. '#111555777') and you need to change the name afterwards using the ``/gymname`` command. You cannot submit a second gym unless you changed the name of the first gym. In case you submit a second gym without changing the name of the previously submitted gym, the first gym coordinates will be overwritten! - -Example input: ``/addgym 52.5145434,13.3501189`` - Command: /gymname ^^^^^^^^^^^^^^^^^ @@ -298,28 +291,3 @@ The bot will set the name of gym to your input. If you submitted a gym via locat Example input: ``/gymname Siegessäule`` Example input with gym id: ``/gymname 34, Siegessäule`` - -Command: /gymaddress -^^^^^^^^^^^^^^^^^^^^ - -The bot will set the address of gym to your input. The id of the gym is required. You can delete the gym address using the keyword 'reset'. - -Example input: ``/gymaddress 34, Großer Stern, 10557 Berlin`` - -Example input to delete the gym address: ``/gymaddress 34, reset`` - -Command: /gymgps -^^^^^^^^^^^^^^^^ - -The bot will set the gps coordinates of gym to your input. The id of the gym is required. - -Example input: ``/gymgps 34, 52.5145434,13.3501189`` - -Command: /gymnote -^^^^^^^^^^^^^^^^^ - -The bot will set the note for gym to your input. The id of the gym is required. You can delete the gym note using the keyword 'reset'. - -Example input: ``/gymnote 34, Meeting point: Behind the building`` - -Example input to delete the gym note: ``/gymnote 34, reset`` diff --git a/lang/language.json b/lang/language.json index 1963c481..af0c2879 100644 --- a/lang/language.json +++ b/lang/language.json @@ -3080,19 +3080,6 @@ "FI": "Valinnainen - aseta sali ja joukkue", "ES": "Opcional - Poner gimnasio y equipo" }, - "set_gym_team_command": { - "NL": "/team Mystic/Valor/Instinct/Blauw/Rood/Geel", - "DE": "/team Mystic/Valor/Instinct/Blau/Rot/Gelb", - "EN": "/team Mystic/Valor/Instinct/Blue/Red/Yellow", - "IT": "/team Saggezza/Valore/Istinto/Blu/Rosso/Giallo", - "PT-BR": "/team Mystic/Valor/Instinct/Azul/Vermelho/Amarelo", - "RU": "/team Mystic/Valor/Instinct/Синий/Красный/Желтый", - "NO": "/team Mystic/Valor/Instinct/Blue/Red/Yellow", - "FR": "/team Sagesse/Bravoure/Intuition/Bleu/Rouge/Jaune", - "PL": "/team Niebieski/Czerowny/Żółty", - "FI": "/team Mystic/Valor/Instinct/Blue/Red/Yellow", - "ES": "/team Sabiduría/Valor/Instinto/Azul/Rojo/Amarillo" - }, "mystic": { "NL": "Mystic/Blauw", "DE": "Weisheit/Blau", @@ -3886,6 +3873,45 @@ "FI": "Saataksesi salin id numeron tai muita tietoja, käytä /gym -komentoa.", "ES": "Para obtener la identificación y más detalles del gimnasio, usa el comando /gym." }, + "gym_name_example": { + "NL": "Als voorbeeld: /gymname 34, Markt 61, 3131 CR Vlaardingen ", + "DE": "Zum Beispiel: /gymname 34, Wasserfall im Park", + "EN": "For example: /gymname 34, Waterfall in the park!", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Esimerkiksi: /gymname 34, Vapauden Muistomerkki!", + "ES": "Por ejemplo: /gymname 34, Waterfall in the park" + }, + "gym_id_name_missing": { + "NL": "Error! Gym id of naam mist!", + "DE": "Fehler! Arena-ID oder Name fehlt!", + "EN": "Error! Gym id or name is missing!", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Virhe! Salin id numero tai nimi puuttuu!", + "ES": "¡Error! ¡Faltan gym id o nombre!" + }, + "gym_name_updated": { + "NL": "Gym naam aangepast.", + "DE": "Der Arena-Name wurde aktualisiert.", + "EN": "Gym name updated.", + "IT": "Nome della Palestra aggiornato.", + "PT-BR": "Nome do ginásio atualizado.", + "RU": "Название гима обновлено.", + "NO": "Gym navn oppdatert.", + "FR": "Nom de l'arène mis à jour", + "PL": "Nazwa Areny zaktualizowana", + "FI": "Salin nimi päivitetty.", + "ES": "Nombre del gimnasio actualizado." + }, "gym_name_edit": { "NL": "Gym naam aanpassen", "DE": "TRANSLATE", diff --git a/logic.php b/logic.php index c6fde260..75f7dbe4 100644 --- a/logic.php +++ b/logic.php @@ -58,7 +58,6 @@ include('logic/show_raid_poll.php'); include('logic/show_raid_poll_small.php'); include('logic/show_trainerinfo.php'); -include('logic/user_tutorial.php'); include('logic/weather_keys.php'); include('logic/curl_get_contents.php'); ?> diff --git a/logic/new_user.php b/logic/new_user.php index 2cbe7a92..8b2e239a 100644 --- a/logic/new_user.php +++ b/logic/new_user.php @@ -5,8 +5,25 @@ * @return bool */ function new_user($user_id) { - global $config, $botUser; - if($config->TUTORIAL_MODE && in_array("force-tutorial", $botUser->userPrivileges['privileges']) && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) return true; - else return false; + global $config, $botUser; + if($config->TUTORIAL_MODE && in_array("force-tutorial", $botUser->userPrivileges['privileges']) && user_tutorial($user_id) < $config->TUTORIAL_LEVEL_REQUIREMENT) + return true; + return false; } + +/** + * Return the tutorial value from users table + * @param $user_id + * @return int + */ +function user_tutorial($user_id) { + debug_log("Reading user's tutorial value: ".$user_id); + $query = my_query("SELECT tutorial FROM users WHERE user_id = :user_id LIMIT 1", [":user_id"=>$user_id]); + $res = $query->fetch(); + $result = 0; + if($query->rowCount() > 0) $result = $res['tutorial']; + debug_log("Result: ".$result); + return $result; +} + ?> \ No newline at end of file diff --git a/logic/user_tutorial.php b/logic/user_tutorial.php deleted file mode 100644 index 8548bcd1..00000000 --- a/logic/user_tutorial.php +++ /dev/null @@ -1,25 +0,0 @@ -prepare( $query ); - $statement->execute([":user_id"=>$user_id]); - $res = $statement->fetch(); - if($statement->rowCount() > 0) $result = $res['tutorial']; - else $result = 0; - debug_log("Result: ".$result); - return $result; - } catch (PDOException $exception) { - error_log($exception->getMessage()); - $dbh = null; - exit; - } -} -?> \ No newline at end of file From f8d961ed63a1964b9d3e3393a70ec8f40062691f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 12 Nov 2022 16:56:25 +0200 Subject: [PATCH 140/367] Improved documentation --- docs/config.rst | 33 ++++++++++++--------------------- docs/development.rst | 2 +- docs/maintenance.rst | 2 +- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index 8f95902b..8797ff5d 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -213,18 +213,6 @@ Set ``RAID_EGG_DURATION`` to the maximum amount of minutes a user can select for Set ``RAID_DURATION`` to the maximum amount of minutes a user can select as raid duration for already running/active raids. -Set ``RAID_HOUR`` to true to enable the raid hour. Enabling the raid hour superseds the normal raid duration. Note that the raid hour takes precedence over the raid day. Make sure to disable the raid hour to get the raid day. - -Set ``RAID_HOUR_DURATION`` to the maximum amount of minutes a user can select as raid duration if the ``RAID_HOUR`` is enabled. Per default max. 60 minutes. - -Set ``RAID_HOUR_CREATION_LIMIT`` to the maximum amount of raids a user can create if the ``RAID_HOUR`` is enabled. Per default 1 raid. - -Set ``RAID_DAY`` to true to enable the raid day. Enabling the raid day superseds the normal raid duration. Note that the raid hour takes precedence over the raid day. Make sure to disable the raid hour to get the raid day. - -Set ``RAID_DAY_DURATION`` to the maximum amount of minutes a user can select as raid duration if the ``RAID_DAY`` is enabled. Per default max. 180 minutes. - -Set ``RAID_DAY_CREATION_LIMIT`` to the maximum amount of raids a user can create if the ``RAID_DAY`` is enabled. Per default 1 raid. - Set ``RAID_DURATION_CLOCK_STYLE`` to customize the default style for the raid start time selection. Set to true, the bot will show the time in clocktime style, e.g. "18:34" as selection when the raid will start. Set to false the bot will show the time until the raid starts in minutes, e.g. "0:16" (similar to the countdown in the gyms). Users can switch between both style in the raid creation process. Set ``RAID_CUSTOM_GYM_LETTERS`` to further split gyms by their first letter. For example if you have a lot of gyms starting with 'St' as there are a lot of churches like St. Helen, St. Jospeh, etc. in your area and the gym list under the letter 'S' is too long, you can tell the bot to put the gyms starting with 'St' under 'St' and exclude them from the letter 'S'. There is no limitation in length, so even 'Berlin' would work to split gyms, but the recommendation is to use as less chars as possible to split the gyms. You can add multiple custom gym letters, just separate them by comma. Example: ``"RAID_CUSTOM_GYM_LETTERS":"Ber,Sch,St,Wi"`` @@ -398,7 +386,7 @@ Predefine sharing all raids to the chats -100111222333 and -100444555666, except Raids from Webhook ~~~~~~~~~~~~~~~~~~ -You can receive Raids from a mapping system such as MAD via Webhook. +You can receive Raids from a mapping systems such as MAD and RDM via Webhook. For that you need to setup ``WEBHOOK_CREATOR``\ , and to automatically share raids to chats, ``"WEBHOOK_CHATS_ALL_LEVELS":"-100444555666"`` or by Raidlevel ``"WEBHOOK_CHATS_LEVEL_5":"-100444555666"`` @@ -443,7 +431,7 @@ Event raids Users with the proper access rights can choose to create event raids. These can be handy for example on raid hours and raid days. These special raid polls have event specific name, description and poll settings that need to be set in database. Example of a few settings is in ``sql/event-table-example.sql``. -``vote_key_mode`` currently supports 2 modes, 0 and 1. 0 is the standard mode where users vote for a time when they are attending. 1 is a mode with no timeslots, just a button for 'attending'. +``vote_key_mode`` currently supports two modes, 0 and 1. 0 is the standard mode where users vote for a time when they are attending. 1 is a mode with no timeslots, just a button for 'attending'. With ``time_slots`` you can set event secific time slots for vote keys when ``vote_key_mode`` 0 is selected. @@ -527,7 +515,7 @@ Access permissions Public access ^^^^^^^^^^^^^ -When no Telegram id, group, supergroup or channel is specified in ``BOT_ADMINS`` the bot will allow everyone to use it (public access). +When no Telegram id is specified in ``BOT_ADMINS`` the bot will allow everyone to use it (public access). Example for public access: ``"BOT_ADMINS":""`` @@ -536,11 +524,11 @@ Access and permissions The ``MAINTAINER_ID`` is not able to access the bot nor has any permissions as that id is only contacted in case of errors and issues with the bot configuration. -The ``BOT_ADMINS`` have all permissions and can use any feature of the bot. +The ``BOT_ADMINS`` have all permissions and can use any feature of the bot. No restrictions specified in access files apply to these users. Telegram Users can only vote on raid polls, but have no access to other bot functions (unless you configured it). -In order to allow Telegram chats to access the bot and use commands/features, you need to create an access file. +In order to allow members of Telegram chats to access the bot and use commands/features, you need to create an access file. It does not matter if a chat is a user, group, supergroup or channel - any kind of chat is supported as every chat has a chat id! @@ -645,7 +633,7 @@ A few examples for access files can be found below the permission overview table - Vote on shared raid poll - Not required! * - - - Create raids ``/start``\ , ``/raid`` + - Create raids ``/start`` - ``create`` * - - Create ex-raids ``/start`` @@ -658,7 +646,7 @@ A few examples for access files can be found below the permission overview table - ``raid-duration`` * - - List all raids ``/list`` and ``/listall`` - - ``list`` + - ``list`` and ``listall`` * - - Manage overview ``/overview`` - ``overview`` @@ -710,6 +698,9 @@ A few examples for access files can be found below the permission overview table * - - Add a gym ``/gym`` - ``gym-add`` + * - + - Edit gym name after creating a gym with ``RAID_VIA_LOCATION`` + - ``gym-name`` * - - - @@ -804,7 +795,7 @@ To enable this feature: * Create ``tutorial.php`` in config folder. Use ``tutorial.php.example`` as reference * Set ``TUTORIAL_MODE`` to ``true`` in ``config.json`` * ``tutorial`` in access config file(s) -* ``force-tutorial`` in access config file(s) to force users to go through the tutorial before they're able to use the bot. +* ``force-tutorial`` in access config file(s) to force users to go through the tutorial before they're able to use the bot. Does not apply to users specified in ``BOT_ADMINS``. Customization ------------- @@ -836,7 +827,7 @@ To change translations you can do the following: * Create a file named ``language.json`` in the custom folder -* Find the translation name/id by searching the core and bot language.php files (\ ``core/lang/language.php`` and ``lang/language.php``\ ) +* Find the translation name/id by searching the bot language.json files (\ ``lang/*.json``\ ) * Set your own translation in your custom language.json * For example to change the translation of 'Friday' to a shorter 'Fri' put the following in your ``custom/language.json``\ : diff --git a/docs/development.rst b/docs/development.rst index dd3da3a9..865506a0 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -32,7 +32,7 @@ the schema version is final and immutable and any schema changes need to happen Translations ------------ -Translations are stored in ``lang/language.json`` and ``core/lang/language.json``. Any string marked as ``TRANSLATE`` hasn't been translated yet. These can be changed by hand but if you want to add a new language or do large scale translation, using translate.py is recommended. +Translations are stored in ``lang/language.json``. Any string marked as ``TRANSLATE`` hasn't been translated yet. These can be changed by hand but if you want to add a new language or do large scale translation, using translate.py is recommended. translate.py ^^^^^^^^^^^^ diff --git a/docs/maintenance.rst b/docs/maintenance.rst index 92195ff1..130c372a 100644 --- a/docs/maintenance.rst +++ b/docs/maintenance.rst @@ -28,7 +28,7 @@ To automatically keep the raid boss data somewhat up to date, you can schedule t ``curl -k -d '{"callback_query":{"data":"LEVELS:update_bosses:SOURCE"}}' https://localhost/botdir/index.php?apikey=111111111:AABBccddEEFFggHHiijjKKLLmmnn`` -Currently supported arguments for LEVELS are raid levels ``1, 3, 5, 6`` in comma separated string, and ``scheduled`` to execute import of scheduled info for tier 5 and 6 raids. +Currently supported arguments for LEVELS are raid levels ``1, 3, 5, 6`` in comma separated string, and ``scheduled`` to execute import of scheduled info for tier 5 and higher raids. Currently supported arguments for SOURCE are ``pogoinfo``, which is only used when importing specific levels. From 5db4c8edb8616c8a375645e0d27c1572549aa274 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Nov 2022 21:49:28 +0200 Subject: [PATCH 141/367] Fixed lang path --- logic/get_pokemon_id_by_name.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/get_pokemon_id_by_name.php b/logic/get_pokemon_id_by_name.php index e8d4e807..de36b538 100644 --- a/logic/get_pokemon_id_by_name.php +++ b/logic/get_pokemon_id_by_name.php @@ -58,7 +58,7 @@ function get_pokemon_id_by_name($pokemon_name, $get_from_db = false) } }else { // Get translation file - $str = file_get_contents(CORE_LANG_PATH . '/pokemon.json'); + $str = file_get_contents(BOT_LANG_PATH . '/pokemon.json'); $json = json_decode($str, true); $search_result = ""; foreach($json as $title => $translations) { @@ -88,7 +88,7 @@ function get_pokemon_id_by_name($pokemon_name, $get_from_db = false) debug_log('Searching for pokemon form: ' . $poke_form); // Get forms translation file - $str_form = file_get_contents(CORE_LANG_PATH . '/pokemon_forms.json'); + $str_form = file_get_contents(BOT_LANG_PATH . '/pokemon_forms.json'); $json_form = json_decode($str_form, true); // Search pokemon form in json From 2f61684b16264425adb6d6095bf469c7528ed7fc Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Nov 2022 21:49:47 +0200 Subject: [PATCH 142/367] Simple uicons support If you have an uicons repo stored on your server already you can just link the pokemon folder from there to images/pokemon in raidbot --- logic/raid_picture.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 4be08320..c6098d88 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -260,11 +260,16 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { } else { // Check pokemon icon source and create image $img_file = null; + $uicons = false; $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); $addressable_icon = 'pm'.$raid['pokemon']; + $uicons_icon = $raid['pokemon']; - if($raid['pokemon_form_name'] != 'normal') $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); + if($raid['pokemon_form_name'] != 'normal') { + $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); + $uicons_icon .= '_f'.$raid['pokemon_form']; + } // Getting the actual icon filename $p_icon = "pokemon_icon_" . $icon_suffix; @@ -275,14 +280,18 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); $addressable_icon .= '.c' . array_search($raid['costume'],$costume); + + $uicons_icon .= '_c'.$raid['costume']; } if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { $p_icon = $p_icon . "_shiny"; $addressable_icon .= '.s'; + $uicons_icon .= '_s'; $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); } $addressable_icon .= '.icon.png'; $p_icon = $p_icon . ".png"; + $uicons_icon .= '.png'; foreach($p_sources as $p_dir) { // Icon dir named 'pokemon'? Then change path to not add '_repo-owner' to icon folder name @@ -302,6 +311,10 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { }else if(file_exists($p_img_base_path . "/" . $p_icon) && filesize($p_img_base_path . "/" . $p_icon) > 0) { $img_file = $p_img_base_path . "/" . $p_icon; break; + }else if(file_exists($p_img_base_path . "/" . $uicons_icon) && filesize($p_img_base_path . "/" . $uicons_icon) > 0) { + $img_file = $p_img_base_path . "/" . $uicons_icon; + $uicons = true; + break; } } @@ -323,7 +336,9 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Position and size of the picture $dst_x = $dst_y = 100; - $dst_w = $dst_h = $src_w = $src_h = 256; + $dst_w = $dst_h = 256; + $src_w = $src_h = $dst_w; + if($uicons === true) $src_w = $src_h = 128; if($raid['type'] != '') $show_boss_pokemon_types = true; } From 9f60827d065d0ec7b9070ae641eb0d25596c66cb Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Nov 2022 22:24:17 +0200 Subject: [PATCH 143/367] Minor translation fix --- lang/language.json | 13 ------------- mods/edit_save.php | 5 +---- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/lang/language.json b/lang/language.json index af0c2879..4b611e0d 100644 --- a/lang/language.json +++ b/lang/language.json @@ -3067,19 +3067,6 @@ "FI": "/gymname Salin nimi", "ES": "/gymname Nombre del gimnasio" }, - "set_gym_team": { - "NL": "Optioneel - zet Gym en Team", - "DE": "Optional - Arena Team setzen", - "EN": "Optional - set Gym and Team", - "IT": "Opzionale - imposta Palestra e Team", - "PT-BR": "Opcional - escolha o gínasio e time", - "RU": "Опционально - указать Гим и Команду", - "NO": "Valgfri - Fortell hvilken Gym og Team", - "FR": "Optionnel - choisir la couleur de l'arène", - "PL": "Opcjonalnie - Wybierz kolor Areny", - "FI": "Valinnainen - aseta sali ja joukkue", - "ES": "Opcional - Poner gimnasio y equipo" - }, "mystic": { "NL": "Mystic/Blauw", "DE": "Weisheit/Blau", diff --git a/mods/edit_save.php b/mods/edit_save.php index b71c3e29..ca3a67c4 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -137,13 +137,10 @@ $user_id_tag = '#' . $update['callback_query']['from']['id']; // Gym Name -if(!empty($raid['gym_name']) && ($raid['gym_name'] != $user_id_tag)) { -$msg .= getTranslation('set_gym_team') . CR2; -} else { +if(!empty($raid['gym_name']) && ($raid['gym_name'] == $user_id_tag)) { $msg .= getTranslation('set_gym_name_and_team') . CR2; $msg .= getTranslation('set_gym_name_command') . CR; } -$msg .= getTranslation('set_gym_team_command'); // Build callback message string. if($arg == 0) { From 1651963a46900c62969144396a26f6323cdcca8c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 13 Nov 2022 22:24:27 +0200 Subject: [PATCH 144/367] Detect UICONS source size automagically --- logic/raid_picture.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index c6098d88..38616e00 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -338,7 +338,9 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $dst_x = $dst_y = 100; $dst_w = $dst_h = 256; $src_w = $src_h = $dst_w; - if($uicons === true) $src_w = $src_h = 128; + if($uicons === true) { + [$src_w, $src_h] = getimagesize($img_file); + } if($raid['type'] != '') $show_boss_pokemon_types = true; } From 9897827214f3d63bfc83253c7fd238020f9b6eed Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:14:16 +0200 Subject: [PATCH 145/367] Added RAID_EXCLUDE_ELITE_DUPLICATION and made duplicate raid check raid level specific for raids received via webhook --- commands/raid_from_webhook.php | 54 ++++++++++++------------- config/defaults-config.json | 1 + docs/config.rst | 4 ++ logic/active_raid_duplication_check.php | 31 ++++++++------ 4 files changed, 50 insertions(+), 40 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index f24b4382..9d0d5d7c 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -189,7 +189,7 @@ function isPointInsidePolygon($point, $vertices) { } // Insert new raid or update existing raid/ex-raid? - $raid_id = active_raid_duplication_check($gym_internal_id); + $raid_id = active_raid_duplication_check($gym_internal_id, $level); $send_updates = false; @@ -306,32 +306,32 @@ function isPointInsidePolygon($point, $vertices) { // Combine resulting data with stuff received from webhook to create a complete raid array $raid = array_merge($missing_raid_data, [ - 'id' => $raid_id, - 'user_id' => $config->WEBHOOK_CREATOR, - 'spawn' => $spawn, - 'pokemon' => $resolved_boss['pokedex_id'], - 'pokemon_form' => $resolved_boss['pokemon_form_id'], - 'start_time' => $start, - 'end_time' => $end, - 'gym_team' => $team, - 'gym_id' => $gym_internal_id, - 'level' => $level, - 'move1' => $move_1, - 'move2' => $move_2, - 'gender' => $gender, - 'costume' => $costume, - 'event' => NULL, - 'event_note' => NULL, - 'event_name' => NULL, - 'event_description' => NULL, - 'event_vote_key_mode' => NULL, - 'event_time_slots' => NULL, - 'event_raid_duration' => NULL, - 'event_hide_raid_picture' => NULL, - 'event_pokemon_title' => NULL, - 'event_poll_template' => NULL, - 'raid_ended' => 0, - ]); + 'id' => $raid_id, + 'user_id' => $config->WEBHOOK_CREATOR, + 'spawn' => $spawn, + 'pokemon' => $resolved_boss['pokedex_id'], + 'pokemon_form' => $resolved_boss['pokemon_form_id'], + 'start_time' => $start, + 'end_time' => $end, + 'gym_team' => $team, + 'gym_id' => $gym_internal_id, + 'level' => $level, + 'move1' => $move_1, + 'move2' => $move_2, + 'gender' => $gender, + 'costume' => $costume, + 'event' => NULL, + 'event_note' => NULL, + 'event_name' => NULL, + 'event_description' => NULL, + 'event_vote_key_mode' => NULL, + 'event_time_slots' => NULL, + 'event_raid_duration' => NULL, + 'event_hide_raid_picture' => NULL, + 'event_pokemon_title' => NULL, + 'event_poll_template' => NULL, + 'raid_ended' => 0, + ]); } catch (PDOException $exception) { error_log($exception->getMessage()); diff --git a/config/defaults-config.json b/config/defaults-config.json index 5aa4d805..1ba353c9 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -45,6 +45,7 @@ "RAID_DURATION_CLOCK_STYLE": true, "RAID_CUSTOM_GYM_LETTERS":"", "RAID_EXCLUDE_EXRAID_DUPLICATION": true, + "RAID_EXCLUDE_ELITE_DUPLICATION": true, "RAID_EXCLUDE_EVENT_DUPLICATION": true, "RAID_LOCATION": false, "RAID_SLOTS":"15", diff --git a/docs/config.rst b/docs/config.rst index 8797ff5d..9bca84b6 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -968,6 +968,10 @@ Config reference - In minutes the maximum length of the egg phase a user is allowed to give. * - RAID_EXCLUDE_EXRAID_DUPLICATION - Bool, true to exclude ex-raids from the duplication check which allows to create an ex-raid and a normal raid at the same gym + * - RAID_EXCLUDE_EVENT_DUPLICATION + - Bool, true to exclude event raids from the duplication check which allows to create an event and a normal raid at the same gym + * - RAID_EXCLUDE_ELITE_DUPLICATION + - Bool, true to exclude elite raids from the duplication check which allows to create an elite raid and a normal raid at the same gym * - RAID_EX_GYM_MARKER - Enum, "icon" (default value, a star icon) or a custom text/icon to indicate an ex-raid gym in the raid polls * - RAID_FIRST_START diff --git a/logic/active_raid_duplication_check.php b/logic/active_raid_duplication_check.php index 9a2b5a46..33a253db 100644 --- a/logic/active_raid_duplication_check.php +++ b/logic/active_raid_duplication_check.php @@ -4,28 +4,33 @@ * @param $gym_id * @return string */ -function active_raid_duplication_check($gym_id) +function active_raid_duplication_check($gym_id, $level = false) { global $config; - + $levelSql = ''; + $args = [$gym_id]; + if($level !== false) { + $levelSql = 'AND level = ?'; + $args[] = $level; + } // Build query. $rs = my_query( - " - SELECT id, event + ' + SELECT id, event, level FROM raids WHERE end_time > (UTC_TIMESTAMP() - INTERVAL 5 MINUTE) - AND gym_id = {$gym_id} - ORDER BY event IS NOT NULL - " + AND gym_id = ? + ' . $levelSql . ' + ORDER BY end_time, event IS NOT NULL + ', $args ); $active = 0; while($raid = $rs->fetch()) { - # TODO: Should document why this check happens / the logic - if($config->RAID_EXCLUDE_EXRAID_DUPLICATION && $raid['event'] == EVENT_ID_EX) { - continue; - } - # TODO: Should document why this check happens / the logic - if($config->RAID_EXCLUDE_EVENT_DUPLICATION && $raid['event'] !== NULL && $raid['event'] != EVENT_ID_EX) { + // In some cases (ex-raids, event raids and elite raids) gyms can have multiple raids saved to them. + // We ignore these raids when performing the duplication check. + if( ($config->RAID_EXCLUDE_EXRAID_DUPLICATION && $raid['event'] == EVENT_ID_EX) + or ($level != 9 && $config->RAID_EXCLUDE_ELITE_DUPLICATION && $raid['level'] == 9) + or ($config->RAID_EXCLUDE_EVENT_DUPLICATION && $raid['event'] !== NULL && $raid['event'] != EVENT_ID_EX)) { continue; } $active = $raid['id']; From 7cc96bdbfe22aff4fa27c06ee9801c6491072051 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:31:12 +0200 Subject: [PATCH 146/367] Documented instructions for using UICONS in raid picture --- docs/config.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/config.rst b/docs/config.rst index 9bca84b6..03b82d95 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -296,6 +296,8 @@ To enable raid announcements as images set ``RAID_PICTURE`` to true. You also need to get the Pokemon sprites from known sources and put them in either images/pokemon/ or the images/pokemon_REPO-OWNER/ folder. The images/pokemon/ directory needs to be created manually, the images/pokemon_REPO-OWNER/ folders will be created automatically when by running the special download script mentioned below. +If you have an UICONS repo stored on your server already you can softlink the ``pokemon`` folder from there to ``images/pokemon/`` in raidbot directory. + Pokemon Icons / Sprites: Link: https://github.com/PokeMiners/pogo_assets/tree/master/Images/Pokemon%20-%20256x256 From 4022ca77a65ff1d7ce0726bbe4bea3c435c68c12 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 15 Nov 2022 23:06:14 +0200 Subject: [PATCH 147/367] Comments in access file names should now work as advertised in documentation Also streamlined the privilege check code a bit --- core/bot/user.php | 128 +++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 74 deletions(-) diff --git a/core/bot/user.php b/core/bot/user.php index 89556590..2638f864 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -52,86 +52,66 @@ public function privilegeCheck($update) { 'kicked' => 'kicked', ]; - // If user specific permissions are found, use them instead of group based - if (is_file(ACCESS_PATH . '/access' . $user_id)) { - $accessChats = [$user_id => null]; - }else { - $chatIds = []; - $rolesToCheck = $telegramRoles; - $rolesToCheck[] = 'access'; - foreach($rolesToCheck as $tgRole => $roleToCheck) { - $chatFiles = str_replace(ACCESS_PATH . '/' . $roleToCheck, '', glob(ACCESS_PATH . '/' . $roleToCheck . '-*')); - $chatIds = array_merge($chatIds, $chatFiles); - } - // Delete duplicates - $chatsToCheck = array_unique($chatIds); - $tg_json = []; - // Check access and permission - foreach($chatsToCheck as $chat) { - // Get chat object - remove comments from filename - // This way some kind of comment like the channel name can be added to the end of the filename, e.g. creator-100123456789-MyPokemonChannel to easily differ between access files :) - // Source: php.net/manual/en/function.intval.php#7707 - preg_match_all('/-?\d+/', $chat, $tg_chat); - $tg_chat = $tg_chat[0][0]; - debug_log("Getting chat object for '$tg_chat'"); - - // Group/channel? - if($tg_chat[0] == '-') { - // Get chat member object and check status - debug_log("Getting user from chat '$tg_chat'"); - $tg_json[$tg_chat] = get_chatmember($tg_chat, $user_id, true); - } + $accessFilesList = $tg_json = $chatIds = []; + foreach(glob(ACCESS_PATH . '/*') as $filePath) { + $filename = str_replace(ACCESS_PATH . '/', '', $filePath); + // Get chat object - remove comments from filename + // This way some kind of comment like the channel name can be added to the end of the filename, e.g. creator-100123456789-MyPokemonChannel to easily differ between access files :) + preg_match('/(access)('.$user_id.')|(access|creator|admins|members|restricted|kicked)(-[0-9]+)/', '-' . $filename, $result); + if(empty($result[0])) continue; + // User specific access file found? + if(!empty($result[1])) { + $privilegeList = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + debug_log($filename, 'Positive result on access check in file:'); + $this->userPrivileges = [ + 'privileges' => $privilegeList, + 'grantedBy' => $filename, + ]; + return; } - $accessChats = curl_json_multi_request($tg_json); + // Group/channel? + $role = $result[3]; + $tg_chat = $result[4]; + $chatIds[] = $tg_chat; + // Save the full filename (with possible comments) to an array for later use + $accessFilesList[$role.$tg_chat] = $filename; + debug_log("Asking Telegram if user is a member of chat '$tg_chat'"); + if(!isset($tg_json[$tg_chat])) $tg_json[$tg_chat] = get_chatmember($tg_chat, $user_id, true); // Get chat member object and check status } + $accessChats = curl_json_multi_request($tg_json); + // Loop through different chats foreach($accessChats as $chatId => $chatObj) { + $userStatus = $chatObj['result']['status']; + if(!isset($chatObj['ok']) or $chatObj['ok'] != true or $userStatus == 'left' or !array_key_exists($userStatus, $telegramRoles)){ + // Deny access + debug_log($chatId, 'Negative result on access check for chat:'); + debug_log('Continuing with next chat...'); + continue; + } // Object contains response from Telegram - if(isset($chatObj['ok'])) { - if($chatObj['ok'] == true) { - debug_log('Proper chat object received, continuing with access check.'); - - // Get access file based on user status/role. - debug_log('Role of user ' . $chatObj['result']['user']['id'] . ' : ' . $chatObj['result']['status']); - - $userStatus = $chatObj['result']['status']; - - if(array_key_exists($userStatus, $telegramRoles) && is_file(ACCESS_PATH . '/' . $telegramRoles[$userStatus] . $chatId)) { - $privilegeList = file(ACCESS_PATH . '/' . $telegramRoles[$userStatus] . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $accessFile = $userStatus . $chatId; - - // Any other user status/role except "left" - } else if($userStatus != 'left' && is_file(ACCESS_PATH . '/access' . $chatId)) { - $privilegeList = file(ACCESS_PATH . '/access' . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $accessFile = 'access' . $chatId; - - // Ignore "Restricted"? - if($userStatus == 'restricted' && in_array('ignore-restricted', $privilegeList)) { - $privilegeList = NULL; - } - - // Ignore "kicked"? - if($userStatus == 'kicked' && in_array('ignore-kicked', $privilegeList)) { - $privilegeList = NULL; - } - } else { - continue; - } - - // Debug. - debug_log('Access file:'); - debug_log($privilegeList); - } else { - // Invalid chat - debug_log('Chat ' . $chatId . ' does not exist! Continuing with next chat...'); - continue; - } - // Process user specific access file - }else { - if(is_file(ACCESS_PATH . '/access' . $chatId)) { - $privilegeList = file(ACCESS_PATH . '/access' . $chatId, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $accessFile = 'access' . $chatId; + debug_log('Proper chat object received, continuing with access check.'); + debug_log('Role of user ' . $chatObj['result']['user']['id'] . ' : ' . $chatObj['result']['status']); + + // Get access file based on user status/role. + $roleAndChat = $telegramRoles[$userStatus] . $chatId; + if(array_key_exists($roleAndChat, $accessFilesList)) { + $privilegeList = file(ACCESS_PATH . '/' . $accessFilesList[$roleAndChat], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $accessFile = $accessFilesList[$roleAndChat]; + + // Any other user status/role except "left" + } else if(array_key_exists('access' . $chatId, $accessFilesList)) { + $privilegeList = file(ACCESS_PATH . '/' . $accessFilesList['access' . $chatId], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $accessFile = $accessFilesList['access' . $chatId]; + + // Ignore "Restricted" or "kicked"? + if( ($userStatus == 'restricted' && in_array('ignore-restricted', $privilegeList)) + or ($userStatus == 'kicked' && in_array('ignore-kicked', $privilegeList))) { + $privilegeList = NULL; } + // Debug. + debug_log('Access file:'); + debug_log($privilegeList); } // Save privileges if found From 079f940bcd4e23a445c85922f26fe67e7d8705d8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 14:30:26 +0200 Subject: [PATCH 148/367] Cleaned up pokedex code --- constants.php | 1 + logic.php | 5 --- logic/get_formatted_pokemon_cp.php | 32 ++++---------- logic/get_pokemon_cp.php | 25 ----------- logic/get_pokemon_info.php | 40 ++++++++--------- logic/get_pokemon_shiny_status.php | 31 ------------- logic/get_pokemon_weather.php | 33 -------------- logic/get_raid.php | 4 +- logic/raid_level.php | 64 --------------------------- logic/show_raid_poll.php | 14 +++--- mods/pokedex_edit_pokemon.php | 48 +++++++++----------- mods/pokedex_set_cp.php | 40 ++++++----------- mods/pokedex_set_raid_level.php | 38 ++++++++-------- mods/pokedex_set_shiny.php | 70 ++++++++++++------------------ mods/pokedex_set_weather.php | 18 ++++---- 15 files changed, 123 insertions(+), 340 deletions(-) delete mode 100644 logic/get_pokemon_cp.php delete mode 100644 logic/get_pokemon_shiny_status.php delete mode 100644 logic/get_pokemon_weather.php delete mode 100644 logic/raid_level.php diff --git a/constants.php b/constants.php index debab865..c0204b55 100644 --- a/constants.php +++ b/constants.php @@ -80,6 +80,7 @@ defined('EMOJI_IN_PERSON') or define('EMOJI_IN_PERSON', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F9E1))); defined('EMOJI_ALIEN') or define('EMOJI_ALIEN', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F47D))); defined('EMOJI_CAN_INVITE')or define('EMOJI_CAN_INVITE', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F695))); +defined('EMOJI_SHINY') or define('EMOJI_SHINY', iconv('UCS-4LE', 'UTF-8', pack('V', 0x2728))); // Weather Icons. defined('EMOJI_W_SUNNY') or define('EMOJI_W_SUNNY', iconv('UCS-4LE', 'UTF-8', pack('V', 0x2600))); diff --git a/logic.php b/logic.php index 75f7dbe4..6c8d681d 100644 --- a/logic.php +++ b/logic.php @@ -22,12 +22,8 @@ include('logic/get_local_pokemon_name.php'); include('logic/get_overview.php'); include('logic/get_pokemon_by_table_id.php'); -include('logic/get_pokemon_cp.php'); include('logic/get_pokemon_form_name.php'); include('logic/get_pokemon_id_by_name.php'); -include('logic/get_pokemon_info.php'); -include('logic/get_pokemon_weather.php'); -include('logic/get_pokemon_shiny_status.php'); include('logic/get_raid.php'); include('logic/get_raid_times.php'); include('logic/get_remote_users_count.php'); @@ -47,7 +43,6 @@ include('logic/raid_edit_gyms_first_letter_keys.php'); include('logic/raid_edit_raidlevel_keys.php'); include('logic/raid_get_gyms_list_keys.php'); -include('logic/raid_level.php'); include('logic/raid_list.php'); include('logic/raid_poll_message.php'); include('logic/sendalarmnotice.php'); diff --git a/logic/get_formatted_pokemon_cp.php b/logic/get_formatted_pokemon_cp.php index a447c68d..053d97f6 100644 --- a/logic/get_formatted_pokemon_cp.php +++ b/logic/get_formatted_pokemon_cp.php @@ -1,39 +1,23 @@ 0) ? $row['min_cp'] : ''; + $cp20 .= (!empty($cp20) && $cp20 > 0) ? ('/' . $row['max_cp']) : ($row['max_cp']); - while($row = $rs->fetch()) { - // CP - $cp20 .= ($row['min_cp'] > 0) ? $row['min_cp'] : ''; - $cp20 .= (!empty($cp20) && $cp20 > 0) ? ('/' . $row['max_cp']) : ($row['max_cp']); - - // Weather boosted CP - $cp25 .= ($row['min_weather_cp'] > 0) ? $row['min_weather_cp'] : ''; - $cp25 .= (!empty($cp25) && $cp25 > 0) ? ('/' . $row['max_weather_cp']) : ($row['max_weather_cp']); - } - } + // Weather boosted CP + $cp25 .= ($row['min_weather_cp'] > 0) ? $row['min_weather_cp'] : ''; + $cp25 .= (!empty($cp25) && $cp25 > 0) ? ('/' . $row['max_weather_cp']) : ($row['max_weather_cp']); // Combine CP and weather boosted CP $text = ($override_language == true) ? (getPublicTranslation('pokedex_cp')) : (getTranslation('pokedex_cp')); diff --git a/logic/get_pokemon_cp.php b/logic/get_pokemon_cp.php deleted file mode 100644 index 0e496fd0..00000000 --- a/logic/get_pokemon_cp.php +++ /dev/null @@ -1,25 +0,0 @@ -fetch(); - - return $cp; -} - -?> diff --git a/logic/get_pokemon_info.php b/logic/get_pokemon_info.php index 19c575aa..b72e6b3f 100644 --- a/logic/get_pokemon_info.php +++ b/logic/get_pokemon_info.php @@ -5,26 +5,24 @@ * @param $pokemon_form_id * @return array */ -function get_pokemon_info($pokemon_id, $pokemon_form_id) +function get_pokemon_info($pokedex_id, $pokemon_form_id) { - /** Example: - * Raid boss: Mewtwo (#ID) - * Weather: Icons - * CP: CP values (Boosted CP values) - * Shiny: Shiny - */ - $info = ''; - $info .= getTranslation('raid_boss') . ': ' . get_local_pokemon_name($pokemon_id, $pokemon_form_id) . ' (#' . $pokemon_id . ')' . CR . CR; - $poke_raid_level = get_raid_level($pokemon_id, $pokemon_form_id); - $poke_cp = get_formatted_pokemon_cp($pokemon_id, $pokemon_form_id); - $poke_weather = get_pokemon_weather($pokemon_id, $pokemon_form_id); - $poke_shiny = get_pokemon_shiny_status($pokemon_id, $pokemon_form_id); - $info .= getTranslation('pokedex_raid_level') . ': ' . getTranslation($poke_raid_level . 'stars') . CR; - $info .= (empty($poke_cp)) ? (getTranslation('pokedex_cp') . CR) : $poke_cp . CR; - $info .= getTranslation('pokedex_weather') . ': ' . get_weather_icons($poke_weather) . CR; - $info .= (($poke_shiny == 1) ? (getTranslation('shiny')) : (getTranslation('not_shiny'))) . CR . CR; - - return $info; + $query = my_query(' + SELECT id, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, + (SELECT raid_level + FROM raid_bosses + WHERE pokedex_id = :pokedex_id + AND pokemon_form_id = :pokemon_form_id + AND scheduled = 0) as raid_level + FROM pokemon + WHERE pokedex_id = :pokedex_id + AND pokemon_form_id = :pokemon_form_id + LIMIT 1 + ', [ + 'pokedex_id' => $pokedex_id, + 'pokemon_form_id' => $pokemon_form_id + ]); + $result = $query->fetch(); + if($result['raid_level'] == NULL) $result['raid_level'] = 0; + return $result; } - -?> diff --git a/logic/get_pokemon_shiny_status.php b/logic/get_pokemon_shiny_status.php deleted file mode 100644 index 0c2c9527..00000000 --- a/logic/get_pokemon_shiny_status.php +++ /dev/null @@ -1,31 +0,0 @@ -fetch(); - debug_log($shiny, 'Per db, shiny status is:'); - - return $shiny['shiny']; - } else { - return 0; - } -} - -?> diff --git a/logic/get_pokemon_weather.php b/logic/get_pokemon_weather.php deleted file mode 100644 index 1835b8dc..00000000 --- a/logic/get_pokemon_weather.php +++ /dev/null @@ -1,33 +0,0 @@ -fetch(); - - if($ww) { - return $ww['weather']; - } else { - throw new Exception("Failed to find pokemon {$pokemon_id}_{$pokemon_form_id} weather."); - } - } else { - return 0; - } -} - -?> diff --git a/logic/get_raid.php b/logic/get_raid.php index f8b9dc67..0bf38024 100644 --- a/logic/get_raid.php +++ b/logic/get_raid.php @@ -27,9 +27,9 @@ function get_raid($raid_id) ON raids.user_id = users.user_id LEFT JOIN events ON events.id = raids.event - WHERE raids.id = '.$raidid.' + WHERE raids.id = ? LIMIT 1 - ' + ', [$raidid] ); // Get the row. $raid = $rs->fetch(); diff --git a/logic/raid_level.php b/logic/raid_level.php deleted file mode 100644 index 0353395a..00000000 --- a/logic/raid_level.php +++ /dev/null @@ -1,64 +0,0 @@ -fetch()) { - $raid_level = $level['raid_level']; - } - debug_log("Resolved level of {$pokedex_id}({$pokemon_form_id}) to {$raid_level}"); - } else { - info_log("Could not resolve level of {$pokedex_id}({$pokemon_form_id}), defaulting to 0!"); - $raid_level = '0'; - } - - return $raid_level; -} - -/** - * Get active raid bosses at a certain time. - * @param $time - string, datetime, local time - * @param $raid_level - ENUM('1', '2', '3', '4', '5', '6', 'X') - * @return array - */ -function get_raid_bosses($time, $raid_level) -{ - // Get raid level from database - $rs = my_query( - ' - SELECT DISTINCT pokedex_id, pokemon_form_id - FROM raid_bosses - WHERE \''.$time.'\' BETWEEN date_start AND date_end - AND raid_level = \''.$raid_level.'\' - '); - debug_log('Checking active raid bosses for raid level '.$raid_level.' at '.$time.':'); - $raid_bosses = []; - $egg_found = false; - while ($result = $rs->fetch()) { - $raid_bosses[] = $result; - if($result['pokedex_id'] == '999'.$raid_level) $egg_found = true; - debug_log('Pokedex id: '.$result['pokedex_id'].' | Form id: '.$result['pokemon_form_id']); - } - if(!$egg_found) $raid_bosses[] = ['pokedex_id' => '999'.$raid_level, 'pokemon_form_id' => 0]; // Add egg if it wasn't found from db - return $raid_bosses; -} - -?> diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index 3c3f22e7..dd2623ab 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -17,6 +17,8 @@ function show_raid_poll($raid, $inline = false) $raid_pokemon_form_id = $raid['pokemon_form']; $raid_pokemon_form_name = ($raid_pokemon_form_id != 0) ? get_pokemon_form_name($raid_pokemon_id, $raid_pokemon_form_id) : ''; $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_id; + require_once(LOGIC_PATH . '/get_pokemon_info.php'); + $raid_pokemon_info = get_pokemon_info($raid_pokemon_id, $raid_pokemon_form_id); // Get raid level $raid_level = $raid['level']; @@ -62,12 +64,11 @@ function show_raid_poll($raid, $inline = false) //Only store address if not empty if(!empty($address)) { my_query( - " + ' UPDATE gyms SET address = ? - WHERE id = '{$raid['gym_id']}' - ", - [$address] + WHERE id = ? + ', [$address, $raid['gym_id']] ); //Use new address $msg = raid_poll_message($msg, ($config->RAID_PICTURE ? $raid['gym_name'].': ' : ''). mapslink($raid,$address) . CR); @@ -86,8 +87,7 @@ function show_raid_poll($raid, $inline = false) $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . '', true); // Display raid boss weather. - $pokemon_weather = get_pokemon_weather($raid_pokemon_id, $raid_pokemon_form_id); - $msg = raid_poll_message($msg, ($pokemon_weather != 0) ? (' ' . get_weather_icons($pokemon_weather)) : '', true); + $msg = raid_poll_message($msg, ($raid_pokemon_info['weather'] != 0) ? (' ' . get_weather_icons($raid_pokemon_info['weather'])) : '', true); $msg = raid_poll_message($msg, CR, true); } @@ -287,7 +287,7 @@ function show_raid_poll($raid, $inline = false) } if($cnt_all > 0 || $buttons_hidden) { // Display raid boss CP values. - $pokemon_cp = get_formatted_pokemon_cp($raid_pokemon_id, $raid_pokemon_form_id, true); + $pokemon_cp = get_formatted_pokemon_cp($raid_pokemon_info, true); $msg = raid_poll_message($msg, (!empty($pokemon_cp)) ? ($pokemon_cp . CR) : '', true); } } diff --git a/mods/pokedex_edit_pokemon.php b/mods/pokedex_edit_pokemon.php index 778e5fb8..4dd18b0f 100644 --- a/mods/pokedex_edit_pokemon.php +++ b/mods/pokedex_edit_pokemon.php @@ -8,21 +8,22 @@ // Check access. $botUser->accessCheck($update, 'pokedex'); - +require_once(LOGIC_PATH . '/get_pokemon_info.php'); // Set the id. $poke_id_form = $data['id']; -$dex_id_form = explode('-',$data['id'],2); -$pokedex_id = $dex_id_form[0]; -$pokemon_form = $dex_id_form[1]; +[$pokedex_id, $pokemon_form_id] = explode('-',$data['id'],2); // Set the arg. $arg = $data['arg']; -// Init empty keys array. -$keys = []; - // Set the message. -$msg = get_pokemon_info($pokedex_id, $pokemon_form); +$pokemon = get_pokemon_info($pokedex_id, $pokemon_form_id); +$poke_cp = get_formatted_pokemon_cp($pokemon); +$msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($pokedex_id, $pokemon_form_id) . ' (#' . $pokedex_id . ')' . CR . CR; +$msg .= getTranslation('pokedex_raid_level') . ': ' . getTranslation($pokemon['raid_level'] . 'stars') . CR; +$msg .= (empty($poke_cp)) ? (getTranslation('pokedex_cp') . CR) : $poke_cp . CR; +$msg .= getTranslation('pokedex_weather') . ': ' . get_weather_icons($pokemon['weather']) . CR; +$msg .= (($pokemon['shiny'] == 1) ? (EMOJI_SHINY . SP . getTranslation('shiny')) : (getTranslation('not_shiny'))) . CR . CR; $msg .= '' . getTranslation('pokedex_select_action') . ''; // Create keys array. @@ -36,8 +37,7 @@ ]; // Raid-Egg? Hide specific options! -$eggs = $GLOBALS['eggs']; -if(!in_array($pokedex_id, $eggs)) { +if(!in_array($pokedex_id, $GLOBALS['eggs'])) { $keys_cp_weather = [ [ [ @@ -92,28 +92,20 @@ ] ]; -// Send message. -if($arg == 'id-or-name') { - // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); - -// Edit message. -} else { - // Build callback message string. - $callback_response = 'OK'; +// Build callback message string. +$callback_response = 'OK'; - // Telegram JSON array. - $tg_json = array(); +// Telegram JSON array. +$tg_json = array(); - // Answer callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); +// Answer callback. +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - // Edit message. - $tg_json[] = edit_message($update, $msg, $keys, false, true); +// Edit message. +$tg_json[] = edit_message($update, $msg, $keys, false, true); - // Telegram multicurl request. - curl_json_multi_request($tg_json); -} +// Telegram multicurl request. +curl_json_multi_request($tg_json); // Exit. exit(); diff --git a/mods/pokedex_set_cp.php b/mods/pokedex_set_cp.php index bc3d4365..edfc506c 100644 --- a/mods/pokedex_set_cp.php +++ b/mods/pokedex_set_cp.php @@ -25,18 +25,15 @@ $cp_value = $data[3]; // Set boosted string -if($cp_level == 25) { - $boosted = '_weather_cp'; -} else { - $boosted = '_cp'; -} +$boosted = ($cp_level == 25) ? '_weather_cp' : '_cp'; // Action to do: Save or add digits to cp $action = $data[2]; // Get current CP values -$cp_old = get_pokemon_cp($dex_id, $dex_form); -$current_cp = $cp_old[$cp_type . $boosted]; +require_once(LOGIC_PATH . '/get_pokemon_info.php'); +$pokemon = get_pokemon_info($dex_id, $dex_form); +$current_cp = $pokemon[$cp_type . $boosted]; // Log debug_log('New CP Type: ' . $cp_type); @@ -75,28 +72,17 @@ // Save cp to database } else if($action == 'save') { - // Set IV level for database - if($cp_level == 25) { - $weather = 'weather_cp'; - } else { - $weather = 'cp'; - } - // Set column name. - $cp_column = $cp_type . '_' . $weather; + $cp_column = $cp_type . $boosted; // Update cp of pokemon. - $rs = my_query( - " - UPDATE pokemon - SET $cp_column = {$cp_value} - WHERE pokedex_id = {$dex_id} - AND pokemon_form_id = '{$dex_form}' - " - ); - - // Init empty keys array. - $keys = []; + $rs = my_query(' + UPDATE pokemon + SET ' . $cp_column . ' = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$cp_value, $dex_id, $dex_form] + ); // Back to pokemon and done keys. $keys = [ @@ -113,7 +99,7 @@ ]; // Build callback message string. - $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($pokedex_id); + $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); // Set the message. $msg = getTranslation('pokemon_saved') . CR; diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index f35bde65..93d025cd 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -20,6 +20,9 @@ $dex_id = $dex_id_form[0]; $dex_form = $dex_id_form[1]; +require_once(LOGIC_PATH . '/get_pokemon_info.php'); +$pokemon = get_pokemon_info($dex_id, $dex_form); + // Set raid level or show raid levels? if($data['arg'] == "setlevel") { $raid_levels = str_split('0' . RAID_LEVEL_ALL); @@ -54,32 +57,25 @@ // Set the message. $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; - $old_raid_level = get_raid_level($dex_id, $dex_form); - $msg .= getTranslation('pokedex_current_raid_level') . ' ' . getTranslation($old_raid_level . 'stars') . CR . CR; + $msg .= getTranslation('pokedex_current_raid_level') . ' ' . getTranslation($pokemon['raid_level'] . 'stars') . CR . CR; $msg .= '' . getTranslation('pokedex_new_raid_level') . ':'; } else { // Update raid level of pokemon. - if($arg == 0 && get_raid_level($dex_id, $dex_form) != 0) { - $rs = my_query( - " - DELETE FROM raid_bosses - WHERE pokedex_id = '{$dex_id}' - AND pokemon_form_id = '{$dex_form}' - AND scheduled = 0 - " - ); - }else { - $rs = my_query( - " - INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) - VALUES ('{$dex_id}', '{$dex_form}', '{$arg}') - " - ); + my_query(' + DELETE FROM raid_bosses + WHERE pokedex_id = ? + AND pokemon_form_id = ? + AND scheduled = 0 + ', [$dex_id, $dex_form] + ); + if($arg != 0) { + my_query(' + INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) + VALUES (?, ?, ?) + ',[$dex_id, $dex_form, $arg] + ); } - // Init empty keys array. - $keys = []; - // Back to pokemon and done keys. $keys = [ [ diff --git a/mods/pokedex_set_shiny.php b/mods/pokedex_set_shiny.php index 9a091554..2aa11d08 100644 --- a/mods/pokedex_set_shiny.php +++ b/mods/pokedex_set_shiny.php @@ -21,44 +21,32 @@ $dex_form = $dex_id_form[1]; // Set shiny or ask to set? -if($data['arg'] == "setshiny") { +if($data['arg'] == 'setshiny') { // Get current shiny status from database. - $shiny = get_pokemon_shiny_status($dex_id, $dex_form); - - // Init empty keys array. - $keys = []; - - // Create keys array. - if($shiny == 0) { - // Enable shiny. - $old_shiny_status = getTranslation('not_shiny'); - $keys[] = [ - array( - 'text' => getTranslation('shiny'), - 'callback_data' => $pokedex_id . ':pokedex_set_shiny:1' - ) - ]; - - } else { - // Disable shiny. - $old_shiny_status = getTranslation('shiny'); - $keys[] = [ - array( - 'text' => getTranslation('not_shiny'), - 'callback_data' => $pokedex_id . ':pokedex_set_shiny:0' - ) - ]; - } + require_once(LOGIC_PATH . '/get_pokemon_info.php'); + $pokemon = get_pokemon_info($dex_id, $dex_form); + + $shinyText = ($pokemon['shiny'] == 0) ? 'shiny' : 'not_shiny'; + $old_shiny_status = ($pokemon['shiny'] == 0) ? getTranslation('not_shiny') : EMOJI_SHINY . SP . getTranslation('shiny'); + $newShinyValue = ($pokemon['shiny'] == 0) ? 1 : 0; // Back and abort. - $keys[] = [ + $keys = [ [ - 'text' => getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + [ + 'text' => getTranslation($shinyText), + 'callback_data' => $pokedex_id . ':pokedex_set_shiny:' . $newShinyValue + ] ], [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + [ + 'text' => getTranslation('back'), + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] ] ]; @@ -71,17 +59,13 @@ $msg .= '' . getTranslation('pokedex_new_status') . ':'; } else { // Update shiny status of pokemon. - $rs = my_query( - " - UPDATE pokemon - SET shiny = '{$arg}' - WHERE pokedex_id = {$dex_id} - AND pokemon_form_id = '{$dex_form}' - " - ); - - // Init empty keys array. - $keys = []; + $rs = my_query(' + UPDATE pokemon + SET shiny = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$arg, $dex_id, $dex_form] + ); // Back to pokemon and done keys. $keys = [ diff --git a/mods/pokedex_set_weather.php b/mods/pokedex_set_weather.php index 2bf5ee27..f0aacfa9 100644 --- a/mods/pokedex_set_weather.php +++ b/mods/pokedex_set_weather.php @@ -22,7 +22,10 @@ $data = explode("-", $arg); $action = $data[0]; $new_weather = $data[1]; -$old_weather = get_pokemon_weather($dex_id, $dex_form); + +require_once(LOGIC_PATH . '/get_pokemon_info.php'); +$pokemon = get_pokemon_info($dex_id, $dex_form); +$old_weather = $pokemon['weather']; // Log debug_log('Action: ' . $action); @@ -61,17 +64,14 @@ } else if($action == 'save') { // Update weather of pokemon. $rs = my_query( - " + ' UPDATE pokemon - SET weather = {$new_weather} - WHERE pokedex_id = {$dex_id} - AND pokemon_form_id = '{$dex_form}' - " + SET weather = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$new_weather, $dex_id, $dex_form] ); - // Init empty keys array. - $keys = []; - // Back to pokemon and done keys. $keys = [ [ From 0fdc6ab6500498938a0ae0df54fa0a465634e95b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 15:25:35 +0200 Subject: [PATCH 149/367] Cleaned up keys_vote code Also refactored the time slot key logic. Hopefully didn't break it --- logic/keys_vote.php | 979 ++++++++++++++++++-------------------------- 1 file changed, 408 insertions(+), 571 deletions(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index bbd72a1b..8859f58f 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -6,580 +6,417 @@ */ function keys_vote($raid) { - global $config; - // Init keys_time array. - $keys_time = []; - - // Get current UTC time and raid UTC times. - $now = utcnow(); - $end_time = $raid['end_time']; - $start_time = $raid['start_time']; - - // Write to log. - debug_log($now, 'UTC NOW:'); - debug_log($end_time, 'UTC END:'); - debug_log($start_time, 'UTC START:'); - - // Raid ended already. - if ($raid['raid_ended']) { - if($config->RAID_ENDED_HIDE_KEYS) { - return []; - }else { - return [ - [ - [ - 'text' => getPublicTranslation('raid_done'), - 'callback_data' => $raid['id'] . ':vote_refresh:1' - ] - ] - ]; - } - // Raid is still running. + global $config; + // Init keys_time array. + $keys_time = []; + + // Get current UTC time and raid UTC times. + $now = utcnow(); + + // Write to log. + debug_log($now, 'UTC NOW:'); + debug_log($raid['end_time'], 'UTC END:'); + debug_log($raid['start_time'], 'UTC START:'); + + // Raid ended already. + if ($raid['raid_ended']) { + if($config->RAID_ENDED_HIDE_KEYS) return []; + return [ + [ + [ + 'text' => getPublicTranslation('raid_done'), + 'callback_data' => $raid['id'] . ':vote_refresh:1' + ] + ] + ]; + } + // Raid is still running. + // Get current pokemon + $raid_pokemon_id = $raid['pokemon']; + $raid_pokemon_form_id = $raid['pokemon_form']; + $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_id; + + // Get raid level + $raid_level = $raid['level']; + + // Are remote players allowed for this raid? + $raid_local_only = in_array($raid_level, RAID_LEVEL_LOCAL_ONLY); + + // Hide buttons for raid levels and pokemon + $hide_buttons_raid_level = explode(',', $config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL); + $hide_buttons_pokemon = explode(',', $config->RAID_POLL_HIDE_BUTTONS_POKEMON); + + // Show buttons to users? + if(in_array($raid_level, $hide_buttons_raid_level) || in_array(($raid_pokemon_id . "-" . get_pokemon_form_name($raid_pokemon_id,$raid_pokemon_form_id)), $hide_buttons_pokemon) || in_array($raid_pokemon_id, $hide_buttons_pokemon)) { + return []; + } + // Extra Keys + $buttons['alone'] = [ + 'text' => EMOJI_SINGLE, + 'callback_data' => $raid['id'] . ':vote_extra:0' + ]; + $buttons['extra'] = [ + 'text' => '+ ' . EMOJI_IN_PERSON, + 'callback_data' => $raid['id'] . ':vote_extra:in_person' + ]; + + // Show buttons regarding remote participation only if raid level allows it + $buttons['extra_alien'] = $buttons['can_inv'] = $buttons['remote'] = $buttons['inv_plz'] = []; + if(!$raid_local_only) { + $buttons['extra_alien'] = [ + 'text' => '+ ' . EMOJI_ALIEN, + 'callback_data' => $raid['id'] . ':vote_extra:alien' + ]; + + // Can invite key + $buttons['can_inv'] = [ + 'text' => EMOJI_CAN_INVITE, + 'callback_data' => $raid['id'] . ':vote_can_invite:0' + ]; + + // Remote Raid Pass key + $buttons['remote'] = [ + 'text' => EMOJI_REMOTE, + 'callback_data' => $raid['id'] . ':vote_remote:0' + ]; + + // Want invite key + $buttons['inv_plz'] = [ + 'text' => EMOJI_WANT_INVITE, + 'callback_data' => $raid['id'] . ':vote_want_invite:0' + ]; + } + + // Team and level keys. + $buttons['teamlvl'] = [ + [ + [ + 'text' => 'Team', + 'callback_data' => $raid['id'] . ':vote_team:0' + ], + [ + 'text' => 'Lvl +', + 'callback_data' => $raid['id'] . ':vote_level:up' + ], + [ + 'text' => 'Lvl -', + 'callback_data' => $raid['id'] . ':vote_level:down' + ] + ] + ]; + + // Ex-Raid Invite key + $buttons['ex_inv'] = []; + if ($raid['event'] == EVENT_ID_EX) { + $buttons['ex_inv'] = [ + 'text' => EMOJI_INVITE, + 'callback_data' => $raid['id'] . ':vote_invite:0' + ]; + } + + // Show icon, icon + text or just text. + // Icon. + if($config->RAID_VOTE_ICONS && !$config->RAID_VOTE_TEXT) { + $text_here = EMOJI_HERE; + $text_late = EMOJI_LATE; + $text_done = TEAM_DONE; + $text_cancel = TEAM_CANCEL; + // Icon + text. + } else if($config->RAID_VOTE_ICONS && $config->RAID_VOTE_TEXT) { + $text_here = EMOJI_HERE . getPublicTranslation('here'); + $text_late = EMOJI_LATE . getPublicTranslation('late'); + $text_done = TEAM_DONE . getPublicTranslation('done'); + $text_cancel = TEAM_CANCEL . getPublicTranslation('cancellation'); + // Text. + } else { + $text_here = getPublicTranslation('here'); + $text_late = getPublicTranslation('late'); + $text_done = getPublicTranslation('done'); + $text_cancel = getPublicTranslation('cancellation'); + } + + // Status keys. + $buttons['alarm'] = [ + 'text' => EMOJI_ALARM, + 'callback_data' => $raid['id'] . ':vote_status:alarm' + ]; + $buttons['here'] = [ + 'text' => $text_here, + 'callback_data' => $raid['id'] . ':vote_status:arrived' + ]; + $buttons['late'] = [ + 'text' => $text_late, + 'callback_data' => $raid['id'] . ':vote_status:late' + ]; + $buttons['done'] = [ + 'text' => $text_done, + 'callback_data' => $raid['id'] . ':vote_status:raid_done' + ]; + $buttons['cancel'] = [ + 'text' => $text_cancel, + 'callback_data' => $raid['id'] . ':vote_status:cancel' + ]; + + $buttons['refresh'] = []; + if(!$config->AUTO_REFRESH_POLLS) { + $buttons['refresh'] = [ + 'text' => EMOJI_REFRESH, + 'callback_data' => $raid['id'] . ':vote_refresh:0' + ]; + } + + if($raid['event_vote_key_mode'] == 1) { + $keys_time = [ + [ + 'text' => getPublicTranslation("Participate"), + 'callback_data' => $raid['id'] . ':vote_time:' . utctime($raid['start_time'], 'YmdHis') + ] + ]; + }else { + $RAID_SLOTS = ($raid['event_time_slots'] > 0) ? $raid['event_time_slots'] : $config->RAID_SLOTS; + $keys_time = generateTimeslotKeys($RAID_SLOTS, $raid); + } + // Add time keys. + $buttons['time'] = inline_key_array($keys_time, 4); + + // Hidden participants? + $hide_users_sql = ''; + if($config->RAID_POLL_HIDE_USERS_TIME > 0) { + if($config->RAID_ANYTIME) { + $hide_users_sql = 'AND (attend_time > (UTC_TIMESTAMP() - INTERVAL ' . $config->RAID_POLL_HIDE_USERS_TIME . ' MINUTE) OR attend_time = \''.ANYTIME.'\')'; } else { - // Get current pokemon - $raid_pokemon_id = $raid['pokemon']; - $raid_pokemon_form_id = $raid['pokemon_form']; - $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_id; - - // Get raid level - $raid_level = $raid['level']; - - // Are remote players allowed for this raid? - $raid_local_only = in_array($raid_level, RAID_LEVEL_LOCAL_ONLY); - - // Hide buttons for raid levels and pokemon - $hide_buttons_raid_level = explode(',', $config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL); - $hide_buttons_pokemon = explode(',', $config->RAID_POLL_HIDE_BUTTONS_POKEMON); - - // Show buttons to users? - if(in_array($raid_level, $hide_buttons_raid_level) || in_array(($raid_pokemon_id . "-" . get_pokemon_form_name($raid_pokemon_id,$raid_pokemon_form_id)), $hide_buttons_pokemon) || in_array($raid_pokemon_id, $hide_buttons_pokemon)) { - return []; - } else { - // Extra Keys - $buttons_alone = [ - 'text' => EMOJI_SINGLE, - 'callback_data' => $raid['id'] . ':vote_extra:0' - ]; - $buttons_extra = [ - 'text' => '+ ' . EMOJI_IN_PERSON, - 'callback_data' => $raid['id'] . ':vote_extra:in_person' - ]; - - // Show buttons regarding remote participation only if raid level allows it - if(!$raid_local_only) { - $buttons_extra_alien = [ - 'text' => '+ ' . EMOJI_ALIEN, - 'callback_data' => $raid['id'] . ':vote_extra:alien' - ]; - - // Can invite key - $buttons_can_inv = [ - 'text' => EMOJI_CAN_INVITE, - 'callback_data' => $raid['id'] . ':vote_can_invite:0' - ]; - - // Remote Raid Pass key - $buttons_remote = [ - 'text' => EMOJI_REMOTE, - 'callback_data' => $raid['id'] . ':vote_remote:0' - ]; - - // Want invite key - $buttons_inv_plz = [ - 'text' => EMOJI_WANT_INVITE, - 'callback_data' => $raid['id'] . ':vote_want_invite:0' - ]; - }else { - $buttons_extra_alien = $buttons_can_inv = $buttons_remote = $buttons_inv_plz = []; - } - - // Team and level keys. - $buttons_teamlvl = [ - [ - [ - 'text' => 'Team', - 'callback_data' => $raid['id'] . ':vote_team:0' - ], - [ - 'text' => 'Lvl +', - 'callback_data' => $raid['id'] . ':vote_level:up' - ], - [ - 'text' => 'Lvl -', - 'callback_data' => $raid['id'] . ':vote_level:down' - ] - ] - ]; - - // Ex-Raid Invite key - if ($raid['event'] == EVENT_ID_EX) { - $buttons_ex_inv = [ - 'text' => EMOJI_INVITE, - 'callback_data' => $raid['id'] . ':vote_invite:0' - ]; - }else { - $buttons_ex_inv = []; - } - - // Show icon, icon + text or just text. - // Icon. - if($config->RAID_VOTE_ICONS && !$config->RAID_VOTE_TEXT) { - $text_here = EMOJI_HERE; - $text_late = EMOJI_LATE; - $text_done = TEAM_DONE; - $text_cancel = TEAM_CANCEL; - // Icon + text. - } else if($config->RAID_VOTE_ICONS && $config->RAID_VOTE_TEXT) { - $text_here = EMOJI_HERE . getPublicTranslation('here'); - $text_late = EMOJI_LATE . getPublicTranslation('late'); - $text_done = TEAM_DONE . getPublicTranslation('done'); - $text_cancel = TEAM_CANCEL . getPublicTranslation('cancellation'); - // Text. - } else { - $text_here = getPublicTranslation('here'); - $text_late = getPublicTranslation('late'); - $text_done = getPublicTranslation('done'); - $text_cancel = getPublicTranslation('cancellation'); - } - - // Status keys. - $buttons_alarm = [ - 'text' => EMOJI_ALARM, - 'callback_data' => $raid['id'] . ':vote_status:alarm' - ]; - $buttons_here = [ - 'text' => $text_here, - 'callback_data' => $raid['id'] . ':vote_status:arrived' - ]; - $buttons_late = [ - 'text' => $text_late, - 'callback_data' => $raid['id'] . ':vote_status:late' - ]; - $buttons_done = [ - 'text' => $text_done, - 'callback_data' => $raid['id'] . ':vote_status:raid_done' - ]; - $buttons_cancel = [ - 'text' => $text_cancel, - 'callback_data' => $raid['id'] . ':vote_status:cancel' - ]; - - if(!$config->AUTO_REFRESH_POLLS) { - $buttons_refresh = [ - 'text' => EMOJI_REFRESH, - 'callback_data' => $raid['id'] . ':vote_refresh:0' - ]; - }else { - $buttons_refresh = []; - } - - if($raid['event_vote_key_mode'] == 1) { - $keys_time = [ - [ - 'text' => getPublicTranslation("Participate"), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($raid['start_time'], 'YmdHis') - ] - ]; - }else { - if($raid['event_time_slots'] > 0) { - $RAID_SLOTS = $raid['event_time_slots']; - }else { - $RAID_SLOTS = $config->RAID_SLOTS; - } - // Get current time. - $now_helper = new DateTimeImmutable('now', new DateTimeZone('UTC')); - $now_helper = $now_helper->format('Y-m-d H:i') . ':00'; - $dt_now = new DateTimeImmutable($now_helper, new DateTimeZone('UTC')); - - // Get direct start slot - $direct_slot = new DateTimeImmutable($start_time, new DateTimeZone('UTC')); - - // Get first raidslot rounded up to the next 5 minutes - // Get minute and convert modulo raidslot - $five_slot = new DateTimeImmutable($start_time, new DateTimeZone('UTC')); - $minute = $five_slot->format("i"); - $minute = $minute % 5; - - // Count minutes to next 5 multiple minutes if necessary - if($minute != 0) - { - // Count difference - $diff = 5 - $minute; - // Add difference - $five_slot = $five_slot->add(new DateInterval("PT".$diff."M")); - } - - // Add $config->RAID_FIRST_START minutes to five minutes slot - //$five_plus_slot = new DateTime($five_slot, new DateTimeZone('UTC')); - $five_plus_slot = $five_slot; - $five_plus_slot = $five_plus_slot->add(new DateInterval("PT".$config->RAID_FIRST_START."M")); - - // Get first regular raidslot - // Get minute and convert modulo raidslot - $first_slot = new DateTimeImmutable($start_time, new DateTimeZone('UTC')); - $minute = $first_slot->format("i"); - $minute = $minute % $config->RAID_SLOTS; - - // Count minutes to next raidslot multiple minutes if necessary - if($minute != 0) - { - // Count difference - $diff = $config->RAID_SLOTS - $minute; - // Add difference - $first_slot = $first_slot->add(new DateInterval("PT".$diff."M")); - } - - // Compare times slots to add them to keys. - // Example Scenarios: - // Raid 1: Start = 17:45, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 2: Start = 17:36, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 3: Start = 17:35, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 4: Start = 17:31, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 5: Start = 17:40, $config->RAID_FIRST_START = 10, $config->RAID_SLOTS = 15 - // Raid 6: Start = 17:32, $config->RAID_FIRST_START = 5, $config->RAID_SLOTS = 5 - - // Write slots to log. - debug_log($direct_slot, 'Direct start slot:'); - debug_log($five_slot, 'Next 5 Minute slot:'); - debug_log($first_slot, 'First regular slot:'); - - // Add first slot only, as all slot times are identical - if($direct_slot == $five_slot && $direct_slot == $first_slot) { - // Raid 1: 17:45 (17:45 == 17:45 && 17:45 == 17:45) - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - // Add either five and first slot or only first slot based on RAID_FIRST_START - } else if($direct_slot == $five_slot && $five_slot < $first_slot) { - // Raid 3: 17:35 == 17:35 && 17:35 < 17:45 - // Raid 5: 17:40 == 17:40 && 17:40 < 17:45 - - // Add next five minutes slot and first regular slot - if($five_plus_slot <= $first_slot) { - // Raid 3: 17:35, 17:45 (17:35 + 10min <= 17:45) - - // Add five minutes slot - if($five_slot >= $dt_now) { - $slot = $five_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - // Add only first regular slot - } else { - // Raid 5: 17:45 - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Add direct slot and first slot - } else if($direct_slot < $five_slot && $five_slot == $first_slot) { - // Raid 6: 17:32 < 17:35 && 17:35 == 17:35 - // Some kind of special case for a low value of RAID_SLOTS - - // Add direct slot? - if($config->RAID_DIRECT_START) { - if($direct_slot >= $dt_now) { - $slot = $direct_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - - // Add either all 3 slots (direct slot, five minutes slot and first regular slot) or - // 2 slots (direct slot and first slot) as $config->RAID_FIRST_START does not allow the five minutes slot to be added - } else if($direct_slot < $five_slot && $five_slot < $first_slot) { - // Raid 2: 17:36 < 17:40 && 17:40 < 17:45 - // Raid 4: 17:31 < 17:35 && 17:35 < 17:45 - - // Add all 3 slots - if($five_plus_slot <= $first_slot) { - // Raid 4: 17:31, 17:35, 17:45 - - // Add direct slot? - if($config->RAID_DIRECT_START) { - if($direct_slot >= $dt_now) { - $slot = $direct_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Add five minutes slot - if($five_slot >= $dt_now) { - $slot = $five_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - // Add direct slot and first regular slot - } else { - // Raid 2: 17:36, 17:45 - - // Add direct slot? - if($config->RAID_DIRECT_START) { - if($direct_slot >= $dt_now) { - $slot = $direct_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Add first slot - if($first_slot >= $dt_now) { - $slot = $first_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // We missed all possible cases or forgot to include them in future else-if-clauses :D - // Try to add at least the direct slot. - } else { - // Add direct slot? - if($config->RAID_DIRECT_START) { - if($first_slot >= $dt_now) { - $slot = $direct_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - } - - - // Init last slot time. - $last_slot = new DateTimeImmutable($start_time, new DateTimeZone('UTC')); - - // Get regular slots - // Start with second slot as first slot is already added to keys. - $second_slot = $first_slot->add(new DateInterval("PT".$RAID_SLOTS."M")); - $dt_end = new DateTimeImmutable($end_time, new DateTimeZone('UTC')); - $regular_slots = new DatePeriod($second_slot, new DateInterval('PT'.$RAID_SLOTS.'M'), $dt_end); - - // Add regular slots. - foreach($regular_slots as $slot){ - $slot_end = $slot->add(new DateInterval('PT'.$config->RAID_LAST_START.'M')); - // Slot + $config->RAID_LAST_START before end_time? - if($slot_end < $dt_end) { - debug_log($slot, 'Regular slot:'); - // Add regular slot. - if($slot >= $dt_now) { - $slot = $slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - - // Set last slot for later. - $last_slot = new DateTimeImmutable($slot, new DateTimeZone('UTC')); - } else { - // Set last slot for later. - $slot = $slot->format('Y-m-d H:i:s'); - $last_slot = new DateTimeImmutable($slot, new DateTimeZone('UTC')); - } - } - } - - // Add raid last start slot - // Set end_time to last extra slot, subtract $config->RAID_LAST_START minutes and round down to earlier 5 minutes. - $last_extra_slot = $dt_end; - $last_extra_slot = $last_extra_slot->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')); - $s = 5 * 60; - $last_extra_slot = $last_extra_slot->setTimestamp($s * floor($last_extra_slot->getTimestamp() / $s)); - //$time_to_last_slot = $last_extra_slot->diff($last_slot)->format("%a"); - - // Last extra slot not conflicting with last slot and time to last regular slot larger than RAID_LAST_START? - //if($last_extra_slot > $last_slot && $time_to_last_slot > $config->RAID_LAST_START) - - // Log last and last extra slot. - debug_log($last_slot, 'Last slot:'); - debug_log($last_extra_slot, 'Last extra slot:'); - - // Last extra slot not conflicting with last slot - if($last_extra_slot > $last_slot) { - // Add last extra slot - if($last_extra_slot >= $dt_now) { - $slot = $last_extra_slot->format('Y-m-d H:i:s'); - $keys_time[] = array( - 'text' => dt2time($slot), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($slot, 'YmdHis') - ); - } - } - - // Attend raid at any time - if($config->RAID_ANYTIME) - { - $keys_time[] = array( - 'text' => getPublicTranslation('anytime'), - 'callback_data' => $raid['id'] . ':vote_time:0' - ); - } - } - // Add time keys. - $buttons_time = inline_key_array($keys_time, 4); - - // Hidden participants? - if($config->RAID_POLL_HIDE_USERS_TIME > 0) { - if($config->RAID_ANYTIME) { - $hide_users_sql = "AND (attend_time > (UTC_TIMESTAMP() - INTERVAL " . $config->RAID_POLL_HIDE_USERS_TIME . " MINUTE) OR attend_time = '".ANYTIME."')"; - } else { - $hide_users_sql = "AND attend_time > (UTC_TIMESTAMP() - INTERVAL " . $config->RAID_POLL_HIDE_USERS_TIME . " MINUTE)"; - } - } else { - $hide_users_sql = ""; - } - - // Get participants - $rs = my_query( - " - SELECT count(attend_time) AS count, - sum(pokemon = '0') AS count_any_pokemon, - sum(pokemon = '{$raid_pokemon}') AS count_raid_pokemon - FROM attendance - WHERE raid_id = {$raid['id']} - $hide_users_sql - AND attend_time IS NOT NULL - AND raid_done != 1 - AND cancel != 1 - " - ); - - $row = $rs->fetch(); - - // Count participants and participants by pokemon - $count_pp = $row['count']; - $count_any_pokemon = $row['count_any_pokemon']; - $count_raid_pokemon = $row['count_raid_pokemon']; - - // Write to log. - debug_log('Participants for raid with ID ' . $raid['id'] . ': ' . $count_pp); - debug_log('Participants who voted for any pokemon: ' . $count_any_pokemon); - debug_log('Participants who voted for ' . $raid_pokemon . ': ' . $count_raid_pokemon); - - // Zero Participants? Show only time buttons! - if($count_pp == 0) { - $keys = $buttons_time; - } else { - // Init keys pokemon array. - $buttons_pokemon = []; - - // Show pokemon keys only if the raid boss is an egg - if(in_array($raid_pokemon_id, $GLOBALS['eggs'])) { - // Get pokemon from database - $raid_spawn = dt2time($raid['spawn'], 'Y-m-d H:i'); // Convert utc spawntime to local time - $raid_bosses = get_raid_bosses($raid_spawn, $raid_level); - - // Get eggs. - $eggs = $GLOBALS['eggs']; - - if(count($raid_bosses) > 2) { - // Add key for each raid level - foreach($raid_bosses as $pokemon) { - if(in_array($pokemon['pokedex_id'], $eggs)) continue; - $buttons_pokemon[] = array( - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), - 'callback_data' => $raid['id'] . ':vote_pokemon:' . $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] - ); - } - - // Add button if raid boss does not matter - $buttons_pokemon[] = array( - 'text' => getPublicTranslation('any_pokemon'), - 'callback_data' => $raid['id'] . ':vote_pokemon:0' - ); - - // Finally add pokemon to keys - $buttons_pokemon = inline_key_array($buttons_pokemon, 2); - } - } - - // Init keys array - $keys = []; - - if($raid['event_poll_template'] != null) $template = json_decode($raid['event_poll_template']); - else $template = $config->RAID_POLL_UI_TEMPLATE; - $r=0; - foreach($template as $row) { - foreach($row as $key) { - $v_name = 'buttons_'.$key; - if($key == 'teamlvl' or $key == 'pokemon' or $key == 'time') { - // Some button variables are "blocks" of keys, process them here - if(empty(${$v_name})) continue; - foreach(${$v_name} as $teamlvl) { - if(!isset($keys[$r])) $keys[$r] = []; - $keys[$r] = array_merge($keys[$r],$teamlvl); - $r++; - } - $r--; - }else { - if(empty(${$v_name})) continue; - $keys[$r][] = ${$v_name}; - } - } - if(!empty($keys[$r][0])) $r++; - } - } - - // Return the keys. - return $keys; + $hide_users_sql = 'AND attend_time > (UTC_TIMESTAMP() - INTERVAL ' . $config->RAID_POLL_HIDE_USERS_TIME . ' MINUTE)'; + } + } + + // Get participants + $rs = my_query( + ' + SELECT count(attend_time) AS count, + sum(pokemon = 0) AS count_any_pokemon, + sum(pokemon = ?) AS count_raid_pokemon + FROM attendance + WHERE raid_id = ? + ' . $hide_users_sql . ' + AND attend_time IS NOT NULL + AND raid_done != 1 + AND cancel != 1 + ', [$raid_pokemon, $raid['id']] + ); + + $row = $rs->fetch(); + + // Count participants and participants by pokemon + $count_pp = $row['count']; + $count_any_pokemon = $row['count_any_pokemon']; + $count_raid_pokemon = $row['count_raid_pokemon']; + + // Write to log. + debug_log('Participants for raid with ID ' . $raid['id'] . ': ' . $count_pp); + debug_log('Participants who voted for any pokemon: ' . $count_any_pokemon); + debug_log('Participants who voted for ' . $raid_pokemon . ': ' . $count_raid_pokemon); + + // Zero Participants? Show only time buttons! + if($row['count'] == 0) { + return $buttons['time']; + } + + // Init keys pokemon array. + $buttons['pokemon'] = []; + // Show pokemon keys only if the raid boss is an egg + if(in_array($raid_pokemon_id, $GLOBALS['eggs'])) { + // Get pokemon from database + $raid_spawn = dt2time($raid['spawn'], 'Y-m-d H:i'); // Convert utc spawntime to local time + $raid_bosses = get_raid_bosses($raid_spawn, $raid_level); + + if(count($raid_bosses) > 2) { + // Add key for each raid level + foreach($raid_bosses as $pokemon) { + if(in_array($pokemon['pokedex_id'], $GLOBALS['eggs'])) continue; + $buttons['pokemon'][] = array( + 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), + 'callback_data' => $raid['id'] . ':vote_pokemon:' . $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] + ); + } + + // Add button if raid boss does not matter + $buttons['pokemon'][] = array( + 'text' => getPublicTranslation('any_pokemon'), + 'callback_data' => $raid['id'] . ':vote_pokemon:0' + ); + + // Finally add pokemon to keys + $buttons['pokemon'] = inline_key_array($buttons['pokemon'], 2); + } + } + + // Init keys array + $keys = []; + + $template = $config->RAID_POLL_UI_TEMPLATE; + if($raid['event_poll_template'] != null) $template = json_decode($raid['event_poll_template']); + $r = 0; + foreach($template as $row) { + foreach($row as $key) { + $v_name = 'buttons_'.$key; + if(!isset($buttons[$key]) or empty($buttons[$key])) continue; + if($key == 'teamlvl' or $key == 'pokemon' or $key == 'time') { + // Some button variables are "blocks" of keys, process them here + foreach($buttons[$key] as $teamlvl) { + if(!isset($keys[$r])) $keys[$r] = []; + $keys[$r] = array_merge($keys[$r],$teamlvl); + $r++; } + $r--; + continue; + } + $keys[$r][] = $buttons[$key]; + } + if(!empty($keys[$r][0])) $r++; + } + + // Return the keys. + return $keys; +} + +/** + * Get active raid bosses at a certain time. + * @param $time - string, datetime, local time + * @param $raid_level - ENUM('1', '2', '3', '4', '5', '6', 'X') + * @return array + */ +function get_raid_bosses($time, $raid_level) +{ + // Get raid level from database + $rs = my_query( + ' + SELECT DISTINCT pokedex_id, pokemon_form_id + FROM raid_bosses + WHERE ? BETWEEN date_start AND date_end + AND raid_level = ? + ', [$time, $raid_level]); + debug_log('Checking active raid bosses for raid level '.$raid_level.' at '.$time.':'); + $raid_bosses = []; + $egg_found = false; + while ($result = $rs->fetch()) { + $raid_bosses[] = $result; + if($result['pokedex_id'] == '999'.$raid_level) $egg_found = true; + debug_log('Pokedex id: '.$result['pokedex_id'].' | Form id: '.$result['pokemon_form_id']); + } + if(!$egg_found) $raid_bosses[] = ['pokedex_id' => '999'.$raid_level, 'pokemon_form_id' => 0]; // Add egg if it wasn't found from db + return $raid_bosses; +} + +/** + * Get active raid bosses at a certain time. + * @param $RAID_SLOTS - int, length of the timeslot + * @param $raid + * @return array + */ +function generateTimeslotKeys($RAID_SLOTS, $raid) { + global $config; + // Get current time. + $now_helper = new DateTimeImmutable('now', new DateTimeZone('UTC')); + $now_helper = $now_helper->format('Y-m-d H:i') . ':00'; + $dt_now = new DateTimeImmutable($now_helper, new DateTimeZone('UTC')); + + // Get direct start slot + $direct_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); + $directStartMinutes = $direct_slot->format('i'); + + // Get first raidslot rounded up to the next 5 minutes + $five_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); + $minute = $directStartMinutes % 5; + $diff = ($minute != 0) ? 5 - $minute : 5; + $five_slot = $five_slot->add(new DateInterval('PT'.$diff.'M')); + + // Get first regular raidslot + $first_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); + $minute = $directStartMinutes % $RAID_SLOTS; + + // Count minutes to next raidslot multiple minutes if necessary + if($minute != 0) { + $diff = $RAID_SLOTS - $minute; + $first_slot = $first_slot->add(new DateInterval('PT'.$diff.'M')); + } + + // Write slots to log. + debug_log($direct_slot, 'Direct start slot:'); + debug_log($five_slot, 'Next 5 Minute slot:'); + debug_log($first_slot, 'First regular slot:'); + $keys_time = []; + // Add button for when raid starts time + if($config->RAID_DIRECT_START && $direct_slot >= $dt_now) { + $keys_time[] = array( + 'text' => dt2time($direct_slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $direct_slot->format('YmdHis') + ); + } + // Add five minutes slot + if($five_slot >= $dt_now && (empty($keys_time) || (!empty($keys_time) && $direct_slot != $five_slot))) { + $keys_time[] = array( + 'text' => dt2time($five_slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $five_slot->format('YmdHis') + ); + } + // Add the first normal slot + if($first_slot >= $dt_now && $first_slot != $five_slot) { + $keys_time[] = array( + 'text' => dt2time($first_slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $first_slot->format('YmdHis') + ); + } + + // Init last slot time. + $last_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); + + // Get regular slots + // Start with second slot as first slot is already added to keys. + $dt_end = new DateTimeImmutable($raid['end_time'], new DateTimeZone('UTC')); + $regular_slots = new DatePeriod($first_slot, new DateInterval('PT'.$RAID_SLOTS.'M'), $dt_end->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')), DatePeriod::EXCLUDE_START_DATE); + info_log($regular_slots); + // Add regular slots. + foreach($regular_slots as $slot){ + debug_log($slot, 'Regular slot:'); + // Add regular slot. + if($slot >= $dt_now) { + $keys_time[] = array( + 'text' => dt2time($slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $slot->format('YmdHis') + ); } + // Set last slot for later. + $last_slot = $slot; + } + + // Add raid last start slot + // Set end_time to last extra slot, subtract $config->RAID_LAST_START minutes and round down to earlier 5 minutes. + $last_extra_slot = $dt_end; + $last_extra_slot = $last_extra_slot->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')); + $s = 5 * 60; + $last_extra_slot = $last_extra_slot->setTimestamp($s * floor($last_extra_slot->getTimestamp() / $s)); + + // Log last and last extra slot. + debug_log($last_slot, 'Last slot:'); + debug_log($last_extra_slot, 'Last extra slot:'); + + // Last extra slot not conflicting with last slot + if($last_extra_slot > $last_slot && $last_extra_slot >= $dt_now) { + // Add last extra slot + $keys_time[] = array( + 'text' => dt2time($last_extra_slot->format('Y-m-d H:i:s')), + 'callback_data' => $raid['id'] . ':vote_time:' . $last_extra_slot->format('YmdHis') + ); + } + + // Attend raid at any time + if($config->RAID_ANYTIME) { + $keys_time[] = array( + 'text' => getPublicTranslation('anytime'), + 'callback_data' => $raid['id'] . ':vote_time:0' + ); + } + return $keys_time; } ?> From c9ea7772414f4c14f2b0126693f8d27e6ada3694 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 15:35:18 +0200 Subject: [PATCH 150/367] Forgot to remove this --- logic/keys_vote.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 8859f58f..8a68fe47 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -374,7 +374,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { // Start with second slot as first slot is already added to keys. $dt_end = new DateTimeImmutable($raid['end_time'], new DateTimeZone('UTC')); $regular_slots = new DatePeriod($first_slot, new DateInterval('PT'.$RAID_SLOTS.'M'), $dt_end->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')), DatePeriod::EXCLUDE_START_DATE); - info_log($regular_slots); + // Add regular slots. foreach($regular_slots as $slot){ debug_log($slot, 'Regular slot:'); From 59c3287389e3a1c0df11dc671822f5f653149f55 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 21:16:05 +0200 Subject: [PATCH 151/367] Fixed gym note deletion feature --- mods/gym_edit_details.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index ede761ea..9d107e3f 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -31,15 +31,9 @@ // Did we receive a call to edit some gym data that requires a text input if(in_array($action, ['name','note','gps','addr'])) { if($value == 'd') { - my_query("DELETE FROM user_input WHERE id=:delete_id'", ['delete_id' => $delete_id]); + my_query("DELETE FROM user_input WHERE id = ?", [$delete_id]); if($action == 'note') { - $query = 'UPDATE gyms SET gym_note = NULL WHERE id = :id'; - $binds = [ - ':id' => $gym_id, - ]; - // Update the event note to raid table - $prepare = $dbh->prepare($query); - $prepare->execute($binds); + my_query('UPDATE gyms SET gym_note = NULL WHERE id = ?', [$gym_id]); $gym['gym_note'] = ''; } $msg = get_gym_details($gym, true); @@ -61,7 +55,7 @@ 'text' => getTranslation("abort"), 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() ]; - if($action == 'note' && !empty($gym['note'])) { + if($action == 'note' && !empty($gym['gym_note'])) { $keys[0][] = [ 'text' => getTranslation("delete"), 'callback_data' => $gym_id.':gym_edit_details:note-d-'.$dbh->lastInsertId() From 6851ec0048e3ba9a0a934bf48c873a558e8aea46 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 22:04:22 +0200 Subject: [PATCH 152/367] Only display each language once --- mods/bot_lang.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mods/bot_lang.php b/mods/bot_lang.php index d06bc214..020e6bce 100644 --- a/mods/bot_lang.php +++ b/mods/bot_lang.php @@ -38,11 +38,14 @@ ]; $callback_msg = $msg; } else { + $displayedLanguages = []; foreach($languages as $lang_tg => $lang_internal) { + if(in_array($lang_internal, $displayedLanguages)) continue; $keys[][] = [ 'text' => getTranslation('lang_name', $lang_internal), 'callback_data' => '0:bot_lang:'.$lang_tg ]; + $displayedLanguages[] = $lang_internal; } $keys[] = [ [ From 1b4a0845a23bd68642453715c192d6c0e9b04c5f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 16 Nov 2022 22:05:07 +0200 Subject: [PATCH 153/367] Added feature under `gym` for saving gym address from OSM/Google lookup --- lang/language.json | 39 ++++++++++++++++++++++++++++++++++ logic/get_gym_details.php | 36 +++++++++++++++++++------------- mods/gym_edit_details.php | 44 ++++++++++++++++++++++++++------------- 3 files changed, 89 insertions(+), 30 deletions(-) diff --git a/lang/language.json b/lang/language.json index 4b611e0d..dfbeb7e4 100644 --- a/lang/language.json +++ b/lang/language.json @@ -2898,6 +2898,19 @@ "FI": "salin osoite", "ES": "TRANSLATE" }, + "gym_stored_address": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Stored address", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tallennettu osoite", + "ES": "TRANSLATE" + }, "gym_address_instructions": { "NL": "Stuur me het nieuwe gym adres:", "DE": "TRANSLATE", @@ -2911,6 +2924,32 @@ "FI": "Lähetä minulle salin uusi osoite:", "ES": "TRANSLATE" }, + "gym_address_lookup_result": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Address lookup result", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Osoitehaun tulos", + "ES": "TRANSLATE" + }, + "gym_save_lookup_result": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Save lookup result", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tallenna osoitehaun tulos", + "ES": "TRANSLATE" + }, "select_raid_boss": { "NL": "Selecteer Raid baas", "DE": "Raid-Boss auswählen", diff --git a/logic/get_gym_details.php b/logic/get_gym_details.php index 19d0cd81..7833787a 100644 --- a/logic/get_gym_details.php +++ b/logic/get_gym_details.php @@ -10,27 +10,33 @@ function get_gym_details($gym, $extended = false) global $config; // Add gym name to message. $msg = '' . getTranslation('gym_details') . ':' . CR . CR; - $msg .= 'ID = ' . $gym['id'] . '' . CR; $msg .= getTranslation('gym') . ':' . SP; $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : '' . $config->RAID_EX_GYM_MARKER . ''; $msg .= ($gym['ex_gym'] ? $ex_raid_gym_marker . SP : '') . '' . $gym['gym_name'] . ''; $msg .= CR; + if($extended) $msg .= getTranslation('gym_stored_address') . CR; // Add maps link to message. - if (!empty($gym['address'])) { - $msg .= mapslink($gym) . CR; - } else { - // Get the address. - $addr = get_address($gym['lat'], $gym['lon']); - $address = format_address($addr); + $address = ''; + $lookupAddress = format_address(get_address($gym['lat'], $gym['lon'])); + if(!empty($gym['address'])) { + $address = $gym['address']; + } elseif(!$extended) { + $address = $lookupAddress; + } - //Only store address if not empty - if(!empty($address)) { - //Use new address - $msg .= mapslink($gym,$address) . CR; - } else { - //If no address is found show maps link - $msg .= mapslink($gym,'1') . CR; - } + //Only store address if not empty + if(!empty($address)) { + //Use new address + $msg .= mapslink($gym, $address) . CR; + } elseif(!$extended) { + //If no address is found show maps link + $msg .= mapslink($gym, '1') . CR; + }else { + $msg .= getTranslation('none') . CR; + } + if($extended) { + $msg .= getTranslation('gym_address_lookup_result') . ': ' . CR; + $msg .= mapslink($gym, $lookupAddress) . CR; } // Add or hide gym note. diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index 9d107e3f..01aa286b 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -31,20 +31,29 @@ // Did we receive a call to edit some gym data that requires a text input if(in_array($action, ['name','note','gps','addr'])) { if($value == 'd') { - my_query("DELETE FROM user_input WHERE id = ?", [$delete_id]); + my_query('DELETE FROM user_input WHERE id = :id', ['id' => $delete_id]); if($action == 'note') { - my_query('UPDATE gyms SET gym_note = NULL WHERE id = ?', [$gym_id]); + my_query('UPDATE gyms SET gym_note = NULL WHERE id = :id', ['id' => $gym_id]); $gym['gym_note'] = ''; } $msg = get_gym_details($gym, true); $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); + }elseif($value == 'e') { + my_query('DELETE FROM user_input WHERE id = ?', [$delete_id]); + if($action == 'addr') { + $addr = format_address(get_address($gym['lat'], $gym['lon'])); + my_query('UPDATE gyms SET address = :addr WHERE id = :id', ['addr' => $addr, 'id' => $gym_id]); + $gym['address'] = $addr; + } + $msg = get_gym_details($gym, true); + $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); }else { // Create an entry to user_input table $userid = $update['callback_query']['from']['id']; $modifiers = json_encode(array("id" => $gym_id, "value" => $action, "old_message_id" => $update['callback_query']['message']['message_id'])); $handler = "save_gym_info"; - my_query("INSERT INTO user_input SET user_id = :userid, modifiers = :modifiers, handler = :handler", [':userid' => $userid, ':modifiers' => $modifiers, ':handler' => $handler]); + my_query('INSERT INTO user_input SET user_id = :userid, modifiers = :modifiers, handler = :handler', [':userid' => $userid, ':modifiers' => $modifiers, ':handler' => $handler]); $msg = get_gym_details($gym, true); if($action == 'addr') $instructions = 'gym_address_instructions'; else $instructions = 'gym_'.$action.'_instructions'; @@ -52,34 +61,39 @@ if($action == 'gps') $msg .= CR. getTranslation('gym_gps_example'); $keys[0][] = [ - 'text' => getTranslation("abort"), - 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() - ]; + 'text' => getTranslation('abort'), + 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() + ]; if($action == 'note' && !empty($gym['gym_note'])) { $keys[0][] = [ - 'text' => getTranslation("delete"), + 'text' => getTranslation('delete'), 'callback_data' => $gym_id.':gym_edit_details:note-d-'.$dbh->lastInsertId() - ]; + ]; + } + if($action == 'addr') { + $keys[0][] = [ + 'text' => getTranslation('gym_save_lookup_result'), + 'callback_data' => $gym_id.':gym_edit_details:addr-e-'.$dbh->lastInsertId() + ]; } } }else { if($action == 'show') { - $gym['show_gym'] = $value; $table = 'show_gym'; }else if($action == 'ex') { - $gym['ex_gym'] = $value; $table = 'ex_gym'; }else if($action == 'abort') { - my_query("DELETE FROM user_input WHERE id = :value", ['value' => $value]); + my_query('DELETE FROM user_input WHERE id = :value', ['value' => $value]); } if(isset($table)) { my_query( - " + ' UPDATE gyms - SET $table = $value - WHERE id = {$gym_id} - " + SET ' . $table . ' = :value + WHERE id = :gym_id + ', ['value' => $value, 'gym_id' => $gym_id] ); + $gym[$table] = $value; } $msg = get_gym_details($gym, true); $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); From da777938d4a06962f4fd823981ccb35b207e1884 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 17 Nov 2022 23:39:59 +0200 Subject: [PATCH 154/367] Added `events` command Simple Telegram UI for managing the settings in `events`-table in database. This feature probably sees so little use it's not worth making translations and explanations for the values --- commands/events.php | 43 +++++++++ commands/help.php | 2 + docs/config.rst | 6 ++ docs/usage.rst | 5 ++ lang/help.json | 14 +++ lang/language.json | 143 +++++++++++++++++++++++++++++ mods/events.php | 52 +++++++++++ mods/events_add.php | 72 +++++++++++++++ mods/events_manage.php | 200 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 537 insertions(+) create mode 100644 commands/events.php create mode 100644 mods/events.php create mode 100644 mods/events_add.php create mode 100644 mods/events_manage.php diff --git a/commands/events.php b/commands/events.php new file mode 100644 index 00000000..db1d5281 --- /dev/null +++ b/commands/events.php @@ -0,0 +1,43 @@ +accessCheck($update, 'event-manage'); + +$q = my_query('SELECT * FROM events'); + +$msg = '' . getTranslation('events_manage') . '' . CR; + +foreach($q->fetchAll() as $event) { + if($event['id'] == EVENT_ID_EX) $event['name'] = getTranslation('Xstars'); + if(empty($event['description'])) $event['description'] = '' . getTranslation('events_no_description') . ''; + $msg .= '' . $event['name'] . '' . CR; + $msg .= $event['description'] . CR . CR; +} + +$keys = []; +$keys[] = [ + [ + 'text' => getTranslation('events_manage'), + 'callback_data' => '0:events:0', + ] +]; +$keys[] = [ + [ + 'text' => getTranslation('events_create'), + 'callback_data' => '0:events_add:0', + ] +]; +$keys[] = [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1', + ] +]; +// Send message. +send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/help.php b/commands/help.php index 3204789b..f6fb1f4a 100644 --- a/commands/help.php +++ b/commands/help.php @@ -23,6 +23,8 @@ $permissions[] = 'config-get'; $permissions[] = 'config-set'; $permissions[] = 'pokedex'; + $permissions[] = 'history'; + $permissions[] = 'event-manage'; $permissions[] = 'help'; } else { // Get permissions. diff --git a/docs/config.rst b/docs/config.rst index 03b82d95..28a1e830 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -745,6 +745,12 @@ A few examples for access files can be found below the permission overview table * - - - + * - Events + - Show help ``/events`` + - ``event-manage`` + * - + - + - * - Tutorial - Allow users to access tutorial - ``tutorial`` diff --git a/docs/usage.rst b/docs/usage.rst index d8ad110e..6cd017c7 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -276,6 +276,11 @@ Command: /history Tool for admins to view history of raids that had at least one person signed up for it. +Command: /events +^^^^^^^^^^^^^^^^ + +Tool for admins to edit raid events. The UI is very simple and for some stuff you need to refer to this documentation. + Command: /gym ^^^^^^^^^^^^^ diff --git a/lang/help.json b/lang/help.json index c5466870..3485edf9 100644 --- a/lang/help.json +++ b/lang/help.json @@ -310,5 +310,19 @@ "PL": "TRANSLATE", "FI": "/history - Listaa päättyneet raidit joissa oli osallistujia", "ES": "TRANSLATE" + }, + "help_event-manage": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "/events - Manage raid events", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "/events - Hallitse raiditapahtumia", + "ES": "TRANSLATE" } + } diff --git a/lang/language.json b/lang/language.json index dfbeb7e4..abc17c92 100644 --- a/lang/language.json +++ b/lang/language.json @@ -4562,6 +4562,149 @@ "FI": "Lisää ilmoituskohtaisia lisätietoja tapahtumaan liittyen. (esim. reitti)", "ES": "Agrega más información para este anuncio específico sobre el evento. (por ejemplo: ruta)" }, + "events_manage": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Manage events", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Hallitse tapahtumia", + "ES": "TRANSLATE" + }, + "events_create": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Create a new event", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Luo uusi tapahtuma", + "ES": "TRANSLATE" + }, + "events_created": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Event created succesfully!", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tapahtuma luotu onnistuneesti!", + "ES": "TRANSLATE" + }, + "events_give_name": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Give the event a name", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Anna tapahtuman nimi", + "ES": "TRANSLATE" + }, + "events_give_description": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Give the event a description", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Anna tapahtuman lisätiedot", + "ES": "TRANSLATE" + }, + "events_no_description": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "No description", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Ei kuvausta", + "ES": "TRANSLATE" + }, + "events_edit_name": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Edit event name", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Muokkaa tapahtuman nimeä", + "ES": "TRANSLATE" + }, + "events_edit_description": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Edit event description", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Muokkaa tapahtuman kuvausta", + "ES": "TRANSLATE" + }, + "events_edit_raid_poll": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Edit event raid poll", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Muokkaa tapahtuman raidi-ilmoitusta", + "ES": "TRANSLATE" + }, + "events_delete": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Delete event", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Poista tapahtuma", + "ES": "TRANSLATE" + }, + "events_delete_confirmation": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Do you really want to delete this event?", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Haluatko varmasti poistaa tämän tapahtuman?", + "ES": "TRANSLATE" + }, "Participate": { "NL": "Deelnemer", "DE": "Teilnehmen", diff --git a/mods/events.php b/mods/events.php new file mode 100644 index 00000000..39ffcf90 --- /dev/null +++ b/mods/events.php @@ -0,0 +1,52 @@ +accessCheck($update, 'event-manage'); + +$id = $data['id']; +$arg = $data['arg']; + +$keys = []; +$callback_response = 'OK'; + +// Manage events +$q = my_query('SELECT * FROM events'); +$msg = '' . getTranslation('events_manage') . '' . CR; +foreach($q->fetchAll() as $event) { + if($event['id'] == EVENT_ID_EX) $event['name'] = getTranslation('Xstars'); + if(empty($event['description'])) $event['description'] = '' . getTranslation('events_no_description') . ''; + $msg .= '' . $event['name'] . '' . CR; + $msg .= $event['description'] . CR . CR; + $keys[] = [ + [ + 'text' => $event['name'], + 'callback_data' => $event['id'] . ':events_manage:0', + ] + ]; +} +$keys[] = [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1', + ] +]; + +$tg_json = []; + +// Answer callback. +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + +// Edit the message. +$tg_json[] = edit_message($update, $msg, $keys, false, true); + +// Telegram multicurl request. +curl_json_multi_request($tg_json); + +// Exit. +exit(); diff --git a/mods/events_add.php b/mods/events_add.php new file mode 100644 index 00000000..567fe5ee --- /dev/null +++ b/mods/events_add.php @@ -0,0 +1,72 @@ +accessCheck($update, 'event-manage'); + +$keys = []; +$callback_response = 'OK'; +$userId = $update['callback_query']['from']['id'] ?? $update['message']['from']['id']; + +if(isset($modifiers)) { + $value = htmlspecialchars(trim($update['message']['text'])); + my_query('INSERT INTO events SET name=?',[$value]); + $eventId = $dbh->lastInsertId(); + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + $callback_response = getTranslation('done'); + editMessageText($modifiers['old_message_id'], getTranslation('events_created'), [], $userId); + $msg = '' . getTranslation('events_created') . '' . CR; + $msg .= $value; + $keys[] = [ + [ + 'text' => getTranslation('next'), + 'callback_data' => $eventId . ':events_manage:0', + ] + ]; +}else { + if($data['arg'] == 0) { + // Add a new event + $msg = '' . getTranslation('events_create') . '' . CR; + $msg .= getTranslation('events_give_name') . ':'; + + $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id']]); + $userId = $update['callback_query']['from']['id']; + + // Data for handling response from the user + my_query('INSERT INTO user_input SET user_id=?, handler=\'events_add\', modifiers=?', [$userId, $modifiers]); + + $keys[] = [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:events_add:a', + ] + ]; + }elseif($data['arg'] == 'a') { + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + answerCallbackQuery($update['callback_query']['id'], 'OK'); + editMessageText($update['callback_query']['message']['message_id'], getTranslation('action_aborted'), [], $userId); + exit; + } +} + +$tg_json = []; + +if(isset($update['callback_query'])) { + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + // Edit the message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); +}else { + $tg_json[] = send_message($update['message']['chat']['id'], $msg, $keys, false, true); +} + +// Telegram multicurl request. +curl_json_multi_request($tg_json); + +// Exit. +exit(); diff --git a/mods/events_manage.php b/mods/events_manage.php new file mode 100644 index 00000000..932b1918 --- /dev/null +++ b/mods/events_manage.php @@ -0,0 +1,200 @@ +accessCheck($update, 'event-manage'); + +$columnSettings = [ + 'vote_key_mode' => ['allowed' => [0,1], 'default' => 0, 'nullable' => false], + 'hide_raid_picture' => ['allowed' => [0,1], 'default' => 0, 'nullable' => false], + 'pokemon_title' => ['allowed' => [0,1,2], 'default' => 1, 'nullable' => false], + 'time_slots' => ['nullable' => true], + 'raid_duration' => ['nullable' => false], + 'poll_template' => ['nullable' => true], +]; + +$eventId = $data['id'] ?? false; +$arg = $data['arg'] ?? false; +$subArg = ($arg !== false) ? explode('-', $arg) : []; +$keys = []; +$callback_response = 'OK'; +$userId = $update['callback_query']['from']['id'] ?? $update['message']['from']['id']; + +// Process user input +if(isset($modifiers) && isset($modifiers['action'])) { + $value = htmlspecialchars(trim($update['message']['text'])); + if($modifiers['action'] == 1) { + // User input is new event name + $column = 'name'; + $arg = 0; + }else if($modifiers['action'] == 2) { + // User input is new description + $column = 'description'; + $arg = 0; + }else if($modifiers['action'] == 3) { + // User input is raid poll settings + $column = $modifiers['column']; + // Validate input + if($columnSettings[$column]['nullable'] && strtolower($value) == 'null') { + $value = NULL; + } + if(in_array($column, ['vote_key_mode','time_slots','raid_duration','hide_raid_picture','pokemon_title']) && $value != NULL) { + $value = preg_replace('/\D/', '', $value); + if(isset($columnSettings[$column]['allowed']) && !in_array($value, $columnSettings[$column]['allowed'])) $value = $columnSettings[$column]['default']; + }elseif($column == 'poll_template' && $value != NULL) { + $rows = preg_split("/\r\n|\n|\r/", $value); + $inputArray = []; + $i = 0; + // Convert input into json array + foreach($rows as $row) { + $buttons = explode(',', $row); + foreach($buttons as $button) { + $button = trim($button); + if(in_array($button, ['alone', 'extra', 'extra_alien', 'remote', 'inv_plz', 'can_inv', 'ex_inv', 'teamlvl', 'time', 'pokemon', 'refresh', 'alarm', 'here', 'late', 'done', 'cancel'])) { + $inputArray[$i][] = $button; + } + } + $i++; + } + $value = (strtolower($value) == 'null' ? NULL : json_encode($inputArray)); + } + $arg = 3; + } + $eventId = $modifiers['eventId']; + my_query('UPDATE events SET ' . $column . ' = ? WHERE id=?', [$value, $eventId]); + $callback_response = getTranslation('done'); + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + editMessageText($modifiers['old_message_id'], getTranslation('updated'), [], $userId); +} + +$q = my_query('SELECT * FROM events where id = ?', [$eventId]); +$event = $q->fetch(); +if($eventId == EVENT_ID_EX) { + $event['name'] = getTranslation('Xstars'); +} +if(empty($event['description'])) $event['description'] = '' . getTranslation('events_no_description') . ''; + +$msg = '' . getTranslation('events_manage') . '' . CR . CR; +$msg .= '' . $event['name'] . '' . CR; +$msg .= $event['description'] . CR . CR; + +if($arg == 0 || $arg == 'a') { + if($arg == 'a') { + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + $callback_response = getTranslation('action_aborted'); + } + if($eventId != EVENT_ID_EX) + $keys = universal_key($keys, $eventId, 'events_manage', '1', getTranslation('events_edit_name')); + $keys = universal_key($keys, $eventId, 'events_manage', '2', getTranslation('events_edit_description')); + $keys = universal_key($keys, $eventId, 'events_manage', '3', getTranslation('events_edit_raid_poll')); + if($eventId != EVENT_ID_EX) + $keys = universal_key($keys, $eventId, 'events_manage', '4', getTranslation('events_delete')); + + $keys[] = [ + universal_inner_key($keys, '0', 'events', '0', getTranslation('back')), + universal_inner_key($keys, '0', 'exit', '0', getTranslation('done')) + ]; + +// Edit event name +}else if($arg == 1) { + $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id'],'action'=>1,'eventId'=>$eventId]); + my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); + + $msg .= '' . getTranslation('events_edit_name') . '' . CR; + $msg .= getTranslation('events_give_name') . ':' . CR; + $keys = universal_key($keys, $eventId, 'events_manage', 'a', getTranslation('abort')); + +// Edit event description +}else if($arg == 2) { + $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id'],'action'=>2,'eventId'=>$eventId]); + my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); + $msg .= '' . getTranslation('events_edit_description') . '' . CR; + $msg .= getTranslation('events_give_description') . ':'; + $keys = universal_key($keys, $eventId, 'events_manage', 'a', getTranslation('abort')); + +// Edt event raid poll settings +}else if($arg == 3) { + my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + $templateArray = ($event['poll_template'] == NULL) ? $config->RAID_POLL_UI_TEMPLATE : json_decode($event['poll_template'], true); + $event['poll_template'] = templateJsonToString($templateArray); + $printColumns = ['vote_key_mode','time_slots','raid_duration','hide_raid_picture','pokemon_title','poll_template']; + + $msg .= 'https://pokemonraidbot.readthedocs.io/en/latest/config.html#event-raids' . CR; + $msg .= 'https://pokemonraidbot.readthedocs.io/en/latest/config.html#raid-poll-design-and-layout' . CR . CR; + foreach($printColumns as $column) { + $msg .= $column . ': '; + $msg .= ($column == 'poll_template' ? CR : ''); + $msg .= '' . ($event[$column] === NULL ? 'NULL' : $event[$column]) . '' . CR; + $keys = universal_key($keys, $eventId, 'events_manage', 'e-'.$column, $column); + } + $keys[] = [ + universal_inner_key($keys, $eventId, 'events_manage', '0', getTranslation('back')), + universal_inner_key($keys, '0', 'exit', '1', getTranslation('done')) + ]; + +// Delete event confirmation +}else if($arg == 4) { + $msg .= '' . getTranslation('events_delete_confirmation') . '' . CR; + $keys[] = [ + universal_inner_key($keys, $eventId, 'events_manage', 'd', getTranslation('yes')), + universal_inner_key($keys, $eventId, 'events_manage', '0', getTranslation('no')) + ]; + +// Delete event +}else if($arg == 'd') { + if($eventId != EVENT_ID_EX) my_query('DELETE FROM events WHERE id=?', [$eventId]); + $data['id'] = $data['arg'] = 0; + include(ROOT_PATH . '/mods/events.php'); + exit; + +// Prompt for raid poll value editing +}else if($subArg[0] == 'e') { + $valueToEdit = $subArg[1]; + $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id'],'action'=>3,'column'=>$valueToEdit,'eventId'=>$eventId]); + my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); + + if($valueToEdit == 'poll_template') { + $templateArray = ($event['poll_template'] == NULL) ? $config->RAID_POLL_UI_TEMPLATE : json_decode($event['poll_template'], true); + $event['poll_template'] = templateJsonToString($templateArray); + } + + $msg .= $valueToEdit . CR; + $msg .= getTranslation('old_value') . CR; + $msg .= '' . ($event[$valueToEdit] === NULL ? 'NULL' : $event[$valueToEdit]) . '' . CR . CR; + $msg .= getTranslation('new_value'); + $keys = universal_key($keys, $eventId, 'events_manage', '3', getTranslation('back')); + +} + +$tg_json = []; + +if(isset($update['callback_query'])) { + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + // Edit the message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); +}else { + $tg_json[] = send_message($update['message']['chat']['id'], $msg, $keys, false, true); +} + +// Telegram multicurl request. +curl_json_multi_request($tg_json); + +function templateJsonToString($templateArray) { + $templateString = ''; + foreach($templateArray as $line) { + foreach($line as $button) { + $templateString .= $button; + $templateString .= ','; + } + $templateString = rtrim($templateString, ',') . CR; + } + return $templateString; +} +// Exit. +exit(); From a03d32e0f5b1401e31d6253dbdb8189f07e7601f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 21 Nov 2022 12:49:42 +0200 Subject: [PATCH 155/367] Cleanup I went through pretty much all the code in an attempt to make it easier to work with. This was done: - more consistent indentation depths - linting - inverted most of the escape clauses to get rid of indentations - moved constants.php, commads/* and logic/* to their respective duplicates in the root folder - bug fixes - added a new function to make it easier to pass data in callback_query - converted most of the rogue pdo statements to using my_query() so they too get logged - edited all the sql queries to use binds instead of having the variables baked into the query string - removed most of the includes from logic.php and moved them to where they're needed --- commands/delete.php | 114 +- commands/events.php | 29 +- commands/exreport.php | 118 +- commands/friendsearch.php | 17 +- commands/get.php | 70 + commands/gym.php | 63 +- commands/gymname.php | 117 +- commands/help.php | 115 +- commands/history.php | 10 +- commands/list.php | 13 +- commands/listall.php | 29 +- commands/overview.php | 21 +- commands/pokedex.php | 122 +- commands/pokemon.php | 138 +- commands/raid_from_webhook.php | 644 ++++----- commands/set.php | 178 +++ commands/start.php | 156 +- commands/trainer.php | 83 +- commands/tutorial.php | 24 +- config/defaults-config.json | 1 - config/defaults-telegram.json | 2 +- config/tutorial.php.example | 2 - constants.php | 91 +- core/bot/apikey.php | 26 +- core/bot/cleanup_collect.php | 39 +- core/bot/cleanup_run.php | 145 +- core/bot/commands.php | 73 +- core/bot/config.php | 4 +- core/bot/constants.php | 31 - core/bot/db.php | 62 +- core/bot/ddos.php | 188 ++- core/bot/error_handlers.php | 2 +- core/bot/importal.php | 201 ++- core/bot/logic.php | 13 - core/bot/logic/bearer_token.php | 33 - core/bot/logic/bot_upgrade_check.php | 120 -- core/bot/logic/date_util.php | 105 -- core/bot/logic/download_Portal_Image.php | 42 - core/bot/logic/geo_api.php | 247 ---- core/bot/modules.php | 22 +- core/bot/requirements.php | 21 +- core/bot/user.php | 229 ++- core/bot/version.php | 20 +- core/commands/get.php | 75 - core/commands/set.php | 182 --- core/telegram/functions.php | 1102 +++++++------- .../raid_hour_creator.php | 4 - .../share_event_raids.php | 3 - core/tools/hash.php | 1 - core/tools/set_commands.php | 2 +- docs/config.rst | 8 +- docs/development.rst | 6 + getPokemonIcons.php | 286 ++-- getTranslations.php | 144 +- index.php | 159 ++- lang/language.json | 33 +- lang/pokemon_moves.json | 1265 +---------------- logic.php | 60 +- logic/active_raid_duplication_check.php | 64 +- logic/alarm.php | 454 +++--- logic/bearer_token.php | 31 + logic/bot_upgrade_check.php | 111 ++ logic/check_time.php | 16 - logic/collectCleanup.php | 87 +- logic/cp_keys.php | 106 -- logic/curl_get_contents.php | 26 +- logic/date_util.php | 101 ++ {core/bot/logic => logic}/debug.php | 64 +- logic/delete_raid.php | 63 - logic/delete_trainerinfo.php | 23 +- logic/disable_raid_level.php | 22 +- logic/download_Portal_Image.php | 40 + logic/edit_gym_keys.php | 142 +- logic/edit_pokedex_keys.php | 180 ++- logic/geo_api.php | 240 ++++ logic/get_chat_title_username.php | 36 +- logic/get_formatted_pokemon_cp.php | 6 +- logic/get_gym.php | 21 +- logic/get_gym_by_telegram_id.php | 27 +- logic/get_gym_details.php | 102 +- logic/get_local_pokemon_name.php | 55 +- logic/get_overview.php | 191 +-- logic/get_pokemon_by_table_id.php | 21 +- logic/get_pokemon_form_name.php | 52 +- logic/get_pokemon_id_by_name.php | 237 +-- logic/get_raid.php | 77 +- logic/get_raid_times.php | 9 +- logic/get_remote_users_count.php | 2 - logic/get_user.php | 114 +- logic/get_weather_icons.php | 35 +- logic/group_code_keys.php | 3 - logic/history.php | 1 - logic/insert_cleanup.php | 56 +- logic/insert_overview.php | 60 +- logic/insert_trainerinfo.php | 48 +- {core/bot/logic => logic}/key_util.php | 27 +- logic/keys_event.php | 29 +- logic/keys_trainerinfo.php | 107 +- logic/keys_vote.php | 60 +- {core/bot/logic => logic}/language.php | 0 logic/mapslink.php | 1 - logic/new_user.php | 8 +- logic/pokemon_keys.php | 70 +- logic/raid_edit_gym_keys.php | 194 ++- logic/raid_edit_gyms_first_letter_keys.php | 314 ++-- logic/raid_edit_raidlevel_keys.php | 143 +- logic/raid_get_gyms_list_keys.php | 85 +- logic/raid_list.php | 105 +- logic/raid_picture.php | 757 +++++----- logic/raid_poll_message.php | 32 +- logic/read_upcoming_bosses.php | 4 +- logic/resolve_boss_name_to_ids.php | 107 +- logic/resolve_raid_boss.php | 62 +- logic/send_raid_poll.php | 137 +- logic/send_trainerinfo.php | 40 +- .../send_vote_remote_users_limit_reached.php | 10 +- logic/send_vote_time_first.php | 12 +- logic/send_vote_time_future.php | 10 +- logic/sendalarmnotice.php | 74 +- logic/show_raid_poll.php | 921 ++++++------ logic/show_raid_poll_small.php | 110 +- logic/show_trainerinfo.php | 25 +- {core/bot/logic => logic}/sql_utils.php | 56 +- logic/update_raid_poll.php | 191 +-- logic/weather_keys.php | 98 +- mods/bot_lang.php | 93 +- mods/change_trainercode.php | 64 +- mods/change_trainername.php | 65 +- mods/code.php | 221 ++- mods/code_start.php | 74 +- mods/delete_scheduled_entry.php | 46 +- mods/edit_date.php | 121 +- mods/edit_event.php | 50 +- mods/edit_event_note.php | 75 +- mods/edit_event_raidlevel.php | 48 +- mods/edit_pokemon.php | 70 +- mods/edit_raidlevel.php | 88 +- mods/edit_save.php | 155 +- mods/edit_starttime.php | 267 ++-- mods/edit_time.php | 345 ++--- mods/end_remote_raid.php | 5 +- mods/events.php | 3 - mods/events_add.php | 4 - mods/events_manage.php | 7 +- mods/exit.php | 3 - mods/getdb.php | 645 +++++---- mods/gym_create.php | 138 +- mods/gym_delete.php | 96 +- mods/gym_details.php | 75 +- mods/gym_edit_details.php | 131 +- mods/gym_hidden_letter.php | 28 +- mods/gym_letter.php | 56 +- mods/history.php | 132 +- mods/history_gyms.php | 96 +- mods/history_raid.php | 22 +- mods/history_raids.php | 57 +- mods/import_future_bosses.php | 122 +- mods/import_shinyinfo.php | 134 +- mods/importal.php | 253 ++-- mods/list_by_gym.php | 36 +- mods/list_by_gym_letter.php | 42 +- mods/list_raid.php | 150 +- mods/list_remote_gyms.php | 14 +- mods/listall.php | 38 +- mods/overview_delete.php | 174 ++- mods/overview_refresh.php | 140 +- mods/overview_share.php | 163 +-- mods/pogoinfo.php | 576 ++++---- mods/pokebattler.php | 614 ++++---- mods/pokedex.php | 41 +- mods/pokedex_disable_raids.php | 178 ++- mods/pokedex_edit_pokemon.php | 109 +- mods/pokedex_import.php | 71 +- mods/pokedex_list_raids.php | 145 +- mods/pokedex_set_cp.php | 187 ++- mods/pokedex_set_raid_level.php | 143 +- mods/pokedex_set_shiny.php | 135 +- mods/pokedex_set_weather.php | 118 +- mods/post_raid.php | 3 - mods/raid_by_gym.php | 36 +- mods/raid_by_gym_letter.php | 54 +- mods/raid_by_location.php | 224 ++- mods/raid_edit_poke.php | 42 +- mods/raid_set_poke.php | 19 +- mods/raid_share.php | 4 - mods/raids_delete.php | 128 +- mods/raids_list.php | 40 +- mods/refresh_polls.php | 60 +- mods/save_event_note.php | 19 +- mods/save_gym_info.php | 69 +- mods/share_raid_by_location.php | 241 ++-- mods/trainer.php | 112 +- mods/trainer_add.php | 88 +- mods/trainer_code.php | 97 +- mods/trainer_delete.php | 188 +-- mods/trainer_level.php | 119 +- mods/trainer_name.php | 136 +- mods/trainer_share.php | 5 +- mods/trainer_team.php | 130 +- mods/tutorial.php | 159 +-- mods/update_bosses.php | 115 +- mods/vote_can_invite.php | 2 + mods/vote_extra.php | 13 +- mods/vote_invite.php | 19 +- mods/vote_level.php | 71 +- mods/vote_pokemon.php | 272 ++-- mods/vote_refresh.php | 1 - mods/vote_remote.php | 10 +- mods/vote_status.php | 164 +-- mods/vote_team.php | 53 +- mods/vote_time.php | 12 +- mods/vote_want_invite.php | 2 + raidpicture.php | 113 +- 213 files changed, 10629 insertions(+), 12876 deletions(-) create mode 100644 commands/get.php create mode 100644 commands/set.php delete mode 100644 core/bot/constants.php delete mode 100644 core/bot/logic.php delete mode 100644 core/bot/logic/bearer_token.php delete mode 100644 core/bot/logic/bot_upgrade_check.php delete mode 100644 core/bot/logic/date_util.php delete mode 100644 core/bot/logic/download_Portal_Image.php delete mode 100644 core/bot/logic/geo_api.php delete mode 100644 core/commands/get.php delete mode 100644 core/commands/set.php create mode 100644 logic/bearer_token.php create mode 100644 logic/bot_upgrade_check.php delete mode 100644 logic/check_time.php delete mode 100644 logic/cp_keys.php create mode 100644 logic/date_util.php rename {core/bot/logic => logic}/debug.php (64%) delete mode 100644 logic/delete_raid.php create mode 100644 logic/download_Portal_Image.php create mode 100644 logic/geo_api.php rename {core/bot/logic => logic}/key_util.php (87%) rename {core/bot/logic => logic}/language.php (100%) rename {core/bot/logic => logic}/sql_utils.php (52%) diff --git a/commands/delete.php b/commands/delete.php index 2a1729b7..fc0dce07 100644 --- a/commands/delete.php +++ b/commands/delete.php @@ -11,83 +11,72 @@ // Count results. $count = 0; -$own_sql = ""; +$own_sql = ''; $own_arr = []; if(!$botUser->accessCheck($update, 'delete', true) && $botUser->accessCheck($update,'delete-own',true)) { - $own_sql = "AND users.user_id = :user_id"; - $own_arr = [":user_id"=>$update['message']['from']['id']]; + $own_sql = 'AND users.user_id = :user_id'; + $own_arr = [":user_id"=>$update['message']['from']['id']]; } // Init text and keys. $text = ''; $keys = []; -try { +$query = my_query(' + SELECT + raids.*, gyms.lat , + gyms.lon , + gyms.address , + gyms.gym_name , + gyms.ex_gym , + users. NAME + FROM + raids + LEFT JOIN gyms ON raids.gym_id = gyms.id + LEFT JOIN users ON raids.user_id = users.user_id + WHERE + raids.end_time > UTC_TIMESTAMP() + '.$own_sql.' + ORDER BY + raids.end_time ASC + LIMIT 20 +', $own_arr); +while ($row = $query->fetch()) { + // Set text and keys. + $text .= $row['gym_name'] . CR; + $now = utcnow(); + $today = dt2date($now); + $raid_day = dt2date($row['start_time']); + $start = dt2time($row['start_time']); + $end = dt2time($row['end_time']); + $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; + $keys[] = array( + 'text' => $row['gym_name'], + 'callback_data' => $row['id'] . ':raids_delete:0' + ); - $query = ' - SELECT - raids.*, gyms.lat , - gyms.lon , - gyms.address , - gyms.gym_name , - gyms.ex_gym , - users. NAME - FROM - raids - LEFT JOIN gyms ON raids.gym_id = gyms.id - LEFT JOIN users ON raids.user_id = users.user_id - WHERE - raids.end_time > UTC_TIMESTAMP() - '.$own_sql.' - ORDER BY - raids.end_time ASC - LIMIT 20 - '; - $statement = $dbh->prepare( $query ); - $statement->execute($own_arr); - while ($row = $statement->fetch()) { - // Set text and keys. - $text .= $row['gym_name'] . CR; - $now = utcnow(); - $today = dt2date($now); - $raid_day = dt2date($row['start_time']); - $start = dt2time($row['start_time']); - $end = dt2time($row['end_time']); - $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; - $keys[] = array( - 'text' => $row['gym_name'], - 'callback_data' => $row['id'] . ':raids_delete:0' - ); - - // Counter++ - $count = $count + 1; - } -} -catch (PDOException $exception) { - - error_log($exception->getMessage()); - $dbh = null; - exit; + // Counter++ + $count = $count + 1; } // Set message. if($count == 0) { - $msg = '' . getTranslation('no_active_raids_found') . ''; + $msg = '' . getTranslation('no_active_raids_found') . ''; } else { - // Get the inline key array. - $keys = inline_key_array($keys, 1); + // Get the inline key array. + $keys = inline_key_array($keys, 1); - // Add exit key. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; + // Add exit key. + $keys[] = [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; - // Build message. - $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; - $msg .= $text; - $msg .= '' . getTranslation('select_gym_name') . '' . CR; + // Build message. + $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; + $msg .= $text; + $msg .= '' . getTranslation('select_gym_name') . '' . CR; } // Build callback message string. @@ -95,4 +84,3 @@ // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); -?> diff --git a/commands/events.php b/commands/events.php index db1d5281..775988b8 100644 --- a/commands/events.php +++ b/commands/events.php @@ -20,23 +20,24 @@ $msg .= $event['description'] . CR . CR; } -$keys = []; -$keys[] = [ +$keys = [ [ - 'text' => getTranslation('events_manage'), - 'callback_data' => '0:events:0', - ] -]; -$keys[] = [ + [ + 'text' => getTranslation('events_manage'), + 'callback_data' => '0:events:0', + ] + ], [ - 'text' => getTranslation('events_create'), - 'callback_data' => '0:events_add:0', - ] -]; -$keys[] = [ + [ + 'text' => getTranslation('events_create'), + 'callback_data' => '0:events_add:0', + ] + ], [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1', + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1', + ] ] ]; // Send message. diff --git a/commands/exreport.php b/commands/exreport.php index 827d37b1..1edc5782 100644 --- a/commands/exreport.php +++ b/commands/exreport.php @@ -21,72 +21,61 @@ $keys[3]['callback_data'] = 0; $i = 4; -try { +$query = my_query(' + SELECT + g.gym_name , + SUM( + CASE + WHEN a.cancel = FALSE + OR a.raid_done = FALSE THEN + ( + a.extra_in_person + a.extra_alien + 1 + ) + ELSE + 0 + END + ) AS Total_attended , + count(DISTINCT r.id) AS Total_raids , + ROUND( + ( + SUM( + CASE + WHEN a.cancel = FALSE + OR a.raid_done = FALSE THEN + ( + a.extra_in_person + a.extra_alien + 1 + ) + ELSE + 0 + END + ) / count(DISTINCT r.id) * 2 + ) + 3 + ) AS players_needed_to_trigger + FROM + raids r + LEFT JOIN attendance a ON a.raid_id = r.id + LEFT JOIN gyms g ON g.id = r.gym_id + WHERE + g.ex_gym = 1 + AND WEEK(r.start_time) BETWEEN WEEK(now()) - 2 + AND WEEK(now()) + GROUP BY + g.gym_name +'); +while ($row = $query->fetch()) { - $query = ' - SELECT - g.gym_name , - SUM( - CASE - WHEN a.cancel = FALSE - OR a.raid_done = FALSE THEN - ( - a.extra_in_person + a.extra_alien + 1 - ) - ELSE - 0 - END - ) AS Total_attended , - count(DISTINCT r.id) AS Total_raids , - ROUND( - ( - SUM( - CASE - WHEN a.cancel = FALSE - OR a.raid_done = FALSE THEN - ( - a.extra_in_person + a.extra_alien + 1 - ) - ELSE - 0 - END - ) / count(DISTINCT r.id) * 2 - ) + 3 - ) AS players_needed_to_trigger - FROM - raids r - LEFT JOIN attendance a ON a.raid_id = r.id - LEFT JOIN gyms g ON g.id = r.gym_id - WHERE - g.ex_gym = 1 - AND WEEK(r.start_time) BETWEEN WEEK(now()) - 2 - AND WEEK(now()) - GROUP BY - g.gym_name - '; - $statement = $dbh->prepare( $query ); - $statement->execute(); - while ($row = $statement->fetch()) { - - $keys[$i]['text'] = $row['gym_name']; - $keys[$i]['callback_data'] = 0; - - $keys[$i+1]['text'] = $row['Total_attended']; - $keys[$i+1]['callback_data'] = 0; - - $keys[$i+2]['text'] = $row['Total_raids']; - $keys[$i+2]['callback_data'] = 0; - - $keys[$i+3]['text'] = $row['players_needed_to_trigger']; - $keys[$i+3]['callback_data'] = 0; - $i = $i+4; - } -} -catch (PDOException $exception) { + $keys[$i]['text'] = $row['gym_name']; + $keys[$i]['callback_data'] = 0; + + $keys[$i+1]['text'] = $row['Total_attended']; + $keys[$i+1]['callback_data'] = 0; + + $keys[$i+2]['text'] = $row['Total_raids']; + $keys[$i+2]['callback_data'] = 0; - error_log($exception->getMessage()); - $dbh = null; - exit; + $keys[$i+3]['text'] = $row['players_needed_to_trigger']; + $keys[$i+3]['callback_data'] = 0; + $i = $i+4; } // Get the inline key array. @@ -97,4 +86,3 @@ // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); -?> diff --git a/commands/friendsearch.php b/commands/friendsearch.php index 67ec7486..fbf5caa7 100644 --- a/commands/friendsearch.php +++ b/commands/friendsearch.php @@ -14,16 +14,13 @@ debug_log($searchterm, 'SEARCHTERM'); -$query = "SELECT user_id, name, team, level, trainername FROM users WHERE trainername LIKE :tn"; -$statement = $dbh->prepare( $query ); -$statement->execute([':tn' => $searchterm]); -if($statement->rowCount() == 1) { - $result = $statement->fetch(); - $msg = ($result['team'] === NULL) ? ($GLOBALS['teams']['unknown'] . ' ') : ($GLOBALS['teams'][$result['team']] . ' '); - $msg .= ($result['level'] == 0) ? ('00 ') : (($result['level'] < 10) ? ('0' . $result['level'] . ' ') : ('' . $result['level'] . ' ')); - $msg .= "".$result['name']." - ".$result['trainername'].""; +$query = my_query('SELECT user_id, name, team, level, trainername FROM users WHERE trainername LIKE :tn', [':tn' => $searchterm]); +if($query->rowCount() == 1) { + $result = $query->fetch(); + $msg = ($result['team'] === NULL) ? ($GLOBALS['teams']['unknown'] . ' ') : ($GLOBALS['teams'][$result['team']] . ' '); + $msg .= ($result['level'] == 0) ? ('00 ') : (($result['level'] < 10) ? ('0' . $result['level'] . ' ') : ('' . $result['level'] . ' ')); + $msg .= '' . $result['name'] . ' - ' . $result['trainername'] . ''; }else { - $msg = $searchterm.CR. getTranslation('trainer_not_found'); + $msg = $searchterm.CR. getTranslation('trainer_not_found'); } send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true]]); -?> \ No newline at end of file diff --git a/commands/get.php b/commands/get.php new file mode 100644 index 00000000..c3d17c65 --- /dev/null +++ b/commands/get.php @@ -0,0 +1,70 @@ +accessCheck($update, 'config-get'); + +// Get all allowed configs. +$allowed = explode(',', $config->ALLOWED_TELEGRAM_CONFIG); +$msg = '' . getTranslation('config') . ':' . CR . CR; + +// Get config restrictions for boolean input +$allowed_bool = explode(',', $config->ALLOW_ONLY_TRUE_FALSE); + +// Get config restrictions for numeric input +$allowed_numbers = explode(',', $config->ALLOW_ONLY_NUMBERS); + +// Get config. +$cfile = CONFIG_PATH . '/config.json'; +if(is_file($cfile)) { + $str = file_get_contents($cfile); + $json = json_decode($str, true); +} + +// Get config aliases. +$afile = CONFIG_PATH . '/alias.json'; +if(is_file($afile)) { + $astr = file_get_contents($afile); + $ajson = json_decode($astr, true); +} + +// Write to log. +debug_log('User requested the allowed telegram configs'); +debug_log('Allowed telegram configs: ' . $config->ALLOWED_TELEGRAM_CONFIG); +debug_log('Allow only boolean input: ' . $config->ALLOW_ONLY_TRUE_FALSE); +debug_log('Allow only numeric input: ' . $config->ALLOW_ONLY_NUMBERS); + +// Any configs allowed? +if(empty($allowed)) { + send_message($update['message']['chat']['id'], getTranslation('not_supported')); + exit; +} +foreach($json as $cfg_name => $cfg_value) { + // Only allowed configs + if(in_array($cfg_name, $allowed)) { + // Is alias set? + $alias = ''; + if(isset($ajson[$cfg_name])){ + $alias = $ajson[$cfg_name]; + } + // Config name / Alias + value + $msg .= (empty($alias) ? $cfg_name : $alias) . SP . (empty($cfg_value) ? '' . getTranslation('no_value') . '' : $cfg_value); + + // Only bool? + if(in_array($cfg_name, $allowed_bool)) { + $msg .= SP . '(' . getTranslation('help_only_bool') . ')'; + + // Only numbers? + } else if(in_array($cfg_name, $allowed_numbers)) { + $msg .= SP . '(' . getTranslation('help_only_numbers') . ')'; + + } + $msg .= CR; + } +} +send_message($update['message']['chat']['id'], $msg); diff --git a/commands/gym.php b/commands/gym.php index 06083133..c091dfa6 100644 --- a/commands/gym.php +++ b/commands/gym.php @@ -1,4 +1,5 @@ ' . getTranslation('show_gym_details') . CR . CR; if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= getTranslation('select_gym_area') . '' . CR; - }elseif($config->DEFAULT_GYM_AREA !== false) { - if($keys_and_gymarea['letters']) { - $msg .= getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= getTranslation('select_gym_name_or_gym_area') . '' . CR; - } + if($keys_and_gymarea['gymarea_name'] == '') { + $msg .= getTranslation('select_gym_area') . '' . CR; + }elseif($config->DEFAULT_GYM_AREA !== false) { + if($keys_and_gymarea['letters']) { + $msg .= getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; }else { - if($keys_and_gymarea['letters']) { - $msg .= getTranslation('select_gym_first_letter') . '' . CR; - }else { - $msg .= getTranslation('select_gym_name') . '' . CR; - } + $msg .= getTranslation('select_gym_name_or_gym_area') . '' . CR; } -}else { + }else { if($keys_and_gymarea['letters']) { - $msg .= getTranslation('select_gym_first_letter') . '' . CR; + $msg .= getTranslation('select_gym_first_letter') . '' . CR; }else { - $msg .= getTranslation('select_gym_name') . '' . CR; + $msg .= getTranslation('select_gym_name') . '' . CR; } + } +}else { + if($keys_and_gymarea['letters']) { + $msg .= getTranslation('select_gym_first_letter') . '' . CR; + }else { + $msg .= getTranslation('select_gym_name') . '' . CR; + } } $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); // Add key for hidden gyms. $h_keys = []; if($config->ENABLE_GYM_AREAS == false or ($config->ENABLE_GYM_AREAS == true && $config->DEFAULT_GYM_AREA !== false)) { - // Add key for hidden gyms. - $h_keys[] = universal_inner_key($h_keys, '0', 'gym_hidden_letter', 'gym_details', getTranslation('hidden_gyms')); - $h_keys = inline_key_array($h_keys, 1); + // Add key for hidden gyms. + $h_keys[] = universal_inner_key($h_keys, '0', 'gym_hidden_letter', 'gym_details', getTranslation('hidden_gyms')); + $h_keys = inline_key_array($h_keys, 1); } // Merge keys. $keys = array_merge($h_keys, $keys); if($botUser->accessCheck($update, 'gym-add')) { - $keys[] = [ - [ - 'text' => getTranslation('gym_create'), - 'callback_data' => '0:gym_create:0' - ] - ]; + $keys[] = [ + [ + 'text' => getTranslation('gym_create'), + 'callback_data' => '0:gym_create:0' + ] + ]; } $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] ]; // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); - -?> +send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); diff --git a/commands/gymname.php b/commands/gymname.php index 18b7d9eb..f243c19f 100644 --- a/commands/gymname.php +++ b/commands/gymname.php @@ -1,6 +1,9 @@ ' . getTranslation('gym_id_name_missing') . ''; - $msg .= CR . CR . getTranslation('gym_name_instructions'); - $msg .= CR . getTranslation('gym_name_example'); - $msg .= CR . CR . getTranslation('gym_get_id_details'); - - // Set keys. - $keys = []; +$input = trim(substr($update['message']['text'], 9)); + +// Init vars. +$gym = false; +$id = 0; +$tg_id = '#' . $update['message']['from']['id']; + +// Maybe get gym by telegram id? +$gym = get_gym_by_telegram_id($tg_id); + +// Update gym info. +if($gym && !empty($input) && $gym['id'] > 0) { + debug_log('Changing name for gym with ID: ' . $gym['id']); + debug_log('Gym name: ' . $input); + my_query(' + UPDATE gyms + SET gym_name = :info + WHERE id = :id + ', ['info' => $input, 'id' => $gym['id']] + ); + $gym['gym_name'] = $input; + // Set message. + $msg = get_gym_details($gym); + $msg .= CR . '' . getTranslation('gym_name_updated') . ''; +} else if($gym && empty($info)) { + debug_log('Missing gym name!'); + // Set message. + $msg = CR . '' . getTranslation('gym_id_name_missing') . ''; + $msg .= CR . CR . getTranslation('gym_name_instructions'); + $msg .= CR . getTranslation('gym_name_example'); } else { - // Set keys. - $keys = []; - - // Init vars. - $gym = false; - $info = ''; - $id = 0; - $tg_id = '#' . $update['message']['from']['id']; - - // Get gym id. - if(substr_count($id_info, ',') >= 1) { - $split_id_info = explode(',', $id_info,2); - $id = $split_id_info[0]; - $info = $split_id_info[1]; - $info = trim($info); - - // Make sure we have a valid gym id. - if(is_numeric($id)) { - $gym = get_gym($id); - } - } - - // Maybe get gym by telegram id? - if(!$gym) { - $gym = get_gym_by_telegram_id($tg_id); - // Get new id. - if($gym) { - $id = $gym['id']; - $info = $id_info; - } - } - - // Update gym info. - if($gym && !empty($info) && $id > 0) { - debug_log('Changing name for gym with ID: ' . $id); - debug_log('Gym name: ' . $info); - $stmt = $dbh->prepare( - " - UPDATE gyms - SET gym_name = :info - WHERE id = :id - " - ); - $stmt->execute([ - 'info' => $info, - 'id' => $id - ]); - - // Set message. - $gym = get_gym($id); - $msg = get_gym_details($gym); - $msg .= CR . '' . getTranslation('gym_name_updated') . ''; - } else if($gym && empty($info)) { - debug_log('Missing gym name!'); - // Set message. - $msg .= CR . '' . getTranslation('gym_id_name_missing') . ''; - $msg .= CR . CR . getTranslation('gym_name_instructions'); - $msg .= CR . getTranslation('gym_name_example'); - $msg .= CR . CR . getTranslation('gym_get_id_details'); - } else { - // Set message. - $msg .= getTranslation('invalid_input'); - } + // Set message. + $msg = getTranslation('gym_not_found'); } // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); - -?> +send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); diff --git a/commands/help.php b/commands/help.php index f6fb1f4a..1e66bb15 100644 --- a/commands/help.php +++ b/commands/help.php @@ -4,77 +4,74 @@ // Display help for each permission if($access) { - if($botUser->userPrivileges['grantedBy'] == 'BOT_ADMINS') { - $permissions = array(); - $permissions[] = 'access-bot'; - $permissions[] = 'create'; - $permissions[] = 'ex-raids'; - $permissions[] = 'raid-duration'; - $permissions[] = 'list'; - $permissions[] = 'listall'; - $permissions[] = 'overview'; - $permissions[] = 'delete-all'; - $permissions[] = 'pokemon-all'; - $permissions[] = 'trainer'; - $permissions[] = 'gym-details'; - $permissions[] = 'gym-edit'; - $permissions[] = 'gym-add'; - $permissions[] = 'portal-import'; - $permissions[] = 'config-get'; - $permissions[] = 'config-set'; - $permissions[] = 'pokedex'; - $permissions[] = 'history'; - $permissions[] = 'event-manage'; - $permissions[] = 'help'; - } else { - // Get permissions. - $permissions = $botUser->userPrivileges['privileges']; - } + if($botUser->userPrivileges['grantedBy'] == 'BOT_ADMINS') { + $permissions = array(); + $permissions[] = 'access-bot'; + $permissions[] = 'create'; + $permissions[] = 'ex-raids'; + $permissions[] = 'raid-duration'; + $permissions[] = 'list'; + $permissions[] = 'listall'; + $permissions[] = 'overview'; + $permissions[] = 'delete-all'; + $permissions[] = 'pokemon-all'; + $permissions[] = 'trainer'; + $permissions[] = 'gym-details'; + $permissions[] = 'gym-edit'; + $permissions[] = 'gym-add'; + $permissions[] = 'portal-import'; + $permissions[] = 'config-get'; + $permissions[] = 'config-set'; + $permissions[] = 'pokedex'; + $permissions[] = 'history'; + $permissions[] = 'event-manage'; + $permissions[] = 'help'; + } else { + // Get permissions. + $permissions = $botUser->userPrivileges['privileges']; + } - // Write to log. - debug_log($permissions,'PERMISSIONS: '); + // Write to log. + debug_log($permissions,'PERMISSIONS: '); - // Show help header. - debug_log('Showing help to user now'); - $msg = '' . getTranslation('personal_help') . '' . CR . CR; + // Show help header. + debug_log('Showing help to user now'); + $msg = '' . getTranslation('personal_help') . '' . CR . CR; - // Raid via location? - if($config->RAID_VIA_LOCATION) { - $msg .= EMOJI_CLIPPY . SP . getTranslation('help_create_via_location') . CR . CR; - } + // Raid via location? + if($config->RAID_VIA_LOCATION) { + $msg .= EMOJI_CLIPPY . SP . getTranslation('help_create_via_location') . CR . CR; + } - // Show help. - foreach($permissions as $id => $p) { - if($p == 'access-bot' || strpos($p, 'share-') === 0 || strpos($p, 'ignore-') === 0) continue; - if(getTranslation('help_' . $p)) { - $msg .= getTranslation('help_' . $p) . CR . CR; - } + // Show help. + foreach($permissions as $id => $p) { + if($p == 'access-bot' || strpos($p, 'share-') === 0 || strpos($p, 'ignore-') === 0) continue; + if(getTranslation('help_' . $p)) { + $msg .= getTranslation('help_' . $p) . CR . CR; } + } } elseif($config->TUTORIAL_MODE) { - if(new_user($update['message']['from']['id'])) { - $msg = $tutorial[0]['msg_new']; - }else { - $msg = $tutorial[0]['msg']; - } - $keys = [ + if(new_user($update['message']['from']['id'])) { + $msg = $tutorial[0]['msg_new']; + }else { + $msg = $tutorial[0]['msg']; + } + $keys = [ + [ [ - [ - 'text' => getTranslation('next'), - 'callback_data' => '0:tutorial:0' - ] + 'text' => getTranslation('next'), + 'callback_data' => '0:tutorial:0' ] - ]; - $photo = $tutorial[0]['photo']; - send_photo($update['message']['from']['id'],$photo, false, $msg, $keys, ['disable_web_page_preview' => 'true']); - exit(); + ] + ]; + $photo = $tutorial[0]['photo']; + send_photo($update['message']['from']['id'],$photo, false, $msg, $keys, ['disable_web_page_preview' => 'true']); + exit(); // No help for the user. } else { - $msg = getTranslation('bot_access_denied'); + $msg = getTranslation('bot_access_denied'); } // Send message. send_message($update['message']['from']['id'], $msg); - -?> - diff --git a/commands/history.php b/commands/history.php index fa6d8e8f..55ab1ea0 100644 --- a/commands/history.php +++ b/commands/history.php @@ -13,13 +13,11 @@ $msg_keys = create_history_date_msg_keys(); if($msg_keys === false) { - $msg = getTranslation('history_no_raids_found'); - $keys = []; + $msg = getTranslation('history_no_raids_found'); + $keys = []; }else { - $msg = $msg_keys[0]; - $keys = $msg_keys[1]; + $msg = $msg_keys[0]; + $keys = $msg_keys[1]; } send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); - -?> diff --git a/commands/list.php b/commands/list.php index 31023618..57a0eed9 100644 --- a/commands/list.php +++ b/commands/list.php @@ -19,25 +19,23 @@ }elseif($botUser->accessCheck($update, 'event-raids', true)) { $event_sql = 'event != ' . EVENT_ID_EX .' OR event IS NULL'; } - +$event_sql = ($event_sql == '') ? '' : 'AND ('.$event_sql.')'; // Get last 12 active raids data. -$rs = my_query( - ' +$rs = my_query(' SELECT raids.pokemon, raids.pokemon_form, raids.id, raids.spawn, raids.start_time, raids.end_time, raids.level, raids.event, gyms.gym_name, gyms.ex_gym, events.name as event_name, - (SELECT COUNT(*) FROM raids WHERE end_time>UTC_TIMESTAMP() ' . ($event_sql == '' ? '' : 'AND ('.$event_sql.')') . ') as r_active + (SELECT COUNT(*) FROM raids WHERE end_time>UTC_TIMESTAMP() ' . $event_sql . ') as r_active FROM raids LEFT JOIN gyms ON raids.gym_id = gyms.id LEFT JOIN events ON events.id = raids.event WHERE end_time>UTC_TIMESTAMP() - ' . ($event_sql == '' ? '' : 'AND ('.$event_sql.')') . ' + ' . $event_sql . ' ORDER BY end_time ASC LIMIT 12 - ' -); +'); // Get the raids. $raids = $rs->fetchAll(); @@ -111,4 +109,3 @@ // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); -?> diff --git a/commands/listall.php b/commands/listall.php index 35f8f95b..128f41c5 100644 --- a/commands/listall.php +++ b/commands/listall.php @@ -1,4 +1,5 @@ getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] ]; // Set message. $msg = '' . getTranslation('list_all_active_raids') . '' . CR; $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] . CR: ''); if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; + if($keys_and_gymarea['gymarea_name'] == '') { + $msg .= '' . getTranslation('select_gym_area') . '' . CR; + }else { + if($keys_and_gymarea['letters']) { + $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } + $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; } + } }elseif($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; + $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; + $msg .= '' . getTranslation('select_gym_name') . '' . CR; } // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); - -?> diff --git a/commands/overview.php b/commands/overview.php index d7396d70..8af13112 100644 --- a/commands/overview.php +++ b/commands/overview.php @@ -9,21 +9,18 @@ // Check access. $botUser->accessCheck($update, 'overview'); -// Init empty keys array. -$keys = []; - // Create keys array. $keys = [ + [ + [ + 'text' => getTranslation('overview_share'), + 'callback_data' => '0:overview_share:0' + ], [ - [ - 'text' => getTranslation('overview_share'), - 'callback_data' => '0:overview_share:0' - ], - [ - 'text' => getTranslation('overview_delete'), - 'callback_data' => '0:overview_delete:0' - ] + 'text' => getTranslation('overview_delete'), + 'callback_data' => '0:overview_delete:0' ] + ] ]; // Set message. @@ -31,5 +28,3 @@ // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); - -?> diff --git a/commands/pokedex.php b/commands/pokedex.php index 12f9d0f1..e7bc0707 100644 --- a/commands/pokedex.php +++ b/commands/pokedex.php @@ -1,6 +1,7 @@ prepare("SELECT pokedex_id, pokemon_form_id FROM pokemon WHERE pokedex_id = :pokedex_id"); - $statement->execute([":pokedex_id" => $pokedex_id]); - while ($pokemon = $statement->fetch()) { - $keys[] = [ - [ - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), - 'callback_data' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' - ] - ]; - } - // Set message. - $msg = '' . getTranslation('pokedex_edit_pokemon') . ''; + // Pokedex_id received? + if(is_numeric($pokemon)) { + $pokedex_id = $pokemon; + // Pokemon name received? + } else { + $pokemon_name_form = get_pokemon_id_by_name($pokemon); + $pokedex_id = $pokemon_name_form[0]; + } + $query = my_query('SELECT pokedex_id, pokemon_form_id FROM pokemon WHERE pokedex_id = :pokedex_id', [':pokedex_id' => $pokedex_id]); + while ($pokemon = $query->fetch()) { + $keys[] = [ + [ + 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), + 'callback_data' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' + ] + ]; + } + // Set message. + $msg = '' . getTranslation('pokedex_edit_pokemon') . ''; } if(count($keys) == 0 ) { - $query = my_query("SELECT * FROM pokemon WHERE pokedex_id='9995'"); // A simple check to see if pokemon table has all the necessary data in it - if($query->rowCount() > 0) { - // Create keys array. - $keys = [ - [ - [ - 'text' => getTranslation('pokedex_raid_pokemon'), - 'callback_data' => '0:pokedex_list_raids:0' - ] - ], - [ - [ - 'text' => getTranslation('edit_pokemon'), - 'callback_data' => '0:pokedex:0' - ] - ], - [ - [ - 'text' => getTranslation('disable_raid_level'), - 'callback_data' => '0:pokedex_disable_raids:0' - ] - ], - [ - [ - 'text' => getTranslation('import'), - 'callback_data' => '0:pokedex_import:0' - ] - ] - ]; - } - $keys[][] = [ - 'text' => getTranslation('update_pokemon_table'), - 'callback_data' => '0:getdb:0' - ]; - // Set message. - $msg = '' . getTranslation('pokedex_start') . ':'; + $query = my_query('SELECT id FROM pokemon WHERE pokedex_id = 9999 and pokemon_form_id = 0'); // A simple check to see if pokemon table has all the necessary data in it + if($query->rowCount() > 0) { + // Create keys array. + $keys = [ + [ + [ + 'text' => getTranslation('pokedex_raid_pokemon'), + 'callback_data' => '0:pokedex_list_raids:0' + ] + ], + [ + [ + 'text' => getTranslation('edit_pokemon'), + 'callback_data' => '0:pokedex:0' + ] + ], + [ + [ + 'text' => getTranslation('disable_raid_level'), + 'callback_data' => '0:pokedex_disable_raids:0' + ] + ], + [ + [ + 'text' => getTranslation('import'), + 'callback_data' => '0:pokedex_import:0' + ] + ] + ]; + } + $keys[][] = [ + 'text' => getTranslation('update_pokemon_table'), + 'callback_data' => '0:getdb:0' + ]; + // Set message. + $msg = '' . getTranslation('pokedex_start') . ':'; } $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] ]; // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); - -?> diff --git a/commands/pokemon.php b/commands/pokemon.php index 24d83ada..4dcab384 100644 --- a/commands/pokemon.php +++ b/commands/pokemon.php @@ -16,85 +16,73 @@ $text = ''; $keys = []; -try { - - $query = ' - SELECT - raids.*, gyms.lat , - gyms.lon , - gyms.address , - gyms.gym_name , - gyms.ex_gym , - users. NAME - FROM - raids - LEFT JOIN gyms ON raids.gym_id = gyms.id - LEFT JOIN users ON raids.user_id = users.user_id - WHERE - raids.end_time > UTC_TIMESTAMP - ORDER BY - raids.end_time ASC - LIMIT 20 - '; - $statement = $dbh->prepare( $query ); - $statement->execute(); - while ($row = $statement->fetch()) { - // Get times. - $now = utcnow(); - $today = dt2date($now); - $raid_day = dt2date($row['start_time']); - $start = dt2time($row['start_time']); - $end = dt2time($row['end_time']); - - // Split pokemon and form to get the pokedex id. - $pokedex_id = explode('-', $row['pokemon'])[0]; - - // Pokemon is an egg? - $eggs = $GLOBALS['eggs']; - if(in_array($pokedex_id, $eggs)) { - $keys_text = EMOJI_EGG . SP . $row['gym_name']; - } else { - $keys_text = $row['gym_name']; - } - - // Set text and keys. - $text .= $row['gym_name'] . CR; - $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; - $keys[] = array( - 'text' => $keys_text, - 'callback_data' => $row['id'] . ':raid_edit_poke:' . $row['level'], - ); - - // Counter++ - $count = $count + 1; - } +$query = my_query(' + SELECT + raids.*, gyms.lat , + gyms.lon , + gyms.address , + gyms.gym_name , + gyms.ex_gym , + users. NAME + FROM + raids + LEFT JOIN gyms ON raids.gym_id = gyms.id + LEFT JOIN users ON raids.user_id = users.user_id + WHERE + raids.end_time > UTC_TIMESTAMP + ORDER BY + raids.end_time ASC + LIMIT 20 +'); + +while ($row = $query->fetch()) { + // Get times. + $now = utcnow(); + $today = dt2date($now); + $raid_day = dt2date($row['start_time']); + $start = dt2time($row['start_time']); + $end = dt2time($row['end_time']); + + // Split pokemon and form to get the pokedex id. + $pokedex_id = explode('-', $row['pokemon'])[0]; + + // Pokemon is an egg? + $keys_text = $row['gym_name']; + if(in_array($pokedex_id, $GLOBALS['eggs'])) { + $keys_text = EMOJI_EGG . SP . $row['gym_name']; + } + + // Set text and keys. + $text .= $row['gym_name'] . CR; + $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; + $keys[] = array( + 'text' => $keys_text, + 'callback_data' => $row['id'] . ':raid_edit_poke:' . $row['level'], + ); + + // Counter++ + $count = $count + 1; } -catch (PDOException $exception) { - error_log($exception->getMessage()); - $dbh = null; - exit; -} - // Set message. if($count == 0) { - $msg = '' . getTranslation('no_active_raids_found') . ''; + $msg = '' . getTranslation('no_active_raids_found') . ''; } else { - // Get the inline key array. - $keys = inline_key_array($keys, 1); - - // Add exit key. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - - // Build message. - $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; - $msg .= $text; - $msg .= '' . getTranslation('select_gym_name') . '' . CR; + // Get the inline key array. + $keys = inline_key_array($keys, 1); + + // Add exit key. + $keys[] = [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; + + // Build message. + $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; + $msg .= $text; + $msg .= '' . getTranslation('select_gym_name') . '' . CR; } // Build callback message string. @@ -102,5 +90,3 @@ // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); - -?> diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 9d0d5d7c..95e46210 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -1,399 +1,349 @@ registerCounter($namespace, 'webhook_raids_received_total', 'Total raids received via webhook'); - $webhook_raids_accepted_total = $metrics->registerCounter($namespace, 'webhook_raids_accepted_total', 'Total raids received & accepted via webhook'); - $webhook_raids_posted_total = $metrics->registerCounter($namespace, 'webhook_raids_posted_total', 'Total raids posted automatically'); +if($metrics) { + $webhook_raids_received_total = $metrics->registerCounter($namespace, 'webhook_raids_received_total', 'Total raids received via webhook'); + $webhook_raids_accepted_total = $metrics->registerCounter($namespace, 'webhook_raids_accepted_total', 'Total raids received & accepted via webhook'); + $webhook_raids_posted_total = $metrics->registerCounter($namespace, 'webhook_raids_posted_total', 'Total raids posted automatically'); } function isPointInsidePolygon($point, $vertices) { - $i = 0; - $j = 0; - $c = 0; - $count_vertices = count($vertices); - for ($i = 0, $j = $count_vertices-1 ; $i < $count_vertices; $j = $i++) { - if ((($vertices[$i]['y'] > $point['y'] != ($vertices[$j]['y'] > $point['y'])) && ($point['x'] < ($vertices[$j]['x'] - $vertices[$i]['x']) * ($point['y'] - $vertices[$i]['y']) / ($vertices[$j]['y'] - $vertices[$i]['y']) + $vertices[$i]['x']) ) ) { - $c = !$c; - } + $i = $j = $c = 0; + $count_vertices = count($vertices); + for($i = 0, $j = $count_vertices-1 ; $i < $count_vertices; $j = $i++) { + if((($vertices[$i]['y'] > $point['y'] != ($vertices[$j]['y'] > $point['y'])) && ($point['x'] < ($vertices[$j]['x'] - $vertices[$i]['x']) * ($point['y'] - $vertices[$i]['y']) / ($vertices[$j]['y'] - $vertices[$i]['y']) + $vertices[$i]['x']) ) ) { + $c = !$c; } - return $c; + } + return $c; } // Geofences $geofences = false; -if (file_exists(CONFIG_PATH . '/geoconfig.json')) { - $raw = file_get_contents(CONFIG_PATH . '/geoconfig.json'); - $geofences = json_decode($raw, true); - $geofence_polygons = []; - foreach($geofences as $geofence) { - foreach ($geofence['path'] as $geopoint) { - $geofence_polygons[$geofence['id']][] = ['x' => $geopoint[0], 'y' => $geopoint[1]]; - } +if(file_exists(CONFIG_PATH . '/geoconfig.json')) { + $raw = file_get_contents(CONFIG_PATH . '/geoconfig.json'); + $geofences = json_decode($raw, true); + $geofence_polygons = []; + foreach($geofences as $geofence) { + foreach($geofence['path'] as $geopoint) { + $geofence_polygons[$geofence['id']][] = ['x' => $geopoint[0], 'y' => $geopoint[1]]; } + } } $cleanup_data = []; if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0])) { - // Fetch cleanup info for later use - try { - $query_cleanup = 'SELECT raid_id, chat_id FROM cleanup'; - $statement_cleanup = $dbh->prepare($query_cleanup); - $statement_cleanup->execute(); - $cleanup_table = $statement_cleanup->fetchAll(); - foreach($cleanup_table as $row) { - $cleanup_data[$row['raid_id']][] = $row['chat_id']; - } - } - catch (PDOException $exception) { - error_log($exception->getMessage()); - $dbh = null; - exit; - } + // Fetch cleanup info for later use + $query_cleanup = my_query('SELECT raid_id, chat_id FROM cleanup'); + while($row = $query_cleanup->fetch()) { + $cleanup_data[$row['raid_id']][] = $row['chat_id']; + } } // Telegram JSON array. $tg_json = []; debug_log(count($update),"Received raids:"); -if ($metrics){ - $webhook_raids_received_total->incBy(count($update)); +if($metrics) { + $webhook_raids_received_total->incBy(count($update)); } -foreach ($update as $raid) { - // Skip posting if create only -mode is set or raid time is greater than value set in config - $no_auto_posting = ($config->WEBHOOK_CREATE_ONLY or ($raid['message']['end']-$raid['message']['start']) > ($config->WEBHOOK_EXCLUDE_AUTOSHARE_DURATION * 60)); - - $level = $raid['message']['level']; - $pokemon = $raid['message']['pokemon_id']; - $exclude_raid_levels = explode(',', $config->WEBHOOK_EXCLUDE_RAID_LEVEL); - $exclude_pokemons = explode(',', $config->WEBHOOK_EXCLUDE_POKEMON); - if ((!empty($level) && in_array($level, $exclude_raid_levels)) || (!empty($pokemon) && in_array($pokemon, $exclude_pokemons))) { - debug_log($pokemon.' Tier: '.$level,'Ignoring raid, the pokemon or raid level is excluded:'); - continue; - } +foreach($update as $raid) { + // Skip posting if create only -mode is set or raid time is greater than value set in config + $no_auto_posting = ($config->WEBHOOK_CREATE_ONLY or ($raid['message']['end']-$raid['message']['start']) > ($config->WEBHOOK_EXCLUDE_AUTOSHARE_DURATION * 60)); - $gym_name = isset($raid['message']['name']) ? $raid['message']['name'] : $raid['message']['gym_name']; - if ($config->WEBHOOK_EXCLUDE_UNKNOWN && ($gym_name === 'unknown' || $gym_name === 'Unknown')) { - debug_log($raid['message']['gym_id'],'Ignoring raid, the gym name is unknown and WEBHOOK_EXCLUDE_UNKNOWN says to ignore. id:'); - continue; - } - $gym_lat = $raid['message']['latitude']; - $gym_lon = $raid['message']['longitude']; - $gym_id = $raid['message']['gym_id']; - $gym_img_url = isset($raid['message']['url']) ? $raid['message']['url'] : $raid['message']['gym_url']; - $gym_is_ex = isset($raid['message']['is_ex_raid_eligible']) ? ( $raid['message']['is_ex_raid_eligible'] ? 1 : 0 ) : ( $raid['message']['ex_raid_eligible'] ? 1 : 0 ); - $gym_internal_id = 0; - - // Check geofence, if available, and skip current raid if not inside any fence - if ($geofences != false) { - $insideGeoFence = false; - $inside_geofences = []; - $point = ['x' => $gym_lat, 'y' => $gym_lon]; - foreach ($geofence_polygons as $geofence_id => $polygon) { - if (isPointInsidePolygon($point, $polygon)) { - $inside_geofences[] = $geofence_id; - $insideGeoFence = true; - debug_log($geofence_id,'Raid inside geofence:'); - } - } - if ($insideGeoFence === false) { - debug_log($gym_name,'Ignoring raid, not inside any geofence:'); - continue; - } - } + $level = $raid['message']['level']; + $pokemon = $raid['message']['pokemon_id']; + $exclude_raid_levels = explode(',', $config->WEBHOOK_EXCLUDE_RAID_LEVEL); + $exclude_pokemons = explode(',', $config->WEBHOOK_EXCLUDE_POKEMON); + if((!empty($level) && in_array($level, $exclude_raid_levels)) || (!empty($pokemon) && in_array($pokemon, $exclude_pokemons))) { + debug_log($pokemon.' Tier: '.$level,'Ignoring raid, the pokemon or raid level is excluded:'); + continue; + } - // Create gym if it doesn't exists, otherwise update gym info. - try { - $query = ' - INSERT INTO gyms (lat, lon, gym_name, gym_id, ex_gym, img_url, show_gym) - VALUES (:lat, :lon, :gym_name, :gym_id, :ex_gym, :img_url, 1) - ON DUPLICATE KEY UPDATE - lat = :lat, - lon = :lon, - gym_name = :gym_name, - ex_gym = :ex_gym, - img_url = :img_url - '; - $statement = $dbh->prepare( $query ); - $statement->execute([ - 'lat' => $gym_lat, - 'lon' => $gym_lon, - 'gym_name' => $gym_name, - 'gym_id' => $gym_id, - 'ex_gym' => $gym_is_ex, - 'img_url' => $gym_img_url - ]); - if($statement->rowCount() == 1) { - $gym_internal_id = $dbh->lastInsertId(); - debug_log($gym_internal_id, 'New gym '.$gym_name.' created with internal id of:'); - }else { - $statement = $dbh->prepare('SELECT id FROM gyms WHERE gym_id LIKE :gym_id LIMIT 1'); - $statement->execute(['gym_id'=>$gym_id]); - $gym_internal_id = $statement->fetch()['id']; - debug_log($gym_internal_id, 'Gym info updated. Internal id:'); - } + $gym_name = isset($raid['message']['name']) ? $raid['message']['name'] : $raid['message']['gym_name']; + if($config->WEBHOOK_EXCLUDE_UNKNOWN && ($gym_name === 'unknown' || $gym_name === 'Unknown')) { + debug_log($raid['message']['gym_id'],'Ignoring raid, the gym name is unknown and WEBHOOK_EXCLUDE_UNKNOWN says to ignore. id:'); + continue; + } + $gym_lat = $raid['message']['latitude']; + $gym_lon = $raid['message']['longitude']; + $gym_id = $raid['message']['gym_id']; + $gym_img_url = isset($raid['message']['url']) ? $raid['message']['url'] : $raid['message']['gym_url']; + $gym_is_ex = isset($raid['message']['is_ex_raid_eligible']) ? ( $raid['message']['is_ex_raid_eligible'] ? 1 : 0 ) : ( $raid['message']['ex_raid_eligible'] ? 1 : 0 ); + $gym_internal_id = 0; + + // Check geofence, if available, and skip current raid if not inside any fence + if($geofences != false) { + $insideGeoFence = false; + $inside_geofences = []; + $point = ['x' => $gym_lat, 'y' => $gym_lon]; + foreach($geofence_polygons as $geofence_id => $polygon) { + if(isPointInsidePolygon($point, $polygon)) { + $inside_geofences[] = $geofence_id; + $insideGeoFence = true; + debug_log($geofence_id,'Raid inside geofence:'); + } } - catch (PDOException $exception) { - error_log($exception->getMessage()); - $dbh = null; - exit; + if($insideGeoFence === false) { + debug_log($gym_name,'Ignoring raid, not inside any geofence:'); + continue; } + } - // Create raid if not exists otherwise update if changes are detected + // Create gym if it doesn't exists, otherwise update gym info. + $query = my_query(' + INSERT INTO gyms (lat, lon, gym_name, gym_id, ex_gym, img_url, show_gym) + VALUES (:lat, :lon, :gym_name, :gym_id, :ex_gym, :img_url, 1) + ON DUPLICATE KEY UPDATE + lat = :lat, + lon = :lon, + gym_name = :gym_name, + ex_gym = :ex_gym, + img_url = :img_url + ',[ + 'lat' => $gym_lat, + 'lon' => $gym_lon, + 'gym_name' => $gym_name, + 'gym_id' => $gym_id, + 'ex_gym' => $gym_is_ex, + 'img_url' => $gym_img_url, + ]); + if($query->rowCount() == 1) { + $gym_internal_id = $dbh->lastInsertId(); + debug_log($gym_internal_id, 'New gym '.$gym_name.' created with internal id of:'); + }else { + $statement = my_query('SELECT id FROM gyms WHERE gym_id LIKE :gym_id LIMIT 1',['gym_id'=>$gym_id]); + $gym_internal_id = $statement->fetch()['id']; + debug_log($gym_internal_id, 'Gym info updated. Internal id:'); + } - // Raid pokemon form - // Use negated evolution id instead of form id if present - if(isset($raid['message']['evolution']) && $raid['message']['evolution'] > 0) { - $form = 0 - $raid['message']['evolution']; - }else { - $form = isset($raid['message']['form']) ? $raid['message']['form'] : 0; - } + // Create raid if not exists otherwise update if changes are detected - // Raid pokemon gender - $gender = 0; - if ( isset($raid['message']['gender']) ) { - $gender = $raid['message']['gender']; - } - // Raid pokemon costume - $costume = 0; - if ( isset($raid['message']['costume']) ) { - $costume = $raid['message']['costume']; - } + // Raid pokemon form + // Use negated evolution id instead of form id if present + if(isset($raid['message']['evolution']) && $raid['message']['evolution'] > 0) { + $form = 0 - $raid['message']['evolution']; + }else { + $form = isset($raid['message']['form']) ? $raid['message']['form'] : 0; + } - // Raid pokemon moveset - $move_1 = 0; - $move_2 = 0; - if ($pokemon < 9900) { - $move_1 = $raid['message']['move_1']; - $move_2 = $raid['message']['move_2']; - } + // Raid pokemon gender + $gender = 0; + if( isset($raid['message']['gender']) ) { + $gender = $raid['message']['gender']; + } + // Raid pokemon costume + $costume = 0; + if( isset($raid['message']['costume']) ) { + $costume = $raid['message']['costume']; + } - // Raid start and endtimes - $spawn = (isset($raid['message']['spawn'])) ? gmdate('Y-m-d H:i:s',$raid['message']['spawn']) : gmdate('Y-m-d H:i:s', ($raid['message']['start'] - $config->RAID_EGG_DURATION*60)); - $start = gmdate('Y-m-d H:i:s',$raid['message']['start']); - $end = gmdate('Y-m-d H:i:s',$raid['message']['end']); - - // Gym team - $team = $raid['message']['team_id']; - if (! empty($team)) { - switch ($team) { - case (1): - $team = 'mystic'; - break; - case (2): - $team = 'valor'; - break; - case (3): - $team = 'instinct'; - break; - } + // Raid pokemon moveset + $move_1 = 0; + $move_2 = 0; + if($pokemon < 9900) { + $move_1 = $raid['message']['move_1']; + $move_2 = $raid['message']['move_2']; + } + + // Raid start and endtimes + $spawn = (isset($raid['message']['spawn'])) ? gmdate('Y-m-d H:i:s',$raid['message']['spawn']) : gmdate('Y-m-d H:i:s', ($raid['message']['start'] - $config->RAID_EGG_DURATION*60)); + $start = gmdate('Y-m-d H:i:s',$raid['message']['start']); + $end = gmdate('Y-m-d H:i:s',$raid['message']['end']); + + // Gym team + $team = $raid['message']['team_id']; + if(!empty($team)) { + switch ($team) { + case (1): + $team = 'mystic'; + break; + case (2): + $team = 'valor'; + break; + case (3): + $team = 'instinct'; + break; } + } - // Insert new raid or update existing raid/ex-raid? - $raid_id = active_raid_duplication_check($gym_internal_id, $level); - - $send_updates = false; - - // Raid exists, do updates! - if ( $raid_id > 0 ) { - debug_log($gym_name, 'Raid already in DB for gym:'); - // Update database - try { - $query = ' - UPDATE raids - SET - pokemon = :pokemon, - pokemon_form = :pokemon_form, - gym_team = :gym_team, - move1 = :move1, - move2 = :move2, - gender = :gender, - costume = :costume - WHERE - id = :id - '; - $execute_array = [ - 'pokemon' => $pokemon, - 'pokemon_form' => $form, - 'gym_team' => $team, - 'move1' => $move_1, - 'move2' => $move_2, - 'gender' => $gender, - 'costume' => $costume, - 'id' => $raid_id - ]; - $statement = $dbh->prepare( $query ); - $statement->execute($execute_array); - } - catch (PDOException $exception) { - error_log($exception->getMessage()); - $dbh = null; - exit; - } - // If update was needed, send them to TG - if($statement->rowCount() > 0) { - $send_updates = true; - debug_log($raid_id, 'Raid updated:'); - }else { - debug_log($gym_name,'Nothing had changed for raid at gym:'); - continue; - } - }else { - // Create Raid and send messages - debug_log($gym_name, 'Raid not in DB yet, creating for gym:'); - try { - $query = ' - INSERT INTO raids (pokemon, pokemon_form, user_id, spawn, start_time, end_time, gym_team, gym_id, level, move1, move2, gender, costume) - VALUES (:pokemon, :pokemon_form, :user_id, :spawn, :start_time, :end_time, :gym_team, :gym_id, :level, :move1, :move2, :gender, :costume) - '; - $execute_array = [ - 'pokemon' => $pokemon, - 'pokemon_form' => $form, - 'user_id' => $config->WEBHOOK_CREATOR, - 'spawn' => $spawn, - 'start_time' => $start, - 'end_time' => $end, - 'gym_team' => $team, - 'gym_id' => $gym_internal_id, - 'level' => $level, - 'move1' => $move_1, - 'move2' => $move_2, - 'gender' => $gender, - 'costume' => $costume - ]; - $statement = $dbh->prepare( $query ); - $statement->execute($execute_array); - $raid_id = $dbh->lastInsertId(); - debug_log($raid_id, 'New raid created, raid id:'); - } - catch (PDOException $exception) { - error_log($exception->getMessage()); - $dbh = null; - exit; - } - if ($metrics){ - $webhook_raids_accepted_total->inc(); - } + // Insert new raid or update existing raid/ex-raid? + $raid_id = active_raid_duplication_check($gym_internal_id, $level); - if ($no_auto_posting) { - debug_log($gym_name,'Not autoposting raid, WEBHOOK_CREATE_ONLY is set to true or raids duration is over the WEBHOOK_EXCLUDE_AUTOSHARE_DURATION threshold:'); - continue; - } + $send_updates = false; + + // Raid exists, do updates! + if( $raid_id > 0 ) { + debug_log($gym_name, 'Raid already in DB for gym:'); + // Update database + $statement = my_query(' + UPDATE raids + SET + pokemon = :pokemon, + pokemon_form = :pokemon_form, + gym_team = :gym_team, + move1 = :move1, + move2 = :move2, + gender = :gender, + costume = :costume + WHERE + id = :id + ',[ + 'pokemon' => $pokemon, + 'pokemon_form' => $form, + 'gym_team' => $team, + 'move1' => $move_1, + 'move2' => $move_2, + 'gender' => $gender, + 'costume' => $costume, + 'id' => $raid_id, + ]); + + // If update was needed, send them to TG + if($statement->rowCount() > 0) { + $send_updates = true; + debug_log($raid_id, 'Raid updated:'); + }else { + debug_log($gym_name,'Nothing had changed for raid at gym:'); + continue; } + }else { + // Create Raid and send messages + debug_log($gym_name, 'Raid not in DB yet, creating for gym:'); + my_query(' + INSERT INTO raids (pokemon, pokemon_form, user_id, spawn, start_time, end_time, gym_team, gym_id, level, move1, move2, gender, costume) + VALUES (:pokemon, :pokemon_form, :user_id, :spawn, :start_time, :end_time, :gym_team, :gym_id, :level, :move1, :move2, :gender, :costume) + ',[ + 'pokemon' => $pokemon, + 'pokemon_form' => $form, + 'user_id' => $config->WEBHOOK_CREATOR, + 'spawn' => $spawn, + 'start_time' => $start, + 'end_time' => $end, + 'gym_team' => $team, + 'gym_id' => $gym_internal_id, + 'level' => $level, + 'move1' => $move_1, + 'move2' => $move_2, + 'gender' => $gender, + 'costume' => $costume + ]); + $raid_id = $dbh->lastInsertId(); + debug_log($raid_id, 'New raid created, raid id:'); - // Query missing data needed to construct the raid poll - try { - $query_missing = ' - SELECT - gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, gyms.gym_note, - users.*, - TIME_FORMAT(TIMEDIFF(:raid_end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left - FROM gyms - LEFT JOIN (SELECT users.name, users.trainername, users.nick FROM users WHERE users.user_id = :user_id) as users on 1 - WHERE gyms.id = :gym_internal_id - LIMIT 1 - '; - $execute_array_missing = [ - 'raid_end_time' => $end, - 'user_id' => $config->WEBHOOK_CREATOR, - 'gym_internal_id' => $gym_internal_id, - ]; - - $statement_missing = $dbh->prepare($query_missing); - $statement_missing->execute($execute_array_missing); - $missing_raid_data = $statement_missing->fetch(); - - $resolved_boss = resolve_raid_boss($pokemon, $form, $spawn, $level); - - // Combine resulting data with stuff received from webhook to create a complete raid array - $raid = array_merge($missing_raid_data, [ - 'id' => $raid_id, - 'user_id' => $config->WEBHOOK_CREATOR, - 'spawn' => $spawn, - 'pokemon' => $resolved_boss['pokedex_id'], - 'pokemon_form' => $resolved_boss['pokemon_form_id'], - 'start_time' => $start, - 'end_time' => $end, - 'gym_team' => $team, - 'gym_id' => $gym_internal_id, - 'level' => $level, - 'move1' => $move_1, - 'move2' => $move_2, - 'gender' => $gender, - 'costume' => $costume, - 'event' => NULL, - 'event_note' => NULL, - 'event_name' => NULL, - 'event_description' => NULL, - 'event_vote_key_mode' => NULL, - 'event_time_slots' => NULL, - 'event_raid_duration' => NULL, - 'event_hide_raid_picture' => NULL, - 'event_pokemon_title' => NULL, - 'event_poll_template' => NULL, - 'raid_ended' => 0, - ]); + if($metrics) { + $webhook_raids_accepted_total->inc(); } - catch (PDOException $exception) { - error_log($exception->getMessage()); - $dbh = null; - exit; + + if($no_auto_posting) { + debug_log($gym_name,'Not autoposting raid, WEBHOOK_CREATE_ONLY is set to true or raids duration is over the WEBHOOK_EXCLUDE_AUTOSHARE_DURATION threshold:'); + continue; } - $chats_geofence = $chats_raidlevel = $webhook_chats = $chats_by_pokemon = []; - if($send_updates == true) { - require_once(LOGIC_PATH .'/update_raid_poll.php'); - $tg_json = update_raid_poll($raid_id, $raid, false, $tg_json, true); - if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0]) && !$no_auto_posting) { - foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { - if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { - foreach($rule['chats'] as $rule_chat) { - // If the raid isn't already posted to the chats specified in WEBHOOK_CHATS_BY_POKEMON, we add it to the array - if(!isset($cleanup_data[$raid_id]) or !in_array($rule_chat, $cleanup_data[$raid_id])) { - $chats_by_pokemon[] = $rule_chat; - } - } - } - } - } - if(empty($chats_by_pokemon)) continue; - }else { - // Get chats to share to by raid level and geofence id - if($geofences != false) { - foreach ($inside_geofences as $geofence_id) { - $const_geofence = 'WEBHOOK_CHATS_LEVEL_' . $level . '_' . $geofence_id; - $const_geofence_chats = $config->{$const_geofence} ?? []; - - if(!empty($const_geofence_chats)) { - $chats_geofence = explode(',', $const_geofence_chats); - } - } - } + } + + // Query missing data needed to construct the raid poll + $query_missing = my_query(' + SELECT + gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, gyms.gym_note, + users.*, + TIME_FORMAT(TIMEDIFF(:raid_end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left + FROM gyms + LEFT JOIN (SELECT users.name, users.trainername, users.nick FROM users WHERE users.user_id = :user_id) as users on 1 + WHERE gyms.id = :gym_internal_id + LIMIT 1 + ',[ + 'raid_end_time' => $end, + 'user_id' => $config->WEBHOOK_CREATOR, + 'gym_internal_id' => $gym_internal_id, + ]); - // Get chats to share to by raid level - $const = 'WEBHOOK_CHATS_LEVEL_' . $level; - $const_chats = $config->{$const} ?? []; + $missing_raid_data = $query_missing->fetch(); - if(!empty($const_chats)) { - $chats_raidlevel = explode(',', $const_chats); + $resolved_boss = resolve_raid_boss($pokemon, $form, $spawn, $level); + + // Combine resulting data with stuff received from webhook to create a complete raid array + $raid = array_merge($missing_raid_data, [ + 'id' => $raid_id, + 'user_id' => $config->WEBHOOK_CREATOR, + 'spawn' => $spawn, + 'pokemon' => $resolved_boss['pokedex_id'], + 'pokemon_form' => $resolved_boss['pokemon_form_id'], + 'start_time' => $start, + 'end_time' => $end, + 'gym_team' => $team, + 'gym_id' => $gym_internal_id, + 'level' => $level, + 'move1' => $move_1, + 'move2' => $move_2, + 'gender' => $gender, + 'costume' => $costume, + 'event' => NULL, + 'event_note' => NULL, + 'event_name' => NULL, + 'event_description' => NULL, + 'event_vote_key_mode' => NULL, + 'event_time_slots' => NULL, + 'event_raid_duration' => NULL, + 'event_hide_raid_picture' => NULL, + 'event_pokemon_title' => NULL, + 'event_poll_template' => NULL, + 'raid_ended' => 0, + ]); + + $chats_geofence = $chats_raidlevel = $webhook_chats = $chats_by_pokemon = []; + if($send_updates == true) { + require_once(LOGIC_PATH .'/update_raid_poll.php'); + $tg_json = update_raid_poll($raid_id, $raid, false, $tg_json, true); + if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0]) && !$no_auto_posting) { + foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { + if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { + foreach($rule['chats'] as $rule_chat) { + // If the raid isn't already posted to the chats specified in WEBHOOK_CHATS_BY_POKEMON, we add it to the array + if(!isset($cleanup_data[$raid_id]) or !in_array($rule_chat, $cleanup_data[$raid_id])) { + $chats_by_pokemon[] = $rule_chat; + } + } } + } + } + if(empty($chats_by_pokemon)) continue; + }else { + // Get chats to share to by raid level and geofence id + if($geofences != false) { + foreach($inside_geofences as $geofence_id) { + $const_geofence = 'WEBHOOK_CHATS_LEVEL_' . $level . '_' . $geofence_id; + $const_geofence_chats = $config->{$const_geofence} ?? []; - // Get chats - if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { - $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); + if(!empty($const_geofence_chats)) { + $chats_geofence = explode(',', $const_geofence_chats); } + } } - $chats = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats, $chats_by_pokemon); + // Get chats to share to by raid level + $const = 'WEBHOOK_CHATS_LEVEL_' . $level; + $const_chats = $config->{$const} ?? []; - require_once(LOGIC_PATH .'/send_raid_poll.php'); - if ($metrics){ - $webhook_raids_posted_total->inc(); + if(!empty($const_chats)) { + $chats_raidlevel = explode(',', $const_chats); } - if(count($chats) > 0) { - $tg_json = send_raid_poll($raid_id, $chats, $raid, $tg_json); + + // Get chats + if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { + $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); } + } + + $chats = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats, $chats_by_pokemon); + + require_once(LOGIC_PATH .'/send_raid_poll.php'); + if($metrics) { + $webhook_raids_posted_total->inc(); + } + if(count($chats) > 0) { + $tg_json = send_raid_poll($raid_id, $chats, $raid, $tg_json); + } } // Telegram multicurl request. curl_json_multi_request($tg_json); - -?> diff --git a/commands/set.php b/commands/set.php new file mode 100644 index 00000000..6e56acd5 --- /dev/null +++ b/commands/set.php @@ -0,0 +1,178 @@ +accessCheck($update, 'config-set'); + +// Get config name and value. +$input = trim(substr($update['message']['text'], 4)); + +// Get delimiter count. +$count = substr_count($input, " "); + +// Get allowed telegram configs. +$allowed = explode(',', $config->ALLOWED_TELEGRAM_CONFIG); + +// Get config restrictions for boolean input +$allowed_bool = explode(',', $config->ALLOW_ONLY_TRUE_FALSE); + +// Get config restrictions for numeric input +$allowed_numbers = explode(',', $config->ALLOW_ONLY_NUMBERS); + +// Write to log. +debug_log('User submitted a telegram config change'); +debug_log('Allowed telegram configs: ' . $config->ALLOWED_TELEGRAM_CONFIG); +debug_log('Allow only boolean input: ' . $config->ALLOW_ONLY_TRUE_FALSE); +debug_log('Allow only numeric input: ' . $config->ALLOW_ONLY_NUMBERS); + +// 0 means we reset config option value to "" +if($count == 0) { + // Upper input. + $config_name = strtoupper($input); + $config_value = ''; + debug_log('Reset for the config value ' . $config_name . ' was requested by the user'); + +// 1 means we set the config option to the given value +} else if($count >= 1) { + // Config name and value. + $cfg_name_value = explode(' ', $input, 2); + $config_name = strtoupper($cfg_name_value[0]); + $config_value = $cfg_name_value[1]; + debug_log('Change for the config option ' . $config_name . ' was requested by the user'); + +// Set config_name to avoid undefined variable for if clause below. +} else { + $config_name = 'not_supported'; +} + +// Config +$cfile = CONFIG_PATH . '/config.json'; +if(is_file($cfile)) { + $str = file_get_contents($cfile); + $json = json_decode($str, true); +} + +// Real config name or alias? +$alias = ''; +$afile = CONFIG_PATH . '/alias.json'; +if(is_file($afile)) { + debug_log('Checking alias for config option ' . $config_name); + $astr = file_get_contents($afile); + // We compare always uppercase, so change str to upper + $astr = strtoupper($astr); + $ajson = json_decode($astr, true); + $alias = array_search($config_name, $ajson); + // Check for alias + if ($alias !== false) { + debug_log('Config option ' . $config_name . ' is an alias for ' . $alias); + $help = $config_name; + $config_name = strtoupper($alias); + $alias = $help; + } else { + debug_log('No alias found. Seems ' . $config_name . ' is the config option name'); + } +} + +// Assume restrictions. +$restrict = 'yes'; + +// Init additional error info. +$msg_error_info = ''; + +// Make sure it's allowed to update the value via telegram. +if(in_array($config_name, $allowed)) { + // Only bool? + if(in_array($config_name, $allowed_bool)) { + if(strcasecmp($config_value, 'true') == 0 || strcasecmp($config_value, 'false') == 0) { + $config_value = strtolower($config_value); + $restrict = 'no'; + } else if($config_value == 0 || $config_value == 1) { + $restrict = 'no'; + } else { + debug_log('Boolean value expected. Got this value: ' . $config_value); + $msg_error_info .= getTranslation('help_bool_expected'); + } + + + // Only numbers? + } else if(in_array($config_name, $allowed_numbers)) { + if(is_numeric($config_value)) { + $restrict = 'no'; + } else { + debug_log('Number expected. Got this value: ' . $config_value); + $msg_error_info .= getTranslation('help_number_expected'); + } + + // No restriction on input type. + } else { + $restrict = 'no'; + } +} + +// Update config. +if(in_array($config_name, $allowed) && $restrict == 'no') { + // Prepare data, replace " with ' + $config_value = str_replace('"', "'", $config_value); + $old_value = $json[$config_name]; + $json[$config_name] = $config_value; + $jsonString = json_encode($json, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT); + debug_log($config_name, 'CONFIG NAME:'); + debug_log($config_value, 'CONFIG VALUE:'); + + // Write to file. + if(json_last_error() === JSON_ERROR_NONE) { + file_put_contents(CONFIG_PATH . '/config.json', $jsonString); + $msg = getTranslation('config_updated') . ':' . CR . CR; + $msg .= '' . (empty($alias) ? $config_name : $alias) . '' . CR; + $msg .= getTranslation('old_value') . SP . $old_value . CR; + $msg .= getTranslation('new_value') . SP . $config_value . CR; + debug_log('Changed the config value for ' . $config_name . ' from ' . $old_value . ' to ' . $config_value); + } else { + $msg_error_info = getTranslation('internal_error'); + $msg = '' . getTranslation('invalid_input') . '' . (!empty($msg_error_info) ? (CR . $msg_error_info) : '') . CR . CR; + } + +// Tell user how to set config and what is allowed to be set by config. +} else { + $msg = '' . getTranslation('invalid_input') . '' . (!empty($msg_error_info) ? (CR . $msg_error_info) : '') . CR . CR; + $msg .= '' . getTranslation('config') . ':' . CR; + // Any configs allowed? + if(!empty($config->ALLOWED_TELEGRAM_CONFIG)) { + $msg .= '/set [' . getTranslation("config_option") . '] [' . getTranslation('option_value') . ']' . CR; + foreach($json as $cfg_name => $cfg_value) { + // Only allowed configs + if(in_array($cfg_name, $allowed)) { + // Is alias set? + $alias = ''; + if(isset($ajson[$cfg_name])){ + $alias = $ajson[$cfg_name]; + } + // Config name / Alias + value + $msg .= '/set' . SP . (empty($alias) ? $cfg_name : $alias) . SP . (empty($cfg_value) ? '' . getTranslation('no_value') . '' : $cfg_value); + + // Only bool? + if(in_array($cfg_name, $allowed_bool)) { + $msg .= SP . '(' . getTranslation('help_only_bool') . ')'; + + // Only numbers? + } else if(in_array($cfg_name, $allowed_numbers)) { + $msg .= SP . '(' . getTranslation('help_only_numbers') . ')'; + + // Any type + } + $msg .= CR; + } + } + } else { + $msg .= getTranslation('not_supported'); + } + debug_log('Unsupported request for a telegram config change: ' . $input); +} + +// Send message. +send_message($update['message']['chat']['id'], $msg); diff --git a/commands/start.php b/commands/start.php index 107b789a..94069605 100644 --- a/commands/start.php +++ b/commands/start.php @@ -1,6 +1,8 @@ accessCheck($update, 'create', true, $new_user); if(!$access && !$new_user) { - if($botUser->accessCheck($update, 'list', true)){ - debug_log('No access to create, will do a list instead'); - require('list.php'); - }else { - $response_msg = '' . getTranslation('bot_access_denied') . ''; - send_message($update['message']['from']['id'], $response_msg); - } - exit; + if($botUser->accessCheck($update, 'list', true)){ + debug_log('No access to create, will do a list instead'); + require('list.php'); + }else { + $response_msg = '' . getTranslation('bot_access_denied') . ''; + send_message($update['message']['from']['id'], $response_msg); + } + exit; } if($new_user && !$access) { - // Tutorial - if(is_file(ROOT_PATH . '/config/tutorial.php')) { - require_once(ROOT_PATH . '/config/tutorial.php'); - } - $msg = $tutorial[0]['msg_new']; - $keys = [ - [ - [ - 'text' => getTranslation("next"), - 'callback_data' => '0:tutorial:1' - ] - ] - ]; - $photo = $tutorial[0]['photo']; - send_photo($update['message']['from']['id'], $photo, false, $msg, $keys, ['disable_web_page_preview' => 'true'],false); -}else { - // Trim away everything before "/start " - $searchterm = $update['message']['text']; - $searchterm = substr($searchterm, 7); - debug_log($searchterm, 'SEARCHTERM'); + // Tutorial + require_once('tutorial.php'); + exit; +} +// Trim away everything before "/start " +$searchterm = $update['message']['text']; +$searchterm = substr($searchterm, 7); +debug_log($searchterm, 'SEARCHTERM'); - // Start raid message. - if(strpos($searchterm , 'c0de-') === 0) { - $code_raid_id = explode("-", $searchterm, 2)[1]; - require_once(ROOT_PATH . '/mods/code_start.php'); - exit(); - } +// Start raid message. +if(strpos($searchterm , 'c0de-') === 0) { + $code_raid_id = explode("-", $searchterm, 2)[1]; + require_once(ROOT_PATH . '/mods/code_start.php'); + exit(); +} - // Get the keys by gym name search. - $keys = ''; - if(!empty($searchterm)) { - $keys = raid_get_gyms_list_keys($searchterm); - } +// Get the keys by gym name search. +$keys = false; +if(!empty($searchterm)) { + $keys = raid_get_gyms_list_keys($searchterm); +} - // Get the keys if nothing was returned. - if(!$keys) { - $keys_and_gymarea = raid_edit_gyms_first_letter_keys('raid_by_gym', false, false, 'raid_by_gym_letter'); - $keys = $keys_and_gymarea['keys']; - } +// Get the keys if nothing was returned. +if(!$keys) { + $keys_and_gymarea = raid_edit_gyms_first_letter_keys('raid_by_gym', false, false, 'raid_by_gym_letter'); + $keys = $keys_and_gymarea['keys']; +} - // No keys found. - if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('not_supported'), - 'callback_data' => '0:exit:0' - ] - ] - ]; - }else { - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - } - $msg = ''; - // Set message. - if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; - }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } - } - }elseif($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; +// No keys found. +if (!$keys) { + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('not_supported'), + 'callback_data' => '0:exit:0' + ] + ] + ]; +}else { + $keys[] = [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; +} +$msg = ''; +// Set message. +if($config->ENABLE_GYM_AREAS) { + if($keys_and_gymarea['gymarea_name'] == '') { + $msg .= '' . getTranslation('select_gym_area') . '' . CR; + }else { + if($keys_and_gymarea['letters']) { + $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; + $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; } - $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); - $msg.= ($config->RAID_VIA_LOCATION ? (CR . CR . getTranslation('send_location')) : ''); - - // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + } +}elseif(isset($keys_and_gymarea) && $keys_and_gymarea['letters']) { + $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; +}else { + $msg .= '' . getTranslation('select_gym_name') . '' . CR; } -?> +$msg.= ((isset($keys_and_gymarea) && $keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); +$msg.= ($config->RAID_VIA_LOCATION ? (CR . CR . getTranslation('send_location')) : ''); + +// Send message. +send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/trainer.php b/commands/trainer.php index 06dbfbb4..e487726a 100644 --- a/commands/trainer.php +++ b/commands/trainer.php @@ -1,6 +1,7 @@ ' . getTranslation('trainerinfo_set_yours') . ''; $user_id = $update['message']['from']['id']; -$msg .= CR.CR.get_user($user_id, false); +$msg .= CR . CR . get_user($user_id, false); // Init empty keys array. $keys = []; // Create keys array. if($config->CUSTOM_TRAINERNAME){ - $keys[0][] = - [ - 'text' => getTranslation('name'), - 'callback_data' => '0:trainer_name:0' - ]; + $keys[0][] = [ + 'text' => getTranslation('name'), + 'callback_data' => '0:trainer_name:0' + ]; } if($config->RAID_POLL_SHOW_TRAINERCODE){ - $keys[0][] = - [ - 'text' => getTranslation('trainercode'), - 'callback_data' => '0:trainer_code:0' - ]; + $keys[0][] = [ + 'text' => getTranslation('trainercode'), + 'callback_data' => '0:trainer_code:0' + ]; } $keys[] = [ - [ - 'text' => getTranslation('team'), - 'callback_data' => '0:trainer_team:0' - ], - [ - 'text' => getTranslation('level'), - 'callback_data' => '0:trainer_level:0' - ] + [ + 'text' => getTranslation('team'), + 'callback_data' => '0:trainer_team:0' + ], + [ + 'text' => getTranslation('level'), + 'callback_data' => '0:trainer_level:0' + ] ]; if ($config->RAID_AUTOMATIC_ALARM == false) { - $q_user = my_query("SELECT auto_alarm FROM users WHERE user_id = '{$user_id}' LIMIT 1"); - $alarm_status = $q_user->fetch()['auto_alarm']; - $keys[] = [ - [ - 'text' => ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), - 'callback_data' => '0:trainer:a' - ] - ]; + $q_user = my_query("SELECT auto_alarm FROM users WHERE user_id = '{$user_id}' LIMIT 1"); + $alarm_status = $q_user->fetch()['auto_alarm']; + $keys[] = [ + [ + 'text' => ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), + 'callback_data' => '0:trainer:a' + ] + ]; } if ($config->LANGUAGE_PRIVATE == '') { - $keys[] = [ - [ - 'text' => getTranslation('bot_lang'), - 'callback_data' => '0:bot_lang:0' - ] - ]; + $keys[] = [ + [ + 'text' => getTranslation('bot_lang'), + 'callback_data' => '0:bot_lang:0' + ] + ]; } // Check access. @@ -66,16 +65,16 @@ // Display sharing options for admins and users with trainer-share permissions if($access) { - // Add sharing keys. - $share_keys = []; - $share_keys[] = universal_inner_key($keys, '0', 'trainer_add', '0', getTranslation('trainer_message_share')); - $share_keys[] = universal_inner_key($keys, '0', 'trainer_delete', '0', getTranslation('trainer_message_delete')); + // Add sharing keys. + $share_keys = []; + $share_keys[] = universal_inner_key($keys, '0', 'trainer_add', '0', getTranslation('trainer_message_share')); + $share_keys[] = universal_inner_key($keys, '0', 'trainer_delete', '0', getTranslation('trainer_message_delete')); - // Get the inline key array. - $keys[] = $share_keys; + // Get the inline key array. + $keys[] = $share_keys; - // Add message. - $msg .= CR . CR . getTranslation('trainer_message_share_or_delete'); + // Add message. + $msg .= CR . CR . getTranslation('trainer_message_share_or_delete'); } // Add abort key. @@ -87,5 +86,3 @@ // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); - -?> diff --git a/commands/tutorial.php b/commands/tutorial.php index 8802908c..e0f2611c 100644 --- a/commands/tutorial.php +++ b/commands/tutorial.php @@ -11,22 +11,18 @@ // Tutorial if(is_file(ROOT_PATH . '/config/tutorial.php')) { - require_once(ROOT_PATH . '/config/tutorial.php'); -} -$new_user = new_user($update['message']['from']['id']); -if($new_user) { - $msg = $tutorial[0]['msg_new']; -}else { - $msg = $tutorial[0]['msg']; + require_once(ROOT_PATH . '/config/tutorial.php'); } +// New user can already be set if this file was included from start.php. If not, set it here +$new_user = $new_user ?? new_user($update['message']['from']['id']); +$msg = ($new_user) ? $tutorial[0]['msg_new'] : $tutorial[0]['msg']; $keys = [ -[ - [ - 'text' => getTranslation("next"), - 'callback_data' => '0:tutorial:1' - ] -] + [ + [ + 'text' => getTranslation("next"), + 'callback_data' => '0:tutorial:1' + ] + ] ]; $photo = $tutorial[0]['photo']; send_photo($update['message']['from']['id'], $photo, false, $msg, $keys, ['disable_web_page_preview' => 'true'],false); -?> \ No newline at end of file diff --git a/config/defaults-config.json b/config/defaults-config.json index 1ba353c9..af1db0c0 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -16,7 +16,6 @@ "APIKEY_HASH":"", "ENABLE_DDOS_PROTECTION": true, "DDOS_MAXIMUM":"10", - "BRIDGE_MODE": false, "CURL_USEPROXY": false, "CURL_PROXYSERVER":"http://example.com:8080", "MAINTAINER":"", diff --git a/config/defaults-telegram.json b/config/defaults-telegram.json index fa9bd880..7cccb0d7 100644 --- a/config/defaults-telegram.json +++ b/config/defaults-telegram.json @@ -1,4 +1,4 @@ -{ +{ "ALLOWED_TELEGRAM_CONFIG":"RAID_EGG_DURATION,RAID_DURATION,ENABLE_BOSS_AUTO_UPDATE", "ALLOW_ONLY_TRUE_FALSE":"ENABLE_BOSS_AUTO_UPDATE", "ALLOW_ONLY_NUMBERS":"RAID_EGG_DURATION,RAID_DURATION" diff --git a/config/tutorial.php.example b/config/tutorial.php.example index bec2229b..694ec8e0 100644 --- a/config/tutorial.php.example +++ b/config/tutorial.php.example @@ -14,5 +14,3 @@ $tutorial[2]['photo'] = '';// A photo url must be set! $tutorial_done = 'Message that is left to user after completing the tutorial.'; $tutorial_grant_level = 1; // The tutorial value set to user in db (int)0-9 - -?> \ No newline at end of file diff --git a/constants.php b/constants.php index c0204b55..4c77c6b4 100644 --- a/constants.php +++ b/constants.php @@ -7,15 +7,15 @@ // Raid eggs. $eggs = array( - '9999', // Level 9 / Elite raid - '9998', // Level 8 / Ultra beast - '9997', // Level 7 / Legendary Mega - '9996', // Level 6 / Mega - '9995', // Level 5 - '9994', // Level 4 - '9993', // Level 3 - '9992', // Level 2 - '9991' // Level 1 + '9999', // Level 9 / Elite raid + '9998', // Level 8 / Ultra beast + '9997', // Level 7 / Legendary Mega + '9996', // Level 6 / Mega + '9995', // Level 5 + '9994', // Level 4 + '9993', // Level 3 + '9992', // Level 2 + '9991' // Level 1 ); // Raid levels limited to local players only @@ -26,24 +26,40 @@ // Map our raid levels to tier names PokeBattler uses $pokebattler_level_map = [ - '1' => 1, - '3' => 3, - '4' => 4, - '5' => 5, - '6' => 'MEGA', - '7' => 'MEGA_5', - '8' => 'ULTRA_BEAST', - '9' => 'ELITE', + '1' => 1, + '3' => 3, + '4' => 4, + '5' => 5, + '6' => 'MEGA', + '7' => 'MEGA_5', + '8' => 'ULTRA_BEAST', + '9' => 'ELITE', ]; $pokebattler_pokemon_map = [ - 'ZACIAN' => 'ZACIAN_HERO_FORM', - 'ZAMAZENTA' => 'ZAMAZENTA_HERO_FORM', + 'ZACIAN' => 'ZACIAN_HERO_FORM', + 'ZAMAZENTA' => 'ZAMAZENTA_HERO_FORM', ]; // Limit the tiers of upcoming raid bosses imported from PokeBattler to legendary and mega $pokebattler_import_future_tiers = [5, 6, 7, 8, 9]; +// Default language. +defined('DEFAULT_LANGUAGE') or define('DEFAULT_LANGUAGE', 'EN'); + +// Telegram language code => Language files. +$languages = array( + 'nl' => 'NL', + 'de' => 'DE', + 'en' => 'EN', + 'it' => 'IT', + 'pt' => 'PT-BR', + 'ru' => 'RU', + 'fr' => 'FR', + 'fi' => 'FI', + 'es' => 'ES', +); + // Value used for denoting anytime attendance define('ANYTIME', '1970-01-01 00:00:00'); define('ANYTIME_TS', preg_replace("/[^0-9]/", "", ANYTIME)); @@ -92,23 +108,34 @@ defined('EMOJI_W_SNOW') or define('EMOJI_W_SNOW', iconv('UCS-4LE', 'UTF-8', pack('V', 0x2744))); defined('EMOJI_W_FOG') or define('EMOJI_W_FOG', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F301))); +defined('EMOJI_WARN') or define('EMOJI_WARN', iconv('UCS-4LE', 'UTF-8', pack('V', 0x26A0))); +defined('EMOJI_DISK') or define('EMOJI_DISK', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F4BE))); +defined('EMOJI_NEW') or define('EMOJI_NEW', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F195))); +defined('EMOJI_CLIPPY') or define('EMOJI_CLIPPY',iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F4CE))); + +// Carriage return. +defined('CR') or define('CR', "\n"); +defined('CR2') or define('CR2', "\n"); +// Space. +defined('SP') or define('SP', " "); + // Weather. $weather = array( - '1' => EMOJI_W_SUNNY, - '2' => EMOJI_W_CLEAR, - '3' => EMOJI_W_RAIN, - '4' => EMOJI_W_PARTLY_CLOUDY, - '5' => EMOJI_W_CLOUDY, - '6' => EMOJI_W_WINDY, - '7' => EMOJI_W_SNOW, - '8' => EMOJI_W_FOG + '1' => EMOJI_W_SUNNY, + '2' => EMOJI_W_CLEAR, + '3' => EMOJI_W_RAIN, + '4' => EMOJI_W_PARTLY_CLOUDY, + '5' => EMOJI_W_CLOUDY, + '6' => EMOJI_W_WINDY, + '7' => EMOJI_W_SNOW, + '8' => EMOJI_W_FOG ); // Teams. $teams = array( - 'mystic' => TEAM_B, - 'valor' => TEAM_R, - 'instinct' => TEAM_Y, - 'unknown' => TEAM_UNKNOWN, - 'cancel' => TEAM_CANCEL + 'mystic' => TEAM_B, + 'valor' => TEAM_R, + 'instinct' => TEAM_Y, + 'unknown' => TEAM_UNKNOWN, + 'cancel' => TEAM_CANCEL ); diff --git a/core/bot/apikey.php b/core/bot/apikey.php index 5f20335d..2289639a 100644 --- a/core/bot/apikey.php +++ b/core/bot/apikey.php @@ -5,29 +5,28 @@ * @return Array */ function get_verified_update(){ - global $config; + global $config, $argv; // Get api key from get parameters. if(isset($_GET['apikey'])) { - $apiKey = $_GET['apikey']; + $apiKey = $_GET['apikey']; // Get api key from argv. } elseif(!empty($argv[1])) { - $apiKey = $argv[1]; + $apiKey = $argv[1]; } else { - debug_log('Called without apikey, returning empty content.'); - http_response_code(204); // HTTP 204: No Content - exit(); + debug_log('Called without apikey, returning empty content.'); + http_response_code(204); // HTTP 204: No Content + exit(); } // Check if hashed api key is matching config. - if (hash('sha512', $apiKey) == strtolower($config->APIKEY_HASH)) { - // Set constants. - define('API_KEY', $apiKey); - } else { - info_log('Incorrect apikey provided! This is most likely a misconfiguration you should fix.'); - http_response_code(403); // HTTP 403: Forbidden - exit(); + if (hash('sha512', $apiKey) != strtolower($config->APIKEY_HASH)) { + info_log('Incorrect apikey provided! This is most likely a misconfiguration you should fix.'); + http_response_code(403); // HTTP 403: Forbidden + exit(); } + // Set constants. + define('API_KEY', $apiKey); // Get content from POST data. $update = null; @@ -37,7 +36,6 @@ function get_verified_update(){ // Decode the json string. $update = json_decode($content, true); } elseif(!empty($argv[2])) { - $arg_content = addslashes($argv[2]); $update = json_decode($argv[2], true); } diff --git a/core/bot/cleanup_collect.php b/core/bot/cleanup_collect.php index f416f5ab..92beb425 100644 --- a/core/bot/cleanup_collect.php +++ b/core/bot/cleanup_collect.php @@ -6,30 +6,31 @@ // Init ID. $cleanup_id = 0; $message = null; -// Channel +// Channel if(isset($update['channel_post']['text'])) { - $message = $update['channel_post']; + $message = $update['channel_post']; // Supergroup } else if (isset($update['message']['text']) && ($update['message']['chat']['type'] == "supergroup" || $update['message']['chat']['type'] == "group")) { - $message = $update['message']; + $message = $update['message']; } if($message != null) { - // Get chat_id and message_id - $chat_id = $message['chat']['id']; - $message_id = $message['message_id']; - if(isset($message['reply_markup']['inline_keyboard'])) { - $split_data = explode(':', $message['reply_markup']['inline_keyboard'][0][0]['callback_data']); - $cleanup_id = $split_data[0]; - }else { - // Get id from text. - $cleanup_id = substr($message['text'],strpos($message['text'], substr(strtoupper($config->BOT_ID), 0, 1) . '-ID = ') + 7); - } + // Get chat_id and message_id + $chat_id = $message['chat']['id']; + $message_id = $message['message_id']; + if(isset($message['reply_markup']['inline_keyboard'])) { + $split_data = explode(':', $message['reply_markup']['inline_keyboard'][0][0]['callback_data']); + $cleanup_id = $split_data[0]; + }else { + // Get id from text. + $cleanup_id = substr($message['text'],strpos($message['text'], substr(strtoupper($config->BOT_ID), 0, 1) . '-ID = ') + 7); + } - // Write cleanup info to database. - cleanup_log('Calling cleanup preparation now!'); - cleanup_log('Cleanup_ID: ' . $cleanup_id); - if($cleanup_id != 0) { - insert_cleanup($chat_id, $message_id, $cleanup_id, 'inline_poll_text'); - } + // Write cleanup info to database. + cleanup_log('Calling cleanup preparation now!'); + cleanup_log('Cleanup_ID: ' . $cleanup_id); + if($cleanup_id != 0) { + require_once(LOGIC_PATH . '/insert_cleanup.php'); + insert_cleanup($chat_id, $message_id, $cleanup_id, 'inline_poll_text'); + } } diff --git a/core/bot/cleanup_run.php b/core/bot/cleanup_run.php index 36d4af37..0e124a42 100644 --- a/core/bot/cleanup_run.php +++ b/core/bot/cleanup_run.php @@ -5,16 +5,15 @@ function cleanup_auth_and_run($update){ global $config; cleanup_log('Cleanup request received.'); - if ($update['cleanup']['secret'] == $config->CLEANUP_SECRET) { - cleanup_log('Cleanup is authenticated.'); - perform_cleanup(); - } else { - $error = 'Cleanup authentication failed.'; - http_response_code(403); - error_log($error); - die($error); - } - exit(); + if ($update['cleanup']['secret'] != $config->CLEANUP_SECRET) { + $error = 'Cleanup authentication failed.'; + http_response_code(403); + error_log($error); + die($error); + } + cleanup_log('Cleanup is authenticated.'); + perform_cleanup(); + exit(); } // Do the actual cleanup. Authentication or authorization is not considered but config is checked @@ -39,70 +38,70 @@ function perform_cleanup(){ throw new Exception($error); } // Start cleanup when at least one parameter is set to trigger cleanup - if ($config->CLEANUP_TELEGRAM || $config->CLEANUP_DATABASE) { - // Query for telegram cleanup without database cleanup - if ($config->CLEANUP_TELEGRAM) { - // Get cleanup info for telegram cleanup. - $rs = my_query(' - SELECT cleanup.id, cleanup.raid_id, cleanup.chat_id, cleanup.message_id, raids.gym_id, - IF(date_of_posting < DATE_SUB(UTC_TIMESTAMP(), INTERVAL 48 HOUR), 1, 0) as skip_del_message - FROM cleanup - LEFT JOIN raids - ON cleanup.raid_id = raids.id - WHERE raids.end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_TG.' MINUTE) - '); - $cleanup_ids = []; - cleanup_log('Telegram cleanup starting. Found ' . $rs->rowCount() . ' entries for cleanup.'); - if($rs->rowCount() > 0) { - while($row = $rs->fetch()) { - if($row['skip_del_message'] == 0) { - delete_message($row['chat_id'], $row['message_id']); - cleanup_log('Deleting raid: '.$row['raid_id'].' from chat '.$row['chat_id'].' (message_id: '.$row['message_id'].')'); - if ($metrics){ - $cleanup_total->inc(['telegram']); - } - } else { - cleanup_log('Chat message for raid '.$row['raid_id'].' in chat '.$row['chat_id'].' is over 48 hours old. It can\'t be deleted by the bot. Skipping deletion and removing database entry.'); - } - $cleanup_ids[] = $row['id']; - } - my_query('DELETE FROM cleanup WHERE id IN (' . implode(',', $cleanup_ids) . ')'); - } + if (!$config->CLEANUP_TELEGRAM && !$config->CLEANUP_DATABASE) { + cleanup_log('Cleanup was called, but nothing was done. Check your config and cleanup request for which actions you would like to perform (Telegram and/or database cleanup)'); + return; + } + // Query for telegram cleanup without database cleanup + if ($config->CLEANUP_TELEGRAM) { + // Get cleanup info for telegram cleanup. + $rs = my_query(' + SELECT cleanup.id, cleanup.raid_id, cleanup.chat_id, cleanup.message_id, raids.gym_id, + IF(date_of_posting < DATE_SUB(UTC_TIMESTAMP(), INTERVAL 48 HOUR), 1, 0) as skip_del_message + FROM cleanup + LEFT JOIN raids + ON cleanup.raid_id = raids.id + WHERE raids.end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_TG.' MINUTE) + '); + $cleanup_ids = []; + cleanup_log('Telegram cleanup starting. Found ' . $rs->rowCount() . ' entries for cleanup.'); + if($rs->rowCount() > 0) { + while($row = $rs->fetch()) { + $cleanup_ids[] = $row['id']; + if($row['skip_del_message'] == 1) { + cleanup_log('Chat message for raid '.$row['raid_id'].' in chat '.$row['chat_id'].' is over 48 hours old. It can\'t be deleted by the bot. Skipping deletion and removing database entry.'); + continue; } - if($config->CLEANUP_DATABASE) { - cleanup_log('Database cleanup called.'); - $rs_temp_gyms = my_query(' - SELECT gyms.id, gyms.gym_name - FROM gyms - LEFT JOIN raids - ON raids.gym_id = gyms.id - WHERE (raids.end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_DB.' MINUTE)) - AND temporary_gym = 1 - '); - if($rs_temp_gyms->rowCount() > 0) { - $cleanup_gyms = []; - while($row = $rs_temp_gyms->fetch()) { - $cleanup_gyms[] = $row['id']; - cleanup_log('Deleting temporary gym ' . $row['id'] . ' from database.'); - } - if(count($cleanup_gyms) > 0) { - my_query('DELETE FROM gyms WHERE id IN (' . implode(',', $cleanup_gyms) . ')'); - } - } - $q_a = my_query('DELETE FROM attendance WHERE raid_id IN (SELECT id FROM raids WHERE raids.end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_DB.' MINUTE))'); - $q_r = my_query('DELETE FROM raids WHERE end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_DB.' MINUTE)'); - $q_p = my_query('DELETE photo_cache FROM photo_cache LEFT JOIN raids ON photo_cache.raid_id = raids.id WHERE photo_cache.ended = 0 AND raids.id IS NULL'); - cleanup_log('Cleaned ' . $q_a->rowCount() . ' rows from attendance table'); - cleanup_log('Cleaned ' . $q_r->rowCount() . ' rows from raids table'); - cleanup_log('Cleaned ' . $q_p->rowCount() . ' rows from photo_cache table'); - if ($metrics){ - $cleanup_total->incBy($q_a->rowCount(), ['db_attendance']); - $cleanup_total->incBy($q_r->rowCount(), ['db_raids']); - } + delete_message($row['chat_id'], $row['message_id']); + cleanup_log('Deleting raid: '.$row['raid_id'].' from chat '.$row['chat_id'].' (message_id: '.$row['message_id'].')'); + if ($metrics){ + $cleanup_total->inc(['telegram']); } - // Write to log. - cleanup_log('Finished with cleanup process!'); - }else { - cleanup_log('Cleanup was called, but nothing was done. Check your config and cleanup request for which actions you would like to perform (Telegram and/or database cleanup)'); + } + my_query('DELETE FROM cleanup WHERE id IN (' . implode(',', $cleanup_ids) . ')'); } + } + if($config->CLEANUP_DATABASE) { + cleanup_log('Database cleanup called.'); + $rs_temp_gyms = my_query(' + SELECT gyms.id, gyms.gym_name + FROM gyms + LEFT JOIN raids + ON raids.gym_id = gyms.id + WHERE (raids.end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_DB.' MINUTE)) + AND temporary_gym = 1 + '); + if($rs_temp_gyms->rowCount() > 0) { + $cleanup_gyms = []; + while($row = $rs_temp_gyms->fetch()) { + $cleanup_gyms[] = $row['id']; + cleanup_log('Deleting temporary gym ' . $row['id'] . ' from database.'); + } + if(count($cleanup_gyms) > 0) { + my_query('DELETE FROM gyms WHERE id IN (' . implode(',', $cleanup_gyms) . ')'); + } + } + $q_a = my_query('DELETE FROM attendance WHERE raid_id IN (SELECT id FROM raids WHERE raids.end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_DB.' MINUTE))'); + $q_r = my_query('DELETE FROM raids WHERE end_time < DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->CLEANUP_TIME_DB.' MINUTE)'); + $q_p = my_query('DELETE photo_cache FROM photo_cache LEFT JOIN raids ON photo_cache.raid_id = raids.id WHERE photo_cache.ended = 0 AND raids.id IS NULL'); + cleanup_log('Cleaned ' . $q_a->rowCount() . ' rows from attendance table'); + cleanup_log('Cleaned ' . $q_r->rowCount() . ' rows from raids table'); + cleanup_log('Cleaned ' . $q_p->rowCount() . ' rows from photo_cache table'); + if ($metrics){ + $cleanup_total->incBy($q_a->rowCount(), ['db_attendance']); + $cleanup_total->incBy($q_r->rowCount(), ['db_raids']); + } + } + // Write to log. + cleanup_log('Finished with cleanup process!'); } diff --git a/core/bot/commands.php b/core/bot/commands.php index ff25936d..3d98a3aa 100644 --- a/core/bot/commands.php +++ b/core/bot/commands.php @@ -4,54 +4,35 @@ // Check message text for a leading slash. if (isset($update['message']['text']) && substr($update['message']['text'], 0, 1) == '/') { - // Get command name. - if($config->BOT_NAME) { - $com = strtolower(str_replace('/', '', str_replace($config->BOT_NAME, '', explode(' ', $update['message']['text'])[0]))); - $altcom = strtolower(str_replace('/' . basename(ROOT_PATH), '', str_replace($config->BOT_NAME, '', explode(' ', $update['message']['text'])[0]))); - } else { - info_log('BOT_NAME is missing! Please define it!', '!'); - $com = 'start'; - $altcom = 'start'; - } + // Get command name. + if($config->BOT_NAME) { + $com = strtolower(str_replace('/', '', str_replace($config->BOT_NAME, '', explode(' ', $update['message']['text'])[0]))); + } else { + info_log('BOT_NAME is missing! Please define it!', '!'); + $com = 'start'; + } - if(isset($update['message']['chat']['id']) && new_user($update['message']['chat']['id']) && $com != 'start' && $com != 'tutorial') { - send_message($update['message']['chat']['id'], getTranslation("tutorial_command_failed")); - $dbh = null; - exit(); - } + if(isset($update['message']['chat']['id']) && new_user($update['message']['chat']['id']) && $com != 'start' && $com != 'tutorial') { + send_message($update['message']['chat']['id'], getTranslation("tutorial_command_failed")); + exit(); + } - // Set command paths. - $command = ROOT_PATH . '/commands/' . basename($com) . '.php'; - $altcommand = ROOT_PATH . '/commands/' . basename($altcom) . '.php'; - $core_command = CORE_COMMANDS_PATH . '/' . basename($com) . '.php'; - $core_altcommand = CORE_COMMANDS_PATH . '/' . basename($altcom) . '.php'; - $startcommand = ROOT_PATH . '/commands/start.php'; + // Set command paths. + $command = ROOT_PATH . '/commands/' . basename($com) . '.php'; + $startcommand = ROOT_PATH . '/commands/start.php'; - // Write to log. - debug_log(CORE_PATH,'Core path'); - debug_log('Command-File: ' . $command); - debug_log('Alternative Command-File: ' . $altcommand); - debug_log('Core Command-File: ' . $core_command); - debug_log('Core Alternative Command-File: ' . $core_altcommand); - debug_log('Start Command-File: ' . $startcommand); + // Write to log. + debug_log('Command-File: ' . $command); + debug_log('Start Command-File: ' . $startcommand); - // Check if command file exits. - if (is_file($command)) { - // Dynamically include command file and exit. - include_once($command); - } else if (is_file($altcommand)) { - // Dynamically include command file and exit. - include_once($altcommand); - } else if (is_file($core_command)) { - // Dynamically include command file and exit. - include_once($core_command); - } else if (is_file($core_altcommand)) { - // Dynamically include command file and exit. - include_once($core_altcommand); - } else if ($com == basename(ROOT_PATH)) { - // Include start file and exit. - include_once($startcommand); - } else { - send_message($update['message']['chat']['id'], '' . getTranslation('not_supported') . ''); - } + // Check if command file exits. + if (is_file($command)) { + // Dynamically include command file and exit. + include_once($command); + } else if ($com == basename(ROOT_PATH)) { + // Include start file and exit. + include_once($startcommand); + } else { + send_message($update['message']['chat']['id'], '' . getTranslation('not_supported') . ''); + } } diff --git a/core/bot/config.php b/core/bot/config.php index 348c425d..4d268243 100644 --- a/core/bot/config.php +++ b/core/bot/config.php @@ -12,7 +12,7 @@ function get_config_array($file) { error_log('Unable to read config file, check permissions: ' . $file); die('Config file not readable, cannot continue: ' . $file); } - + $config_array = json_decode($file_contents, true); if(json_last_error() !== JSON_ERROR_NONE) { @@ -92,5 +92,3 @@ function build_config() { // Object, access a config option with e.g. $config->VERSION $config = build_config(); - -?> diff --git a/core/bot/constants.php b/core/bot/constants.php deleted file mode 100644 index 73813dd7..00000000 --- a/core/bot/constants.php +++ /dev/null @@ -1,31 +0,0 @@ - Language files. -$languages = array( - 'nl' => 'NL', - 'de' => 'DE', - 'en-US' => 'EN', - 'en' => 'EN', - 'it' => 'IT', - 'pt' => 'PT-BR', - 'ru' => 'RU', - 'fr' => 'FR', - 'fi' => 'FI', - 'es' => 'ES', -); - -// Icons. -defined('EMOJI_WARN') or define('EMOJI_WARN', iconv('UCS-4LE', 'UTF-8', pack('V', 0x26A0))); -defined('EMOJI_DISK') or define('EMOJI_DISK', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F4BE))); -defined('EMOJI_NEW') or define('EMOJI_NEW', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F195))); -defined('EMOJI_CLIPPY') or define('EMOJI_CLIPPY', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F4CE))); - diff --git a/core/bot/db.php b/core/bot/db.php index c1b0db46..bf9a1330 100644 --- a/core/bot/db.php +++ b/core/bot/db.php @@ -1,40 +1,38 @@ DB_HOST && $config->DB_PORT && $config->DB_NAME && $config->DB_USER && $config->DB_PASSWORD) { - // Establish PDO connection - $dbh = new PDO( - "mysql:host=" . $config->DB_HOST - . ";port=" . $config->DB_PORT - . ";dbname=" . $config->DB_NAME - . ";charset=utf8mb4", - $config->DB_USER, - $config->DB_PASSWORD, - array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) - ); - $dbh->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING); - $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); - // Route SQL errors to Exceptions so we can handle them centrally - $dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - - // Verify connection works and the DB schema has been loaded - $query = $dbh->prepare('SHOW TABLES LIKE "attendance";'); - $query->execute(); - $table_exists = $query->fetch(PDO::FETCH_NUM); - if(empty($table_exists)){ - info_log('Database has not been initialized yet, running it now!'); - $success = run_sql_file(ROOT_PATH . '/sql/pokemon-raid-bot.sql'); - if(!$success){ - $error = "DB initialization failed, see error_log for more details."; - info_log($error); - die($error); - } else { - info_log('DB init success!'); - } - } -} else { +if(!$config->DB_HOST || !$config->DB_PORT || !$config->DB_NAME || !$config->DB_USER || !$config->DB_PASSWORD) { $error = "Failed to connect to Database! Make sure DB_HOST, DB_NAME, DB_USER and DB_PASSWORD are defined and that you've provided a config/config.json in the first place!"; error_log($error); http_response_code(409); die($error); } +// Establish PDO connection +$dbh = new PDO( + "mysql:host=" . $config->DB_HOST + . ";port=" . $config->DB_PORT + . ";dbname=" . $config->DB_NAME + . ";charset=utf8mb4", + $config->DB_USER, + $config->DB_PASSWORD, + array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) +); +$dbh->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING); +$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); +// Route SQL errors to Exceptions so we can handle them centrally +$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + +// Verify connection works and the DB schema has been loaded +$query = $dbh->prepare('SHOW TABLES LIKE "attendance";'); +$query->execute(); +$table_exists = $query->fetch(PDO::FETCH_NUM); +if(empty($table_exists)){ + info_log('Database has not been initialized yet, running it now!'); + $success = run_sql_file(ROOT_PATH . '/sql/pokemon-raid-bot.sql'); + if(!$success){ + $error = "DB initialization failed, see error_log for more details."; + info_log($error); + die($error); + } + info_log('DB init success!'); +} diff --git a/core/bot/ddos.php b/core/bot/ddos.php index a39e6a21..bac5c796 100644 --- a/core/bot/ddos.php +++ b/core/bot/ddos.php @@ -2,119 +2,97 @@ // Write to log debug_log('DDOS Check'); if ($metrics){ - $ddos_old_updates_total = $metrics->registerCounter($namespace, 'ddos_old_updates_total', 'Total old updates received'); - $ddos_last_update = $metrics->registerGauge($namespace, 'ddos_last_update', 'Last known update_id'); - $ddos_state = $metrics->registerGauge($namespace, 'ddos_state', 'current DDoS values', ['user_id']); - $ddos_fails_total = $metrics->registerCounter($namespace, 'ddos_fails_total', 'Total DDoS failures', ['user_id']); + $ddos_old_updates_total = $metrics->registerCounter($namespace, 'ddos_old_updates_total', 'Total old updates received'); + $ddos_last_update = $metrics->registerGauge($namespace, 'ddos_last_update', 'Last known update_id'); + $ddos_state = $metrics->registerGauge($namespace, 'ddos_state', 'current DDoS values', ['user_id']); + $ddos_fails_total = $metrics->registerCounter($namespace, 'ddos_fails_total', 'Total DDoS failures', ['user_id']); } -// Update_ID file. -$id_file = DDOS_PATH . '/update_id'; +verifyUpdate($update, $data); +ddosCheck($update, $data); -// Skip DDOS check for specific stuff, e.g. cleanup and overview refresh. -$skip_ddos_check = 0; +function verifyUpdate($update, $data) { + global $metrics; + if ($update['type'] == 'callback_query' + && in_array($data['callbackAction'], ['overview_refresh', 'refresh_polls', 'getdb', 'update_bosses']) + or ($data['callbackAction'] == 'post_raid' && $update['skip_ddos'] == true) + or isset($update['cleanup'])) + { + debug_log('Skipping DDOS check...','!'); + return; + } + $id_file = DDOS_PATH . '/update_id'; -// Update the update_id and reject old updates -if (file_exists($id_file) && filesize($id_file) > 0) { - // Get update_ids from Telegram and locally stored in the file - $update_id = isset($update['update_id']) ? $update['update_id'] : 0; - $last_update_id = is_file($id_file) ? file_get_contents($id_file) : 0; - if ($metrics){ - $ddos_last_update->set($last_update_id); - } - if (isset($update['callback_query'])) { - $action = $data['action']; - if ($action == 'overview_refresh') { - $skip_ddos_check = 1; - debug_log('Skipping DDOS check for overview refresh...','!'); - }else if ($action == 'refresh_polls') { - $skip_ddos_check = 1; - debug_log('Skipping DDOS check for poll refresh...','!'); - }else if ($action == 'post_raid' && $update['skip_ddos'] == true) { - $skip_ddos_check = 1; - debug_log('Skipping DDOS check for posting raid directly...','!'); - }else if ($action == 'getdb') { - $skip_ddos_check = 1; - debug_log('Skipping DDOS check for database update...','!'); - }else if ($action == 'update_bosses') { - $skip_ddos_check = 1; - debug_log('Skipping DDOS check for boss data update...','!'); - } - } else if(isset($update['cleanup'])) { - $skip_ddos_check = 1; - debug_log('Skipping DDOS check for cleanup...','!'); - } + // Update the update_id and reject old updates + // Get update_ids from Telegram and locally stored in the file + $update_id = isset($update['update_id']) ? $update['update_id'] : 0; + $last_update_id = is_file($id_file) ? file_get_contents($id_file) : 0; + if ($metrics){ + $GLOBALS['ddos_last_update']->set($last_update_id); + } - // End script if update_id is older than stored update_id - if ($update_id < $last_update_id && $skip_ddos_check == 0) { - info_log("FATAL ERROR! Received old update_id: {$update_id} vs {$last_update_id}",'!'); - if ($metrics){ - $ddos_old_updates_total->incBy(1); - } - exit(); + // End script if update_id is older than stored update_id + if ($update_id < $last_update_id) { + info_log("FATAL ERROR! Received old update_id: {$update_id} vs {$last_update_id}",'!'); + if ($metrics){ + $GLOBALS['ddos_old_updates_total']->incBy(1); } -} else { - // Create file with initial update_id - $update_id = 1; + exit(); + } + // Write update_id to file + file_put_contents($id_file, $update_id); } -// Write update_id to file -if($skip_ddos_check == 0) { - file_put_contents($id_file, $update_id); -} - -// Init DDOS count -$ddos_count = 0; +function ddosCheck($update, $data) { + global $botUser, $metrics, $config; + // DDOS protection + // Init DDOS count + $ddos_count = 0; + // Get callback query data + if (!isset($update['callback_query']) or !$update['callback_query']['data']) return; + // Split callback data and assign to data array. + $splitAction = explode('_', $data['callbackAction']); + // Check the action + if ($splitAction[0] != 'vote') return; -// DDOS protection -if (isset($update['callback_query'])) { - // Get callback query data - if ($update['callback_query']['data']) { - // Split callback data and assign to data array. - $splitAction = explode('_', $data['action']); - // Check the action - if ($splitAction[0] == 'vote') { - // Get the user_id and set the related ddos file - $ddos_id = $update['callback_query']['from']['id']; - $ddos_file = (DDOS_PATH . '/' . $ddos_id); - // Check if ddos file exists and is not empty - if (file_exists($ddos_file) && filesize($ddos_file) > 0) { - // Get current time and last modification time of file - $now = date("YmdHi"); - $lastchange = date("YmdHi", filemtime($ddos_file)); - // Get DDOS count or rest DDOS count if new minute - if ($now == $lastchange) { - // Get DDOS count from file - $ddos_count = file_get_contents($ddos_file); - $ddos_count = $ddos_count + 1; - if ($metrics){ - $ddos_state->set($ddos_count, [$ddos_id]); - } - // Reset DDOS count to 1 - } else { - $ddos_count = 1; - if ($metrics){ - $ddos_state->set(1, [$ddos_id]); - } - } - // Exit if DDOS of user_id count is exceeded. - if ($ddos_count > $config->DDOS_MAXIMUM) { - if ($metrics){ - $ddos_fails_total->inc([$ddos_id]); - } - exit(); - // Update DDOS count in file - } else { - file_put_contents($ddos_file, $ddos_count); - } - // Create file with initial DDOS count - } else { - $ddos_count = 1; - file_put_contents($ddos_file, $ddos_count); - if ($metrics){ - $ddos_state->set($ddos_count, [$ddos_id]); - } - } - } + // Get the user_id and set the related ddos file + $ddos_id = $update['callback_query']['from']['id']; + $ddos_file = (DDOS_PATH . '/' . $ddos_id); + // Check if ddos file exists and is not empty + if (!file_exists($ddos_file) || filesize($ddos_file) == 0) { + // Create file with initial DDOS count + $ddos_count = 1; + file_put_contents($ddos_file, $ddos_count); + if ($metrics){ + $GLOBALS['ddos_state']->set($ddos_count, [$ddos_id]); + } + return; + } + // Get current time and last modification time of file + $now = date("YmdHi"); + $lastchange = date("YmdHi", filemtime($ddos_file)); + // Get DDOS count or rest DDOS count if new minute + if ($now == $lastchange) { + // Get DDOS count from file + $ddos_count = file_get_contents($ddos_file); + $ddos_count = $ddos_count + 1; + if ($metrics){ + $GLOBALS['ddos_state']->set($ddos_count, [$ddos_id]); + } + // Reset DDOS count to 1 + } else { + $ddos_count = 1; + if ($metrics){ + $GLOBALS['ddos_state']->set(1, [$ddos_id]); + } + } + // Exit if DDOS of user_id count is exceeded. + if ($ddos_count > $config->DDOS_MAXIMUM) { + if ($metrics){ + $GLOBALS['ddos_fails_total']->inc([$ddos_id]); } + exit(); + } + file_put_contents($ddos_file, $ddos_count); + $botUser->ddosCount = $ddos_count; } diff --git a/core/bot/error_handlers.php b/core/bot/error_handlers.php index 63b0bce1..f6942fdb 100644 --- a/core/bot/error_handlers.php +++ b/core/bot/error_handlers.php @@ -32,7 +32,7 @@ function error_handler($severity, $message, $filename, $lineno) { $logger = 'error_log'; } $logger('Crash incoming, have a detailed backtrace:'); - $logger(debug_backtrace()); + $logger(print_r(debug_backtrace(), true)); throw new ErrorException($message, 0, $severity, $filename, $lineno); } diff --git a/core/bot/importal.php b/core/bot/importal.php index 456c4e63..f8a2436b 100644 --- a/core/bot/importal.php +++ b/core/bot/importal.php @@ -1,102 +1,101 @@ ' . getTranslation('invalid_input') . ''; - $msg .= CR . CR . getTranslation('not_supported') . SP . getTranslation('or') . SP . getTranslation('internal_error'); - send_message($update['message']['from']['id'], $msg); - exit(); - } - - // Ingressportalbot - if($parse_bot == 'Ingressportalbot') { - // Set portal bot name. - $botname = '@Ingressportalbot'; - - // Get portal name. - $portal = trim(str_replace($icon . 'Portal:', '', $msg_to_rows[0])); - - // Get portal address. - $address = trim(explode(':', $msg_to_rows[1], 2)[1]); - - // Split address? - debug_log($address, 'Address:'); - if(substr_count($address, ',') == 7) { - // Split address into 6 pieces which are separated by comma: - // Street Number, Street, Locality, Sublocality, City, State, ZIP Code, Country - $pieces = explode(',', $address); - $address = trim($pieces[1]) . SP . trim($pieces[0]) . ', ' . trim($pieces[6]) . SP . trim($pieces[4]); - } else if(substr_count($address, ',') == 8) { - // Split address into 7 pieces which are separated by comma: - // Place, Street Number, Street, Locality, Sublocality, City, State, ZIP Code, Country - $pieces = explode(',', $address); - $address = trim($pieces[2]) . SP . trim($pieces[1]) . ', ' . trim($pieces[7]) . SP . trim($pieces[5]); - } - - // Portal id - $portal_id = trim(substr($msg_to_rows[(count($msg_to_rows)-1)], 6)); - - // Portal image - $portal_image = $update['message']['entities']['0']['url']; - - // PortalMapBot - } else if($parse_bot == 'PortalMapBot') { - // Set portal bot name. - $botname = '@PortalMapBot'; - - // Get portal name. - $portal = trim(str_replace('(Intel)','', str_replace('(Scanner)','',$msg_to_rows[0]))); - - // Check for strange characters at the beginn of the portal name: â<81>£ - // â = 0x00E2 - // <81> = 0x81 - // £ = 0x00A3 - if(strpos($portal, chr(0x00E2) . chr(0x81) . chr(0x00A3)) === 0) { - // Remove strange characters from portal name. - $portal = substr($portal, 3); - debug_log('Strange characters â<81>£ detected and removed from portal name!'); - } - - // Get portal address. - $address = trim($msg_to_rows[4]); - - // Remove country from address, e.g. ", Netherlands" - $address = explode(',',$address,-1); - $address = trim(implode(',',$address)); - - // Portal id - $portal_id = trim($msg_to_rows[(count($msg_to_rows)-1)]); - - // Portal image - $portal_image = $update['message']['entities']['0']['url']; - - } - - // Empty address? Try lookup. - if(empty($address)) { - // Get address. - $addr = get_address($lat, $lon); - $address = format_address($addr); - } - - // Write to log. - debug_log('Detected message from ' . $botname); - debug_log($portal, 'Portal:'); - debug_log($coords, 'Coordinates:'); - debug_log($lat, 'Latitude:'); - debug_log($lon, 'Longitude:'); - debug_log($address, 'Address:'); - debug_log($portal_id, 'Portal id:'); - -?> + +$supported_bots = ['Ingressportalbot', 'PortalMapBot']; +if(!isset($update['message']['via_bot']) || !in_array($update['message']['via_bot']['username'], $supported_bots)) { + // Invalid input or unknown bot - send message and end. + $msg = '' . getTranslation('invalid_input') . ''; + $msg .= CR . CR . getTranslation('not_supported') . SP . getTranslation('or') . SP . getTranslation('internal_error'); + send_message($update['message']['from']['id'], $msg); + exit(); +} + +// Ingressportalbot icon +$icon = iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F4DC)); +$coords = explode('&pll=',$update['message']['entities']['1']['url'])[1]; +$latlon = explode(',', $coords); +$lat = $latlon[0]; +$lon = $latlon[1]; + +$msg_to_rows = explode(PHP_EOL, $update['message']['text']); + +$parse_bot = $update['message']['via_bot']['username']; + +// Ingressportalbot +if($parse_bot == 'Ingressportalbot') { + // Set portal bot name. + $botname = '@Ingressportalbot'; + + // Get portal name. + $portal = trim(str_replace($icon . 'Portal:', '', $msg_to_rows[0])); + + // Get portal address. + $address = trim(explode(':', $msg_to_rows[1], 2)[1]); + + // Split address? + debug_log($address, 'Address:'); + if(substr_count($address, ',') == 7) { + // Split address into 6 pieces which are separated by comma: + // Street Number, Street, Locality, Sublocality, City, State, ZIP Code, Country + $pieces = explode(',', $address); + $address = trim($pieces[1]) . SP . trim($pieces[0]) . ', ' . trim($pieces[6]) . SP . trim($pieces[4]); + } else if(substr_count($address, ',') == 8) { + // Split address into 7 pieces which are separated by comma: + // Place, Street Number, Street, Locality, Sublocality, City, State, ZIP Code, Country + $pieces = explode(',', $address); + $address = trim($pieces[2]) . SP . trim($pieces[1]) . ', ' . trim($pieces[7]) . SP . trim($pieces[5]); + } + + // Portal id + $portal_id = trim(substr($msg_to_rows[(count($msg_to_rows)-1)], 6)); + + // Portal image + $portal_image = $update['message']['entities']['0']['url']; + +// PortalMapBot +} else if($parse_bot == 'PortalMapBot') { + // Set portal bot name. + $botname = '@PortalMapBot'; + + // Get portal name. + $portal = trim(str_replace('(Intel)','', str_replace('(Scanner)','',$msg_to_rows[0]))); + + // Check for strange characters at the beginn of the portal name: â<81>£ + // â = 0x00E2 + // <81> = 0x81 + // £ = 0x00A3 + if(strpos($portal, chr(0x00E2) . chr(0x81) . chr(0x00A3)) === 0) { + // Remove strange characters from portal name. + $portal = substr($portal, 3); + debug_log('Strange characters â<81>£ detected and removed from portal name!'); + } + + // Get portal address. + $address = trim($msg_to_rows[4]); + + // Remove country from address, e.g. ", Netherlands" + $address = explode(',',$address,-1); + $address = trim(implode(',',$address)); + + // Portal id + $portal_id = trim($msg_to_rows[(count($msg_to_rows)-1)]); + + // Portal image + $portal_image = $update['message']['entities']['0']['url']; + +} + +// Empty address? Try lookup. +if(empty($address)) { + // Get address. + $addr = get_address($lat, $lon); + $address = format_address($addr); +} + +// Write to log. +debug_log('Detected message from ' . $botname); +debug_log($portal, 'Portal:'); +debug_log($coords, 'Coordinates:'); +debug_log($lat, 'Latitude:'); +debug_log($lon, 'Longitude:'); +debug_log($address, 'Address:'); +debug_log($portal_id, 'Portal id:'); diff --git a/core/bot/logic.php b/core/bot/logic.php deleted file mode 100644 index f2c33105..00000000 --- a/core/bot/logic.php +++ /dev/null @@ -1,13 +0,0 @@ - diff --git a/core/bot/logic/bearer_token.php b/core/bot/logic/bearer_token.php deleted file mode 100644 index e68ae330..00000000 --- a/core/bot/logic/bearer_token.php +++ /dev/null @@ -1,33 +0,0 @@ - $version), CONFIG_PATH . '/config.json'); -} - -/** - * Get current code revision from git state, or 'manual' if no git state exists. - * @return string - */ -function get_rev() -{ - if (file_exists(ROOT_PATH . '/.git/HEAD')){ - $ref = trim(file_get_contents(ROOT_PATH . '/.git/HEAD')); - if (ctype_xdigit($ref)){ - // Is already a hex string and thus valid rev - // Return first 6 digits of the hash - return substr($ref, 0, 6); - } - // strip 'ref: ' to get file path - $ref_file = ROOT_PATH . '/.git/' . substr($ref, 5); - if (file_exists($ref_file)){ - // Return first 6 digits of the hash, this matches our naming of docker image tags - return substr(file_get_contents($ref_file), 0, 6); - } else { - error_log("Git ref found but we cannot resolve it to a revision ({$ref_file}). Was the .git folder mangled?"); - return 'manual'; - } - } else { - debug_log('No .git/HEAD present, marking revision as manual'); - return 'manual'; - } -} - -/** - * Bot upgrade check - * @param $current - * @param $latest - * @return bool: if a manual upgrade is needed - */ -function bot_upgrade_check($current, $latest) -{ - global $config, $metrics, $namespace; - $orig = $current; // we may have to do multiple upgrades - if ($metrics){ - // This is the one place where we have full knowledge of version information & upgrades - debug_log('init upgrade metrics'); - $version_info = $metrics->registerGauge($namespace, 'version_info', 'Schema and revision information', ['current_schema', 'required_schema', 'rev', 'upgraded_timestamp', 'upgraded_from']); - } - - - $upgrade_verdict = null; - $manual_upgrade_verdict = null; - // Same version? - if($current == $latest) { - $upgrade_verdict = false; - $manual_upgrade_verdict = false; - } else { - $upgrade_verdict = true; - if ($metrics && IS_INIT){ - // record initial version even if we don't do upgrades. - $version_info->set(1, [$current, $latest, get_rev(), null, null]); - } - // Check if upgrade files exist. - $upgrade_files = array(); - $upgrade_files = str_replace(UPGRADE_PATH . '/','', glob(UPGRADE_PATH . '/*.sql')); - if(is_array($upgrade_files) && count($upgrade_files) > 0) { - // Check each sql filename. - foreach ($upgrade_files as $ufile) - { - $target = str_replace('.sql', '', $ufile); - // Skip every older sql file from array. - if($target <= $current) { - continue; - } else { - if ($config->UPGRADE_SQL_AUTO){ - info_log('PERFORMING AUTO SQL UPGRADE: ' . UPGRADE_PATH . '/' . $ufile, '!'); - require_once('sql_utils.php'); - if (run_sql_file(UPGRADE_PATH . '/' . $ufile)) { - $manual_upgrade_verdict = false; - upgrade_config_version($target); - if ($metrics){ - $version_info->set(1, [$target, $latest, get_rev(), time(), $current]); - } - $current = $target; - } else { - $manual_upgrade_verdict = true; - $error = 'AUTO UPGRADE FAILED: ' . UPGRADE_PATH . '/' . $ufile; - throw new Exception($error); - } - } else { - $manual_upgrade_verdict = true; - debug_log("There's a schema upgrade to {$target} we could have run, but auto-upgrades have been disabled!"); - } - } - } - } else { - // No upgrade files found! Since the version now would only go up with upgrade files, something is off. - // It could be the user has bumped the VERSION file manually, or omitted upgrade files. - $error = 'NO SQL UPGRADE FILES FOUND FOR LATEST SCHEMA, THIS SHOULD NOT HAPPEN'; - throw new Exception($error); - } - } - // If previous sql upgrades had to be done and were successful, update also pokemon table - if($upgrade_verdict === true && $manual_upgrade_verdict === false) { - require_once(ROOT_PATH . '/mods/getdb.php'); - } - - // Signal whether manual action is required or not. - if ($manual_upgrade_verdict === true){ - $error = "The bot has pending schema upgrades ({$current} -> {$latest}) but you've disabled automatic upgrades. Nothing will work until you go do the upgrade(s) manually. You'll find them in the dir sql/upgrade/"; - throw new Exception($error); - } -} diff --git a/core/bot/logic/date_util.php b/core/bot/logic/date_util.php deleted file mode 100644 index 137bbacc..00000000 --- a/core/bot/logic/date_util.php +++ /dev/null @@ -1,105 +0,0 @@ -format('Y-m-d'); -} - -/** - * Get current utc datetime. - * @param $format - * @return string - */ -function utcnow($format = 'Y-m-d H:i:s') -{ - // Create a object with UTC timezone - $datetime = new DateTime('now', new DateTimeZone('UTC')); - - return $datetime->format($format); -} - - -/** - * Format utc time from datetime value. - * @param $datetime_value - * @param $format - * @return string - */ -function utctime($datetime_value, $format = 'H:i') -{ - // Create a object with UTC timezone - $datetime = new DateTime($datetime_value, new DateTimeZone('UTC')); - - return $datetime->format($format); -} - -/** - * Get date from datetime value. - * @param $datetime_value - * @param $tz - * @return string - */ -function dt2date($datetime_value, $tz = NULL) -{ - global $config; - if($tz == NULL){ - $tz = $config->TIMEZONE; - } - // Create a object with UTC timezone - $datetime = new DateTime($datetime_value, new DateTimeZone('UTC')); - - // Change the timezone of the object without changing it's time - $datetime->setTimezone(new DateTimeZone($tz)); - - return $datetime->format('Y-m-d'); -} - -/** - * Get time from datetime value. - * @param $datetime_value - * @param $format - * @param $tz - * @return string - */ -function dt2time($datetime_value, $format = 'H:i', $tz = NULL) -{ - global $config; - if($tz == NULL){ - $tz = $config->TIMEZONE; - } - // Create a object with UTC timezone - $datetime = new DateTime($datetime_value, new DateTimeZone('UTC')); - - // Change the timezone of the object without changing it's time - $datetime->setTimezone(new DateTimeZone($tz)); - - return $datetime->format($format); -} - -function tz_diff($src = 'UTC', $dst = NULL) { - global $config; - if($dst == NULL){ - $dst = $config->TIMEZONE; - } - $dateTimeZoneSrc = new DateTimeZone($src); - $dateTimeZoneDst = new DateTimeZone($dst); - $dateTimeSrc = new datetime('now',$dateTimeZoneSrc); - $diff = $dateTimeZoneDst->getOffset($dateTimeSrc); - - $hours = str_pad(floor($diff/60/60),2,'0',STR_PAD_LEFT); - $minutes = str_pad(floor(($diff-$hours*60*60)/60),2,'0',STR_PAD_LEFT); - if($diff < 0) { - $res = '-'.$hours.':'.$minutes; - }else { - $res = '+'.$hours.':'.$minutes; - } - return $res; -} -?> diff --git a/core/bot/logic/download_Portal_Image.php b/core/bot/logic/download_Portal_Image.php deleted file mode 100644 index 61aef5cd..00000000 --- a/core/bot/logic/download_Portal_Image.php +++ /dev/null @@ -1,42 +0,0 @@ - diff --git a/core/bot/logic/geo_api.php b/core/bot/logic/geo_api.php deleted file mode 100644 index 98d94fa3..00000000 --- a/core/bot/logic/geo_api.php +++ /dev/null @@ -1,247 +0,0 @@ -MAPS_LOOKUP && !empty($config->MAPS_API_KEY)) { - // Init defaults. - $location = []; - $location['street'] = ''; - $location['street_number'] = ''; - $location['postal_code'] = ''; - $location['district'] = ''; - - // Set maps geocode url. - $language = strtolower($config->LANGUAGE_PUBLIC); - $MapsApiKey = $config->MAPS_API_KEY; - $url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' . $lat . ',' . $lon . '&language=' . $language; - $url .= '&key=' . $MapsApiKey; - - // Curl request. - $curl = curl_init($url); - curl_setopt($curl, CURLOPT_HEADER, false); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - - // Proxy server? - // Use Proxyserver for curl if configured - if ($config->CURL_USEPROXY) { - curl_setopt($curl, CURLOPT_PROXY, $config->CURL_PROXYSERVER); - } - - // Curl response. - $json_response = curl_exec($curl); - - // Write request and response to log. - debug_log($url, 'G>'); - debug_log($json_response, 'status) && $data->status == 'OK' && !empty($data->results)) { - - // Init vars. - $locality = ''; - $sublocalityLv2 = ''; - $sublocality = ''; - - // Iterate each result. - foreach ($data->results as $result) { - - // Check for address components. - if (!empty($result->address_components)) { - // Iterate each address component. - foreach ($result->address_components as $address_component) { - - // Street found. - if (in_array('route', $address_component->types) && !empty($address_component->long_name)) { - // Set street by first found. - $location['street'] = empty($location['street']) ? $address_component->long_name : $location['street']; - } - - // Street number found. - if (in_array('street_number', $address_component->types) && !empty($address_component->long_name)) { - // Set street by first found. - $location['street_number'] = empty($location['street_number']) ? $address_component->long_name : $location['street_number']; - } - - // Postal code found. - if (in_array('postal_code', $address_component->types) && !empty($address_component->long_name)) { - // Set street by first found. - $location['postal_code'] = empty($location['postal_code']) ? $address_component->long_name : $location['postal_code']; - } - - // Sublocality level2 found. - if (in_array('sublocality_level_2', $address_component->types) && !empty($address_component->long_name)) { - // Set sublocality level 2 by first found. - $sublocalityLv2 = empty($sublocalityLv2) ? $address_component->long_name : $sublocalityLv2; - } - - // Sublocality found. - if (in_array('sublocality', $address_component->types) && !empty($address_component->long_name)) { - // Set sublocality by first found. - $sublocality = empty($sublocality) ? $address_component->long_name : $sublocality; - } - - // Locality found. - if (in_array('locality', $address_component->types) && !empty($address_component->long_name)) { - // Set sublocality by first found. - $locality = empty($sublocality) ? $address_component->long_name : $sublocality; - } - } - } - break; - } - - // Set district by priority. - if (!empty($sublocalityLv2)) { - $location['district'] = $sublocalityLv2; - - } else if ($sublocality) { - $location['district'] = $sublocality; - - } else if ($locality) { - $location['district'] = $locality; - } - - // Rename street responses. - switch ($location['street']) { - case 'Unnamed Road': - $location['street'] = getPublicTranslation('directions'); - break; - } - - // Return the location array. - return $location; - - // No valid data received. - } else { - return false; - } - - // OpenStreetMap lookup? - } elseif($config->OSM_LOOKUP) { - // Init defaults. - $location = []; - $location['street'] = ''; - $location['street_number'] = ''; - $location['postal_code'] = ''; - $location['district'] = ''; - - // Set maps geocode url. - $language = strtolower($config->LANGUAGE_PUBLIC); - $url = $config->OSM_URL . '/reverse?lat=' . $lat . '&lon=' . $lon . '&format=json&accept-language=' . $language; - - // Curl request. - $curl = curl_init($url); - curl_setopt($curl, CURLOPT_HTTPHEADER, array("User-Agent: PokemonRaidBot")); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - - // Proxy server? - // Use Proxyserver for curl if configured - if ($config->CURL_USEPROXY) { - curl_setopt($curl, CURLOPT_PROXY, $config->CURL_PROXYSERVER); - } - - // Curl response. - $json_response = curl_exec($curl); - - // Write request and response to log. - debug_log($url, 'OSM>'); - debug_log($json_response, ' '', ]; public $userLanguage = ''; + public $ddosCount = 0; /** * Run privilege check for Telegram user and save them for later use. - * @param $update Update array from Telegram + * @param $update array Update array from Telegram */ public function privilegeCheck($update) { global $config; // Get Telegram user ID to check access from $update - either message, callback_query or inline_query - $update_type = ''; - $update_type = !empty($update['message']['from']['id']) ? 'message' : $update_type; - $update_type = (empty($update_type) && !empty($update['callback_query']['from']['id'])) ? 'callback_query' : $update_type; - $update_type = (empty($update_type) && !empty($update['inline_query']['from']['id'])) ? 'inline_query' : $update_type; - if(empty($update_type)) return; // If no update type was found, the call probably didn't come from Telegram and privileges don't need to be checked - $user_id = $update[$update_type]['from']['id']; + $user_id = $update[$update['type']]['from']['id']; // Write to log. - debug_log('Telegram message type: ' . $update_type); + debug_log('Telegram message type: ' . $update['type']); debug_log('Checking access for ID: ' . $user_id); // Public access? @@ -31,28 +27,27 @@ public function privilegeCheck($update) { debug_log('Bot access is not restricted! Allowing access for user: ' . CR . $user_id); $this->userPrivileges['grantedBy'] = 'NOT_RESTRICTED'; return; - }else { - // Admin? - $admins = explode(',', $config->BOT_ADMINS); - if(in_array($user_id,$admins)) { - debug_log('Positive result on access check for Bot Admins'); - debug_log('Bot Admins: ' . $config->BOT_ADMINS); - debug_log('user_id: ' . $user_id); - $this->userPrivileges['grantedBy'] = 'BOT_ADMINS'; - return; - } + } + // Admin? + $admins = explode(',', $config->BOT_ADMINS); + if(in_array($user_id,$admins)) { + debug_log('Positive result on access check for Bot Admins'); + debug_log('Bot Admins: ' . $config->BOT_ADMINS); + debug_log('user_id: ' . $user_id); + $this->userPrivileges['grantedBy'] = 'BOT_ADMINS'; + return; } // Map telegram roles to access file names $telegramRoles = [ - 'creator' => 'creator', - 'administrator' => 'admins', - 'member' => 'members', - 'restricted' => 'restricted', - 'kicked' => 'kicked', - ]; - - $accessFilesList = $tg_json = $chatIds = []; + 'creator' => 'creator', + 'administrator' => 'admins', + 'member' => 'members', + 'restricted' => 'restricted', + 'kicked' => 'kicked', + ]; + + $accessFilesList = $tg_json = []; foreach(glob(ACCESS_PATH . '/*') as $filePath) { $filename = str_replace(ACCESS_PATH . '/', '', $filePath); // Get chat object - remove comments from filename @@ -72,10 +67,9 @@ public function privilegeCheck($update) { // Group/channel? $role = $result[3]; $tg_chat = $result[4]; - $chatIds[] = $tg_chat; // Save the full filename (with possible comments) to an array for later use $accessFilesList[$role.$tg_chat] = $filename; - debug_log("Asking Telegram if user is a member of chat '$tg_chat'"); + debug_log('Asking Telegram if user is a member of chat \'' . $tg_chat . '\''); if(!isset($tg_json[$tg_chat])) $tg_json[$tg_chat] = get_chatmember($tg_chat, $user_id, true); // Get chat member object and check status } $accessChats = curl_json_multi_request($tg_json); @@ -124,17 +118,17 @@ public function privilegeCheck($update) { break; } // Deny access - debug_log($chat, 'Negative result on access check for chat:'); + debug_log($chatId, 'Negative result on access check for chat:'); debug_log('Continuing with next chat...'); } } /** * Check users privileges for a specific action. Exits by default if access is denied. - * @param $update Update array from Telegram - * @param $permission Permission to check - * @param $return_result Return the result of privilege check - * @param $new_user Has user completed tutorial or not + * @param $update array Update array from Telegram + * @param $permission string Permission to check + * @param $return_result bool Return the result of privilege check + * @param $new_user bool Has user completed tutorial or not * @return bool|string */ public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { @@ -148,18 +142,18 @@ public function accessCheck($update, $permission = 'access-bot', $return_result $response_msg = '' . getTranslation('bot_access_denied') . ''; // Edit message or send new message based on type of received call - if (isset($update['callback_query'])) { - $keys = []; - - // Telegram JSON array. - $tg_json = array(); - $tg_json[] = edit_message($update, $response_msg, $keys, false, true); - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('bot_access_denied'), true); - - curl_json_multi_request($tg_json); - } else { + if ($update['type'] != 'callback_query') { send_message($update['message']['from']['id'], $response_msg); + exit; } + $keys = []; + + // Telegram JSON array. + $tg_json = array(); + $tg_json[] = edit_message($update, $response_msg, $keys, false, true); + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('bot_access_denied'), true); + + curl_json_multi_request($tg_json); exit; } @@ -176,12 +170,11 @@ public function raidAccessCheck($update, $raidId, $permission, $return_result = $raid_access = false; // Build query. - $rs = my_query( - " - SELECT user_id - FROM raids - WHERE id = {$raidId} - " + $rs = my_query(' + SELECT user_id + FROM raids + WHERE id = ? + ', [$raidId] ); $raid = $rs->fetch(); @@ -191,52 +184,42 @@ public function raidAccessCheck($update, $raidId, $permission, $return_result = // Check "-all" permission debug_log('Checking permission:' . $permission . '-all'); $permission = $permission . '-all'; - $raid_access = $botUser->accessCheck($update, $permission, $return_result); - } else { - // Check "-own" permission - debug_log('Checking permission:' . $permission . '-own'); - $permission_own = $permission . '-own'; - $permission_all = $permission . '-all'; - $raid_access = $botUser->accessCheck($update, $permission_own, true); - - // Check "-all" permission if we get "access denied" - // Maybe necessary if user has only "-all" configured, but not "-own" - if(!$raid_access) { - debug_log('Permission check for ' . $permission_own . ' failed! Maybe the access is just granted via ' . $permission . '-all ?'); - debug_log('Checking permission:' . $permission_all); - $raid_access = $botUser->accessCheck($update, $permission_all, $return_result); - } else { - $raid_access = $botUser->accessCheck($update, $permission_own, $return_result); - } + return $botUser->accessCheck($update, $permission, $return_result); } - - // Return result - return $raid_access; + // Check "-own" permission + debug_log('Checking permission:' . $permission . '-own'); + $permission_own = $permission . '-own'; + $permission_all = $permission . '-all'; + $raid_access = $botUser->accessCheck($update, $permission_own, true); + + if($raid_access) { + return $botUser->accessCheck($update, $permission_own, $return_result); + } + // Check "-all" permission if we get "access denied" + // Maybe necessary if user has only "-all" configured, but not "-own" + debug_log('Permission check for ' . $permission_own . ' failed! Maybe the access is just granted via ' . $permission . '-all ?'); + debug_log('Checking permission:' . $permission_all); + return $botUser->accessCheck($update, $permission_all, $return_result); } /** * Update users info if allowed * @param $update - * @return bool|mysqli_result */ public function updateUser($update) { - global $ddos_count; - // Check DDOS count - if ($ddos_count < 2) { - // Update the user. - $userUpdate = $this->updateUserdb($update); + if ($this->ddosCount >= 2) return; + // Update the user. + $userUpdate = $this->updateUserdb($update); - // Write to log. - debug_log('Update user: ' . $userUpdate); - } + // Write to log. + debug_log('Update user: ' . $userUpdate); } /** * Define userlanguage * @param $update - * @return bool|mysqli_result */ public function defineUserLanguage($update) { global $config; @@ -244,57 +227,43 @@ public function defineUserLanguage($update) { debug_log('Language Check'); // Get language from user - otherwise use language from config. - if ($config->LANGUAGE_PRIVATE == '') { - // Message or callback? - if(isset($update['message']['from'])) { - $from = $update['message']['from']; - } else if(isset($update['callback_query']['from'])) { - $from = $update['callback_query']['from']; - } else if(isset($update['inline_query']['from'])) { - $from = $update['inline_query']['from']; - } - if(isset($from)) { - $q = my_query("SELECT lang FROM users WHERE user_id='".$from['id']."' LIMIT 1"); - $res = $q->fetch(); - $language_code = $res['lang']; - }else { - $language_code = ''; - } - - // Get and define userlanguage. - $languages = $GLOBALS['languages']; - - // Get languages from normal translation. - if(array_key_exists($language_code, $languages)) { - $userlanguage = $languages[$language_code]; - } else { - $userlanguage = DEFAULT_LANGUAGE; - } - - debug_log('User language: ' . $userlanguage); - $this->userLanguage = $userlanguage; - } else { + if ($config->LANGUAGE_PRIVATE != '') { // Set user language to language from config. $this->userLanguage = $config->LANGUAGE_PRIVATE; + return; + } + // Message or callback? + $from = $update[$update['type']]['from']; + + $language_code = ''; + if(isset($from)) { + $q = my_query('SELECT lang FROM users WHERE user_id = ? LIMIT 1', [$from['id']]); + $res = $q->fetch(); + $language_code = $res['lang']; + } + + // Get and define userlanguage. + $languages = $GLOBALS['languages']; + + // Get languages from normal translation. + $userlanguage = DEFAULT_LANGUAGE; + if(array_key_exists($language_code, $languages)) { + $userlanguage = $languages[$language_code]; } + + debug_log('User language: ' . $userlanguage); + $this->userLanguage = $userlanguage; } /** * Update users info into database. * @param $update - * @return bool|mysqli_result */ private function updateUserdb($update) { - global $dbh, $config; - - if (isset($update['message']['from'])) { - $msg = $update['message']['from']; - } else if (isset($update['callback_query']['from'])) { - $msg = $update['callback_query']['from']; - } else if (isset($update['inline_query']['from'])) { - $msg = $update['inline_query']['from']; - } + global $config; + + $msg = $update[$update['type']]['from']; if (empty($msg['id'])) { debug_log('No id', '!'); @@ -319,9 +288,10 @@ private function updateUserdb($update) $lang = (isset($msg['language_code']) && array_key_exists($msg['language_code'], $GLOBALS['languages'])) ? $msg['language_code'] : 'en'; + $alarm_setting = ($config->RAID_AUTOMATIC_ALARM ? 1 : 0); + // Create or update the user. - $stmt = $dbh->prepare( - ' + my_query(' INSERT INTO users SET user_id = :id, nick = :nick, @@ -333,17 +303,16 @@ private function updateUserdb($update) name = :name, lang = IF(lang_manual = 1, lang, :lang), auto_alarm = IF(:auto_alarm = 1, 1, auto_alarm) - ' + ', + [ + ':id' => $id, + ':nick' => $nick, + ':name' => $name, + ':lang' => $lang, + ':auto_alarm' => $alarm_setting, + ] ); - $alarm_setting = ($config->RAID_AUTOMATIC_ALARM ? 1 : 0); - $stmt->bindParam(':id', $id); - $stmt->bindParam(':nick', $nick); - $stmt->bindParam(':name', $name); - $stmt->bindParam(':lang', $lang); - $stmt->bindParam(':auto_alarm', $alarm_setting); - $stmt->execute(); return 'Updated user ' . $nick; } } -?> \ No newline at end of file diff --git a/core/bot/version.php b/core/bot/version.php index 9797e7a9..aa251da3 100644 --- a/core/bot/version.php +++ b/core/bot/version.php @@ -1,26 +1,22 @@ VERSION) or $config->VERSION = '1'; -$current = $config->VERSION; +require_once(ROOT_PATH . '/logic/bot_upgrade_check.php'); // Get version from VERSION file. $lfile = ROOT_PATH . '/VERSION'; -if(is_file($lfile) && filesize($lfile)) { - $latest = file($lfile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $latest = $latest[0]; -} else { +if(!is_file($lfile) || !filesize($lfile)) { $error = 'VERSION file missing, cannot continue without it since we would not know the required DB schema version.'; throw new Exception($error); } +$latest = file($lfile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); +$latest = $latest[0]; -// Current version not defined in config! -if($current == '1') { - $error = "Failed to determine your bot version! Have you removed it from config.json? or not defined POKEMONRAIDBOT_VERSION ? If this is a new installation, use the value {$latest}"; +// Check if version is defined in config. +if(!isset($config->VERSION) or empty($config->VERSION) or $config->VERSION == '1') { + $error = 'Failed to determine your bot version! Have you removed it from config.json? or not defined POKEMONRAIDBOT_VERSION ? If this is a new installation, use the value ' . $latest; throw new Exception($error); } +$current = $config->VERSION; // Check if we have the latest version and perform upgrade if needed & possible. bot_upgrade_check($current, $latest); diff --git a/core/commands/get.php b/core/commands/get.php deleted file mode 100644 index b16e3734..00000000 --- a/core/commands/get.php +++ /dev/null @@ -1,75 +0,0 @@ -accessCheck($update, 'config-get'); - -// Get all allowed configs. -$allowed = explode(',', $config->ALLOWED_TELEGRAM_CONFIG); -$msg = '' . getTranslation('config') . ':' . CR . CR; - -// Get config restrictions for boolean input -$allowed_bool = explode(',', $config->ALLOW_ONLY_TRUE_FALSE); - -// Get config restrictions for numeric input -$allowed_numbers = explode(',', $config->ALLOW_ONLY_NUMBERS); - -// Get config. -$cfile = CONFIG_PATH . '/config.json'; -if(is_file($cfile)) { - $str = file_get_contents($cfile); - $json = json_decode($str, true); -} - -// Get config aliases. -$afile = CONFIG_PATH . '/alias.json'; -if(is_file($afile)) { - $astr = file_get_contents($afile); - $ajson = json_decode($astr, true); -} - -// Write to log. -debug_log('User requested the allowed telegram configs'); -debug_log('Allowed telegram configs: ' . $config->ALLOWED_TELEGRAM_CONFIG); -debug_log('Allow only boolean input: ' . $config->ALLOW_ONLY_TRUE_FALSE); -debug_log('Allow only numeric input: ' . $config->ALLOW_ONLY_NUMBERS); - -// Any configs allowed? -if(!empty($config->ALLOWED_TELEGRAM_CONFIG)) { - foreach($json as $cfg_name => $cfg_value) { - // Only allowed configs - if(in_array($cfg_name, $allowed)) { - // Is alias set? - $alias = ''; - if(isset($ajson[$cfg_name])){ - $alias = $ajson[$cfg_name]; - } - // Config name / Alias + value - $msg .= (empty($alias) ? $cfg_name : $alias) . SP . (empty($cfg_value) ? '' . getTranslation('no_value') . '' : $cfg_value); - - // Only bool? - if(in_array($cfg_name, $allowed_bool)) { - $msg .= SP . '(' . getTranslation('help_only_bool') . ')' . CR; - - // Only numbers? - } else if(in_array($cfg_name, $allowed_numbers)) { - $msg .= SP . '(' . getTranslation('help_only_numbers') . ')' . CR; - - // Any type - } else { - $msg .= CR; - } - } - } -} else { - $msg .= getTranslation('not_supported'); -} - -send_message($update['message']['chat']['id'], $msg); - -?> diff --git a/core/commands/set.php b/core/commands/set.php deleted file mode 100644 index b58fc9a3..00000000 --- a/core/commands/set.php +++ /dev/null @@ -1,182 +0,0 @@ -accessCheck($update, 'config-set'); - -// Get config name and value. -$input = trim(substr($update['message']['text'], 4)); - -// Get delimiter count. -$count = substr_count($input, " "); - -// Get allowed telegram configs. -$allowed = explode(',', $config->ALLOWED_TELEGRAM_CONFIG); - -// Get config restrictions for boolean input -$allowed_bool = explode(',', $config->ALLOW_ONLY_TRUE_FALSE); - -// Get config restrictions for numeric input -$allowed_numbers = explode(',', $config->ALLOW_ONLY_NUMBERS); - -// Write to log. -debug_log('User submitted a telegram config change'); -debug_log('Allowed telegram configs: ' . $config->ALLOWED_TELEGRAM_CONFIG); -debug_log('Allow only boolean input: ' . $config->ALLOW_ONLY_TRUE_FALSE); -debug_log('Allow only numeric input: ' . $config->ALLOW_ONLY_NUMBERS); - -// 0 means we reset config option value to "" -if($count == 0) { - // Upper input. - $config_name = strtoupper($input); - //$config_value = '"" (' . getTranslation('no_value') . ' / ' . getTranslation('resetted') . ')'; - $config_value = ""; - debug_log('Reset for the config value ' . $config_name . ' was requested by the user'); - -// 1 means we set the config option to the given value -} else if($count >= 1) { - // Config name and value. - $cfg_name_value = explode(' ', $input, 2); - $config_name = strtoupper($cfg_name_value[0]); - $config_value = $cfg_name_value[1]; - debug_log('Change for the config option ' . $config_name . ' was requested by the user'); - -// Set config_name to avoid undefined variable for if clause below. -} else { - $config_name = 'not_supported'; -} - -// Config -$cfile = CONFIG_PATH . '/config.json'; -if(is_file($cfile)) { - $str = file_get_contents($cfile); - $json = json_decode($str, true); -} - -// Real config name or alias? -$alias = ''; -$afile = CONFIG_PATH . '/alias.json'; -if(is_file($afile)) { - debug_log('Checking alias for config option ' . $config_name); - $astr = file_get_contents($afile); - // We compare always uppercase, so change str to upper - $astr = strtoupper($astr); - $ajson = json_decode($astr, true); - $alias = array_search($config_name, $ajson); - // Check for alias - if ($alias !== false) { - debug_log('Config option ' . $config_name . ' is an alias for ' . $alias); - $help = $config_name; - $config_name = strtoupper($alias); - $alias = $help; - } else { - debug_log('No alias found. Seems ' . $config_name . ' is the config option name'); - } -} - -// Assume restrictions. -$restrict = 'yes'; - -// Init additional error info. -$msg_error_info = ''; - -// Make sure it's allowed to update the value via telegram. -if(in_array($config_name, $allowed)) { - // Only bool? - if(in_array($config_name, $allowed_bool)) { - if(strcasecmp($config_value, 'true') == 0 || strcasecmp($config_value, 'false') == 0) { - $config_value = strtolower($config_value); - $restrict = 'no'; - } else if($config_value == 0 || $config_value == 1) { - $restrict = 'no'; - } else { - debug_log('Boolean value expected. Got this value: ' . $config_value); - $msg_error_info .= getTranslation('help_bool_expected'); - } - - - // Only numbers? - } else if(in_array($config_name, $allowed_numbers)) { - if(is_numeric($config_value)) { - $restrict = 'no'; - } else { - debug_log('Number expected. Got this value: ' . $config_value); - $msg_error_info .= getTranslation('help_number_expected'); - } - - // No restriction on input type. - } else { - $restrict = 'no'; - } -} - -// Update config. -if(in_array($config_name, $allowed) && $restrict == 'no') { - // Prepare data, replace " with ' - $config_value = str_replace('"', "'", $config_value); - $old_value = $json[$config_name]; - $json[$config_name] = $config_value; - $json = json_encode($json, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT); - debug_log($config_name, 'CONFIG NAME:'); - debug_log($config_value, 'CONFIG VALUE:'); - - // Write to file. - if(!(is_array($json) && is_string(json_decode($json, true)) && (json_last_error() === JSON_ERROR_NONE))) { - file_put_contents(CONFIG_PATH . '/config.json', $json); - $msg = getTranslation('config_updated') . ':' . CR . CR; - $msg .= '' . (empty($alias) ? $config_name : $alias) . '' . CR; - $msg .= getTranslation('old_value') . SP . $old_value . CR; - $msg .= getTranslation('new_value') . SP . $config_value . CR; - debug_log('Changed the config value for ' . $config_name . ' from ' . $old_value . ' to ' . $config_value); - } else { - $msg_error_info = getTranslation('internal_error'); - $msg = '' . getTranslation('invalid_input') . '' . (!empty($msg_error_info) ? (CR . $msg_error_info) : '') . CR . CR; - } - -// Tell user how to set config and what is allowed to be set by config. -} else { - $msg = '' . getTranslation('invalid_input') . '' . (!empty($msg_error_info) ? (CR . $msg_error_info) : '') . CR . CR; - $msg .= '' . getTranslation('config') . ':' . CR; - // Any configs allowed? - if(!empty($config->ALLOWED_TELEGRAM_CONFIG)) { - $msg .= '/set [' . getTranslation("config_option") . '] [' . getTranslation('option_value') . ']' . CR; - foreach($json as $cfg_name => $cfg_value) { - // Only allowed configs - if(in_array($cfg_name, $allowed)) { - // Is alias set? - $alias = ''; - if(isset($ajson[$cfg_name])){ - $alias = $ajson[$cfg_name]; - } - // Config name / Alias + value - $msg .= '/set' . SP . (empty($alias) ? $cfg_name : $alias) . SP . (empty($cfg_value) ? '' . getTranslation('no_value') . '' : $cfg_value); - - // Only bool? - if(in_array($cfg_name, $allowed_bool)) { - $msg .= SP . '(' . getTranslation('help_only_bool') . ')' . CR; - - // Only numbers? - } else if(in_array($cfg_name, $allowed_numbers)) { - $msg .= SP . '(' . getTranslation('help_only_numbers') . ')' . CR; - - // Any type - } else { - $msg .= CR; - } - } - } - } else { - $msg .= getTranslation('not_supported'); - } - debug_log('Unsupported request for a telegram config change: ' . $input); -} - -// Send message. -send_message($update['message']['chat']['id'], $msg); - -?> diff --git a/core/telegram/functions.php b/core/telegram/functions.php index 1fb09915..350837e7 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -6,8 +6,8 @@ */ function is_valid_target($chat_id, $message_id, $no_chat = false, $no_message = false){ if($chat_id === null && isset($message_id)) { - debug_log("Inline message id received, skipping chat id check: {$message_id}"); - return true; + debug_log("Inline message id received, skipping chat id check: {$message_id}"); + return true; } debug_log("Checking for validity chat_id:{$chat_id} and message_id:{$message_id}"); // First check that both are numbers, if they are required @@ -28,51 +28,51 @@ function is_valid_target($chat_id, $message_id, $no_chat = false, $no_message = /** * Send message. * @param int $chat_id - * @param array $text + * @param string $text * @param mixed $inline_keyboard - * @param array $merge_args - * @param array|false $multicurl + * @param array|bool $merge_args + * @param array|bool $multicurl * @param int|string $identifier * @return mixed */ function send_message($chat_id, $text = [], $inline_keyboard = false, $merge_args = [], $multicurl = false, $identifier = false) { - // Create response content array. - $reply_content = [ - 'method' => 'sendMessage', - 'chat_id' => $chat_id, - 'parse_mode' => 'HTML', - 'text' => $text - ]; - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); - info_log($reply_content, 'ERROR: data would have been:'); - exit(); - } + // Create response content array. + $reply_content = [ + 'method' => 'sendMessage', + 'chat_id' => $chat_id, + 'parse_mode' => 'HTML', + 'text' => $text + ]; + if(!is_valid_target($chat_id, null, false, true)){ + info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); + info_log($reply_content, 'ERROR: data would have been:'); + exit(); + } - // Write to log. - debug_log('KEYS'); - debug_log($inline_keyboard); + // Write to log. + debug_log('KEYS'); + debug_log($inline_keyboard); - if ($inline_keyboard != false) { - $reply_content['reply_markup'] = ['inline_keyboard' => $inline_keyboard]; - } + if ($inline_keyboard != false) { + $reply_content['reply_markup'] = ['inline_keyboard' => $inline_keyboard]; + } - if (is_array($merge_args) && count($merge_args)) { - $reply_content = array_merge_recursive($reply_content, $merge_args); - } + if (is_array($merge_args) && count($merge_args)) { + $reply_content = array_merge_recursive($reply_content, $merge_args); + } - // Encode data to json. - $reply_json = json_encode($reply_content); + // Encode data to json. + $reply_json = json_encode($reply_content); - // Set header to json. - header('Content-Type: application/json'); + // Set header to json. + header('Content-Type: application/json'); - // Write to log. - debug_log($reply_json, '>'); + // Write to log. + debug_log($reply_json, '>'); - // Send request to telegram api. - return curl_request($reply_json, $multicurl, $identifier); + // Send request to telegram api. + return curl_request($reply_json, $multicurl, $identifier); } /** @@ -89,40 +89,40 @@ function send_message($chat_id, $text = [], $inline_keyboard = false, $merge_arg */ function send_venue($chat_id, $lat, $lon, $title, $address, $inline_keyboard = false, $multicurl = false, $identifier = false) { - // Create reply content array. - $reply_content = [ - 'method' => 'sendVenue', - 'chat_id' => $chat_id, - 'latitude' => $lat, - 'longitude' => $lon, - 'title' => $title, - 'address' => $address - ]; - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); - info_log($reply_content, 'ERROR: data would have been:'); - exit(); - } + // Create reply content array. + $reply_content = [ + 'method' => 'sendVenue', + 'chat_id' => $chat_id, + 'latitude' => $lat, + 'longitude' => $lon, + 'title' => $title, + 'address' => $address + ]; + if(!is_valid_target($chat_id, null, false, true)){ + info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); + info_log($reply_content, 'ERROR: data would have been:'); + exit(); + } - // Write to log. - debug_log('KEYS'); - debug_log($inline_keyboard); + // Write to log. + debug_log('KEYS'); + debug_log($inline_keyboard); - if (is_array($inline_keyboard)) { - $reply_content['reply_markup'] = ['inline_keyboard' => $inline_keyboard]; - } + if (is_array($inline_keyboard)) { + $reply_content['reply_markup'] = ['inline_keyboard' => $inline_keyboard]; + } - // Encode data to json. - $reply_json = json_encode($reply_content); + // Encode data to json. + $reply_json = json_encode($reply_content); - // Set header to json. - header('Content-Type: application/json'); + // Set header to json. + header('Content-Type: application/json'); - // Write to log. - debug_log($reply_json, '>'); + // Write to log. + debug_log($reply_json, '>'); - // Send request to telegram api and return response. - return curl_request($reply_json, $multicurl, $identifier); + // Send request to telegram api and return response. + return curl_request($reply_json, $multicurl, $identifier); } /** @@ -132,57 +132,58 @@ function send_venue($chat_id, $lat, $lon, $title, $address, $inline_keyboard = f */ function sendMessageEcho($chat_id, $text) { - // Create reply content array. - $reply_content = [ - 'method' => 'sendMessage', - 'chat_id' => $chat_id, - 'parse_mode' => 'HTML', - 'text' => $text - ]; - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); - info_log($reply_content, 'ERROR: data would have been:'); - exit(); - } + // Create reply content array. + $reply_content = [ + 'method' => 'sendMessage', + 'chat_id' => $chat_id, + 'parse_mode' => 'HTML', + 'text' => $text + ]; + if(!is_valid_target($chat_id, null, false, true)){ + info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); + info_log($reply_content, 'ERROR: data would have been:'); + exit(); + } - // Encode data to json. - $reply_json = json_encode($reply_content); + // Encode data to json. + $reply_json = json_encode($reply_content); - // Set header to json. - header('Content-Type: application/json'); + // Set header to json. + header('Content-Type: application/json'); - // Write to log. - debug_log($reply_json, '>'); + // Write to log. + debug_log($reply_json, '>'); - // Echo json. - echo($reply_json); + // Echo json. + echo($reply_json); } /** * Answer callback query. - * @param $query_id - * @param $text + * @param int $query_id + * @param string $text + * @param bool $multicurl */ function answerCallbackQuery($query_id, $text, $multicurl = false) { - // Create response array. - $response = [ - 'method' => 'answerCallbackQuery', - 'callback_query_id' => $query_id, - 'text' => $text - ]; + // Create response array. + $response = [ + 'method' => 'answerCallbackQuery', + 'callback_query_id' => $query_id, + 'text' => $text + ]; - // Encode response to json format. - $json_response = json_encode($response); + // Encode response to json format. + $json_response = json_encode($response); - // Set header to json. - header('Content-Type: application/json'); + // Set header to json. + header('Content-Type: application/json'); - // Write to log. - debug_log($json_response, '>'); + // Write to log. + debug_log($json_response, '>'); - // Send request to telegram api. - return curl_request($json_response, $multicurl); + // Send request to telegram api. + return curl_request($json_response, $multicurl); } /** @@ -192,50 +193,50 @@ function answerCallbackQuery($query_id, $text, $multicurl = false) */ function answerInlineQuery($query_id, $contents) { - // Init empty result array. - $results = []; - - // For each content. - foreach($contents as $key => $row) { - $text = $contents[$key]['text']; - $title = $contents[$key]['title']; - $desc = $contents[$key]['desc']; - $inline_keyboard = $contents[$key]['keyboard']; - - // Create input message content array. - $input_message_content = [ - 'parse_mode' => 'HTML', - 'message_text' => $text, - 'disable_web_page_preview' => true - ]; - - // Fill results array. - $results[] = [ - 'type' => 'article', - 'id' => $query_id . $key, - 'title' => $title, - 'description' => $desc, - 'input_message_content' => $input_message_content, - 'reply_markup' => [ - 'inline_keyboard' => $inline_keyboard - ] - ]; - } + // Init empty result array. + $results = []; + + // For each content. + foreach($contents as $key => $row) { + $text = $contents[$key]['text']; + $title = $contents[$key]['title']; + $desc = $contents[$key]['desc']; + $inline_keyboard = $contents[$key]['keyboard']; + + // Create input message content array. + $input_message_content = [ + 'parse_mode' => 'HTML', + 'message_text' => $text, + 'disable_web_page_preview' => true + ]; - // Create reply content array. - $reply_content = [ - 'method' => 'answerInlineQuery', - 'inline_query_id' => $query_id, - 'is_personal' => true, - 'cache_time' => 10, - 'results' => $results + // Fill results array. + $results[] = [ + 'type' => 'article', + 'id' => $query_id . $key, + 'title' => $title, + 'description' => $desc, + 'input_message_content' => $input_message_content, + 'reply_markup' => [ + 'inline_keyboard' => $inline_keyboard + ] ]; + } - // Encode to json - $reply_json = json_encode($reply_content); + // Create reply content array. + $reply_content = [ + 'method' => 'answerInlineQuery', + 'inline_query_id' => $query_id, + 'is_personal' => true, + 'cache_time' => 10, + 'results' => $results + ]; - // Send request to telegram api. - return curl_request($reply_json); + // Encode to json + $reply_json = json_encode($reply_content); + + // Send request to telegram api. + return curl_request($reply_json); } /** @@ -243,17 +244,15 @@ function answerInlineQuery($query_id, $contents) * @param $update * @param $message * @param $keys - * @param bool $merge_args + * @param array|bool $merge_args * @param $multicurl */ function edit_message($update, $message, $keys, $merge_args = false, $multicurl = false) { - if (isset($update['callback_query']['inline_message_id'])) { - $json_response = editMessageText($update['callback_query']['inline_message_id'], $message, $keys, NULL, $merge_args, $multicurl); - } else { - $json_response = editMessageText($update['callback_query']['message']['message_id'], $message, $keys, $update['callback_query']['message']['chat']['id'], $merge_args, $multicurl); - } - return $json_response; + if (isset($update['callback_query']['inline_message_id'])) { + return editMessageText($update['callback_query']['inline_message_id'], $message, $keys, NULL, $merge_args, $multicurl); + } + return editMessageText($update['callback_query']['message']['message_id'], $message, $keys, $update['callback_query']['message']['chat']['id'], $merge_args, $multicurl); } /** @@ -267,48 +266,48 @@ function edit_message($update, $message, $keys, $merge_args = false, $multicurl */ function editMessageText($id_val, $text_val, $markup_val, $chat_id = NULL, $merge_args = false, $multicurl = false) { - // Create response array. - $response = [ - 'method' => 'editMessageText', - 'text' => $text_val, - 'parse_mode' => 'HTML', - 'reply_markup' => [ - 'inline_keyboard' => $markup_val - ] - ]; - - if ($markup_val == false) { - unset($response['reply_markup']); - $response['remove_keyboard'] = true; - } + // Create response array. + $response = [ + 'method' => 'editMessageText', + 'text' => $text_val, + 'parse_mode' => 'HTML', + 'reply_markup' => [ + 'inline_keyboard' => $markup_val + ] + ]; + + if ($markup_val == false) { + unset($response['reply_markup']); + $response['remove_keyboard'] = true; + } - // Valid chat id. - if ($chat_id != null) { - $response['chat_id'] = $chat_id; - $response['message_id'] = $id_val; - } else { - $response['inline_message_id'] = $id_val; - } + // Valid chat id. + if ($chat_id != null) { + $response['chat_id'] = $chat_id; + $response['message_id'] = $id_val; + } else { + $response['inline_message_id'] = $id_val; + } - // Write to log. - //debug_log($merge_args, 'K'); - //debug_log($response, 'K'); + // Write to log. + //debug_log($merge_args, 'K'); + //debug_log($response, 'K'); - if (is_array($merge_args) && count($merge_args)) { - $response = array_merge_recursive($response, $merge_args); - } + if (is_array($merge_args) && count($merge_args)) { + $response = array_merge_recursive($response, $merge_args); + } - if(!is_valid_target($chat_id, $id_val, true, false)){ - info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit invalid chat/message id:'); - info_log($response, 'ERROR: data would have been:'); - exit(); - } - debug_log($response, '<-'); + if(!is_valid_target($chat_id, $id_val, true, false)){ + info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit invalid chat/message id:'); + info_log($response, 'ERROR: data would have been:'); + exit(); + } + debug_log($response, '<-'); - // Encode response to json format. - $json_response = json_encode($response); - // Send request to telegram api. - return curl_request($json_response, $multicurl); + // Encode response to json format. + $json_response = json_encode($response); + // Send request to telegram api. + return curl_request($json_response, $multicurl); } /** @@ -321,12 +320,12 @@ function editMessageText($id_val, $text_val, $markup_val, $chat_id = NULL, $merg */ function edit_caption($update, $message, $keys, $merge_args = false, $multicurl = false) { - if (isset($update['callback_query']['inline_message_id'])) { - $json_response = editMessageCaption($update['callback_query']['inline_message_id'], $message, $keys, NULL, $merge_args, $multicurl); - } else { - $json_response = editMessageCaption($update['callback_query']['message']['message_id'], $message, $keys, $update['callback_query']['message']['chat']['id'], $merge_args, $multicurl); - } - return $json_response; + if (isset($update['callback_query']['inline_message_id'])) { + $json_response = editMessageCaption($update['callback_query']['inline_message_id'], $message, $keys, NULL, $merge_args, $multicurl); + } else { + $json_response = editMessageCaption($update['callback_query']['message']['message_id'], $message, $keys, $update['callback_query']['message']['chat']['id'], $merge_args, $multicurl); + } + return $json_response; } /** @@ -340,45 +339,45 @@ function edit_caption($update, $message, $keys, $merge_args = false, $multicurl */ function editMessageCaption($id_val, $text_val, $markup_val, $chat_id = NULL, $merge_args = false, $multicurl = false) { - // Create response array. - $response = [ - 'method' => 'editMessageCaption', - 'caption' => $text_val, - 'parse_mode' => 'HTML', - 'reply_markup' => [ - 'inline_keyboard' => $markup_val - ] - ]; - - if ($markup_val == false) { - unset($response['reply_markup']); - $response['remove_keyboard'] = true; - } + // Create response array. + $response = [ + 'method' => 'editMessageCaption', + 'caption' => $text_val, + 'parse_mode' => 'HTML', + 'reply_markup' => [ + 'inline_keyboard' => $markup_val + ] + ]; + + if ($markup_val == false) { + unset($response['reply_markup']); + $response['remove_keyboard'] = true; + } - // Valid chat id. - if ($chat_id != null) { - $response['chat_id'] = $chat_id; - $response['message_id'] = $id_val; - } else { - $response['inline_message_id'] = $id_val; - } + // Valid chat id. + if ($chat_id != null) { + $response['chat_id'] = $chat_id; + $response['message_id'] = $id_val; + } else { + $response['inline_message_id'] = $id_val; + } - if (is_array($merge_args) && count($merge_args)) { - $response = array_merge_recursive($response, $merge_args); - } + if (is_array($merge_args) && count($merge_args)) { + $response = array_merge_recursive($response, $merge_args); + } - if(!is_valid_target($chat_id, $id_val, true, false)){ - info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit invalid chat/message id:'); - info_log($response, 'ERROR: data would have been:'); - exit(); - } - debug_log($response, '<-'); + if(!is_valid_target($chat_id, $id_val, true, false)){ + info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit invalid chat/message id:'); + info_log($response, 'ERROR: data would have been:'); + exit(); + } + debug_log($response, '<-'); - // Encode response to json format. - $json_response = json_encode($response); + // Encode response to json format. + $json_response = json_encode($response); - // Send request to telegram api. - return curl_request($json_response, $multicurl); + // Send request to telegram api. + return curl_request($json_response, $multicurl); } /** @@ -390,33 +389,33 @@ function editMessageCaption($id_val, $text_val, $markup_val, $chat_id = NULL, $m */ function editMessageReplyMarkup($id_val, $markup_val, $chat_id, $multicurl = false) { - // Create response array. - $response = [ - 'method' => 'editMessageReplyMarkup', - 'reply_markup' => [ - 'inline_keyboard' => $markup_val - ] - ]; - - // Valid chat id. - if ($chat_id != null) { - $response['chat_id'] = $chat_id; - $response['message_id'] = $id_val; - - } else { - $response['inline_message_id'] = $id_val; - } - if(!is_valid_target($chat_id, $id_val)){ - info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit invalid chat/message id:'); - info_log($response, 'ERROR: data would have been:'); - exit(); - } - debug_log($response, '->'); + // Create response array. + $response = [ + 'method' => 'editMessageReplyMarkup', + 'reply_markup' => [ + 'inline_keyboard' => $markup_val + ] + ]; + + // Valid chat id. + if ($chat_id != null) { + $response['chat_id'] = $chat_id; + $response['message_id'] = $id_val; + + } else { + $response['inline_message_id'] = $id_val; + } + if(!is_valid_target($chat_id, $id_val)){ + info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit invalid chat/message id:'); + info_log($response, 'ERROR: data would have been:'); + exit(); + } + debug_log($response, '->'); // Encode response to json format. - $json_response = json_encode($response); + $json_response = json_encode($response); - // Send request to telegram api. - return curl_request($json_response, $multicurl); + // Send request to telegram api. + return curl_request($json_response, $multicurl); } /** @@ -428,36 +427,36 @@ function editMessageReplyMarkup($id_val, $markup_val, $chat_id, $multicurl = fal */ function edit_message_keyboard($id_val, $markup_val, $chat_id, $multicurl = false) { - // Create response array. - $response = [ - 'method' => 'editMessageReplyMarkup', - 'reply_markup' => [ - 'inline_keyboard' => $markup_val - ] - ]; - - // Valid chat id. - if ($chat_id != null) { - $response['chat_id'] = $chat_id; - $response['message_id'] = $id_val; - - } else { - $response['inline_message_id'] = $id_val; - } - if(!is_valid_target($chat_id, $id_val)){ - info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit invalid chat/message id:'); - info_log($response, 'ERROR: data would have been:'); - exit(); - } + // Create response array. + $response = [ + 'method' => 'editMessageReplyMarkup', + 'reply_markup' => [ + 'inline_keyboard' => $markup_val + ] + ]; + + // Valid chat id. + if ($chat_id != null) { + $response['chat_id'] = $chat_id; + $response['message_id'] = $id_val; + + } else { + $response['inline_message_id'] = $id_val; + } + if(!is_valid_target($chat_id, $id_val)){ + info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit invalid chat/message id:'); + info_log($response, 'ERROR: data would have been:'); + exit(); + } - // Encode response to json format. - $json_response = json_encode($response); + // Encode response to json format. + $json_response = json_encode($response); - // Write to log. - debug_log($response, '->'); + // Write to log. + debug_log($response, '->'); - // Send request to telegram api. - return curl_request($json_response, $multicurl); + // Send request to telegram api. + return curl_request($json_response, $multicurl); } /** @@ -468,29 +467,29 @@ function edit_message_keyboard($id_val, $markup_val, $chat_id, $multicurl = fals */ function delete_message($chat_id, $message_id, $multicurl = false) { - // Create response content array. - $reply_content = [ - 'method' => 'deleteMessage', - 'chat_id' => $chat_id, - 'message_id' => $message_id, - ]; - if(!is_valid_target($chat_id, $message_id)){ - info_log("{$chat_id}/{$message_id}", 'ERROR: Cannot delete invalid chat/message id:'); - info_log($reply_content, 'ERROR: data would have been:'); - exit(); - } + // Create response content array. + $reply_content = [ + 'method' => 'deleteMessage', + 'chat_id' => $chat_id, + 'message_id' => $message_id, + ]; + if(!is_valid_target($chat_id, $message_id)){ + info_log("{$chat_id}/{$message_id}", 'ERROR: Cannot delete invalid chat/message id:'); + info_log($reply_content, 'ERROR: data would have been:'); + exit(); + } - // Encode data to json. - $reply_json = json_encode($reply_content); + // Encode data to json. + $reply_json = json_encode($reply_content); - // Set header to json. - header('Content-Type: application/json'); + // Set header to json. + header('Content-Type: application/json'); - // Write to log. - debug_log($reply_json, '>'); + // Write to log. + debug_log($reply_json, '>'); - // Send request to telegram api. - return curl_request($reply_json, $multicurl); + // Send request to telegram api. + return curl_request($reply_json, $multicurl); } /** @@ -500,28 +499,28 @@ function delete_message($chat_id, $message_id, $multicurl = false) */ function get_chat($chat_id, $multicurl = false) { - // Create response content array. - $reply_content = [ - 'method' => 'getChat', - 'chat_id' => $chat_id, - ]; - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot get invalid chat id:'); - info_log($reply_content, 'ERROR: data would have been:'); - exit(); - } + // Create response content array. + $reply_content = [ + 'method' => 'getChat', + 'chat_id' => $chat_id, + ]; + if(!is_valid_target($chat_id, null, false, true)){ + info_log($chat_id, 'ERROR: Cannot get invalid chat id:'); + info_log($reply_content, 'ERROR: data would have been:'); + exit(); + } - // Encode data to json. - $reply_json = json_encode($reply_content); + // Encode data to json. + $reply_json = json_encode($reply_content); - // Set header to json. - header('Content-Type: application/json'); + // Set header to json. + header('Content-Type: application/json'); - // Write to log. - debug_log($reply_json, '>'); + // Write to log. + debug_log($reply_json, '>'); - // Send request to telegram api. - return curl_request($reply_json, $multicurl); + // Send request to telegram api. + return curl_request($reply_json, $multicurl); } /** @@ -531,28 +530,28 @@ function get_chat($chat_id, $multicurl = false) */ function get_admins($chat_id, $multicurl = false) { - // Create response content array. - $reply_content = [ - 'method' => 'getChatAdministrators', - 'chat_id' => $chat_id, - ]; - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot get invalid chat id:'); - info_log($reply_content, 'ERROR: data would have been:'); - exit(); - } + // Create response content array. + $reply_content = [ + 'method' => 'getChatAdministrators', + 'chat_id' => $chat_id, + ]; + if(!is_valid_target($chat_id, null, false, true)){ + info_log($chat_id, 'ERROR: Cannot get invalid chat id:'); + info_log($reply_content, 'ERROR: data would have been:'); + exit(); + } - // Encode data to json. - $reply_json = json_encode($reply_content); + // Encode data to json. + $reply_json = json_encode($reply_content); - // Set header to json. - header('Content-Type: application/json'); + // Set header to json. + header('Content-Type: application/json'); - // Write to log. - debug_log($reply_json, '>'); + // Write to log. + debug_log($reply_json, '>'); - // Send request to telegram api. - return curl_request($reply_json, $multicurl); + // Send request to telegram api. + return curl_request($reply_json, $multicurl); } /** @@ -563,29 +562,29 @@ function get_admins($chat_id, $multicurl = false) */ function get_chatmember($chat_id, $user_id, $multicurl = false) { - // Create response content array. - $reply_content = [ - 'method' => 'getChatMember', - 'chat_id' => $chat_id, - 'user_id' => $user_id, - ]; - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot get invalid chat id:'); - info_log($reply_content, 'ERROR: data would have been:'); - exit(); - } + // Create response content array. + $reply_content = [ + 'method' => 'getChatMember', + 'chat_id' => $chat_id, + 'user_id' => $user_id, + ]; + if(!is_valid_target($chat_id, null, false, true)){ + info_log($chat_id, 'ERROR: Cannot get invalid chat id:'); + info_log($reply_content, 'ERROR: data would have been:'); + exit(); + } - // Encode data to json. - $reply_json = json_encode($reply_content); + // Encode data to json. + $reply_json = json_encode($reply_content); - // Set header to json. - header('Content-Type: application/json'); + // Set header to json. + header('Content-Type: application/json'); - // Write to log. - debug_log($reply_json, '>'); + // Write to log. + debug_log($reply_json, '>'); - // Send request to telegram api. - return curl_request($reply_json, $multicurl); + // Send request to telegram api. + return curl_request($reply_json, $multicurl); } /** @@ -593,42 +592,42 @@ function get_chatmember($chat_id, $user_id, $multicurl = false) * @param $chat_id * @param string $media_content content of the media file. * @param bool $content_type true = photo file, false = file_id - * @param array $text - * @param mixed $inline_keyboard + * @param string|bool $text + * @param array|bool $inline_keyboard * @param array $merge_args - * @param array $multicurl - * @param int $identifier + * @param array|bool $multicurl + * @param int|bool $identifier */ function send_photo($chat_id, $media_content, $content_type, $text = '', $inline_keyboard = false, $merge_args = [], $multicurl = false, $identifier = false) { - // Create response content array. - $post_contents = [ - 'method' => 'sendPhoto', - 'chat_id' => $chat_id, - 'reply_markup' => json_encode(['inline_keyboard' => $inline_keyboard]), - ]; - if($text != '') { - $post_contents['caption'] = $text; - $post_contents['parse_mode'] = 'HTML'; - } - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); - info_log(print_r($post_contents, true), 'ERROR: data would have been:'); - exit(); - } + // Create response content array. + $post_contents = [ + 'method' => 'sendPhoto', + 'chat_id' => $chat_id, + 'reply_markup' => json_encode(['inline_keyboard' => $inline_keyboard]), + ]; + if($text != '') { + $post_contents['caption'] = $text; + $post_contents['parse_mode'] = 'HTML'; + } + if(!is_valid_target($chat_id, null, false, true)){ + info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); + info_log(print_r($post_contents, true), 'ERROR: data would have been:'); + exit(); + } - $post_contents['photo'] = ($content_type) ? new CURLStringFile($media_content, 'photo') : $media_content; + $post_contents['photo'] = ($content_type) ? new CURLStringFile($media_content, 'photo') : $media_content; - debug_log($inline_keyboard, 'KEYS:'); + debug_log($inline_keyboard, 'KEYS:'); - if (is_array($merge_args) && count($merge_args)) { - $post_contents = array_merge_recursive($post_contents, $merge_args); - } + if (is_array($merge_args) && count($merge_args)) { + $post_contents = array_merge_recursive($post_contents, $merge_args); + } - debug_log(print_r($post_contents, true), '>'); + debug_log(print_r($post_contents, true), '>'); - // Send request to telegram api. - return curl_request($post_contents, $multicurl, $identifier); + // Send request to telegram api. + return curl_request($post_contents, $multicurl, $identifier); } /** @@ -644,48 +643,48 @@ function send_photo($chat_id, $media_content, $content_type, $text = '', $inline */ function editMessageMedia($id_val, $text_val, $media_content, $content_type, $inline_keyboard = false, $chat_id = NULL, $merge_args = false, $multicurl = false, $identifier = false) { - // Create response array. - $post_contents = [ - 'method' => 'editMessageMedia', - 'media' => [ - 'type' => 'photo', - 'caption' => $text_val, - 'parse_mode'=> 'HTML' - ] - ]; - - if ($inline_keyboard !== false) { - $post_contents['reply_markup'] = json_encode(['inline_keyboard' => $inline_keyboard]); - }else { - $post_contents['remove_keyboard'] = true; - } - if ($chat_id != null) { - $post_contents['chat_id'] = $chat_id; - $post_contents['message_id'] = $id_val; - } else { - $post_contents['inline_message_id'] = $id_val; - } - if (is_array($merge_args) && count($merge_args)) { - $post_contents = array_merge_recursive($post_contents, $merge_args); - } - if(!is_valid_target($chat_id, $id_val, true, false)){ - info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit media of invalid chat/message id:'); - info_log(print_r($post_contents, true), 'ERROR: data would have been:'); - exit(); - } + // Create response array. + $post_contents = [ + 'method' => 'editMessageMedia', + 'media' => [ + 'type' => 'photo', + 'caption' => $text_val, + 'parse_mode'=> 'HTML' + ] + ]; + + if ($inline_keyboard !== false) { + $post_contents['reply_markup'] = json_encode(['inline_keyboard' => $inline_keyboard]); + }else { + $post_contents['remove_keyboard'] = true; + } + if ($chat_id != null) { + $post_contents['chat_id'] = $chat_id; + $post_contents['message_id'] = $id_val; + } else { + $post_contents['inline_message_id'] = $id_val; + } + if (is_array($merge_args) && count($merge_args)) { + $post_contents = array_merge_recursive($post_contents, $merge_args); + } + if(!is_valid_target($chat_id, $id_val, true, false)){ + info_log("{$chat_id}/{$id_val}", 'ERROR: Cannot edit media of invalid chat/message id:'); + info_log(print_r($post_contents, true), 'ERROR: data would have been:'); + exit(); + } - // Encode response to json format. - if($content_type) { - $post_contents['photo'] = new CURLStringFile($media_content, 'photo'); - $post_contents['media']['media'] = 'attach://photo'; - } else { - $post_contents['media']['media'] = $media_content; - } - $post_contents['media'] = json_encode($post_contents['media']); - debug_log(print_r($post_contents, true), '->'); + // Encode response to json format. + if($content_type) { + $post_contents['photo'] = new CURLStringFile($media_content, 'photo'); + $post_contents['media']['media'] = 'attach://photo'; + } else { + $post_contents['media']['media'] = $media_content; + } + $post_contents['media'] = json_encode($post_contents['media']); + debug_log(print_r($post_contents, true), '->'); - // Send request to telegram api. - return curl_request($post_contents, $multicurl, $identifier); + // Send request to telegram api. + return curl_request($post_contents, $multicurl, $identifier); } /** @@ -698,12 +697,12 @@ function editMessageMedia($id_val, $text_val, $media_content, $content_type, $in function curl_request($post_contents, $multicurl = false, $identifier = false) { - // Send request to telegram api. - if($multicurl == true) { - return ['post_contents' => $post_contents, 'identifier' => $identifier]; - } else { - return curl_json_request($post_contents, $identifier); - } + // Send request to telegram api. + if($multicurl == true) { + return ['post_contents' => $post_contents, 'identifier' => $identifier]; + } else { + return curl_json_request($post_contents, $identifier); + } } /** @@ -714,46 +713,46 @@ function curl_request($post_contents, $multicurl = false, $identifier = false) */ function curl_json_request($post_contents, $identifier) { - global $config; - - // Telegram - $URL = 'https://api.telegram.org/bot' . API_KEY . '/'; - $curl = curl_init($URL); - - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - if(!is_array($post_contents)) curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json")); - curl_setopt($curl, CURLOPT_POST, true); - curl_setopt($curl, CURLOPT_POSTFIELDS, $post_contents); - curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); - curl_setopt($curl, CURLOPT_TIMEOUT, 10); - - // Use Proxyserver for curl if configured - if ($config->CURL_USEPROXY && !empty($config->CURL_PROXYSERVER)) { - curl_setopt($curl, CURLOPT_PROXY, $config->CURL_PROXYSERVER); - } + global $config; + + // Telegram + $URL = 'https://api.telegram.org/bot' . API_KEY . '/'; + $curl = curl_init($URL); + + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + if(!is_array($post_contents)) curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json")); + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $post_contents); + curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); + curl_setopt($curl, CURLOPT_TIMEOUT, 10); + + // Use Proxyserver for curl if configured + if ($config->CURL_USEPROXY && !empty($config->CURL_PROXYSERVER)) { + curl_setopt($curl, CURLOPT_PROXY, $config->CURL_PROXYSERVER); + } - // Write to log. - if(is_array($post_contents)) debug_log(print_r($post_contents,true), '->'); - else debug_log($post_contents, '->'); + // Write to log. + if(is_array($post_contents)) debug_log(print_r($post_contents,true), '->'); + else debug_log($post_contents, '->'); - // Execute curl request. - $json_response = curl_exec($curl); + // Execute curl request. + $json_response = curl_exec($curl); - if($json_response === false) { - info_log(curl_error($curl)); - } + if($json_response === false) { + info_log(curl_error($curl)); + } - // Close connection. - curl_close($curl); + // Close connection. + curl_close($curl); - // Process response from telegram api. - responseHandler($json_response, $post_contents); + // Process response from telegram api. + responseHandler($json_response, $post_contents); - $responseArray = json_decode($json_response, true); - collectCleanup($responseArray, $post_contents, $identifier); + $responseArray = json_decode($json_response, true); + collectCleanup($responseArray, $post_contents, $identifier); - // Return response. - return $responseArray; + // Return response. + return $responseArray; } /** @@ -763,103 +762,103 @@ function curl_json_request($post_contents, $identifier) */ function curl_json_multi_request($json) { - global $config; - // Set URL. - $URL = 'https://api.telegram.org/bot' . API_KEY . '/'; - - // Curl handles. - $curly = array(); - - // Curl response. - $response = array(); - - // Init multi handle. - $mh = curl_multi_init(); - - // Loop through json array, create curl handles and add them to the multi-handle. - foreach ($json as $id => $data) { - // Init. - $curly[$id] = curl_init(); - - // Curl options. - curl_setopt($curly[$id], CURLOPT_URL, $URL); - curl_setopt($curly[$id], CURLOPT_HEADER, false); - if(!is_array($data['post_contents'])) curl_setopt($curly[$id], CURLOPT_HTTPHEADER, array("Content-type: application/json")); - curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, true); - curl_setopt($curly[$id], CURLOPT_CONNECTTIMEOUT, 5); - curl_setopt($curly[$id], CURLOPT_TIMEOUT, 10); - - // Use Proxyserver for curl if configured. - if($config->CURL_USEPROXY && !empty($config->CURL_PROXYSERVER)) { - curl_setopt($curly[$id], CURLOPT_PROXY, $config->CURL_PROXYSERVER); - } - - // Curl post. - curl_setopt($curly[$id], CURLOPT_POST, true); - curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $data['post_contents']); - - // Add multi handle. - curl_multi_add_handle($mh, $curly[$id]); - - // Write to log. - if(is_array($data['post_contents'])) debug_log(print_r($data['post_contents'],true), '->'); - else debug_log($data['post_contents'], '->'); + global $config; + // Set URL. + $URL = 'https://api.telegram.org/bot' . API_KEY . '/'; + + // Curl handles. + $curly = array(); + + // Curl response. + $response = array(); + + // Init multi handle. + $mh = curl_multi_init(); + + // Loop through json array, create curl handles and add them to the multi-handle. + foreach ($json as $id => $data) { + // Init. + $curly[$id] = curl_init(); + + // Curl options. + curl_setopt($curly[$id], CURLOPT_URL, $URL); + curl_setopt($curly[$id], CURLOPT_HEADER, false); + if(!is_array($data['post_contents'])) curl_setopt($curly[$id], CURLOPT_HTTPHEADER, array("Content-type: application/json")); + curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, true); + curl_setopt($curly[$id], CURLOPT_CONNECTTIMEOUT, 5); + curl_setopt($curly[$id], CURLOPT_TIMEOUT, 10); + + // Use Proxyserver for curl if configured. + if($config->CURL_USEPROXY && !empty($config->CURL_PROXYSERVER)) { + curl_setopt($curly[$id], CURLOPT_PROXY, $config->CURL_PROXYSERVER); } - // Get content and remove handles. + // Curl post. + curl_setopt($curly[$id], CURLOPT_POST, true); + curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $data['post_contents']); + + // Add multi handle. + curl_multi_add_handle($mh, $curly[$id]); + + // Write to log. + if(is_array($data['post_contents'])) debug_log(print_r($data['post_contents'],true), '->'); + else debug_log($data['post_contents'], '->'); + } + + // Get content and remove handles. + $retry = false; + $maxRetries = 3; + $retryCount = 0; + $sleep = 0; + do { + // On the second pass and onwards sleep before executing curls + if($retry === true) { $retry = false; - $maxRetries = 3; - $retryCount = 0; $sleep = 0; + $retryCount++; + debug_log('Retrying in '.$sleep.' seconds'); + sleep($sleep); + debug_log('Retry count: '.($retryCount).'...'); + } + + // Execute the handles. + $running = null; do { - // On the second pass and onwards sleep before executing curls - if($retry === true) { - $retry = false; - $sleep = 0; - $retryCount++; - debug_log('Retrying in '.$sleep.' seconds'); - sleep($sleep); - debug_log('Retry count: '.($retryCount).'...'); - } - - // Execute the handles. - $running = null; - do { - $status = curl_multi_exec($mh, $running); - curl_multi_select($mh); - } while($running > 0 && $status === CURLM_OK); - - if ($status != CURLM_OK) { - info_log(curl_multi_strerror($status)); - } - - foreach($curly as $id => $content) { - $response[$id] = curl_multi_getcontent($content); - curl_multi_remove_handle($mh, $content); - $responseResults = responseHandler($response[$id], $json[$id]['post_contents']); - // Handle errors - if(is_array($responseResults) && $responseResults[0] === 'retry') { - $retry = true; - // Use the highest sleep value returned by TG - $sleep = $responseResults[1] > $sleep ? $responseResults[1] : $sleep; - // Re-add this handle with the same info - curl_multi_add_handle($mh, $curly[$id]); - continue; - } - - unset($curly[$id]); - } - }while($retry === true && $retryCount < $maxRetries); - - $responseArrays = []; - // Process response from telegram api. - foreach($response as $id => $json_response) { - $responseArrays[$id] = json_decode($response[$id], true); - collectCleanup($responseArrays[$id], $json[$id]['post_contents'], $json[$id]['identifier']); + $status = curl_multi_exec($mh, $running); + curl_multi_select($mh); + } while($running > 0 && $status === CURLM_OK); + + if ($status != CURLM_OK) { + info_log(curl_multi_strerror($status)); + } + + foreach($curly as $id => $content) { + $response[$id] = curl_multi_getcontent($content); + curl_multi_remove_handle($mh, $content); + $responseResults = responseHandler($response[$id], $json[$id]['post_contents']); + // Handle errors + if(is_array($responseResults) && $responseResults[0] === 'retry') { + $retry = true; + // Use the highest sleep value returned by TG + $sleep = $responseResults[1] > $sleep ? $responseResults[1] : $sleep; + // Re-add this handle with the same info + curl_multi_add_handle($mh, $curly[$id]); + continue; } - // Return response. - return $responseArrays; + unset($curly[$id]); + } + }while($retry === true && $retryCount < $maxRetries); + + $responseArrays = []; + // Process response from telegram api. + foreach($response as $id => $json_response) { + $responseArrays[$id] = json_decode($response[$id], true); + collectCleanup($responseArrays[$id], $json[$id]['post_contents'], $json[$id]['identifier']); + } + + // Return response. + return $responseArrays; } if($metrics) { $tg_response_code = $metrics->registerCounter($namespace, 'tg_response_count', 'Counters of response codes from Telegram', ['code', 'method', 'description']); @@ -867,8 +866,8 @@ function curl_json_multi_request($json) /** * Process response from Telegram. - * @param $jsonResponse JSON string returned by Telegram - * @param $request The request we sent to Telegram + * @param $jsonResponse string JSON string returned by Telegram + * @param $request string|array The request we sent to Telegram * @return mixed */ function responseHandler($jsonResponse, $request) { @@ -903,14 +902,15 @@ function responseHandler($jsonResponse, $request) { $i++; } while($q->rowCount() == 0 && $i < count($table)); info_log($table[$i-1], 'A message was deleted by someone else than us. Deleting info from database table:'); - info_log($chatId, 'chat_id:'); - info_log($messageId, 'message_id:'); + info_log($request_array['chat_id'], 'chat_id:'); + info_log($request_array['message_id'], 'message_id:'); return true; } if(substr($response['description'], 0, 30) == 'Too Many Requests: retry after') { - return [ 'retry', - ($response['parameters']['retry_after'] + 1), - ]; + return [ + 'retry', + ($response['parameters']['retry_after'] + 1), + ]; } info_log("{$json} -> {$jsonResponse}", 'ERROR:'); // Log unhandled errors diff --git a/core/tools/automate_raid_hour_creation/raid_hour_creator.php b/core/tools/automate_raid_hour_creation/raid_hour_creator.php index b6ba37a8..e1e81ac2 100644 --- a/core/tools/automate_raid_hour_creation/raid_hour_creator.php +++ b/core/tools/automate_raid_hour_creation/raid_hour_creator.php @@ -104,10 +104,8 @@ } catch (PDOException $exception) { echo($exception->getMessage()); - $dbh = null; exit; } -$dbh = null; function get_current_bosses($spawn) { global $dbh; $i = 0; @@ -146,5 +144,3 @@ function curl_get_contents($url) curl_close($ch); return $content; } - -?> diff --git a/core/tools/automate_raid_hour_creation/share_event_raids.php b/core/tools/automate_raid_hour_creation/share_event_raids.php index 13bd629b..255110bc 100644 --- a/core/tools/automate_raid_hour_creation/share_event_raids.php +++ b/core/tools/automate_raid_hour_creation/share_event_raids.php @@ -49,6 +49,3 @@ // Close connection. curl_close($curl); } - -$dbh = null; -?> diff --git a/core/tools/hash.php b/core/tools/hash.php index 8fea50c1..bf087ec1 100644 --- a/core/tools/hash.php +++ b/core/tools/hash.php @@ -1,4 +1,3 @@ diff --git a/core/tools/set_commands.php b/core/tools/set_commands.php index 2054f1c6..7cdc1bcd 100644 --- a/core/tools/set_commands.php +++ b/core/tools/set_commands.php @@ -48,7 +48,7 @@ $request = json_encode([ 'method'=>'deleteMyCommands', 'scope'=>$scope, - + ]); $response = curl_json_request($request); } diff --git a/docs/config.rst b/docs/config.rst index 28a1e830..be6e7aca 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -110,8 +110,6 @@ Set ``APIKEY_HASH`` to the hashed value of your bot token (preferably lowercase) Set ``DDOS_MAXIMUM`` to the amount of callback queries each user is allowed to do each minute. If the amount is reached any further callback query is rejected by the DDOS check. Default value: 10. -Set ``BRIDGE_MODE`` to true when you're using the PokemonBotBridge. If you're not using the PokemonBotBridge the default value of false is used. PokemonBotBridge: https://github.com/pokepark/PokemonBotBridge - More config options ------------------- @@ -389,7 +387,7 @@ Raids from Webhook ~~~~~~~~~~~~~~~~~~ You can receive Raids from a mapping systems such as MAD and RDM via Webhook. -For that you need to setup ``WEBHOOK_CREATOR``\ , and to automatically share raids to chats, +For that you need to setup ``WEBHOOK_CREATOR``\ , and to automatically share raids to chats, ``"WEBHOOK_CHATS_ALL_LEVELS":"-100444555666"`` or by Raidlevel ``"WEBHOOK_CHATS_LEVEL_5":"-100444555666"`` All incoming raids will be published in these chats. @@ -874,8 +872,6 @@ Config reference - One letter ID for the bot used in debug logging. Mostly useful if you run multiple. * - BOT_NAME - Name of the bot. - * - BRIDGE_MODE - - Bool, whether to enable bridge mode. * - CLEANUP_DATABASE - Bool, whether to clean up finished raids from DB if cleanup is enabled. * - CLEANUP_LOG @@ -935,7 +931,7 @@ Config reference * - MAINTAINER - Name of main maintainer * - AUTO_REFRESH_POLLS - - Bool, enable the auto refresh feature and hides the refresh button from polls. Requires a curl job for refreshing. + - Bool, enable the auto refresh feature and hides the refresh button from polls. Requires a curl job for refreshing. * - MAPS_API_KEY - Google Maps API key for ``MAPS_LOOKUP`` * - MAPS_LOOKUP diff --git a/docs/development.rst b/docs/development.rst index 865506a0..08aee9f4 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -9,6 +9,12 @@ Adding new config values * You can access the new config item in code with ``$config->CONFIG_ITEM_NAME`` but if inside a function, remember to specify ``global $config;`` * Don't break backwards compatibility if you can. +Formatting callback data in inline keyboards +-------------------------------------------- + +Old way of sending data over key presses was ``id:action:arg``. These values got stored early on in ``$data`` array. This is still supported for as long as this method is used in the code somewhere, but we'll try to move to the new system overtime. +New data format adds variable names to passed data. When forming keyboard arrays you should use the function ``formatCallbackData()`` to convert your array to string. + Adding new metrics ------------------ diff --git a/getPokemonIcons.php b/getPokemonIcons.php index 6037f62f..a66ad91a 100644 --- a/getPokemonIcons.php +++ b/getPokemonIcons.php @@ -10,15 +10,15 @@ $repos = []; $repos[] = array('owner' => "PokeMiners", - 'name' => "pogo_assets", - 'branch' => "master", - 'subdir' => "", - 'dir' => "Images/Pokemon - 256x256"); + 'name' => "pogo_assets", + 'branch' => "master", + 'subdir' => "", + 'dir' => "Images/Pokemon - 256x256"); $repos[] = array('owner' => "PokeMiners", - 'name' => "pogo_assets", - 'branch' => "master", - 'subdir' => "Addressable_Assets/", - 'dir' => "Images/Pokemon - 256x256/Addressable Assets"); + 'name' => "pogo_assets", + 'branch' => "master", + 'subdir' => "Addressable_Assets/", + 'dir' => "Images/Pokemon - 256x256/Addressable Assets"); // Get download function curl_get_contents include('logic/curl_get_contents.php'); @@ -46,152 +46,144 @@ function is_updated($path, $file_object) { // Process each repo foreach ($repos as $key => $r) { - $repo_owner = $r['owner']; - $repo_name = $r['name']; - $repo_branch = $r['branch']; - $repo_dir = $r['dir']; - $dest = $destination . 'pokemon_' . $repo_owner . '/' . $r['subdir']; - - // Set destination to different path - if(isset($options['dir'])) { - $dest = rtrim($options['dir'],"/") . '/'; - } + $repo_owner = $r['owner']; + $repo_name = $r['name']; + $repo_branch = $r['branch']; + $repo_dir = $r['dir']; + $dest = $destination . 'pokemon_' . $repo_owner . '/' . $r['subdir']; + + // Set destination to different path + if(isset($options['dir'])) { + $dest = rtrim($options['dir'],"/") . '/'; + } - // Make sure destination exists otherwise create it - if (!file_exists($dest)) { - mkdir($dest); - } + // Make sure destination exists otherwise create it + if (!file_exists($dest)) { + mkdir($dest); + } - // Content dir - $content_dir = ''; - if (strpos($repo_dir, '/') !== false) { - $content_dir = str_replace(' ', '%20',substr($repo_dir, 0, strrpos($repo_dir, '/'))); - } - // Raw download dir - $raw_dir = $repo_dir; - if (strpos($repo_dir, ' ') !== false) { - $raw_dir = str_replace(' ', '%20', $repo_dir); - } + // Content dir + $content_dir = ''; + if (strpos($repo_dir, '/') !== false) { + $content_dir = str_replace(' ', '%20',substr($repo_dir, 0, strrpos($repo_dir, '/'))); + } + // Raw download dir + $raw_dir = $repo_dir; + if (strpos($repo_dir, ' ') !== false) { + $raw_dir = str_replace(' ', '%20', $repo_dir); + } - // Git urls - $repo_content = 'https://api.github.com/repos/' . $repo_owner . '/' . $repo_name . '/contents/' . $content_dir; - $repo_html = 'https://github.com/' . $repo_owner . '/' . $repo_name . '/' . $repo_dir . '/'; - $repo_raw = 'https://raw.githubusercontent.com/' . $repo_owner . '/' . $repo_name . '/' . $repo_branch . '/' . $raw_dir . '/'; - - // Git tree lookup - $tree = curl_get_contents($repo_content); - $leaf = json_decode($tree, true); - // Detect rate-limiting and die gracefully - if(is_array($leaf) && in_array('message', $leaf)) { - die('Failed to download repo index: ' . $leaf['message']); - } + // Git urls + $repo_content = 'https://api.github.com/repos/' . $repo_owner . '/' . $repo_name . '/contents/' . $content_dir; + $repo_html = 'https://github.com/' . $repo_owner . '/' . $repo_name . '/' . $repo_dir . '/'; + $repo_raw = 'https://raw.githubusercontent.com/' . $repo_owner . '/' . $repo_name . '/' . $repo_branch . '/' . $raw_dir . '/'; + + // Git tree lookup + $tree = curl_get_contents($repo_content); + $leaf = json_decode($tree, true); + // Detect rate-limiting and die gracefully + if(is_array($leaf) && in_array('message', $leaf)) { + die('Failed to download repo index: ' . $leaf['message']); + } - // Debug - //echo 'LEAF:' . PHP_EOL; - //print_r($leaf) . PHP_EOL; - - // Git tree lookup for repo dir - $content = ''; - $foldername = basename($repo_html); - echo 'Downloading each file from ' . $repo_html . PHP_EOL; - foreach ($leaf as $l) { - if($l['name'] == $foldername && $l['type'] == 'dir') { - $json = curl_get_contents($l['git_url']); - $content = json_decode($json, true); - break; - } + // Debug + //echo 'LEAF:' . PHP_EOL; + //print_r($leaf) . PHP_EOL; + + // Git tree lookup for repo dir + $content = ''; + $foldername = basename($repo_html); + echo 'Downloading each file from ' . $repo_html . PHP_EOL; + foreach ($leaf as $l) { + if($l['name'] == $foldername && $l['type'] == 'dir') { + $json = curl_get_contents($l['git_url']); + $content = json_decode($json, true); + break; } + } - // Download each file. - if(is_array($content)) { - $count_unchanged = 0; - $count_extension = 0; - $i = 0; - $successfull_count = 0; - $files_downloaded = 0; - $chunk_start = 0; - $multi_handle = curl_multi_init(); - $treecount = count($content['tree']); - // Divide downloadable content into chunks. Download 20 files at a time by default - if(isset($options['chunk']) && is_integer($options['chunk'])) $file_chunk = $options['chunk']; else $file_chunk = 20; - $chunk_end = floor($treecount/$file_chunk); - for( $p=$chunk_start; $p < $chunk_end; $p++ ) { - $file_pointers = []; - $curl_handles = []; - $output_info = []; - $start = $p*$file_chunk; - $handles = 0; - if( ($start+$file_chunk) > $treecount) $end = $treecount-$start; else $end = $start+$file_chunk; - for( $i=$start; $i < $end; $i++) { - $c = $content['tree'][$i]; - - // Filter by file extension - $ext = '.' . pathinfo($c['path'], PATHINFO_EXTENSION); - if($filter == $ext) { - // Only get files that don't exist or where the hash doesn't match - if(is_updated($dest . $c['path'], $c)) { - echo 'Downloading ' . $c['path'] . PHP_EOL; - $input = $repo_raw . $c['path']; - $output = $dest . $c['path']; - - $output_info[$handles] = ['file'=>$output, 'source_size'=>$c['size']]; - $curl_handles[$handles] = curl_init($input); - $file_pointers[$handles] = fopen($output, 'w'); - curl_setopt($curl_handles[$handles], CURLOPT_FILE, $file_pointers[$handles]); - curl_setopt($curl_handles[$handles], CURLOPT_HEADER, 0); - curl_setopt($curl_handles[$handles], CURLOPT_CONNECTTIMEOUT, 60); - curl_multi_add_handle($multi_handle,$curl_handles[$handles]); - $handles++; - } else { - $count_unchanged = $count_unchanged + 1; - // Debug - // echo 'Skipping file: ' . $c['path'] . " (File hasn't changed.)" . PHP_EOL; - } - } else { - $count_extension = $count_extension + 1; - // Debug - // echo 'Skipping file: ' . $c['path'] . ' (File extension filtering)' . PHP_EOL; - } - } - // Download the files - do { - curl_multi_exec($multi_handle,$running); - } while ($running > 0); - - for($o=0;$o<$handles;$o++) { - curl_multi_remove_handle($multi_handle, $curl_handles[$o]); - curl_close($curl_handles[$o]); - fclose ($file_pointers[$o]); - $files_downloaded++; - // Verify download - // File successfully created? - if(!is_file($output_info[$o]['file'])) { - echo 'Error downloading file, no output file was found: ' . $output_info[$o]['file'] . PHP_EOL; - } else { - $real_filesize = filesize($output_info[$o]['file']); - if ($real_filesize != $output_info[$o]['source_size']) { - echo "Error downloading file, size doesn't match (" . $real_filesize . " != " . $output_info[$o]['source_size'] . ")!" . PHP_EOL; - }else { - $successfull_count++; - } - } - } - } - echo $successfull_count . '/' . $files_downloaded . ' files downloaded successfully!' . PHP_EOL . PHP_EOL; - curl_multi_close($multi_handle); - // Unchanged files - if($count_unchanged > 0) { - echo 'Skipped ' . $count_unchanged . ' unchanged files' . PHP_EOL; - } - // Filtered files - if($count_extension > 0) { - echo 'Skipped ' . $count_extension . ' files due to wrong file extension'. PHP_EOL; - } - } else { - echo "Failed to download repo content!" . PHP_EOL; - echo "Repo content: " . $repo_content . PHP_EOL; + // Download each file. + if(!is_array($content)) { + echo "Failed to download repo content!" . PHP_EOL; + echo "Repo content: " . $repo_content . PHP_EOL; + continue; + } + $count_unchanged = $count_extension = $i = $successfull_count = $files_downloaded = $chunk_start = 0; + $multi_handle = curl_multi_init(); + $treecount = count($content['tree']); + // Divide downloadable content into chunks. Download 20 files at a time by default + if(isset($options['chunk']) && is_integer($options['chunk'])) $file_chunk = $options['chunk']; else $file_chunk = 20; + $chunk_end = floor($treecount/$file_chunk); + for( $p = $chunk_start; $p < $chunk_end; $p++ ) { + $file_pointers = $curl_handles = $output_info = []; + $start = $p*$file_chunk; + $handles = 0; + if( ($start+$file_chunk) > $treecount) $end = $treecount-$start; else $end = $start+$file_chunk; + for( $i = $start; $i < $end; $i++) { + $c = $content['tree'][$i]; + + // Filter by file extension + $ext = '.' . pathinfo($c['path'], PATHINFO_EXTENSION); + if($filter != $ext) { + $count_extension = $count_extension + 1; + // Debug + // echo 'Skipping file: ' . $c['path'] . ' (File extension filtering)' . PHP_EOL; + continue; + } + // Only get files that don't exist or where the hash doesn't match + if(!is_updated($dest . $c['path'], $c)) { + $count_unchanged = $count_unchanged + 1; + // Debug + // echo 'Skipping file: ' . $c['path'] . " (File hasn't changed.)" . PHP_EOL; + continue; + } + echo 'Downloading ' . $c['path'] . PHP_EOL; + $input = $repo_raw . $c['path']; + $output = $dest . $c['path']; + + $output_info[$handles] = ['file'=>$output, 'source_size'=>$c['size']]; + $curl_handles[$handles] = curl_init($input); + $file_pointers[$handles] = fopen($output, 'w'); + curl_setopt($curl_handles[$handles], CURLOPT_FILE, $file_pointers[$handles]); + curl_setopt($curl_handles[$handles], CURLOPT_HEADER, 0); + curl_setopt($curl_handles[$handles], CURLOPT_CONNECTTIMEOUT, 60); + curl_multi_add_handle($multi_handle,$curl_handles[$handles]); + $handles++; } + // Download the files + do { + curl_multi_exec($multi_handle,$running); + } while ($running > 0); + + for($o=0;$o<$handles;$o++) { + curl_multi_remove_handle($multi_handle, $curl_handles[$o]); + curl_close($curl_handles[$o]); + fclose ($file_pointers[$o]); + $files_downloaded++; + // Verify download + // File successfully created? + if(!is_file($output_info[$o]['file'])) { + echo 'Error downloading file, no output file was found: ' . $output_info[$o]['file'] . PHP_EOL; + continue; + } + $real_filesize = filesize($output_info[$o]['file']); + if ($real_filesize != $output_info[$o]['source_size']) { + echo "Error downloading file, size doesn't match (" . $real_filesize . " != " . $output_info[$o]['source_size'] . ")!" . PHP_EOL; + continue; + } + $successfull_count++; + } + } + echo $successfull_count . '/' . $files_downloaded . ' files downloaded successfully!' . PHP_EOL . PHP_EOL; + curl_multi_close($multi_handle); + // Unchanged files + if($count_unchanged > 0) { + echo 'Skipped ' . $count_unchanged . ' unchanged files' . PHP_EOL; + } + // Filtered files + if($count_extension > 0) { + echo 'Skipped ' . $count_extension . ' files due to wrong file extension'. PHP_EOL; + } } echo "Finished pokemon image refresh." . PHP_EOL; -?> diff --git a/getTranslations.php b/getTranslations.php index e5f77abf..5c340fa2 100644 --- a/getTranslations.php +++ b/getTranslations.php @@ -1,29 +1,31 @@ ["PT-BR"], - "English" => ["EN"], - "French" => ["FR"], - "German" => ["DE"], - "Italian" => ["IT"], - "Russian" => ["RU"], - "Spanish" => ["ES"], - ]; + 'BrazilianPortuguese' => ['PT-BR'], + 'English' => ['EN'], + 'French' => ['FR'], + 'German' => ['DE'], + 'Italian' => ['IT'], + 'Russian' => ['RU'], + 'Spanish' => ['ES'], +]; $move_translations_to_fetch = [ - "BrazilianPortuguese" => ["PT-BR"], - "English" => ["EN", "FI", "NL", "NO", "PL"], - "French" => ["FR"], - "German" => ["DE"], - "Italian" => ["IT"], - "Russian" => ["RU"], - "Spanish" => ["ES"], - ]; + 'BrazilianPortuguese' => ['PT-BR'], + 'English' => ['EN', 'FI', 'NL', 'NO', 'PL'], + 'French' => ['FR'], + 'German' => ['DE'], + 'Italian' => ['IT'], + 'Russian' => ['RU'], + 'Spanish' => ['ES'], +]; // Initialize array $move_array = []; @@ -31,51 +33,54 @@ // Loop through all available translations foreach($translations_available as $language) { - $write_pokemon_translation = array_key_exists($language, $pokemon_translations_to_fetch); - $write_move_translation = array_key_exists($language, $move_translations_to_fetch); + $write_pokemon_translation = array_key_exists($language, $pokemon_translations_to_fetch); + $write_move_translation = array_key_exists($language, $move_translations_to_fetch); - // Only read the file if a translation is wanted - if( $write_pokemon_translation || $write_move_translation ) { - // Open the file(s) and write it into an array - foreach($lang_directory_url as $url) { - $file = curl_open_file($url . $language . '.txt'); - $data = explode("\n", $file); + // Only read the file if a translation is wanted + if( !$write_pokemon_translation && !$write_move_translation ) { + continue; + } + // Open the file(s) and write it into an array + foreach($lang_directory_url as $url) { + $file = curl_open_file($url . $language . '.txt'); + $data = preg_split('/\r\n|\r|\n/', $file); - // Read the file line by line - foreach($data as $row) { - // Handle resource ID rows - if(substr($row, 0, 1) == 'R') { - $resource_id = substr(trim($row), 13); - $resource_part = explode("_",$resource_id); - } - // Handle text rows - if(substr($row, 0, 1) == 'T') { - $text = substr(trim($row), 6); + // Read the file line by line + foreach($data as $row) { + // Handle resource ID rows + if(substr($row, 0, 1) == 'R') { + $resource_id = substr(trim($row), 13); + $resource_part = explode('_',$resource_id); + } + // Handle text rows + if(substr($row, 0, 1) == 'T') { + $text = substr(trim($row), 6); - // Filter out mega translations - if(count($resource_part) == 3 && $resource_part[1] == 'name') { - $id = intval($resource_part[2]); // remove leading zeroes - // Save pokemon names into an array if pokemon id is larger than 0 - if($write_pokemon_translation && $resource_part[0] == 'pokemon' && $id > 0) { - foreach($pokemon_translations_to_fetch[$language] as $lan) { - $pokemon_array['pokemon_id_'.$id][$lan] = $text; - } - // Save pokemon moves into an array - }elseif($write_move_translation && $resource_part[0] == 'move') { - foreach($move_translations_to_fetch[$language] as $lan) { - $move_array['pokemon_move_'.$id][$lan] = $text; - } - } - } - } - } - unset($file); - unset($data); + // Filter out mega translations + if(count($resource_part) != 3 || $resource_part[1] != 'name') { + continue; } + $id = intval($resource_part[2]); // remove leading zeroes + // Save pokemon names into an array if pokemon id is larger than 0 + if($write_pokemon_translation && $resource_part[0] == 'pokemon' && $id > 0) { + foreach($pokemon_translations_to_fetch[$language] as $lan) { + $pokemon_array['pokemon_id_'.$id][$lan] = $text; + } + // Save pokemon moves into an array + }elseif($write_move_translation && $resource_part[0] == 'move') { + foreach($move_translations_to_fetch[$language] as $lan) { + $move_array['pokemon_move_'.$id][$lan] = $text; + } + } + } } + unset($file); + unset($data); + } } // Bot defaults to using english translations, so no need to add duplicates for every language $pokemon_array = remove_duplicate_translations($pokemon_array); +$move_array = remove_duplicate_translations($move_array); // Build the path to move translation file $moves_translation_file = $lang_dir . 'pokemon_moves.json'; @@ -90,22 +95,21 @@ file_put_contents($pokemon_translation_file, json_encode($pokemon_array,JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX); function curl_open_file($input) { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $input); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - $data = curl_exec($ch); - curl_close ($ch); - return $data; + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $input); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $data = curl_exec($ch); + curl_close ($ch); + return $data; } function remove_duplicate_translations($array) { - $new_array = []; - foreach($array as $translation_id => $translations) { - foreach($translations as $lang => $translation) { - if($lang == 'EN' or $translation != $array[$translation_id]['EN']) - $new_array[$translation_id][$lang] = $translation; - } + $new_array = []; + foreach($array as $translation_id => $translations) { + foreach($translations as $lang => $translation) { + if($lang == 'EN' or $translation != $array[$translation_id]['EN']) + $new_array[$translation_id][$lang] = $translation; } - return $new_array; + } + return $new_array; } -?> \ No newline at end of file diff --git a/index.php b/index.php index dda9f0ac..81d8cb8f 100644 --- a/index.php +++ b/index.php @@ -22,121 +22,124 @@ if (isset($raid['type']) && $raid['type'] == 'raid') { // Create raid(s) and exit. include_once(ROOT_PATH . '/commands/raid_from_webhook.php'); - $dbh = null; exit(); } } } + +$update['type'] = NULL; +if(isset($update['message'])) { + $update['type'] = 'message'; +} else if(isset($update['callback_query'])) { + $update['type'] = 'callback_query'; +} else if(isset($update['inline_query'])) { + $update['type'] = 'inline_query'; +} else if(isset($update['channel_post'])) { + $update['type'] = 'channel_post'; +} + // Init empty data array. $data = []; // Callback data found. if (isset($update['callback_query']['data'])) { - // Bridge mode? - if($config->BRIDGE_MODE) { - // Split bot folder name away from actual data. - $botnameData = explode(':', $update['callback_query']['data'], 2); - $botname = $botnameData[0]; - $thedata = $botnameData[1]; - // Write to log - debug_log('Bot Name: ' . $botname); - debug_log('The Data: ' . $thedata); - $botname_length = count(str_split($botname)); - if($botname_length > 8) { - info_log("ERROR! Botname '" . $botname . "' is too long, max: 8","!"); - exit(); - } - } else { - // Data is just the data. - $thedata = $update['callback_query']['data']; + $thedata = $update['callback_query']['data']; + $splitDataOld = explode(':', $thedata); + // Split callback data and assign to data array. + if(count($splitDataOld) > 2) { + $data['id'] = $splitDataOld[0]; + $data['callbackAction'] = $splitDataOld[1]; + $data['arg'] = $splitDataOld[2]; + }else { + $splitData = explode('|', $thedata); + $data['callbackAction'] = $splitData[0]; + unset($splitData[0]); + $data = []; + foreach($splitData as $dataPiece) { + [$key, $value] = explode('=', $dataPiece, 2); + $data[$key] = $value; } - // Split callback data and assign to data array. - $splitData = explode(':', $thedata); - $data['id'] = $splitData[0]; - $data['action'] = $splitData[1]; - $data['arg'] = $splitData[2]; + } } // Run cleanup if requested if (isset($update['cleanup'])) { include_once(CORE_BOT_PATH . '/cleanup_run.php'); cleanup_auth_and_run($update); + exit; } // DDOS protection if($config->ENABLE_DDOS_PROTECTION) { - include_once(CORE_BOT_PATH . '/ddos.php'); + include_once(CORE_BOT_PATH . '/ddos.php'); } +if(isset($update[$update['type']]['from'])) { // Update the user -$botUser->updateUser($update); + $botUser->updateUser($update); -// Get language -$botUser->defineUserLanguage($update); + // Get language + $botUser->defineUserLanguage($update); -$botUser->privilegeCheck($update); + $botUser->privilegeCheck($update); +} // Callback query received. if (isset($update['callback_query'])) { - // Logic to get the module - include_once(CORE_BOT_PATH . '/modules.php'); + // Logic to get the module + include_once(CORE_BOT_PATH . '/modules.php'); // Inline query received. } else if (isset($update['inline_query'])) { - // List quests and exit. - raid_list($update); - $dbh = null; - exit(); + include_once(LOGIC_PATH . '/raid_list.php'); + // List raids and exit. + raid_list($update); + exit(); // Location received. } else if (isset($update['message']['location']) && $update['message']['chat']['type'] == 'private') { - if($config->RAID_VIA_LOCATION_FUNCTION == 'list') { - include_once(ROOT_PATH . '/mods/share_raid_by_location.php'); - }else { - // Create raid and exit. - include_once(ROOT_PATH . '/mods/raid_by_location.php'); - } - $dbh = null; - exit(); + if($config->RAID_VIA_LOCATION_FUNCTION == 'list') { + include_once(ROOT_PATH . '/mods/share_raid_by_location.php'); + }else { + // Create raid and exit. + include_once(ROOT_PATH . '/mods/raid_by_location.php'); + } + exit(); // Cleanup collection from channel/supergroup messages. -} else if ((isset($update['channel_post']) && $update['channel_post']['chat']['type'] == "channel") || (isset($update['message']) && $update['message']['chat']['type'] == "supergroup")) { - // Collect cleanup information - include_once(CORE_BOT_PATH . '/cleanup_collect.php'); +} else if (isset($update[$update['type']]) && in_array($update[$update['type']]['chat']['type'], ['channel', 'supergroup'])) { + // Collect cleanup information + include_once(CORE_BOT_PATH . '/cleanup_collect.php'); // Message is required to check for commands. -} else if (isset($update['message']) && ($update['message']['chat']['type'] == 'private' || $update['message']['chat']['type'] == 'channel')) { - // Portal message? - if(isset($update['message']['entities']['1']['type']) && $update['message']['entities']['1']['type'] == 'text_link' && strpos($update['message']['entities']['1']['url'], 'https://intel.ingress.com/intel?ll=') === 0) { - // Import portal. - include_once(ROOT_PATH . '/mods/importal.php'); - } else { - // Check if user is expected to be posting something we want to save to db - if($update['message']['chat']['type'] == 'private') { - $q = my_query("SELECT id, handler, modifiers FROM user_input WHERE user_id='{$update['message']['from']['id']}' LIMIT 1"); - if( $q->rowCount() > 0 ) { - debug_log("Expecting a response message from user: " . $update['message']['from']['id']); - $res = $q->fetch(); - // Modifiers to pass to handler - $modifiers = json_decode($res['modifiers'], true); - - debug_log("Calling: " . $res['handler'] . '.php'); - debug_log("With modifiers: " . $res['modifiers']); - include_once(ROOT_PATH . '/mods/' . $res['handler'] . '.php'); - - debug_log("Response handeled successfully!"); - // Delete the entry if the call was handled without errors - my_query("DELETE FROM user_input WHERE id='{$res['id']}'"); - - $dbh = null; - exit(); - } - } - - // Logic to get the command - include_once(CORE_BOT_PATH . '/commands.php'); +} else if (isset($update['message']) && $update['message']['chat']['type'] == 'private') { + // Portal message? + if(isset($update['message']['entities']['1']['type']) && $update['message']['entities']['1']['type'] == 'text_link' && strpos($update['message']['entities']['1']['url'], 'https://intel.ingress.com/intel?ll=') === 0) { + // Import portal. + include_once(ROOT_PATH . '/mods/importal.php'); + exit; + } + // Check if user is expected to be posting something we want to save to db + if($update['message']['chat']['type'] == 'private') { + $q = my_query('SELECT id, handler, modifiers FROM user_input WHERE user_id = ? LIMIT 1', [$update['message']['from']['id']]); + if( $q->rowCount() > 0 ) { + debug_log('Expecting a response message from user: ' . $update['message']['from']['id']); + $res = $q->fetch(); + // Modifiers to pass to handler + $modifiers = json_decode($res['modifiers'], true); + + debug_log('Calling: ' . $res['handler'] . '.php'); + debug_log('With modifiers: ' . $res['modifiers']); + include_once(ROOT_PATH . '/mods/' . $res['handler'] . '.php'); + + debug_log('Response handeled successfully!'); + // Delete the entry if the call was handled without errors + my_query('DELETE FROM user_input WHERE id = ?', [$res['id']]); + + exit(); } -} + } -$dbh = null; -?> + // Logic to get the command + include_once(CORE_BOT_PATH . '/commands.php'); +} diff --git a/lang/language.json b/lang/language.json index abc17c92..9777b3c0 100644 --- a/lang/language.json +++ b/lang/language.json @@ -2677,19 +2677,6 @@ "FI": "Virhe! Anna koordinaatit muotossa Leveysaste,Pituusaste lisätäksesi uuden salin!", "ES": "¡Error! ¡Envía las coordenadas en el formato latitud,longitud para agregar un nuevo gimnasio!" }, - "gym_coordinates_format_example": { - "NL": "Als voorbeeld: /addgym 51.516263,4.377755", - "DE": "Zum Beispiel: /addgym 52.516263,13.377755", - "EN": "For example: /addgym 52.516263,13.377755", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Esimerkiksi: /addgym 52.516263,13.377755", - "ES": "Por ejemplo: /addgym 52.516263,13.377755" - }, "gym_gps_coordinates_format_error": { "NL": "Error! Stuur de coordinaten in het volgende formaat: Latitude,Longitude", "DE": "Fehler! Bitte übermittle die Koordinaten im folgenden Format: Breitengrad,Längengrad", @@ -3900,30 +3887,30 @@ "ES": "Para obtener la identificación y más detalles del gimnasio, usa el comando /gym." }, "gym_name_example": { - "NL": "Als voorbeeld: /gymname 34, Markt 61, 3131 CR Vlaardingen ", - "DE": "Zum Beispiel: /gymname 34, Wasserfall im Park", - "EN": "For example: /gymname 34, Waterfall in the park!", + "NL": "Als voorbeeld: /gymname Markt 61, 3131 CR Vlaardingen ", + "DE": "Zum Beispiel: /gymname Wasserfall im Park", + "EN": "For example: /gymname Waterfall in the park!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Esimerkiksi: /gymname 34, Vapauden Muistomerkki!", - "ES": "Por ejemplo: /gymname 34, Waterfall in the park" + "FI": "Esimerkiksi: /gymname Vapauden Muistomerkki!", + "ES": "Por ejemplo: /gymname Waterfall in the park" }, "gym_id_name_missing": { - "NL": "Error! Gym id of naam mist!", - "DE": "Fehler! Arena-ID oder Name fehlt!", - "EN": "Error! Gym id or name is missing!", + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Error! Gym name is missing!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Virhe! Salin id numero tai nimi puuttuu!", - "ES": "¡Error! ¡Faltan gym id o nombre!" + "FI": "Virhe! Salin nimi puuttuu!", + "ES": "TRANSLATE" }, "gym_name_updated": { "NL": "Gym naam aangepast.", diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index cc69948a..7074c55a 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -2,10 +2,6 @@ "pokemon_move_1": { "PT-BR": "Trovoada de Choques", "EN": "Thunder Shock", - "FI": "Thunder Shock", - "NL": "Thunder Shock", - "NO": "Thunder Shock", - "PL": "Thunder Shock", "FR": "Éclair", "DE": "Donnerschock", "IT": "Tuonoshock", @@ -15,10 +11,6 @@ "pokemon_move_2": { "PT-BR": "Ataque Rápido", "EN": "Quick Attack", - "FI": "Quick Attack", - "NL": "Quick Attack", - "NO": "Quick Attack", - "PL": "Quick Attack", "FR": "Vive-Attaque", "DE": "Ruckzuckhieb", "IT": "Attacco Rapido", @@ -28,10 +20,6 @@ "pokemon_move_3": { "PT-BR": "Arranhão", "EN": "Scratch", - "FI": "Scratch", - "NL": "Scratch", - "NO": "Scratch", - "PL": "Scratch", "FR": "Griffe", "DE": "Kratzer", "IT": "Graffio", @@ -41,10 +29,6 @@ "pokemon_move_4": { "PT-BR": "Brasa", "EN": "Ember", - "FI": "Ember", - "NL": "Ember", - "NO": "Ember", - "PL": "Ember", "FR": "Flammèche", "DE": "Glut", "IT": "Braciere", @@ -54,10 +38,6 @@ "pokemon_move_5": { "PT-BR": "Chicote de Vinha", "EN": "Vine Whip", - "FI": "Vine Whip", - "NL": "Vine Whip", - "NO": "Vine Whip", - "PL": "Vine Whip", "FR": "Fouet Lianes", "DE": "Rankenhieb", "IT": "Frustata", @@ -67,12 +47,7 @@ "pokemon_move_6": { "PT-BR": "Investida", "EN": "Tackle", - "FI": "Tackle", - "NL": "Tackle", - "NO": "Tackle", - "PL": "Tackle", "FR": "Charge", - "DE": "Tackle", "IT": "Azione", "RU": "Бросок", "ES": "Placaje" @@ -80,10 +55,6 @@ "pokemon_move_7": { "PT-BR": "Folha Navalha", "EN": "Razor Leaf", - "FI": "Razor Leaf", - "NL": "Razor Leaf", - "NO": "Razor Leaf", - "PL": "Razor Leaf", "FR": "Tranch’Herbe", "DE": "Rasierblatt", "IT": "Foglielama", @@ -93,10 +64,6 @@ "pokemon_move_8": { "PT-BR": "Desmantelar", "EN": "Take Down", - "FI": "Take Down", - "NL": "Take Down", - "NO": "Take Down", - "PL": "Take Down", "FR": "Bélier", "DE": "Bodycheck", "IT": "Riduttore", @@ -106,10 +73,6 @@ "pokemon_move_9": { "PT-BR": "Revólver d'Água", "EN": "Water Gun", - "FI": "Water Gun", - "NL": "Water Gun", - "NO": "Water Gun", - "PL": "Water Gun", "FR": "Pistolet à O", "DE": "Aquaknarre", "IT": "Pistolacqua", @@ -119,10 +82,6 @@ "pokemon_move_10": { "PT-BR": "Mordida", "EN": "Bite", - "FI": "Bite", - "NL": "Bite", - "NO": "Bite", - "PL": "Bite", "FR": "Morsure", "DE": "Biss", "IT": "Morso", @@ -132,10 +91,6 @@ "pokemon_move_11": { "PT-BR": "Pancada", "EN": "Pound", - "FI": "Pound", - "NL": "Pound", - "NO": "Pound", - "PL": "Pound", "FR": "Écras’Face", "DE": "Klaps", "IT": "Botta", @@ -145,10 +100,6 @@ "pokemon_move_12": { "PT-BR": "Tapa Duplo", "EN": "Double Slap", - "FI": "Double Slap", - "NL": "Double Slap", - "NO": "Double Slap", - "PL": "Double Slap", "FR": "Torgnoles", "DE": "Duplexhieb", "IT": "Doppiasberla", @@ -158,10 +109,6 @@ "pokemon_move_13": { "PT-BR": "Embrulho", "EN": "Wrap", - "FI": "Wrap", - "NL": "Wrap", - "NO": "Wrap", - "PL": "Wrap", "FR": "Ligotage", "DE": "Wickel", "IT": "Avvolgibotta", @@ -171,10 +118,6 @@ "pokemon_move_14": { "PT-BR": "Hiper-raio", "EN": "Hyper Beam", - "FI": "Hyper Beam", - "NL": "Hyper Beam", - "NO": "Hyper Beam", - "PL": "Hyper Beam", "FR": "Ultralaser", "DE": "Hyperstrahl", "IT": "Iper Raggio", @@ -184,10 +127,6 @@ "pokemon_move_15": { "PT-BR": "Lambida", "EN": "Lick", - "FI": "Lick", - "NL": "Lick", - "NO": "Lick", - "PL": "Lick", "FR": "Léchouille", "DE": "Schlecker", "IT": "Leccata", @@ -197,10 +136,6 @@ "pokemon_move_16": { "PT-BR": "Pulso Sombrio", "EN": "Dark Pulse", - "FI": "Dark Pulse", - "NL": "Dark Pulse", - "NO": "Dark Pulse", - "PL": "Dark Pulse", "FR": "Vibrobscur", "DE": "Finsteraura", "IT": "Neropulsar", @@ -210,23 +145,13 @@ "pokemon_move_17": { "PT-BR": "Nevoeiro de Fumaça", "EN": "Smog", - "FI": "Smog", - "NL": "Smog", - "NO": "Smog", - "PL": "Smog", "FR": "Purédpois", - "DE": "Smog", - "IT": "Smog", "RU": "Дым", "ES": "Polución" }, "pokemon_move_18": { "PT-BR": "Ataque de Lama", "EN": "Sludge", - "FI": "Sludge", - "NL": "Sludge", - "NO": "Sludge", - "PL": "Sludge", "FR": "Détritus", "DE": "Schlammbad", "IT": "Fango", @@ -236,10 +161,6 @@ "pokemon_move_19": { "PT-BR": "Garra de Metal", "EN": "Metal Claw", - "FI": "Metal Claw", - "NL": "Metal Claw", - "NO": "Metal Claw", - "PL": "Metal Claw", "FR": "Griffe Acier", "DE": "Metallklaue", "IT": "Ferrartigli", @@ -249,10 +170,6 @@ "pokemon_move_20": { "PT-BR": "Agarramento Compressor", "EN": "Vise Grip", - "FI": "Vise Grip", - "NL": "Vise Grip", - "NO": "Vise Grip", - "PL": "Vise Grip", "FR": "Force Poigne", "DE": "Klammer", "IT": "Presa", @@ -262,10 +179,6 @@ "pokemon_move_21": { "PT-BR": "Roda de Fogo", "EN": "Flame Wheel", - "FI": "Flame Wheel", - "NL": "Flame Wheel", - "NO": "Flame Wheel", - "PL": "Flame Wheel", "FR": "Roue de Feu", "DE": "Flammenrad", "IT": "Ruotafuoco", @@ -275,10 +188,6 @@ "pokemon_move_22": { "PT-BR": "Megachifre", "EN": "Megahorn", - "FI": "Megahorn", - "NL": "Megahorn", - "NO": "Megahorn", - "PL": "Megahorn", "FR": "Mégacorne", "DE": "Vielender", "IT": "Megacorno", @@ -288,10 +197,6 @@ "pokemon_move_23": { "PT-BR": "Ataque de Asa", "EN": "Wing Attack", - "FI": "Wing Attack", - "NL": "Wing Attack", - "NO": "Wing Attack", - "PL": "Wing Attack", "FR": "Cru-Ailes", "DE": "Flügelschlag", "IT": "Attacco d’Ala", @@ -301,10 +206,6 @@ "pokemon_move_24": { "PT-BR": "Lança-chamas", "EN": "Flamethrower", - "FI": "Flamethrower", - "NL": "Flamethrower", - "NO": "Flamethrower", - "PL": "Flamethrower", "FR": "Lance-Flammes", "DE": "Flammenwurf", "IT": "Lanciafiamme", @@ -314,10 +215,6 @@ "pokemon_move_25": { "PT-BR": "Soco Enganador", "EN": "Sucker Punch", - "FI": "Sucker Punch", - "NL": "Sucker Punch", - "NO": "Sucker Punch", - "PL": "Sucker Punch", "FR": "Coup Bas", "DE": "Tiefschlag", "IT": "Sbigoattacco", @@ -327,10 +224,6 @@ "pokemon_move_26": { "PT-BR": "Cavar", "EN": "Dig", - "FI": "Dig", - "NL": "Dig", - "NO": "Dig", - "PL": "Dig", "FR": "Tunnel", "DE": "Schaufler", "IT": "Fossa", @@ -340,10 +233,6 @@ "pokemon_move_27": { "PT-BR": "Rasteira", "EN": "Low Kick", - "FI": "Low Kick", - "NL": "Low Kick", - "NO": "Low Kick", - "PL": "Low Kick", "FR": "Balayage", "DE": "Fußkick", "IT": "Colpo Basso", @@ -353,10 +242,6 @@ "pokemon_move_28": { "PT-BR": "Golpe Cruzado", "EN": "Cross Chop", - "FI": "Cross Chop", - "NL": "Cross Chop", - "NO": "Cross Chop", - "PL": "Cross Chop", "FR": "Coup Croix", "DE": "Kreuzhieb", "IT": "Incrocolpo", @@ -366,10 +251,6 @@ "pokemon_move_29": { "PT-BR": "Corte Psíquico", "EN": "Psycho Cut", - "FI": "Psycho Cut", - "NL": "Psycho Cut", - "NO": "Psycho Cut", - "PL": "Psycho Cut", "FR": "Coupe Psycho", "DE": "Psychoklinge", "IT": "Psicotaglio", @@ -379,10 +260,6 @@ "pokemon_move_30": { "PT-BR": "Feixe Psíquico", "EN": "Psybeam", - "FI": "Psybeam", - "NL": "Psybeam", - "NO": "Psybeam", - "PL": "Psybeam", "FR": "Rafale Psy", "DE": "Psystrahl", "IT": "Psicoraggio", @@ -392,10 +269,6 @@ "pokemon_move_31": { "PT-BR": "Terremoto", "EN": "Earthquake", - "FI": "Earthquake", - "NL": "Earthquake", - "NO": "Earthquake", - "PL": "Earthquake", "FR": "Séisme", "DE": "Erdbeben", "IT": "Terremoto", @@ -405,10 +278,6 @@ "pokemon_move_32": { "PT-BR": "Gume de Pedra", "EN": "Stone Edge", - "FI": "Stone Edge", - "NL": "Stone Edge", - "NO": "Stone Edge", - "PL": "Stone Edge", "FR": "Lame de Roc", "DE": "Steinkante", "IT": "Pietrataglio", @@ -418,10 +287,6 @@ "pokemon_move_33": { "PT-BR": "Soco de Gelo", "EN": "Ice Punch", - "FI": "Ice Punch", - "NL": "Ice Punch", - "NO": "Ice Punch", - "PL": "Ice Punch", "FR": "Poing Glace", "DE": "Eishieb", "IT": "Gelopugno", @@ -431,10 +296,6 @@ "pokemon_move_34": { "PT-BR": "Estampa de Coração", "EN": "Heart Stamp", - "FI": "Heart Stamp", - "NL": "Heart Stamp", - "NO": "Heart Stamp", - "PL": "Heart Stamp", "FR": "Crève-Cœur", "DE": "Herzstempel", "IT": "Cuorestampo", @@ -444,10 +305,6 @@ "pokemon_move_35": { "PT-BR": "Descarga", "EN": "Discharge", - "FI": "Discharge", - "NL": "Discharge", - "NO": "Discharge", - "PL": "Discharge", "FR": "Coup d’Jus", "DE": "Ladungsstoß", "IT": "Scarica", @@ -457,10 +314,6 @@ "pokemon_move_36": { "PT-BR": "Canhão de Flash", "EN": "Flash Cannon", - "FI": "Flash Cannon", - "NL": "Flash Cannon", - "NO": "Flash Cannon", - "PL": "Flash Cannon", "FR": "Luminocanon", "DE": "Lichtkanone", "IT": "Cannonflash", @@ -470,10 +323,6 @@ "pokemon_move_37": { "PT-BR": "Bicada", "EN": "Peck", - "FI": "Peck", - "NL": "Peck", - "NO": "Peck", - "PL": "Peck", "FR": "Picpic", "DE": "Pikser", "IT": "Beccata", @@ -483,10 +332,6 @@ "pokemon_move_38": { "PT-BR": "Bico Broca", "EN": "Drill Peck", - "FI": "Drill Peck", - "NL": "Drill Peck", - "NO": "Drill Peck", - "PL": "Drill Peck", "FR": "Bec Vrille", "DE": "Bohrschnabel", "IT": "Perforbecco", @@ -496,10 +341,6 @@ "pokemon_move_39": { "PT-BR": "Raio Congelante", "EN": "Ice Beam", - "FI": "Ice Beam", - "NL": "Ice Beam", - "NO": "Ice Beam", - "PL": "Ice Beam", "FR": "Laser Glace", "DE": "Eisstrahl", "IT": "Geloraggio", @@ -509,12 +350,6 @@ "pokemon_move_40": { "PT-BR": "Nevasca", "EN": "Blizzard", - "FI": "Blizzard", - "NL": "Blizzard", - "NO": "Blizzard", - "PL": "Blizzard", - "FR": "Blizzard", - "DE": "Blizzard", "IT": "Bora", "RU": "Метель", "ES": "Ventisca" @@ -522,10 +357,6 @@ "pokemon_move_41": { "PT-BR": "Golpe de Ar", "EN": "Air Slash", - "FI": "Air Slash", - "NL": "Air Slash", - "NO": "Air Slash", - "PL": "Air Slash", "FR": "Lame d’Air", "DE": "Luftschnitt", "IT": "Eterelama", @@ -535,10 +366,6 @@ "pokemon_move_42": { "PT-BR": "Onda de Calor", "EN": "Heat Wave", - "FI": "Heat Wave", - "NL": "Heat Wave", - "NO": "Heat Wave", - "PL": "Heat Wave", "FR": "Canicule", "DE": "Hitzewelle", "IT": "Ondacalda", @@ -548,10 +375,6 @@ "pokemon_move_43": { "PT-BR": "Agulha Dupla", "EN": "Twineedle", - "FI": "Twineedle", - "NL": "Twineedle", - "NO": "Twineedle", - "PL": "Twineedle", "FR": "Double Dard", "DE": "Duonadel", "IT": "Doppio Ago", @@ -561,10 +384,6 @@ "pokemon_move_44": { "PT-BR": "Golpe Envenenado", "EN": "Poison Jab", - "FI": "Poison Jab", - "NL": "Poison Jab", - "NO": "Poison Jab", - "PL": "Poison Jab", "FR": "Direct Toxik", "DE": "Gifthieb", "IT": "Velenpuntura", @@ -574,10 +393,6 @@ "pokemon_move_45": { "PT-BR": "Ás dos Ares", "EN": "Aerial Ace", - "FI": "Aerial Ace", - "NL": "Aerial Ace", - "NO": "Aerial Ace", - "PL": "Aerial Ace", "FR": "Aéropique", "DE": "Aero-Ass", "IT": "Aeroassalto", @@ -587,10 +402,6 @@ "pokemon_move_46": { "PT-BR": "Furação", "EN": "Drill Run", - "FI": "Drill Run", - "NL": "Drill Run", - "NO": "Drill Run", - "PL": "Drill Run", "FR": "Tunnelier", "DE": "Schlagbohrer", "IT": "Giravvita", @@ -600,10 +411,6 @@ "pokemon_move_47": { "PT-BR": "Nevasca de Pétalas", "EN": "Petal Blizzard", - "FI": "Petal Blizzard", - "NL": "Petal Blizzard", - "NO": "Petal Blizzard", - "PL": "Petal Blizzard", "FR": "Tempête Florale", "DE": "Blütenwirbel", "IT": "Fiortempesta", @@ -613,10 +420,6 @@ "pokemon_move_48": { "PT-BR": "Megadreno", "EN": "Mega Drain", - "FI": "Mega Drain", - "NL": "Mega Drain", - "NO": "Mega Drain", - "PL": "Mega Drain", "FR": "Méga-Sangsue", "DE": "Megasauger", "IT": "Megassorbimento", @@ -626,10 +429,6 @@ "pokemon_move_49": { "PT-BR": "Zumbido de Inseto", "EN": "Bug Buzz", - "FI": "Bug Buzz", - "NL": "Bug Buzz", - "NO": "Bug Buzz", - "PL": "Bug Buzz", "FR": "Bourdon", "DE": "Käfergebrumm", "IT": "Ronzio", @@ -639,10 +438,6 @@ "pokemon_move_50": { "PT-BR": "Presa Venenosa", "EN": "Poison Fang", - "FI": "Poison Fang", - "NL": "Poison Fang", - "NO": "Poison Fang", - "PL": "Poison Fang", "FR": "Crochet Venin", "DE": "Giftzahn", "IT": "Velenodenti", @@ -652,10 +447,6 @@ "pokemon_move_51": { "PT-BR": "Talho Noturno", "EN": "Night Slash", - "FI": "Night Slash", - "NL": "Night Slash", - "NO": "Night Slash", - "PL": "Night Slash", "FR": "Tranche-Nuit", "DE": "Nachthieb", "IT": "Nottesferza", @@ -665,10 +456,6 @@ "pokemon_move_52": { "PT-BR": "Talho", "EN": "Slash", - "FI": "Slash", - "NL": "Slash", - "NO": "Slash", - "PL": "Slash", "FR": "Tranche", "DE": "Schlitzer", "IT": "Lacerazione", @@ -678,10 +465,6 @@ "pokemon_move_53": { "PT-BR": "Jato de Bolhas", "EN": "Bubble Beam", - "FI": "Bubble Beam", - "NL": "Bubble Beam", - "NO": "Bubble Beam", - "PL": "Bubble Beam", "FR": "Bulles d’O", "DE": "Blubbstrahl", "IT": "Bollaraggio", @@ -691,10 +474,6 @@ "pokemon_move_54": { "PT-BR": "Submissão", "EN": "Submission", - "FI": "Submission", - "NL": "Submission", - "NO": "Submission", - "PL": "Submission", "FR": "Sacrifice", "DE": "Überroller", "IT": "Sottomissione", @@ -704,10 +483,6 @@ "pokemon_move_55": { "PT-BR": "Golpe de Caratê", "EN": "Karate Chop", - "FI": "Karate Chop", - "NL": "Karate Chop", - "NO": "Karate Chop", - "PL": "Karate Chop", "FR": "Poing Karaté", "DE": "Karateschlag", "IT": "Colpokarate", @@ -717,10 +492,6 @@ "pokemon_move_56": { "PT-BR": "Movimento Baixo", "EN": "Low Sweep", - "FI": "Low Sweep", - "NL": "Low Sweep", - "NO": "Low Sweep", - "PL": "Low Sweep", "FR": "Balayette", "DE": "Fußtritt", "IT": "Calciobasso", @@ -730,10 +501,6 @@ "pokemon_move_57": { "PT-BR": "Aqua Jato", "EN": "Aqua Jet", - "FI": "Aqua Jet", - "NL": "Aqua Jet", - "NO": "Aqua Jet", - "PL": "Aqua Jet", "FR": "Aqua-Jet", "DE": "Wasserdüse", "IT": "Acquagetto", @@ -743,10 +510,6 @@ "pokemon_move_58": { "PT-BR": "Aqua Cauda", "EN": "Aqua Tail", - "FI": "Aqua Tail", - "NL": "Aqua Tail", - "NO": "Aqua Tail", - "PL": "Aqua Tail", "FR": "Hydro-Queue", "DE": "Nassschweif", "IT": "Idrondata", @@ -756,10 +519,6 @@ "pokemon_move_59": { "PT-BR": "Bomba de Sementes", "EN": "Seed Bomb", - "FI": "Seed Bomb", - "NL": "Seed Bomb", - "NO": "Seed Bomb", - "PL": "Seed Bomb", "FR": "Canon Graine", "DE": "Samenbomben", "IT": "Semebomba", @@ -769,10 +528,6 @@ "pokemon_move_60": { "PT-BR": "Choque Psíquico", "EN": "Psyshock", - "FI": "Psyshock", - "NL": "Psyshock", - "NO": "Psyshock", - "PL": "Psyshock", "FR": "Choc Psy", "DE": "Psychoschock", "IT": "Psicoshock", @@ -782,10 +537,6 @@ "pokemon_move_61": { "PT-BR": "Lançamento de Rocha", "EN": "Rock Throw", - "FI": "Rock Throw", - "NL": "Rock Throw", - "NO": "Rock Throw", - "PL": "Rock Throw", "FR": "Jet-Pierres", "DE": "Steinwurf", "IT": "Sassata", @@ -795,10 +546,6 @@ "pokemon_move_62": { "PT-BR": "Poder Ancestral", "EN": "Ancient Power", - "FI": "Ancient Power", - "NL": "Ancient Power", - "NO": "Ancient Power", - "PL": "Ancient Power", "FR": "Pouvoir Antique", "DE": "Antik-Kraft", "IT": "Forzantica", @@ -808,10 +555,6 @@ "pokemon_move_63": { "PT-BR": "Tumba de Rochas", "EN": "Rock Tomb", - "FI": "Rock Tomb", - "NL": "Rock Tomb", - "NO": "Rock Tomb", - "PL": "Rock Tomb", "FR": "Tomberoche", "DE": "Felsgrab", "IT": "Rocciotomba", @@ -821,10 +564,6 @@ "pokemon_move_64": { "PT-BR": "Deslize de Pedras", "EN": "Rock Slide", - "FI": "Rock Slide", - "NL": "Rock Slide", - "NO": "Rock Slide", - "PL": "Rock Slide", "FR": "Éboulement", "DE": "Steinhagel", "IT": "Frana", @@ -834,10 +573,6 @@ "pokemon_move_65": { "PT-BR": "Gema Poderosa", "EN": "Power Gem", - "FI": "Power Gem", - "NL": "Power Gem", - "NO": "Power Gem", - "PL": "Power Gem", "FR": "Rayon Gemme", "DE": "Juwelenkraft", "IT": "Gemmoforza", @@ -847,10 +582,6 @@ "pokemon_move_66": { "PT-BR": "Furtividade nas Sombras", "EN": "Shadow Sneak", - "FI": "Shadow Sneak", - "NL": "Shadow Sneak", - "NO": "Shadow Sneak", - "PL": "Shadow Sneak", "FR": "Ombre Portée", "DE": "Schattenstoß", "IT": "Furtivombra", @@ -860,10 +591,6 @@ "pokemon_move_67": { "PT-BR": "Soco Sombrio", "EN": "Shadow Punch", - "FI": "Shadow Punch", - "NL": "Shadow Punch", - "NO": "Shadow Punch", - "PL": "Shadow Punch", "FR": "Poing Ombre", "DE": "Finsterfaust", "IT": "Pugnodombra", @@ -873,10 +600,6 @@ "pokemon_move_68": { "PT-BR": "Garra Sombria", "EN": "Shadow Claw", - "FI": "Shadow Claw", - "NL": "Shadow Claw", - "NO": "Shadow Claw", - "PL": "Shadow Claw", "FR": "Griffe Ombre", "DE": "Dunkelklaue", "IT": "Ombrartigli", @@ -886,10 +609,6 @@ "pokemon_move_69": { "PT-BR": "Vento Ominoso", "EN": "Ominous Wind", - "FI": "Ominous Wind", - "NL": "Ominous Wind", - "NO": "Ominous Wind", - "PL": "Ominous Wind", "FR": "Vent Mauvais", "DE": "Unheilböen", "IT": "Funestovento", @@ -899,10 +618,6 @@ "pokemon_move_70": { "PT-BR": "Bola Sombria", "EN": "Shadow Ball", - "FI": "Shadow Ball", - "NL": "Shadow Ball", - "NO": "Shadow Ball", - "PL": "Shadow Ball", "FR": "Ball’Ombre", "DE": "Spukball", "IT": "Palla Ombra", @@ -912,10 +627,6 @@ "pokemon_move_71": { "PT-BR": "Soco Projétil", "EN": "Bullet Punch", - "FI": "Bullet Punch", - "NL": "Bullet Punch", - "NO": "Bullet Punch", - "PL": "Bullet Punch", "FR": "Pisto-Poing", "DE": "Patronenhieb", "IT": "Pugnoscarica", @@ -925,10 +636,6 @@ "pokemon_move_72": { "PT-BR": "Bomba Ímã", "EN": "Magnet Bomb", - "FI": "Magnet Bomb", - "NL": "Magnet Bomb", - "NO": "Magnet Bomb", - "PL": "Magnet Bomb", "FR": "Bombe Aimant", "DE": "Magnetbombe", "IT": "Bombagnete", @@ -938,10 +645,6 @@ "pokemon_move_73": { "PT-BR": "Asa de Aço", "EN": "Steel Wing", - "FI": "Steel Wing", - "NL": "Steel Wing", - "NO": "Steel Wing", - "PL": "Steel Wing", "FR": "Ailes d’Acier", "DE": "Stahlflügel", "IT": "Alacciaio", @@ -951,10 +654,6 @@ "pokemon_move_74": { "PT-BR": "Cabeça de Ferro", "EN": "Iron Head", - "FI": "Iron Head", - "NL": "Iron Head", - "NO": "Iron Head", - "PL": "Iron Head", "FR": "Tête de Fer", "DE": "Eisenschädel", "IT": "Metaltestata", @@ -964,10 +663,6 @@ "pokemon_move_75": { "PT-BR": "Ataque Parabólico", "EN": "Parabolic Charge", - "FI": "Parabolic Charge", - "NL": "Parabolic Charge", - "NO": "Parabolic Charge", - "PL": "Parabolic Charge", "FR": "Parabocharge", "DE": "Parabolladung", "IT": "Caricaparabola", @@ -977,10 +672,6 @@ "pokemon_move_76": { "PT-BR": "Faísca", "EN": "Spark", - "FI": "Spark", - "NL": "Spark", - "NO": "Spark", - "PL": "Spark", "FR": "Étincelle", "DE": "Funkensprung", "IT": "Scintilla", @@ -990,10 +681,6 @@ "pokemon_move_77": { "PT-BR": "Soco Trovoada", "EN": "Thunder Punch", - "FI": "Thunder Punch", - "NL": "Thunder Punch", - "NO": "Thunder Punch", - "PL": "Thunder Punch", "FR": "Poing Éclair", "DE": "Donnerschlag", "IT": "Tuonopugno", @@ -1003,10 +690,6 @@ "pokemon_move_78": { "PT-BR": "Trovão", "EN": "Thunder", - "FI": "Thunder", - "NL": "Thunder", - "NO": "Thunder", - "PL": "Thunder", "FR": "Fatal-Foudre", "DE": "Donner", "IT": "Tuono", @@ -1016,10 +699,6 @@ "pokemon_move_79": { "PT-BR": "Relâmpago", "EN": "Thunderbolt", - "FI": "Thunderbolt", - "NL": "Thunderbolt", - "NO": "Thunderbolt", - "PL": "Thunderbolt", "FR": "Tonnerre", "DE": "Donnerblitz", "IT": "Fulmine", @@ -1027,12 +706,7 @@ "ES": "Rayo" }, "pokemon_move_80": { - "PT-BR": "Twister", "EN": "Twister", - "FI": "Twister", - "NL": "Twister", - "NO": "Twister", - "PL": "Twister", "FR": "Ouragan", "DE": "Windhose", "IT": "Tornado", @@ -1042,10 +716,6 @@ "pokemon_move_81": { "PT-BR": "Sopro do Dragão", "EN": "Dragon Breath", - "FI": "Dragon Breath", - "NL": "Dragon Breath", - "NO": "Dragon Breath", - "PL": "Dragon Breath", "FR": "Draco-Souffle", "DE": "Feuerodem", "IT": "Dragospiro", @@ -1055,10 +725,6 @@ "pokemon_move_82": { "PT-BR": "Pulso do Dragão", "EN": "Dragon Pulse", - "FI": "Dragon Pulse", - "NL": "Dragon Pulse", - "NO": "Dragon Pulse", - "PL": "Dragon Pulse", "FR": "Draco-Choc", "DE": "Drachenpuls", "IT": "Dragopulsar", @@ -1068,10 +734,6 @@ "pokemon_move_83": { "PT-BR": "Garra de Dragão", "EN": "Dragon Claw", - "FI": "Dragon Claw", - "NL": "Dragon Claw", - "NO": "Dragon Claw", - "PL": "Dragon Claw", "FR": "Draco-Griffe", "DE": "Drachenklaue", "IT": "Dragartigli", @@ -1081,10 +743,6 @@ "pokemon_move_84": { "PT-BR": "Voz Desarmante", "EN": "Disarming Voice", - "FI": "Disarming Voice", - "NL": "Disarming Voice", - "NO": "Disarming Voice", - "PL": "Disarming Voice", "FR": "Voix Enjôleuse", "DE": "Säuselstimme", "IT": "Incantavoce", @@ -1094,10 +752,6 @@ "pokemon_move_85": { "PT-BR": "Beijo Drenante", "EN": "Draining Kiss", - "FI": "Draining Kiss", - "NL": "Draining Kiss", - "NO": "Draining Kiss", - "PL": "Draining Kiss", "FR": "Vampibaiser", "DE": "Diebeskuss", "IT": "Assorbibacio", @@ -1107,10 +761,6 @@ "pokemon_move_86": { "PT-BR": "Clarão Deslumbrante", "EN": "Dazzling Gleam", - "FI": "Dazzling Gleam", - "NL": "Dazzling Gleam", - "NO": "Dazzling Gleam", - "PL": "Dazzling Gleam", "FR": "Éclat Magique", "DE": "Zauberschein", "IT": "Magibrillio", @@ -1120,10 +770,6 @@ "pokemon_move_87": { "PT-BR": "Explosão Lunar", "EN": "Moonblast", - "FI": "Moonblast", - "NL": "Moonblast", - "NO": "Moonblast", - "PL": "Moonblast", "FR": "Pouvoir Lunaire", "DE": "Mondgewalt", "IT": "Forza Lunare", @@ -1133,10 +779,6 @@ "pokemon_move_88": { "PT-BR": "Jogo Duro", "EN": "Play Rough", - "FI": "Play Rough", - "NL": "Play Rough", - "NO": "Play Rough", - "PL": "Play Rough", "FR": "Câlinerie", "DE": "Knuddler", "IT": "Carineria", @@ -1146,10 +788,6 @@ "pokemon_move_89": { "PT-BR": "Corte-veneno", "EN": "Cross Poison", - "FI": "Cross Poison", - "NL": "Cross Poison", - "NO": "Cross Poison", - "PL": "Cross Poison", "FR": "Poison Croix", "DE": "Giftstreich", "IT": "Velenocroce", @@ -1159,10 +797,6 @@ "pokemon_move_90": { "PT-BR": "Bomba de Lodo", "EN": "Sludge Bomb", - "FI": "Sludge Bomb", - "NL": "Sludge Bomb", - "NO": "Sludge Bomb", - "PL": "Sludge Bomb", "FR": "Bombe Beurk", "DE": "Matschbombe", "IT": "Fangobomba", @@ -1172,10 +806,6 @@ "pokemon_move_91": { "PT-BR": "Onda de Lama", "EN": "Sludge Wave", - "FI": "Sludge Wave", - "NL": "Sludge Wave", - "NO": "Sludge Wave", - "PL": "Sludge Wave", "FR": "Cradovague", "DE": "Schlammwoge", "IT": "Fangonda", @@ -1185,10 +815,6 @@ "pokemon_move_92": { "PT-BR": "Tiro de Sujeira", "EN": "Gunk Shot", - "FI": "Gunk Shot", - "NL": "Gunk Shot", - "NO": "Gunk Shot", - "PL": "Gunk Shot", "FR": "Détricanon", "DE": "Mülltreffer", "IT": "Sporcolancio", @@ -1198,10 +824,6 @@ "pokemon_move_93": { "PT-BR": "Tiro de Lama", "EN": "Mud Shot", - "FI": "Mud Shot", - "NL": "Mud Shot", - "NO": "Mud Shot", - "PL": "Mud Shot", "FR": "Tir de Boue", "DE": "Lehmschuss", "IT": "Colpodifango", @@ -1211,10 +833,6 @@ "pokemon_move_94": { "PT-BR": "Bastão de Osso", "EN": "Bone Club", - "FI": "Bone Club", - "NL": "Bone Club", - "NO": "Bone Club", - "PL": "Bone Club", "FR": "Massd’Os", "DE": "Knochenkeule", "IT": "Ossoclava", @@ -1224,10 +842,6 @@ "pokemon_move_95": { "PT-BR": "Tremor", "EN": "Bulldoze", - "FI": "Bulldoze", - "NL": "Bulldoze", - "NO": "Bulldoze", - "PL": "Bulldoze", "FR": "Piétisol", "DE": "Dampfwalze", "IT": "Battiterra", @@ -1237,10 +851,6 @@ "pokemon_move_96": { "PT-BR": "Bomba de Lama", "EN": "Mud Bomb", - "FI": "Mud Bomb", - "NL": "Mud Bomb", - "NO": "Mud Bomb", - "PL": "Mud Bomb", "FR": "Boue-Bombe", "DE": "Schlammbombe", "IT": "Pantanobomba", @@ -1250,10 +860,6 @@ "pokemon_move_97": { "PT-BR": "Cortador de Fúria", "EN": "Fury Cutter", - "FI": "Fury Cutter", - "NL": "Fury Cutter", - "NO": "Fury Cutter", - "PL": "Fury Cutter", "FR": "Taillade", "DE": "Zornklinge", "IT": "Tagliofuria", @@ -1263,10 +869,6 @@ "pokemon_move_98": { "PT-BR": "Picada", "EN": "Bug Bite", - "FI": "Bug Bite", - "NL": "Bug Bite", - "NO": "Bug Bite", - "PL": "Bug Bite", "FR": "Piqûre", "DE": "Käferbiss", "IT": "Coleomorso", @@ -1276,10 +878,6 @@ "pokemon_move_99": { "PT-BR": "Feixe Sinalizador", "EN": "Signal Beam", - "FI": "Signal Beam", - "NL": "Signal Beam", - "NO": "Signal Beam", - "PL": "Signal Beam", "FR": "Rayon Signal", "DE": "Ampelleuchte", "IT": "Segnoraggio", @@ -1289,10 +887,6 @@ "pokemon_move_100": { "PT-BR": "Tesoura X", "EN": "X-Scissor", - "FI": "X-Scissor", - "NL": "X-Scissor", - "NO": "X-Scissor", - "PL": "X-Scissor", "FR": "Plaie Croix", "DE": "Kreuzschere", "IT": "Forbice X", @@ -1302,10 +896,6 @@ "pokemon_move_101": { "PT-BR": "Ataque de Chamas", "EN": "Flame Charge", - "FI": "Flame Charge", - "NL": "Flame Charge", - "NO": "Flame Charge", - "PL": "Flame Charge", "FR": "Nitrocharge", "DE": "Nitroladung", "IT": "Nitrocarica", @@ -1315,10 +905,6 @@ "pokemon_move_102": { "PT-BR": "Rajada de Chamas", "EN": "Flame Burst", - "FI": "Flame Burst", - "NL": "Flame Burst", - "NO": "Flame Burst", - "PL": "Flame Burst", "FR": "Rebondifeu", "DE": "Funkenflug", "IT": "Pirolancio", @@ -1328,10 +914,6 @@ "pokemon_move_103": { "PT-BR": "Rajada de Fogo", "EN": "Fire Blast", - "FI": "Fire Blast", - "NL": "Fire Blast", - "NO": "Fire Blast", - "PL": "Fire Blast", "FR": "Déflagration", "DE": "Feuersturm", "IT": "Fuocobomba", @@ -1341,10 +923,6 @@ "pokemon_move_104": { "PT-BR": "Salmoura", "EN": "Brine", - "FI": "Brine", - "NL": "Brine", - "NO": "Brine", - "PL": "Brine", "FR": "Saumure", "DE": "Lake", "IT": "Acquadisale", @@ -1354,10 +932,6 @@ "pokemon_move_105": { "PT-BR": "Pulso d'Água", "EN": "Water Pulse", - "FI": "Water Pulse", - "NL": "Water Pulse", - "NO": "Water Pulse", - "PL": "Water Pulse", "FR": "Vibraqua", "DE": "Aquawelle", "IT": "Idropulsar", @@ -1367,10 +941,6 @@ "pokemon_move_106": { "PT-BR": "Escaldada", "EN": "Scald", - "FI": "Scald", - "NL": "Scald", - "NO": "Scald", - "PL": "Scald", "FR": "Ébullition", "DE": "Siedewasser", "IT": "Idrovampata", @@ -1380,10 +950,6 @@ "pokemon_move_107": { "PT-BR": "Jato d'Água", "EN": "Hydro Pump", - "FI": "Hydro Pump", - "NL": "Hydro Pump", - "NO": "Hydro Pump", - "PL": "Hydro Pump", "FR": "Hydrocanon", "DE": "Hydropumpe", "IT": "Idropompa", @@ -1393,10 +959,6 @@ "pokemon_move_108": { "PT-BR": "Psíquico", "EN": "Psychic", - "FI": "Psychic", - "NL": "Psychic", - "NO": "Psychic", - "PL": "Psychic", "FR": "Psyko", "DE": "Psychokinese", "IT": "Psichico", @@ -1406,10 +968,6 @@ "pokemon_move_109": { "PT-BR": "Golpe Psíquico", "EN": "Psystrike", - "FI": "Psystrike", - "NL": "Psystrike", - "NO": "Psystrike", - "PL": "Psystrike", "FR": "Frappe Psy", "DE": "Psychostoß", "IT": "Psicobotta", @@ -1419,10 +977,6 @@ "pokemon_move_110": { "PT-BR": "Caco de Gelo", "EN": "Ice Shard", - "FI": "Ice Shard", - "NL": "Ice Shard", - "NO": "Ice Shard", - "PL": "Ice Shard", "FR": "Éclats Glace", "DE": "Eissplitter", "IT": "Geloscheggia", @@ -1432,10 +986,6 @@ "pokemon_move_111": { "PT-BR": "Vento Congelante", "EN": "Icy Wind", - "FI": "Icy Wind", - "NL": "Icy Wind", - "NO": "Icy Wind", - "PL": "Icy Wind", "FR": "Vent Glace", "DE": "Eissturm", "IT": "Ventogelato", @@ -1445,10 +995,6 @@ "pokemon_move_112": { "PT-BR": "Respiração de Gelo", "EN": "Frost Breath", - "FI": "Frost Breath", - "NL": "Frost Breath", - "NO": "Frost Breath", - "PL": "Frost Breath", "FR": "Souffle Glacé", "DE": "Eisesodem", "IT": "Alitogelido", @@ -1458,10 +1004,6 @@ "pokemon_move_113": { "PT-BR": "Absorção", "EN": "Absorb", - "FI": "Absorb", - "NL": "Absorb", - "NO": "Absorb", - "PL": "Absorb", "FR": "Vole-Vie", "DE": "Absorber", "IT": "Assorbimento", @@ -1471,10 +1013,6 @@ "pokemon_move_114": { "PT-BR": "Gigadreno", "EN": "Giga Drain", - "FI": "Giga Drain", - "NL": "Giga Drain", - "NO": "Giga Drain", - "PL": "Giga Drain", "FR": "Giga-Sangsue", "DE": "Gigasauger", "IT": "Gigassorbimento", @@ -1484,10 +1022,6 @@ "pokemon_move_115": { "PT-BR": "Soco de Fogo", "EN": "Fire Punch", - "FI": "Fire Punch", - "NL": "Fire Punch", - "NO": "Fire Punch", - "PL": "Fire Punch", "FR": "Poing Feu", "DE": "Feuerschlag", "IT": "Fuocopugno", @@ -1497,10 +1031,6 @@ "pokemon_move_116": { "PT-BR": "Raio Solar", "EN": "Solar Beam", - "FI": "Solar Beam", - "NL": "Solar Beam", - "NO": "Solar Beam", - "PL": "Solar Beam", "FR": "Lance-Soleil", "DE": "Solarstrahl", "IT": "Solarraggio", @@ -1510,10 +1040,6 @@ "pokemon_move_117": { "PT-BR": "Lâmina de Folha", "EN": "Leaf Blade", - "FI": "Leaf Blade", - "NL": "Leaf Blade", - "NO": "Leaf Blade", - "PL": "Leaf Blade", "FR": "Lame Feuille", "DE": "Laubklinge", "IT": "Fendifoglia", @@ -1523,10 +1049,6 @@ "pokemon_move_118": { "PT-BR": "Chicote Poderoso", "EN": "Power Whip", - "FI": "Power Whip", - "NL": "Power Whip", - "NO": "Power Whip", - "PL": "Power Whip", "FR": "Mégafouet", "DE": "Blattgeißel", "IT": "Vigorcolpo", @@ -1536,23 +1058,14 @@ "pokemon_move_119": { "PT-BR": "Borrifada", "EN": "Splash", - "FI": "Splash", - "NL": "Splash", - "NO": "Splash", - "PL": "Splash", "FR": "Trempette", "DE": "Platscher", - "IT": "Splash", "RU": "Всплеск", "ES": "Salpicadura" }, "pokemon_move_120": { "PT-BR": "Ácido", "EN": "Acid", - "FI": "Acid", - "NL": "Acid", - "NO": "Acid", - "PL": "Acid", "FR": "Acide", "DE": "Säure", "IT": "Acido", @@ -1562,10 +1075,6 @@ "pokemon_move_121": { "PT-BR": "Cortador de Ar", "EN": "Air Cutter", - "FI": "Air Cutter", - "NL": "Air Cutter", - "NO": "Air Cutter", - "PL": "Air Cutter", "FR": "Tranch’Air", "DE": "Windschnitt", "IT": "Aerasoio", @@ -1575,10 +1084,6 @@ "pokemon_move_122": { "PT-BR": "Furacão", "EN": "Hurricane", - "FI": "Hurricane", - "NL": "Hurricane", - "NO": "Hurricane", - "PL": "Hurricane", "FR": "Vent Violent", "DE": "Orkan", "IT": "Tifone", @@ -1588,10 +1093,6 @@ "pokemon_move_123": { "PT-BR": "Quebra-telha", "EN": "Brick Break", - "FI": "Brick Break", - "NL": "Brick Break", - "NO": "Brick Break", - "PL": "Brick Break", "FR": "Casse-Brique", "DE": "Durchbruch", "IT": "Breccia", @@ -1601,10 +1102,6 @@ "pokemon_move_124": { "PT-BR": "Cortar", "EN": "Cut", - "FI": "Cut", - "NL": "Cut", - "NO": "Cut", - "PL": "Cut", "FR": "Coupe", "DE": "Zerschneider", "IT": "Taglio", @@ -1614,10 +1111,6 @@ "pokemon_move_125": { "PT-BR": "Ataque Veloz", "EN": "Swift", - "FI": "Swift", - "NL": "Swift", - "NO": "Swift", - "PL": "Swift", "FR": "Météores", "DE": "Sternschauer", "IT": "Comete", @@ -1627,10 +1120,6 @@ "pokemon_move_126": { "PT-BR": "Ataque de Chifre", "EN": "Horn Attack", - "FI": "Horn Attack", - "NL": "Horn Attack", - "NO": "Horn Attack", - "PL": "Horn Attack", "FR": "Koud’Korne", "DE": "Hornattacke", "IT": "Incornata", @@ -1640,10 +1129,6 @@ "pokemon_move_127": { "PT-BR": "Pisotear", "EN": "Stomp", - "FI": "Stomp", - "NL": "Stomp", - "NO": "Stomp", - "PL": "Stomp", "FR": "Écrasement", "DE": "Stampfer", "IT": "Pestone", @@ -1653,10 +1138,6 @@ "pokemon_move_128": { "PT-BR": "Cabeçada", "EN": "Headbutt", - "FI": "Headbutt", - "NL": "Headbutt", - "NO": "Headbutt", - "PL": "Headbutt", "FR": "Coup d’Boule", "DE": "Kopfnuss", "IT": "Bottintesta", @@ -1666,10 +1147,6 @@ "pokemon_move_129": { "PT-BR": "Hiperpresa", "EN": "Hyper Fang", - "FI": "Hyper Fang", - "NL": "Hyper Fang", - "NO": "Hyper Fang", - "PL": "Hyper Fang", "FR": "Croc de Mort", "DE": "Hyperzahn", "IT": "Iperzanna", @@ -1679,12 +1156,7 @@ "pokemon_move_130": { "PT-BR": "Pancada Brusca", "EN": "Slam", - "FI": "Slam", - "NL": "Slam", - "NO": "Slam", - "PL": "Slam", "FR": "Souplesse", - "DE": "Slam", "IT": "Schianto", "RU": "Таранный Удар", "ES": "Atizar" @@ -1692,10 +1164,6 @@ "pokemon_move_131": { "PT-BR": "Pancada Corporal", "EN": "Body Slam", - "FI": "Body Slam", - "NL": "Body Slam", - "NO": "Body Slam", - "PL": "Body Slam", "FR": "Plaquage", "DE": "Bodyslam", "IT": "Corposcontro", @@ -1705,10 +1173,6 @@ "pokemon_move_132": { "PT-BR": "Descansar", "EN": "Rest", - "FI": "Rest", - "NL": "Rest", - "NO": "Rest", - "PL": "Rest", "FR": "Repos", "DE": "Erholung", "IT": "Riposo", @@ -1718,10 +1182,6 @@ "pokemon_move_133": { "PT-BR": "Insistência", "EN": "Struggle", - "FI": "Struggle", - "NL": "Struggle", - "NO": "Struggle", - "PL": "Struggle", "FR": "Lutte", "DE": "Verzweifler", "IT": "Scontro", @@ -1731,10 +1191,6 @@ "pokemon_move_134": { "PT-BR": "Escaldada", "EN": "Scald", - "FI": "Scald", - "NL": "Scald", - "NO": "Scald", - "PL": "Scald", "FR": "Ébullition", "DE": "Siedewasser", "IT": "Idrovampata", @@ -1744,10 +1200,6 @@ "pokemon_move_135": { "PT-BR": "Jato d'Água", "EN": "Hydro Pump", - "FI": "Hydro Pump", - "NL": "Hydro Pump", - "NO": "Hydro Pump", - "PL": "Hydro Pump", "FR": "Hydrocanon", "DE": "Hydropumpe", "IT": "Idropompa", @@ -1757,10 +1209,6 @@ "pokemon_move_136": { "PT-BR": "Embrulho", "EN": "Wrap", - "FI": "Wrap", - "NL": "Wrap", - "NO": "Wrap", - "PL": "Wrap", "FR": "Ligotage", "DE": "Wickel", "IT": "Avvolgibotta", @@ -1770,10 +1218,6 @@ "pokemon_move_137": { "PT-BR": "Embrulho", "EN": "Wrap", - "FI": "Wrap", - "NL": "Wrap", - "NO": "Wrap", - "PL": "Wrap", "FR": "Ligotage", "DE": "Wickel", "IT": "Avvolgibotta", @@ -1783,10 +1227,6 @@ "pokemon_move_200": { "PT-BR": "Cortador de Fúria", "EN": "Fury Cutter", - "FI": "Fury Cutter", - "NL": "Fury Cutter", - "NO": "Fury Cutter", - "PL": "Fury Cutter", "FR": "Taillade", "DE": "Zornklinge", "IT": "Tagliofuria", @@ -1796,10 +1236,6 @@ "pokemon_move_201": { "PT-BR": "Picada", "EN": "Bug Bite", - "FI": "Bug Bite", - "NL": "Bug Bite", - "NO": "Bug Bite", - "PL": "Bug Bite", "FR": "Piqûre", "DE": "Käferbiss", "IT": "Coleomorso", @@ -1809,10 +1245,6 @@ "pokemon_move_202": { "PT-BR": "Mordida", "EN": "Bite", - "FI": "Bite", - "NL": "Bite", - "NO": "Bite", - "PL": "Bite", "FR": "Morsure", "DE": "Biss", "IT": "Morso", @@ -1822,10 +1254,6 @@ "pokemon_move_203": { "PT-BR": "Soco Enganador", "EN": "Sucker Punch", - "FI": "Sucker Punch", - "NL": "Sucker Punch", - "NO": "Sucker Punch", - "PL": "Sucker Punch", "FR": "Coup Bas", "DE": "Tiefschlag", "IT": "Sbigoattacco", @@ -1835,10 +1263,6 @@ "pokemon_move_204": { "PT-BR": "Sopro do Dragão", "EN": "Dragon Breath", - "FI": "Dragon Breath", - "NL": "Dragon Breath", - "NO": "Dragon Breath", - "PL": "Dragon Breath", "FR": "Draco-Souffle", "DE": "Feuerodem", "IT": "Dragospiro", @@ -1848,10 +1272,6 @@ "pokemon_move_205": { "PT-BR": "Trovoada de Choques", "EN": "Thunder Shock", - "FI": "Thunder Shock", - "NL": "Thunder Shock", - "NO": "Thunder Shock", - "PL": "Thunder Shock", "FR": "Éclair", "DE": "Donnerschock", "IT": "Tuonoshock", @@ -1861,10 +1281,6 @@ "pokemon_move_206": { "PT-BR": "Faísca", "EN": "Spark", - "FI": "Spark", - "NL": "Spark", - "NO": "Spark", - "PL": "Spark", "FR": "Étincelle", "DE": "Funkensprung", "IT": "Scintilla", @@ -1874,10 +1290,6 @@ "pokemon_move_207": { "PT-BR": "Rasteira", "EN": "Low Kick", - "FI": "Low Kick", - "NL": "Low Kick", - "NO": "Low Kick", - "PL": "Low Kick", "FR": "Balayage", "DE": "Fußkick", "IT": "Colpo Basso", @@ -1887,10 +1299,6 @@ "pokemon_move_208": { "PT-BR": "Golpe de Caratê", "EN": "Karate Chop", - "FI": "Karate Chop", - "NL": "Karate Chop", - "NO": "Karate Chop", - "PL": "Karate Chop", "FR": "Poing Karaté", "DE": "Karateschlag", "IT": "Colpokarate", @@ -1900,10 +1308,6 @@ "pokemon_move_209": { "PT-BR": "Brasa", "EN": "Ember", - "FI": "Ember", - "NL": "Ember", - "NO": "Ember", - "PL": "Ember", "FR": "Flammèche", "DE": "Glut", "IT": "Braciere", @@ -1913,10 +1317,6 @@ "pokemon_move_210": { "PT-BR": "Ataque de Asa", "EN": "Wing Attack", - "FI": "Wing Attack", - "NL": "Wing Attack", - "NO": "Wing Attack", - "PL": "Wing Attack", "FR": "Cru-Ailes", "DE": "Flügelschlag", "IT": "Attacco d’Ala", @@ -1926,10 +1326,6 @@ "pokemon_move_211": { "PT-BR": "Bicada", "EN": "Peck", - "FI": "Peck", - "NL": "Peck", - "NO": "Peck", - "PL": "Peck", "FR": "Picpic", "DE": "Pikser", "IT": "Beccata", @@ -1939,10 +1335,6 @@ "pokemon_move_212": { "PT-BR": "Lambida", "EN": "Lick", - "FI": "Lick", - "NL": "Lick", - "NO": "Lick", - "PL": "Lick", "FR": "Léchouille", "DE": "Schlecker", "IT": "Leccata", @@ -1952,10 +1344,6 @@ "pokemon_move_213": { "PT-BR": "Garra Sombria", "EN": "Shadow Claw", - "FI": "Shadow Claw", - "NL": "Shadow Claw", - "NO": "Shadow Claw", - "PL": "Shadow Claw", "FR": "Griffe Ombre", "DE": "Dunkelklaue", "IT": "Ombrartigli", @@ -1965,10 +1353,6 @@ "pokemon_move_214": { "PT-BR": "Chicote de Vinha", "EN": "Vine Whip", - "FI": "Vine Whip", - "NL": "Vine Whip", - "NO": "Vine Whip", - "PL": "Vine Whip", "FR": "Fouet Lianes", "DE": "Rankenhieb", "IT": "Frustata", @@ -1978,10 +1362,6 @@ "pokemon_move_215": { "PT-BR": "Folha Navalha", "EN": "Razor Leaf", - "FI": "Razor Leaf", - "NL": "Razor Leaf", - "NO": "Razor Leaf", - "PL": "Razor Leaf", "FR": "Tranch’Herbe", "DE": "Rasierblatt", "IT": "Foglielama", @@ -1991,10 +1371,6 @@ "pokemon_move_216": { "PT-BR": "Tiro de Lama", "EN": "Mud Shot", - "FI": "Mud Shot", - "NL": "Mud Shot", - "NO": "Mud Shot", - "PL": "Mud Shot", "FR": "Tir de Boue", "DE": "Lehmschuss", "IT": "Colpodifango", @@ -2004,10 +1380,6 @@ "pokemon_move_217": { "PT-BR": "Caco de Gelo", "EN": "Ice Shard", - "FI": "Ice Shard", - "NL": "Ice Shard", - "NO": "Ice Shard", - "PL": "Ice Shard", "FR": "Éclats Glace", "DE": "Eissplitter", "IT": "Geloscheggia", @@ -2017,10 +1389,6 @@ "pokemon_move_218": { "PT-BR": "Respiração de Gelo", "EN": "Frost Breath", - "FI": "Frost Breath", - "NL": "Frost Breath", - "NO": "Frost Breath", - "PL": "Frost Breath", "FR": "Souffle Glacé", "DE": "Eisesodem", "IT": "Alitogelido", @@ -2030,10 +1398,6 @@ "pokemon_move_219": { "PT-BR": "Ataque Rápido", "EN": "Quick Attack", - "FI": "Quick Attack", - "NL": "Quick Attack", - "NO": "Quick Attack", - "PL": "Quick Attack", "FR": "Vive-Attaque", "DE": "Ruckzuckhieb", "IT": "Attacco Rapido", @@ -2043,10 +1407,6 @@ "pokemon_move_220": { "PT-BR": "Arranhão", "EN": "Scratch", - "FI": "Scratch", - "NL": "Scratch", - "NO": "Scratch", - "PL": "Scratch", "FR": "Griffe", "DE": "Kratzer", "IT": "Graffio", @@ -2056,12 +1416,7 @@ "pokemon_move_221": { "PT-BR": "Investida", "EN": "Tackle", - "FI": "Tackle", - "NL": "Tackle", - "NO": "Tackle", - "PL": "Tackle", "FR": "Charge", - "DE": "Tackle", "IT": "Azione", "RU": "Бросок", "ES": "Placaje" @@ -2069,10 +1424,6 @@ "pokemon_move_222": { "PT-BR": "Pancada", "EN": "Pound", - "FI": "Pound", - "NL": "Pound", - "NO": "Pound", - "PL": "Pound", "FR": "Écras’Face", "DE": "Klaps", "IT": "Botta", @@ -2082,10 +1433,6 @@ "pokemon_move_223": { "PT-BR": "Cortar", "EN": "Cut", - "FI": "Cut", - "NL": "Cut", - "NO": "Cut", - "PL": "Cut", "FR": "Coupe", "DE": "Zerschneider", "IT": "Taglio", @@ -2095,10 +1442,6 @@ "pokemon_move_224": { "PT-BR": "Golpe Envenenado", "EN": "Poison Jab", - "FI": "Poison Jab", - "NL": "Poison Jab", - "NO": "Poison Jab", - "PL": "Poison Jab", "FR": "Direct Toxik", "DE": "Gifthieb", "IT": "Velenpuntura", @@ -2108,10 +1451,6 @@ "pokemon_move_225": { "PT-BR": "Ácido", "EN": "Acid", - "FI": "Acid", - "NL": "Acid", - "NO": "Acid", - "PL": "Acid", "FR": "Acide", "DE": "Säure", "IT": "Acido", @@ -2121,10 +1460,6 @@ "pokemon_move_226": { "PT-BR": "Corte Psíquico", "EN": "Psycho Cut", - "FI": "Psycho Cut", - "NL": "Psycho Cut", - "NO": "Psycho Cut", - "PL": "Psycho Cut", "FR": "Coupe Psycho", "DE": "Psychoklinge", "IT": "Psicotaglio", @@ -2134,10 +1469,6 @@ "pokemon_move_227": { "PT-BR": "Lançamento de Rocha", "EN": "Rock Throw", - "FI": "Rock Throw", - "NL": "Rock Throw", - "NO": "Rock Throw", - "PL": "Rock Throw", "FR": "Jet-Pierres", "DE": "Steinwurf", "IT": "Sassata", @@ -2147,10 +1478,6 @@ "pokemon_move_228": { "PT-BR": "Garra de Metal", "EN": "Metal Claw", - "FI": "Metal Claw", - "NL": "Metal Claw", - "NO": "Metal Claw", - "PL": "Metal Claw", "FR": "Griffe Acier", "DE": "Metallklaue", "IT": "Ferrartigli", @@ -2160,10 +1487,6 @@ "pokemon_move_229": { "PT-BR": "Soco Projétil", "EN": "Bullet Punch", - "FI": "Bullet Punch", - "NL": "Bullet Punch", - "NO": "Bullet Punch", - "PL": "Bullet Punch", "FR": "Pisto-Poing", "DE": "Patronenhieb", "IT": "Pugnoscarica", @@ -2173,10 +1496,6 @@ "pokemon_move_230": { "PT-BR": "Revólver d'Água", "EN": "Water Gun", - "FI": "Water Gun", - "NL": "Water Gun", - "NO": "Water Gun", - "PL": "Water Gun", "FR": "Pistolet à O", "DE": "Aquaknarre", "IT": "Pistolacqua", @@ -2186,23 +1505,14 @@ "pokemon_move_231": { "PT-BR": "Borrifada", "EN": "Splash", - "FI": "Splash", - "NL": "Splash", - "NO": "Splash", - "PL": "Splash", "FR": "Trempette", "DE": "Platscher", - "IT": "Splash", "RU": "Всплеск", "ES": "Salpicadura" }, "pokemon_move_232": { "PT-BR": "Revólver d'Água", "EN": "Water Gun", - "FI": "Water Gun", - "NL": "Water Gun", - "NO": "Water Gun", - "PL": "Water Gun", "FR": "Pistolet à O", "DE": "Aquaknarre", "IT": "Pistolacqua", @@ -2212,10 +1522,6 @@ "pokemon_move_233": { "PT-BR": "Tapa de Lama", "EN": "Mud-Slap", - "FI": "Mud-Slap", - "NL": "Mud-Slap", - "NO": "Mud-Slap", - "PL": "Mud-Slap", "FR": "Coud’Boue", "DE": "Lehmschelle", "IT": "Fangosberla", @@ -2225,10 +1531,6 @@ "pokemon_move_234": { "PT-BR": "Cabeçada Zen", "EN": "Zen Headbutt", - "FI": "Zen Headbutt", - "NL": "Zen Headbutt", - "NO": "Zen Headbutt", - "PL": "Zen Headbutt", "FR": "Psykoud’Boul", "DE": "Zen-Kopfstoß", "IT": "Cozzata Zen", @@ -2238,10 +1540,6 @@ "pokemon_move_235": { "PT-BR": "Confusão", "EN": "Confusion", - "FI": "Confusion", - "NL": "Confusion", - "NO": "Confusion", - "PL": "Confusion", "FR": "Choc Mental", "DE": "Konfusion", "IT": "Confusione", @@ -2251,10 +1549,6 @@ "pokemon_move_236": { "PT-BR": "Ferrão Venenoso", "EN": "Poison Sting", - "FI": "Poison Sting", - "NL": "Poison Sting", - "NO": "Poison Sting", - "PL": "Poison Sting", "FR": "Dard-Venin", "DE": "Giftstachel", "IT": "Velenospina", @@ -2264,10 +1558,6 @@ "pokemon_move_237": { "PT-BR": "Bolha", "EN": "Bubble", - "FI": "Bubble", - "NL": "Bubble", - "NO": "Bubble", - "PL": "Bubble", "FR": "Écume", "DE": "Blubber", "IT": "Bolla", @@ -2277,10 +1567,6 @@ "pokemon_move_238": { "PT-BR": "Ataque Dissimulado", "EN": "Feint Attack", - "FI": "Feint Attack", - "NL": "Feint Attack", - "NO": "Feint Attack", - "PL": "Feint Attack", "FR": "Feinte", "DE": "Finte", "IT": "Finta", @@ -2290,10 +1576,6 @@ "pokemon_move_239": { "PT-BR": "Asa de Aço", "EN": "Steel Wing", - "FI": "Steel Wing", - "NL": "Steel Wing", - "NO": "Steel Wing", - "PL": "Steel Wing", "FR": "Ailes d’Acier", "DE": "Stahlflügel", "IT": "Alacciaio", @@ -2303,10 +1585,6 @@ "pokemon_move_240": { "PT-BR": "Presas de Fogo", "EN": "Fire Fang", - "FI": "Fire Fang", - "NL": "Fire Fang", - "NO": "Fire Fang", - "PL": "Fire Fang", "FR": "Crocs Feu", "DE": "Feuerzahn", "IT": "Rogodenti", @@ -2316,10 +1594,6 @@ "pokemon_move_241": { "PT-BR": "Esmagamento de Pedras", "EN": "Rock Smash", - "FI": "Rock Smash", - "NL": "Rock Smash", - "NO": "Rock Smash", - "PL": "Rock Smash", "FR": "Éclate-Roc", "DE": "Zertrümmerer", "IT": "Spaccaroccia", @@ -2329,10 +1603,6 @@ "pokemon_move_242": { "PT-BR": "Transformação", "EN": "Transform", - "FI": "Transform", - "NL": "Transform", - "NO": "Transform", - "PL": "Transform", "FR": "Morphing", "DE": "Wandler", "IT": "Trasformazione", @@ -2342,10 +1612,6 @@ "pokemon_move_243": { "PT-BR": "Contra-atacar", "EN": "Counter", - "FI": "Counter", - "NL": "Counter", - "NO": "Counter", - "PL": "Counter", "FR": "Riposte", "DE": "Konter", "IT": "Contrattacco", @@ -2355,10 +1621,6 @@ "pokemon_move_244": { "PT-BR": "Neve em Pó", "EN": "Powder Snow", - "FI": "Powder Snow", - "NL": "Powder Snow", - "NO": "Powder Snow", - "PL": "Powder Snow", "FR": "Poudreuse", "DE": "Pulverschnee", "IT": "Polneve", @@ -2368,11 +1630,6 @@ "pokemon_move_245": { "PT-BR": "Corpo-a-corpo", "EN": "Close Combat", - "FI": "Close Combat", - "NL": "Close Combat", - "NO": "Close Combat", - "PL": "Close Combat", - "FR": "Close Combat", "DE": "Nahkampf", "IT": "Zuffa", "RU": "Ближний Бой", @@ -2381,10 +1638,6 @@ "pokemon_move_246": { "PT-BR": "Soco Dinâmico", "EN": "Dynamic Punch", - "FI": "Dynamic Punch", - "NL": "Dynamic Punch", - "NO": "Dynamic Punch", - "PL": "Dynamic Punch", "FR": "Dynamo-Poing", "DE": "Wuchtschlag", "IT": "Dinamipugno", @@ -2394,10 +1647,6 @@ "pokemon_move_247": { "PT-BR": "Explosão Focalizada", "EN": "Focus Blast", - "FI": "Focus Blast", - "NL": "Focus Blast", - "NO": "Focus Blast", - "PL": "Focus Blast", "FR": "Exploforce", "DE": "Fokusstoß", "IT": "Focalcolpo", @@ -2407,10 +1656,6 @@ "pokemon_move_248": { "PT-BR": "Raio Aurora", "EN": "Aurora Beam", - "FI": "Aurora Beam", - "NL": "Aurora Beam", - "NO": "Aurora Beam", - "PL": "Aurora Beam", "FR": "Onde Boréale", "DE": "Aurorastrahl", "IT": "Raggiaurora", @@ -2420,10 +1665,6 @@ "pokemon_move_249": { "PT-BR": "Carga de Raio", "EN": "Charge Beam", - "FI": "Charge Beam", - "NL": "Charge Beam", - "NO": "Charge Beam", - "PL": "Charge Beam", "FR": "Rayon Chargé", "DE": "Ladestrahl", "IT": "Raggioscossa", @@ -2433,10 +1674,6 @@ "pokemon_move_250": { "PT-BR": "Troca Elétrica", "EN": "Volt Switch", - "FI": "Volt Switch", - "NL": "Volt Switch", - "NO": "Volt Switch", - "PL": "Volt Switch", "FR": "Change Éclair", "DE": "Voltwechsel", "IT": "Invertivolt", @@ -2446,10 +1683,6 @@ "pokemon_move_251": { "PT-BR": "Ataque Selvagem", "EN": "Wild Charge", - "FI": "Wild Charge", - "NL": "Wild Charge", - "NO": "Wild Charge", - "PL": "Wild Charge", "FR": "Éclair Fou", "DE": "Stromstoß", "IT": "Sprizzalampo", @@ -2459,10 +1692,6 @@ "pokemon_move_252": { "PT-BR": "Canhão Zap", "EN": "Zap Cannon", - "FI": "Zap Cannon", - "NL": "Zap Cannon", - "NO": "Zap Cannon", - "PL": "Zap Cannon", "FR": "Élecanon", "DE": "Blitzkanone", "IT": "Falcecannone", @@ -2472,10 +1701,6 @@ "pokemon_move_253": { "PT-BR": "Cauda do Dragão", "EN": "Dragon Tail", - "FI": "Dragon Tail", - "NL": "Dragon Tail", - "NO": "Dragon Tail", - "PL": "Dragon Tail", "FR": "Draco-Queue", "DE": "Drachenrute", "IT": "Codadrago", @@ -2483,13 +1708,7 @@ "ES": "Cola Dragón" }, "pokemon_move_254": { - "PT-BR": "Avalanche", "EN": "Avalanche", - "FI": "Avalanche", - "NL": "Avalanche", - "NO": "Avalanche", - "PL": "Avalanche", - "FR": "Avalanche", "DE": "Lawine", "IT": "Slavina", "RU": "Лавина", @@ -2498,10 +1717,6 @@ "pokemon_move_255": { "PT-BR": "Golpe de Ar", "EN": "Air Slash", - "FI": "Air Slash", - "NL": "Air Slash", - "NO": "Air Slash", - "PL": "Air Slash", "FR": "Lame d’Air", "DE": "Luftschnitt", "IT": "Eterelama", @@ -2511,10 +1726,6 @@ "pokemon_move_256": { "PT-BR": "Pássaro Bravo", "EN": "Brave Bird", - "FI": "Brave Bird", - "NL": "Brave Bird", - "NO": "Brave Bird", - "PL": "Brave Bird", "FR": "Rapace", "DE": "Sturzflug", "IT": "Baldeali", @@ -2524,10 +1735,6 @@ "pokemon_move_257": { "PT-BR": "Ataque do Céu", "EN": "Sky Attack", - "FI": "Sky Attack", - "NL": "Sky Attack", - "NO": "Sky Attack", - "PL": "Sky Attack", "FR": "Piqué", "DE": "Himmelsfeger", "IT": "Aeroattacco", @@ -2537,10 +1744,6 @@ "pokemon_move_258": { "PT-BR": "Fosso de Areia", "EN": "Sand Tomb", - "FI": "Sand Tomb", - "NL": "Sand Tomb", - "NO": "Sand Tomb", - "PL": "Sand Tomb", "FR": "Tourbi-Sable", "DE": "Sandgrab", "IT": "Sabbiotomba", @@ -2550,10 +1753,6 @@ "pokemon_move_259": { "PT-BR": "Explosão de Rocha", "EN": "Rock Blast", - "FI": "Rock Blast", - "NL": "Rock Blast", - "NO": "Rock Blast", - "PL": "Rock Blast", "FR": "Boule Roc", "DE": "Felswurf", "IT": "Cadutamassi", @@ -2563,10 +1762,6 @@ "pokemon_move_260": { "PT-BR": "Infestação", "EN": "Infestation", - "FI": "Infestation", - "NL": "Infestation", - "NO": "Infestation", - "PL": "Infestation", "FR": "Harcèlement", "DE": "Plage", "IT": "Assillo", @@ -2576,10 +1771,6 @@ "pokemon_move_261": { "PT-BR": "Ira de Inseto", "EN": "Struggle Bug", - "FI": "Struggle Bug", - "NL": "Struggle Bug", - "NO": "Struggle Bug", - "PL": "Struggle Bug", "FR": "Survinsecte", "DE": "Käfertrutz", "IT": "Entomoblocco", @@ -2589,10 +1780,6 @@ "pokemon_move_262": { "PT-BR": "Vento Prateado", "EN": "Silver Wind", - "FI": "Silver Wind", - "NL": "Silver Wind", - "NO": "Silver Wind", - "PL": "Silver Wind", "FR": "Vent Argenté", "DE": "Silberhauch", "IT": "Ventargenteo", @@ -2602,10 +1789,6 @@ "pokemon_move_263": { "PT-BR": "Abismar", "EN": "Astonish", - "FI": "Astonish", - "NL": "Astonish", - "NO": "Astonish", - "PL": "Astonish", "FR": "Étonnement", "DE": "Erstauner", "IT": "Sgomento", @@ -2615,10 +1798,6 @@ "pokemon_move_264": { "PT-BR": "Feitiço", "EN": "Hex", - "FI": "Hex", - "NL": "Hex", - "NO": "Hex", - "PL": "Hex", "FR": "Châtiment", "DE": "Bürde", "IT": "Sciagura", @@ -2628,10 +1807,6 @@ "pokemon_move_265": { "PT-BR": "Sombra Noturna", "EN": "Night Shade", - "FI": "Night Shade", - "NL": "Night Shade", - "NO": "Night Shade", - "PL": "Night Shade", "FR": "Ombre Nocturne", "DE": "Nachtnebel", "IT": "Ombra Notturna", @@ -2641,10 +1816,6 @@ "pokemon_move_266": { "PT-BR": "Cauda de Ferro", "EN": "Iron Tail", - "FI": "Iron Tail", - "NL": "Iron Tail", - "NO": "Iron Tail", - "PL": "Iron Tail", "FR": "Queue de Fer", "DE": "Eisenschweif", "IT": "Codacciaio", @@ -2654,10 +1825,6 @@ "pokemon_move_267": { "PT-BR": "Girobola", "EN": "Gyro Ball", - "FI": "Gyro Ball", - "NL": "Gyro Ball", - "NO": "Gyro Ball", - "PL": "Gyro Ball", "FR": "Gyroballe", "DE": "Gyroball", "IT": "Vortexpalla", @@ -2667,10 +1834,6 @@ "pokemon_move_268": { "PT-BR": "Golpe Pesado", "EN": "Heavy Slam", - "FI": "Heavy Slam", - "NL": "Heavy Slam", - "NO": "Heavy Slam", - "PL": "Heavy Slam", "FR": "Tacle Lourd", "DE": "Rammboss", "IT": "Pesobomba", @@ -2680,10 +1843,6 @@ "pokemon_move_269": { "PT-BR": "Chama Furacão", "EN": "Fire Spin", - "FI": "Fire Spin", - "NL": "Fire Spin", - "NO": "Fire Spin", - "PL": "Fire Spin", "FR": "Danse Flammes", "DE": "Feuerwirbel", "IT": "Turbofuoco", @@ -2693,10 +1852,6 @@ "pokemon_move_270": { "PT-BR": "Superaquecimento", "EN": "Overheat", - "FI": "Overheat", - "NL": "Overheat", - "NO": "Overheat", - "PL": "Overheat", "FR": "Surchauffe", "DE": "Hitzekoller", "IT": "Vampata", @@ -2706,10 +1861,6 @@ "pokemon_move_271": { "PT-BR": "Projétil de Semente", "EN": "Bullet Seed", - "FI": "Bullet Seed", - "NL": "Bullet Seed", - "NO": "Bullet Seed", - "PL": "Bullet Seed", "FR": "Balle Graine", "DE": "Kugelsaat", "IT": "Semitraglia", @@ -2719,10 +1870,6 @@ "pokemon_move_272": { "PT-BR": "Nó de Grama", "EN": "Grass Knot", - "FI": "Grass Knot", - "NL": "Grass Knot", - "NO": "Grass Knot", - "PL": "Grass Knot", "FR": "Nœud Herbe", "DE": "Strauchler", "IT": "Laccioerboso", @@ -2732,10 +1879,6 @@ "pokemon_move_273": { "PT-BR": "Bola de Energia", "EN": "Energy Ball", - "FI": "Energy Ball", - "NL": "Energy Ball", - "NO": "Energy Ball", - "PL": "Energy Ball", "FR": "Éco-Sphère", "DE": "Energieball", "IT": "Energipalla", @@ -2745,10 +1888,6 @@ "pokemon_move_274": { "PT-BR": "Extrassensorial", "EN": "Extrasensory", - "FI": "Extrasensory", - "NL": "Extrasensory", - "NO": "Extrasensory", - "PL": "Extrasensory", "FR": "Extrasenseur", "DE": "Sondersensor", "IT": "Extrasenso", @@ -2758,10 +1897,6 @@ "pokemon_move_275": { "PT-BR": "Visão do Futuro", "EN": "Future Sight", - "FI": "Future Sight", - "NL": "Future Sight", - "NO": "Future Sight", - "PL": "Future Sight", "FR": "Prescience", "DE": "Seher", "IT": "Divinazione", @@ -2771,10 +1906,6 @@ "pokemon_move_276": { "PT-BR": "Casaco Espelhado", "EN": "Mirror Coat", - "FI": "Mirror Coat", - "NL": "Mirror Coat", - "NO": "Mirror Coat", - "PL": "Mirror Coat", "FR": "Voile Miroir", "DE": "Spiegelcape", "IT": "Specchiovelo", @@ -2784,10 +1915,6 @@ "pokemon_move_277": { "PT-BR": "Ultraje", "EN": "Outrage", - "FI": "Outrage", - "NL": "Outrage", - "NO": "Outrage", - "PL": "Outrage", "FR": "Colère", "DE": "Wutanfall", "IT": "Oltraggio", @@ -2797,10 +1924,6 @@ "pokemon_move_278": { "PT-BR": "Rosnado", "EN": "Snarl", - "FI": "Snarl", - "NL": "Snarl", - "NO": "Snarl", - "PL": "Snarl", "FR": "Aboiement", "DE": "Standpauke", "IT": "Urlorabbia", @@ -2810,10 +1933,6 @@ "pokemon_move_279": { "PT-BR": "Mastigada", "EN": "Crunch", - "FI": "Crunch", - "NL": "Crunch", - "NO": "Crunch", - "PL": "Crunch", "FR": "Mâchouille", "DE": "Knirscher", "IT": "Sgranocchio", @@ -2823,10 +1942,6 @@ "pokemon_move_280": { "PT-BR": "Jogo Sujo", "EN": "Foul Play", - "FI": "Foul Play", - "NL": "Foul Play", - "NO": "Foul Play", - "PL": "Foul Play", "FR": "Tricherie", "DE": "Schmarotzer", "IT": "Ripicca", @@ -2836,10 +1951,6 @@ "pokemon_move_281": { "PT-BR": "Poder Oculto", "EN": "Hidden Power", - "FI": "Hidden Power", - "NL": "Hidden Power", - "NO": "Hidden Power", - "PL": "Hidden Power", "FR": "Puissance Cachée", "DE": "Kraftreserve", "IT": "Introforza", @@ -2849,10 +1960,6 @@ "pokemon_move_282": { "PT-BR": "Desmantelar", "EN": "Take Down", - "FI": "Take Down", - "NL": "Take Down", - "NO": "Take Down", - "PL": "Take Down", "FR": "Bélier", "DE": "Bodycheck", "IT": "Riduttore", @@ -2862,10 +1969,6 @@ "pokemon_move_283": { "PT-BR": "Cachoeira", "EN": "Waterfall", - "FI": "Waterfall", - "NL": "Waterfall", - "NO": "Waterfall", - "PL": "Waterfall", "FR": "Cascade", "DE": "Kaskade", "IT": "Cascata", @@ -2875,25 +1978,13 @@ "pokemon_move_284": { "PT-BR": "Surfar", "EN": "Surf", - "FI": "Surf", - "NL": "Surf", - "NO": "Surf", - "PL": "Surf", - "FR": "Surf", "DE": "Surfer", - "IT": "Surf", - "RU": "Сёрф", - "ES": "Surf" + "RU": "Сёрф" }, "pokemon_move_285": { "PT-BR": "Meteoro do Dragão", "EN": "Draco Meteor", - "FI": "Draco Meteor", - "NL": "Draco Meteor", - "NO": "Draco Meteor", - "PL": "Draco Meteor", "FR": "Draco-Météore", - "DE": "Draco Meteor", "IT": "Dragobolide", "RU": "Метеор Дракона", "ES": "Cometa Draco" @@ -2901,10 +1992,6 @@ "pokemon_move_286": { "PT-BR": "Desejo Cruel", "EN": "Doom Desire", - "FI": "Doom Desire", - "NL": "Doom Desire", - "NO": "Doom Desire", - "PL": "Doom Desire", "FR": "Carnareket", "DE": "Kismetwunsch", "IT": "Obbliderio", @@ -2914,10 +2001,6 @@ "pokemon_move_287": { "PT-BR": "Bocejo", "EN": "Yawn", - "FI": "Yawn", - "NL": "Yawn", - "NO": "Yawn", - "PL": "Yawn", "FR": "Bâillement", "DE": "Gähner", "IT": "Sbadiglio", @@ -2927,10 +2010,6 @@ "pokemon_move_288": { "PT-BR": "Impulso Psíquico", "EN": "Psycho Boost", - "FI": "Psycho Boost", - "NL": "Psycho Boost", - "NO": "Psycho Boost", - "PL": "Psycho Boost", "FR": "Psycho-Boost", "DE": "Psyschub", "IT": "Psicoslancio", @@ -2940,10 +2019,6 @@ "pokemon_move_289": { "PT-BR": "Pulso Original", "EN": "Origin Pulse", - "FI": "Origin Pulse", - "NL": "Origin Pulse", - "NO": "Origin Pulse", - "PL": "Origin Pulse", "FR": "Onde Originelle", "DE": "Ursprungswoge", "IT": "Primopulsar", @@ -2953,10 +2028,6 @@ "pokemon_move_290": { "PT-BR": "Lâmina Abissal", "EN": "Precipice Blades", - "FI": "Precipice Blades", - "NL": "Precipice Blades", - "NO": "Precipice Blades", - "PL": "Precipice Blades", "FR": "Lame Pangéenne", "DE": "Abgrundsklinge", "IT": "Spade Telluriche", @@ -2966,10 +2037,6 @@ "pokemon_move_291": { "PT-BR": "Presente", "EN": "Present", - "FI": "Present", - "NL": "Present", - "NO": "Present", - "PL": "Present", "FR": "Cadeau", "DE": "Geschenk", "IT": "Regalino", @@ -2979,10 +2046,6 @@ "pokemon_move_292": { "PT-BR": "Esfera Climática", "EN": "Weather Ball", - "FI": "Weather Ball", - "NL": "Weather Ball", - "NO": "Weather Ball", - "PL": "Weather Ball", "FR": "Ball’Météo", "DE": "Meteorologe", "IT": "Palla Clima", @@ -2992,10 +2055,6 @@ "pokemon_move_293": { "PT-BR": "Esfera Climática", "EN": "Weather Ball", - "FI": "Weather Ball", - "NL": "Weather Ball", - "NO": "Weather Ball", - "PL": "Weather Ball", "FR": "Ball’Météo", "DE": "Meteorologe", "IT": "Palla Clima", @@ -3005,10 +2064,6 @@ "pokemon_move_294": { "PT-BR": "Esfera Climática", "EN": "Weather Ball", - "FI": "Weather Ball", - "NL": "Weather Ball", - "NO": "Weather Ball", - "PL": "Weather Ball", "FR": "Ball’Météo", "DE": "Meteorologe", "IT": "Palla Clima", @@ -3018,10 +2073,6 @@ "pokemon_move_295": { "PT-BR": "Esfera Climática", "EN": "Weather Ball", - "FI": "Weather Ball", - "NL": "Weather Ball", - "NO": "Weather Ball", - "PL": "Weather Ball", "FR": "Ball’Météo", "DE": "Meteorologe", "IT": "Palla Clima", @@ -3031,10 +2082,6 @@ "pokemon_move_296": { "PT-BR": "Planta Mortal", "EN": "Frenzy Plant", - "FI": "Frenzy Plant", - "NL": "Frenzy Plant", - "NO": "Frenzy Plant", - "PL": "Frenzy Plant", "FR": "Végé-Attaque", "DE": "Flora-Statue", "IT": "Radicalbero", @@ -3044,10 +2091,6 @@ "pokemon_move_297": { "PT-BR": "Derrubada", "EN": "Smack Down", - "FI": "Smack Down", - "NL": "Smack Down", - "NO": "Smack Down", - "PL": "Smack Down", "FR": "Anti-Air", "DE": "Katapult", "IT": "Abbattimento", @@ -3057,10 +2100,6 @@ "pokemon_move_298": { "PT-BR": "Queimadura Explosiva", "EN": "Blast Burn", - "FI": "Blast Burn", - "NL": "Blast Burn", - "NO": "Blast Burn", - "PL": "Blast Burn", "FR": "Rafale Feu", "DE": "Lohekanonade", "IT": "Incendio", @@ -3070,10 +2109,6 @@ "pokemon_move_299": { "PT-BR": "Hidro Canhão", "EN": "Hydro Cannon", - "FI": "Hydro Cannon", - "NL": "Hydro Cannon", - "NO": "Hydro Cannon", - "PL": "Hydro Cannon", "FR": "Hydroblast", "DE": "Aquahaubitze", "IT": "Idrocannone", @@ -3083,10 +2118,6 @@ "pokemon_move_300": { "PT-BR": "Último Recurso", "EN": "Last Resort", - "FI": "Last Resort", - "NL": "Last Resort", - "NO": "Last Resort", - "PL": "Last Resort", "FR": "Dernier Recours", "DE": "Zuflucht", "IT": "Ultimascelta", @@ -3096,10 +2127,6 @@ "pokemon_move_301": { "PT-BR": "Meteoro Esmagador", "EN": "Meteor Mash", - "FI": "Meteor Mash", - "NL": "Meteor Mash", - "NO": "Meteor Mash", - "PL": "Meteor Mash", "FR": "Poing Météore", "DE": "Sternenhieb", "IT": "Meteorpugno", @@ -3109,10 +2136,6 @@ "pokemon_move_302": { "PT-BR": "Quebra-crânio", "EN": "Skull Bash", - "FI": "Skull Bash", - "NL": "Skull Bash", - "NO": "Skull Bash", - "PL": "Skull Bash", "FR": "Coud’Krâne", "DE": "Schädelwumme", "IT": "Capocciata", @@ -3122,10 +2145,6 @@ "pokemon_move_303": { "PT-BR": "Spray Ácido", "EN": "Acid Spray", - "FI": "Acid Spray", - "NL": "Acid Spray", - "NO": "Acid Spray", - "PL": "Acid Spray", "FR": "Bombe Acide", "DE": "Säurespeier", "IT": "Acidobomba", @@ -3135,10 +2154,6 @@ "pokemon_move_304": { "PT-BR": "Poder da Terra", "EN": "Earth Power", - "FI": "Earth Power", - "NL": "Earth Power", - "NO": "Earth Power", - "PL": "Earth Power", "FR": "Telluriforce", "DE": "Erdkräfte", "IT": "Geoforza", @@ -3148,10 +2163,6 @@ "pokemon_move_305": { "PT-BR": "Martelo Caranguejo", "EN": "Crabhammer", - "FI": "Crabhammer", - "NL": "Crabhammer", - "NO": "Crabhammer", - "PL": "Crabhammer", "FR": "Pince-Masse", "DE": "Krabbhammer", "IT": "Martellata", @@ -3161,10 +2172,6 @@ "pokemon_move_306": { "PT-BR": "Estocada", "EN": "Lunge", - "FI": "Lunge", - "NL": "Lunge", - "NO": "Lunge", - "PL": "Lunge", "FR": "Furie-Bond", "DE": "Anfallen", "IT": "Assalto", @@ -3174,10 +2181,6 @@ "pokemon_move_307": { "PT-BR": "Garra Esmagadora", "EN": "Crush Claw", - "FI": "Crush Claw", - "NL": "Crush Claw", - "NO": "Crush Claw", - "PL": "Crush Claw", "FR": "Éclate Griffe", "DE": "Zermalmklaue", "IT": "Tritartigli", @@ -3187,23 +2190,12 @@ "pokemon_move_308": { "PT-BR": "Polvo-canhão", "EN": "Octazooka", - "FI": "Octazooka", - "NL": "Octazooka", - "NO": "Octazooka", - "PL": "Octazooka", - "FR": "Octazooka", - "DE": "Octazooka", - "IT": "Octazooka", "RU": "Чернильная Пушка", "ES": "Pulpocañón" }, "pokemon_move_309": { "PT-BR": "Tiro no Espelho", "EN": "Mirror Shot", - "FI": "Mirror Shot", - "NL": "Mirror Shot", - "NO": "Mirror Shot", - "PL": "Mirror Shot", "FR": "Miroi-Tir", "DE": "Spiegelsalve", "IT": "Cristalcolpo", @@ -3213,10 +2205,6 @@ "pokemon_move_310": { "PT-BR": "Superpoder", "EN": "Superpower", - "FI": "Superpower", - "NL": "Superpower", - "NO": "Superpower", - "PL": "Superpower", "FR": "Surpuissance", "DE": "Kraftkoloss", "IT": "Troppoforte", @@ -3226,10 +2214,6 @@ "pokemon_move_311": { "PT-BR": "Ferrão Letal", "EN": "Fell Stinger", - "FI": "Fell Stinger", - "NL": "Fell Stinger", - "NO": "Fell Stinger", - "PL": "Fell Stinger", "FR": "Dard Mortel", "DE": "Stachelfinale", "IT": "Pungiglione", @@ -3239,10 +2223,6 @@ "pokemon_move_312": { "PT-BR": "Tornado de Folhas", "EN": "Leaf Tornado", - "FI": "Leaf Tornado", - "NL": "Leaf Tornado", - "NO": "Leaf Tornado", - "PL": "Leaf Tornado", "FR": "Phytomixeur", "DE": "Grasmixer", "IT": "Vorticerba", @@ -3252,10 +2232,6 @@ "pokemon_move_313": { "PT-BR": "Suga-vidas", "EN": "Leech Life", - "FI": "Leech Life", - "NL": "Leech Life", - "NO": "Leech Life", - "PL": "Leech Life", "FR": "Vampirisme", "DE": "Blutsauger", "IT": "Sanguisuga", @@ -3265,10 +2241,6 @@ "pokemon_move_314": { "PT-BR": "Soco Dreno", "EN": "Drain Punch", - "FI": "Drain Punch", - "NL": "Drain Punch", - "NO": "Drain Punch", - "PL": "Drain Punch", "FR": "Vampi-Poing", "DE": "Ableithieb", "IT": "Assorbipugno", @@ -3278,10 +2250,6 @@ "pokemon_move_315": { "PT-BR": "Osso Sombrio", "EN": "Shadow Bone", - "FI": "Shadow Bone", - "NL": "Shadow Bone", - "NO": "Shadow Bone", - "PL": "Shadow Bone", "FR": "Os Ombre", "DE": "Schattenknochen", "IT": "Ossotetro", @@ -3291,10 +2259,6 @@ "pokemon_move_316": { "PT-BR": "Água Barrenta", "EN": "Muddy Water", - "FI": "Muddy Water", - "NL": "Muddy Water", - "NO": "Muddy Water", - "PL": "Muddy Water", "FR": "Ocroupi", "DE": "Lehmbrühe", "IT": "Fanghiglia", @@ -3304,10 +2268,6 @@ "pokemon_move_317": { "PT-BR": "Chute Labareda", "EN": "Blaze Kick", - "FI": "Blaze Kick", - "NL": "Blaze Kick", - "NO": "Blaze Kick", - "PL": "Blaze Kick", "FR": "Pied Brûleur", "DE": "Feuerfeger", "IT": "Calciardente", @@ -3317,10 +2277,6 @@ "pokemon_move_318": { "PT-BR": "Concha Navalha", "EN": "Razor Shell", - "FI": "Razor Shell", - "NL": "Razor Shell", - "NO": "Razor Shell", - "PL": "Razor Shell", "FR": "Coqui-Lame", "DE": "Kalkklinge", "IT": "Conchilama", @@ -3330,10 +2286,6 @@ "pokemon_move_319": { "PT-BR": "Soco Empoderador", "EN": "Power-Up Punch", - "FI": "Power-Up Punch", - "NL": "Power-Up Punch", - "NO": "Power-Up Punch", - "PL": "Power-Up Punch", "FR": "Poing Boost", "DE": "Steigerungshieb", "IT": "Crescipugno", @@ -3343,10 +2295,6 @@ "pokemon_move_320": { "PT-BR": "Encantar", "EN": "Charm", - "FI": "Charm", - "NL": "Charm", - "NO": "Charm", - "PL": "Charm", "FR": "Charme", "DE": "Charme", "IT": "Fascino", @@ -3356,11 +2304,6 @@ "pokemon_move_321": { "PT-BR": "Gigaimpacto", "EN": "Giga Impact", - "FI": "Giga Impact", - "NL": "Giga Impact", - "NO": "Giga Impact", - "PL": "Giga Impact", - "FR": "Giga Impact", "DE": "Gigastoß", "IT": "Gigaimpatto", "RU": "Гига-Удар", @@ -3369,12 +2312,6 @@ "pokemon_move_322": { "PT-BR": "Frustração", "EN": "Frustration", - "FI": "Frustration", - "NL": "Frustration", - "NO": "Frustration", - "PL": "Frustration", - "FR": "Frustration", - "DE": "Frustration", "IT": "Frustrazione", "RU": "Фрустрация", "ES": "Frustración" @@ -3382,10 +2319,6 @@ "pokemon_move_323": { "PT-BR": "Retorno", "EN": "Return", - "FI": "Return", - "NL": "Return", - "NO": "Return", - "PL": "Return", "FR": "Retour", "DE": "Rückkehr", "IT": "Ritorno", @@ -3395,10 +2328,6 @@ "pokemon_move_324": { "PT-BR": "Barulho Sincronizado", "EN": "Synchronoise", - "FI": "Synchronoise", - "NL": "Synchronoise", - "NO": "Synchronoise", - "PL": "Synchronoise", "FR": "Synchropeine", "DE": "Synchrolärm", "IT": "Sincrumore", @@ -3408,10 +2337,6 @@ "pokemon_move_325": { "PT-BR": "Mirar", "EN": "Lock-On", - "FI": "Lock-On", - "NL": "Lock-On", - "NO": "Lock-On", - "PL": "Lock-On", "FR": "Verrouillage", "DE": "Zielschuss", "IT": "Localizza", @@ -3421,10 +2346,6 @@ "pokemon_move_326": { "PT-BR": "Presa Trovejante", "EN": "Thunder Fang", - "FI": "Thunder Fang", - "NL": "Thunder Fang", - "NO": "Thunder Fang", - "PL": "Thunder Fang", "FR": "Crocs Éclair", "DE": "Donnerzahn", "IT": "Fulmindenti", @@ -3434,10 +2355,6 @@ "pokemon_move_327": { "PT-BR": "Presa de Gelo", "EN": "Ice Fang", - "FI": "Ice Fang", - "NL": "Ice Fang", - "NO": "Ice Fang", - "PL": "Ice Fang", "FR": "Crocs Givre", "DE": "Eiszahn", "IT": "Gelodenti", @@ -3447,10 +2364,6 @@ "pokemon_move_328": { "PT-BR": "Chifre Broca", "EN": "Horn Drill", - "FI": "Horn Drill", - "NL": "Horn Drill", - "NO": "Horn Drill", - "PL": "Horn Drill", "FR": "Empal’Korne", "DE": "Hornbohrer", "IT": "Perforcorno", @@ -3460,10 +2373,6 @@ "pokemon_move_329": { "PT-BR": "Fissura", "EN": "Fissure", - "FI": "Fissure", - "NL": "Fissure", - "NO": "Fissure", - "PL": "Fissure", "FR": "Abîme", "DE": "Geofissur", "IT": "Abisso", @@ -3473,10 +2382,6 @@ "pokemon_move_330": { "PT-BR": "Espada Sagrada", "EN": "Sacred Sword", - "FI": "Sacred Sword", - "NL": "Sacred Sword", - "NO": "Sacred Sword", - "PL": "Sacred Sword", "FR": "Lame Sainte", "DE": "Sanctoklinge", "IT": "Spadasolenne", @@ -3486,12 +2391,6 @@ "pokemon_move_331": { "PT-BR": "Aperto Voador", "EN": "Flying Press", - "FI": "Flying Press", - "NL": "Flying Press", - "NO": "Flying Press", - "PL": "Flying Press", - "FR": "Flying Press", - "DE": "Flying Press", "IT": "Schiacciatuffo", "RU": "Летающий Пресс", "ES": "Plancha Voladora" @@ -3499,10 +2398,6 @@ "pokemon_move_332": { "PT-BR": "Aura Esférica", "EN": "Aura Sphere", - "FI": "Aura Sphere", - "NL": "Aura Sphere", - "NO": "Aura Sphere", - "PL": "Aura Sphere", "FR": "Aurasphère", "DE": "Aurasphäre", "IT": "Forzasfera", @@ -3512,10 +2407,6 @@ "pokemon_move_333": { "PT-BR": "Revide", "EN": "Payback", - "FI": "Payback", - "NL": "Payback", - "NO": "Payback", - "PL": "Payback", "FR": "Représailles", "DE": "Gegenstoß", "IT": "Rivincita", @@ -3525,10 +2416,6 @@ "pokemon_move_334": { "PT-BR": "Demolidor de Pedras", "EN": "Rock Wrecker", - "FI": "Rock Wrecker", - "NL": "Rock Wrecker", - "NO": "Rock Wrecker", - "PL": "Rock Wrecker", "FR": "Roc-Boulet", "DE": "Felswerfer", "IT": "Devastomasso", @@ -3538,10 +2425,6 @@ "pokemon_move_335": { "PT-BR": "Explosão Aérea", "EN": "Aeroblast", - "FI": "Aeroblast", - "NL": "Aeroblast", - "NO": "Aeroblast", - "PL": "Aeroblast", "FR": "Aéroblast", "DE": "Luftstoß", "IT": "Aerocolpo", @@ -3551,10 +2434,6 @@ "pokemon_move_336": { "PT-BR": "Rajada Tecnológica", "EN": "Techno Blast", - "FI": "Techno Blast", - "NL": "Techno Blast", - "NO": "Techno Blast", - "PL": "Techno Blast", "FR": "Techno-Buster", "DE": "Techblaster", "IT": "Tecnobotto", @@ -3564,10 +2443,6 @@ "pokemon_move_337": { "PT-BR": "Rajada Tecnológica", "EN": "Techno Blast", - "FI": "Techno Blast", - "NL": "Techno Blast", - "NO": "Techno Blast", - "PL": "Techno Blast", "FR": "Techno-Buster", "DE": "Techblaster", "IT": "Tecnobotto", @@ -3577,10 +2452,6 @@ "pokemon_move_338": { "PT-BR": "Rajada Tecnológica", "EN": "Techno Blast", - "FI": "Techno Blast", - "NL": "Techno Blast", - "NO": "Techno Blast", - "PL": "Techno Blast", "FR": "Techno-Buster", "DE": "Techblaster", "IT": "Tecnobotto", @@ -3590,10 +2461,6 @@ "pokemon_move_339": { "PT-BR": "Rajada Tecnológica", "EN": "Techno Blast", - "FI": "Techno Blast", - "NL": "Techno Blast", - "NO": "Techno Blast", - "PL": "Techno Blast", "FR": "Techno-Buster", "DE": "Techblaster", "IT": "Tecnobotto", @@ -3603,10 +2470,6 @@ "pokemon_move_340": { "PT-BR": "Rajada Tecnológica", "EN": "Techno Blast", - "FI": "Techno Blast", - "NL": "Techno Blast", - "NO": "Techno Blast", - "PL": "Techno Blast", "FR": "Techno-Buster", "DE": "Techblaster", "IT": "Tecnobotto", @@ -3616,10 +2479,6 @@ "pokemon_move_341": { "PT-BR": "Voar", "EN": "Fly", - "FI": "Fly", - "NL": "Fly", - "NO": "Fly", - "PL": "Fly", "FR": "Vol", "DE": "Fliegen", "IT": "Volo", @@ -3629,10 +2488,6 @@ "pokemon_move_342": { "PT-BR": "Criação V", "EN": "V-create", - "FI": "V-create", - "NL": "V-create", - "NO": "V-create", - "PL": "V-create", "FR": "Coup Victoire", "DE": "V-Generator", "IT": "Generatore V", @@ -3642,10 +2497,6 @@ "pokemon_move_343": { "PT-BR": "Tempestade de Folhas", "EN": "Leaf Storm", - "FI": "Leaf Storm", - "NL": "Leaf Storm", - "NO": "Leaf Storm", - "PL": "Leaf Storm", "FR": "Tempête Verte", "DE": "Blättersturm", "IT": "Verdebufera", @@ -3655,10 +2506,6 @@ "pokemon_move_344": { "PT-BR": "Triataque", "EN": "Tri Attack", - "FI": "Tri Attack", - "NL": "Tri Attack", - "NO": "Tri Attack", - "PL": "Tri Attack", "FR": "Triplattaque", "DE": "Triplette", "IT": "Tripletta", @@ -3668,10 +2515,6 @@ "pokemon_move_345": { "PT-BR": "Lufada de Vento", "EN": "Gust", - "FI": "Gust", - "NL": "Gust", - "NO": "Gust", - "PL": "Gust", "FR": "Tornade", "DE": "Windstoß", "IT": "Raffica", @@ -3681,10 +2524,6 @@ "pokemon_move_346": { "PT-BR": "Incinerar", "EN": "Incinerate", - "FI": "Incinerate", - "NL": "Incinerate", - "NO": "Incinerate", - "PL": "Incinerate", "FR": "Calcination", "DE": "Einäschern", "IT": "Bruciatutto", @@ -3694,10 +2533,6 @@ "pokemon_move_348": { "PT-BR": "Dança das Penas", "EN": "Feather Dance", - "FI": "Feather Dance", - "NL": "Feather Dance", - "NO": "Feather Dance", - "PL": "Feather Dance", "FR": "Danse Plumes", "DE": "Daunenreigen", "IT": "Danzadipiume", @@ -3707,10 +2542,6 @@ "pokemon_move_350": { "PT-BR": "Vento de Fada", "EN": "Fairy Wind", - "FI": "Fairy Wind", - "NL": "Fairy Wind", - "NO": "Fairy Wind", - "PL": "Fairy Wind", "FR": "Vent Féérique", "DE": "Feenbrise", "IT": "Vento di Fata", @@ -3720,10 +2551,6 @@ "pokemon_move_352": { "PT-BR": "Esfera Climática", "EN": "Weather Ball", - "FI": "Weather Ball", - "NL": "Weather Ball", - "NO": "Weather Ball", - "PL": "Weather Ball", "FR": "Ball’Météo", "DE": "Meteorologe", "IT": "Palla Clima", @@ -3733,10 +2560,6 @@ "pokemon_move_353": { "PT-BR": "Caninos Psíquicos", "EN": "Psychic Fangs", - "FI": "Psychic Fangs", - "NL": "Psychic Fangs", - "NO": "Psychic Fangs", - "PL": "Psychic Fangs", "FR": "Psycho-Croc", "DE": "Psychobeißer", "IT": "Psicozanna", @@ -3746,10 +2569,6 @@ "pokemon_move_354": { "PT-BR": "Fúria de Hiperespaço", "EN": "Hyperspace Fury", - "FI": "Hyperspace Fury", - "NL": "Hyperspace Fury", - "NO": "Hyperspace Fury", - "PL": "Hyperspace Fury", "FR": "Furie Dimension", "DE": "Dimensionswahn", "IT": "Urtodimensionale", @@ -3759,10 +2578,6 @@ "pokemon_move_355": { "PT-BR": "Fenda de Hiperespaço", "EN": "Hyperspace Hole", - "FI": "Hyperspace Hole", - "NL": "Hyperspace Hole", - "NO": "Hyperspace Hole", - "PL": "Hyperspace Hole", "FR": "TrouDimensionnel", "DE": "Dimensionsloch", "IT": "Forodimensionale", @@ -3772,10 +2587,6 @@ "pokemon_move_356": { "PT-BR": "Chute Duplo", "EN": "Double Kick", - "FI": "Double Kick", - "NL": "Double Kick", - "NO": "Double Kick", - "PL": "Double Kick", "FR": "Double Pied", "DE": "Doppelkick", "IT": "Doppiocalcio", @@ -3785,10 +2596,6 @@ "pokemon_move_357": { "PT-BR": "Folha Mágica", "EN": "Magical Leaf", - "FI": "Magical Leaf", - "NL": "Magical Leaf", - "NO": "Magical Leaf", - "PL": "Magical Leaf", "FR": "Feuille Magik", "DE": "Zauberblatt", "IT": "Fogliamagica", @@ -3798,10 +2605,6 @@ "pokemon_move_358": { "PT-BR": "Fogo Sagrado", "EN": "Sacred Fire", - "FI": "Sacred Fire", - "NL": "Sacred Fire", - "NO": "Sacred Fire", - "PL": "Sacred Fire", "FR": "Feu Sacré", "DE": "Läuterfeuer", "IT": "Magifuoco", @@ -3811,10 +2614,6 @@ "pokemon_move_359": { "PT-BR": "Lança Congelada", "EN": "Icicle Spear", - "FI": "Icicle Spear", - "NL": "Icicle Spear", - "NO": "Icicle Spear", - "PL": "Icicle Spear", "FR": "Stalactite", "DE": "Eisspeer", "IT": "Gelolancia", @@ -3824,10 +2623,6 @@ "pokemon_move_360": { "PT-BR": "Explosão Aérea+", "EN": "Aeroblast+", - "FI": "Aeroblast+", - "NL": "Aeroblast+", - "NO": "Aeroblast+", - "PL": "Aeroblast+", "FR": "Aéroblast+", "DE": "Luftstoß+", "IT": "Aerocolpo+", @@ -3837,10 +2632,6 @@ "pokemon_move_361": { "PT-BR": "Explosão Aérea++", "EN": "Aeroblast++", - "FI": "Aeroblast++", - "NL": "Aeroblast++", - "NO": "Aeroblast++", - "PL": "Aeroblast++", "FR": "Aéroblast++", "DE": "Luftstoß++", "IT": "Aerocolpo++", @@ -3850,10 +2641,6 @@ "pokemon_move_362": { "PT-BR": "Fogo Sagrado+", "EN": "Sacred Fire+", - "FI": "Sacred Fire+", - "NL": "Sacred Fire+", - "NO": "Sacred Fire+", - "PL": "Sacred Fire+", "FR": "Feu Sacré+", "DE": "Läuterfeuer+", "IT": "Magifuoco+", @@ -3863,10 +2650,6 @@ "pokemon_move_363": { "PT-BR": "Fogo Sagrado++", "EN": "Sacred Fire++", - "FI": "Sacred Fire++", - "NL": "Sacred Fire++", - "NO": "Sacred Fire++", - "PL": "Sacred Fire++", "FR": "Feu Sacré++", "DE": "Läuterfeuer++", "IT": "Magifuoco++", @@ -3876,10 +2659,6 @@ "pokemon_move_364": { "PT-BR": "Acrobático", "EN": "Acrobatics", - "FI": "Acrobatics", - "NL": "Acrobatics", - "NO": "Acrobatics", - "PL": "Acrobatics", "FR": "Acrobatie", "DE": "Akrobatik", "IT": "Acrobazia", @@ -3889,10 +2668,6 @@ "pokemon_move_365": { "PT-BR": "Purga de Esplendor", "EN": "Luster Purge", - "FI": "Luster Purge", - "NL": "Luster Purge", - "NO": "Luster Purge", - "PL": "Luster Purge", "FR": "Lumi-Éclat", "DE": "Scheinwerfer", "IT": "Abbagliante", @@ -3902,10 +2677,6 @@ "pokemon_move_366": { "PT-BR": "Bola de Névoa", "EN": "Mist Ball", - "FI": "Mist Ball", - "NL": "Mist Ball", - "NO": "Mist Ball", - "PL": "Mist Ball", "FR": "Ball’Brume", "DE": "Nebelball", "IT": "Foschisfera", @@ -3915,10 +2686,6 @@ "pokemon_move_367": { "PT-BR": "Balanço Violento", "EN": "Brutal Swing", - "FI": "Brutal Swing", - "NL": "Brutal Swing", - "NO": "Brutal Swing", - "PL": "Brutal Swing", "FR": "Centrifugifle", "DE": "Wirbler", "IT": "Vorticolpo", @@ -3928,10 +2695,6 @@ "pokemon_move_368": { "PT-BR": "Rolagem", "EN": "Rollout", - "FI": "Rollout", - "NL": "Rollout", - "NO": "Rollout", - "PL": "Rollout", "FR": "Roulade", "DE": "Walzer", "IT": "Rotolamento", @@ -3941,10 +2704,6 @@ "pokemon_move_369": { "PT-BR": "Semente Ofuscante", "EN": "Seed Flare", - "FI": "Seed Flare", - "NL": "Seed Flare", - "NO": "Seed Flare", - "PL": "Seed Flare", "FR": "Fulmigraine", "DE": "Schocksamen", "IT": "Infuriaseme", @@ -3954,10 +2713,6 @@ "pokemon_move_370": { "PT-BR": "Obstruir", "EN": "Obstruct", - "FI": "Obstruct", - "NL": "Obstruct", - "NO": "Obstruct", - "PL": "Obstruct", "FR": "Blocage", "DE": "Abblocker", "IT": "Sbarramento", @@ -3967,10 +2722,6 @@ "pokemon_move_371": { "PT-BR": "Força das Sombras", "EN": "Shadow Force", - "FI": "Shadow Force", - "NL": "Shadow Force", - "NO": "Shadow Force", - "PL": "Shadow Force", "FR": "Revenant", "DE": "Schemenkraft", "IT": "Oscurotuffo", @@ -3980,10 +2731,6 @@ "pokemon_move_372": { "PT-BR": "Raio Meteórico", "EN": "Meteor Beam", - "FI": "Meteor Beam", - "NL": "Meteor Beam", - "NO": "Meteor Beam", - "PL": "Meteor Beam", "FR": "Laser Météore", "DE": "Meteorstrahl", "IT": "Raggiometeora", @@ -3991,16 +2738,8 @@ "ES": "Rayo Meteórico" }, "pokemon_move_376": { - "PT-BR": "Poltergeist", "EN": "Poltergeist", - "FI": "Poltergeist", - "NL": "Poltergeist", - "NO": "Poltergeist", - "PL": "Poltergeist", "FR": "Esprit Frappeur", - "DE": "Poltergeist", - "IT": "Poltergeist", - "RU": "Полтергейст", - "ES": "Poltergeist" + "RU": "Полтергейст" } } \ No newline at end of file diff --git a/logic.php b/logic.php index 6c8d681d..3665c3d3 100644 --- a/logic.php +++ b/logic.php @@ -4,55 +4,11 @@ // Any new logic functions should be included directly where they are needed, // NOT via this file! -include('logic/active_raid_duplication_check.php'); -include('logic/alarm.php'); -include('logic/check_time.php'); -include('logic/cp_keys.php'); -include('logic/collectCleanup.php'); -include('logic/delete_raid.php'); -include('logic/delete_trainerinfo.php'); -include('logic/disable_raid_level.php'); -include('logic/edit_gym_keys.php'); -include('logic/edit_pokedex_keys.php'); -include('logic/get_chat_title_username.php'); -include('logic/get_formatted_pokemon_cp.php'); -include('logic/get_gym_by_telegram_id.php'); -include('logic/get_gym_details.php'); -include('logic/get_gym.php'); -include('logic/get_local_pokemon_name.php'); -include('logic/get_overview.php'); -include('logic/get_pokemon_by_table_id.php'); -include('logic/get_pokemon_form_name.php'); -include('logic/get_pokemon_id_by_name.php'); -include('logic/get_raid.php'); -include('logic/get_raid_times.php'); -include('logic/get_remote_users_count.php'); -include('logic/get_user.php'); -include('logic/get_weather_icons.php'); -include('logic/group_code_keys.php'); -include('logic/insert_cleanup.php'); -include('logic/insert_overview.php'); -include('logic/insert_trainerinfo.php'); -include('logic/keys_event.php'); -include('logic/keys_trainerinfo.php'); -include('logic/keys_vote.php'); -include('logic/mapslink.php'); -include('logic/new_user.php'); -include('logic/pokemon_keys.php'); -include('logic/raid_edit_gym_keys.php'); -include('logic/raid_edit_gyms_first_letter_keys.php'); -include('logic/raid_edit_raidlevel_keys.php'); -include('logic/raid_get_gyms_list_keys.php'); -include('logic/raid_list.php'); -include('logic/raid_poll_message.php'); -include('logic/sendalarmnotice.php'); -include('logic/send_trainerinfo.php'); -include('logic/send_vote_remote_users_limit_reached.php'); -include('logic/send_vote_time_first.php'); -include('logic/send_vote_time_future.php'); -include('logic/show_raid_poll.php'); -include('logic/show_raid_poll_small.php'); -include('logic/show_trainerinfo.php'); -include('logic/weather_keys.php'); -include('logic/curl_get_contents.php'); -?> +require_once('logic/date_util.php'); +require_once('logic/geo_api.php'); +require_once('logic/key_util.php'); +require_once('logic/language.php'); +require_once('logic/collectCleanup.php'); +require_once('logic/get_local_pokemon_name.php'); +require_once('logic/get_raid.php'); +require_once('logic/new_user.php'); diff --git a/logic/active_raid_duplication_check.php b/logic/active_raid_duplication_check.php index 33a253db..c61bb4df 100644 --- a/logic/active_raid_duplication_check.php +++ b/logic/active_raid_duplication_check.php @@ -1,42 +1,38 @@ (UTC_TIMESTAMP() - INTERVAL 5 MINUTE) + AND gym_id = ? + ' . $levelSql . ' + ORDER BY end_time, event IS NOT NULL + ', $args + ); + while($raid = $rs->fetch()) { + // In some cases (ex-raids, event raids and elite raids) gyms can have multiple raids saved to them. + // We ignore these raids when performing the duplication check. + if( ($config->RAID_EXCLUDE_EXRAID_DUPLICATION && $raid['event'] == EVENT_ID_EX) + or ($level != 9 && $config->RAID_EXCLUDE_ELITE_DUPLICATION && $raid['level'] == 9) + or ($config->RAID_EXCLUDE_EVENT_DUPLICATION && $raid['event'] !== NULL && $raid['event'] != EVENT_ID_EX)) { + continue; } - // Build query. - $rs = my_query( - ' - SELECT id, event, level - FROM raids - WHERE end_time > (UTC_TIMESTAMP() - INTERVAL 5 MINUTE) - AND gym_id = ? - ' . $levelSql . ' - ORDER BY end_time, event IS NOT NULL - ', $args - ); - $active = 0; - while($raid = $rs->fetch()) { - // In some cases (ex-raids, event raids and elite raids) gyms can have multiple raids saved to them. - // We ignore these raids when performing the duplication check. - if( ($config->RAID_EXCLUDE_EXRAID_DUPLICATION && $raid['event'] == EVENT_ID_EX) - or ($level != 9 && $config->RAID_EXCLUDE_ELITE_DUPLICATION && $raid['level'] == 9) - or ($config->RAID_EXCLUDE_EVENT_DUPLICATION && $raid['event'] !== NULL && $raid['event'] != EVENT_ID_EX)) { - continue; - } - $active = $raid['id']; - break; - } - return $active; + return $raid['id']; + } + return 0; } - -?> diff --git a/logic/alarm.php b/logic/alarm.php index 1ef4174c..bc65bfc2 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -1,4 +1,5 @@ fetch(); - // Get Trainername - $answer_quests = check_trainername($answer_quests); - $username = '' . $answer_quests['name'] . ''; - // Get Trainercode - $trainercode = $answer_quests['trainercode']; - } + // Get user info if it's needed for the alarm + if(!empty($user_id)) { + // Name of the user, which executes a status update + $requestUserinfo = my_query('SELECT * FROM users WHERE user_id = ? LIMIT 1', [$user_id]); + $answer_quests = $requestUserinfo->fetch(); + // Get Trainername + $answer_quests = check_trainername($answer_quests); + $username = '' . $answer_quests['name'] . ''; + // Get Trainercode + $trainercode = $answer_quests['trainercode']; + } - // Gym name and raid times - if(is_array($raid_id_array)) { - $raid = $raid_id_array; - }else { - $raid = get_raid($raid_id_array); - } - $raid_id = $raid['id']; + // Gym name and raid times + $raid = (is_array($raid_id_array) ? $raid_id_array : get_raid($raid_id_array)); - $gymname = $raid['gym_name']; - $raidtimes = str_replace(CR, '', str_replace(' ', '', get_raid_times($raid, false, true))); + $raid_id = $raid['id']; - // Get attend time. - if(!in_array($action, ['new_att','new_boss','change_time','group_code_private','group_code_public'])) { - $r = my_query("SELECT DISTINCT attend_time FROM attendance WHERE raid_id = {$raid_id} and user_id = {$user_id}"); - $a = $r->fetch(); - if(isset($a['attend_time'])) { - $attendtime = $a['attend_time']; - }else { - $attendtime = 0; - } - } + $gymname = $raid['gym_name']; + $raidtimes = str_replace(CR, '', str_replace(' ', '', get_raid_times($raid, false, true))); - if($action == 'group_code_public' or $action == 'group_code_private') { - $request = my_query(" SELECT DISTINCT attendance.user_id, attendance.remote, users.lang - FROM attendance - LEFT JOIN users - ON users.user_id = attendance.user_id - WHERE raid_id = {$raid_id} - AND attend_time = (SELECT attend_time from attendance WHERE raid_id = {$raid_id} AND user_id = {$user_id}) - "); - }else { - $request = my_query(" SELECT DISTINCT attendance.user_id, users.lang - FROM attendance - LEFT JOIN users - ON users.user_id = attendance.user_id - WHERE raid_id = {$raid_id} - AND attendance.user_id != {$user_id} - AND cancel = 0 - AND raid_done = 0 - AND alarm = 1 - "); - } + // Get attend time. + if(!in_array($action, ['new_att','new_boss','change_time','group_code_private','group_code_public'])) { + $r = my_query('SELECT DISTINCT attend_time FROM attendance WHERE raid_id = ? and user_id = ? LIMIT 1', [$raid_id, $user_id]); + $a = $r->fetch(); - while($answer = $request->fetch()) - { - if(!isset($answer['lang']) or empty($answer['lang'])) $recipient_language = $config->LANGUAGE_PUBLIC; - else $recipient_language = $GLOBALS['languages'][$answer['lang']]; - // Adding a guest - if($action == "extra") { - debug_log('Alarm additional trainer: ' . $info); - $icons = ['alien' => EMOJI_ALIEN, 'in_person' => EMOJI_IN_PERSON]; + $attendtime = isset($a['attend_time']) ? $a['attend_time'] : 0; + } - // Sending message - if($info == 'alien') { - $msg_text = '' . getTranslation('alert_add_alien_trainer', $recipient_language) . '' . CR; - }else { - $msg_text = '' . getTranslation('alert_add_trainer', $recipient_language) . '' . CR; - } - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . SP . '+' . $icons[$info] . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); - $msg_text .= create_traincode_msg($trainercode); + if($action == 'group_code_public' or $action == 'group_code_private') { + $request = my_query(' + SELECT DISTINCT attendance.user_id, attendance.remote, users.lang + FROM attendance + LEFT JOIN users + ON users.user_id = attendance.user_id + WHERE raid_id = :raidId + AND attend_time = (SELECT attend_time from attendance WHERE raid_id = :raidId AND user_id = :userId) + ', ['raidId' => $raid_id, 'userId' => $user_id]); + }else { + $request = my_query(' + SELECT DISTINCT attendance.user_id, users.lang + FROM attendance + LEFT JOIN users + ON users.user_id = attendance.user_id + WHERE raid_id = :raidId + AND attendance.user_id != :userId + AND cancel = 0 + AND raid_done = 0 + AND alarm = 1 + ', ['raidId' => $raid_id, 'userId' => $user_id]); + } - // Updating status - here or cancel - } else if($action == "status") { - // If trainer changes state (to late or cancelation) - if($info == 'late') { - debug_log('Alarm late: ' . $info); - // Send message. - $msg_text = '' . getTranslation('alert_later', $recipient_language) . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); - $msg_text .= create_traincode_msg($trainercode); - } else if($info == 'cancel') { - debug_log('Alarm cancel: ' . $info); - $msg_text = '' . getTranslation('alert_cancel', $recipient_language) . '' . CR; - $msg_text .= TEAM_CANCEL . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); - } + while($answer = $request->fetch()) + { + if(!isset($answer['lang']) or empty($answer['lang'])) $recipient_language = $config->LANGUAGE_PUBLIC; + else $recipient_language = $GLOBALS['languages'][$answer['lang']]; + // Adding a guest + if($action == 'extra') { + debug_log('Alarm additional trainer: ' . $info); + $icons = ['alien' => EMOJI_ALIEN, 'in_person' => EMOJI_IN_PERSON]; - // Updating pokemon - } else if($action == "pok_individual") { - debug_log('Alarm Pokemon: ' . $info); + // Sending message + if($info == 'alien') { + $msg_text = '' . getTranslation('alert_add_alien_trainer', $recipient_language) . '' . CR; + }else { + $msg_text = '' . getTranslation('alert_add_trainer', $recipient_language) . '' . CR; + } + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . SP . '+' . $icons[$info] . CR; + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= create_traincode_msg($trainercode); - // Only a specific pokemon - if($info != '0') { - $pokemon = explode("-",$info,2); - $poke_name = get_local_pokemon_name($pokemon[0],$pokemon[1]); - $msg_text = '' . getTranslation('alert_individual_poke', $recipient_language) . SP . $poke_name . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); - $msg_text .= create_traincode_msg($trainercode); - // Any pokemon - } else { - $msg_text = '' . getTranslation('alert_every_poke', $recipient_language) . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); - $msg_text .= create_traincode_msg($trainercode); - } + // Updating status - here or cancel + } else if($action == 'status') { + // If trainer changes state (to late or cancelation) + if($info == 'late') { + debug_log('Alarm late: ' . $info); + // Send message. + $msg_text = '' . getTranslation('alert_later', $recipient_language) . '' . CR; + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= create_traincode_msg($trainercode); + } else if($info == 'cancel') { + debug_log('Alarm cancel: ' . $info); + $msg_text = '' . getTranslation('alert_cancel', $recipient_language) . '' . CR; + $msg_text .= TEAM_CANCEL . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + } - // Cancel pokemon - } else if($action == "pok_cancel_individual") { - debug_log('Alarm Pokemon: ' . $info); - $pokemon = explode("-",$info,2); - $poke_name = get_local_pokemon_name($pokemon[0],$pokemon[1]); - $msg_text = '' . getTranslation('alert_cancel_individual_poke', $recipient_language) . SP . $poke_name . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); - $msg_text .= create_traincode_msg($trainercode); + // Updating pokemon + } else if($action == 'pok_individual') { + debug_log('Alarm Pokemon: ' . $info); - } else if($action == "new_boss") { - $msg_text = '' . getTranslation('alert_raid_boss') . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_EGG . SP . '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . '' . CR; + if($info != '0') { + // Only a specific pokemon + $pokemon = explode("-",$info,2); + $poke_name = get_local_pokemon_name($pokemon[0],$pokemon[1]); + $msg_text = '' . getTranslation('alert_individual_poke', $recipient_language) . SP . $poke_name . '' . CR; + } else { + // Any pokemon + $msg_text = '' . getTranslation('alert_every_poke', $recipient_language) . '' . CR; + } + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= create_traincode_msg($trainercode); - // New attendance - } else if($action == "new_att") { - debug_log('Alarm new attendance: ' . $info); - // Will Attend - $msg_text = '' . getTranslation('alert_new_att', $recipient_language) . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($info); - $msg_text .= create_traincode_msg($trainercode); + // Cancel pokemon + } else if($action == 'pok_cancel_individual') { + debug_log('Alarm Pokemon: ' . $info); + $pokemon = explode("-",$info,2); + $poke_name = get_local_pokemon_name($pokemon[0],$pokemon[1]); + $msg_text = '' . getTranslation('alert_cancel_individual_poke', $recipient_language) . SP . $poke_name . '' . CR; + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= create_traincode_msg($trainercode); - // Attendance time change - } else if($action == "change_time") { - debug_log('Alarm changed attendance time: ' . $info); - // Changes Time - $msg_text = '' . getTranslation('alert_change_time', $recipient_language) . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($info) . ''; - $msg_text .= create_traincode_msg($trainercode); + } else if($action == 'new_boss') { + $msg_text = '' . getTranslation('alert_raid_boss') . '' . CR; + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_EGG . SP . '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . '' . CR; - // Attendance from remote - } else if($action == "remote") { - debug_log('Alarm remote attendance changed: ' . $info); - // Changes Time - $msg_text = '' . getTranslation('alert_remote', $recipient_language) . '' . CR; - $msg_text .= EMOJI_REMOTE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; - $msg_text .= create_traincode_msg($trainercode); + // New attendance + } else if($action == 'new_att') { + debug_log('Alarm new attendance: ' . $info); + // Will Attend + $msg_text = '' . getTranslation('alert_new_att', $recipient_language) . '' . CR; + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . check_time($info); + $msg_text .= create_traincode_msg($trainercode); - // Attendance no longer from remote - } else if($action == "no_remote") { - debug_log('Alarm remote attendance changed: ' . $info); - // Changes Time - $msg_text = '' . getTranslation('alert_no_remote', $recipient_language) . '' . CR; - $msg_text .= EMOJI_REMOTE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + // Attendance time change + } else if($action == 'change_time') { + debug_log('Alarm changed attendance time: ' . $info); + // Changes Time + $msg_text = '' . getTranslation('alert_change_time', $recipient_language) . '' . CR; + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($info) . ''; + $msg_text .= create_traincode_msg($trainercode); - // No additional trainer - } else if($action == "extra_alone") { - debug_log('Alarm no additional trainers: ' . $info); - $msg_text = '' . getTranslation('alert_extra_alone', $recipient_language) . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); - $msg_text .= create_traincode_msg($trainercode); + // Attendance from remote + } else if($action == 'remote') { + debug_log('Alarm remote attendance changed: ' . $info); + // Changes Time + $msg_text = '' . getTranslation('alert_remote', $recipient_language) . '' . CR; + $msg_text .= EMOJI_REMOTE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= create_traincode_msg($trainercode); - // Group code public - } else if($action == "group_code_public") { - debug_log('Alarm for group code: ' . $info); - $msg_text = '' . getTranslation('alert_raid_starts_now', $recipient_language) . CR . getTranslation('alert_raid_get_in', $recipient_language) . '' . CR . CR; - $msg_text .= '' . getTranslation('alert_public_group', $recipient_language) . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_REMOTE . SP . $info; + // Attendance no longer from remote + } else if($action == 'no_remote') { + debug_log('Alarm remote attendance changed: ' . $info); + // Changes Time + $msg_text = '' . getTranslation('alert_no_remote', $recipient_language) . '' . CR; + $msg_text .= EMOJI_REMOTE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; - // Group code private - } else if($action == "group_code_private") { - debug_log('Alarm for group code: ' . $info); - $msg_text = '' . getTranslation('alert_raid_starts_now', $recipient_language) . CR . getTranslation('alert_raid_get_in', $recipient_language) . '' . CR . CR; - $msg_text .= '' . getTranslation('alert_private_group', $recipient_language) . '' . CR; - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; + // No additional trainer + } else if($action == 'extra_alone') { + debug_log('Alarm no additional trainers: ' . $info); + $msg_text = '' . getTranslation('alert_extra_alone', $recipient_language) . '' . CR; + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= create_traincode_msg($trainercode); - // Send code to remote raiders - if($answer['remote'] == 1) { - $msg_text .= EMOJI_REMOTE . SP . '' . $info . ''; - } + // Group code public + } else if($action == 'group_code_public') { + debug_log('Alarm for group code: ' . $info); + $msg_text = '' . getTranslation('alert_raid_starts_now', $recipient_language) . CR . getTranslation('alert_raid_get_in', $recipient_language) . '' . CR . CR; + $msg_text .= '' . getTranslation('alert_public_group', $recipient_language) . '' . CR; + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_REMOTE . SP . $info; - // Send message to local raiders - if($answer['remote'] == 0) { - $msg_text .= EMOJI_REMOTE . SP . '' . getTranslation('group_code_only_for_remote_raiders', $recipient_language) . ''; - } - // Attendance from remote - } else if($action == "want_invite") { - debug_log('Alarm invite begging changed: ' . $info); - $msg_text = '' . getTranslation('alert_want_invite', $recipient_language) . '' . CR; - $msg_text .= EMOJI_WANT_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; - $msg_text .= create_traincode_msg($trainercode); + // Group code private + } else if($action == 'group_code_private') { + debug_log('Alarm for group code: ' . $info); + $msg_text = '' . getTranslation('alert_raid_starts_now', $recipient_language) . CR . getTranslation('alert_raid_get_in', $recipient_language) . '' . CR . CR; + $msg_text .= '' . getTranslation('alert_private_group', $recipient_language) . '' . CR; + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; - // Attendance no longer from remote - } else if($action == "no_want_invite") { - debug_log('Alarm invite begging changed: ' . $info); - $msg_text = '' . getTranslation('alert_no_want_invite', $recipient_language) . '' . CR; - $msg_text .= EMOJI_WANT_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; - $msg_text .= create_traincode_msg($trainercode); + // Send code to remote raiders + if($answer['remote'] == 1) { + $msg_text .= EMOJI_REMOTE . SP . '' . $info . ''; + } - // Let others know you are not playing, but can invite others - } else if($action == "can_invite") { - debug_log('Alarm: ' . $action); - $msg_text = '' . getTranslation('alert_can_invite', $recipient_language) . '' . CR; - $msg_text .= EMOJI_CAN_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; - $msg_text .= create_traincode_msg($trainercode); + // Send message to local raiders + if($answer['remote'] == 0) { + $msg_text .= EMOJI_REMOTE . SP . '' . getTranslation('group_code_only_for_remote_raiders', $recipient_language) . ''; + } + // Attendance from remote + } else if($action == 'want_invite') { + debug_log('Alarm invite begging changed: ' . $info); + $msg_text = '' . getTranslation('alert_want_invite', $recipient_language) . '' . CR; + $msg_text .= EMOJI_WANT_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= create_traincode_msg($trainercode); - // Let others know you are not longer able to invite them - } else if($action == "no_can_invite") { - debug_log('Alarm: ' . $action); - $msg_text = '' . getTranslation('alert_no_can_invite', $recipient_language) . '' . CR; - $msg_text .= EMOJI_CAN_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; - $msg_text .= create_traincode_msg($trainercode); - } - $tg_json[] = send_message($answer['user_id'], $msg_text, false, false, true); + // Attendance no longer from remote + } else if($action == 'no_want_invite') { + debug_log('Alarm invite begging changed: ' . $info); + $msg_text = '' . getTranslation('alert_no_want_invite', $recipient_language) . '' . CR; + $msg_text .= EMOJI_WANT_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= create_traincode_msg($trainercode); + + // Let others know you are not playing, but can invite others + } else if($action == 'can_invite') { + debug_log('Alarm: ' . $action); + $msg_text = '' . getTranslation('alert_can_invite', $recipient_language) . '' . CR; + $msg_text .= EMOJI_CAN_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= create_traincode_msg($trainercode); + + // Let others know you are not longer able to invite them + } else if($action == 'no_can_invite') { + debug_log('Alarm: ' . $action); + $msg_text = '' . getTranslation('alert_no_can_invite', $recipient_language) . '' . CR; + $msg_text .= EMOJI_CAN_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; + $msg_text .= EMOJI_SINGLE . SP . $username . CR; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= create_traincode_msg($trainercode); } - return $tg_json; + $tg_json[] = send_message($answer['user_id'], $msg_text, false, false, true); + } + return $tg_json; } /** @@ -271,9 +264,20 @@ function create_traincode_msg($trainercode){ global $config; $message = ''; if($config->RAID_POLL_SHOW_TRAINERCODE == true && !is_null($trainercode)) { - $message = CR . EMOJI_FRIEND . SP . '' . $trainercode . ''; + $message = CR . EMOJI_FRIEND . SP . '' . $trainercode . ''; } return $message; } -?> +/** + * Check attendance time against anytime. + * @param $time + */ +function check_time($time) +{ + // Raid anytime? + if(strcmp($time, ANYTIME)===0){ + return getTranslation('anytime'); + } + return dt2time($time); +} diff --git a/logic/bearer_token.php b/logic/bearer_token.php new file mode 100644 index 00000000..0884ec58 --- /dev/null +++ b/logic/bearer_token.php @@ -0,0 +1,31 @@ + $version), CONFIG_PATH . '/config.json'); +} + +/** + * Get current code revision from git state, or 'manual' if no git state exists. + * @return string + */ +function get_rev() +{ + if (!file_exists(ROOT_PATH . '/.git/HEAD')){ + debug_log('No .git/HEAD present, marking revision as manual'); + return 'manual'; + } + $ref = trim(file_get_contents(ROOT_PATH . '/.git/HEAD')); + if (ctype_xdigit($ref)){ + // Is already a hex string and thus valid rev + // Return first 6 digits of the hash + return substr($ref, 0, 6); + } + // strip 'ref: ' to get file path + $ref_file = ROOT_PATH . '/.git/' . substr($ref, 5); + if (file_exists($ref_file)){ + // Return first 6 digits of the hash, this matches our naming of docker image tags + return substr(file_get_contents($ref_file), 0, 6); + } + error_log("Git ref found but we cannot resolve it to a revision ({$ref_file}). Was the .git folder mangled?"); + return 'manual'; +} + +/** + * Bot upgrade check + * @param $current + * @param $latest + * @return bool: if a manual upgrade is needed + */ +function bot_upgrade_check($current, $latest) +{ + global $config, $metrics, $namespace; + $orig = $current; // we may have to do multiple upgrades + if ($metrics){ + // This is the one place where we have full knowledge of version information & upgrades + debug_log('init upgrade metrics'); + $version_info = $metrics->registerGauge($namespace, 'version_info', 'Schema and revision information', ['current_schema', 'required_schema', 'rev', 'upgraded_timestamp', 'upgraded_from']); + } + + $upgrade_verdict = null; + $manual_upgrade_verdict = null; + // Same version? + if($current == $latest) { + return; + } + $upgrade_verdict = true; + if ($metrics && IS_INIT){ + // record initial version even if we don't do upgrades. + $version_info->set(1, [$current, $latest, get_rev(), null, null]); + } + // Check if upgrade files exist. + $upgrade_files = array(); + $upgrade_files = str_replace(UPGRADE_PATH . '/','', glob(UPGRADE_PATH . '/*.sql')); + if(!is_array($upgrade_files) or count($upgrade_files) == 0 or !in_array($latest . '.sql', $upgrade_files)) { + // No upgrade files found! Since the version now would only go up with upgrade files, something is off. + // It could be the user has bumped the VERSION file manually, or omitted upgrade files. + $error = 'NO SQL UPGRADE FILES FOUND FOR LATEST SCHEMA, THIS SHOULD NOT HAPPEN'; + throw new Exception($error); + } + // Check each sql filename. + foreach ($upgrade_files as $ufile) + { + $target = str_replace('.sql', '', $ufile); + // Skip every older sql file from array. + if($target <= $current) continue; + + if (!$config->UPGRADE_SQL_AUTO){ + $manual_upgrade_verdict = true; + debug_log("There's a schema upgrade to {$target} we could have run, but auto-upgrades have been disabled!"); + break; + } + info_log('PERFORMING AUTO SQL UPGRADE: ' . UPGRADE_PATH . '/' . $ufile, '!'); + require_once('sql_utils.php'); + if (!run_sql_file(UPGRADE_PATH . '/' . $ufile)) { + $manual_upgrade_verdict = true; + $error = 'AUTO UPGRADE FAILED: ' . UPGRADE_PATH . '/' . $ufile; + throw new Exception($error); + } + $manual_upgrade_verdict = false; + upgrade_config_version($target); + if ($metrics){ + $version_info->set(1, [$target, $latest, get_rev(), time(), $current]); + } + $current = $target; + } + // If previous sql upgrades had to be done and were successful, update also pokemon table + if($upgrade_verdict === true && $manual_upgrade_verdict === false) { + require_once(ROOT_PATH . '/mods/getdb.php'); + } + + // Signal whether manual action is required or not. + if ($manual_upgrade_verdict === true){ + $error = "The bot has pending schema upgrades ({$current} -> {$latest}) but you've disabled automatic upgrades. Nothing will work until you go do the upgrade(s) manually. You'll find them in the dir sql/upgrade/"; + throw new Exception($error); + } +} diff --git a/logic/check_time.php b/logic/check_time.php deleted file mode 100644 index f1e6af25..00000000 --- a/logic/check_time.php +++ /dev/null @@ -1,16 +0,0 @@ - diff --git a/logic/collectCleanup.php b/logic/collectCleanup.php index 53274d71..6970f7fd 100644 --- a/logic/collectCleanup.php +++ b/logic/collectCleanup.php @@ -1,8 +1,11 @@ $largest_size) { - $largest_size = $photo['file_size']; - $save_id = $photo['file_id']; - $unique_id = $photo['file_unique_id']; - } - } - $standalone_photo = (array_key_exists('standalone_photo', $identifier) && $identifier['standalone_photo'] === true) ? 1 : 0; - my_query(" - REPLACE INTO photo_cache - VALUES (:id, :unique_id, :pokedex_id, :form_id, :raid_id, :ended, :gym_id, :standalone) - ",[ - ':id' => $save_id, - ':unique_id' => $unique_id, - ':pokedex_id' => $identifier['pokemon'], - ':form_id' => $identifier['pokemon_form'], - ':raid_id' => ($identifier['raid_ended'] ? 0 : $identifier['id']), // No need to save raid id if raid has ended - ':ended' => $identifier['raid_ended'], - ':gym_id' => $identifier['gym_id'], - ':standalone' => $standalone_photo, - ] - ); + return $response; + } + + if(isset($response['result']['text']) && !empty($response['result']['text'])) { + $type = 'poll_text'; + } else if(isset($response['result']['caption']) && !empty($response['result']['caption'])) { + $type = 'poll_photo'; + } else if(isset($response['result']['venue']) && !empty($response['result']['venue'])) { + $type = 'poll_venue'; + }else if(isset($response['result']['photo']) && !isset($response['result']['caption'])) { + $type = 'photo'; + } + $save_id = $unique_id = false; + if(isset($response['result']['photo'])) { + $largest_size = 0; + foreach($response['result']['photo'] as $photo) { + if($photo['file_size'] < $largest_size) continue; + $largest_size = $photo['file_size']; + $save_id = $photo['file_id']; + $unique_id = $photo['file_unique_id']; } - $raid_id = is_array($identifier) ? $identifier['id'] : $identifier; - insert_cleanup($chat_id, $message_id, $raid_id, $type, $unique_id); + $standalone_photo = (array_key_exists('standalone_photo', $identifier) && $identifier['standalone_photo'] === true) ? 1 : 0; + my_query(' + REPLACE INTO photo_cache + VALUES (:id, :unique_id, :pokedex_id, :form_id, :raid_id, :ended, :gym_id, :standalone) + ',[ + ':id' => $save_id, + ':unique_id' => $unique_id, + ':pokedex_id' => $identifier['pokemon'], + ':form_id' => $identifier['pokemon_form'], + ':raid_id' => ($identifier['raid_ended'] ? 0 : $identifier['id']), // No need to save raid id if raid has ended + ':ended' => $identifier['raid_ended'], + ':gym_id' => $identifier['gym_id'], + ':standalone' => $standalone_photo, + ] + ); } + $raid_id = is_array($identifier) ? $identifier['id'] : $identifier; + insert_cleanup($chat_id, $message_id, $raid_id, $type, $unique_id); // Return response. return $response; } - -?> diff --git a/logic/cp_keys.php b/logic/cp_keys.php deleted file mode 100644 index 0d68cc1a..00000000 --- a/logic/cp_keys.php +++ /dev/null @@ -1,106 +0,0 @@ - $i, - 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_cp - ); - } - - // 4 5 6 - for ($i = 4; $i <= 6; $i = $i + 1) { - // Set new cp - $new_cp = $cp_add . ($old_cp == 0 ? '' : $old_cp) . $i; - - // Set keys. - $keys[] = array( - 'text' => $i, - 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_cp - ); - } - - // 1 2 3 - for ($i = 1; $i <= 3; $i = $i + 1) { - // Set new cp - $new_cp = $cp_add . ($old_cp == 0 ? '' : $old_cp) . $i; - - // Set keys. - $keys[] = array( - 'text' => $i, - 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_cp - ); - } - - // 0 - if($old_cp != 0) { - // Set new cp - $new_cp = $cp_add . $old_cp . '0'; - } else { - $new_cp = $reset_arg; - } - - // Set keys. - $keys[] = array( - 'text' => '0', - 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_cp - ); - } - - // Save - $keys[] = array( - 'text' => EMOJI_DISK, - 'callback_data' => $pokedex_id . ':' . $action . ':' . $save_arg - ); - - // Reset - $keys[] = array( - 'text' => getTranslation('reset'), - 'callback_data' => $pokedex_id . ':' . $action . ':' . $reset_arg - ); - - // Get the inline key array. - $keys = inline_key_array($keys, 3); - - return $keys; -} - -?> diff --git a/logic/curl_get_contents.php b/logic/curl_get_contents.php index 1f32f4db..2f829770 100644 --- a/logic/curl_get_contents.php +++ b/logic/curl_get_contents.php @@ -1,22 +1,20 @@ diff --git a/logic/date_util.php b/logic/date_util.php new file mode 100644 index 00000000..f8af7bb2 --- /dev/null +++ b/logic/date_util.php @@ -0,0 +1,101 @@ +format('Y-m-d'); +} + +/** + * Get current utc datetime. + * @param $format + * @return string + */ +function utcnow($format = 'Y-m-d H:i:s') +{ + // Create a object with UTC timezone + $datetime = new DateTime('now', new DateTimeZone('UTC')); + + return $datetime->format($format); +} + +/** + * Format utc time from datetime value. + * @param $datetime_value + * @param $format + * @return string + */ +function utctime($datetime_value, $format = 'H:i') +{ + // Create a object with UTC timezone + $datetime = new DateTime($datetime_value, new DateTimeZone('UTC')); + + return $datetime->format($format); +} + +/** + * Get date from datetime value. + * @param $datetime_value + * @param $tz + * @return string + */ +function dt2date($datetime_value, $tz = NULL) +{ + global $config; + if($tz == NULL){ + $tz = $config->TIMEZONE; + } + // Create a object with UTC timezone + $datetime = new DateTime($datetime_value, new DateTimeZone('UTC')); + + // Change the timezone of the object without changing it's time + $datetime->setTimezone(new DateTimeZone($tz)); + + return $datetime->format('Y-m-d'); +} + +/** + * Get time from datetime value. + * @param $datetime_value + * @param $format + * @param $tz + * @return string + */ +function dt2time($datetime_value, $format = 'H:i', $tz = NULL) +{ + global $config; + if($tz == NULL){ + $tz = $config->TIMEZONE; + } + // Create a object with UTC timezone + $datetime = new DateTime($datetime_value, new DateTimeZone('UTC')); + + // Change the timezone of the object without changing it's time + $datetime->setTimezone(new DateTimeZone($tz)); + + return $datetime->format($format); +} + +function tz_diff($src = 'UTC', $dst = NULL) { + global $config; + if($dst == NULL){ + $dst = $config->TIMEZONE; + } + $dateTimeZoneSrc = new DateTimeZone($src); + $dateTimeZoneDst = new DateTimeZone($dst); + $dateTimeSrc = new datetime('now',$dateTimeZoneSrc); + $diff = $dateTimeZoneDst->getOffset($dateTimeSrc); + + $hours = str_pad(floor($diff/60/60),2,'0',STR_PAD_LEFT); + $minutes = str_pad(floor(($diff-$hours*60*60)/60),2,'0',STR_PAD_LEFT); + if($diff < 0) { + return '-'.$hours.':'.$minutes; + } + return '+'.$hours.':'.$minutes; +} diff --git a/core/bot/logic/debug.php b/logic/debug.php similarity index 64% rename from core/bot/logic/debug.php rename to logic/debug.php index caa1e6e7..b698cdc7 100644 --- a/core/bot/logic/debug.php +++ b/logic/debug.php @@ -37,36 +37,36 @@ */ function generic_log($val, $type, $logfile) { - $date = @date('Y-m-d H:i:s'); - $usec = microtime(true); - $date = $date . '.' . str_pad(substr($usec, 11, 4), 4, '0', STR_PAD_RIGHT); + $date = @date('Y-m-d H:i:s'); + $usec = microtime(true); + $date = $date . '.' . str_pad(substr($usec, 11, 4), 4, '0', STR_PAD_RIGHT); - $bt = debug_backtrace(); - $bl = ''; + $bt = debug_backtrace(); + $bl = ''; - // How many calls back to print - // Increasing this makes it easier to hunt down issues, but increases log line length - $layers = 1; + // How many calls back to print + // Increasing this makes it easier to hunt down issues, but increases log line length + $layers = 1; - while ($btl = array_shift($bt)) { - // Ignore generic_log and it's calling function in the call stack - // Not sure why it works exactly like that, but it does. - if ($btl['function'] == __FUNCTION__){ - continue; - } - --$layers; - $bl = $bl . '[' . basename($btl['file']) . ':' . $btl['line'] . ']'; - if($layers <= 0) { - $bl = $bl . ' '; - break; - } + while ($btl = array_shift($bt)) { + // Ignore generic_log and it's calling function in the call stack + // Not sure why it works exactly like that, but it does. + if ($btl['function'] == __FUNCTION__){ + continue; } - - if (gettype($val) != 'string') $val = var_export($val, 1); - $rows = explode("\n", $val); - foreach ($rows as $v) { - error_log('[' . $date . '][' . getmypid() . '] ' . $bl . $type . ' ' . $v . "\n", 3, $logfile); + --$layers; + $bl = $bl . '[' . basename($btl['file']) . ':' . $btl['line'] . ']'; + if($layers <= 0) { + $bl = $bl . ' '; + break; } + } + + if (gettype($val) != 'string') $val = var_export($val, 1); + $rows = explode("\n", $val); + foreach ($rows as $v) { + error_log('[' . $date . '][' . getmypid() . '] ' . $bl . $type . ' ' . $v . "\n", 3, $logfile); + } } /** @@ -76,12 +76,12 @@ function generic_log($val, $type, $logfile) */ function debug_log($message, $type = '*') { - global $config; - // Write to log only if debug is enabled. - if ($config->DEBUG === false){ - return; - } - generic_log($message, $type, $logfile = $config->DEBUG_LOGFILE); + global $config; + // Write to log only if debug is enabled. + if ($config->DEBUG === false){ + return; + } + generic_log($message, $type, $logfile = $config->DEBUG_LOGFILE); } /** @@ -95,7 +95,7 @@ function cleanup_log($message, $type = '*'){ if ($config->CLEANUP_LOG === false){ return; } - generic_log($message, $type, $logfile = $config->CLEANUP_LOGFILE); + generic_log($message, $type, $logfile = $config->CLEANUP_LOGFILE); } /** diff --git a/logic/delete_raid.php b/logic/delete_raid.php deleted file mode 100644 index ade9f0f3..00000000 --- a/logic/delete_raid.php +++ /dev/null @@ -1,63 +0,0 @@ - 0 - " - ); - - // Counter - $counter = 0; - - // Delete every telegram message - while ($row = $rs->fetch()) { - // Delete telegram message. - debug_log('Deleting telegram message ' . $row['message_id'] . ' from chat ' . $row['chat_id'] . ' for raid ' . $row['raid_id']); - delete_message($row['chat_id'], $row['message_id']); - $counter = $counter + 1; - } - - // Nothing to delete on telegram. - if ($counter == 0) { - debug_log('Raid with ID ' . $raid_id . ' was not found in the cleanup table! Skipping deletion of telegram messages!'); - } - - // Delete raid from cleanup table. - debug_log('Deleting raid ' . $raid_id . ' from the cleanup table:'); - $rs_cleanup = my_query( - " - DELETE FROM cleanup - WHERE raid_id = '{$raid_id}' - " - ); - - // Delete raid from attendance table. - debug_log('Deleting raid ' . $raid_id . ' from the attendance table:'); - $rs_attendance = my_query( - " - DELETE FROM attendance - WHERE raid_id = '{$raid_id}' - " - ); - - // Delete raid from raid table. - debug_log('Deleting raid ' . $raid_id . ' from the raid table:'); - $rs_raid = my_query( - " - DELETE FROM raids - WHERE id = '{$raid_id}' - " - ); -} - - -?> diff --git a/logic/delete_trainerinfo.php b/logic/delete_trainerinfo.php index 46d88d1c..587bcace 100644 --- a/logic/delete_trainerinfo.php +++ b/logic/delete_trainerinfo.php @@ -6,18 +6,15 @@ */ function delete_trainerinfo($chat_id, $message_id) { - // Delete telegram message. - debug_log('Deleting trainer info telegram message ' . $message_id . ' from chat ' . $chat_id); - delete_message($chat_id, $message_id); + // Delete telegram message. + debug_log('Deleting trainer info telegram message ' . $message_id . ' from chat ' . $chat_id); + delete_message($chat_id, $message_id); - // Delete trainer info from database. - debug_log('Deleting trainer information from database for Chat_ID: ' . $chat_id); - $rs = my_query( - " - DELETE FROM trainerinfo - WHERE chat_id = '{$chat_id}' - " - ); + // Delete trainer info from database. + debug_log('Deleting trainer information from database for Chat_ID: ' . $chat_id); + my_query(' + DELETE FROM trainerinfo + WHERE chat_id = ? + ', [$chat_id] + ); } - -?> diff --git a/logic/disable_raid_level.php b/logic/disable_raid_level.php index 55fd8fe3..977591a4 100644 --- a/logic/disable_raid_level.php +++ b/logic/disable_raid_level.php @@ -1,19 +1,15 @@ diff --git a/logic/download_Portal_Image.php b/logic/download_Portal_Image.php new file mode 100644 index 00000000..67e42b5e --- /dev/null +++ b/logic/download_Portal_Image.php @@ -0,0 +1,40 @@ + $text_show_button, + 'callback_data' => $gym_id . ':gym_edit_details:show-' . $arg_show + ], + [ + 'text' => $text_ex_button, + 'callback_data' => $gym_id . ':gym_edit_details:ex-' . $arg_ex + ] + ]; + if($botUser->accessCheck($update, 'gym-name', true)) { + $keys[] = [ + [ + 'text' => EMOJI_PENCIL . ' ' . getTranslation("gym_name_edit"), + 'callback_data' => $gym_id . ':gym_edit_details:name' + ] + ]; + } + if($botUser->accessCheck($update, 'gym-edit', true)) { + $keys[] = [ + [ + 'text' => EMOJI_INFO . ' ' . (!empty($gym_note) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_add_edit_note"), + 'callback_data' => $gym_id . ':gym_edit_details:note' + ] + ]; + $keys[] = [ + [ + 'text' => EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("directions")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), + 'callback_data' => $gym_id . ':gym_edit_details:addr' + ] + ]; $keys[] = [ - [ - 'text' => $text_show_button, - 'callback_data' => $gym_id . ':gym_edit_details:show-' . $arg_show - ], - [ - 'text' => $text_ex_button, - 'callback_data' => $gym_id . ':gym_edit_details:ex-' . $arg_ex - ] + [ + 'text' => EMOJI_HERE . ' ' . getTranslation("gym_edit_coordinates"), + 'callback_data' => $gym_id . ':gym_edit_details:gps' + ] ]; - if($botUser->accessCheck($update, 'gym-name', true)) { - $keys[] = [ - [ - 'text' => EMOJI_PENCIL . ' ' . getTranslation("gym_name_edit"), - 'callback_data' => $gym_id . ':gym_edit_details:name' - ] - ]; - } - if($botUser->accessCheck($update, 'gym-edit', true)) { - $keys[] = [ - [ - 'text' => EMOJI_INFO . ' ' . (!empty($gym_note) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_add_edit_note"), - 'callback_data' => $gym_id . ':gym_edit_details:note' - ] - ]; - $keys[] = [ - [ - 'text' => EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("directions")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), - 'callback_data' => $gym_id . ':gym_edit_details:addr' - ] - ]; - $keys[] = [ - [ - 'text' => EMOJI_HERE . ' ' . getTranslation("gym_edit_coordinates"), - 'callback_data' => $gym_id . ':gym_edit_details:gps' - ] - ]; - } - if($botUser->accessCheck($update, 'gym-delete', true)) { - $keys[] = [ - [ - 'text' => EMOJI_DELETE . ' ' . getTranslation("gym_delete"), - 'callback_data' => '0:gym_delete:'.$gym_id.'-delete' - ] - ]; - } + } + if($botUser->accessCheck($update, 'gym-delete', true)) { $keys[] = [ - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] + [ + 'text' => EMOJI_DELETE . ' ' . getTranslation("gym_delete"), + 'callback_data' => '0:gym_delete:'.$gym_id.'-delete' + ] ]; + } + $keys[] = [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ]; - return $keys; + return $keys; } -?> diff --git a/logic/edit_pokedex_keys.php b/logic/edit_pokedex_keys.php index 05a7ca4c..40d1ce66 100644 --- a/logic/edit_pokedex_keys.php +++ b/logic/edit_pokedex_keys.php @@ -7,98 +7,92 @@ */ function edit_pokedex_keys($limit, $action) { - // Number of entries to display at once. - $entries = 10; - - // Number of entries to skip with skip-back and skip-next buttons - $skip = 50; - - // Module for back and next keys - $module = "pokedex"; - - // Init empty keys array. - $keys = []; - - // Get all pokemon from database - $rs = my_query( - " - SELECT pokedex_id, pokemon_form_id - FROM pokemon - ORDER BY pokedex_id, pokemon_form_name != 'normal', pokemon_form_name - LIMIT $limit, $entries - " + // Number of entries to display at once. + $entries = 10; + + // Number of entries to skip with skip-back and skip-next buttons + $skip = 50; + + // Module for back and next keys + $module = 'pokedex'; + + // Init empty keys array. + $keys = []; + + // Get all pokemon from database + $rs = my_query(' + SELECT pokedex_id, pokemon_form_id + FROM pokemon + ORDER BY pokedex_id, pokemon_form_name != \'normal\', pokemon_form_name + LIMIT ' . $limit . ',' . $entries + ); + + // Number of entries + $cnt = my_query(' + SELECT COUNT(*) AS count + FROM pokemon + '); + + // Number of database entries found. + $sum = $cnt->fetch(); + $count = $sum['count']; + + // List users / moderators + while ($mon = $rs->fetch()) { + $pokemon_name = get_local_pokemon_name($mon['pokedex_id'], $mon['pokemon_form_id']); + $keys[] = array( + 'text' => $mon['pokedex_id'] . SP . $pokemon_name, + 'callback_data' => $mon['pokedex_id'] . '-' . $mon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' ); - - // Number of entries - $cnt = my_query( - " - SELECT COUNT(*) AS count - FROM pokemon - " - ); - - // Number of database entries found. - $sum = $cnt->fetch(); - $count = $sum['count']; - - // List users / moderators - while ($mon = $rs->fetch()) { - $pokemon_name = get_local_pokemon_name($mon['pokedex_id'], $mon['pokemon_form_id']); - $keys[] = array( - 'text' => $mon['pokedex_id'] . SP . $pokemon_name, - 'callback_data' => $mon['pokedex_id'] . '-' . $mon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' - ); - } - - // Empty backs and next keys - $keys_back = []; - $keys_next = []; - - // Add back key. - if ($limit > 0) { - $new_limit = $limit - $entries; - $empty_back_key = []; - $back = universal_key($empty_back_key, $new_limit, $module, $action, getTranslation('back') . " (-" . $entries . ")"); - $keys_back[] = $back[0][0]; - } - - // Add skip back key. - if ($limit - $skip > 0) { - $new_limit = $limit - $skip - $entries; - $empty_back_key = []; - $back = universal_key($empty_back_key, $new_limit, $module, $action, getTranslation('back') . " (-" . $skip . ")"); - $keys_back[] = $back[0][0]; - } - - // Add next key. - if (($limit + $entries) < $count) { - $new_limit = $limit + $entries; - $empty_next_key = []; - $next = universal_key($empty_next_key, $new_limit, $module, $action, getTranslation('next') . " (+" . $entries . ")"); - $keys_next[] = $next[0][0]; - } - - // Add skip next key. - if (($limit + $skip + $entries) < $count) { - $new_limit = $limit + $skip + $entries; - $empty_next_key = []; - $next = universal_key($empty_next_key, $new_limit, $module, $action, getTranslation('next') . " (+" . $skip . ")"); - $keys_next[] = $next[0][0]; - } - - // Exit key - $empty_exit_key = []; - $key_exit = universal_key($empty_exit_key, "0", "exit", "0", getTranslation('abort')); - - // Get the inline key array. - $keys = inline_key_array($keys, 1); - $keys_back = inline_key_array($keys_back, 2); - $keys_next = inline_key_array($keys_next, 2); - $keys = array_merge($keys_back, $keys); - $keys = array_merge($keys, $keys_next); - $keys = array_merge($keys, $key_exit); - - return $keys; + } + + // Empty backs and next keys + $keys_back = []; + $keys_next = []; + + // Add back key. + if ($limit > 0) { + $new_limit = $limit - $entries; + $empty_back_key = []; + $back = universal_key($empty_back_key, $new_limit, $module, $action, getTranslation('back') . ' (-' . $entries . ')'); + $keys_back[] = $back[0][0]; + } + + // Add skip back key. + if ($limit - $skip > 0) { + $new_limit = $limit - $skip - $entries; + $empty_back_key = []; + $back = universal_key($empty_back_key, $new_limit, $module, $action, getTranslation('back') . ' (-' . $skip . ')'); + $keys_back[] = $back[0][0]; + } + + // Add next key. + if (($limit + $entries) < $count) { + $new_limit = $limit + $entries; + $empty_next_key = []; + $next = universal_key($empty_next_key, $new_limit, $module, $action, getTranslation('next') . ' (+' . $entries . ')'); + $keys_next[] = $next[0][0]; + } + + // Add skip next key. + if (($limit + $skip + $entries) < $count) { + $new_limit = $limit + $skip + $entries; + $empty_next_key = []; + $next = universal_key($empty_next_key, $new_limit, $module, $action, getTranslation('next') . ' (+' . $skip . ')'); + $keys_next[] = $next[0][0]; + } + + // Exit key + $empty_exit_key = []; + $key_exit = universal_key($empty_exit_key, '0', 'exit', '0', getTranslation('abort')); + + // Get the inline key array. + $keys = inline_key_array($keys, 1); + $keys_back = inline_key_array($keys_back, 2); + $keys_next = inline_key_array($keys_next, 2); + $keys = array_merge($keys_back, $keys); + $keys = array_merge($keys, $keys_next); + $keys = array_merge($keys, $key_exit); + + return $keys; } - -?> diff --git a/logic/geo_api.php b/logic/geo_api.php new file mode 100644 index 00000000..370bbc0c --- /dev/null +++ b/logic/geo_api.php @@ -0,0 +1,240 @@ +MAPS_LOOKUP && !empty($config->MAPS_API_KEY)) { + // Init defaults. + $location = []; + $location['street'] = ''; + $location['street_number'] = ''; + $location['postal_code'] = ''; + $location['district'] = ''; + + // Set maps geocode url. + $language = strtolower($config->LANGUAGE_PUBLIC); + $MapsApiKey = $config->MAPS_API_KEY; + $url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' . $lat . ',' . $lon . '&language=' . $language; + $url .= '&key=' . $MapsApiKey; + + // Curl request. + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + + // Proxy server? + // Use Proxyserver for curl if configured + if ($config->CURL_USEPROXY) { + curl_setopt($curl, CURLOPT_PROXY, $config->CURL_PROXYSERVER); + } + + // Curl response. + $json_response = curl_exec($curl); + + // Write request and response to log. + debug_log($url, 'G>'); + debug_log($json_response, 'status) || $data->status != 'OK' && empty($data->results)) { + // No valid data received. + return false; + } + + // Init vars. + $locality = ''; + $sublocalityLv2 = ''; + $sublocality = ''; + + // Iterate each result. + foreach ($data->results as $result) { + + // Check for address components. + if (!empty($result->address_components)) { + // Iterate each address component. + foreach ($result->address_components as $address_component) { + + // Street found. + if (in_array('route', $address_component->types) && !empty($address_component->long_name)) { + // Set street by first found. + $location['street'] = empty($location['street']) ? $address_component->long_name : $location['street']; + } + + // Street number found. + if (in_array('street_number', $address_component->types) && !empty($address_component->long_name)) { + // Set street by first found. + $location['street_number'] = empty($location['street_number']) ? $address_component->long_name : $location['street_number']; + } + + // Postal code found. + if (in_array('postal_code', $address_component->types) && !empty($address_component->long_name)) { + // Set street by first found. + $location['postal_code'] = empty($location['postal_code']) ? $address_component->long_name : $location['postal_code']; + } + + // Sublocality level2 found. + if (in_array('sublocality_level_2', $address_component->types) && !empty($address_component->long_name)) { + // Set sublocality level 2 by first found. + $sublocalityLv2 = empty($sublocalityLv2) ? $address_component->long_name : $sublocalityLv2; + } + + // Sublocality found. + if (in_array('sublocality', $address_component->types) && !empty($address_component->long_name)) { + // Set sublocality by first found. + $sublocality = empty($sublocality) ? $address_component->long_name : $sublocality; + } + + // Locality found. + if (in_array('locality', $address_component->types) && !empty($address_component->long_name)) { + // Set sublocality by first found. + $locality = empty($sublocality) ? $address_component->long_name : $sublocality; + } + } + } + break; + } + + // Set district by priority. + if (!empty($sublocalityLv2)) { + $location['district'] = $sublocalityLv2; + + } else if ($sublocality) { + $location['district'] = $sublocality; + + } else if ($locality) { + $location['district'] = $locality; + } + + // Rename street responses. + switch ($location['street']) { + case 'Unnamed Road': + $location['street'] = getPublicTranslation('directions'); + break; + } + + // Return the location array. + return $location; + + // OpenStreetMap lookup? + } elseif($config->OSM_LOOKUP) { + // Init defaults. + $location = []; + $location['street'] = ''; + $location['street_number'] = ''; + $location['postal_code'] = ''; + $location['district'] = ''; + + // Set maps geocode url. + $language = strtolower($config->LANGUAGE_PUBLIC); + $url = $config->OSM_URL . '/reverse?lat=' . $lat . '&lon=' . $lon . '&format=json&accept-language=' . $language; + + // Curl request. + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_HTTPHEADER, array("User-Agent: PokemonRaidBot")); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + + // Proxy server? + // Use Proxyserver for curl if configured + if ($config->CURL_USEPROXY) { + curl_setopt($curl, CURLOPT_PROXY, $config->CURL_PROXYSERVER); + } + + // Curl response. + $json_response = curl_exec($curl); + + // Write request and response to log. + debug_log($url, 'OSM>'); + debug_log($json_response, ' diff --git a/logic/get_formatted_pokemon_cp.php b/logic/get_formatted_pokemon_cp.php index 053d97f6..da7a73c4 100644 --- a/logic/get_formatted_pokemon_cp.php +++ b/logic/get_formatted_pokemon_cp.php @@ -1,8 +1,8 @@ diff --git a/logic/get_gym.php b/logic/get_gym.php index e75066bf..407a76a3 100644 --- a/logic/get_gym.php +++ b/logic/get_gym.php @@ -6,18 +6,15 @@ */ function get_gym($id) { - // Get gym from database - $rs = my_query( - " - SELECT * - FROM gyms - WHERE id = {$id} - " - ); + // Get gym from database + $rs = my_query(' + SELECT * + FROM gyms + WHERE id = ? + ', [$id] + ); - $gym = $rs->fetch(); + $gym = $rs->fetch(); - return $gym; + return $gym; } - -?> diff --git a/logic/get_gym_by_telegram_id.php b/logic/get_gym_by_telegram_id.php index d8d77e44..70e98b64 100644 --- a/logic/get_gym_by_telegram_id.php +++ b/logic/get_gym_by_telegram_id.php @@ -1,25 +1,22 @@ fetch(); + $gym = $rs->fetch(); - return $gym; + return $gym; } - -?> diff --git a/logic/get_gym_details.php b/logic/get_gym_details.php index 7833787a..90159864 100644 --- a/logic/get_gym_details.php +++ b/logic/get_gym_details.php @@ -1,4 +1,5 @@ ' . getTranslation('gym_details') . ':' . CR . CR; - $msg .= getTranslation('gym') . ':' . SP; - $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : '' . $config->RAID_EX_GYM_MARKER . ''; - $msg .= ($gym['ex_gym'] ? $ex_raid_gym_marker . SP : '') . '' . $gym['gym_name'] . ''; - $msg .= CR; - if($extended) $msg .= getTranslation('gym_stored_address') . CR; - // Add maps link to message. - $address = ''; - $lookupAddress = format_address(get_address($gym['lat'], $gym['lon'])); - if(!empty($gym['address'])) { - $address = $gym['address']; - } elseif(!$extended) { - $address = $lookupAddress; - } + global $config; + // Add gym name to message. + $msg = '' . getTranslation('gym_details') . ':' . CR . CR; + $msg .= getTranslation('gym') . ':' . SP; + $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : '' . $config->RAID_EX_GYM_MARKER . ''; + $msg .= ($gym['ex_gym'] ? $ex_raid_gym_marker . SP : '') . '' . $gym['gym_name'] . ''; + $msg .= CR; + if($extended) $msg .= getTranslation('gym_stored_address') . CR; + // Add maps link to message. + $address = ''; + $lookupAddress = format_address(get_address($gym['lat'], $gym['lon'])); + if(!empty($gym['address'])) { + $address = $gym['address']; + } elseif(!$extended) { + $address = $lookupAddress; + } - //Only store address if not empty - if(!empty($address)) { - //Use new address - $msg .= mapslink($gym, $address) . CR; - } elseif(!$extended) { - //If no address is found show maps link - $msg .= mapslink($gym, '1') . CR; - }else { - $msg .= getTranslation('none') . CR; - } - if($extended) { - $msg .= getTranslation('gym_address_lookup_result') . ': ' . CR; - $msg .= mapslink($gym, $lookupAddress) . CR; - } + //Only store address if not empty + if(!empty($address)) { + //Use new address + $msg .= mapslink($gym, $address) . CR; + } elseif(!$extended) { + //If no address is found show maps link + $msg .= mapslink($gym, '1') . CR; + }else { + $msg .= getTranslation('none') . CR; + } + if($extended) { + $msg .= getTranslation('gym_address_lookup_result') . ': ' . CR; + $msg .= mapslink($gym, $lookupAddress) . CR; + } - // Add or hide gym note. - if(!empty($gym['gym_note'])) { - $msg .= EMOJI_INFO . SP . $gym['gym_note'] . CR; - } - - // Get extended gym details? - if($extended == true) { - $msg .= CR . '' . getTranslation('extended_gym_details') . ''; - // Hidden gym? - if($gym['show_gym'] == 0) { - $msg .= CR . '-' . SP . getTranslation('hidden_gym'); - }else { - // Normal gym? - if($gym['ex_gym'] == 1) { - $msg .= CR . '-' . SP . getTranslation('ex_gym'); - }else { - $msg .= CR . '-' . SP . getTranslation('normal_gym'); - } - } - $msg .= CR . '-' . SP . getTranslation('gym_coordinates') . ': ' . (float)$gym['lat'] . ',' . (float)$gym['lon'].''; - } + // Add or hide gym note. + if(!empty($gym['gym_note'])) { + $msg .= EMOJI_INFO . SP . $gym['gym_note'] . CR; + } + // Get extended gym details? + if(!$extended) return $msg; -} -?> + $msg .= CR . '' . getTranslation('extended_gym_details') . ''; + // Hidden gym? + $translation = 'hidden_gym'; + if($gym['show_gym'] == 1) { + // Normal gym? + $translation = ($gym['ex_gym'] == 1) ? 'ex_gym' : 'normal_gym'; + } + $msg .= CR . '-' . SP . getTranslation($translation); + $msg .= CR . '-' . SP . getTranslation('gym_coordinates') . ': ' . (float)$gym['lat'] . ',' . (float)$gym['lon'].''; + + return $msg; +} diff --git a/logic/get_local_pokemon_name.php b/logic/get_local_pokemon_name.php index 2d8de959..c9721b98 100644 --- a/logic/get_local_pokemon_name.php +++ b/logic/get_local_pokemon_name.php @@ -8,46 +8,25 @@ */ function get_local_pokemon_name($pokemon_id, $pokemon_form_id, $override_language = false) { - $q = my_query("SELECT pokemon_name, pokemon_form_name FROM pokemon WHERE pokedex_id = '{$pokemon_id}' AND pokemon_form_id = '{$pokemon_form_id}'"); - $res = $q->fetch(); - $pokemon_form_name = $res['pokemon_form_name'] ?? 'normal'; + $q = my_query('SELECT pokemon_name, pokemon_form_name FROM pokemon WHERE pokedex_id = ? AND pokemon_form_id = ?', [$pokemon_id, $pokemon_form_id]); + $res = $q->fetch(); + $pokemon_form_name = $res['pokemon_form_name'] ?? 'normal'; - debug_log('Pokemon_form: ' . $pokemon_form_name); - - // Get translation type - if($override_language == true) { - $getTypeTranslation = 'getPublicTranslation'; - } else { - $getTypeTranslation = 'getTranslation'; - } - // Init pokemon name and define fake pokedex ids used for raid eggs - $pokemon_name = ''; - $eggs = $GLOBALS['eggs']; + debug_log('Pokemon_form: ' . $pokemon_form_name); - // Get eggs from normal translation. - if(in_array($pokemon_id, $eggs)) { - $pokemon_name = $getTypeTranslation('egg_' . substr($pokemon_id, -1)); - } else { - $pokemon_name = $getTypeTranslation('pokemon_id_' . $pokemon_id); - } - if ($pokemon_form_name != 'normal') { - $pokemon_form_name = $getTypeTranslation('pokemon_form_' . $pokemon_form_name); - } - // Fallback 1: Valid pokedex id or just a raid egg? - if($pokemon_id === "NULL" || $pokemon_id == 0) { - $pokemon_name = $getTypeTranslation('egg_0'); + // Get translation type + $getTypeTranslation = ($override_language == true) ? 'getPublicTranslation' : 'getTranslation'; - // Fallback 2: Get original pokemon name and/or form name from database - } else if(empty($pokemon_name) or empty($pokemon_form_name)) { - // Pokemon name - $pokemon_name = (empty($pokemon_name)?$res['pokemon_name']:$pokemon_name); - // Pokemon form - if(empty($pokemon_form_name) && $res['pokemon_form_name'] != 'normal') { - $pokemon_form_name = ucfirst(str_replace("_"," ",$res['pokemon_form_name'])); - } - } + // Init pokemon name and define fake pokedex ids used for raid eggs + $pokemon_name = ''; + $eggs = $GLOBALS['eggs']; - return $pokemon_name . ($pokemon_form_name != "normal" ? " " . $pokemon_form_name : ""); -} + // Get eggs from normal translation. + $pokemon_name = (in_array($pokemon_id, $eggs)) ? $getTypeTranslation('egg_' . substr($pokemon_id, -1)) : $getTypeTranslation('pokemon_id_' . $pokemon_id); + + if ($pokemon_form_name != 'normal') { + $pokemon_form_name = $getTypeTranslation('pokemon_form_' . $pokemon_form_name); + } -?> + return $pokemon_name . ($pokemon_form_name != "normal" ? " " . $pokemon_form_name : ""); +} diff --git a/logic/get_overview.php b/logic/get_overview.php index 2db0c738..1df0be46 100644 --- a/logic/get_overview.php +++ b/logic/get_overview.php @@ -1,110 +1,113 @@ ' . getPublicTranslation('raid_overview_for_chat') . ' ' . $chat_title . ' ' . getPublicTranslation('from') . ' '. dt2time('now') . '' . CR . CR; + $msg = '' . getPublicTranslation('raid_overview_for_chat') . ' ' . $chat_title . ' ' . getPublicTranslation('from') . ' '. dt2time('now') . '' . CR . CR; - $now = utcnow(); - - if(count($active_raids) == 0) { - $msg .= getPublicTranslation('no_active_raids') . CR . CR; - }else { - foreach($active_raids as $row) { - // Set variables for easier message building. - $raid_id = $row['id']; - $resolved_boss = resolve_raid_boss($row['pokemon'], $row['pokemon_form'], $row['spawn'], $row['level']); - $row['pokemon'] = $resolved_boss['pokedex_id']; - $row['pokemon_form'] = $resolved_boss['pokemon_form_id']; - $pokemon = get_local_pokemon_name($row['pokemon'], $row['pokemon_form'], true); - $gym = $row['gym_name']; - $ex_gym = $row['ex_gym']; - $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : '' . $config->RAID_EX_GYM_MARKER . ''; - $start_time = $row['start_time']; - $time_left = $row['t_left']; + if(count($active_raids) == 0) { + $msg .= getPublicTranslation('no_active_raids') . CR . CR; + //Add custom message from the config. + if (!empty($config->RAID_PIN_MESSAGE)) { + $msg .= $config->RAID_PIN_MESSAGE; + } + return $msg; + } + $now = utcnow(); + foreach($active_raids as $row) { + // Set variables for easier message building. + $raid_id = $row['id']; + $resolved_boss = resolve_raid_boss($row['pokemon'], $row['pokemon_form'], $row['spawn'], $row['level']); + $row['pokemon'] = $resolved_boss['pokedex_id']; + $row['pokemon_form'] = $resolved_boss['pokemon_form_id']; + $pokemon = get_local_pokemon_name($row['pokemon'], $row['pokemon_form'], true); + $gym = $row['gym_name']; + $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : '' . $config->RAID_EX_GYM_MARKER . ''; + $start_time = $row['start_time']; + $time_left = $row['t_left']; - debug_log($pokemon . '@' . $gym . ' found for overview.'); - // Build message and add each gym in this format - link gym_name to raid poll chat_id + message_id if possible - /* Example: - * Raid Overview from 18:18h - * - * Train Station Gym - * Raikou - still 0:24h - * - * Bus Station Gym - * Level 5 Egg 18:41 to 19:26 - */ - // Gym name. - $msg .= $ex_gym ? $ex_raid_gym_marker . SP : ''; - $msg .= !empty($chat_username) ? '' . htmlspecialchars($gym) . '' : $gym; - $msg .= CR; + debug_log($pokemon . '@' . $gym . ' found for overview.'); + // Build message and add each gym in this format - link gym_name to raid poll chat_id + message_id if possible + /* Example: + * Raid Overview from 18:18h + * + * Train Station Gym + * Raikou - still 0:24h + * + * Bus Station Gym + * Level 5 Egg 18:41 to 19:26 + */ + // Gym name. + $msg .= $row['ex_gym'] ? $ex_raid_gym_marker . SP : ''; + $msg .= !empty($chat_username) ? '' . htmlspecialchars($gym) . '' : $gym; + $msg .= CR; - if(isset($row['event_name']) && $row['event_name'] != "") { - $msg .= "" . $row['event_name'] . "" . CR; - } + if(isset($row['event_name']) && $row['event_name'] != '') { + $msg .= '' . $row['event_name'] . '' . CR; + } - // Raid has not started yet - adjust time left message - if ($now < $start_time) { - $msg .= get_raid_times($row, true); - // Raid has started already - } else { - // Add time left message. - $msg .= $pokemon . ' — ' . getPublicTranslation('still') . SP . $time_left . 'h' . CR; - } - $exclude_pokemon_sql = ""; - if(!in_array($row['pokemon'], $GLOBALS['eggs'])) { - $exclude_pokemon_sql = 'AND (pokemon = \''.$row['pokemon'].'-'.$row['pokemon_form'].'\' or pokemon = \'0\')'; - } - // Count attendances - $rs_att = my_query( - " - SELECT count(attend_time) AS count, - sum(want_invite = 0 && remote = 0 && can_invite = 0) + sum(case when want_invite = 0 && remote = 0 then attendance.extra_in_person else 0 end) AS count_in_person, - sum(want_invite = 0 && remote = 1 && can_invite = 0) + sum(case when want_invite = 0 && remote = 1 then attendance.extra_in_person else 0 end) AS count_remote, - sum(case when want_invite = 0 && can_invite = 0 then attendance.extra_alien else 0 end) AS extra_alien, - sum(case when want_invite = 1 && can_invite = 0 then 1 + attendance.extra_in_person else 0 end) AS count_want_invite, - sum(can_invite = 1) AS count_can_invite - FROM ( - SELECT DISTINCT attend_time, user_id, extra_in_person, extra_alien, remote, want_invite, can_invite - FROM attendance - WHERE raid_id = {$raid_id} - AND attend_time IS NOT NULL - AND ( attend_time > UTC_TIMESTAMP() or attend_time = '" . ANYTIME . "' ) - AND raid_done != 1 - AND cancel != 1 - {$exclude_pokemon_sql} - ) as attendance - LEFT JOIN users - ON attendance.user_id = users.user_id - " - ); + // Raid has not started yet - adjust time left message + if ($now < $start_time) { + $msg .= get_raid_times($row, true); + // Raid has started already + } else { + // Add time left message. + $msg .= $pokemon . ' — ' . getPublicTranslation('still') . SP . $time_left . 'h' . CR; + } + $exclude_pokemon_sql = ''; + if(!in_array($row['pokemon'], $GLOBALS['eggs'])) { + $exclude_pokemon_sql = 'AND (pokemon = \''.$row['pokemon'].'-'.$row['pokemon_form'].'\' or pokemon = \'0\')'; + } + // Count attendances + $rs_att = my_query(' + SELECT + count(attend_time) AS count, + sum(want_invite = 0 && remote = 0 && can_invite = 0) + sum(case when want_invite = 0 && remote = 0 then attendance.extra_in_person else 0 end) AS count_in_person, + sum(want_invite = 0 && remote = 1 && can_invite = 0) + sum(case when want_invite = 0 && remote = 1 then attendance.extra_in_person else 0 end) AS count_remote, + sum(case when want_invite = 0 && can_invite = 0 then attendance.extra_alien else 0 end) AS extra_alien, + sum(case when want_invite = 1 && can_invite = 0 then 1 + attendance.extra_in_person else 0 end) AS count_want_invite, + sum(can_invite = 1) AS count_can_invite + FROM ( + SELECT DISTINCT attend_time, user_id, extra_in_person, extra_alien, remote, want_invite, can_invite + FROM attendance + WHERE raid_id = ? + AND attend_time IS NOT NULL + AND ( attend_time > UTC_TIMESTAMP() or attend_time = \'' . ANYTIME . '\' ) + AND raid_done != 1 + AND cancel != 1 + ' .$exclude_pokemon_sql . ' + ) as attendance + LEFT JOIN users + ON attendance.user_id = users.user_id + ', [$raid_id] + ); - $att = $rs_att->fetch(); + $att = $rs_att->fetch(); - // Add to message. - if ($att['count'] > 0) { - $msg .= EMOJI_GROUP . ' ' . ($att['count_in_person'] + $att['count_remote'] + $att['extra_alien'] + $att['count_want_invite']) . ' — '; - $msg .= ((($att['count_can_invite']) > 0) ? EMOJI_CAN_INVITE . ($att['count_can_invite']) . ' ' : ''); - $msg .= ((($att['count_in_person']) > 0) ? EMOJI_IN_PERSON . ($att['count_in_person']) . ' ' : ''); - $msg .= ((($att['count_remote']) > 0) ? EMOJI_REMOTE . ($att['count_remote']) . ' ' : ''); - $msg .= ((($att['extra_alien']) > 0) ? EMOJI_ALIEN . ($att['extra_alien']) . ' ' : ''); - $msg .= (($att['count_want_invite'] > 0) ? EMOJI_WANT_INVITE . $att['count_want_invite'] : ''); - $msg .= CR; - } - $msg .= CR; - } - } - //Add custom message from the config. - if (!empty($config->RAID_PIN_MESSAGE)) { - $msg .= $config->RAID_PIN_MESSAGE; + if ($att['count'] == 0) { + $msg .= CR; + continue; } - return $msg; + // Add to message. + $msg .= EMOJI_GROUP . ' ' . ($att['count_in_person'] + $att['count_remote'] + $att['extra_alien'] + $att['count_want_invite']) . ' — '; + $msg .= ((($att['count_can_invite']) > 0) ? EMOJI_CAN_INVITE . ($att['count_can_invite']) . ' ' : ''); + $msg .= ((($att['count_in_person']) > 0) ? EMOJI_IN_PERSON . ($att['count_in_person']) . ' ' : ''); + $msg .= ((($att['count_remote']) > 0) ? EMOJI_REMOTE . ($att['count_remote']) . ' ' : ''); + $msg .= ((($att['extra_alien']) > 0) ? EMOJI_ALIEN . ($att['extra_alien']) . ' ' : ''); + $msg .= (($att['count_want_invite'] > 0) ? EMOJI_WANT_INVITE . $att['count_want_invite'] : ''); + $msg .= CR . CR; + } + //Add custom message from the config. + if (!empty($config->RAID_PIN_MESSAGE)) { + $msg .= $config->RAID_PIN_MESSAGE; + } + return $msg; } -?> diff --git a/logic/get_pokemon_by_table_id.php b/logic/get_pokemon_by_table_id.php index a917cb79..16bd49c1 100644 --- a/logic/get_pokemon_by_table_id.php +++ b/logic/get_pokemon_by_table_id.php @@ -5,13 +5,14 @@ * @return array */ function get_pokemon_by_table_id($pokemon_table_id) { - $q = my_query(" - SELECT pokedex_id, - pokemon_form_id - FROM pokemon - WHERE id = {$pokemon_table_id} - LIMIT 1 - "); - $return = $q->fetch(); - return $return; -} \ No newline at end of file + $q = my_query(' + SELECT pokedex_id, + pokemon_form_id + FROM pokemon + WHERE id = ? + LIMIT 1 + ', [$pokemon_table_id] + ); + $return = $q->fetch(); + return $return; +} diff --git a/logic/get_pokemon_form_name.php b/logic/get_pokemon_form_name.php index 075e742b..44705126 100644 --- a/logic/get_pokemon_form_name.php +++ b/logic/get_pokemon_form_name.php @@ -7,34 +7,32 @@ */ function get_pokemon_form_name($pokedex_id, $pokemon_form_id) { - debug_log($pokedex_id.'-'.$pokemon_form_id, 'Finding Pokemon form name for:'); + debug_log($pokedex_id.'-'.$pokemon_form_id, 'Finding Pokemon form name for:'); - $pokemon_form_name = 'normal'; - // Make sure $dex_id is numeric - if(is_numeric($pokedex_id) && is_numeric($pokemon_form_id)) { - // Get raid level from database - $rs = my_query( - " - SELECT pokemon_form_name - FROM pokemon - WHERE pokedex_id = {$pokedex_id} - AND pokemon_form_id = '{$pokemon_form_id}' - LIMIT 1 - " - ); + $pokemon_form_name = 'normal'; + // Make sure $dex_id is numeric + if(!is_numeric($pokedex_id) || !is_numeric($pokemon_form_id)) { + debug_log('Faulty dex_id or form_id, defaulting to normal.'); + return $pokemon_form_name; + } + // Get raid level from database + $rs = my_query(' + SELECT pokemon_form_name + FROM pokemon + WHERE pokedex_id = ? + AND pokemon_form_id = ? + LIMIT 1 + ', [$pokedex_id, $pokemon_form_id] + ); - $level = $rs->fetch(); - if($level) { - $pokemon_form_name = $level['pokemon_form_name']; - } else { - $error = "pokemon_form_name unknown for pokedex_id: {$pokedex_id}, pokemon_form_id: {$pokemon_form_id}"; - throw new Exception($error); - } - debug_log($pokemon_form_name, 'Per db, level is:'); - } else { - debug_log('Faulty dex_id or form_id, defaulting to normal.'); - } + $level = $rs->fetch(); + if($level) { + $pokemon_form_name = $level['pokemon_form_name']; + } else { + $error = "pokemon_form_name unknown for pokedex_id: {$pokedex_id}, pokemon_form_id: {$pokemon_form_id}"; + throw new Exception($error); + } + debug_log($pokemon_form_name, 'Per db, level is:'); - return $pokemon_form_name; + return $pokemon_form_name; } -?> diff --git a/logic/get_pokemon_id_by_name.php b/logic/get_pokemon_id_by_name.php index de36b538..3d5b006b 100644 --- a/logic/get_pokemon_id_by_name.php +++ b/logic/get_pokemon_id_by_name.php @@ -7,134 +7,135 @@ */ function get_pokemon_id_by_name($pokemon_name, $get_from_db = false) { - global $dbh, $botUser; - debug_log($pokemon_name,'P:'); + global $dbh, $botUser; + debug_log($pokemon_name,'P:'); - // Explode pokemon name in case we have a form too. - $delimiter = ''; - if(strpos($pokemon_name, ' ') !== false) { - $delimiter = ' '; - } else if (strpos($pokemon_name, '-') !== false) { - $delimiter = '-'; - } else if (strpos($pokemon_name, ',') !== false) { - $delimiter = ','; - } + // Explode pokemon name in case we have a form too. + $delimiter = ''; + if(strpos($pokemon_name, ' ') !== false) { + $delimiter = ' '; + } else if (strpos($pokemon_name, '-') !== false) { + $delimiter = '-'; + } else if (strpos($pokemon_name, ',') !== false) { + $delimiter = ','; + } + + // Explode if delimiter was found. + $poke_name = $pokemon_name; + $poke_form = ""; + if($delimiter != '') { + $pokemon_name_form = explode($delimiter,$pokemon_name,2); + $poke_name = trim($pokemon_name_form[0]); + $poke_name = strtolower($poke_name); + $poke_form = trim($pokemon_name_form[1]); + $poke_form = strtolower($poke_form); + debug_log($poke_name,'P NAME:'); + debug_log($poke_form,'P FORM:'); + } + + // Init id and write name to search to log. + $pokemon_id = 0; + $pokemon_form = ($poke_form!="")?$poke_form:"normal"; + + // Set language + $language = $botUser->userLanguage; - // Explode if delimiter was found. - $poke_name = $pokemon_name; - $poke_form = ""; - if($delimiter != '') { - $pokemon_name_form = explode($delimiter,$pokemon_name,2); - $poke_name = trim($pokemon_name_form[0]); - $poke_name = strtolower($poke_name); - $poke_form = trim($pokemon_name_form[1]); - $poke_form = strtolower($poke_form); - debug_log($poke_name,'P NAME:'); - debug_log($poke_form,'P FORM:'); + if($get_from_db) { + // Fetch Pokemon form ID from database + $query = my_query(' + SELECT pokedex_id, pokemon_form_id + FROM pokemon + WHERE pokemon_name = :poke_name + AND pokemon_form_name = :form_name + LIMIT 1 + ', ['poke_name' => $poke_name, 'form_name' => $pokemon_form] + ); + $res = $query->fetch(); + $pokemon_form_id = 0; + if($query->rowCount() > 0) { + $pokemon_form_id = $res['pokemon_form_id']; + $pokemon_id = $res['pokedex_id']; } - - // Init id and write name to search to log. - $pokemon_id = 0; - $pokemon_form = ($poke_form!="")?$poke_form:"normal"; + // Write to log. + debug_log($pokemon_id,'P:'); + debug_log($pokemon_form.' (ID: '.$pokemon_form_id.')','P:'); - // Set language - $language = $botUser->userLanguage; - if($get_from_db) { - // Fetch Pokemon form ID from database - $stmt = $dbh->prepare(" - SELECT pokedex_id, pokemon_form_id - FROM pokemon - WHERE pokemon_name = :poke_name - AND pokemon_form_name = :form_name - LIMIT 1 - "); - $stmt->execute(['poke_name' => $poke_name, 'form_name' => $pokemon_form]); - $res = $stmt->fetch(); - if($stmt->rowCount() > 0) { - $pokemon_form_id = $res['pokemon_form_id']; - $pokemon_id = $res['pokedex_id']; - }else { - $pokemon_form_id = 0; - } - }else { - // Get translation file - $str = file_get_contents(BOT_LANG_PATH . '/pokemon.json'); - $json = json_decode($str, true); - $search_result = ""; - foreach($json as $title => $translations) { - // Try to find translation for userlanguage - if(isset($translations[$language]) && ucfirst($poke_name) == $translations[$language]) { - $search_result = $title; - debug_log('Translation found for lang: '.$language, 'P:'); - debug_log('Translation result: '.$title, 'P:'); - break; - // Also look for fallback in default language - }elseif(ucfirst($poke_name) == $translations[DEFAULT_LANGUAGE]) { - $search_result = $title; - } - } - if($search_result != "") { - $pokemon_id = str_replace('pokemon_id_','', $search_result); - }else { - // Debug log. - info_log('Error! Pokedex ID could not be found for pokemon with name: ' . $poke_name); - } + // Return pokemon_id and pokemon_form_id + return [$pokemon_id, $pokemon_form_id]; + } - // Get form. - // Works like this: Search form in language file via language, e.g. 'DE' and local form translation, e.g. 'Alola' for 'DE'. - // In additon we are searching the DEFAULT_LANGUAGE and the key name for the form name. - // Once we found the key name, e.g. 'pokemon_form_attack', get the form name 'attack' from it via str_replace'ing the prefix 'pokemon_form'. - if($pokemon_id != 0 && isset($poke_form) && !empty($poke_form) && $poke_form != 'normal') { - debug_log('Searching for pokemon form: ' . $poke_form); + // Get translation file + $str = file_get_contents(BOT_LANG_PATH . '/pokemon.json'); + $json = json_decode($str, true); + $search_result = ""; + foreach($json as $title => $translations) { + // Try to find translation for userlanguage + if(isset($translations[$language]) && ucfirst($poke_name) == $translations[$language]) { + $search_result = $title; + debug_log('Translation found for lang: '.$language, 'P:'); + debug_log('Translation result: '.$title, 'P:'); + break; + // Also look for fallback in default language + }elseif(ucfirst($poke_name) == $translations[DEFAULT_LANGUAGE]) { + $search_result = $title; + } + } + if($search_result != "") { + $pokemon_id = str_replace('pokemon_id_','', $search_result); + }else { + // Debug log. + info_log('Error! Pokedex ID could not be found for pokemon with name: ' . $poke_name); + } - // Get forms translation file - $str_form = file_get_contents(BOT_LANG_PATH . '/pokemon_forms.json'); - $json_form = json_decode($str_form, true); + // Get form. + // Works like this: Search form in language file via language, e.g. 'DE' and local form translation, e.g. 'Alola' for 'DE'. + // In additon we are searching the DEFAULT_LANGUAGE and the key name for the form name. + // Once we found the key name, e.g. 'pokemon_form_attack', get the form name 'attack' from it via str_replace'ing the prefix 'pokemon_form'. + if($pokemon_id != 0 && isset($poke_form) && !empty($poke_form) && $poke_form != 'normal') { + debug_log('Searching for pokemon form: ' . $poke_form); - // Search pokemon form in json - foreach($json_form as $key_form => $jform) { - // Stop search if we found it. - if ($jform[$language] === ucfirst($poke_form)) { - $pokemon_form = str_replace('pokemon_form_','',$key_form); - debug_log('Found pokemon form by user language: ' . $language); - break; + // Get forms translation file + $str_form = file_get_contents(BOT_LANG_PATH . '/pokemon_forms.json'); + $json_form = json_decode($str_form, true); - // Try DEFAULT_LANGUAGE too. - } else if ($jform[DEFAULT_LANGUAGE] === ucfirst($poke_form)) { - $pokemon_form = str_replace('pokemon_form_','',$key_form); - debug_log('Found pokemon form by default language: ' . DEFAULT_LANGUAGE); - break; + // Search pokemon form in json + foreach($json_form as $key_form => $jform) { + // Stop search if we found it. + if ($jform[$language] === ucfirst($poke_form)) { + $pokemon_form = str_replace('pokemon_form_','',$key_form); + debug_log('Found pokemon form by user language: ' . $language); + break; - // Try key name. - } else if ($key_form === ('pokemon_form_' . $poke_form)) { - $pokemon_form = str_replace('pokemon_form_','',$key_form); - debug_log('Found pokemon form by json key name: pokemon_form_' . $key_form); - break; - } - } - } - // Fetch Pokemon form ID from database - $stmt = $dbh->prepare(" - SELECT pokemon_form_id - FROM pokemon - WHERE pokedex_id = :pokedex_id - AND pokemon_form_name = :form_name - LIMIT 1 - "); - $stmt->execute(['pokedex_id' => $pokemon_id, 'form_name' => $pokemon_form]); - $res = $stmt->fetch(); - $pokemon_form_id = isset($res['pokemon_form_id']) ? $res['pokemon_form_id'] : ''; - } + // Try DEFAULT_LANGUAGE too. + } else if ($jform[DEFAULT_LANGUAGE] === ucfirst($poke_form)) { + $pokemon_form = str_replace('pokemon_form_','',$key_form); + debug_log('Found pokemon form by default language: ' . DEFAULT_LANGUAGE); + break; - // Write to log. - debug_log($pokemon_id,'P:'); - debug_log($pokemon_form.' (ID: '.$pokemon_form_id.')','P:'); + // Try key name. + } else if ($key_form === ('pokemon_form_' . $poke_form)) { + $pokemon_form = str_replace('pokemon_form_','',$key_form); + debug_log('Found pokemon form by json key name: pokemon_form_' . $key_form); + break; + } + } + } + // Fetch Pokemon form ID from database + $query = my_query(' + SELECT pokemon_form_id + FROM pokemon + WHERE pokedex_id = :pokedex_id + AND pokemon_form_name = :form_name + LIMIT 1 + ', ['pokedex_id' => $pokemon_id, 'form_name' => $pokemon_form] + ); + $res = $query->fetch(); + $pokemon_form_id = isset($res['pokemon_form_id']) ? $res['pokemon_form_id'] : 0; - // Set pokemon form. - $pokemon_id = $pokemon_id . '-' . $pokemon_form_id; + // Write to log. + debug_log($pokemon_id,'P:'); + debug_log($pokemon_form.' (ID: '.$pokemon_form_id.')','P:'); - // Return pokemon_id - return $pokemon_id; + // Return pokemon_id and pokemon_form_id + return [$pokemon_id, $pokemon_form_id]; } - -?> diff --git a/logic/get_raid.php b/logic/get_raid.php index 0bf38024..a24bc028 100644 --- a/logic/get_raid.php +++ b/logic/get_raid.php @@ -4,53 +4,50 @@ * @param $raid_id * @return array */ +require_once(LOGIC_PATH . '/get_user.php'); require_once(LOGIC_PATH . '/resolve_raid_boss.php'); function get_raid($raid_id) { - global $dbh; - // Remove all non-numeric characters - $raidid = preg_replace( '/[^0-9]/', '', $raid_id ); + // Remove all non-numeric characters + $raidid = preg_replace( '/[^0-9]/', '', $raid_id ); - // Get the raid data by id. - $rs = my_query( - ' - SELECT raids.pokemon, raids.pokemon_form, raids.id, raids.user_id, raids.spawn, raids.start_time, raids.end_time, raids.gym_team, raids.gym_id, raids.level, raids.move1, raids.move2, raids.gender, raids.event, raids.costume, raids.event_note, - gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, gyms.gym_note, - users.name, users.trainername, users.nick, - events.name as event_name, events.description as event_description, events.vote_key_mode as event_vote_key_mode, events.time_slots as event_time_slots, events.raid_duration as event_raid_duration, events.hide_raid_picture as event_hide_raid_picture, events.pokemon_title as event_pokemon_title, events.poll_template as event_poll_template, - TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left, - IF(UTC_TIMESTAMP() > end_time, 1, 0) as raid_ended - FROM raids - LEFT JOIN gyms - ON raids.gym_id = gyms.id - LEFT JOIN users - ON raids.user_id = users.user_id - LEFT JOIN events - ON events.id = raids.event - WHERE raids.id = ? - LIMIT 1 - ', [$raidid] - ); - // Get the row. - $raid = $rs->fetch(); + // Get the raid data by id. + $rs = my_query(' + SELECT raids.pokemon, raids.pokemon_form, raids.id, raids.user_id, raids.spawn, raids.start_time, raids.end_time, raids.gym_team, raids.gym_id, raids.level, raids.move1, raids.move2, raids.gender, raids.event, raids.costume, raids.event_note, + gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, gyms.gym_note, + users.name, users.trainername, users.nick, users.display_name, + events.name as event_name, events.description as event_description, events.vote_key_mode as event_vote_key_mode, events.time_slots as event_time_slots, events.raid_duration as event_raid_duration, events.hide_raid_picture as event_hide_raid_picture, events.pokemon_title as event_pokemon_title, events.poll_template as event_poll_template, + TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left, + IF(UTC_TIMESTAMP() > end_time, 1, 0) as raid_ended + FROM raids + LEFT JOIN gyms + ON raids.gym_id = gyms.id + LEFT JOIN users + ON raids.user_id = users.user_id + LEFT JOIN events + ON events.id = raids.event + WHERE raids.id = ? + LIMIT 1 + ', [$raidid] + ); + // Get the row. + $raid = $rs->fetch(); - // Resolve the boss id - $resolved_boss = resolve_raid_boss($raid['pokemon'], $raid['pokemon_form'], $raid['spawn'], $raid['level']); - $raid['pokemon'] = $resolved_boss['pokedex_id']; - $raid['pokemon_form'] = $resolved_boss['pokemon_form_id']; + // Resolve the boss id + $resolved_boss = resolve_raid_boss($raid['pokemon'], $raid['pokemon_form'], $raid['spawn'], $raid['level']); + $raid['pokemon'] = $resolved_boss['pokedex_id']; + $raid['pokemon_form'] = $resolved_boss['pokemon_form_id']; - if (!$raid){ - $rs = my_query("SELECT * FROM raids WHERE raids.id = {$raid_id}"); - $row = json_encode($rs->fetch()); - throw new Exception("Failed to fetch raid id {$raid_id}, data we do have on it: {$row}"); - } + if (!$raid){ + $rs = my_query('SELECT * FROM raids WHERE raids.id = ?', [$raid_id]); + $row = json_encode($rs->fetch()); + throw new Exception("Failed to fetch raid id {$raid_id}, data we do have on it: {$row}"); + } - // Check trainername - $raid = check_trainername($raid); + // Check trainername + $raid = check_trainername($raid); - debug_log($raid); + debug_log($raid); - return $raid; + return $raid; } - -?> diff --git a/logic/get_raid_times.php b/logic/get_raid_times.php index 255589f8..a8fc8dd0 100644 --- a/logic/get_raid_times.php +++ b/logic/get_raid_times.php @@ -1,10 +1,9 @@ diff --git a/logic/get_remote_users_count.php b/logic/get_remote_users_count.php index 2863e3c7..f5c98aa3 100644 --- a/logic/get_remote_users_count.php +++ b/logic/get_remote_users_count.php @@ -51,5 +51,3 @@ function get_remote_users_count($raidId, $userId, $attendTime = false) return $remoteUsers; } - -?> diff --git a/logic/get_user.php b/logic/get_user.php index 46c554a3..99bf1db4 100644 --- a/logic/get_user.php +++ b/logic/get_user.php @@ -4,65 +4,52 @@ * @param $user_id * @param $public * @param $return_row - * @return message + * @return array|string message */ function get_user($user_id, $public = true, $return_row = false) { - global $config; - // Get user details. - $rs = my_query( - " - SELECT * - FROM users - WHERE user_id = {$user_id} - " - ); + global $config; + // Get user details. + $rs = my_query(' + SELECT * + FROM users + WHERE user_id = ? + ', [$user_id] + ); + // Fetch the row. + $row = $rs->fetch(); + // Build message string. + $msg = ''; - // Fetch the row. - $row = $rs->fetch(); - // Build message string. - $msg = ''; + $display_name = ['','']; + if(!$public) $display_name[intval($row['display_name'])] = '-> '; - $display_name = ['','']; - if(!$public) $display_name[intval($row['display_name'])] = '-> '; + // Add name. + $msg .= $display_name[0] . getTranslation('name') . ': ' . htmlspecialchars($row['name']) . '' . CR; + // Add name. + $msg .= $display_name[1] . getTranslation('trainername') . ': ' . (check_for_empty_string($row['trainername']) ? getTranslation('not_set') : $row['trainername'] ) . CR; - // Add name. - $msg .= $display_name[0] . getTranslation('name') . ': ' . htmlspecialchars($row['name']) . '' . CR; - // Add name. - $msg .= $display_name[1] . getTranslation('trainername') . ': ' . (check_for_empty_string($row['trainername']) ? getTranslation('not_set') : $row['trainername'] ) . CR; + if($config->RAID_POLL_SHOW_TRAINERCODE){ // is Trainercode enabled? + $trainercode = ($row['trainercode'] === NULL ? getTranslation('not_set') : $row['trainercode']); + $msg .= getTranslation('trainercode') . ': ' . $trainercode . CR; + } - if($config->RAID_POLL_SHOW_TRAINERCODE){ // is Trainercode enabled? - // Unknown trainercode. - if ($row['trainercode'] === NULL) { - $msg .= getTranslation('trainercode') . ': ' . getTranslation('not_set') . CR; - // Known Trainercode. - } else { - $msg .= getTranslation('trainercode') . ': ' . $row['trainercode'] . CR; - } - } + $team = ($row['team'] === NULL) ? $GLOBALS['teams']['unknown'] : $GLOBALS['teams'][$row['team']]; + $msg .= getTranslation('team') . ': ' . $team . CR; - // Unknown team. - if ($row['team'] === NULL) { - $msg .= getTranslation('team') . ': ' . $GLOBALS['teams']['unknown'] . CR; - // Known team. - } else { - $msg .= getTranslation('team') . ': ' . $GLOBALS['teams'][$row['team']] . CR; - } - - // Add level. - if ($row['level'] != 0) { - $msg .= getTranslation('level') . ': ' . $row['level'] . '' . CR . CR; - } - if(!$public) $msg .= getTranslation('display_name_explanation') . CR; + // Add level. + if ($row['level'] != 0) { + $msg .= getTranslation('level') . ': ' . $row['level'] . '' . CR . CR; + } + if(!$public) $msg .= getTranslation('display_name_explanation') . CR; - if($return_row) { - return [ - 'message' => $msg, - 'row' => $row - ]; - }else { - return $msg; - } + if($return_row) { + return [ + 'message' => $msg, + 'row' => $row + ]; + } + return $msg; } /** @@ -71,22 +58,22 @@ function get_user($user_id, $public = true, $return_row = false) * @return array $row */ function check_trainername($row){ - global $config; - // if Custom Trainername is enabled by config - if($config->CUSTOM_TRAINERNAME == false || check_for_empty_string($row['trainername']) || (isset($row['display_name']) && $row['display_name'] != 1)){ // trainername not set by user - // check if Telegram-@Nick is set - if(!check_for_empty_string($row['nick']) && $config->RAID_POLL_SHOW_NICK_OVER_NAME){ - // set Telegram-@Nick as Name inside the bot - $row['name'] = $row['nick']; - }else{ - // leave Telegram-name as it is (Trainername and Telegram-@Nick were not configured by user) - } + global $config; + // if Custom Trainername is enabled by config + if($config->CUSTOM_TRAINERNAME == false || check_for_empty_string($row['trainername']) || $row['display_name'] != 1){ // trainername not set by user + // check if Telegram-@Nick is set + if(!check_for_empty_string($row['nick']) && $config->RAID_POLL_SHOW_NICK_OVER_NAME){ + // set Telegram-@Nick as Name inside the bot + $row['name'] = $row['nick']; }else{ - // Trainername is configured by User - $row['name'] = $row['trainername']; + // leave Telegram-name as it is (Trainername and Telegram-@Nick were not configured by user) } + }else{ + // Trainername is configured by User + $row['name'] = $row['trainername']; + } - return $row; + return $row; } /** @@ -100,4 +87,3 @@ function check_for_empty_string($string){ } return false; } -?> diff --git a/logic/get_weather_icons.php b/logic/get_weather_icons.php index 1d6461f6..7b642ba1 100644 --- a/logic/get_weather_icons.php +++ b/logic/get_weather_icons.php @@ -6,28 +6,23 @@ */ function get_weather_icons($weather_value) { - if($weather_value > 0) { - // Get length of arg and split arg - $weather_value_length = strlen((string)$weather_value); - $weather_value_string = str_split((string)$weather_value); + if($weather_value == 0) return ''; + // Get length of arg and split arg + $weather_value_length = strlen((string)$weather_value); + $weather_value_string = str_split((string)$weather_value); - // Init weather icons string. - $weather_icons = ''; + // Init weather icons string. + $weather_icons = ''; - // Add icons to string. - for ($i = 0; $i < $weather_value_length; $i = $i + 1) { - // Get weather icon from constants - $weather_icons .= $GLOBALS['weather'][$weather_value_string[$i]]; - $weather_icons .= ' '; - } + // Add icons to string. + for ($i = 0; $i < $weather_value_length; $i = $i + 1) { + // Get weather icon from constants + $weather_icons .= $GLOBALS['weather'][$weather_value_string[$i]]; + $weather_icons .= ' '; + } - // Trim space after last icon - $weather_icons = rtrim($weather_icons); - } else { - $weather_icons = ''; - } + // Trim space after last icon + $weather_icons = rtrim($weather_icons); - return $weather_icons; + return $weather_icons; } - -?> diff --git a/logic/group_code_keys.php b/logic/group_code_keys.php index 82b14723..e7e4615b 100644 --- a/logic/group_code_keys.php +++ b/logic/group_code_keys.php @@ -63,6 +63,3 @@ function group_code_keys($raid_id, $action, $arg) return $keys; } - - -?> diff --git a/logic/history.php b/logic/history.php index 2c243157..7f231fa9 100644 --- a/logic/history.php +++ b/logic/history.php @@ -47,4 +47,3 @@ function create_history_date_msg_keys($current = '(SELECT max(start_time) FROM r ]; return [$msg, $keys]; } -?> \ No newline at end of file diff --git a/logic/insert_cleanup.php b/logic/insert_cleanup.php index 827fffac..4835cb74 100644 --- a/logic/insert_cleanup.php +++ b/logic/insert_cleanup.php @@ -9,34 +9,32 @@ */ function insert_cleanup($chat_id, $message_id, $raid_id, $type, $photo_id = NULL) { - // Log ID's of raid, chat and message - debug_log('Raid_ID: ' . $raid_id); - debug_log('Chat_ID: ' . $chat_id); - debug_log('Message_ID: ' . $message_id); - debug_log('Type: ' . $type); + // Log ID's of raid, chat and message + debug_log('Raid_ID: ' . $raid_id); + debug_log('Chat_ID: ' . $chat_id); + debug_log('Message_ID: ' . $message_id); + debug_log('Type: ' . $type); - if ((is_numeric($chat_id)) && (is_numeric($message_id)) && (is_numeric($raid_id)) && ($raid_id > 0)) { - // Build query for cleanup table to add cleanup info to database - debug_log('Adding cleanup info to database:'); - my_query( - " - REPLACE INTO cleanup - SET raid_id = :raid_id, - chat_id = :chat_id, - message_id = :message_id, - type = :type, - media_unique_id = :media_unique_id - ", [ - ':raid_id' => $raid_id, - ':chat_id' => $chat_id, - ':message_id' => $message_id, - ':type' => $type, - ':media_unique_id' => $photo_id, - ] - ); - } else { - debug_log('Invalid input for cleanup preparation!'); - } -} + if (!is_numeric($chat_id) || !is_numeric($message_id) || !is_numeric($raid_id) || $raid_id < 1) { + debug_log('Invalid input for cleanup preparation!'); + return; + } -?> + // Build query for cleanup table to add cleanup info to database + debug_log('Adding cleanup info to database:'); + my_query(' + REPLACE INTO cleanup + SET raid_id = :raid_id, + chat_id = :chat_id, + message_id = :message_id, + type = :type, + media_unique_id = :media_unique_id + ', [ + ':raid_id' => $raid_id, + ':chat_id' => $chat_id, + ':message_id' => $message_id, + ':type' => $type, + ':media_unique_id' => $photo_id, + ] + ); +} diff --git a/logic/insert_overview.php b/logic/insert_overview.php index ea79a141..dedbcfc8 100644 --- a/logic/insert_overview.php +++ b/logic/insert_overview.php @@ -8,35 +8,37 @@ */ function insert_overview($chat_id, $message_id, $chat_title, $chat_username) { - // Build query to check if overview details are already in database or not - $rs = my_query( - " - SELECT COUNT(*) AS count - FROM overview - WHERE chat_id = '{$chat_id}' - " - ); + // Build query to check if overview details are already in database or not + $rs = my_query(' + SELECT COUNT(*) AS count + FROM overview + WHERE chat_id = ? + ', [$chat_id] + ); - $row = $rs->fetch(); + $row = $rs->fetch(); - // Overview already in database or new - if (empty($row['count'])) { - // Build query for overview table to add overview info to database - debug_log('Adding new overview information to database overview list!'); - $rs = my_query( - " - INSERT INTO overview - SET chat_id = '{$chat_id}', - message_id = '{$message_id}', - chat_title = '{$chat_title}', - chat_username = '{$chat_username}', - updated = DATE(NOW()) - " - ); - } else { - // Nothing to do - overview information is already in database. - debug_log('Overview information is already in database! Nothing to do...'); - } + // Overview already in database or new + if (!empty($row['count'])) { + // Nothing to do - overview information is already in database. + debug_log('Overview information is already in database! Nothing to do...'); + return; + } + // Build query for overview table to add overview info to database + debug_log('Adding new overview information to database overview list!'); + my_query( + ' + INSERT INTO overview + SET chat_id = :chat_id, + message_id = :message_id, + chat_title = :chat_title, + chat_username = :chat_username, + updated = DATE(NOW()) + ', [ + 'chat_id' => $chat_id, + 'message_id' => $message_id, + 'chat_title' => $chat_title, + 'chat_username' => $chat_username, + ] + ); } - -?> diff --git a/logic/insert_trainerinfo.php b/logic/insert_trainerinfo.php index 210f0e71..f485d682 100644 --- a/logic/insert_trainerinfo.php +++ b/logic/insert_trainerinfo.php @@ -6,32 +6,28 @@ */ function insert_trainerinfo($chat_id, $message_id) { - // Build query to check if trainer info details are already in database or not - $rs = my_query( - " - SELECT COUNT(*) AS count - FROM trainerinfo - WHERE chat_id = '{$chat_id}' - " - ); + // Build query to check if trainer info details are already in database or not + $rs = my_query(' + SELECT COUNT(*) AS count + FROM trainerinfo + WHERE chat_id = ? + ', [$chat_id] + ); - $row = $rs->fetch(); + $row = $rs->fetch(); - // Trainer info already in database or new - if (empty($row['count'])) { - // Build query for trainerinfo table to add trainer info to database - debug_log('Adding new trainer information to database trainer info list!'); - $rs = my_query( - " - INSERT INTO trainerinfo - SET chat_id = '{$chat_id}', - message_id = '{$message_id}' - " - ); - } else { - // Nothing to do - trainer information is already in database. - debug_log('Trainer information is already in database! Nothing to do...'); - } + // Trainer info already in database or new + if (!empty($row['count'])) { + // Nothing to do - trainer information is already in database. + debug_log('Trainer information is already in database! Nothing to do...'); + return; + } + // Build query for trainerinfo table to add trainer info to database + debug_log('Adding new trainer information to database trainer info list!'); + my_query(' + INSERT INTO trainerinfo + SET chat_id = ?, + message_id = ? + ', [$chat_id, $message_id] + ); } - -?> diff --git a/core/bot/logic/key_util.php b/logic/key_util.php similarity index 87% rename from core/bot/logic/key_util.php rename to logic/key_util.php index 355274c5..1fd21ad0 100644 --- a/core/bot/logic/key_util.php +++ b/logic/key_util.php @@ -73,12 +73,12 @@ function universal_key($keys, $id, $action, $arg, $text = '0') /** * Share keys. Has own logic for fetching chat id's if used to generate share keys for raids. - * @param $id Id to pass to callback query - * @param $action Action to pass to callback query - * @param $update Update from Telegram - * @param $raidLevel Raid level if sharing a raid - * @param $chats List of chats if using alternative list - * @param $hideGeneralShare Leave out the general share button + * @param int $id Id to pass to callback query + * @param string $action Action to pass to callback query + * @param array $update Update from Telegram + * @param int $raidLevel Raid level if sharing a raid + * @param string $chats List of chats if using alternative list + * @param bool $hideGeneralShare Leave out the general share button * @return array */ function share_keys($id, $action, $update, $raidLevel = '', $chats = '', $hideGeneralShare = false) @@ -162,4 +162,17 @@ function share_keys($id, $action, $update, $raidLevel = '', $chats = '', $hideGe return $keys; } -?> +/** + * Format + * @param array $array + * @return string Formated + */ +function formatCallbackData($array) +{ + $return = $array['callbackAction'] . '|'; + unset($array['callbackAction']); + foreach($array as $key => $value) { + $return .= $key . '=' . $value . '|'; + } + return rtrim('|', $return); +} diff --git a/logic/keys_event.php b/logic/keys_event.php index 944a29fa..520166e4 100644 --- a/logic/keys_event.php +++ b/logic/keys_event.php @@ -9,27 +9,27 @@ function keys_event($gym_id_plus_letter, $action, $admin_access = [false,false]) { $keys = []; if($admin_access[1] === true) { - $q = my_query(" - SELECT id, - name - FROM events - WHERE id != 999 - "); + $q = my_query(' + SELECT id, + name + FROM events + WHERE id != 999 + '); while($event = $q->fetch()) { - if(!empty($event['name'])) { - $keys[] = array( - 'text' => $event['name'], - 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . $event['id'] - ); - }else { + if(empty($event['name'])) { info_log('Invalid event name on event '. $event['id']); + continue; } + $keys[] = array( + 'text' => $event['name'], + 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . $event['id'] + ); } } if($admin_access[0] === true) { $keys[] = array( - 'text' => getTranslation("Xstars"), - 'callback_data' => $gym_id_plus_letter . ':' . $action . ':X' + 'text' => getTranslation("Xstars"), + 'callback_data' => $gym_id_plus_letter . ':' . $action . ':X' ); } // Get the inline key array. @@ -37,4 +37,3 @@ function keys_event($gym_id_plus_letter, $action, $admin_access = [false,false]) return $keys; } -?> \ No newline at end of file diff --git a/logic/keys_trainerinfo.php b/logic/keys_trainerinfo.php index aea1d9c6..a027f13e 100644 --- a/logic/keys_trainerinfo.php +++ b/logic/keys_trainerinfo.php @@ -6,61 +6,58 @@ */ function keys_trainerinfo($show = false) { - global $config; - // Toggle state. - $status = 'show'; - if($show || !$config->TRAINER_BUTTONS_TOGGLE) { - // Always show buttons? - if(($show == true && !$config->TRAINER_BUTTONS_TOGGLE) || $config->TRAINER_BUTTONS_TOGGLE) { - $status = 'hide'; - } + global $config; + // Toggle state. + $status = 'show'; + if(!$show || $config->TRAINER_BUTTONS_TOGGLE) { + // Key to show/hide trainer info. + return [ + [ + [ + 'text' => getPublicTranslation('trainerinfo'), + 'callback_data' => 'trainer:vote_level:' . $status + ], + ] + ]; + } + // Always show buttons? + if(($show == true && !$config->TRAINER_BUTTONS_TOGGLE) || $config->TRAINER_BUTTONS_TOGGLE) { + $status = 'hide'; + } - // Keys to set team and level - $keys = [ - [ - [ - 'text' => getPublicTranslation('trainerinfo'), - 'callback_data' => 'trainer:vote_level:' . $status - ], - ], - [ - [ - 'text' => getPublicTranslation('team') . SP . TEAM_B, - 'callback_data' => 'trainer:vote_team:mystic' - ], - [ - 'text' => getPublicTranslation('team') . SP . TEAM_R, - 'callback_data' => 'trainer:vote_team:valor' - ], - [ - 'text' => getPublicTranslation('team') . SP . TEAM_Y, - 'callback_data' => 'trainer:vote_team:instinct' - ], - ], - [ - [ - 'text' => getPublicTranslation('level') . ' +', - 'callback_data' => 'trainer:vote_level:up' - ], - [ - 'text' => getPublicTranslation('level') . ' -', - 'callback_data' => 'trainer:vote_level:down' - ] - ] - ]; - } else { - // Key to show/hide trainer info. - $keys = [ - [ - [ - 'text' => getPublicTranslation('trainerinfo'), - 'callback_data' => 'trainer:vote_level:' . $status - ], - ] - ]; - } + // Keys to set team and level + $keys = [ + [ + [ + 'text' => getPublicTranslation('trainerinfo'), + 'callback_data' => 'trainer:vote_level:' . $status + ], + ], + [ + [ + 'text' => getPublicTranslation('team') . SP . TEAM_B, + 'callback_data' => 'trainer:vote_team:mystic' + ], + [ + 'text' => getPublicTranslation('team') . SP . TEAM_R, + 'callback_data' => 'trainer:vote_team:valor' + ], + [ + 'text' => getPublicTranslation('team') . SP . TEAM_Y, + 'callback_data' => 'trainer:vote_team:instinct' + ], + ], + [ + [ + 'text' => getPublicTranslation('level') . ' +', + 'callback_data' => 'trainer:vote_level:up' + ], + [ + 'text' => getPublicTranslation('level') . ' -', + 'callback_data' => 'trainer:vote_level:down' + ] + ] + ]; - return $keys; + return $keys; } - -?> diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 8a68fe47..e8ffe675 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -1,4 +1,5 @@ getPublicTranslation('raid_done'), + 'text' => getPublicTranslation('raid_done'), 'callback_data' => $raid['id'] . ':vote_refresh:1' ] ] @@ -52,11 +53,11 @@ function keys_vote($raid) } // Extra Keys $buttons['alone'] = [ - 'text' => EMOJI_SINGLE, + 'text' => EMOJI_SINGLE, 'callback_data' => $raid['id'] . ':vote_extra:0' ]; $buttons['extra'] = [ - 'text' => '+ ' . EMOJI_IN_PERSON, + 'text' => '+ ' . EMOJI_IN_PERSON, 'callback_data' => $raid['id'] . ':vote_extra:in_person' ]; @@ -64,25 +65,25 @@ function keys_vote($raid) $buttons['extra_alien'] = $buttons['can_inv'] = $buttons['remote'] = $buttons['inv_plz'] = []; if(!$raid_local_only) { $buttons['extra_alien'] = [ - 'text' => '+ ' . EMOJI_ALIEN, + 'text' => '+ ' . EMOJI_ALIEN, 'callback_data' => $raid['id'] . ':vote_extra:alien' ]; // Can invite key $buttons['can_inv'] = [ - 'text' => EMOJI_CAN_INVITE, + 'text' => EMOJI_CAN_INVITE, 'callback_data' => $raid['id'] . ':vote_can_invite:0' ]; // Remote Raid Pass key $buttons['remote'] = [ - 'text' => EMOJI_REMOTE, + 'text' => EMOJI_REMOTE, 'callback_data' => $raid['id'] . ':vote_remote:0' ]; // Want invite key $buttons['inv_plz'] = [ - 'text' => EMOJI_WANT_INVITE, + 'text' => EMOJI_WANT_INVITE, 'callback_data' => $raid['id'] . ':vote_want_invite:0' ]; } @@ -91,15 +92,15 @@ function keys_vote($raid) $buttons['teamlvl'] = [ [ [ - 'text' => 'Team', + 'text' => 'Team', 'callback_data' => $raid['id'] . ':vote_team:0' ], [ - 'text' => 'Lvl +', + 'text' => 'Lvl +', 'callback_data' => $raid['id'] . ':vote_level:up' ], [ - 'text' => 'Lvl -', + 'text' => 'Lvl -', 'callback_data' => $raid['id'] . ':vote_level:down' ] ] @@ -109,7 +110,7 @@ function keys_vote($raid) $buttons['ex_inv'] = []; if ($raid['event'] == EVENT_ID_EX) { $buttons['ex_inv'] = [ - 'text' => EMOJI_INVITE, + 'text' => EMOJI_INVITE, 'callback_data' => $raid['id'] . ':vote_invite:0' ]; } @@ -137,30 +138,30 @@ function keys_vote($raid) // Status keys. $buttons['alarm'] = [ - 'text' => EMOJI_ALARM, + 'text' => EMOJI_ALARM, 'callback_data' => $raid['id'] . ':vote_status:alarm' ]; $buttons['here'] = [ - 'text' => $text_here, + 'text' => $text_here, 'callback_data' => $raid['id'] . ':vote_status:arrived' ]; $buttons['late'] = [ - 'text' => $text_late, + 'text' => $text_late, 'callback_data' => $raid['id'] . ':vote_status:late' ]; $buttons['done'] = [ - 'text' => $text_done, + 'text' => $text_done, 'callback_data' => $raid['id'] . ':vote_status:raid_done' ]; $buttons['cancel'] = [ - 'text' => $text_cancel, + 'text' => $text_cancel, 'callback_data' => $raid['id'] . ':vote_status:cancel' ]; $buttons['refresh'] = []; if(!$config->AUTO_REFRESH_POLLS) { $buttons['refresh'] = [ - 'text' => EMOJI_REFRESH, + 'text' => EMOJI_REFRESH, 'callback_data' => $raid['id'] . ':vote_refresh:0' ]; } @@ -168,7 +169,7 @@ function keys_vote($raid) if($raid['event_vote_key_mode'] == 1) { $keys_time = [ [ - 'text' => getPublicTranslation("Participate"), + 'text' => getPublicTranslation("Participate"), 'callback_data' => $raid['id'] . ':vote_time:' . utctime($raid['start_time'], 'YmdHis') ] ]; @@ -190,8 +191,7 @@ function keys_vote($raid) } // Get participants - $rs = my_query( - ' + $rs = my_query(' SELECT count(attend_time) AS count, sum(pokemon = 0) AS count_any_pokemon, sum(pokemon = ?) AS count_raid_pokemon @@ -234,14 +234,14 @@ function keys_vote($raid) foreach($raid_bosses as $pokemon) { if(in_array($pokemon['pokedex_id'], $GLOBALS['eggs'])) continue; $buttons['pokemon'][] = array( - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), + 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), 'callback_data' => $raid['id'] . ':vote_pokemon:' . $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] ); } // Add button if raid boss does not matter $buttons['pokemon'][] = array( - 'text' => getPublicTranslation('any_pokemon'), + 'text' => getPublicTranslation('any_pokemon'), 'callback_data' => $raid['id'] . ':vote_pokemon:0' ); @@ -258,7 +258,6 @@ function keys_vote($raid) $r = 0; foreach($template as $row) { foreach($row as $key) { - $v_name = 'buttons_'.$key; if(!isset($buttons[$key]) or empty($buttons[$key])) continue; if($key == 'teamlvl' or $key == 'pokemon' or $key == 'time') { // Some button variables are "blocks" of keys, process them here @@ -281,15 +280,14 @@ function keys_vote($raid) /** * Get active raid bosses at a certain time. - * @param $time - string, datetime, local time - * @param $raid_level - ENUM('1', '2', '3', '4', '5', '6', 'X') + * @param string $time - string, datetime, local time + * @param int|string $raid_level - ENUM('1', '2', '3', '4', '5', '6', 'X') * @return array */ function get_raid_bosses($time, $raid_level) { // Get raid level from database - $rs = my_query( - ' + $rs = my_query(' SELECT DISTINCT pokedex_id, pokemon_form_id FROM raid_bosses WHERE ? BETWEEN date_start AND date_end @@ -309,8 +307,8 @@ function get_raid_bosses($time, $raid_level) /** * Get active raid bosses at a certain time. - * @param $RAID_SLOTS - int, length of the timeslot - * @param $raid + * @param int $RAID_SLOTS Length of the timeslot + * @param array $raid * @return array */ function generateTimeslotKeys($RAID_SLOTS, $raid) { @@ -381,7 +379,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { // Add regular slot. if($slot >= $dt_now) { $keys_time[] = array( - 'text' => dt2time($slot->format('Y-m-d H:i:s')), + 'text' => dt2time($slot->format('Y-m-d H:i:s')), 'callback_data' => $raid['id'] . ':vote_time:' . $slot->format('YmdHis') ); } @@ -418,5 +416,3 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { } return $keys_time; } - -?> diff --git a/core/bot/logic/language.php b/logic/language.php similarity index 100% rename from core/bot/logic/language.php rename to logic/language.php diff --git a/logic/mapslink.php b/logic/mapslink.php index cff5f41b..f7c1f681 100644 --- a/logic/mapslink.php +++ b/logic/mapslink.php @@ -42,4 +42,3 @@ function mapslink($gym, $gym_address = '0'){ // returning Maps Link return $maps_link; } -?> diff --git a/logic/new_user.php b/logic/new_user.php index 8b2e239a..f5e0f408 100644 --- a/logic/new_user.php +++ b/logic/new_user.php @@ -17,13 +17,11 @@ function new_user($user_id) { * @return int */ function user_tutorial($user_id) { - debug_log("Reading user's tutorial value: ".$user_id); - $query = my_query("SELECT tutorial FROM users WHERE user_id = :user_id LIMIT 1", [":user_id"=>$user_id]); + debug_log('Reading user\'s tutorial value: '.$user_id); + $query = my_query('SELECT tutorial FROM users WHERE user_id = :user_id LIMIT 1', [":user_id"=>$user_id]); $res = $query->fetch(); $result = 0; if($query->rowCount() > 0) $result = $res['tutorial']; - debug_log("Result: ".$result); + debug_log('Result: '.$result); return $result; } - -?> \ No newline at end of file diff --git a/logic/pokemon_keys.php b/logic/pokemon_keys.php index f282ef54..3d6f1be6 100644 --- a/logic/pokemon_keys.php +++ b/logic/pokemon_keys.php @@ -8,45 +8,43 @@ */ function pokemon_keys($gym_id_plus_letter, $raid_level, $action, $event_id = false) { - global $config; - // Init empty keys array. - $keys = []; + global $config; + // Init empty keys array. + $keys = []; - $time_now = dt2time(utcnow(), 'Y-m-d H:i'); + $time_now = dt2time(utcnow(), 'Y-m-d H:i'); - $egg_id = '999' . $raid_level; + $egg_id = '999' . $raid_level; - // Get pokemon from database - $query = ' - SELECT pokemon.id, pokemon.pokedex_id, pokemon.pokemon_form_id - FROM raid_bosses - LEFT JOIN pokemon - ON pokemon.pokedex_id = raid_bosses.pokedex_id - AND pokemon.pokemon_form_id = raid_bosses.pokemon_form_id - WHERE raid_bosses.raid_level = \'' . $raid_level . '\' - AND ( - DATE_SUB(\'' . $time_now . '\', INTERVAL '.$config->RAID_EGG_DURATION.' MINUTE) between date_start and date_end - OR DATE_ADD(\'' . $time_now . '\', INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end - ) - UNION - SELECT id, pokedex_id, pokemon_form_id - FROM pokemon - WHERE pokedex_id = \'' . $egg_id . '\' - ORDER BY pokedex_id - '; - $rs = my_query($query); - // Add key for each raid level - while ($pokemon = $rs->fetch()) { - $keys[] = array( - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), - 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . (($event_id!==false) ? $event_id . ',' . $raid_level . ',' : '') . $pokemon['id'] - ); - } + // Get pokemon from database + $rs = my_query(' + SELECT pokemon.id, pokemon.pokedex_id, pokemon.pokemon_form_id + FROM raid_bosses + LEFT JOIN pokemon + ON pokemon.pokedex_id = raid_bosses.pokedex_id + AND pokemon.pokemon_form_id = raid_bosses.pokemon_form_id + WHERE raid_bosses.raid_level = :raidLevel + AND ( + DATE_SUB(\'' . $time_now . '\', INTERVAL '.$config->RAID_EGG_DURATION.' MINUTE) between date_start and date_end + OR DATE_ADD(\'' . $time_now . '\', INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end + ) + UNION + SELECT id, pokedex_id, pokemon_form_id + FROM pokemon + WHERE pokedex_id = :eggId + ORDER BY pokedex_id + ', ['raidLevel' => $raid_level, 'eggId' => $egg_id] + ); + // Add key for each raid level + while ($pokemon = $rs->fetch()) { + $keys[] = array( + 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), + 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . (($event_id!==false) ? $event_id . ',' . $raid_level . ',' : '') . $pokemon['id'] + ); + } - // Get the inline key array. - $keys = inline_key_array($keys, 1); + // Get the inline key array. + $keys = inline_key_array($keys, 1); - return $keys; + return $keys; } - -?> diff --git a/logic/raid_edit_gym_keys.php b/logic/raid_edit_gym_keys.php index 5868b04a..6fe4d050 100644 --- a/logic/raid_edit_gym_keys.php +++ b/logic/raid_edit_gym_keys.php @@ -1,4 +1,5 @@ RAID_CUSTOM_GYM_LETTERS) && $first_length == 1) { - // Explode special letters. - $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); + // Special/Custom gym letters? + $not = ''; + if(!empty($config->RAID_CUSTOM_GYM_LETTERS) && $first_length == 1) { + // Explode special letters. + $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); - foreach($special_keys as $id => $letter) - { - $letter = trim($letter); - debug_log($letter, 'Special gym letter:'); - // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); - $not .= SP . "AND UPPER(LEFT(gym_name, " . $length . ")) != UPPER('" . $letter . "')" . SP; - } + foreach($special_keys as $id => $letter) + { + $letter = trim($letter); + debug_log($letter, 'Special gym letter:'); + // Fix chinese chars, prior: $length = strlen($letter); + $length = strlen(utf8_decode($letter)); + $not .= SP . "AND UPPER(LEFT(gym_name, " . $length . ")) != UPPER('" . $letter . "')" . SP; } - $gymarea_query = ''; - if($gymarea_id != false) { - $json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'),1); - $points = []; - foreach($json as $area) { - if($gymarea_id == $area['id']) { - foreach($area['path'] as $point) { - $points[] = $point[0].' '.$point[1]; - } - if($points[0] != $points[count($points)-1]) $points[] = $points[0]; - break; - } + } + $gymarea_query = ''; + if($gymarea_id != false) { + $json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'),1); + $points = []; + foreach($json as $area) { + if($gymarea_id == $area['id']) { + foreach($area['path'] as $point) { + $points[] = $point[0].' '.$point[1]; } - $polygon_string = implode(',', $points); - $gymarea_query = "AND ST_CONTAINS(ST_GEOMFROMTEXT('POLYGON((".$polygon_string."))'), ST_GEOMFROMTEXT(CONCAT('POINT(',lat,' ',lon,')')))"; - } - // Show hidden gyms? - if($hidden == true) { - $show_gym = 0; - } else { - $show_gym = 1; + if($points[0] != $points[count($points)-1]) $points[] = $points[0]; + break; + } } - $query_collate = ""; - if($config->MYSQL_SORT_COLLATE != "") { - $query_collate = "COLLATE " . $config->MYSQL_SORT_COLLATE; - } - // Get gyms from database - $rs = my_query( - " - SELECT gyms.id, gyms.gym_name, gyms.ex_gym, - CASE WHEN SUM(raids.end_time > UTC_TIMESTAMP() - INTERVAL 10 MINUTE) THEN 1 ELSE 0 END AS active_raid - FROM gyms - LEFT JOIN raids - ON raids.gym_id = gyms.id - WHERE UPPER(LEFT(gym_name, $first_length)) = UPPER('{$first}') - $not - $gymarea_query - AND gyms.show_gym = {$show_gym} - GROUP BY gym_name, raids.gym_id, gyms.id, gyms.ex_gym - ORDER BY gym_name " . $query_collate . " - " - ); + $polygon_string = implode(',', $points); + $gymarea_query = 'AND ST_CONTAINS(ST_GEOMFROMTEXT(\'POLYGON(('.$polygon_string.'))\'), ST_GEOMFROMTEXT(CONCAT(\'POINT(\',lat,\' \',lon,\')\')))'; + } + // Show hidden gyms? + $show_gym = ($hidden == true) ? 0 : 1; - // Init empty keys array. - $keys = []; + $query_collate = ''; + if($config->MYSQL_SORT_COLLATE != "") { + $query_collate = 'COLLATE ' . $config->MYSQL_SORT_COLLATE; + } + // Get gyms from database + $rs = my_query(' + SELECT gyms.id, gyms.gym_name, gyms.ex_gym, + CASE WHEN SUM(raids.end_time > UTC_TIMESTAMP() - INTERVAL 10 MINUTE) THEN 1 ELSE 0 END AS active_raid + FROM gyms + LEFT JOIN raids + ON raids.gym_id = gyms.id + WHERE UPPER(LEFT(gym_name, ' . $first_length . ')) = UPPER(\'' . $first . '\') + ' . $not . ' + ' . $gymarea_query . ' + AND gyms.show_gym = ? + GROUP BY gym_name, raids.gym_id, gyms.id, gyms.ex_gym + ORDER BY gym_name ' . $query_collate . ' + ', [$show_gym] + ); - while ($gym = $rs->fetch()) { - // Add delete argument to keys - if ($delete == true) { - $arg = $gym['id'] . '-delete'; - } else { - $arg = $gym['id']; - } + // Init empty keys array. + $keys = []; - // List action to list only gyms with active raids, so always continue at the end - if ($action == 'list_raid') { - if ($gym['active_raid'] == 1) { - $keys[] = array( - 'text' => $gym['gym_name'], - 'callback_data' => '0:' . $action . ':' . $arg - ); - } - // Continue always in case of list action - continue; - } + while ($gym = $rs->fetch()) { + $arg = $gym['id']; + // Add delete argument to keys + if ($delete == true) { + $arg .= '-delete'; + } - // Write to log. - // debug_log($gym); - - $active_raid = active_raid_duplication_check($gym['id']); - - // Show Ex-Gym-Marker? - if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { - $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; - $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; - } else { - $gym_name = $gym['gym_name']; - } - // Add warning emoji for active raid - if ($active_raid > 0) { - $gym_name = EMOJI_WARN . SP . $gym_name; - } + // List action to list only gyms with active raids, so always continue at the end + if ($action == 'list_raid') { + if ($gym['active_raid'] == 1) { $keys[] = array( - 'text' => $gym_name, - 'callback_data' => $first . ':' . $action . ':' . $arg + 'text' => $gym['gym_name'], + 'callback_data' => '0:' . $action . ':' . $arg ); + } + // Continue always in case of list action + continue; } - // Get the inline key array. - $keys = inline_key_array($keys, 1); + // Write to log. + // debug_log($gym); - return $keys; + $active_raid = active_raid_duplication_check($gym['id']); -} + // Show Ex-Gym-Marker? + if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { + $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; + $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; + } else { + $gym_name = $gym['gym_name']; + } + // Add warning emoji for active raid + if ($active_raid > 0) { + $gym_name = EMOJI_WARN . SP . $gym_name; + } + $keys[] = array( + 'text' => $gym_name, + 'callback_data' => $first . ':' . $action . ':' . $arg + ); + } + + // Get the inline key array. + $keys = inline_key_array($keys, 1); -?> + return $keys; + +} diff --git a/logic/raid_edit_gyms_first_letter_keys.php b/logic/raid_edit_gyms_first_letter_keys.php index 573397fa..f29dd023 100644 --- a/logic/raid_edit_gyms_first_letter_keys.php +++ b/logic/raid_edit_gyms_first_letter_keys.php @@ -1,4 +1,5 @@ ENABLE_GYM_AREAS) { - $json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'),1); - $points = []; - foreach($json as $area) { - $gymarea_id = ($gymarea_id !== false) ? $gymarea_id : $config->DEFAULT_GYM_AREA; - if($gymarea_id !== false && $gymarea_id == $area['id']) { - foreach($area['path'] as $point) { - $points[] = $point[0].' '.$point[1]; - } - $gymarea_name = $area['name']; - if($points[0] != $points[count($points)-1]) $points[] = $points[0]; - $skip_letter_keys = false; - } else { - $gymarea_keys[] = [ - 'text' => $area['name'], - 'callback_data' => $area['id'] . ':' . $gymarea_action . ':' . $action - ]; - } + global $config; + $gymarea_query = $gymarea_name = ''; + $gymarea_keys = []; + $skip_letter_keys = true; + $letters = false; + if($config->ENABLE_GYM_AREAS) { + $json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'),1); + $points = []; + foreach($json as $area) { + $gymarea_id = ($gymarea_id !== false) ? $gymarea_id : $config->DEFAULT_GYM_AREA; + if($gymarea_id !== false && $gymarea_id == $area['id']) { + foreach($area['path'] as $point) { + $points[] = $point[0].' '.$point[1]; } - $polygon_string = implode(',', $points); - $gymarea_query = "AND ST_CONTAINS(ST_GEOMFROMTEXT('POLYGON((".$polygon_string."))'), ST_GEOMFROMTEXT(CONCAT('POINT(',lat,' ',lon,')')))"; + $gymarea_name = $area['name']; + if($points[0] != $points[count($points)-1]) $points[] = $points[0]; + $skip_letter_keys = false; + } else { + $gymarea_keys[] = [ + 'text' => $area['name'], + 'callback_data' => $area['id'] . ':' . $gymarea_action . ':' . $action + ]; + } } - // Init empty keys array. - $keys = []; + $polygon_string = implode(',', $points); + $gymarea_query = 'AND ST_CONTAINS(ST_GEOMFROMTEXT(\'POLYGON(('.$polygon_string.'))\'), ST_GEOMFROMTEXT(CONCAT(\'POINT(\',lat,\' \',lon,\')\')))'; + } + // Init empty keys array. + $keys = []; - if(!$skip_letter_keys or !$config->ENABLE_GYM_AREAS or $hidden) { - // Special/Custom gym letters? - if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { - // Explode special letters. - $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); - $select = 'SELECT CASE '; - foreach($special_keys as $letter) - { - $letter = trim($letter); - debug_log($letter, 'Special gym letter:'); - // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); - $select .= SP . "WHEN UPPER(LEFT(gym_name, " . $length . ")) = '" . $letter . "' THEN UPPER(LEFT(gym_name, " . $length . "))" . SP; - } - $select .= 'ELSE UPPER(LEFT(gym_name, 1)) END AS first_letter'; - $group_order = 'GROUP BY 1 ORDER BY gym_name'; - }else { - $select = 'SELECT DISTINCT UPPER(SUBSTR(gym_name, 1, 1)) AS first_letter'; - $group_order = 'ORDER BY 1'; - } - // Show hidden gyms? - $show_gym = $hidden ? 0 : 1; - - if($action == 'list_by_gym') { - // Select only gyms with active raids - $query_condition = ' - LEFT JOIN raids - ON raids.gym_id = gyms.id - WHERE end_time > UTC_TIMESTAMP() - AND show_gym = ' . $show_gym; - }else { - $query_condition = 'WHERE show_gym = ' . $show_gym; - } + if(!$skip_letter_keys or !$config->ENABLE_GYM_AREAS or $hidden) { + // Special/Custom gym letters? + if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { + // Explode special letters. + $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); + $select = 'SELECT CASE '; + foreach($special_keys as $letter) + { + $letter = trim($letter); + debug_log($letter, 'Special gym letter:'); + // Fix chinese chars, prior: $length = strlen($letter); + $length = strlen(utf8_decode($letter)); + $select .= SP . 'WHEN UPPER(LEFT(gym_name, ' . $length . ')) = \'' . $letter . '\' THEN UPPER(LEFT(gym_name, ' . $length . '))' . SP; + } + $select .= 'ELSE UPPER(LEFT(gym_name, 1)) END AS first_letter'; + $group_order = ' GROUP BY 1 ORDER BY gym_name'; + }else { + $select = 'SELECT DISTINCT UPPER(SUBSTR(gym_name, 1, 1)) AS first_letter'; + $group_order = ' ORDER BY 1'; + } + // Show hidden gyms? + $show_gym = $hidden ? 0 : 1; - $rs_count = my_query("SELECT COUNT(gym_name) as count FROM gyms {$query_condition} {$gymarea_query}"); - $gym_count = $rs_count->fetch(); - $rs = my_query( - " - {$select} - FROM gyms - {$query_condition} - {$gymarea_query} - {$group_order} - " - ); - // If found over 20 gyms, print letters - if($gym_count['count'] > 20) { - while ($gym = $rs->fetch()) { - // Add first letter to keys array - $keys[] = array( - 'text' => $gym['first_letter'], - 'callback_data' => $show_gym . ':' . $action . ':' . $gym['first_letter'] . (($gymarea_id !== 'n') ? ',' .$gymarea_id : '') - ); - } + if($action == 'list_by_gym') { + // Select only gyms with active raids + $query_condition = ' + LEFT JOIN raids + ON raids.gym_id = gyms.id + WHERE end_time > UTC_TIMESTAMP() + AND show_gym = ' . $show_gym . ' '; + }else { + $query_condition = 'WHERE show_gym = ' . $show_gym . ' '; + } - // Get the inline key array. - $keys = inline_key_array($keys, 4); - $letters = true; - }else { - // If less than 20 gyms was found, print gym names - if($action == 'list_by_gym') { - // Select only gyms with active raids - $query_condition = ' - WHERE end_time > UTC_TIMESTAMP() - AND show_gym = ' . $show_gym; - }else { - $query_condition = 'WHERE show_gym = ' . $show_gym; - } - $query_collate = ''; - if($config->MYSQL_SORT_COLLATE != "") { - $query_collate = "COLLATE " . $config->MYSQL_SORT_COLLATE; - } - $rs = my_query( - " - SELECT gyms.id, gyms.gym_name, gyms.ex_gym, - CASE WHEN SUM(raids.end_time > UTC_TIMESTAMP() - INTERVAL 10 MINUTE) THEN 1 ELSE 0 END AS active_raid - FROM gyms - LEFT JOIN raids - ON raids.gym_id = gyms.id - {$query_condition} - {$gymarea_query} - GROUP BY gym_name, raids.gym_id, gyms.id, gyms.ex_gym - ORDER BY gym_name " . $query_collate . " - " - ); - // Init empty keys array. - $keys = []; + $rs_count = my_query('SELECT COUNT(gym_name) as count FROM gyms ' . $query_condition . ' ' . $gymarea_query); + $gym_count = $rs_count->fetch(); + // If found over 20 gyms, print letters + if($gym_count['count'] > 20) { + $rs = my_query( + $select . + ' FROM gyms ' . + $query_condition . + $gymarea_query . + $group_order + ); + while ($gym = $rs->fetch()) { + // Add first letter to keys array + $keys[] = array( + 'text' => $gym['first_letter'], + 'callback_data' => $show_gym . ':' . $action . ':' . $gym['first_letter'] . (($gymarea_id !== 'n') ? ',' .$gymarea_id : '') + ); + } - while ($gym = $rs->fetch()) { - if($gym['id'] != NULL) { - $active_raid = active_raid_duplication_check($gym['id']); + // Get the inline key array. + $keys = inline_key_array($keys, 4); + $letters = true; + }else { + // If less than 20 gyms was found, print gym names + if($action == 'list_by_gym') { + // Select only gyms with active raids + $query_condition = ' + WHERE end_time > UTC_TIMESTAMP() + AND show_gym = ' . $show_gym; + }else { + $query_condition = 'WHERE show_gym = ' . $show_gym; + } + $query_collate = ''; + if($config->MYSQL_SORT_COLLATE != "") { + $query_collate = 'COLLATE ' . $config->MYSQL_SORT_COLLATE; + } + $rs = my_query(' + SELECT gyms.id, gyms.gym_name, gyms.ex_gym, + CASE WHEN SUM(raids.end_time > UTC_TIMESTAMP() - INTERVAL 10 MINUTE) THEN 1 ELSE 0 END AS active_raid + FROM gyms + LEFT JOIN raids + ON raids.gym_id = gyms.id + ' . $query_condition . ' + ' . $gymarea_query . ' + GROUP BY gym_name, raids.gym_id, gyms.id, gyms.ex_gym + ORDER BY gym_name ' . $query_collate + ); + // Init empty keys array. + $keys = []; - // Show Ex-Gym-Marker? - if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { - $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; - $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; - } else { - $gym_name = $gym['gym_name']; - } - // Add warning emoji for active raid - if ($active_raid > 0) { - $gym_name = EMOJI_WARN . SP . $gym_name; - } - if($gym_name_action == 'list_raid') { - $keys[] = array( - 'text' => $gym_name, - 'callback_data' => '0:' . $gym_name_action . ':' . $gym['id'] - ); - }else { - $keys[] = array( - 'text' => $gym_name, - 'callback_data' => 'gl' . $gymarea_id . ':' . $gym_name_action . ':' . $gym['id'] - ); - } - } - } + while ($gym = $rs->fetch()) { + if($gym['id'] == NULL) continue; + $active_raid = active_raid_duplication_check($gym['id']); - // Get the inline key array. - $keys = inline_key_array($keys, 1); + // Show Ex-Gym-Marker? + if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { + $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; + $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; + } else { + $gym_name = $gym['gym_name']; } - } - - // Add back navigation key. - if($hidden == false) { - if($config->RAID_VIA_LOCATION_FUNCTION == 'remote') { - $query_remote = my_query('SELECT count(*) as count FROM raids LEFT JOIN gyms on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); - if($query_remote->fetch()['count'] > 0) { - $keys[][] = array( - 'text' => getTranslation('remote_raids'), - 'callback_data' => '0:list_remote_gyms:0' - ); - } + // Add warning emoji for active raid + if ($active_raid > 0) { + $gym_name = EMOJI_WARN . SP . $gym_name; + } + if($gym_name_action == 'list_raid') { + $keys[] = array( + 'text' => $gym_name, + 'callback_data' => '0:' . $gym_name_action . ':' . $gym['id'] + ); + }else { + $keys[] = array( + 'text' => $gym_name, + 'callback_data' => 'gl' . $gymarea_id . ':' . $gym_name_action . ':' . $gym['id'] + ); } - $nav_keys = []; - if(!empty($gymarea_keys) && ($config->DEFAULT_GYM_AREA !== false || $gymarea_id === false)) $keys = array_merge($keys, inline_key_array($gymarea_keys, 2)); + } - // Get the inline key array. - $keys[] = $nav_keys; + // Get the inline key array. + $keys = inline_key_array($keys, 1); } + } - return ['keys' => $keys, 'gymarea_name' => $gymarea_name, 'letters' => $letters]; -} + // Add back navigation key. + if($hidden == false) { + if($config->RAID_VIA_LOCATION_FUNCTION == 'remote') { + $query_remote = my_query('SELECT count(*) as count FROM raids LEFT JOIN gyms on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); + if($query_remote->fetch()['count'] > 0) { + $keys[][] = array( + 'text' => getTranslation('remote_raids'), + 'callback_data' => '0:list_remote_gyms:0' + ); + } + } + $nav_keys = []; + if(!empty($gymarea_keys) && ($config->DEFAULT_GYM_AREA !== false || $gymarea_id === false)) $keys = array_merge($keys, inline_key_array($gymarea_keys, 2)); -?> + // Get the inline key array. + $keys[] = $nav_keys; + } + + return ['keys' => $keys, 'gymarea_name' => $gymarea_name, 'letters' => $letters]; +} diff --git a/logic/raid_edit_raidlevel_keys.php b/logic/raid_edit_raidlevel_keys.php index d1e93f25..af8e84d4 100644 --- a/logic/raid_edit_raidlevel_keys.php +++ b/logic/raid_edit_raidlevel_keys.php @@ -9,83 +9,82 @@ */ function raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access = [false,false], $event = false) { - global $config; + global $config; - $time_now = dt2time(utcnow(), 'Y-m-d H:i'); + $time_now = dt2time(utcnow(), 'Y-m-d H:i'); - if($event === false) { - // Set event ID to null if no event was selected - $event_id = 'N'; - $query_event = 'AND raid_bosses.raid_level != \'X\''; - }else { - $event_id = $event; - if($admin_access[0] === true) $query_event = ''; - else $query_event = 'AND raid_bosses.raid_level != \'X\''; - } - $query_counts = ' - SELECT raid_level, COUNT(*) AS raid_level_count - FROM raid_bosses - WHERE ( - DATE_SUB(\'' . $time_now . '\', INTERVAL '.$config->RAID_EGG_DURATION.' MINUTE) between date_start and date_end - OR DATE_ADD(\'' . $time_now . '\', INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end - ) - '.$query_event.' - GROUP BY raid_bosses.raid_level - ORDER BY FIELD(raid_bosses.raid_level, \'6\', \'5\', \'4\', \'3\', \'2\', \'1\', \'X\') - '; - // Get all raid levels from database - $rs_counts = my_query($query_counts); + if($event === false) { + // Set event ID to null if no event was selected + $event_id = 'N'; + $query_event = 'AND raid_bosses.raid_level != \'X\''; + }else { + $event_id = $event; + if($admin_access[0] === true) $query_event = ''; + else $query_event = 'AND raid_bosses.raid_level != \'X\''; + } + $query_counts = ' + SELECT raid_level, COUNT(*) AS raid_level_count + FROM raid_bosses + WHERE ( + DATE_SUB(\'' . $time_now . '\', INTERVAL '.$config->RAID_EGG_DURATION.' MINUTE) between date_start and date_end + OR DATE_ADD(\'' . $time_now . '\', INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end + ) + '.$query_event.' + GROUP BY raid_bosses.raid_level + ORDER BY FIELD(raid_bosses.raid_level, \'9\', \'8\', \'7\', \'6\', \'5\', \'4\', \'3\', \'2\', \'1\', \'X\') + '; + // Get all raid levels from database + $rs_counts = my_query($query_counts); - // Init empty keys array. - $keys = []; + // Init empty keys array. + $keys = []; - // Add key for each raid level - while ($level = $rs_counts->fetch()) { - // Raid level and action - $raid_level = $level['raid_level']; + // Add key for each raid level + while ($level = $rs_counts->fetch()) { + // Raid level and action + $raid_level = $level['raid_level']; - // Add key for pokemon if we have just 1 pokemon for a level - if($level['raid_level_count'] == 1) { - $query_mon = my_query(' - SELECT pokemon.id, pokemon.pokedex_id, pokemon.pokemon_form_id - FROM raid_bosses - LEFT JOIN pokemon - ON pokemon.pokedex_id = raid_bosses.pokedex_id - AND pokemon.pokemon_form_id = raid_bosses.pokemon_form_id - WHERE ( - DATE_SUB(\'' . $time_now . '\', INTERVAL '.$config->RAID_EGG_DURATION.' MINUTE) between date_start and date_end - OR DATE_ADD(\'' . $time_now . '\', INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end - ) - AND raid_level = \''.$raid_level.'\' - '.$query_event.' - LIMIT 1 - '); - $pokemon = $query_mon->fetch(); - // Add key for pokemon - $keys[] = array( - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), - 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_starttime:' . $event_id . ',' . $raid_level . ',' . $pokemon['id'] - ); - } else { - // Add key for raid level - $keys[] = array( - 'text' => getTranslation($raid_level . 'stars'), - 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_pokemon:' . $event_id . ',' . $raid_level - ); - } - } - // Add key for raid event if user allowed to create event raids - if(($admin_access[1] === true or $admin_access[0] === true) && $event === false) { - $keys[] = array( - 'text' => getTranslation('event'), - 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_event:0' - ); + // Add key for pokemon if we have just 1 pokemon for a level + if($level['raid_level_count'] != 1) { + // Add key for raid level + $keys[] = array( + 'text' => getTranslation($raid_level . 'stars'), + 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_pokemon:' . $event_id . ',' . $raid_level + ); + continue; } - - // Get the inline key array. - $keys = inline_key_array($keys, 3); + $query_mon = my_query(' + SELECT pokemon.id, pokemon.pokedex_id, pokemon.pokemon_form_id + FROM raid_bosses + LEFT JOIN pokemon + ON pokemon.pokedex_id = raid_bosses.pokedex_id + AND pokemon.pokemon_form_id = raid_bosses.pokemon_form_id + WHERE ( + DATE_SUB(\'' . $time_now . '\', INTERVAL '.$config->RAID_EGG_DURATION.' MINUTE) between date_start and date_end + OR DATE_ADD(\'' . $time_now . '\', INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end + ) + AND raid_level = ? + '.$query_event.' + LIMIT 1 + ', [$raid_level] + ); + $pokemon = $query_mon->fetch(); + // Add key for pokemon + $keys[] = array( + 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), + 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_starttime:' . $event_id . ',' . $raid_level . ',' . $pokemon['id'] + ); + } + // Add key for raid event if user allowed to create event raids + if(($admin_access[1] === true or $admin_access[0] === true) && $event === false) { + $keys[] = array( + 'text' => getTranslation('event'), + 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_event:0' + ); + } - return $keys; -} + // Get the inline key array. + $keys = inline_key_array($keys, 3); -?> + return $keys; +} diff --git a/logic/raid_get_gyms_list_keys.php b/logic/raid_get_gyms_list_keys.php index 5d99b73e..fbb06323 100644 --- a/logic/raid_get_gyms_list_keys.php +++ b/logic/raid_get_gyms_list_keys.php @@ -6,54 +6,39 @@ */ function raid_get_gyms_list_keys($searchterm) { - // Init empty keys array. - $keys = []; - - // Make sure the search term is not empty - if(!empty($searchterm)) { - // Get gyms from database - $rs = my_query( - " - SELECT id, gym_name - FROM gyms - WHERE gym_name LIKE '$searchterm%' - AND show_gym LIKE 1 - OR gym_name LIKE '%$searchterm%' - AND show_gym LIKE 1 - ORDER BY - CASE - WHEN gym_name LIKE '$searchterm%' THEN 1 - WHEN gym_name LIKE '%$searchterm%' THEN 2 - ELSE 3 - END - LIMIT 15 - " - ); - - while ($gym = $rs->fetch()) { - $first = strtoupper(substr($gym['gym_name'], 0, 1)); - $keys[] = array( - 'text' => $gym['gym_name'], - 'callback_data' => $first . ':edit_raidlevel:' . $gym['id'] - ); - } - } - - // Add abort key. - if($keys) { - // Get the inline key array. - $keys = inline_key_array($keys, 1); - - // Add back navigation key. - $nav_keys = []; - $nav_keys[] = universal_inner_key($keys, '0', 'exit', '0', getTranslation('abort')); - - // Get the inline key array. - $keys[] = $nav_keys; - } - - return $keys; + // Get gyms from database + $rs = my_query(' + SELECT id, gym_name + FROM gyms + WHERE gym_name LIKE \'' . $searchterm . '%\' + AND show_gym LIKE 1 + OR gym_name LIKE \'% ' .$searchterm . '%\' + AND show_gym LIKE 1 + ORDER BY + CASE + WHEN gym_name LIKE \'' . $searchterm . '%\' THEN 1 + WHEN gym_name LIKE \'%' . $searchterm . '%\' THEN 2 + ELSE 3 + END + LIMIT 15 + ' + ); + // Init empty keys array. + $keys = []; + + while ($gym = $rs->fetch()) { + $first = strtoupper(substr($gym['gym_name'], 0, 1)); + $keys[] = array( + 'text' => $gym['gym_name'], + 'callback_data' => $first . ':edit_raidlevel:' . $gym['id'] + ); + } + + // Add abort key. + if($keys) { + // Get the inline key array. + $keys = inline_key_array($keys, 1); + } + + return $keys; } - - -?> diff --git a/logic/raid_list.php b/logic/raid_list.php index 904f6546..bd2727fe 100644 --- a/logic/raid_list.php +++ b/logic/raid_list.php @@ -1,66 +1,57 @@ UTC_TIMESTAMP() - ORDER BY id DESC LIMIT 2 - " - ); - while ($answer_raids = $request->fetch()) { - $rows[] = get_raid($answer_raids['id']); - } + // Init raid id. + $iqq = 0; + + // Botname:raid_id received? + if (substr_count($update['inline_query']['query'], ':') == 1) { + // Botname: received, is there a raid_id after : or not? + if(strlen(explode(':', $update['inline_query']['query'])[1]) != 0) { + // Raid ID. + $iqq = intval(explode(':', $update['inline_query']['query'])[1]); } - - - // Init array. - $contents = array(); - - // For each rows. - foreach ($rows as $key => $row) { - // Get raid poll. - $contents[$key]['text'] = show_raid_poll($row, true)['full']; - - // Set the title. - $contents[$key]['title'] = get_local_pokemon_name($row['pokemon'],$row['pokemon_form'], true) . ' ' . getPublicTranslation('from') . ' ' . dt2time($row['start_time']) . ' ' . getPublicTranslation('to') . ' ' . dt2time($row['end_time']); - - // Get inline keyboard. - $contents[$key]['keyboard'] = keys_vote($row); - - // Set the description. - $contents[$key]['desc'] = strval($row['gym_name']); - } - - debug_log($contents); - answerInlineQuery($update['inline_query']['id'], $contents); + } + + // Inline list polls. + $ids = [['id' => $iqq]]; + if ($iqq == 0) { + // If no id was given, search for two raids saved by the user + $request = my_query(' + SELECT id + FROM raids + WHERE user_id = ? + AND end_time>UTC_TIMESTAMP() + ORDER BY id DESC LIMIT 2 + ', [$update['inline_query']['from']['id']] + ); + $ids = $request->fetchAll(); + } + + $contents = []; + $i = 0; + foreach ($ids as $raid) { + $row = get_raid($raid['id']); + // Get raid poll. + $contents[$i]['text'] = show_raid_poll($row, true)['full']; + + // Set the title. + $contents[$i]['title'] = get_local_pokemon_name($row['pokemon'],$row['pokemon_form'], true) . ' ' . getPublicTranslation('from') . ' ' . dt2time($row['start_time']) . ' ' . getPublicTranslation('to') . ' ' . dt2time($row['end_time']); + + // Get inline keyboard. + $contents[$i]['keyboard'] = keys_vote($row); + + // Set the description. + $contents[$i]['desc'] = strval($row['gym_name']); + $i++; + } + + debug_log($contents); + answerInlineQuery($update['inline_query']['id'], $contents); } - -?> diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 38616e00..01418be6 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -1,5 +1,6 @@ $raid['id'], - ':gym_id' => $raid['gym_id'], - ':pokedex_id' => $raid['pokemon'], - ':pokemon_form' => $raid['pokemon_form'], - ':standalone' => $standalone_photo, - ':ended' => $raid['raid_ended'], - ]; - $query_cache = my_query(" - SELECT id, unique_id - FROM photo_cache - WHERE raid_id = :raid_id - AND gym_id = :gym_id - AND pokedex_id = :pokedex_id - AND form_id = :pokemon_form - AND ended = :ended - AND standalone = :standalone - LIMIT 1", $binds - ); - - if($query_cache->rowCount() > 0) { - $result = $query_cache->fetch(); - return [false, $result['id'], $result['unique_id']]; - } - return [true, create_raid_picture($raid, $standalone_photo)]; + $binds = [ + ':raid_id' => $raid['id'], + ':gym_id' => $raid['gym_id'], + ':pokedex_id' => $raid['pokemon'], + ':pokemon_form' => $raid['pokemon_form'], + ':standalone' => $standalone_photo, + ':ended' => $raid['raid_ended'], + ]; + $query_cache = my_query(' + SELECT id, unique_id + FROM photo_cache + WHERE raid_id = :raid_id + AND gym_id = :gym_id + AND pokedex_id = :pokedex_id + AND form_id = :pokemon_form + AND ended = :ended + AND standalone = :standalone + LIMIT 1', $binds + ); + + if($query_cache->rowCount() > 0) { + $result = $query_cache->fetch(); + return [false, $result['id'], $result['unique_id']]; + } + return [true, create_raid_picture($raid, $standalone_photo)]; } /** @@ -49,17 +50,22 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { } // Query missing raid info - $q_pokemon_info = my_query(" - SELECT - pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, asset_suffix, type, type2, - (SELECT img_url FROM gyms WHERE id='".$raid['gym_id']."' LIMIT 1) as img_url - FROM pokemon - WHERE pokedex_id = '".$raid['pokemon']."' - AND pokemon_form_id = '".$raid['pokemon_form']."' LIMIT 1"); + $q_pokemon_info = my_query(' + SELECT + pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, asset_suffix, type, type2, + (SELECT img_url FROM gyms WHERE id=:gymId LIMIT 1) as img_url + FROM pokemon + WHERE pokedex_id = :pokemonId + AND pokemon_form_id = :pokemonForm LIMIT 1 + ',[ + 'gymId' => $raid['gym_id'], + 'pokemonId' => $raid['pokemon'], + 'pokemonForm' => $raid['pokemon_form'], + ]); if($q_pokemon_info->rowCount() == 0) { - info_log("Something wrong with the raid data provided!"); - info_log(print_r($raid,true)); - exit(); + info_log("Something wrong with the raid data provided!"); + info_log(print_r($raid,true)); + exit(); } $raid = array_merge($raid, $q_pokemon_info->fetch()); @@ -81,7 +87,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $bg_rgb = [255,255,255]; $config_bg_color = explode(',',$config->RAID_PICTURE_BG_COLOR); if(count($config_bg_color) == 3) { - $bg_rgb = $config_bg_color; + $bg_rgb = $config_bg_color; } else { info_log($config->RAID_PICTURE_BG_COLOR, 'Invalid value RAID_PICTURE_BG_COLOR:'); } @@ -93,7 +99,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $font_rgb = [0,0,0]; $config_font_color = explode(',',$config->RAID_PICTURE_TEXT_COLOR); if(count($config_font_color) == 3) { - $font_rgb = $config_font_color; + $font_rgb = $config_font_color; } else { info_log($config->RAID_PICTURE_TEXT_COLOR, 'Invalid value RAID_PICTURE_TEXT_COLOR:'); } @@ -107,38 +113,38 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $gym_url = $raid['img_url']; $gym_image_path = ''; if($config->RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY && !empty($gym_url)) { - if(substr($gym_url, 0, 7) == 'file://') { + if(substr($gym_url, 0, 7) == 'file://') { + $gym_image_path = $gym_url; + debug_log($gym_image_path, 'Found an image imported via a portal bot: '); + }else { + $file_name = explode('/', $gym_url)[3]; + $gym_image_path = PORTAL_IMAGES_PATH .'/'. $file_name.'.png'; + debug_log($gym_image_path, 'Attempting to use locally stored gym image'); + if(!file_exists($gym_image_path)) { + debug_log($gym_url, 'Gym image not found, attempting to downloading it from: '); + if(is_writable(PORTAL_IMAGES_PATH)) { + download_Portal_Image($gym_url, PORTAL_IMAGES_PATH, $file_name . '.png'); + }else { $gym_image_path = $gym_url; - debug_log($gym_image_path, 'Found an image imported via a portal bot: '); - }else { - $file_name = explode('/', $gym_url)[3]; - $gym_image_path = PORTAL_IMAGES_PATH .'/'. $file_name.'.png'; - debug_log($gym_image_path, 'Attempting to use locally stored gym image'); - if(!file_exists($gym_image_path)) { - debug_log($gym_url, 'Gym image not found, attempting to downloading it from: '); - if(is_writable(PORTAL_IMAGES_PATH)) { - download_Portal_Image($gym_url, PORTAL_IMAGES_PATH, $file_name . '.png'); - }else { - $gym_image_path = $gym_url; - info_log(PORTAL_IMAGES_PATH, 'Failed to write new gym image, incorrect permissions in directory '); - } - } + info_log(PORTAL_IMAGES_PATH, 'Failed to write new gym image, incorrect permissions in directory '); + } } + } }else { - $img_gym = false; - if (!empty($gym_url)) { - $gym_image_path = $gym_url; - } + $img_gym = false; + if (!empty($gym_url)) { + $gym_image_path = $gym_url; + } } $img_gym = $gym_image_path != '' ? grab_img($gym_image_path) : false; if($img_gym == false) { - info_log($gym_image_path, 'Loading the gym image failed, using default gym image'); - if(is_file($config->RAID_DEFAULT_PICTURE)) { - $img_gym = grab_img($config->RAID_DEFAULT_PICTURE); - } else { - info_log($config->RAID_DEFAULT_PICTURE, 'Cannot read default gym image:'); - $img_gym = grab_img(IMAGES_PATH . "/gym_default.png"); - } + info_log($gym_image_path, 'Loading the gym image failed, using default gym image'); + if(is_file($config->RAID_DEFAULT_PICTURE)) { + $img_gym = grab_img($config->RAID_DEFAULT_PICTURE); + } else { + info_log($config->RAID_DEFAULT_PICTURE, 'Cannot read default gym image:'); + $img_gym = grab_img(IMAGES_PATH . "/gym_default.png"); + } } // Get the width and height of the gym picture @@ -147,13 +153,13 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Crop gym image if($gym_w > $gym_h) { - $size = $gym_h; - $crop_x = floor((($gym_w/2)-($gym_h/2))); - $crop_y = 0; + $size = $gym_h; + $crop_x = floor((($gym_w/2)-($gym_h/2))); + $crop_y = 0; } else { - $size = $gym_w; - $crop_x = 0; - $crop_y = floor((($gym_h/2)-($gym_w/2))); + $size = $gym_w; + $crop_x = 0; + $crop_y = floor((($gym_h/2)-($gym_w/2))); } // Create mask @@ -187,175 +193,174 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Is ex gym? if($raid['ex_gym'] == 1) { - $ex_text_size = 20; - $ex_text_angle = 0; - $corner = 16; // Roundness of the corners - $extra = $ex_text_size/5+1; // Some extra height - - $ex_mark_bg_color = [94,169,190]; - $ex_mark_text_color = [255,255,255]; - - // Get the text with local translation for EX Raid gym - $ex_raid_gym_text = strtoupper(getPublicTranslation('ex_gym')); - // Finding out the size of text - $ex_text_box = imagettfbbox($ex_text_size,$ex_text_angle,$font_ex_gym,$ex_raid_gym_text); - - $ex_logo_width = $ex_text_box[2]+($corner); - $ex_logo_height = $ex_text_size+$extra; - - - // Create the canvas for EX RAID indicator - $ex_logo = imagecreatetruecolor($ex_logo_width,$ex_logo_height); - // Defining the transparent color - $ex_transparent = imagecolorallocate($ex_logo,$transparent_rgb[0],$transparent_rgb[1],$transparent_rgb[2]); - imagecolortransparent($ex_logo,$ex_transparent); - // Defining background color - $ex_logo_bg = imagecolorallocate($mask,$ex_mark_bg_color[0],$ex_mark_bg_color[1], $ex_mark_bg_color[2]); - $ex_text_color = imagecolorallocate($ex_logo,$ex_mark_text_color[0],$ex_mark_text_color[1],$ex_mark_text_color[2]); - - //Filling the canvas with transparent color - imagefill($ex_logo,0,0,$ex_transparent); - - // Creating 4 balls, one in each corner - imagefilledellipse($ex_logo,$corner/2,$corner/2,$corner,$corner,$ex_logo_bg); - imagefilledellipse($ex_logo,$corner/2,$ex_logo_height-$corner/2,$corner,$corner,$ex_logo_bg); - imagefilledellipse($ex_logo,$ex_logo_width-$corner/2,$corner/2,$corner,$corner,$ex_logo_bg); - imagefilledellipse($ex_logo,$ex_logo_width-$corner/2,$ex_logo_height-$corner/2,$corner,$corner,$ex_logo_bg); - // And two rectangles to fill the rest - imagefilledrectangle($ex_logo,$corner/2,0,$ex_logo_width-($corner/2),$ex_logo_height,$ex_logo_bg); - imagefilledrectangle($ex_logo,0,$corner/2,$ex_logo_width,$ex_logo_height-($corner/2),$ex_logo_bg); - - // Draw the text - imagettftext($ex_logo,$ex_text_size,$ex_text_angle,$corner/2,$ex_text_size+1,$ex_text_color,$font_ex_gym,$ex_raid_gym_text); - - // Copy icon into canvas - imagecopy($canvas,$ex_logo,20,20,0,0,$ex_logo_width,$ex_logo_height); + $ex_text_size = 20; + $ex_text_angle = 0; + $corner = 16; // Roundness of the corners + $extra = $ex_text_size/5+1; // Some extra height + + $ex_mark_bg_color = [94,169,190]; + $ex_mark_text_color = [255,255,255]; + + // Get the text with local translation for EX Raid gym + $ex_raid_gym_text = strtoupper(getPublicTranslation('ex_gym')); + // Finding out the size of text + $ex_text_box = imagettfbbox($ex_text_size,$ex_text_angle,$font_ex_gym,$ex_raid_gym_text); + + $ex_logo_width = $ex_text_box[2]+($corner); + $ex_logo_height = $ex_text_size+$extra; + + // Create the canvas for EX RAID indicator + $ex_logo = imagecreatetruecolor($ex_logo_width,$ex_logo_height); + // Defining the transparent color + $ex_transparent = imagecolorallocate($ex_logo,$transparent_rgb[0],$transparent_rgb[1],$transparent_rgb[2]); + imagecolortransparent($ex_logo,$ex_transparent); + // Defining background color + $ex_logo_bg = imagecolorallocate($mask,$ex_mark_bg_color[0],$ex_mark_bg_color[1], $ex_mark_bg_color[2]); + $ex_text_color = imagecolorallocate($ex_logo,$ex_mark_text_color[0],$ex_mark_text_color[1],$ex_mark_text_color[2]); + + //Filling the canvas with transparent color + imagefill($ex_logo,0,0,$ex_transparent); + + // Creating 4 balls, one in each corner + imagefilledellipse($ex_logo,$corner/2,$corner/2,$corner,$corner,$ex_logo_bg); + imagefilledellipse($ex_logo,$corner/2,$ex_logo_height-$corner/2,$corner,$corner,$ex_logo_bg); + imagefilledellipse($ex_logo,$ex_logo_width-$corner/2,$corner/2,$corner,$corner,$ex_logo_bg); + imagefilledellipse($ex_logo,$ex_logo_width-$corner/2,$ex_logo_height-$corner/2,$corner,$corner,$ex_logo_bg); + // And two rectangles to fill the rest + imagefilledrectangle($ex_logo,$corner/2,0,$ex_logo_width-($corner/2),$ex_logo_height,$ex_logo_bg); + imagefilledrectangle($ex_logo,0,$corner/2,$ex_logo_width,$ex_logo_height-($corner/2),$ex_logo_bg); + + // Draw the text + imagettftext($ex_logo,$ex_text_size,$ex_text_angle,$corner/2,$ex_text_size+1,$ex_text_color,$font_ex_gym,$ex_raid_gym_text); + + // Copy icon into canvas + imagecopy($canvas,$ex_logo,20,20,0,0,$ex_logo_width,$ex_logo_height); } $show_boss_pokemon_types = false; // Raid running if(!$raid['raid_ended']) { - if(strlen($raid['asset_suffix']) > 2) { - $icon_suffix = $raid['asset_suffix']; - }else { - $pad_zeroes = ''; - for ($o=3-strlen($raid['pokemon']);$o>0;$o--) { - $pad_zeroes .= 0; - } - $icon_suffix = $pad_zeroes.$raid['pokemon'] . "_" . $raid['asset_suffix']; + if(strlen($raid['asset_suffix']) > 2) { + $icon_suffix = $raid['asset_suffix']; + }else { + $pad_zeroes = ''; + for ($o=3-strlen($raid['pokemon']);$o>0;$o--) { + $pad_zeroes .= 0; } + $icon_suffix = $pad_zeroes.$raid['pokemon'] . "_" . $raid['asset_suffix']; + } + + // Raid Egg + if($raid['pokemon'] > 9990) { + // Getting the actual icon + $img_pokemon = grab_img(IMAGES_PATH . "/raid_eggs/pokemon_icon_" . $raid['pokemon'] . "_00.png"); - // Raid Egg - if($raid['pokemon'] > 9990) { - // Getting the actual icon - $img_pokemon = grab_img(IMAGES_PATH . "/raid_eggs/pokemon_icon_" . $raid['pokemon'] . "_00.png"); - - // Position and size of the picture - $dst_x = $dst_y = 150; - $dst_w = $dst_h = 200; - $src_w = $src_h = 128; - - //Pokemon - } else { - // Check pokemon icon source and create image - $img_file = null; - $uicons = false; - $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); - - $addressable_icon = 'pm'.$raid['pokemon']; - $uicons_icon = $raid['pokemon']; - - if($raid['pokemon_form_name'] != 'normal') { - $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); - $uicons_icon .= '_f'.$raid['pokemon_form']; - } - - // Getting the actual icon filename - $p_icon = "pokemon_icon_" . $icon_suffix; - - // Add costume info for every mon except megas - if($raid['costume'] != 0 && $raid['pokemon_form'] >= 0) { - $p_icon .= '_' . str_pad($raid['costume'], 2, '0', STR_PAD_LEFT); - - $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); - $addressable_icon .= '.c' . array_search($raid['costume'],$costume); - - $uicons_icon .= '_c'.$raid['costume']; - } - if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { - $p_icon = $p_icon . "_shiny"; - $addressable_icon .= '.s'; - $uicons_icon .= '_s'; - $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); - } - $addressable_icon .= '.icon.png'; - $p_icon = $p_icon . ".png"; - $uicons_icon .= '.png'; - - foreach($p_sources as $p_dir) { - // Icon dir named 'pokemon'? Then change path to not add '_repo-owner' to icon folder name - if($p_dir == 'pokemon') $asset_dir = 'pokemon'; else $asset_dir = 'pokemon_' . $p_dir; - // Set pokemon icon dir - $p_img_base_path = IMAGES_PATH . "/" . $asset_dir; - - // Check if file exists in this collection - // Prioritize addressable asset file - if(file_exists($p_img_base_path . "/" . $addressable_icon) && filesize($p_img_base_path . "/" . $addressable_icon) > 0) { - $img_file = $p_img_base_path . "/" . $addressable_icon; - break; - // These elseifs become redundant after PokeMiners move the files from Addressable Assets folder to the parent directory on 1.6.2022 - }else if(file_exists($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) && filesize($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) > 0) { - $img_file = $p_img_base_path . "/Addressable_Assets/" . $addressable_icon; - break; - }else if(file_exists($p_img_base_path . "/" . $p_icon) && filesize($p_img_base_path . "/" . $p_icon) > 0) { - $img_file = $p_img_base_path . "/" . $p_icon; - break; - }else if(file_exists($p_img_base_path . "/" . $uicons_icon) && filesize($p_img_base_path . "/" . $uicons_icon) > 0) { - $img_file = $p_img_base_path . "/" . $uicons_icon; - $uicons = true; - break; - } - } - - // If no image was found, substitute with a fallback - if($img_file === null) { - info_log($p_icon . ' ' . $addressable_icon, 'Failed to find an image in any pokemon image collection for:'); - $img_fallback_file = null; - // If we know the raid level, fallback to egg image - if(array_key_exists('level', $raid) && $raid['level'] !== null && $raid['level'] != 0) { - $img_fallback_file = IMAGES_PATH . "/raid_eggs/pokemon_icon_999" . $raid['level'] . "_00.png"; - } else { - info_log('Unknown raid level, using fallback icon.'); - $img_fallback_file = $config->RAID_PICTURE_POKEMON_FALLBACK; - } - $img_file = $img_fallback_file; - } - - $img_pokemon = grab_img($img_file); - - // Position and size of the picture - $dst_x = $dst_y = 100; - $dst_w = $dst_h = 256; - $src_w = $src_h = $dst_w; - if($uicons === true) { - [$src_w, $src_h] = getimagesize($img_file); - } - - if($raid['type'] != '') $show_boss_pokemon_types = true; + // Position and size of the picture + $dst_x = $dst_y = 150; + $dst_w = $dst_h = 200; + $src_w = $src_h = 128; + + //Pokemon + } else { + // Check pokemon icon source and create image + $img_file = null; + $uicons = false; + $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); + + $addressable_icon = 'pm'.$raid['pokemon']; + $uicons_icon = $raid['pokemon']; + + if($raid['pokemon_form_name'] != 'normal') { + $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); + $uicons_icon .= '_f'.$raid['pokemon_form']; } - // Raid ended - } else { - // Raid won image - $img_pokemon = grab_img(IMAGES_PATH . "/raidwon.png"); + // Getting the actual icon filename + $p_icon = "pokemon_icon_" . $icon_suffix; + + // Add costume info for every mon except megas + if($raid['costume'] != 0 && $raid['pokemon_form'] >= 0) { + $p_icon .= '_' . str_pad($raid['costume'], 2, '0', STR_PAD_LEFT); + + $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); + $addressable_icon .= '.c' . array_search($raid['costume'],$costume); + + $uicons_icon .= '_c'.$raid['costume']; + } + if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { + $p_icon = $p_icon . "_shiny"; + $addressable_icon .= '.s'; + $uicons_icon .= '_s'; + $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); + } + $addressable_icon .= '.icon.png'; + $p_icon = $p_icon . ".png"; + $uicons_icon .= '.png'; + + foreach($p_sources as $p_dir) { + // Icon dir named 'pokemon'? Then change path to not add '_repo-owner' to icon folder name + if($p_dir == 'pokemon') $asset_dir = 'pokemon'; else $asset_dir = 'pokemon_' . $p_dir; + // Set pokemon icon dir + $p_img_base_path = IMAGES_PATH . "/" . $asset_dir; + + // Check if file exists in this collection + // Prioritize addressable asset file + if(file_exists($p_img_base_path . "/" . $addressable_icon) && filesize($p_img_base_path . "/" . $addressable_icon) > 0) { + $img_file = $p_img_base_path . "/" . $addressable_icon; + break; + // These elseifs become redundant after PokeMiners move the files from Addressable Assets folder to the parent directory on 1.6.2022 + }else if(file_exists($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) && filesize($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) > 0) { + $img_file = $p_img_base_path . "/Addressable_Assets/" . $addressable_icon; + break; + }else if(file_exists($p_img_base_path . "/" . $p_icon) && filesize($p_img_base_path . "/" . $p_icon) > 0) { + $img_file = $p_img_base_path . "/" . $p_icon; + break; + }else if(file_exists($p_img_base_path . "/" . $uicons_icon) && filesize($p_img_base_path . "/" . $uicons_icon) > 0) { + $img_file = $p_img_base_path . "/" . $uicons_icon; + $uicons = true; + break; + } + } + + // If no image was found, substitute with a fallback + if($img_file === null) { + info_log($p_icon . ' ' . $addressable_icon, 'Failed to find an image in any pokemon image collection for:'); + $img_fallback_file = null; + // If we know the raid level, fallback to egg image + if(array_key_exists('level', $raid) && $raid['level'] !== null && $raid['level'] != 0) { + $img_fallback_file = IMAGES_PATH . "/raid_eggs/pokemon_icon_999" . $raid['level'] . "_00.png"; + } else { + info_log('Unknown raid level, using fallback icon.'); + $img_fallback_file = $config->RAID_PICTURE_POKEMON_FALLBACK; + } + $img_file = $img_fallback_file; + } + + $img_pokemon = grab_img($img_file); // Position and size of the picture - $dst_x = $dst_y = 172; - $src_w = 444; - $src_h = 512; - $dst_w = 160; - $dst_h = floor($dst_w/$src_w*$src_h); + $dst_x = $dst_y = 100; + $dst_w = $dst_h = 256; + $src_w = $src_h = $dst_w; + if($uicons === true) { + [$src_w, $src_h] = getimagesize($img_file); + } + + if($raid['type'] != '') $show_boss_pokemon_types = true; + } + + // Raid ended + } else { + // Raid won image + $img_pokemon = grab_img(IMAGES_PATH . "/raidwon.png"); + + // Position and size of the picture + $dst_x = $dst_y = 172; + $src_w = 444; + $src_h = 512; + $dst_w = 160; + $dst_h = floor($dst_w/$src_w*$src_h); } // Create pokemon image. @@ -363,9 +368,9 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Debug - Add border around pokemon image if($debug) { - $im = imagecreate($src_w,$src_h); - $black = imagecolorallocate($im,0,0,0); - imagerectangle($img_pokemon,0,0,$src_w-1,$src_h-1,$black); + $im = imagecreate($src_w,$src_h); + $black = imagecolorallocate($im,0,0,0); + imagerectangle($img_pokemon,0,0,$src_w-1,$src_h-1,$black); } // Add pokemon to image @@ -373,36 +378,36 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Add pokemon types if($config->RAID_PICTURE_POKEMON_TYPES && $show_boss_pokemon_types) { - $img_type = grab_img(IMAGES_PATH . "/types/".$raid['type'].".png"); - $type1_x = 300; - imagesavealpha($img_type, true); - if($raid['type2'] != '') { - $img_type2 = grab_img(IMAGES_PATH . "/types/".$raid['type2'].".png"); - imagesavealpha($img_type2, true); - imagecopyresampled($canvas,$img_type2,300,300,0,0,40,40,64,64); - $type1_x -= 50; - } - imagecopyresampled($canvas,$img_type,$type1_x,300,0,0,40,40,64,64); + $img_type = grab_img(IMAGES_PATH . "/types/".$raid['type'].".png"); + $type1_x = 300; + imagesavealpha($img_type, true); + if($raid['type2'] != '') { + $img_type2 = grab_img(IMAGES_PATH . "/types/".$raid['type2'].".png"); + imagesavealpha($img_type2, true); + imagecopyresampled($canvas,$img_type2,300,300,0,0,40,40,64,64); + $type1_x -= 50; + } + imagecopyresampled($canvas,$img_type,$type1_x,300,0,0,40,40,64,64); } if(isset($shiny_icon)) { - imagesavealpha($shiny_icon,true); - $light_white = imagecolorallocatealpha($canvas, 255,255,255,50); - imagefilledellipse($canvas, $type1_x-35 ,320,40,40,$light_white); - imagecopyresampled($canvas,$shiny_icon,$type1_x-52,301,0,0,35,35,100,100); + imagesavealpha($shiny_icon,true); + $light_white = imagecolorallocatealpha($canvas, 255,255,255,50); + imagefilledellipse($canvas, $type1_x-35 ,320,40,40,$light_white); + imagecopyresampled($canvas,$shiny_icon,$type1_x-52,301,0,0,35,35,100,100); } // Ex-Raid? if($raid['event'] == EVENT_ID_EX) { - $img_expass = grab_img(IMAGES_PATH . "/expass.png"); - imagesavealpha($img_expass,true); - - // Debug - Add border around expass image - if($debug) { - $im = imagecreate(256,256); - $black = imagecolorallocate($im,0,0,0); - imagerectangle($img_expass,0,0,255,255,$black); - } - imagecopyresampled($canvas,$img_expass,0,225,0,0,100,100,256,256); + $img_expass = grab_img(IMAGES_PATH . "/expass.png"); + imagesavealpha($img_expass,true); + + // Debug - Add border around expass image + if($debug) { + $im = imagecreate(256,256); + $black = imagecolorallocate($im,0,0,0); + imagerectangle($img_expass,0,0,255,255,$black); + } + imagecopyresampled($canvas,$img_expass,0,225,0,0,100,100,256,256); } @@ -431,9 +436,9 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Number of rows based on number of words or total chars $gym_name_rows = 1; if(count($gym_name_words) > 1 && $gym_name_total_chars >= 18 && $gym_name_total_chars <= 50) { - $gym_name_rows = 2; + $gym_name_rows = 2; } else if($gym_name_total_chars > 50) { - $gym_name_rows = 3; + $gym_name_rows = 3; } // Wrap gym name to multiple lines if too long @@ -450,79 +455,79 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Get largest possible fontsize for each gym name line $fontsize_gym = 0; for($l=0; $l= $targetWidth || $height >= $rowHeight){ - break; - } + for($s=1; $s<70/count($gym_name_lines); $s=$s+0.5){ + $box = imagettfbbox($s, 0, $font_gym, $gym_name_lines[$l]); + $min_x = min(array($box[0], $box[2], $box[4], $box[6])); + $max_x = max(array($box[0], $box[2], $box[4], $box[6])); + $min_y = min(array($box[1], $box[3], $box[5], $box[7])); + $max_y = max(array($box[1], $box[3], $box[5], $box[7])); + $width = ($max_x - $min_x); + $height = ($max_y - $min_y); + $targetsize = $s; + // Exit once we exceed width or height + if($width >= $targetWidth || $height >= $rowHeight){ + break; } + } - // Gym name font size and spacing - if($l == 0 || $targetsize < $fontsize_gym) { - $fontsize_gym = $targetsize; - $spacing_gym = $height * 0.30; - } + // Gym name font size and spacing + if($l == 0 || $targetsize < $fontsize_gym) { + $fontsize_gym = $targetsize; + $spacing_gym = $height * 0.30; + } } // Add gym name to image for($y=0;$y 20) { - $pokemon_text_lines = explode(SP,$pokemon_name); - if(count($pokemon_text_lines) == 1) { - // Wrapping the time text if too long (to 20 letters) - $pokemon_text_lines = explode(PHP_EOL,wordwrap(trim($pokemon_name),20,PHP_EOL)); - } + $pokemon_text_lines = explode(SP,$pokemon_name); + if(count($pokemon_text_lines) == 1) { + // Wrapping the time text if too long (to 20 letters) + $pokemon_text_lines = explode(PHP_EOL,wordwrap(trim($pokemon_name),20,PHP_EOL)); + } } $num_pokemon_lines = count($pokemon_text_lines); @@ -565,25 +570,25 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Get largest possible fontsize for each pokemon name and form line $fontsize_poke = 0; for($p=0; $p<($num_pokemon_lines); $p++) { - for($s=1; $s<40; $s=$s+0.5){ - $box = imagettfbbox($s, 0, $font_text, $pokemon_text_lines[$p]); - $min_x = min(array($box[0], $box[2], $box[4], $box[6])); - $max_x = max(array($box[0], $box[2], $box[4], $box[6])); - $min_y = min(array($box[1], $box[3], $box[5], $box[7])); - $max_y = max(array($box[1], $box[3], $box[5], $box[7])); - $width = ($max_x - $min_x); - $height = ($max_y - $min_y); - $targetsize = $s; - // Exit once we exceed width or height - if($width >= $targetWidth || $height >= $targetHeight){ - break; - } + for($s=1; $s<40; $s=$s+0.5){ + $box = imagettfbbox($s, 0, $font_text, $pokemon_text_lines[$p]); + $min_x = min(array($box[0], $box[2], $box[4], $box[6])); + $max_x = max(array($box[0], $box[2], $box[4], $box[6])); + $min_y = min(array($box[1], $box[3], $box[5], $box[7])); + $max_y = max(array($box[1], $box[3], $box[5], $box[7])); + $width = ($max_x - $min_x); + $height = ($max_y - $min_y); + $targetsize = $s; + // Exit once we exceed width or height + if($width >= $targetWidth || $height >= $targetHeight){ + break; } + } - // Gym name font size and spacing - if($p == 0 || $targetsize < $fontsize_poke) { - $fontsize_poke = $targetsize; - } + // Gym name font size and spacing + if($p == 0 || $targetsize < $fontsize_poke) { + $fontsize_poke = $targetsize; + } } // Pokemon name (and form) in 1 row @@ -591,7 +596,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Pokemon name and form in one or two lines? if($num_pokemon_lines > 1) { - $poke_text_top = 272; + $poke_text_top = 272; } // If the photo is sent without caption, we want to keep the bottom right corcer clear of text because Telegram covers it with a timestamp @@ -599,35 +604,35 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Add pokemon name to image for($pa=0;$pa<$num_pokemon_lines;$pa++){ - // Get text width and height - $textwidth = ($max_x - $min_x); - $textheight = ($max_y - $min_y); - // Position from top - $poke_text_top = floor($poke_text_top+($pa*($fontsize_poke+$spacing))); - imagettftext($canvas,$fontsize_poke,$angle,$left_after_poke,$poke_text_top,$font_color,$font_text,$pokemon_text_lines[$pa]); + // Get text width and height + $textwidth = ($max_x - $min_x); + $textheight = ($max_y - $min_y); + // Position from top + $poke_text_top = floor($poke_text_top+($pa*($fontsize_poke+$spacing))); + imagettftext($canvas,$fontsize_poke,$angle,$left_after_poke,$poke_text_top,$font_color,$font_text,$pokemon_text_lines[$pa]); } // Pokemon CP if($raid['pokemon'] < 9990) { - $cp_text_top = $poke_text_top+$text_size+$spacing; - $cp_text = $raid['min_cp']." - ".$raid['max_cp']; - $cp_text2 = "(".$raid['min_weather_cp']."-".$raid['max_weather_cp'].")"; - - imagettftext($canvas,$text_size,$angle,$left_after_poke,$cp_text_top,$font_color,$font_text,$cp_text); - $cp_weather_text_box = imagettfbbox($text_size_cp_weather,$angle,$font_text,$cp_text2); - imagettftext($canvas,$text_size_cp_weather,$angle,($canvas_width-$cp_weather_text_box[2]-$spacing_right),$cp_text_top,$font_color,$font_text,$cp_text2); - - $count_weather = strlen($raid['weather']); - for($i=0;$i<$count_weather;$i++) { - $we = substr($raid['weather'],$i,1); - $weather_icon_path = IMAGES_PATH . "/weather/"; - // Use white icons? - if($config->RAID_PICTURE_ICONS_WHITE) { - $weather_icon_path = IMAGES_PATH . "/weather_white/"; - } - $weather_icon = grab_img($weather_icon_path . $we . ".png"); // 64x64 - imagecopyresampled($canvas,$weather_icon,$canvas_width-$spacing_right-($count_weather-$i)*40,$poke_text_top-30,0,0,38,38,64,64); + $cp_text_top = $poke_text_top+$text_size+$spacing; + $cp_text = $raid['min_cp']." - ".$raid['max_cp']; + $cp_text2 = "(".$raid['min_weather_cp']."-".$raid['max_weather_cp'].")"; + + imagettftext($canvas,$text_size,$angle,$left_after_poke,$cp_text_top,$font_color,$font_text,$cp_text); + $cp_weather_text_box = imagettfbbox($text_size_cp_weather,$angle,$font_text,$cp_text2); + imagettftext($canvas,$text_size_cp_weather,$angle,($canvas_width-$cp_weather_text_box[2]-$spacing_right),$cp_text_top,$font_color,$font_text,$cp_text2); + + $count_weather = strlen($raid['weather']); + for($i=0;$i<$count_weather;$i++) { + $we = substr($raid['weather'],$i,1); + $weather_icon_path = IMAGES_PATH . "/weather/"; + // Use white icons? + if($config->RAID_PICTURE_ICONS_WHITE) { + $weather_icon_path = IMAGES_PATH . "/weather_white/"; } + $weather_icon = grab_img($weather_icon_path . $we . ".png"); // 64x64 + imagecopyresampled($canvas,$weather_icon,$canvas_width-$spacing_right-($count_weather-$i)*40,$poke_text_top-30,0,0,38,38,64,64); + } } ob_start(); @@ -651,16 +656,14 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { /** * Create GD image object from given URI regardless of file type * @param string $uri Image uri - * @return object + * @return bool|object */ function grab_img($uri) { - try { - $img = imagecreatefromstring(file_get_contents($uri)); - }catch(Exception $e) { - info_log($uri, 'Failed to get image:'); - return false; - } - return $img; + try { + $img = imagecreatefromstring(file_get_contents($uri)); + }catch(Exception $e) { + info_log($uri, 'Failed to get image:'); + return false; + } + return $img; } - -?> diff --git a/logic/raid_poll_message.php b/logic/raid_poll_message.php index 26156c00..6621cece 100644 --- a/logic/raid_poll_message.php +++ b/logic/raid_poll_message.php @@ -8,24 +8,22 @@ */ function raid_poll_message($msg_array, $append, $skip = false) { - global $config; - // Array key full already created? - if(!(array_key_exists('full', $msg_array))) { - $msg_array['full'] = ''; - } - - //Raid picture? - $msg_array['full'] .= $append; - if($config->RAID_PICTURE && $skip == false) { - // Array key short already created? - if(!(array_key_exists('short', $msg_array))) { - $msg_array['short'] = ''; - } + global $config; + // Array key full already created? + if(!(array_key_exists('full', $msg_array))) { + $msg_array['full'] = ''; + } - $msg_array['short'] .= $append; + //Raid picture? + $msg_array['full'] .= $append; + if($config->RAID_PICTURE && $skip == false) { + // Array key short already created? + if(!(array_key_exists('short', $msg_array))) { + $msg_array['short'] = ''; } - return $msg_array; -} + $msg_array['short'] .= $append; + } -?> + return $msg_array; +} diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index 951e796e..60160867 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -1,5 +1,6 @@ ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; $prev_rl = ''; @@ -66,4 +67,3 @@ function read_upcoming_bosses($return_sql = false) { if($return_sql) return $sql; else return $list; } -?> \ No newline at end of file diff --git a/logic/resolve_boss_name_to_ids.php b/logic/resolve_boss_name_to_ids.php index e64f8ffe..bedb2c3f 100644 --- a/logic/resolve_boss_name_to_ids.php +++ b/logic/resolve_boss_name_to_ids.php @@ -1,70 +1,69 @@ = 1) { + $pokemon = str_replace('_', '-', $pokemon_name); } else { - // Fix pokemon like "HO_OH"... - if(substr_count($pokemon_name, '_') >= 1) { - $pokemon = str_replace('_', '-', $pokemon_name); - } else { - $pokemon = $pokemon_name; - } - // Name and form. - $name = $pokemon; - $form = 'normal'; + $pokemon = $pokemon_name; + } + // Name and form. + $name = $pokemon; + $form = 'normal'; - // Fix for GIRATINA as the actual GIRATINA_ALTERED_FORM is just GIRATINA - if($name == 'GIRATINA' && $form == 'normal') { - $form = 'ALTERED'; - } + // Fix for GIRATINA as the actual GIRATINA_ALTERED_FORM is just GIRATINA + if($name == 'GIRATINA' && $form == 'normal') { + $form = 'ALTERED'; } - // Get ID and form name used internally. - debug_log('Getting dex id and form for pokemon ' . $name . ' with form ' . $form); - return get_pokemon_id_by_name($name . ' ' . $form, true); + } + // Get ID and form name used internally. + debug_log('Getting dex id and form for pokemon ' . $name . ' with form ' . $form); + return get_pokemon_id_by_name($name . ' ' . $form, true); } - -?> \ No newline at end of file diff --git a/logic/resolve_raid_boss.php b/logic/resolve_raid_boss.php index 5e68b6d7..8d964fb5 100644 --- a/logic/resolve_raid_boss.php +++ b/logic/resolve_raid_boss.php @@ -8,37 +8,37 @@ * @return array */ function resolve_raid_boss($pokemon, $pokemon_form, $spawn, $raid_level) { - if($pokemon == 0) { - $tz_diff = tz_diff(); - $query = my_query(' SELECT DISTINCT pokedex_id, pokemon_form_id - FROM raid_bosses - WHERE raid_level = "' . $raid_level . '" - AND scheduled = 1 - AND convert_tz("' . $spawn . '","+00:00","'.$tz_diff.'") BETWEEN date_start AND date_end'); - if($query->rowCount() == 1) { - $row = $query->fetch(); - // Return active boss - $pokemon_id = $row['pokedex_id']; - $pokemon_form_id = $row['pokemon_form_id']; - }else { - // Return egg - $pokemon_id = '999'.$raid_level; - $pokemon_form_id = 0; - } - }else { - $pokemon_id = $pokemon; - if($pokemon_form == 0) { - // If pokemon_form is 0 (often received from webhook), resolve the form id of normal form from our database - $form_query = my_query(' SELECT pokemon_form_id - FROM pokemon - WHERE pokedex_id = "' . $pokemon . '" - AND pokemon_form_name = \'normal\' - LIMIT 1'); - $pokemon_form_id = $form_query->fetch()['pokemon_form_id']; - }else { - $pokemon_form_id = $pokemon_form; - } + if($pokemon == 0) { + $tz_diff = tz_diff(); + $query = my_query(' + SELECT DISTINCT pokedex_id, pokemon_form_id + FROM raid_bosses + WHERE raid_level = :raidLevel + AND scheduled = 1 + AND convert_tz(:spawn, "+00:00", :tzDiff) BETWEEN date_start AND date_end + ', ['raidLevel' => $raid_level, 'spawn' => $spawn, 'tzDiff' => $tz_diff]); + // Return egg + $pokemon_id = '999'.$raid_level; + $pokemon_form_id = 0; + if($query->rowCount() == 1) { + $row = $query->fetch(); + // Return active boss + $pokemon_id = $row['pokedex_id']; + $pokemon_form_id = $row['pokemon_form_id']; } return ['pokedex_id' => $pokemon_id, 'pokemon_form_id' => $pokemon_form_id]; + } + $pokemon_id = $pokemon; + $pokemon_form_id = $pokemon_form; + if($pokemon_form == 0) { + // If pokemon_form is 0 (often received from webhook), resolve the form id of normal form from our database + $form_query = my_query(' + SELECT pokemon_form_id + FROM pokemon + WHERE pokedex_id = ? + AND pokemon_form_name = \'normal\' + LIMIT 1', [$pokemon]); + $pokemon_form_id = $form_query->fetch()['pokemon_form_id']; + } + return ['pokedex_id' => $pokemon_id, 'pokemon_form_id' => $pokemon_form_id]; } -?> diff --git a/logic/send_raid_poll.php b/logic/send_raid_poll.php index 79989dc0..03ad1922 100644 --- a/logic/send_raid_poll.php +++ b/logic/send_raid_poll.php @@ -1,4 +1,7 @@ $raid_id, - ]); - $chatsAlreadySharedTo = $resultChats->fetchAll(PDO::FETCH_COLUMN, 0); - $chats = array_diff($shareChats, $chatsAlreadySharedTo); - if(count($chats) == 0) return $tg_json; + global $config; + // Telegram JSON array. + if($tg_json == false) $tg_json = []; + if(!is_array($shareChats)) $shareChats = [$shareChats]; + // Check if Raid has been posted to target chat + $resultChats = my_query(' + SELECT DISTINCT chat_id + FROM cleanup + WHERE raid_id = :raidId + AND chat_id IN ("' . implode('","',$shareChats) . '") + ', + [ + 'raidId' => $raid_id, + ]); + $chatsAlreadySharedTo = $resultChats->fetchAll(PDO::FETCH_COLUMN, 0); + $chats = array_diff($shareChats, $chatsAlreadySharedTo); + if(count($chats) == 0) return $tg_json; - // Get raid data. - if($raid == false) $raid = get_raid($raid_id); + // Get raid data. + if($raid == false) $raid = get_raid($raid_id); - // Get text and keys. - $text = show_raid_poll($raid); - $keys = keys_vote($raid); + // Get text and keys. + $text = show_raid_poll($raid); + $keys = keys_vote($raid); - $post_text = false; - if(array_key_exists('short', $text)) { - $msg_short_len = strlen(utf8_decode($text['short'])); - debug_log($msg_short_len, 'Raid poll short message length:'); - // Message short enough? - if($msg_short_len >= 1024) { - // Use full text and reset text to true regardless of prior value - $post_text = true; - } - } else { - // Use full text and reset text to true regardless of prior value - $post_text = true; + $post_text = false; + if(array_key_exists('short', $text)) { + $msg_short_len = strlen(utf8_decode($text['short'])); + debug_log($msg_short_len, 'Raid poll short message length:'); + // Message short enough? + if($msg_short_len >= 1024) { + // Use full text and reset text to true regardless of prior value + $post_text = true; } + } else { + // Use full text and reset text to true regardless of prior value + $post_text = true; + } + // Send the message. + $raid_picture_hide_level = explode(",",$config->RAID_PICTURE_HIDE_LEVEL); + $raid_picture_hide_pokemon = explode(",",$config->RAID_PICTURE_HIDE_POKEMON); + $raid_poll_hide_buttons_levels = explode(",",$config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL); - // Send the message. - $raid_picture_hide_level = explode(",",$config->RAID_PICTURE_HIDE_LEVEL); - $raid_picture_hide_pokemon = explode(",",$config->RAID_PICTURE_HIDE_POKEMON); - $raid_poll_hide_buttons_levels = explode(",",$config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL); + $raid_pokemon_id = $raid['pokemon']; + $raid_level = $raid['level']; + $raid_pokemon_form_name = get_pokemon_form_name($raid_pokemon_id,$raid['pokemon_form']); + $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_name; - $raid_pokemon_id = $raid['pokemon']; - $raid_level = $raid['level']; - $raid_pokemon_form_name = get_pokemon_form_name($raid_pokemon_id,$raid['pokemon_form']); - $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_name; - - foreach($chats as $chat_id) { - // Send location. - if ($config->RAID_LOCATION) { - // Send location. - $msg_text = !empty($raid['address']) ? $raid['address'] : $raid['pokemon']; - // Sending venue together with raid poll can't be multicurled since they would appear to the chat in random order - send_venue($chat_id, $raid['lat'], $raid['lon'], '', $msg_text, false, false, $raid_id); - send_message($chat_id, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); - }else { - if($config->RAID_PICTURE && $raid['event_hide_raid_picture'] == 0 && !in_array($raid_level, $raid_picture_hide_level) && !in_array($raid_pokemon, $raid_picture_hide_pokemon) && !in_array($raid_pokemon_id, $raid_picture_hide_pokemon)) { - require_once(LOGIC_PATH . '/raid_picture.php'); - $media_content = get_raid_picture($raid, $config->RAID_PICTURE_AUTOEXTEND); - if(($config->RAID_PICTURE_AUTOEXTEND && !in_array($raid['level'], $raid_poll_hide_buttons_levels)) or $post_text) { - $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache - send_photo($chat_id, $media_content[1], $media_content[0], '', [], [], false, $raid); - send_message($chat_id, $text['short'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); - } else { - $tg_json[] = send_photo($chat_id, $media_content[1], $media_content[0], $text['short'], $keys, ['disable_web_page_preview' => 'true'], true, $raid); - } - } else { - $tg_json[] = send_message($chat_id, $text['full'], $keys, ['disable_web_page_preview' => 'true'], true, $raid_id); - } - } + foreach($chats as $chat_id) { + if ($config->RAID_LOCATION) { + // Send location. + $msg_text = !empty($raid['address']) ? $raid['address'] : $raid['pokemon']; + // Sending venue together with raid poll can't be multicurled since they would appear to the chat in random order + send_venue($chat_id, $raid['lat'], $raid['lon'], '', $msg_text, false, false, $raid_id); + send_message($chat_id, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); + continue; + } + if(!$config->RAID_PICTURE || $raid['event_hide_raid_picture'] == 1 || in_array($raid_level, $raid_picture_hide_level) || in_array($raid_pokemon, $raid_picture_hide_pokemon) || in_array($raid_pokemon_id, $raid_picture_hide_pokemon)) { + $tg_json[] = send_message($chat_id, $text['full'], $keys, ['disable_web_page_preview' => 'true'], true, $raid_id); + continue; + } + require_once(LOGIC_PATH . '/raid_picture.php'); + $media_content = get_raid_picture($raid, $config->RAID_PICTURE_AUTOEXTEND); + if((!$config->RAID_PICTURE_AUTOEXTEND || in_array($raid['level'], $raid_poll_hide_buttons_levels)) or !$post_text) { + $tg_json[] = send_photo($chat_id, $media_content[1], $media_content[0], $text['short'], $keys, ['disable_web_page_preview' => 'true'], true, $raid); + continue; } - return $tg_json; + $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache + send_photo($chat_id, $media_content[1], $media_content[0], '', [], [], false, $raid); + send_message($chat_id, $text['short'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); + } + return $tg_json; } -?> \ No newline at end of file diff --git a/logic/send_trainerinfo.php b/logic/send_trainerinfo.php index 5ac1eab4..0fa43aff 100644 --- a/logic/send_trainerinfo.php +++ b/logic/send_trainerinfo.php @@ -1,35 +1,35 @@ 'true'], true); + // Edit the message. + $tg_json[] = edit_message($update, $msg, $keys, ['disable_web_page_preview' => 'true'], true); - // Telegram multicurl request. - curl_json_multi_request($tg_json); + // Telegram multicurl request. + curl_json_multi_request($tg_json); - // Exit. - exit(); + // Exit. + exit(); } - -?> diff --git a/logic/send_vote_remote_users_limit_reached.php b/logic/send_vote_remote_users_limit_reached.php index a96ef971..a4cbb59e 100644 --- a/logic/send_vote_remote_users_limit_reached.php +++ b/logic/send_vote_remote_users_limit_reached.php @@ -5,11 +5,9 @@ */ function send_vote_remote_users_limit_reached($update) { - // Set the message. - $msg = getTranslation('vote_remote_users_limit_reached'); + // Set the message. + $msg = getTranslation('vote_remote_users_limit_reached'); - // Answer the callback. - answerCallbackQuery($update['callback_query']['id'], $msg); + // Answer the callback. + answerCallbackQuery($update['callback_query']['id'], $msg); } - -?> diff --git a/logic/send_vote_time_first.php b/logic/send_vote_time_first.php index b6305545..fbc69e19 100644 --- a/logic/send_vote_time_first.php +++ b/logic/send_vote_time_first.php @@ -5,13 +5,11 @@ */ function send_vote_time_first($update) { - // Set the message. - $msg = getTranslation('vote_time_first'); + // Set the message. + $msg = getTranslation('vote_time_first'); - // Answer the callback. - answerCallbackQuery($update['callback_query']['id'], $msg); + // Answer the callback. + answerCallbackQuery($update['callback_query']['id'], $msg); - exit(); + exit(); } - -?> diff --git a/logic/send_vote_time_future.php b/logic/send_vote_time_future.php index 21a17891..e11d60f8 100644 --- a/logic/send_vote_time_future.php +++ b/logic/send_vote_time_future.php @@ -5,11 +5,9 @@ */ function send_vote_time_future($update) { - // Set the message. - $msg = getPublicTranslation('vote_time_future'); + // Set the message. + $msg = getPublicTranslation('vote_time_future'); - // Answer the callback. - answerCallbackQuery($update['callback_query']['id'], $msg); + // Answer the callback. + answerCallbackQuery($update['callback_query']['id'], $msg); } - -?> diff --git a/logic/sendalarmnotice.php b/logic/sendalarmnotice.php index 924d3c30..ddd4cd50 100644 --- a/logic/sendalarmnotice.php +++ b/logic/sendalarmnotice.php @@ -1,51 +1,47 @@ fetch(); - } - $gymname = '' . $raid['gym_name'] . ''; - // parse raidtimes - $raidtimes = str_replace(CR, '', str_replace(' ', '', get_raid_times($raid, false, true))); + if(empty($raid)){ + // Request limited raid info + $request = my_query(' + SELECT g.gym_name, r.start_time, r.end_time + FROM raids as r + LEFT JOIN gyms as g + ON r.gym_id = g.id + WHERE r.id = ? + ', [$raid_id]); + $raid = $request->fetch(); + } + $gymname = '' . $raid['gym_name'] . ''; + // parse raidtimes + $raidtimes = str_replace(CR, '', str_replace(' ', '', get_raid_times($raid, false, true))); - if(empty($alarm)){ - // Get the new value - $rs = my_query( - " - SELECT alarm - FROM attendance - WHERE raid_id = {$raid_id} - AND user_id = {$user_id} - " - ); - $answer = $rs->fetch(); - $alarm = $answer['alarm']; - } + if(empty($alarm)){ + // Get the new value + $rs = my_query(' + SELECT alarm + FROM attendance + WHERE raid_id = ? + AND user_id = ? + ',[$raid_id, $user_id] + ); + $answer = $rs->fetch(); + $alarm = $answer['alarm']; + } - $msg_text = ''; - - if($alarm) {// Enable alerts message. - $msg_text = EMOJI_ALARM . SP . '' . getTranslation('alert_updates_on') . '' . CR; - } else {// Disable alerts message. - $msg_text = EMOJI_NO_ALARM . SP . '' . getTranslation('alert_no_updates') . '' . CR; + if($alarm) {// Enable alerts message. + $msg_text = EMOJI_ALARM . SP . '' . getTranslation('alert_updates_on') . '' . CR; + } else {// Disable alerts message. + $msg_text = EMOJI_NO_ALARM . SP . '' . getTranslation('alert_no_updates') . '' . CR; } - $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')'; - send_message($user_id, $msg_text); + $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')'; + send_message($user_id, $msg_text); } - -?> diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index dd2623ab..9cab2cb9 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -1,4 +1,11 @@ ".$raid['event_name']."".CR, true); + global $config; + // Init empty message array. + //$msg = ''; + $msg = array(); + + // Get current pokemon + $raid_pokemon_id = $raid['pokemon']; + $raid_pokemon_form_id = $raid['pokemon_form']; + $raid_pokemon_form_name = ($raid_pokemon_form_id != 0) ? get_pokemon_form_name($raid_pokemon_id, $raid_pokemon_form_id) : ''; + $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_id; + $raid_pokemon_info = get_pokemon_info($raid_pokemon_id, $raid_pokemon_form_id); + + // Get raid level + $raid_level = $raid['level']; + + // Are remote players allowed for this raid? + $raid_local_only = in_array($raid_level, RAID_LEVEL_LOCAL_ONLY); + + if($raid['event_name'] != NULL && $raid['event_name'] != "") { + $msg = raid_poll_message($msg, "".$raid['event_name']."".CR, true); + } + + // Get raid times. + $msg = raid_poll_message($msg, get_raid_times($raid, true, ($raid['event_pokemon_title'] == 0 ? true : false)), true); + + // Get current time and time left. + $time_now = utcnow(); + $time_left = $raid['t_left']; + + // Display gym details. + if ($raid['gym_name'] || $raid['gym_team']) { + // Add gym name to message. + if ($raid['gym_name']) { + $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : '' . $config->RAID_EX_GYM_MARKER . ''; + $msg = raid_poll_message($msg, getPublicTranslation('gym') . ': ' . ($raid['ex_gym'] ? $ex_raid_gym_marker . SP : '') . '' . $raid['gym_name'] . '', true); } - // Get raid times. - $msg = raid_poll_message($msg, get_raid_times($raid, true, ($raid['event_pokemon_title'] == 0 ? true : false)), true); + // Add team to message. + if ($raid['gym_team']) { + $msg = raid_poll_message($msg, SP . $GLOBALS['teams'][$raid['gym_team']], true); + } - // Get current time and time left. - $time_now = utcnow(); - $time_left = $raid['t_left']; + $msg = raid_poll_message($msg, CR, true); + } + + // Add maps link to message. + if (!empty($raid['address'])) { + $msg = raid_poll_message($msg, ($config->RAID_PICTURE ? $raid['gym_name'].': ' : ''). mapslink($raid) . CR); + } else { + // Get the address. + $addr = get_address($raid['lat'], $raid['lon']); + $address = format_address($addr); + + //Only store address if not empty + if(!empty($address)) { + my_query(' + UPDATE gyms + SET address = ? + WHERE id = ? + ', [$address, $raid['gym_id']] + ); + //Use new address + $msg = raid_poll_message($msg, ($config->RAID_PICTURE ? $raid['gym_name'].': ' : ''). mapslink($raid,$address) . CR); + } else { + //If no address is found show maps link + $msg = raid_poll_message($msg, ($config->RAID_PICTURE ? $raid['gym_name'].': ' : ''). mapslink($raid,'1') . CR); + } + } + + // Display raid boss name and boss' weather unless hidden for a specific event + if($raid['event_pokemon_title'] != 0 or $raid['event_pokemon_title'] == NULL) { + // Display raid boss name. + if($raid['event_pokemon_title'] == 1) $title = getPublicTranslation('raid_boss'); + elseif($raid['event_pokemon_title'] == 2) $title = getPublicTranslation('featured_pokemon'); + else $title = getPublicTranslation('raid_boss'); + $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . '', true); + + // Display raid boss weather. + $msg = raid_poll_message($msg, ($raid_pokemon_info['weather'] != 0) ? (' ' . get_weather_icons($raid_pokemon_info['weather'])) : '', true); + $msg = raid_poll_message($msg, CR, true); + } + + // Display attacks. + if ($raid['move1'] > 1 && $raid['move2'] > 2 ) { + $msg = raid_poll_message($msg, getPublicTranslation('pokemon_move_' . $raid['move1']) . '/' . getPublicTranslation('pokemon_move_' . $raid['move2'])); + $msg = raid_poll_message($msg, CR); + } + + // Hide participants? + $hide_users_sql = ""; + if($config->RAID_POLL_HIDE_USERS_TIME > 0) { + if($config->RAID_ANYTIME) { + $hide_users_sql = 'AND (attend_time > (UTC_TIMESTAMP() - INTERVAL ' . $config->RAID_POLL_HIDE_USERS_TIME . ' MINUTE) OR attend_time = \''. ANYTIME .'\')'; + } else { + $hide_users_sql = 'AND attend_time > (UTC_TIMESTAMP() - INTERVAL ' . $config->RAID_POLL_HIDE_USERS_TIME . ' MINUTE)'; + } + } + + // When the raid egg is hatched, hide all attendances that did not voted for hatched pokemon or any pokemon + // Remaining attendances are combined and treated as users that voted for any pokemon from now on + $order_by_sql = 'pokemon,'; + $combine_attendances = false; + if(!in_array($raid['pokemon'], $GLOBALS['eggs'])) { + $hide_users_sql.= 'AND (pokemon = \''.$raid['pokemon'].'-'.$raid['pokemon_form'].'\' OR pokemon = \'0\')'; + $order_by_sql = ''; // Remove sorting by pokemon since all attendances are combined + $combine_attendances = true; + } + + // Buttons for raid levels and pokemon hidden? + $hide_buttons_raid_level = explode(',', $config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL); + $hide_buttons_pokemon = explode(',', $config->RAID_POLL_HIDE_BUTTONS_POKEMON); + $buttons_hidden = false; + if(in_array($raid_level, $hide_buttons_raid_level) || in_array($raid_pokemon_id, $hide_buttons_pokemon) || in_array($raid_pokemon_id.'-'.$raid_pokemon_form_name, $hide_buttons_pokemon)) { + $buttons_hidden = true; + } + + // Get attendances + $rs_attendance = my_query(' + SELECT attendance.*, + users.name, + users.nick, + users.trainername, + users.display_name, + users.trainercode, + users.level, + users.team + FROM attendance + LEFT JOIN users + ON attendance.user_id = users.user_id + WHERE raid_id = ? + ' . $hide_users_sql . ' + AND attend_time IS NOT NULL + ORDER BY attend_time, + ' . $order_by_sql . ' + can_invite DESC, + users.team, + arrived, + users.level desc, + users.name + ', [$raid['id']] + ); + + // Init empty attendance array and trigger variables + $att_array = $cnt_array = $done_array = $cancel_array = []; + $cnt_all = $cnt_remote = $cnt_want_invite = $cnt_extra_alien = $cnt_latewait = $cnt_cancel = $cnt_done = $cnt_can_invite = 0; + + while ($attendance = $rs_attendance->fetch()) { + // Attendance found + $cnt_all = 1; + $attendance_pokemon = $combine_attendances ? 0 : $attendance['pokemon']; // If raid egg has hatched, combine all attendances under 'any pokemon' + + // Check trainername + $attendance = check_trainername($attendance); + + // Define variables if necessary + if(!isset($cnt_array[$attendance['attend_time']][$attendance_pokemon])) + $cnt_array[$attendance['attend_time']][$attendance_pokemon]['extra_alien']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['in_person']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['late']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['remote']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['want_invite']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['total']=0; + if(!isset($cnt_array[$attendance['attend_time']]['other_pokemon'])) $cnt_array[$attendance['attend_time']]['other_pokemon'] = $cnt_array[$attendance['attend_time']]['raid_pokemon'] = $cnt_array[$attendance['attend_time']]['any_pokemon'] = 0; + + if($attendance['cancel'] == 0 && $attendance['raid_done'] == 0 && $attendance['can_invite'] == 0) { + // These counts are used to control printing of pokemon/time headers, so just number of entries is enough + if($attendance['pokemon'] != 0 && $raid_pokemon != $attendance['pokemon']){ + $cnt_array[$attendance['attend_time']]['other_pokemon']+=1; + }elseif($attendance['pokemon'] != 0 && $raid_pokemon == $attendance['pokemon']) { + $cnt_array[$attendance['attend_time']]['raid_pokemon']+= 1; + }else { + $cnt_array[$attendance['attend_time']]['any_pokemon']+= 1; + } + + // Adding to total count of specific pokemon at specific time + $cnt_array[$attendance['attend_time']][$attendance_pokemon]['total'] += 1 + $attendance['extra_in_person'] + $attendance['extra_alien']; + + if($attendance['want_invite'] == 0) { + // Fill attendance array with results + $att_array[$attendance['attend_time']][$attendance_pokemon][] = $attendance; - // Display gym details. - if ($raid['gym_name'] || $raid['gym_team']) { - // Add gym name to message. - if ($raid['gym_name']) { - $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : '' . $config->RAID_EX_GYM_MARKER . ''; - $msg = raid_poll_message($msg, getPublicTranslation('gym') . ': ' . ($raid['ex_gym'] ? $ex_raid_gym_marker . SP : '') . '' . $raid['gym_name'] . '', true); + // Fill counts array + if($attendance['extra_alien'] > 0) { + $cnt_extra_alien = 1; + $cnt_array[$attendance['attend_time']][$attendance_pokemon]['extra_alien'] += $attendance['extra_alien']; } - // Add team to message. - if ($raid['gym_team']) { - $msg = raid_poll_message($msg, SP . $GLOBALS['teams'][$raid['gym_team']], true); + if($attendance['late'] == 1) { + $cnt_latewait = 1; + $cnt_array[$attendance['attend_time']][$attendance_pokemon]['late'] += 1 + $attendance['extra_in_person'] + $attendance['extra_alien']; + } + if($attendance['remote'] == 1) { + $cnt_remote = 1; + $cnt_array[$attendance['attend_time']][$attendance_pokemon]['remote'] += 1 + $attendance['extra_in_person']; + }else { + $cnt_array[$attendance['attend_time']][$attendance_pokemon]['in_person'] += 1 + $attendance['extra_in_person']; + } + }else if($attendance['want_invite'] == 1) { + // Create array key for attend time and pokemon to maintain correct sorting order + if(!array_key_exists($attendance['attend_time'], $att_array)) { + $att_array[$attendance['attend_time']] = []; + $att_array[$attendance['attend_time']][$attendance_pokemon] = []; + }elseif(!array_key_exists($attendance_pokemon, $att_array[$attendance['attend_time']])) { + $att_array[$attendance['attend_time']][$attendance_pokemon] = []; } - $msg = raid_poll_message($msg, CR, true); + $cnt_array[$attendance['attend_time']][$attendance_pokemon]['want_invite'] += 1 + $attendance['extra_in_person']; + } + }else { + if($attendance['raid_done']==1) { + $cnt_done += 1 + $attendance['extra_in_person'] + $attendance['extra_alien']; + $done_array[$attendance['user_id']] = $attendance; // Adding user_id as key to overwrite duplicate entries and thus only display user once even if they made multiple pokemon selections + }else if($attendance['cancel']==1) { + $cnt_cancel += 1 + $attendance['extra_in_person'] + $attendance['extra_alien']; + $cancel_array[$attendance['user_id']] = $attendance; + }else if($attendance['can_invite']==1) { + $cnt_can_invite++; + $att_array[$attendance['attend_time']][$attendance_pokemon][] = $attendance; + } } - - // Add maps link to message. - if (!empty($raid['address'])) { - $msg = raid_poll_message($msg, ($config->RAID_PICTURE ? $raid['gym_name'].': ' : ''). mapslink($raid) . CR); + } + + // Get attendances with invite beggars + // Using a separate query so they can be displayed in the order they're in the db (who voted first) + $rs_attendance_want_inv = my_query(' + SELECT attendance.*, + users.name, + users.nick, + users.trainername, + users.display_name, + users.trainercode, + users.level, + users.team + FROM attendance + LEFT JOIN users + ON attendance.user_id = users.user_id + WHERE raid_id = ? + AND want_invite = 1 + AND cancel = 0 + AND raid_done = 0 + ' . $hide_users_sql . ' + AND attend_time IS NOT NULL + ORDER BY attend_time, + ' . $order_by_sql . ' + attendance.id + ', [$raid['id']] + ); + while ($attendance = $rs_attendance_want_inv->fetch()) { + // Attendance found + $cnt_want_invite = 1; + $attendance = check_trainername($attendance); + + // Fill attendance array with results + if($combine_attendances) { + $att_array[$attendance['attend_time']][0][] = $attendance; + }else { + $att_array[$attendance['attend_time']][$attendance['pokemon']][] = $attendance; + } + } + // Raid has started and has participants + if($time_now > $raid['start_time']) { + // Add raid is done message. + if($raid['raid_ended']) { + $msg = raid_poll_message($msg, '' . getPublicTranslation('raid_done') . '' . CR); + // Add time left message. } else { - // Get the address. - $addr = get_address($raid['lat'], $raid['lon']); - $address = format_address($addr); - - //Only store address if not empty - if(!empty($address)) { - my_query( - ' - UPDATE gyms - SET address = ? - WHERE id = ? - ', [$address, $raid['gym_id']] - ); - //Use new address - $msg = raid_poll_message($msg, ($config->RAID_PICTURE ? $raid['gym_name'].': ' : ''). mapslink($raid,$address) . CR); - } else { - //If no address is found show maps link - $msg = raid_poll_message($msg, ($config->RAID_PICTURE ? $raid['gym_name'].': ' : ''). mapslink($raid,'1') . CR); - } + $msg = raid_poll_message($msg, getPublicTranslation('raid') . ' — ' . getPublicTranslation('still') . ' ' . $time_left . 'h' . CR); } - - // Display raid boss name and boss' weather unless hidden for a specific event - if($raid['event_pokemon_title'] != 0 or $raid['event_pokemon_title'] == NULL) { - // Display raid boss name. - if($raid['event_pokemon_title'] == 1) $title = getPublicTranslation('raid_boss'); - elseif($raid['event_pokemon_title'] == 2) $title = getPublicTranslation('featured_pokemon'); - else $title = getPublicTranslation('raid_boss'); - $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . '', true); - - // Display raid boss weather. - $msg = raid_poll_message($msg, ($raid_pokemon_info['weather'] != 0) ? (' ' . get_weather_icons($raid_pokemon_info['weather'])) : '', true); - $msg = raid_poll_message($msg, CR, true); + if($cnt_all > 0 || $buttons_hidden) { + // Display raid boss CP values. + $pokemon_cp = get_formatted_pokemon_cp($raid_pokemon_info, true); + $msg = raid_poll_message($msg, (!empty($pokemon_cp)) ? ($pokemon_cp . CR) : '', true); } - - // Display attacks. - if ($raid['move1'] > 1 && $raid['move2'] > 2 ) { - $msg = raid_poll_message($msg, getPublicTranslation('pokemon_move_' . $raid['move1']) . '/' . getPublicTranslation('pokemon_move_' . $raid['move2'])); - $msg = raid_poll_message($msg, CR); + } + + // Hide info if buttons are hidden + if($buttons_hidden) { + // Show message that voting is not possible! + $msg = raid_poll_message($msg, CR . '' . getPublicTranslation('raid_info_no_voting') . ' ' . CR); + } else { + // Gym note? + if(!empty($raid['gym_note'])) { + $msg = raid_poll_message($msg, EMOJI_INFO . SP . $raid['gym_note'] . CR); } - // Hide participants? - if($config->RAID_POLL_HIDE_USERS_TIME > 0) { - if($config->RAID_ANYTIME) { - $hide_users_sql = "AND (attend_time > (UTC_TIMESTAMP() - INTERVAL " . $config->RAID_POLL_HIDE_USERS_TIME . " MINUTE) OR attend_time = '". ANYTIME ."')"; - } else { - $hide_users_sql = "AND attend_time > (UTC_TIMESTAMP() - INTERVAL " . $config->RAID_POLL_HIDE_USERS_TIME . " MINUTE)"; - } - } else { - $hide_users_sql = ""; + // Add Ex-Raid Message if Pokemon is in Ex-Raid-List. + if($raid['event'] == EVENT_ID_EX) { + $msg = raid_poll_message($msg, CR . EMOJI_WARN . ' ' . getPublicTranslation('exraid_pass') . ' ' . EMOJI_WARN . CR); + } + // Add hint that remote participation is not possible + if($raid_local_only) { + $msg = raid_poll_message($msg, CR . EMOJI_WARN . SP . getPublicTranslation('no_remote_parcipants') . CR); } - // When the raid egg is hatched, hide all attendances that did not voted for hatched pokemon or any pokemon - // Remaining attendances are combined and treated as users that voted for any pokemon from now on - $order_by_sql = 'pokemon,'; - $combine_attendances = false; - if(!in_array($raid['pokemon'], $GLOBALS['eggs'])) { - $hide_users_sql.= 'AND (pokemon = \''.$raid['pokemon'].'-'.$raid['pokemon_form'].'\' OR pokemon = \'0\')'; - $order_by_sql = ''; // Remove sorting by pokemon since all attendances are combined - $combine_attendances = true; + // Add event description + if($raid['event_description'] != NULL && $raid['event_description'] != "") { + $msg = raid_poll_message($msg, CR . "".$raid['event_name']."" . CR); + $msg = raid_poll_message($msg, $raid['event_description'] . CR); } - // Buttons for raid levels and pokemon hidden? - $hide_buttons_raid_level = explode(',', $config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL); - $hide_buttons_pokemon = explode(',', $config->RAID_POLL_HIDE_BUTTONS_POKEMON); - $buttons_hidden = false; - if(in_array($raid_level, $hide_buttons_raid_level) || in_array($raid_pokemon_id, $hide_buttons_pokemon) || in_array($raid_pokemon_id.'-'.$raid_pokemon_form_name, $hide_buttons_pokemon)) { - $buttons_hidden = true; + // Add event note + if($raid['event_note'] != NULL && $raid['event_note'] != "") { + $msg = raid_poll_message($msg, CR . $raid['event_note'] . CR); } + // Add attendances message. + if ($cnt_all > 0) { + // Init previous attend time and pokemon + $previous_att_time = 'FIRST_RUN'; + $previous_pokemon = 'FIRST_RUN'; + + // Add hint for remote attendances. + if(!$raid_local_only && ($cnt_remote > 0 || $cnt_want_invite > 0 || $cnt_extra_alien > 0)) { + $remote_max_msg = str_replace('REMOTE_MAX_USERS', $config->RAID_REMOTEPASS_USERS_LIMIT, getPublicTranslation('remote_participants_max')); + $msg = raid_poll_message($msg, CR . ($cnt_remote > 0 ? EMOJI_REMOTE : '') . ($cnt_extra_alien > 0 ? EMOJI_ALIEN : '') . ($cnt_want_invite > 0 ? EMOJI_WANT_INVITE : '') . SP . getPublicTranslation('remote_participants') . SP . '' . $remote_max_msg . '' . CR); + } + // Add hint for attendees that only invite. + if(!$raid_local_only && $cnt_can_invite > 0) { + $msg = raid_poll_message($msg, CR . EMOJI_CAN_INVITE . SP . getPublicTranslation('alert_can_invite') . CR); + } + // Add start raid message + if($cnt_all > 0 && $config->RAID_POLL_SHOW_START_LINK) { + $msg = raid_poll_message($msg, CR . '' . str_replace('START_CODE', '' . getPublicTranslation('telegram_bot_start') . '', getPublicTranslation('start_raid')) . '' . SP . '' . getPublicTranslation('start_raid_info') . '' . CR); + } + // Add hint for late attendances. + if($config->RAID_LATE_MSG && $cnt_latewait > 0) { + $late_wait_msg = ""; + if($config->RAID_LATE_TIME > 0) { + $late_wait_msg = str_replace('RAID_LATE_TIME', $config->RAID_LATE_TIME, getPublicTranslation('late_participants_wait')); + } + $msg = raid_poll_message($msg, CR . EMOJI_LATE . '' . getPublicTranslation('late_participants') . ' ' . $late_wait_msg . '' . CR); + } + // For each attendance. + foreach($att_array as $att_time => $att_time_row) { + // Set current attend time and pokemon + $current_att_time = $att_time; + $dt_att_time = dt2time($current_att_time); + foreach($att_time_row as $att_pokemon => $att_pokemon_row) { + $current_pokemon = $att_pokemon; + $string_trainernames = ''; + foreach($att_pokemon_row as $att_row) { + // Add section/header for time + if($previous_att_time != $current_att_time) { + // Add to message. + if($raid['event_vote_key_mode'] == 1) { + // When vote key mode is set to 1, only display "Participating" in title, since no other timeslot selections are available + $msg = raid_poll_message($msg, CR . '' . getPublicTranslation('participating'). ''); + }else { + $msg = raid_poll_message($msg, CR . '' . (($current_att_time == ANYTIME) ? (getPublicTranslation('anytime')) : ($dt_att_time)) . ''); + } + + // Hide counts if other pokemon got selected. Show them in pokemon headers instead of attend time header + if ($cnt_array[$current_att_time][$current_pokemon]['total'] > 0 && $cnt_array[$current_att_time]['other_pokemon'] == 0) { + $msg = raid_poll_print_counts($msg, $cnt_array[$current_att_time][$current_pokemon]); + }else { + $msg = raid_poll_message($msg, CR ); + } + } - // Get attendances - $rs_attendance = my_query( - " - SELECT attendance.*, - users.name, - users.nick, - users.trainername, - users.display_name, - users.trainercode, - users.level, - users.team - FROM attendance - LEFT JOIN users - ON attendance.user_id = users.user_id - WHERE raid_id = {$raid['id']} - {$hide_users_sql} - AND attend_time IS NOT NULL - ORDER BY attend_time, - {$order_by_sql} - can_invite DESC, - users.team, - arrived, - users.level desc, - users.name - " - ); - - // Init empty attendance array and trigger variables - $att_array = []; - $cnt_array = []; - $done_array = []; - $cancel_array = []; - $cnt_all = 0; - $cnt_remote = 0; - $cnt_want_invite = 0; - $cnt_extra_alien = 0; - $cnt_latewait = 0; - $cnt_cancel = 0; - $cnt_done = 0; - $cnt_can_invite = 0; - - while ($attendance = $rs_attendance->fetch()) { - // Attendance found - $cnt_all = 1; - $attendance_pokemon = $combine_attendances ? 0 : $attendance['pokemon']; // If raid egg has hatched, combine all attendances under 'any pokemon' - - // Check trainername - $attendance = check_trainername($attendance); - - // Define variables if necessary - if(!isset($cnt_array[$attendance['attend_time']][$attendance_pokemon])) - $cnt_array[$attendance['attend_time']][$attendance_pokemon]['extra_alien']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['in_person']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['late']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['remote']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['want_invite']=$cnt_array[$attendance['attend_time']][$attendance_pokemon]['total']=0; - if(!isset($cnt_array[$attendance['attend_time']]['other_pokemon'])) $cnt_array[$attendance['attend_time']]['other_pokemon'] = $cnt_array[$attendance['attend_time']]['raid_pokemon'] = $cnt_array[$attendance['attend_time']]['any_pokemon'] = 0; - - if($attendance['cancel'] == 0 && $attendance['raid_done'] == 0 && $attendance['can_invite'] == 0) { - // These counts are used to control printing of pokemon/time headers, so just number of entries is enough - if($attendance['pokemon'] != 0 && $raid_pokemon != $attendance['pokemon']){ - $cnt_array[$attendance['attend_time']]['other_pokemon']+=1; - }elseif($attendance['pokemon'] != 0 && $raid_pokemon == $attendance['pokemon']) { - $cnt_array[$attendance['attend_time']]['raid_pokemon']+= 1; - }else { - $cnt_array[$attendance['attend_time']]['any_pokemon']+= 1; + // Add section/header for pokemon + if($previous_pokemon != $current_pokemon || $previous_att_time != $current_att_time) { + // Only display the pokemon titles if other pokemon than raid pokemon and any pokemon was selected + if($cnt_array[$current_att_time]['other_pokemon'] > 0 ) { + // Add pokemon name. + $pokemon_id_form = explode("-",$current_pokemon,2); + $msg = raid_poll_message($msg, ($current_pokemon == 0) ? ('' . getPublicTranslation('any_pokemon') . '') : ('' . get_local_pokemon_name($pokemon_id_form[0],$pokemon_id_form[1], true) . '')); + + // Add counts to message. + $msg = raid_poll_print_counts($msg, $cnt_array[$current_att_time][$current_pokemon]); + } } - // Adding to total count of specific pokemon at specific time - $cnt_array[$attendance['attend_time']][$attendance_pokemon]['total'] += 1 + $attendance['extra_in_person'] + $attendance['extra_alien']; - - if($attendance['want_invite'] == 0) { - // Fill attendance array with results - $att_array[$attendance['attend_time']][$attendance_pokemon][] = $attendance; - - // Fill counts array - if($attendance['extra_alien'] > 0) { - $cnt_extra_alien = 1; - $cnt_array[$attendance['attend_time']][$attendance_pokemon]['extra_alien'] += $attendance['extra_alien']; - } - - if($attendance['late'] == 1) { - $cnt_latewait = 1; - $cnt_array[$attendance['attend_time']][$attendance_pokemon]['late'] += 1 + $attendance['extra_in_person'] + $attendance['extra_alien']; - } - if($attendance['remote'] == 1) { - $cnt_remote = 1; - $cnt_array[$attendance['attend_time']][$attendance_pokemon]['remote'] += 1 + $attendance['extra_in_person']; - }else { - $cnt_array[$attendance['attend_time']][$attendance_pokemon]['in_person'] += 1 + $attendance['extra_in_person']; - } - }else if($attendance['want_invite'] == 1) { - // Create array key for attend time and pokemon to maintain correct sorting order - if(!array_key_exists($attendance['attend_time'], $att_array)) { - $att_array[$attendance['attend_time']] = []; - $att_array[$attendance['attend_time']][$attendance_pokemon] = []; - }elseif(!array_key_exists($attendance_pokemon, $att_array[$attendance['attend_time']])) { - $att_array[$attendance['attend_time']][$attendance_pokemon] = []; - } - - $cnt_array[$attendance['attend_time']][$attendance_pokemon]['want_invite'] += 1 + $attendance['extra_in_person']; + if($config->RAID_POLL_ENABLE_HYPERLINKS_IN_NAMES) { + $trainername = '' . htmlspecialchars($att_row['name']) . ' '; + }else { + $trainername = htmlspecialchars($att_row['name']) . ' '; } - }else { - if($attendance['raid_done']==1) { - $cnt_done += 1 + $attendance['extra_in_person'] + $attendance['extra_alien']; - $done_array[$attendance['user_id']] = $attendance; // Adding user_id as key to overwrite duplicate entries and thus only display user once even if they made multiple pokemon selections - }else if($attendance['cancel']==1) { - $cnt_cancel += 1 + $attendance['extra_in_person'] + $attendance['extra_alien']; - $cancel_array[$attendance['user_id']] = $attendance; - }else if($attendance['can_invite']==1) { - $cnt_can_invite++; - $att_array[$attendance['attend_time']][$attendance_pokemon][] = $attendance; + if(isset($att_row['trainername']) && $config->RAID_POLL_SHOW_TRAINERNAME_STRING && $att_row['want_invite']) { + if(!empty($string_trainernames)) $string_trainernames .= ','; + $string_trainernames .= $att_row['trainername']; } + // Add users: ARRIVED --- TEAM -- LEVEL -- NAME -- INVITE -- EXTRAPEOPLE + $msg = raid_poll_message($msg, ($att_row['arrived']) ? (EMOJI_HERE . ' ') : (($att_row['late']) ? (EMOJI_LATE . ' ') : '└ ')); + $msg = raid_poll_message($msg, ($att_row['team'] === NULL) ? ($GLOBALS['teams']['unknown'] . ' ') : ($GLOBALS['teams'][$att_row['team']] . ' ')); + $msg = raid_poll_message($msg, ($att_row['level'] == 0) ? ('00 ') : (($att_row['level'] < 10) ? ('0' . $att_row['level'] . ' ') : ('' . $att_row['level'] . ' '))); + $msg = raid_poll_message($msg, $trainername); + $msg = raid_poll_message($msg, ($att_row['remote']) ? (EMOJI_REMOTE) : ''); + $msg = raid_poll_message($msg, ($raid['event'] == EVENT_ID_EX && $att_row['invite']) ? (EMOJI_INVITE . ' ') : ''); + $msg = raid_poll_message($msg, ($att_row['extra_in_person']) ? ('+' . $att_row['extra_in_person'] . EMOJI_IN_PERSON . ' ') : ''); + $msg = raid_poll_message($msg, ($att_row['extra_alien']) ? ('+' . $att_row['extra_alien'] . EMOJI_ALIEN . ' ') : ''); + $msg = raid_poll_message($msg, ($att_row['want_invite']) ? (EMOJI_WANT_INVITE) : ''); + $msg = raid_poll_message($msg, ($att_row['can_invite']) ? (EMOJI_CAN_INVITE) : ''); + $msg = raid_poll_message($msg, ($config->RAID_POLL_SHOW_TRAINERCODE && ($att_row['want_invite'] || $att_row['can_invite']) && !is_null($att_row['trainercode'])) ? ' ' . $att_row['trainercode'] . ' ': ''); + + $msg = raid_poll_message($msg, CR); + + // Prepare next result + $previous_att_time = $current_att_time; + $previous_pokemon = $current_pokemon; + } + if(!empty($string_trainernames)) { + $msg = raid_poll_message($msg, '' . $string_trainernames . '' . CR); + } } + } } - // Get attendances with invite beggars - // Using a separate query so they can be displayed in the order they're in the db (who voted first) - $rs_attendance_want_inv = my_query( - " - SELECT attendance.*, - users.name, - users.nick, - users.trainername, - users.display_name, - users.trainercode, - users.level, - users.team - FROM attendance - LEFT JOIN users - ON attendance.user_id = users.user_id - WHERE raid_id = {$raid['id']} - AND want_invite = 1 - AND cancel = 0 - AND raid_done = 0 - {$hide_users_sql} - AND attend_time IS NOT NULL - ORDER BY attend_time, - {$order_by_sql} - attendance.id - " - ); - while ($attendance = $rs_attendance_want_inv->fetch()) { - // Attendance found - $cnt_want_invite = 1; - $attendance = check_trainername($attendance); - - // Fill attendance array with results - if($combine_attendances) { - $att_array[$attendance['attend_time']][0][] = $attendance; - }else { - $att_array[$attendance['attend_time']][$attendance['pokemon']][] = $attendance; - } - } - // Raid has started and has participants - if($time_now > $raid['start_time']) { - // Add raid is done message. - if($raid['raid_ended']) { - $msg = raid_poll_message($msg, '' . getPublicTranslation('raid_done') . '' . CR); - // Add time left message. - } else { - $msg = raid_poll_message($msg, getPublicTranslation('raid') . ' — ' . getPublicTranslation('still') . ' ' . $time_left . 'h' . CR); - } - if($cnt_all > 0 || $buttons_hidden) { - // Display raid boss CP values. - $pokemon_cp = get_formatted_pokemon_cp($raid_pokemon_info, true); - $msg = raid_poll_message($msg, (!empty($pokemon_cp)) ? ($pokemon_cp . CR) : '', true); - } - } - - // Hide info if buttons are hidden - if($buttons_hidden) { - // Show message that voting is not possible! - $msg = raid_poll_message($msg, CR . '' . getPublicTranslation('raid_info_no_voting') . ' ' . CR); - } else { - // Gym note? - if(!empty($raid['gym_note'])) { - $msg = raid_poll_message($msg, EMOJI_INFO . SP . $raid['gym_note'] . CR); + // Canceled or done? + if(!$config->RAID_POLL_HIDE_DONE_CANCELED && ($cnt_cancel > 0 || $cnt_done > 0)) { + // Init cancel_done value. + $cancel_done = 'CANCEL'; + $array_cancel_done = array_merge($cancel_array,$done_array); + // For each canceled / done. + foreach ($array_cancel_done as $row) { + // Attend time. + $dt_att_time = dt2time($row['attend_time']); + + // Add section/header for canceled + if($row['cancel'] == 1 && $cancel_done == 'CANCEL') { + $msg = raid_poll_message($msg, CR . TEAM_CANCEL . ' ' . getPublicTranslation('cancelled') . ': ' . '[' . $cnt_cancel . ']' . CR); + $cancel_done = 'DONE'; } - // Add Ex-Raid Message if Pokemon is in Ex-Raid-List. - if($raid['event'] == EVENT_ID_EX) { - $msg = raid_poll_message($msg, CR . EMOJI_WARN . ' ' . getPublicTranslation('exraid_pass') . ' ' . EMOJI_WARN . CR); + // Add section/header for canceled + if($row['raid_done'] == 1 && $cancel_done == 'CANCEL' || $row['raid_done'] == 1 && $cancel_done == 'DONE') { + $msg = raid_poll_message($msg, CR . TEAM_DONE . ' ' . getPublicTranslation('finished') . ': ' . '[' . $cnt_done . ']' . CR); + $cancel_done = 'END'; } - // Add hint that remote participation is not possible - if($raid_local_only) { - $msg = raid_poll_message($msg, CR . EMOJI_WARN . SP . getPublicTranslation('no_remote_parcipants') . CR); - } - - // Add event description - if($raid['event_description'] != NULL && $raid['event_description'] != "") { - $msg = raid_poll_message($msg, CR . "".$raid['event_name']."" . CR); - $msg = raid_poll_message($msg, $raid['event_description'] . CR); - } - - // Add event note - if($raid['event_note'] != NULL && $raid['event_note'] != "") { - $msg = raid_poll_message($msg, CR . $raid['event_note'] . CR); - } - // Add attendances message. - if ($cnt_all > 0) { - // Init previous attend time and pokemon - $previous_att_time = 'FIRST_RUN'; - $previous_pokemon = 'FIRST_RUN'; - - // Add hint for remote attendances. - if(!$raid_local_only && ($cnt_remote > 0 || $cnt_want_invite > 0 || $cnt_extra_alien > 0)) { - $remote_max_msg = str_replace('REMOTE_MAX_USERS', $config->RAID_REMOTEPASS_USERS_LIMIT, getPublicTranslation('remote_participants_max')); - $msg = raid_poll_message($msg, CR . ($cnt_remote > 0 ? EMOJI_REMOTE : '') . ($cnt_extra_alien > 0 ? EMOJI_ALIEN : '') . ($cnt_want_invite > 0 ? EMOJI_WANT_INVITE : '') . SP . getPublicTranslation('remote_participants') . SP . '' . $remote_max_msg . '' . CR); - } - // Add hint for attendees that only invite. - if(!$raid_local_only && $cnt_can_invite > 0) { - $msg = raid_poll_message($msg, CR . EMOJI_CAN_INVITE . SP . getPublicTranslation('alert_can_invite') . CR); - } - // Add start raid message - if($cnt_all > 0 && $config->RAID_POLL_SHOW_START_LINK) { - $msg = raid_poll_message($msg, CR . '' . str_replace('START_CODE', '' . getPublicTranslation('telegram_bot_start') . '', getPublicTranslation('start_raid')) . '' . SP . '' . getPublicTranslation('start_raid_info') . '' . CR); - } - // Add hint for late attendances. - if($config->RAID_LATE_MSG && $cnt_latewait > 0) { - $late_wait_msg = ""; - if($config->RAID_LATE_TIME > 0) { - $late_wait_msg = str_replace('RAID_LATE_TIME', $config->RAID_LATE_TIME, getPublicTranslation('late_participants_wait')); - } - $msg = raid_poll_message($msg, CR . EMOJI_LATE . '' . getPublicTranslation('late_participants') . ' ' . $late_wait_msg . '' . CR); - } - // For each attendance. - foreach($att_array as $att_time => $att_time_row) { - // Set current attend time and pokemon - $current_att_time = $att_time; - $dt_att_time = dt2time($current_att_time); - foreach($att_time_row as $att_pokemon => $att_pokemon_row) { - $current_pokemon = $att_pokemon; - $string_trainernames = ''; - foreach($att_pokemon_row as $att_row) { - // Add section/header for time - if($previous_att_time != $current_att_time) { - // Add to message. - if($raid['event_vote_key_mode'] == 1) { - // When vote key mode is set to 1, only display "Participating" in title, since no other timeslot selections are available - $msg = raid_poll_message($msg, CR . '' . getPublicTranslation('participating'). ''); - }else { - $msg = raid_poll_message($msg, CR . '' . (($current_att_time == ANYTIME) ? (getPublicTranslation('anytime')) : ($dt_att_time)) . ''); - } - - // Hide counts if other pokemon got selected. Show them in pokemon headers instead of attend time header - if ($cnt_array[$current_att_time][$current_pokemon]['total'] > 0 && $cnt_array[$current_att_time]['other_pokemon'] == 0) { - $msg = raid_poll_print_counts($msg, $cnt_array[$current_att_time][$current_pokemon]); - }else { - $msg = raid_poll_message($msg, CR ); - } - } - - // Add section/header for pokemon - if($previous_pokemon != $current_pokemon || $previous_att_time != $current_att_time) { - // Only display the pokemon titles if other pokemon than raid pokemon and any pokemon was selected - if($cnt_array[$current_att_time]['other_pokemon'] > 0 ) { - // Add pokemon name. - $pokemon_id_form = explode("-",$current_pokemon,2); - $msg = raid_poll_message($msg, ($current_pokemon == 0) ? ('' . getPublicTranslation('any_pokemon') . '') : ('' . get_local_pokemon_name($pokemon_id_form[0],$pokemon_id_form[1], true) . '')); - - // Add counts to message. - $msg = raid_poll_print_counts($msg, $cnt_array[$current_att_time][$current_pokemon]); - } - } - - if($config->RAID_POLL_ENABLE_HYPERLINKS_IN_NAMES) { - $trainername = '' . htmlspecialchars($att_row['name']) . ' '; - }else { - $trainername = htmlspecialchars($att_row['name']) . ' '; - } - if(isset($att_row['trainername']) && $config->RAID_POLL_SHOW_TRAINERNAME_STRING && $att_row['want_invite']) { - if(!empty($string_trainernames)) $string_trainernames .= ','; - $string_trainernames .= $att_row['trainername']; - } - // Add users: ARRIVED --- TEAM -- LEVEL -- NAME -- INVITE -- EXTRAPEOPLE - $msg = raid_poll_message($msg, ($att_row['arrived']) ? (EMOJI_HERE . ' ') : (($att_row['late']) ? (EMOJI_LATE . ' ') : '└ ')); - $msg = raid_poll_message($msg, ($att_row['team'] === NULL) ? ($GLOBALS['teams']['unknown'] . ' ') : ($GLOBALS['teams'][$att_row['team']] . ' ')); - $msg = raid_poll_message($msg, ($att_row['level'] == 0) ? ('00 ') : (($att_row['level'] < 10) ? ('0' . $att_row['level'] . ' ') : ('' . $att_row['level'] . ' '))); - $msg = raid_poll_message($msg, $trainername); - $msg = raid_poll_message($msg, ($att_row['remote']) ? (EMOJI_REMOTE) : ''); - $msg = raid_poll_message($msg, ($raid['event'] == EVENT_ID_EX && $att_row['invite']) ? (EMOJI_INVITE . ' ') : ''); - $msg = raid_poll_message($msg, ($att_row['extra_in_person']) ? ('+' . $att_row['extra_in_person'] . EMOJI_IN_PERSON . ' ') : ''); - $msg = raid_poll_message($msg, ($att_row['extra_alien']) ? ('+' . $att_row['extra_alien'] . EMOJI_ALIEN . ' ') : ''); - $msg = raid_poll_message($msg, ($att_row['want_invite']) ? (EMOJI_WANT_INVITE) : ''); - $msg = raid_poll_message($msg, ($att_row['can_invite']) ? (EMOJI_CAN_INVITE) : ''); - $msg = raid_poll_message($msg, ($config->RAID_POLL_SHOW_TRAINERCODE && ($att_row['want_invite'] || $att_row['can_invite']) && !is_null($att_row['trainercode'])) ? ' ' . $att_row['trainercode'] . ' ': ''); - - $msg = raid_poll_message($msg, CR); - - // Prepare next result - $previous_att_time = $current_att_time; - $previous_pokemon = $current_pokemon; - } - if(!empty($string_trainernames)) { - $msg = raid_poll_message($msg, '' . $string_trainernames . '' . CR); - } - } - } - } - - // Canceled or done? - if(!$config->RAID_POLL_HIDE_DONE_CANCELED && ($cnt_cancel > 0 || $cnt_done > 0)) { - // Init cancel_done value. - $cancel_done = 'CANCEL'; - $array_cancel_done = array_merge($cancel_array,$done_array); - // For each canceled / done. - foreach ($array_cancel_done as $row) { - // Attend time. - $dt_att_time = dt2time($row['attend_time']); - - // Add section/header for canceled - if($row['cancel'] == 1 && $cancel_done == 'CANCEL') { - $msg = raid_poll_message($msg, CR . TEAM_CANCEL . ' ' . getPublicTranslation('cancelled') . ': ' . '[' . $cnt_cancel . ']' . CR); - $cancel_done = 'DONE'; - } - - // Add section/header for canceled - if($row['raid_done'] == 1 && $cancel_done == 'CANCEL' || $row['raid_done'] == 1 && $cancel_done == 'DONE') { - $msg = raid_poll_message($msg, CR . TEAM_DONE . ' ' . getPublicTranslation('finished') . ': ' . '[' . $cnt_done . ']' . CR); - $cancel_done = 'END'; - } - if($config->RAID_POLL_ENABLE_HYPERLINKS_IN_NAMES) { - $trainername = '' . htmlspecialchars($row['name']) . ' '; - }else { - $trainername = htmlspecialchars($row['name']) . ' '; - } - - // Add users: TEAM -- LEVEL -- NAME -- CANCELED/DONE -- EXTRAPEOPLE - $msg = raid_poll_message($msg, ($row['team'] === NULL) ? ('└ ' . $GLOBALS['teams']['unknown'] . ' ') : ('└ ' . $GLOBALS['teams'][$row['team']] . ' ')); - $msg = raid_poll_message($msg, ($row['level'] == 0) ? ('00 ') : (($row['level'] < 10) ? ('0' . $row['level'] . ' ') : ('' . $row['level'] . ' '))); - $msg = raid_poll_message($msg, $trainername); - $msg = raid_poll_message($msg, ($raid['event'] == EVENT_ID_EX && $row['invite']) ? (EMOJI_INVITE . ' ') : ''); - if($raid['event_vote_key_mode'] != 1) { - $msg = raid_poll_message($msg, ($row['cancel'] == 1 || $row['raid_done'] == 1) ? ('[' . (($row['attend_time'] == ANYTIME) ? (getPublicTranslation('anytime')) : ($dt_att_time)) . '] ') : ''); - } - $msg = raid_poll_message($msg, ($row['extra_in_person']) ? ('+' . $row['extra_in_person'] . EMOJI_IN_PERSON . ' ') : ''); - $msg = raid_poll_message($msg, ($row['extra_alien']) ? ('+' . $row['extra_alien'] . EMOJI_ALIEN . ' ') : ''); - $msg = raid_poll_message($msg, CR); - } + if($config->RAID_POLL_ENABLE_HYPERLINKS_IN_NAMES) { + $trainername = '' . htmlspecialchars($row['name']) . ' '; + }else { + $trainername = htmlspecialchars($row['name']) . ' '; } - // Add no attendance found message. - if ($cnt_all + $cnt_cancel + $cnt_done == 0) { - $msg = raid_poll_message($msg, CR . getPublicTranslation('no_participants_yet') . CR); + // Add users: TEAM -- LEVEL -- NAME -- CANCELED/DONE -- EXTRAPEOPLE + $msg = raid_poll_message($msg, ($row['team'] === NULL) ? ('└ ' . $GLOBALS['teams']['unknown'] . ' ') : ('└ ' . $GLOBALS['teams'][$row['team']] . ' ')); + $msg = raid_poll_message($msg, ($row['level'] == 0) ? ('00 ') : (($row['level'] < 10) ? ('0' . $row['level'] . ' ') : ('' . $row['level'] . ' '))); + $msg = raid_poll_message($msg, $trainername); + $msg = raid_poll_message($msg, ($raid['event'] == EVENT_ID_EX && $row['invite']) ? (EMOJI_INVITE . ' ') : ''); + if($raid['event_vote_key_mode'] != 1) { + $msg = raid_poll_message($msg, ($row['cancel'] == 1 || $row['raid_done'] == 1) ? ('[' . (($row['attend_time'] == ANYTIME) ? (getPublicTranslation('anytime')) : ($dt_att_time)) . '] ') : ''); } + $msg = raid_poll_message($msg, ($row['extra_in_person']) ? ('+' . $row['extra_in_person'] . EMOJI_IN_PERSON . ' ') : ''); + $msg = raid_poll_message($msg, ($row['extra_alien']) ? ('+' . $row['extra_alien'] . EMOJI_ALIEN . ' ') : ''); + $msg = raid_poll_message($msg, CR); + } } - //Add custom message from the config. - if (!empty($config->MAP_URL)) { - $msg = raid_poll_message($msg, CR . $config->MAP_URL); - } - - // Display creator. - if($config->RAID_POLL_SHOW_CREATOR) { - $msg = raid_poll_message($msg, ($raid['user_id'] && $raid['name']) ? (CR . getPublicTranslation('created_by') . ': ' . htmlspecialchars($raid['name']) . '') : ''); - } - - // Add update time and raid id to message. - $msg = raid_poll_message($msg, CR . '' . getPublicTranslation('updated') . ': ' . dt2time('now', 'H:i:s') . ''); - if($inline && ($buttons_hidden or ($raid['raid_ended'] && $config->RAID_ENDED_HIDE_KEYS))) { - // Only case this is needed anymore is a poll shared via inline that has no vote keys - $msg = raid_poll_message($msg, SP . SP . substr(strtoupper($config->BOT_ID), 0, 1) . '-ID = ' . $raid['id']); + // Add no attendance found message. + if ($cnt_all + $cnt_cancel + $cnt_done == 0) { + $msg = raid_poll_message($msg, CR . getPublicTranslation('no_participants_yet') . CR); } - // Return the message. - return $msg; + } + + //Add custom message from the config. + if (!empty($config->MAP_URL)) { + $msg = raid_poll_message($msg, CR . $config->MAP_URL); + } + + // Display creator. + if($config->RAID_POLL_SHOW_CREATOR) { + $msg = raid_poll_message($msg, ($raid['user_id'] && $raid['name']) ? (CR . getPublicTranslation('created_by') . ': ' . htmlspecialchars($raid['name']) . '') : ''); + } + + // Add update time and raid id to message. + $msg = raid_poll_message($msg, CR . '' . getPublicTranslation('updated') . ': ' . dt2time('now', 'H:i:s') . ''); + if($inline && ($buttons_hidden or ($raid['raid_ended'] && $config->RAID_ENDED_HIDE_KEYS))) { + // Only case this is needed anymore is a poll shared via inline that has no vote keys + $msg = raid_poll_message($msg, SP . SP . substr(strtoupper($config->BOT_ID), 0, 1) . '-ID = ' . $raid['id']); + } + // Return the message. + return $msg; } /** * Print counts to raid poll headers. - * @param $msg - The array containing short and long poll messages - * @param $cnt_array - A row of cnt_array created in show_raid_poll for specific time/pokemon + * @param array $msg The array containing short and long poll messages + * @param array $cnt_array A row of cnt_array created in show_raid_poll for specific time/pokemon * @return array */ function raid_poll_print_counts($msg, $cnt_array) { - // Attendance counts - $count_in_person = $cnt_array['in_person']; - $count_remote = $cnt_array['remote']; - $count_extra_alien = $cnt_array['extra_alien']; - $count_want_invite = $cnt_array['want_invite']; - $count_late = $cnt_array['late']; - $count_total = (is_numeric($cnt_array['total'])?$cnt_array['total']:0); - - // Add to message. - $msg = raid_poll_message($msg, ' [' . ($count_total) . '] — '); - $msg = raid_poll_message($msg, (($count_in_person > 0) ? EMOJI_IN_PERSON . $count_in_person . ' ' : '')); - $msg = raid_poll_message($msg, (($count_remote > 0) ? EMOJI_REMOTE . $count_remote . ' ' : '')); - $msg = raid_poll_message($msg, (($count_extra_alien > 0) ? EMOJI_ALIEN . $count_extra_alien . ' ' : '')); - $msg = raid_poll_message($msg, (($count_want_invite > 0) ? EMOJI_WANT_INVITE . $count_want_invite . ' ' : '')); - $msg = raid_poll_message($msg, (($count_late > 0) ? EMOJI_LATE . $count_late . ' ' : '')); - $msg = raid_poll_message($msg, CR); - return $msg; + // Attendance counts + $count_in_person = $cnt_array['in_person']; + $count_remote = $cnt_array['remote']; + $count_extra_alien = $cnt_array['extra_alien']; + $count_want_invite = $cnt_array['want_invite']; + $count_late = $cnt_array['late']; + $count_total = (is_numeric($cnt_array['total'])?$cnt_array['total']:0); + + // Add to message. + $msg = raid_poll_message($msg, ' [' . ($count_total) . '] — '); + $msg = raid_poll_message($msg, (($count_in_person > 0) ? EMOJI_IN_PERSON . $count_in_person . ' ' : '')); + $msg = raid_poll_message($msg, (($count_remote > 0) ? EMOJI_REMOTE . $count_remote . ' ' : '')); + $msg = raid_poll_message($msg, (($count_extra_alien > 0) ? EMOJI_ALIEN . $count_extra_alien . ' ' : '')); + $msg = raid_poll_message($msg, (($count_want_invite > 0) ? EMOJI_WANT_INVITE . $count_want_invite . ' ' : '')); + $msg = raid_poll_message($msg, (($count_late > 0) ? EMOJI_LATE . $count_late . ' ' : '')); + $msg = raid_poll_message($msg, CR); + return $msg; } -?> diff --git a/logic/show_raid_poll_small.php b/logic/show_raid_poll_small.php index df738477..9eb79eef 100644 --- a/logic/show_raid_poll_small.php +++ b/logic/show_raid_poll_small.php @@ -1,4 +1,5 @@ ' . $raid['gym_name'] . '' . CR; - } + // Gym Name + if(!empty($raid['gym_name'])) { + $msg .= '' . $raid['gym_name'] . '' . CR; + } - // Address found. - if (!empty($raid['address'])) { - $msg .= '' . $raid['address'] . '' . CR2; - } + // Address found. + if (!empty($raid['address'])) { + $msg .= '' . $raid['address'] . '' . CR2; + } - // Pokemon - if(!empty($raid['pokemon'])) { - $msg .= '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ' ' . CR; - } - // Start time and end time - if(!empty($raid['start_time']) && !empty($raid['end_time'])) { - // Get raid times message. - $msg .= get_raid_times($raid, $override_language); - } + // Pokemon + if(!empty($raid['pokemon'])) { + $msg .= '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ' ' . CR; + } + // Start time and end time + if(!empty($raid['start_time']) && !empty($raid['end_time'])) { + // Get raid times message. + $msg .= get_raid_times($raid, $override_language); + } - // Count attendances - $rs = my_query( - " - SELECT count(attend_time) AS count, - sum(remote = 0) AS count_in_person, - sum(remote = 1) + sum(case when remote = 1 then extra_in_person else 0 end) AS count_remote, - sum(case when remote = 0 then extra_in_person else 0 end) AS extra_in_person, - sum(extra_alien) AS extra_alien - FROM attendance - LEFT JOIN users - ON attendance.user_id = users.user_id - WHERE raid_id = {$raid['id']} - AND attend_time IS NOT NULL - AND raid_done != 1 - AND cancel != 1 - " - ); + // Count attendances + $rs = my_query(' + SELECT count(attend_time) AS count, + sum(remote = 0) AS count_in_person, + sum(remote = 1) + sum(case when remote = 1 then extra_in_person else 0 end) AS count_remote, + sum(case when remote = 0 then extra_in_person else 0 end) AS extra_in_person, + sum(extra_alien) AS extra_alien + FROM attendance + LEFT JOIN users + ON attendance.user_id = users.user_id + WHERE raid_id = ? + AND attend_time IS NOT NULL + AND raid_done != 1 + AND cancel != 1 + ', [$raid['id']] + ); - $row = $rs->fetch(); + $row = $rs->fetch(); - // Add to message. - if ($row['count'] > 0) { - // Count by team. - $count_in_person = $row['count_in_person']; - $count_remote = $row['count_remote']; - $extra_in_person = $row['extra_in_person']; - $extra_alien = $row['extra_alien']; + // Add to message. + if ($row['count'] < 1) { + $msg .= getTranslation('no_participants') . CR; + return $msg; + } + // Count by team. + $count_in_person = $row['count_in_person']; + $count_remote = $row['count_remote']; + $extra_in_person = $row['extra_in_person']; + $extra_alien = $row['extra_alien']; - // Add to message. - $msg .= EMOJI_GROUP . ' ' . ($count_in_person + $count_remote + $extra_in_person + $extra_alien) . ' — '; - $msg .= (($count_in_person > 0) ? EMOJI_IN_PERSON . ($count_in_person + $extra_in_person) . ' ' : ''); - $msg .= (($count_remote > 0) ? EMOJI_REMOTE . $count_remote . ' ' : ''); - $msg .= (($extra_alien > 0) ? EMOJI_ALIEN . $extra_alien . ' ' : ''); - $msg .= CR; - } else { - $msg .= getTranslation('no_participants') . CR; - } + // Add to message. + $msg .= EMOJI_GROUP . ' ' . ($count_in_person + $count_remote + $extra_in_person + $extra_alien) . ' — '; + $msg .= (($count_in_person > 0) ? EMOJI_IN_PERSON . ($count_in_person + $extra_in_person) . ' ' : ''); + $msg .= (($count_remote > 0) ? EMOJI_REMOTE . $count_remote . ' ' : ''); + $msg .= (($extra_alien > 0) ? EMOJI_ALIEN . $extra_alien . ' ' : ''); + $msg .= CR; - return $msg; + return $msg; } - -?> diff --git a/logic/show_trainerinfo.php b/logic/show_trainerinfo.php index 70765af1..bd3e298e 100644 --- a/logic/show_trainerinfo.php +++ b/logic/show_trainerinfo.php @@ -1,4 +1,5 @@ ' . getPublicTranslation('trainerinfo') . ':' . CR; - $msg .= getPublicTranslation('trainer_set_your_info') . CR . CR; - $msg .= getPublicTranslation('trainer_set_your_info_done') . CR . CR; + // Instructions + $msg = '' . getPublicTranslation('trainerinfo') . ':' . CR; + $msg .= getPublicTranslation('trainer_set_your_info') . CR . CR; + $msg .= getPublicTranslation('trainer_set_your_info_done') . CR . CR; - // Show user info? - if($show) { - $msg .= '' . getPublicTranslation('your_trainer_info') . '' . CR; - $msg .= get_user($update['callback_query']['from']['id']) . CR; - } + // Show user info? + if($show) { + $msg .= '' . getPublicTranslation('your_trainer_info') . '' . CR; + $msg .= get_user($update['callback_query']['from']['id']) . CR; + } - $msg .= '' . getPublicTranslation('updated') . ': ' . dt2time('now', 'H:i:s') . ''; + $msg .= '' . getPublicTranslation('updated') . ': ' . dt2time('now', 'H:i:s') . ''; - return $msg; + return $msg; } - -?> diff --git a/core/bot/logic/sql_utils.php b/logic/sql_utils.php similarity index 52% rename from core/bot/logic/sql_utils.php rename to logic/sql_utils.php index 74bad175..a3dc2417 100644 --- a/core/bot/logic/sql_utils.php +++ b/logic/sql_utils.php @@ -9,7 +9,7 @@ function run_sql_file($file) { if (!$dbh) { error_log('No DB handle!'); return false; - } + } try { $query = file_get_contents($file); $dbh->exec( $query ); @@ -26,41 +26,41 @@ function run_sql_file($file) { /** * DB query wrapper that supports binds. - * @param $query - * @param binds + * @param $query string + * @param $binds Array * @return PDOStatement */ function my_query($query, $binds=null) { - global $dbh; - global $config; - require_once(CORE_BOT_PATH . '/logic/debug.php'); + global $dbh; + global $config; + require_once(ROOT_PATH . '/logic/debug.php'); - try { - $stmt = $dbh->prepare($query); - $stmt->execute($binds); - } catch (PDOException $exception) { - // The message will be output in the global handler, we just need to extract the failing query - error_log('The following query failed:'); - log_query($stmt, print_r($binds, true), 'error_log'); - throw $exception; - } finally { - debug_log_sql('Query success', '$'); - if($config->DEBUG_SQL) { - log_query($stmt, print_r($binds, true), 'debug_log_sql'); - } + try { + $stmt = $dbh->prepare($query); + $stmt->execute($binds); + } catch (PDOException $exception) { + // The message will be output in the global handler, we just need to extract the failing query + error_log('The following query failed:'); + log_query($stmt, print_r($binds, true), 'error_log'); + throw $exception; + } finally { + debug_log_sql('Query success', '$'); + if($config->DEBUG_SQL) { + log_query($stmt, print_r($binds, true), 'debug_log_sql'); } - return $stmt; + } + return $stmt; } // Debug log the full statement with parameters function log_query($stmt, $binds, $logger='debug_log_sql'){ - ob_start(); - $stmt->debugDumpParams(); - $debug = ob_get_contents(); - ob_end_clean(); - $logger($debug); - $logger('The parameters bound were:'); - if($binds === null) $binds = 'null'; - $logger($binds); + ob_start(); + $stmt->debugDumpParams(); + $debug = ob_get_contents(); + ob_end_clean(); + $logger($debug); + $logger('The parameters bound were:'); + if($binds === null) $binds = 'null'; + $logger($binds); } diff --git a/logic/update_raid_poll.php b/logic/update_raid_poll.php index 3c0ccfd5..cb8af2ef 100644 --- a/logic/update_raid_poll.php +++ b/logic/update_raid_poll.php @@ -1,4 +1,6 @@ null, - 'message_id' => $update['callback_query']['inline_message_id'], - 'type' => 'poll_text', - ]; - // For updating a poll - }else if(isset($update['push'])) { - $chat_and_message[] = $update['push']; + global $config; + $chat_and_message = []; + // Parsing the update type here, since the callback_query can come from regular message or inline message + if(isset($update['callback_query']['inline_message_id'])) { + $chat_and_message[] = [ + 'chat_id' => null, + 'message_id' => $update['callback_query']['inline_message_id'], + 'type' => 'poll_text', + ]; + // For updating a poll + }else if(isset($update['push'])) { + $chat_and_message[] = $update['push']; + } + // If neither of the methods above yielded results, or update came from a inline poll, check cleanup table for chat messages to update + if(empty($chat_and_message) or isset($update['callback_query']['inline_message_id'])) { + if($update_photo) $photo_query = 'AND (type = \'photo\' OR type = \'poll_photo\')'; else $photo_query = ''; + $rs_chann = my_query(' + SELECT chat_id, message_id, type, media_unique_id + FROM cleanup + WHERE raid_id = ? + ' . $photo_query,[$raid_id] + ); + if ($rs_chann->rowCount() > 0) { + while($chat = $rs_chann->fetch()) { + $chat_and_message[] = $chat; + } + }else { + if(is_array($tg_json)) return $tg_json; + else return []; } - // If neither of the methods above yielded results, or update came from a inline poll, check cleanup table for chat messages to update - if(empty($chat_and_message) or isset($update['callback_query']['inline_message_id'])) { - if($update_photo) $photo_query = 'AND (type = \'photo\' OR type = \'poll_photo\')'; else $photo_query = ''; - $rs_chann = my_query(' - SELECT chat_id, message_id, type, media_unique_id - FROM cleanup - WHERE raid_id = ' . $raid_id . ' - ' . $photo_query - ); - if ($rs_chann->rowCount() > 0) { - while($chat = $rs_chann->fetch()) { - $chat_and_message[] = $chat; - } - }else { - if(is_array($tg_json)) return $tg_json; - else return []; - } - } - // Get the raid data by id. - if($raid == false) $raid = get_raid($raid_id); + } + // Get the raid data by id. + if($raid == false) $raid = get_raid($raid_id); - // Message - make sure to not exceed Telegrams 1024 characters limit for caption - $text = show_raid_poll($raid); - $post_text = false; - if(array_key_exists('short', $text)) { - $msg_short_len = strlen(utf8_decode($text['short'])); - debug_log($msg_short_len, 'Raid poll short message length:'); - // Message short enough? - if($msg_short_len >= 1024) { - // Use full text and reset text to true regardless of prior value - $post_text = true; - } - } else { - // Use full text and reset text to true regardless of prior value - $post_text = true; + // Message - make sure to not exceed Telegrams 1024 characters limit for caption + $text = show_raid_poll($raid); + $post_text = false; + if(array_key_exists('short', $text)) { + $msg_short_len = strlen(utf8_decode($text['short'])); + debug_log($msg_short_len, 'Raid poll short message length:'); + // Message short enough? + if($msg_short_len >= 1024) { + // Use full text and reset text to true regardless of prior value + $post_text = true; } - $keys = keys_vote($raid); + } else { + // Use full text and reset text to true regardless of prior value + $post_text = true; + } + $keys = keys_vote($raid); - // Telegram JSON array. - if($tg_json == false) $tg_json = []; + // Telegram JSON array. + if($tg_json == false) $tg_json = []; - foreach($chat_and_message as $chat_id_msg_id) { - $chat = $chat_id_msg_id['chat_id']; - $message = $chat_id_msg_id['message_id']; - $type = $chat_id_msg_id['type']; - if ($type == 'poll_text') { - $raid_picture_hide_level = explode(",",$config->RAID_PICTURE_HIDE_LEVEL); - $raid_picture_hide_pokemon = explode(",",$config->RAID_PICTURE_HIDE_POKEMON); + foreach($chat_and_message as $chat_id_msg_id) { + $chat = $chat_id_msg_id['chat_id']; + $message = $chat_id_msg_id['message_id']; + $type = $chat_id_msg_id['type']; + if ($type == 'poll_text') { + $raid_picture_hide_level = explode(",",$config->RAID_PICTURE_HIDE_LEVEL); + $raid_picture_hide_pokemon = explode(",",$config->RAID_PICTURE_HIDE_POKEMON); - // If poll type was text, and RAID_PICUTRE_AUTO_EXTEND is set true in config, we most likely want to update the poll with the short message - // Exceptions are: inline poll (chat = null) and events with raid picture hidden - if($config->RAID_PICTURE && $config->RAID_PICTURE_AUTOEXTEND && $raid['event_hide_raid_picture'] != 1 && $chat != null && !in_array($raid['level'], $raid_picture_hide_level) && !in_array($raid['pokemon'], $raid_picture_hide_pokemon) && !in_array($raid['pokemon'].'-'.$raid['pokemon_form'], $raid_picture_hide_pokemon)) { - $tg_json[] = editMessageText($message, $text['short'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); - }else { - $tg_json[] = editMessageText($message, $text['full'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); - } - }else { - require_once(LOGIC_PATH . '/raid_picture.php'); - if($type == 'poll_photo') { - // If the poll message gets too long, we'll replace it with regular text based poll - if($post_text == true) { - // Delete raid picture and caption. - $tg_json[] = delete_message($chat, $message, true); - my_query("DELETE FROM cleanup WHERE chat_id = '{$chat}' AND message_id = '{$message}'"); + // If poll type was text, and RAID_PICUTRE_AUTO_EXTEND is set true in config, we most likely want to update the poll with the short message + // Exceptions are: inline poll (chat = null) and events with raid picture hidden + if($config->RAID_PICTURE && $config->RAID_PICTURE_AUTOEXTEND && $raid['event_hide_raid_picture'] != 1 && $chat != null && !in_array($raid['level'], $raid_picture_hide_level) && !in_array($raid['pokemon'], $raid_picture_hide_pokemon) && !in_array($raid['pokemon'].'-'.$raid['pokemon_form'], $raid_picture_hide_pokemon)) { + $tg_json[] = editMessageText($message, $text['short'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); + }else { + $tg_json[] = editMessageText($message, $text['full'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); + } + }else { + require_once(LOGIC_PATH . '/raid_picture.php'); + if($type == 'poll_photo') { + // If the poll message gets too long, we'll replace it with regular text based poll + if($post_text == true) { + // Delete raid picture and caption. + $tg_json[] = delete_message($chat, $message, true); + my_query("DELETE FROM cleanup WHERE chat_id = '{$chat}' AND message_id = '{$message}'"); - $media_content = get_raid_picture($raid, true); - $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache - // Resend raid poll as text message. - send_photo($chat, $media_content[1], $media_content[0], '', [], [], false, $raid); - send_message($chat, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); - } else { - $media_content = get_raid_picture($raid); - // Edit the picture and caption - if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { - $tg_json[] = editMessageMedia($message, $text['short'], $media_content[1], $media_content[0], $keys, $chat, ['disable_web_page_preview' => 'true'], true, $raid); - }else { - // Edit the caption. - $tg_json[] = editMessageCaption($message, $text['short'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); - } - } - }else if ($type == 'photo' && $update_photo) { - $media_content = get_raid_picture($raid, 1); - $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache - if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { - $tg_json[] = editMessageMedia($message, '', $media_content[1], $media_content[0], false, $chat, false, true, $raid); - } - } + $media_content = get_raid_picture($raid, true); + $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache + // Resend raid poll as text message. + send_photo($chat, $media_content[1], $media_content[0], '', [], [], false, $raid); + send_message($chat, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); + } else { + $media_content = get_raid_picture($raid); + // Edit the picture and caption + if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { + $tg_json[] = editMessageMedia($message, $text['short'], $media_content[1], $media_content[0], $keys, $chat, ['disable_web_page_preview' => 'true'], true, $raid); + }else { + // Edit the caption. + $tg_json[] = editMessageCaption($message, $text['short'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); + } + } + }else if ($type == 'photo' && $update_photo) { + $media_content = get_raid_picture($raid, 1); + $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache + if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { + $tg_json[] = editMessageMedia($message, '', $media_content[1], $media_content[0], false, $chat, false, true, $raid); } + } } - return $tg_json; + } + return $tg_json; } -?> \ No newline at end of file diff --git a/logic/weather_keys.php b/logic/weather_keys.php index 43272bb9..96718a8d 100644 --- a/logic/weather_keys.php +++ b/logic/weather_keys.php @@ -8,65 +8,63 @@ */ function weather_keys($pokedex_id, $action, $arg) { - // Get the type, level and cp - $data = explode("-", $arg); - $weather_add = $data[0] . '-'; - $weather_value = $data[1]; + // Get the type, level and cp + $data = explode("-", $arg); + $weather_add = $data[0] . '-'; + $weather_value = $data[1]; - // Save and reset values - $save_arg = 'save-' . $weather_value; - $reset_arg = $weather_add . '0'; + // Save and reset values + $save_arg = 'save-' . $weather_value; + $reset_arg = $weather_add . '0'; - // Init empty keys array. - $keys = []; + // Init empty keys array. + $keys = []; - // Max amount of weathers a pokemon raid boss can have is 3 which means 999 - // Keys will be shown up to 99 and when user is adding one more weather we exceed 99, so we remove the keys then - // This means we do not exceed the max amout of 3 weathers a pokemon can have :) - // And no, 99 is not a typo if you read my comment above :P - if($weather_value <= 99) { - // Get last number from weather array - end($GLOBALS['weather']); - $last = key($GLOBALS['weather']); + // Max amount of weathers a pokemon raid boss can have is 3 which means 999 + // Keys will be shown up to 99 and when user is adding one more weather we exceed 99, so we remove the keys then + // This means we do not exceed the max amout of 3 weathers a pokemon can have :) + // And no, 99 is not a typo if you read my comment above :P + if($weather_value <= 99) { + // Get last number from weather array + end($GLOBALS['weather']); + $last = key($GLOBALS['weather']); - // Add buttons for each weather. - for ($i = 1; $i <= $last; $i = $i + 1) { - // Get length of arg and split arg - $weather_value_length = strlen((string)$weather_value); - $weather_value_string = str_split((string)$weather_value); + // Add buttons for each weather. + for ($i = 1; $i <= $last; $i = $i + 1) { + // Get length of arg and split arg + $weather_value_length = strlen((string)$weather_value); + $weather_value_string = str_split((string)$weather_value); - // Continue if weather got already selected - if($weather_value_length == 1 && $weather_value == $i) continue; - if($weather_value_length == 2 && $weather_value_string[0] == $i) continue; - if($weather_value_length == 2 && $weather_value_string[1] == $i) continue; + // Continue if weather got already selected + if($weather_value_length == 1 && $weather_value == $i) continue; + if($weather_value_length == 2 && $weather_value_string[0] == $i) continue; + if($weather_value_length == 2 && $weather_value_string[1] == $i) continue; - // Set new weather. - $new_weather = $weather_add . ($weather_value == 0 ? '' : $weather_value) . $i; + // Set new weather. + $new_weather = $weather_add . ($weather_value == 0 ? '' : $weather_value) . $i; - // Set keys. - $keys[] = array( - 'text' => $GLOBALS['weather'][$i], - 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_weather - ); - } + // Set keys. + $keys[] = array( + 'text' => $GLOBALS['weather'][$i], + 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_weather + ); } + } - // Get the inline key array. - $keys = inline_key_array($keys, 3); + // Get the inline key array. + $keys = inline_key_array($keys, 3); - // Save and Reset key - $keys[] = array( - array( - 'text' => EMOJI_DISK, - 'callback_data' => $pokedex_id . ':' . $action . ':' . $save_arg - ), - array( - 'text' => getTranslation('reset'), - 'callback_data' => $pokedex_id . ':' . $action . ':' . $reset_arg - ) - ); + // Save and Reset key + $keys[] = array( + array( + 'text' => EMOJI_DISK, + 'callback_data' => $pokedex_id . ':' . $action . ':' . $save_arg + ), + array( + 'text' => getTranslation('reset'), + 'callback_data' => $pokedex_id . ':' . $action . ':' . $reset_arg + ) + ); - return $keys; + return $keys; } - -?> diff --git a/mods/bot_lang.php b/mods/bot_lang.php index 020e6bce..776b1c95 100644 --- a/mods/bot_lang.php +++ b/mods/bot_lang.php @@ -9,56 +9,53 @@ // Access check. $botUser->accessCheck($update, 'trainer'); - $keys = []; if($data['arg'] != '0') { - $query = " - UPDATE users - SET lang_manual = 1, - lang= :lang - WHERE user_id = :user_id - "; - $q = $dbh->prepare($query); - $q->execute([ - 'lang' => $data['arg'], - 'user_id' => $update['callback_query']['from']['id'] - ]); - $new_lang_internal = $languages[$data['arg']]; - $msg = getTranslation('new_lang_saved', $new_lang_internal); - $keys[] = [ - [ - 'text' => getTranslation('back', $new_lang_internal), - 'callback_data' => '0:trainer:0' - ], - [ - 'text' => getTranslation('done', $new_lang_internal), - 'callback_data' => '0:exit:1' - ] - ]; - $callback_msg = $msg; + $query = my_query(' + UPDATE users + SET lang_manual = 1, + lang= :lang + WHERE user_id = :user_id + ',[ + 'lang' => $data['arg'], + 'user_id' => $update['callback_query']['from']['id'], + ]); + $new_lang_internal = $languages[$data['arg']]; + $msg = getTranslation('new_lang_saved', $new_lang_internal); + $keys[] = [ + [ + 'text' => getTranslation('back', $new_lang_internal), + 'callback_data' => '0:trainer:0' + ], + [ + 'text' => getTranslation('done', $new_lang_internal), + 'callback_data' => '0:exit:1' + ] + ]; + $callback_msg = $msg; } else { - $displayedLanguages = []; - foreach($languages as $lang_tg => $lang_internal) { - if(in_array($lang_internal, $displayedLanguages)) continue; - $keys[][] = [ - 'text' => getTranslation('lang_name', $lang_internal), - 'callback_data' => '0:bot_lang:'.$lang_tg - ]; - $displayedLanguages[] = $lang_internal; - } - $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] + $displayedLanguages = []; + foreach($languages as $lang_tg => $lang_internal) { + if(in_array($lang_internal, $displayedLanguages)) continue; + $keys[][] = [ + 'text' => getTranslation('lang_name', $lang_internal), + 'callback_data' => '0:bot_lang:'.$lang_tg ]; - $msg = getTranslation('change_lang').':'; - $callback_msg = getTranslation('change_lang'); + $displayedLanguages[] = $lang_internal; + } + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:trainer:0' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ]; + $msg = getTranslation('change_lang').':'; + $callback_msg = getTranslation('change_lang'); } // Answer callback. @@ -66,9 +63,3 @@ // Edit message. edit_message($update, $msg, $keys, false); - -// Exit. -$dbh = null; -exit(); - -?> \ No newline at end of file diff --git a/mods/change_trainercode.php b/mods/change_trainercode.php index b8aa396b..6941ae90 100644 --- a/mods/change_trainercode.php +++ b/mods/change_trainercode.php @@ -7,37 +7,35 @@ $trainercode = preg_replace('/\D/', '', $update['message']['text']); // Check that Code is 12 digits long -if(strlen($trainercode)==12){ - // Store new Trainercode to DB - my_query( - " - UPDATE users - SET trainercode = '{$trainercode}' - WHERE user_id = {$target_user_id} - " - ); - - // Remove back button from previous message to avoid confusion - edit_message_keyboard($modifiers['old_message_id'], [], $target_user_id); - - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; - - // confirm Trainercode-Change - send_message($target_user_id, getTranslation('trainercode_success').' '.$trainercode.'', $keys); -}else{ - // Trainer Code got unallowed Chars -> Error-Message - send_message($target_user_id, getTranslation('trainercode_fail')); - exit(); +if(strlen($trainercode) != 12){ + // Trainer Code got unallowed Chars -> Error-Message + send_message($target_user_id, getTranslation('trainercode_fail')); + exit(); } +// Store new Trainercode to DB +my_query(' + UPDATE users + SET trainercode = ? + WHERE user_id = ? + ', [$trainercode, $target_user_id] +); + +// Remove back button from previous message to avoid confusion +edit_message_keyboard($modifiers['old_message_id'], [], $target_user_id); + +// Create the keys. +$keys = [ + [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:trainer:0' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ] +]; + +// confirm Trainercode-Change +send_message($target_user_id, getTranslation('trainercode_success').' '.$trainercode.'', $keys); diff --git a/mods/change_trainername.php b/mods/change_trainername.php index 7d0abb4a..5c865ea6 100644 --- a/mods/change_trainername.php +++ b/mods/change_trainername.php @@ -5,40 +5,37 @@ $returnValue = preg_match('/^[A-Za-z0-9]{0,15}$/', $update['message']['text']); // Only numbers and alphabetic character allowed -if($returnValue){ - $trainername = $update['message']['text']; - // Store new Gamer-Name to DB - my_query( - " - UPDATE users - SET trainername = '{$trainername}', - display_name = IF(trainername is null, 0, 1) - WHERE user_id = {$userid} - " - ); - - // Remove back button from previous message to avoid confusion - edit_message_keyboard($modifiers['old_message_id'], [], $userid); +if(!$returnValue){ + // Trainer Name got unallowed Chars -> Error-Message + send_message($userid, getTranslation('trainername_fail')); + exit(); +} +$trainername = $update['message']['text']; +// Store new Gamer-Name to DB +my_query(' + UPDATE users + SET trainername = ?, + display_name = IF(trainername is null, 0, 1) + WHERE user_id = ? + ', [$trainername, $userid] +); - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; +// Remove back button from previous message to avoid confusion +edit_message_keyboard($modifiers['old_message_id'], [], $userid); - // confirm Name-Change - send_message($userid, getTranslation('trainername_success').' '.$trainername.'', $keys); -}else{ - // Trainer Name got unallowed Chars -> Error-Message - send_message($userid, getTranslation('trainername_fail')); - exit(); -} +// Create the keys. +$keys = [ + [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:trainer:0' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ] +]; +// confirm Name-Change +send_message($userid, getTranslation('trainername_success').' '.$trainername.'', $keys); diff --git a/mods/code.php b/mods/code.php index 25ae1f44..bdc6addb 100644 --- a/mods/code.php +++ b/mods/code.php @@ -1,6 +1,7 @@ ' . getTranslation('code_send') . '' . CR . CR; - $msg .= getTranslation('group_code') . ':' . CR; - $msg .= $group_code; - } else { - // Init empty keys array. - $keys = []; - - // Back and abort. - $keys[] = [ - [ - 'text' => EMOJI_INVITE, - 'callback_data' => $raid_id . ':code:public-send' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - - // Build callback message string. - $callback_response = 'OK'; - - // Set the message. - $msg .= '' . getTranslation('start_raid_now') . ':' . CR . CR; - } + // Log + debug_log('Public raid group'); + if($arg == 'public-send') { + // Groupcode + $group_code = getTranslation('start_raid_public') . SP . getTranslation('no_group_code'); + + // Send code via alarm function + $tg_json = alarm($raid_id,$update['callback_query']['from']['id'],'group_code_public',$group_code, $tg_json); + + // Init empty keys array. + $keys = []; + + // Build callback message string. + $callback_response = getTranslation('code_send'); + + // Set the message. + $msg .= '' . getTranslation('code_send') . '' . CR . CR; + $msg .= getTranslation('group_code') . ':' . CR; + $msg .= $group_code; + } else { + // Init empty keys array. + $keys = []; + + // Back and abort. + $keys[] = [ + [ + 'text' => EMOJI_INVITE, + 'callback_data' => $raid_id . ':code:public-send' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; + + // Build callback message string. + $callback_response = 'OK'; + + // Set the message. + $msg .= '' . getTranslation('start_raid_now') . ':' . CR . CR; + } } else { - // Get the current code - $data = explode("-", $arg); - $c1 = $data[0]; - $c2 = $data[1]; - $c3 = $data[2]; - - // Get pokemon names. - $p1 = ($c1 > 0) ? get_local_pokemon_name($c1, 0) : ''; - $p2 = ($c2 > 0) ? get_local_pokemon_name($c2, 0) : ''; - $p3 = ($c3 > 0) ? get_local_pokemon_name($c3, 0) : ''; - - // Action to do: Ask to send or add code? - $action = $data[3]; - - // Log - debug_log('Code #1: ' . $c1 . SP . '(' . $p1 . ')'); - debug_log('Code #2: ' . $c2 . SP . '(' . $p2 . ')'); - debug_log('Code #3: ' . $c3 . SP . '(' . $p3 . ')'); - debug_log('Action: ' . $action); - - // Add digits to cp - if($action == 'add') { - // Init empty keys array. - $keys = []; - - // Get the keys. - $keys = group_code_keys($raid_id, 'code', $arg); - - // Back and abort. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - - // Build callback message string. - $callback_response = 'OK'; - - // Set the message. - $msg .= '' . getTranslation('group_code') . ':' . CR; - $msg .= ($c1 > 0) ? ($p1 . CR) : ''; - $msg .= ($c2 > 0) ? ($p2 . CR) : ''; - $msg .= ($c3 > 0) ? ($p3 . CR . CR . '' . getTranslation('start_raid_now') . ':' . CR) : ''; - - // Send code to users - } else if($action == 'send') { - // Groupcode - $group_code = $p1 . '--' . SP; - $group_code .= $p2 . '--' . SP; - $group_code .= $p3 . CR; - - // Send code via alarm function - $tg_json = alarm($raid_id,$update['callback_query']['from']['id'],'group_code_private',$group_code, $tg_json); - - // Init empty keys array. - $keys = []; - - // Build callback message string. - $callback_response = getTranslation('code_send'); - - // Set the message. - $msg .= '' . getTranslation('code_send') . '' . CR . CR; - $msg .= getTranslation('group_code') . ':' . CR; - $msg .= $group_code; - } + // Get the current code + $data = explode("-", $arg); + $c1 = $data[0]; + $c2 = $data[1]; + $c3 = $data[2]; + + // Get pokemon names. + $p1 = ($c1 > 0) ? get_local_pokemon_name($c1, 0) : ''; + $p2 = ($c2 > 0) ? get_local_pokemon_name($c2, 0) : ''; + $p3 = ($c3 > 0) ? get_local_pokemon_name($c3, 0) : ''; + + // Action to do: Ask to send or add code? + $action = $data[3]; + + // Log + debug_log('Code #1: ' . $c1 . SP . '(' . $p1 . ')'); + debug_log('Code #2: ' . $c2 . SP . '(' . $p2 . ')'); + debug_log('Code #3: ' . $c3 . SP . '(' . $p3 . ')'); + debug_log('Action: ' . $action); + + // Add digits to cp + if($action == 'add') { + require_once(LOGIC_PATH . '/group_code_keys.php'); + // Init empty keys array. + $keys = []; + + // Get the keys. + $keys = group_code_keys($raid_id, 'code', $arg); + + // Back and abort. + $keys[] = [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; + + // Build callback message string. + $callback_response = 'OK'; + + // Set the message. + $msg .= '' . getTranslation('group_code') . ':' . CR; + $msg .= ($c1 > 0) ? ($p1 . CR) : ''; + $msg .= ($c2 > 0) ? ($p2 . CR) : ''; + $msg .= ($c3 > 0) ? ($p3 . CR . CR . '' . getTranslation('start_raid_now') . ':' . CR) : ''; + + // Send code to users + } else if($action == 'send') { + // Groupcode + $group_code = $p1 . '--' . SP; + $group_code .= $p2 . '--' . SP; + $group_code .= $p3 . CR; + + // Send code via alarm function + $tg_json = alarm($raid_id,$update['callback_query']['from']['id'],'group_code_private',$group_code, $tg_json); + + // Init empty keys array. + $keys = []; + + // Build callback message string. + $callback_response = getTranslation('code_send'); + + // Set the message. + $msg .= '' . getTranslation('code_send') . '' . CR . CR; + $msg .= getTranslation('group_code') . ':' . CR; + $msg .= $group_code; + } } // Answer callback. @@ -153,6 +155,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/code_start.php b/mods/code_start.php index 8a8b8540..9b73e25f 100644 --- a/mods/code_start.php +++ b/mods/code_start.php @@ -23,49 +23,47 @@ // Raid ended already. if ($end_time > $now) { - // Set text and keys. - $gym_name = $raid['gym_name']; - if(empty($gym_name)) { - $gym_name = ''; - } + // Set text and keys. + $gym_name = $raid['gym_name']; + if(empty($gym_name)) { + $gym_name = ''; + } - $text .= $gym_name . CR; - $raid_day = dt2date($raid['start_time']); - $now = utcnow(); - $today = dt2date($now); - $start = dt2time($raid['start_time']); - $end = dt2time($raid['end_time']); - $text .= get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . SP . '-' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; + $text .= $gym_name . CR; + $raid_day = dt2date($raid['start_time']); + $now = utcnow(); + $today = dt2date($now); + $start = dt2time($raid['start_time']); + $end = dt2time($raid['end_time']); + $text .= get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . SP . '-' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; - // Add exit key. - $keys = [ - [ - [ - 'text' => getTranslation('start_raid_public'), - 'callback_data' => $raid['id'] . ':code:public-unconfirmed' - ], - [ - 'text' => getTranslation('start_raid_private'), - 'callback_data' => $raid['id'] . ':code:0-0-0-add' - ] - ], - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + // Add exit key. + $keys = [ + [ + [ + 'text' => getTranslation('start_raid_public'), + 'callback_data' => $raid['id'] . ':code:public-unconfirmed' + ], + [ + 'text' => getTranslation('start_raid_private'), + 'callback_data' => $raid['id'] . ':code:0-0-0-add' + ] + ], + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; - // Build message. - $msg = '' . getTranslation('start_raid_now') . ':' . CR . CR; - $msg .= $text; + // Build message. + $msg = '' . getTranslation('start_raid_now') . ':' . CR . CR; + $msg .= $text; } else { - $msg = '' . getTranslation('group_code_share') . ':' . CR; - $msg .= '' . getTranslation('no_active_raids_found') . ''; + $msg = '' . getTranslation('group_code_share') . ':' . CR; + $msg .= '' . getTranslation('no_active_raids_found') . ''; } // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); - -?> diff --git a/mods/delete_scheduled_entry.php b/mods/delete_scheduled_entry.php index 6166880e..990b94ab 100644 --- a/mods/delete_scheduled_entry.php +++ b/mods/delete_scheduled_entry.php @@ -8,28 +8,27 @@ $id = $data['id']; if($arg == 1) { - my_query("DELETE FROM raid_bosses WHERE id='".$id."'"); - include(ROOT_PATH . '/mods/pokedex_list_raids.php'); - exit(); -}else { - $query = my_query("SELECT pokedex_id, pokemon_form_id, date_start, date_end, raid_level FROM raid_bosses WHERE id ='" . $id . "' LIMIT 1"); - $pokemon = $query->fetch(); - $msg = getTranslation('delete_scheduled_confirmation') . CR . CR; - $msg .= $pokemon['date_start'] . ' - ' . $pokemon['date_end'] . ':' . CR; - $msg .= getTranslation($pokemon['raid_level'] . 'stars') . ': '; - $msg .= get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']); - - $keys[] = [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => $id . ':' . 'delete_scheduled_entry' . ':1' - ], - [ - 'text' => getTranslation('no'), - 'callback_data' => '0:pokedex_list_raids:0' - ], - ]; + my_query("DELETE FROM raid_bosses WHERE id='".$id."'"); + include(ROOT_PATH . '/mods/pokedex_list_raids.php'); + exit(); } +$query = my_query('SELECT pokedex_id, pokemon_form_id, date_start, date_end, raid_level FROM raid_bosses WHERE id = ? LIMIT 1', [$id]); +$pokemon = $query->fetch(); +$msg = getTranslation('delete_scheduled_confirmation') . CR . CR; +$msg .= $pokemon['date_start'] . ' - ' . $pokemon['date_end'] . ':' . CR; +$msg .= getTranslation($pokemon['raid_level'] . 'stars') . ': '; +$msg .= get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']); + +$keys[] = [ + [ + 'text' => getTranslation('yes'), + 'callback_data' => $id . ':' . 'delete_scheduled_entry' . ':1' + ], + [ + 'text' => getTranslation('no'), + 'callback_data' => '0:pokedex_list_raids:0' + ], +]; // Build callback message string. $callback_response = 'OK'; @@ -45,8 +44,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); - -?> diff --git a/mods/edit_date.php b/mods/edit_date.php index 6084c4d6..25bf48ff 100644 --- a/mods/edit_date.php +++ b/mods/edit_date.php @@ -27,65 +27,65 @@ // Received: Year-Month-Day / 1970-01-01 / 2x "-" if (substr_count($raid_time, '-') == 2) { - debug_log('Generating buttons for each hour of the day'); - // Buttons for each hour - for ($i = 0; $i <= 23; $i = $i + 1) { - // Create the keys. - $keys[] = array( - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => str_pad($i, 2, '0', STR_PAD_LEFT) . ':xx', - 'callback_data' => $id . ':edit_date:' . $arg . ' ' . str_pad($i, 2, '0', STR_PAD_LEFT) . '-' - ); - } - // Set keys count and message. - $keys_count = 4; - $msg = getTranslation('raid_select_hour'); + debug_log('Generating buttons for each hour of the day'); + // Buttons for each hour + for ($i = 0; $i <= 23; $i = $i + 1) { + // Create the keys. + $keys[] = array( + // Just show the time, no text - not everyone has a phone or tablet with a large screen... + 'text' => str_pad($i, 2, '0', STR_PAD_LEFT) . ':xx', + 'callback_data' => $id . ':edit_date:' . $arg . ' ' . str_pad($i, 2, '0', STR_PAD_LEFT) . '-' + ); + } + // Set keys count and message. + $keys_count = 4; + $msg = getTranslation('raid_select_hour'); // Received: Year-Month-Day Hour- / 1970-01-01 00- / 3x "-" } else if (substr_count($raid_time, '-') == 3) { - debug_log('Generating buttons for minute of the hour'); - $hour = explode(" ", $raid_time); - $hour = $hour[1]; - // Buttons for each minute - for ($i = 0; $i <= 45; $i = $i + 15) { - // Create the keys. - $keys[] = array( - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => substr($hour, 0, -1) . ':' . str_pad($i, 2, '0', STR_PAD_LEFT), - 'callback_data' => $id . ':edit_date:' . $arg . str_pad($i, 2, '0', STR_PAD_LEFT) . '-00' - ); - } - // Set keys count and message. - $keys_count = 4; - $msg = getTranslation('raid_select_start_time'); -// Received: Year-Month-Day Hour-Minute-Second / 1970-01-01 00-00-00 / 4x "-" -} else if (substr_count($raid_time, '-') == 4) { - debug_log('Received the following date for the raid: ' . $raid_time); - - // Format date, e.g 14 April 2019, 15:15h - $tz = $config->TIMEZONE; - $tz_raid_time = DateTimeImmutable::createFromFormat('Y-m-d H-i-s', $raid_time, new DateTimeZone($tz)); - $date_tz = $tz_raid_time->format('Y-m-d'); - $text_split = explode('-', $date_tz); - $text_day = $text_split[2]; - $text_month = getTranslation('month_' . $text_split[1]); - $text_year = $text_split[0]; - $time_tz = $tz_raid_time->format('H:i') . 'h'; - - // Raid time in UTC - $utc_raid_time = $tz_raid_time->setTimezone(new DateTimeZone('UTC')); - $utc_raid_time = $utc_raid_time->format('Y-m-d H-i-s'); - debug_log('Converting date to UTC to store in database'); - debug_log('UTC date for the raid: ' . $utc_raid_time); - debug_log('Waiting for confirmation to save the raid'); - - // Adding button to continue with next step in raid creation + debug_log('Generating buttons for minute of the hour'); + $hour = explode(" ", $raid_time); + $hour = $hour[1]; + // Buttons for each minute + for ($i = 0; $i <= 45; $i = $i + 15) { + // Create the keys. $keys[] = array( - 'text' => getTranslation('next'), - 'callback_data' => $id . ':edit_time:' . $event_id . ','. $raid_level . ',' . $pokemon_id . ',' . $utc_raid_time . ',X,0' + // Just show the time, no text - not everyone has a phone or tablet with a large screen... + 'text' => substr($hour, 0, -1) . ':' . str_pad($i, 2, '0', STR_PAD_LEFT), + 'callback_data' => $id . ':edit_date:' . $arg . str_pad($i, 2, '0', STR_PAD_LEFT) . '-00' ); - - // Set message. - $msg = getTranslation('start_date_time') . ':' . CR .'' . $text_day . SP . $text_month . SP . $text_year . ',' . SP . $time_tz . ''; + } + // Set keys count and message. + $keys_count = 4; + $msg = getTranslation('raid_select_start_time'); +// Received: Year-Month-Day Hour-Minute-Second / 1970-01-01 00-00-00 / 4x "-" +} else if (substr_count($raid_time, '-') == 4) { + debug_log('Received the following date for the raid: ' . $raid_time); + + // Format date, e.g 14 April 2019, 15:15h + $tz = $config->TIMEZONE; + $tz_raid_time = DateTimeImmutable::createFromFormat('Y-m-d H-i-s', $raid_time, new DateTimeZone($tz)); + $date_tz = $tz_raid_time->format('Y-m-d'); + $text_split = explode('-', $date_tz); + $text_day = $text_split[2]; + $text_month = getTranslation('month_' . $text_split[1]); + $text_year = $text_split[0]; + $time_tz = $tz_raid_time->format('H:i') . 'h'; + + // Raid time in UTC + $utc_raid_time = $tz_raid_time->setTimezone(new DateTimeZone('UTC')); + $utc_raid_time = $utc_raid_time->format('Y-m-d H-i-s'); + debug_log('Converting date to UTC to store in database'); + debug_log('UTC date for the raid: ' . $utc_raid_time); + debug_log('Waiting for confirmation to save the raid'); + + // Adding button to continue with next step in raid creation + $keys[] = array( + 'text' => getTranslation('next'), + 'callback_data' => $id . ':edit_time:' . $event_id . ','. $raid_level . ',' . $pokemon_id . ',' . $utc_raid_time . ',X,0' + ); + + // Set message. + $msg = getTranslation('start_date_time') . ':' . CR .'' . $text_day . SP . $text_month . SP . $text_year . ',' . SP . $time_tz . ''; } // Get the inline key array. @@ -96,10 +96,10 @@ // Back key id, action and arg if(substr_count($raid_time, '-') == 1 || substr_count($raid_time, '-') == 4) { - $back_id = $id; - $back_action = 'edit_starttime'; - $back_arg = $arg; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); + $back_id = $id; + $back_action = 'edit_starttime'; + $back_arg = $arg; + $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); } $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); @@ -122,6 +122,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/edit_event.php b/mods/edit_event.php index b6aa75b5..c28523b3 100644 --- a/mods/edit_event.php +++ b/mods/edit_event.php @@ -1,6 +1,7 @@ accessCheck($update, 'event-raids', true); // Get the keys. -$keys = keys_event($gym_id_plus_letter, "edit_event_raidlevel", $admin_access); +$keys = keys_event($gym_id_plus_letter, 'edit_event_raidlevel', $admin_access); // No keys found. if (!$keys) { - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + $keys = [ + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } else { - // Back key id, action and arg - $back_id_arg = explode(',', $gym_id_plus_letter); - $back_id = $back_id_arg[1]; - $back_action = 'edit_raidlevel'; - $back_arg = $back_id_arg[0]; - - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $back_arg, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - - // Merge keys. - $keys = array_merge($keys, $nav_keys); + // Back key id, action and arg + $back_id_arg = explode(',', $gym_id_plus_letter); + $back_id = $back_id_arg[1]; + $back_action = 'edit_raidlevel'; + $back_arg = $back_id_arg[0]; + + // Add navigation keys. + $nav_keys = []; + $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); + $nav_keys[] = universal_inner_key($nav_keys, $back_arg, 'exit', '2', getTranslation('abort')); + $nav_keys = inline_key_array($nav_keys, 2); + + // Merge keys. + $keys = array_merge($keys, $nav_keys); } // Build callback message string. @@ -60,6 +61,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); \ No newline at end of file diff --git a/mods/edit_event_note.php b/mods/edit_event_note.php index 5ceb9fba..9705cef7 100644 --- a/mods/edit_event_note.php +++ b/mods/edit_event_note.php @@ -1,19 +1,20 @@ $raid_id,"old_message_id"=>$update['callback_query']['message']['message_id'])); // Save the raid id and the message id to db so we can delete it later - $handler = "save_event_note"; // call for mods/save_event_note.php after user posts the answer - - my_query("INSERT INTO user_input SET user_id='{$userid}', modifiers='{$modifiers}', handler='{$handler}'"); -}elseif($mode == "cancel") { - my_query("DELETE FROM user_input WHERE user_id='{$userid}'"); - $data['arg'] = 0; - require_once("edit_save.php"); +if($mode == 'edit') { + $msg.= getTranslation('event_note_edit') . ': '; + + // Create an entry to user_input table + $modifiers = json_encode(array("id"=>$raid_id,"old_message_id"=>$update['callback_query']['message']['message_id'])); // Save the raid id and the message id to db so we can delete it later + $handler = "save_event_note"; // call for mods/save_event_note.php after user posts the answer + + my_query('INSERT INTO user_input SET user_id=:userId, modifiers=:modifiers, handler=:handler', ['userId' => $userid, 'modifiers' => $modifiers, 'handler' => $handler]); +}elseif($mode == 'cancel') { + my_query('DELETE FROM user_input WHERE user_id = ?', [$userid]); + $data['arg'] = 0; + require_once('edit_save.php'); }else { - if($raid['event'] == EVENT_ID_EX) { - $event_name = getTranslation('Xstars'); - }else { - $q = my_query("SELECT * FROM events WHERE id='{$raid['event']}'"); - $res = $q->fetch(); - $event_name = $res['name']; - } + if($raid['event'] == EVENT_ID_EX) { + $event_name = getTranslation('Xstars'); + }else { + $q = my_query('SELECT name FROM events WHERE id = ?', [$raid['event']]); + $res = $q->fetch(); + $event_name = $res['name']; + } - $msg.= getTranslation("event") . ": ".$event_name."".CR; - $msg.= getTranslation("event_add_note_description"); - - // Create an entry to user_input table - $modifiers = json_encode(array("id"=>$raid_id,"old_message_id"=>$update['callback_query']['message']['message_id'])); // Save the raid id and the message id to db so we can delete it later - $handler = "save_event_note"; // call for mods/save_event_note.php after user posts the answer - - my_query("INSERT INTO user_input SET user_id='{$userid}', modifiers='{$modifiers}', handler='{$handler}'"); + $msg.= getTranslation('event') . ': ' . $event_name . '' . CR; + $msg.= getTranslation('event_add_note_description'); + + // Create an entry to user_input table + $modifiers = json_encode(array('id'=>$raid_id, 'old_message_id' => $update['callback_query']['message']['message_id'])); // Save the raid id and the message id to db so we can delete it later + $handler = 'save_event_note'; // call for mods/save_event_note.php after user posts the answer + + my_query('INSERT INTO user_input SET user_id=:userId, modifiers = :modifiers, handler = :handler', ['userId' => $userid, 'modifiers' => $modifiers, 'handler' => $handler]); } $keys[] = [ - [ - 'text' => getTranslation('cancel'), - 'callback_data' => $raid_id . ':edit_event_note:'. $arg[0] . ',cancel' - ] - ]; + [ + 'text' => getTranslation('cancel'), + 'callback_data' => $raid_id . ':edit_event_note:'. $arg[0] . ',cancel' + ] +]; // Answer callback. answerCallbackQuery($update['callback_query']['id'], $callback_response); // Edit message. edit_message($update, $msg, $keys, false); - -exit(); \ No newline at end of file diff --git a/mods/edit_event_raidlevel.php b/mods/edit_event_raidlevel.php index 69156d4a..346b6255 100644 --- a/mods/edit_event_raidlevel.php +++ b/mods/edit_event_raidlevel.php @@ -1,6 +1,8 @@ getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); + // Add navigation keys. + $nav_keys = []; + $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); + $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); + $nav_keys = inline_key_array($nav_keys, 2); + // Merge keys. + $keys = array_merge($keys, $nav_keys); } -// Get event info -$q = my_query("SELECT name, description FROM events WHERE id='{$event_id}' LIMIT 1"); +// Get event info +$q = my_query('SELECT name, description FROM events WHERE id = ? LIMIT 1', [$event_id]); $rs = $q->fetch(); // Build message. if($event_id == 'X') { - $msg = "".getTranslation('Xstars')."".CR; + $msg = "".getTranslation('Xstars')."".CR; }else { - $msg = "{$rs['name']}".CR."{$rs['description']}".CR; + $msg = '' . $rs['name'] . '' . CR . $rs['description'] . CR; } -$msg.= getTranslation('create_raid') . ': ' . (($gym['address']=="") ? $gym['gym_name'] : $gym['address']) . ''; +$msg.= getTranslation('create_raid') . ': ' . (($gym['address']=='') ? $gym['gym_name'] : $gym['address']) . ''; // Build callback message string. $callback_response = getTranslation('gym_saved'); @@ -76,7 +78,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); - diff --git a/mods/edit_pokemon.php b/mods/edit_pokemon.php index f9ee421e..b567806d 100644 --- a/mods/edit_pokemon.php +++ b/mods/edit_pokemon.php @@ -1,4 +1,5 @@ getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + $keys = [ + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } else { - if($event_id == "N") { - $back_id_arg = explode(',', $gym_id_plus_letter); - $back_id = $back_id_arg[1]; - $back_action = 'edit_raidlevel'; - $back_arg = $back_id_arg[0]; - }else { - $back_id = $gym_id_plus_letter; - $back_action = 'edit_event_raidlevel'; - $back_arg = $event_id; - } - - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $back_arg, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - - // Merge keys. - $keys = array_merge($keys, $nav_keys); + if($event_id == "N") { + $back_id_arg = explode(',', $gym_id_plus_letter); + $back_id = $back_id_arg[1]; + $back_action = 'edit_raidlevel'; + $back_arg = $back_id_arg[0]; + }else { + $back_id = $gym_id_plus_letter; + $back_action = 'edit_event_raidlevel'; + $back_arg = $event_id; + } + + // Add navigation keys. + $nav_keys = []; + $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); + $nav_keys[] = universal_inner_key($nav_keys, $back_arg, 'exit', '2', getTranslation('abort')); + $nav_keys = inline_key_array($nav_keys, 2); + + // Merge keys. + $keys = array_merge($keys, $nav_keys); } // Build callback message string. @@ -73,13 +74,10 @@ // Edit the message. if (isset($update['callback_query']['inline_message_id'])) { - $tg_json[] = editMessageText($update['callback_query']['inline_message_id'], getTranslation('select_raid_boss') . ':', $keys, NULL, false, true); + $tg_json[] = editMessageText($update['callback_query']['inline_message_id'], getTranslation('select_raid_boss') . ':', $keys, NULL, false, true); } else { - $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], getTranslation('select_raid_boss') . ':', $keys, $update['callback_query']['message']['chat']['id'], $keys, true); + $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], getTranslation('select_raid_boss') . ':', $keys, $update['callback_query']['message']['chat']['id'], $keys, true); } // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index a4de71f5..cb4593e5 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -1,6 +1,10 @@ 0) { - $keys = []; - $raid_id = $duplicate_id; - $raid = get_raid($raid_id); - $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); + $keys = []; + $raid_id = $duplicate_id; + $raid = get_raid($raid_id); + $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); - $keys = share_keys($raid_id, 'raid_share', $update, $raid['level']); + $keys = share_keys($raid_id, 'raid_share', $update, $raid['level']); - // Add keys for sharing the raid. - if(!empty($keys)) { - // Exit key - $keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); - } + // Add keys for sharing the raid. + if(!empty($keys)) { + // Exit key + $keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); + } - // Answer callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('raid_already_exists'), true); + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('raid_already_exists'), true); - // Edit the message. - $tg_json[] = edit_message($update, $msg, $keys, false, true); + // Edit the message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); - // Telegram multicurl request. - curl_json_multi_request($tg_json); + // Telegram multicurl request. + curl_json_multi_request($tg_json); - // Exit. - exit(); + // Exit. + exit(); } //Initialize admin rights table [ ex-raid , raid-event ] @@ -69,23 +73,23 @@ // No keys found. if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); + // Add navigation keys. + $nav_keys = []; + $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); + $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); + $nav_keys = inline_key_array($nav_keys, 2); + // Merge keys. + $keys = array_merge($keys, $nav_keys); } // Build message. @@ -102,7 +106,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); - diff --git a/mods/edit_save.php b/mods/edit_save.php index ca3a67c4..cda46a18 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -1,6 +1,7 @@ RAID_DURATION && $arg != 0) { - // Build query. - my_query( - " - UPDATE raids - SET end_time = DATE_ADD(start_time, INTERVAL {$arg} MINUTE) - WHERE id = {$id} - " - ); + // Build query. + my_query(' + UPDATE raids + SET end_time = DATE_ADD(start_time, INTERVAL ' . $arg . ' MINUTE) + WHERE id = :id + ', ['id' => $id] + ); } // Fast forward to raid sharing. if(substr_count($data['id'], ',') == 1) { - // Write to log. - debug_log('Doing a fast forward now!'); - debug_log('Changing data array first...'); - - // Reset data array - $data = []; - $data['id'] = $id; - $data['action'] = 'raid_share'; - $data['arg'] = $chat; - - // Write to log. - debug_log($data, '* NEW DATA= '); - - // Set module path by sent action name. - $module = ROOT_PATH . '/mods/raid_share.php'; - - // Write module to log. - debug_log($module); - - // Check if the module file exists. - if (file_exists($module)) { - // Dynamically include module file and exit. - include_once($module); - exit(); - } else { - info_log($module, 'Error! Fast forward failed as file does not exist:'); - exit(); - } + // Write to log. + debug_log('Doing a fast forward now!'); + debug_log('Changing data array first...'); + + // Reset data array + $data = []; + $data['id'] = $id; + $data['action'] = 'raid_share'; + $data['arg'] = $chat; + + // Write to log. + debug_log($data, '* NEW DATA= '); + + // Set module path by sent action name. + $module = ROOT_PATH . '/mods/raid_share.php'; + + // Write module to log. + debug_log($module); + + // Check if the module file exists. + if (file_exists($module)) { + // Dynamically include module file and exit. + include_once($module); + exit(); + } else { + info_log($module, 'Error! Fast forward failed as file does not exist:'); + exit(); + } } // Telegram JSON array. @@ -78,27 +78,27 @@ // Add delete to keys. $keys = [ + [ [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => $id . ':raids_delete:0' - ] + 'text' => getTranslation('delete'), + 'callback_data' => $id . ':raids_delete:0' ] + ] ]; // Check access level prior allowing to change raid time $admin_access = $botUser->accessCheck($update, 'raid-duration', true); if($admin_access) { - // Add time change to keys. - $keys_time = [ - [ - [ - 'text' => getTranslation('change_raid_duration'), - 'callback_data' => $id . ':edit_time:0,0,0,0,more,1' - ] - ] - ]; - $keys = array_merge($keys, $keys_time); + // Add time change to keys. + $keys_time = [ + [ + [ + 'text' => getTranslation('change_raid_duration'), + 'callback_data' => $id . ':edit_time:0,0,0,0,more,1' + ] + ] + ]; + $keys = array_merge($keys, $keys_time); } // Get raid times. @@ -107,21 +107,21 @@ // Get raid level. $raid_level = $raid['level']; -if($raid['event']!==NULL) { - if($raid['event_note']==NULL) { - $event_button_text = getTranslation("event_note_add"); - }else { - $event_button_text = getTranslation("event_note_edit"); - } - $keys_edit_event_note = [ - [ - [ - 'text' => $event_button_text, - 'callback_data' => $id . ':edit_event_note:0' - ] - ] - ]; - $keys = array_merge($keys, $keys_edit_event_note); +if($raid['event'] !== NULL) { + if($raid['event_note'] == NULL) { + $event_button_text = getTranslation("event_note_add"); + }else { + $event_button_text = getTranslation("event_note_edit"); + } + $keys_edit_event_note = [ + [ + [ + 'text' => $event_button_text, + 'callback_data' => $id . ':edit_event_note:0' + ] + ] + ]; + $keys = array_merge($keys, $keys_edit_event_note); } // Add keys to share. @@ -138,15 +138,15 @@ // Gym Name if(!empty($raid['gym_name']) && ($raid['gym_name'] == $user_id_tag)) { - $msg .= getTranslation('set_gym_name_and_team') . CR2; - $msg .= getTranslation('set_gym_name_command') . CR; + $msg .= getTranslation('set_gym_name_and_team') . CR2; + $msg .= getTranslation('set_gym_name_command') . CR; } // Build callback message string. if($arg == 0) { - $callback_response = 'OK'; + $callback_response = 'OK'; }else { - $callback_response = getTranslation('end_time') . ' ' . $data['arg'] . ' ' . getTranslation('minutes'); + $callback_response = getTranslation('end_time') . ' ' . $data['arg'] . ' ' . getTranslation('minutes'); } // Answer callback. @@ -157,6 +157,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index 964069b2..fbd4eb3e 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -17,9 +17,9 @@ $arg = ""; // Check for options. if (isset($arg_data[3])) -{ - // Switch time display ( min / clock ) - $arg = $arg_data[3]; +{ + // Switch time display ( min / clock ) + $arg = $arg_data[3]; } // Set the id. $gym_id_plus_letter = $data['id']; @@ -27,155 +27,155 @@ // Are we creating an event? if($event_id != 'N' or $raid_level == 9) { - // Init empty keys array. - $keys = []; - - // Current time from the user - // We let the user pick the raid date and time and convert to UTC afterwards in edit_date.php - $tz = $config->TIMEZONE; - $today = new DateTimeImmutable('now', new DateTimeZone($tz)); - - // Create date buttons. Two days for Elite Raids, 15 days for EX raids. - $days = ($raid_level == 9) ? 1 : 14; - for ($d = 0; $d <= $days; $d++) { - // Add day to today. - $today_plus_d = $today->add(new DateInterval("P".$d."D")); - - // Format date, e.g 14 April 2019 - $date_tz = $today_plus_d->format('Y-m-d'); - $text_split = explode('-', $date_tz); - $text_day = $text_split[2]; - $text_month = getTranslation('month_' . $text_split[1]); - $text_year = $text_split[0]; - - // Add keys. - $cb_date = $today_plus_d->format('Y-m-d'); - $keys[] = array( - 'text' => $text_day . SP . $text_month . SP . $text_year, - 'callback_data' => $gym_id_plus_letter . ':edit_date:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . $cb_date - ); - } + // Init empty keys array. + $keys = []; + + // Current time from the user + // We let the user pick the raid date and time and convert to UTC afterwards in edit_date.php + $tz = $config->TIMEZONE; + $today = new DateTimeImmutable('now', new DateTimeZone($tz)); + + // Create date buttons. Two days for Elite Raids, 15 days for EX raids. + $days = ($raid_level == 9) ? 1 : 14; + for ($d = 0; $d <= $days; $d++) { + // Add day to today. + $today_plus_d = $today->add(new DateInterval("P".$d."D")); + + // Format date, e.g 14 April 2019 + $date_tz = $today_plus_d->format('Y-m-d'); + $text_split = explode('-', $date_tz); + $text_day = $text_split[2]; + $text_month = getTranslation('month_' . $text_split[1]); + $text_year = $text_split[0]; + + // Add keys. + $cb_date = $today_plus_d->format('Y-m-d'); + $keys[] = array( + 'text' => $text_day . SP . $text_month . SP . $text_year, + 'callback_data' => $gym_id_plus_letter . ':edit_date:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . $cb_date + ); + } - // Get the inline key array. - $keys = inline_key_array($keys, 2); + // Get the inline key array. + $keys = inline_key_array($keys, 2); // Not creating an event } else { - if ($arg != "min" && $arg != "clock") { - // Get default raid duration style from config - if ($config->RAID_DURATION_CLOCK_STYLE) { - $arg = "clock"; - } else { - $arg = "min"; - } - } - - // Init empty keys array. - $keys = []; - - // Now - $now = utcnow(); - - if ($arg == "min") { - // Set switch view. - $switch_text = getTranslation('raid_starts_when_clocktime_view'); - $switch_view = "clock"; - $key_count = 5; - - for ($i = 1; $i <= $config->RAID_EGG_DURATION; $i = $i + 1) { - // Create new DateTime object, add minutes and convert back to string. - $now_plus_i = new DateTime($now, new DateTimeZone('UTC')); - $now_plus_i->add(new DateInterval('PT'.$i.'M')); - $now_plus_i = $now_plus_i->format("Y-m-d H:i:s"); - // Create the keys. - $keys[] = array( - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT), - 'callback_data' => $gym_id_plus_letter . ':edit_time:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . utctime($now_plus_i,"H-i") - ); - } + if ($arg != "min" && $arg != "clock") { + // Get default raid duration style from config + if ($config->RAID_DURATION_CLOCK_STYLE) { + $arg = "clock"; } else { - // Set switch view. - $switch_text = getTranslation('raid_starts_when_minutes_view'); - $switch_view = "min"; - // Small screen fix - $key_count = 4; - - for ($i = 1; $i <= $config->RAID_EGG_DURATION; $i = $i + 1) { - // Create new DateTime object, add minutes and convert back to string. - $now_plus_i = new DateTime($now, new DateTimeZone('UTC')); - $now_plus_i->add(new DateInterval('PT'.$i.'M')); - $now_plus_i = $now_plus_i->format("Y-m-d H:i:s"); - // Create the keys. - $keys[] = array( - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => dt2time($now_plus_i), - 'callback_data' => $gym_id_plus_letter . ':edit_time:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . utctime($now_plus_i,"H-i") - ); - } + $arg = "min"; + } + } + + // Init empty keys array. + $keys = []; + + // Now + $now = utcnow(); + + if ($arg == "min") { + // Set switch view. + $switch_text = getTranslation('raid_starts_when_clocktime_view'); + $switch_view = "clock"; + $key_count = 5; + + for ($i = 1; $i <= $config->RAID_EGG_DURATION; $i = $i + 1) { + // Create new DateTime object, add minutes and convert back to string. + $now_plus_i = new DateTime($now, new DateTimeZone('UTC')); + $now_plus_i->add(new DateInterval('PT'.$i.'M')); + $now_plus_i = $now_plus_i->format("Y-m-d H:i:s"); + // Create the keys. + $keys[] = array( + // Just show the time, no text - not everyone has a phone or tablet with a large screen... + 'text' => floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT), + 'callback_data' => $gym_id_plus_letter . ':edit_time:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . utctime($now_plus_i,"H-i") + ); } + } else { + // Set switch view. + $switch_text = getTranslation('raid_starts_when_minutes_view'); + $switch_view = "min"; + // Small screen fix + $key_count = 4; + + for ($i = 1; $i <= $config->RAID_EGG_DURATION; $i = $i + 1) { + // Create new DateTime object, add minutes and convert back to string. + $now_plus_i = new DateTime($now, new DateTimeZone('UTC')); + $now_plus_i->add(new DateInterval('PT'.$i.'M')); + $now_plus_i = $now_plus_i->format("Y-m-d H:i:s"); + // Create the keys. + // Just show the time, no text - not everyone has a phone or tablet with a large screen... + $keys[] = array( + 'text' => dt2time($now_plus_i), + 'callback_data' => $gym_id_plus_letter . ':edit_time:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . utctime($now_plus_i,"H-i") + ); + } + } - // Get the inline key array. - $keys = inline_key_array($keys, $key_count); + // Get the inline key array. + $keys = inline_key_array($keys, $key_count); - // Init empty keys other options array. - $keys_opt = []; + // Init empty keys other options array. + $keys_opt = []; - // Raid already running - $keys_opt[] = array( - 'text' => getTranslation('is_raid_active'), - 'callback_data' => $gym_id_plus_letter . ':edit_time:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . utctime($now,"H-i").",more,0" - ); + // Raid already running + $keys_opt[] = array( + 'text' => getTranslation('is_raid_active'), + 'callback_data' => $gym_id_plus_letter . ':edit_time:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . utctime($now,"H-i").",more,0" + ); - // Switch view: clocktime / minutes until start - $keys_opt[] = array( - 'text' => $switch_text, - 'callback_data' => $gym_id_plus_letter . ':edit_starttime:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . $switch_view - ); + // Switch view: clocktime / minutes until start + $keys_opt[] = array( + 'text' => $switch_text, + 'callback_data' => $gym_id_plus_letter . ':edit_starttime:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . $switch_view + ); - // Get the inline key array. - $keys_opt = inline_key_array($keys_opt, 2); + // Get the inline key array. + $keys_opt = inline_key_array($keys_opt, 2); - // Merge keys - $keys = array_merge($keys, $keys_opt); + // Merge keys + $keys = array_merge($keys, $keys_opt); - // Write to log. - debug_log($keys); + // Write to log. + debug_log($keys); } // No keys found. if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } else { - // Back key id, action and arg - $back_id = $gym_id_plus_letter; - $back_action = 'edit_pokemon'; - $back_arg = $event_id . ',' . $raid_level; - - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - - // Merge keys. - $keys = array_merge($keys, $nav_keys); + // Back key id, action and arg + $back_id = $gym_id_plus_letter; + $back_action = 'edit_pokemon'; + $back_arg = $event_id . ',' . $raid_level; + + // Add navigation keys. + $nav_keys = []; + $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); + $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); + $nav_keys = inline_key_array($nav_keys, 2); + + // Merge keys. + $keys = array_merge($keys, $nav_keys); } // Build callback message string. if ($arg != "min" && $arg != "clock") { - $callback_response = getTranslation('pokemon_saved'); + $callback_response = getTranslation('pokemon_saved'); } else { - $callback_response = getTranslation('raid_starts_when_view_changed'); + $callback_response = getTranslation('raid_starts_when_view_changed'); } // Telegram JSON array. @@ -186,12 +186,12 @@ // Set the message. if ($arg == 'min') { - $msg = getTranslation('raid_starts_when_minutes'); + $msg = getTranslation('raid_starts_when_minutes'); } else if ($event_id == EVENT_ID_EX) { - $msg = getTranslation('raid_starts_when'); - $msg .= CR . CR . getTranslation('raid_select_date'); + $msg = getTranslation('raid_starts_when'); + $msg .= CR . CR . getTranslation('raid_select_date'); } else { - $msg = getTranslation('raid_starts_when'); + $msg = getTranslation('raid_starts_when'); } // Edit the message. @@ -199,6 +199,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/edit_time.php b/mods/edit_time.php index 3d0d8477..24109c79 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -1,6 +1,9 @@ = 4) { - $pokemon_table_id = $arg_data[2]; - $starttime = $arg_data[3]; -} + $pokemon_table_id = $arg_data[2]; + $starttime = $arg_data[3]; +} if($count_arg >= 5) { - $opt_arg = $arg_data[4]; + $opt_arg = $arg_data[4]; } if($count_arg >= 6) { - $slot_switch = $arg_data[5]; + $slot_switch = $arg_data[5]; } // Write to log. @@ -59,104 +62,110 @@ // raid_id is 0, means we did not create it yet // gym_id is not 0, means we have a gym_id for creation if ($raid_id == 0 && $gym_id != 0) { - // Replace "-" with ":" to get proper time format - debug_log('Formatting the raid time properly now.'); - $arg_time = str_replace('-', ':', $starttime); - - // Event raids - if($event_id != 'N') { - debug_log('Event time :D ... Setting raid date to ' . $arg_time); - $start_date_time = $arg_time; - $query = my_query("SELECT raid_duration FROM events WHERE id = '{$event_id}' LIMIT 1"); - $result = $query->fetch(); - $duration = $result['raid_duration'] ?? $config->RAID_DURATION; - $egg_duration = $config->RAID_EGG_DURATION; - - // Elite raids - }elseif($raid_level == 9) { - debug_log('Elite Raid time :D ... Setting raid date to ' . $arg_time); - $start_date_time = $arg_time; - $duration = $config->RAID_DURATION_ELITE; - $egg_duration = $config->RAID_EGG_DURATION_ELITE; - - // Normal raids - } else { - // Current date - $current_date = date('Y-m-d', strtotime('now')); - debug_log('Today is a raid day! Setting raid date to ' . $current_date); - // Raid time - $start_date_time = $current_date . ' ' . $arg_time . ':00'; - debug_log('Received the following time for the raid: ' . $start_date_time); - $duration = $config->RAID_DURATION; - $egg_duration = $config->RAID_EGG_DURATION; + // Replace "-" with ":" to get proper time format + debug_log('Formatting the raid time properly now.'); + $arg_time = str_replace('-', ':', $starttime); + + // Event raids + if($event_id != 'N') { + debug_log('Event time :D ... Setting raid date to ' . $arg_time); + $start_date_time = $arg_time; + $query = my_query("SELECT raid_duration FROM events WHERE id = '{$event_id}' LIMIT 1"); + $result = $query->fetch(); + $duration = $result['raid_duration'] ?? $config->RAID_DURATION; + $egg_duration = $config->RAID_EGG_DURATION; + + // Elite raids + }elseif($raid_level == 9) { + debug_log('Elite Raid time :D ... Setting raid date to ' . $arg_time); + $start_date_time = $arg_time; + $duration = $config->RAID_DURATION_ELITE; + $egg_duration = $config->RAID_EGG_DURATION_ELITE; + + // Normal raids + } else { + // Current date + $current_date = date('Y-m-d', strtotime('now')); + debug_log('Today is a raid day! Setting raid date to ' . $current_date); + // Raid time + $start_date_time = $current_date . ' ' . $arg_time . ':00'; + debug_log('Received the following time for the raid: ' . $start_date_time); + $duration = $config->RAID_DURATION; + $egg_duration = $config->RAID_EGG_DURATION; + } + + // Check for duplicate raid + $duplicate_id = active_raid_duplication_check($gym_id); + + // Continue with raid creation + if($duplicate_id == 0) { + // Now. + $now = utcnow(); + + $pokemon_id_formid = get_pokemon_by_table_id($pokemon_table_id); + + // Saving event info to db. N = null + $event = (($event_id == "N") ? NULL : (($event_id=="X") ? EVENT_ID_EX : $event_id )); + debug_log("Event: ".$event); + debug_log("Event-id: ".$event_id); + debug_log("Raid level: ".$raid_level); + debug_log("Pokemon: ".$pokemon_id_formid['pokedex_id']."-".$pokemon_id_formid['pokemon_form_id']); + + // Create raid in database. + $rs = my_query(' + INSERT INTO raids + SET user_id = :userId, + pokemon = :pokemon, + pokemon_form = :pokemonForm, + start_time = :startTime, + spawn = DATE_SUB(start_time, INTERVAL ' . $egg_duration . ' MINUTE), + end_time = DATE_ADD(start_time, INTERVAL ' . $duration . ' MINUTE), + gym_id = :gymId, + level = :level, + event = :event + ', [ + 'userId' => $update['callback_query']['from']['id'], + 'pokemon' => $pokemon_id_formid['pokedex_id'], + 'pokemonForm' => $pokemon_id_formid['pokemon_form_id'], + 'startTime' => $start_date_time, + 'gymId' => $gym_id, + 'level' => $raid_level, + 'event' => $event, + ]); + + // Get last insert id from db. + $raid_id = $dbh->lastInsertId(); + + // Write to log. + debug_log('ID=' . $raid_id); + + // Tell user the raid already exists and exit! + } else { + $keys = []; + $raid_id = $duplicate_id; + $raid = get_raid($raid_id); + $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); + + $keys = share_keys($raid_id, 'raid_share', $update, $raid['level']); + + // Add keys for sharing the raid. + if(!empty($keys)) { + // Exit key + $keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); } - // Check for duplicate raid - $duplicate_id = active_raid_duplication_check($gym_id); - - // Continue with raid creation - if($duplicate_id == 0) { - // Now. - $now = utcnow(); - - $pokemon_id_formid = get_pokemon_by_table_id($pokemon_table_id); - - // Saving event info to db. N = null - $event = (($event_id == "N") ? "NULL" : (($event_id=="X") ? EVENT_ID_EX : $event_id )); - debug_log("Event: ".$event); - debug_log("Event-id: ".$event_id); - debug_log("Raid level: ".$raid_level); - debug_log("Pokemon: ".$pokemon_id_formid['pokedex_id']."-".$pokemon_id_formid['pokemon_form_id']); - - // Create raid in database. - $rs = my_query( - " - INSERT INTO raids - SET user_id = {$update['callback_query']['from']['id']}, - pokemon = '{$pokemon_id_formid['pokedex_id']}', - pokemon_form = '{$pokemon_id_formid['pokemon_form_id']}', - start_time = '{$start_date_time}', - spawn = DATE_SUB(start_time, INTERVAL ".$egg_duration." MINUTE), - end_time = DATE_ADD(start_time, INTERVAL {$duration} MINUTE), - gym_id = '{$gym_id}', - level = '{$raid_level}', - event = {$event} - " - ); - - // Get last insert id from db. - $raid_id = $dbh->lastInsertId(); - - // Write to log. - debug_log('ID=' . $raid_id); - - // Tell user the raid already exists and exit! - } else { - $keys = []; - $raid_id = $duplicate_id; - $raid = get_raid($raid_id); - $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); - - $keys = share_keys($raid_id, 'raid_share', $update, $raid['level']); - - // Add keys for sharing the raid. - if(!empty($keys)) { - // Exit key - $keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); - } - - // Answer callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('raid_already_exists'), true); - - // Edit the message. - $tg_json[] = edit_message($update, $msg, $keys, false, true); - - // Telegram multicurl request. - curl_json_multi_request($tg_json); - - // Exit. - exit(); - } + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('raid_already_exists'), true); + + // Edit the message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); + + // Telegram multicurl request. + curl_json_multi_request($tg_json); + + // Exit. + exit(); + } } // Init empty keys array. @@ -164,67 +173,66 @@ // Raid pokemon duration short or 1 Minute / 5 minute time slots if($opt_arg == 'more') { - // 1-minute selection - $slotsize = 1; - - $slotmax = $config->RAID_DURATION; - - for ($i = $slotmax; $i >= 15; $i = $i - $slotsize) { - // Create the keys. - $keys[] = array( - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT), - 'callback_data' => $raid_id . ':edit_save:' . $i - ); - } + // 1-minute selection + $slotsize = 1; + + $slotmax = $config->RAID_DURATION; + + for ($i = $slotmax; $i >= 15; $i = $i - $slotsize) { + // Create the keys. + $keys[] = array( + // Just show the time, no text - not everyone has a phone or tablet with a large screen... + 'text' => floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT), + 'callback_data' => $raid_id . ':edit_save:' . $i + ); + } } else { - debug_log('Comparing slot switch and argument for fast forward'); - if ($slot_switch == 0) { - $raidduration = $config->RAID_DURATION; - - // Write to log. - debug_log('Doing a fast forward now!'); - debug_log('Changing data array first...'); - - // Reset data array - $data = []; - $data['id'] = $raid_id; - $data['action'] = 'edit_save'; - $data['arg'] = $raidduration; - - // Write to log. - debug_log($data, '* NEW DATA= '); - - // Set module path by sent action name. - $module = ROOT_PATH . '/mods/edit_save.php'; - - // Write module to log. - debug_log($module); - - // Check if the module file exists. - if (file_exists($module)) { - // Dynamically include module file and exit. - include_once($module); - exit(); - } - } else { - - // Use raid pokemon duration short. - // Use normal raid duration. - $keys[] = array( - 'text' => '0:' . $config->RAID_DURATION, - 'callback_data' => $raid_id . ':edit_save:' . $config->RAID_DURATION - ); - - // Button for more options. - $keys[] = array( - 'text' => getTranslation('expand'), - 'callback_data' => $raid_id . ':edit_time:' . $pokemon_id . ',' . $start_time . ',more,' . $slot_switch - ); - - - } + debug_log('Comparing slot switch and argument for fast forward'); + if ($slot_switch == 0) { + $raidduration = $config->RAID_DURATION; + + // Write to log. + debug_log('Doing a fast forward now!'); + debug_log('Changing data array first...'); + + // Reset data array + $data = []; + $data['id'] = $raid_id; + $data['action'] = 'edit_save'; + $data['arg'] = $raidduration; + + // Write to log. + debug_log($data, '* NEW DATA= '); + + // Set module path by sent action name. + $module = ROOT_PATH . '/mods/edit_save.php'; + + // Write module to log. + debug_log($module); + + // Check if the module file exists. + if (file_exists($module)) { + // Dynamically include module file and exit. + include_once($module); + exit(); + } + } else { + + // Use raid pokemon duration short. + // Use normal raid duration. + $keys[] = array( + 'text' => '0:' . $config->RAID_DURATION, + 'callback_data' => $raid_id . ':edit_save:' . $config->RAID_DURATION + ); + + // Button for more options. + $keys[] = array( + 'text' => getTranslation('expand'), + 'callback_data' => $raid_id . ':edit_time:' . $pokemon_id . ',' . $start_time . ',more,' . $slot_switch + ); + + } } // Get the inline key array. @@ -235,9 +243,9 @@ // Build callback message string. if ($opt_arg != 'more' && $event_id == 'N') { - $callback_response = getTranslation('start_date_time') . ' ' . $arg_time; + $callback_response = getTranslation('start_date_time') . ' ' . $arg_time; } else { - $callback_response = getTranslation('raid_starts_when_view_changed'); + $callback_response = getTranslation('raid_starts_when_view_changed'); } // Answer callback. @@ -248,6 +256,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/end_remote_raid.php b/mods/end_remote_raid.php index 428f5485..65f9419d 100644 --- a/mods/end_remote_raid.php +++ b/mods/end_remote_raid.php @@ -2,13 +2,12 @@ $raid_id = $data['id']; -my_query('UPDATE raids SET end_time = date_sub(UTC_TIMESTAMP(),interval 1 minute) WHERE id = \'' . $raid_id . '\''); +my_query('UPDATE raids SET end_time = date_sub(UTC_TIMESTAMP(),interval 1 minute) WHERE id = ?', [$raid_id]); require_once(LOGIC_PATH . '/update_raid_poll.php'); $tg_json = update_raid_poll($raid_id, false, $update, false); $tg_json[] = edit_message($update, getTranslation('raid_done'), [], false, true); -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation("remote_raid_marked_ended"), true); +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('remote_raid_marked_ended'), true); curl_json_multi_request($tg_json); -?> diff --git a/mods/events.php b/mods/events.php index 39ffcf90..e78defcd 100644 --- a/mods/events.php +++ b/mods/events.php @@ -47,6 +47,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/events_add.php b/mods/events_add.php index 567fe5ee..8854a6e3 100644 --- a/mods/events_add.php +++ b/mods/events_add.php @@ -17,7 +17,6 @@ $value = htmlspecialchars(trim($update['message']['text'])); my_query('INSERT INTO events SET name=?',[$value]); $eventId = $dbh->lastInsertId(); - my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); $callback_response = getTranslation('done'); editMessageText($modifiers['old_message_id'], getTranslation('events_created'), [], $userId); $msg = '' . getTranslation('events_created') . '' . CR; @@ -67,6 +66,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/events_manage.php b/mods/events_manage.php index 932b1918..a9e2df44 100644 --- a/mods/events_manage.php +++ b/mods/events_manage.php @@ -68,7 +68,6 @@ $eventId = $modifiers['eventId']; my_query('UPDATE events SET ' . $column . ' = ? WHERE id=?', [$value, $eventId]); $callback_response = getTranslation('done'); - my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); editMessageText($modifiers['old_message_id'], getTranslation('updated'), [], $userId); } @@ -120,7 +119,7 @@ // Edt event raid poll settings }else if($arg == 3) { my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); - $templateArray = ($event['poll_template'] == NULL) ? $config->RAID_POLL_UI_TEMPLATE : json_decode($event['poll_template'], true); + $templateArray = ($event['poll_template'] == NULL) ? $config->RAID_POLL_UI_TEMPLATE : json_decode($event['poll_template'], true); $event['poll_template'] = templateJsonToString($templateArray); $printColumns = ['vote_key_mode','time_slots','raid_duration','hide_raid_picture','pokemon_title','poll_template']; @@ -159,7 +158,7 @@ my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); if($valueToEdit == 'poll_template') { - $templateArray = ($event['poll_template'] == NULL) ? $config->RAID_POLL_UI_TEMPLATE : json_decode($event['poll_template'], true); + $templateArray = ($event['poll_template'] == NULL) ? $config->RAID_POLL_UI_TEMPLATE : json_decode($event['poll_template'], true); $event['poll_template'] = templateJsonToString($templateArray); } @@ -196,5 +195,3 @@ function templateJsonToString($templateArray) { } return $templateString; } -// Exit. -exit(); diff --git a/mods/exit.php b/mods/exit.php index c1d5dee2..bdd4bd78 100644 --- a/mods/exit.php +++ b/mods/exit.php @@ -23,6 +23,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/getdb.php b/mods/getdb.php index 9040972b..502ee414 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -1,12 +1,11 @@ $pokemon_name, - 'pokemon_form_name'=>$form_name, - 'pokemon_form_id'=>0, - 'asset_suffix'=>0, - 'shiny'=>0, - 'min_cp'=>0, - 'max_cp'=>0, - 'min_weather_cp'=>0, - 'max_weather_cp'=>0, - 'type' => '', - 'type2' => '', - 'shiny'=>0, - 'weather'=>0 - ]; - } - $i = 0; - $SQL = ''; - foreach($pokemon_array as $id => $forms) { - $pokemon_id = $id; - foreach($forms as $form=>$data) { - // Check that data is set, if not the mon is probably not in the game yet and there's no point in having them in a broken state - if(isset($data['weather']) && isset($data['min_cp']) && isset($data['max_cp']) && isset($data['min_weather_cp']) && isset($data['max_weather_cp']) && isset($data['pokemon_name'])) { - $poke_form = $form; - - $poke_name = $data['pokemon_name']; - $form_id = $data['pokemon_form_id']; - $form_asset_suffix = $data['asset_suffix']; - $poke_min_cp = $data['min_cp']; - $poke_max_cp = $data['max_cp']; - $poke_min_weather_cp = $data['min_weather_cp']; - $poke_max_weather_cp = $data['max_weather_cp']; - $poke_type = $data['type']; - $poke_type2 = $data['type2']; - $poke_weather = $data['weather']; - - if($pokemon_id == 150 && $data['pokemon_form_name']=="a") { - // Because logic and consistency - $poke_form = 'armored'; - }else { - $poke_form = strtolower($data['pokemon_form_name']); - } - if($i==0) $i=1; else $SQL .= ","; - $SQL .= PHP_EOL . "(\"${pokemon_id}\", \"${poke_name}\", \"${poke_form}\", \"${form_id}\", \"${form_asset_suffix}\", \"${poke_min_cp}\", \"${poke_max_cp}\", \"${poke_min_weather_cp}\", \"${poke_max_weather_cp}\", \"${poke_type}\", \"${poke_type2}\", \"${poke_weather}\")"; - } - } - } - ## MySQL 8 compatible - #$SQL = $PRE . $SQL . ' as new' . PHP_EOL; - #$SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = new.pokedex_id, pokemon_name = new.pokemon_name, pokemon_form_name = new.pokemon_form_name,' . PHP_EOL; - #$SQL .= 'pokemon_form_id = new.pokemon_form_id, asset_suffix = new.asset_suffix, min_cp = new.min_cp, max_cp = new.max_cp,' . PHP_EOL; - #$SQL .= 'min_weather_cp = new.min_weather_cp, max_weather_cp = new.max_weather_cp, type = new.type, type2 = new.type2, weather = new.weather;'; - $SQL = $PRE . $SQL . PHP_EOL; - $SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = VALUES(pokedex_id), pokemon_name = VALUES(pokemon_name), pokemon_form_name = VALUES(pokemon_form_name),' . PHP_EOL; - $SQL .= 'pokemon_form_id = VALUES(pokemon_form_id), asset_suffix = VALUES(asset_suffix), min_cp = VALUES(min_cp),' . PHP_EOL; - $SQL .= 'max_cp = VALUES(max_cp), min_weather_cp = VALUES(min_weather_cp), max_weather_cp = VALUES(max_weather_cp),' . PHP_EOL; - $SQL .= 'type = VALUES(type), type2 = VALUES(type2), weather = VALUES(weather);' . PHP_EOL; - try { - $prep = $dbh->prepare($SQL); - $prep->execute(); - } catch (Exception $e) { - if(isset($update['message']['from']['id'])) $error = $e; + // Save costume data to json file + if(file_put_contents(ROOT_PATH.'/protos/costume.json', json_encode($costume, JSON_PRETTY_PRINT))) { + // Parse the game master data together with form ids into format we can use + $pokemon_array = parse_master_into_pokemon_table($form_ids, $game_master_url); + if(!$pokemon_array) { + $error = "Failed to open game master file."; + } else { + $PRE = 'INSERT INTO `pokemon`' . PHP_EOL; + $PRE .= '(pokedex_id, pokemon_name, pokemon_form_name, pokemon_form_id, asset_suffix, min_cp, max_cp, min_weather_cp, max_weather_cp, type, type2, weather) VALUES'; + foreach($eggs as $egg) { + $pokemon_id = $egg; + $form_name = 'normal'; + $pokemon_name = 'Level '. $egg[3] .' Egg'; + $pokemon_array[$pokemon_id][$form_name] = [ + 'pokemon_name'=>$pokemon_name, + 'pokemon_form_name'=>$form_name, + 'pokemon_form_id'=>0, + 'asset_suffix'=>0, + 'shiny'=>0, + 'min_cp'=>0, + 'max_cp'=>0, + 'min_weather_cp'=>0, + 'max_weather_cp'=>0, + 'type' => '', + 'type2' => '', + 'weather'=>0 + ]; + } + $i = 0; + $SQL = ''; + foreach($pokemon_array as $id => $forms) { + $pokemon_id = $id; + foreach($forms as $form=>$data) { + // Check that data is set, if not the mon is probably not in the game yet and there's no point in having them in a broken state + if(isset($data['weather']) && isset($data['min_cp']) && isset($data['max_cp']) && isset($data['min_weather_cp']) && isset($data['max_weather_cp']) && isset($data['pokemon_name'])) { + $poke_form = $form; + + $poke_name = $data['pokemon_name']; + $form_id = $data['pokemon_form_id']; + $form_asset_suffix = $data['asset_suffix']; + $poke_min_cp = $data['min_cp']; + $poke_max_cp = $data['max_cp']; + $poke_min_weather_cp = $data['min_weather_cp']; + $poke_max_weather_cp = $data['max_weather_cp']; + $poke_type = $data['type']; + $poke_type2 = $data['type2']; + $poke_weather = $data['weather']; + + if($pokemon_id == 150 && $data['pokemon_form_name']=="a") { + // Because logic and consistency + $poke_form = 'armored'; + }else { + $poke_form = strtolower($data['pokemon_form_name']); } + if($i==0) $i=1; else $SQL .= ","; + $SQL .= PHP_EOL . "(\"${pokemon_id}\", \"${poke_name}\", \"${poke_form}\", \"${form_id}\", \"${form_asset_suffix}\", \"${poke_min_cp}\", \"${poke_max_cp}\", \"${poke_min_weather_cp}\", \"${poke_max_weather_cp}\", \"${poke_type}\", \"${poke_type2}\", \"${poke_weather}\")"; + } } - }else { - $error = 'Failed to write costume data to protos/costume.json'; + } + ## MySQL 8 compatible + #$SQL = $PRE . $SQL . ' as new' . PHP_EOL; + #$SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = new.pokedex_id, pokemon_name = new.pokemon_name, pokemon_form_name = new.pokemon_form_name,' . PHP_EOL; + #$SQL .= 'pokemon_form_id = new.pokemon_form_id, asset_suffix = new.asset_suffix, min_cp = new.min_cp, max_cp = new.max_cp,' . PHP_EOL; + #$SQL .= 'min_weather_cp = new.min_weather_cp, max_weather_cp = new.max_weather_cp, type = new.type, type2 = new.type2, weather = new.weather;'; + $SQL = $PRE . $SQL . PHP_EOL; + $SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = VALUES(pokedex_id), pokemon_name = VALUES(pokemon_name), pokemon_form_name = VALUES(pokemon_form_name),' . PHP_EOL; + $SQL .= 'pokemon_form_id = VALUES(pokemon_form_id), asset_suffix = VALUES(asset_suffix), min_cp = VALUES(min_cp),' . PHP_EOL; + $SQL .= 'max_cp = VALUES(max_cp), min_weather_cp = VALUES(min_weather_cp), max_weather_cp = VALUES(max_weather_cp),' . PHP_EOL; + $SQL .= 'type = VALUES(type), type2 = VALUES(type2), weather = VALUES(weather);' . PHP_EOL; + try { + $prep = $dbh->prepare($SQL); + $prep->execute(); + } catch (Exception $e) { + if(isset($update['message']['from']['id'])) $error = $e; + } } + }else { + $error = 'Failed to write costume data to protos/costume.json'; + } } else { - $error = 'Failed to get protos.'; + $error = 'Failed to get protos.'; } -if(!$error) { - $msg = 'Updated successfully!' . CR; - $msg.= $prep->rowCount() . ' rows required updating!'; - // Sometimes Nia can push form id's a bit later than other stats, so the script may insert incomplete rows - // This hopefully clears those faulty rows out when the complete data is received without effecting any actual data - my_query(' - DELETE t1 FROM pokemon t1 - INNER JOIN pokemon t2 - WHERE - t1.pokedex_id = t2.pokedex_id - AND t1.pokemon_form_name = t2.pokemon_form_name - AND t1.pokemon_form_name <> \'normal\' - AND t1.pokemon_form_id = 0 - '); - $callback_msg = 'OK!'; +if(!$error) { + $msg = 'Updated successfully!' . CR; + $msg.= $prep->rowCount() . ' rows required updating!'; + // Sometimes Nia can push form id's a bit later than other stats, so the script may insert incomplete rows + // This hopefully clears those faulty rows out when the complete data is received without effecting any actual data + my_query(' + DELETE t1 FROM pokemon t1 + INNER JOIN pokemon t2 + WHERE + t1.pokedex_id = t2.pokedex_id + AND t1.pokemon_form_name = t2.pokemon_form_name + AND t1.pokemon_form_name <> \'normal\' + AND t1.pokemon_form_id = 0 + '); + $callback_msg = 'OK!'; }else { - $msg = $error; - info_log('Pokemon table update failed: ' . $error); - $callback_msg = 'Error!'; + $msg = $error; + info_log('Pokemon table update failed: ' . $error); + $callback_msg = 'Error!'; +} +if(!isset($update['callback_query']['id'])) { + info_log($msg); + exit(); } -if(isset($update['callback_query']['id'])) { - // Answer callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_msg, true); +// Answer callback. +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_msg, true); - // Edit the message. - $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['message']['chat']['id'], false, true); +// Edit the message. +$tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['message']['chat']['id'], false, true); - // Telegram multicurl request. - curl_json_multi_request($tg_json); +// Telegram multicurl request. +curl_json_multi_request($tg_json); - // Exit. - $dbh = null; - exit(); -} else { - info_log($msg); -} function calculate_cps($base_stats) { - // CP = (Attack * Defense^0.5 * Stamina^0.5 * CP_Multiplier^2) / 10 - $cp_multiplier = array(20 => 0.5974 ,25 =>0.667934 ); - $min = floor((($base_stats['baseAttack']+10)*(($base_stats['baseDefense']+10)**0.5)*(($base_stats['baseStamina']+10)**0.5)*$cp_multiplier[20]**2)/10); - $max = floor((($base_stats['baseAttack']+15)*(($base_stats['baseDefense']+15)**0.5)*(($base_stats['baseStamina']+15)**0.5)*$cp_multiplier[20]**2)/10); - $min_weather = floor((($base_stats['baseAttack']+10)*(($base_stats['baseDefense']+10)**0.5)*(($base_stats['baseStamina']+10)**0.5)*$cp_multiplier[25]**2)/10); - $max_weather = floor((($base_stats['baseAttack']+15)*(($base_stats['baseDefense']+15)**0.5)*(($base_stats['baseStamina']+15)**0.5)*$cp_multiplier[25]**2)/10); - return [$min,$max,$min_weather,$max_weather]; + // CP = (Attack * Defense^0.5 * Stamina^0.5 * CP_Multiplier^2) / 10 + $cp_multiplier = array(20 => 0.5974 ,25 =>0.667934 ); + $min = floor((($base_stats['baseAttack']+10)*(($base_stats['baseDefense']+10)**0.5)*(($base_stats['baseStamina']+10)**0.5)*$cp_multiplier[20]**2)/10); + $max = floor((($base_stats['baseAttack']+15)*(($base_stats['baseDefense']+15)**0.5)*(($base_stats['baseStamina']+15)**0.5)*$cp_multiplier[20]**2)/10); + $min_weather = floor((($base_stats['baseAttack']+10)*(($base_stats['baseDefense']+10)**0.5)*(($base_stats['baseStamina']+10)**0.5)*$cp_multiplier[25]**2)/10); + $max_weather = floor((($base_stats['baseAttack']+15)*(($base_stats['baseDefense']+15)**0.5)*(($base_stats['baseStamina']+15)**0.5)*$cp_multiplier[25]**2)/10); + return [$min,$max,$min_weather,$max_weather]; } function get_protos($proto_url) { - //Parse the form ID's from pogoprotos - if(!$proto_file = curl_get_contents($proto_url)) return false; - $proto = preg_split('/\r\n|\r|\n/', $proto_file); - $count = count($proto); - $form_ids = $costume = array(); - $data_array = false; - $data_start_line = 0; - for($i=0;$i<$count;$i++) { - $line = trim($proto[$i]); - if($data_array != false && $i >= $data_start_line) { - $data = explode(':', $line, 2); - // End of pokemon data, no need to loop further - if(trim($data[0]) == ']') { - $data_array = false; - $data_start_line = 0; - if(count($form_ids) > 0 && count($costume) > 0) { - // We found what we needed so we can stop looping through proto file and exit - break; - } - continue; - } - $value = explode('"', $data[1]); - if(strlen($value[1]) > 0) { - ${$data_array}[trim($value[1])] = trim($data[0]); - } - }else { - if($line == 'extension PokemonDisplayProto.Costume: SwiftProtobuf._ProtoNameProviding {') { - $data_array = 'costume'; - $data_start_line = $i+2; - } - if($line == 'extension PokemonDisplayProto.Form: SwiftProtobuf._ProtoNameProviding {') { - $data_array = 'form_ids'; - $data_start_line = $i+2; - } + //Parse the form ID's from pogoprotos + if(!$proto_file = curl_get_contents($proto_url)) return false; + $proto = preg_split('/\r\n|\r|\n/', $proto_file); + $count = count($proto); + $form_ids = $costume = array(); + $data_array = false; + $data_start_line = 0; + for($i=0;$i<$count;$i++) { + $line = trim($proto[$i]); + if($data_array != false && $i >= $data_start_line) { + $data = explode(':', $line, 2); + // End of pokemon data, no need to loop further + if(trim($data[0]) == ']') { + $data_array = false; + $data_start_line = 0; + if(count($form_ids) > 0 && count($costume) > 0) { + // We found what we needed so we can stop looping through proto file and exit + break; } + continue; + } + $value = explode('"', $data[1]); + if(strlen($value[1]) > 0) { + ${$data_array}[trim($value[1])] = trim($data[0]); + } + }else { + if($line == 'extension PokemonDisplayProto.Costume: SwiftProtobuf._ProtoNameProviding {') { + $data_array = 'costume'; + $data_start_line = $i+2; + } + if($line == 'extension PokemonDisplayProto.Form: SwiftProtobuf._ProtoNameProviding {') { + $data_array = 'form_ids'; + $data_start_line = $i+2; + } } - unset($proto); - return [$form_ids, $costume]; + } + unset($proto); + return [$form_ids, $costume]; } function parse_master_into_pokemon_table($form_ids, $game_master_url) { - // Set ID's for mega evolutions - // Using negative to prevent mixup with actual form ID's - // Collected from pogoprotos (hoping they won't change, so hard coding them here) - $mega_ids = array('MEGA'=>-1,'MEGA_X'=>-2,'MEGA_Y'=>-3); - $mega_asset_suffixes = array('MEGA'=>51,'MEGA_X'=>51,'MEGA_Y'=>52); + // Set ID's for mega evolutions + // Using negative to prevent mixup with actual form ID's + // Collected from pogoprotos (hoping they won't change, so hard coding them here) + $mega_ids = array('MEGA'=>-1,'MEGA_X'=>-2,'MEGA_Y'=>-3); + $mega_asset_suffixes = array('MEGA'=>51,'MEGA_X'=>51,'MEGA_Y'=>52); - $weatherboost_table = array( - 'POKEMON_TYPE_BUG' => '3', - 'POKEMON_TYPE_DARK' => '8', - 'POKEMON_TYPE_DRAGON' => '6', - 'POKEMON_TYPE_ELECTRIC' => '3', - 'POKEMON_TYPE_FAIRY' => '5', - 'POKEMON_TYPE_FIGHTING' => '5', - 'POKEMON_TYPE_FIRE' => '12', - 'POKEMON_TYPE_FLYING' => '6', - 'POKEMON_TYPE_GHOST' => '8', - 'POKEMON_TYPE_GRASS' => '12', - 'POKEMON_TYPE_GROUND' => '12', - 'POKEMON_TYPE_ICE' => '7', - 'POKEMON_TYPE_NORMAL' => '4', - 'POKEMON_TYPE_POISON' => '5', - 'POKEMON_TYPE_PSYCHIC' => '6', - 'POKEMON_TYPE_ROCK' => '4', - 'POKEMON_TYPE_STEEL' => '7', - 'POKEMON_TYPE_WATER' => '3' - ); - if(!$master_file = curl_get_contents($game_master_url)) return false; - $master = json_decode($master_file, true); - foreach($master as $row) { - $part = explode('_',$row['templateId']); - $form_data = []; - $pokemon_id = ''; - if(count($part)<2) continue; - if($part[0] == 'FORMS' && $part[2] == 'POKEMON') { - // Found Pokemon form data + $weatherboost_table = array( + 'POKEMON_TYPE_BUG' => '3', + 'POKEMON_TYPE_DARK' => '8', + 'POKEMON_TYPE_DRAGON' => '6', + 'POKEMON_TYPE_ELECTRIC' => '3', + 'POKEMON_TYPE_FAIRY' => '5', + 'POKEMON_TYPE_FIGHTING' => '5', + 'POKEMON_TYPE_FIRE' => '12', + 'POKEMON_TYPE_FLYING' => '6', + 'POKEMON_TYPE_GHOST' => '8', + 'POKEMON_TYPE_GRASS' => '12', + 'POKEMON_TYPE_GROUND' => '12', + 'POKEMON_TYPE_ICE' => '7', + 'POKEMON_TYPE_NORMAL' => '4', + 'POKEMON_TYPE_POISON' => '5', + 'POKEMON_TYPE_PSYCHIC' => '6', + 'POKEMON_TYPE_ROCK' => '4', + 'POKEMON_TYPE_STEEL' => '7', + 'POKEMON_TYPE_WATER' => '3' + ); + if(!$master_file = curl_get_contents($game_master_url)) return false; + $master = json_decode($master_file, true); + foreach($master as $row) { + $part = explode('_',$row['templateId']); + $form_data = []; + $pokemon_id = ''; + if(count($part)<2) continue; + if($part[0] == 'FORMS' && $part[2] == 'POKEMON') { + // Found Pokemon form data - // Get pokemon ID - $pokemon_id = ltrim(str_replace('V','',$part[1]),'0'); - unset($part[0]); - unset($part[1]); - unset($part[2]); + // Get pokemon ID + $pokemon_id = ltrim(str_replace('V','',$part[1]),'0'); + unset($part[0]); + unset($part[1]); + unset($part[2]); - // Pokemon name - $pokemon_name = implode('_',$part); - // Get pokemon forms - if(!isset($row['data']['formSettings']['forms']) or empty($row['data']['formSettings']['forms'][0])) { - $form_data[] = array('form'=>$pokemon_name.'_NORMAL'); - }else { - $form_data = $row['data']['formSettings']['forms']; - } - foreach($form_data as $form) { - $form_name = strtolower(str_replace($pokemon_name.'_','',$form['form'])); - if($form_name != 'purified' && $form_name != 'shadow') { + // Pokemon name + $pokemon_name = implode('_',$part); + // Get pokemon forms + if(!isset($row['data']['formSettings']['forms']) or empty($row['data']['formSettings']['forms'][0])) { + $form_data[] = array('form'=>$pokemon_name.'_NORMAL'); + }else { + $form_data = $row['data']['formSettings']['forms']; + } + foreach($form_data as $form) { + $form_name = strtolower(str_replace($pokemon_name.'_','',$form['form'])); + if($form_name == 'purified' || $form_name == 'shadow') continue; - // Nidoran - $poke_name = ucfirst(strtolower(str_replace(['_FEMALE','_MALE'],['♀','♂'],$row['data']['formSettings']['pokemon']))); - // Ho-oh - $poke_name = str_replace('_','-',$poke_name); + // Nidoran + $poke_name = ucfirst(strtolower(str_replace(['_FEMALE','_MALE'],['♀','♂'],$row['data']['formSettings']['pokemon']))); + // Ho-oh + $poke_name = str_replace('_','-',$poke_name); - if(!isset($form_ids[$form['form']])) { - $form_id = 0; - }else { - $form_id = $form_ids[$form['form']]; - } - $form_asset_suffix = (isset($form['assetBundleValue']) ? $form['assetBundleValue'] : (isset($form['assetBundleSuffix'])?$form['assetBundleSuffix']:'00')); + if(!isset($form_ids[$form['form']])) { + $form_id = 0; + }else { + $form_id = $form_ids[$form['form']]; + } + $form_asset_suffix = (isset($form['assetBundleValue']) ? $form['assetBundleValue'] : (isset($form['assetBundleSuffix'])?$form['assetBundleSuffix']:'00')); - $pokemon_array[$pokemon_id][$form_name] = [ 'pokemon_name'=>$poke_name, - 'pokemon_form_name'=>$form_name, - 'pokemon_form_id'=>$form_id, - 'asset_suffix'=>$form_asset_suffix - ]; - - } - } - }else if ($part[1] == "POKEMON" && $part[0][0] == "V" && isset($row['data']['pokemonSettings'])) { - // Found Pokemon data - $pokemon_id = (int)str_replace("V","",$part[0]); - $form_name = str_replace($row['data']['pokemonSettings']['pokemonId']."_","",substr($row['data']['templateId'],14)); - if($form_name != 'PURIFIED' && $form_name != 'SHADOW' && $form_name != 'NORMAL' - && isset($pokemon_array[$pokemon_id]) - && isset($row['data']['pokemonSettings']['stats']['baseAttack']) - && isset($row['data']['pokemonSettings']['stats']['baseDefense']) - && isset($row['data']['pokemonSettings']['stats']['baseStamina'])) { - if($form_name == $row['data']['pokemonSettings']['pokemonId']) { - $form_name = "normal"; - }else { - $form_name = strtolower($form_name); - } - $CPs = calculate_cps($row['data']['pokemonSettings']['stats']); - $min_cp = $CPs[0]; - $max_cp = $CPs[1]; - $min_weather_cp = $CPs[2]; - $max_weather_cp = $CPs[3]; + $pokemon_array[$pokemon_id][$form_name] = [ + 'pokemon_name'=>$poke_name, + 'pokemon_form_name'=>$form_name, + 'pokemon_form_id'=>$form_id, + 'asset_suffix'=>$form_asset_suffix + ]; + } + }else if ($part[1] == "POKEMON" && $part[0][0] == "V" && isset($row['data']['pokemonSettings'])) { + // Found Pokemon data + $pokemon_id = (int)str_replace("V","",$part[0]); + $form_name = str_replace($row['data']['pokemonSettings']['pokemonId']."_","",substr($row['data']['templateId'],14)); + if($form_name == 'PURIFIED' || $form_name == 'SHADOW' || $form_name == 'NORMAL' + || !isset($pokemon_array[$pokemon_id]) + || !isset($row['data']['pokemonSettings']['stats']['baseAttack']) + || !isset($row['data']['pokemonSettings']['stats']['baseDefense']) + || !isset($row['data']['pokemonSettings']['stats']['baseStamina'])) { + continue; + } + $form_name = "normal"; + if($form_name != $row['data']['pokemonSettings']['pokemonId']) { + $form_name = strtolower($form_name); + } + [$min_cp, $max_cp, $min_weather_cp, $max_weather_cp] = calculate_cps($row['data']['pokemonSettings']['stats']); - $type = strtolower(str_replace('POKEMON_TYPE_','', $row['data']['pokemonSettings']['type'])); - $type2 = ''; + $type = strtolower(str_replace('POKEMON_TYPE_','', $row['data']['pokemonSettings']['type'])); + $type2 = ''; - $weather = $weatherboost_table[$row['data']['pokemonSettings']['type']]; - if(isset($row['data']['pokemonSettings']['type2'])) { - $type2 = strtolower(str_replace('POKEMON_TYPE_','', $row['data']['pokemonSettings']['type2'])); + $weather = $weatherboost_table[$row['data']['pokemonSettings']['type']]; + if(isset($row['data']['pokemonSettings']['type2'])) { + $type2 = strtolower(str_replace('POKEMON_TYPE_','', $row['data']['pokemonSettings']['type2'])); - # Add type2 weather boost only if there is a second type and it's not the same weather as the first type! - if($weatherboost_table[$row['data']['pokemonSettings']['type2']] != $weatherboost_table[$row['data']['pokemonSettings']['type']]) { - $weather .= $weatherboost_table[$row['data']['pokemonSettings']['type2']]; - } - } - if(isset($pokemon_array[$pokemon_id][$form_name])) { - $pokemon_array[$pokemon_id][$form_name]['min_cp'] = $min_cp; - $pokemon_array[$pokemon_id][$form_name]['max_cp'] = $max_cp; - $pokemon_array[$pokemon_id][$form_name]['min_weather_cp'] = $min_weather_cp; - $pokemon_array[$pokemon_id][$form_name]['max_weather_cp'] = $max_weather_cp; - $pokemon_array[$pokemon_id][$form_name]['weather'] = $weather; - $pokemon_array[$pokemon_id][$form_name]['type'] = $type; - $pokemon_array[$pokemon_id][$form_name]['type2'] = $type2; - }else { - // Fill data for Pokemon that have form data but no stats for forms specifically - foreach($pokemon_array[$pokemon_id] as $form=>$data) { - $pokemon_array[$pokemon_id][$form]['min_cp'] = $min_cp; - $pokemon_array[$pokemon_id][$form]['max_cp'] = $max_cp; - $pokemon_array[$pokemon_id][$form]['min_weather_cp'] = $min_weather_cp; - $pokemon_array[$pokemon_id][$form]['max_weather_cp'] = $max_weather_cp; - $pokemon_array[$pokemon_id][$form]['weather'] = $weather; - $pokemon_array[$pokemon_id][$form]['type'] = $type; - $pokemon_array[$pokemon_id][$form]['type2'] = $type2; - } - } - if(isset($row['data']['pokemonSettings']['tempEvoOverrides'])) { - foreach($row['data']['pokemonSettings']['tempEvoOverrides'] as $temp_evolution) { - if(isset($temp_evolution['tempEvoId'])) { - $mega_evolution_name = str_replace('TEMP_EVOLUTION_','',$temp_evolution['tempEvoId']); - // We only override the types for megas - // weather info is used to display boosts for caught mons, which often are different from mega's typing - $typeOverride = strtolower(str_replace('POKEMON_TYPE_','', $temp_evolution['typeOverride1'])); - $typeOverride2 = ''; + # Add type2 weather boost only if there is a second type and it's not the same weather as the first type! + if($weatherboost_table[$row['data']['pokemonSettings']['type2']] != $weatherboost_table[$row['data']['pokemonSettings']['type']]) { + $weather .= $weatherboost_table[$row['data']['pokemonSettings']['type2']]; + } + } + if(isset($pokemon_array[$pokemon_id][$form_name])) { + $pokemon_array[$pokemon_id][$form_name]['min_cp'] = $min_cp; + $pokemon_array[$pokemon_id][$form_name]['max_cp'] = $max_cp; + $pokemon_array[$pokemon_id][$form_name]['min_weather_cp'] = $min_weather_cp; + $pokemon_array[$pokemon_id][$form_name]['max_weather_cp'] = $max_weather_cp; + $pokemon_array[$pokemon_id][$form_name]['weather'] = $weather; + $pokemon_array[$pokemon_id][$form_name]['type'] = $type; + $pokemon_array[$pokemon_id][$form_name]['type2'] = $type2; + }else { + // Fill data for Pokemon that have form data but no stats for forms specifically + foreach($pokemon_array[$pokemon_id] as $form => $data) { + $pokemon_array[$pokemon_id][$form]['min_cp'] = $min_cp; + $pokemon_array[$pokemon_id][$form]['max_cp'] = $max_cp; + $pokemon_array[$pokemon_id][$form]['min_weather_cp'] = $min_weather_cp; + $pokemon_array[$pokemon_id][$form]['max_weather_cp'] = $max_weather_cp; + $pokemon_array[$pokemon_id][$form]['weather'] = $weather; + $pokemon_array[$pokemon_id][$form]['type'] = $type; + $pokemon_array[$pokemon_id][$form]['type2'] = $type2; + } + } + if(!isset($row['data']['pokemonSettings']['tempEvoOverrides'])) continue; + foreach($row['data']['pokemonSettings']['tempEvoOverrides'] as $temp_evolution) { + if(!isset($temp_evolution['tempEvoId'])) continue; - if(isset($temp_evolution['typeOverride2'])) { - $typeOverride2 = strtolower(str_replace('POKEMON_TYPE_','', $temp_evolution['typeOverride2'])); - } - $pokemon_array[$pokemon_id][$mega_evolution_name] = [ 'pokemon_name' => $pokemon_array[$pokemon_id][$form_name]['pokemon_name'], - 'pokemon_form_name' => $mega_evolution_name, - 'pokemon_form_id' => $mega_ids[$mega_evolution_name], - 'asset_suffix' => $mega_asset_suffixes[$mega_evolution_name], - 'min_cp' => $min_cp, - 'max_cp' => $max_cp, - 'min_weather_cp' => $min_weather_cp, - 'max_weather_cp' => $max_weather_cp, - 'weather' => $weather, - 'type' => $typeOverride, - 'type2' => $typeOverride2, - ]; - } - } - } - } + $mega_evolution_name = str_replace('TEMP_EVOLUTION_','',$temp_evolution['tempEvoId']); + // We only override the types for megas + // weather info is used to display boosts for caught mons, which often are different from mega's typing + $typeOverride = strtolower(str_replace('POKEMON_TYPE_','', $temp_evolution['typeOverride1'])); + $typeOverride2 = ''; + + if(isset($temp_evolution['typeOverride2'])) { + $typeOverride2 = strtolower(str_replace('POKEMON_TYPE_','', $temp_evolution['typeOverride2'])); } + $pokemon_array[$pokemon_id][$mega_evolution_name] = [ + 'pokemon_name' => $pokemon_array[$pokemon_id][$form_name]['pokemon_name'], + 'pokemon_form_name' => $mega_evolution_name, + 'pokemon_form_id' => $mega_ids[$mega_evolution_name], + 'asset_suffix' => $mega_asset_suffixes[$mega_evolution_name], + 'min_cp' => $min_cp, + 'max_cp' => $max_cp, + 'min_weather_cp' => $min_weather_cp, + 'max_weather_cp' => $max_weather_cp, + 'weather' => $weather, + 'type' => $typeOverride, + 'type2' => $typeOverride2, + ]; + } } - return $pokemon_array; + } + return $pokemon_array; } // Fetch the latest version of proto files. // vbase.proto has only the latest fully deobfuscated protos, // but we only need the latest form and costume data which is available in the partially obfuscated protofiles function getProtoURL() { - $repo_owner = 'Furtif'; - $repo_name = 'POGOProtos'; - $content_dir = 'base'; + $repo_owner = 'Furtif'; + $repo_name = 'POGOProtos'; + $content_dir = 'base'; - $repo_content = 'https://api.github.com/repos/' . $repo_owner . '/' . $repo_name . '/contents/' . $content_dir; - // Git tree lookup - $tree = curl_get_contents($repo_content); - $leaf = json_decode($tree, true); - // Detect rate-limiting and die gracefully - if(is_array($leaf) && in_array('message', $leaf)) { - die('Failed to download repo index: ' . $leaf['message']); - } - $highest = 0; - $url = ''; - foreach($leaf as $l) { - $version = trim(preg_replace('/\D/', '', substr($l['name'], 3))); - if($version > $highest) { - $split = explode(".",$l['name']); - // Only allow fully or partially deobfuscated iterations of the proto file - if($split[2] == 'x' or $split[2] == 'x_p_obf') { - $highest = $version; - $url = $l['download_url']; - } - } + $repo_content = 'https://api.github.com/repos/' . $repo_owner . '/' . $repo_name . '/contents/' . $content_dir; + // Git tree lookup + $tree = curl_get_contents($repo_content); + $leaf = json_decode($tree, true); + // Detect rate-limiting and die gracefully + if(is_array($leaf) && in_array('message', $leaf)) { + die('Failed to download repo index: ' . $leaf['message']); + } + $highest = 0; + $url = ''; + foreach($leaf as $l) { + $version = trim(preg_replace('/\D/', '', substr($l['name'], 3))); + if($version > $highest) { + $split = explode(".",$l['name']); + // Only allow fully or partially deobfuscated iterations of the proto file + if($split[2] == 'x' or $split[2] == 'x_p_obf') { + $highest = $version; + $url = $l['download_url']; + } } - return $url; + } + return $url; } diff --git a/mods/gym_create.php b/mods/gym_create.php index 9bc3b20b..0c406ad3 100644 --- a/mods/gym_create.php +++ b/mods/gym_create.php @@ -10,26 +10,26 @@ $botUser->accessCheck($update, 'gym-edit'); function insertUserInput($userId, $stage, $oldMessageId, $gymId = 0) { - global $dbh; - // Create an entry to user_input table - $modifierArray = ["stage" => $stage + 1, "oldMessageId" => $oldMessageId]; - if($gymId !== 0) $modifierArray['gymId'] = $gymId; - $modifiers = json_encode($modifierArray); - $handler = "gym_create"; + global $dbh; + // Create an entry to user_input table + $modifierArray = ['stage' => $stage + 1, 'oldMessageId' => $oldMessageId]; + if($gymId !== 0) $modifierArray['gymId'] = $gymId; + $modifiers = json_encode($modifierArray); + $handler = 'gym_create'; - my_query("INSERT INTO user_input SET user_id = :userId, modifiers = :modifiers, handler = :handler", [':userId' => $userId, ':modifiers' => $modifiers, ':handler' => $handler]); - return $dbh->lastInsertId(); + my_query('INSERT INTO user_input SET user_id = :userId, modifiers = :modifiers, handler = :handler', [':userId' => $userId, ':modifiers' => $modifiers, ':handler' => $handler]); + return $dbh->lastInsertId(); } function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [], $sendMsg = '', $sendKeys = [], $callbackMsg = '', $callbackId = 0) { - if($callbackId != 0) answerCallbackQuery($callbackId, $callbackMsg); - if($editMsg != '') editMessageText($oldMessageId, $editMsg, $editKeys, $userId, ['disable_web_page_preview' => 'true']); - if($sendMsg != '') send_message($userId, $sendMsg, $sendKeys, ['disable_web_page_preview' => 'true']); + if($callbackId != 0) answerCallbackQuery($callbackId, $callbackMsg); + if($editMsg != '') editMessageText($oldMessageId, $editMsg, $editKeys, $userId, ['disable_web_page_preview' => 'true']); + if($sendMsg != '') send_message($userId, $sendMsg, $sendKeys, ['disable_web_page_preview' => 'true']); } if(isset($data['arg'])) { - // Split the arg. - $split_arg = explode('-', $data['arg']); - $action = $split_arg[0] ?? false; - $deleteId = $split_arg[1] ?? false; + // Split the arg. + $split_arg = explode('-', $data['arg']); + $action = $split_arg[0] ?? false; + $deleteId = $split_arg[1] ?? false; } // Set keys. $keys = []; @@ -37,67 +37,67 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $stage = $modifiers['stage'] ?? 1; if(isset($action) && $action == 'abort') { - my_query("DELETE FROM user_input WHERE id = :deleteId", ['deleteId' => $deleteId]); - $msg = getTranslation("action_aborted"); - editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['from']['id']); + my_query("DELETE FROM user_input WHERE id = :deleteId", ['deleteId' => $deleteId]); + $msg = getTranslation("action_aborted"); + editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['from']['id']); }else { - if($stage == 1) { - $callbackResponse = getTranslation('here_we_go'); - $callbackId = $update['callback_query']['id']; + if($stage == 1) { + $callbackResponse = getTranslation('here_we_go'); + $callbackId = $update['callback_query']['id']; - $userId = $update['callback_query']['from']['id']; - $oldMessageId = $update['callback_query']['message']['message_id']; + $userId = $update['callback_query']['from']['id']; + $oldMessageId = $update['callback_query']['message']['message_id']; - $userInputId = insertUserInput($userId, $stage, $oldMessageId); + $userInputId = insertUserInput($userId, $stage, $oldMessageId); - $editMsg = getTranslation("gym_create") . ':'; - $editKeys[0][] = [ - 'text' => getTranslation("abort"), - 'callback_data' => '0:gym_create:abort-' . $userInputId - ]; - $sendMsg = EMOJI_HERE . getTranslation('gym_gps_instructions') . CR; - $sendMsg .= getTranslation('gym_gps_example'); - respondToUser($userId, $oldMessageId, $editMsg, $editKeys, $sendMsg, [], $callbackResponse, $callbackId); - }else { - $userId = $update['message']['from']['id']; - $oldMessageId = $modifiers['oldMessageId']; + $editMsg = getTranslation("gym_create") . ':'; + $editKeys[0][] = [ + 'text' => getTranslation("abort"), + 'callback_data' => '0:gym_create:abort-' . $userInputId + ]; + $sendMsg = EMOJI_HERE . getTranslation('gym_gps_instructions') . CR; + $sendMsg .= getTranslation('gym_gps_example'); + respondToUser($userId, $oldMessageId, $editMsg, $editKeys, $sendMsg, [], $callbackResponse, $callbackId); + }else { + $userId = $update['message']['from']['id']; + $oldMessageId = $modifiers['oldMessageId']; - if($stage == 2) { - $input = $update['message']['text']; - $reg_exp_coordinates = '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$^'; - if(preg_match($reg_exp_coordinates, $input)) { - [$lat,$lon] = explode(',', $input, 2); - my_query("INSERT INTO gyms (gym_name, lat, lon) VALUES ('unknown', :lat, :lon)", [':lat' => $lat, ':lon' => $lon]); - $gymId = $dbh->lastInsertId(); + if($stage == 2) { + $input = $update['message']['text']; + $reg_exp_coordinates = '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$^'; + if(preg_match($reg_exp_coordinates, $input)) { + [$lat,$lon] = explode(',', $input, 2); + my_query('INSERT INTO gyms (gym_name, lat, lon) VALUES (\'unknown\', :lat, :lon)', [':lat' => $lat, ':lon' => $lon]); + $gymId = $dbh->lastInsertId(); - $userInputId = insertUserInput($userId, $stage, $oldMessageId, $gymId); - $msg = EMOJI_PENCIL . getTranslation('gym_name_instructions'); - respondToUser($userId, 0, '', [], $msg); - }else { - $msg = getTranslation('gym_gps_coordinates_format_error'); - respondToUser($userId, 0, '', [], $msg); - exit(); - } + $userInputId = insertUserInput($userId, $stage, $oldMessageId, $gymId); + $msg = EMOJI_PENCIL . getTranslation('gym_name_instructions'); + respondToUser($userId, 0, '', [], $msg); + }else { + $msg = getTranslation('gym_gps_coordinates_format_error'); + respondToUser($userId, 0, '', [], $msg); + exit(); + } - }elseif($stage == 3) { - $input = trim($update['message']['text']); - if(strlen($input) <= 255) { - $gymId = $modifiers['gymId']; - my_query("UPDATE gyms SET gym_name = :gym_name WHERE id = :gymId", [':gym_name' => $input, ':gymId' => $gymId]); + }elseif($stage == 3) { + $input = trim($update['message']['text']); + if(strlen($input) <= 255) { + $gymId = $modifiers['gymId']; + my_query('UPDATE gyms SET gym_name = :gym_name WHERE id = :gymId', [':gym_name' => $input, ':gymId' => $gymId]); - $msg = getTranslation('gym_added'); - $keys[] = [ - [ - 'text' => getTranslation('show_gym_details'), - 'callback_data' => 'N:gym_details:' . $gymId - ] - ]; - respondToUser($userId, $oldMessageId, 'OK', [], $msg, $keys); - }else { - $msg = getTranslation('gym_edit_text_too_long'); - respondToUser($userId, 0, '', [], $msg); - exit(); - } - } + $msg = getTranslation('gym_added'); + $keys[] = [ + [ + 'text' => getTranslation('show_gym_details'), + 'callback_data' => 'N:gym_details:' . $gymId + ] + ]; + respondToUser($userId, $oldMessageId, 'OK', [], $msg, $keys); + }else { + $msg = getTranslation('gym_edit_text_too_long'); + respondToUser($userId, 0, '', [], $msg); + exit(); + } } + } } diff --git a/mods/gym_delete.php b/mods/gym_delete.php index 03b076e6..0e1aaeb8 100644 --- a/mods/gym_delete.php +++ b/mods/gym_delete.php @@ -1,6 +1,8 @@ 0 && $delete == true && $confirm == false) { - $gym = get_gym($new_arg); - - // Set message - $msg = EMOJI_WARN . SP . '' . getTranslation('delete_this_gym') . '' . SP . EMOJI_WARN; - $msg .= CR . get_gym_details($gym); + $gym = get_gym($new_arg); - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => '0:gym_delete:' . $new_arg . '-delete-yes' - ] - ], - [ - [ - 'text' => getTranslation('no'), - 'callback_data' => $new_arg . ':gym_edit_details:' - ] - ] - ]; + // Set message + $msg = EMOJI_WARN . SP . '' . getTranslation('delete_this_gym') . '' . SP . EMOJI_WARN; + $msg .= CR . get_gym_details($gym); + + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('yes'), + 'callback_data' => '0:gym_delete:' . $new_arg . '-delete-yes' + ] + ], + [ + [ + 'text' => getTranslation('no'), + 'callback_data' => $new_arg . ':gym_edit_details:' + ] + ] + ]; // Delete the gym. } else if ($new_arg > 0 && $delete == true && $confirm == true) { - debug_log('Deleting gym with ID ' . $new_arg); - // Get gym. - $gym = get_gym($new_arg); - - // Set message - $msg = '' . getTranslation('deleted_this_gym') . '' . CR; - $msg .= get_gym_details($gym); - $keys = []; + require_once(LOGIC_PATH . '/get_gym_details.php'); + require_once(LOGIC_PATH . '/get_gym.php'); + debug_log('Deleting gym with ID ' . $new_arg); + // Get gym. + $gym = get_gym($new_arg); + + // Set message + $msg = '' . getTranslation('deleted_this_gym') . '' . CR; + $msg .= get_gym_details($gym); + $keys = []; - // Delete gym. - my_query( - " - DELETE FROM gyms - WHERE id = {$new_arg} - " - ); + // Delete gym. + my_query(' + DELETE FROM gyms + WHERE id = + ', [$new_arg] + ); } // Build callback message string. @@ -85,6 +88,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/gym_details.php b/mods/gym_details.php index 1d328815..2eb5a25d 100644 --- a/mods/gym_details.php +++ b/mods/gym_details.php @@ -1,6 +1,10 @@ ' . getTranslation('show_gym_details') . CR . CR . getTranslation('select_gym_name') . ''; - - // No keys found. - if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; - } else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $gymarea_id, 'gym_letter', 'gym_details', getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); - } + // Get hidden gyms? + $hidden = ($id == 0) ? true : false; + + // Get the keys. + $keys = raid_edit_gym_keys($arg, $gymarea_id, 'gym_details', false, $hidden); + + // Set keys. + $msg = '' . getTranslation('show_gym_details') . CR . CR . getTranslation('select_gym_name') . ''; + + // No keys found. + if (!$keys) { + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; + } else { + // Add navigation keys. + $nav_keys = []; + $nav_keys[] = universal_inner_key($nav_keys, $gymarea_id, 'gym_letter', 'gym_details', getTranslation('back')); + $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); + $nav_keys = inline_key_array($nav_keys, 2); + // Merge keys. + $keys = array_merge($keys, $nav_keys); + } // Get gym info. } else { - $gym = get_gym($arg); - $msg = get_gym_details($gym, true); + $gym = get_gym($arg); + $msg = get_gym_details($gym, true); - $keys = edit_gym_keys($update, $arg, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); + $keys = edit_gym_keys($update, $arg, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); } // Build callback message string. @@ -75,6 +75,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index 01aa286b..7a6892fd 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -1,6 +1,9 @@ $delete_id]); - if($action == 'note') { - my_query('UPDATE gyms SET gym_note = NULL WHERE id = :id', ['id' => $gym_id]); - $gym['gym_note'] = ''; - } - $msg = get_gym_details($gym, true); - $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); - }elseif($value == 'e') { - my_query('DELETE FROM user_input WHERE id = ?', [$delete_id]); - if($action == 'addr') { - $addr = format_address(get_address($gym['lat'], $gym['lon'])); - my_query('UPDATE gyms SET address = :addr WHERE id = :id', ['addr' => $addr, 'id' => $gym_id]); - $gym['address'] = $addr; - } - $msg = get_gym_details($gym, true); - $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); - }else { - // Create an entry to user_input table - $userid = $update['callback_query']['from']['id']; - $modifiers = json_encode(array("id" => $gym_id, "value" => $action, "old_message_id" => $update['callback_query']['message']['message_id'])); - $handler = "save_gym_info"; - - my_query('INSERT INTO user_input SET user_id = :userid, modifiers = :modifiers, handler = :handler', [':userid' => $userid, ':modifiers' => $modifiers, ':handler' => $handler]); - - $msg = get_gym_details($gym, true); - if($action == 'addr') $instructions = 'gym_address_instructions'; else $instructions = 'gym_'.$action.'_instructions'; - $msg .= CR . CR . '' . getTranslation($instructions) . ''; - if($action == 'gps') $msg .= CR. getTranslation('gym_gps_example'); - - $keys[0][] = [ - 'text' => getTranslation('abort'), - 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() - ]; - if($action == 'note' && !empty($gym['gym_note'])) { - $keys[0][] = [ - 'text' => getTranslation('delete'), - 'callback_data' => $gym_id.':gym_edit_details:note-d-'.$dbh->lastInsertId() - ]; - } - if($action == 'addr') { - $keys[0][] = [ - 'text' => getTranslation('gym_save_lookup_result'), - 'callback_data' => $gym_id.':gym_edit_details:addr-e-'.$dbh->lastInsertId() - ]; - } + if($value == 'd') { + my_query('DELETE FROM user_input WHERE id = :id', ['id' => $delete_id]); + if($action == 'note') { + my_query('UPDATE gyms SET gym_note = NULL WHERE id = :id', ['id' => $gym_id]); + $gym['gym_note'] = ''; } -}else { - if($action == 'show') { - $table = 'show_gym'; - }else if($action == 'ex') { - $table = 'ex_gym'; - }else if($action == 'abort') { - my_query('DELETE FROM user_input WHERE id = :value', ['value' => $value]); - } - if(isset($table)) { - my_query( - ' - UPDATE gyms - SET ' . $table . ' = :value - WHERE id = :gym_id - ', ['value' => $value, 'gym_id' => $gym_id] - ); - $gym[$table] = $value; + $msg = get_gym_details($gym, true); + $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); + }elseif($value == 'e') { + my_query('DELETE FROM user_input WHERE id = ?', [$delete_id]); + if($action == 'addr') { + $addr = format_address(get_address($gym['lat'], $gym['lon'])); + my_query('UPDATE gyms SET address = :addr WHERE id = :id', ['addr' => $addr, 'id' => $gym_id]); + $gym['address'] = $addr; } $msg = get_gym_details($gym, true); $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); + }else { + // Create an entry to user_input table + $userid = $update['callback_query']['from']['id']; + $modifiers = json_encode(array('id' => $gym_id, 'value' => $action, 'old_message_id' => $update['callback_query']['message']['message_id'])); + $handler = 'save_gym_info'; + + my_query('INSERT INTO user_input SET user_id = :userid, modifiers = :modifiers, handler = :handler', [':userid' => $userid, ':modifiers' => $modifiers, ':handler' => $handler]); + + $msg = get_gym_details($gym, true); + if($action == 'addr') $instructions = 'gym_address_instructions'; else $instructions = 'gym_'.$action.'_instructions'; + $msg .= CR . CR . '' . getTranslation($instructions) . ''; + if($action == 'gps') $msg .= CR. getTranslation('gym_gps_example'); + + $keys[0][] = [ + 'text' => getTranslation('abort'), + 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() + ]; + if($action == 'note' && !empty($gym['gym_note'])) { + $keys[0][] = [ + 'text' => getTranslation('delete'), + 'callback_data' => $gym_id.':gym_edit_details:note-d-'.$dbh->lastInsertId() + ]; + } + if($action == 'addr') { + $keys[0][] = [ + 'text' => getTranslation('gym_save_lookup_result'), + 'callback_data' => $gym_id.':gym_edit_details:addr-e-'.$dbh->lastInsertId() + ]; + } + } +}else { + if($action == 'show') { + $table = 'show_gym'; + }else if($action == 'ex') { + $table = 'ex_gym'; + }else if($action == 'abort') { + my_query('DELETE FROM user_input WHERE id = :value', ['value' => $value]); + } + if(isset($table)) { + my_query(' + UPDATE gyms + SET ' . $table . ' = :value + WHERE id = :gym_id + ', ['value' => $value, 'gym_id' => $gym_id] + ); + $gym[$table] = $value; + } + $msg = get_gym_details($gym, true); + $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); } // Build callback message string. @@ -113,6 +115,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/gym_hidden_letter.php b/mods/gym_hidden_letter.php index 97bb6ef0..dd7fecb4 100644 --- a/mods/gym_hidden_letter.php +++ b/mods/gym_hidden_letter.php @@ -1,6 +1,7 @@ accessCheck($update, 'gym-delete'); + // Check access. + $botUser->accessCheck($update, 'gym-delete'); - // Set message. - $msg = '' . getTranslation('gym_delete') . SP . '—' . SP . getTranslation('select_gym_first_letter') . ''; + // Set message. + $msg = '' . getTranslation('gym_delete') . SP . '—' . SP . getTranslation('select_gym_first_letter') . ''; } else { - // Force set arg. - $arg = 'gym_details'; + // Force set arg. + $arg = 'gym_details'; - // Check access. - $botUser->accessCheck($update, 'gym-details'); + // Check access. + $botUser->accessCheck($update, 'gym-details'); - // Set message. - $msg = '' . getTranslation('show_gym_details') . SP . '—' . SP . getTranslation('select_gym_first_letter') . ''; + // Set message. + $msg = '' . getTranslation('show_gym_details') . SP . '—' . SP . getTranslation('select_gym_first_letter') . ''; } // Set keys. @@ -34,7 +35,7 @@ // Set message. if(!$keys) { - $msg = CR . '' . getTranslation('no_hidden_gyms') . ''; + $msg = CR . '' . getTranslation('no_hidden_gyms') . ''; } // Add navigation keys. @@ -60,8 +61,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); - -?> diff --git a/mods/gym_letter.php b/mods/gym_letter.php index cb9bcf4b..d38117f2 100644 --- a/mods/gym_letter.php +++ b/mods/gym_letter.php @@ -1,6 +1,7 @@ accessCheck($update, 'gym-delete'); + // Check access. + $botUser->accessCheck($update, 'gym-delete'); - // Set message. - $msg = '' . getTranslation('gym_delete') . CR . getTranslation('select_gym_first_letter') . ''; - $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); + // Set message. + $msg = '' . getTranslation('gym_delete') . CR . getTranslation('select_gym_first_letter') . ''; + $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); } else { - // Force set arg. - $arg = 'gym_details'; + // Force set arg. + $arg = 'gym_details'; - // Check access. - $botUser->accessCheck($update, 'gym-details'); + // Check access. + $botUser->accessCheck($update, 'gym-details'); - // Set message. - $msg = '' . getTranslation('show_gym_details') . CR . getTranslation('select_gym_first_letter') . ''; - $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); + // Set message. + $msg = '' . getTranslation('show_gym_details') . CR . getTranslation('select_gym_first_letter') . ''; + $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); } $nav_keys = []; if($data['id'] != 'n' or $config->ENABLE_GYM_AREAS === false) { - $nav_keys[] = [ - 'text' => getTranslation('back'), - 'callback_data' => 'n:gym_letter:gym_details' - ]; - // Add key for hidden gyms. - $h_keys = []; - $h_keys[] = universal_inner_key($h_keys, $data['id'], 'gym_hidden_letter', $arg, getTranslation('hidden_gyms')); - $h_keys = inline_key_array($h_keys, 1); - // Merge keys. - $keys = array_merge($h_keys, $keys); + $nav_keys[] = [ + 'text' => getTranslation('back'), + 'callback_data' => 'n:gym_letter:gym_details' + ]; + // Add key for hidden gyms. + $h_keys = []; + $h_keys[] = universal_inner_key($h_keys, $data['id'], 'gym_hidden_letter', $arg, getTranslation('hidden_gyms')); + $h_keys = inline_key_array($h_keys, 1); + // Merge keys. + $keys = array_merge($h_keys, $keys); } $nav_keys[] = [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ]; + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' +]; $nav_keys = inline_key_array($nav_keys, 2); // Merge keys. $keys = array_merge($keys, $nav_keys); @@ -69,8 +70,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); - -?> diff --git a/mods/history.php b/mods/history.php index 1d17404a..c36d3ce8 100644 --- a/mods/history.php +++ b/mods/history.php @@ -17,74 +17,72 @@ $current_year_month = $data['arg']; if($current_day == 0) { - $msg_keys = create_history_date_msg_keys($current_year_month); - $msg = $msg_keys[0]; - $keys = $msg_keys[1]; + $msg_keys = create_history_date_msg_keys($current_year_month); + $msg = $msg_keys[0]; + $keys = $msg_keys[1]; }else { - $msg = getTranslation('history_title') . CR . CR; - $msg.= '' . getTranslation('date') . ': ' . getTranslation('month_' . substr($current_year_month,5)) . ' ' . $current_day . CR . CR; - $msg.= getTranslation('select_gym_first_letter'); - // Special/Custom gym letters? - if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { - // Explode special letters. - $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); - $select_query = 'CASE'; - foreach($special_keys as $id => $letter) - { - $letter = trim($letter); - debug_log($letter, 'Special gym letter:'); - // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); - $select_query .= SP . "WHEN UPPER(LEFT(gym_name, " . $length . ")) = '" . $letter . "' THEN UPPER(LEFT(gym_name, " . $length . "))" . SP; - } - $select_query .= 'ELSE UPPER(LEFT(gym_name, 1)) END'; - }else { - $select_query = 'DISTINCT UPPER(SUBSTR(gym_name, 1, 1))'; + $msg = getTranslation('history_title') . CR . CR; + $msg.= '' . getTranslation('date') . ': ' . getTranslation('month_' . substr($current_year_month,5)) . ' ' . $current_day . CR . CR; + $msg.= getTranslation('select_gym_first_letter'); + // Special/Custom gym letters? + if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { + // Explode special letters. + $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); + $select_query = 'CASE'; + foreach($special_keys as $id => $letter) + { + $letter = trim($letter); + debug_log($letter, 'Special gym letter:'); + // Fix chinese chars, prior: $length = strlen($letter); + $length = strlen(utf8_decode($letter)); + $select_query .= SP . "WHEN UPPER(LEFT(gym_name, " . $length . ")) = '" . $letter . "' THEN UPPER(LEFT(gym_name, " . $length . "))" . SP; } - $date = $current_year_month.'-'.$current_day; - - $rs = my_query( - ' - SELECT '.$select_query.' AS first_letter - FROM raids - LEFT JOIN gyms - ON raids.gym_id = gyms.id - LEFT JOIN attendance - ON attendance.raid_id = raids.id - WHERE date_format(start_time, "%Y-%m-%d") = \''.$date.'\' - AND raids.end_time < UTC_TIMESTAMP() - AND attendance.id IS NOT NULL - AND gyms.gym_name IS NOT NULL - ORDER BY first_letter - ' - ); - - // Init empty keys array. - $keys = []; - - while ($gym = $rs->fetch()) { + $select_query .= 'ELSE UPPER(LEFT(gym_name, 1)) END'; + }else { + $select_query = 'DISTINCT UPPER(SUBSTR(gym_name, 1, 1))'; + } + $date = $current_year_month.'-'.$current_day; + + $rs = my_query(' + SELECT '.$select_query.' AS first_letter + FROM raids + LEFT JOIN gyms + ON raids.gym_id = gyms.id + LEFT JOIN attendance + ON attendance.raid_id = raids.id + WHERE date_format(start_time, "%Y-%m-%d") = \''.$date.'\' + AND raids.end_time < UTC_TIMESTAMP() + AND attendance.id IS NOT NULL + AND gyms.gym_name IS NOT NULL + ORDER BY first_letter + '); + + // Init empty keys array. + $keys = []; + + while ($gym = $rs->fetch()) { // Add first letter to keys array - $keys[] = array( - 'text' => $gym['first_letter'], - 'callback_data' => $date . ':history_gyms:' . $gym['first_letter'] - ); - } - // Format buttons - $keys = inline_key_array($keys, 4); - - $nav_keys = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:history:' . $current_year_month - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - - // Get the inline key array. - $keys[] = $nav_keys; + $keys[] = array( + 'text' => $gym['first_letter'], + 'callback_data' => $date . ':history_gyms:' . $gym['first_letter'] + ); + } + // Format buttons + $keys = inline_key_array($keys, 4); + + $nav_keys = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:history:' . $current_year_month + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; + + // Get the inline key array. + $keys[] = $nav_keys; } @@ -98,7 +96,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); -?> diff --git a/mods/history_gyms.php b/mods/history_gyms.php index 4dec71d2..ca673897 100644 --- a/mods/history_gyms.php +++ b/mods/history_gyms.php @@ -25,64 +25,64 @@ // Special/Custom gym letters? $not = ''; if(!empty($config->RAID_CUSTOM_GYM_LETTERS) && $first_length == 1) { - // Explode special letters. - $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); - - foreach($special_keys as $id => $letter) - { - $letter = trim($letter); - debug_log($letter, 'Special gym letter:'); - // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); - $not .= SP . "AND UPPER(LEFT(gym_name, " . $length . ")) != UPPER('" . $letter . "')" . SP; - } + // Explode special letters. + $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); + + foreach($special_keys as $id => $letter) + { + $letter = trim($letter); + debug_log($letter, 'Special gym letter:'); + // Fix chinese chars, prior: $length = strlen($letter); + $length = strlen(utf8_decode($letter)); + $not .= SP . "AND UPPER(LEFT(gym_name, " . $length . ")) != UPPER('" . $letter . "')" . SP; + } } $query_collate = ""; -if($config->MYSQL_SORT_COLLATE != "") { - $query_collate = "COLLATE " . $config->MYSQL_SORT_COLLATE; +if($config->MYSQL_SORT_COLLATE != '') { + $query_collate = 'COLLATE ' . $config->MYSQL_SORT_COLLATE; } // Get gyms from database $rs = my_query( - ' - SELECT gyms.id, gyms.gym_name, gyms.ex_gym - FROM gyms - LEFT JOIN raids - ON raids.gym_id = gyms.id - LEFT JOIN attendance - ON attendance.raid_id = raids.id - WHERE UPPER(LEFT(gym_name, ' . $first_length . ')) = UPPER("' . $first . '") - AND date_format(start_time, "%Y-%m-%d") = "' . $current_date . '" - AND raids.end_time < UTC_TIMESTAMP() - AND attendance.id IS NOT NULL - ' . $not . ' - GROUP BY gym_name, raids.gym_id, gyms.id, gyms.ex_gym - ORDER BY gym_name ' . $query_collate - + ' + SELECT gyms.id, gyms.gym_name, gyms.ex_gym + FROM gyms + LEFT JOIN raids + ON raids.gym_id = gyms.id + LEFT JOIN attendance + ON attendance.raid_id = raids.id + WHERE UPPER(LEFT(gym_name, ' . $first_length . ')) = UPPER("' . $first . '") + AND date_format(start_time, "%Y-%m-%d") = "' . $current_date . '" + AND raids.end_time < UTC_TIMESTAMP() + AND attendance.id IS NOT NULL + ' . $not . ' + GROUP BY gym_name, raids.gym_id, gyms.id, gyms.ex_gym + ORDER BY gym_name ' . $query_collate + ); while ($gym = $rs->fetch()) { - // Show Ex-Gym-Marker? - if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { - $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; - $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; - } else { - $gym_name = $gym['gym_name']; - } - $keys[][] = [ - 'text' => $gym_name, - 'callback_data' => $current_date . '/' . $first . ':history_raids:' . $gym['id'] - ]; + // Show Ex-Gym-Marker? + if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { + $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; + $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; + } else { + $gym_name = $gym['gym_name']; + } + $keys[][] = [ + 'text' => $gym_name, + 'callback_data' => $current_date . '/' . $first . ':history_raids:' . $gym['id'] + ]; } $nav_keys = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $current_day.':history:' . $current_year_month - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] + [ + 'text' => getTranslation('back'), + 'callback_data' => $current_day.':history:' . $current_year_month + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ], ]; $keys[] = $nav_keys; @@ -99,5 +99,3 @@ curl_json_multi_request($tg_json); exit(); - -?> \ No newline at end of file diff --git a/mods/history_raid.php b/mods/history_raid.php index 90f925f1..dffbe0c3 100644 --- a/mods/history_raid.php +++ b/mods/history_raid.php @@ -1,6 +1,7 @@ getTranslation('back'), - 'callback_data' => $data['id'] . ':history_raids:' . $gym_id - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] + [ + 'text' => getTranslation('back'), + 'callback_data' => $data['id'] . ':history_raids:' . $gym_id + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ], ]; // Edit message. @@ -41,8 +42,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); - -?> \ No newline at end of file diff --git a/mods/history_raids.php b/mods/history_raids.php index f75e73c3..7cf229fd 100644 --- a/mods/history_raids.php +++ b/mods/history_raids.php @@ -18,38 +18,37 @@ $gym_id = $data['arg']; // Get raids from database -$rs = my_query( - ' - SELECT gyms.gym_name, raids.id, raids.start_time, raids.pokemon, raids.pokemon_form - FROM gyms - LEFT JOIN raids - ON raids.gym_id = gyms.id - LEFT JOIN attendance - ON attendance.raid_id = raids.id - WHERE gyms.id = "'.$gym_id.'" - AND raids.end_time < UTC_TIMESTAMP() - AND attendance.id IS NOT NULL - GROUP BY raids.id, raids.start_time, raids.pokemon, raids.pokemon_form, gyms.gym_name - ORDER BY start_time - ' +$rs = my_query(' + SELECT gyms.gym_name, raids.id, raids.start_time, raids.pokemon, raids.pokemon_form + FROM gyms + LEFT JOIN raids + ON raids.gym_id = gyms.id + LEFT JOIN attendance + ON attendance.raid_id = raids.id + WHERE gyms.id = ? + AND raids.end_time < UTC_TIMESTAMP() + AND attendance.id IS NOT NULL + GROUP BY raids.id, raids.start_time, raids.pokemon, raids.pokemon_form, gyms.gym_name + ORDER BY start_time + ', [$gym_id] ); while ($raid = $rs->fetch()) { - $keys[][] = [ - 'text' => dt2time($raid['start_time']) . ': ' . get_local_pokemon_name($raid['pokemon'],$raid['pokemon_form']), - 'callback_data' => $data['id'] . ':history_raid:' . $gym_id .'/' . $raid['id'] - ]; - $gym_name = $raid['gym_name']; - $start_time = $raid['start_time']; + $keys[][] = [ + 'text' => dt2time($raid['start_time']) . ': ' . get_local_pokemon_name($raid['pokemon'],$raid['pokemon_form']), + 'callback_data' => $data['id'] . ':history_raid:' . $gym_id .'/' . $raid['id'] + ]; + $gym_name = $raid['gym_name']; + $start_time = $raid['start_time']; } $nav_keys = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $current_date . ':history_gyms:' . $gym_first_letter - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] + [ + 'text' => getTranslation('back'), + 'callback_data' => $current_date . ':history_gyms:' . $gym_first_letter + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ], ]; $keys[] = $nav_keys; @@ -67,5 +66,3 @@ curl_json_multi_request($tg_json); exit(); - -?> \ No newline at end of file diff --git a/mods/import_future_bosses.php b/mods/import_future_bosses.php index 03dbbd29..0ee1464d 100644 --- a/mods/import_future_bosses.php +++ b/mods/import_future_bosses.php @@ -14,71 +14,64 @@ $arg = $data['arg']; if($arg == '1') { - try { - $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1;'; - $sql .= read_upcoming_bosses(true); - $query = $dbh->prepare($sql); - $query->execute(); - $msg = getTranslation('import_done'); - }catch (PDOException $exception) { - $msg = getTranslation('internal_error') . CR; - $msg.= $exception->getMessage(); - info_log($exception->getMessage()); - } - $keys = []; + $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1;'; + $sql .= read_upcoming_bosses(true); + $query = my_query($sql); + $msg = getTranslation('import_done'); + $keys = []; }else { - $list = read_upcoming_bosses(); - $msg = ''; - if(!empty($list)) { - $now = new DateTime('now', new DateTimeZone($config->TIMEZONE)); - $query = my_query(" - SELECT id, pokedex_id, pokemon_form_id, raid_level, scheduled, DATE_FORMAT(date_start, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_start, DATE_FORMAT(date_end, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_end FROM raid_bosses - WHERE date_end > '" . $now->format('Y-m-d H:i:s') . "' - AND scheduled = 1 - ORDER BY date_start, raid_level, pokedex_id, pokemon_form_id - "); - $prev_start = $prev_rl = ''; - $msg = '' . getTranslation('current_scheduled_bosses') . ':'; - foreach($query->fetchAll() as $result) { - if($prev_start != $result['date_start']) { - $msg.= CR . EMOJI_CLOCK . ' ' . $result['date_start'] . ' — ' . $result['date_end'] . ':' . CR; - $prev_rl = ''; - } - if($prev_rl != $result['raid_level']) { - $msg.= '' . getTranslation($result['raid_level'] . 'stars') .':' . CR; - } - $msg.= get_local_pokemon_name($result['pokedex_id'], $result['pokemon_form_id']) . CR; - $prev_start = $result['date_start']; - $prev_rl = $result['raid_level']; - } - $msg .= CR . CR . '' . getTranslation('found_upcoming_bosses') . ':'; - $msg .= $list; - $msg .= CR . CR . getTranslation('confirm_replace_upcoming'); - $keys = [ - [ - [ - 'text' => getTranslation('replace'), - 'callback_data' => '1:import_future_bosses:1' - ] - ], - [ - [ - 'text'=>getTranslation('back'), - 'callback_data' => '0:pokedex_import:0' - ] - ] - ]; - }else { - $msg .= getTranslation('upcoming_bosses_not_found'); - $keys = [ - [ - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; + $list = read_upcoming_bosses(); + $msg = ''; + if(!empty($list)) { + $now = new DateTime('now', new DateTimeZone($config->TIMEZONE)); + $query = my_query(" + SELECT id, pokedex_id, pokemon_form_id, raid_level, scheduled, DATE_FORMAT(date_start, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_start, DATE_FORMAT(date_end, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_end FROM raid_bosses + WHERE date_end > '" . $now->format('Y-m-d H:i:s') . "' + AND scheduled = 1 + ORDER BY date_start, raid_level, pokedex_id, pokemon_form_id + "); + $prev_start = $prev_rl = ''; + $msg = '' . getTranslation('current_scheduled_bosses') . ':'; + foreach($query->fetchAll() as $result) { + if($prev_start != $result['date_start']) { + $msg.= CR . EMOJI_CLOCK . ' ' . $result['date_start'] . ' — ' . $result['date_end'] . ':' . CR; + $prev_rl = ''; + } + if($prev_rl != $result['raid_level']) { + $msg.= '' . getTranslation($result['raid_level'] . 'stars') .':' . CR; + } + $msg.= get_local_pokemon_name($result['pokedex_id'], $result['pokemon_form_id']) . CR; + $prev_start = $result['date_start']; + $prev_rl = $result['raid_level']; } + $msg .= CR . CR . '' . getTranslation('found_upcoming_bosses') . ':'; + $msg .= $list; + $msg .= CR . CR . getTranslation('confirm_replace_upcoming'); + $keys = [ + [ + [ + 'text' => getTranslation('replace'), + 'callback_data' => '1:import_future_bosses:1' + ] + ], + [ + [ + 'text'=>getTranslation('back'), + 'callback_data' => '0:pokedex_import:0' + ] + ] + ]; + }else { + $msg .= getTranslation('upcoming_bosses_not_found'); + $keys = [ + [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ] + ]; + } } // Callback message string. @@ -96,7 +89,4 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); -$dbh = null; exit(); - -?> \ No newline at end of file diff --git a/mods/import_shinyinfo.php b/mods/import_shinyinfo.php index c6e3586d..36c94fe8 100644 --- a/mods/import_shinyinfo.php +++ b/mods/import_shinyinfo.php @@ -1,6 +1,7 @@ accessCheck($update, 'pokedex'); +include(LOGIC_PATH . '/resolve_boss_name_to_ids.php'); // Get raid levels $id = $data['id']; @@ -25,106 +27,41 @@ $shinydata = []; foreach($pb_data['tiers'] as $tier) { - // Raid level and message. - $rl = str_replace('RAID_LEVEL_','', $tier['tier']); - if($rl == "MEGA") $raid_level_id = 6; else $raid_level_id = $rl; - $rl_parts = explode('_', $rl); - if($rl_parts[count($rl_parts)-1] == 'FUTURE') continue; - #$msg .= '' . getTranslation('pokedex_raid_level') . SP . $rl . ':' . CR; - - // Get raid bosses for each raid level. - foreach($tier['raids'] as $raid) { - if(!isset($raid['pokemon']) || $raid['shiny'] != 'true') continue; - // Pokemon name ending with "_FORM" ? - if(substr_compare($raid['pokemon'], '_FORM', -strlen('_FORM')) === 0) { - debug_log('Pokemon with a special form received: ' . $raid['pokemon']); - // Remove "_FORM" - $pokemon = str_replace('_FORM', '', $raid['pokemon']); - - // Get pokemon name and form. - $name = explode("_", $pokemon, 2)[0]; - $form = explode("_", $pokemon, 2)[1]; - - // Fix for MEWTWO_A_FORM - if($name == 'MEWTWO' && $form == 'A') { - $form = 'ARMORED'; - } - - // Pokemon name ending with "_MALE" ? - } else if(substr_compare($raid['pokemon'], '_MALE', -strlen('_MALE')) === 0) { - debug_log('Pokemon with gender MALE received: ' . $raid['pokemon']); - // Remove "_MALE" - $pokemon = str_replace('_MALE', '', $raid['pokemon']); - - // Get pokemon name and form. - $name = explode("_", $pokemon, 2)[0] . '♂'; - $form = 'normal'; - - // Pokemon name ending with "_FEMALE" ? - } else if(substr_compare($raid['pokemon'], '_FEMALE', -strlen('_FEMALE')) === 0) { - debug_log('Pokemon with gender FEMALE received: ' . $raid['pokemon']); - // Remove "_FEMALE" - $pokemon = str_replace('_FEMALE', '', $raid['pokemon']); - - // Get pokemon name and form. - $name = explode("_", $pokemon, 2)[0] . '♀'; - $form = 'normal'; - - // Mega pokemon ? - }else if(substr_compare($raid['pokemon'], '_MEGA', -strlen('_MEGA')) === 0 or substr_compare($raid['pokemon'], '_MEGA_X', -strlen('_MEGA_X')) === 0 or substr_compare($raid['pokemon'], '_MEGA_Y', -strlen('_MEGA_Y')) === 0) { - debug_log('Mega Pokemon received: ' . $raid['pokemon']); - - // Get pokemon name and form. - $name_form = explode("_", $raid['pokemon'], 2); - $name = $name_form[0]; - $form = $name_form[1]; - - // Normal pokemon without form or gender. - } else { - // Fix pokemon like "HO_OH"... - if(substr_count($raid['pokemon'], '_') >= 1) { - $pokemon = str_replace('_', '-', $raid['pokemon']); - } else { - $pokemon = $raid['pokemon']; - } - // Name and form. - $name = $pokemon; - $form = 'normal'; - - // Fix for GIRATINA as the actual GIRATINA_ALTERED_FORM is just GIRATINA - if($name == 'GIRATINA' && $form == 'normal') { - $form = 'ALTERED'; - } - } - if($form != 'normal') continue; - // Get ID and form name used internally. - debug_log('Getting dex id and form for pokemon ' . $name . ' with form ' . $form); - $dex_id_form = get_pokemon_id_by_name($name . '-' . $form, true); - $dex_id = explode('-', $dex_id_form, 2)[0]; - $dex_form = explode('-', $dex_id_form, 2)[1]; - - // Make sure we received a valid dex id. - if(!is_numeric($dex_id) || $dex_id == 0) { - info_log('Failed to get a valid pokemon dex id: '. $dex_id .' Continuing with next raid boss...'); - continue; - } - - $shinydata[] = [':dex_id' => $dex_id, ':dex_form' => $dex_form]; + // Raid level and message. + $rl = str_replace('RAID_LEVEL_','', $tier['tier']); + if($rl == "MEGA") $raid_level_id = 6; else $raid_level_id = $rl; + $rl_parts = explode('_', $rl); + if($rl_parts[count($rl_parts)-1] == 'FUTURE') continue; + #$msg .= '' . getTranslation('pokedex_raid_level') . SP . $rl . ':' . CR; + + // Get raid bosses for each raid level. + foreach($tier['raids'] as $raid) { + if(!isset($raid['pokemon']) || $raid['shiny'] != 'true') continue; + + // Get ID and form name used internally. + [$dex_id, $dex_form] = resolve_boss_name_to_ids($raid['pokemon']); + + // Make sure we received a valid dex id. + if(!is_numeric($dex_id) || $dex_id == 0) { + info_log('Failed to get a valid pokemon dex id: '. $dex_id .', pokemon: ' . $raid['pokemon'] . '. Continuing with next raid boss...', 'Import shinyinfo:'); + continue; } - $msg .= CR; + $shinydata[] = [':dex_id' => $dex_id, ':dex_form' => $dex_form]; + } + $msg .= CR; } - // Back button. - $keys[] = [ - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ]; +// Back button. +$keys[] = [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] +]; if(count($shinydata) > 0) { - $query = $dbh->prepare("UPDATE pokemon SET shiny = 1 WHERE pokedex_id = :dex_id AND pokemon_form_id = :dex_form"); - foreach($shinydata as $row_data) { - $query->execute($row_data); - } + $query = $dbh->prepare("UPDATE pokemon SET shiny = 1 WHERE pokedex_id = :dex_id AND pokemon_form_id = :dex_form"); + foreach($shinydata as $row_data) { + $query->execute($row_data); + } } $msg .= 'Updated '.count($shinydata).' rows'.CR; @@ -143,6 +80,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/importal.php b/mods/importal.php index 4eabb6cc..9a09fab6 100644 --- a/mods/importal.php +++ b/mods/importal.php @@ -1,6 +1,9 @@ accessCheck($update, 'portal-import'); - function escape($value){ - $search = array("\\", "\x00", "\n", "\r", "'", '"', "\x1a"); - $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z"); + $search = array("\\", "\x00", "\n", "\r", "'", '"', "\x1a"); + $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z"); - return str_replace($search, $replace, $value); + return str_replace($search, $replace, $value); } // Import allowed? -if($config->PORTAL_IMPORT) { - - // Process message for portal information. - require_once(CORE_BOT_PATH . '/importal.php'); - - // Insert gym. - try { - - global $dbh; - - // Gym name. - $gym_name = $portal; - if(empty($portal)) { - $gym_name = '#' . $update['message']['from']['id']; - } - - // Gym image. - if($config->RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY) { - $no_spaces_gym_name = str_replace(array(' ', '\''), array('_', ''), $gym_name) . '.png'; - $gym_image = download_Portal_Image($portal_image, PORTAL_IMAGES_PATH, $no_spaces_gym_name); - if($gym_image) { - $gym_image = "file://" . $gym_image; - } - } else { - $gym_image = $portal_image; - } - - $gym_name_no_spec = escape($portal); // Convert special characters in gym name - // Build query to check if gym is already in database or not - // First check if gym is found by portal id - $gym_query = 'SELECT id FROM gyms WHERE gym_id = :gym_id LIMIT 1'; - $gym_statement = $dbh->prepare($gym_query); - $gym_statement->execute(['gym_id' => $portal_id]); - if($gym_statement->rowCount() == 1) { - $row = $gym_statement->fetch(); - $update_where_condition = 'gym_id = :gym_id'; - $update_values = ''; - }else { - // If portal id wasn't found, check by gym name - $gym_query_by_name = 'SELECT id FROM gyms WHERE gym_name = :gym_name LIMIT 1'; - $gym_statement_by_name = $dbh->prepare($gym_query_by_name); - $gym_statement_by_name->execute(['gym_name' => $gym_name_no_spec]); - $row = $gym_statement_by_name->fetch(); - $update_where_condition = 'gym_name = :gym_name'; - $update_values = 'gym_id = :gym_id, '; - } - - // Gym already in database or new - if (empty($row['id'])) { - // insert gym in table. - debug_log('Gym not found in database gym list! Inserting gym "' . $gym_name . '" now.'); - $query = ' - INSERT INTO gyms (gym_name, lat, lon, address, show_gym, img_url, gym_id) - VALUES (:gym_name, :lat, :lon, :address, 0, :gym_image, :gym_id) - '; - $msg = getTranslation('gym_added'); - - } else { - // Update gyms table to reflect gym changes. - debug_log('Gym found in database gym list! Updating gym "' . $gym_name . '" now.'); - $query = ' - UPDATE gyms - SET lat = :lat, - lon = :lon, - gym_name = :gym_name, - address = :address, - ' . $update_values . ' - img_url = :gym_image - WHERE ' . $update_where_condition . ' - '; - $msg = getTranslation('gym_updated'); - $gym_id = $row['id']; - } - - // Insert / Update. - $statement = $dbh->prepare($query); - $statement->execute([ - 'gym_name' => $gym_name_no_spec, - 'lat' => $lat, - 'lon' => $lon, - 'address' => $address, - 'gym_image' => $gym_image, - 'gym_id' => $portal_id - ]); - } catch (PDOException $exception) { - error_log($exception->getMessage()); - $dbh = null; - exit(); - } - - // Get last insert id. - if (empty($row['id'])) { - $gym_id = $dbh->lastInsertId(); - } - - // Gym details. - if($gym_id > 0) { - $gym = get_gym($gym_id); - $msg .= CR . CR . get_gym_details($gym); - } - - // Gym photo. - if($config->RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY && $gym_image) { - $msg .= EMOJI_CAMERA . SP . $no_spaces_gym_name; - } - - // Set keys. - $keys = [ - [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => $gym_name[0] . ':gym_delete:' . $gym_id . '-delete' - ], - [ - 'text' => getTranslation('show_gym'), - 'callback_data' => $gym_id . ':gym_edit_details:show-1' - ] - ], - [ - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; +if(!$config->PORTAL_IMPORT) { + $msg = getTranslation('bot_access_denied'); + $keys = []; + send_message($update['message']['chat']['id'], $msg, $keys, ['disable_web_page_preview' => 'true']); + exit; +} + +// Process message for portal information. +require_once(CORE_BOT_PATH . '/importal.php'); +// Gym name. +$gym_name = $portal; +if(empty($portal)) { + $gym_name = '#' . $update['message']['from']['id']; +} + +// Gym image. +if($config->RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY) { + $no_spaces_gym_name = str_replace(array(' ', '\''), array('_', ''), $gym_name) . '.png'; + $gym_image = download_Portal_Image($portal_image, PORTAL_IMAGES_PATH, $no_spaces_gym_name); + if($gym_image) { + $gym_image = "file://" . $gym_image; + } } else { - $msg = getTranslation('bot_access_denied'); - $keys = []; + $gym_image = $portal_image; } +$gym_name_no_spec = escape($portal); // Convert special characters in gym name +// Build query to check if gym is already in database or not +// First check if gym is found by portal id +$gym_statement = my_query('SELECT id FROM gyms WHERE gym_id = :gym_id LIMIT 1', ['gym_id' => $portal_id]); +if($gym_statement->rowCount() == 1) { + $row = $gym_statement->fetch(); + $update_where_condition = 'gym_id = :gym_id'; + $update_values = ''; +}else { + // If portal id wasn't found, check by gym name + $gym_statement_by_name = my_query('SELECT id FROM gyms WHERE gym_name = :gym_name LIMIT 1', ['gym_name' => $gym_name_no_spec]); + $row = $gym_statement_by_name->fetch(); + $update_where_condition = 'gym_name = :gym_name'; + $update_values = 'gym_id = :gym_id, '; +} + +// Gym already in database or new +if (empty($row['id'])) { + // insert gym in table. + debug_log('Gym not found in database gym list! Inserting gym "' . $gym_name . '" now.'); + $query = ' + INSERT INTO gyms (gym_name, lat, lon, address, show_gym, img_url, gym_id) + VALUES (:gym_name, :lat, :lon, :address, 0, :gym_image, :gym_id) + '; + $msg = getTranslation('gym_added'); + +} else { + // Update gyms table to reflect gym changes. + debug_log('Gym found in database gym list! Updating gym "' . $gym_name . '" now.'); + $query = ' + UPDATE gyms + SET lat = :lat, + lon = :lon, + gym_name = :gym_name, + address = :address, + ' . $update_values . ' + img_url = :gym_image + WHERE ' . $update_where_condition . ' + '; + $msg = getTranslation('gym_updated'); + $gym_id = $row['id']; +} + +// Insert / Update. +$statement = my_query( + $query,[ + 'gym_name' => $gym_name_no_spec, + 'lat' => $lat, + 'lon' => $lon, + 'address' => $address, + 'gym_image' => $gym_image, + 'gym_id' => $portal_id +]); + + +// Get last insert id. +if (empty($row['id'])) { + $gym_id = $dbh->lastInsertId(); +} + +// Gym details. +if($gym_id > 0) { + $gym = get_gym($gym_id); + $msg .= CR . CR . get_gym_details($gym); +} + +// Gym photo. +if($config->RAID_PICTURE_STORE_GYM_IMAGES_LOCALLY && $gym_image) { + $msg .= EMOJI_CAMERA . SP . $no_spaces_gym_name; +} + +// Set keys. +$keys = [ + [ + [ + 'text' => getTranslation('delete'), + 'callback_data' => $gym_name[0] . ':gym_delete:' . $gym_id . '-delete' + ], + [ + 'text' => getTranslation('show_gym'), + 'callback_data' => $gym_id . ':gym_edit_details:show-1' + ] + ], + [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ] +]; + // Send the message. send_message($update['message']['chat']['id'], $msg, $keys, ['disable_web_page_preview' => 'true']); - -?> diff --git a/mods/list_by_gym.php b/mods/list_by_gym.php index 4a73be46..9c9eb84a 100644 --- a/mods/list_by_gym.php +++ b/mods/list_by_gym.php @@ -1,6 +1,7 @@ getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); + // Add navigation keys. + $nav_keys = []; + $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); + $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); + $nav_keys = inline_key_array($nav_keys, 2); + // Merge keys. + $keys = array_merge($keys, $nav_keys); } // Build callback message string. @@ -57,6 +58,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/list_by_gym_letter.php b/mods/list_by_gym_letter.php index e310824a..59d1915d 100644 --- a/mods/list_by_gym_letter.php +++ b/mods/list_by_gym_letter.php @@ -1,6 +1,7 @@ getTranslation('not_supported'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('not_supported'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } // Build callback message string. @@ -48,25 +49,22 @@ // Edit the message. $msg = '' . getTranslation('list_all_active_raids') . '' . CR; if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; + if($keys_and_gymarea['gymarea_name'] == '') { + $msg .= '' . getTranslation('select_gym_area') . '' . CR; + }else { + if($keys_and_gymarea['letters']) { + $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } + $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; } + } }elseif($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; + $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; + $msg .= '' . getTranslation('select_gym_name') . '' . CR; } $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); $tg_json[] = edit_message($update, $msg, $keys, false, true); // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/list_raid.php b/mods/list_raid.php index ea44fecb..74c87662 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -1,6 +1,8 @@ UTC_TIMESTAMP() - INTERVAL 10 MINUTE - {$sql_condition} - ", - $binds +$rs = my_query(' + SELECT raids.id + FROM raids + LEFT JOIN gyms + ON raids.gym_id = gyms.id + WHERE end_time > UTC_TIMESTAMP() - INTERVAL 10 MINUTE + ' . $sql_condition . ' + ', + $binds ); if($rs->rowcount() == 1) { - // Get the row. - $raid_fetch = $rs->fetch(); - $raid = get_raid($raid_fetch['id']); + // Get the row. + $raid_fetch = $rs->fetch(); + $raid = get_raid($raid_fetch['id']); - debug_log($raid); + debug_log($raid); - // Create keys array. - $keys = [ + // Create keys array. + $keys = [ + [ + [ + 'text' => getTranslation('expand'), + 'callback_data' => $raid['id'] . ':vote_refresh:0', + ] + ] + ]; + if($botUser->raidAccessCheck($update, $raid_id, 'pokemon', true)) { + $keys[] = [ + [ + 'text' => getTranslation('update_pokemon'), + 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], + ] + ]; + } + if($botUser->raidAccessCheck($update, $raid_id, 'delete', true)) { + $keys[] = [ [ - [ - 'text' => getTranslation('expand'), - 'callback_data' => $raid['id'] . ':vote_refresh:0', - ] + 'text' => getTranslation('delete'), + 'callback_data' => $raid['id'] . ':raids_delete:0' ] ]; - if($botUser->raidAccessCheck($update, $raid_id, 'pokemon', true)) { - $keys[] = [ - [ - 'text' => getTranslation('update_pokemon'), - 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], - ] - ]; - } - if($botUser->raidAccessCheck($update, $raid_id, 'delete', true)) { - $keys[] = [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => $raid['id'] . ':raids_delete:0' - ] - ]; - } + } - // Add keys to share. - debug_log($raid, 'raw raid data for share: '); - $keys_share = share_keys($raid['id'], 'raid_share', $update, $raid['level']); - if(!empty($keys_share)) { - $keys = array_merge($keys, $keys_share); - } else { - debug_log('There are no groups to share to, is SHARE_CHATS set?'); - } - // Exit key - $keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); + // Add keys to share. + debug_log($raid, 'raw raid data for share: '); + $keys_share = share_keys($raid['id'], 'raid_share', $update, $raid['level']); + if(!empty($keys_share)) { + $keys = array_merge($keys, $keys_share); + } else { + debug_log('There are no groups to share to, is SHARE_CHATS set?'); + } + // Exit key + $keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); - // Get message. - $msg = show_raid_poll_small($raid); + // Get message. + $msg = show_raid_poll_small($raid); }else { - $msg = getTranslation('list_all_active_raids').':'. CR; - $keys = []; - $i = 1; - while($raid_fetch = $rs->fetch()) { - $raid = get_raid($raid_fetch['id']); - $raid_pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']); - $msg .= '' . $i .'. ' . $raid_pokemon_name . '' . CR; - if(!empty($raid['event_name'])) $msg .= $raid['event_name'] . CR; - $msg .= get_raid_times($raid,false, true) . CR . CR; - $keys[] = [ - [ - 'text' => $i . '. ' . $raid_pokemon_name, - 'callback_data' => $raid['id'] . ':list_raid:0' - ] - ]; - $i++; - } + $msg = getTranslation('list_all_active_raids').':'. CR; + $keys = []; + $i = 1; + while($raid_fetch = $rs->fetch()) { + $raid = get_raid($raid_fetch['id']); + $raid_pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']); + $msg .= '' . $i .'. ' . $raid_pokemon_name . '' . CR; + if(!empty($raid['event_name'])) $msg .= $raid['event_name'] . CR; + $msg .= get_raid_times($raid,false, true) . CR . CR; $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:list_by_gym:' . $raid['gym_name'][0] - ] + [ + 'text' => $i . '. ' . $raid_pokemon_name, + 'callback_data' => $raid['id'] . ':list_raid:0' + ] ]; + $i++; + } + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:list_by_gym:' . $raid['gym_name'][0] + ] + ]; } // Build callback message string. @@ -119,6 +120,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/list_remote_gyms.php b/mods/list_remote_gyms.php index 24326b5d..9fb90433 100644 --- a/mods/list_remote_gyms.php +++ b/mods/list_remote_gyms.php @@ -16,11 +16,11 @@ // Get the keys. $query_remote = my_query('SELECT raids.id, gyms.gym_name, raids.start_time, raids.end_time FROM gyms LEFT JOIN raids on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); while($gym = $query_remote->fetch()) { - $keys[][] = [ - 'text' => $gym['gym_name'], - 'callback_data' => $gym['id'] . ':list_raid:' - ]; -} + $keys[][] = [ + 'text' => $gym['gym_name'], + 'callback_data' => $gym['id'] . ':list_raid:' + ]; +} // Add navigation keys. $nav_keys = []; $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); @@ -29,7 +29,6 @@ // Merge keys. $keys = array_merge($keys, $nav_keys); - // Build callback message string. $callback_response = getTranslation('here_we_go'); @@ -44,6 +43,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/listall.php b/mods/listall.php index 87885b56..b93149a7 100644 --- a/mods/listall.php +++ b/mods/listall.php @@ -1,6 +1,7 @@ ' . getTranslation('list_all_active_raids') . '' . CR; if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; - }elseif($config->DEFAULT_GYM_AREA !== false) { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } + if($keys_and_gymarea['gymarea_name'] == '') { + $msg .= '' . getTranslation('select_gym_area') . '' . CR; + }elseif($config->DEFAULT_GYM_AREA !== false) { + if($keys_and_gymarea['letters']) { + $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; - } + $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; } -}else { + }else { if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; + $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; + $msg .= '' . getTranslation('select_gym_name') . '' . CR; } + } +}else { + if($keys_and_gymarea['letters']) { + $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; + }else { + $msg .= '' . getTranslation('select_gym_name') . '' . CR; + } } $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); $tg_json[] = edit_message($update, $msg, $keys, false, true); // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/overview_delete.php b/mods/overview_delete.php index dd92e87d..985ab0bc 100644 --- a/mods/overview_delete.php +++ b/mods/overview_delete.php @@ -18,98 +18,94 @@ // Get all or specific overview if ($chat_id == 0) { - $request_overviews = my_query( - " - SELECT * - FROM overview - " - ); - - // Count results. - $count = 0; - - while ($rowOverviews = $request_overviews->fetch()) { - // Counter++ - $count = $count + 1; - - // Get info about chat for title. - debug_log('Getting chat object for chat_id: ' . $rowOverviews['chat_id']); - $chat_obj = get_chat($rowOverviews['chat_id']); - $chat_title = ''; - - // Set title. - if ($chat_obj['ok'] == 'true') { - $chat_title = $chat_obj['result']['title']; - debug_log('Title of the chat: ' . $chat_obj['result']['title']); - } - - // Build message string. - $msg = '' . getTranslation('delete_raid_overview_for_chat') . ' ' . $chat_title . '?'; - - // Set keys - Delete button. - $keys = [ - [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => '0:overview_delete:' . $rowOverviews['chat_id'] - ], - [ - 'text' => getTranslation('no'), - 'callback_data' => '0:overview_delete:1' - ] - ] - ]; - - // Send the message, but disable the web preview! - $tg_json[] = send_message($update['callback_query']['message']['chat']['id'], $msg, $keys, false, true); + $request_overviews = my_query(' + SELECT * + FROM overview + '); + + // Count results. + $count = 0; + + while ($rowOverviews = $request_overviews->fetch()) { + // Counter++ + $count = $count + 1; + + // Get info about chat for title. + debug_log('Getting chat object for chat_id: ' . $rowOverviews['chat_id']); + $chat_obj = get_chat($rowOverviews['chat_id']); + $chat_title = ''; + + // Set title. + if ($chat_obj['ok'] == 'true') { + $chat_title = $chat_obj['result']['title']; + debug_log('Title of the chat: ' . $chat_obj['result']['title']); } - // Set message. - if($count == 0) { - $callback_msg = '' . getTranslation('no_overviews_found') . ''; - } else { - $callback_msg = '' . getTranslation('list_all_overviews') . ':'; - } + // Build message string. + $msg = '' . getTranslation('delete_raid_overview_for_chat') . ' ' . $chat_title . '?'; + + // Set keys - Delete button. + $keys = [ + [ + [ + 'text' => getTranslation('yes'), + 'callback_data' => '0:overview_delete:' . $rowOverviews['chat_id'] + ], + [ + 'text' => getTranslation('no'), + 'callback_data' => '0:overview_delete:1' + ] + ] + ]; + + // Send the message, but disable the web preview! + $tg_json[] = send_message($update['callback_query']['message']['chat']['id'], $msg, $keys, false, true); + } + + // Set message. + if($count == 0) { + $callback_msg = '' . getTranslation('no_overviews_found') . ''; + } else { + $callback_msg = '' . getTranslation('list_all_overviews') . ':'; + } } else if ($chat_id == 1) { - // Write to log. - debug_log('Deletion of the raid overview was canceled!'); + // Write to log. + debug_log('Deletion of the raid overview was canceled!'); - // Set message. - $callback_msg = '' . getTranslation('overview_deletion_was_canceled') . ''; + // Set message. + $callback_msg = '' . getTranslation('overview_deletion_was_canceled') . ''; } else { - // Write to log. - debug_log('Triggering deletion of overview for Chat_ID ' . $chat_id); - - // Get chat and message ids for overview. - $request_overviews = my_query( - " - SELECT * - FROM overview - WHERE chat_id = '{$chat_id}' - " - ); - - $overview = $request_overviews->fetch(); - - // Delete overview - $chat_id = $overview['chat_id']; - $message_id = $overview['message_id']; - - // Delete telegram message. - debug_log('Deleting overview telegram message ' . $message_id . ' from chat ' . $chat_id); - delete_message($chat_id, $message_id); - - // Delete overview from database. - debug_log('Deleting overview information from database for Chat_ID: ' . $chat_id); - $rs = my_query( - " - DELETE FROM overview - WHERE chat_id = '{$chat_id}' - " - ); - - // Set message. - $callback_msg = '' . getTranslation('overview_successfully_deleted') . ''; + // Write to log. + debug_log('Triggering deletion of overview for Chat_ID ' . $chat_id); + + // Get chat and message ids for overview. + $request_overviews = my_query(' + SELECT * + FROM overview + WHERE chat_id = ? + ', [$chat_id] + ); + + $overview = $request_overviews->fetch(); + + // Delete overview + $chat_id = $overview['chat_id']; + $message_id = $overview['message_id']; + + // Delete telegram message. + debug_log('Deleting overview telegram message ' . $message_id . ' from chat ' . $chat_id); + delete_message($chat_id, $message_id); + + // Delete overview from database. + debug_log('Deleting overview information from database for Chat_ID: ' . $chat_id); + $rs = my_query(' + DELETE FROM overview + WHERE chat_id = ? + ', [$chat_id] + ); + + // Set message. + $callback_msg = '' . getTranslation('overview_successfully_deleted') . ''; } // Set keys. @@ -126,7 +122,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -$dbh = null; -exit(); diff --git a/mods/overview_refresh.php b/mods/overview_refresh.php index 2428bba1..15ee9120 100644 --- a/mods/overview_refresh.php +++ b/mods/overview_refresh.php @@ -1,6 +1,8 @@ fetchAll(); @@ -31,71 +31,71 @@ $active_raids = []; $tg_json = []; foreach($overviews as $overview_row) { - $request_raids = my_query(' - SELECT raids.pokemon, raids.pokemon_form, raids.spawn, raids.level, raids.id, raids.start_time, raids.end_time, raids.gym_id, - MAX(cleanup.message_id) as message_id, - events.name as event_name, - gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, - TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left - FROM cleanup - LEFT JOIN raids - ON raids.id = cleanup.raid_id - LEFT JOIN gyms - ON raids.gym_id = gyms.id - LEFT JOIN events - ON events.id = raids.event - WHERE cleanup.chat_id = \'' . $overview_row['chat_id'] . '\' - AND raids.end_time>UTC_TIMESTAMP() - GROUP BY raids.id, raids.pokemon, raids.pokemon_form, raids.start_time, raids.end_time, raids.gym_id, gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, events.name - ORDER BY raids.end_time ASC, gyms.gym_name - '); - // Write active raids to array - $active_raids = $request_raids->fetchAll(); - debug_log('Active raids:'); - debug_log($active_raids); + $request_raids = my_query(' + SELECT raids.pokemon, raids.pokemon_form, raids.spawn, raids.level, raids.id, raids.start_time, raids.end_time, raids.gym_id, + MAX(cleanup.message_id) as message_id, + events.name as event_name, + gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, + TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left + FROM cleanup + LEFT JOIN raids + ON raids.id = cleanup.raid_id + LEFT JOIN gyms + ON raids.gym_id = gyms.id + LEFT JOIN events + ON events.id = raids.event + WHERE cleanup.chat_id = ? + AND raids.end_time>UTC_TIMESTAMP() + GROUP BY raids.id, raids.pokemon, raids.pokemon_form, raids.start_time, raids.end_time, raids.gym_id, gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, events.name + ORDER BY raids.end_time ASC, gyms.gym_name + ', [$overview_row['chat_id']] + ); + // Write active raids to array + $active_raids = $request_raids->fetchAll(); + debug_log('Active raids:'); + debug_log($active_raids); - if($overview_row['update_needed'] == 1) { - $chat_title_username = get_chat_title_username($overview_row['chat_id']); - $chat_title = $chat_title_username[0]; - $chat_username = $chat_title_username[1]; - my_query(' - UPDATE overview - SET chat_title = \''.$chat_title.'\', - chat_username = \''.$chat_username.'\', - updated = DATE(NOW()) - WHERE chat_id = \''.$overview_row['chat_id'].'\' - '); - }else { - $chat_title = $overview_row['chat_title']; - $chat_username = $overview_row['chat_username']; - } - $overview_message = get_overview($active_raids, $chat_title, $chat_username); - // Triggered from user or cronjob? - if (!empty($update['callback_query']['id'])) { - // Answer the callback. - answerCallbackQuery($update['callback_query']['id'], 'OK'); - $message_id = $update['callback_query']['message']['message_id']; - $chat_id = $update['callback_query']['from']['id']; - $keys[] = [ - [ - 'text' => EMOJI_REFRESH, - 'callback_data' => '0:overview_refresh:' . $overview_row['chat_id'] - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ]; - }else { - $message_id = $overview_row['message_id']; - $chat_id = $overview_row['chat_id']; - $keys = []; - } + if($overview_row['update_needed'] == 1) { + [$chat_title, $chat_username] = get_chat_title_username($overview_row['chat_id']); + my_query(' + UPDATE overview + SET chat_title = ?, + chat_username = ?, + updated = DATE(NOW()) + WHERE chat_id = ? + ',[$chat_title, $chat_username, $overview_row['chat_id']] + ); + }else { + $chat_title = $overview_row['chat_title']; + $chat_username = $overview_row['chat_username']; + } + $overview_message = get_overview($active_raids, $chat_title, $chat_username); + // Triggered from user or cronjob? + if (!empty($update['callback_query']['id'])) { + // Answer the callback. + answerCallbackQuery($update['callback_query']['id'], 'OK'); + $message_id = $update['callback_query']['message']['message_id']; + $chat_id = $update['callback_query']['from']['id']; + $keys[] = [ + [ + 'text' => EMOJI_REFRESH, + 'callback_data' => '0:overview_refresh:' . $overview_row['chat_id'] + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ]; + }else { + $message_id = $overview_row['message_id']; + $chat_id = $overview_row['chat_id']; + $keys = []; + } - $tg_json[] = editMessageText($message_id, $overview_message, $keys, $chat_id, ['disable_web_page_preview' => 'true'], true); + $tg_json[] = editMessageText($message_id, $overview_message, $keys, $chat_id, ['disable_web_page_preview' => 'true'], true); } // Telegram multicurl request. curl_json_multi_request($tg_json); $dbh=null; -exit; \ No newline at end of file +exit; diff --git a/mods/overview_share.php b/mods/overview_share.php index 2cc58ef7..92b50d46 100644 --- a/mods/overview_share.php +++ b/mods/overview_share.php @@ -1,6 +1,8 @@ UTC_TIMESTAMP() - {$query_chat} - ORDER BY cleanup.chat_id, raids.end_time ASC, gyms.gym_name - " -); +$request_active_raids = my_query(' + SELECT + cleanup.chat_id, cleanup.message_id, + raids.*, + gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, + TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left + FROM cleanup + LEFT JOIN raids + ON raids.id = cleanup.raid_id + LEFT JOIN gyms + ON raids.gym_id = gyms.id + WHERE raids.end_time>UTC_TIMESTAMP() + ' . $query_chat . ' + ORDER BY cleanup.chat_id, raids.end_time ASC, gyms.gym_name +'); // Collect results in an array $active_raids = $request_active_raids->fetchAll(PDO::FETCH_GROUP); @@ -43,81 +43,74 @@ // Share an overview if($chat_id != 0) { - $chat_title_username = get_chat_title_username($chat_id); - $overview_message = get_overview($active_raids[$chat_id], $chat_title_username[1], $chat_title_username[0]); - // Shared overview - $keys = []; + [$chat_title, $chat_username] = get_chat_title_username($chat_id); + $overview_message = get_overview($active_raids[$chat_id], $chat_title, $chat_username); + // Shared overview + $keys = []; - // Set callback message string. - $msg_callback = getTranslation('successfully_shared'); + // Set callback message string. + $msg_callback = getTranslation('successfully_shared'); - // Answer the callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $msg_callback, true); + // Answer the callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $msg_callback, true); - // Edit the message, but disable the web preview! - $tg_json[] = edit_message($update, $msg_callback, $keys, ['disable_web_page_preview' => 'true'], true); + // Edit the message, but disable the web preview! + $tg_json[] = edit_message($update, $msg_callback, $keys, ['disable_web_page_preview' => 'true'], true); - // Send the message, but disable the web preview! - $tg_json[] = send_message($chat_id, $overview_message, $keys, ['disable_web_page_preview' => 'true'], true, 'overview'); + // Send the message, but disable the web preview! + $tg_json[] = send_message($chat_id, $overview_message, $keys, ['disable_web_page_preview' => 'true'], true, 'overview'); }else { - // List all overviews to user - foreach( array_keys($active_raids) as $chat_id ) { - // Make sure it's not already shared - $rs = my_query( - " - SELECT chat_id, message_id, chat_title, chat_username - FROM overview - WHERE chat_id = '{$chat_id}' - LIMIT 1 - " - ); - // Already shared - if($rs->rowCount() > 0 ) { - $keys = [ - [ - [ - 'text' => EMOJI_REFRESH, - 'callback_data' => '0:overview_refresh:' . $chat_id - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; - $res = $rs->fetch(); - $chat_title = $res['chat_title']; - $chat_username = $res['chat_username']; - }else { - $chat_title_username = get_chat_title_username($chat_id); - $chat_title = $chat_title_username[0]; - $chat_username = $chat_title_username[1]; - $keys = [ - [ - [ - 'text' => getTranslation('share_with') . ' ' . $chat_title, - 'callback_data' => '0:overview_share:' . $chat_id - ] - ] - ]; - } - $overview_message = get_overview($active_raids[$chat_id], $chat_title, $chat_username); - // Send the message, but disable the web preview! - $tg_json[] = send_message($update['callback_query']['message']['chat']['id'], $overview_message, $keys, ['disable_web_page_preview' => 'true'], true); + // List all overviews to user + foreach( array_keys($active_raids) as $chat_id ) { + // Make sure it's not already shared + $rs = my_query(' + SELECT chat_id, message_id, chat_title, chat_username + FROM overview + WHERE chat_id = ? + LIMIT 1 + ', [$chat_id] + ); + $keys = []; + // Already shared + if($rs->rowCount() > 0 ) { + $keys[] = [ + [ + 'text' => EMOJI_REFRESH, + 'callback_data' => '0:overview_refresh:' . $chat_id + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ]; + $res = $rs->fetch(); + $chat_title = $res['chat_title']; + $chat_username = $res['chat_username']; + }else { + [$chat_title, $chat_username] = get_chat_title_username($chat_id); + $keys[] = [ + [ + 'text' => getTranslation('share_with') . ' ' . $chat_title, + 'callback_data' => '0:overview_share:' . $chat_id + ] + ]; } - // Set the callback message and keys - $callback_keys = []; - $callback_msg = '' . getTranslation('list_all_overviews') . ':'; + $overview_message = get_overview($active_raids[$chat_id], $chat_title, $chat_username); + // Send the message, but disable the web preview! + $tg_json[] = send_message($update['callback_query']['message']['chat']['id'], $overview_message, $keys, ['disable_web_page_preview' => 'true'], true); + } + // Set the callback message and keys + $callback_keys = []; + $callback_msg = '' . getTranslation('list_all_overviews') . ':'; - // Answer the callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], 'OK', true); + // Answer the callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], 'OK', true); - // Edit the message. - $tg_json[] = edit_message($update, $callback_msg, $callback_keys, false, true); + // Edit the message. + $tg_json[] = edit_message($update, $callback_msg, $callback_keys, false, true); } // Telegram multicurl request. curl_json_multi_request($tg_json); -$dbh = null; -exit; \ No newline at end of file +exit; diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index 6d84ea57..e2c54d4b 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -1,6 +1,7 @@ ' . getTranslation('import') . SP . '(ccev pogoinfo)' . '' . CR . CR; - $msg .= '' . getTranslation('select_raid_level') . ':'; + // Set message. + $msg = '' . getTranslation('import') . SP . '(ccev pogoinfo)' . '' . CR . CR; + $msg .= '' . getTranslation('select_raid_level') . ':'; - // Init empty keys array. - $keys = []; + // Init empty keys array. + $keys = []; - // All raid level keys. - $keys[][] = array( - 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => RAID_LEVEL_ALL . ':pogoinfo:ex#0,0,0' - ); + // All raid level keys. + $keys[][] = array( + 'text' => getTranslation('pokedex_all_raid_level'), + 'callback_data' => RAID_LEVEL_ALL . ':pogoinfo:ex#0,0,0' + ); - // Add key for each raid level - foreach($levels as $l) { - $keys[][] = array( - 'text' => getTranslation($l . 'stars'), - 'callback_data' => $l . ':pogoinfo:ex#0,0,0' - ); - } + // Add key for each raid level + foreach($levels as $l) { $keys[][] = array( - 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), - 'callback_data' => '3,1:pogoinfo:ex#0,0,0' + 'text' => getTranslation($l . 'stars'), + 'callback_data' => $l . ':pogoinfo:ex#0,0,0' ); - - // Add back and abort buttons - $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:pokedex_import:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; + } + $keys[][] = array( + 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), + 'callback_data' => '3,1:pogoinfo:ex#0,0,0' + ); + + // Add back and abort buttons + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:pokedex_import:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; } else if($id > 0) { - // Set message and init message to exclude raid bosses. - $msg = '' . getTranslation('import') . SP . '(ccev pogoinfo)' . '' . CR . CR; - $ex_msg = ''; - - // Get pogoinfo data. - debug_log('Getting raid bosses from pogoinfo repository now...'); - $link = 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/raids.json'; - $data = curl_get_contents($link); - $data = json_decode($data,true); - - // All raid levels? - if($id == RAID_LEVEL_ALL) { - $get_levels = $levels; - $clear = "'6','5','3','1'"; - } else { - $get_levels = explode(",", $id); - $clear = $id; + // Set message and init message to exclude raid bosses. + $msg = '' . getTranslation('import') . SP . '(ccev pogoinfo)' . '' . CR . CR; + $ex_msg = ''; + + // Get pogoinfo data. + debug_log('Getting raid bosses from pogoinfo repository now...'); + $link = 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/raids.json'; + $data = curl_get_contents($link); + $data = json_decode($data,true); + + // All raid levels? + if($id == RAID_LEVEL_ALL) { + $get_levels = $levels; + $clear = "'6','5','3','1'"; + } else { + $get_levels = explode(",", $id); + $clear = $id; + } + + // Prefix for exclusion. + $prefix = 'ex#'; + + // New request + if($arg == 'ex#0,0,0') { + $poke1 = 0; + $poke2 = 0; + $poke3 = 0; + + // Get raid bosses to exclude. + } else if(strpos($arg, 'ex#') === 0 || strpos($arg, 'save#') === 0) { + $poke_ids = explode('#', $arg); + $poke_ids = explode(',', $poke_ids[1]); + $poke1 = $poke_ids[0]; + $poke2 = $poke_ids[1]; + $poke3 = $poke_ids[2]; + debug_log('Excluded raid boss #1: ' . $poke1); + debug_log('Excluded raid boss #2: ' . $poke2); + debug_log('Excluded raid boss #3: ' . $poke3); + } + + // Clear old raid bosses. + if(strpos($arg, 'save#') === 0) { + require_once(LOGIC_PATH . '/disable_raid_level.php'); + debug_log('Disabling old raid bosses for levels: '. $clear); + disable_raid_level($clear); + } + + // Init empty keys array. + $keys = []; + + // Raid tier array + debug_log('Processing the following raid levels:'); + debug_log($get_levels); + + // Process raid tier(s) + debug_log('Processing received ccev pogoinfo raid bosses for each raid level'); + foreach($data as $tier => $tier_pokemon) { + // Process raid level? + if(!in_array($tier,$get_levels)) { + continue; } + // Raid level and message. + $msg .= '' . getTranslation('pokedex_raid_level') . SP . $tier . ':' . CR; + + // Count raid bosses and add raid egg later if 2 or more bosses. + $bosscount = 0; + + // Get raid bosses for each raid level. + foreach($tier_pokemon as $raid_id_form) { + $dex_id = $raid_id_form['id']; + $dex_form = 0; + if(isset($raid_id_form['temp_evolution_id'])) { + $dex_form = '-'.$raid_id_form['temp_evolution_id']; + }elseif(isset($raid_id_form['form'])) { + $dex_form = $raid_id_form['form']; + }else { + // If no form id is provided, let's check our db for normal form + $query_form_id = my_query("SELECT pokemon_form_id FROM pokemon WHERE pokedex_id='".$dex_id."' and pokemon_form_name='normal' LIMIT 1"); + if($query_form_id->rowCount() == 0) { + // If normal form doesn't exist in our db, use the smallest form id as a fallback + $query_form_id = my_query("SELECT min(pokemon_form_id) as pokemon_form_id FROM pokemon WHERE pokedex_id='".$dex_id."' LIMIT 1"); + } + $result = $query_form_id->fetch(); + $dex_form = $result['pokemon_form_id']; + } + + $pokemon_arg = $dex_id . $dex_form; + + // Get ID and form name used internally. + $local_pokemon = get_local_pokemon_name($dex_id, $dex_form); + debug_log('Got this pokemon dex id: ' . $dex_id); + debug_log('Got this pokemon dex form: ' . $dex_form); + debug_log('Got this local pokemon name and form: ' . $local_pokemon); + + // Make sure we received a valid dex id. + if(!is_numeric($dex_id) || $dex_id == 0) { + info_log('Failed to get a valid pokemon dex id: '. $dex_id .' Continuing with next raid boss...'); + continue; + } + + // Build new arg. + // Exclude 1 pokemon + if($poke1 == '0') { + $new_arg = $prefix . $pokemon_arg . ',0,0'; + + // Exclude 2 pokemon + } else if ($poke1 != '0' && $poke2 == '0') { + $new_arg = $prefix . $poke1 . ',' . $pokemon_arg . ',0'; + + // Exclude 3 pokemon + } else if ($poke1 != '0' && $poke2 != '0' && $poke3 == '0') { + $new_arg = $prefix . $poke1 . ',' . $poke2 . ',' . $pokemon_arg; + } + + // Exclude pokemon? + if($pokemon_arg == $poke1 || $pokemon_arg == $poke2 || $pokemon_arg == $poke3) { + // Add pokemon to exclude message. + $ex_msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; + + } else { + // Add pokemon to message. + $msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; + + // Counter. + $bosscount = $bosscount + 1; + + // Save to database? + if(strpos($arg, 'save#') === 0) { + // Update raid level of pokemon + my_query(' + INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) + VALUES (?, ?, ?) + ', [$dex_id, $dex_form, $tier] + ); + continue; + } - // Prefix for exclusion. - $prefix = 'ex#'; - - // New request - if($arg == 'ex#0,0,0') { - $poke1 = 0; - $poke2 = 0; - $poke3 = 0; - - // Get raid bosses to exclude. - } else if(strpos($arg, 'ex#') === 0 || strpos($arg, 'save#') === 0) { - $poke_ids = explode('#', $arg); - $poke_ids = explode(',', $poke_ids[1]); - $poke1 = $poke_ids[0]; - $poke2 = $poke_ids[1]; - $poke3 = $poke_ids[2]; - debug_log('Excluded raid boss #1: ' . $poke1); - debug_log('Excluded raid boss #2: ' . $poke2); - debug_log('Excluded raid boss #3: ' . $poke3); + // Are 3 raid bosses already selected? + if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { + // Add raid level to pokemon name + if($id == RAID_LEVEL_ALL) { + // Add key to exclude pokemon from import. + $keys[] = array( + 'text' => '[' . ($tier) . ']' . SP . $local_pokemon, + 'callback_data' => $id . ':pogoinfo:' . $new_arg + ); + } else { + // Add key to exclude pokemon from import. + $keys[] = array( + 'text' => $local_pokemon, + 'callback_data' => $id . ':pogoinfo:' . $new_arg + ); + } + } + } } - // Clear old raid bosses. - if(strpos($arg, 'save#') === 0) { - debug_log('Disabling old raid bosses for levels: '. $clear); - disable_raid_level($clear); - } + $msg .= CR; + } + + // Get the inline key array. + $keys = inline_key_array($keys, 2); + + // Saved raid bosses? + if(strpos($arg, 'save#') === 0) { + // Get all pokemon with raid levels from database. + $rs = my_query(' + SELECT raid_bosses.pokedex_id, raid_bosses.pokemon_form_id, raid_bosses.raid_level + FROM raid_bosses + LEFT JOIN pokemon + ON raid_bosses.pokedex_id = pokemon.pokedex_id + AND raid_bosses.pokemon_form_id = pokemon.pokemon_form_id + WHERE raid_bosses.raid_level IN (' . $clear . ') + AND raid_bosses.scheduled = 0 + ORDER BY raid_bosses.raid_level, raid_bosses.pokedex_id, pokemon.pokemon_form_name != \'normal\', pokemon.pokemon_form_name, raid_bosses.pokemon_form_id + '); // Init empty keys array. $keys = []; - // Raid tier array - debug_log('Processing the following raid levels:'); - debug_log($get_levels); - - // Process raid tier(s) - debug_log('Processing received ccev pogoinfo raid bosses for each raid level'); - foreach($data as $tier => $tier_pokemon) { - // Process raid level? - if(!in_array($tier,$get_levels)) { - continue; - } - // Raid level and message. - $msg .= '' . getTranslation('pokedex_raid_level') . SP . $tier . ':' . CR; - - // Count raid bosses and add raid egg later if 2 or more bosses. - $bosscount = 0; - - // Get raid bosses for each raid level. - foreach($tier_pokemon as $raid_id_form) { - $dex_id = $raid_id_form['id']; - $dex_form = 0; - if(isset($raid_id_form['temp_evolution_id'])) { - $dex_form = '-'.$raid_id_form['temp_evolution_id']; - }elseif(isset($raid_id_form['form'])) { - $dex_form = $raid_id_form['form']; - }else { - // If no form id is provided, let's check our db for normal form - $query_form_id = my_query("SELECT pokemon_form_id FROM pokemon WHERE pokedex_id='".$dex_id."' and pokemon_form_name='normal' LIMIT 1"); - if($query_form_id->rowCount() == 0) { - // If normal form doesn't exist in our db, use the smallest form id as a fallback - $query_form_id = my_query("SELECT min(pokemon_form_id) as pokemon_form_id FROM pokemon WHERE pokedex_id='".$dex_id."' LIMIT 1"); - } - $result = $query_form_id->fetch(); - $dex_form = $result['pokemon_form_id']; - } - - $pokemon_arg = $dex_id . $dex_form; - - // Get ID and form name used internally. - $local_pokemon = get_local_pokemon_name($dex_id, $dex_form); - debug_log('Got this pokemon dex id: ' . $dex_id); - debug_log('Got this pokemon dex form: ' . $dex_form); - debug_log('Got this local pokemon name and form: ' . $local_pokemon); - - // Make sure we received a valid dex id. - if(!is_numeric($dex_id) || $dex_id == 0) { - info_log('Failed to get a valid pokemon dex id: '. $dex_id .' Continuing with next raid boss...'); - continue; - } - - // Build new arg. - // Exclude 1 pokemon - if($poke1 == '0') { - $new_arg = $prefix . $pokemon_arg . ',0,0'; - - // Exclude 2 pokemon - } else if ($poke1 != '0' && $poke2 == '0') { - $new_arg = $prefix . $poke1 . ',' . $pokemon_arg . ',0'; - - // Exclude 3 pokemon - } else if ($poke1 != '0' && $poke2 != '0' && $poke3 == '0') { - $new_arg = $prefix . $poke1 . ',' . $poke2 . ',' . $pokemon_arg; - } - - // Exclude pokemon? - if($pokemon_arg == $poke1 || $pokemon_arg == $poke2 || $pokemon_arg == $poke3) { - // Add pokemon to exclude message. - $ex_msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - - } else { - // Add pokemon to message. - $msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - - // Counter. - $bosscount = $bosscount + 1; - - // Save to database? - if(strpos($arg, 'save#') === 0) { - // Update raid level of pokemon - my_query( - " - INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) - VALUES ('{$dex_id}', '{$dex_form}', '{$tier}') - " - ); - continue; - } - - // Are 3 raid bosses already selected? - if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { - // Add raid level to pokemon name - if($id == RAID_LEVEL_ALL) { - // Add key to exclude pokemon from import. - $keys[] = array( - 'text' => '[' . ($tier) . ']' . SP . $local_pokemon, - 'callback_data' => $id . ':pogoinfo:' . $new_arg - ); - } else { - // Add key to exclude pokemon from import. - $keys[] = array( - 'text' => $local_pokemon, - 'callback_data' => $id . ':pogoinfo:' . $new_arg - ); - } - } - } - } + // Init message and previous. + $msg = 'Pogoinfo' . SP . '—' . SP . getTranslation('import_done') . '' . CR; + $previous = ''; + + // Build the message + while ($pokemon = $rs->fetch()) { + // Set current level + $current = $pokemon['raid_level']; + + // Add header for each raid level + if($previous != $current) { + $msg .= CR . '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; + } + + // Add pokemon with id and name. + $dex_id = $pokemon['pokedex_id']; + $pokemon_form_id = $pokemon['pokemon_form_id']; + $poke_name = get_local_pokemon_name($dex_id, $pokemon_form_id); + $msg .= $poke_name . ' (#' . $dex_id . ')' . CR; + + // Add button to edit pokemon. + if($id == RAID_LEVEL_ALL) { + $keys[] = array( + 'text' => '[' . $pokemon['raid_level'] . ']' . SP . $poke_name, + 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' + ); + } else { + $keys[] = array( + 'text' => $poke_name, + 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' + ); + } - $msg .= CR; + // Prepare next run. + $previous = $current; } - // Get the inline key array. + // Inline key array. $keys = inline_key_array($keys, 2); - // Saved raid bosses? - if(strpos($arg, 'save#') === 0) { - // Get all pokemon with raid levels from database. - $rs = my_query( - " - SELECT raid_bosses.pokedex_id, raid_bosses.pokemon_form_id, raid_bosses.raid_level - FROM raid_bosses - LEFT JOIN pokemon - ON raid_bosses.pokedex_id = pokemon.pokedex_id - AND raid_bosses.pokemon_form_id = pokemon.pokemon_form_id - WHERE raid_bosses.raid_level IN ({$clear}) - AND raid_bosses.scheduled = 0 - ORDER BY raid_bosses.raid_level, raid_bosses.pokedex_id, pokemon.pokemon_form_name != 'normal', pokemon.pokemon_form_name, raid_bosses.pokemon_form_id - " - ); + // Navigation keys. + $nav_keys = []; - // Init empty keys array. - $keys = []; - - // Init message and previous. - $msg = 'Pogoinfo' . SP . '—' . SP . getTranslation('import_done') . '' . CR; - $previous = ''; - - // Build the message - while ($pokemon = $rs->fetch()) { - // Set current level - $current = $pokemon['raid_level']; - - // Add header for each raid level - if($previous != $current) { - $msg .= CR . '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; - } - - // Add pokemon with id and name. - $dex_id = $pokemon['pokedex_id']; - $pokemon_form_id = $pokemon['pokemon_form_id']; - $poke_name = get_local_pokemon_name($dex_id, $pokemon_form_id); - $msg .= $poke_name . ' (#' . $dex_id . ')' . CR; - - // Add button to edit pokemon. - if($id == RAID_LEVEL_ALL) { - $keys[] = array( - 'text' => '[' . $pokemon['raid_level'] . ']' . SP . $poke_name, - 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' - ); - } else { - $keys[] = array( - 'text' => $poke_name, - 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' - ); - } - - // Prepare next run. - $previous = $current; - } - - // Inline key array. - $keys = inline_key_array($keys, 2); - - // Navigation keys. - $nav_keys = []; + // Abort button. + $nav_keys[] = array( + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ); - // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ); + // Keys. + $nav_keys = inline_key_array($nav_keys, 1); + $keys = array_merge($keys, $nav_keys); - // Keys. - $nav_keys = inline_key_array($nav_keys, 1); - $keys = array_merge($keys, $nav_keys); + // User is still on the import. + } else { + $msg .= '' . getTranslation('excluded_raid_bosses') . '' . CR; + $msg .= (empty($ex_msg) ? (getTranslation('none') . CR) : $ex_msg) . CR; - // User is still on the import. + // Import or select more pokemon to exclude? + if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { + $msg .= '' . getTranslation('exclude_raid_boss_or_import') . ':'; } else { - $msg .= '' . getTranslation('excluded_raid_bosses') . '' . CR; - $msg .= (empty($ex_msg) ? (getTranslation('none') . CR) : $ex_msg) . CR; - - // Import or select more pokemon to exclude? - if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { - $msg .= '' . getTranslation('exclude_raid_boss_or_import') . ':'; - } else { - $msg .= '' . getTranslation('import_raid_bosses') . ''; - } + $msg .= '' . getTranslation('import_raid_bosses') . ''; + } - // Navigation keys. - $nav_keys = []; + // Navigation keys. + $nav_keys = []; - // Back button. - $nav_keys[] = array( - 'text' => getTranslation('back'), - 'callback_data' => '0:pogoinfo:0' - ); + // Back button. + $nav_keys[] = array( + 'text' => getTranslation('back'), + 'callback_data' => '0:pogoinfo:0' + ); - // Save button. - $nav_keys[] = array( - 'text' => EMOJI_DISK, - 'callback_data' => $id . ':pogoinfo:save#' . $poke1 . ',' . $poke2 . ',' . $poke3 - ); + // Save button. + $nav_keys[] = array( + 'text' => EMOJI_DISK, + 'callback_data' => $id . ':pogoinfo:save#' . $poke1 . ',' . $poke2 . ',' . $poke3 + ); - // Reset button. - if($poke1 != 0) { - $nav_keys[] = array( - 'text' => getTranslation('reset'), - 'callback_data' => $id . ':pogoinfo:ex#0,0,0' - ); - } + // Reset button. + if($poke1 != 0) { + $nav_keys[] = array( + 'text' => getTranslation('reset'), + 'callback_data' => $id . ':pogoinfo:ex#0,0,0' + ); + } - // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ); + // Abort button. + $nav_keys[] = array( + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ); - // Get the inline key array and merge keys. - $nav_keys = inline_key_array($nav_keys, 2); - $keys = array_merge($keys, $nav_keys); - } + // Get the inline key array and merge keys. + $nav_keys = inline_key_array($nav_keys, 2); + $keys = array_merge($keys, $nav_keys); + } } // Callback message string. @@ -354,6 +353,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/pokebattler.php b/mods/pokebattler.php index 8f23125a..27925893 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -1,6 +1,7 @@ ' . getTranslation('import') . SP . '(Pokebattler)' . '' . CR . CR; - $msg .= '' . getTranslation('select_raid_level') . ':'; + // Set message. + $msg = '' . getTranslation('import') . SP . '(Pokebattler)' . '' . CR . CR; + $msg .= '' . getTranslation('select_raid_level') . ':'; - // Init empty keys array. - $keys = []; + // Init empty keys array. + $keys = []; - // All raid level keys. - $keys[][] = array( - 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => implode(",", $pokebattler_levels) . ':pokebattler:ex#0,0,0' - ); + // All raid level keys. + $keys[][] = array( + 'text' => getTranslation('pokedex_all_raid_level'), + 'callback_data' => implode(",", $pokebattler_levels) . ':pokebattler:ex#0,0,0' + ); - // Add key for each raid level - foreach($pokebattler_levels as $l) { - $keys[][] = array( - 'text' => getTranslation($l . 'stars'), - 'callback_data' => $l . ':pokebattler:ex#0,0,0' - ); - } + // Add key for each raid level + foreach($pokebattler_levels as $l) { $keys[][] = array( - 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), - 'callback_data' => '3,1:pokebattler:ex#0,0,0' + 'text' => getTranslation($l . 'stars'), + 'callback_data' => $l . ':pokebattler:ex#0,0,0' ); - - // Add back and abort buttons - $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:pokedex_import:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; + } + $keys[][] = array( + 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), + 'callback_data' => '3,1:pokebattler:ex#0,0,0' + ); + + // Add back and abort buttons + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:pokedex_import:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; } else if($id > 0) { - // Set message and init message to exclude raid bosses. - $msg = '' . getTranslation('import') . SP . '(Pokebattler)' . '' . CR . CR; - $ex_msg = ''; - - // Get pokebattler data. - debug_log('Getting raid bosses from pokebattler.com now...'); - $link = 'https://fight.pokebattler.com/raids'; - $pb_data = curl_get_contents($link); - $pb_data = json_decode($pb_data,true); - - $get_levels = explode(",", $id); - $clear = $id; - - // Prefix for exclusion. - $prefix = 'ex#'; - - // New request - if($arg == 'ex#0,0,0') { - $poke1 = 0; - $poke2 = 0; - $poke3 = 0; - - // Get raid bosses to exclude. - } else if(strpos($arg, 'ex#') === 0 || strpos($arg, 'save#') === 0) { - $poke_ids = explode('#', $arg); - $poke_ids = explode(',', $poke_ids[1]); - $poke1 = $poke_ids[0]; - $poke2 = $poke_ids[1]; - $poke3 = $poke_ids[2]; - debug_log('Excluded raid boss #1: ' . $poke1); - debug_log('Excluded raid boss #2: ' . $poke2); - debug_log('Excluded raid boss #3: ' . $poke3); - } - - // Clear old raid bosses. - if(strpos($arg, 'save#') === 0) { - debug_log('Disabling old raid bosses for levels: '. $clear); - disable_raid_level($clear); + // Set message and init message to exclude raid bosses. + $msg = '' . getTranslation('import') . SP . '(Pokebattler)' . '' . CR . CR; + $ex_msg = ''; + + // Get pokebattler data. + debug_log('Getting raid bosses from pokebattler.com now...'); + $link = 'https://fight.pokebattler.com/raids'; + $pb_data = curl_get_contents($link); + $pb_data = json_decode($pb_data,true); + + $get_levels = explode(",", $id); + $clear = $id; + + // Prefix for exclusion. + $prefix = 'ex#'; + + // New request + if($arg == 'ex#0,0,0') { + $poke1 = 0; + $poke2 = 0; + $poke3 = 0; + + // Get raid bosses to exclude. + } else if(strpos($arg, 'ex#') === 0 || strpos($arg, 'save#') === 0) { + $poke_ids = explode('#', $arg); + $poke_ids = explode(',', $poke_ids[1]); + $poke1 = $poke_ids[0]; + $poke2 = $poke_ids[1]; + $poke3 = $poke_ids[2]; + debug_log('Excluded raid boss #1: ' . $poke1); + debug_log('Excluded raid boss #2: ' . $poke2); + debug_log('Excluded raid boss #3: ' . $poke3); + } + + // Clear old raid bosses. + if(strpos($arg, 'save#') === 0) { + require_once(LOGIC_PATH . '/disable_raid_level.php'); + debug_log('Disabling old raid bosses for levels: '. $clear); + disable_raid_level($clear); + } + + // Init empty keys array. + $keys = []; + + // Raid tier array + debug_log('Processing the following raid levels:'); + $raidlevels = array(); + foreach($get_levels as $level) { + $raidlevels[] = 'RAID_LEVEL_' . $pokebattler_level_map[$level]; + } + debug_log($raidlevels); + $levels_processed = []; + $bosses = []; + // Process breaking news section + $now = new DateTime('now', new DateTimeZone($config->TIMEZONE)); + $ph = new dateTimeZone('America/Phoenix'); + foreach($pb_data['breakingNews'] as $news) { + if($news['type'] == 'RAID_TYPE_RAID') { + $rl = str_replace('RAID_LEVEL_','', $news['tier']); + $raid_level_id = array_search($rl, $pokebattler_level_map); + $starttime = new DateTime("@".substr($news['startDate'],0,10)); + $endtime = new DateTime("@".substr($news['endDate'],0,10)); + $starttime->setTimezone($ph); + $endtime->setTimezone($ph); + + if(in_array($news['tier'], $raidlevels) && $starttime->getTimestamp() < $now->getTimestamp() && $endtime->getTimestamp() > $now->getTimestamp()) { + $levels_processed[$raid_level_id] = $news['tier']; + $dex_id_form = resolve_boss_name_to_ids($news['pokemon']); + $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $news['shiny']]; + } } - - // Init empty keys array. - $keys = []; - - // Raid tier array - debug_log('Processing the following raid levels:'); - $raidlevels = array(); - foreach($get_levels as $level) { - $raidlevels[] = 'RAID_LEVEL_' . $pokebattler_level_map[$level]; + } + // Process raid tier(s) + debug_log('Processing received pokebattler raid bosses for each raid level'); + foreach($pb_data['tiers'] as $tier) { + $rl = str_replace('RAID_LEVEL_','', $tier['tier']); + $raid_level_id = array_search($rl, $pokebattler_level_map); + // Skip this raid level if the boss data was already collected from breaking news or raid level doesn't interest us + if(!in_array($tier['tier'], $raidlevels) or isset($levels_processed[$raid_level_id])) { + continue; } - debug_log($raidlevels); - $levels_processed = []; - $bosses = []; - // Process breaking news section - $now = new DateTime('now', new DateTimeZone($config->TIMEZONE)); - $ph = new dateTimeZone('America/Phoenix'); - foreach($pb_data['breakingNews'] as $news) { - if($news['type'] == 'RAID_TYPE_RAID') { - $rl = str_replace('RAID_LEVEL_','', $news['tier']); - $raid_level_id = array_search($rl, $pokebattler_level_map); - $starttime = new DateTime("@".substr($news['startDate'],0,10)); - $endtime = new DateTime("@".substr($news['endDate'],0,10)); - $starttime->setTimezone($ph); - $endtime->setTimezone($ph); - - if(in_array($news['tier'], $raidlevels) && $starttime->getTimestamp() < $now->getTimestamp() && $endtime->getTimestamp() > $now->getTimestamp()) { - $levels_processed[$raid_level_id] = $news['tier']; - $dex_id_form = resolve_boss_name_to_ids($news['pokemon']); - $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $news['shiny']]; - } - } + // Get raid bosses for each raid level. + foreach($tier['raids'] as $raid) { + // Raid level + if ($raid['id'] == 0) { + debug_log("Skipping raid boss {$raid['pokemon']} since it has no id, it's likely in the future!"); + continue; + } + $dex_id_form = resolve_boss_name_to_ids($raid['pokemon']); + $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $raid['shiny']]; } - // Process raid tier(s) - debug_log('Processing received pokebattler raid bosses for each raid level'); - foreach($pb_data['tiers'] as $tier) { - $rl = str_replace('RAID_LEVEL_','', $tier['tier']); - $raid_level_id = array_search($rl, $pokebattler_level_map); - // Skip this raid level if the boss data was already collected from breaking news or raid level doesn't interest us - if(!in_array($tier['tier'], $raidlevels) or isset($levels_processed[$raid_level_id])) { - continue; + } + + foreach($get_levels as $raid_level_id) { + if($raid_level_id > 5) $raid_level_text = getTranslation($raid_level_id . 'stars_short'); else $raid_level_text = $raid_level_id; + if(!isset($bosses[$raid_level_id])) continue; + $msg .= '' . getTranslation('pokedex_raid_level') . SP . $raid_level_text . ':' . CR; + foreach($bosses[$raid_level_id] as $dex_id_form) { + [$dex_id, $dex_form] = $dex_id_form['id']; + $pokemon_arg = $dex_id . (($dex_form != 'normal') ? ('-' . $dex_form) : '-0'); + $local_pokemon = get_local_pokemon_name($dex_id, $dex_form); + debug_log('Got this pokemon dex id: ' . $dex_id); + debug_log('Got this pokemon dex form: ' . $dex_form); + debug_log('Got this local pokemon name and form: ' . $local_pokemon); + + // Make sure we received a valid dex id. + if(!is_numeric($dex_id) || $dex_id == 0) { + info_log('Failed to get a valid pokemon dex id: '. $dex_id .' Continuing with next raid boss...'); + continue; + } + + // Build new arg. + // Exclude 1 pokemon + if($poke1 == '0') { + $new_arg = $prefix . $pokemon_arg . ',0,0'; + + // Exclude 2 pokemon + } else if ($poke1 != '0' && $poke2 == '0') { + $new_arg = $prefix . $poke1 . ',' . $pokemon_arg . ',0'; + + // Exclude 3 pokemon + } else if ($poke1 != '0' && $poke2 != '0' && $poke3 == '0') { + $new_arg = $prefix . $poke1 . ',' . $poke2 . ',' . $pokemon_arg; + } + + // Exclude pokemon? + if($pokemon_arg == $poke1 || $pokemon_arg == $poke2 || $pokemon_arg == $poke3) { + // Add pokemon to exclude message. + $ex_msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; + + } else { + // Add pokemon to message. + $msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; + + // Shiny? + $shiny = 0; + if($dex_id_form['shiny'] == 'true') { + $shiny = 1; } - // Get raid bosses for each raid level. - foreach($tier['raids'] as $raid) { - // Raid level - if ($raid['id'] == 0) { - debug_log("Skipping raid boss {$raid['pokemon']} since it has no id, it's likely in the future!"); - continue; - } - $dex_id_form = resolve_boss_name_to_ids($raid['pokemon']); - $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $raid['shiny']]; + + // Save to database? + if(strpos($arg, 'save#') === 0) { + // Update raid level of pokemon + my_query(' + UPDATE pokemon + SET shiny = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$shiny, $dex_id, $dex_form] + ); + my_query(' + INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) + VALUES (?, ?, ?) + ', [$dex_id, $dex_form, $raid_level_id] + ); + continue; } - } - foreach($get_levels as $raid_level_id) { - if($raid_level_id > 5) $raid_level_text = getTranslation($raid_level_id . 'stars_short'); else $raid_level_text = $raid_level_id; - if(!isset($bosses[$raid_level_id])) continue; - $msg .= '' . getTranslation('pokedex_raid_level') . SP . $raid_level_text . ':' . CR; - foreach($bosses[$raid_level_id] as $dex_id_form) { - $dex_id = explode('-', $dex_id_form['id'], 2)[0]; - $dex_form = explode('-', $dex_id_form['id'], 2)[1]; - $pokemon_arg = $dex_id . (($dex_form != 'normal') ? ('-' . $dex_form) : '-0'); - $local_pokemon = get_local_pokemon_name($dex_id, $dex_form); - debug_log('Got this pokemon dex id: ' . $dex_id); - debug_log('Got this pokemon dex form: ' . $dex_form); - debug_log('Got this local pokemon name and form: ' . $local_pokemon); - - // Make sure we received a valid dex id. - if(!is_numeric($dex_id) || $dex_id == 0) { - info_log('Failed to get a valid pokemon dex id: '. $dex_id .' Continuing with next raid boss...'); - continue; - } - - // Build new arg. - // Exclude 1 pokemon - if($poke1 == '0') { - $new_arg = $prefix . $pokemon_arg . ',0,0'; - - // Exclude 2 pokemon - } else if ($poke1 != '0' && $poke2 == '0') { - $new_arg = $prefix . $poke1 . ',' . $pokemon_arg . ',0'; - - // Exclude 3 pokemon - } else if ($poke1 != '0' && $poke2 != '0' && $poke3 == '0') { - $new_arg = $prefix . $poke1 . ',' . $poke2 . ',' . $pokemon_arg; - } - - // Exclude pokemon? - if($pokemon_arg == $poke1 || $pokemon_arg == $poke2 || $pokemon_arg == $poke3) { - // Add pokemon to exclude message. - $ex_msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - - } else { - // Add pokemon to message. - $msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - - // Shiny? - $shiny = 0; - if($dex_id_form['shiny'] == 'true') { - $shiny = 1; - } - - // Save to database? - if(strpos($arg, 'save#') === 0) { - // Update raid level of pokemon - my_query( - " - UPDATE pokemon - SET shiny = {$shiny} - WHERE pokedex_id = {$dex_id} - AND pokemon_form_id = '{$dex_form}' - " - ); - my_query( - " - INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) - VALUES ('{$dex_id}', '{$dex_form}', '{$raid_level_id}') - " - ); - continue; - } - - // Are 3 raid bosses already selected? - if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { - // Add key to exclude pokemon from import. - $button_text_prefix = ''; - if($id == implode(",", $pokebattler_levels)) { - // Add raid level to pokemon name - $button_text_prefix = '[' . ($raid_level_text) . ']'; - } - $keys[] = array( - 'text' => $button_text_prefix . SP . $local_pokemon, - 'callback_data' => $id . ':pokebattler:' . $new_arg - ); - } - } + // Are 3 raid bosses already selected? + if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { + // Add key to exclude pokemon from import. + $button_text_prefix = ''; + if($id == implode(",", $pokebattler_levels)) { + // Add raid level to pokemon name + $button_text_prefix = '[' . ($raid_level_text) . ']'; + } + $keys[] = array( + 'text' => $button_text_prefix . SP . $local_pokemon, + 'callback_data' => $id . ':pokebattler:' . $new_arg + ); } - $msg .= CR; + } } + $msg .= CR; + } + + // Get the inline key array. + $keys = inline_key_array($keys, 2); + + // Saved raid bosses? + if(strpos($arg, 'save#') === 0) { + // Get all pokemon with raid levels from database. + $rs = my_query(' + SELECT raid_bosses.pokedex_id, raid_bosses.pokemon_form_id, raid_bosses.raid_level + FROM raid_bosses + LEFT JOIN pokemon + ON raid_bosses.pokedex_id = pokemon.pokedex_id + AND raid_bosses.pokemon_form_id = pokemon.pokemon_form_id + WHERE raid_bosses.raid_level IN (' . $clear . ') + AND raid_bosses.scheduled = 0 + ORDER BY raid_bosses.raid_level, raid_bosses.pokedex_id, pokemon.pokemon_form_name != \'normal\', pokemon.pokemon_form_name, raid_bosses.pokemon_form_id + '); - // Get the inline key array. - $keys = inline_key_array($keys, 2); + // Init empty keys array. + $keys = []; - // Saved raid bosses? - if(strpos($arg, 'save#') === 0) { - // Get all pokemon with raid levels from database. - $rs = my_query( - " - SELECT raid_bosses.pokedex_id, raid_bosses.pokemon_form_id, raid_bosses.raid_level - FROM raid_bosses - LEFT JOIN pokemon - ON raid_bosses.pokedex_id = pokemon.pokedex_id - AND raid_bosses.pokemon_form_id = pokemon.pokemon_form_id - WHERE raid_bosses.raid_level IN ({$clear}) - AND raid_bosses.scheduled = 0 - ORDER BY raid_bosses.raid_level, raid_bosses.pokedex_id, pokemon.pokemon_form_name != 'normal', pokemon.pokemon_form_name, raid_bosses.pokemon_form_id - " + // Init message and previous. + $msg = 'Pokebattler' . SP . '—' . SP . getTranslation('import_done') . '' . CR; + $previous = ''; + + // Build the message + while ($pokemon = $rs->fetch()) { + // Set current level + $current = $pokemon['raid_level']; + + // Add header for each raid level + if($previous != $current) { + $msg .= CR . '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; + } + + // Add pokemon with id and name. + $dex_id = $pokemon['pokedex_id']; + $pokemon_form_id = $pokemon['pokemon_form_id']; + $poke_name = get_local_pokemon_name($dex_id, $pokemon_form_id); + $msg .= $poke_name . ' (#' . $dex_id . ')' . CR; + + // Add button to edit pokemon. + if($id == RAID_LEVEL_ALL) { + $keys[] = array( + 'text' => '[' . $pokemon['raid_level'] . ']' . SP . $poke_name, + 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' ); + } else { + $keys[] = array( + 'text' => $poke_name, + 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' + ); + } - // Init empty keys array. - $keys = []; - - // Init message and previous. - $msg = 'Pokebattler' . SP . '—' . SP . getTranslation('import_done') . '' . CR; - $previous = ''; - - // Build the message - while ($pokemon = $rs->fetch()) { - // Set current level - $current = $pokemon['raid_level']; - - // Add header for each raid level - if($previous != $current) { - $msg .= CR . '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; - } - - // Add pokemon with id and name. - $dex_id = $pokemon['pokedex_id']; - $pokemon_form_id = $pokemon['pokemon_form_id']; - $poke_name = get_local_pokemon_name($dex_id, $pokemon_form_id); - $msg .= $poke_name . ' (#' . $dex_id . ')' . CR; - - // Add button to edit pokemon. - if($id == RAID_LEVEL_ALL) { - $keys[] = array( - 'text' => '[' . $pokemon['raid_level'] . ']' . SP . $poke_name, - 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' - ); - } else { - $keys[] = array( - 'text' => $poke_name, - 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' - ); - } - - // Prepare next run. - $previous = $current; - } + // Prepare next run. + $previous = $current; + } - // Message. - $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; + // Message. + $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; - // Inline key array. - $keys = inline_key_array($keys, 2); + // Inline key array. + $keys = inline_key_array($keys, 2); - // Navigation keys. - $nav_keys = []; + // Navigation keys. + $nav_keys = []; - // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ); + // Abort button. + $nav_keys[] = array( + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ); - // Keys. - $nav_keys = inline_key_array($nav_keys, 1); - $keys = array_merge($keys, $nav_keys); + // Keys. + $nav_keys = inline_key_array($nav_keys, 1); + $keys = array_merge($keys, $nav_keys); - // User is still on the import. - } else { - $msg .= '' . getTranslation('excluded_raid_bosses') . '' . CR; - $msg .= (empty($ex_msg) ? (getTranslation('none') . CR) : $ex_msg) . CR; + // User is still on the import. + } else { + $msg .= '' . getTranslation('excluded_raid_bosses') . '' . CR; + $msg .= (empty($ex_msg) ? (getTranslation('none') . CR) : $ex_msg) . CR; - // Import or select more pokemon to exclude? - if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { - $msg .= '' . getTranslation('exclude_raid_boss_or_import') . ':'; - } else { - $msg .= '' . getTranslation('import_raid_bosses') . ''; - } + // Import or select more pokemon to exclude? + if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { + $msg .= '' . getTranslation('exclude_raid_boss_or_import') . ':'; + } else { + $msg .= '' . getTranslation('import_raid_bosses') . ''; + } - // Navigation keys. - $nav_keys = []; + // Navigation keys. + $nav_keys = []; - // Back button. - $nav_keys[] = array( - 'text' => getTranslation('back'), - 'callback_data' => '0:pokebattler:0' - ); + // Back button. + $nav_keys[] = array( + 'text' => getTranslation('back'), + 'callback_data' => '0:pokebattler:0' + ); - // Save button. - $nav_keys[] = array( - 'text' => EMOJI_DISK, - 'callback_data' => $id . ':pokebattler:save#' . $poke1 . ',' . $poke2 . ',' . $poke3 - ); + // Save button. + $nav_keys[] = array( + 'text' => EMOJI_DISK, + 'callback_data' => $id . ':pokebattler:save#' . $poke1 . ',' . $poke2 . ',' . $poke3 + ); - // Reset button. - if($poke1 != 0) { - $nav_keys[] = array( - 'text' => getTranslation('reset'), - 'callback_data' => $id . ':pokebattler:ex#0,0,0' - ); - } + // Reset button. + if($poke1 != 0) { + $nav_keys[] = array( + 'text' => getTranslation('reset'), + 'callback_data' => $id . ':pokebattler:ex#0,0,0' + ); + } - // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ); + // Abort button. + $nav_keys[] = array( + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ); - // Get the inline key array and merge keys. - $nav_keys = inline_key_array($nav_keys, 2); - $keys = array_merge($keys, $nav_keys); - } + // Get the inline key array and merge keys. + $nav_keys = inline_key_array($nav_keys, 2); + $keys = array_merge($keys, $nav_keys); + } } // Callback message string. @@ -373,6 +370,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/pokedex.php b/mods/pokedex.php index 7a2c4a00..1b3559a9 100644 --- a/mods/pokedex.php +++ b/mods/pokedex.php @@ -1,6 +1,7 @@ ' . getTranslation('pokedex_edit_pokemon') . ''; +// Set message. +$msg = getTranslation('pokedex_list_of_all') . CR . CR . '' . getTranslation('pokedex_edit_pokemon') . ''; - // Get pokemon. - $keys = edit_pokedex_keys($limit, $action); +// Get pokemon. +$keys = edit_pokedex_keys($limit, $action); - // Empty keys? - if (!$keys) { - $msg = getTranslation('pokedex_not_found'); - } +// Empty keys? +if (!$keys) { + $msg = getTranslation('pokedex_not_found'); +} - // Build callback message string. - $callback_response = 'OK'; +// Telegram JSON array. +$tg_json = array(); - // Telegram JSON array. - $tg_json = array(); +// Answer callback. +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], 'OK', true); - // Answer callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); +// Edit message. +$tg_json[] = edit_message($update, $msg, $keys, false, true); - // Edit message. - $tg_json[] = edit_message($update, $msg, $keys, false, true); - - // Telegram multicurl request. - curl_json_multi_request($tg_json); -} - -// Exit. -exit(); +// Telegram multicurl request. +curl_json_multi_request($tg_json); diff --git a/mods/pokedex_disable_raids.php b/mods/pokedex_disable_raids.php index 9bd87b41..0f001dd1 100644 --- a/mods/pokedex_disable_raids.php +++ b/mods/pokedex_disable_raids.php @@ -20,120 +20,119 @@ // All raid levels? if($id == RAID_LEVEL_ALL) { - $clear = "'" . implode("','", $levels) . "'"; + $clear = "'" . implode("','", $levels) . "'"; } else { - $clear = "'" . $id . "'"; + $clear = "'" . $id . "'"; } // Raid level selection if($arg == 0) { - // Set message. - $msg = '' . getTranslation('disable_raid_level') . ':'; + // Set message. + $msg = '' . getTranslation('disable_raid_level') . ':'; - // Init empty keys array. - $keys = []; + // Init empty keys array. + $keys = []; - // All raid level keys. - $keys[] = array( - 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => RAID_LEVEL_ALL . ':pokedex_disable_raids:1' - ); + // All raid level keys. + $keys[] = array( + 'text' => getTranslation('pokedex_all_raid_level'), + 'callback_data' => RAID_LEVEL_ALL . ':pokedex_disable_raids:1' + ); - // Add key for each raid level - foreach($levels as $l) { - $keys[] = array( - 'text' => getTranslation($l . 'stars'), - 'callback_data' => $l . ':pokedex_disable_raids:1' - ); - } - - // Add abort button + // Add key for each raid level + foreach($levels as $l) { $keys[] = array( - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'text' => getTranslation($l . 'stars'), + 'callback_data' => $l . ':pokedex_disable_raids:1' ); + } + + // Add abort button + $keys[] = array( + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ); - // Get the inline key array. - $keys = inline_key_array($keys, 1); + // Get the inline key array. + $keys = inline_key_array($keys, 1); // Confirmation to disable raid level } else if($arg == 1) { - // Get all pokemon with raid levels from database. - $rs = my_query( - " - SELECT pokemon.pokedex_id, pokemon.pokemon_form_name, pokemon.pokemon_form_id, raid_bosses.raid_level - FROM raid_bosses - LEFT JOIN pokemon - ON pokemon.pokedex_id = raid_bosses.pokedex_id - AND pokemon.pokemon_form_id = raid_bosses.pokemon_form_id - WHERE raid_bosses.raid_level IN ({$clear}) - AND raid_bosses.scheduled = 0 - ORDER BY raid_level, pokedex_id, pokemon_form_name != 'normal', pokemon_form_name - " - ); - - // Init empty keys array. - $keys = []; - - // Init message and previous. - $msg = '' . getTranslation('disable_raid_level') . '?' . CR; - $previous = ''; - - // Build the message - while ($pokemon = $rs->fetch()) { - // Set current level - $current = $pokemon['raid_level']; + // Get all pokemon with raid levels from database. + $rs = my_query(' + SELECT pokemon.pokedex_id, pokemon.pokemon_form_name, pokemon.pokemon_form_id, raid_bosses.raid_level + FROM raid_bosses + LEFT JOIN pokemon + ON pokemon.pokedex_id = raid_bosses.pokedex_id + AND pokemon.pokemon_form_id = raid_bosses.pokemon_form_id + WHERE raid_bosses.raid_level IN (' . $clear . ') + AND raid_bosses.scheduled = 0 + ORDER BY raid_level, pokedex_id, pokemon_form_name != \'normal\', pokemon_form_name + '); + + // Init empty keys array. + $keys = []; + + // Init message and previous. + $msg = '' . getTranslation('disable_raid_level') . '?' . CR; + $previous = ''; + + // Build the message + while ($pokemon = $rs->fetch()) { + // Set current level + $current = $pokemon['raid_level']; + + // Add header for each raid level + if($previous != $current) { + $msg .= CR . '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; + } - // Add header for each raid level - if($previous != $current) { - $msg .= CR . '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; - } + // Add pokemon with id and name. + $dex_id = $pokemon['pokedex_id']; + $poke_name = get_local_pokemon_name($dex_id, $pokemon['pokemon_form_id']); + $msg .= $poke_name . ' (#' . $dex_id . ')' . CR; - // Add pokemon with id and name. - $dex_id = $pokemon['pokedex_id']; - $poke_name = get_local_pokemon_name($dex_id, $pokemon['pokemon_form_id']); - $msg .= $poke_name . ' (#' . $dex_id . ')' . CR; + // Prepare next run. + $previous = $current; + } - // Prepare next run. - $previous = $current; - } + // Disable. + $keys[] = array( + 'text' => getTranslation('yes'), + 'callback_data' => $id . ':pokedex_disable_raids:2' + ); - // Disable. - $keys[] = array( - 'text' => getTranslation('yes'), - 'callback_data' => $id . ':pokedex_disable_raids:2' - ); + // Abort. + $keys[] = array( + 'text' => getTranslation('no'), + 'callback_data' => '0:exit:0' + ); - // Abort. - $keys[] = array( - 'text' => getTranslation('no'), - 'callback_data' => '0:exit:0' - ); - - // Inline keys array. - $keys = inline_key_array($keys, 2); + // Inline keys array. + $keys = inline_key_array($keys, 2); // Disable raid level } else if($arg == 2) { - debug_log('Disabling old raid bosses for levels: '. $clear); - disable_raid_level($clear); + require_once(LOGIC_PATH . '/disable_raid_level.php'); + debug_log('Disabling old raid bosses for levels: '. $clear); + disable_raid_level($clear); - // Message. - $msg = '' . getTranslation('disabled_raid_level') . ':' . CR; + // Message. + $msg = '' . getTranslation('disabled_raid_level') . ':' . CR; - // All levels - if($id == RAID_LEVEL_ALL) { - foreach($levels as $lv) { - $msg .= getTranslation($lv . 'stars') . CR; - } + // All levels + if($id == RAID_LEVEL_ALL) { + foreach($levels as $lv) { + $msg .= getTranslation($lv . 'stars') . CR; + } - // Specific level - } else { - $msg .= getTranslation($id . 'stars'); - } + // Specific level + } else { + $msg .= getTranslation($id . 'stars'); + } - // Empty keys. - $keys = []; + // Empty keys. + $keys = []; } // Build callback message string. @@ -150,6 +149,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/pokedex_edit_pokemon.php b/mods/pokedex_edit_pokemon.php index 4dd18b0f..16b659f5 100644 --- a/mods/pokedex_edit_pokemon.php +++ b/mods/pokedex_edit_pokemon.php @@ -1,6 +1,9 @@ accessCheck($update, 'pokedex'); -require_once(LOGIC_PATH . '/get_pokemon_info.php'); // Set the id. $poke_id_form = $data['id']; [$pokedex_id, $pokemon_form_id] = explode('-',$data['id'],2); @@ -28,68 +30,68 @@ // Create keys array. $keys = [ + [ [ - [ - 'text' => getTranslation('pokedex_raid_level'), - 'callback_data' => $poke_id_form . ':pokedex_set_raid_level:setlevel' - ] + 'text' => getTranslation('pokedex_raid_level'), + 'callback_data' => $poke_id_form . ':pokedex_set_raid_level:setlevel' ] + ] ]; // Raid-Egg? Hide specific options! if(!in_array($pokedex_id, $GLOBALS['eggs'])) { - $keys_cp_weather = [ - [ - [ - 'text' => getTranslation('pokedex_min_cp'), - 'callback_data' => $poke_id_form . ':pokedex_set_cp:min-20-add-0' - ] - ], - [ - [ - 'text' => getTranslation('pokedex_max_cp'), - 'callback_data' => $poke_id_form . ':pokedex_set_cp:max-20-add-0' - ] - ], - [ - [ - 'text' => getTranslation('pokedex_min_weather_cp'), - 'callback_data' => $poke_id_form . ':pokedex_set_cp:min-25-add-0' - ] - ], - [ - [ - 'text' => getTranslation('pokedex_max_weather_cp'), - 'callback_data' => $poke_id_form . ':pokedex_set_cp:max-25-add-0' - ] - ], - [ - [ - 'text' => getTranslation('pokedex_weather'), - 'callback_data' => $poke_id_form . ':pokedex_set_weather:add-0' - ] - ], - [ - [ - 'text' => getTranslation('shiny'), - 'callback_data' => $poke_id_form . ':pokedex_set_shiny:setshiny' - ] - ] - ]; + $keys_cp_weather = [ + [ + [ + 'text' => getTranslation('pokedex_min_cp'), + 'callback_data' => $poke_id_form . ':pokedex_set_cp:min-20-add-0' + ] + ], + [ + [ + 'text' => getTranslation('pokedex_max_cp'), + 'callback_data' => $poke_id_form . ':pokedex_set_cp:max-20-add-0' + ] + ], + [ + [ + 'text' => getTranslation('pokedex_min_weather_cp'), + 'callback_data' => $poke_id_form . ':pokedex_set_cp:min-25-add-0' + ] + ], + [ + [ + 'text' => getTranslation('pokedex_max_weather_cp'), + 'callback_data' => $poke_id_form . ':pokedex_set_cp:max-25-add-0' + ] + ], + [ + [ + 'text' => getTranslation('pokedex_weather'), + 'callback_data' => $poke_id_form . ':pokedex_set_weather:add-0' + ] + ], + [ + [ + 'text' => getTranslation('shiny'), + 'callback_data' => $poke_id_form . ':pokedex_set_shiny:setshiny' + ] + ] + ]; - $keys = array_merge($keys, $keys_cp_weather); + $keys = array_merge($keys, $keys_cp_weather); } // Back and abort. $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:pokedex:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:pokedex:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] ]; // Build callback message string. @@ -106,6 +108,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/pokedex_import.php b/mods/pokedex_import.php index fc700b83..6ae0707a 100644 --- a/mods/pokedex_import.php +++ b/mods/pokedex_import.php @@ -12,42 +12,42 @@ $id = $data['id']; $arg = $data['arg']; -$msg = "Import data from community maintained sources:".CR; -$msg.= "ccev's github repository".CR; -$msg.= "Pokebattler"; +$msg = 'Import data from community maintained sources:'.CR; +$msg.= 'ccev\'s github repository'.CR; +$msg.= 'Pokebattler'; $keys = [ - [ - [ - 'text' => getTranslation('import') . SP . '(Pokebattler)', - 'callback_data' => '0:pokebattler:0' - ] - ], - [ - [ - 'text' => getTranslation('import') . SP . getTranslation('upcoming') . SP . '(Pokebattler)', - 'callback_data' => '0:import_future_bosses:0' - ] - ], - [ - [ - 'text' => getTranslation('import') . SP . getTranslation('shiny') . SP . '(Pokebattler)', - 'callback_data' => '0:import_shinyinfo:0' - ] - ], - [ - [ - 'text' => getTranslation('import') . SP . '(ccev pogoinfo)', - 'callback_data' => '0:pogoinfo:0' - ] - ], - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + [ + [ + 'text' => getTranslation('import') . SP . '(Pokebattler)', + 'callback_data' => '0:pokebattler:0' + ] + ], + [ + [ + 'text' => getTranslation('import') . SP . getTranslation('upcoming') . SP . '(Pokebattler)', + 'callback_data' => '0:import_future_bosses:0' + ] + ], + [ + [ + 'text' => getTranslation('import') . SP . getTranslation('shiny') . SP . '(Pokebattler)', + 'callback_data' => '0:import_shinyinfo:0' + ] + ], + [ + [ + 'text' => getTranslation('import') . SP . '(ccev pogoinfo)', + 'callback_data' => '0:pogoinfo:0' + ] + ], + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; // Callback message string. $callback_response = 'OK'; @@ -64,7 +64,4 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); -$dbh = null; exit(); - -?> \ No newline at end of file diff --git a/mods/pokedex_list_raids.php b/mods/pokedex_list_raids.php index 065d47cb..ec2c5696 100644 --- a/mods/pokedex_list_raids.php +++ b/mods/pokedex_list_raids.php @@ -10,16 +10,20 @@ $botUser->accessCheck($update, 'pokedex'); // Get all pokemon with raid levels from database. -$rs = my_query( - " - SELECT raid_bosses.id, raid_bosses.pokedex_id, raid_bosses.pokemon_form_id, raid_bosses.raid_level, DATE_FORMAT(date_start, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_start, DATE_FORMAT(date_end, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_end, raid_bosses.scheduled - FROM raid_bosses - LEFT JOIN pokemon - ON raid_bosses.pokedex_id = pokemon.pokedex_id - AND raid_bosses.pokemon_form_id = pokemon.pokemon_form_id - ORDER BY raid_bosses.date_start, raid_bosses.date_end, raid_bosses.raid_level, raid_bosses.pokedex_id, pokemon.pokemon_form_name != 'normal', pokemon.pokemon_form_name, raid_bosses.pokemon_form_id - " - ); +$rs = my_query(' + SELECT raid_bosses.id, + raid_bosses.pokedex_id, + raid_bosses.pokemon_form_id, + raid_bosses.raid_level, + DATE_FORMAT(date_start, \'%e.%c. ' . getTranslation('raid_egg_opens_at') . ' %H:%i\') as date_start, + DATE_FORMAT(date_end, \'%e.%c. ' . getTranslation('raid_egg_opens_at') . ' %H:%i\') as date_end, + raid_bosses.scheduled + FROM raid_bosses + LEFT JOIN pokemon + ON raid_bosses.pokedex_id = pokemon.pokedex_id + AND raid_bosses.pokemon_form_id = pokemon.pokemon_form_id + ORDER BY raid_bosses.date_start, raid_bosses.date_end, raid_bosses.raid_level, raid_bosses.pokedex_id, pokemon.pokemon_form_name != \'normal\', pokemon.pokemon_form_name, raid_bosses.pokemon_form_id +'); // Init empty keys array. $keys = []; @@ -31,74 +35,74 @@ $previous_date_end = ''; // Build the message while ($pokemon = $rs->fetch()) { - // Set current level - $current_level = $pokemon['raid_level']; - $current_date_start = $pokemon['date_start']; - $current_date_end = $pokemon['date_end']; - if($previous_date_start != $current_date_start || $previous_date_end != $current_date_end || $previous_date_start == 'FIRST_RUN') { - // Formatting. - if($previous_date_start != 'FIRST_RUN') { - $msg .= CR; - } - // Add header. - if($pokemon['scheduled'] == 0) { - $msg .= '' . getTranslation('unscheduled_bosses') . ':' . CR; - }else { - $msg .= EMOJI_CLOCK . ' ' . $pokemon['date_start'] . ' — ' . $pokemon['date_end'] . ':' . CR ; - } - $previous_level = 'FIRST_RUN'; + // Set current level + $current_level = $pokemon['raid_level']; + $current_date_start = $pokemon['date_start']; + $current_date_end = $pokemon['date_end']; + if($previous_date_start != $current_date_start || $previous_date_end != $current_date_end || $previous_date_start == 'FIRST_RUN') { + // Formatting. + if($previous_date_start != 'FIRST_RUN') { + $msg .= CR; } - // Add header for each raid level - if($previous_level != $current_level || $previous_level == 'FIRST_RUN') { - // Formatting. - if($previous_level != 'FIRST_RUN') { - $msg .= CR; - } - // Add header. - $msg .= '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; + // Add header. + if($pokemon['scheduled'] == 0) { + $msg .= '' . getTranslation('unscheduled_bosses') . ':' . CR; + }else { + $msg .= EMOJI_CLOCK . ' ' . $pokemon['date_start'] . ' — ' . $pokemon['date_end'] . ':' . CR ; } - // Add pokemon with id and name. - $poke_name = get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']); - $msg .= $poke_name . ' (#' . $pokemon['pokedex_id'] . ')' . CR; - - // Add button to edit pokemon. - if($pokemon['scheduled'] == 1) { - $keys[] = array( - 'text' => EMOJI_CLOCK . ' [' . $pokemon['raid_level'] . ']' . SP . $poke_name, - 'callback_data' => $pokemon['id'] . ':delete_scheduled_entry:0' - ); - } else { - $keys[] = array( - 'text' => '[' . $pokemon['raid_level'] . ']' . SP . $poke_name, - 'callback_data' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' - ); + $previous_level = 'FIRST_RUN'; + } + // Add header for each raid level + if($previous_level != $current_level || $previous_level == 'FIRST_RUN') { + // Formatting. + if($previous_level != 'FIRST_RUN') { + $msg .= CR; } + // Add header. + $msg .= '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; + } + // Add pokemon with id and name. + $poke_name = get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']); + $msg .= $poke_name . ' (#' . $pokemon['pokedex_id'] . ')' . CR; + + // Add button to edit pokemon. + if($pokemon['scheduled'] == 1) { + $keys[] = array( + 'text' => EMOJI_CLOCK . ' [' . $pokemon['raid_level'] . ']' . SP . $poke_name, + 'callback_data' => $pokemon['id'] . ':delete_scheduled_entry:0' + ); + } else { + $keys[] = array( + 'text' => '[' . $pokemon['raid_level'] . ']' . SP . $poke_name, + 'callback_data' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' + ); + } - // Prepare next run. - $previous_level = $current_level; - $previous_date_start = $current_date_start; - $previous_date_end = $current_date_end; + // Prepare next run. + $previous_level = $current_level; + $previous_date_start = $current_date_start; + $previous_date_end = $current_date_end; } if(!empty($msg)) { - // Set the message. - $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; - // Set the keys. - $keys = inline_key_array($keys, 2); - - // Done key. - $keys[] = [ - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ]; + // Set the message. + $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; + // Set the keys. + $keys = inline_key_array($keys, 2); + + // Done key. + $keys[] = [ + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ]; } else { - // Set empty keys. - $keys = []; + // Set empty keys. + $keys = []; - // Set the message. - $msg = getTranslation('pokedex_not_found'); + // Set the message. + $msg = getTranslation('pokedex_not_found'); } // Build callback message string. @@ -115,6 +119,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/pokedex_set_cp.php b/mods/pokedex_set_cp.php index edfc506c..cdd1db05 100644 --- a/mods/pokedex_set_cp.php +++ b/mods/pokedex_set_cp.php @@ -1,6 +1,7 @@ getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - - // Build callback message string. - $callback_response = 'OK'; - - // Set the message. - $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; - $msg .= getTranslation('pokedex_current_cp') . ' ' . $current_cp . CR . CR; - $msg .= '' .getTranslation('pokedex_' . $cp_type . $boosted) . ': ' . $cp_value . ''; + // Init empty keys array. + $keys = []; + + // Get the keys. + $keys = cp_keys($pokedex_id, 'pokedex_set_cp', $arg); + + // Back and abort. + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; + + // Build callback message string. + $callback_response = 'OK'; + + // Set the message. + $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; + $msg .= getTranslation('pokedex_current_cp') . ' ' . $current_cp . CR . CR; + $msg .= '' .getTranslation('pokedex_' . $cp_type . $boosted) . ': ' . $cp_value . ''; // Save cp to database } else if($action == 'save') { - // Set column name. - $cp_column = $cp_type . $boosted; - - // Update cp of pokemon. - $rs = my_query(' - UPDATE pokemon - SET ' . $cp_column . ' = ? - WHERE pokedex_id = ? - AND pokemon_form_id = ? - ', [$cp_value, $dex_id, $dex_form] - ); - - // Back to pokemon and done keys. - $keys = [ - [ - [ - 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; - - // Build callback message string. - $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); - - // Set the message. - $msg = getTranslation('pokemon_saved') . CR; - $msg .= '' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR . CR; - $msg .= getTranslation('pokedex_' . $cp_type . $boosted) . ': ' . $cp_value . ''; + // Set column name. + $cp_column = $cp_type . $boosted; + + // Update cp of pokemon. + $rs = my_query(' + UPDATE pokemon + SET ' . $cp_column . ' = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$cp_value, $dex_id, $dex_form] + ); + + // Back to pokemon and done keys. + $keys = [ + [ + [ + 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ] + ]; + + // Build callback message string. + $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); + + // Set the message. + $msg = getTranslation('pokemon_saved') . CR; + $msg .= '' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR . CR; + $msg .= getTranslation('pokedex_' . $cp_type . $boosted) . ': ' . $cp_value . ''; } // Telegram JSON array. @@ -119,5 +119,70 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); -// Exit. -exit(); +function cp_keys($pokedex_id, $action, $arg) +{ + // Get the type, level and cp + $data = explode("-", $arg); + $cp_type_level = $data[0] . '-' . $data[1]; + $cp_add = $data[0] . '-' . $data[1] . '-' . $data[2] . '-'; + $old_cp = $data[3]; + + // Save and reset values + $save_arg = $cp_type_level . '-save-' . $old_cp; + $reset_arg = $cp_add . '0'; + + // Init empty keys array. + $keys = []; + + // Max CP is 9999 and no the value 999 is not a typo! + // Keys will be shown up to 999 and when user is adding one more number we exceed 999, so we remove the keys then + // This means we do not exceed a Max CP of 9999 :) + if($old_cp <= 999) { + + // Add keys 0 to 9 + /** + * 7 8 9 + * 4 5 6 + * 1 2 3 + * 0 + */ + + // 7 8 9 + foreach ([7, 8, 9, 4, 5, 6, 1, 2, 3] as $i) { + // Set new cp + $new_cp = $cp_add . ($old_cp == 0 ? '' : $old_cp) . $i; + + // Set keys. + $keys[] = array( + 'text' => $i, + 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_cp + ); + } + + // 0 + $new_cp = ($old_cp != 0) ? $cp_add . $old_cp . '0' : $reset_arg; + + // Set keys. + $keys[] = array( + 'text' => '0', + 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_cp + ); + } + + // Save + $keys[] = array( + 'text' => EMOJI_DISK, + 'callback_data' => $pokedex_id . ':' . $action . ':' . $save_arg + ); + + // Reset + $keys[] = array( + 'text' => getTranslation('reset'), + 'callback_data' => $pokedex_id . ':' . $action . ':' . $reset_arg + ); + + // Get the inline key array. + $keys = inline_key_array($keys, 3); + + return $keys; +} diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index 93d025cd..381d7d42 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -1,6 +1,7 @@ getTranslation($lv . 'stars'), - 'callback_data' => $pokedex_id . ':pokedex_set_raid_level:' . $lv - ) - ]; - } - - // Back and abort. - $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; +if($data['arg'] == 'setlevel') { + $raid_levels = str_split('0' . RAID_LEVEL_ALL); - // Build callback message string. - $callback_response = getTranslation('select_raid_level'); + // Init empty keys array. + $keys = []; - // Set the message. - $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; - $msg .= getTranslation('pokedex_current_raid_level') . ' ' . getTranslation($pokemon['raid_level'] . 'stars') . CR . CR; - $msg .= '' . getTranslation('pokedex_new_raid_level') . ':'; + // Create keys array. + foreach($raid_levels as $lv) { + $keys[] = [ + array( + 'text' => getTranslation($lv . 'stars'), + 'callback_data' => $pokedex_id . ':pokedex_set_raid_level:' . $lv + ) + ]; + } + + // Back and abort. + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; + + // Build callback message string. + $callback_response = getTranslation('select_raid_level'); + + // Set the message. + $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; + $msg .= getTranslation('pokedex_current_raid_level') . ' ' . getTranslation($pokemon['raid_level'] . 'stars') . CR . CR; + $msg .= '' . getTranslation('pokedex_new_raid_level') . ':'; } else { - // Update raid level of pokemon. + // Update raid level of pokemon. + my_query(' + DELETE FROM raid_bosses + WHERE pokedex_id = ? + AND pokemon_form_id = ? + AND scheduled = 0 + ', [$dex_id, $dex_form] + ); + if($arg != 0) { my_query(' - DELETE FROM raid_bosses - WHERE pokedex_id = ? - AND pokemon_form_id = ? - AND scheduled = 0 - ', [$dex_id, $dex_form] + INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) + VALUES (?, ?, ?) + ',[$dex_id, $dex_form, $arg] ); - if($arg != 0) { - my_query(' - INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) - VALUES (?, ?, ?) - ',[$dex_id, $dex_form, $arg] - ); - } - - // Back to pokemon and done keys. - $keys = [ - [ - [ - 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; - - // Build callback message string. - $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); - - // Set the message. - $msg = getTranslation('pokemon_saved') . CR; - $msg .= '' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR . CR; - $msg .= getTranslation('pokedex_new_raid_level') . ':' . CR; - $msg .= '' . getTranslation($arg . 'stars') . ''; + } + + // Back to pokemon and done keys. + $keys = [ + [ + [ + 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ] + ]; + + // Build callback message string. + $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); + + // Set the message. + $msg = getTranslation('pokemon_saved') . CR; + $msg .= '' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR . CR; + $msg .= getTranslation('pokedex_new_raid_level') . ':' . CR; + $msg .= '' . getTranslation($arg . 'stars') . ''; } // Telegram JSON array. @@ -111,6 +111,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/pokedex_set_shiny.php b/mods/pokedex_set_shiny.php index 2aa11d08..484adb9b 100644 --- a/mods/pokedex_set_shiny.php +++ b/mods/pokedex_set_shiny.php @@ -1,6 +1,7 @@ getTranslation($shinyText), - 'callback_data' => $pokedex_id . ':pokedex_set_shiny:' . $newShinyValue - ] - ], - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; - - // Build callback message string. - $callback_response = getTranslation('select_shiny_status'); - - // Set the message. - $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; - $msg .= getTranslation('pokedex_current_status') . SP . $old_shiny_status . CR . CR; - $msg .= '' . getTranslation('pokedex_new_status') . ':'; + // Get current shiny status from database. + $pokemon = get_pokemon_info($dex_id, $dex_form); + + $shinyText = ($pokemon['shiny'] == 0) ? 'shiny' : 'not_shiny'; + $old_shiny_status = ($pokemon['shiny'] == 0) ? getTranslation('not_shiny') : EMOJI_SHINY . SP . getTranslation('shiny'); + $newShinyValue = ($pokemon['shiny'] == 0) ? 1 : 0; + + // Back and abort. + $keys = [ + [ + [ + 'text' => getTranslation($shinyText), + 'callback_data' => $pokedex_id . ':pokedex_set_shiny:' . $newShinyValue + ] + ], + [ + [ + 'text' => getTranslation('back'), + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; + + // Build callback message string. + $callback_response = getTranslation('select_shiny_status'); + + // Set the message. + $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; + $msg .= getTranslation('pokedex_current_status') . SP . $old_shiny_status . CR . CR; + $msg .= '' . getTranslation('pokedex_new_status') . ':'; } else { - // Update shiny status of pokemon. - $rs = my_query(' - UPDATE pokemon - SET shiny = ? - WHERE pokedex_id = ? - AND pokemon_form_id = ? - ', [$arg, $dex_id, $dex_form] - ); - - // Back to pokemon and done keys. - $keys = [ - [ - [ - 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; - - // Build callback message string. - $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); - - // Set the message. - $msg = getTranslation('pokemon_saved') . CR; - $msg .= '' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR . CR; - $msg .= getTranslation('pokedex_new_status') . ':' . CR; - $msg .= '' . (($arg == 1) ? (getTranslation('shiny')) : (getTranslation('not_shiny'))) . ''; + // Update shiny status of pokemon. + $rs = my_query(' + UPDATE pokemon + SET shiny = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$arg, $dex_id, $dex_form] + ); + + // Back to pokemon and done keys. + $keys = [ + [ + [ + 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ] + ]; + + // Build callback message string. + $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); + + // Set the message. + $msg = getTranslation('pokemon_saved') . CR; + $msg .= '' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR . CR; + $msg .= getTranslation('pokedex_new_status') . ':' . CR; + $msg .= '' . (($arg == 1) ? (getTranslation('shiny')) : (getTranslation('not_shiny'))) . ''; } // Telegram JSON array. @@ -102,6 +102,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/pokedex_set_weather.php b/mods/pokedex_set_weather.php index f0aacfa9..92f4a404 100644 --- a/mods/pokedex_set_weather.php +++ b/mods/pokedex_set_weather.php @@ -1,6 +1,9 @@ getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - - // Set the message. - $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; - $msg .= getTranslation('pokedex_current_weather') . ' ' . get_weather_icons($old_weather) . CR . CR; - $msg .= '' . getTranslation('pokedex_new_weather') . ' ' . get_weather_icons($new_weather); + + // Get the keys. + $keys = weather_keys($pokedex_id, 'pokedex_set_weather', $arg); + + // Build callback message string. + $callback_response = 'OK'; + + // Back and abort. + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; + + // Set the message. + $msg = getTranslation('raid_boss') . ': ' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR; + $msg .= getTranslation('pokedex_current_weather') . ' ' . get_weather_icons($old_weather) . CR . CR; + $msg .= '' . getTranslation('pokedex_new_weather') . ' ' . get_weather_icons($new_weather); // Save weather to database } else if($action == 'save') { - // Update weather of pokemon. - $rs = my_query( - ' - UPDATE pokemon - SET weather = ? - WHERE pokedex_id = ? - AND pokemon_form_id = ? - ', [$new_weather, $dex_id, $dex_form] - ); - - // Back to pokemon and done keys. - $keys = [ - [ - [ - 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; - - // Build callback message string. - $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); - - // Set the message. - $msg = getTranslation('pokemon_saved') . CR; - $msg .= '' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR . CR; - $msg .= getTranslation('pokedex_weather') . ':' . CR; - $msg .= '' . get_weather_icons($new_weather) . ''; + // Update weather of pokemon. + $rs = my_query(' + UPDATE pokemon + SET weather = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$new_weather, $dex_id, $dex_form] + ); + + // Back to pokemon and done keys. + $keys[] = [ + [ + 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', + 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ]; + + // Build callback message string. + $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); + + // Set the message. + $msg = getTranslation('pokemon_saved') . CR; + $msg .= '' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR . CR; + $msg .= getTranslation('pokedex_weather') . ':' . CR; + $msg .= '' . get_weather_icons($new_weather) . ''; } // Telegram JSON array. @@ -107,6 +106,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/post_raid.php b/mods/post_raid.php index a165074d..a5463c12 100644 --- a/mods/post_raid.php +++ b/mods/post_raid.php @@ -18,6 +18,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/raid_by_gym.php b/mods/raid_by_gym.php index fa4b66db..21d64a7b 100644 --- a/mods/raid_by_gym.php +++ b/mods/raid_by_gym.php @@ -1,6 +1,7 @@ getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); + // Add navigation keys. + $nav_keys = []; + $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); + $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); + $nav_keys = inline_key_array($nav_keys, 2); + // Merge keys. + $keys = array_merge($keys, $nav_keys); } // Build callback message string. @@ -57,6 +58,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/raid_by_gym_letter.php b/mods/raid_by_gym_letter.php index 02299807..4f1b785f 100644 --- a/mods/raid_by_gym_letter.php +++ b/mods/raid_by_gym_letter.php @@ -1,6 +1,7 @@ getTranslation('not_supported'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('not_supported'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } // Build callback message string. @@ -53,31 +54,28 @@ $msg = ''; // Edit the message. if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; - }elseif($config->DEFAULT_GYM_AREA !== false) { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } + if($keys_and_gymarea['gymarea_name'] == '') { + $msg .= '' . getTranslation('select_gym_area') . '' . CR; + }elseif($config->DEFAULT_GYM_AREA !== false) { + if($keys_and_gymarea['letters']) { + $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; - } + $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; } + }else { + if($keys_and_gymarea['letters']) { + $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; + }else { + $msg .= '' . getTranslation('select_gym_name') . '' . CR; + } + } }elseif($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; + $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; + $msg .= '' . getTranslation('select_gym_name') . '' . CR; } $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); $tg_json[] = edit_message($update, $msg, $keys, false, true); // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/raid_by_location.php b/mods/raid_by_location.php index e2e45065..927ccee6 100644 --- a/mods/raid_by_location.php +++ b/mods/raid_by_location.php @@ -1,6 +1,9 @@ RAID_VIA_LOCATION) { - debug_log('Creating raids by sharing a location is not enabled in config! Exiting!'); - send_message($update['message']['chat']['id'], '' . getTranslation('bot_access_denied') . ''); - exit(); + debug_log('Creating raids by sharing a location is not enabled in config! Exiting!'); + send_message($update['message']['chat']['id'], '' . getTranslation('bot_access_denied') . ''); + exit(); } $reg_exp_coordinates = '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$^'; // Get latitude / longitude values from Telegram if(isset($update['message']['location']) && preg_match($reg_exp_coordinates, $update['message']['location']['latitude'] . ',' . $update['message']['location']['longitude'])) { - $lat = $update['message']['location']['latitude']; - $lon = $update['message']['location']['longitude']; + $lat = $update['message']['location']['latitude']; + $lon = $update['message']['location']['longitude']; } else if(isset($update['callback_query']) && preg_match($reg_exp_coordinates, $data['id'] . ',' . $data['arg'])) { - $lat = $data['id']; - $lon = $data['arg']; + $lat = $data['id']; + $lon = $data['arg']; } else { - send_message($update['message']['chat']['id'], '' . getTranslation('invalid_input') . ''); - exit(); + send_message($update['message']['chat']['id'], '' . getTranslation('invalid_input') . ''); + exit(); } // Debug @@ -39,103 +42,95 @@ // Temporary gym_name if($config->RAID_VIA_LOCATION_FUNCTION == 'remote') { - $gym_name = getPublicTranslation('remote_raid') . ': '.$addr['district']; - $gym = false; - $gym_letter = substr($gym_name, 0, 1); + $gym_name = getPublicTranslation('remote_raid') . ': '.$addr['district']; + $gym = false; + $gym_letter = substr($gym_name, 0, 1); }else { - $gym_name = '#' . $update['message']['chat']['id']; - $gym_letter = substr($gym_name, 0, 1); - // Get gym by temporary name. - $gym = get_gym_by_telegram_id($gym_name); + $gym_name = '#' . $update['message']['chat']['id']; + $gym_letter = substr($gym_name, 0, 1); + // Get gym by temporary name. + $gym = get_gym_by_telegram_id($gym_name); } // If gym is already in the database, make sure no raid is active before continuing! if($gym) { - debug_log('Gym found in the database! Checking for active raid now!'); - $gym_id = $gym['id']; + debug_log('Gym found in the database! Checking for active raid now!'); + $gym_id = $gym['id']; - // Check for duplicate raid - $duplicate_id = 0; - $duplicate_id = active_raid_duplication_check($gym_id); + // Check for duplicate raid + $duplicate_id = 0; + $duplicate_id = active_raid_duplication_check($gym_id); - // Continue with raid creation - if($duplicate_id > 0) { - debug_log('Active raid is in progress!'); - debug_log('Tell user to update the gymname and exit!'); + // Continue with raid creation + if($duplicate_id > 0) { + debug_log('Active raid is in progress!'); + debug_log('Tell user to update the gymname and exit!'); - // Show message that a raid is active on that gym. - $raid_id = $duplicate_id; - $raid = get_raid($raid_id); + // Show message that a raid is active on that gym. + $raid_id = $duplicate_id; + $raid = get_raid($raid_id); - // Build message. - $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); + // Build message. + $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); - // Tell user to update the gymname first to create another raid by location - $msg .= getTranslation('gymname_then_location'); - $keys = []; + // Tell user to update the gymname first to create another raid by location + $msg .= getTranslation('gymname_then_location'); + $keys = []; - // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + // Send message. + send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); - exit(); - } else { - debug_log('No active raid found! Continuing now ...'); - } + exit(); + } else { + debug_log('No active raid found! Continuing now ...'); + } } else { - // Set gym_id to 0 - $gym_id = 0; - debug_log('No gym found in the database! Continuing now ...'); + // Set gym_id to 0 + $gym_id = 0; + debug_log('No gym found in the database! Continuing now ...'); } // Insert / update gym. -try { - - global $dbh; - - // Build query to check if gym is already in database or not - $rs = my_query(" - SELECT COUNT(*) AS count - FROM gyms - WHERE gym_name = '{$gym_name}' - "); - - $row = $rs->fetch(); - $parameters = [ 'gym_name' => $gym_name, - 'lat' => $lat, - 'lon' => $lon, - 'address' => $address, - ]; - // Gym already in database or new - if (empty($row['count']) or $config->RAID_VIA_LOCATION_FUNCTION == 'remote') { - // insert gym in table. - debug_log('Gym not found in database gym list! Inserting gym "' . $gym_name . '" now.'); - $parameters['img_url'] = 'file://' . IMAGES_PATH . '/gym_default.png'; - $query = ' - INSERT INTO gyms (gym_name, lat, lon, address, show_gym, img_url, temporary_gym) - VALUES (:gym_name, :lat, :lon, :address, 0, :img_url, 1) - '; - } else { - // Update gyms table to reflect gym changes. - debug_log('Gym found in database gym list! Updating gym "' . $gym_name . '" now.'); - $query = ' - UPDATE gyms - SET lat = :lat, - lon = :lon, - address = :address - WHERE gym_name = :gym_name - '; - } - $statement = $dbh->prepare($query); - $statement->execute($parameters); - // Get gym id from insert. - if($gym_id == 0) { - $gym_id = $dbh->lastInsertId(); - } -} catch (PDOException $exception) { - - error_log($exception->getMessage()); - $dbh = null; - exit(); + +// Build query to check if gym is already in database or not +$rs = my_query(' + SELECT COUNT(*) AS count + FROM gyms + WHERE gym_name = ? + ',[$gym_name] +); + +$row = $rs->fetch(); +$parameters = [ + 'gym_name' => $gym_name, + 'lat' => $lat, + 'lon' => $lon, + 'address' => $address, +]; +// Gym already in database or new +if (empty($row['count']) or $config->RAID_VIA_LOCATION_FUNCTION == 'remote') { + // insert gym in table. + debug_log('Gym not found in database gym list! Inserting gym "' . $gym_name . '" now.'); + $parameters['img_url'] = 'file://' . IMAGES_PATH . '/gym_default.png'; + $query = ' + INSERT INTO gyms (gym_name, lat, lon, address, show_gym, img_url, temporary_gym) + VALUES (:gym_name, :lat, :lon, :address, 0, :img_url, 1) + '; +} else { + // Update gyms table to reflect gym changes. + debug_log('Gym found in database gym list! Updating gym "' . $gym_name . '" now.'); + $query = ' + UPDATE gyms + SET lat = :lat, + lon = :lon, + address = :address + WHERE gym_name = :gym_name + '; +} +$statement = my_query($query, $parameters); +// Get gym id from insert. +if($gym_id == 0) { + $gym_id = $dbh->lastInsertId(); } // Write to log. @@ -144,45 +139,42 @@ // Create the keys. $keys = [ + [ [ - [ - 'text' => getTranslation('next'), - 'callback_data' => $gym_letter . ':edit_raidlevel:' . $gym_id - ] - ], + 'text' => getTranslation('next'), + 'callback_data' => $gym_letter . ':edit_raidlevel:' . $gym_id + ] + ], + [ [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => $gym_id . ':exit:2' - ] + 'text' => getTranslation('abort'), + 'callback_data' => $gym_id . ':exit:2' ] + ] ]; // Answer location message. if(isset($update['message']['location'])) { - // Build message. - $msg = getTranslation('create_raid') . ': ' . $address . ''; + // Build message. + $msg = getTranslation('create_raid') . ': ' . $address . ''; - // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + // Send message. + send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); // Answer forwarded location message from geo_create. } else if(isset($update['callback_query'])) { - // Build callback message string. - $callback_response = getTranslation('here_we_go'); + // Build callback message string. + $callback_response = getTranslation('here_we_go'); - // Telegram JSON array. - $tg_json = array(); + // Telegram JSON array. + $tg_json = array(); - // Answer callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - // Edit the message. - $tg_json[] = edit_message($update, getTranslation('select_gym_name'), $keys, false, true); + // Edit the message. + $tg_json[] = edit_message($update, getTranslation('select_gym_name'), $keys, false, true); - // Telegram multicurl request. - curl_json_multi_request($tg_json); + // Telegram multicurl request. + curl_json_multi_request($tg_json); } - -// Exit. -exit(); diff --git a/mods/raid_edit_poke.php b/mods/raid_edit_poke.php index c717f8fd..099c1fb3 100644 --- a/mods/raid_edit_poke.php +++ b/mods/raid_edit_poke.php @@ -1,4 +1,5 @@ getTranslation('not_supported'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('not_supported'), + 'callback_data' => '0:exit:0' + ] + ] + ]; } // Build callback message string. @@ -55,13 +56,10 @@ $msg = getTranslation('raid_boss') . ':' . SP . get_local_pokemon_name($raid['pokemon'],$raid['pokemon_form']) . CR . CR; $msg .= '' . getTranslation('select_raid_boss') . ':'; if (isset($update['callback_query']['inline_message_id'])) { - $tg_json[] = editMessageText($update['callback_query']['inline_message_id'], $msg, $keys, NULL, false, true); + $tg_json[] = editMessageText($update['callback_query']['inline_message_id'], $msg, $keys, NULL, false, true); } else { - $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, $keys, $update['callback_query']['message']['chat']['id'], $keys, true); + $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, $keys, $update['callback_query']['message']['chat']['id'], $keys, true); } // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/raid_set_poke.php b/mods/raid_set_poke.php index ea3b864f..e72be018 100644 --- a/mods/raid_set_poke.php +++ b/mods/raid_set_poke.php @@ -1,6 +1,9 @@ getTranslation('yes'), - 'callback_data' => $raid['id'] . ':raids_delete:2' - ], - [ - 'text' => getTranslation('no'), - 'callback_data' => $raid['id'] . ':raids_delete:1' - ] - ] - ]; - - // Set message. - $msg = EMOJI_WARN . ' ' . getTranslation('delete_this_raid') . ' ' . EMOJI_WARN . CR . CR; - $msg .= show_raid_poll_small($raid); + // Get raid. + $raid = get_raid($raidId); + + // Write to log. + debug_log('Asking for confirmation to delete the following raid:'); + debug_log($raid); + + // Create keys array. + $keys = [ + [ + [ + 'text' => getTranslation('yes'), + 'callback_data' => $raid['id'] . ':raids_delete:2' + ], + [ + 'text' => getTranslation('no'), + 'callback_data' => $raid['id'] . ':raids_delete:1' + ] + ] + ]; + + // Set message. + $msg = EMOJI_WARN . ' ' . getTranslation('delete_this_raid') . ' ' . EMOJI_WARN . CR . CR; + $msg .= show_raid_poll_small($raid); } else if ($action == 1) { - debug_log('Raid deletion for ' . $raidId . ' was canceled!'); - // Set message. - $msg = '' . getTranslation('raid_deletion_was_canceled') . ''; + debug_log('Raid deletion for ' . $raidId . ' was canceled!'); + // Set message. + $msg = '' . getTranslation('raid_deletion_was_canceled') . ''; - // Set keys. - $keys = []; + // Set keys. + $keys = []; } else if ($action == 2) { - debug_log('Confirmation to delete raid ' . $raidId . ' was received!'); - // Set message. - $msg = getTranslation('raid_successfully_deleted'); - - // Set keys. - $keys = []; - - // Delete raid from database. - delete_raid($raidId); + debug_log('Confirmation to delete raid ' . $raidId . ' was received!'); + // Delete telegram messages for raid. + $rs = my_query(' + SELECT * + FROM cleanup + WHERE raid_id = ? + AND chat_id <> 0 + ', [$raidId] + ); + + // Counter + $counter = 0; + + // Delete every telegram message + while ($row = $rs->fetch()) { + // Delete telegram message. + debug_log('Deleting telegram message ' . $row['message_id'] . ' from chat ' . $row['chat_id'] . ' for raid ' . $row['raid_id']); + delete_message($row['chat_id'], $row['message_id']); + $counter = $counter + 1; + } + + // Nothing to delete on telegram. + if ($counter == 0) { + debug_log('Raid with ID ' . $raidId . ' was not found in the cleanup table! Skipping deletion of telegram messages!'); + } + + // Delete raid from cleanup table. + debug_log('Deleting raid ' . $raidId . ' from the cleanup table:'); + my_query(' + DELETE FROM cleanup + WHERE raid_id = ? + ', [$raidId] + ); + + // Delete raid from attendance table. + debug_log('Deleting raid ' . $raidId . ' from the attendance table:'); + my_query(' + DELETE FROM attendance + WHERE raid_id = ? + ', [$raidId] + ); + + // Delete raid from raid table. + debug_log('Deleting raid ' . $raidId . ' from the raid table:'); + my_query(' + DELETE FROM raids + WHERE id = ? + ', [$raidId] + ); + + // Set message. + $msg = getTranslation('raid_successfully_deleted'); + + // Set keys. + $keys = []; } - + // Build callback message string. $callback_response = 'OK'; @@ -77,6 +124,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/raids_list.php b/mods/raids_list.php index 3328ee50..54a4ddc3 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -1,6 +1,7 @@ getTranslation('expand'), - 'callback_data' => $raid['id'] . ':vote_refresh:0', - ] + 'text' => getTranslation('expand'), + 'callback_data' => $raid['id'] . ':vote_refresh:0', ] + ] ]; if($botUser->raidAccessCheck($update, $raidId, 'pokemon', true)) { - $keys[] = [ - [ - 'text' => getTranslation('update_pokemon'), - 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], - ] - ]; + $keys[] = [ + [ + 'text' => getTranslation('update_pokemon'), + 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], + ] + ]; } if($botUser->raidAccessCheck($update, $raidId, 'delete', true)) { - $keys[] = [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => $raid['id'] . ':raids_delete:0' - ] - ]; + $keys[] = [ + [ + 'text' => getTranslation('delete'), + 'callback_data' => $raid['id'] . ':raids_delete:0' + ] + ]; } // Add keys to share. debug_log($raid, 'raw raid data for share: '); $keys_share = share_keys($raid['id'], 'raid_share', $update, $raid['level']); if(!empty($keys_share)) { - $keys = array_merge($keys, $keys_share); + $keys = array_merge($keys, $keys_share); } else { - debug_log('There are no groups to share to, is SHARE_CHATS set?'); + debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key $keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); @@ -69,6 +70,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -// Exit. -exit(); diff --git a/mods/refresh_polls.php b/mods/refresh_polls.php index 5da202cf..c0179c46 100644 --- a/mods/refresh_polls.php +++ b/mods/refresh_polls.php @@ -1,37 +1,37 @@ AUTO_REFRESH_POLLS) { - if(strlen($data['id']) > 5) $where_chat = 'chat_id = '.$data['id']; else $where_chat = 'chat_id != 0'; - if(!empty($config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL)) $level_exclude = 'AND raids.level NOT IN ('.$config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL.')'; else $level_exclude = ''; - $query_messages = my_query(" - SELECT cleanup.raid_id, cleanup.chat_id, cleanup.message_id, cleanup.type, cleanup.media_unique_id - FROM cleanup - LEFT JOIN raids - ON cleanup.raid_id = raids.id - WHERE {$where_chat} - AND cleanup.type IN ('poll_text', 'poll_photo', 'photo') - AND raids.start_time <= UTC_TIMESTAMP() - AND raids.end_time > DATE_SUB(UTC_TIMESTAMP(), INTERVAL 1 MINUTE) - AND message_id != 0 - {$level_exclude} - "); - debug_log("REFRESH POLLS:"); - debug_log("Num rows: ".$query_messages->rowCount()); - $tg_json = []; - while($res_messages = $query_messages->fetch()) { +if(!$config->AUTO_REFRESH_POLLS) { + info_log("Automatic refresh of raid polls failed, AUTO_REFRESH_POLLS is set to false in config."); + exit(); +} +if(strlen($data['id']) > 5) $where_chat = 'chat_id = '.$data['id']; else $where_chat = 'chat_id != 0'; +if(!empty($config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL)) $level_exclude = 'AND raids.level NOT IN ('.$config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL.')'; else $level_exclude = ''; +$query_messages = my_query(' + SELECT cleanup.raid_id, cleanup.chat_id, cleanup.message_id, cleanup.type, cleanup.media_unique_id + FROM cleanup + LEFT JOIN raids + ON cleanup.raid_id = raids.id + WHERE ' .$where_chat . ' + AND cleanup.type IN (\'poll_text\', \'poll_photo\', \'photo\') + AND raids.start_time <= UTC_TIMESTAMP() + AND raids.end_time > DATE_SUB(UTC_TIMESTAMP(), INTERVAL 1 MINUTE) + AND message_id != 0 + ' . $level_exclude +); +debug_log("REFRESH POLLS:"); +debug_log("Num rows: ".$query_messages->rowCount()); +$tg_json = []; +while($res_messages = $query_messages->fetch()) { - debug_log("message id: ".$res_messages['message_id']); - debug_log("chat id: ".$res_messages['chat_id']); - debug_log("raid id: ".$res_messages['raid_id']); + debug_log("message id: ".$res_messages['message_id']); + debug_log("chat id: ".$res_messages['chat_id']); + debug_log("raid id: ".$res_messages['raid_id']); - $data_poll['push'] = $res_messages; + $data_poll['push'] = $res_messages; - require_once(LOGIC_PATH . '/update_raid_poll.php'); - $tg_json = update_raid_poll($res_messages['raid_id'], get_raid($res_messages['raid_id']), $data_poll, $tg_json); - } - curl_json_multi_request($tg_json); -}else { - info_log("Automatic refresh of raid polls failed, AUTO_REFRESH_POLLS is set to false in config."); + require_once(LOGIC_PATH . '/update_raid_poll.php'); + $tg_json = update_raid_poll($res_messages['raid_id'], get_raid($res_messages['raid_id']), $data_poll, $tg_json); } -exit(); \ No newline at end of file +curl_json_multi_request($tg_json); +exit(); diff --git a/mods/save_event_note.php b/mods/save_event_note.php index 76ee6def..7e283d26 100644 --- a/mods/save_event_note.php +++ b/mods/save_event_note.php @@ -1,6 +1,7 @@ getTranslation('event_note_edit'), - 'callback_data' => $raid_id . ':edit_event_note:edit' - ] - ], + 'text' => getTranslation('event_note_edit'), + 'callback_data' => $raid_id . ':edit_event_note:edit' + ] + ], + [ [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => $raid_id . ':raids_delete:0' - ] + 'text' => getTranslation('delete'), + 'callback_data' => $raid_id . ':raids_delete:0' ] + ] ]; $keys_share = share_keys($raid_id, 'raid_share', $update, $raid['level']); $keys = array_merge($keys, $keys_share); diff --git a/mods/save_gym_info.php b/mods/save_gym_info.php index 8c5327e1..d0496d2c 100644 --- a/mods/save_gym_info.php +++ b/mods/save_gym_info.php @@ -1,6 +1,9 @@ $lat, - ':lon' => $lon, - ':id' => $gym_id, - ]; - $gym['lat'] = $lat; - $gym['lon'] = $lon; - }else { - send_message($user_id, getTranslation("gym_gps_coordinates_format_error") . CR . getTranslation("gym_coordinates_format_example")); - exit(); - } + $reg_exp_coordinates = '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$^'; + if(!preg_match($reg_exp_coordinates, $input)) { + send_message($user_id, getTranslation("gym_gps_coordinates_format_error") . CR . getTranslation("gym_gps_example")); + exit(); + } + [$lat, $lon] = explode(',', $input, 2); + $query = 'UPDATE gyms SET lat = :lat, lon = :lon WHERE id = :id'; + $binds = [ + ':lat' => $lat, + ':lon' => $lon, + ':id' => $gym_id, + ]; + $gym['lat'] = $lat; + $gym['lon'] = $lon; }else if(in_array($action, ['addr','name','note'])) { - $column_map = ['addr' => 'address', 'name' => 'gym_name', 'note' => 'gym_note']; - if(strlen($input) <= 255) { - $query = 'UPDATE gyms SET '.$column_map[$action].'=:value WHERE id = :id'; - $binds = [ - ':value' => $input, - ':id' => $gym_id, - ]; - $gym[$column_map[$action]] = $input; - }else { - send_message($user_id, getTranslation("gym_edit_text_too_long")); - exit(); - } + if(strlen($input) > 255) { + send_message($user_id, getTranslation('gym_edit_text_too_long')); + exit(); + } + $column_map = ['addr' => 'address', 'name' => 'gym_name', 'note' => 'gym_note']; + $query = 'UPDATE gyms SET ' . $column_map[$action] . ' = :value WHERE id = :id'; + $binds = [ + ':value' => $input, + ':id' => $gym_id, + ]; + $gym[$column_map[$action]] = $input; } if($query !== false) { - $prepare = $dbh->prepare($query); - $prepare->execute($binds); + my_query($query, $binds); - $msg = get_gym_details($gym, true); - $msg .= CR . CR . getTranslation("gym_saved"); - $update['callback_query']['from']['id'] = $user_id; - $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); + $msg = get_gym_details($gym, true); + $msg .= CR . CR . getTranslation('gym_saved'); + $update['callback_query']['from']['id'] = $user_id; + $keys = edit_gym_keys($update, $gym_id, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); } // Remove back button from previous message to avoid confusion editMessageText($modifiers['old_message_id'], $msg, $keys, $user_id, ['disable_web_page_preview' => 'true']); -if($error) exit(); diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 88b769a4..7f9034c0 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -1,6 +1,8 @@ accessCheck($update, 'share-all'); if(isset($data['arg']) && $data['arg'] == 1) { - $raid_id = $data['id']; + $raid_id = $data['id']; - // Get raid details. - $raid = get_raid($raid_id); + // Get raid details. + $raid = get_raid($raid_id); - $keys = []; + $keys = []; - // Add keys to share. - debug_log($raid, 'raw raid data for share: '); - $keys_share = share_keys($raid['id'], 'raid_share', $update, $raid['level']); - if(!empty($keys_share)) { - $keys = array_merge($keys, $keys_share); - } else { - debug_log('There are no groups to share to, is SHARE_CHATS set?'); - } - // Exit key - $keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); + // Add keys to share. + debug_log($raid, 'raw raid data for share: '); + $keys_share = share_keys($raid['id'], 'raid_share', $update, $raid['level']); + if(!empty($keys_share)) { + $keys = array_merge($keys, $keys_share); + } else { + debug_log('There are no groups to share to, is SHARE_CHATS set?'); + } + // Exit key + $keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); - // Get message. - $msg = show_raid_poll_small($raid); + // Get message. + $msg = show_raid_poll_small($raid); - // Build callback message string. - $callback_response = 'OK'; + // Build callback message string. + $callback_response = 'OK'; - // Telegram JSON array. - $tg_json = array(); + // Telegram JSON array. + $tg_json = array(); - // Answer callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - // Edit message. - $tg_json[] = edit_message($update, $msg, $keys, false, true); + // Edit message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); - // Telegram multicurl request. - curl_json_multi_request($tg_json); + // Telegram multicurl request. + curl_json_multi_request($tg_json); }else { - if(isset($update['message']['location'])) { - $lat = (float)$update['message']['location']['latitude']; - $lon = (float)$update['message']['location']['longitude']; - }else { - send_message($update['message']['chat']['id'], '' . getTranslation('invalid_input') . ''); - exit(); + if(!isset($update['message']['location'])) { + send_message($update['message']['chat']['id'], '' . getTranslation('invalid_input') . ''); + exit(); + } + $lat = (float)$update['message']['location']['latitude']; + $lon = (float)$update['message']['location']['longitude']; + $gps_diff = (float)0.01; + + // Build query. + $rs = my_query(' + SELECT raids.*, + gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, + users.name, + TIME_FORMAT(TIMEDIFF(raids.end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left + FROM raids + LEFT JOIN gyms + ON raids.gym_id = gyms.id + LEFT JOIN users + ON raids.user_id = users.user_id + WHERE raids.end_time>UTC_TIMESTAMP() + AND gyms.lat BETWEEN \''.($lat-$gps_diff).'\' AND \''.($lat+$gps_diff).'\' + AND gyms.lon BETWEEN \''.($lon-$gps_diff).'\' AND \''.($lon+$gps_diff).'\' + ORDER BY raids.end_time ASC LIMIT 20 + '); + + // Count results. + $count = 0; + + // Init text and keys. + $text = ''; + $keys = []; + + // Get raids. + while ($raid = $rs->fetch()) { + // Set text and keys. + $gym_name = $raid['gym_name']; + if(empty($gym_name)) { + $gym_name = ''; } - $gps_diff = (float)0.01; - - // Build query. - $rs = my_query( - ' - SELECT raids.*, - gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, - users.name, - TIME_FORMAT(TIMEDIFF(raids.end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left - FROM raids - LEFT JOIN gyms - ON raids.gym_id = gyms.id - LEFT JOIN users - ON raids.user_id = users.user_id - WHERE raids.end_time>UTC_TIMESTAMP() - AND gyms.lat BETWEEN \''.($lat-$gps_diff).'\' AND \''.($lat+$gps_diff).'\' - AND gyms.lon BETWEEN \''.($lon-$gps_diff).'\' AND \''.($lon+$gps_diff).'\' - ORDER BY raids.end_time ASC LIMIT 20 - ' - ); - // Count results. - $count = 0; - - // Init text and keys. - $text = ''; - $keys = []; - - // Get raids. - while ($raid = $rs->fetch()) { - // Set text and keys. - $gym_name = $raid['gym_name']; - if(empty($gym_name)) { - $gym_name = ''; - } - - $text .= $gym_name . CR; - $raid_day = dt2date($raid['start_time']); - $now = utcnow(); - $today = dt2date($now); - $start = dt2time($raid['start_time']); - $end = dt2time($raid['end_time']); - $time_left = $raid['t_left']; - if ($now < $start) { - $text .= get_raid_times($raid, true); - // Raid has started already - } else { - // Add time left message. - $text .= get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ' — ' . getPublicTranslation('still') . SP . $time_left . 'h' . CR . CR; - } - - - // Split pokemon and form to get the pokedex id. - $pokedex_id = explode('-', $raid['pokemon'])[0]; - - // Pokemon is an egg? - $eggs = $GLOBALS['eggs']; - if(in_array($pokedex_id, $eggs)) { - $keys_text = EMOJI_EGG . SP . $gym_name; - } else { - $keys_text = $gym_name; - } - - $keys[] = array( - 'text' => $keys_text, - 'callback_data' => $raid['id'] . ':share_raid_by_location:1' - ); - - // Counter++ - $count = $count + 1; + $text .= $gym_name . CR; + $raid_day = dt2date($raid['start_time']); + $now = utcnow(); + $today = dt2date($now); + $start = dt2time($raid['start_time']); + $end = dt2time($raid['end_time']); + $time_left = $raid['t_left']; + if ($now < $start) { + $text .= get_raid_times($raid, true); + // Raid has started already + } else { + // Add time left message. + $text .= get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ' — ' . getPublicTranslation('still') . SP . $time_left . 'h' . CR . CR; } - // Set message. - if($count == 0) { - $msg = '' . getTranslation('no_active_raids_found') . ''; + // Split pokemon and form to get the pokedex id. + $pokedex_id = explode('-', $raid['pokemon'])[0]; + + // Pokemon is an egg? + $eggs = $GLOBALS['eggs']; + if(in_array($pokedex_id, $eggs)) { + $keys_text = EMOJI_EGG . SP . $gym_name; } else { - // Get the inline key array. - $keys = inline_key_array($keys, 1); - - // Add exit key. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; - - // Build message. - $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; - $msg .= $text; - $msg .= '' . getTranslation('select_gym_name') . '' . CR; + $keys_text = $gym_name; } - // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + $keys[] = array( + 'text' => $keys_text, + 'callback_data' => $raid['id'] . ':share_raid_by_location:1' + ); + + // Counter++ + $count = $count + 1; + } + + // Set message. + if($count == 0) { + $msg = '' . getTranslation('no_active_raids_found') . ''; + } else { + // Get the inline key array. + $keys = inline_key_array($keys, 1); + + // Add exit key. + $keys[] = [ + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ]; + + // Build message. + $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; + $msg .= $text; + $msg .= '' . getTranslation('select_gym_name') . '' . CR; + } + + // Send message. + send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); } -?> diff --git a/mods/trainer.php b/mods/trainer.php index 151b6ea1..92b71c4a 100644 --- a/mods/trainer.php +++ b/mods/trainer.php @@ -1,6 +1,7 @@ accessCheck($update, 'trainer'); $user_id = $update['callback_query']['from']['id']; -if($data['arg'] == "a") { - my_query("UPDATE users SET auto_alarm = IF(auto_alarm = 1, 0, 1) WHERE user_id = {$user_id}"); +if($data['arg'] == 'a') { + my_query('UPDATE users SET auto_alarm = IF(auto_alarm = 1, 0, 1) WHERE user_id = ?', [$user_id]); } // Set message. $msg = '' . getTranslation('trainerinfo_set_yours') . ''; -$msg .= CR.CR.get_user($user_id, false); +$msg .= CR . CR . get_user($user_id, false); // Init empty keys array. $keys = []; // Create keys array. -if($config->CUSTOM_TRAINERNAME){ - $keys[0][] = - [ - 'text' => getTranslation('name'), - 'callback_data' => '0:trainer_name:0' - ]; +if($config->CUSTOM_TRAINERNAME) { + $keys[0][] = + [ + 'text' => getTranslation('name'), + 'callback_data' => '0:trainer_name:0' + ]; } -if($config->RAID_POLL_SHOW_TRAINERCODE){ - $keys[0][] = - [ - 'text' => getTranslation('trainercode'), - 'callback_data' => '0:trainer_code:0' - ]; +if($config->RAID_POLL_SHOW_TRAINERCODE) { + $keys[0][] = + [ + 'text' => getTranslation('trainercode'), + 'callback_data' => '0:trainer_code:0' + ]; } $keys[] = [ - [ - 'text' => getTranslation('team'), - 'callback_data' => '0:trainer_team:0' - ], - [ - 'text' => getTranslation('level'), - 'callback_data' => '0:trainer_level:0' - ] + [ + 'text' => getTranslation('team'), + 'callback_data' => '0:trainer_team:0' + ], + [ + 'text' => getTranslation('level'), + 'callback_data' => '0:trainer_level:0' + ] ]; -if ($config->RAID_AUTOMATIC_ALARM == false) { - $q_user = my_query("SELECT auto_alarm FROM users WHERE user_id = '{$user_id}' LIMIT 1"); - $alarm_status = $q_user->fetch()['auto_alarm']; - $keys[] = [ - [ - 'text' => ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), - 'callback_data' => '0:trainer:a' - ] - ]; +if($config->RAID_AUTOMATIC_ALARM == false) { + $q_user = my_query('SELECT auto_alarm FROM users WHERE user_id = ? LIMIT 1', [$user_id]); + $alarm_status = $q_user->fetch()['auto_alarm']; + $keys[] = [ + [ + 'text' => ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), + 'callback_data' => '0:trainer:a' + ] + ]; } -if ($config->LANGUAGE_PRIVATE == '') { - $keys[] = [ - [ - 'text' => getTranslation('bot_lang'), - 'callback_data' => '0:bot_lang:0' - ] - ]; +if($config->LANGUAGE_PRIVATE == '') { + $keys[] = [ + [ + 'text' => getTranslation('bot_lang'), + 'callback_data' => '0:bot_lang:0' + ] + ]; } -// Check access. -$access = $botUser->accessCheck($update, 'trainer-share', true); - // Display sharing options for admins and users with trainer-share permissions -if($access) { - // Add sharing keys. - $share_keys = []; - $share_keys[] = universal_inner_key($keys, '0', 'trainer_add', '0', getTranslation('trainer_message_share')); - $share_keys[] = universal_inner_key($keys, '0', 'trainer_delete', '0', getTranslation('trainer_message_delete')); +if($botUser->accessCheck($update, 'trainer-share', true)) { + // Add sharing keys. + $share_keys = []; + $share_keys[] = universal_inner_key($keys, '0', 'trainer_add', '0', getTranslation('trainer_message_share')); + $share_keys[] = universal_inner_key($keys, '0', 'trainer_delete', '0', getTranslation('trainer_message_delete')); - // Get the inline key array. - $keys[] = $share_keys; + // Get the inline key array. + $keys[] = $share_keys; - // Add message. - $msg .= CR . CR . getTranslation('trainer_message_share_or_delete'); + // Add message. + $msg .= CR . CR . getTranslation('trainer_message_share_or_delete'); } -// Add abort key. -$nav_keys = []; -$nav_keys[] = universal_inner_key($keys, '0', 'exit', '0', getTranslation('abort')); - // Get the inline key array. -$keys[] = $nav_keys; +$keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); // Answer callback. answerCallbackQuery($update['callback_query']['id'], 'OK'); // Edit message. edit_message($update, $msg, $keys, false); - -// Exit. -$dbh = null; -exit(); - -?> \ No newline at end of file diff --git a/mods/trainer_add.php b/mods/trainer_add.php index cfcf4510..5464423f 100644 --- a/mods/trainer_add.php +++ b/mods/trainer_add.php @@ -15,42 +15,42 @@ // $config->TRAINER_CHATS ? if(!empty($config->TRAINER_CHATS)) { - $chat_list = $config->TRAINER_CHATS; - debug_log($chat_list, 'Added trainer chats to the chat list:'); + $chat_list = $config->TRAINER_CHATS; + debug_log($chat_list, 'Added trainer chats to the chat list:'); } // $config->SHARE_CHATS ? if(!empty($config->SHARE_CHATS) && !empty($chat_list)) { - $chat_list .= ',' . $config->SHARE_CHATS; - debug_log($chat_list, 'Added share chats to the chat list:'); + $chat_list .= ',' . $config->SHARE_CHATS; + debug_log($chat_list, 'Added share chats to the chat list:'); } else if(!empty($config->SHARE_CHATS) && empty($chat_list)) { - $chat_list = $config->SHARE_CHATS; - debug_log($chat_list, 'Added share chats to the chat list:'); + $chat_list = $config->SHARE_CHATS; + debug_log($chat_list, 'Added share chats to the chat list:'); } // Get chats from config and add to keys. -for($i = 1; $i <= 6; $i++) { - // Raid level adjustment - if($i == 6) { - $raid_level = 'X'; +for($i = 1; $i <= 10; $i++) { + // Raid level adjustment + if($i == 10) { + $raid_level = 'X'; + } else { + $raid_level = $i; + } + $const = 'SHARE_CHATS_LEVEL_' . $raid_level; + $const_chats = $config->{$const}; + + // Sharing keys for this raid level? + if(!empty($const_chats)) { + debug_log('Found chats by level, adding them'); + // Add chats. + if(!empty($chat_list)) { + $chat_list .= ',' . $const_chats; + debug_log($chat_list, 'Added ' . $const . ' chats to the chat list:'); } else { - $raid_level = $i; - } - $const = 'SHARE_CHATS_LEVEL_' . $raid_level; - $const_chats = $config->{$const}; - - // Sharing keys for this raid level? - if(!empty($const_chats)) { - debug_log('Found chats by level, adding them'); - // Add chats. - if(!empty($chat_list)) { - $chat_list .= ',' . $const_chats; - debug_log($chat_list, 'Added ' . $const . ' chats to the chat list:'); - } else { - $chat_list = $const_chats; - debug_log($chat_list, 'Added ' . $const . ' chats to the chat list:'); - } + $chat_list = $const_chats; + debug_log($chat_list, 'Added ' . $const . ' chats to the chat list:'); } + } } // Delete duplicate chats. @@ -60,16 +60,14 @@ // Get chats already in the database. debug_log('Searching and removing chats already having the trainer message'); -$rs = my_query( - " - SELECT chat_id - FROM trainerinfo - " -); +$rs = my_query(' + SELECT chat_id + FROM trainerinfo +'); $chats_db = []; while ($row = $rs->fetch()) { - $chats_db[] = $row['chat_id']; + $chats_db[] = $row['chat_id']; } $log_chats_db = implode(',', $chats_db); @@ -81,24 +79,24 @@ // Create keys. if(!empty($chats)) { - $keys = share_keys('0', 'trainer_share', $update, '', $chats, true); + $keys = share_keys('0', 'trainer_share', $update, '', $chats, true); } // Add abort key. if($keys) { - // Add back navigation key. - $nav_keys = []; - $nav_keys[] = universal_inner_key($keys, '0', 'trainer', '0', getTranslation('back')); - $nav_keys[] = universal_inner_key($keys, '0', 'exit', '0', getTranslation('abort')); + // Add back navigation key. + $nav_keys = []; + $nav_keys[] = universal_inner_key($keys, '0', 'trainer', '0', getTranslation('back')); + $nav_keys[] = universal_inner_key($keys, '0', 'exit', '0', getTranslation('abort')); - // Get the inline key array. - $keys[] = $nav_keys; + // Get the inline key array. + $keys[] = $nav_keys; - // Set message. - $msg = '' . getTranslation('trainer_info_share_with_chat') . ''; + // Set message. + $msg = '' . getTranslation('trainer_info_share_with_chat') . ''; } else { - // Set message. - $msg = '' . getTranslation('trainer_info_no_chats') . ''; + // Set message. + $msg = '' . getTranslation('trainer_info_no_chats') . ''; } // Answer callback. @@ -106,5 +104,3 @@ // Edit message. edit_message($update, $msg, $keys, false); - -?> diff --git a/mods/trainer_code.php b/mods/trainer_code.php index dac90e8a..fa19de5a 100644 --- a/mods/trainer_code.php +++ b/mods/trainer_code.php @@ -1,6 +1,7 @@ $user_id]); + my_query(' + UPDATE users + SET trainercode = NULL + WHERE user_id = ? + ',[$user_id + ]); - // Build callback message string. - $callback_response = 'OK'; + // Build callback message string. + $callback_response = 'OK'; - $data['arg'] = $data['id'] = 0; - require_once(ROOT_PATH . '/mods/trainer.php'); + $data['arg'] = $data['id'] = 0; + require_once(ROOT_PATH . '/mods/trainer.php'); }else { - $user_data = get_user($user_id, false, true); - // Build message string. - $msg = '' . getTranslation('your_trainer_info') . '' . CR; - $msg .= $user_data['message'] . CR; - - // Save the message id to db so we can delete it later - $modifiers = json_encode(["old_message_id"=>$update['callback_query']['message']['message_id']]); - - $msg .= '' . getTranslation('trainercode_select') . ''; - // Data for handling response from the user - my_query("INSERT INTO user_input SET user_id='{$user_id}', handler='change_trainercode', modifiers='{$modifiers}' "); - - // Build callback message string. - $callback_response = 'OK'; - - $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:trainer_code:cancel' - ],[ - 'text' => getTranslation('delete'), - 'callback_data' => '0:trainer_code:delete' - ] - ]; - // Answer callback. - answerCallbackQuery($update['callback_query']['id'], $callback_response); - - // Edit message. - edit_message($update, $msg, $keys, false); + $user_data = get_user($user_id, false, true); + // Build message string. + $msg = '' . getTranslation('your_trainer_info') . '' . CR; + $msg .= $user_data['message'] . CR; + + // Save the message id to db so we can delete it later + $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id']]); + + $msg .= '' . getTranslation('trainercode_select') . ''; + // Data for handling response from the user + my_query('INSERT INTO user_input SET user_id = ?, handler = \'change_trainercode\', modifiers = ?',[$user_id, $modifiers]); + + // Build callback message string. + $callback_response = 'OK'; + + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:trainer_code:cancel' + ],[ + 'text' => getTranslation('delete'), + 'callback_data' => '0:trainer_code:delete' + ] + ]; + // Answer callback. + answerCallbackQuery($update['callback_query']['id'], $callback_response); + + // Edit message. + edit_message($update, $msg, $keys, false); } // Exit. -$dbh = null; exit(); - -?> diff --git a/mods/trainer_delete.php b/mods/trainer_delete.php index f338a4e0..a3726a87 100644 --- a/mods/trainer_delete.php +++ b/mods/trainer_delete.php @@ -1,6 +1,7 @@ fetch()) { - // Chat and message ID - $chat_id = $row['chat_id']; - $message_id = $row['message_id']; - - // Get info about chat for title. - debug_log('Getting chat object for chat_id: ' . $chat_id); - $chat_obj = get_chat($chat_id); - $chat_title = ''; - - // Set title. - if ($chat_obj['ok'] == 'true') { - $chat_title = $chat_obj['result']['title']; - debug_log('Title of the chat: ' . $chat_obj['result']['title']); - } else { - $chat_title = $chat_id; - } - - $keys[] = universal_inner_key($keys, $chat_id, 'trainer_delete', '1', $chat_title); - } - - // Add abort key. - if($keys) { - // Inline key array. - $keys = inline_key_array($keys, 1); - - // Add back navigation key. - $nav_keys = []; - $nav_keys[] = universal_inner_key($keys, '0', 'trainer', '0', getTranslation('back')); - $nav_keys[] = universal_inner_key($keys, '0', 'exit', '0', getTranslation('abort')); - - // Get the inline key array. - $keys[] = $nav_keys; - - // Set message. - $msg = '' . getTranslation('trainer_message_delete') . '?'; - } else { - // Set message. - $msg = '' . getTranslation('trainer_info_no_chats') . ''; - } + debug_log('Getting chats the trainer message was shared with'); + $rs = my_query(' + SELECT chat_id + FROM trainerinfo + '); + + while ($row = $rs->fetch()) { + // Chat and message ID + $chat_id = $row['chat_id']; + [$chat_title, $chat_username] = get_chat_title_username($chat_id); + + $keys[] = universal_inner_key($keys, $chat_id, 'trainer_delete', '1', $chat_title); + } + + // Add abort key. + if($keys) { + // Inline key array. + $keys = inline_key_array($keys, 1); + + // Add back navigation key. + $nav_keys = []; + $nav_keys[] = universal_inner_key($keys, '0', 'trainer', '0', getTranslation('back')); + $nav_keys[] = universal_inner_key($keys, '0', 'exit', '0', getTranslation('abort')); + + // Get the inline key array. + $keys[] = $nav_keys; + + // Set message. + $msg = '' . getTranslation('trainer_message_delete') . '?'; + } else { + // Set message. + $msg = '' . getTranslation('trainer_info_no_chats') . ''; + } // Confirm deletion } else if($action == 1 && $trainer_chat != 0) { - // Get info about chat for title. - debug_log('Getting chat object for chat_id: ' . $trainer_chat); - $chat_obj = get_chat($trainer_chat); - $chat_title = ''; - - // Set title. - if ($chat_obj['ok'] == 'true') { - $chat_title = $chat_obj['result']['title']; - debug_log('Title of the chat: ' . $chat_obj['result']['title']); - } else { - $chat_title = $trainer_chat; - } - - // Set message - $msg = $chat_title . CR . CR; - $msg .= EMOJI_WARN . SP . '' . getTranslation('delete_trainer_message_from_chat') . '' . SP . EMOJI_WARN; - - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => $trainer_chat . ':trainer_delete:2' - ] - ], - [ - [ - 'text' => getTranslation('no'), - 'callback_data' => '0:exit:0' - ] - ] - ]; + [$chat_title, $chat_username] = get_chat_title_username($trainer_chat); + + // Set message + $msg = $chat_title . CR . CR; + $msg .= EMOJI_WARN . SP . '' . getTranslation('delete_trainer_message_from_chat') . '' . SP . EMOJI_WARN; + + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('yes'), + 'callback_data' => $trainer_chat . ':trainer_delete:2' + ] + ], + [ + [ + 'text' => getTranslation('no'), + 'callback_data' => '0:exit:0' + ] + ] + ]; // Delete trainer message } else if($action == 2 && $trainer_chat != 0) { - debug_log('Deleting trainer message from chat ' . $trainer_chat); - // Get info about chat for title. - debug_log('Getting chat object for chat_id: ' . $trainer_chat); - $chat_obj = get_chat($trainer_chat); - $chat_title = ''; - - // Set title. - if ($chat_obj['ok'] == 'true') { - $chat_title = $chat_obj['result']['title']; - debug_log('Title of the chat: ' . $chat_obj['result']['title']); - } else { - $chat_title = $trainer_chat; - } - - // Set message - $msg = '' . getTranslation('deleted_trainer_message') . '' . CR; - - // Get trainer messages - debug_log('Getting chats the trainer message was shared with'); - $rs = my_query( - " - SELECT * - FROM trainerinfo - WHERE chat_id = '{$trainer_chat}' - " - ); - - // Delete trainer message. - while ($row = $rs->fetch()) { - delete_trainerinfo($row['chat_id'], $row['message_id']); - } + require_once(LOGIC_PATH . '/delete_trainerinfo.php'); + debug_log('Deleting trainer message from chat ' . $trainer_chat); + [$chat_title, $chat_username] = get_chat_title_username($trainer_chat); + + // Set message + $msg = '' . getTranslation('deleted_trainer_message') . '' . CR; + + // Get trainer messages + debug_log('Getting chats the trainer message was shared with'); + $rs = my_query(' + SELECT message_id + FROM trainerinfo + WHERE chat_id = ? + ', [$trainer_chat] + ); + + // Delete trainer message. + while ($row = $rs->fetch()) { + delete_trainerinfo($trainer_chat, $row['message_id']); + } } // Answer callback. @@ -142,5 +106,3 @@ // Edit message. edit_message($update, $msg, $keys, false); - -?> diff --git a/mods/trainer_level.php b/mods/trainer_level.php index f9502448..6339213e 100644 --- a/mods/trainer_level.php +++ b/mods/trainer_level.php @@ -1,6 +1,7 @@ ' . getTranslation('your_trainer_info') . '' . CR; - $msg .= get_user($user_id) . CR; - $msg .= '' . getTranslation('level_select') . ''; - - // Set keys. - $keys = []; - for($i = 5; $i <= $config->TRAINER_MAX_LEVEL; $i++) { - $keys[] = array( - 'text' => $i, - 'callback_data' => '1:trainer_level:' . $i - ); - } - - // Get the inline key array. - $keys = inline_key_array($keys, 5); - - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, '0', 'trainer', '0', getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - - // Merge keys. - $keys = array_merge($keys, $nav_keys); - - // Build callback message string. - $callback_response = 'OK'; + // Build message string. + $msg = '' . getTranslation('your_trainer_info') . '' . CR; + $msg .= get_user($user_id) . CR; + $msg .= '' . getTranslation('level_select') . ''; + + // Set keys. + $keys = []; + for($i = 5; $i <= $config->TRAINER_MAX_LEVEL; $i++) { + $keys[] = array( + 'text' => $i, + 'callback_data' => '1:trainer_level:' . $i + ); + } + + // Get the inline key array. + $keys = inline_key_array($keys, 5); + + // Add navigation keys. + $nav_keys = []; + $nav_keys[] = universal_inner_key($nav_keys, '0', 'trainer', '0', getTranslation('back')); + $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); + $nav_keys = inline_key_array($nav_keys, 2); + + // Merge keys. + $keys = array_merge($keys, $nav_keys); + + // Build callback message string. + $callback_response = 'OK'; // Save user level } else if($confirm == 1 && $level > 0) { - // Update the user. - my_query( - " - UPDATE users - SET level = {$level} - WHERE user_id = {$user_id} - " - ); - - // Build message string. - $msg = '' . getTranslation('level_saved') . '' . CR . CR; - $msg .= '' . getTranslation('your_trainer_info') . '' . CR; - $msg .= get_user($user_id) . CR; - - // Build callback message string. - $callback_response = 'OK'; - - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; + // Update the user. + my_query(' + UPDATE users + SET level = ? + WHERE user_id = ? + ', [$level, $user_id] + ); + + // Build message string. + $msg = '' . getTranslation('level_saved') . '' . CR . CR; + $msg .= '' . getTranslation('your_trainer_info') . '' . CR; + $msg .= get_user($user_id) . CR; + + // Build callback message string. + $callback_response = 'OK'; + + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:trainer:0' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ] + ]; } // Answer callback. @@ -87,6 +87,3 @@ // Edit message. edit_message($update, $msg, $keys, false); - -// Exit. -exit(); diff --git a/mods/trainer_name.php b/mods/trainer_name.php index cb0985f4..b23f094a 100644 --- a/mods/trainer_name.php +++ b/mods/trainer_name.php @@ -1,6 +1,7 @@ $update['callback_query']['message']['message_id']]); if($action == 'add') { - $msg .= '' . getTranslation('trainername_select') . ''; - // Data for handling response from the user - my_query("INSERT INTO user_input SET user_id='{$user_id}', handler='change_trainername', modifiers='{$modifiers}' "); + $msg .= '' . getTranslation('trainername_select') . ''; + // Data for handling response from the user + my_query('INSERT INTO user_input SET user_id = ?, handler = \'change_trainername\', modifiers = ?', [$user_id, $modifiers]); } // Build callback message string. $callback_response = 'OK'; if($action != 'add') { - if(!empty($user_data['row']['trainername'])) { - $keys[] = [ - [ - 'text' => getTranslation('switch_display_name'), - 'callback_data' => '0:trainer_name:switch' - ] - ]; - $keys[] = [ - [ - 'text' => getTranslation('trainername_edit'), - 'callback_data' => '0:trainer_name:add' - ],[ - 'text' => getTranslation('delete'), - 'callback_data' => '0:trainer_name:delete' - ] - ]; - }else { - $keys[] = [ - [ - 'text' => getTranslation('trainername_add'), - 'callback_data' => '0:trainer_name:add' - ] - ]; - } -} -$keys[] = [ + if(!empty($user_data['row']['trainername'])) { + $keys[] = [ + [ + 'text' => getTranslation('switch_display_name'), + 'callback_data' => '0:trainer_name:switch' + ] + ]; + $keys[] = [ + [ + 'text' => getTranslation('trainername_edit'), + 'callback_data' => '0:trainer_name:add' + ],[ + 'text' => getTranslation('delete'), + 'callback_data' => '0:trainer_name:delete' + ] + ]; + }else { + $keys[] = [ [ - 'text' => getTranslation('back'), - 'callback_data' => $mode.':trainer_name:cancel' + 'text' => getTranslation('trainername_add'), + 'callback_data' => '0:trainer_name:add' ] - ]; + ]; + } +} +$keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => $mode.':trainer_name:cancel' + ] + ]; - // Answer callback. + // Answer callback. answerCallbackQuery($update['callback_query']['id'], $callback_response); // Edit message. edit_message($update, $msg, $keys, false); - - -// Exit. -$dbh = null; -exit(); - -?> diff --git a/mods/trainer_share.php b/mods/trainer_share.php index db812bd0..88000779 100644 --- a/mods/trainer_share.php +++ b/mods/trainer_share.php @@ -1,6 +1,8 @@ TEAM_B, - 'callback_data' => '1:trainer_team:mystic' - ], - [ - 'text' => TEAM_R, - 'callback_data' => '1:trainer_team:valor' - ], - [ - 'text' => TEAM_Y, - 'callback_data' => '1:trainer_team:instinct' - ] - ], - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; - - // Build message string. - $msg = '' . getTranslation('your_trainer_info') . '' . CR; - $msg .= get_user($user_id) . CR; - $msg .= '' . getTranslation('team_select') . ''; - - // Build callback message string. - $callback_response = 'OK'; + // Set keys. + $keys = [ + [ + [ + 'text' => TEAM_B, + 'callback_data' => '1:trainer_team:mystic' + ], + [ + 'text' => TEAM_R, + 'callback_data' => '1:trainer_team:valor' + ], + [ + 'text' => TEAM_Y, + 'callback_data' => '1:trainer_team:instinct' + ] + ], + [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:trainer:0' + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ] + ] + ]; + + // Build message string. + $msg = '' . getTranslation('your_trainer_info') . '' . CR; + $msg .= get_user($user_id) . CR; + $msg .= '' . getTranslation('team_select') . ''; + + // Build callback message string. + $callback_response = 'OK'; // Write team to database. } else if($confirm == 1 && ($team == 'mystic' || $team == 'valor' || $team == 'instinct')) { - // Update the user. - my_query( - " - UPDATE users - SET team = '{$team}' - WHERE user_id = {$user_id} - " - ); - - // Build message string. - $msg = '' . getTranslation('team_saved') . '' . CR . CR; - $msg .= '' . getTranslation('your_trainer_info') . '' . CR; - $msg .= get_user($user_id) . CR; - - // Build callback message string. - $callback_response = 'OK'; - - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ] - ] - ]; + // Update the user. + my_query(' + UPDATE users + SET team = ? + WHERE user_id = ? + ', [$team, $user_id] + ); + + // Build message string. + $msg = '' . getTranslation('team_saved') . '' . CR . CR; + $msg .= '' . getTranslation('your_trainer_info') . '' . CR; + $msg .= get_user($user_id) . CR; + + // Build callback message string. + $callback_response = 'OK'; + + // Create the keys. + $keys = [ + [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:trainer:0' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' + ] + ] + ]; } diff --git a/mods/tutorial.php b/mods/tutorial.php index abe0a216..cbf46cee 100644 --- a/mods/tutorial.php +++ b/mods/tutorial.php @@ -11,106 +11,103 @@ // Tutorial if(is_file(ROOT_PATH . '/config/tutorial.php')) { - require_once(ROOT_PATH . '/config/tutorial.php'); + require_once(ROOT_PATH . '/config/tutorial.php'); } $action = $data['arg']; $user_id = $update['callback_query']['from']['id']; $new_user = new_user($user_id); $tutorial_count = count($tutorial); -if($action == "end") { - answerCallbackQuery($update['callback_query']['id'], "OK!"); - delete_message($update['callback_query']['message']['chat']['id'],$update['callback_query']['message']['message_id']); - if($new_user) { - my_query("UPDATE users SET tutorial = '{$data['id']}' WHERE user_id = '{$user_id}'"); +if($action == 'end') { + answerCallbackQuery($update['callback_query']['id'], "OK!"); + delete_message($update['callback_query']['message']['chat']['id'],$update['callback_query']['message']['message_id']); + if($new_user) { + my_query('UPDATE users SET tutorial = ? WHERE user_id = ?', [$data['id'], $user_id]); - send_message($user_id, $tutorial_done, []); - - // Post the user id to external address if specified - if(isset($config->TUTORIAL_COMPLETED_CURL_ADDRESS) && $config->TUTORIAL_COMPLETED_CURL_ADDRESS != "") { - $post_array = [ - "tutorial"=> "OK", - "user_id" => $user_id - ]; - $json = json_encode($post_array); - $URL = $config->TUTORIAL_COMPLETED_CURL_ADDRESS; - $curl = curl_init($URL); + send_message($user_id, $tutorial_done, []); - curl_setopt($curl, CURLOPT_HEADER, false); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json")); - curl_setopt($curl, CURLOPT_POST, true); - curl_setopt($curl, CURLOPT_POSTFIELDS, $json); - curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); - curl_setopt($curl, CURLOPT_TIMEOUT, 10); + // Post the user id to external address if specified + if(isset($config->TUTORIAL_COMPLETED_CURL_ADDRESS) && $config->TUTORIAL_COMPLETED_CURL_ADDRESS != "") { + $post_array = [ + 'tutorial' => 'OK', + 'user_id' => $user_id + ]; + $json = json_encode($post_array); + $URL = $config->TUTORIAL_COMPLETED_CURL_ADDRESS; + $curl = curl_init($URL); - // Use Proxyserver for curl if configured - if ($config->CURL_USEPROXY && !empty($config->CURL_PROXYSERVER)) { - curl_setopt($curl, CURLOPT_PROXY, $config->CURL_PROXYSERVER); - } + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json")); + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $json); + curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); + curl_setopt($curl, CURLOPT_TIMEOUT, 10); - // Execute curl request. - $json_response = curl_exec($curl); + // Use Proxyserver for curl if configured + if ($config->CURL_USEPROXY && !empty($config->CURL_PROXYSERVER)) { + curl_setopt($curl, CURLOPT_PROXY, $config->CURL_PROXYSERVER); + } - // Close connection. - curl_close($curl); - } + // Execute curl request. + $json_response = curl_exec($curl); + + // Close connection. + curl_close($curl); } - - - $q = my_query("SELECT level, team FROM users WHERE user_id='{$user_id}' LIMIT 1"); - $row = $q->fetch(); + } + - if(($row['level']==0 or $row['team']=="" or $row['team']==NULL)) { - $msg = getTranslation("tutorial_no_user_info_set"); - $keys = [ + $q = my_query('SELECT level, team FROM users WHERE user_id = ? LIMIT 1', [$user_id]); + $row = $q->fetch(); + + if($row['level'] == 0 or $row['team'] == '' or $row['team'] == NULL) { + $msg = getTranslation('tutorial_no_user_info_set'); + $keys = [ + [ + [ + 'text' => getTranslation('yes'), + 'callback_data' => '0:trainer:0' + ], [ - [ - 'text' => getTranslation("yes"), - 'callback_data' => '0:trainer:0' - ], - [ - 'text' => getTranslation("no"), - 'callback_data' => '0:exit:1' - ] + 'text' => getTranslation('no'), + 'callback_data' => '0:exit:1' ] - ]; - send_message($user_id,$msg,$keys); - } - $dbh = null; - exit(); + ] + ]; + send_message($user_id,$msg,$keys); + } + exit(); -}else { +} - if($new_user && isset($tutorial[($action)]['msg_new'])) { - $msg = $tutorial[($action)]['msg_new']; - }else { - $msg = $tutorial[($action)]['msg']; - } - $photo = $tutorial[$action]['photo']; - $keys = []; - if($action > 0) { - $keys = [ +if($new_user && isset($tutorial[($action)]['msg_new'])) { + $msg = $tutorial[($action)]['msg_new']; +}else { + $msg = $tutorial[($action)]['msg']; +} +$photo = $tutorial[$action]['photo']; +$keys = []; +if($action > 0) { + $keys = [ + [ [ - [ - 'text' => getTranslation("back") . " (".($action)."/".($tutorial_count).")", - 'callback_data' => "0:tutorial:".($action-1) - ] + 'text' => getTranslation("back") . " (".($action)."/".($tutorial_count).")", + 'callback_data' => "0:tutorial:".($action-1) ] - ]; - } - if($action < ($tutorial_count - 1)) { - $keys[0][] = [ - 'text' => getTranslation("next") . " (".($action+2)."/".($tutorial_count).")", - 'callback_data' => "0:tutorial:".($action+1) - ]; - }else { - $keys[0][] = [ - 'text' => getTranslation("done"), - 'callback_data' => $tutorial_grant_level . ":tutorial:end" - ]; - } + ] + ]; +} +if($action < ($tutorial_count - 1)) { + $keys[0][] = [ + 'text' => getTranslation("next") . " (".($action+2)."/".($tutorial_count).")", + 'callback_data' => "0:tutorial:".($action+1) + ]; +}else { + $keys[0][] = [ + 'text' => getTranslation("done"), + 'callback_data' => $tutorial_grant_level . ":tutorial:end" + ]; } answerCallbackQuery($update['callback_query']['id'], "OK!"); editMessageMedia($update['callback_query']['message']['message_id'], $msg, $photo, false, $keys, $update['callback_query']['message']['chat']['id'], ['disable_web_page_preview' => 'true']); -?> \ No newline at end of file diff --git a/mods/update_bosses.php b/mods/update_bosses.php index 71f85808..5d6b0814 100644 --- a/mods/update_bosses.php +++ b/mods/update_bosses.php @@ -1,4 +1,5 @@ ENABLE_BOSS_AUTO_UPDATE) { exit; } @@ -7,78 +8,70 @@ $source = $data['arg']; $add_mons = []; if($levels != 'scheduled') { - $get_levels = explode(",",$levels); + $get_levels = explode(',',$levels); - // Clear currently saved bosses that were imported with this method or inserted by hand - disable_raid_level($levels); - if($source == 'pogoinfo') { - debug_log('Getting raid bosses from pogoinfo repository now...'); - $link = 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/raids.json'; - $data = curl_get_contents($link); - $data = json_decode($data,true); + require_once(LOGIC_PATH . '/disable_raid_level.php'); + // Clear currently saved bosses that were imported with this method or inserted by hand + disable_raid_level($levels); + if($source != 'pogoinfo') { + info_log("Invalid argumens supplied to update_bosses!"); + exit(); + } + debug_log('Getting raid bosses from pogoinfo repository now...'); + $link = 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/raids.json'; + $data = curl_get_contents($link); + $data = json_decode($data,true); - debug_log('Processing received ccev pogoinfo raid bosses for each raid level'); - foreach($data as $tier => $tier_pokemon) { - // Process raid level? - if(!in_array($tier,$get_levels)) { - continue; - } - foreach($tier_pokemon as $raid_id_form) { - $dex_id = $raid_id_form['id']; - $dex_form = 0; - if(isset($raid_id_form['temp_evolution_id'])) { - $dex_form = '-'.$raid_id_form['temp_evolution_id']; - }elseif(isset($raid_id_form['form'])) { - $dex_form = $raid_id_form['form']; - }else { - // If no form id is provided, let's check our db for normal form - $query_form_id = my_query("SELECT pokemon_form_id FROM pokemon WHERE pokedex_id='".$dex_id."' and pokemon_form_name='normal' LIMIT 1"); - if($query_form_id->rowCount() == 0) { - // If normal form doesn't exist in our db, use the smallest form id as a fallback - $query_form_id = my_query("SELECT min(pokemon_form_id) as pokemon_form_id FROM pokemon WHERE pokedex_id='".$dex_id."' LIMIT 1"); - } - $result = $query_form_id->fetch(); - $dex_form = $result['pokemon_form_id']; - } + debug_log('Processing received ccev pogoinfo raid bosses for each raid level'); + foreach($data as $tier => $tier_pokemon) { + // Process raid level? + if(!in_array($tier,$get_levels)) continue; - $add_mons[] = [ - 'pokedex_id' => $dex_id, - 'pokemon_form_id' => $dex_form, - 'raid_level' => $tier, - ]; - } + foreach($tier_pokemon as $raid_id_form) { + $dex_id = $raid_id_form['id']; + $dex_form = 0; + if(isset($raid_id_form['temp_evolution_id'])) { + $dex_form = '-'.$raid_id_form['temp_evolution_id']; + }elseif(isset($raid_id_form['form'])) { + $dex_form = $raid_id_form['form']; + }else { + // If no form id is provided, let's check our db for normal form + $query_form_id = my_query('SELECT pokemon_form_id FROM pokemon WHERE pokedex_id = ? and pokemon_form_name=\'normal\' LIMIT 1', [$dex_id]); + if($query_form_id->rowCount() == 0) { + // If normal form doesn't exist in our db, use the smallest form id as a fallback + $query_form_id = my_query('SELECT min(pokemon_form_id) as pokemon_form_id FROM pokemon WHERE pokedex_id = ? LIMIT 1', [$dex_id]); } - }else { - info_log("Invalid argumens supplied to update_bosses!"); - exit(); + $result = $query_form_id->fetch(); + $dex_form = $result['pokemon_form_id']; + } + + $add_mons[] = [ + 'pokedex_id' => $dex_id, + 'pokemon_form_id' => $dex_form, + 'raid_level' => $tier, + ]; } + } }elseif($levels == 'scheduled') { - require_once(LOGIC_PATH . '/read_upcoming_bosses.php'); - $data = read_upcoming_bosses(true); - if(empty($data)) exit; - $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1;'; - $sql .= $data; + require_once(LOGIC_PATH . '/read_upcoming_bosses.php'); + $data = read_upcoming_bosses(true); + if(empty($data)) exit; + $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1;'; + $sql .= $data; }else { - info_log("Invalid argumens supplied to update_bosses!"); - exit(); + info_log("Invalid argumens supplied to update_bosses!"); + exit(); } $count = count($add_mons); $start = false; $sql_values = ''; if($count > 0) { - $sql_cols = implode(", ", array_keys($add_mons[0])); - for($i=0;$i<$count;$i++) { - if($i > 0) $sql_values .= ','; - $sql_values .= "('" . implode("', '", array_values($add_mons[$i])) . "')"; - } - $sql = "INSERT INTO raid_bosses (" . $sql_cols . ") VALUES " . $sql_values . ";"; -} - -try { - $query = $dbh->prepare($sql); - $query->execute(); -}catch (PDOException $exception) { - info_log($exception->getMessage()); + $sql_cols = implode(", ", array_keys($add_mons[0])); + for($i=0;$i<$count;$i++) { + if($i > 0) $sql_values .= ','; + $sql_values .= '(\'' . implode("', '", array_values($add_mons[$i])) . '\')'; + } + $sql = 'INSERT INTO raid_bosses (' . $sql_cols . ') VALUES ' . $sql_values . ';'; } -?> +my_query($sql); diff --git a/mods/vote_can_invite.php b/mods/vote_can_invite.php index 7b1a483f..e8944f8c 100644 --- a/mods/vote_can_invite.php +++ b/mods/vote_can_invite.php @@ -1,6 +1,8 @@ TRAINER_MAX_LEVEL} - " - ); + // Increase users level. + my_query( + ' + UPDATE users + SET level = IF(level = 0, 30, level+1) + WHERE user_id = ? + AND level < ' . $config->TRAINER_MAX_LEVEL . ' + ', [$update['callback_query']['from']['id']] + ); } // Down-vote. if ($action == 'down') { - // Decrease users level. - my_query( - " - UPDATE users - SET level = level-1 - WHERE user_id = {$update['callback_query']['from']['id']} - AND level > 5 - " - ); + // Decrease users level. + my_query( + ' + UPDATE users + SET level = level-1 + WHERE user_id = ? + AND level > 5 + ', [$update['callback_query']['from']['id']] + ); } // Message coming from raid or trainer info? if($data['id'] == 'trainer') { - if($action == 'hide') { - // Send trainer info update. - send_trainerinfo($update, false); - } else if($action == 'show') { - // Send trainer info update. - send_trainerinfo($update, true); - } else { - // Send trainer info update. - send_trainerinfo($update, true); - } -} else { - // Send vote response. - require_once(LOGIC_PATH . '/update_raid_poll.php'); - - $tg_json = update_raid_poll($data['id'], false, $update); - - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); - - curl_json_multi_request($tg_json); + if($action == 'hide') { + // Send trainer info update. + send_trainerinfo($update, false); + } + // Send trainer info update. + send_trainerinfo($update, true); } +// Send vote response. +require_once(LOGIC_PATH . '/update_raid_poll.php'); + +$tg_json = update_raid_poll($data['id'], false, $update); + +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); + +curl_json_multi_request($tg_json); + exit(); diff --git a/mods/vote_pokemon.php b/mods/vote_pokemon.php index 7cd8c7d1..5f209322 100644 --- a/mods/vote_pokemon.php +++ b/mods/vote_pokemon.php @@ -1,181 +1,147 @@ fetch()) { - $atts[] = $row; - $count = $count + 1; -} +$atts = $rs->fetchAll(); +$count = $rs->rowCount(); // Write to log. debug_log($atts); // User has voted before. -if(!empty($atts)) { - // Any pokemon? - if($data['arg'] == 0) { - // Update attendance. - my_query( - " - UPDATE attendance - SET pokemon = '{$data['arg']}' - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " +if(empty($atts)) { + // Send vote time first. + send_vote_time_first($update); + exit; +} +// Any pokemon? +if($data['arg'] == 0) { + // Delete any attendances except the first one. + my_query(' + DELETE FROM attendance + WHERE id NOT IN ( + SELECT * FROM ( + SELECT MIN(id) + FROM attendance + WHERE raid_id = :raidId + AND user_id = :userId + ) AS AVOID_MYSQL_ERROR_1093 + ) + AND raid_id = :raidId + AND user_id = :userId + ', ['raidId' => $data['id'], 'userId' => $update['callback_query']['from']['id']] + ); + + // Update attendance. + my_query(' + UPDATE attendance + SET pokemon = ? + WHERE raid_id = ? + AND user_id = ? + ', [$data['arg'], $data['id'], $update['callback_query']['from']['id']] + ); + + // Send alarm + $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'pok_individual',$data['arg']); +} else { + // Init found and count. + $found = false; + + // Loop thru attendances + foreach($atts as $att_row => $att_data) { + // Remove vote for specific pokemon + if($att_data['pokemon'] == $data['arg']) { + // Is it the only vote? Update to "Any raid boss" instead of deleting it! + if($count == 1) { + my_query(' + UPDATE attendance + SET pokemon = 0 + WHERE raid_id = ? + AND user_id = ? + ', [$data['id'], $update['callback_query']['from']['id']] ); - - // Delete any attendances except the first one. - my_query( - " + // Other votes are still there, delete this one! + } else { + my_query(' DELETE FROM attendance - WHERE id NOT IN ( - SELECT * FROM ( - SELECT MIN(id) - FROM attendance - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - ) AS AVOID_MYSQL_ERROR_1093 - ) - AND raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " + WHERE raid_id = ? + AND user_id = ? + AND pokemon = ? + ', [$data['id'], $update['callback_query']['from']['id'], $data['arg']] ); + } + // Send alarm + $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'pok_cancel_individual',$data['arg']); - // Send alarm - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'pok_individual',$data['arg']); - } else { - // Init found and count. - $found = false; - - // Loop thru attendances - foreach($atts as $att_row => $att_data) { - // Remove vote for specific pokemon - if($att_data['pokemon'] == $data['arg']) { - // Is it the only vote? Update to "Any raid boss" instead of deleting it! - if($count == 1) { - my_query( - " - UPDATE attendance - SET pokemon = '0' - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " - ); - // Other votes are still there, delete this one! - } else { - my_query( - " - DELETE FROM attendance - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - AND pokemon = '{$data['arg']}' - " - ); - } - // Send alarm - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'pok_cancel_individual',$data['arg']); - - // Update count. - $count = $count - 1; - - // Found and break. - $found = true; - break; - } - } - - // Not found? Insert! - if(!$found) { - // Send alarm - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'pok_individual',$data['arg']); - - // Insert vote. - my_query( - " - INSERT INTO attendance - ( - user_id, - raid_id, - attend_time, - extra_in_person, - extra_alien, - arrived, - raid_done, - cancel, - late, - remote, - invite, - pokemon, - alarm, - want_invite, - can_invite - ) - VALUES( - '{$atts[0]['user_id']}', - '{$atts[0]['raid_id']}', - '{$atts[0]['attend_time']}', - '{$atts[0]['extra_in_person']}', - '{$atts[0]['extra_alien']}', - '{$atts[0]['arrived']}', - '{$atts[0]['raid_done']}', - '{$atts[0]['cancel']}', - '{$atts[0]['late']}', - '{$atts[0]['remote']}', - '{$atts[0]['invite']}', - '{$data['arg']}', - '{$atts[0]['alarm']}', - '{$atts[0]['want_invite']}', - '{$atts[0]['can_invite']}' - ) - " - ); - - // Update counter. - $count = $count + 1; - } - - // Delete "Any raid boss" vote if count is larger than 0 - if($count > 0) { - my_query( - " - DELETE FROM attendance - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - AND pokemon = '0' - " - ); - } + // Update count. + $count = $count - 1; + + // Found and break. + $found = true; + break; + } + } + + // Not found? Insert! + if(!$found) { + // Send alarm + $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'pok_individual',$data['arg']); + + $keys = $values = ''; + $binds = []; + foreach($atts[0] as $key => $value) { + if($key == 'id') continue; + $keys .= $key . ','; + $values .= '?,'; + $binds[] = ($key == 'pokemon') ? $data['arg'] : $value; } + $keys = rtrim($keys, ','); + $values = rtrim($values, ','); + // Insert vote. + my_query(' + INSERT INTO attendance (' . $keys . ') + VALUES (' . $values . ') + ', $binds + ); + + // Update counter. + $count = $count + 1; + } + + // Delete "Any raid boss" vote if count is larger than 0 + if($count > 1) { + my_query(' + DELETE FROM attendance + WHERE raid_id = ? + AND user_id = ? + AND pokemon = 0 + ', [$data['id'], $update['callback_query']['from']['id']] + ); + } +} - require_once(LOGIC_PATH . '/update_raid_poll.php'); +require_once(LOGIC_PATH . '/update_raid_poll.php'); - $tg_json = update_raid_poll($data['id'], false, $update, $tg_json); +$tg_json = update_raid_poll($data['id'], false, $update, $tg_json); - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); - curl_json_multi_request($tg_json); -} else { - // Send vote time first. - send_vote_time_first($update); -} +curl_json_multi_request($tg_json); exit(); diff --git a/mods/vote_refresh.php b/mods/vote_refresh.php index 22ebad3d..85155577 100644 --- a/mods/vote_refresh.php +++ b/mods/vote_refresh.php @@ -7,5 +7,4 @@ curl_json_multi_request($tg_json); -$dbh = null; exit(); diff --git a/mods/vote_remote.php b/mods/vote_remote.php index 24bbef32..16be78e4 100644 --- a/mods/vote_remote.php +++ b/mods/vote_remote.php @@ -1,6 +1,10 @@ $update['callback_query']['from']['id'], 'raidId' => $data['id']] ); // Get the answer. @@ -35,78 +37,76 @@ $status = $data['arg']; // Make sure user has voted before. -if (!empty($answer)) { - // Prevent invite beggars from voting late or arrived - if(!($answer['want_invite'] == 1 && ($status == 'late' || $status == 'arrived'))) { - // Update attendance. - if($status == 'alarm') { - // Enable / Disable alarm - my_query( - " - UPDATE attendance - SET alarm = CASE - WHEN alarm = '0' THEN '1' - ELSE '0' - END - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " - ); - $new_alarm_value = $answer['alarm'] = 0 ? 1 : 0; - // Inform User about change - sendAlertOnOffNotice($data['id'], $update['callback_query']['from']['id'], $new_alarm_value); - } else { - // All other status-updates are using the short query - my_query( - " - UPDATE attendance - SET arrived = 0, - raid_done = 0, - cancel = 0, - late = 0, - $status = 1 - WHERE raid_id = {$data['id']} - AND user_id = {$update['callback_query']['from']['id']} - " - ); - if($status == 'raid_done' or $status == 'cancel') { - if($status == 'cancel') $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'status',$status, $tg_json); - // If the gym is a temporary remote raid gym and raid creator voted for done, send message asking for raid deletion - if($answer['is_remote_gym'] == '1' && $answer['user_is_creator']) { - $keys = [[ - [ - 'text' => getTranslation('yes'), - 'callback_data' => $data['id'].':end_remote_raid:0' - ], - [ - 'text' => getTranslation('no'), - 'callback_data' => '0:exit:0' - ], - ]]; - if($status == 'raid_done') $msg = getTranslation("delete_remote_raid_done"); - else if($status == 'cancel') $msg = getTranslation("delete_remote_raid_cancel"); - $tg_json[] = send_message($update['callback_query']['from']['id'], $msg, $keys, false, true); - } - }elseif($status != 'arrived') { - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'status',$status, $tg_json); - } - } +if (empty($answer)) { + // Send vote time first. + send_vote_time_first($update); + exit; +} +// Prevent invite beggars from voting late or arrived +if(($answer['want_invite'] == 1 && ($status == 'late' || $status == 'arrived'))) { + $msg = getTranslation('vote_status_not_allowed'); + answerCallbackQuery($update['callback_query']['id'], $msg); + exit; +} +// Update attendance. +if($status == 'alarm') { + // Enable / Disable alarm + my_query(' + UPDATE attendance + SET alarm = CASE + WHEN alarm = 0 THEN 1 + ELSE 0 + END + WHERE raid_id = ? + AND user_id = ? + ', [$data['id'], $update['callback_query']['from']['id']] + ); + $new_alarm_value = $answer['alarm'] = 0 ? 1 : 0; + // Inform User about change + sendAlertOnOffNotice($data['id'], $update['callback_query']['from']['id'], $new_alarm_value); +} else { + // All other status-updates are using the short query + my_query(' + UPDATE attendance + SET arrived = 0, + raid_done = 0, + cancel = 0, + late = 0, + ' . $status . ' = 1 + WHERE raid_id = ? + AND user_id = ? + ', [$data['id'], $update['callback_query']['from']['id']] + ); + if($status == 'raid_done' or $status == 'cancel') { + if($status == 'cancel') $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'status',$status, $tg_json); + // If the gym is a temporary remote raid gym and raid creator voted for done, send message asking for raid deletion + if($answer['is_remote_gym'] == '1' && $answer['user_is_creator']) { + $keys = [[ + [ + 'text' => getTranslation('yes'), + 'callback_data' => $data['id'].':end_remote_raid:0' + ], + [ + 'text' => getTranslation('no'), + 'callback_data' => '0:exit:0' + ], + ]]; + if($status == 'raid_done') $msg = getTranslation("delete_remote_raid_done"); + else if($status == 'cancel') $msg = getTranslation("delete_remote_raid_cancel"); + $tg_json[] = send_message($update['callback_query']['from']['id'], $msg, $keys, false, true); + } + }elseif($status != 'arrived') { + $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'status',$status, $tg_json); + } +} - // Send vote response. - require_once(LOGIC_PATH . '/update_raid_poll.php'); +// Send vote response. +require_once(LOGIC_PATH . '/update_raid_poll.php'); - $tg_json = update_raid_poll($data['id'], false, $update, $tg_json); +$tg_json = update_raid_poll($data['id'], false, $update, $tg_json); - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); - curl_json_multi_request($tg_json); - }else { - $msg = getTranslation('vote_status_not_allowed'); - answerCallbackQuery($update['callback_query']['id'], $msg); - } -} else { - // Send vote time first. - send_vote_time_first($update); -} +curl_json_multi_request($tg_json); exit(); diff --git a/mods/vote_team.php b/mods/vote_team.php index d35590df..2e5eb983 100644 --- a/mods/vote_team.php +++ b/mods/vote_team.php @@ -1,6 +1,7 @@ 0) && $vote_time != 0 && $config->RAID_REMOTEPASS_USERS_LIMIT < ($remote_users + $answer['user_count'])) { // Send max remote users reached. send_vote_remote_users_limit_reached($update); - $dbh = null; exit; } @@ -105,8 +108,7 @@ ]); $update_pokemon_sql = 'pokemon = \'0\','; } - my_query( - ' + my_query(' UPDATE attendance SET attend_time = :attendTimeSave, cancel = 0, diff --git a/mods/vote_want_invite.php b/mods/vote_want_invite.php index 6c7363f1..9ff93ee0 100644 --- a/mods/vote_want_invite.php +++ b/mods/vote_want_invite.php @@ -1,6 +1,8 @@ inc(['raidpicture']); -} - -if(isset($_GET['sa']) && $_GET['sa'] == 1) $standalone_photo = true; else $standalone_photo = false; -// Debug switch -$debug = false; -if(isset($_GET['debug']) && $_GET['debug'] == 1) { - $debug = true; - $raid_id = preg_replace("/\D/","",$_GET['raid']); - if(preg_match("^[0-9]+$^",$raid_id)) $raid = get_raid($raid_id); - else die("Invalid raid id!"); -} else { - $required_parameters = ['pokemon', 'pokemon_form', 'start_time', 'end_time', 'gym_id', 'ex_raid']; - $failed = []; - // Raid info - foreach($required_parameters as $required) { - if(!array_key_exists($required, $_GET)) { - $failed[] = $required; - } - } - if(count($failed) > 0) { - info_log('Raidpicture called without '.join(', ',$failed).', ending execution'); - exit(); - } - $raid = []; - $raid['pokemon'] = preg_replace("/\D/","",$_GET['pokemon']); - $raid['gym_id'] = preg_replace("/\D/","",$_GET['gym_id']); - $raid['raid_costume'] = false; - $raid['event'] = ($_GET['ex_raid'] == 1) ? EVENT_ID_EX : 0; - if($_GET['start_time'] == 0) { - $raid['raid_ended'] = true; - }else { - $raid['raid_ended'] = false; - $raid['start_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['start_time'])); - $raid['end_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['end_time'])); - } - if(in_array($_GET['pokemon_form'], ['-1','-2','-3'])) { - $raid['pokemon_form'] = $_GET['pokemon_form']; - }else { - $raid['pokemon_form'] = preg_replace("/\D/","",$_GET['pokemon_form']); - } - $raid['costume'] = 0; - if(array_key_exists('costume', $_GET) && $_GET['costume'] != '') { - $raid['costume'] = preg_replace("/\D/","",$_GET['costume']); - } - $q_pokemon_info = my_query(" - SELECT - pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, asset_suffix, type, type2 - FROM pokemon - WHERE pokedex_id = '".$raid['pokemon']."' - AND pokemon_form_id = '".$raid['pokemon_form']."' LIMIT 1")->fetch(); - $q_gym_info = my_query("SELECT img_url, gym_name, ex_gym FROM gyms WHERE id='".$raid['gym_id']."'")->fetch(); - $raid = array_merge($raid, $q_pokemon_info, $q_gym_info); + $requests_total->inc(['raidpicture']); } // Define and print picture // PNG if($config->RAID_PICTURE_FILE_FORMAT == 'png') { - header("Content-type: image/png"); + header("Content-type: image/png"); // JPEG } else if($config->RAID_PICTURE_FILE_FORMAT == 'jpeg' || $config->RAID_PICTURE_FILE_FORMAT == 'jpg') { - header("Content-type: image/jpeg"); + header("Content-type: image/jpeg"); // Use GIF as default - smallest file size without compression } else { - header("Content-type: image/gif"); + header("Content-type: image/gif"); +} +$standalone_photo = (isset($_GET['sa']) && $_GET['sa'] == 1) ? true : false; + +if(isset($_GET['debug']) && $_GET['debug'] == 1) { + $raid_id = preg_replace("/\D/","",$_GET['raid']); + if(preg_match("^[0-9]+$^",$raid_id)) $raid = get_raid($raid_id); + else die("Invalid raid id!"); + echo create_raid_picture($raid, $standalone_photo, true); + exit; } -echo create_raid_picture($raid, $standalone_photo, $debug); +$required_parameters = ['pokemon', 'pokemon_form', 'start_time', 'end_time', 'gym_id', 'ex_raid']; +$failed = []; +// Raid info +foreach($required_parameters as $required) { + if(!array_key_exists($required, $_GET)) { + $failed[] = $required; + } +} +if(count($failed) > 0) { + info_log('Raidpicture called without '.join(', ',$failed).', ending execution'); + exit(); +} +$raid = []; +$raid['pokemon'] = preg_replace("/\D/","",$_GET['pokemon']); +$raid['gym_id'] = preg_replace("/\D/","",$_GET['gym_id']); +$raid['raid_costume'] = false; +$raid['event'] = ($_GET['ex_raid'] == 1) ? EVENT_ID_EX : 0; +if($_GET['start_time'] == 0) { + $raid['raid_ended'] = true; +}else { + $raid['raid_ended'] = false; + $raid['start_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['start_time'])); + $raid['end_time'] = date("Y-M-d H:i:s",preg_replace("/\D/","",$_GET['end_time'])); +} +if(in_array($_GET['pokemon_form'], ['-1','-2','-3'])) { + $raid['pokemon_form'] = $_GET['pokemon_form']; +}else { + $raid['pokemon_form'] = preg_replace("/\D/","",$_GET['pokemon_form']); +} +$raid['costume'] = 0; +if(array_key_exists('costume', $_GET) && $_GET['costume'] != '') { + $raid['costume'] = preg_replace("/\D/","",$_GET['costume']); +} +$q_pokemon_info = my_query(' + SELECT pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, asset_suffix, type, type2 + FROM pokemon + WHERE pokedex_id = ? + AND pokemon_form_id = ? + LIMIT 1', [$raid['pokemon'], $raid['pokemon_form']])->fetch(); +$q_gym_info = my_query('SELECT img_url, gym_name, ex_gym FROM gyms WHERE id = ?', [$raid['gym_id']])->fetch(); +$raid = array_merge($raid, $q_pokemon_info, $q_gym_info); -?> +echo create_raid_picture($raid, $standalone_photo); From 4d6c6adec1b108df2fb7a11a6fff91f649aa1a2b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 21 Nov 2022 14:10:45 +0200 Subject: [PATCH 156/367] ddos check fix --- core/bot/ddos.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/bot/ddos.php b/core/bot/ddos.php index bac5c796..7bf77fda 100644 --- a/core/bot/ddos.php +++ b/core/bot/ddos.php @@ -14,8 +14,8 @@ function verifyUpdate($update, $data) { global $metrics; if ($update['type'] == 'callback_query' - && in_array($data['callbackAction'], ['overview_refresh', 'refresh_polls', 'getdb', 'update_bosses']) - or ($data['callbackAction'] == 'post_raid' && $update['skip_ddos'] == true) + && (in_array($data['callbackAction'], ['overview_refresh', 'refresh_polls', 'getdb', 'update_bosses']) + or ($data['callbackAction'] == 'post_raid' && $update['skip_ddos'] == true)) or isset($update['cleanup'])) { debug_log('Skipping DDOS check...','!'); From 811a8d625dfd2c993eb723e40ded067ddcd17619 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 21 Nov 2022 14:21:47 +0200 Subject: [PATCH 157/367] Store user's privileges in db Privileges are cached in db and read from there by default. Full privilege check is now performed only when user runs a command. --- VERSION | 2 +- core/bot/user.php | 40 +++++++++++++++++++++++++++------------- index.php | 3 ++- sql/pokemon-raid-bot.sql | 1 + sql/upgrade/6.sql | 1 + 5 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 sql/upgrade/6.sql diff --git a/VERSION b/VERSION index 7ed6ff82..1e8b3149 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5 +6 diff --git a/core/bot/user.php b/core/bot/user.php index 1e38eee7..89ca0f9e 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -9,9 +9,22 @@ class botUser public $userLanguage = ''; public $ddosCount = 0; + /** + * Read user privileges from db + * @param array $update Update array from Telegram + */ + public function initPrivileges($update) { + $user_id = $update[$update['type']]['from']['id']; + + $q = my_query('SELECT privileges FROM users WHERE user_id = ? LIMIT 1', [$user_id]); + $result = $q->fetch(); + if($result['privileges'] === NULL) return; + $this->userPrivileges = json_decode($result['privileges'], true); + } + /** * Run privilege check for Telegram user and save them for later use. - * @param $update array Update array from Telegram + * @param array $update Update array from Telegram */ public function privilegeCheck($update) { global $config; @@ -109,12 +122,14 @@ public function privilegeCheck($update) { } // Save privileges if found - if(is_array($privilegeList)) { + if(isset($privilegeList) && is_array($privilegeList)) { debug_log($accessFile, 'Positive result on access check in file:'); - $this->userPrivileges = [ + $privilegeArray = [ 'privileges' => $privilegeList, 'grantedBy' => $accessFile, ]; + my_query('UPDATE users SET privileges = ? WHERE user_id = ? LIMIT 1', [json_encode($privilegeArray), $user_id]); + $this->userPrivileges = $privilegeArray; break; } // Deny access @@ -125,10 +140,10 @@ public function privilegeCheck($update) { /** * Check users privileges for a specific action. Exits by default if access is denied. - * @param $update array Update array from Telegram - * @param $permission string Permission to check - * @param $return_result bool Return the result of privilege check - * @param $new_user bool Has user completed tutorial or not + * @param array $update Update array from Telegram + * @param string $permission Permission to check + * @param bool $return_result Return the result of privilege check + * @param bool $new_user Has user completed tutorial or not * @return bool|string */ public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { @@ -159,8 +174,10 @@ public function accessCheck($update, $permission = 'access-bot', $return_result /** * Raid access check. - * @param $update - * @param $data + * @param array $update + * @param int $raidId + * @param string $permission + * @param bool $return_result * @return bool */ public function raidAccessCheck($update, $raidId, $permission, $return_result = false) @@ -246,10 +263,7 @@ public function defineUserLanguage($update) { $languages = $GLOBALS['languages']; // Get languages from normal translation. - $userlanguage = DEFAULT_LANGUAGE; - if(array_key_exists($language_code, $languages)) { - $userlanguage = $languages[$language_code]; - } + $userlanguage = (array_key_exists($language_code, $languages)) ? $languages[$language_code] : DEFAULT_LANGUAGE; debug_log('User language: ' . $userlanguage); $this->userLanguage = $userlanguage; diff --git a/index.php b/index.php index 81d8cb8f..6721f1fa 100644 --- a/index.php +++ b/index.php @@ -81,7 +81,7 @@ // Get language $botUser->defineUserLanguage($update); - $botUser->privilegeCheck($update); + $botUser->initPrivileges($update); } // Callback query received. @@ -113,6 +113,7 @@ // Message is required to check for commands. } else if (isset($update['message']) && $update['message']['chat']['type'] == 'private') { + $botUser->privilegeCheck($update); // Portal message? if(isset($update['message']['entities']['1']['type']) && $update['message']['entities']['1']['type'] == 'text_link' && strpos($update['message']['entities']['1']['url'], 'https://intel.ingress.com/intel?ll=') === 0) { // Import portal. diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index eb30c025..7d9b6556 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -153,6 +153,7 @@ CREATE TABLE `users` ( `lang_manual` TINYINT UNSIGNED NOT NULL DEFAULT 0, `tutorial` TINYINT(1) NOT NULL DEFAULT 0, `auto_alarm` TINYINT(1) UNSIGNED NULL DEFAULT 0, + `privileges` JSON NULL, PRIMARY KEY (`id`), UNIQUE KEY `i_userid` (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8mb4; diff --git a/sql/upgrade/6.sql b/sql/upgrade/6.sql new file mode 100644 index 00000000..872dafc4 --- /dev/null +++ b/sql/upgrade/6.sql @@ -0,0 +1 @@ +ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `privileges` JSON NULL AFTER `auto_alarm`; From e2fb7aa0cf5328a87d67a20934226766c6dc8c19 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 21 Nov 2022 17:45:10 +0200 Subject: [PATCH 158/367] Minor fixes --- index.php | 2 ++ mods/gym_delete.php | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/index.php b/index.php index 6721f1fa..0ae951f0 100644 --- a/index.php +++ b/index.php @@ -113,7 +113,9 @@ // Message is required to check for commands. } else if (isset($update['message']) && $update['message']['chat']['type'] == 'private') { + // Update user's privileges into database $botUser->privilegeCheck($update); + // Portal message? if(isset($update['message']['entities']['1']['type']) && $update['message']['entities']['1']['type'] == 'text_link' && strpos($update['message']['entities']['1']['url'], 'https://intel.ingress.com/intel?ll=') === 0) { // Import portal. diff --git a/mods/gym_delete.php b/mods/gym_delete.php index 0e1aaeb8..5686ae46 100644 --- a/mods/gym_delete.php +++ b/mods/gym_delete.php @@ -1,7 +1,7 @@ Date: Tue, 22 Nov 2022 15:34:39 +0200 Subject: [PATCH 159/367] fixes --- commands/gym.php | 2 +- logic/raid_edit_gyms_first_letter_keys.php | 92 +++++++++------------- 2 files changed, 40 insertions(+), 54 deletions(-) diff --git a/commands/gym.php b/commands/gym.php index c091dfa6..2fe0fe09 100644 --- a/commands/gym.php +++ b/commands/gym.php @@ -69,4 +69,4 @@ ]; // Send message. -send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); +send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); diff --git a/logic/raid_edit_gyms_first_letter_keys.php b/logic/raid_edit_gyms_first_letter_keys.php index f29dd023..13489103 100644 --- a/logic/raid_edit_gyms_first_letter_keys.php +++ b/logic/raid_edit_gyms_first_letter_keys.php @@ -42,28 +42,10 @@ function raid_edit_gyms_first_letter_keys($action = 'raid_by_gym', $hidden = fal $keys = []; if(!$skip_letter_keys or !$config->ENABLE_GYM_AREAS or $hidden) { - // Special/Custom gym letters? - if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { - // Explode special letters. - $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); - $select = 'SELECT CASE '; - foreach($special_keys as $letter) - { - $letter = trim($letter); - debug_log($letter, 'Special gym letter:'); - // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); - $select .= SP . 'WHEN UPPER(LEFT(gym_name, ' . $length . ')) = \'' . $letter . '\' THEN UPPER(LEFT(gym_name, ' . $length . '))' . SP; - } - $select .= 'ELSE UPPER(LEFT(gym_name, 1)) END AS first_letter'; - $group_order = ' GROUP BY 1 ORDER BY gym_name'; - }else { - $select = 'SELECT DISTINCT UPPER(SUBSTR(gym_name, 1, 1)) AS first_letter'; - $group_order = ' ORDER BY 1'; - } // Show hidden gyms? $show_gym = $hidden ? 0 : 1; + // Get the number of gyms to display if($action == 'list_by_gym') { // Select only gyms with active raids $query_condition = ' @@ -74,11 +56,29 @@ function raid_edit_gyms_first_letter_keys($action = 'raid_by_gym', $hidden = fal }else { $query_condition = 'WHERE show_gym = ' . $show_gym . ' '; } - $rs_count = my_query('SELECT COUNT(gym_name) as count FROM gyms ' . $query_condition . ' ' . $gymarea_query); $gym_count = $rs_count->fetch(); + // If found over 20 gyms, print letters if($gym_count['count'] > 20) { + $select = 'SELECT DISTINCT UPPER(SUBSTR(gym_name, 1, 1)) AS first_letter'; + $group_order = ' ORDER BY 1'; + // Special/Custom gym letters? + if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { + // Explode special letters. + $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); + $select = 'SELECT CASE '; + foreach($special_keys as $letter) + { + $letter = trim($letter); + debug_log($letter, 'Special gym letter:'); + // Fix chinese chars, prior: $length = strlen($letter); + $length = strlen(utf8_decode($letter)); + $select .= SP . 'WHEN UPPER(LEFT(gym_name, ' . $length . ')) = \'' . $letter . '\' THEN UPPER(LEFT(gym_name, ' . $length . '))' . SP; + } + $select .= 'ELSE UPPER(LEFT(gym_name, 1)) END AS first_letter'; + $group_order = ' GROUP BY 1 ORDER BY gym_name'; + } $rs = my_query( $select . ' FROM gyms ' . @@ -107,13 +107,9 @@ function raid_edit_gyms_first_letter_keys($action = 'raid_by_gym', $hidden = fal }else { $query_condition = 'WHERE show_gym = ' . $show_gym; } - $query_collate = ''; - if($config->MYSQL_SORT_COLLATE != "") { - $query_collate = 'COLLATE ' . $config->MYSQL_SORT_COLLATE; - } + $query_collate = ($config->MYSQL_SORT_COLLATE != '') ? 'COLLATE ' . $config->MYSQL_SORT_COLLATE : ''; $rs = my_query(' - SELECT gyms.id, gyms.gym_name, gyms.ex_gym, - CASE WHEN SUM(raids.end_time > UTC_TIMESTAMP() - INTERVAL 10 MINUTE) THEN 1 ELSE 0 END AS active_raid + SELECT gyms.id, gyms.gym_name, gyms.ex_gym FROM gyms LEFT JOIN raids ON raids.gym_id = gyms.id @@ -129,28 +125,21 @@ function raid_edit_gyms_first_letter_keys($action = 'raid_by_gym', $hidden = fal if($gym['id'] == NULL) continue; $active_raid = active_raid_duplication_check($gym['id']); + $gym_name = $gym['gym_name']; // Show Ex-Gym-Marker? if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; - } else { - $gym_name = $gym['gym_name']; } // Add warning emoji for active raid if ($active_raid > 0) { $gym_name = EMOJI_WARN . SP . $gym_name; } - if($gym_name_action == 'list_raid') { - $keys[] = array( - 'text' => $gym_name, - 'callback_data' => '0:' . $gym_name_action . ':' . $gym['id'] - ); - }else { - $keys[] = array( - 'text' => $gym_name, - 'callback_data' => 'gl' . $gymarea_id . ':' . $gym_name_action . ':' . $gym['id'] - ); - } + $buttonId = ($gym_name_action == 'list_raid') ? 0 : 'gl' . $gymarea_id; + $keys[] = array( + 'text' => $gym_name, + 'callback_data' => $buttonId . ':' . $gym_name_action . ':' . $gym['id'] + ); } // Get the inline key array. @@ -159,22 +148,19 @@ function raid_edit_gyms_first_letter_keys($action = 'raid_by_gym', $hidden = fal } // Add back navigation key. - if($hidden == false) { - if($config->RAID_VIA_LOCATION_FUNCTION == 'remote') { - $query_remote = my_query('SELECT count(*) as count FROM raids LEFT JOIN gyms on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); - if($query_remote->fetch()['count'] > 0) { - $keys[][] = array( - 'text' => getTranslation('remote_raids'), - 'callback_data' => '0:list_remote_gyms:0' - ); - } + if($hidden == true) { + return ['keys' => $keys, 'gymarea_name' => $gymarea_name, 'letters' => $letters]; + } + if($config->RAID_VIA_LOCATION_FUNCTION == 'remote') { + $query_remote = my_query('SELECT count(*) as count FROM raids LEFT JOIN gyms on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); + if($query_remote->fetch()['count'] > 0) { + $keys[][] = array( + 'text' => getTranslation('remote_raids'), + 'callback_data' => '0:list_remote_gyms:0' + ); } - $nav_keys = []; - if(!empty($gymarea_keys) && ($config->DEFAULT_GYM_AREA !== false || $gymarea_id === false)) $keys = array_merge($keys, inline_key_array($gymarea_keys, 2)); - - // Get the inline key array. - $keys[] = $nav_keys; } + if(!empty($gymarea_keys) && ($config->DEFAULT_GYM_AREA !== false || $gymarea_id === false)) $keys = array_merge($keys, inline_key_array($gymarea_keys, 2)); return ['keys' => $keys, 'gymarea_name' => $gymarea_name, 'letters' => $letters]; } From fe74192fcc1448f990d9b598fe9fc9f590fe5feb Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 23 Nov 2022 20:32:06 +0200 Subject: [PATCH 160/367] Refactored gym menus and minor edits to botUser class Combined all the gym listing menu functions under one gymMenu function. Start, list and gym commands now use this function Also edited botUser class so there is less need to pass the $update variable there --- commands/delete.php | 4 +- commands/events.php | 2 +- commands/exreport.php | 2 +- commands/friendsearch.php | 2 +- commands/get.php | 2 +- commands/gym.php | 60 +--- commands/gymname.php | 2 +- commands/help.php | 2 +- commands/history.php | 2 +- commands/list.php | 18 +- commands/listall.php | 29 +- commands/overview.php | 2 +- commands/pokedex.php | 2 +- commands/pokemon.php | 2 +- commands/set.php | 2 +- commands/start.php | 49 +--- commands/trainer.php | 4 +- commands/tutorial.php | 2 +- core/bot/user.php | 57 ++-- index.php | 5 +- logic/edit_gym_keys.php | 22 +- logic/gymMenu.php | 320 +++++++++++++++++++++ logic/key_util.php | 4 +- logic/raid_edit_gym_keys.php | 122 -------- logic/raid_edit_gyms_first_letter_keys.php | 166 ----------- logic/raid_get_gyms_list_keys.php | 2 +- mods/bot_lang.php | 2 +- mods/code.php | 2 +- mods/code_start.php | 2 +- mods/delete_scheduled_entry.php | 2 +- mods/edit_date.php | 2 +- mods/edit_event.php | 4 +- mods/edit_event_raidlevel.php | 4 +- mods/edit_pokemon.php | 2 +- mods/edit_raidlevel.php | 52 ++-- mods/edit_save.php | 4 +- mods/edit_starttime.php | 2 +- mods/edit_time.php | 2 +- mods/events.php | 2 +- mods/events_add.php | 2 +- mods/events_manage.php | 2 +- mods/gymMenu.php | 29 ++ mods/gym_create.php | 2 +- mods/gym_delete.php | 37 +-- mods/gym_details.php | 50 +--- mods/gym_edit_details.php | 22 +- mods/gym_hidden_letter.php | 63 ---- mods/gym_letter.php | 72 ----- mods/history.php | 2 +- mods/history_gyms.php | 2 +- mods/history_raid.php | 2 +- mods/history_raids.php | 2 +- mods/import_future_bosses.php | 2 +- mods/import_shinyinfo.php | 2 +- mods/importal.php | 2 +- mods/list_by_gym.php | 60 ---- mods/list_by_gym_letter.php | 70 ----- mods/list_raid.php | 10 +- mods/listall.php | 65 ----- mods/overview_delete.php | 2 +- mods/overview_share.php | 2 +- mods/pogoinfo.php | 2 +- mods/pokebattler.php | 2 +- mods/pokedex.php | 2 +- mods/pokedex_disable_raids.php | 2 +- mods/pokedex_edit_pokemon.php | 2 +- mods/pokedex_import.php | 2 +- mods/pokedex_list_raids.php | 2 +- mods/pokedex_set_cp.php | 2 +- mods/pokedex_set_raid_level.php | 2 +- mods/pokedex_set_shiny.php | 2 +- mods/pokedex_set_weather.php | 2 +- mods/raid_by_gym.php | 60 ---- mods/raid_by_gym_letter.php | 81 ------ mods/raid_by_location.php | 2 +- mods/raid_edit_poke.php | 2 +- mods/raid_set_poke.php | 2 +- mods/raid_share.php | 2 +- mods/raids_delete.php | 2 +- mods/raids_list.php | 6 +- mods/share_raid_by_location.php | 2 +- mods/trainer.php | 4 +- mods/trainer_add.php | 2 +- mods/trainer_code.php | 2 +- mods/trainer_delete.php | 2 +- mods/trainer_level.php | 2 +- mods/trainer_name.php | 2 +- mods/trainer_share.php | 2 +- mods/trainer_team.php | 2 +- mods/tutorial.php | 2 +- 90 files changed, 537 insertions(+), 1134 deletions(-) create mode 100644 logic/gymMenu.php delete mode 100644 logic/raid_edit_gym_keys.php delete mode 100644 logic/raid_edit_gyms_first_letter_keys.php create mode 100644 mods/gymMenu.php delete mode 100644 mods/gym_hidden_letter.php delete mode 100644 mods/gym_letter.php delete mode 100644 mods/list_by_gym.php delete mode 100644 mods/list_by_gym_letter.php delete mode 100644 mods/listall.php delete mode 100644 mods/raid_by_gym.php delete mode 100644 mods/raid_by_gym_letter.php diff --git a/commands/delete.php b/commands/delete.php index fc0dce07..cd20f37b 100644 --- a/commands/delete.php +++ b/commands/delete.php @@ -7,13 +7,13 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'access-bot'); +$botUser->accessCheck('access-bot'); // Count results. $count = 0; $own_sql = ''; $own_arr = []; -if(!$botUser->accessCheck($update, 'delete', true) && $botUser->accessCheck($update,'delete-own',true)) { +if(!$botUser->accessCheck('delete', true) && $botUser->accessCheck('delete-own',true)) { $own_sql = 'AND users.user_id = :user_id'; $own_arr = [":user_id"=>$update['message']['from']['id']]; } diff --git a/commands/events.php b/commands/events.php index 775988b8..7e8bf0dd 100644 --- a/commands/events.php +++ b/commands/events.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'event-manage'); +$botUser->accessCheck('event-manage'); $q = my_query('SELECT * FROM events'); diff --git a/commands/exreport.php b/commands/exreport.php index 1edc5782..2df2d625 100644 --- a/commands/exreport.php +++ b/commands/exreport.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'ex-report'); +$botUser->accessCheck('ex-report'); // Init empty keys array. $keys = []; diff --git a/commands/friendsearch.php b/commands/friendsearch.php index fbf5caa7..a0707cd0 100644 --- a/commands/friendsearch.php +++ b/commands/friendsearch.php @@ -6,7 +6,7 @@ //debug_log($update); //debug_log($data); -$botUser->accessCheck($update, 'friendsearch'); +$botUser->accessCheck('friendsearch'); // Trim away everything before "/FRIENDSEARCH" $searchterm = $update['message']['text']; diff --git a/commands/get.php b/commands/get.php index c3d17c65..e4d97a7e 100644 --- a/commands/get.php +++ b/commands/get.php @@ -7,7 +7,7 @@ // debug_log($data); // Check access. -$botUser->accessCheck($update, 'config-get'); +$botUser->accessCheck('config-get'); // Get all allowed configs. $allowed = explode(',', $config->ALLOWED_TELEGRAM_CONFIG); diff --git a/commands/gym.php b/commands/gym.php index 2fe0fe09..267690f4 100644 --- a/commands/gym.php +++ b/commands/gym.php @@ -1,5 +1,5 @@ accessCheck($update, 'gym-details'); +$botUser->accessCheck('gym-details'); // Set keys. -$keys_and_gymarea = raid_edit_gyms_first_letter_keys('gym_details', false, false, 'gym_letter'); +$keys_and_gymarea = gymMenu('gym', false, 1, false, $config->DEFAULT_GYM_AREA); $keys = $keys_and_gymarea['keys']; // Set message. -$msg = '' . getTranslation('show_gym_details') . CR . CR; -if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= getTranslation('select_gym_area') . '' . CR; - }elseif($config->DEFAULT_GYM_AREA !== false) { - if($keys_and_gymarea['letters']) { - $msg .= getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= getTranslation('select_gym_name_or_gym_area') . '' . CR; - } - }else { - if($keys_and_gymarea['letters']) { - $msg .= getTranslation('select_gym_first_letter') . '' . CR; - }else { - $msg .= getTranslation('select_gym_name') . '' . CR; - } - } -}else { - if($keys_and_gymarea['letters']) { - $msg .= getTranslation('select_gym_first_letter') . '' . CR; - }else { - $msg .= getTranslation('select_gym_name') . '' . CR; - } -} -$msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); - -// Add key for hidden gyms. -$h_keys = []; -if($config->ENABLE_GYM_AREAS == false or ($config->ENABLE_GYM_AREAS == true && $config->DEFAULT_GYM_AREA !== false)) { - // Add key for hidden gyms. - $h_keys[] = universal_inner_key($h_keys, '0', 'gym_hidden_letter', 'gym_details', getTranslation('hidden_gyms')); - $h_keys = inline_key_array($h_keys, 1); -} - -// Merge keys. -$keys = array_merge($h_keys, $keys); - -if($botUser->accessCheck($update, 'gym-add')) { - $keys[] = [ - [ - 'text' => getTranslation('gym_create'), - 'callback_data' => '0:gym_create:0' - ] - ]; -} - -$keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] -]; +$msg = '' . getTranslation('show_gym_details') . '' . CR . CR; +$msg.= $keys_and_gymarea['gymareaTitle']; // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); diff --git a/commands/gymname.php b/commands/gymname.php index f243c19f..335250ed 100644 --- a/commands/gymname.php +++ b/commands/gymname.php @@ -10,7 +10,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'gym-name'); +$botUser->accessCheck('gym-name'); // Get gym by name. // Trim away everything before "/gymname " diff --git a/commands/help.php b/commands/help.php index 1e66bb15..d5996998 100644 --- a/commands/help.php +++ b/commands/help.php @@ -1,6 +1,6 @@ accessCheck($update, 'help', true); +$access = $botUser->accessCheck('help', true); // Display help for each permission if($access) { diff --git a/commands/history.php b/commands/history.php index 55ab1ea0..60722539 100644 --- a/commands/history.php +++ b/commands/history.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'history'); +$botUser->accessCheck('history'); require_once(LOGIC_PATH .'/history.php'); diff --git a/commands/list.php b/commands/list.php index 57a0eed9..f43f9c90 100644 --- a/commands/list.php +++ b/commands/list.php @@ -8,15 +8,15 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'list'); +$botUser->accessCheck('list'); $event_sql = 'event IS NULL'; -if($botUser->accessCheck($update, 'ex-raids', true)) { - if($botUser->accessCheck($update, 'event-raids', true)) +if($botUser->accessCheck('ex-raids', true)) { + if($botUser->accessCheck('event-raids', true)) $event_sql = ''; else $event_sql .= ' OR event = ' . EVENT_ID_EX; -}elseif($botUser->accessCheck($update, 'event-raids', true)) { +}elseif($botUser->accessCheck('event-raids', true)) { $event_sql = 'event != ' . EVENT_ID_EX .' OR event IS NULL'; } $event_sql = ($event_sql == '') ? '' : 'AND ('.$event_sql.')'; @@ -51,7 +51,7 @@ debug_log($raids[0]['r_active'], 'Active raids:'); // More raids as we like? -if($raids[0]['r_active'] > 12 && $botUser->accessCheck($update, 'listall', true)) { +if($raids[0]['r_active'] > 12 && $botUser->accessCheck('listall', true)) { // Forward to /listall debug_log('Too much raids, forwarding to /listall'); $skip_access = true; @@ -94,14 +94,6 @@ // Get the inline key array. $keys = inline_key_array($keys, 1); -// Add exit key. -$keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] -]; - // Build message. $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; $msg .= $text; diff --git a/commands/listall.php b/commands/listall.php index 128f41c5..2a5d7bbb 100644 --- a/commands/listall.php +++ b/commands/listall.php @@ -1,5 +1,5 @@ accessCheck($update, 'listall'); +if(!isset($skip_access) or $skip_access != true) $botUser->accessCheck('listall'); // Set keys. -$keys_and_gymarea = raid_edit_gyms_first_letter_keys('list_by_gym', false, false, 'listall', 'list_raid'); +$keys_and_gymarea = gymMenu('list', false, 1, false, $config->DEFAULT_GYM_AREA); $keys = $keys_and_gymarea['keys']; -$keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] -]; // Set message. $msg = '' . getTranslation('list_all_active_raids') . '' . CR; -$msg.= (($keys_and_gymarea['gymarea_name'] != '') ? getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] . CR: ''); -if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; - }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } - } -}elseif($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; -}else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; -} +$msg.= $keys_and_gymarea['gymareaTitle']; // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); diff --git a/commands/overview.php b/commands/overview.php index 8af13112..cd4f7701 100644 --- a/commands/overview.php +++ b/commands/overview.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'overview'); +$botUser->accessCheck('overview'); // Create keys array. $keys = [ diff --git a/commands/pokedex.php b/commands/pokedex.php index e7bc0707..f68d1156 100644 --- a/commands/pokedex.php +++ b/commands/pokedex.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Get pokemon name or dex id. $pokemon = trim(substr($update['message']['text'], 8)); diff --git a/commands/pokemon.php b/commands/pokemon.php index 4dcab384..6cef3c82 100644 --- a/commands/pokemon.php +++ b/commands/pokemon.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'access-bot'); +$botUser->accessCheck('access-bot'); // Count results. $count = 0; diff --git a/commands/set.php b/commands/set.php index 6e56acd5..a18f8c14 100644 --- a/commands/set.php +++ b/commands/set.php @@ -7,7 +7,7 @@ // debug_log($data); // Check access. -$botUser->accessCheck($update, 'config-set'); +$botUser->accessCheck('config-set'); // Get config name and value. $input = trim(substr($update['message']['text'], 4)); diff --git a/commands/start.php b/commands/start.php index 94069605..33b4a883 100644 --- a/commands/start.php +++ b/commands/start.php @@ -1,7 +1,7 @@ accessCheck($update, 'create', true, $new_user); +$access = $botUser->accessCheck('create', true, $new_user); if(!$access && !$new_user) { - if($botUser->accessCheck($update, 'list', true)){ + if($botUser->accessCheck('list', true)){ debug_log('No access to create, will do a list instead'); require('list.php'); }else { @@ -38,55 +38,30 @@ } // Get the keys by gym name search. +$addAbortKey = true; $keys = false; if(!empty($searchterm)) { $keys = raid_get_gyms_list_keys($searchterm); + $msg = getTranslation('select_gym_name'); } // Get the keys if nothing was returned. if(!$keys) { - $keys_and_gymarea = raid_edit_gyms_first_letter_keys('raid_by_gym', false, false, 'raid_by_gym_letter'); + $keys_and_gymarea = gymMenu('create', false, 1, false, $config->DEFAULT_GYM_AREA); $keys = $keys_and_gymarea['keys']; + $msg = $keys_and_gymarea['gymareaTitle']; + $addAbortKey = false; } // No keys found. -if (!$keys) { - // Create the keys. - $keys = [ +if ($addAbortKey) { + $keys[] = [ [ - [ - 'text' => getTranslation('not_supported'), - 'callback_data' => '0:exit:0' - ] + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' ] ]; -}else { - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ]; -} -$msg = ''; -// Set message. -if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; - }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } - } -}elseif(isset($keys_and_gymarea) && $keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; -}else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; } -$msg.= ((isset($keys_and_gymarea) && $keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); -$msg.= ($config->RAID_VIA_LOCATION ? (CR . CR . getTranslation('send_location')) : ''); // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/trainer.php b/commands/trainer.php index e487726a..6538eae1 100644 --- a/commands/trainer.php +++ b/commands/trainer.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'trainer'); +$botUser->accessCheck('trainer'); // Set message. $msg = '' . getTranslation('trainerinfo_set_yours') . ''; @@ -61,7 +61,7 @@ } // Check access. -$access = $botUser->accessCheck($update, 'trainer-share', true); +$access = $botUser->accessCheck('trainer-share', true); // Display sharing options for admins and users with trainer-share permissions if($access) { diff --git a/commands/tutorial.php b/commands/tutorial.php index e0f2611c..638aafb4 100644 --- a/commands/tutorial.php +++ b/commands/tutorial.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'tutorial'); +$botUser->accessCheck('tutorial'); // Tutorial if(is_file(ROOT_PATH . '/config/tutorial.php')) { diff --git a/core/bot/user.php b/core/bot/user.php index 89ca0f9e..11ab997f 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -8,15 +8,14 @@ class botUser ]; public $userLanguage = ''; public $ddosCount = 0; + public $userId = 0; /** * Read user privileges from db * @param array $update Update array from Telegram */ - public function initPrivileges($update) { - $user_id = $update[$update['type']]['from']['id']; - - $q = my_query('SELECT privileges FROM users WHERE user_id = ? LIMIT 1', [$user_id]); + public function initPrivileges() { + $q = my_query('SELECT privileges FROM users WHERE user_id = ? LIMIT 1', [$this->userId]); $result = $q->fetch(); if($result['privileges'] === NULL) return; $this->userPrivileges = json_decode($result['privileges'], true); @@ -26,27 +25,23 @@ public function initPrivileges($update) { * Run privilege check for Telegram user and save them for later use. * @param array $update Update array from Telegram */ - public function privilegeCheck($update) { + public function privilegeCheck() { global $config; - // Get Telegram user ID to check access from $update - either message, callback_query or inline_query - $user_id = $update[$update['type']]['from']['id']; - // Write to log. - debug_log('Telegram message type: ' . $update['type']); - debug_log('Checking access for ID: ' . $user_id); + debug_log('Checking access for ID: ' . $this->userId); // Public access? if(empty($config->BOT_ADMINS)) { - debug_log('Bot access is not restricted! Allowing access for user: ' . CR . $user_id); + debug_log('Bot access is not restricted! Allowing access for user: ' . CR . $this->userId); $this->userPrivileges['grantedBy'] = 'NOT_RESTRICTED'; return; } // Admin? $admins = explode(',', $config->BOT_ADMINS); - if(in_array($user_id,$admins)) { + if(in_array($this->userId, $admins)) { debug_log('Positive result on access check for Bot Admins'); debug_log('Bot Admins: ' . $config->BOT_ADMINS); - debug_log('user_id: ' . $user_id); + debug_log('user_id: ' . $this->userId); $this->userPrivileges['grantedBy'] = 'BOT_ADMINS'; return; } @@ -65,7 +60,7 @@ public function privilegeCheck($update) { $filename = str_replace(ACCESS_PATH . '/', '', $filePath); // Get chat object - remove comments from filename // This way some kind of comment like the channel name can be added to the end of the filename, e.g. creator-100123456789-MyPokemonChannel to easily differ between access files :) - preg_match('/(access)('.$user_id.')|(access|creator|admins|members|restricted|kicked)(-[0-9]+)/', '-' . $filename, $result); + preg_match('/(access)('.$this->userId.')|(access|creator|admins|members|restricted|kicked)(-[0-9]+)/', '-' . $filename, $result); if(empty($result[0])) continue; // User specific access file found? if(!empty($result[1])) { @@ -83,7 +78,7 @@ public function privilegeCheck($update) { // Save the full filename (with possible comments) to an array for later use $accessFilesList[$role.$tg_chat] = $filename; debug_log('Asking Telegram if user is a member of chat \'' . $tg_chat . '\''); - if(!isset($tg_json[$tg_chat])) $tg_json[$tg_chat] = get_chatmember($tg_chat, $user_id, true); // Get chat member object and check status + if(!isset($tg_json[$tg_chat])) $tg_json[$tg_chat] = get_chatmember($tg_chat, $this->userId, true); // Get chat member object and check status } $accessChats = curl_json_multi_request($tg_json); @@ -128,7 +123,7 @@ public function privilegeCheck($update) { 'privileges' => $privilegeList, 'grantedBy' => $accessFile, ]; - my_query('UPDATE users SET privileges = ? WHERE user_id = ? LIMIT 1', [json_encode($privilegeArray), $user_id]); + my_query('UPDATE users SET privileges = ? WHERE user_id = ? LIMIT 1', [json_encode($privilegeArray), $this->userId]); $this->userPrivileges = $privilegeArray; break; } @@ -140,13 +135,13 @@ public function privilegeCheck($update) { /** * Check users privileges for a specific action. Exits by default if access is denied. - * @param array $update Update array from Telegram * @param string $permission Permission to check * @param bool $return_result Return the result of privilege check * @param bool $new_user Has user completed tutorial or not * @return bool|string */ - public function accessCheck($update, $permission = 'access-bot', $return_result = false, $new_user = false) { + public function accessCheck($permission = 'access-bot', $return_result = false, $new_user = false) { + global $update; if(!$new_user && in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { return true; } @@ -174,15 +169,14 @@ public function accessCheck($update, $permission = 'access-bot', $return_result /** * Raid access check. - * @param array $update * @param int $raidId * @param string $permission * @param bool $return_result * @return bool */ - public function raidAccessCheck($update, $raidId, $permission, $return_result = false) + public function raidaccessCheck($raidId, $permission, $return_result = false) { - global $botUser; + global $update; // Default: Deny access to raids $raid_access = false; @@ -197,26 +191,26 @@ public function raidAccessCheck($update, $raidId, $permission, $return_result = $raid = $rs->fetch(); // Check permissions - if ($rs->rowCount() == 0 or $update['callback_query']['from']['id'] != $raid['user_id']) { + if ($rs->rowCount() == 0 or $this->userId != $raid['user_id']) { // Check "-all" permission debug_log('Checking permission:' . $permission . '-all'); $permission = $permission . '-all'; - return $botUser->accessCheck($update, $permission, $return_result); + return $this->accessCheck($permission, $return_result); } // Check "-own" permission debug_log('Checking permission:' . $permission . '-own'); $permission_own = $permission . '-own'; $permission_all = $permission . '-all'; - $raid_access = $botUser->accessCheck($update, $permission_own, true); + $raid_access = $this->accessCheck($permission_own, true); if($raid_access) { - return $botUser->accessCheck($update, $permission_own, $return_result); + return $this->accessCheck($permission_own, $return_result); } // Check "-all" permission if we get "access denied" // Maybe necessary if user has only "-all" configured, but not "-own" debug_log('Permission check for ' . $permission_own . ' failed! Maybe the access is just granted via ' . $permission . '-all ?'); debug_log('Checking permission:' . $permission_all); - return $botUser->accessCheck($update, $permission_all, $return_result); + return $this->accessCheck($permission_all, $return_result); } /** @@ -250,14 +244,11 @@ public function defineUserLanguage($update) { return; } // Message or callback? - $from = $update[$update['type']]['from']; $language_code = ''; - if(isset($from)) { - $q = my_query('SELECT lang FROM users WHERE user_id = ? LIMIT 1', [$from['id']]); - $res = $q->fetch(); - $language_code = $res['lang']; - } + $q = my_query('SELECT lang FROM users WHERE user_id = ? LIMIT 1', [$this->userId]); + $res = $q->fetch(); + $language_code = $res['lang']; // Get and define userlanguage. $languages = $GLOBALS['languages']; @@ -284,7 +275,7 @@ private function updateUserdb($update) debug_log($update, '!'); return false; } - $id = $msg['id']; + $id = $this->userId = $msg['id']; $name = ''; $sep = ''; diff --git a/index.php b/index.php index 0ae951f0..b6cc1129 100644 --- a/index.php +++ b/index.php @@ -54,7 +54,6 @@ $splitData = explode('|', $thedata); $data['callbackAction'] = $splitData[0]; unset($splitData[0]); - $data = []; foreach($splitData as $dataPiece) { [$key, $value] = explode('=', $dataPiece, 2); $data[$key] = $value; @@ -81,7 +80,7 @@ // Get language $botUser->defineUserLanguage($update); - $botUser->initPrivileges($update); + $botUser->initPrivileges(); } // Callback query received. @@ -114,7 +113,7 @@ // Message is required to check for commands. } else if (isset($update['message']) && $update['message']['chat']['type'] == 'private') { // Update user's privileges into database - $botUser->privilegeCheck($update); + $botUser->privilegeCheck(); // Portal message? if(isset($update['message']['entities']['1']['type']) && $update['message']['entities']['1']['type'] == 'text_link' && strpos($update['message']['entities']['1']['url'], 'https://intel.ingress.com/intel?ll=') === 0) { diff --git a/logic/edit_gym_keys.php b/logic/edit_gym_keys.php index cc323fe9..4ca45b94 100644 --- a/logic/edit_gym_keys.php +++ b/logic/edit_gym_keys.php @@ -20,52 +20,52 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add $text_ex_button = ($ex_gym == 1) ? getTranslation('normal_gym') : getTranslation('ex_gym'); $arg_ex = ($ex_gym == 1) ? 0 : 1; - // Add buttons to show/hide the gym and add/remove ex-raid flag $keys = []; + $callback = ['callbackAction' => 'gym_edit_details', 'g' => $gym_id]; $keys[] = [ [ 'text' => $text_show_button, - 'callback_data' => $gym_id . ':gym_edit_details:show-' . $arg_show + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'show', 'v' => $arg_show]) ], [ 'text' => $text_ex_button, - 'callback_data' => $gym_id . ':gym_edit_details:ex-' . $arg_ex + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'ex', 'v' => $arg_ex]) ] ]; - if($botUser->accessCheck($update, 'gym-name', true)) { + if($botUser->accessCheck('gym-name', true)) { $keys[] = [ [ 'text' => EMOJI_PENCIL . ' ' . getTranslation("gym_name_edit"), - 'callback_data' => $gym_id . ':gym_edit_details:name' + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'name']) ] ]; } - if($botUser->accessCheck($update, 'gym-edit', true)) { + if($botUser->accessCheck('gym-edit', true)) { $keys[] = [ [ 'text' => EMOJI_INFO . ' ' . (!empty($gym_note) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_add_edit_note"), - 'callback_data' => $gym_id . ':gym_edit_details:note' + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'note']) ] ]; $keys[] = [ [ 'text' => EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("directions")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), - 'callback_data' => $gym_id . ':gym_edit_details:addr' + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'addr']) ] ]; $keys[] = [ [ 'text' => EMOJI_HERE . ' ' . getTranslation("gym_edit_coordinates"), - 'callback_data' => $gym_id . ':gym_edit_details:gps' + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'gps']) ] ]; } - if($botUser->accessCheck($update, 'gym-delete', true)) { + if($botUser->accessCheck('gym-delete', true)) { $keys[] = [ [ 'text' => EMOJI_DELETE . ' ' . getTranslation("gym_delete"), - 'callback_data' => '0:gym_delete:'.$gym_id.'-delete' + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_delete', 'g' => $gym_id, 'c' => 0]) ] ]; } diff --git a/logic/gymMenu.php b/logic/gymMenu.php new file mode 100644 index 00000000..33050e47 --- /dev/null +++ b/logic/gymMenu.php @@ -0,0 +1,320 @@ + 'edit_raidlevel', + 'list' => 'list_raid', + 'gym' => 'gym_edit_details', +]; + +/** + * Raid gym first letter selection + * @param string $buttonAction Action that is performed by gym letter keys + * @param bool $showHidden Show only hidden gyms? + * @param int $stage + * @param string $firstLetter + * @param int|false $gymareaId + * @return array + */ +function gymMenu($buttonAction, $showHidden, $stage, $firstLetter = false, $gymareaId = false) { + + global $config, $botUser; + // Stage 0: Only gym area keys + // Stage 1: Gym letter keys (or just gym names if 20 or less gyms were found) with areas under them + // Stage 2: Gym names + $stage = ($config->ENABLE_GYM_AREAS && $stage == 1 && $gymareaId == false) ? 0 : $stage; + [$gymareaName, $gymareaKeys, $gymareaQuery] = ($config->ENABLE_GYM_AREAS) ? getGymareas($gymareaId, $stage, $buttonAction) : ['', [], '']; + if($stage == 2) + $gymKeys = createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery, $buttonAction, $gymareaId); + else + $gymKeys = createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $stage); + $keys = ($stage == 0) ? [] : $gymKeys[0]; + if($stage == 0) { + $title = getTranslation('select_gym_area'); + }elseif($stage == 1) { + if($config->ENABLE_GYM_AREAS) { + $title = $gymKeys[1] === true ? getTranslation('select_gym_first_letter_or_gym_area') : getTranslation('select_gym_name_or_gym_area'); + }else { + $title = $gymKeys[1] === true ? getTranslation('select_gym_first_letter') : getTranslation('select_gym_name'); + } + }else { + $title = getTranslation('select_gym_name'); + } + $gymareaTitle = '' . $title . '' . CR; + $gymareaTitle.= ($gymareaName != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $gymareaName : ''; + + $gymareaTitle.= ($config->RAID_VIA_LOCATION && $buttonAction == 'create' ? (CR . CR . getTranslation('send_location')) : ''); + + if($config->RAID_VIA_LOCATION_FUNCTION == 'remote' && $buttonAction == 'list') { + $query_remote = my_query('SELECT count(*) as count FROM raids LEFT JOIN gyms on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); + if($query_remote->fetch()['count'] > 0) { + $keys = array_merge($keys, [[[ + 'text' => getTranslation('remote_raids'), + 'callback_data' => formatCallbackData(['callbackAction' => 'list_remote_raids']) + ]]]); + } + } + // Merge keys. + if($stage < 2 && $showHidden == 0) { + $keys = array_merge($keys, inline_key_array($gymareaKeys, 2)); + } + // Add key for hidden gyms. + if($buttonAction == 'gym') { + if($stage == 1 && $showHidden == 0) { + // Add key for hidden gyms. + $h_keys[] = [ + [ + 'text' => getTranslation('hidden_gyms'), + 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'h' => 1, 'a' => 'gym', 'ga' => $gymareaId]) + ] + ]; + $keys = array_merge($h_keys, $keys); + } + if($stage == 0 && $botUser->accessCheck('gym-add', true)) { + $keys[] = [ + [ + 'text' => getTranslation('gym_create'), + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_create']) + ] + ]; + } + } + if($stage == 1 && $config->DEFAULT_GYM_AREA === false) { + $backKey = [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'stage' => 0, 'a' => $buttonAction]) + ]; + }elseif($stage == 2) { + $backKey = [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'stage' => 1, 'a' => $buttonAction, 'h' => $showHidden, 'ga' => $gymareaId]) + ]; + } + $abortKey = [ + 'text' => getTranslation('abort'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit', 'arg' => 0]) + ]; + if(isset($backKey)) + $keys[] = [$backKey, $abortKey]; + else + $keys[] = [$abortKey]; + return ['keys' => $keys, 'gymareaTitle' => $gymareaTitle]; +} + +/** + * @param int $gymareaId + * @param int $stage + * @param string $buttonAction + * @return array [$gymareaName, $gymareaKeys, $query] + */ +function getGymareas($gymareaId, $stage, $buttonAction) { + $gymareaKeys = $points = []; + $gymareaName = ''; + $json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'), 1); + foreach($json as $area) { + if($gymareaId == $area['id']) { + foreach($area['path'] as $point) { + $points[] = $point[0].' '.$point[1]; + } + $gymareaName = $area['name']; + if($points[0] != $points[count($points)-1]) $points[] = $points[0]; + } else { + $gymareaKeys[] = [ + 'text' => $area['name'], + 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'a' => $buttonAction, 'stage' => 1, 'ga' => $area['id']]) + ]; + } + } + $polygon_string = implode(',', $points); + $query = count($points) > 0 ? 'AND ST_CONTAINS(ST_GEOMFROMTEXT(\'POLYGON(('.$polygon_string.'))\'), ST_GEOMFROMTEXT(CONCAT(\'POINT(\',lat,\' \',lon,\')\')))' : ''; + return [$gymareaName, $gymareaKeys, $query]; +} + +/** + * @param string $buttonAction + * @param bool $showHidden + * @param int $gymareaId + * @param string $gymareaQuery + * @param int $stage + * @return array + */ +function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $stage) { + global $config, $menuActions; + // Show hidden gyms? + $show_gym = $showHidden ? 0 : 1; + $collateQuery = ($config->MYSQL_SORT_COLLATE != '') ? ' COLLATE ' . $config->MYSQL_SORT_COLLATE : ''; + + // Get the number of gyms to display + if($buttonAction == 'list') { + // Select only gyms with active raids + $queryConditions = ' + LEFT JOIN raids + ON raids.gym_id = gyms.id + WHERE end_time > UTC_TIMESTAMP()'; + }else { + $queryConditions = 'WHERE show_gym = ' . $show_gym . ' '; + } + $rs_count = my_query('SELECT COUNT(gym_name) as count FROM gyms ' . $queryConditions . ' ' . $gymareaQuery); + $gym_count = $rs_count->fetch(); + + // If found over 20 gyms, print letters + if($gym_count['count'] > 20) { + $select = 'SELECT DISTINCT UPPER(SUBSTR(gym_name, 1, 1)) AS first_letter'; + $group_order = ' ORDER BY 1'; + // Special/Custom gym letters? + if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { + // Explode special letters. + $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); + $select = 'SELECT CASE '; + foreach($special_keys as $letter) + { + $letter = trim($letter); + debug_log($letter, 'Special gym letter:'); + // Fix chinese chars, prior: $length = strlen($letter); + $length = strlen(utf8_decode($letter)); + $select .= SP . 'WHEN UPPER(LEFT(gym_name, ' . $length . ')) = \'' . $letter . '\' THEN UPPER(LEFT(gym_name, ' . $length . '))' . SP; + } + $select .= 'ELSE UPPER(LEFT(gym_name, 1)) END AS first_letter'; + $group_order = ' GROUP BY 1 ORDER BY gym_name'; + } + $rs = my_query( + $select . + ' FROM gyms ' . + $queryConditions . + $gymareaQuery . + $group_order . + $collateQuery + ); + while ($gym = $rs->fetch()) { + // Add first letter to keys array + $keys[] = array( + 'text' => $gym['first_letter'], + 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'a' => $buttonAction, 'stage' => $stage+1, 'fl' => $gym['first_letter'], 'ga' => $gymareaId]) + ); + } + + // Get the inline key array. + return [inline_key_array($keys, 4), true]; + } + + // If less than 20 gyms was found, print gym names + $rs = my_query(' + SELECT gyms.id, gyms.gym_name, gyms.ex_gym + FROM gyms + ' . $queryConditions . ' + ' . $gymareaQuery . ' + ORDER BY gym_name ' . $collateQuery + ); + // Init empty keys array. + $keys = []; + + while ($gym = $rs->fetch()) { + if($gym['id'] == NULL) continue; + $active_raid = active_raid_duplication_check($gym['id']); + + $gym_name = $gym['gym_name']; + // Show Ex-Gym-Marker? + if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { + $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; + $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; + } + // Add warning emoji for active raid + if ($active_raid > 0) { + $gym_name = EMOJI_WARN . SP . $gym_name; + } + $callback = [ + 'callbackAction' => $menuActions[$buttonAction], + 'g' => $gym['id'], + 'ga' => $gymareaId, + 'h' => $showHidden, + ]; + if($buttonAction == 'list') $callback['r'] = $active_raid; + $keys[] = array( + 'text' => $gym_name, + 'callback_data' => formatCallbackData($callback) + ); + } + + // Get the inline key array. + return [inline_key_array($keys, 1), false]; +} +/** + * Raid edit gym keys with active raids marker. + * @param string $firstLetter + * @param bool $showHidden + * @param string $gymareaQuery + * @param string $action + * @return array + */ +function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery = '', $action = '', $gymareaId = false) { + global $config, $menuActions; + // Length of first letter. + // Fix chinese chars, prior: $first_length = strlen($first); + $first_length = strlen(utf8_decode($firstLetter)); + + // Special/Custom gym letters? + $not = ''; + if(!empty($config->RAID_CUSTOM_GYM_LETTERS) && $first_length == 1) { + // Explode special letters. + $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); + + foreach($special_keys as $letter) + { + $letter = trim($letter); + debug_log($letter, 'Special gym letter:'); + // Fix chinese chars, prior: $length = strlen($letter); + $length = strlen(utf8_decode($letter)); + $not .= SP . 'AND UPPER(LEFT(gym_name, ' . $length . ')) != UPPER(\'' . $letter . '\')' . SP; + } + } + $show_gym = $showHidden ? 0 : 1; + + $query_collate = ($config->MYSQL_SORT_COLLATE != '') ? 'COLLATE ' . $config->MYSQL_SORT_COLLATE : ''; + // Get gyms from database + $rs = my_query(' + SELECT gyms.id, gyms.gym_name, gyms.ex_gym + FROM gyms + WHERE UPPER(LEFT(gym_name, ' . $first_length . ')) = UPPER(\'' . $firstLetter . '\') + ' . $not . ' + ' . $gymareaQuery . ' + AND show_gym = ? + ORDER BY gym_name ' . $query_collate + , [$show_gym] + ); + + // Init empty keys array. + $keys = []; + + while ($gym = $rs->fetch()) { + $active_raid = active_raid_duplication_check($gym['id']); + if($action == 'list' && $active_raid == 0) continue; + // Show Ex-Gym-Marker? + if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { + $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; + $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; + } else { + $gym_name = $gym['gym_name']; + } + // Add warning emoji for active raid + if ($active_raid > 0) { + $gym_name = EMOJI_WARN . SP . $gym_name; + } + $callback = [ + 'callbackAction' => $menuActions[$action], + 'g' => $gym['id'], + 'ga' => $gymareaId, + 'h' => $showHidden, + ]; + if($action == 'list') $callback['r'] = $active_raid; + else $callback['fl'] = $firstLetter; + $keys[] = array( + 'text' => $gym_name, + 'callback_data' => formatCallbackData($callback) + ); + } + + // Get the inline key array. + $keys = inline_key_array($keys, 1); + + return [$keys]; + +} diff --git a/logic/key_util.php b/logic/key_util.php index 1fd21ad0..e08c45e6 100644 --- a/logic/key_util.php +++ b/logic/key_util.php @@ -86,7 +86,7 @@ function share_keys($id, $action, $update, $raidLevel = '', $chats = '', $hideGe global $config, $botUser; $keys = []; // Check access. - $share_access = $botUser->accessCheck($update, 'share-any-chat', true); + $share_access = $botUser->accessCheck('share-any-chat', true); // Add share button if not restricted to allow sharing to any chat. if ($share_access == true && $hideGeneralShare == false) { @@ -174,5 +174,5 @@ function formatCallbackData($array) foreach($array as $key => $value) { $return .= $key . '=' . $value . '|'; } - return rtrim('|', $return); + return rtrim($return, '|'); } diff --git a/logic/raid_edit_gym_keys.php b/logic/raid_edit_gym_keys.php deleted file mode 100644 index 6fe4d050..00000000 --- a/logic/raid_edit_gym_keys.php +++ /dev/null @@ -1,122 +0,0 @@ -RAID_CUSTOM_GYM_LETTERS) && $first_length == 1) { - // Explode special letters. - $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); - - foreach($special_keys as $id => $letter) - { - $letter = trim($letter); - debug_log($letter, 'Special gym letter:'); - // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); - $not .= SP . "AND UPPER(LEFT(gym_name, " . $length . ")) != UPPER('" . $letter . "')" . SP; - } - } - $gymarea_query = ''; - if($gymarea_id != false) { - $json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'),1); - $points = []; - foreach($json as $area) { - if($gymarea_id == $area['id']) { - foreach($area['path'] as $point) { - $points[] = $point[0].' '.$point[1]; - } - if($points[0] != $points[count($points)-1]) $points[] = $points[0]; - break; - } - } - $polygon_string = implode(',', $points); - $gymarea_query = 'AND ST_CONTAINS(ST_GEOMFROMTEXT(\'POLYGON(('.$polygon_string.'))\'), ST_GEOMFROMTEXT(CONCAT(\'POINT(\',lat,\' \',lon,\')\')))'; - } - // Show hidden gyms? - $show_gym = ($hidden == true) ? 0 : 1; - - $query_collate = ''; - if($config->MYSQL_SORT_COLLATE != "") { - $query_collate = 'COLLATE ' . $config->MYSQL_SORT_COLLATE; - } - // Get gyms from database - $rs = my_query(' - SELECT gyms.id, gyms.gym_name, gyms.ex_gym, - CASE WHEN SUM(raids.end_time > UTC_TIMESTAMP() - INTERVAL 10 MINUTE) THEN 1 ELSE 0 END AS active_raid - FROM gyms - LEFT JOIN raids - ON raids.gym_id = gyms.id - WHERE UPPER(LEFT(gym_name, ' . $first_length . ')) = UPPER(\'' . $first . '\') - ' . $not . ' - ' . $gymarea_query . ' - AND gyms.show_gym = ? - GROUP BY gym_name, raids.gym_id, gyms.id, gyms.ex_gym - ORDER BY gym_name ' . $query_collate . ' - ', [$show_gym] - ); - - // Init empty keys array. - $keys = []; - - while ($gym = $rs->fetch()) { - $arg = $gym['id']; - // Add delete argument to keys - if ($delete == true) { - $arg .= '-delete'; - } - - // List action to list only gyms with active raids, so always continue at the end - if ($action == 'list_raid') { - if ($gym['active_raid'] == 1) { - $keys[] = array( - 'text' => $gym['gym_name'], - 'callback_data' => '0:' . $action . ':' . $arg - ); - } - // Continue always in case of list action - continue; - } - - // Write to log. - // debug_log($gym); - - $active_raid = active_raid_duplication_check($gym['id']); - - // Show Ex-Gym-Marker? - if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { - $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; - $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; - } else { - $gym_name = $gym['gym_name']; - } - // Add warning emoji for active raid - if ($active_raid > 0) { - $gym_name = EMOJI_WARN . SP . $gym_name; - } - $keys[] = array( - 'text' => $gym_name, - 'callback_data' => $first . ':' . $action . ':' . $arg - ); - } - - // Get the inline key array. - $keys = inline_key_array($keys, 1); - - return $keys; - -} diff --git a/logic/raid_edit_gyms_first_letter_keys.php b/logic/raid_edit_gyms_first_letter_keys.php deleted file mode 100644 index 13489103..00000000 --- a/logic/raid_edit_gyms_first_letter_keys.php +++ /dev/null @@ -1,166 +0,0 @@ -ENABLE_GYM_AREAS) { - $json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'),1); - $points = []; - foreach($json as $area) { - $gymarea_id = ($gymarea_id !== false) ? $gymarea_id : $config->DEFAULT_GYM_AREA; - if($gymarea_id !== false && $gymarea_id == $area['id']) { - foreach($area['path'] as $point) { - $points[] = $point[0].' '.$point[1]; - } - $gymarea_name = $area['name']; - if($points[0] != $points[count($points)-1]) $points[] = $points[0]; - $skip_letter_keys = false; - } else { - $gymarea_keys[] = [ - 'text' => $area['name'], - 'callback_data' => $area['id'] . ':' . $gymarea_action . ':' . $action - ]; - } - } - $polygon_string = implode(',', $points); - $gymarea_query = 'AND ST_CONTAINS(ST_GEOMFROMTEXT(\'POLYGON(('.$polygon_string.'))\'), ST_GEOMFROMTEXT(CONCAT(\'POINT(\',lat,\' \',lon,\')\')))'; - } - // Init empty keys array. - $keys = []; - - if(!$skip_letter_keys or !$config->ENABLE_GYM_AREAS or $hidden) { - // Show hidden gyms? - $show_gym = $hidden ? 0 : 1; - - // Get the number of gyms to display - if($action == 'list_by_gym') { - // Select only gyms with active raids - $query_condition = ' - LEFT JOIN raids - ON raids.gym_id = gyms.id - WHERE end_time > UTC_TIMESTAMP() - AND show_gym = ' . $show_gym . ' '; - }else { - $query_condition = 'WHERE show_gym = ' . $show_gym . ' '; - } - $rs_count = my_query('SELECT COUNT(gym_name) as count FROM gyms ' . $query_condition . ' ' . $gymarea_query); - $gym_count = $rs_count->fetch(); - - // If found over 20 gyms, print letters - if($gym_count['count'] > 20) { - $select = 'SELECT DISTINCT UPPER(SUBSTR(gym_name, 1, 1)) AS first_letter'; - $group_order = ' ORDER BY 1'; - // Special/Custom gym letters? - if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { - // Explode special letters. - $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); - $select = 'SELECT CASE '; - foreach($special_keys as $letter) - { - $letter = trim($letter); - debug_log($letter, 'Special gym letter:'); - // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); - $select .= SP . 'WHEN UPPER(LEFT(gym_name, ' . $length . ')) = \'' . $letter . '\' THEN UPPER(LEFT(gym_name, ' . $length . '))' . SP; - } - $select .= 'ELSE UPPER(LEFT(gym_name, 1)) END AS first_letter'; - $group_order = ' GROUP BY 1 ORDER BY gym_name'; - } - $rs = my_query( - $select . - ' FROM gyms ' . - $query_condition . - $gymarea_query . - $group_order - ); - while ($gym = $rs->fetch()) { - // Add first letter to keys array - $keys[] = array( - 'text' => $gym['first_letter'], - 'callback_data' => $show_gym . ':' . $action . ':' . $gym['first_letter'] . (($gymarea_id !== 'n') ? ',' .$gymarea_id : '') - ); - } - - // Get the inline key array. - $keys = inline_key_array($keys, 4); - $letters = true; - }else { - // If less than 20 gyms was found, print gym names - if($action == 'list_by_gym') { - // Select only gyms with active raids - $query_condition = ' - WHERE end_time > UTC_TIMESTAMP() - AND show_gym = ' . $show_gym; - }else { - $query_condition = 'WHERE show_gym = ' . $show_gym; - } - $query_collate = ($config->MYSQL_SORT_COLLATE != '') ? 'COLLATE ' . $config->MYSQL_SORT_COLLATE : ''; - $rs = my_query(' - SELECT gyms.id, gyms.gym_name, gyms.ex_gym - FROM gyms - LEFT JOIN raids - ON raids.gym_id = gyms.id - ' . $query_condition . ' - ' . $gymarea_query . ' - GROUP BY gym_name, raids.gym_id, gyms.id, gyms.ex_gym - ORDER BY gym_name ' . $query_collate - ); - // Init empty keys array. - $keys = []; - - while ($gym = $rs->fetch()) { - if($gym['id'] == NULL) continue; - $active_raid = active_raid_duplication_check($gym['id']); - - $gym_name = $gym['gym_name']; - // Show Ex-Gym-Marker? - if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { - $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; - $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; - } - // Add warning emoji for active raid - if ($active_raid > 0) { - $gym_name = EMOJI_WARN . SP . $gym_name; - } - $buttonId = ($gym_name_action == 'list_raid') ? 0 : 'gl' . $gymarea_id; - $keys[] = array( - 'text' => $gym_name, - 'callback_data' => $buttonId . ':' . $gym_name_action . ':' . $gym['id'] - ); - } - - // Get the inline key array. - $keys = inline_key_array($keys, 1); - } - } - - // Add back navigation key. - if($hidden == true) { - return ['keys' => $keys, 'gymarea_name' => $gymarea_name, 'letters' => $letters]; - } - if($config->RAID_VIA_LOCATION_FUNCTION == 'remote') { - $query_remote = my_query('SELECT count(*) as count FROM raids LEFT JOIN gyms on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); - if($query_remote->fetch()['count'] > 0) { - $keys[][] = array( - 'text' => getTranslation('remote_raids'), - 'callback_data' => '0:list_remote_gyms:0' - ); - } - } - if(!empty($gymarea_keys) && ($config->DEFAULT_GYM_AREA !== false || $gymarea_id === false)) $keys = array_merge($keys, inline_key_array($gymarea_keys, 2)); - - return ['keys' => $keys, 'gymarea_name' => $gymarea_name, 'letters' => $letters]; -} diff --git a/logic/raid_get_gyms_list_keys.php b/logic/raid_get_gyms_list_keys.php index fbb06323..3b1ddbea 100644 --- a/logic/raid_get_gyms_list_keys.php +++ b/logic/raid_get_gyms_list_keys.php @@ -30,7 +30,7 @@ function raid_get_gyms_list_keys($searchterm) $first = strtoupper(substr($gym['gym_name'], 0, 1)); $keys[] = array( 'text' => $gym['gym_name'], - 'callback_data' => $first . ':edit_raidlevel:' . $gym['id'] + 'callback_data' => formatCallbackData(['callbackAction' => 'edit_raidlevel', 'g' => $gym['id'], 'fl' => $first]) ); } diff --git a/mods/bot_lang.php b/mods/bot_lang.php index 776b1c95..be8326a6 100644 --- a/mods/bot_lang.php +++ b/mods/bot_lang.php @@ -7,7 +7,7 @@ //debug_log($data); // Access check. -$botUser->accessCheck($update, 'trainer'); +$botUser->accessCheck('trainer'); $keys = []; diff --git a/mods/code.php b/mods/code.php index bdc6addb..3df48334 100644 --- a/mods/code.php +++ b/mods/code.php @@ -9,7 +9,7 @@ // Allow anyone to use /code // Check access. -//$botUser->accessCheck($update, 'list'); +//$botUser->accessCheck('list'); // Set the raid id. $raid_id = $data['id']; diff --git a/mods/code_start.php b/mods/code_start.php index 9b73e25f..2e9b4e23 100644 --- a/mods/code_start.php +++ b/mods/code_start.php @@ -8,7 +8,7 @@ // Allow anyone to use /code // Check access. -//$botUser->accessCheck($update, 'list'); +//$botUser->accessCheck('list'); // Get raid $raid = get_raid($code_raid_id); diff --git a/mods/delete_scheduled_entry.php b/mods/delete_scheduled_entry.php index 990b94ab..6a6510bb 100644 --- a/mods/delete_scheduled_entry.php +++ b/mods/delete_scheduled_entry.php @@ -3,7 +3,7 @@ debug_log('delete_scheduled_entry()'); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); $arg = $data['arg']; $id = $data['id']; diff --git a/mods/edit_date.php b/mods/edit_date.php index 25bf48ff..5498c39b 100644 --- a/mods/edit_date.php +++ b/mods/edit_date.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'create'); +$botUser->accessCheck('create'); // Set the id. $id = $data['id']; diff --git a/mods/edit_event.php b/mods/edit_event.php index c28523b3..71f56038 100644 --- a/mods/edit_event.php +++ b/mods/edit_event.php @@ -13,9 +13,9 @@ //Initialize admin rights table [ ex-raid , raid-event ] $admin_access = [false, false]; // Check access - user must be admin for raid_level X -$admin_access[0] = $botUser->accessCheck($update, 'ex-raids', true); +$admin_access[0] = $botUser->accessCheck('ex-raids', true); // Check access - user must be admin for raid event creation -$admin_access[1] = $botUser->accessCheck($update, 'event-raids', true); +$admin_access[1] = $botUser->accessCheck('event-raids', true); // Get the keys. $keys = keys_event($gym_id_plus_letter, 'edit_event_raidlevel', $admin_access); diff --git a/mods/edit_event_raidlevel.php b/mods/edit_event_raidlevel.php index 346b6255..adec89c9 100644 --- a/mods/edit_event_raidlevel.php +++ b/mods/edit_event_raidlevel.php @@ -28,9 +28,9 @@ //Initialize admin rights table [ ex-raid , raid-event ] $admin_access = [false, false]; // Check access - user must be admin for raid_level X -$admin_access[0] = $botUser->accessCheck($update, 'ex-raids', true); +$admin_access[0] = $botUser->accessCheck('ex-raids', true); // Check access - user must be admin for raid event creation -$admin_access[1] = $botUser->accessCheck($update, 'event-raids', true); +$admin_access[1] = $botUser->accessCheck('event-raids', true); // Get the keys. $keys = raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access, $event_id); diff --git a/mods/edit_pokemon.php b/mods/edit_pokemon.php index b567806d..b08e8808 100644 --- a/mods/edit_pokemon.php +++ b/mods/edit_pokemon.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'create'); +$botUser->accessCheck('create'); // Set the id. $gym_id_plus_letter = $data['id']; diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index cb4593e5..2177e792 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -11,23 +11,15 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'create'); +$botUser->accessCheck('create'); // Get gym data via ID in arg -$gym_id = $data['arg']; +$gym_id = $data['g']; $gym = get_gym($gym_id); -// Back key id, action and arg -if(substr($data['id'],0,2) == 'gl') { - $back_id = substr($data['id'],2); - $back_action = 'raid_by_gym_letter'; - $back_arg = '0'; -}else { - $back_id = 0; - $back_action = 'raid_by_gym'; - $back_arg = $data['id']; -} -$gym_first_letter = $back_arg; +$gym_first_letter = $data['fl'] ?? ''; +$showHidden = $data['h'] ?? 0; +$gymareaId = $data['ga'] ?? false; // Telegram JSON array. $tg_json = array(); @@ -64,33 +56,23 @@ //Initialize admin rights table [ ex-raid , raid-event ] $admin_access = [false,false]; // Check access - user must be admin for raid_level X -$admin_access[0] = $botUser->accessCheck($update, 'ex-raids', true); +$admin_access[0] = $botUser->accessCheck('ex-raids', true); // Check access - user must be admin for raid event creation -$admin_access[1] = $botUser->accessCheck($update, 'event-raids', true); +$admin_access[1] = $botUser->accessCheck('event-raids', true); // Get the keys. $keys = raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access); -// No keys found. -if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; -} else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); -} +// Add navigation keys. +$nav_keys = []; +$nav_keys[] = [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'stage' => 2, 'a' => 'create', 'h' => $showHidden, 'ga' => $gymareaId, 'fl' => $gym_first_letter]) +]; +$nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); +$nav_keys = inline_key_array($nav_keys, 2); +// Merge keys. +$keys = array_merge($keys, $nav_keys); // Build message. $msg = getTranslation('create_raid') . ': ' . (($gym['address']=="") ? $gym['gym_name'] : $gym['address']) . ''; diff --git a/mods/edit_save.php b/mods/edit_save.php index cda46a18..20f67dba 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'create'); +$botUser->accessCheck('create'); // Set the id and arg. if(substr_count($data['id'], ',') == 1) { @@ -87,7 +87,7 @@ ]; // Check access level prior allowing to change raid time -$admin_access = $botUser->accessCheck($update, 'raid-duration', true); +$admin_access = $botUser->accessCheck('raid-duration', true); if($admin_access) { // Add time change to keys. $keys_time = [ diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index fbd4eb3e..90aeb0cd 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'create'); +$botUser->accessCheck('create'); // Get the argument. $arg_data = explode(",", $data['arg']); diff --git a/mods/edit_time.php b/mods/edit_time.php index 24109c79..f05e3f67 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -10,7 +10,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'create'); +$botUser->accessCheck('create'); // Get count of ID and argument. $count_id = substr_count($data['id'], ','); diff --git a/mods/events.php b/mods/events.php index e78defcd..6f7a9628 100644 --- a/mods/events.php +++ b/mods/events.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'event-manage'); +$botUser->accessCheck('event-manage'); $id = $data['id']; $arg = $data['arg']; diff --git a/mods/events_add.php b/mods/events_add.php index 8854a6e3..e31f3943 100644 --- a/mods/events_add.php +++ b/mods/events_add.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'event-manage'); +$botUser->accessCheck('event-manage'); $keys = []; $callback_response = 'OK'; diff --git a/mods/events_manage.php b/mods/events_manage.php index a9e2df44..2c4e6b3f 100644 --- a/mods/events_manage.php +++ b/mods/events_manage.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'event-manage'); +$botUser->accessCheck('event-manage'); $columnSettings = [ 'vote_key_mode' => ['allowed' => [0,1], 'default' => 0, 'nullable' => false], diff --git a/mods/gymMenu.php b/mods/gymMenu.php new file mode 100644 index 00000000..0562be60 --- /dev/null +++ b/mods/gymMenu.php @@ -0,0 +1,29 @@ +accessCheck($update, 'gym-edit'); +$botUser->accessCheck('gym-edit'); function insertUserInput($userId, $stage, $oldMessageId, $gymId = 0) { global $dbh; diff --git a/mods/gym_delete.php b/mods/gym_delete.php index 5686ae46..025a3e2e 100644 --- a/mods/gym_delete.php +++ b/mods/gym_delete.php @@ -9,29 +9,14 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'gym-delete'); +$botUser->accessCheck('gym-delete'); // Get the arg. -$arg = $data['arg']; +$gymId = $data['g']; +$confirm = $data['c'] == 1 ? true : false; -// Delete? -if(substr_count($arg, '-') == 1) { - $split_arg = explode('-', $arg); - $new_arg = $split_arg[0]; - $delete = true; - $confirm = false; -} else if(substr_count($arg, '-') == 2) { - $split_arg = explode('-', $arg); - $new_arg = $split_arg[0]; - $delete = true; - $confirm = true; -} else { - $msg = 'ERROR!'; - $keys = []; -} - -if ($new_arg > 0 && $delete == true && $confirm == false) { - $gym = get_gym($new_arg); +if ($gymId > 0 && $confirm == false) { + $gym = get_gym($gymId); // Set message $msg = EMOJI_WARN . SP . '' . getTranslation('delete_this_gym') . '' . SP . EMOJI_WARN; @@ -42,24 +27,24 @@ [ [ 'text' => getTranslation('yes'), - 'callback_data' => '0:gym_delete:' . $new_arg . '-delete-yes' + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_delete', 'g' => $gymId, 'c' => 1]) ] ], [ [ 'text' => getTranslation('no'), - 'callback_data' => $new_arg . ':gym_edit_details:' + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gymId]) ] ] ]; // Delete the gym. -} else if ($new_arg > 0 && $delete == true && $confirm == true) { +} else if ($gymId > 0 && $confirm == true) { require_once(LOGIC_PATH . '/get_gym_details.php'); require_once(LOGIC_PATH . '/get_gym.php'); - debug_log('Deleting gym with ID ' . $new_arg); + debug_log('Deleting gym with ID ' . $gymId); // Get gym. - $gym = get_gym($new_arg); + $gym = get_gym($gymId); // Set message $msg = '' . getTranslation('deleted_this_gym') . '' . CR; @@ -70,7 +55,7 @@ my_query(' DELETE FROM gyms WHERE id = ? - ', [$new_arg] + ', [$gymId] ); } diff --git a/mods/gym_details.php b/mods/gym_details.php index 2eb5a25d..a361ff3e 100644 --- a/mods/gym_details.php +++ b/mods/gym_details.php @@ -4,62 +4,26 @@ require_once(LOGIC_PATH . '/edit_gym_keys.php'); require_once(LOGIC_PATH . '/get_gym.php'); require_once(LOGIC_PATH . '/get_gym_details.php'); -require_once(LOGIC_PATH . '/raid_edit_gym_keys.php'); // For debug. //debug_log($update); //debug_log($data); // Check access. -$botUser->accessCheck($update, 'gym-details'); +$botUser->accessCheck('gym-details'); // Get the arg. -$args = explode(',',$data['arg'],2); -$arg = $args[0]; -$gymarea_id = (count($args) > 1) ? $args[1] : false; +$arg = $data['g']; +$gymarea_id = $data['ga'] ?? false; // Get the id. -$id = $data['id']; - -// ID or Arg = 0 ? -if($arg == 0 || $id == '0' || $id == '1') { - // Get hidden gyms? - $hidden = ($id == 0) ? true : false; - - // Get the keys. - $keys = raid_edit_gym_keys($arg, $gymarea_id, 'gym_details', false, $hidden); - - // Set keys. - $msg = '' . getTranslation('show_gym_details') . CR . CR . getTranslation('select_gym_name') . ''; - - // No keys found. - if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; - } else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $gymarea_id, 'gym_letter', 'gym_details', getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); - } +$id = $data['g']; // Get gym info. -} else { - $gym = get_gym($arg); - $msg = get_gym_details($gym, true); +$gym = get_gym($arg); +$msg = get_gym_details($gym, true); - $keys = edit_gym_keys($update, $arg, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); -} +$keys = edit_gym_keys($update, $arg, $gym['show_gym'], $gym['ex_gym'], $gym['gym_note'], $gym['address']); // Build callback message string. $callback_response = getTranslation('here_we_go'); diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index 7a6892fd..dcc9c720 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -10,19 +10,15 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'gym-edit'); +$botUser->accessCheck('gym-edit'); // Get the id. -$gym_id = $data['id']; - -// Get the arg. -$arg = $data['arg']; +$gym_id = $data['g']; // Split the arg. -$split_arg = explode('-', $arg); -$action = $split_arg[0]; -$value = $split_arg[1] ?? false; -$delete_id = $split_arg[2] ?? false; +$action = $data['a'] ?? ''; +$value = $data['v'] ?? false; +$delete_id = $data['d'] ?? false; // Set keys. $keys = []; @@ -65,18 +61,18 @@ $keys[0][] = [ 'text' => getTranslation('abort'), - 'callback_data' => $gym_id.':gym_edit_details:abort-'.$dbh->lastInsertId() + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'abort', 'd' => $dbh->lastInsertId()]) ]; if($action == 'note' && !empty($gym['gym_note'])) { $keys[0][] = [ 'text' => getTranslation('delete'), - 'callback_data' => $gym_id.':gym_edit_details:note-d-'.$dbh->lastInsertId() + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'note', 'd' => $dbh->lastInsertId()]) ]; } if($action == 'addr') { $keys[0][] = [ 'text' => getTranslation('gym_save_lookup_result'), - 'callback_data' => $gym_id.':gym_edit_details:addr-e-'.$dbh->lastInsertId() + 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'addr', 'd' => $dbh->lastInsertId()]) ]; } } @@ -86,7 +82,7 @@ }else if($action == 'ex') { $table = 'ex_gym'; }else if($action == 'abort') { - my_query('DELETE FROM user_input WHERE id = :value', ['value' => $value]); + my_query('DELETE FROM user_input WHERE id = :delete_id', ['delete_id' => $delete_id]); } if(isset($table)) { my_query(' diff --git a/mods/gym_hidden_letter.php b/mods/gym_hidden_letter.php deleted file mode 100644 index dd7fecb4..00000000 --- a/mods/gym_hidden_letter.php +++ /dev/null @@ -1,63 +0,0 @@ -accessCheck($update, 'gym-delete'); - - // Set message. - $msg = '' . getTranslation('gym_delete') . SP . '—' . SP . getTranslation('select_gym_first_letter') . ''; -} else { - // Force set arg. - $arg = 'gym_details'; - - // Check access. - $botUser->accessCheck($update, 'gym-details'); - - // Set message. - $msg = '' . getTranslation('show_gym_details') . SP . '—' . SP . getTranslation('select_gym_first_letter') . ''; -} - -// Set keys. - -$keys_and_gymarea = raid_edit_gyms_first_letter_keys($arg, true, $data['id'], 'gym_letter', 'gym_details'); -$keys = $keys_and_gymarea['keys']; - -// Set message. -if(!$keys) { - $msg = CR . '' . getTranslation('no_hidden_gyms') . ''; -} - -// Add navigation keys. -$nav_keys = []; -$nav_keys[] = universal_inner_key($nav_keys, $data['id'], 'gym_letter', $arg, getTranslation('back')); -$nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); -$nav_keys = inline_key_array($nav_keys, 2); - -// Merge keys. -$keys = array_merge($keys, $nav_keys); - -// Build callback message string. -$callback_response = getTranslation('here_we_go'); - -// Telegram JSON array. -$tg_json = array(); - -// Answer callback. -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - -// Edit the message. -$tg_json[] = edit_message($update, $msg, $keys, ['disable_web_page_preview' => 'true'], true); - -// Telegram multicurl request. -curl_json_multi_request($tg_json); diff --git a/mods/gym_letter.php b/mods/gym_letter.php deleted file mode 100644 index d38117f2..00000000 --- a/mods/gym_letter.php +++ /dev/null @@ -1,72 +0,0 @@ -accessCheck($update, 'gym-delete'); - - // Set message. - $msg = '' . getTranslation('gym_delete') . CR . getTranslation('select_gym_first_letter') . ''; - $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); -} else { - // Force set arg. - $arg = 'gym_details'; - - // Check access. - $botUser->accessCheck($update, 'gym-details'); - - // Set message. - $msg = '' . getTranslation('show_gym_details') . CR . getTranslation('select_gym_first_letter') . ''; - $msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); -} - -$nav_keys = []; - -if($data['id'] != 'n' or $config->ENABLE_GYM_AREAS === false) { - $nav_keys[] = [ - 'text' => getTranslation('back'), - 'callback_data' => 'n:gym_letter:gym_details' - ]; - // Add key for hidden gyms. - $h_keys = []; - $h_keys[] = universal_inner_key($h_keys, $data['id'], 'gym_hidden_letter', $arg, getTranslation('hidden_gyms')); - $h_keys = inline_key_array($h_keys, 1); - // Merge keys. - $keys = array_merge($h_keys, $keys); -} -$nav_keys[] = [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' -]; -$nav_keys = inline_key_array($nav_keys, 2); -// Merge keys. -$keys = array_merge($keys, $nav_keys); - -// Build callback message string. -$callback_response = getTranslation('here_we_go'); - -// Telegram JSON array. -$tg_json = array(); - -// Answer callback. -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - -// Edit the message. -$tg_json[] = edit_message($update, $msg, $keys, ['disable_web_page_preview' => 'true'], true); - -// Telegram multicurl request. -curl_json_multi_request($tg_json); diff --git a/mods/history.php b/mods/history.php index c36d3ce8..632ee0e4 100644 --- a/mods/history.php +++ b/mods/history.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'history'); +$botUser->accessCheck('history'); // Expected callback data: [Day number (0-31), DD]:history:[Year and month, YYYY-MM] diff --git a/mods/history_gyms.php b/mods/history_gyms.php index ca673897..b8d8e610 100644 --- a/mods/history_gyms.php +++ b/mods/history_gyms.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'history'); +$botUser->accessCheck('history'); // Expected callback data: [Date, YYYY-MM-DD]:history_gyms:[GYM_LETTER] diff --git a/mods/history_raid.php b/mods/history_raid.php index dffbe0c3..4895cd90 100644 --- a/mods/history_raid.php +++ b/mods/history_raid.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'history'); +$botUser->accessCheck('history'); // Expected callback data: [Date, YYYY-MM-DD]/[GYM_LETTER]:history_raid:[GYM_ID]/[RAID_ID] diff --git a/mods/history_raids.php b/mods/history_raids.php index 7cf229fd..76d3095c 100644 --- a/mods/history_raids.php +++ b/mods/history_raids.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'history'); +$botUser->accessCheck('history'); // Expected callback data: [Date, YYYY-MM-DD]/[GYM_LETTER]:history_raids:[GYM_ID] diff --git a/mods/import_future_bosses.php b/mods/import_future_bosses.php index 0ee1464d..ec43fba2 100644 --- a/mods/import_future_bosses.php +++ b/mods/import_future_bosses.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); require_once(LOGIC_PATH . '/read_upcoming_bosses.php'); $id = $data['id']; diff --git a/mods/import_shinyinfo.php b/mods/import_shinyinfo.php index 36c94fe8..60dbeb2f 100644 --- a/mods/import_shinyinfo.php +++ b/mods/import_shinyinfo.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); include(LOGIC_PATH . '/resolve_boss_name_to_ids.php'); // Get raid levels diff --git a/mods/importal.php b/mods/importal.php index 9a09fab6..1f17f250 100644 --- a/mods/importal.php +++ b/mods/importal.php @@ -10,7 +10,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'portal-import'); +$botUser->accessCheck('portal-import'); function escape($value){ $search = array("\\", "\x00", "\n", "\r", "'", '"', "\x1a"); diff --git a/mods/list_by_gym.php b/mods/list_by_gym.php deleted file mode 100644 index 9c9eb84a..00000000 --- a/mods/list_by_gym.php +++ /dev/null @@ -1,60 +0,0 @@ -accessCheck($update, 'list'); - -// Get the first letter -$args = explode(',',$data['arg'],2); -$first = $args[0]; -$gymarea_id = (count($args) > 1) ? $args[1] : false; - -// Back key id, action and arg -$back_id = 'n'; -$back_action = 'list_by_gym_letter'; -$back_arg = 0; - -// Get the keys. -$keys = raid_edit_gym_keys($first, $gymarea_id, 'list_raid'); - -// No keys found. -if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; -} else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); -} - -// Build callback message string. -$callback_response = getTranslation('here_we_go'); - -// Telegram JSON array. -$tg_json = array(); - -// Answer callback. -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - -// Edit the message. -$tg_json[] = edit_message($update, getTranslation('select_gym_name'), $keys, false, true); - -// Telegram multicurl request. -curl_json_multi_request($tg_json); diff --git a/mods/list_by_gym_letter.php b/mods/list_by_gym_letter.php deleted file mode 100644 index 59d1915d..00000000 --- a/mods/list_by_gym_letter.php +++ /dev/null @@ -1,70 +0,0 @@ -accessCheck($update, 'list'); - -// Get the keys. -$keys_and_gymarea = raid_edit_gyms_first_letter_keys('list_by_gym', false, ($data['id'] == 'n' ? false : $data['id']), 'list_by_gym_letter'); -$keys = $keys_and_gymarea['keys']; - -// Add navigation keys. -$nav_keys = []; -if($data['id'] != 'n') { - $nav_keys[] = universal_inner_key($nav_keys, 'n', 'listall', '', getTranslation('back')); -} -$nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); -$nav_keys = inline_key_array($nav_keys, 2); -// Merge keys. -$keys = array_merge($keys, $nav_keys); - -// No keys found. -if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('not_supported'), - 'callback_data' => '0:exit:0' - ] - ] - ]; -} - -// Build callback message string. -$callback_response = getTranslation('select_gym'); - -// Telegram JSON array. -$tg_json = array(); - -// Answer callback. -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - -// Edit the message. -$msg = '' . getTranslation('list_all_active_raids') . '' . CR; -if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; - }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } - } -}elseif($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; -}else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; -} -$msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); -$tg_json[] = edit_message($update, $msg, $keys, false, true); - -// Telegram multicurl request. -curl_json_multi_request($tg_json); diff --git a/mods/list_raid.php b/mods/list_raid.php index 74c87662..ce2db191 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -9,11 +9,11 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'list'); +$botUser->accessCheck('list'); // Get gym ID. -$gym_id = $data['arg']; -$raid_id = $data['id']; +$gym_id = $data['g']; +$raid_id = $data['r']; // Get raid details. if($raid_id != 0) { @@ -49,7 +49,7 @@ ] ] ]; - if($botUser->raidAccessCheck($update, $raid_id, 'pokemon', true)) { + if($botUser->raidaccessCheck($raid_id, 'pokemon', true)) { $keys[] = [ [ 'text' => getTranslation('update_pokemon'), @@ -57,7 +57,7 @@ ] ]; } - if($botUser->raidAccessCheck($update, $raid_id, 'delete', true)) { + if($botUser->raidaccessCheck($raid_id, 'delete', true)) { $keys[] = [ [ 'text' => getTranslation('delete'), diff --git a/mods/listall.php b/mods/listall.php deleted file mode 100644 index b93149a7..00000000 --- a/mods/listall.php +++ /dev/null @@ -1,65 +0,0 @@ -accessCheck($update, 'list'); - -// Get the keys. -$keys_and_gymarea = raid_edit_gyms_first_letter_keys('list_by_gym', false, ($data['id'] == 'n' ? false : $data['id']), 'listall', 'list_raid'); -$keys = $keys_and_gymarea['keys']; - -// Add navigation keys. -$nav_keys = []; -if($data['id'] != 'n') { - $nav_keys[] = universal_inner_key($nav_keys, 'n', 'listall', '', getTranslation('back')); -} -$nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); -$nav_keys = inline_key_array($nav_keys, 2); -// Merge keys. -$keys = array_merge($keys, $nav_keys); - -// Telegram JSON array. -$tg_json = array(); - -// Build callback message string. -$callback_response = getTranslation('select_gym'); - -// Answer callback. -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - -// Edit the message. -$msg = '' . getTranslation('list_all_active_raids') . '' . CR; -if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; - }elseif($config->DEFAULT_GYM_AREA !== false) { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } - }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; - } - } -}else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; - } -} -$msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); -$tg_json[] = edit_message($update, $msg, $keys, false, true); - -// Telegram multicurl request. -curl_json_multi_request($tg_json); diff --git a/mods/overview_delete.php b/mods/overview_delete.php index 985ab0bc..077ad725 100644 --- a/mods/overview_delete.php +++ b/mods/overview_delete.php @@ -11,7 +11,7 @@ $chat_id = $data['arg']; // Check access. -$botUser->accessCheck($update, 'overview'); +$botUser->accessCheck('overview'); // Telegram JSON array. $tg_json = array(); diff --git a/mods/overview_share.php b/mods/overview_share.php index 92b50d46..45348083 100644 --- a/mods/overview_share.php +++ b/mods/overview_share.php @@ -9,7 +9,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'overview'); +$botUser->accessCheck('overview'); // Get chat ID from data $chat_id = 0; diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index e2c54d4b..1890d6a4 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Levels available for import $levels = array('6', '5', '3', '1'); diff --git a/mods/pokebattler.php b/mods/pokebattler.php index 27925893..459f0d39 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); include(LOGIC_PATH . '/resolve_boss_name_to_ids.php'); // Get raid levels diff --git a/mods/pokedex.php b/mods/pokedex.php index 1b3559a9..1f506335 100644 --- a/mods/pokedex.php +++ b/mods/pokedex.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Get the limit. $limit = $data['id']; diff --git a/mods/pokedex_disable_raids.php b/mods/pokedex_disable_raids.php index 0f001dd1..bb032c40 100644 --- a/mods/pokedex_disable_raids.php +++ b/mods/pokedex_disable_raids.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Get raid levels. $id = $data['id']; diff --git a/mods/pokedex_edit_pokemon.php b/mods/pokedex_edit_pokemon.php index 16b659f5..869b3a06 100644 --- a/mods/pokedex_edit_pokemon.php +++ b/mods/pokedex_edit_pokemon.php @@ -10,7 +10,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Set the id. $poke_id_form = $data['id']; [$pokedex_id, $pokemon_form_id] = explode('-',$data['id'],2); diff --git a/mods/pokedex_import.php b/mods/pokedex_import.php index 6ae0707a..b3ee2d5f 100644 --- a/mods/pokedex_import.php +++ b/mods/pokedex_import.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); $id = $data['id']; $arg = $data['arg']; diff --git a/mods/pokedex_list_raids.php b/mods/pokedex_list_raids.php index ec2c5696..ac5a7de4 100644 --- a/mods/pokedex_list_raids.php +++ b/mods/pokedex_list_raids.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Get all pokemon with raid levels from database. $rs = my_query(' diff --git a/mods/pokedex_set_cp.php b/mods/pokedex_set_cp.php index cdd1db05..5292608d 100644 --- a/mods/pokedex_set_cp.php +++ b/mods/pokedex_set_cp.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Set the id. $pokedex_id = $data['id']; diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index 381d7d42..076299bf 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Set the id. $pokedex_id = $data['id']; diff --git a/mods/pokedex_set_shiny.php b/mods/pokedex_set_shiny.php index 484adb9b..dbe9eebc 100644 --- a/mods/pokedex_set_shiny.php +++ b/mods/pokedex_set_shiny.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Set the id. $pokedex_id = $data['id']; diff --git a/mods/pokedex_set_weather.php b/mods/pokedex_set_weather.php index 92f4a404..ecbe1fba 100644 --- a/mods/pokedex_set_weather.php +++ b/mods/pokedex_set_weather.php @@ -10,7 +10,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'pokedex'); +$botUser->accessCheck('pokedex'); // Set the id. $pokedex_id = $data['id']; diff --git a/mods/raid_by_gym.php b/mods/raid_by_gym.php deleted file mode 100644 index 21d64a7b..00000000 --- a/mods/raid_by_gym.php +++ /dev/null @@ -1,60 +0,0 @@ -accessCheck($update, 'create'); - -// Get the first letter -$args = explode(',',$data['arg'],2); -$first = $args[0]; -$gymarea_id = (count($args) > 1) ? $args[1] : false; - -// Back key id, action and arg -$back_id = $gymarea_id; -$back_action = 'raid_by_gym_letter'; -$back_arg = 0; - -// Get the keys. -$keys = raid_edit_gym_keys($first, $gymarea_id); - -// No keys found. -if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; -} else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); -} - -// Build callback message string. -$callback_response = getTranslation('here_we_go'); - -// Telegram JSON array. -$tg_json = array(); - -// Answer callback. -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - -// Edit the message. -$tg_json[] = edit_message($update, getTranslation('select_gym_name'), $keys, false, true); - -// Telegram multicurl request. -curl_json_multi_request($tg_json); diff --git a/mods/raid_by_gym_letter.php b/mods/raid_by_gym_letter.php deleted file mode 100644 index 4f1b785f..00000000 --- a/mods/raid_by_gym_letter.php +++ /dev/null @@ -1,81 +0,0 @@ -accessCheck($update, 'create'); - -// Back key id, action and arg -$back_id = 'n'; -$back_action = 'raid_by_gym_letter'; -$back_arg = 0; - -// Get the keys. -$keys_and_gymarea = raid_edit_gyms_first_letter_keys('raid_by_gym', false, ($data['id'] == 'n' ? false : $data['id']), 'raid_by_gym_letter'); -$keys = $keys_and_gymarea['keys']; - -// Add navigation keys. -$nav_keys = []; -if($data['id'] != 'n') { - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); -} -$nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); -$nav_keys = inline_key_array($nav_keys, 2); -// Merge keys. -$keys = array_merge($keys, $nav_keys); - -// No keys found. -if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('not_supported'), - 'callback_data' => '0:exit:0' - ] - ] - ]; -} - -// Build callback message string. -$callback_response = getTranslation('select_gym'); - -// Telegram JSON array. -$tg_json = array(); - -// Answer callback. -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - -$msg = ''; -// Edit the message. -if($config->ENABLE_GYM_AREAS) { - if($keys_and_gymarea['gymarea_name'] == '') { - $msg .= '' . getTranslation('select_gym_area') . '' . CR; - }elseif($config->DEFAULT_GYM_AREA !== false) { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter_or_gym_area') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name_or_gym_area') . '' . CR; - } - }else { - if($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; - }else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; - } - } -}elseif($keys_and_gymarea['letters']) { - $msg .= '' . getTranslation('select_gym_first_letter') . '' . CR; -}else { - $msg .= '' . getTranslation('select_gym_name') . '' . CR; -} -$msg.= (($keys_and_gymarea['gymarea_name'] != '') ? CR . CR . getTranslation('current_gymarea') . ': ' . $keys_and_gymarea['gymarea_name'] : ''); -$tg_json[] = edit_message($update, $msg, $keys, false, true); - -// Telegram multicurl request. -curl_json_multi_request($tg_json); diff --git a/mods/raid_by_location.php b/mods/raid_by_location.php index 927ccee6..82fe718d 100644 --- a/mods/raid_by_location.php +++ b/mods/raid_by_location.php @@ -10,7 +10,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'create'); +$botUser->accessCheck('create'); // Enabled? if(!$config->RAID_VIA_LOCATION) { diff --git a/mods/raid_edit_poke.php b/mods/raid_edit_poke.php index 099c1fb3..9b1e2a03 100644 --- a/mods/raid_edit_poke.php +++ b/mods/raid_edit_poke.php @@ -11,7 +11,7 @@ $raid_id = $data['id']; // Access check. -$botUser->raidAccessCheck($update, $raid_id, 'pokemon'); +$botUser->raidaccessCheck($raid_id, 'pokemon'); // Get raid level $raid_level = $data['arg']; diff --git a/mods/raid_set_poke.php b/mods/raid_set_poke.php index e72be018..67f8e73c 100644 --- a/mods/raid_set_poke.php +++ b/mods/raid_set_poke.php @@ -13,7 +13,7 @@ $raidId = $data['id']; // Access check. -$botUser->raidAccessCheck($update, $raidId, 'pokemon'); +$botUser->raidaccessCheck($raidId, 'pokemon'); $pokemon_id_form = get_pokemon_by_table_id($data['arg']); diff --git a/mods/raid_share.php b/mods/raid_share.php index 95bc8c69..f15fa519 100644 --- a/mods/raid_share.php +++ b/mods/raid_share.php @@ -11,7 +11,7 @@ $raidId = $data['id']; // Access check. -$botUser->raidAccessCheck($update, $raidId, 'share'); +$botUser->raidaccessCheck($raidId, 'share'); // Get chat id. $chat = $data['arg']; diff --git a/mods/raids_delete.php b/mods/raids_delete.php index cd839686..febeb84e 100644 --- a/mods/raids_delete.php +++ b/mods/raids_delete.php @@ -17,7 +17,7 @@ $raidId = $data['id']; // Access check. -$botUser->raidAccessCheck($update, $raidId, 'delete'); +$botUser->raidaccessCheck($raidId, 'delete'); // Execute the action. if ($action == 0) { diff --git a/mods/raids_list.php b/mods/raids_list.php index 54a4ddc3..50a74eff 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -11,7 +11,7 @@ $raidId = $data['id']; // Check access. -$botUser->accessCheck($update, 'list'); +$botUser->accessCheck('list'); // Get raid details. $raid = get_raid($raidId); @@ -25,7 +25,7 @@ ] ] ]; -if($botUser->raidAccessCheck($update, $raidId, 'pokemon', true)) { +if($botUser->raidaccessCheck($raidId, 'pokemon', true)) { $keys[] = [ [ 'text' => getTranslation('update_pokemon'), @@ -33,7 +33,7 @@ ] ]; } -if($botUser->raidAccessCheck($update, $raidId, 'delete', true)) { +if($botUser->raidaccessCheck($raidId, 'delete', true)) { $keys[] = [ [ 'text' => getTranslation('delete'), diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 7f9034c0..43d5ccc2 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -9,7 +9,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'share-all'); +$botUser->accessCheck('share-all'); if(isset($data['arg']) && $data['arg'] == 1) { $raid_id = $data['id']; diff --git a/mods/trainer.php b/mods/trainer.php index 92b71c4a..8264952f 100644 --- a/mods/trainer.php +++ b/mods/trainer.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'trainer'); +$botUser->accessCheck('trainer'); $user_id = $update['callback_query']['from']['id']; if($data['arg'] == 'a') { @@ -67,7 +67,7 @@ } // Display sharing options for admins and users with trainer-share permissions -if($botUser->accessCheck($update, 'trainer-share', true)) { +if($botUser->accessCheck('trainer-share', true)) { // Add sharing keys. $share_keys = []; $share_keys[] = universal_inner_key($keys, '0', 'trainer_add', '0', getTranslation('trainer_message_share')); diff --git a/mods/trainer_add.php b/mods/trainer_add.php index 5464423f..d6c81e3f 100644 --- a/mods/trainer_add.php +++ b/mods/trainer_add.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'trainer-share'); +$botUser->accessCheck('trainer-share'); // Init keys and chat list. $keys = []; diff --git a/mods/trainer_code.php b/mods/trainer_code.php index fa19de5a..0df92fc4 100644 --- a/mods/trainer_code.php +++ b/mods/trainer_code.php @@ -8,7 +8,7 @@ //debug_log($data); // Access check. -$botUser->accessCheck($update, 'trainer'); +$botUser->accessCheck('trainer'); // Mode and action $mode = $data['id']; diff --git a/mods/trainer_delete.php b/mods/trainer_delete.php index a3726a87..2e750f93 100644 --- a/mods/trainer_delete.php +++ b/mods/trainer_delete.php @@ -8,7 +8,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'trainer-delete'); +$botUser->accessCheck('trainer-delete'); // Init keys and chat list. $keys = []; diff --git a/mods/trainer_level.php b/mods/trainer_level.php index 6339213e..86836ded 100644 --- a/mods/trainer_level.php +++ b/mods/trainer_level.php @@ -8,7 +8,7 @@ //debug_log($data); // Access check. -$botUser->accessCheck($update, 'trainer'); +$botUser->accessCheck('trainer'); // Confirmation and level $confirm = $data['id']; diff --git a/mods/trainer_name.php b/mods/trainer_name.php index b23f094a..c95d06ce 100644 --- a/mods/trainer_name.php +++ b/mods/trainer_name.php @@ -8,7 +8,7 @@ //debug_log($data); // Access check. -$botUser->accessCheck($update, 'trainer'); +$botUser->accessCheck('trainer'); // Mode and action $mode = $data['id']; diff --git a/mods/trainer_share.php b/mods/trainer_share.php index 88000779..0913c70b 100644 --- a/mods/trainer_share.php +++ b/mods/trainer_share.php @@ -9,7 +9,7 @@ //debug_log($data); // Access check. -$botUser->accessCheck($update, 'trainer-share'); +$botUser->accessCheck('trainer-share'); // Get chat id. $chat = $data['arg']; diff --git a/mods/trainer_team.php b/mods/trainer_team.php index ba9d4aca..8d6a0379 100644 --- a/mods/trainer_team.php +++ b/mods/trainer_team.php @@ -8,7 +8,7 @@ //debug_log($data); // Access check. -$botUser->accessCheck($update, 'trainer'); +$botUser->accessCheck('trainer'); // Confirmation and level $confirm = $data['id']; diff --git a/mods/tutorial.php b/mods/tutorial.php index cbf46cee..4296787a 100644 --- a/mods/tutorial.php +++ b/mods/tutorial.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck($update, 'tutorial'); +$botUser->accessCheck('tutorial'); // Tutorial if(is_file(ROOT_PATH . '/config/tutorial.php')) { From 77db02c0bf1a6b40cbb649913941c0447997f92e Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 23 Nov 2022 20:59:09 +0200 Subject: [PATCH 161/367] Dependencies --- logic/alarm.php | 1 + logic/show_raid_poll.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/logic/alarm.php b/logic/alarm.php index bc65bfc2..0424e350 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -1,5 +1,6 @@ Date: Wed, 23 Nov 2022 21:51:06 +0200 Subject: [PATCH 162/367] User specific default gymareas Users can now set default gymarea via `/trainer` --- commands/gym.php | 3 ++- commands/listall.php | 3 ++- commands/start.php | 3 ++- commands/trainer.php | 10 ++++++- lang/language.json | 13 ++++++++++ logic/gymMenu.php | 6 +++++ mods/trainer.php | 10 ++++++- mods/trainerGymarea.php | 56 ++++++++++++++++++++++++++++++++++++++++ sql/pokemon-raid-bot.sql | 1 + sql/upgrade/6.sql | 3 ++- 10 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 mods/trainerGymarea.php diff --git a/commands/gym.php b/commands/gym.php index 267690f4..29850775 100644 --- a/commands/gym.php +++ b/commands/gym.php @@ -11,7 +11,8 @@ $botUser->accessCheck('gym-details'); // Set keys. -$keys_and_gymarea = gymMenu('gym', false, 1, false, $config->DEFAULT_GYM_AREA); +$gymarea = resolveDefaultGymarea($botUser->userId); +$keys_and_gymarea = gymMenu('gym', false, 1, false, $gymarea); $keys = $keys_and_gymarea['keys']; // Set message. diff --git a/commands/listall.php b/commands/listall.php index 2a5d7bbb..af8f8db4 100644 --- a/commands/listall.php +++ b/commands/listall.php @@ -11,7 +11,8 @@ if(!isset($skip_access) or $skip_access != true) $botUser->accessCheck('listall'); // Set keys. -$keys_and_gymarea = gymMenu('list', false, 1, false, $config->DEFAULT_GYM_AREA); +$gymarea = resolveDefaultGymarea($botUser->userId); +$keys_and_gymarea = gymMenu('list', false, 1, false, $gymarea); $keys = $keys_and_gymarea['keys']; // Set message. diff --git a/commands/start.php b/commands/start.php index 33b4a883..8463ca4b 100644 --- a/commands/start.php +++ b/commands/start.php @@ -47,7 +47,8 @@ // Get the keys if nothing was returned. if(!$keys) { - $keys_and_gymarea = gymMenu('create', false, 1, false, $config->DEFAULT_GYM_AREA); + $gymarea = resolveDefaultGymarea($botUser->userId); + $keys_and_gymarea = gymMenu('create', false, 1, false, $gymarea); $keys = $keys_and_gymarea['keys']; $msg = $keys_and_gymarea['gymareaTitle']; $addAbortKey = false; diff --git a/commands/trainer.php b/commands/trainer.php index 6538eae1..1a05597c 100644 --- a/commands/trainer.php +++ b/commands/trainer.php @@ -59,6 +59,14 @@ ] ]; } +if ($config->ENABLE_GYM_AREAS == true) { + $keys[] = [ + [ + 'text' => getTranslation('default_gymarea'), + 'callback_data' => formatCallbackData(['callbackAction' => 'trainerGymarea']) + ] + ]; +} // Check access. $access = $botUser->accessCheck('trainer-share', true); @@ -79,7 +87,7 @@ // Add abort key. $nav_keys = []; -$nav_keys[] = universal_inner_key($keys, '0', 'exit', '0', getTranslation('abort')); +$nav_keys[] = universal_inner_key($keys, '0', 'exit', '1', getTranslation('done')); // Get the inline key array. $keys[] = $nav_keys; diff --git a/lang/language.json b/lang/language.json index 9777b3c0..e06a0025 100644 --- a/lang/language.json +++ b/lang/language.json @@ -1910,6 +1910,19 @@ "FI": "Valitse salialue:", "ES": "Por favor, selecciona la zona del gimnasio:" }, + "default_gymarea": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Default gymarea", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Oletussalialue:", + "ES": "TRANSLATE" + }, "select_gym": { "NL": "Beginletter geselecteerd.", "DE": "Anfangsbuchstabe ausgewählt.", diff --git a/logic/gymMenu.php b/logic/gymMenu.php index 33050e47..6b41411b 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -6,6 +6,12 @@ 'gym' => 'gym_edit_details', ]; +function resolveDefaultGymarea($userId) { + global $config; + $q = my_query('SELECT gymarea FROM users WHERE user_id = ? LIMIT 1', [$userId]); + $userGymarea = $q->fetch()['gymarea']; + return $userGymarea !== NULL ? $userGymarea : $config->DEFAULT_GYM_AREA; +} /** * Raid gym first letter selection * @param string $buttonAction Action that is performed by gym letter keys diff --git a/mods/trainer.php b/mods/trainer.php index 8264952f..0234d4ef 100644 --- a/mods/trainer.php +++ b/mods/trainer.php @@ -65,6 +65,14 @@ ] ]; } +if ($config->ENABLE_GYM_AREAS == true) { + $keys[] = [ + [ + 'text' => getTranslation('default_gymarea'), + 'callback_data' => formatCallbackData(['callbackAction' => 'trainerGymarea']) + ] + ]; +} // Display sharing options for admins and users with trainer-share permissions if($botUser->accessCheck('trainer-share', true)) { @@ -81,7 +89,7 @@ } // Get the inline key array. -$keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); +$keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); // Answer callback. answerCallbackQuery($update['callback_query']['id'], 'OK'); diff --git a/mods/trainerGymarea.php b/mods/trainerGymarea.php new file mode 100644 index 00000000..62dbd106 --- /dev/null +++ b/mods/trainerGymarea.php @@ -0,0 +1,56 @@ +accessCheck('trainer'); + +$gymarea = $data['i'] ?? false; + +if($gymarea !== false) { + my_query('UPDATE users SET gymarea = ? WHERE user_id = ?',[$gymarea, $botUser->userId]); +}else { + $q = my_query('SELECT gymarea FROM users WHERE user_id = ? LIMIT 1', [$botUser->userId]); + $gymarea = $q->fetch()['gymarea']; +} + +// Init empty keys array. +$keys = []; + +$json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'), 1); +$gymareaName = ''; +foreach($json as $area) { + if($area['id'] == $gymarea) $gymareaName = $area['name']; + $keys[] = [ + 'text' => $area['name'], + 'callback_data' => formatCallbackData(['callbackAction' => 'trainerGymarea', 'i' => $area['id']]) + ]; +} +$keys = inline_key_array($keys, 2); +$keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData(['callbackAction' => 'trainer', 'arg' => 0]) + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit', 'arg' => 1]) + ] +]; +// Set message. +$msg = '' . getTranslation('trainerinfo_set_yours') . ''; + +$msg .= CR . CR . get_user($botUser->userId, true); +$msg .= '' . getTranslation('default_gymarea') . ': '; +$msg .= $gymareaName; + +// Answer callback. +answerCallbackQuery($update['callback_query']['id'], 'OK'); + +// Edit message. +edit_message($update, $msg, $keys, false); diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 7d9b6556..ee03bea6 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -153,6 +153,7 @@ CREATE TABLE `users` ( `lang_manual` TINYINT UNSIGNED NOT NULL DEFAULT 0, `tutorial` TINYINT(1) NOT NULL DEFAULT 0, `auto_alarm` TINYINT(1) UNSIGNED NULL DEFAULT 0, + `gymarea` TINYINT UNSIGNED NULL, `privileges` JSON NULL, PRIMARY KEY (`id`), UNIQUE KEY `i_userid` (`user_id`) diff --git a/sql/upgrade/6.sql b/sql/upgrade/6.sql index 872dafc4..9aee6de5 100644 --- a/sql/upgrade/6.sql +++ b/sql/upgrade/6.sql @@ -1 +1,2 @@ -ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `privileges` JSON NULL AFTER `auto_alarm`; +ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `gymarea` TINYINT UNSIGNED NULL AFTER `auto_alarm`; +ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `privileges` JSON NULL AFTER `gymarea`; From 7bc35b0de8104baecfd6e446ee6716cb5e2a90d2 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 24 Nov 2022 10:16:52 +0200 Subject: [PATCH 163/367] Added a submenu button for when there are more than six gymareas --- lang/language.json | 15 ++++++++++++++- logic/gymMenu.php | 7 +++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lang/language.json b/lang/language.json index e06a0025..0e60fff0 100644 --- a/lang/language.json +++ b/lang/language.json @@ -1920,7 +1920,20 @@ "NO": "TRANSLATE", "FR": "TRANSLATE", "PL": "TRANSLATE", - "FI": "Oletussalialue:", + "FI": "Oletussalialue", + "ES": "TRANSLATE" + }, + "gymareas": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Gymareas", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Salialueet", "ES": "TRANSLATE" }, "select_gym": { diff --git a/logic/gymMenu.php b/logic/gymMenu.php index 6b41411b..ff630295 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -130,6 +130,13 @@ function getGymareas($gymareaId, $stage, $buttonAction) { ]; } } + if(count($gymareaKeys) > 6 && $stage != 0) { + // If list of area buttons is getting too large, replace it with a key that opens a submenu + $gymareaKeys = [[ + 'text' => getTranslation('gymareas'), + 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'a' => $buttonAction, 'stage' => 0]) + ]]; + } $polygon_string = implode(',', $points); $query = count($points) > 0 ? 'AND ST_CONTAINS(ST_GEOMFROMTEXT(\'POLYGON(('.$polygon_string.'))\'), ST_GEOMFROMTEXT(CONCAT(\'POINT(\',lat,\' \',lon,\')\')))' : ''; return [$gymareaName, $gymareaKeys, $query]; From 657140393672de8a27dd31c47775a44132353fd8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 26 Nov 2022 19:52:32 +0200 Subject: [PATCH 164/367] Fixed pogoinfo imports --- mods/pogoinfo.php | 1 + mods/update_bosses.php | 1 + 2 files changed, 2 insertions(+) diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index 6d84ea57..25b368c4 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -126,6 +126,7 @@ // Get raid bosses for each raid level. foreach($tier_pokemon as $raid_id_form) { + if(!isset($raid_id_form['id'])) continue; $dex_id = $raid_id_form['id']; $dex_form = 0; if(isset($raid_id_form['temp_evolution_id'])) { diff --git a/mods/update_bosses.php b/mods/update_bosses.php index 71f85808..2ac49115 100644 --- a/mods/update_bosses.php +++ b/mods/update_bosses.php @@ -24,6 +24,7 @@ continue; } foreach($tier_pokemon as $raid_id_form) { + if(!isset($raid_id_form['id'])) continue; $dex_id = $raid_id_form['id']; $dex_form = 0; if(isset($raid_id_form['temp_evolution_id'])) { From 687ac1f0af804525d1c782fbe5dcf40c86b376f4 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 26 Nov 2022 21:11:56 +0200 Subject: [PATCH 165/367] Fixed pogoinfo imports --- mods/pogoinfo.php | 1 + mods/update_bosses.php | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index 1890d6a4..b086fc1b 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -128,6 +128,7 @@ // Get raid bosses for each raid level. foreach($tier_pokemon as $raid_id_form) { + if(!isset($raid_id_form['id'])) continue; $dex_id = $raid_id_form['id']; $dex_form = 0; if(isset($raid_id_form['temp_evolution_id'])) { diff --git a/mods/update_bosses.php b/mods/update_bosses.php index 5d6b0814..da3546d8 100644 --- a/mods/update_bosses.php +++ b/mods/update_bosses.php @@ -28,6 +28,7 @@ if(!in_array($tier,$get_levels)) continue; foreach($tier_pokemon as $raid_id_form) { + if(!isset($raid_id_form['id'])) continue; $dex_id = $raid_id_form['id']; $dex_form = 0; if(isset($raid_id_form['temp_evolution_id'])) { @@ -46,9 +47,9 @@ } $add_mons[] = [ - 'pokedex_id' => $dex_id, - 'pokemon_form_id' => $dex_form, - 'raid_level' => $tier, + 'pokedex_id' => $dex_id, + 'pokemon_form_id' => $dex_form, + 'raid_level' => $tier, ]; } } @@ -65,13 +66,13 @@ $count = count($add_mons); $start = false; $sql_values = ''; -if($count > 0) { - $sql_cols = implode(", ", array_keys($add_mons[0])); - for($i=0;$i<$count;$i++) { - if($i > 0) $sql_values .= ','; - $sql_values .= '(\'' . implode("', '", array_values($add_mons[$i])) . '\')'; - } - $sql = 'INSERT INTO raid_bosses (' . $sql_cols . ') VALUES ' . $sql_values . ';'; +if($count == 0) exit; + +$sql_cols = implode(", ", array_keys($add_mons[0])); +for($i=0;$i<$count;$i++) { + if($i > 0) $sql_values .= ','; + $sql_values .= '(\'' . implode("', '", array_values($add_mons[$i])) . '\')'; } +$sql = 'INSERT INTO raid_bosses (' . $sql_cols . ') VALUES ' . $sql_values . ';'; my_query($sql); From 46e231bd381c3e6a7d93843613b8d433ef843893 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 26 Nov 2022 23:02:13 +0200 Subject: [PATCH 166/367] Simplified pokebattler and pogoinfo import scripts' code --- mods/pogoinfo.php | 428 ++++++++++++++++----------------------- mods/pokebattler.php | 471 ++++++++++++++++++------------------------- 2 files changed, 366 insertions(+), 533 deletions(-) diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index b086fc1b..bff804f3 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -12,12 +12,8 @@ // Levels available for import $levels = array('6', '5', '3', '1'); - -// Get raid levels -$id = $data['id']; - -// Exclude pokemon -$arg = $data['arg']; +$id = $data['rl'] ?? 0; +$action = $data['a'] ?? ''; // Raid level selection if($id == 0) { @@ -31,314 +27,232 @@ // All raid level keys. $keys[][] = array( 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => RAID_LEVEL_ALL . ':pogoinfo:ex#0,0,0' + 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => RAID_LEVEL_ALL]) ); // Add key for each raid level foreach($levels as $l) { $keys[][] = array( 'text' => getTranslation($l . 'stars'), - 'callback_data' => $l . ':pogoinfo:ex#0,0,0' + 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => $l]) ); } $keys[][] = array( 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), - 'callback_data' => '3,1:pogoinfo:ex#0,0,0' + 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => '1,3']) ); // Add back and abort buttons $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:pokedex_import:0' + 'callback_data' => formatCallbackData(['callbackAction' => 'pokedex_import']) ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) ] ]; -} else if($id > 0) { - // Set message and init message to exclude raid bosses. - $msg = '' . getTranslation('import') . SP . '(ccev pogoinfo)' . '' . CR . CR; - $ex_msg = ''; - - // Get pogoinfo data. - debug_log('Getting raid bosses from pogoinfo repository now...'); - $link = 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/raids.json'; - $data = curl_get_contents($link); - $data = json_decode($data,true); - - // All raid levels? - if($id == RAID_LEVEL_ALL) { - $get_levels = $levels; - $clear = "'6','5','3','1'"; - } else { - $get_levels = explode(",", $id); - $clear = $id; - } + // Callback message string. + $callback_response = 'OK'; - // Prefix for exclusion. - $prefix = 'ex#'; - - // New request - if($arg == 'ex#0,0,0') { - $poke1 = 0; - $poke2 = 0; - $poke3 = 0; - - // Get raid bosses to exclude. - } else if(strpos($arg, 'ex#') === 0 || strpos($arg, 'save#') === 0) { - $poke_ids = explode('#', $arg); - $poke_ids = explode(',', $poke_ids[1]); - $poke1 = $poke_ids[0]; - $poke2 = $poke_ids[1]; - $poke3 = $poke_ids[2]; - debug_log('Excluded raid boss #1: ' . $poke1); - debug_log('Excluded raid boss #2: ' . $poke2); - debug_log('Excluded raid boss #3: ' . $poke3); - } + // Telegram JSON array. + $tg_json = array(); - // Clear old raid bosses. - if(strpos($arg, 'save#') === 0) { - require_once(LOGIC_PATH . '/disable_raid_level.php'); - debug_log('Disabling old raid bosses for levels: '. $clear); - disable_raid_level($clear); - } + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - // Init empty keys array. - $keys = []; + // Edit message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); - // Raid tier array - debug_log('Processing the following raid levels:'); - debug_log($get_levels); + // Telegram multicurl request. + curl_json_multi_request($tg_json); + exit; +} +// Set message and init message to exclude raid bosses. +$msg = '' . getTranslation('import') . SP . '(ccev pogoinfo)' . '' . CR . CR; +$ex_msg = ''; + +// Get pogoinfo data. +debug_log('Getting raid bosses from pogoinfo repository now...'); +$link = 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/raids.json'; +$raiddata = curl_get_contents($link); +$raiddata = json_decode($raiddata,true); + +// All raid levels? +if($id == RAID_LEVEL_ALL) { + $get_levels = $levels; + $clear = "'6','5','3','1'"; +} else { + $get_levels = explode(",", $id); + $clear = $id; +} - // Process raid tier(s) - debug_log('Processing received ccev pogoinfo raid bosses for each raid level'); - foreach($data as $tier => $tier_pokemon) { - // Process raid level? - if(!in_array($tier,$get_levels)) { - continue; - } - // Raid level and message. - $msg .= '' . getTranslation('pokedex_raid_level') . SP . $tier . ':' . CR; - - // Count raid bosses and add raid egg later if 2 or more bosses. - $bosscount = 0; - - // Get raid bosses for each raid level. - foreach($tier_pokemon as $raid_id_form) { - if(!isset($raid_id_form['id'])) continue; - $dex_id = $raid_id_form['id']; - $dex_form = 0; - if(isset($raid_id_form['temp_evolution_id'])) { - $dex_form = '-'.$raid_id_form['temp_evolution_id']; - }elseif(isset($raid_id_form['form'])) { - $dex_form = $raid_id_form['form']; - }else { - // If no form id is provided, let's check our db for normal form - $query_form_id = my_query("SELECT pokemon_form_id FROM pokemon WHERE pokedex_id='".$dex_id."' and pokemon_form_name='normal' LIMIT 1"); - if($query_form_id->rowCount() == 0) { - // If normal form doesn't exist in our db, use the smallest form id as a fallback - $query_form_id = my_query("SELECT min(pokemon_form_id) as pokemon_form_id FROM pokemon WHERE pokedex_id='".$dex_id."' LIMIT 1"); - } - $result = $query_form_id->fetch(); - $dex_form = $result['pokemon_form_id']; - } +// New request +$exclusions = isset($data['e']) ? explode('#', $data['e']) : []; +if(!empty($exclusions[0])) { + debug_log('Excluded raid bosses: ' . implode(', ', $exclusions)); +} - $pokemon_arg = $dex_id . $dex_form; +// Clear old raid bosses. +if($action == 's') { + require_once(LOGIC_PATH . '/disable_raid_level.php'); + debug_log('Disabling old raid bosses for levels: '. $clear); + disable_raid_level($clear); +} - // Get ID and form name used internally. - $local_pokemon = get_local_pokemon_name($dex_id, $dex_form); - debug_log('Got this pokemon dex id: ' . $dex_id); - debug_log('Got this pokemon dex form: ' . $dex_form); - debug_log('Got this local pokemon name and form: ' . $local_pokemon); +// Raid tier array +debug_log('Processing the following raid levels:'); +debug_log($get_levels); - // Make sure we received a valid dex id. - if(!is_numeric($dex_id) || $dex_id == 0) { - info_log('Failed to get a valid pokemon dex id: '. $dex_id .' Continuing with next raid boss...'); - continue; +// Process raid tier(s) +debug_log('Processing received ccev pogoinfo raid bosses for each raid level'); +foreach($raiddata as $tier => $tier_pokemon) { + // Process raid level? + if(!in_array($tier,$get_levels)) { + continue; + } + // Raid level and message. + $msg .= '' . getTranslation('pokedex_raid_level') . SP . $tier . ':' . CR; + + // Count raid bosses and add raid egg later if 2 or more bosses. + $bosscount = 0; + + // Get raid bosses for each raid level. + foreach($tier_pokemon as $raid_id_form) { + if(!isset($raid_id_form['id'])) continue; + $dex_id = $raid_id_form['id']; + $dex_form = 0; + if(isset($raid_id_form['temp_evolution_id'])) { + $dex_form = '-'.$raid_id_form['temp_evolution_id']; + }elseif(isset($raid_id_form['form'])) { + $dex_form = $raid_id_form['form']; + }else { + // If no form id is provided, let's check our db for normal form + $query_form_id = my_query('SELECT pokemon_form_id FROM pokemon WHERE pokedex_id = ? and pokemon_form_name = \'normal\' LIMIT 1', [$dex_id]); + if($query_form_id->rowCount() == 0) { + // If normal form doesn't exist in our db, use the smallest form id as a fallback + $query_form_id = my_query('SELECT min(pokemon_form_id) as pokemon_form_id FROM pokemon WHERE pokedex_id = ? LIMIT 1', [$dex_id]); } + $result = $query_form_id->fetch(); + $dex_form = $result['pokemon_form_id']; + } - // Build new arg. - // Exclude 1 pokemon - if($poke1 == '0') { - $new_arg = $prefix . $pokemon_arg . ',0,0'; - - // Exclude 2 pokemon - } else if ($poke1 != '0' && $poke2 == '0') { - $new_arg = $prefix . $poke1 . ',' . $pokemon_arg . ',0'; + $pokemon_arg = $dex_id . $dex_form; - // Exclude 3 pokemon - } else if ($poke1 != '0' && $poke2 != '0' && $poke3 == '0') { - $new_arg = $prefix . $poke1 . ',' . $poke2 . ',' . $pokemon_arg; - } + // Make sure we received a valid dex id. + if(!is_numeric($dex_id) || $dex_id == 0) { + info_log('Failed to get a valid pokemon dex id: '. $dex_id .' Continuing with next raid boss...'); + continue; + } - // Exclude pokemon? - if($pokemon_arg == $poke1 || $pokemon_arg == $poke2 || $pokemon_arg == $poke3) { - // Add pokemon to exclude message. - $ex_msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - - } else { - // Add pokemon to message. - $msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - - // Counter. - $bosscount = $bosscount + 1; - - // Save to database? - if(strpos($arg, 'save#') === 0) { - // Update raid level of pokemon - my_query(' - INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) - VALUES (?, ?, ?) - ', [$dex_id, $dex_form, $tier] - ); - continue; - } - - // Are 3 raid bosses already selected? - if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { - // Add raid level to pokemon name - if($id == RAID_LEVEL_ALL) { - // Add key to exclude pokemon from import. - $keys[] = array( - 'text' => '[' . ($tier) . ']' . SP . $local_pokemon, - 'callback_data' => $id . ':pogoinfo:' . $new_arg - ); - } else { - // Add key to exclude pokemon from import. - $keys[] = array( - 'text' => $local_pokemon, - 'callback_data' => $id . ':pogoinfo:' . $new_arg - ); - } - } - } + // Save to database? + if($action == 's') { + // Update raid level of pokemon + my_query(' + INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) + VALUES (?, ?, ?) + ', [$dex_id, $dex_form, $tier] + ); } - $msg .= CR; - } + // Get ID and form name used internally. + $local_pokemon = get_local_pokemon_name($dex_id, $dex_form); + debug_log('Got this pokemon dex id: ' . $dex_id); + debug_log('Got this pokemon dex form: ' . $dex_form); + debug_log('Got this local pokemon name and form: ' . $local_pokemon); - // Get the inline key array. - $keys = inline_key_array($keys, 2); - - // Saved raid bosses? - if(strpos($arg, 'save#') === 0) { - // Get all pokemon with raid levels from database. - $rs = my_query(' - SELECT raid_bosses.pokedex_id, raid_bosses.pokemon_form_id, raid_bosses.raid_level - FROM raid_bosses - LEFT JOIN pokemon - ON raid_bosses.pokedex_id = pokemon.pokedex_id - AND raid_bosses.pokemon_form_id = pokemon.pokemon_form_id - WHERE raid_bosses.raid_level IN (' . $clear . ') - AND raid_bosses.scheduled = 0 - ORDER BY raid_bosses.raid_level, raid_bosses.pokedex_id, pokemon.pokemon_form_name != \'normal\', pokemon.pokemon_form_name, raid_bosses.pokemon_form_id - '); - - // Init empty keys array. - $keys = []; - - // Init message and previous. - $msg = 'Pogoinfo' . SP . '—' . SP . getTranslation('import_done') . '' . CR; - $previous = ''; - - // Build the message - while ($pokemon = $rs->fetch()) { - // Set current level - $current = $pokemon['raid_level']; - - // Add header for each raid level - if($previous != $current) { - $msg .= CR . '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; - } + // Exclude pokemon? + if(in_array($pokemon_arg, $exclusions)) { + // Add pokemon to exclude message. + $ex_msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - // Add pokemon with id and name. - $dex_id = $pokemon['pokedex_id']; - $pokemon_form_id = $pokemon['pokemon_form_id']; - $poke_name = get_local_pokemon_name($dex_id, $pokemon_form_id); - $msg .= $poke_name . ' (#' . $dex_id . ')' . CR; + } else { + // Add pokemon to message. + $msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; + + // Counter. + $bosscount = $bosscount + 1; - // Add button to edit pokemon. + // Are 3 raid bosses already selected? + if(count($exclusions) == 3) continue; + + $keyText = $local_pokemon; if($id == RAID_LEVEL_ALL) { - $keys[] = array( - 'text' => '[' . $pokemon['raid_level'] . ']' . SP . $poke_name, - 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' - ); - } else { - $keys[] = array( - 'text' => $poke_name, - 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' - ); + $keyText = '[' . ($tier) . ']' . SP . $local_pokemon; } - - // Prepare next run. - $previous = $current; + $e = $exclusions; + $e[] = $pokemon_arg; + $keyAction = ($action == 's') ? + ['callbackAction' => 'pokedex_edit_pokemon', 'id' => $dex_id . "-" . $dex_form, 'arg' => ''] : + ['callbackAction' => 'pogoinfo', 'rl' => $id, 'e' => implode('#', $e)]; + // Add key + $keys[] = array( + 'text' => $keyText, + 'callback_data' => formatCallbackData($keyAction) + ); } + } + $msg .= CR; +} - // Inline key array. - $keys = inline_key_array($keys, 2); +// Get the inline key array. +$keys = inline_key_array($keys, 2); - // Navigation keys. - $nav_keys = []; +// Saved raid bosses? +if($action == 's') { + $msg .= '' . getTranslation('import_done') . '' . CR; + $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; - // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ); + // Abort button. + $nav_keys = universal_key([], 0, 'exit', 0, getTranslation('done')); - // Keys. - $nav_keys = inline_key_array($nav_keys, 1); - $keys = array_merge($keys, $nav_keys); +// User is still on the import. +} else { + $msg .= '' . getTranslation('excluded_raid_bosses') . '' . CR; + $msg .= (empty($ex_msg) ? (getTranslation('none') . CR) : $ex_msg) . CR; - // User is still on the import. + // Import or select more pokemon to exclude? + if(!isset($exclusions[2])) { + $msg .= '' . getTranslation('exclude_raid_boss_or_import') . ':'; } else { - $msg .= '' . getTranslation('excluded_raid_bosses') . '' . CR; - $msg .= (empty($ex_msg) ? (getTranslation('none') . CR) : $ex_msg) . CR; + $msg .= '' . getTranslation('import_raid_bosses') . ''; + } - // Import or select more pokemon to exclude? - if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { - $msg .= '' . getTranslation('exclude_raid_boss_or_import') . ':'; - } else { - $msg .= '' . getTranslation('import_raid_bosses') . ''; - } + // Navigation keys. + $nav_keys = []; - // Navigation keys. - $nav_keys = []; + // Back button. + $nav_keys[] = array( + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo']) + ); - // Back button. - $nav_keys[] = array( - 'text' => getTranslation('back'), - 'callback_data' => '0:pogoinfo:0' - ); + // Save button. + $nav_keys[] = array( + 'text' => EMOJI_DISK, + 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]) + ); - // Save button. + // Reset button. + if(isset($exclusions[0])) { $nav_keys[] = array( - 'text' => EMOJI_DISK, - 'callback_data' => $id . ':pogoinfo:save#' . $poke1 . ',' . $poke2 . ',' . $poke3 + 'text' => getTranslation('reset'), + 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => $id]) ); + } - // Reset button. - if($poke1 != 0) { - $nav_keys[] = array( - 'text' => getTranslation('reset'), - 'callback_data' => $id . ':pogoinfo:ex#0,0,0' - ); - } - - // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ); + // Abort button. + $nav_keys[] = array( + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ); - // Get the inline key array and merge keys. - $nav_keys = inline_key_array($nav_keys, 2); - $keys = array_merge($keys, $nav_keys); - } + // Get the inline key array and merge keys. + $nav_keys = inline_key_array($nav_keys, 2); } +$keys = array_merge($keys, $nav_keys); // Callback message string. $callback_response = 'OK'; diff --git a/mods/pokebattler.php b/mods/pokebattler.php index 459f0d39..cb758eca 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -12,10 +12,8 @@ include(LOGIC_PATH . '/resolve_boss_name_to_ids.php'); // Get raid levels -$id = $data['id']; - -// Exclude pokemon -$arg = $data['arg']; +$id = $data['rl'] ?? 0; +$action = $data['a'] ?? ''; // Raid level selection if($id == 0) { @@ -29,332 +27,253 @@ // All raid level keys. $keys[][] = array( 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => implode(",", $pokebattler_levels) . ':pokebattler:ex#0,0,0' + 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => implode(",", $pokebattler_levels)]) ); // Add key for each raid level foreach($pokebattler_levels as $l) { $keys[][] = array( 'text' => getTranslation($l . 'stars'), - 'callback_data' => $l . ':pokebattler:ex#0,0,0' + 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => $l]) ); } $keys[][] = array( 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), - 'callback_data' => '3,1:pokebattler:ex#0,0,0' + 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => '1,3']) ); // Add back and abort buttons $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:pokedex_import:0' + 'callback_data' => formatCallbackData(['callbackAction' => 'pokedex_import']) ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) ] ]; + // Callback message string. + $callback_response = 'OK'; -} else if($id > 0) { - // Set message and init message to exclude raid bosses. - $msg = '' . getTranslation('import') . SP . '(Pokebattler)' . '' . CR . CR; - $ex_msg = ''; - - // Get pokebattler data. - debug_log('Getting raid bosses from pokebattler.com now...'); - $link = 'https://fight.pokebattler.com/raids'; - $pb_data = curl_get_contents($link); - $pb_data = json_decode($pb_data,true); - - $get_levels = explode(",", $id); - $clear = $id; - - // Prefix for exclusion. - $prefix = 'ex#'; - - // New request - if($arg == 'ex#0,0,0') { - $poke1 = 0; - $poke2 = 0; - $poke3 = 0; - - // Get raid bosses to exclude. - } else if(strpos($arg, 'ex#') === 0 || strpos($arg, 'save#') === 0) { - $poke_ids = explode('#', $arg); - $poke_ids = explode(',', $poke_ids[1]); - $poke1 = $poke_ids[0]; - $poke2 = $poke_ids[1]; - $poke3 = $poke_ids[2]; - debug_log('Excluded raid boss #1: ' . $poke1); - debug_log('Excluded raid boss #2: ' . $poke2); - debug_log('Excluded raid boss #3: ' . $poke3); - } + // Telegram JSON array. + $tg_json = array(); - // Clear old raid bosses. - if(strpos($arg, 'save#') === 0) { - require_once(LOGIC_PATH . '/disable_raid_level.php'); - debug_log('Disabling old raid bosses for levels: '. $clear); - disable_raid_level($clear); - } + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - // Init empty keys array. - $keys = []; + // Edit message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); + + // Telegram multicurl request. + curl_json_multi_request($tg_json); + exit; +} +// Set message and init message to exclude raid bosses. +$msg = '' . getTranslation('import') . SP . '(Pokebattler)' . '' . CR . CR; +$ex_msg = ''; + +// Get pokebattler data. +debug_log('Getting raid bosses from pokebattler.com now...'); +$link = 'https://fight.pokebattler.com/raids'; +$pb_data = curl_get_contents($link); +$pb_data = json_decode($pb_data,true); + +$get_levels = explode(',', $id); +$clear = $id; + +// New request +$exclusions = isset($data['e']) ? explode('#', $data['e']) : []; +if(!empty($exclusions[0])) { + debug_log('Excluded raid bosses: ' . implode(', ', $exclusions)); +} + +// Clear old raid bosses. +if($action == 's') { + require_once(LOGIC_PATH . '/disable_raid_level.php'); + debug_log('Disabling old raid bosses for levels: '. $clear); + disable_raid_level($clear); +} - // Raid tier array - debug_log('Processing the following raid levels:'); - $raidlevels = array(); - foreach($get_levels as $level) { - $raidlevels[] = 'RAID_LEVEL_' . $pokebattler_level_map[$level]; +// Init empty keys array. +$keys = []; + +// Raid tier array +debug_log('Processing the following raid levels:'); +$raidlevels = array(); +foreach($get_levels as $level) { + $raidlevels[] = 'RAID_LEVEL_' . $pokebattler_level_map[$level]; +} +debug_log($raidlevels); +$levels_processed = $bosses = []; +// Process breaking news section +$now = new DateTime('now', new DateTimeZone($config->TIMEZONE)); +$ph = new dateTimeZone('America/Los_Angeles'); +foreach($pb_data['breakingNews'] as $news) { + if($news['type'] != 'RAID_TYPE_RAID') continue; + + $rl = str_replace('RAID_LEVEL_','', $news['tier']); + $raid_level_id = array_search($rl, $pokebattler_level_map); + $starttime = new DateTime("@".substr($news['startDate'],0,10)); + $endtime = new DateTime("@".substr($news['endDate'],0,10)); + $starttime->setTimezone($ph); + $endtime->setTimezone($ph); + + if(in_array($news['tier'], $raidlevels) && $starttime->getTimestamp() < $now->getTimestamp() && $endtime->getTimestamp() > $now->getTimestamp()) { + $levels_processed[$raid_level_id] = $news['tier']; + $dex_id_form = resolve_boss_name_to_ids($news['pokemon']); + $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $news['shiny']]; } - debug_log($raidlevels); - $levels_processed = []; - $bosses = []; - // Process breaking news section - $now = new DateTime('now', new DateTimeZone($config->TIMEZONE)); - $ph = new dateTimeZone('America/Phoenix'); - foreach($pb_data['breakingNews'] as $news) { - if($news['type'] == 'RAID_TYPE_RAID') { - $rl = str_replace('RAID_LEVEL_','', $news['tier']); - $raid_level_id = array_search($rl, $pokebattler_level_map); - $starttime = new DateTime("@".substr($news['startDate'],0,10)); - $endtime = new DateTime("@".substr($news['endDate'],0,10)); - $starttime->setTimezone($ph); - $endtime->setTimezone($ph); - - if(in_array($news['tier'], $raidlevels) && $starttime->getTimestamp() < $now->getTimestamp() && $endtime->getTimestamp() > $now->getTimestamp()) { - $levels_processed[$raid_level_id] = $news['tier']; - $dex_id_form = resolve_boss_name_to_ids($news['pokemon']); - $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $news['shiny']]; - } - } +} +// Process raid tier(s) +debug_log('Processing received pokebattler raid bosses for each raid level'); +foreach($pb_data['tiers'] as $tier) { + $rl = str_replace('RAID_LEVEL_','', $tier['tier']); + $raid_level_id = array_search($rl, $pokebattler_level_map); + // Skip this raid level if the boss data was already collected from breaking news or raid level doesn't interest us + if(!in_array($tier['tier'], $raidlevels) or isset($levels_processed[$raid_level_id])) { + continue; } - // Process raid tier(s) - debug_log('Processing received pokebattler raid bosses for each raid level'); - foreach($pb_data['tiers'] as $tier) { - $rl = str_replace('RAID_LEVEL_','', $tier['tier']); - $raid_level_id = array_search($rl, $pokebattler_level_map); - // Skip this raid level if the boss data was already collected from breaking news or raid level doesn't interest us - if(!in_array($tier['tier'], $raidlevels) or isset($levels_processed[$raid_level_id])) { + // Get raid bosses for each raid level. + foreach($tier['raids'] as $raid) { + // Raid level + if ($raid['id'] == 0) { + debug_log('Skipping raid boss ' . $raid['pokemon'] . ' since it has no id, it\'s likely in the future!'); continue; } - // Get raid bosses for each raid level. - foreach($tier['raids'] as $raid) { - // Raid level - if ($raid['id'] == 0) { - debug_log("Skipping raid boss {$raid['pokemon']} since it has no id, it's likely in the future!"); - continue; - } - $dex_id_form = resolve_boss_name_to_ids($raid['pokemon']); - $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $raid['shiny']]; - } + $dex_id_form = resolve_boss_name_to_ids($raid['pokemon']); + $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $raid['shiny']]; } +} - foreach($get_levels as $raid_level_id) { - if($raid_level_id > 5) $raid_level_text = getTranslation($raid_level_id . 'stars_short'); else $raid_level_text = $raid_level_id; - if(!isset($bosses[$raid_level_id])) continue; - $msg .= '' . getTranslation('pokedex_raid_level') . SP . $raid_level_text . ':' . CR; - foreach($bosses[$raid_level_id] as $dex_id_form) { - [$dex_id, $dex_form] = $dex_id_form['id']; - $pokemon_arg = $dex_id . (($dex_form != 'normal') ? ('-' . $dex_form) : '-0'); - $local_pokemon = get_local_pokemon_name($dex_id, $dex_form); - debug_log('Got this pokemon dex id: ' . $dex_id); - debug_log('Got this pokemon dex form: ' . $dex_form); - debug_log('Got this local pokemon name and form: ' . $local_pokemon); - - // Make sure we received a valid dex id. - if(!is_numeric($dex_id) || $dex_id == 0) { - info_log('Failed to get a valid pokemon dex id: '. $dex_id .' Continuing with next raid boss...'); - continue; - } - - // Build new arg. - // Exclude 1 pokemon - if($poke1 == '0') { - $new_arg = $prefix . $pokemon_arg . ',0,0'; +foreach($get_levels as $raid_level_id) { + if(!isset($bosses[$raid_level_id])) continue; + if($raid_level_id > 5) $raid_level_text = getTranslation($raid_level_id . 'stars_short'); else $raid_level_text = $raid_level_id; + $msg .= '' . getTranslation('pokedex_raid_level') . SP . $raid_level_text . ':' . CR; + foreach($bosses[$raid_level_id] as $dex_id_form) { + [$dex_id, $dex_form] = $dex_id_form['id']; + $pokemon_arg = $dex_id . (($dex_form != 'normal') ? ('-' . $dex_form) : '-0'); + $local_pokemon = get_local_pokemon_name($dex_id, $dex_form); + debug_log('Got this pokemon dex id: ' . $dex_id); + debug_log('Got this pokemon dex form: ' . $dex_form); + debug_log('Got this local pokemon name and form: ' . $local_pokemon); + + // Make sure we received a valid dex id. + if(!is_numeric($dex_id) || $dex_id == 0) { + info_log('Failed to get a valid pokemon dex id: '. $dex_id .' Continuing with next raid boss...'); + continue; + } - // Exclude 2 pokemon - } else if ($poke1 != '0' && $poke2 == '0') { - $new_arg = $prefix . $poke1 . ',' . $pokemon_arg . ',0'; + // Save to database? + if($action == 's') { + // Update raid level of pokemon + my_query(' + UPDATE pokemon + SET shiny = ? + WHERE pokedex_id = ? + AND pokemon_form_id = ? + ', [$dex_id_form['shiny'], $dex_id, $dex_form] + ); + my_query(' + INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) + VALUES (?, ?, ?) + ', [$dex_id, $dex_form, $raid_level_id] + ); + } - // Exclude 3 pokemon - } else if ($poke1 != '0' && $poke2 != '0' && $poke3 == '0') { - $new_arg = $prefix . $poke1 . ',' . $poke2 . ',' . $pokemon_arg; - } + // Exclude pokemon? + if(in_array($pokemon_arg, $exclusions)) { + // Add pokemon to exclude message. + $ex_msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - // Exclude pokemon? - if($pokemon_arg == $poke1 || $pokemon_arg == $poke2 || $pokemon_arg == $poke3) { - // Add pokemon to exclude message. - $ex_msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - - } else { - // Add pokemon to message. - $msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - - // Shiny? - $shiny = 0; - if($dex_id_form['shiny'] == 'true') { - $shiny = 1; - } - - // Save to database? - if(strpos($arg, 'save#') === 0) { - // Update raid level of pokemon - my_query(' - UPDATE pokemon - SET shiny = ? - WHERE pokedex_id = ? - AND pokemon_form_id = ? - ', [$shiny, $dex_id, $dex_form] - ); - my_query(' - INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) - VALUES (?, ?, ?) - ', [$dex_id, $dex_form, $raid_level_id] - ); - continue; - } - - // Are 3 raid bosses already selected? - if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { - // Add key to exclude pokemon from import. - $button_text_prefix = ''; - if($id == implode(",", $pokebattler_levels)) { - // Add raid level to pokemon name - $button_text_prefix = '[' . ($raid_level_text) . ']'; - } - $keys[] = array( - 'text' => $button_text_prefix . SP . $local_pokemon, - 'callback_data' => $id . ':pokebattler:' . $new_arg - ); - } - } - } - $msg .= CR; - } + } else { + // Add pokemon to message. + $msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - // Get the inline key array. - $keys = inline_key_array($keys, 2); - - // Saved raid bosses? - if(strpos($arg, 'save#') === 0) { - // Get all pokemon with raid levels from database. - $rs = my_query(' - SELECT raid_bosses.pokedex_id, raid_bosses.pokemon_form_id, raid_bosses.raid_level - FROM raid_bosses - LEFT JOIN pokemon - ON raid_bosses.pokedex_id = pokemon.pokedex_id - AND raid_bosses.pokemon_form_id = pokemon.pokemon_form_id - WHERE raid_bosses.raid_level IN (' . $clear . ') - AND raid_bosses.scheduled = 0 - ORDER BY raid_bosses.raid_level, raid_bosses.pokedex_id, pokemon.pokemon_form_name != \'normal\', pokemon.pokemon_form_name, raid_bosses.pokemon_form_id - '); - - // Init empty keys array. - $keys = []; - - // Init message and previous. - $msg = 'Pokebattler' . SP . '—' . SP . getTranslation('import_done') . '' . CR; - $previous = ''; - - // Build the message - while ($pokemon = $rs->fetch()) { - // Set current level - $current = $pokemon['raid_level']; - - // Add header for each raid level - if($previous != $current) { - $msg .= CR . '' . getTranslation($pokemon['raid_level'] . 'stars') . ':' . CR ; + // Shiny? + $shiny = 0; + if($dex_id_form['shiny'] == 'true') { + $shiny = 1; } - // Add pokemon with id and name. - $dex_id = $pokemon['pokedex_id']; - $pokemon_form_id = $pokemon['pokemon_form_id']; - $poke_name = get_local_pokemon_name($dex_id, $pokemon_form_id); - $msg .= $poke_name . ' (#' . $dex_id . ')' . CR; - - // Add button to edit pokemon. - if($id == RAID_LEVEL_ALL) { - $keys[] = array( - 'text' => '[' . $pokemon['raid_level'] . ']' . SP . $poke_name, - 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' - ); - } else { - $keys[] = array( - 'text' => $poke_name, - 'callback_data' => $dex_id . "-" . $pokemon_form_id . ':pokedex_edit_pokemon:0' - ); + // Add key to exclude pokemon from import. + $button_text_prefix = ''; + if($id == implode(",", $pokebattler_levels)) { + // Add raid level to pokemon name + $button_text_prefix = '[' . ($raid_level_text) . ']'; } - - // Prepare next run. - $previous = $current; + $e = $exclusions; + $e[] = $pokemon_arg; + // Are 3 raid bosses already selected? + if(count($exclusions) == 3) continue; + $keyAction = ($action == 's') ? + ['callbackAction' => 'pokedex_edit_pokemon', 'id' => $dex_id . "-" . $dex_form, 'arg' => ''] : + ['callbackAction' => 'pokebattler', 'rl' => $id, 'e' => implode('#', $e)]; + $keys[] = array( + 'text' => $button_text_prefix . SP . $local_pokemon, + 'callback_data' => formatCallbackData($keyAction) + ); } + } + $msg .= CR; +} - // Message. - $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; - - // Inline key array. - $keys = inline_key_array($keys, 2); +// Get the inline key array. +$keys = inline_key_array($keys, 2); - // Navigation keys. - $nav_keys = []; +// Saved raid bosses? +if($action == 's') { + $msg .= '' . getTranslation('import_done') . '' . CR; + $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; - // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' - ); + // Abort button. + $nav_keys = universal_key([], 0, 'exit', 0, getTranslation('done')); - // Keys. - $nav_keys = inline_key_array($nav_keys, 1); - $keys = array_merge($keys, $nav_keys); +// User is still on the import. +} else { + $msg .= '' . getTranslation('excluded_raid_bosses') . '' . CR; + $msg .= (empty($ex_msg) ? (getTranslation('none') . CR) : $ex_msg) . CR; - // User is still on the import. + // Import or select more pokemon to exclude? + if(!isset($exclusions[2])) { + $msg .= '' . getTranslation('exclude_raid_boss_or_import') . ':'; } else { - $msg .= '' . getTranslation('excluded_raid_bosses') . '' . CR; - $msg .= (empty($ex_msg) ? (getTranslation('none') . CR) : $ex_msg) . CR; + $msg .= '' . getTranslation('import_raid_bosses') . ''; + } - // Import or select more pokemon to exclude? - if($poke1 == '0' || $poke2 == '0' || $poke3 == '0') { - $msg .= '' . getTranslation('exclude_raid_boss_or_import') . ':'; - } else { - $msg .= '' . getTranslation('import_raid_bosses') . ''; - } + // Navigation keys. + $nav_keys = []; - // Navigation keys. - $nav_keys = []; + // Back button. + $nav_keys[] = array( + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler']) + ); - // Back button. - $nav_keys[] = array( - 'text' => getTranslation('back'), - 'callback_data' => '0:pokebattler:0' - ); + // Save button. + $nav_keys[] = array( + 'text' => EMOJI_DISK, + 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]) + ); - // Save button. + // Reset button. + if(isset($exclusions[0])) { $nav_keys[] = array( - 'text' => EMOJI_DISK, - 'callback_data' => $id . ':pokebattler:save#' . $poke1 . ',' . $poke2 . ',' . $poke3 + 'text' => getTranslation('reset'), + 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => $id]) ); + } - // Reset button. - if($poke1 != 0) { - $nav_keys[] = array( - 'text' => getTranslation('reset'), - 'callback_data' => $id . ':pokebattler:ex#0,0,0' - ); - } - - // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ); + // Abort button. + $nav_keys[] = array( + 'text' => getTranslation('abort'), + 'callback_data' => '0:exit:0' + ); - // Get the inline key array and merge keys. - $nav_keys = inline_key_array($nav_keys, 2); - $keys = array_merge($keys, $nav_keys); - } + // Get the inline key array and merge keys. + $nav_keys = inline_key_array($nav_keys, 2); } +$keys = array_merge($keys, $nav_keys); // Callback message string. $callback_response = 'OK'; From 1818bd72e5ddccc7fba9aa5809c80308bf151c53 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 26 Nov 2022 23:05:20 +0200 Subject: [PATCH 167/367] Correct shiny format --- mods/pokebattler.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mods/pokebattler.php b/mods/pokebattler.php index cb758eca..80711fc6 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -166,13 +166,15 @@ // Save to database? if($action == 's') { + // Shiny? + $shiny = ($dex_id_form['shiny'] == 'true') ? 1 : 0; // Update raid level of pokemon my_query(' UPDATE pokemon SET shiny = ? WHERE pokedex_id = ? AND pokemon_form_id = ? - ', [$dex_id_form['shiny'], $dex_id, $dex_form] + ', [$shiny, $dex_id, $dex_form] ); my_query(' INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) @@ -190,12 +192,6 @@ // Add pokemon to message. $msg .= $local_pokemon . SP . '(#' . $dex_id . ')' . CR; - // Shiny? - $shiny = 0; - if($dex_id_form['shiny'] == 'true') { - $shiny = 1; - } - // Add key to exclude pokemon from import. $button_text_prefix = ''; if($id == implode(",", $pokebattler_levels)) { From c30f1d898354d337e500068d23243975fe340bf6 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 27 Nov 2022 15:40:06 +0200 Subject: [PATCH 168/367] Added done-button to list-menu --- commands/list.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/commands/list.php b/commands/list.php index f43f9c90..bb57e5a6 100644 --- a/commands/list.php +++ b/commands/list.php @@ -90,6 +90,10 @@ 'callback_data' => $raid['id'] . ':raids_list:0' ); } +$keys[] = array( + 'text' => getTranslation('done'), + 'callback_data' => '0:exit:1' +); // Get the inline key array. $keys = inline_key_array($keys, 1); From ae070cfc0e11c95bffb8627b86d8a435e329de87 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 28 Nov 2022 10:51:52 +0200 Subject: [PATCH 169/367] Save user id in a better place --- core/bot/user.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/bot/user.php b/core/bot/user.php index 11ab997f..1545fdf1 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -219,6 +219,7 @@ public function raidaccessCheck($raidId, $permission, $return_result = false) */ public function updateUser($update) { + $this->userId = $update[$update['type']]['from']['id']; // Check DDOS count if ($this->ddosCount >= 2) return; // Update the user. @@ -275,7 +276,7 @@ private function updateUserdb($update) debug_log($update, '!'); return false; } - $id = $this->userId = $msg['id']; + $id = $this->userId; $name = ''; $sep = ''; From c16977313f5a9837cd0ac3f626ac7935103f3d1c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 28 Nov 2022 11:37:37 +0200 Subject: [PATCH 170/367] Added a fallback if nothing was fround from cleanup --- logic/update_raid_poll.php | 84 ++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/logic/update_raid_poll.php b/logic/update_raid_poll.php index cb8af2ef..dacd0a61 100644 --- a/logic/update_raid_poll.php +++ b/logic/update_raid_poll.php @@ -41,8 +41,32 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f $chat_and_message[] = $chat; } }else { - if(is_array($tg_json)) return $tg_json; - else return []; + if($update === false) { + if(is_array($tg_json)) return $tg_json; + else return []; + } + $chatId = $update[$update['type']]['message']['chat']['id']; + $messageId = $update[$update['type']]['message']['message_id']; + if(isset($update[$update['type']]['message']['text']) && !empty($update[$update['type']]['message']['text'])) { + $type = 'poll_text'; + }else if(isset($update[$update['type']]['message']['caption']) && !empty($update[$update['type']]['message']['caption'])) { + $type = 'poll_photo'; + }else if(isset($update[$update['type']]['message']['venue']) && !empty($update[$update['type']]['message']['venue'])) { + $type = 'poll_venue'; + }else if(isset($update[$update['type']]['message']['photo']) && !isset($update[$update['type']]['message']['caption'])) { + $type = 'photo'; + } + $unique_id = null; + if(isset($update[$update['type']]['message']['photo'])) { + $largest_size = 0; + foreach($update[$update['type']]['message']['photo'] as $photo) { + if($photo['file_size'] < $largest_size) continue; + $largest_size = $photo['file_size']; + $save_id = $photo['file_id']; + $unique_id = $photo['file_unique_id']; + } + } + $chat_and_message[] = ['chat_id' => $chatId, 'message_id' => $messageId, 'type' => $type, 'media_unique_id' => $unique_id]; } } // Get the raid data by id. @@ -83,36 +107,36 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f }else { $tg_json[] = editMessageText($message, $text['full'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); } - }else { - require_once(LOGIC_PATH . '/raid_picture.php'); - if($type == 'poll_photo') { - // If the poll message gets too long, we'll replace it with regular text based poll - if($post_text == true) { - // Delete raid picture and caption. - $tg_json[] = delete_message($chat, $message, true); - my_query("DELETE FROM cleanup WHERE chat_id = '{$chat}' AND message_id = '{$message}'"); + continue; + } + require_once(LOGIC_PATH . '/raid_picture.php'); + if($type == 'poll_photo') { + // If the poll message gets too long, we'll replace it with regular text based poll + if($post_text == true) { + // Delete raid picture and caption. + $tg_json[] = delete_message($chat, $message, true); + my_query('DELETE FROM cleanup WHERE chat_id = ? AND message_id = ?', [$chat, $message]); - $media_content = get_raid_picture($raid, true); - $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache - // Resend raid poll as text message. - send_photo($chat, $media_content[1], $media_content[0], '', [], [], false, $raid); - send_message($chat, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); - } else { - $media_content = get_raid_picture($raid); - // Edit the picture and caption - if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { - $tg_json[] = editMessageMedia($message, $text['short'], $media_content[1], $media_content[0], $keys, $chat, ['disable_web_page_preview' => 'true'], true, $raid); - }else { - // Edit the caption. - $tg_json[] = editMessageCaption($message, $text['short'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); - } - } - }else if ($type == 'photo' && $update_photo) { - $media_content = get_raid_picture($raid, 1); + $media_content = get_raid_picture($raid, true); $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache - if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { - $tg_json[] = editMessageMedia($message, '', $media_content[1], $media_content[0], false, $chat, false, true, $raid); - } + // Resend raid poll as text message. + send_photo($chat, $media_content[1], $media_content[0], '', [], [], false, $raid); + send_message($chat, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); + continue; + } + $media_content = get_raid_picture($raid); + // Edit the picture and caption + if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { + $tg_json[] = editMessageMedia($message, $text['short'], $media_content[1], $media_content[0], $keys, $chat, ['disable_web_page_preview' => 'true'], true, $raid); + }else { + // Edit the caption. + $tg_json[] = editMessageCaption($message, $text['short'], $keys, $chat, ['disable_web_page_preview' => 'true'], true); + } + }else if ($type == 'photo' && $update_photo) { + $media_content = get_raid_picture($raid, 1); + $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache + if(!isset($media_content[2]) or $media_content[2] != $chat_id_msg_id['media_unique_id']) { + $tg_json[] = editMessageMedia($message, '', $media_content[1], $media_content[0], false, $chat, false, true, $raid); } } } From 389c5b577f55f0ab1a32c43d06d7037f89d81f50 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 28 Nov 2022 13:42:28 +0200 Subject: [PATCH 171/367] Fixed extend logic --- logic/send_raid_poll.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/logic/send_raid_poll.php b/logic/send_raid_poll.php index 03ad1922..a6f5098e 100644 --- a/logic/send_raid_poll.php +++ b/logic/send_raid_poll.php @@ -75,11 +75,12 @@ function send_raid_poll($raid_id, $shareChats, $raid = false, $tg_json = false) continue; } require_once(LOGIC_PATH . '/raid_picture.php'); - $media_content = get_raid_picture($raid, $config->RAID_PICTURE_AUTOEXTEND); - if((!$config->RAID_PICTURE_AUTOEXTEND || in_array($raid['level'], $raid_poll_hide_buttons_levels)) or !$post_text) { + if(!($config->RAID_PICTURE_AUTOEXTEND && !in_array($raid['level'], $raid_poll_hide_buttons_levels)) && $post_text == false) { + $media_content = get_raid_picture($raid); $tg_json[] = send_photo($chat_id, $media_content[1], $media_content[0], $text['short'], $keys, ['disable_web_page_preview' => 'true'], true, $raid); continue; } + $media_content = get_raid_picture($raid, true); $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache send_photo($chat_id, $media_content[1], $media_content[0], '', [], [], false, $raid); send_message($chat_id, $text['short'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); From 1badc0cdcf65b3ff15a85ecd275fea8fcf5e2935 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 28 Nov 2022 13:43:09 +0200 Subject: [PATCH 172/367] Update also raid start and end times of they change --- commands/raid_from_webhook.php | 8 ++++++++ logic/collectCleanup.php | 11 ++++++++--- logic/raid_picture.php | 9 +++++++++ sql/pokemon-raid-bot.sql | 2 ++ sql/upgrade/6.sql | 3 +++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 95e46210..c3905c37 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -181,7 +181,11 @@ function isPointInsidePolygon($point, $vertices) { SET pokemon = :pokemon, pokemon_form = :pokemon_form, + spawn = :spawn, + start_time = :start_time, + end_time = :end_time, gym_team = :gym_team, + level = :level, move1 = :move1, move2 = :move2, gender = :gender, @@ -191,7 +195,11 @@ function isPointInsidePolygon($point, $vertices) { ',[ 'pokemon' => $pokemon, 'pokemon_form' => $form, + 'spawn' => $spawn, + 'start_time' => $start, + 'end_time' => $end, 'gym_team' => $team, + 'level' => $level, 'move1' => $move_1, 'move2' => $move_2, 'gender' => $gender, diff --git a/logic/collectCleanup.php b/logic/collectCleanup.php index 6970f7fd..1e6854ae 100644 --- a/logic/collectCleanup.php +++ b/logic/collectCleanup.php @@ -12,8 +12,11 @@ */ function collectCleanup($response, $request, $identifier = false) { - if($identifier == false) return $response; - if(!isset($response['result']['chat']['type']) or !in_array($response['result']['chat']['type'], ['channel','group','supergroup'])) return $response; + if( + $identifier == false or + !isset($response['result']['chat']['type']) or + !in_array($response['result']['chat']['type'], ['channel','group','supergroup']) + ) {return $response;} // Set chat and message_id $chat_id = $response['result']['chat']['id']; @@ -54,7 +57,7 @@ function collectCleanup($response, $request, $identifier = false) $standalone_photo = (array_key_exists('standalone_photo', $identifier) && $identifier['standalone_photo'] === true) ? 1 : 0; my_query(' REPLACE INTO photo_cache - VALUES (:id, :unique_id, :pokedex_id, :form_id, :raid_id, :ended, :gym_id, :standalone) + VALUES (:id, :unique_id, :pokedex_id, :form_id, :raid_id, :ended, :start_time, :end_time, :gym_id, :standalone) ',[ ':id' => $save_id, ':unique_id' => $unique_id, @@ -62,6 +65,8 @@ function collectCleanup($response, $request, $identifier = false) ':form_id' => $identifier['pokemon_form'], ':raid_id' => ($identifier['raid_ended'] ? 0 : $identifier['id']), // No need to save raid id if raid has ended ':ended' => $identifier['raid_ended'], + ':start_time' => ($identifier['raid_ended'] ? 'NULL' : $identifier['start_time']), + ':end_time' => ($identifier['raid_ended'] ? 'NULL' : $identifier['end_time']), ':gym_id' => $identifier['gym_id'], ':standalone' => $standalone_photo, ] diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 01418be6..05a40636 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -17,6 +17,14 @@ function get_raid_picture($raid, $standalone_photo = false) { ':standalone' => $standalone_photo, ':ended' => $raid['raid_ended'], ]; + $timeQuery = ''; + if($raid['raid_ended'] == 0) { + $timeQuery = ' + AND start_time = :start_time + AND end_time = :end_time'; + $binds['start_time'] = $raid['start_time']; + $binds['end_time'] = $raid['end_time']; + } $query_cache = my_query(' SELECT id, unique_id FROM photo_cache @@ -24,6 +32,7 @@ function get_raid_picture($raid, $standalone_photo = false) { AND gym_id = :gym_id AND pokedex_id = :pokedex_id AND form_id = :pokemon_form + ' . $timeQuery . ' AND ended = :ended AND standalone = :standalone LIMIT 1', $binds diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index ee03bea6..bda6975a 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -73,6 +73,8 @@ CREATE TABLE `photo_cache` ( `form_id` int(4) DEFAULT NULL, `raid_id` int(10) unsigned DEFAULT NULL, `ended` tinyint(1) DEFAULT NULL, + `start_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, `gym_id` int(10) unsigned DEFAULT NULL, `standalone` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`unique_id`) diff --git a/sql/upgrade/6.sql b/sql/upgrade/6.sql index 9aee6de5..af84a857 100644 --- a/sql/upgrade/6.sql +++ b/sql/upgrade/6.sql @@ -1,2 +1,5 @@ ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `gymarea` TINYINT UNSIGNED NULL AFTER `auto_alarm`; ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `privileges` JSON NULL AFTER `gymarea`; + +ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `end_time` DATETIME NULL AFTER `ended`; +ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `start_time` DATETIME NULL AFTER `ended`; From 864709b4551f051ab767b7d666c9db155bc30d05 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 28 Nov 2022 17:35:58 +0200 Subject: [PATCH 173/367] Send alarms when webhook updates raid pokemon --- commands/raid_from_webhook.php | 15 ++++++++++++++- logic/active_raid_duplication_check.php | 10 ++++++---- logic/alarm.php | 3 +++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index c3905c37..13177a4e 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -2,6 +2,7 @@ // Write to log. debug_log('RAID_FROM_WEBHOOK()'); require_once(LOGIC_PATH . '/active_raid_duplication_check.php'); +require_once(LOGIC_PATH . '/alarm.php'); if($metrics) { $webhook_raids_received_total = $metrics->registerCounter($namespace, 'webhook_raids_received_total', 'Total raids received via webhook'); @@ -168,7 +169,8 @@ function isPointInsidePolygon($point, $vertices) { } // Insert new raid or update existing raid/ex-raid? - $raid_id = active_raid_duplication_check($gym_internal_id, $level); + $activeRaid = active_raid_duplication_check($gym_internal_id, $level, true); + $raid_id = (is_array($activeRaid)) ? $activeRaid['id'] : $activeRaid; $send_updates = false; @@ -268,6 +270,16 @@ function isPointInsidePolygon($point, $vertices) { $missing_raid_data = $query_missing->fetch(); $resolved_boss = resolve_raid_boss($pokemon, $form, $spawn, $level); + $wasBossUpdated = false; + if(is_array($activeRaid)) { + $resolvedOldBoss = resolve_raid_boss($activeRaid['pokemon'], $activeRaid['pokemon_form'], $activeRaid['spawn'], $activeRaid['level']); + if( + $resolved_boss['pokedex_id'] != $resolvedOldBoss['pokedex_id'] or + $resolved_boss['pokemon_form_id'] != $resolvedOldBoss['pokemon_form_id'] + ) { + $wasBossUpdated = true; + } + } // Combine resulting data with stuff received from webhook to create a complete raid array $raid = array_merge($missing_raid_data, [ @@ -302,6 +314,7 @@ function isPointInsidePolygon($point, $vertices) { if($send_updates == true) { require_once(LOGIC_PATH .'/update_raid_poll.php'); $tg_json = update_raid_poll($raid_id, $raid, false, $tg_json, true); + if($wasBossUpdated) $tg_json = alarm($raid, false, 'new_boss', '', $tg_json); if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0]) && !$no_auto_posting) { foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { diff --git a/logic/active_raid_duplication_check.php b/logic/active_raid_duplication_check.php index c61bb4df..8dbfedfc 100644 --- a/logic/active_raid_duplication_check.php +++ b/logic/active_raid_duplication_check.php @@ -3,9 +3,10 @@ * Active raid duplication check. * @param int $gym_id Internal gym id * @param int $level (optional) raid level - * @return int + * @param bool $returnArray Return additional info of the raid + * @return int|array */ -function active_raid_duplication_check($gym_id, $level = false) +function active_raid_duplication_check($gym_id, $level = false, $returnArray = false) { global $config; $levelSql = ''; @@ -16,7 +17,7 @@ function active_raid_duplication_check($gym_id, $level = false) } // Build query. $rs = my_query(' - SELECT id, event, level + SELECT id, event, level, pokemon, pokemon_form, spawn FROM raids WHERE end_time > (UTC_TIMESTAMP() - INTERVAL 5 MINUTE) AND gym_id = ? @@ -32,7 +33,8 @@ function active_raid_duplication_check($gym_id, $level = false) or ($config->RAID_EXCLUDE_EVENT_DUPLICATION && $raid['event'] !== NULL && $raid['event'] != EVENT_ID_EX)) { continue; } - return $raid['id']; + if($returnArray === true) return $raid; + else return $raid['id']; } return 0; } diff --git a/logic/alarm.php b/logic/alarm.php index 0424e350..f84a50f8 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -25,6 +25,9 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $username = '' . $answer_quests['name'] . ''; // Get Trainercode $trainercode = $answer_quests['trainercode']; + }else { + // Set this to 0 so we get every attendee from database + $user_id = 0; } // Gym name and raid times From a5c75a93374ff4e078999b9c9ad1b9d2bf12b2ca Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 28 Nov 2022 23:28:16 +0200 Subject: [PATCH 174/367] Fixed metrics endpoint --- logic/bearer_token.php | 3 +++ metrics/index.php | 4 ++-- mods/pokedex_import.php | 3 --- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/logic/bearer_token.php b/logic/bearer_token.php index 0884ec58..77f6d085 100644 --- a/logic/bearer_token.php +++ b/logic/bearer_token.php @@ -10,6 +10,9 @@ function getAuthorizationHeader(){ if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI return trim($_SERVER["HTTP_AUTHORIZATION"]); } + if(isset(getallheaders()['Authorization'])) { + return getallheaders()['Authorization']; + } if (function_exists('apache_request_headers')) { $requestHeaders = apache_request_headers(); if (isset($requestHeaders['Authorization'])) { diff --git a/metrics/index.php b/metrics/index.php index e30c31dc..77e16ef4 100644 --- a/metrics/index.php +++ b/metrics/index.php @@ -7,8 +7,8 @@ use Prometheus\RenderTextFormat; require_once __DIR__ . '/../core/bot/paths.php'; -require_once(CORE_BOT_PATH . '/logic/debug.php'); -require_once(CORE_BOT_PATH . '/logic/bearer_token.php'); +require_once(ROOT_PATH . '/logic/debug.php'); +require_once(ROOT_PATH . '/logic/bearer_token.php'); require_once(CORE_BOT_PATH . '/config.php'); // Authentication is done based on a Bearer Token provided as a header diff --git a/mods/pokedex_import.php b/mods/pokedex_import.php index b3ee2d5f..ac8b9349 100644 --- a/mods/pokedex_import.php +++ b/mods/pokedex_import.php @@ -9,9 +9,6 @@ // Check access. $botUser->accessCheck('pokedex'); -$id = $data['id']; -$arg = $data['arg']; - $msg = 'Import data from community maintained sources:'.CR; $msg.= 'ccev\'s github repository'.CR; $msg.= 'Pokebattler'; From 8d1b88b7fddfe5eb28744c6c34cc8fc5940d80cb Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 28 Nov 2022 23:28:42 +0200 Subject: [PATCH 175/367] Minor cleanups --- mods/delete_scheduled_entry.php | 3 +- mods/gym_create.php | 106 ++++++++++++++++---------------- mods/gym_details.php | 1 - 3 files changed, 54 insertions(+), 56 deletions(-) diff --git a/mods/delete_scheduled_entry.php b/mods/delete_scheduled_entry.php index 6a6510bb..e76f47c2 100644 --- a/mods/delete_scheduled_entry.php +++ b/mods/delete_scheduled_entry.php @@ -4,11 +4,10 @@ // Check access. $botUser->accessCheck('pokedex'); -$arg = $data['arg']; $id = $data['id']; if($arg == 1) { - my_query("DELETE FROM raid_bosses WHERE id='".$id."'"); + my_query('DELETE FROM raid_bosses WHERE id = ?', [$id]); include(ROOT_PATH . '/mods/pokedex_list_raids.php'); exit(); } diff --git a/mods/gym_create.php b/mods/gym_create.php index 5ba57b73..97aa4e9c 100644 --- a/mods/gym_create.php +++ b/mods/gym_create.php @@ -40,64 +40,64 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] my_query("DELETE FROM user_input WHERE id = :deleteId", ['deleteId' => $deleteId]); $msg = getTranslation("action_aborted"); editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['from']['id']); -}else { - if($stage == 1) { - $callbackResponse = getTranslation('here_we_go'); - $callbackId = $update['callback_query']['id']; - - $userId = $update['callback_query']['from']['id']; - $oldMessageId = $update['callback_query']['message']['message_id']; + exit; +} +if($stage == 1) { + $callbackResponse = getTranslation('here_we_go'); + $callbackId = $update['callback_query']['id']; - $userInputId = insertUserInput($userId, $stage, $oldMessageId); + $userId = $update['callback_query']['from']['id']; + $oldMessageId = $update['callback_query']['message']['message_id']; - $editMsg = getTranslation("gym_create") . ':'; - $editKeys[0][] = [ - 'text' => getTranslation("abort"), - 'callback_data' => '0:gym_create:abort-' . $userInputId - ]; - $sendMsg = EMOJI_HERE . getTranslation('gym_gps_instructions') . CR; - $sendMsg .= getTranslation('gym_gps_example'); - respondToUser($userId, $oldMessageId, $editMsg, $editKeys, $sendMsg, [], $callbackResponse, $callbackId); - }else { - $userId = $update['message']['from']['id']; - $oldMessageId = $modifiers['oldMessageId']; + $userInputId = insertUserInput($userId, $stage, $oldMessageId); - if($stage == 2) { - $input = $update['message']['text']; - $reg_exp_coordinates = '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$^'; - if(preg_match($reg_exp_coordinates, $input)) { - [$lat,$lon] = explode(',', $input, 2); - my_query('INSERT INTO gyms (gym_name, lat, lon) VALUES (\'unknown\', :lat, :lon)', [':lat' => $lat, ':lon' => $lon]); - $gymId = $dbh->lastInsertId(); + $editMsg = getTranslation("gym_create") . ':'; + $editKeys[0][] = [ + 'text' => getTranslation("abort"), + 'callback_data' => '0:gym_create:abort-' . $userInputId + ]; + $sendMsg = EMOJI_HERE . getTranslation('gym_gps_instructions') . CR; + $sendMsg .= getTranslation('gym_gps_example'); + respondToUser($userId, $oldMessageId, $editMsg, $editKeys, $sendMsg, [], $callbackResponse, $callbackId); + exit; +} +$userId = $update['message']['from']['id']; +$oldMessageId = $modifiers['oldMessageId']; - $userInputId = insertUserInput($userId, $stage, $oldMessageId, $gymId); - $msg = EMOJI_PENCIL . getTranslation('gym_name_instructions'); - respondToUser($userId, 0, '', [], $msg); - }else { - $msg = getTranslation('gym_gps_coordinates_format_error'); - respondToUser($userId, 0, '', [], $msg); - exit(); - } +if($stage == 2) { + $input = $update['message']['text']; + $reg_exp_coordinates = '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$^'; + if(preg_match($reg_exp_coordinates, $input)) { + [$lat,$lon] = explode(',', $input, 2); + my_query('INSERT INTO gyms (gym_name, lat, lon) VALUES (\'unknown\', :lat, :lon)', [':lat' => $lat, ':lon' => $lon]); + $gymId = $dbh->lastInsertId(); - }elseif($stage == 3) { - $input = trim($update['message']['text']); - if(strlen($input) <= 255) { - $gymId = $modifiers['gymId']; - my_query('UPDATE gyms SET gym_name = :gym_name WHERE id = :gymId', [':gym_name' => $input, ':gymId' => $gymId]); + $userInputId = insertUserInput($userId, $stage, $oldMessageId, $gymId); + $msg = EMOJI_PENCIL . getTranslation('gym_name_instructions'); + respondToUser($userId, 0, '', [], $msg); + }else { + $msg = getTranslation('gym_gps_coordinates_format_error'); + respondToUser($userId, 0, '', [], $msg); + } + exit; +} +if($stage == 3) { + $input = trim($update['message']['text']); + if(strlen($input) <= 255) { + $gymId = $modifiers['gymId']; + my_query('UPDATE gyms SET gym_name = :gym_name WHERE id = :gymId', [':gym_name' => $input, ':gymId' => $gymId]); - $msg = getTranslation('gym_added'); - $keys[] = [ - [ - 'text' => getTranslation('show_gym_details'), - 'callback_data' => 'N:gym_details:' . $gymId - ] - ]; - respondToUser($userId, $oldMessageId, 'OK', [], $msg, $keys); - }else { - $msg = getTranslation('gym_edit_text_too_long'); - respondToUser($userId, 0, '', [], $msg); - exit(); - } - } + $msg = getTranslation('gym_added'); + $keys[] = [ + [ + 'text' => getTranslation('show_gym_details'), + 'callback_data' => 'N:gym_details:' . $gymId + ] + ]; + respondToUser($userId, $oldMessageId, 'OK', [], $msg, $keys); + }else { + $msg = getTranslation('gym_edit_text_too_long'); + respondToUser($userId, 0, '', [], $msg); } + exit; } diff --git a/mods/gym_details.php b/mods/gym_details.php index a361ff3e..2c091497 100644 --- a/mods/gym_details.php +++ b/mods/gym_details.php @@ -14,7 +14,6 @@ // Get the arg. $arg = $data['g']; -$gymarea_id = $data['ga'] ?? false; // Get the id. $id = $data['g']; From 6cf051c932d0478bfaa07e4c4543abc314457b90 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 30 Nov 2022 19:12:48 +0200 Subject: [PATCH 176/367] Fixed participate-key --- mods/vote_time.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/vote_time.php b/mods/vote_time.php index 9081d361..342f73bd 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -23,16 +23,16 @@ $now = $now->format('Y-m-d H:i') . ':00'; } +// Request Raid and Gym - Infos +$raid = get_raid($raidId); + // Vote time in the future? -if($attend_time_compare != ANYTIME && $now >= $attend_time_compare) { +if($attend_time_compare != ANYTIME && $now >= $attend_time_compare && $raid['event_vote_key_mode'] != 1) { // Send vote time first. send_vote_time_future($update); exit; } -// Request Raid and Gym - Infos -$raid = get_raid($raidId); - // Check if the user has voted for this raid before. $rs = my_query( ' From ec8d57011bfcdda8887b6034d5b5834cb81c69ad Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 30 Nov 2022 19:12:48 +0200 Subject: [PATCH 177/367] Fixed participate-key --- mods/vote_time.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/vote_time.php b/mods/vote_time.php index e21fbe08..9bb2fd61 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -28,16 +28,16 @@ $now = $now->format('Y-m-d H:i') . ':00'; } +// Request Raid and Gym - Infos +$raid = get_raid($raidId); + // Vote time in the future? -if($attend_time_compare != ANYTIME && $now >= $attend_time_compare) { +if($attend_time_compare != ANYTIME && $now >= $attend_time_compare && $raid['event_vote_key_mode'] != 1) { // Send vote time first. send_vote_time_future($update); exit; } -// Request Raid and Gym - Infos -$raid = get_raid($raidId); - // Check if the user has voted for this raid before. $rs = my_query(' SELECT count(attendance.attend_time) AS count, userInfo.* From 805e9ac7761bda09ea73ffbc697b0c267357cc10 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 4 Dec 2022 19:55:43 +0200 Subject: [PATCH 178/367] Fixed gym listing menus for event raids --- logic/active_raid_duplication_check.php | 2 +- logic/gymMenu.php | 162 +++++++++++------------- logic/show_raid_poll_small.php | 3 + mods/list_raid.php | 39 ++++-- 4 files changed, 106 insertions(+), 100 deletions(-) diff --git a/logic/active_raid_duplication_check.php b/logic/active_raid_duplication_check.php index 8dbfedfc..bb033b2c 100644 --- a/logic/active_raid_duplication_check.php +++ b/logic/active_raid_duplication_check.php @@ -19,7 +19,7 @@ function active_raid_duplication_check($gym_id, $level = false, $returnArray = f $rs = my_query(' SELECT id, event, level, pokemon, pokemon_form, spawn FROM raids - WHERE end_time > (UTC_TIMESTAMP() - INTERVAL 5 MINUTE) + WHERE end_time > UTC_TIMESTAMP() AND gym_id = ? ' . $levelSql . ' ORDER BY end_time, event IS NOT NULL diff --git a/logic/gymMenu.php b/logic/gymMenu.php index ff630295..31ab263c 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -151,115 +151,89 @@ function getGymareas($gymareaId, $stage, $buttonAction) { * @return array */ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $stage) { - global $config, $menuActions; + global $config, $menuActions, $botUser; // Show hidden gyms? $show_gym = $showHidden ? 0 : 1; $collateQuery = ($config->MYSQL_SORT_COLLATE != '') ? ' COLLATE ' . $config->MYSQL_SORT_COLLATE : ''; - // Get the number of gyms to display - if($buttonAction == 'list') { + $eventQuery = ' '; + if ($buttonAction == 'list') { // Select only gyms with active raids $queryConditions = ' LEFT JOIN raids ON raids.gym_id = gyms.id - WHERE end_time > UTC_TIMESTAMP()'; + WHERE show_gym = ' . $show_gym; + $queryConditions .= ' AND end_time > UTC_TIMESTAMP() '; + $eventQuery = 'event IS NULL'; + if($botUser->accessCheck('ex-raids', true)) { + if($botUser->accessCheck('event-raids', true)) + $eventQuery = ' '; + else + $eventQuery .= ' OR event = ' . EVENT_ID_EX; + }elseif($botUser->accessCheck('event-raids', true)) { + $eventQuery = 'event != ' . EVENT_ID_EX .' OR event IS NULL'; + } + $eventQuery = ($eventQuery == '') ? ' ' : ' AND ('.$eventQuery.') '; }else { - $queryConditions = 'WHERE show_gym = ' . $show_gym . ' '; + $queryConditions = ' WHERE show_gym = ' . $show_gym; } - $rs_count = my_query('SELECT COUNT(gym_name) as count FROM gyms ' . $queryConditions . ' ' . $gymareaQuery); + $rs_count = my_query('SELECT COUNT(gym_name) as count FROM gyms ' . $queryConditions . $eventQuery . $gymareaQuery); $gym_count = $rs_count->fetch(); + // Found 20 or less gyms, print gym names + if($gym_count['count'] <= 20) { + $keys = createGymListKeysByFirstLetter('', $showHidden, $gymareaQuery, $buttonAction, $gymareaId); + return [$keys[0], false]; + } + // If found over 20 gyms, print letters - if($gym_count['count'] > 20) { - $select = 'SELECT DISTINCT UPPER(SUBSTR(gym_name, 1, 1)) AS first_letter'; - $group_order = ' ORDER BY 1'; - // Special/Custom gym letters? - if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { - // Explode special letters. - $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); - $select = 'SELECT CASE '; - foreach($special_keys as $letter) - { - $letter = trim($letter); - debug_log($letter, 'Special gym letter:'); - // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); - $select .= SP . 'WHEN UPPER(LEFT(gym_name, ' . $length . ')) = \'' . $letter . '\' THEN UPPER(LEFT(gym_name, ' . $length . '))' . SP; - } - $select .= 'ELSE UPPER(LEFT(gym_name, 1)) END AS first_letter'; - $group_order = ' GROUP BY 1 ORDER BY gym_name'; - } - $rs = my_query( - $select . - ' FROM gyms ' . - $queryConditions . - $gymareaQuery . - $group_order . - $collateQuery - ); - while ($gym = $rs->fetch()) { - // Add first letter to keys array - $keys[] = array( - 'text' => $gym['first_letter'], - 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'a' => $buttonAction, 'stage' => $stage+1, 'fl' => $gym['first_letter'], 'ga' => $gymareaId]) - ); + $select = 'SELECT DISTINCT UPPER(SUBSTR(gym_name, 1, 1)) AS first_letter'; + $group_order = ' ORDER BY 1'; + // Special/Custom gym letters? + if(!empty($config->RAID_CUSTOM_GYM_LETTERS)) { + // Explode special letters. + $special_keys = explode(',', $config->RAID_CUSTOM_GYM_LETTERS); + $select = 'SELECT CASE '; + foreach($special_keys as $letter) + { + $letter = trim($letter); + debug_log($letter, 'Special gym letter:'); + // Fix chinese chars, prior: $length = strlen($letter); + $length = strlen(utf8_decode($letter)); + $select .= SP . 'WHEN UPPER(LEFT(gym_name, ' . $length . ')) = \'' . $letter . '\' THEN UPPER(LEFT(gym_name, ' . $length . '))' . SP; } - - // Get the inline key array. - return [inline_key_array($keys, 4), true]; + $select .= 'ELSE UPPER(LEFT(gym_name, 1)) END AS first_letter'; + $group_order = ' GROUP BY 1 ORDER BY gym_name'; } - - // If less than 20 gyms was found, print gym names - $rs = my_query(' - SELECT gyms.id, gyms.gym_name, gyms.ex_gym - FROM gyms - ' . $queryConditions . ' - ' . $gymareaQuery . ' - ORDER BY gym_name ' . $collateQuery + $rs = my_query( + $select . + ' FROM gyms ' . + $queryConditions . ' ' . + $gymareaQuery . + $group_order . + $collateQuery ); - // Init empty keys array. - $keys = []; - while ($gym = $rs->fetch()) { - if($gym['id'] == NULL) continue; - $active_raid = active_raid_duplication_check($gym['id']); - - $gym_name = $gym['gym_name']; - // Show Ex-Gym-Marker? - if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { - $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; - $gym_name = $ex_raid_gym_marker . SP . $gym['gym_name']; - } - // Add warning emoji for active raid - if ($active_raid > 0) { - $gym_name = EMOJI_WARN . SP . $gym_name; - } - $callback = [ - 'callbackAction' => $menuActions[$buttonAction], - 'g' => $gym['id'], - 'ga' => $gymareaId, - 'h' => $showHidden, - ]; - if($buttonAction == 'list') $callback['r'] = $active_raid; + // Add first letter to keys array $keys[] = array( - 'text' => $gym_name, - 'callback_data' => formatCallbackData($callback) + 'text' => $gym['first_letter'], + 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'a' => $buttonAction, 'stage' => $stage+1, 'fl' => $gym['first_letter'], 'ga' => $gymareaId]) ); } // Get the inline key array. - return [inline_key_array($keys, 1), false]; + return [inline_key_array($keys, 4), true]; } /** * Raid edit gym keys with active raids marker. * @param string $firstLetter * @param bool $showHidden * @param string $gymareaQuery - * @param string $action + * @param string $buttonAction * @return array */ -function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery = '', $action = '', $gymareaId = false) { - global $config, $menuActions; +function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery = '', $buttonAction = '', $gymareaId = false) { + global $config, $menuActions, $botUser; // Length of first letter. // Fix chinese chars, prior: $first_length = strlen($first); $first_length = strlen(utf8_decode($firstLetter)); @@ -281,15 +255,29 @@ function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery } $show_gym = $showHidden ? 0 : 1; + $eventQuery = 'event IS NULL'; + if($botUser->accessCheck('ex-raids', true)) { + if($botUser->accessCheck('event-raids', true)) + $eventQuery = ''; + else + $eventQuery .= ' OR event = ' . EVENT_ID_EX; + }elseif($botUser->accessCheck('event-raids', true)) { + $eventQuery = 'event != ' . EVENT_ID_EX .' OR event IS NULL'; + } + $eventQuery = ($eventQuery == '') ? ' ' : ' AND ('.$eventQuery.') '; + + $letterQuery = ($firstLetter != '') ? 'AND UPPER(LEFT(gym_name, ' . $first_length . ')) = UPPER(\'' . $firstLetter . '\')' : ''; + $query_collate = ($config->MYSQL_SORT_COLLATE != '') ? 'COLLATE ' . $config->MYSQL_SORT_COLLATE : ''; // Get gyms from database $rs = my_query(' - SELECT gyms.id, gyms.gym_name, gyms.ex_gym + SELECT gyms.id, gyms.gym_name, gyms.ex_gym, + case when (select 1 from raids where gym_id = gyms.id and end_time > utc_timestamp() '.$eventQuery.' LIMIT 1) = 1 then 1 else 0 end as active_raid FROM gyms - WHERE UPPER(LEFT(gym_name, ' . $first_length . ')) = UPPER(\'' . $firstLetter . '\') + WHERE show_gym = ? + ' . $letterQuery . ' ' . $not . ' ' . $gymareaQuery . ' - AND show_gym = ? ORDER BY gym_name ' . $query_collate , [$show_gym] ); @@ -298,8 +286,7 @@ function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery $keys = []; while ($gym = $rs->fetch()) { - $active_raid = active_raid_duplication_check($gym['id']); - if($action == 'list' && $active_raid == 0) continue; + if ($buttonAction == 'list' && $gym['active_raid'] == 0) continue; // Show Ex-Gym-Marker? if($config->RAID_CREATION_EX_GYM_MARKER && $gym['ex_gym'] == 1) { $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : $config->RAID_EX_GYM_MARKER; @@ -308,17 +295,16 @@ function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery $gym_name = $gym['gym_name']; } // Add warning emoji for active raid - if ($active_raid > 0) { + if ($gym['active_raid'] == 1) { $gym_name = EMOJI_WARN . SP . $gym_name; } $callback = [ - 'callbackAction' => $menuActions[$action], + 'callbackAction' => $menuActions[$buttonAction], 'g' => $gym['id'], 'ga' => $gymareaId, + 'fl' => $firstLetter, 'h' => $showHidden, ]; - if($action == 'list') $callback['r'] = $active_raid; - else $callback['fl'] = $firstLetter; $keys[] = array( 'text' => $gym_name, 'callback_data' => formatCallbackData($callback) diff --git a/logic/show_raid_poll_small.php b/logic/show_raid_poll_small.php index 9eb79eef..649c0b3d 100644 --- a/logic/show_raid_poll_small.php +++ b/logic/show_raid_poll_small.php @@ -21,6 +21,9 @@ function show_raid_poll_small($raid, $override_language = false) $msg .= '' . $raid['address'] . '' . CR2; } + if(isset($raid['event_name']) && !empty($raid['event_name'])) { + $msg .= $raid['event_name'] . CR; + } // Pokemon if(!empty($raid['pokemon'])) { $msg .= '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ' ' . CR; diff --git a/mods/list_raid.php b/mods/list_raid.php index ce2db191..b286939f 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -12,15 +12,25 @@ $botUser->accessCheck('list'); // Get gym ID. -$gym_id = $data['g']; -$raid_id = $data['r']; +$gym_id = $data['g'] ?? 0; +$raid_id = $data['r'] ?? 0; // Get raid details. if($raid_id != 0) { $sql_condition = 'AND raids.id = ? LIMIT 1'; $binds = [$raid_id]; }else { - $sql_condition = 'AND gyms.id = ?'; + $eventQuery = 'event IS NULL'; + if($botUser->accessCheck('ex-raids', true)) { + if($botUser->accessCheck('event-raids', true)) + $eventQuery = ''; + else + $eventQuery .= ' OR event = ' . EVENT_ID_EX; + }elseif($botUser->accessCheck('event-raids', true)) { + $eventQuery = 'event != ' . EVENT_ID_EX .' OR event IS NULL'; + } + $eventQuery = ($eventQuery == '') ? ' ' : ' AND ('.$eventQuery.') '; + $sql_condition = 'AND gyms.id = ? ' . $eventQuery; $binds = [$gym_id]; } $rs = my_query(' @@ -28,10 +38,9 @@ FROM raids LEFT JOIN gyms ON raids.gym_id = gyms.id - WHERE end_time > UTC_TIMESTAMP() - INTERVAL 10 MINUTE - ' . $sql_condition . ' - ', - $binds + WHERE end_time > UTC_TIMESTAMP() + ' . $sql_condition + ,$binds ); if($rs->rowcount() == 1) { // Get the row. @@ -49,7 +58,7 @@ ] ] ]; - if($botUser->raidaccessCheck($raid_id, 'pokemon', true)) { + if($botUser->raidaccessCheck($raid['id'], 'pokemon', true)) { $keys[] = [ [ 'text' => getTranslation('update_pokemon'), @@ -57,7 +66,7 @@ ] ]; } - if($botUser->raidaccessCheck($raid_id, 'delete', true)) { + if($botUser->raidaccessCheck($raid['id'], 'delete', true)) { $keys[] = [ [ 'text' => getTranslation('delete'), @@ -93,15 +102,23 @@ $keys[] = [ [ 'text' => $i . '. ' . $raid_pokemon_name, - 'callback_data' => $raid['id'] . ':list_raid:0' + 'callback_data' => formatCallbackData(['callbackAction' => 'list_raid', 'r' => $raid['id']]) ] ]; $i++; } + $callback = [ + 'callbackAction' => 'gymMenu', + 'stage' => 2, + 'a' => 'list', + 'fl' => $data['fl'], + 'ga' => $data['ga'], + 'h' => $data['h'], + ]; $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:list_by_gym:' . $raid['gym_name'][0] + 'callback_data' => formatCallbackData($callback) ] ]; } From e652ac14989e745fcc736cf8644781f9977d83f9 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 6 Dec 2022 20:13:17 +0200 Subject: [PATCH 179/367] Fixes and improvements to raid creation menu - Back-buttons should now work - Users can now create event raids even if the gym already has a regular raid ongoing --- lang/language.json | 39 ++++++ logic/keys_event.php | 11 +- logic/pokemon_keys.php | 13 +- logic/raid_edit_raidlevel_keys.php | 44 +++--- mods/edit_date.php | 62 +++++---- mods/edit_event.php | 48 +++---- mods/edit_event_raidlevel.php | 52 +++---- mods/edit_pokemon.php | 61 +++------ mods/edit_raidlevel.php | 111 ++++++++++----- mods/edit_save.php | 88 ++---------- mods/edit_starttime.php | 119 ++++++++-------- mods/edit_time.php | 213 +++++++++++------------------ mods/exit.php | 3 +- mods/raids_list.php | 21 +-- 14 files changed, 409 insertions(+), 476 deletions(-) diff --git a/lang/language.json b/lang/language.json index 0e60fff0..13d2b417 100644 --- a/lang/language.json +++ b/lang/language.json @@ -1962,6 +1962,45 @@ "FI": "Raidi on jo olemassa!", "ES": "¡La incursión ya existe!" }, + "inspect_raid_or_create_event": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Inspect the existing raid or create a new event raid", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tarkaste tallennettua raidia tai luo tapahtuma", + "ES": "TRANSLATE" + }, + "saved_raid": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Show saved raid", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tallennettu raidi", + "ES": "TRANSLATE" + }, + "create_event_raid": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Create event raid", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Luo raiditapahtuma", + "ES": "TRANSLATE" + }, "create_raid": { "NL": "Begin Raid in", "DE": "Erstelle Raid in", diff --git a/logic/keys_event.php b/logic/keys_event.php index 520166e4..4a402531 100644 --- a/logic/keys_event.php +++ b/logic/keys_event.php @@ -1,13 +1,14 @@ $event['name'], - 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . $event['id'] + 'callback_data' => formatCallbackData($callbackData) ); } } if($admin_access[0] === true) { + $callbackData['e'] = 'X'; $keys[] = array( 'text' => getTranslation("Xstars"), - 'callback_data' => $gym_id_plus_letter . ':' . $action . ':X' + 'callback_data' => formatCallbackData($callbackData) ); } // Get the inline key array. diff --git a/logic/pokemon_keys.php b/logic/pokemon_keys.php index 3d6f1be6..d66ddbd8 100644 --- a/logic/pokemon_keys.php +++ b/logic/pokemon_keys.php @@ -1,12 +1,13 @@ $raid_level, 'eggId' => $egg_id] ); // Add key for each raid level + $callbackData['callbackAction'] = $action; while ($pokemon = $rs->fetch()) { + $callbackData['p'] = $pokemon['id']; $keys[] = array( 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), - 'callback_data' => $gym_id_plus_letter . ':' . $action . ':' . (($event_id!==false) ? $event_id . ',' . $raid_level . ',' : '') . $pokemon['id'] + 'callback_data' => formatCallbackData($callbackData) ); } diff --git a/logic/raid_edit_raidlevel_keys.php b/logic/raid_edit_raidlevel_keys.php index af8e84d4..d1c76936 100644 --- a/logic/raid_edit_raidlevel_keys.php +++ b/logic/raid_edit_raidlevel_keys.php @@ -1,24 +1,19 @@ RAID_EGG_DURATION.' MINUTE) between date_start and date_end - OR DATE_ADD(\'' . $time_now . '\', INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end + DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->RAID_EGG_DURATION.' MINUTE) between date_start and date_end + OR DATE_ADD(UTC_TIMESTAMP(), INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end ) '.$query_event.' GROUP BY raid_bosses.raid_level @@ -40,16 +35,17 @@ function raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access = [f $keys = []; // Add key for each raid level + $buttonData = $callbackData; while ($level = $rs_counts->fetch()) { - // Raid level and action - $raid_level = $level['raid_level']; - // Add key for pokemon if we have just 1 pokemon for a level if($level['raid_level_count'] != 1) { + // Raid level and action + $buttonData['callbackAction'] = 'edit_pokemon'; + $buttonData['rl'] = $level['raid_level']; // Add key for raid level $keys[] = array( - 'text' => getTranslation($raid_level . 'stars'), - 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_pokemon:' . $event_id . ',' . $raid_level + 'text' => getTranslation($level['raid_level'] . 'stars'), + 'callback_data' => formatCallbackData($buttonData) ); continue; } @@ -60,26 +56,32 @@ function raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access = [f ON pokemon.pokedex_id = raid_bosses.pokedex_id AND pokemon.pokemon_form_id = raid_bosses.pokemon_form_id WHERE ( - DATE_SUB(\'' . $time_now . '\', INTERVAL '.$config->RAID_EGG_DURATION.' MINUTE) between date_start and date_end - OR DATE_ADD(\'' . $time_now . '\', INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end + DATE_SUB(UTC_TIMESTAMP(), INTERVAL '.$config->RAID_EGG_DURATION.' MINUTE) between date_start and date_end + OR DATE_ADD(UTC_TIMESTAMP(), INTERVAL '.$config->RAID_DURATION.' MINUTE) between date_start and date_end ) AND raid_level = ? '.$query_event.' LIMIT 1 - ', [$raid_level] + ', [$level['raid_level']] ); $pokemon = $query_mon->fetch(); + $buttonData['callbackAction'] = 'edit_starttime'; + $buttonData['rl'] = $level['raid_level']; + $buttonData['p'] = $pokemon['id']; // Add key for pokemon $keys[] = array( 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), - 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_starttime:' . $event_id . ',' . $raid_level . ',' . $pokemon['id'] + 'callback_data' => formatCallbackData($buttonData) ); + unset($buttonData['p']); } // Add key for raid event if user allowed to create event raids if(($admin_access[1] === true or $admin_access[0] === true) && $event === false) { + $eventData = $callbackData; + $eventData['callbackAction'] = 'edit_event'; $keys[] = array( 'text' => getTranslation('event'), - 'callback_data' => $gym_id . ',' . $gym_first_letter . ':edit_event:0' + 'callback_data' => formatCallbackData($eventData) ); } diff --git a/mods/edit_date.php b/mods/edit_date.php index 5498c39b..3435b68d 100644 --- a/mods/edit_date.php +++ b/mods/edit_date.php @@ -9,61 +9,55 @@ // Check access. $botUser->accessCheck('create'); -// Set the id. -$id = $data['id']; -$gym_id = explode(',',$data['id'])[0]; - -// Get the argument. -$arg = $data['arg']; -$arg_data = explode(',', $arg); -$event_id = $arg_data[0]; -$raid_level = $arg_data[1]; -$pokemon_id = $arg_data[2]; -$raid_time = $arg_data[3]; +$raid_time = $data['t']; // Init empty keys array and set keys count. $keys = []; $keys_count = 2; -// Received: Year-Month-Day / 1970-01-01 / 2x "-" -if (substr_count($raid_time, '-') == 2) { +$buttonData = $data; +// Received: YearMonthDay / 19700101 +if (strlen($raid_time) == 8) { debug_log('Generating buttons for each hour of the day'); // Buttons for each hour + $buttonData['callbackAction'] = 'edit_date'; for ($i = 0; $i <= 23; $i = $i + 1) { + $buttonData['t'] = $data['t'] . str_pad($i, 2, '0', STR_PAD_LEFT); // Create the keys. $keys[] = array( // Just show the time, no text - not everyone has a phone or tablet with a large screen... 'text' => str_pad($i, 2, '0', STR_PAD_LEFT) . ':xx', - 'callback_data' => $id . ':edit_date:' . $arg . ' ' . str_pad($i, 2, '0', STR_PAD_LEFT) . '-' + 'callback_data' => formatCallbackData($buttonData) ); } // Set keys count and message. $keys_count = 4; $msg = getTranslation('raid_select_hour'); -// Received: Year-Month-Day Hour- / 1970-01-01 00- / 3x "-" -} else if (substr_count($raid_time, '-') == 3) { +// Received: YearMonthDayHour / 1970010100 +} else if (strlen($raid_time) == 10) { debug_log('Generating buttons for minute of the hour'); - $hour = explode(" ", $raid_time); - $hour = $hour[1]; + $hour = substr($raid_time,8,2); // Buttons for each minute + $buttonData['callbackAction'] = 'edit_date'; for ($i = 0; $i <= 45; $i = $i + 15) { + $buttonData['t'] = $data['t'] . str_pad($i, 2, '0', STR_PAD_LEFT); // Create the keys. $keys[] = array( // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => substr($hour, 0, -1) . ':' . str_pad($i, 2, '0', STR_PAD_LEFT), - 'callback_data' => $id . ':edit_date:' . $arg . str_pad($i, 2, '0', STR_PAD_LEFT) . '-00' + 'text' => $hour . ':' . str_pad($i, 2, '0', STR_PAD_LEFT), + 'callback_data' => formatCallbackData($buttonData) ); } // Set keys count and message. $keys_count = 4; $msg = getTranslation('raid_select_start_time'); -// Received: Year-Month-Day Hour-Minute-Second / 1970-01-01 00-00-00 / 4x "-" -} else if (substr_count($raid_time, '-') == 4) { +// Received: YearMonthDayHourMinute / 197001010000 +} else if (strlen($raid_time) == 12) { debug_log('Received the following date for the raid: ' . $raid_time); // Format date, e.g 14 April 2019, 15:15h $tz = $config->TIMEZONE; - $tz_raid_time = DateTimeImmutable::createFromFormat('Y-m-d H-i-s', $raid_time, new DateTimeZone($tz)); + $tz_raid_time = DateTimeImmutable::createFromFormat('YmdHi', $raid_time, new DateTimeZone($tz)); $date_tz = $tz_raid_time->format('Y-m-d'); $text_split = explode('-', $date_tz); $text_day = $text_split[2]; @@ -73,15 +67,17 @@ // Raid time in UTC $utc_raid_time = $tz_raid_time->setTimezone(new DateTimeZone('UTC')); - $utc_raid_time = $utc_raid_time->format('Y-m-d H-i-s'); + $utc_raid_time = $utc_raid_time->format('YmdHi'); debug_log('Converting date to UTC to store in database'); debug_log('UTC date for the raid: ' . $utc_raid_time); debug_log('Waiting for confirmation to save the raid'); // Adding button to continue with next step in raid creation + $buttonData['callbackAction'] = 'edit_time'; + $buttonData['t'] = $utc_raid_time; $keys[] = array( 'text' => getTranslation('next'), - 'callback_data' => $id . ':edit_time:' . $event_id . ','. $raid_level . ',' . $pokemon_id . ',' . $utc_raid_time . ',X,0' + 'callback_data' => formatCallbackData($buttonData) ); // Set message. @@ -96,13 +92,19 @@ // Back key id, action and arg if(substr_count($raid_time, '-') == 1 || substr_count($raid_time, '-') == 4) { - $back_id = $id; - $back_action = 'edit_starttime'; - $back_arg = $arg; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); + $backData = $data; + $backData['callbackAction'] = 'edit_starttime'; + unset($backData['t']); + $nav_keys[] = [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData($backData) + ]; } -$nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); +$nav_keys[] = [ + 'text' => getTranslation('abort'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) +]; $nav_keys = inline_key_array($nav_keys, 2); // Merge keys. diff --git a/mods/edit_event.php b/mods/edit_event.php index 71f56038..2452a2ad 100644 --- a/mods/edit_event.php +++ b/mods/edit_event.php @@ -7,9 +7,6 @@ //debug_log($update); //debug_log($data); -// Set the id. -$gym_id_plus_letter = $data['id']; - //Initialize admin rights table [ ex-raid , raid-event ] $admin_access = [false, false]; // Check access - user must be admin for raid_level X @@ -18,34 +15,23 @@ $admin_access[1] = $botUser->accessCheck('event-raids', true); // Get the keys. -$keys = keys_event($gym_id_plus_letter, 'edit_event_raidlevel', $admin_access); - -// No keys found. -if (!$keys) { - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; -} else { - // Back key id, action and arg - $back_id_arg = explode(',', $gym_id_plus_letter); - $back_id = $back_id_arg[1]; - $back_action = 'edit_raidlevel'; - $back_arg = $back_id_arg[0]; - - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $back_arg, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - - // Merge keys. - $keys = array_merge($keys, $nav_keys); -} +$keys = keys_event($data, 'edit_event_raidlevel', $admin_access); + +$backData = $data; +$backData['callbackAction'] = 'edit_raidlevel'; + +// Add navigation keys. +$keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData($backData) + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + ] +]; + // Build callback message string. $callback_response = 'OK'; diff --git a/mods/edit_event_raidlevel.php b/mods/edit_event_raidlevel.php index adec89c9..75e663e0 100644 --- a/mods/edit_event_raidlevel.php +++ b/mods/edit_event_raidlevel.php @@ -9,18 +9,10 @@ //debug_log($data); // Get gym data via ID -$id_data = explode(",", $data['id']); -$gym_id = $id_data[0]; -$gym_first_letter = $id_data[1]; -$gym = get_gym($gym_id); +$gym = get_gym($data['g']); // Get event ID -$event_id = $data['arg']; - -// Back key id, action and arg -$back_id = $data['id']; -$back_action = 'edit_event'; -$back_arg = $data['arg']; +$event_id = $data['e']; // Telegram JSON array. $tg_json = array(); @@ -33,39 +25,33 @@ $admin_access[1] = $botUser->accessCheck('event-raids', true); // Get the keys. -$keys = raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access, $event_id); +$keys = raid_edit_raidlevel_keys($data, $admin_access, $event_id); + +$backData = $data; +$backData['callbackAction'] = 'edit_event'; +// Add navigation keys. +$keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData($backData) + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + ] +]; -// No keys found. -if (!$keys) { - // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; -} else { - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - // Merge keys. - $keys = array_merge($keys, $nav_keys); -} // Get event info $q = my_query('SELECT name, description FROM events WHERE id = ? LIMIT 1', [$event_id]); $rs = $q->fetch(); // Build message. if($event_id == 'X') { - $msg = "".getTranslation('Xstars')."".CR; + $msg = '' . getTranslation('Xstars') . '' . CR; }else { $msg = '' . $rs['name'] . '' . CR . $rs['description'] . CR; } -$msg.= getTranslation('create_raid') . ': ' . (($gym['address']=='') ? $gym['gym_name'] : $gym['address']) . ''; +$msg .= getTranslation('create_raid') . ': ' . (($gym['address']=='') ? $gym['gym_name'] : $gym['address']) . ''; // Build callback message string. $callback_response = getTranslation('gym_saved'); diff --git a/mods/edit_pokemon.php b/mods/edit_pokemon.php index b08e8808..b75d8464 100644 --- a/mods/edit_pokemon.php +++ b/mods/edit_pokemon.php @@ -10,17 +10,12 @@ // Check access. $botUser->accessCheck('create'); -// Set the id. -$gym_id_plus_letter = $data['id']; - -$arg_data = explode(",", $data['arg']); - // Set the raid level and event. -$event_id = $arg_data[0]; -$raid_level = $arg_data[1]; +$eventId = $data['e'] ?? NULL; +$raidLevel = $data['rl']; // Check if we are creating an event -if($event_id != "N") { +if($eventId != NULL) { // If yes, go to date selection $action = "edit_time"; }else { @@ -29,39 +24,23 @@ } // Get the keys. -$keys = pokemon_keys($gym_id_plus_letter, $raid_level, "edit_starttime", $event_id); - -// No keys found. -if (!$keys) { - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' - ] - ] - ]; -} else { - if($event_id == "N") { - $back_id_arg = explode(',', $gym_id_plus_letter); - $back_id = $back_id_arg[1]; - $back_action = 'edit_raidlevel'; - $back_arg = $back_id_arg[0]; - }else { - $back_id = $gym_id_plus_letter; - $back_action = 'edit_event_raidlevel'; - $back_arg = $event_id; - } - - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $back_arg, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - - // Merge keys. - $keys = array_merge($keys, $nav_keys); -} +$keys = pokemon_keys($data, $raidLevel, 'edit_starttime', $eventId); + +$back_action = ($eventId == NULL) ? 'edit_raidlevel' : 'edit_event_raidlevel'; + +// Add navigation keys. +$backData = $data; +$backData['callbackAction'] = $back_action; +$keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData($backData), + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + ] +]; // Build callback message string. $callback_response = 'OK'; diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index 2177e792..472da966 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -13,31 +13,82 @@ // Check access. $botUser->accessCheck('create'); -// Get gym data via ID in arg $gym_id = $data['g']; $gym = get_gym($gym_id); -$gym_first_letter = $data['fl'] ?? ''; -$showHidden = $data['h'] ?? 0; -$gymareaId = $data['ga'] ?? false; - // Telegram JSON array. $tg_json = array(); +//Initialize admin rights table [ ex-raid , raid-event ] +$admin_access = [false,false]; +// Check access - user must be admin for raid_level X +$admin_access[0] = $botUser->accessCheck('ex-raids', true); +// Check access - user must be admin for raid event creation +$admin_access[1] = $botUser->accessCheck('event-raids', true); + // Active raid? $duplicate_id = active_raid_duplication_check($gym_id); if ($duplicate_id > 0) { - $keys = []; - $raid_id = $duplicate_id; - $raid = get_raid($raid_id); - $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); - - $keys = share_keys($raid_id, 'raid_share', $update, $raid['level']); - - // Add keys for sharing the raid. - if(!empty($keys)) { - // Exit key - $keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); + // In case gym has already a normal raid saved to it and user has privileges to create an event raid, create a special menu + if($admin_access[0] == true || $admin_access[1] == true) { + $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . CR; + $msg .= getTranslation('inspect_raid_or_create_event') . ':'; + + $eventData = $backData = $data; + $eventData['callbackAction'] = 'edit_event'; + $backData['callbackAction'] = 'gymMenu'; + $backData['stage'] = 2; + $backData['a'] = 'create'; + $keys = [ + [ + [ + 'text' => getTranslation('saved_raid'), + 'callback_data' => formatCallbackData(['callbackAction' => 'raids_list', 'id' => $duplicate_id]) + ] + ], + [ + [ + 'text' => getTranslation('create_event_raid'), + 'callback_data' => formatCallbackData($eventData) + ] + ], + [ + [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData($backData) + ], + [ + 'text' => getTranslation('exit'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + ] + ], + ]; + } else { + $keys = []; + $raid_id = $duplicate_id; + $raid = get_raid($raid_id); + $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); + $keys = share_keys($raid_id, 'raid_share', $update, $raid['level']); + if($botUser->raidaccessCheck($raid['id'], 'pokemon', true)) { + $keys[] = [ + [ + 'text' => getTranslation('update_pokemon'), + 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], + ] + ]; + } + if($botUser->raidaccessCheck($raid['id'], 'delete', true)) { + $keys[] = [ + [ + 'text' => getTranslation('delete'), + 'callback_data' => $raid['id'] . ':raids_delete:0' + ] + ]; + } + $keys[][] = [ + 'text' => getTranslation('abort'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + ]; } // Answer callback. @@ -53,26 +104,22 @@ exit(); } -//Initialize admin rights table [ ex-raid , raid-event ] -$admin_access = [false,false]; -// Check access - user must be admin for raid_level X -$admin_access[0] = $botUser->accessCheck('ex-raids', true); -// Check access - user must be admin for raid event creation -$admin_access[1] = $botUser->accessCheck('event-raids', true); - // Get the keys. -$keys = raid_edit_raidlevel_keys($gym_id, $gym_first_letter, $admin_access); +$keys = raid_edit_raidlevel_keys($data, $admin_access); +$backData = $data; +$backData['callbackAction'] = 'gymMenu'; // Add navigation keys. -$nav_keys = []; -$nav_keys[] = [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'stage' => 2, 'a' => 'create', 'h' => $showHidden, 'ga' => $gymareaId, 'fl' => $gym_first_letter]) +$keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData($backData) + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + ] ]; -$nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); -$nav_keys = inline_key_array($nav_keys, 2); -// Merge keys. -$keys = array_merge($keys, $nav_keys); // Build message. $msg = getTranslation('create_raid') . ': ' . (($gym['address']=="") ? $gym['gym_name'] : $gym['address']) . ''; diff --git a/mods/edit_save.php b/mods/edit_save.php index 20f67dba..0328757f 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -10,72 +10,27 @@ // Check access. $botUser->accessCheck('create'); -// Set the id and arg. -if(substr_count($data['id'], ',') == 1) { - - $idval = explode(',', $data['id']); - $id = $idval[0]; - $arg = $idval[1]; - $chat = $data['arg']; -} else { - $id = $data['id']; - $arg = $data['arg']; - $chat = 0; -} +// Set raid id +$id = $data['r']; // Set the user id. $userid = $update['callback_query']['from']['id']; // Update only if time is not equal to RAID_DURATION -if($arg != $config->RAID_DURATION && $arg != 0) { +if($data['d'] != $config->RAID_DURATION) { // Build query. my_query(' UPDATE raids - SET end_time = DATE_ADD(start_time, INTERVAL ' . $arg . ' MINUTE) + SET end_time = DATE_ADD(start_time, INTERVAL ' . $data['d'] . ' MINUTE) WHERE id = :id ', ['id' => $id] ); } -// Fast forward to raid sharing. -if(substr_count($data['id'], ',') == 1) { - // Write to log. - debug_log('Doing a fast forward now!'); - debug_log('Changing data array first...'); - - // Reset data array - $data = []; - $data['id'] = $id; - $data['action'] = 'raid_share'; - $data['arg'] = $chat; - - // Write to log. - debug_log($data, '* NEW DATA= '); - - // Set module path by sent action name. - $module = ROOT_PATH . '/mods/raid_share.php'; - - // Write module to log. - debug_log($module); - - // Check if the module file exists. - if (file_exists($module)) { - // Dynamically include module file and exit. - include_once($module); - exit(); - } else { - info_log($module, 'Error! Fast forward failed as file does not exist:'); - exit(); - } -} - // Telegram JSON array. $tg_json = array(); -// Init keys. -$keys = []; - // Add delete to keys. $keys = [ [ @@ -87,41 +42,30 @@ ]; // Check access level prior allowing to change raid time -$admin_access = $botUser->accessCheck('raid-duration', true); -if($admin_access) { +if($botUser->accessCheck('raid-duration', true)) { // Add time change to keys. - $keys_time = [ + $keys[] = [ [ - [ - 'text' => getTranslation('change_raid_duration'), - 'callback_data' => $id . ':edit_time:0,0,0,0,more,1' - ] + 'text' => getTranslation('change_raid_duration'), + 'callback_data' => formatCallbackData(['callbackAction' => 'edit_time', 'r' => $id, 'o' => 'm']) ] ]; - $keys = array_merge($keys, $keys_time); } // Get raid times. -$raid = get_raid($data['id']); +$raid = get_raid($id); // Get raid level. $raid_level = $raid['level']; if($raid['event'] !== NULL) { - if($raid['event_note'] == NULL) { - $event_button_text = getTranslation("event_note_add"); - }else { - $event_button_text = getTranslation("event_note_edit"); - } - $keys_edit_event_note = [ + $event_button_text = ($raid['event_note'] == NULL) ? getTranslation("event_note_add") : getTranslation("event_note_edit"); + $keys[] = [ [ - [ - 'text' => $event_button_text, - 'callback_data' => $id . ':edit_event_note:0' - ] + 'text' => $event_button_text, + 'callback_data' => $id . ':edit_event_note:0' ] ]; - $keys = array_merge($keys, $keys_edit_event_note); } // Add keys to share. @@ -143,11 +87,7 @@ } // Build callback message string. -if($arg == 0) { - $callback_response = 'OK'; -}else { - $callback_response = getTranslation('end_time') . ' ' . $data['arg'] . ' ' . getTranslation('minutes'); -} +$callback_response = 'OK'; // Answer callback. $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index 90aeb0cd..16f5f382 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -10,23 +10,15 @@ $botUser->accessCheck('create'); // Get the argument. -$arg_data = explode(",", $data['arg']); -$event_id = $arg_data[0]; -$raid_level = $arg_data[1]; -$pokemon_id = $arg_data[2]; -$arg = ""; -// Check for options. -if (isset($arg_data[3])) -{ - // Switch time display ( min / clock ) - $arg = $arg_data[3]; -} +$event_id = $data['e'] ?? NULL; +$raid_level = $data['rl']; +$arg = $data['o'] ?? ''; + // Set the id. -$gym_id_plus_letter = $data['id']; -$gym_id = explode(',', $data['id'])[0]; +$gym_id = $data['g']; // Are we creating an event? -if($event_id != 'N' or $raid_level == 9) { +if($event_id != NULL or $raid_level == 9) { // Init empty keys array. $keys = []; @@ -37,22 +29,27 @@ // Create date buttons. Two days for Elite Raids, 15 days for EX raids. $days = ($raid_level == 9) ? 1 : 14; + unset($data['o']); + $buttonData = $data; + $buttonData['callbackAction'] = 'edit_date'; + // Drop these from callback_data string, these are no longer needed + unset($buttonData['fl']); + unset($buttonData['ga']); for ($d = 0; $d <= $days; $d++) { // Add day to today. $today_plus_d = $today->add(new DateInterval("P".$d."D")); // Format date, e.g 14 April 2019 - $date_tz = $today_plus_d->format('Y-m-d'); - $text_split = explode('-', $date_tz); - $text_day = $text_split[2]; - $text_month = getTranslation('month_' . $text_split[1]); - $text_year = $text_split[0]; + $date_tz = $today_plus_d->format('Ymd'); + $text_day = $today_plus_d->format('d'); + $text_month = getTranslation('month_' . $today_plus_d->format('m')); + $text_year = $today_plus_d->format('Y'); // Add keys. - $cb_date = $today_plus_d->format('Y-m-d'); + $buttonData['t'] = $date_tz; $keys[] = array( 'text' => $text_day . SP . $text_month . SP . $text_year, - 'callback_data' => $gym_id_plus_letter . ':edit_date:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . $cb_date + 'callback_data' => formatCallbackData($buttonData) ); } @@ -76,43 +73,36 @@ // Now $now = utcnow(); + // Copy received callbackData to new variable that we can edit + $buttonData = $data; + $buttonData['callbackAction'] = 'edit_time'; if ($arg == "min") { // Set switch view. $switch_text = getTranslation('raid_starts_when_clocktime_view'); $switch_view = "clock"; $key_count = 5; - for ($i = 1; $i <= $config->RAID_EGG_DURATION; $i = $i + 1) { - // Create new DateTime object, add minutes and convert back to string. - $now_plus_i = new DateTime($now, new DateTimeZone('UTC')); - $now_plus_i->add(new DateInterval('PT'.$i.'M')); - $now_plus_i = $now_plus_i->format("Y-m-d H:i:s"); - // Create the keys. - $keys[] = array( - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT), - 'callback_data' => $gym_id_plus_letter . ':edit_time:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . utctime($now_plus_i,"H-i") - ); - } } else { // Set switch view. $switch_text = getTranslation('raid_starts_when_minutes_view'); $switch_view = "min"; // Small screen fix $key_count = 4; - - for ($i = 1; $i <= $config->RAID_EGG_DURATION; $i = $i + 1) { - // Create new DateTime object, add minutes and convert back to string. - $now_plus_i = new DateTime($now, new DateTimeZone('UTC')); - $now_plus_i->add(new DateInterval('PT'.$i.'M')); - $now_plus_i = $now_plus_i->format("Y-m-d H:i:s"); - // Create the keys. - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - $keys[] = array( - 'text' => dt2time($now_plus_i), - 'callback_data' => $gym_id_plus_letter . ':edit_time:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . utctime($now_plus_i,"H-i") - ); - } + } + $now_plus_i = new DateTime($now, new DateTimeZone('UTC')); + for ($i = 1; $i <= $config->RAID_EGG_DURATION; $i = $i + 1) { + $now_plus_i->add(new DateInterval('PT1M')); + $buttonData['t'] = $now_plus_i->format("H:i"); + if ($arg == 'min') + $buttonText = floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT); + else + $buttonText = dt2time($now_plus_i->format('Y-m-d H:i:s')); + + // Create the keys. + $keys[] = array( + 'text' => $buttonText, + 'callback_data' => formatCallbackData($buttonData) + ); } // Get the inline key array. @@ -120,17 +110,22 @@ // Init empty keys other options array. $keys_opt = []; - + $keyData = $data; + $keyData['callbackAction'] = 'edit_time'; + $keyData['o'] = 'm'; + $keyData['t'] = utctime($now,"H-i"); // Raid already running $keys_opt[] = array( 'text' => getTranslation('is_raid_active'), - 'callback_data' => $gym_id_plus_letter . ':edit_time:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . utctime($now,"H-i").",more,0" + 'callback_data' => formatCallbackData($keyData) ); - + $keyData['callbackAction'] = 'edit_starttime'; + $keyData['o'] = $switch_view; + unset($keyData['t']); // Switch view: clocktime / minutes until start $keys_opt[] = array( 'text' => $switch_text, - 'callback_data' => $gym_id_plus_letter . ':edit_starttime:' . $event_id . ',' . $raid_level . ',' . $pokemon_id . ',' . $switch_view + 'callback_data' => formatCallbackData($keyData) ); // Get the inline key array. @@ -156,19 +151,19 @@ ] ]; } else { - // Back key id, action and arg - $back_id = $gym_id_plus_letter; - $back_action = 'edit_pokemon'; - $back_arg = $event_id . ',' . $raid_level; - + $backData = $data; + $backData['callbackAction'] = 'edit_pokemon'; // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, $gym_id, 'exit', '2', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - - // Merge keys. - $keys = array_merge($keys, $nav_keys); + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => formatCallbackData($backData) + ], + [ + 'text' => getTranslation('abort'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + ] + ]; } // Build callback message string. diff --git a/mods/edit_time.php b/mods/edit_time.php index f05e3f67..d1dc0633 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -12,48 +12,13 @@ // Check access. $botUser->accessCheck('create'); -// Get count of ID and argument. -$count_id = substr_count($data['id'], ','); - -// Set the id. -// Count 0 means we just received the raid_id -// Count 1 means we received gym_id and gym_first_letter -$raid_id = 0; -$gym_id = 0; -$gym_letter = 99; -if($count_id == 0) { - $raid_id = $data['id']; -} else if($count_id == 1) { - $gym_id_letter = explode(',', $data['id']); - $gym_id = $gym_id_letter[0]; - $gym_letter = $gym_id_letter[1]; -} - -// Count 3 means we received pokemon_table_id and starttime -// Count 4 means we received pokemon_table_id, starttime and an optional argument -// Count 5 means we received pokemon_table_id, starttime, optional argument and slot switch -$arg_data = explode(',', $data['arg']); -$count_arg = count($arg_data); -$event_id = $arg_data[0]; -$raid_level = $arg_data[1]; -$opt_arg = 'new-raid'; -$slot_switch = 0; -if($count_arg >= 4) { - $pokemon_table_id = $arg_data[2]; - $starttime = $arg_data[3]; -} -if($count_arg >= 5) { - $opt_arg = $arg_data[4]; -} -if($count_arg >= 6) { - $slot_switch = $arg_data[5]; -} - -// Write to log. -debug_log('count_id: ' . $count_id); -debug_log('count_arg: ' . $count_arg); -debug_log('opt_arg: ' . $opt_arg); -debug_log('slot_switch: ' . $slot_switch); +$raid_id = $data['r'] ?? 0; +$gym_id = $data['g'] ?? 0; +$event_id = $data['e'] ?? NULL; +$raid_level = $data['rl']; +$pokemon_table_id = $data['p']; +$starttime = $data['t'] ?? 0; +$opt_arg = $data['o'] ?? 'new-raid'; // Telegram JSON array. $tg_json = array(); @@ -64,26 +29,28 @@ if ($raid_id == 0 && $gym_id != 0) { // Replace "-" with ":" to get proper time format debug_log('Formatting the raid time properly now.'); - $arg_time = str_replace('-', ':', $starttime); // Event raids - if($event_id != 'N') { - debug_log('Event time :D ... Setting raid date to ' . $arg_time); - $start_date_time = $arg_time; - $query = my_query("SELECT raid_duration FROM events WHERE id = '{$event_id}' LIMIT 1"); + if($event_id != NULL) { + // Date was received in format YearMonthDayHourMinute so we need to reformat it to datetime + $start_date_time = substr($starttime,0,4) . '-' . substr($starttime,4,2) . '-' . substr($starttime,6,2) . ' ' . substr($starttime,8,2) . ':' . substr($starttime,10,2) . ':00'; + debug_log('Event time :D ... Setting raid date to ' . $start_date_time); + $query = my_query('SELECT raid_duration FROM events WHERE id = ? LIMIT 1', [$event_id]); $result = $query->fetch(); $duration = $result['raid_duration'] ?? $config->RAID_DURATION; $egg_duration = $config->RAID_EGG_DURATION; // Elite raids }elseif($raid_level == 9) { - debug_log('Elite Raid time :D ... Setting raid date to ' . $arg_time); - $start_date_time = $arg_time; + // Date was received in format YearMonthDayHourMinute so we need to reformat it to datetime + $start_date_time = substr($starttime,0,4) . '-' . substr($starttime,4,2) . '-' . substr($starttime,6,2) . ' ' . substr($starttime,8,2) . ':' . substr($starttime,10,2) . ':00'; + debug_log('Elite Raid time :D ... Setting raid date to ' . $start_date_time); $duration = $config->RAID_DURATION_ELITE; $egg_duration = $config->RAID_EGG_DURATION_ELITE; // Normal raids } else { + $arg_time = str_replace('-', ':', $starttime); // Current date $current_date = date('Y-m-d', strtotime('now')); debug_log('Today is a raid day! Setting raid date to ' . $current_date); @@ -97,50 +64,12 @@ // Check for duplicate raid $duplicate_id = active_raid_duplication_check($gym_id); - // Continue with raid creation - if($duplicate_id == 0) { - // Now. - $now = utcnow(); - - $pokemon_id_formid = get_pokemon_by_table_id($pokemon_table_id); - - // Saving event info to db. N = null - $event = (($event_id == "N") ? NULL : (($event_id=="X") ? EVENT_ID_EX : $event_id )); - debug_log("Event: ".$event); - debug_log("Event-id: ".$event_id); - debug_log("Raid level: ".$raid_level); - debug_log("Pokemon: ".$pokemon_id_formid['pokedex_id']."-".$pokemon_id_formid['pokemon_form_id']); - - // Create raid in database. - $rs = my_query(' - INSERT INTO raids - SET user_id = :userId, - pokemon = :pokemon, - pokemon_form = :pokemonForm, - start_time = :startTime, - spawn = DATE_SUB(start_time, INTERVAL ' . $egg_duration . ' MINUTE), - end_time = DATE_ADD(start_time, INTERVAL ' . $duration . ' MINUTE), - gym_id = :gymId, - level = :level, - event = :event - ', [ - 'userId' => $update['callback_query']['from']['id'], - 'pokemon' => $pokemon_id_formid['pokedex_id'], - 'pokemonForm' => $pokemon_id_formid['pokemon_form_id'], - 'startTime' => $start_date_time, - 'gymId' => $gym_id, - 'level' => $raid_level, - 'event' => $event, - ]); - - // Get last insert id from db. - $raid_id = $dbh->lastInsertId(); - - // Write to log. - debug_log('ID=' . $raid_id); - // Tell user the raid already exists and exit! - } else { + // Unless we are creating an event raid + if($duplicate_id != 0 && + !($event_id == EVENT_ID_EX && $botUser->accessCheck('ex-raids', true)) && + !($event_id != EVENT_ID_EX && $event_id != NULL && $botUser->accessCheck('event-raids', true)) + ) { $keys = []; $raid_id = $duplicate_id; $raid = get_raid($raid_id); @@ -166,13 +95,48 @@ // Exit. exit(); } + // Continue with raid creation + $pokemon_id_formid = get_pokemon_by_table_id($pokemon_table_id); + + // Saving event info to db. N = null + debug_log("Event-id: ".$event_id); + debug_log("Raid level: ".$raid_level); + debug_log("Pokemon: ".$pokemon_id_formid['pokedex_id']."-".$pokemon_id_formid['pokemon_form_id']); + + // Create raid in database. + $rs = my_query(' + INSERT INTO raids + SET user_id = :userId, + pokemon = :pokemon, + pokemon_form = :pokemonForm, + start_time = :startTime, + spawn = DATE_SUB(start_time, INTERVAL ' . $egg_duration . ' MINUTE), + end_time = DATE_ADD(start_time, INTERVAL ' . $duration . ' MINUTE), + gym_id = :gymId, + level = :level, + event = :event + ', [ + 'userId' => $update['callback_query']['from']['id'], + 'pokemon' => $pokemon_id_formid['pokedex_id'], + 'pokemonForm' => $pokemon_id_formid['pokemon_form_id'], + 'startTime' => $start_date_time, + 'gymId' => $gym_id, + 'level' => $raid_level, + 'event' => $event_id, + ]); + + // Get last insert id from db. + $raid_id = $dbh->lastInsertId(); + + // Write to log. + debug_log('ID=' . $raid_id); } // Init empty keys array. $keys = []; // Raid pokemon duration short or 1 Minute / 5 minute time slots -if($opt_arg == 'more') { +if($opt_arg == 'm') { // 1-minute selection $slotsize = 1; @@ -183,56 +147,39 @@ $keys[] = array( // Just show the time, no text - not everyone has a phone or tablet with a large screen... 'text' => floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT), - 'callback_data' => $raid_id . ':edit_save:' . $i + 'callback_data' => formatCallbackData(['callbackAction' => 'edit_save', 'd' => $i, 'r' => $raid_id]) ); } } else { debug_log('Comparing slot switch and argument for fast forward'); - if ($slot_switch == 0) { - $raidduration = $config->RAID_DURATION; + $raidduration = $config->RAID_DURATION; - // Write to log. - debug_log('Doing a fast forward now!'); - debug_log('Changing data array first...'); + // Write to log. + debug_log('Doing a fast forward now!'); + debug_log('Changing data array first...'); - // Reset data array - $data = []; - $data['id'] = $raid_id; - $data['action'] = 'edit_save'; - $data['arg'] = $raidduration; + // Reset data array + $data = []; + $data['r'] = $raid_id; + $data['callbackAction'] = 'edit_save'; + $data['d'] = $raidduration; - // Write to log. - debug_log($data, '* NEW DATA= '); + // Write to log. + debug_log($data, '* NEW DATA= '); - // Set module path by sent action name. - $module = ROOT_PATH . '/mods/edit_save.php'; + // Set module path by sent action name. + $module = ROOT_PATH . '/mods/edit_save.php'; - // Write module to log. - debug_log($module); + // Write module to log. + debug_log($module); - // Check if the module file exists. - if (file_exists($module)) { - // Dynamically include module file and exit. - include_once($module); - exit(); - } - } else { - - // Use raid pokemon duration short. - // Use normal raid duration. - $keys[] = array( - 'text' => '0:' . $config->RAID_DURATION, - 'callback_data' => $raid_id . ':edit_save:' . $config->RAID_DURATION - ); - - // Button for more options. - $keys[] = array( - 'text' => getTranslation('expand'), - 'callback_data' => $raid_id . ':edit_time:' . $pokemon_id . ',' . $start_time . ',more,' . $slot_switch - ); - - } + // Check if the module file exists. + if (file_exists($module)) { + // Dynamically include module file and exit. + include_once($module); + exit(); + } } // Get the inline key array. @@ -242,7 +189,7 @@ debug_log($keys); // Build callback message string. -if ($opt_arg != 'more' && $event_id == 'N') { +if ($opt_arg != 'more' && $event_id == NULL) { $callback_response = getTranslation('start_date_time') . ' ' . $arg_time; } else { $callback_response = getTranslation('raid_starts_when_view_changed'); diff --git a/mods/exit.php b/mods/exit.php index bdd4bd78..116dbb62 100644 --- a/mods/exit.php +++ b/mods/exit.php @@ -8,9 +8,10 @@ // Set empty keys. $keys = []; +$arg = $data['arg'] ?? 0; // Build message string. -$msg = ($data['arg'] == 1) ? (getTranslation('done') . '!') : (getTranslation('action_aborted')); +$msg = ($arg == 1) ? (getTranslation('done') . '!') : (getTranslation('action_aborted')); // Telegram JSON array. $tg_json = array(); diff --git a/mods/raids_list.php b/mods/raids_list.php index 50a74eff..876a4f92 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -27,18 +27,18 @@ ]; if($botUser->raidaccessCheck($raidId, 'pokemon', true)) { $keys[] = [ - [ - 'text' => getTranslation('update_pokemon'), - 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], - ] + [ + 'text' => getTranslation('update_pokemon'), + 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], + ] ]; } if($botUser->raidaccessCheck($raidId, 'delete', true)) { $keys[] = [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => $raid['id'] . ':raids_delete:0' - ] + [ + 'text' => getTranslation('delete'), + 'callback_data' => $raid['id'] . ':raids_delete:0' + ] ]; } @@ -51,7 +51,10 @@ debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key -$keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); +$keys[][] = [ + 'text' => getTranslation('done'), + 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) +]; // Get message. $msg = show_raid_poll_small($raid); From 6b1254cb577848edbfb82318d7847933a6d14845 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 6 Dec 2022 21:56:20 +0200 Subject: [PATCH 180/367] Fixes --- mods/edit_raidlevel.php | 2 ++ mods/edit_time.php | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index 472da966..ebef93cc 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -109,6 +109,8 @@ $backData = $data; $backData['callbackAction'] = 'gymMenu'; +$backData['a'] = 'create'; +$backData['stage'] = 2; // Add navigation keys. $keys[] = [ [ diff --git a/mods/edit_time.php b/mods/edit_time.php index d1dc0633..a6e0ec6e 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -15,8 +15,8 @@ $raid_id = $data['r'] ?? 0; $gym_id = $data['g'] ?? 0; $event_id = $data['e'] ?? NULL; -$raid_level = $data['rl']; -$pokemon_table_id = $data['p']; +$raid_level = $data['rl'] ?? 0; +$pokemon_table_id = $data['p'] ?? 0; $starttime = $data['t'] ?? 0; $opt_arg = $data['o'] ?? 'new-raid'; @@ -190,7 +190,7 @@ // Build callback message string. if ($opt_arg != 'more' && $event_id == NULL) { - $callback_response = getTranslation('start_date_time') . ' ' . $arg_time; + $callback_response = 'OK'; } else { $callback_response = getTranslation('raid_starts_when_view_changed'); } From 68d312fd185135c3b971bca65f83f8c78df48191 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 6 Dec 2022 23:13:47 +0200 Subject: [PATCH 181/367] Renamed `callbackAction` array key to `0` in callback data handling Also further improved the start menu --- commands/trainer.php | 8 ++-- core/bot/ddos.php | 6 +-- core/bot/modules.php | 5 +-- index.php | 4 +- logic/edit_gym_keys.php | 16 ++++---- logic/gymMenu.php | 64 ++++++++++++++---------------- logic/key_util.php | 4 +- logic/keys_event.php | 2 +- logic/pokemon_keys.php | 2 +- logic/raid_edit_raidlevel_keys.php | 6 +-- logic/raid_get_gyms_list_keys.php | 2 +- mods/edit_date.php | 10 ++--- mods/edit_event.php | 4 +- mods/edit_event_raidlevel.php | 4 +- mods/edit_pokemon.php | 4 +- mods/edit_raidlevel.php | 14 +++---- mods/edit_save.php | 2 +- mods/edit_starttime.php | 12 +++--- mods/edit_time.php | 4 +- mods/gym_delete.php | 4 +- mods/gym_edit_details.php | 6 +-- mods/list_raid.php | 4 +- mods/pogoinfo.php | 20 +++++----- mods/pokebattler.php | 20 +++++----- mods/raids_list.php | 2 +- mods/trainer.php | 2 +- mods/trainerGymarea.php | 6 +-- mods/trainer_code.php | 56 +++++++++++++------------- mods/trainer_name.php | 13 +++--- 29 files changed, 150 insertions(+), 156 deletions(-) diff --git a/commands/trainer.php b/commands/trainer.php index 1a05597c..010f6564 100644 --- a/commands/trainer.php +++ b/commands/trainer.php @@ -13,7 +13,7 @@ // Set message. $msg = '' . getTranslation('trainerinfo_set_yours') . ''; -$user_id = $update['message']['from']['id']; +$user_id = $botUser->userId; $msg .= CR . CR . get_user($user_id, false); // Init empty keys array. @@ -42,12 +42,12 @@ ] ]; if ($config->RAID_AUTOMATIC_ALARM == false) { - $q_user = my_query("SELECT auto_alarm FROM users WHERE user_id = '{$user_id}' LIMIT 1"); + $q_user = my_query('SELECT auto_alarm FROM users WHERE user_id = ? LIMIT 1', [$user_id]); $alarm_status = $q_user->fetch()['auto_alarm']; $keys[] = [ [ 'text' => ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), - 'callback_data' => '0:trainer:a' + 'callback_data' => formatCallbackData(['trainerGymarea', 'a' => ($alarm_status == 1 ? 0 : 1)]) ] ]; } @@ -63,7 +63,7 @@ $keys[] = [ [ 'text' => getTranslation('default_gymarea'), - 'callback_data' => formatCallbackData(['callbackAction' => 'trainerGymarea']) + 'callback_data' => 'trainerGymarea' ] ]; } diff --git a/core/bot/ddos.php b/core/bot/ddos.php index 7bf77fda..4ccff56d 100644 --- a/core/bot/ddos.php +++ b/core/bot/ddos.php @@ -14,8 +14,8 @@ function verifyUpdate($update, $data) { global $metrics; if ($update['type'] == 'callback_query' - && (in_array($data['callbackAction'], ['overview_refresh', 'refresh_polls', 'getdb', 'update_bosses']) - or ($data['callbackAction'] == 'post_raid' && $update['skip_ddos'] == true)) + && (in_array($data[0], ['overview_refresh', 'refresh_polls', 'getdb', 'update_bosses']) + or ($data[0] == 'post_raid' && $update['skip_ddos'] == true)) or isset($update['cleanup'])) { debug_log('Skipping DDOS check...','!'); @@ -51,7 +51,7 @@ function ddosCheck($update, $data) { // Get callback query data if (!isset($update['callback_query']) or !$update['callback_query']['data']) return; // Split callback data and assign to data array. - $splitAction = explode('_', $data['callbackAction']); + $splitAction = explode('_', $data[0]); // Check the action if ($splitAction[0] != 'vote') return; diff --git a/core/bot/modules.php b/core/bot/modules.php index 816b7a9f..68b8d08a 100644 --- a/core/bot/modules.php +++ b/core/bot/modules.php @@ -1,13 +1,13 @@ 2) { $data['id'] = $splitDataOld[0]; - $data['callbackAction'] = $splitDataOld[1]; + $data[0] = $splitDataOld[1]; $data['arg'] = $splitDataOld[2]; }else { $splitData = explode('|', $thedata); - $data['callbackAction'] = $splitData[0]; + $data[0] = $splitData[0]; unset($splitData[0]); foreach($splitData as $dataPiece) { [$key, $value] = explode('=', $dataPiece, 2); diff --git a/logic/edit_gym_keys.php b/logic/edit_gym_keys.php index 4ca45b94..b32d34d4 100644 --- a/logic/edit_gym_keys.php +++ b/logic/edit_gym_keys.php @@ -22,22 +22,22 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add // Add buttons to show/hide the gym and add/remove ex-raid flag $keys = []; - $callback = ['callbackAction' => 'gym_edit_details', 'g' => $gym_id]; + $callback = ['gym_edit_details', 'g' => $gym_id]; $keys[] = [ [ 'text' => $text_show_button, - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'show', 'v' => $arg_show]) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'show', 'v' => $arg_show]) ], [ 'text' => $text_ex_button, - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'ex', 'v' => $arg_ex]) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'ex', 'v' => $arg_ex]) ] ]; if($botUser->accessCheck('gym-name', true)) { $keys[] = [ [ 'text' => EMOJI_PENCIL . ' ' . getTranslation("gym_name_edit"), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'name']) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'name']) ] ]; } @@ -45,19 +45,19 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add $keys[] = [ [ 'text' => EMOJI_INFO . ' ' . (!empty($gym_note) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_add_edit_note"), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'note']) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'note']) ] ]; $keys[] = [ [ 'text' => EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("directions")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'addr']) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'addr']) ] ]; $keys[] = [ [ 'text' => EMOJI_HERE . ' ' . getTranslation("gym_edit_coordinates"), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'gps']) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'gps']) ] ]; } @@ -65,7 +65,7 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add $keys[] = [ [ 'text' => EMOJI_DELETE . ' ' . getTranslation("gym_delete"), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_delete', 'g' => $gym_id, 'c' => 0]) + 'callback_data' => formatCallbackData(['gym_delete', 'g' => $gym_id, 'c' => 0]) ] ]; } diff --git a/logic/gymMenu.php b/logic/gymMenu.php index 31ab263c..60f0a810 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -29,7 +29,7 @@ function gymMenu($buttonAction, $showHidden, $stage, $firstLetter = false, $gyma // Stage 2: Gym names $stage = ($config->ENABLE_GYM_AREAS && $stage == 1 && $gymareaId == false) ? 0 : $stage; [$gymareaName, $gymareaKeys, $gymareaQuery] = ($config->ENABLE_GYM_AREAS) ? getGymareas($gymareaId, $stage, $buttonAction) : ['', [], '']; - if($stage == 2) + if($stage == 2 && $firstLetter != '') $gymKeys = createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery, $buttonAction, $gymareaId); else $gymKeys = createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $stage); @@ -53,56 +53,52 @@ function gymMenu($buttonAction, $showHidden, $stage, $firstLetter = false, $gyma if($config->RAID_VIA_LOCATION_FUNCTION == 'remote' && $buttonAction == 'list') { $query_remote = my_query('SELECT count(*) as count FROM raids LEFT JOIN gyms on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); if($query_remote->fetch()['count'] > 0) { - $keys = array_merge($keys, [[[ + $keys[][] = [ 'text' => getTranslation('remote_raids'), - 'callback_data' => formatCallbackData(['callbackAction' => 'list_remote_raids']) - ]]]); + 'callback_data' => 'list_remote_raids' + ]; } } // Merge keys. - if($stage < 2 && $showHidden == 0) { + if(($stage < 2 or ($stage == 2 && $firstLetter == '')) && $showHidden == 0) { $keys = array_merge($keys, inline_key_array($gymareaKeys, 2)); } // Add key for hidden gyms. if($buttonAction == 'gym') { if($stage == 1 && $showHidden == 0) { // Add key for hidden gyms. - $h_keys[] = [ - [ - 'text' => getTranslation('hidden_gyms'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'h' => 1, 'a' => 'gym', 'ga' => $gymareaId]) - ] + $h_keys[][] = [ + 'text' => getTranslation('hidden_gyms'), + 'callback_data' => formatCallbackData(['gymMenu', 'h' => 1, 'a' => 'gym', 'ga' => $gymareaId]) ]; $keys = array_merge($h_keys, $keys); } if($stage == 0 && $botUser->accessCheck('gym-add', true)) { - $keys[] = [ - [ - 'text' => getTranslation('gym_create'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_create']) - ] + $keys[][] = [ + 'text' => getTranslation('gym_create'), + 'callback_data' => 'gym_create' ]; } } - if($stage == 1 && $config->DEFAULT_GYM_AREA === false) { + if((($stage == 1 or ($stage == 2 && $firstLetter == '')) && $config->DEFAULT_GYM_AREA === false)) { $backKey = [ 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'stage' => 0, 'a' => $buttonAction]) + 'callback_data' => formatCallbackData(['gymMenu', 'stage' => 0, 'a' => $buttonAction]) ]; - }elseif($stage == 2) { + }elseif($stage == 2 && $firstLetter !== '') { $backKey = [ 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'stage' => 1, 'a' => $buttonAction, 'h' => $showHidden, 'ga' => $gymareaId]) + 'callback_data' => formatCallbackData(['gymMenu', 'stage' => 1, 'a' => $buttonAction, 'h' => $showHidden, 'ga' => $gymareaId]) ]; } $abortKey = [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit', 'arg' => 0]) + 'callback_data' => 'exit' ]; - if(isset($backKey)) + if (isset($backKey)) { $keys[] = [$backKey, $abortKey]; - else - $keys[] = [$abortKey]; + }else{ + $keys[] = [$abortKey];} return ['keys' => $keys, 'gymareaTitle' => $gymareaTitle]; } @@ -123,18 +119,18 @@ function getGymareas($gymareaId, $stage, $buttonAction) { } $gymareaName = $area['name']; if($points[0] != $points[count($points)-1]) $points[] = $points[0]; - } else { - $gymareaKeys[] = [ - 'text' => $area['name'], - 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'a' => $buttonAction, 'stage' => 1, 'ga' => $area['id']]) - ]; } + if ($stage != 0 && $gymareaId == $area['id']) continue; + $gymareaKeys[] = [ + 'text' => $area['name'], + 'callback_data' => formatCallbackData(['gymMenu', 'a' => $buttonAction, 'stage' => 1, 'ga' => $area['id']]) + ]; } if(count($gymareaKeys) > 6 && $stage != 0) { // If list of area buttons is getting too large, replace it with a key that opens a submenu $gymareaKeys = [[ 'text' => getTranslation('gymareas'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'a' => $buttonAction, 'stage' => 0]) + 'callback_data' => formatCallbackData(['gymMenu', 'a' => $buttonAction, 'stage' => 0]) ]]; } $polygon_string = implode(',', $points); @@ -148,7 +144,7 @@ function getGymareas($gymareaId, $stage, $buttonAction) { * @param int $gymareaId * @param string $gymareaQuery * @param int $stage - * @return array + * @return array [keyArray, isArrayListOfLetters] */ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $stage) { global $config, $menuActions, $botUser; @@ -183,7 +179,7 @@ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $s // Found 20 or less gyms, print gym names if($gym_count['count'] <= 20) { $keys = createGymListKeysByFirstLetter('', $showHidden, $gymareaQuery, $buttonAction, $gymareaId); - return [$keys[0], false]; + return $keys; } // If found over 20 gyms, print letters @@ -217,7 +213,7 @@ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $s // Add first letter to keys array $keys[] = array( 'text' => $gym['first_letter'], - 'callback_data' => formatCallbackData(['callbackAction' => 'gymMenu', 'a' => $buttonAction, 'stage' => $stage+1, 'fl' => $gym['first_letter'], 'ga' => $gymareaId]) + 'callback_data' => formatCallbackData(['gymMenu', 'a' => $buttonAction, 'stage' => $stage+1, 'fl' => $gym['first_letter'], 'ga' => $gymareaId]) ); } @@ -299,7 +295,7 @@ function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery $gym_name = EMOJI_WARN . SP . $gym_name; } $callback = [ - 'callbackAction' => $menuActions[$buttonAction], + $menuActions[$buttonAction], 'g' => $gym['id'], 'ga' => $gymareaId, 'fl' => $firstLetter, @@ -314,6 +310,6 @@ function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery // Get the inline key array. $keys = inline_key_array($keys, 1); - return [$keys]; + return [$keys, false]; } diff --git a/logic/key_util.php b/logic/key_util.php index e08c45e6..b2b496b0 100644 --- a/logic/key_util.php +++ b/logic/key_util.php @@ -169,8 +169,8 @@ function share_keys($id, $action, $update, $raidLevel = '', $chats = '', $hideGe */ function formatCallbackData($array) { - $return = $array['callbackAction'] . '|'; - unset($array['callbackAction']); + $return = $array[0] . '|'; + unset($array[0]); foreach($array as $key => $value) { $return .= $key . '=' . $value . '|'; } diff --git a/logic/keys_event.php b/logic/keys_event.php index 4a402531..28287830 100644 --- a/logic/keys_event.php +++ b/logic/keys_event.php @@ -8,7 +8,7 @@ */ function keys_event($callbackData, $action, $admin_access = [false,false]) { $keys = []; - $callbackData['callbackAction'] = $action; + $callbackData[0] = $action; if($admin_access[1] === true) { $q = my_query(' SELECT id, diff --git a/logic/pokemon_keys.php b/logic/pokemon_keys.php index d66ddbd8..bbc2419e 100644 --- a/logic/pokemon_keys.php +++ b/logic/pokemon_keys.php @@ -37,7 +37,7 @@ function pokemon_keys($callbackData, $raid_level, $action, $event_id = false) ', ['raidLevel' => $raid_level, 'eggId' => $egg_id] ); // Add key for each raid level - $callbackData['callbackAction'] = $action; + $callbackData[0] = $action; while ($pokemon = $rs->fetch()) { $callbackData['p'] = $pokemon['id']; $keys[] = array( diff --git a/logic/raid_edit_raidlevel_keys.php b/logic/raid_edit_raidlevel_keys.php index d1c76936..223065f2 100644 --- a/logic/raid_edit_raidlevel_keys.php +++ b/logic/raid_edit_raidlevel_keys.php @@ -40,7 +40,7 @@ function raid_edit_raidlevel_keys($callbackData, $admin_access = [false,false], // Add key for pokemon if we have just 1 pokemon for a level if($level['raid_level_count'] != 1) { // Raid level and action - $buttonData['callbackAction'] = 'edit_pokemon'; + $buttonData[0] = 'edit_pokemon'; $buttonData['rl'] = $level['raid_level']; // Add key for raid level $keys[] = array( @@ -65,7 +65,7 @@ function raid_edit_raidlevel_keys($callbackData, $admin_access = [false,false], ', [$level['raid_level']] ); $pokemon = $query_mon->fetch(); - $buttonData['callbackAction'] = 'edit_starttime'; + $buttonData[0] = 'edit_starttime'; $buttonData['rl'] = $level['raid_level']; $buttonData['p'] = $pokemon['id']; // Add key for pokemon @@ -78,7 +78,7 @@ function raid_edit_raidlevel_keys($callbackData, $admin_access = [false,false], // Add key for raid event if user allowed to create event raids if(($admin_access[1] === true or $admin_access[0] === true) && $event === false) { $eventData = $callbackData; - $eventData['callbackAction'] = 'edit_event'; + $eventData[0] = 'edit_event'; $keys[] = array( 'text' => getTranslation('event'), 'callback_data' => formatCallbackData($eventData) diff --git a/logic/raid_get_gyms_list_keys.php b/logic/raid_get_gyms_list_keys.php index 3b1ddbea..7e6f82d4 100644 --- a/logic/raid_get_gyms_list_keys.php +++ b/logic/raid_get_gyms_list_keys.php @@ -30,7 +30,7 @@ function raid_get_gyms_list_keys($searchterm) $first = strtoupper(substr($gym['gym_name'], 0, 1)); $keys[] = array( 'text' => $gym['gym_name'], - 'callback_data' => formatCallbackData(['callbackAction' => 'edit_raidlevel', 'g' => $gym['id'], 'fl' => $first]) + 'callback_data' => formatCallbackData(['edit_raidlevel', 'g' => $gym['id'], 'fl' => $first]) ); } diff --git a/mods/edit_date.php b/mods/edit_date.php index 3435b68d..20a4ae30 100644 --- a/mods/edit_date.php +++ b/mods/edit_date.php @@ -20,7 +20,7 @@ if (strlen($raid_time) == 8) { debug_log('Generating buttons for each hour of the day'); // Buttons for each hour - $buttonData['callbackAction'] = 'edit_date'; + $buttonData[0] = 'edit_date'; for ($i = 0; $i <= 23; $i = $i + 1) { $buttonData['t'] = $data['t'] . str_pad($i, 2, '0', STR_PAD_LEFT); // Create the keys. @@ -38,7 +38,7 @@ debug_log('Generating buttons for minute of the hour'); $hour = substr($raid_time,8,2); // Buttons for each minute - $buttonData['callbackAction'] = 'edit_date'; + $buttonData[0] = 'edit_date'; for ($i = 0; $i <= 45; $i = $i + 15) { $buttonData['t'] = $data['t'] . str_pad($i, 2, '0', STR_PAD_LEFT); // Create the keys. @@ -73,7 +73,7 @@ debug_log('Waiting for confirmation to save the raid'); // Adding button to continue with next step in raid creation - $buttonData['callbackAction'] = 'edit_time'; + $buttonData[0] = 'edit_time'; $buttonData['t'] = $utc_raid_time; $keys[] = array( 'text' => getTranslation('next'), @@ -93,7 +93,7 @@ // Back key id, action and arg if(substr_count($raid_time, '-') == 1 || substr_count($raid_time, '-') == 4) { $backData = $data; - $backData['callbackAction'] = 'edit_starttime'; + $backData[0] = 'edit_starttime'; unset($backData['t']); $nav_keys[] = [ 'text' => getTranslation('back'), @@ -103,7 +103,7 @@ $nav_keys[] = [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ]; $nav_keys = inline_key_array($nav_keys, 2); diff --git a/mods/edit_event.php b/mods/edit_event.php index 2452a2ad..19d4220e 100644 --- a/mods/edit_event.php +++ b/mods/edit_event.php @@ -18,7 +18,7 @@ $keys = keys_event($data, 'edit_event_raidlevel', $admin_access); $backData = $data; -$backData['callbackAction'] = 'edit_raidlevel'; +$backData[0] = 'edit_raidlevel'; // Add navigation keys. $keys[] = [ @@ -28,7 +28,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ] ]; diff --git a/mods/edit_event_raidlevel.php b/mods/edit_event_raidlevel.php index 75e663e0..bd50e700 100644 --- a/mods/edit_event_raidlevel.php +++ b/mods/edit_event_raidlevel.php @@ -28,7 +28,7 @@ $keys = raid_edit_raidlevel_keys($data, $admin_access, $event_id); $backData = $data; -$backData['callbackAction'] = 'edit_event'; +$backData[0] = 'edit_event'; // Add navigation keys. $keys[] = [ [ @@ -37,7 +37,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ] ]; diff --git a/mods/edit_pokemon.php b/mods/edit_pokemon.php index b75d8464..1562550f 100644 --- a/mods/edit_pokemon.php +++ b/mods/edit_pokemon.php @@ -30,7 +30,7 @@ // Add navigation keys. $backData = $data; -$backData['callbackAction'] = $back_action; +$backData[0] = $back_action; $keys[] = [ [ 'text' => getTranslation('back'), @@ -38,7 +38,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ] ]; diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index ebef93cc..8724b610 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -35,15 +35,15 @@ $msg .= getTranslation('inspect_raid_or_create_event') . ':'; $eventData = $backData = $data; - $eventData['callbackAction'] = 'edit_event'; - $backData['callbackAction'] = 'gymMenu'; + $eventData[0] = 'edit_event'; + $backData[0] = 'gymMenu'; $backData['stage'] = 2; $backData['a'] = 'create'; $keys = [ [ [ 'text' => getTranslation('saved_raid'), - 'callback_data' => formatCallbackData(['callbackAction' => 'raids_list', 'id' => $duplicate_id]) + 'callback_data' => formatCallbackData(['raids_list', 'id' => $duplicate_id]) ] ], [ @@ -59,7 +59,7 @@ ], [ 'text' => getTranslation('exit'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ] ], ]; @@ -87,7 +87,7 @@ } $keys[][] = [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ]; } @@ -108,7 +108,7 @@ $keys = raid_edit_raidlevel_keys($data, $admin_access); $backData = $data; -$backData['callbackAction'] = 'gymMenu'; +$backData[0] = 'gymMenu'; $backData['a'] = 'create'; $backData['stage'] = 2; // Add navigation keys. @@ -119,7 +119,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ] ]; diff --git a/mods/edit_save.php b/mods/edit_save.php index 0328757f..11574e38 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -47,7 +47,7 @@ $keys[] = [ [ 'text' => getTranslation('change_raid_duration'), - 'callback_data' => formatCallbackData(['callbackAction' => 'edit_time', 'r' => $id, 'o' => 'm']) + 'callback_data' => formatCallbackData(['edit_time', 'r' => $id, 'o' => 'm']) ] ]; } diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index 16f5f382..e8306d01 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -31,7 +31,7 @@ $days = ($raid_level == 9) ? 1 : 14; unset($data['o']); $buttonData = $data; - $buttonData['callbackAction'] = 'edit_date'; + $buttonData[0] = 'edit_date'; // Drop these from callback_data string, these are no longer needed unset($buttonData['fl']); unset($buttonData['ga']); @@ -75,7 +75,7 @@ // Copy received callbackData to new variable that we can edit $buttonData = $data; - $buttonData['callbackAction'] = 'edit_time'; + $buttonData[0] = 'edit_time'; if ($arg == "min") { // Set switch view. $switch_text = getTranslation('raid_starts_when_clocktime_view'); @@ -111,7 +111,7 @@ // Init empty keys other options array. $keys_opt = []; $keyData = $data; - $keyData['callbackAction'] = 'edit_time'; + $keyData[0] = 'edit_time'; $keyData['o'] = 'm'; $keyData['t'] = utctime($now,"H-i"); // Raid already running @@ -119,7 +119,7 @@ 'text' => getTranslation('is_raid_active'), 'callback_data' => formatCallbackData($keyData) ); - $keyData['callbackAction'] = 'edit_starttime'; + $keyData[0] = 'edit_starttime'; $keyData['o'] = $switch_view; unset($keyData['t']); // Switch view: clocktime / minutes until start @@ -152,7 +152,7 @@ ]; } else { $backData = $data; - $backData['callbackAction'] = 'edit_pokemon'; + $backData[0] = 'edit_pokemon'; // Add navigation keys. $keys[] = [ [ @@ -161,7 +161,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ] ]; } diff --git a/mods/edit_time.php b/mods/edit_time.php index a6e0ec6e..1b743f01 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -147,7 +147,7 @@ $keys[] = array( // Just show the time, no text - not everyone has a phone or tablet with a large screen... 'text' => floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT), - 'callback_data' => formatCallbackData(['callbackAction' => 'edit_save', 'd' => $i, 'r' => $raid_id]) + 'callback_data' => formatCallbackData(['edit_save', 'd' => $i, 'r' => $raid_id]) ); } @@ -162,7 +162,7 @@ // Reset data array $data = []; $data['r'] = $raid_id; - $data['callbackAction'] = 'edit_save'; + $data[0] = 'edit_save'; $data['d'] = $raidduration; // Write to log. diff --git a/mods/gym_delete.php b/mods/gym_delete.php index 025a3e2e..01842b2d 100644 --- a/mods/gym_delete.php +++ b/mods/gym_delete.php @@ -27,13 +27,13 @@ [ [ 'text' => getTranslation('yes'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_delete', 'g' => $gymId, 'c' => 1]) + 'callback_data' => formatCallbackData(['gym_delete', 'g' => $gymId, 'c' => 1]) ] ], [ [ 'text' => getTranslation('no'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gymId]) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gymId]) ] ] ]; diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index dcc9c720..96c9a34e 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -61,18 +61,18 @@ $keys[0][] = [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'abort', 'd' => $dbh->lastInsertId()]) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'abort', 'd' => $dbh->lastInsertId()]) ]; if($action == 'note' && !empty($gym['gym_note'])) { $keys[0][] = [ 'text' => getTranslation('delete'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'note', 'd' => $dbh->lastInsertId()]) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'note', 'd' => $dbh->lastInsertId()]) ]; } if($action == 'addr') { $keys[0][] = [ 'text' => getTranslation('gym_save_lookup_result'), - 'callback_data' => formatCallbackData(['callbackAction' => 'gym_edit_details', 'g' => $gym_id, 'a' => 'addr', 'd' => $dbh->lastInsertId()]) + 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'addr', 'd' => $dbh->lastInsertId()]) ]; } } diff --git a/mods/list_raid.php b/mods/list_raid.php index b286939f..2290f363 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -102,13 +102,13 @@ $keys[] = [ [ 'text' => $i . '. ' . $raid_pokemon_name, - 'callback_data' => formatCallbackData(['callbackAction' => 'list_raid', 'r' => $raid['id']]) + 'callback_data' => formatCallbackData(['list_raid', 'r' => $raid['id']]) ] ]; $i++; } $callback = [ - 'callbackAction' => 'gymMenu', + 'gymMenu', 'stage' => 2, 'a' => 'list', 'fl' => $data['fl'], diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index bff804f3..9afc8618 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -27,30 +27,30 @@ // All raid level keys. $keys[][] = array( 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => RAID_LEVEL_ALL]) + 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => RAID_LEVEL_ALL]) ); // Add key for each raid level foreach($levels as $l) { $keys[][] = array( 'text' => getTranslation($l . 'stars'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => $l]) + 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => $l]) ); } $keys[][] = array( 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => '1,3']) + 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => '1,3']) ); // Add back and abort buttons $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pokedex_import']) + 'callback_data' => 'pokedex_import' ], [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ] ]; @@ -185,8 +185,8 @@ $e = $exclusions; $e[] = $pokemon_arg; $keyAction = ($action == 's') ? - ['callbackAction' => 'pokedex_edit_pokemon', 'id' => $dex_id . "-" . $dex_form, 'arg' => ''] : - ['callbackAction' => 'pogoinfo', 'rl' => $id, 'e' => implode('#', $e)]; + ['pokedex_edit_pokemon', 'id' => $dex_id . "-" . $dex_form, 'arg' => ''] : + ['pogoinfo', 'rl' => $id, 'e' => implode('#', $e)]; // Add key $keys[] = array( 'text' => $keyText, @@ -226,20 +226,20 @@ // Back button. $nav_keys[] = array( 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo']) + 'callback_data' => 'pogoinfo' ); // Save button. $nav_keys[] = array( 'text' => EMOJI_DISK, - 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]) + 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]) ); // Reset button. if(isset($exclusions[0])) { $nav_keys[] = array( 'text' => getTranslation('reset'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pogoinfo', 'rl' => $id]) + 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => $id]) ); } diff --git a/mods/pokebattler.php b/mods/pokebattler.php index 80711fc6..33655a4d 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -27,30 +27,30 @@ // All raid level keys. $keys[][] = array( 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => implode(",", $pokebattler_levels)]) + 'callback_data' => formatCallbackData(['pokebattler', 'rl' => implode(",", $pokebattler_levels)]) ); // Add key for each raid level foreach($pokebattler_levels as $l) { $keys[][] = array( 'text' => getTranslation($l . 'stars'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => $l]) + 'callback_data' => formatCallbackData(['pokebattler', 'rl' => $l]) ); } $keys[][] = array( 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => '1,3']) + 'callback_data' => formatCallbackData(['pokebattler', 'rl' => '1,3']) ); // Add back and abort buttons $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pokedex_import']) + 'callback_data' => 'pokedex_import' ], [ 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ] ]; // Callback message string. @@ -203,8 +203,8 @@ // Are 3 raid bosses already selected? if(count($exclusions) == 3) continue; $keyAction = ($action == 's') ? - ['callbackAction' => 'pokedex_edit_pokemon', 'id' => $dex_id . "-" . $dex_form, 'arg' => ''] : - ['callbackAction' => 'pokebattler', 'rl' => $id, 'e' => implode('#', $e)]; + ['pokedex_edit_pokemon', 'id' => $dex_id . "-" . $dex_form, 'arg' => ''] : + ['pokebattler', 'rl' => $id, 'e' => implode('#', $e)]; $keys[] = array( 'text' => $button_text_prefix . SP . $local_pokemon, 'callback_data' => formatCallbackData($keyAction) @@ -243,20 +243,20 @@ // Back button. $nav_keys[] = array( 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler']) + 'callback_data' => 'pokebattler' ); // Save button. $nav_keys[] = array( 'text' => EMOJI_DISK, - 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]) + 'callback_data' => formatCallbackData(['pokebattler', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]) ); // Reset button. if(isset($exclusions[0])) { $nav_keys[] = array( 'text' => getTranslation('reset'), - 'callback_data' => formatCallbackData(['callbackAction' => 'pokebattler', 'rl' => $id]) + 'callback_data' => formatCallbackData(['pokebattler', 'rl' => $id]) ); } diff --git a/mods/raids_list.php b/mods/raids_list.php index 876a4f92..620b2c6d 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -53,7 +53,7 @@ // Exit key $keys[][] = [ 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit']) + 'callback_data' => 'exit' ]; // Get message. diff --git a/mods/trainer.php b/mods/trainer.php index 0234d4ef..b45fff96 100644 --- a/mods/trainer.php +++ b/mods/trainer.php @@ -69,7 +69,7 @@ $keys[] = [ [ 'text' => getTranslation('default_gymarea'), - 'callback_data' => formatCallbackData(['callbackAction' => 'trainerGymarea']) + 'callback_data' => 'trainerGymarea' ] ]; } diff --git a/mods/trainerGymarea.php b/mods/trainerGymarea.php index 62dbd106..3b13aa78 100644 --- a/mods/trainerGymarea.php +++ b/mods/trainerGymarea.php @@ -28,18 +28,18 @@ if($area['id'] == $gymarea) $gymareaName = $area['name']; $keys[] = [ 'text' => $area['name'], - 'callback_data' => formatCallbackData(['callbackAction' => 'trainerGymarea', 'i' => $area['id']]) + 'callback_data' => formatCallbackData(['trainerGymarea', 'i' => $area['id']]) ]; } $keys = inline_key_array($keys, 2); $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['callbackAction' => 'trainer', 'arg' => 0]) + 'callback_data' => formatCallbackData(['trainer', 'arg' => 0]) ], [ 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['callbackAction' => 'exit', 'arg' => 1]) + 'callback_data' => formatCallbackData(['exit', 'arg' => 1]) ] ]; // Set message. diff --git a/mods/trainer_code.php b/mods/trainer_code.php index 0df92fc4..ff9c542b 100644 --- a/mods/trainer_code.php +++ b/mods/trainer_code.php @@ -25,6 +25,7 @@ $data['arg'] = $data['id'] = 0; require_once(ROOT_PATH . '/mods/trainer.php'); + exit; }elseif($action == 'delete') { my_query('DELETE FROM user_input WHERE user_id = :user_id AND handler=\'change_trainercode\'', ['user_id' => $user_id]); my_query(' @@ -39,37 +40,34 @@ $data['arg'] = $data['id'] = 0; require_once(ROOT_PATH . '/mods/trainer.php'); -}else { - $user_data = get_user($user_id, false, true); - // Build message string. - $msg = '' . getTranslation('your_trainer_info') . '' . CR; - $msg .= $user_data['message'] . CR; + exit; +} +$user_data = get_user($user_id, false, true); +// Build message string. +$msg = '' . getTranslation('your_trainer_info') . '' . CR; +$msg .= $user_data['message'] . CR; - // Save the message id to db so we can delete it later - $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id']]); +// Save the message id to db so we can delete it later +$modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id']]); - $msg .= '' . getTranslation('trainercode_select') . ''; - // Data for handling response from the user - my_query('INSERT INTO user_input SET user_id = ?, handler = \'change_trainercode\', modifiers = ?',[$user_id, $modifiers]); +$msg .= '' . getTranslation('trainercode_select') . ''; +// Data for handling response from the user +my_query('INSERT INTO user_input SET user_id = ?, handler = \'change_trainercode\', modifiers = ?',[$user_id, $modifiers]); - // Build callback message string. - $callback_response = 'OK'; +// Build callback message string. +$callback_response = 'OK'; - $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:trainer_code:cancel' - ],[ - 'text' => getTranslation('delete'), - 'callback_data' => '0:trainer_code:delete' - ] - ]; - // Answer callback. - answerCallbackQuery($update['callback_query']['id'], $callback_response); - - // Edit message. - edit_message($update, $msg, $keys, false); -} +$keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:trainer_code:cancel' + ],[ + 'text' => getTranslation('delete'), + 'callback_data' => '0:trainer_code:delete' + ] +]; +// Answer callback. +answerCallbackQuery($update['callback_query']['id'], $callback_response); -// Exit. -exit(); +// Edit message. +edit_message($update, $msg, $keys, false); diff --git a/mods/trainer_name.php b/mods/trainer_name.php index c95d06ce..8381b13c 100644 --- a/mods/trainer_name.php +++ b/mods/trainer_name.php @@ -15,7 +15,7 @@ $action = $data['arg']; // Set the user_id -$user_id = $update['callback_query']['from']['id']; +$user_id = $botUser->userId; if($action == 'cancel') { my_query('DELETE FROM user_input WHERE user_id = ? AND handler=\'change_trainername\'', [$user_id]); @@ -25,6 +25,7 @@ $data['arg'] = $data['id'] = 0; require_once(ROOT_PATH . '/mods/trainer.php'); + exit; }elseif($action == 'delete') { my_query('DELETE FROM user_input WHERE user_id = ? AND handler = \'change_trainername\'', [$user_id]); my_query(' @@ -93,11 +94,11 @@ } } $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $mode.':trainer_name:cancel' - ] - ]; + [ + 'text' => getTranslation('back'), + 'callback_data' => '0:trainer_name:cancel' + ] +]; // Answer callback. answerCallbackQuery($update['callback_query']['id'], $callback_response); From 56f91bdcf9ef410b5dc0399588b25ea716742236 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 7 Dec 2022 21:36:40 +0200 Subject: [PATCH 182/367] Fixed ex raid creation and gym menu --- logic/gymMenu.php | 10 +++++----- mods/edit_time.php | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/logic/gymMenu.php b/logic/gymMenu.php index 60f0a810..3a61b5ad 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -152,18 +152,17 @@ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $s $show_gym = $showHidden ? 0 : 1; $collateQuery = ($config->MYSQL_SORT_COLLATE != '') ? ' COLLATE ' . $config->MYSQL_SORT_COLLATE : ''; - $eventQuery = ' '; if ($buttonAction == 'list') { // Select only gyms with active raids $queryConditions = ' LEFT JOIN raids ON raids.gym_id = gyms.id - WHERE show_gym = ' . $show_gym; - $queryConditions .= ' AND end_time > UTC_TIMESTAMP() '; + WHERE show_gym = ' . $show_gym . ' + AND end_time > UTC_TIMESTAMP() '; $eventQuery = 'event IS NULL'; if($botUser->accessCheck('ex-raids', true)) { if($botUser->accessCheck('event-raids', true)) - $eventQuery = ' '; + $eventQuery = ''; else $eventQuery .= ' OR event = ' . EVENT_ID_EX; }elseif($botUser->accessCheck('event-raids', true)) { @@ -171,7 +170,8 @@ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $s } $eventQuery = ($eventQuery == '') ? ' ' : ' AND ('.$eventQuery.') '; }else { - $queryConditions = ' WHERE show_gym = ' . $show_gym; + $eventQuery = ' '; + $queryConditions = ' WHERE show_gym = ' . $show_gym; } $rs_count = my_query('SELECT COUNT(gym_name) as count FROM gyms ' . $queryConditions . $eventQuery . $gymareaQuery); $gym_count = $rs_count->fetch(); diff --git a/mods/edit_time.php b/mods/edit_time.php index 1b743f01..55aa7f80 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -32,6 +32,7 @@ // Event raids if($event_id != NULL) { + $event_id = ($event_id == 'X') ? EVENT_ID_EX : $event_id; // Date was received in format YearMonthDayHourMinute so we need to reformat it to datetime $start_date_time = substr($starttime,0,4) . '-' . substr($starttime,4,2) . '-' . substr($starttime,6,2) . ' ' . substr($starttime,8,2) . ':' . substr($starttime,10,2) . ':00'; debug_log('Event time :D ... Setting raid date to ' . $start_date_time); From 6ece786f1e43e1044205de8bb884992ea37e1d63 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 8 Dec 2022 12:18:36 +0200 Subject: [PATCH 183/367] Latest translations --- lang/pokemon_moves.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index 7074c55a..04c020be 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -2741,5 +2741,14 @@ "EN": "Poltergeist", "FR": "Esprit Frappeur", "RU": "Полтергейст" + }, + "pokemon_move_377": { + "PT-BR": "Potência Equina", + "EN": "High Horsepower", + "FR": "Cavalerie Lourde", + "DE": "Pferdestärke", + "IT": "Forza Equina", + "RU": "Лошадиная Сила", + "ES": "Fuerza Equina" } } \ No newline at end of file From ca9f496129e2be17cddd03199931cf62cdd9d2b7 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 8 Dec 2022 12:25:23 +0200 Subject: [PATCH 184/367] Changed privileges datatype from json to text mariadb doesn't like json and we don't really need that --- sql/pokemon-raid-bot.sql | 2 +- sql/upgrade/6.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index bda6975a..594fcdb4 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -156,7 +156,7 @@ CREATE TABLE `users` ( `tutorial` TINYINT(1) NOT NULL DEFAULT 0, `auto_alarm` TINYINT(1) UNSIGNED NULL DEFAULT 0, `gymarea` TINYINT UNSIGNED NULL, - `privileges` JSON NULL, + `privileges` TEXT NULL, PRIMARY KEY (`id`), UNIQUE KEY `i_userid` (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8mb4; diff --git a/sql/upgrade/6.sql b/sql/upgrade/6.sql index af84a857..df4b153b 100644 --- a/sql/upgrade/6.sql +++ b/sql/upgrade/6.sql @@ -1,5 +1,5 @@ ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `gymarea` TINYINT UNSIGNED NULL AFTER `auto_alarm`; -ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `privileges` JSON NULL AFTER `gymarea`; +ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `privileges` TEXT NULL AFTER `gymarea`; ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `end_time` DATETIME NULL AFTER `ended`; ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `start_time` DATETIME NULL AFTER `ended`; From 81264e44fb3053eeea9533ee145633e9500fc75d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 8 Dec 2022 12:48:39 +0200 Subject: [PATCH 185/367] Fixed gym creation --- mods/gym_create.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mods/gym_create.php b/mods/gym_create.php index 97aa4e9c..a5850464 100644 --- a/mods/gym_create.php +++ b/mods/gym_create.php @@ -37,8 +37,8 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $stage = $modifiers['stage'] ?? 1; if(isset($action) && $action == 'abort') { - my_query("DELETE FROM user_input WHERE id = :deleteId", ['deleteId' => $deleteId]); - $msg = getTranslation("action_aborted"); + my_query('DELETE FROM user_input WHERE id = :deleteId', ['deleteId' => $deleteId]); + $msg = getTranslation('action_aborted'); editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['from']['id']); exit; } @@ -59,7 +59,6 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $sendMsg = EMOJI_HERE . getTranslation('gym_gps_instructions') . CR; $sendMsg .= getTranslation('gym_gps_example'); respondToUser($userId, $oldMessageId, $editMsg, $editKeys, $sendMsg, [], $callbackResponse, $callbackId); - exit; } $userId = $update['message']['from']['id']; $oldMessageId = $modifiers['oldMessageId']; @@ -79,7 +78,6 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $msg = getTranslation('gym_gps_coordinates_format_error'); respondToUser($userId, 0, '', [], $msg); } - exit; } if($stage == 3) { $input = trim($update['message']['text']); @@ -91,7 +89,7 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $keys[] = [ [ 'text' => getTranslation('show_gym_details'), - 'callback_data' => 'N:gym_details:' . $gymId + 'callback_data' => formatCallbackData(['gym_details', 'g' => $gymId]) ] ]; respondToUser($userId, $oldMessageId, 'OK', [], $msg, $keys); @@ -99,5 +97,4 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $msg = getTranslation('gym_edit_text_too_long'); respondToUser($userId, 0, '', [], $msg); } - exit; } From fd4d36496c3840bba923548d580a7d1a3d70ad06 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 8 Dec 2022 13:14:39 +0200 Subject: [PATCH 186/367] =?UTF-8?q?Removed=20collate=20from=20letter=20men?= =?UTF-8?q?u=20creation=20since=20it=20doesn't=20do=20anything=20mysql=20d?= =?UTF-8?q?istinct=20thinks=20that=20=C3=A4=3Da?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- logic/gymMenu.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/logic/gymMenu.php b/logic/gymMenu.php index 3a61b5ad..7687c8ad 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -73,7 +73,7 @@ function gymMenu($buttonAction, $showHidden, $stage, $firstLetter = false, $gyma ]; $keys = array_merge($h_keys, $keys); } - if($stage == 0 && $botUser->accessCheck('gym-add', true)) { + if($stage == 0 or $stage == 1 && $botUser->accessCheck('gym-add', true)) { $keys[][] = [ 'text' => getTranslation('gym_create'), 'callback_data' => 'gym_create' @@ -150,7 +150,6 @@ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $s global $config, $menuActions, $botUser; // Show hidden gyms? $show_gym = $showHidden ? 0 : 1; - $collateQuery = ($config->MYSQL_SORT_COLLATE != '') ? ' COLLATE ' . $config->MYSQL_SORT_COLLATE : ''; if ($buttonAction == 'list') { // Select only gyms with active raids @@ -206,8 +205,7 @@ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $s ' FROM gyms ' . $queryConditions . ' ' . $gymareaQuery . - $group_order . - $collateQuery + $group_order ); while ($gym = $rs->fetch()) { // Add first letter to keys array From 41b57e365cbe07de97ff26b504ea5952f3138758 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 8 Dec 2022 13:29:54 +0200 Subject: [PATCH 187/367] Fixed privilege caching for admins and not restricted --- core/bot/user.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/bot/user.php b/core/bot/user.php index 1545fdf1..73afe266 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -18,7 +18,9 @@ public function initPrivileges() { $q = my_query('SELECT privileges FROM users WHERE user_id = ? LIMIT 1', [$this->userId]); $result = $q->fetch(); if($result['privileges'] === NULL) return; - $this->userPrivileges = json_decode($result['privileges'], true); + $privilegesArray = json_decode($result['privileges'], true); + $this->userPrivileges['privileges'] = $privilegesArray['privileges'] ?? []; + $this->userPrivileges['grantedBy'] = $privilegesArray['grantedBy'] ?? []; } /** @@ -34,6 +36,7 @@ public function privilegeCheck() { if(empty($config->BOT_ADMINS)) { debug_log('Bot access is not restricted! Allowing access for user: ' . CR . $this->userId); $this->userPrivileges['grantedBy'] = 'NOT_RESTRICTED'; + my_query('UPDATE users SET privileges = ? WHERE user_id = ? LIMIT 1', [json_encode(['grantedBy' => 'NOT_RESTRICTED']), $this->userId]); return; } // Admin? @@ -42,6 +45,7 @@ public function privilegeCheck() { debug_log('Positive result on access check for Bot Admins'); debug_log('Bot Admins: ' . $config->BOT_ADMINS); debug_log('user_id: ' . $this->userId); + my_query('UPDATE users SET privileges = ? WHERE user_id = ? LIMIT 1', [json_encode(['grantedBy' => 'BOT_ADMINS']), $this->userId]); $this->userPrivileges['grantedBy'] = 'BOT_ADMINS'; return; } From 2b802364693543747aec3fe92d0a4151a56850a2 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 8 Dec 2022 19:53:00 +0200 Subject: [PATCH 188/367] Fixed raid creation via location --- mods/edit_raidlevel.php | 28 +++++++++++++++------------- mods/raid_by_location.php | 4 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index 8724b610..e3b7a417 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -58,7 +58,7 @@ 'callback_data' => formatCallbackData($backData) ], [ - 'text' => getTranslation('exit'), + 'text' => getTranslation('abort'), 'callback_data' => 'exit' ] ], @@ -107,21 +107,23 @@ // Get the keys. $keys = raid_edit_raidlevel_keys($data, $admin_access); -$backData = $data; -$backData[0] = 'gymMenu'; -$backData['a'] = 'create'; -$backData['stage'] = 2; -// Add navigation keys. -$keys[] = [ - [ +$lastRow = []; +if(!isset($data['r']) or $data['r'] != 1) { + $backData = $data; + $backData[0] = 'gymMenu'; + $backData['a'] = 'create'; + $backData['stage'] = 2; + // Add navigation keys. + $lastRow[] = [ 'text' => getTranslation('back'), 'callback_data' => formatCallbackData($backData) - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + ]; +} +$lastRow[] = [ + 'text' => getTranslation('abort'), + 'callback_data' => 'exit' ]; +$keys[] = $lastRow; // Build message. $msg = getTranslation('create_raid') . ': ' . (($gym['address']=="") ? $gym['gym_name'] : $gym['address']) . ''; diff --git a/mods/raid_by_location.php b/mods/raid_by_location.php index 82fe718d..330e1b3b 100644 --- a/mods/raid_by_location.php +++ b/mods/raid_by_location.php @@ -142,13 +142,13 @@ [ [ 'text' => getTranslation('next'), - 'callback_data' => $gym_letter . ':edit_raidlevel:' . $gym_id + 'callback_data' => formatCallbackData(['edit_raidlevel', 'gl' => $gym_letter, 'g' => $gym_id, 'r' => 1]) ] ], [ [ 'text' => getTranslation('abort'), - 'callback_data' => $gym_id . ':exit:2' + 'callback_data' => 'exit' ] ] ]; From 6d64ddfeb7f72ded276d463a6dd3ff67be87be82 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 9 Dec 2022 20:13:46 +0200 Subject: [PATCH 189/367] More callback_data reformatting --- commands/delete.php | 4 ++-- commands/events.php | 6 +++--- commands/help.php | 2 +- commands/list.php | 4 ++-- commands/overview.php | 4 ++-- commands/pokedex.php | 12 ++++++------ commands/pokemon.php | 4 ++-- commands/start.php | 2 +- commands/trainer.php | 10 +++++----- logic/edit_gym_keys.php | 2 +- logic/history.php | 2 +- mods/bot_lang.php | 8 ++++---- mods/change_trainercode.php | 4 ++-- mods/change_trainername.php | 4 ++-- mods/code.php | 4 ++-- mods/code_start.php | 2 +- mods/delete_scheduled_entry.php | 2 +- mods/edit_raidlevel.php | 8 ++++---- mods/edit_starttime.php | 2 +- mods/events.php | 2 +- mods/exit.php | 2 +- mods/history.php | 2 +- mods/history_gyms.php | 2 +- mods/history_raid.php | 2 +- mods/history_raids.php | 2 +- mods/import_future_bosses.php | 4 ++-- mods/import_shinyinfo.php | 2 +- mods/importal.php | 2 +- mods/list_raid.php | 2 +- mods/overview_refresh.php | 2 +- mods/overview_share.php | 2 +- mods/pogoinfo.php | 2 +- mods/pokebattler.php | 2 +- mods/pokedex_disable_raids.php | 4 ++-- mods/pokedex_edit_pokemon.php | 4 ++-- mods/pokedex_import.php | 10 +++++----- mods/pokedex_list_raids.php | 2 +- mods/pokedex_set_cp.php | 4 ++-- mods/pokedex_set_raid_level.php | 4 ++-- mods/pokedex_set_shiny.php | 4 ++-- mods/pokedex_set_weather.php | 4 ++-- mods/raid_edit_poke.php | 2 +- mods/raids_delete.php | 8 ++++---- mods/raids_list.php | 2 +- mods/share_raid_by_location.php | 2 +- mods/trainer.php | 10 +++++----- mods/trainer_delete.php | 2 +- mods/trainer_level.php | 4 ++-- mods/trainer_team.php | 8 ++++---- mods/tutorial.php | 4 ++-- mods/vote_status.php | 2 +- 51 files changed, 98 insertions(+), 98 deletions(-) diff --git a/commands/delete.php b/commands/delete.php index cd20f37b..fee622b5 100644 --- a/commands/delete.php +++ b/commands/delete.php @@ -51,7 +51,7 @@ $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; $keys[] = array( 'text' => $row['gym_name'], - 'callback_data' => $row['id'] . ':raids_delete:0' + 'callback_data' => formatCallbackData(['raids_delete', 'r' => $row['id']]) ); // Counter++ @@ -69,7 +69,7 @@ $keys[] = [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; diff --git a/commands/events.php b/commands/events.php index 7e8bf0dd..fec4c1e6 100644 --- a/commands/events.php +++ b/commands/events.php @@ -24,19 +24,19 @@ [ [ 'text' => getTranslation('events_manage'), - 'callback_data' => '0:events:0', + 'callback_data' => 'events', ] ], [ [ 'text' => getTranslation('events_create'), - 'callback_data' => '0:events_add:0', + 'callback_data' => 'events_add', ] ], [ [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1', + 'callback_data' => formatCallbackData(['exit', 'd' => '1']), ] ] ]; diff --git a/commands/help.php b/commands/help.php index d5996998..aeae022b 100644 --- a/commands/help.php +++ b/commands/help.php @@ -60,7 +60,7 @@ [ [ 'text' => getTranslation('next'), - 'callback_data' => '0:tutorial:0' + 'callback_data' => 'tutorial' ] ] ]; diff --git a/commands/list.php b/commands/list.php index bb57e5a6..f8633cee 100644 --- a/commands/list.php +++ b/commands/list.php @@ -87,12 +87,12 @@ $keys[] = array( 'text' => $keys_text, - 'callback_data' => $raid['id'] . ':raids_list:0' + 'callback_data' => formatCallbackData(['raids_list', 'r' => $raid['id']]) ); } $keys[] = array( 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ); // Get the inline key array. diff --git a/commands/overview.php b/commands/overview.php index cd4f7701..891d800f 100644 --- a/commands/overview.php +++ b/commands/overview.php @@ -14,11 +14,11 @@ [ [ 'text' => getTranslation('overview_share'), - 'callback_data' => '0:overview_share:0' + 'callback_data' => 'overview_share' ], [ 'text' => getTranslation('overview_delete'), - 'callback_data' => '0:overview_delete:0' + 'callback_data' => 'overview_delete' ] ] ]; diff --git a/commands/pokedex.php b/commands/pokedex.php index f68d1156..f170c4d5 100644 --- a/commands/pokedex.php +++ b/commands/pokedex.php @@ -47,32 +47,32 @@ [ [ 'text' => getTranslation('pokedex_raid_pokemon'), - 'callback_data' => '0:pokedex_list_raids:0' + 'callback_data' => 'pokedex_list_raids' ] ], [ [ 'text' => getTranslation('edit_pokemon'), - 'callback_data' => '0:pokedex:0' + 'callback_data' => 'pokedex' ] ], [ [ 'text' => getTranslation('disable_raid_level'), - 'callback_data' => '0:pokedex_disable_raids:0' + 'callback_data' => 'pokedex_disable_raids' ] ], [ [ 'text' => getTranslation('import'), - 'callback_data' => '0:pokedex_import:0' + 'callback_data' => 'pokedex_import' ] ] ]; } $keys[][] = [ 'text' => getTranslation('update_pokemon_table'), - 'callback_data' => '0:getdb:0' + 'callback_data' => 'getdb' ]; // Set message. $msg = '' . getTranslation('pokedex_start') . ':'; @@ -80,7 +80,7 @@ $keys[] = [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; diff --git a/commands/pokemon.php b/commands/pokemon.php index 6cef3c82..033f49bb 100644 --- a/commands/pokemon.php +++ b/commands/pokemon.php @@ -57,7 +57,7 @@ $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; $keys[] = array( 'text' => $keys_text, - 'callback_data' => $row['id'] . ':raid_edit_poke:' . $row['level'], + 'callback_data' => formatCallbackData(['raid_edit_poke', 'r' => $row['id'], 'rl' => $row['level']]), ); // Counter++ @@ -75,7 +75,7 @@ $keys[] = [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; diff --git a/commands/start.php b/commands/start.php index 8463ca4b..8f44b554 100644 --- a/commands/start.php +++ b/commands/start.php @@ -59,7 +59,7 @@ $keys[] = [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; } diff --git a/commands/trainer.php b/commands/trainer.php index 010f6564..d511736d 100644 --- a/commands/trainer.php +++ b/commands/trainer.php @@ -22,23 +22,23 @@ if($config->CUSTOM_TRAINERNAME){ $keys[0][] = [ 'text' => getTranslation('name'), - 'callback_data' => '0:trainer_name:0' + 'callback_data' => 'trainer_name' ]; } if($config->RAID_POLL_SHOW_TRAINERCODE){ $keys[0][] = [ 'text' => getTranslation('trainercode'), - 'callback_data' => '0:trainer_code:0' + 'callback_data' => 'trainer_code' ]; } $keys[] = [ [ 'text' => getTranslation('team'), - 'callback_data' => '0:trainer_team:0' + 'callback_data' => 'trainer_team' ], [ 'text' => getTranslation('level'), - 'callback_data' => '0:trainer_level:0' + 'callback_data' => 'trainer_level' ] ]; if ($config->RAID_AUTOMATIC_ALARM == false) { @@ -55,7 +55,7 @@ $keys[] = [ [ 'text' => getTranslation('bot_lang'), - 'callback_data' => '0:bot_lang:0' + 'callback_data' => 'bot_lang' ] ]; } diff --git a/logic/edit_gym_keys.php b/logic/edit_gym_keys.php index b32d34d4..31c0568a 100644 --- a/logic/edit_gym_keys.php +++ b/logic/edit_gym_keys.php @@ -72,7 +72,7 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add $keys[] = [ [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ]; diff --git a/logic/history.php b/logic/history.php index 7f231fa9..d318eed0 100644 --- a/logic/history.php +++ b/logic/history.php @@ -42,7 +42,7 @@ function create_history_date_msg_keys($current = '(SELECT max(start_time) FROM r $keys[] = [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; return [$msg, $keys]; diff --git a/mods/bot_lang.php b/mods/bot_lang.php index be8326a6..4cb6a626 100644 --- a/mods/bot_lang.php +++ b/mods/bot_lang.php @@ -26,11 +26,11 @@ $keys[] = [ [ 'text' => getTranslation('back', $new_lang_internal), - 'callback_data' => '0:trainer:0' + 'callback_data' => 'trainer' ], [ 'text' => getTranslation('done', $new_lang_internal), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ]; $callback_msg = $msg; @@ -47,11 +47,11 @@ $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' + 'callback_data' => 'trainer' ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ]; $msg = getTranslation('change_lang').':'; diff --git a/mods/change_trainercode.php b/mods/change_trainercode.php index 6941ae90..3da1a738 100644 --- a/mods/change_trainercode.php +++ b/mods/change_trainercode.php @@ -28,11 +28,11 @@ [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' + 'callback_data' => 'trainer' ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/change_trainername.php b/mods/change_trainername.php index 5c865ea6..be67e252 100644 --- a/mods/change_trainername.php +++ b/mods/change_trainername.php @@ -28,11 +28,11 @@ [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' + 'callback_data' => 'trainer' ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/code.php b/mods/code.php index 3df48334..f1b520bf 100644 --- a/mods/code.php +++ b/mods/code.php @@ -67,7 +67,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; @@ -111,7 +111,7 @@ $keys[] = [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; diff --git a/mods/code_start.php b/mods/code_start.php index 2e9b4e23..7f704358 100644 --- a/mods/code_start.php +++ b/mods/code_start.php @@ -52,7 +52,7 @@ [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ] ]; diff --git a/mods/delete_scheduled_entry.php b/mods/delete_scheduled_entry.php index e76f47c2..3ed0dd85 100644 --- a/mods/delete_scheduled_entry.php +++ b/mods/delete_scheduled_entry.php @@ -25,7 +25,7 @@ ], [ 'text' => getTranslation('no'), - 'callback_data' => '0:pokedex_list_raids:0' + 'callback_data' => 'pokedex_list_raids' ], ]; diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index e3b7a417..ba6b57fb 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -43,7 +43,7 @@ [ [ 'text' => getTranslation('saved_raid'), - 'callback_data' => formatCallbackData(['raids_list', 'id' => $duplicate_id]) + 'callback_data' => formatCallbackData(['raids_list', 'r' => $duplicate_id]) ] ], [ @@ -73,7 +73,7 @@ $keys[] = [ [ 'text' => getTranslation('update_pokemon'), - 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], + 'callback_data' => formatCallbackData(['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]), ] ]; } @@ -81,7 +81,7 @@ $keys[] = [ [ 'text' => getTranslation('delete'), - 'callback_data' => $raid['id'] . ':raids_delete:0' + 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id']]) ] ]; } @@ -126,7 +126,7 @@ $keys[] = $lastRow; // Build message. -$msg = getTranslation('create_raid') . ': ' . (($gym['address']=="") ? $gym['gym_name'] : $gym['address']) . ''; +$msg = getTranslation('create_raid') . ': ' . (($gym['address'] == '') ? $gym['gym_name'] : $gym['address']) . ''; // Build callback message string. $callback_response = getTranslation('gym_saved'); diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index e8306d01..ef5c04c3 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -146,7 +146,7 @@ [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ] ]; diff --git a/mods/events.php b/mods/events.php index 6f7a9628..93c4527e 100644 --- a/mods/events.php +++ b/mods/events.php @@ -33,7 +33,7 @@ $keys[] = [ [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1', + 'callback_data' => formatCallbackData(['exit', 'd' => '1']), ] ]; diff --git a/mods/exit.php b/mods/exit.php index 116dbb62..953e057a 100644 --- a/mods/exit.php +++ b/mods/exit.php @@ -8,7 +8,7 @@ // Set empty keys. $keys = []; -$arg = $data['arg'] ?? 0; +$arg = $data['d'] ?? 0; // Build message string. $msg = ($arg == 1) ? (getTranslation('done') . '!') : (getTranslation('action_aborted')); diff --git a/mods/history.php b/mods/history.php index 632ee0e4..816d0898 100644 --- a/mods/history.php +++ b/mods/history.php @@ -77,7 +77,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; diff --git a/mods/history_gyms.php b/mods/history_gyms.php index b8d8e610..48c9f7a5 100644 --- a/mods/history_gyms.php +++ b/mods/history_gyms.php @@ -81,7 +81,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ], ]; $keys[] = $nav_keys; diff --git a/mods/history_raid.php b/mods/history_raid.php index 4895cd90..5c4d7a85 100644 --- a/mods/history_raid.php +++ b/mods/history_raid.php @@ -33,7 +33,7 @@ ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ], ]; diff --git a/mods/history_raids.php b/mods/history_raids.php index 76d3095c..d55f43df 100644 --- a/mods/history_raids.php +++ b/mods/history_raids.php @@ -47,7 +47,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ], ]; $keys[] = $nav_keys; diff --git a/mods/import_future_bosses.php b/mods/import_future_bosses.php index ec43fba2..325e6e3d 100644 --- a/mods/import_future_bosses.php +++ b/mods/import_future_bosses.php @@ -57,7 +57,7 @@ [ [ 'text'=>getTranslation('back'), - 'callback_data' => '0:pokedex_import:0' + 'callback_data' => 'pokedex_import' ] ] ]; @@ -67,7 +67,7 @@ [ [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/import_shinyinfo.php b/mods/import_shinyinfo.php index 60dbeb2f..083bdeaf 100644 --- a/mods/import_shinyinfo.php +++ b/mods/import_shinyinfo.php @@ -54,7 +54,7 @@ $keys[] = [ [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ]; if(count($shinydata) > 0) { diff --git a/mods/importal.php b/mods/importal.php index 1f17f250..eb05f4fb 100644 --- a/mods/importal.php +++ b/mods/importal.php @@ -132,7 +132,7 @@ function escape($value){ [ [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/list_raid.php b/mods/list_raid.php index 2290f363..85e3d675 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -62,7 +62,7 @@ $keys[] = [ [ 'text' => getTranslation('update_pokemon'), - 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], + 'callback_data' => formatCallbackData(['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]), ] ]; } diff --git a/mods/overview_refresh.php b/mods/overview_refresh.php index 15ee9120..bfad161c 100644 --- a/mods/overview_refresh.php +++ b/mods/overview_refresh.php @@ -83,7 +83,7 @@ ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ]; }else { diff --git a/mods/overview_share.php b/mods/overview_share.php index 45348083..4b93cc99 100644 --- a/mods/overview_share.php +++ b/mods/overview_share.php @@ -80,7 +80,7 @@ ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ]; $res = $rs->fetch(); diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index 9afc8618..539e07ac 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -246,7 +246,7 @@ // Abort button. $nav_keys[] = array( 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ); // Get the inline key array and merge keys. diff --git a/mods/pokebattler.php b/mods/pokebattler.php index 33655a4d..1141bd8b 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -263,7 +263,7 @@ // Abort button. $nav_keys[] = array( 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ); // Get the inline key array and merge keys. diff --git a/mods/pokedex_disable_raids.php b/mods/pokedex_disable_raids.php index bb032c40..aa83290a 100644 --- a/mods/pokedex_disable_raids.php +++ b/mods/pokedex_disable_raids.php @@ -50,7 +50,7 @@ // Add abort button $keys[] = array( 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ); // Get the inline key array. @@ -105,7 +105,7 @@ // Abort. $keys[] = array( 'text' => getTranslation('no'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ); // Inline keys array. diff --git a/mods/pokedex_edit_pokemon.php b/mods/pokedex_edit_pokemon.php index 869b3a06..87dba22a 100644 --- a/mods/pokedex_edit_pokemon.php +++ b/mods/pokedex_edit_pokemon.php @@ -86,11 +86,11 @@ $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:pokedex:0' + 'callback_data' => 'pokedex' ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; diff --git a/mods/pokedex_import.php b/mods/pokedex_import.php index ac8b9349..d13ddb9e 100644 --- a/mods/pokedex_import.php +++ b/mods/pokedex_import.php @@ -17,31 +17,31 @@ [ [ 'text' => getTranslation('import') . SP . '(Pokebattler)', - 'callback_data' => '0:pokebattler:0' + 'callback_data' => 'pokebattler' ] ], [ [ 'text' => getTranslation('import') . SP . getTranslation('upcoming') . SP . '(Pokebattler)', - 'callback_data' => '0:import_future_bosses:0' + 'callback_data' => 'import_future_bosses' ] ], [ [ 'text' => getTranslation('import') . SP . getTranslation('shiny') . SP . '(Pokebattler)', - 'callback_data' => '0:import_shinyinfo:0' + 'callback_data' => 'import_shinyinfo' ] ], [ [ 'text' => getTranslation('import') . SP . '(ccev pogoinfo)', - 'callback_data' => '0:pogoinfo:0' + 'callback_data' => 'pogoinfo' ] ], [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ] ]; diff --git a/mods/pokedex_list_raids.php b/mods/pokedex_list_raids.php index ac5a7de4..5a11f644 100644 --- a/mods/pokedex_list_raids.php +++ b/mods/pokedex_list_raids.php @@ -94,7 +94,7 @@ $keys[] = [ [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ]; } else { diff --git a/mods/pokedex_set_cp.php b/mods/pokedex_set_cp.php index 5292608d..ccbcd869 100644 --- a/mods/pokedex_set_cp.php +++ b/mods/pokedex_set_cp.php @@ -58,7 +58,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; @@ -93,7 +93,7 @@ ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index 076299bf..1b46fde8 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -48,7 +48,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; @@ -85,7 +85,7 @@ ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/pokedex_set_shiny.php b/mods/pokedex_set_shiny.php index dbe9eebc..8d421f08 100644 --- a/mods/pokedex_set_shiny.php +++ b/mods/pokedex_set_shiny.php @@ -45,7 +45,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ] ]; @@ -76,7 +76,7 @@ ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/pokedex_set_weather.php b/mods/pokedex_set_weather.php index ecbe1fba..eebce178 100644 --- a/mods/pokedex_set_weather.php +++ b/mods/pokedex_set_weather.php @@ -53,7 +53,7 @@ ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; @@ -81,7 +81,7 @@ ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ]; diff --git a/mods/raid_edit_poke.php b/mods/raid_edit_poke.php index 9b1e2a03..bac6399c 100644 --- a/mods/raid_edit_poke.php +++ b/mods/raid_edit_poke.php @@ -36,7 +36,7 @@ [ [ 'text' => getTranslation('not_supported'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ] ]; diff --git a/mods/raids_delete.php b/mods/raids_delete.php index febeb84e..3f6bae83 100644 --- a/mods/raids_delete.php +++ b/mods/raids_delete.php @@ -11,10 +11,10 @@ // 0 -> Confirmation required // 1 -> Cancel deletion // 2 -> Execute deletion -$action = $data['arg']; +$action = $data['a']; // Get the raid id. -$raidId = $data['id']; +$raidId = $data['r']; // Access check. $botUser->raidaccessCheck($raidId, 'delete'); @@ -33,11 +33,11 @@ [ [ 'text' => getTranslation('yes'), - 'callback_data' => $raid['id'] . ':raids_delete:2' + 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id'], 'a' => 2]) ], [ 'text' => getTranslation('no'), - 'callback_data' => $raid['id'] . ':raids_delete:1' + 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id'], 'a' => 1]) ] ] ]; diff --git a/mods/raids_list.php b/mods/raids_list.php index 620b2c6d..e608a9c3 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -8,7 +8,7 @@ //debug_log($data); // Get ID. -$raidId = $data['id']; +$raidId = $data['r']; // Check access. $botUser->accessCheck('list'); diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 43d5ccc2..52210593 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -135,7 +135,7 @@ $keys[] = [ [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ]; diff --git a/mods/trainer.php b/mods/trainer.php index b45fff96..544bb81a 100644 --- a/mods/trainer.php +++ b/mods/trainer.php @@ -27,24 +27,24 @@ $keys[0][] = [ 'text' => getTranslation('name'), - 'callback_data' => '0:trainer_name:0' + 'callback_data' => 'trainer_name' ]; } if($config->RAID_POLL_SHOW_TRAINERCODE) { $keys[0][] = [ 'text' => getTranslation('trainercode'), - 'callback_data' => '0:trainer_code:0' + 'callback_data' => 'trainer_code' ]; } $keys[] = [ [ 'text' => getTranslation('team'), - 'callback_data' => '0:trainer_team:0' + 'callback_data' => 'trainer_team' ], [ 'text' => getTranslation('level'), - 'callback_data' => '0:trainer_level:0' + 'callback_data' => 'trainer_level' ] ]; if($config->RAID_AUTOMATIC_ALARM == false) { @@ -61,7 +61,7 @@ $keys[] = [ [ 'text' => getTranslation('bot_lang'), - 'callback_data' => '0:bot_lang:0' + 'callback_data' => 'bot_lang' ] ]; } diff --git a/mods/trainer_delete.php b/mods/trainer_delete.php index 2e750f93..a34a7ce0 100644 --- a/mods/trainer_delete.php +++ b/mods/trainer_delete.php @@ -72,7 +72,7 @@ [ [ 'text' => getTranslation('no'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ] ]; diff --git a/mods/trainer_level.php b/mods/trainer_level.php index 86836ded..a50fe769 100644 --- a/mods/trainer_level.php +++ b/mods/trainer_level.php @@ -72,11 +72,11 @@ [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' + 'callback_data' => 'trainer' ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/trainer_team.php b/mods/trainer_team.php index 8d6a0379..735d6ee1 100644 --- a/mods/trainer_team.php +++ b/mods/trainer_team.php @@ -39,11 +39,11 @@ [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' + 'callback_data' => 'trainer' ], [ 'text' => getTranslation('abort'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ] ] ]; @@ -79,11 +79,11 @@ [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:trainer:0' + 'callback_data' => 'trainer' ], [ 'text' => getTranslation('done'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/tutorial.php b/mods/tutorial.php index 4296787a..23abf92f 100644 --- a/mods/tutorial.php +++ b/mods/tutorial.php @@ -67,11 +67,11 @@ [ [ 'text' => getTranslation('yes'), - 'callback_data' => '0:trainer:0' + 'callback_data' => 'trainer' ], [ 'text' => getTranslation('no'), - 'callback_data' => '0:exit:1' + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) ] ] ]; diff --git a/mods/vote_status.php b/mods/vote_status.php index be93b9c4..c668d96c 100644 --- a/mods/vote_status.php +++ b/mods/vote_status.php @@ -88,7 +88,7 @@ ], [ 'text' => getTranslation('no'), - 'callback_data' => '0:exit:0' + 'callback_data' => 'exit' ], ]]; if($status == 'raid_done') $msg = getTranslation("delete_remote_raid_done"); From abd3f23d7a0ad7e074df5aed41a4da701d9327ec Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 9 Dec 2022 20:56:43 +0200 Subject: [PATCH 190/367] New button to display saved raid if it's elite --- logic/raid_edit_raidlevel_keys.php | 3 ++- mods/edit_raidlevel.php | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/logic/raid_edit_raidlevel_keys.php b/logic/raid_edit_raidlevel_keys.php index 223065f2..3abfd89c 100644 --- a/logic/raid_edit_raidlevel_keys.php +++ b/logic/raid_edit_raidlevel_keys.php @@ -6,7 +6,7 @@ * @param int|bool $event_id * @return array */ -function raid_edit_raidlevel_keys($callbackData, $admin_access = [false,false], $event = false) +function raid_edit_raidlevel_keys($callbackData, $admin_access = [false,false], $event = false, $excludeElite = false) { global $config; @@ -37,6 +37,7 @@ function raid_edit_raidlevel_keys($callbackData, $admin_access = [false,false], // Add key for each raid level $buttonData = $callbackData; while ($level = $rs_counts->fetch()) { + if ($level['raid_level'] == 9 && $excludeElite) continue; // Add key for pokemon if we have just 1 pokemon for a level if($level['raid_level_count'] != 1) { // Raid level and action diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index ba6b57fb..06e41392 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -104,8 +104,17 @@ exit(); } +$eliteId = active_raid_duplication_check($gym_id, 9); +$excludeElite = $eliteId == 0 ? false : true; // Get the keys. -$keys = raid_edit_raidlevel_keys($data, $admin_access); +$keys = raid_edit_raidlevel_keys($data, $admin_access, false, $excludeElite); + +if($eliteId > 0) { + $keys[][] = [ + 'text' => getTranslation('saved_raid'), + 'callback_data' => formatCallbackData(['raids_list', 'r' => $eliteId]) + ]; +} $lastRow = []; if(!isset($data['r']) or $data['r'] != 1) { From d1ba2d38b9b7efa3b88416dbe5fd843a5a64fd19 Mon Sep 17 00:00:00 2001 From: Jinna Kiisuo Date: Thu, 8 Dec 2022 13:36:18 +0200 Subject: [PATCH 191/367] Disable image build message notifications The messages are still sent, just without triggering a notification. --- .github/workflows/publish-image.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml index 387f55b0..925cb180 100644 --- a/.github/workflows/publish-image.yml +++ b/.github/workflows/publish-image.yml @@ -60,3 +60,5 @@ jobs: token: ${{ secrets.TELEGRAM_TOKEN }} message: "New Docker image has been built: ${{ steps.meta.outputs.tags }}" disable_web_page_preview: true + disable_notification: true + From d6a1f5afdc0adb92e4a7b0661b72ea20d3b5010a Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 9 Dec 2022 21:47:37 +0200 Subject: [PATCH 192/367] Added translation for Unbound-form --- lang/pokemon_forms.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index a44c8157..de57bf67 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -825,5 +825,8 @@ }, "pokemon_form_question_mark": { "EN": "?" + }, + "pokemon_form_unbound": { + "EN": "Unbound" } } From d9035d3b3da1c556bbc1d3d9eef5816e706d27e0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 9 Dec 2022 22:23:49 +0200 Subject: [PATCH 193/367] Bring back Pokemon name translation fallback logic --- logic/get_local_pokemon_name.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/logic/get_local_pokemon_name.php b/logic/get_local_pokemon_name.php index c9721b98..f242a645 100644 --- a/logic/get_local_pokemon_name.php +++ b/logic/get_local_pokemon_name.php @@ -27,6 +27,14 @@ function get_local_pokemon_name($pokemon_id, $pokemon_form_id, $override_languag if ($pokemon_form_name != 'normal') { $pokemon_form_name = $getTypeTranslation('pokemon_form_' . $pokemon_form_name); } - + // If we didn't find Pokemon name or form name from translation files, use the name from database as fallback + if(empty($pokemon_name) or empty($pokemon_form_name)) { + // Pokemon name + $pokemon_name = (empty($pokemon_name) ? $res['pokemon_name'] : $pokemon_name); + // Pokemon form + if(empty($pokemon_form_name) && $res['pokemon_form_name'] != 'normal') { + $pokemon_form_name = ucfirst(str_replace('_',' ',$res['pokemon_form_name'])); + } + } return $pokemon_name . ($pokemon_form_name != "normal" ? " " . $pokemon_form_name : ""); } From 9329d0fe0dd4f55af034370492e52fd5495d5489 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 11 Dec 2022 13:16:58 +0200 Subject: [PATCH 194/367] Fixed raid deletion --- mods/edit_save.php | 2 +- mods/list_raid.php | 2 +- mods/raids_delete.php | 2 +- mods/raids_list.php | 2 +- mods/save_event_note.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mods/edit_save.php b/mods/edit_save.php index 11574e38..e79852f8 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -36,7 +36,7 @@ [ [ 'text' => getTranslation('delete'), - 'callback_data' => $id . ':raids_delete:0' + 'callback_data' => formatCallbackData(['raids_delete', 'r' => $id]) ] ] ]; diff --git a/mods/list_raid.php b/mods/list_raid.php index 85e3d675..faa20391 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -70,7 +70,7 @@ $keys[] = [ [ 'text' => getTranslation('delete'), - 'callback_data' => $raid['id'] . ':raids_delete:0' + 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id']]) ] ]; } diff --git a/mods/raids_delete.php b/mods/raids_delete.php index 3f6bae83..89159900 100644 --- a/mods/raids_delete.php +++ b/mods/raids_delete.php @@ -11,7 +11,7 @@ // 0 -> Confirmation required // 1 -> Cancel deletion // 2 -> Execute deletion -$action = $data['a']; +$action = $data['a'] ?? 0; // Get the raid id. $raidId = $data['r']; diff --git a/mods/raids_list.php b/mods/raids_list.php index e608a9c3..515d3ede 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -37,7 +37,7 @@ $keys[] = [ [ 'text' => getTranslation('delete'), - 'callback_data' => $raid['id'] . ':raids_delete:0' + 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id']]) ] ]; } diff --git a/mods/save_event_note.php b/mods/save_event_note.php index 7e283d26..814181b8 100644 --- a/mods/save_event_note.php +++ b/mods/save_event_note.php @@ -33,7 +33,7 @@ [ [ 'text' => getTranslation('delete'), - 'callback_data' => $raid_id . ':raids_delete:0' + 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid_id]) ] ] ]; From 8658729e22b0a7b36200b0f6d51db3140d301c3e Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 11 Dec 2022 23:26:02 +0200 Subject: [PATCH 195/367] Moved access denied -logic to it's own function --- core/bot/user.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/bot/user.php b/core/bot/user.php index 73afe266..74847875 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -142,10 +142,9 @@ public function privilegeCheck() { * @param string $permission Permission to check * @param bool $return_result Return the result of privilege check * @param bool $new_user Has user completed tutorial or not - * @return bool|string + * @return bool|void */ public function accessCheck($permission = 'access-bot', $return_result = false, $new_user = false) { - global $update; if(!$new_user && in_array($permission, $this->userPrivileges['privileges']) or $this->userPrivileges['grantedBy'] === 'BOT_ADMINS' or $this->userPrivileges['grantedBy'] === 'NOT_RESTRICTED') { return true; } @@ -154,6 +153,15 @@ public function accessCheck($permission = 'access-bot', $return_result = false, if($return_result) return false; + $this->denyAccess(); + } + + /** + * Send Access denied -message to user and exit + * @return void + */ + public function denyAccess() { + global $update; $response_msg = '' . getTranslation('bot_access_denied') . ''; // Edit message or send new message based on type of received call if ($update['type'] != 'callback_query') { From e223760ea5ad3b3a4003bd6445173c7ed0418d9c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 12 Dec 2022 00:00:45 +0200 Subject: [PATCH 196/367] More callback_data formatting that fixes a lot of bugs Also cleaned up code for `/delete` and `/pokemon` --- commands/delete.php | 89 ++++++++++++---------------- commands/pokemon.php | 87 ++++++++++++--------------- commands/trainer.php | 2 +- logic/edit_pokedex_keys.php | 55 ++++++++--------- mods/bot_lang.php | 8 +-- mods/delete_scheduled_entry.php | 6 +- mods/events.php | 3 - mods/events_add.php | 18 +++--- mods/list_raid.php | 5 +- mods/overview_delete.php | 7 +-- mods/overview_share.php | 102 ++++++++++++++++---------------- mods/pokedex.php | 7 +-- mods/pokedex_list_raids.php | 2 +- mods/raid_edit_poke.php | 17 +++--- mods/raid_set_poke.php | 4 +- mods/raids_list.php | 2 +- mods/share_raid_by_location.php | 5 +- mods/trainer.php | 9 ++- mods/trainerGymarea.php | 2 +- mods/trainer_code.php | 7 +-- mods/trainer_level.php | 31 +++++----- mods/trainer_name.php | 14 ++--- mods/trainer_team.php | 13 ++-- 23 files changed, 231 insertions(+), 264 deletions(-) diff --git a/commands/delete.php b/commands/delete.php index fee622b5..e3cc8a54 100644 --- a/commands/delete.php +++ b/commands/delete.php @@ -6,40 +6,37 @@ //debug_log($update); //debug_log($data); -// Check access. -$botUser->accessCheck('access-bot'); +if($botUser->accessCheck('delete-own', true)) { + $userRestriction = 'AND raids.user_id = ?'; + $binds = [$update['message']['chat']['id']]; +}elseif($botUser->accessCheck('delete-all', true)) { + $userRestriction = ''; + $binds = []; +}else { + $botUser->denyAccess(); +} + +$query = my_query(' + SELECT raids.*, gyms.gym_name + FROM raids + LEFT JOIN gyms + ON raids.gym_id = gyms.id + WHERE raids.end_time > UTC_TIMESTAMP + ' . $userRestriction . ' + ORDER BY raids.end_time ASC + LIMIT 20 +', $binds); -// Count results. -$count = 0; -$own_sql = ''; -$own_arr = []; -if(!$botUser->accessCheck('delete', true) && $botUser->accessCheck('delete-own',true)) { - $own_sql = 'AND users.user_id = :user_id'; - $own_arr = [":user_id"=>$update['message']['from']['id']]; +if($query->rowCount() == 0) { + $msg = '' . getTranslation('no_active_raids_found') . ''; + send_message($update['message']['chat']['id'], $msg); + exit; } + // Init text and keys. $text = ''; $keys = []; -$query = my_query(' - SELECT - raids.*, gyms.lat , - gyms.lon , - gyms.address , - gyms.gym_name , - gyms.ex_gym , - users. NAME - FROM - raids - LEFT JOIN gyms ON raids.gym_id = gyms.id - LEFT JOIN users ON raids.user_id = users.user_id - WHERE - raids.end_time > UTC_TIMESTAMP() - '.$own_sql.' - ORDER BY - raids.end_time ASC - LIMIT 20 -', $own_arr); while ($row = $query->fetch()) { // Set text and keys. $text .= $row['gym_name'] . CR; @@ -49,35 +46,25 @@ $start = dt2time($row['start_time']); $end = dt2time($row['end_time']); $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; - $keys[] = array( + $keys[] = [ 'text' => $row['gym_name'], 'callback_data' => formatCallbackData(['raids_delete', 'r' => $row['id']]) - ); - - // Counter++ - $count = $count + 1; + ]; } -// Set message. -if($count == 0) { - $msg = '' . getTranslation('no_active_raids_found') . ''; -} else { - // Get the inline key array. - $keys = inline_key_array($keys, 1); +// Get the inline key array. +$keys = inline_key_array($keys, 1); - // Add exit key. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ]; +// Add exit key. +$keys[][] = [ + 'text' => getTranslation('abort'), + 'callback_data' => 'exit' +]; - // Build message. - $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; - $msg .= $text; - $msg .= '' . getTranslation('select_gym_name') . '' . CR; -} +// Build message. +$msg = '' . getTranslation('list_all_active_raids') . ':' . CR; +$msg .= $text; +$msg .= '' . getTranslation('select_gym_name') . '' . CR; // Build callback message string. $callback_response = 'OK'; diff --git a/commands/pokemon.php b/commands/pokemon.php index 033f49bb..91c932b3 100644 --- a/commands/pokemon.php +++ b/commands/pokemon.php @@ -6,35 +6,37 @@ //debug_log($update); //debug_log($data); -// Check access. -$botUser->accessCheck('access-bot'); +if($botUser->accessCheck('pokemon-own', true)) { + $userRestriction = 'AND raids.user_id = ?'; + $binds = [$update['message']['chat']['id']]; +}elseif($botUser->accessCheck('pokemon-all', true)) { + $userRestriction = ''; + $binds = []; +}else { + $botUser->denyAccess(); +} -// Count results. -$count = 0; +$query = my_query(' + SELECT raids.*, gyms.gym_name + FROM raids + LEFT JOIN gyms + ON raids.gym_id = gyms.id + WHERE raids.end_time > UTC_TIMESTAMP + ' . $userRestriction . ' + ORDER BY raids.end_time ASC + LIMIT 20 +', $binds); + +if($query->rowCount() == 0) { + $msg = '' . getTranslation('no_active_raids_found') . ''; + send_message($update['message']['chat']['id'], $msg); + exit; +} // Init text and keys. $text = ''; $keys = []; -$query = my_query(' - SELECT - raids.*, gyms.lat , - gyms.lon , - gyms.address , - gyms.gym_name , - gyms.ex_gym , - users. NAME - FROM - raids - LEFT JOIN gyms ON raids.gym_id = gyms.id - LEFT JOIN users ON raids.user_id = users.user_id - WHERE - raids.end_time > UTC_TIMESTAMP - ORDER BY - raids.end_time ASC - LIMIT 20 -'); - while ($row = $query->fetch()) { // Get times. $now = utcnow(); @@ -55,38 +57,25 @@ // Set text and keys. $text .= $row['gym_name'] . CR; $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; - $keys[] = array( + $keys[] = [ 'text' => $keys_text, 'callback_data' => formatCallbackData(['raid_edit_poke', 'r' => $row['id'], 'rl' => $row['level']]), - ); - - // Counter++ - $count = $count + 1; + ]; } -// Set message. -if($count == 0) { - $msg = '' . getTranslation('no_active_raids_found') . ''; -} else { - // Get the inline key array. - $keys = inline_key_array($keys, 1); - - // Add exit key. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ]; +// Get the inline key array. +$keys = inline_key_array($keys, 1); - // Build message. - $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; - $msg .= $text; - $msg .= '' . getTranslation('select_gym_name') . '' . CR; -} +// Add exit key. +$keys[][] = [ + 'text' => getTranslation('abort'), + 'callback_data' => 'exit' +]; -// Build callback message string. -$callback_response = 'OK'; +// Build message. +$msg = '' . getTranslation('list_all_active_raids') . ':' . CR; +$msg .= $text; +$msg .= '' . getTranslation('select_gym_name') . '' . CR; // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/trainer.php b/commands/trainer.php index d511736d..0de84160 100644 --- a/commands/trainer.php +++ b/commands/trainer.php @@ -47,7 +47,7 @@ $keys[] = [ [ 'text' => ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), - 'callback_data' => formatCallbackData(['trainerGymarea', 'a' => ($alarm_status == 1 ? 0 : 1)]) + 'callback_data' => formatCallbackData(['trainer', 'a' => 1]) ] ]; } diff --git a/logic/edit_pokedex_keys.php b/logic/edit_pokedex_keys.php index 40d1ce66..57fc6e9c 100644 --- a/logic/edit_pokedex_keys.php +++ b/logic/edit_pokedex_keys.php @@ -2,10 +2,9 @@ /** * Pokedex edit pokemon keys. * @param $limit - * @param $action * @return array */ -function edit_pokedex_keys($limit, $action) +function edit_pokedex_keys($limit) { // Number of entries to display at once. $entries = 10; @@ -13,11 +12,8 @@ function edit_pokedex_keys($limit, $action) // Number of entries to skip with skip-back and skip-next buttons $skip = 50; - // Module for back and next keys - $module = 'pokedex'; - // Init empty keys array. - $keys = []; + $pokemonKeys = []; // Get all pokemon from database $rs = my_query(' @@ -40,10 +36,10 @@ function edit_pokedex_keys($limit, $action) // List users / moderators while ($mon = $rs->fetch()) { $pokemon_name = get_local_pokemon_name($mon['pokedex_id'], $mon['pokemon_form_id']); - $keys[] = array( + $pokemonKeys[][] = [ 'text' => $mon['pokedex_id'] . SP . $pokemon_name, 'callback_data' => $mon['pokedex_id'] . '-' . $mon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' - ); + ]; } // Empty backs and next keys @@ -53,46 +49,45 @@ function edit_pokedex_keys($limit, $action) // Add back key. if ($limit > 0) { $new_limit = $limit - $entries; - $empty_back_key = []; - $back = universal_key($empty_back_key, $new_limit, $module, $action, getTranslation('back') . ' (-' . $entries . ')'); - $keys_back[] = $back[0][0]; + $keys_back[0][] = [ + 'text' => getTranslation('back') . ' (-' . $entries . ')', + 'callback_data' => formatCallbackData(['pokedex', 'l' => $new_limit]) + ]; } // Add skip back key. if ($limit - $skip > 0) { $new_limit = $limit - $skip - $entries; - $empty_back_key = []; - $back = universal_key($empty_back_key, $new_limit, $module, $action, getTranslation('back') . ' (-' . $skip . ')'); - $keys_back[] = $back[0][0]; + $keys_back[0][] = [ + 'text' => getTranslation('back') . ' (-' . $skip . ')', + 'callback_data' => formatCallbackData(['pokedex', 'l' => $new_limit]) + ]; } // Add next key. if (($limit + $entries) < $count) { $new_limit = $limit + $entries; - $empty_next_key = []; - $next = universal_key($empty_next_key, $new_limit, $module, $action, getTranslation('next') . ' (+' . $entries . ')'); - $keys_next[] = $next[0][0]; + $keys_next[0][] = [ + 'text' => getTranslation('next') . ' (+' . $entries . ')', + 'callback_data' => formatCallbackData(['pokedex', 'l' => $new_limit]) + ]; } // Add skip next key. if (($limit + $skip + $entries) < $count) { $new_limit = $limit + $skip + $entries; - $empty_next_key = []; - $next = universal_key($empty_next_key, $new_limit, $module, $action, getTranslation('next') . ' (+' . $skip . ')'); - $keys_next[] = $next[0][0]; + $keys_next[0][] = [ + 'text' => getTranslation('next') . ' (+' . $skip . ')', + 'callback_data' => formatCallbackData(['pokedex', 'l' => $new_limit]) + ]; } - // Exit key - $empty_exit_key = []; - $key_exit = universal_key($empty_exit_key, '0', 'exit', '0', getTranslation('abort')); - // Get the inline key array. - $keys = inline_key_array($keys, 1); - $keys_back = inline_key_array($keys_back, 2); - $keys_next = inline_key_array($keys_next, 2); - $keys = array_merge($keys_back, $keys); - $keys = array_merge($keys, $keys_next); - $keys = array_merge($keys, $key_exit); + $keys = array_merge($keys_back, $pokemonKeys, $keys_next); + $keys[][] = [ + 'text' => getTranslation('abort'), + 'callback_data' => 'exit' + ]; return $keys; } diff --git a/mods/bot_lang.php b/mods/bot_lang.php index 4cb6a626..e4cd8178 100644 --- a/mods/bot_lang.php +++ b/mods/bot_lang.php @@ -11,17 +11,17 @@ $keys = []; -if($data['arg'] != '0') { +if(isset($data['l'])) { $query = my_query(' UPDATE users SET lang_manual = 1, lang= :lang WHERE user_id = :user_id ',[ - 'lang' => $data['arg'], + 'lang' => $data['l'], 'user_id' => $update['callback_query']['from']['id'], ]); - $new_lang_internal = $languages[$data['arg']]; + $new_lang_internal = $languages[$data['l']]; $msg = getTranslation('new_lang_saved', $new_lang_internal); $keys[] = [ [ @@ -40,7 +40,7 @@ if(in_array($lang_internal, $displayedLanguages)) continue; $keys[][] = [ 'text' => getTranslation('lang_name', $lang_internal), - 'callback_data' => '0:bot_lang:'.$lang_tg + 'callback_data' => formatCallbackData(['bot_lang', 'l' => $lang_tg]) ]; $displayedLanguages[] = $lang_internal; } diff --git a/mods/delete_scheduled_entry.php b/mods/delete_scheduled_entry.php index 3ed0dd85..2cd3b643 100644 --- a/mods/delete_scheduled_entry.php +++ b/mods/delete_scheduled_entry.php @@ -4,9 +4,9 @@ // Check access. $botUser->accessCheck('pokedex'); -$id = $data['id']; +$id = $data['i']; -if($arg == 1) { +if(isset($data['s']) && $data['s'] == 1) { my_query('DELETE FROM raid_bosses WHERE id = ?', [$id]); include(ROOT_PATH . '/mods/pokedex_list_raids.php'); exit(); @@ -21,7 +21,7 @@ $keys[] = [ [ 'text' => getTranslation('yes'), - 'callback_data' => $id . ':' . 'delete_scheduled_entry' . ':1' + 'callback_data' => formatCallbackData(['delete_scheduled_entry', 'i' => $id, 's' => 1]) ], [ 'text' => getTranslation('no'), diff --git a/mods/events.php b/mods/events.php index 93c4527e..c4cfea12 100644 --- a/mods/events.php +++ b/mods/events.php @@ -9,9 +9,6 @@ // Check access. $botUser->accessCheck('event-manage'); -$id = $data['id']; -$arg = $data['arg']; - $keys = []; $callback_response = 'OK'; diff --git a/mods/events_add.php b/mods/events_add.php index e31f3943..dcd120b5 100644 --- a/mods/events_add.php +++ b/mods/events_add.php @@ -9,6 +9,8 @@ // Check access. $botUser->accessCheck('event-manage'); +$abort = $data['a'] ?? 0; + $keys = []; $callback_response = 'OK'; $userId = $update['callback_query']['from']['id'] ?? $update['message']['from']['id']; @@ -28,7 +30,7 @@ ] ]; }else { - if($data['arg'] == 0) { + if($abort == 0) { // Add a new event $msg = '' . getTranslation('events_create') . '' . CR; $msg .= getTranslation('events_give_name') . ':'; @@ -37,16 +39,14 @@ $userId = $update['callback_query']['from']['id']; // Data for handling response from the user - my_query('INSERT INTO user_input SET user_id=?, handler=\'events_add\', modifiers=?', [$userId, $modifiers]); + my_query('INSERT INTO user_input SET user_id = ?, handler = \'events_add\', modifiers = ?', [$userId, $modifiers]); - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => '0:events_add:a', - ] + $keys[][] = [ + 'text' => getTranslation('abort'), + 'callback_data' => formatCallbackData(['events_add', 'a' => 1]), ]; - }elseif($data['arg'] == 'a') { - my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); + }elseif($abort == 1) { + my_query('DELETE FROM user_input WHERE user_id = ?', [$userId]); answerCallbackQuery($update['callback_query']['id'], 'OK'); editMessageText($update['callback_query']['message']['message_id'], getTranslation('action_aborted'), [], $userId); exit; diff --git a/mods/list_raid.php b/mods/list_raid.php index faa20391..5cc878f2 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -84,7 +84,10 @@ debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key - $keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); + $keys[][] = [ + 'text' => getTranslation('done'), + 'callback_data' => formatCallbackData(['exit', 'd' => 1]) +]; // Get message. $msg = show_raid_poll_small($raid); diff --git a/mods/overview_delete.php b/mods/overview_delete.php index 077ad725..e86662fc 100644 --- a/mods/overview_delete.php +++ b/mods/overview_delete.php @@ -7,8 +7,7 @@ //debug_log($data); // Delete or list to deletion? -$chat_id = 0; -$chat_id = $data['arg']; +$chat_id = $data['c'] ?? 0; // Check access. $botUser->accessCheck('overview'); @@ -49,11 +48,11 @@ [ [ 'text' => getTranslation('yes'), - 'callback_data' => '0:overview_delete:' . $rowOverviews['chat_id'] + 'callback_data' => formatCallbackData(['overview_delete', 'c' => $rowOverviews['chat_id']]) ], [ 'text' => getTranslation('no'), - 'callback_data' => '0:overview_delete:1' + 'callback_data' => formatCallbackData(['overview_delete', 'c' => 1]) ] ] ]; diff --git a/mods/overview_share.php b/mods/overview_share.php index 4b93cc99..de95e044 100644 --- a/mods/overview_share.php +++ b/mods/overview_share.php @@ -12,8 +12,7 @@ $botUser->accessCheck('overview'); // Get chat ID from data -$chat_id = 0; -$chat_id = $data['arg']; +$chat_id = $data['c'] ?? 0; // Get all or specific overview $query_chat = ''; @@ -59,58 +58,59 @@ // Send the message, but disable the web preview! $tg_json[] = send_message($chat_id, $overview_message, $keys, ['disable_web_page_preview' => 'true'], true, 'overview'); -}else { - // List all overviews to user - foreach( array_keys($active_raids) as $chat_id ) { - // Make sure it's not already shared - $rs = my_query(' - SELECT chat_id, message_id, chat_title, chat_username - FROM overview - WHERE chat_id = ? - LIMIT 1 - ', [$chat_id] - ); - $keys = []; - // Already shared - if($rs->rowCount() > 0 ) { - $keys[] = [ - [ - 'text' => EMOJI_REFRESH, - 'callback_data' => '0:overview_refresh:' . $chat_id - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ]; - $res = $rs->fetch(); - $chat_title = $res['chat_title']; - $chat_username = $res['chat_username']; - }else { - [$chat_title, $chat_username] = get_chat_title_username($chat_id); - $keys[] = [ - [ - 'text' => getTranslation('share_with') . ' ' . $chat_title, - 'callback_data' => '0:overview_share:' . $chat_id - ] - ]; - } - $overview_message = get_overview($active_raids[$chat_id], $chat_title, $chat_username); - // Send the message, but disable the web preview! - $tg_json[] = send_message($update['callback_query']['message']['chat']['id'], $overview_message, $keys, ['disable_web_page_preview' => 'true'], true); + // Telegram multicurl request. + curl_json_multi_request($tg_json); + + exit; +} +// List all overviews to user +foreach( array_keys($active_raids) as $chat_id ) { + // Make sure it's not already shared + $rs = my_query(' + SELECT chat_id, message_id, chat_title, chat_username + FROM overview + WHERE chat_id = ? + LIMIT 1 + ', [$chat_id] + ); + $keys = []; + // Already shared + if($rs->rowCount() > 0 ) { + $keys[] = [ + [ + 'text' => EMOJI_REFRESH, + 'callback_data' => '0:overview_refresh:' . $chat_id + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) + ] + ]; + $res = $rs->fetch(); + $chat_title = $res['chat_title']; + $chat_username = $res['chat_username']; + }else { + [$chat_title, $chat_username] = get_chat_title_username($chat_id); + $keys[] = [ + [ + 'text' => getTranslation('share_with') . ' ' . $chat_title, + 'callback_data' => formatCallbackData(['overview_share', 'c' => $chat_id]) + ] + ]; } - // Set the callback message and keys - $callback_keys = []; - $callback_msg = '' . getTranslation('list_all_overviews') . ':'; + $overview_message = get_overview($active_raids[$chat_id], $chat_title, $chat_username); + // Send the message, but disable the web preview! + $tg_json[] = send_message($update['callback_query']['message']['chat']['id'], $overview_message, $keys, ['disable_web_page_preview' => 'true'], true); +} +// Set the callback message and keys +$callback_keys = []; +$callback_msg = '' . getTranslation('list_all_overviews') . ':'; - // Answer the callback. - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], 'OK', true); +// Answer the callback. +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], 'OK', true); - // Edit the message. - $tg_json[] = edit_message($update, $callback_msg, $callback_keys, false, true); -} +// Edit the message. +$tg_json[] = edit_message($update, $callback_msg, $callback_keys, false, true); // Telegram multicurl request. curl_json_multi_request($tg_json); - -exit; diff --git a/mods/pokedex.php b/mods/pokedex.php index 1f506335..06fef626 100644 --- a/mods/pokedex.php +++ b/mods/pokedex.php @@ -11,16 +11,13 @@ $botUser->accessCheck('pokedex'); // Get the limit. -$limit = $data['id']; - -// Get the action. -$action = $data['arg']; +$limit = $data['l'] ?? 0; // Set message. $msg = getTranslation('pokedex_list_of_all') . CR . CR . '' . getTranslation('pokedex_edit_pokemon') . ''; // Get pokemon. -$keys = edit_pokedex_keys($limit, $action); +$keys = edit_pokedex_keys($limit); // Empty keys? if (!$keys) { diff --git a/mods/pokedex_list_raids.php b/mods/pokedex_list_raids.php index 5a11f644..d2fe6f4b 100644 --- a/mods/pokedex_list_raids.php +++ b/mods/pokedex_list_raids.php @@ -69,7 +69,7 @@ if($pokemon['scheduled'] == 1) { $keys[] = array( 'text' => EMOJI_CLOCK . ' [' . $pokemon['raid_level'] . ']' . SP . $poke_name, - 'callback_data' => $pokemon['id'] . ':delete_scheduled_entry:0' + 'callback_data' => formatCallbackData(['delete_scheduled_entry', 'i' => $pokemon['id']]) ); } else { $keys[] = array( diff --git a/mods/raid_edit_poke.php b/mods/raid_edit_poke.php index bac6399c..c880e9a0 100644 --- a/mods/raid_edit_poke.php +++ b/mods/raid_edit_poke.php @@ -8,28 +8,25 @@ //debug_log($data); // Set the id. -$raid_id = $data['id']; +$raid_id = $data['r'] ?? 0; // Access check. $botUser->raidaccessCheck($raid_id, 'pokemon'); // Get raid level -$raid_level = $data['arg']; +$raid_level = $data['rl']; debug_log('Raid level of pokemon: ' . $raid_level); // Level found if ($raid_level != '0') { // Get the keys. - $keys = pokemon_keys($raid_id, $raid_level, 'raid_set_poke'); + $keys = pokemon_keys($data, $raid_level, 'raid_set_poke'); - // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 1); - - // Merge keys. - $keys = array_merge($keys, $nav_keys); + $keys[][] = [ + 'text' => getTranslation('abort'), + 'callback_data' => 'exit' + ]; } else { // Create the keys. $keys = [ diff --git a/mods/raid_set_poke.php b/mods/raid_set_poke.php index 67f8e73c..2d880362 100644 --- a/mods/raid_set_poke.php +++ b/mods/raid_set_poke.php @@ -10,12 +10,12 @@ //debug_log($data); // Set the id. -$raidId = $data['id']; +$raidId = $data['r']; // Access check. $botUser->raidaccessCheck($raidId, 'pokemon'); -$pokemon_id_form = get_pokemon_by_table_id($data['arg']); +$pokemon_id_form = get_pokemon_by_table_id($data['p']); // Update pokemon in the raid table. my_query(' diff --git a/mods/raids_list.php b/mods/raids_list.php index 515d3ede..493afa6f 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -29,7 +29,7 @@ $keys[] = [ [ 'text' => getTranslation('update_pokemon'), - 'callback_data' => $raid['id'] . ':raid_edit_poke:' . $raid['level'], + 'callback_data' => formatCallbackData(['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]), ] ]; } diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 52210593..7c6d4813 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -28,7 +28,10 @@ debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key - $keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); + $keys[][] = [ + 'text' => getTranslation('done'), + 'callback_data' => formatCallbackData(['exit', 'd' => 1]) +]; // Get message. $msg = show_raid_poll_small($raid); diff --git a/mods/trainer.php b/mods/trainer.php index 544bb81a..c1e81bfc 100644 --- a/mods/trainer.php +++ b/mods/trainer.php @@ -11,7 +11,7 @@ $botUser->accessCheck('trainer'); $user_id = $update['callback_query']['from']['id']; -if($data['arg'] == 'a') { +if(isset($data['a']) && $data['a'] == 1) { my_query('UPDATE users SET auto_alarm = IF(auto_alarm = 1, 0, 1) WHERE user_id = ?', [$user_id]); } @@ -53,7 +53,7 @@ $keys[] = [ [ 'text' => ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), - 'callback_data' => '0:trainer:a' + 'callback_data' => formatCallbackData(['trainer', 'a' => 1]) ] ]; } @@ -89,7 +89,10 @@ } // Get the inline key array. -$keys = universal_key($keys, '0', 'exit', '1', getTranslation('done')); +$keys[][] = [ + 'text' => getTranslation('done'), + 'callback_data' => formatCallbackData(['exit', 'd' => 1]) +]; // Answer callback. answerCallbackQuery($update['callback_query']['id'], 'OK'); diff --git a/mods/trainerGymarea.php b/mods/trainerGymarea.php index 3b13aa78..b02503ff 100644 --- a/mods/trainerGymarea.php +++ b/mods/trainerGymarea.php @@ -39,7 +39,7 @@ ], [ 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'arg' => 1]) + 'callback_data' => formatCallbackData(['exit', 'd' => 1]) ] ]; // Set message. diff --git a/mods/trainer_code.php b/mods/trainer_code.php index ff9c542b..9a0380dd 100644 --- a/mods/trainer_code.php +++ b/mods/trainer_code.php @@ -11,8 +11,7 @@ $botUser->accessCheck('trainer'); // Mode and action -$mode = $data['id']; -$action = $data['arg']; +$action = $data['a'] ?? ''; // Set the user_id $user_id = $update['callback_query']['from']['id']; @@ -60,10 +59,10 @@ $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:trainer_code:cancel' + 'callback_data' => formatCallbackData(['trainer_code', 'a' => 'cancel']) ],[ 'text' => getTranslation('delete'), - 'callback_data' => '0:trainer_code:delete' + 'callback_data' => formatCallbackData(['trainer_code', 'a' => 'delete']) ] ]; // Answer callback. diff --git a/mods/trainer_level.php b/mods/trainer_level.php index a50fe769..8ef8be0c 100644 --- a/mods/trainer_level.php +++ b/mods/trainer_level.php @@ -10,15 +10,13 @@ // Access check. $botUser->accessCheck('trainer'); -// Confirmation and level -$confirm = $data['id']; -$level = $data['arg']; +$level = $data['l'] ?? 0; // Set the user_id $user_id = $update['callback_query']['from']['id']; // Ask for user level -if($confirm == 0) { +if($level == 0) { // Build message string. $msg = '' . getTranslation('your_trainer_info') . '' . CR; $msg .= get_user($user_id) . CR; @@ -27,29 +25,32 @@ // Set keys. $keys = []; for($i = 5; $i <= $config->TRAINER_MAX_LEVEL; $i++) { - $keys[] = array( + $keys[] = [ 'text' => $i, - 'callback_data' => '1:trainer_level:' . $i - ); + 'callback_data' => formatCallbackData(['trainer_level', 'l' => $i]) + ]; } // Get the inline key array. $keys = inline_key_array($keys, 5); // Add navigation keys. - $nav_keys = []; - $nav_keys[] = universal_inner_key($nav_keys, '0', 'trainer', '0', getTranslation('back')); - $nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); - $nav_keys = inline_key_array($nav_keys, 2); - - // Merge keys. - $keys = array_merge($keys, $nav_keys); + $keys[] = [ + [ + 'text' => getTranslation('back'), + 'callback_data' => 'trainer' + ], + [ + 'text' => getTranslation('done'), + 'callback_data' => formatCallbackData(['exit', 'd' => '1']) + ] + ]; // Build callback message string. $callback_response = 'OK'; // Save user level -} else if($confirm == 1 && $level > 0) { +} else { // Update the user. my_query(' diff --git a/mods/trainer_name.php b/mods/trainer_name.php index 8381b13c..05c1df12 100644 --- a/mods/trainer_name.php +++ b/mods/trainer_name.php @@ -10,9 +10,7 @@ // Access check. $botUser->accessCheck('trainer'); -// Mode and action -$mode = $data['id']; -$action = $data['arg']; +$action = $data['a'] ?? ''; // Set the user_id $user_id = $botUser->userId; @@ -72,23 +70,23 @@ $keys[] = [ [ 'text' => getTranslation('switch_display_name'), - 'callback_data' => '0:trainer_name:switch' + 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'switch']) ] ]; $keys[] = [ [ 'text' => getTranslation('trainername_edit'), - 'callback_data' => '0:trainer_name:add' + 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'add']) ],[ 'text' => getTranslation('delete'), - 'callback_data' => '0:trainer_name:delete' + 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'delete']) ] ]; }else { $keys[] = [ [ 'text' => getTranslation('trainername_add'), - 'callback_data' => '0:trainer_name:add' + 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'add']) ] ]; } @@ -96,7 +94,7 @@ $keys[] = [ [ 'text' => getTranslation('back'), - 'callback_data' => '0:trainer_name:cancel' + 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'cancel']) ] ]; diff --git a/mods/trainer_team.php b/mods/trainer_team.php index 735d6ee1..acbea422 100644 --- a/mods/trainer_team.php +++ b/mods/trainer_team.php @@ -11,29 +11,28 @@ $botUser->accessCheck('trainer'); // Confirmation and level -$confirm = $data['id']; -$team = $data['arg']; +$team = $data['t'] ?? ''; // Set the user_id $user_id = $update['callback_query']['from']['id']; // Ask for user level -if($confirm == 0) { +if($team == '') { // Set keys. $keys = [ [ [ 'text' => TEAM_B, - 'callback_data' => '1:trainer_team:mystic' + 'callback_data' => formatCallbackData(['trainer_team', 't' => 'mystic']) ], [ 'text' => TEAM_R, - 'callback_data' => '1:trainer_team:valor' + 'callback_data' => formatCallbackData(['trainer_team', 't' => 'valor']) ], [ 'text' => TEAM_Y, - 'callback_data' => '1:trainer_team:instinct' + 'callback_data' => formatCallbackData(['trainer_team', 't' => 'instinct']) ] ], [ @@ -57,7 +56,7 @@ $callback_response = 'OK'; // Write team to database. -} else if($confirm == 1 && ($team == 'mystic' || $team == 'valor' || $team == 'instinct')) { +} else if($team == 'mystic' || $team == 'valor' || $team == 'instinct') { // Update the user. my_query(' UPDATE users From c0e18ba03fae2954e175f4f31ae80f09a97b64e0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 13 Dec 2022 00:18:51 +0200 Subject: [PATCH 197/367] Make the code a bit easier to read --- mods/getdb.php | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 502ee414..64c2941e 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -49,31 +49,30 @@ $SQL = ''; foreach($pokemon_array as $id => $forms) { $pokemon_id = $id; - foreach($forms as $form=>$data) { + foreach($forms as $form => $data) { // Check that data is set, if not the mon is probably not in the game yet and there's no point in having them in a broken state - if(isset($data['weather']) && isset($data['min_cp']) && isset($data['max_cp']) && isset($data['min_weather_cp']) && isset($data['max_weather_cp']) && isset($data['pokemon_name'])) { - $poke_form = $form; + if(!isset($data['weather']) || !isset($data['min_cp']) || !isset($data['max_cp']) || !isset($data['min_weather_cp']) || !isset($data['max_weather_cp']) || !isset($data['pokemon_name'])) continue; - $poke_name = $data['pokemon_name']; - $form_id = $data['pokemon_form_id']; - $form_asset_suffix = $data['asset_suffix']; - $poke_min_cp = $data['min_cp']; - $poke_max_cp = $data['max_cp']; - $poke_min_weather_cp = $data['min_weather_cp']; - $poke_max_weather_cp = $data['max_weather_cp']; - $poke_type = $data['type']; - $poke_type2 = $data['type2']; - $poke_weather = $data['weather']; + $poke_name = $data['pokemon_name']; + $form_id = $data['pokemon_form_id']; + $form_asset_suffix = $data['asset_suffix']; + $poke_min_cp = $data['min_cp']; + $poke_max_cp = $data['max_cp']; + $poke_min_weather_cp = $data['min_weather_cp']; + $poke_max_weather_cp = $data['max_weather_cp']; + $poke_type = $data['type']; + $poke_type2 = $data['type2']; + $poke_weather = $data['weather']; - if($pokemon_id == 150 && $data['pokemon_form_name']=="a") { - // Because logic and consistency - $poke_form = 'armored'; - }else { - $poke_form = strtolower($data['pokemon_form_name']); - } - if($i==0) $i=1; else $SQL .= ","; - $SQL .= PHP_EOL . "(\"${pokemon_id}\", \"${poke_name}\", \"${poke_form}\", \"${form_id}\", \"${form_asset_suffix}\", \"${poke_min_cp}\", \"${poke_max_cp}\", \"${poke_min_weather_cp}\", \"${poke_max_weather_cp}\", \"${poke_type}\", \"${poke_type2}\", \"${poke_weather}\")"; + if($pokemon_id == 150 && $data['pokemon_form_name']=="a") { + // Because logic and consistency + $poke_form = 'armored'; + }else { + $poke_form = strtolower($data['pokemon_form_name']); } + if($i==0) $i=1; else $SQL .= ","; + $insertData = [$pokemon_id, $poke_name, $poke_form, $form_id, $form_asset_suffix, $poke_min_cp, $poke_max_cp, $poke_min_weather_cp, $poke_max_weather_cp, $poke_type, $poke_type2, $poke_weather]; + $SQL .= PHP_EOL . '("' . implode('","', $insertData) . '")'; } } ## MySQL 8 compatible @@ -88,6 +87,7 @@ $SQL .= 'type = VALUES(type), type2 = VALUES(type2), weather = VALUES(weather);' . PHP_EOL; try { $prep = $dbh->prepare($SQL); + info_log($SQL); $prep->execute(); } catch (Exception $e) { if(isset($update['message']['from']['id'])) $error = $e; From ccfd78273e23607b13907b658d64b3f1c2745b8e Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 13 Dec 2022 00:19:08 +0200 Subject: [PATCH 198/367] Added a new function to create a simple tg button --- logic/key_util.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/logic/key_util.php b/logic/key_util.php index b2b496b0..f82331db 100644 --- a/logic/key_util.php +++ b/logic/key_util.php @@ -176,3 +176,19 @@ function formatCallbackData($array) } return rtrim($return, '|'); } + +/** + * Return a button element + * @param string Button text + * @param string|array Callback data + * @return array Button + */ +function button($text, $callbackData) +{ + $callback = is_array($callbackData) ? formatCallbackData($callbackData) : $callbackData; + $button = [ + 'text' => $text, + 'callback_data' => $callback + ]; + return $button; +} From 9c7c141edbfa97b307906719de3c546afff3384d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 14 Dec 2022 00:07:03 +0200 Subject: [PATCH 199/367] Fixed remote gyms button --- logic/gymMenu.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/gymMenu.php b/logic/gymMenu.php index 7687c8ad..acd5d17c 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -55,7 +55,7 @@ function gymMenu($buttonAction, $showHidden, $stage, $firstLetter = false, $gyma if($query_remote->fetch()['count'] > 0) { $keys[][] = [ 'text' => getTranslation('remote_raids'), - 'callback_data' => 'list_remote_raids' + 'callback_data' => 'list_remote_gyms' ]; } } From fc41dbf159ca83eb4cd5f87150f3457bd059ba58 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Wed, 14 Dec 2022 17:10:26 +0200 Subject: [PATCH 200/367] Ignore unneeded config folder items when building an image The risk is for example accidentally building an image with a preset config.json --- .dockerignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.dockerignore b/.dockerignore index 707fbd5f..47d9cbdf 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,3 +7,5 @@ docs .git !.git/HEAD !.git/refs/* +config/ +!config/defaults-*.json From bce5949b3d5d8ffc8c8516e21792a55c8df15182 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Wed, 14 Dec 2022 17:11:45 +0200 Subject: [PATCH 201/367] Import config earlier in the metrics endpoint It's already needed for debug to work. --- metrics/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics/index.php b/metrics/index.php index 77e16ef4..e5214954 100644 --- a/metrics/index.php +++ b/metrics/index.php @@ -7,9 +7,9 @@ use Prometheus\RenderTextFormat; require_once __DIR__ . '/../core/bot/paths.php'; +require_once(CORE_BOT_PATH . '/config.php'); require_once(ROOT_PATH . '/logic/debug.php'); require_once(ROOT_PATH . '/logic/bearer_token.php'); -require_once(CORE_BOT_PATH . '/config.php'); // Authentication is done based on a Bearer Token provided as a header $bearer_token = getBearerToken(); From 9caff33d6725335a6a957f2fa2e216b014631b2c Mon Sep 17 00:00:00 2001 From: Artanicus Date: Wed, 14 Dec 2022 17:13:46 +0200 Subject: [PATCH 202/367] Improve errors for bad config json, debug logging of media edit --- core/bot/config.php | 2 +- core/telegram/functions.php | 2 +- logic/debug.php | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/bot/config.php b/core/bot/config.php index 4d268243..9baca4e1 100644 --- a/core/bot/config.php +++ b/core/bot/config.php @@ -16,7 +16,7 @@ function get_config_array($file) { $config_array = json_decode($file_contents, true); if(json_last_error() !== JSON_ERROR_NONE) { - error_log('Invalid JSON (' . json_last_error_msg() . '): ' . $file); + error_log('[core/bot/config.php] Invalid JSON (' . json_last_error_msg() . '): ' . $file . "\n What we got from the file: \n" . $file_contents); die('Config file not valid JSON, cannot continue: ' . $file); } diff --git a/core/telegram/functions.php b/core/telegram/functions.php index 350837e7..5197d0a1 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -681,7 +681,7 @@ function editMessageMedia($id_val, $text_val, $media_content, $content_type, $in $post_contents['media']['media'] = $media_content; } $post_contents['media'] = json_encode($post_contents['media']); - debug_log(print_r($post_contents, true), '->'); + debug_log("Editing message ${post_contents['message_id']} media: ${post_contents['media']}", '->'); // Send request to telegram api. return curl_request($post_contents, $multicurl, $identifier); diff --git a/logic/debug.php b/logic/debug.php index b698cdc7..1a876434 100644 --- a/logic/debug.php +++ b/logic/debug.php @@ -1,5 +1,8 @@ Date: Wed, 14 Dec 2022 17:10:26 +0200 Subject: [PATCH 203/367] Ignore unneeded config folder items when building an image The risk is for example accidentally building an image with a preset config.json --- .dockerignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.dockerignore b/.dockerignore index 707fbd5f..47d9cbdf 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,3 +7,5 @@ docs .git !.git/HEAD !.git/refs/* +config/ +!config/defaults-*.json From 6c5434ccc162bb8be902e1a772e222bdab4a961c Mon Sep 17 00:00:00 2001 From: Artanicus Date: Wed, 14 Dec 2022 17:13:46 +0200 Subject: [PATCH 204/367] Improve errors for bad config json, debug logging of media edit --- core/bot/config.php | 2 +- core/bot/logic/debug.php | 3 +++ core/telegram/functions.php | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/bot/config.php b/core/bot/config.php index 348c425d..e3503a39 100644 --- a/core/bot/config.php +++ b/core/bot/config.php @@ -16,7 +16,7 @@ function get_config_array($file) { $config_array = json_decode($file_contents, true); if(json_last_error() !== JSON_ERROR_NONE) { - error_log('Invalid JSON (' . json_last_error_msg() . '): ' . $file); + error_log('[core/bot/config.php] Invalid JSON (' . json_last_error_msg() . '): ' . $file . "\n What we got from the file: \n" . $file_contents); die('Config file not valid JSON, cannot continue: ' . $file); } diff --git a/core/bot/logic/debug.php b/core/bot/logic/debug.php index caa1e6e7..ae633c49 100644 --- a/core/bot/logic/debug.php +++ b/core/bot/logic/debug.php @@ -1,5 +1,8 @@ '); + debug_log("Editing message ${post_contents['message_id']} media: ${post_contents['media']}", '->'); // Send request to telegram api. return curl_request($post_contents, $multicurl, $identifier); From ddec52732524f2d718ee1a03225badf23bc4cb41 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 14 Dec 2022 18:34:24 +0200 Subject: [PATCH 205/367] Fixed remote raids --- mods/edit_raidlevel.php | 8 +++++++- mods/raid_by_location.php | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index 06e41392..cc5c1686 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -16,6 +16,12 @@ $gym_id = $data['g']; $gym = get_gym($gym_id); +$showBackButton = true; +if(isset($data['z'])) { + $showBackButton = false; + unset($data['z']); +} + // Telegram JSON array. $tg_json = array(); @@ -117,7 +123,7 @@ } $lastRow = []; -if(!isset($data['r']) or $data['r'] != 1) { +if($showBackButton) { $backData = $data; $backData[0] = 'gymMenu'; $backData['a'] = 'create'; diff --git a/mods/raid_by_location.php b/mods/raid_by_location.php index 330e1b3b..2917bd32 100644 --- a/mods/raid_by_location.php +++ b/mods/raid_by_location.php @@ -142,7 +142,7 @@ [ [ 'text' => getTranslation('next'), - 'callback_data' => formatCallbackData(['edit_raidlevel', 'gl' => $gym_letter, 'g' => $gym_id, 'r' => 1]) + 'callback_data' => formatCallbackData(['edit_raidlevel', 'gl' => $gym_letter, 'g' => $gym_id, 'z' => 1]) ] ], [ From f292fa0c0034546c92ef2856e2bf361b7b017b1f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 15 Dec 2022 10:38:50 +0200 Subject: [PATCH 206/367] Use more accurate date in raid creation --- mods/edit_starttime.php | 31 ++++++------------------------- mods/edit_time.php | 21 +++++---------------- 2 files changed, 11 insertions(+), 41 deletions(-) diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index ef5c04c3..127f2e95 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -92,7 +92,7 @@ $now_plus_i = new DateTime($now, new DateTimeZone('UTC')); for ($i = 1; $i <= $config->RAID_EGG_DURATION; $i = $i + 1) { $now_plus_i->add(new DateInterval('PT1M')); - $buttonData['t'] = $now_plus_i->format("H:i"); + $buttonData['t'] = $now_plus_i->format("YmdHi"); if ($arg == 'min') $buttonText = floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT); else @@ -115,18 +115,12 @@ $keyData['o'] = 'm'; $keyData['t'] = utctime($now,"H-i"); // Raid already running - $keys_opt[] = array( - 'text' => getTranslation('is_raid_active'), - 'callback_data' => formatCallbackData($keyData) - ); + $keys_opt[] = button(getTranslation('is_raid_active'), $keyData); $keyData[0] = 'edit_starttime'; $keyData['o'] = $switch_view; unset($keyData['t']); // Switch view: clocktime / minutes until start - $keys_opt[] = array( - 'text' => $switch_text, - 'callback_data' => formatCallbackData($keyData) - ); + $keys_opt[] = button($switch_text, $keyData); // Get the inline key array. $keys_opt = inline_key_array($keys_opt, 2); @@ -142,27 +136,14 @@ // No keys found. if (!$keys) { // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ] - ]; + $keys[][] = button(getTranslation('abort'), 'exit'); } else { $backData = $data; $backData[0] = 'edit_pokemon'; // Add navigation keys. $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData($backData) - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + button(getTranslation('back'), formatCallbackData($backData)), + button(getTranslation('abort'), 'exit') ]; } diff --git a/mods/edit_time.php b/mods/edit_time.php index 55aa7f80..e55205cb 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -30,11 +30,11 @@ // Replace "-" with ":" to get proper time format debug_log('Formatting the raid time properly now.'); + // Date was received in format YearMonthDayHourMinute so we need to reformat it to datetime + $start_date_time = substr($starttime,0,4) . '-' . substr($starttime,4,2) . '-' . substr($starttime,6,2) . ' ' . substr($starttime,8,2) . ':' . substr($starttime,10,2) . ':00'; // Event raids if($event_id != NULL) { $event_id = ($event_id == 'X') ? EVENT_ID_EX : $event_id; - // Date was received in format YearMonthDayHourMinute so we need to reformat it to datetime - $start_date_time = substr($starttime,0,4) . '-' . substr($starttime,4,2) . '-' . substr($starttime,6,2) . ' ' . substr($starttime,8,2) . ':' . substr($starttime,10,2) . ':00'; debug_log('Event time :D ... Setting raid date to ' . $start_date_time); $query = my_query('SELECT raid_duration FROM events WHERE id = ? LIMIT 1', [$event_id]); $result = $query->fetch(); @@ -43,20 +43,12 @@ // Elite raids }elseif($raid_level == 9) { - // Date was received in format YearMonthDayHourMinute so we need to reformat it to datetime - $start_date_time = substr($starttime,0,4) . '-' . substr($starttime,4,2) . '-' . substr($starttime,6,2) . ' ' . substr($starttime,8,2) . ':' . substr($starttime,10,2) . ':00'; debug_log('Elite Raid time :D ... Setting raid date to ' . $start_date_time); $duration = $config->RAID_DURATION_ELITE; $egg_duration = $config->RAID_EGG_DURATION_ELITE; // Normal raids } else { - $arg_time = str_replace('-', ':', $starttime); - // Current date - $current_date = date('Y-m-d', strtotime('now')); - debug_log('Today is a raid day! Setting raid date to ' . $current_date); - // Raid time - $start_date_time = $current_date . ' ' . $arg_time . ':00'; debug_log('Received the following time for the raid: ' . $start_date_time); $duration = $config->RAID_DURATION; $egg_duration = $config->RAID_EGG_DURATION; @@ -81,7 +73,7 @@ // Add keys for sharing the raid. if(!empty($keys)) { // Exit key - $keys = universal_key($keys, '0', 'exit', '0', getTranslation('abort')); + $keys[][] = button(getTranslation('abort'), 'exit'); } // Answer callback. @@ -145,11 +137,8 @@ for ($i = $slotmax; $i >= 15; $i = $i - $slotsize) { // Create the keys. - $keys[] = array( - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT), - 'callback_data' => formatCallbackData(['edit_save', 'd' => $i, 'r' => $raid_id]) - ); + $buttonText = floor($i / 60) . ':' . str_pad($i % 60, 2, '0', STR_PAD_LEFT); + $keys[] = button($buttonText, ['edit_save', 'd' => $i, 'r' => $raid_id]); } } else { From e26ce7057d9ddf3d71741495d19ac801735d2061 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 15 Dec 2022 14:20:13 +0200 Subject: [PATCH 207/367] Forgot to remove logging --- mods/getdb.php | 1 - 1 file changed, 1 deletion(-) diff --git a/mods/getdb.php b/mods/getdb.php index 64c2941e..9840879a 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -87,7 +87,6 @@ $SQL .= 'type = VALUES(type), type2 = VALUES(type2), weather = VALUES(weather);' . PHP_EOL; try { $prep = $dbh->prepare($SQL); - info_log($SQL); $prep->execute(); } catch (Exception $e) { if(isset($update['message']['from']['id'])) $error = $e; From 8978d4d4d9dbf34d933b598d90581df001131418 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 15 Dec 2022 14:46:41 +0200 Subject: [PATCH 208/367] Finalized the conversion to the new callback_data system Everything works mostly, but I might have missed something. Existing trainerinfo messages will stop working so they need to be deleted and reshared --- commands/delete.php | 12 +- commands/events.php | 24 +--- commands/help.php | 9 +- commands/list.php | 10 +- commands/overview.php | 14 +- commands/pokedex.php | 49 +------ commands/pokemon.php | 10 +- commands/start.php | 7 +- commands/trainer.php | 48 ++----- commands/tutorial.php | 9 +- logic/edit_gym_keys.php | 62 +++------ logic/edit_pokedex_keys.php | 33 +---- logic/group_code_keys.php | 90 ++++++------ logic/gymMenu.php | 51 ++----- logic/history.php | 77 +++++------ logic/key_util.php | 214 +++++++++++------------------ logic/keys_event.php | 10 +- logic/keys_trainerinfo.php | 48 ++----- logic/keys_vote.php | 142 ++++--------------- logic/pokemon_keys.php | 5 +- logic/raid_edit_raidlevel_keys.php | 15 +- logic/raid_get_gyms_list_keys.php | 5 +- logic/weather_keys.php | 46 ++----- mods/bot_lang.php | 27 +--- mods/change_trainercode.php | 14 +- mods/change_trainername.php | 14 +- mods/code.php | 23 +--- mods/code_start.php | 21 +-- mods/delete_scheduled_entry.php | 12 +- mods/edit_date.php | 27 +--- mods/edit_event.php | 12 +- mods/edit_event_note.php | 25 ++-- mods/edit_event_raidlevel.php | 12 +- mods/edit_pokemon.php | 10 +- mods/edit_raidlevel.php | 64 ++------- mods/edit_save.php | 25 +--- mods/edit_starttime.php | 10 +- mods/end_remote_raid.php | 2 +- mods/events.php | 14 +- mods/events_add.php | 12 +- mods/events_manage.php | 61 ++++---- mods/gym_create.php | 26 +--- mods/gym_delete.php | 18 +-- mods/gym_edit_details.php | 15 +- mods/history.php | 43 +++--- mods/history_gyms.php | 23 +--- mods/history_raid.php | 18 +-- mods/history_raids.php | 28 ++-- mods/import_future_bosses.php | 95 +++++-------- mods/import_shinyinfo.php | 15 +- mods/importal.php | 21 +-- mods/list_raid.php | 55 ++------ mods/list_remote_gyms.php | 14 +- mods/overview_delete.php | 14 +- mods/overview_refresh.php | 13 +- mods/overview_share.php | 19 +-- mods/pogoinfo.php | 54 ++------ mods/pokebattler.php | 57 ++------ mods/pokedex_disable_raids.php | 32 +---- mods/pokedex_edit_pokemon.php | 72 ++-------- mods/pokedex_import.php | 37 +---- mods/pokedex_list_raids.php | 18 +-- mods/pokedex_set_cp.php | 79 +++-------- mods/pokedex_set_raid_level.php | 44 ++---- mods/pokedex_set_shiny.php | 41 ++---- mods/pokedex_set_weather.php | 32 ++--- mods/raid_by_location.php | 16 +-- mods/raid_edit_poke.php | 14 +- mods/raid_share.php | 4 +- mods/raids_delete.php | 14 +- mods/raids_list.php | 28 +--- mods/save_event_note.php | 19 +-- mods/share_raid_by_location.php | 186 ++++++++++++------------- mods/trainer.php | 55 ++------ mods/trainerGymarea.php | 16 +-- mods/trainer_add.php | 9 +- mods/trainer_code.php | 9 +- mods/trainer_delete.php | 26 +--- mods/trainer_level.php | 29 +--- mods/trainer_name.php | 34 +---- mods/trainer_share.php | 2 +- mods/trainer_team.php | 46 +------ mods/tutorial.php | 56 ++------ mods/update_bosses.php | 1 - mods/vote_can_invite.php | 2 +- mods/vote_extra.php | 19 +-- mods/vote_invite.php | 4 +- mods/vote_level.php | 24 ++-- mods/vote_pokemon.php | 29 ++-- mods/vote_refresh.php | 2 +- mods/vote_remote.php | 2 +- mods/vote_status.php | 29 ++-- mods/vote_team.php | 12 +- mods/vote_time.php | 4 +- mods/vote_want_invite.php | 2 +- 95 files changed, 817 insertions(+), 2134 deletions(-) diff --git a/commands/delete.php b/commands/delete.php index e3cc8a54..3fd087ec 100644 --- a/commands/delete.php +++ b/commands/delete.php @@ -46,20 +46,16 @@ $start = dt2time($row['start_time']); $end = dt2time($row['end_time']); $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; - $keys[] = [ - 'text' => $row['gym_name'], - 'callback_data' => formatCallbackData(['raids_delete', 'r' => $row['id']]) - ]; + $keys[] = button($row['gym_name'], ['raids_delete', 'r' => $row['id']]); + } // Get the inline key array. $keys = inline_key_array($keys, 1); // Add exit key. -$keys[][] = [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' -]; +$keys[][] = button(getTranslation('abort'), 'exit'); + // Build message. $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; diff --git a/commands/events.php b/commands/events.php index fec4c1e6..874f8594 100644 --- a/commands/events.php +++ b/commands/events.php @@ -20,25 +20,9 @@ $msg .= $event['description'] . CR . CR; } -$keys = [ - [ - [ - 'text' => getTranslation('events_manage'), - 'callback_data' => 'events', - ] - ], - [ - [ - 'text' => getTranslation('events_create'), - 'callback_data' => 'events_add', - ] - ], - [ - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']), - ] - ] -]; +$keys[][] = button(getTranslation('events_manage'), 'events'); +$keys[][] = button(getTranslation('events_create'), 'events_add'); +$keys[][] = button(getTranslation('done'), ['exit', 'd' => '1']); + // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/help.php b/commands/help.php index aeae022b..3ab5b021 100644 --- a/commands/help.php +++ b/commands/help.php @@ -56,14 +56,7 @@ }else { $msg = $tutorial[0]['msg']; } - $keys = [ - [ - [ - 'text' => getTranslation('next'), - 'callback_data' => 'tutorial' - ] - ] - ]; + $keys[][] = button(getTranslation('next'), 'tutorial'); $photo = $tutorial[0]['photo']; send_photo($update['message']['from']['id'],$photo, false, $msg, $keys, ['disable_web_page_preview' => 'true']); exit(); diff --git a/commands/list.php b/commands/list.php index f8633cee..a1b7175b 100644 --- a/commands/list.php +++ b/commands/list.php @@ -85,15 +85,9 @@ } $keys_text .= ($raid['ex_gym'] === 1 ? EMOJI_STAR . SP : '') . $gym_name; - $keys[] = array( - 'text' => $keys_text, - 'callback_data' => formatCallbackData(['raids_list', 'r' => $raid['id']]) - ); + $keys[] = button($keys_text, ['raids_list', 'r' => $raid['id']]); } -$keys[] = array( - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) -); +$keys[] = button(getTranslation('done'), ['exit', 'd' => '1']); // Get the inline key array. $keys = inline_key_array($keys, 1); diff --git a/commands/overview.php b/commands/overview.php index 891d800f..c5e71ced 100644 --- a/commands/overview.php +++ b/commands/overview.php @@ -10,18 +10,8 @@ $botUser->accessCheck('overview'); // Create keys array. -$keys = [ - [ - [ - 'text' => getTranslation('overview_share'), - 'callback_data' => 'overview_share' - ], - [ - 'text' => getTranslation('overview_delete'), - 'callback_data' => 'overview_delete' - ] - ] -]; +$keys[][] = button(getTranslation('overview_share'), 'overview_share'); +$keys[][] = button(getTranslation('overview_delete'), 'overview_delete'); // Set message. $msg = '' . getTranslation('raids_share_overview') . ':'; diff --git a/commands/pokedex.php b/commands/pokedex.php index f170c4d5..f3bf495c 100644 --- a/commands/pokedex.php +++ b/commands/pokedex.php @@ -28,12 +28,7 @@ } $query = my_query('SELECT pokedex_id, pokemon_form_id FROM pokemon WHERE pokedex_id = :pokedex_id', [':pokedex_id' => $pokedex_id]); while ($pokemon = $query->fetch()) { - $keys[] = [ - [ - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), - 'callback_data' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' - ] - ]; + $keys[][] = button(get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), ['pokedex_edit_pokemon', 'p' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id']]); } // Set message. $msg = '' . getTranslation('pokedex_edit_pokemon') . ''; @@ -43,46 +38,16 @@ $query = my_query('SELECT id FROM pokemon WHERE pokedex_id = 9999 and pokemon_form_id = 0'); // A simple check to see if pokemon table has all the necessary data in it if($query->rowCount() > 0) { // Create keys array. - $keys = [ - [ - [ - 'text' => getTranslation('pokedex_raid_pokemon'), - 'callback_data' => 'pokedex_list_raids' - ] - ], - [ - [ - 'text' => getTranslation('edit_pokemon'), - 'callback_data' => 'pokedex' - ] - ], - [ - [ - 'text' => getTranslation('disable_raid_level'), - 'callback_data' => 'pokedex_disable_raids' - ] - ], - [ - [ - 'text' => getTranslation('import'), - 'callback_data' => 'pokedex_import' - ] - ] - ]; + $keys[][] = button(getTranslation('pokedex_raid_pokemon'), 'pokedex_list_raids'); + $keys[][] = button(getTranslation('edit_pokemon'), 'pokedex'); + $keys[][] = button(getTranslation('disable_raid_level'), 'pokedex_disable_raids'); + $keys[][] = button(getTranslation('import'), 'pokedex_import'); } - $keys[][] = [ - 'text' => getTranslation('update_pokemon_table'), - 'callback_data' => 'getdb' - ]; + $keys[][] = button(getTranslation('update_pokemon_table'), 'getdb'); // Set message. $msg = '' . getTranslation('pokedex_start') . ':'; } -$keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] -]; +$keys[][] = button(getTranslation('abort'), 'exit'); // Send message. send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/pokemon.php b/commands/pokemon.php index 91c932b3..4228a8cf 100644 --- a/commands/pokemon.php +++ b/commands/pokemon.php @@ -57,20 +57,14 @@ // Set text and keys. $text .= $row['gym_name'] . CR; $text .= get_local_pokemon_name($row['pokemon'], $row['pokemon_form']) . SP . '—' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; - $keys[] = [ - 'text' => $keys_text, - 'callback_data' => formatCallbackData(['raid_edit_poke', 'r' => $row['id'], 'rl' => $row['level']]), - ]; + $keys[] = button($keys_text, ['raid_edit_poke', 'r' => $row['id'], 'rl' => $row['level']]); } // Get the inline key array. $keys = inline_key_array($keys, 1); // Add exit key. -$keys[][] = [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' -]; +$keys[][] = button(getTranslation('abort'), 'exit'); // Build message. $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; diff --git a/commands/start.php b/commands/start.php index 8f44b554..84d15a3b 100644 --- a/commands/start.php +++ b/commands/start.php @@ -56,12 +56,7 @@ // No keys found. if ($addAbortKey) { - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ]; + $keys[][] = button(getTranslation('abort'), 'exit'); } // Send message. diff --git a/commands/trainer.php b/commands/trainer.php index 0de84160..73280de4 100644 --- a/commands/trainer.php +++ b/commands/trainer.php @@ -20,52 +20,26 @@ $keys = []; // Create keys array. if($config->CUSTOM_TRAINERNAME){ - $keys[0][] = [ - 'text' => getTranslation('name'), - 'callback_data' => 'trainer_name' - ]; + $keys[0][] = button(getTranslation('name'), 'trainer_name'); } if($config->RAID_POLL_SHOW_TRAINERCODE){ - $keys[0][] = [ - 'text' => getTranslation('trainercode'), - 'callback_data' => 'trainer_code' - ]; + $keys[0][] = button(getTranslation('trainercode'), 'trainer_code'); } $keys[] = [ - [ - 'text' => getTranslation('team'), - 'callback_data' => 'trainer_team' - ], - [ - 'text' => getTranslation('level'), - 'callback_data' => 'trainer_level' - ] + button(getTranslation('team'), 'trainer_team'), + button(getTranslation('level'), 'trainer_level') ]; if ($config->RAID_AUTOMATIC_ALARM == false) { $q_user = my_query('SELECT auto_alarm FROM users WHERE user_id = ? LIMIT 1', [$user_id]); $alarm_status = $q_user->fetch()['auto_alarm']; - $keys[] = [ - [ - 'text' => ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), - 'callback_data' => formatCallbackData(['trainer', 'a' => 1]) - ] - ]; + $buttonText = ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM); + $keys[][] = button($buttonText, ['trainer', 'a' => 1]); } if ($config->LANGUAGE_PRIVATE == '') { - $keys[] = [ - [ - 'text' => getTranslation('bot_lang'), - 'callback_data' => 'bot_lang' - ] - ]; + $keys[][] = button(getTranslation('bot_lang'), 'bot_lang'); } if ($config->ENABLE_GYM_AREAS == true) { - $keys[] = [ - [ - 'text' => getTranslation('default_gymarea'), - 'callback_data' => 'trainerGymarea' - ] - ]; + $keys[][] = button(getTranslation('default_gymarea'), 'trainerGymarea'); } // Check access. @@ -75,8 +49,8 @@ if($access) { // Add sharing keys. $share_keys = []; - $share_keys[] = universal_inner_key($keys, '0', 'trainer_add', '0', getTranslation('trainer_message_share')); - $share_keys[] = universal_inner_key($keys, '0', 'trainer_delete', '0', getTranslation('trainer_message_delete')); + $share_keys[] = button(getTranslation('trainer_message_share'), 'trainer_add'); + $share_keys[] = button(getTranslation('trainer_message_delete'), 'trainer_delete'); // Get the inline key array. $keys[] = $share_keys; @@ -87,7 +61,7 @@ // Add abort key. $nav_keys = []; -$nav_keys[] = universal_inner_key($keys, '0', 'exit', '1', getTranslation('done')); +$nav_keys[] = button(getTranslation('done'), 'exit'); // Get the inline key array. $keys[] = $nav_keys; diff --git a/commands/tutorial.php b/commands/tutorial.php index 638aafb4..a6601b3e 100644 --- a/commands/tutorial.php +++ b/commands/tutorial.php @@ -16,13 +16,6 @@ // New user can already be set if this file was included from start.php. If not, set it here $new_user = $new_user ?? new_user($update['message']['from']['id']); $msg = ($new_user) ? $tutorial[0]['msg_new'] : $tutorial[0]['msg']; -$keys = [ - [ - [ - 'text' => getTranslation("next"), - 'callback_data' => '0:tutorial:1' - ] - ] -]; +$keys[][] = button(getTranslation('next'), ['tutorial', 'p' => 1]); $photo = $tutorial[0]['photo']; send_photo($update['message']['from']['id'], $photo, false, $msg, $keys, ['disable_web_page_preview' => 'true'],false); diff --git a/logic/edit_gym_keys.php b/logic/edit_gym_keys.php index 31c0568a..4eed092c 100644 --- a/logic/edit_gym_keys.php +++ b/logic/edit_gym_keys.php @@ -22,59 +22,31 @@ function edit_gym_keys($update, $gym_id, $show_gym, $ex_gym, $gym_note, $gym_add // Add buttons to show/hide the gym and add/remove ex-raid flag $keys = []; - $callback = ['gym_edit_details', 'g' => $gym_id]; $keys[] = [ - [ - 'text' => $text_show_button, - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'show', 'v' => $arg_show]) - ], - [ - 'text' => $text_ex_button, - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'ex', 'v' => $arg_ex]) - ] + button($text_show_button, ['gym_edit_details', 'g' => $gym_id, 'a' => 'show', 'v' => $arg_show]), + button($text_ex_button, ['gym_edit_details', 'g' => $gym_id, 'a' => 'ex', 'v' => $arg_ex]) ]; if($botUser->accessCheck('gym-name', true)) { - $keys[] = [ - [ - 'text' => EMOJI_PENCIL . ' ' . getTranslation("gym_name_edit"), - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'name']) - ] - ]; + $keys[][] = button(EMOJI_PENCIL . ' ' . getTranslation('gym_name_edit'), ['gym_edit_details', 'g' => $gym_id, 'a' => 'name']); } if($botUser->accessCheck('gym-edit', true)) { - $keys[] = [ - [ - 'text' => EMOJI_INFO . ' ' . (!empty($gym_note) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_add_edit_note"), - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'note']) - ] - ]; - $keys[] = [ - [ - 'text' => EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation("directions")) ? getTranslation("edit") : getTranslation("add") ) . ' ' . getTranslation("gym_address"), - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'addr']) - ] - ]; - $keys[] = [ - [ - 'text' => EMOJI_HERE . ' ' . getTranslation("gym_edit_coordinates"), - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'gps']) - ] - ]; + $keys[][] = button( + EMOJI_INFO . ' ' . (!empty($gym_note) ? getTranslation('edit') : getTranslation('add') ) . ' ' . getTranslation('gym_add_edit_note'), + ['gym_edit_details', 'g' => $gym_id, 'a' => 'note'] + ); + $keys[][] = button( + EMOJI_MAP . ' ' . ((!empty($gym_address) && $gym_address != getTranslation('directions')) ? getTranslation('edit') : getTranslation('add')) . ' ' . getTranslation('gym_address'), + ['gym_edit_details', 'g' => $gym_id, 'a' => 'addr'] + ); + $keys[][] = button( + EMOJI_HERE . ' ' . getTranslation('gym_edit_coordinates'), + ['gym_edit_details', 'g' => $gym_id, 'a' => 'gps'] + ); } if($botUser->accessCheck('gym-delete', true)) { - $keys[] = [ - [ - 'text' => EMOJI_DELETE . ' ' . getTranslation("gym_delete"), - 'callback_data' => formatCallbackData(['gym_delete', 'g' => $gym_id, 'c' => 0]) - ] - ]; + $keys[][] = button(EMOJI_DELETE . ' ' . getTranslation('gym_delete'), ['gym_delete', 'g' => $gym_id, 'c' => 0]); } - $keys[] = [ - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ]; + $keys[][] = button(getTranslation('done'), ['exit', 'd' => '1']); return $keys; } diff --git a/logic/edit_pokedex_keys.php b/logic/edit_pokedex_keys.php index 57fc6e9c..20471f3d 100644 --- a/logic/edit_pokedex_keys.php +++ b/logic/edit_pokedex_keys.php @@ -36,58 +36,39 @@ function edit_pokedex_keys($limit) // List users / moderators while ($mon = $rs->fetch()) { $pokemon_name = get_local_pokemon_name($mon['pokedex_id'], $mon['pokemon_form_id']); - $pokemonKeys[][] = [ - 'text' => $mon['pokedex_id'] . SP . $pokemon_name, - 'callback_data' => $mon['pokedex_id'] . '-' . $mon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' - ]; + $pokemonKeys[][] = button($mon['pokedex_id'] . SP . $pokemon_name, ['pokedex_edit_pokemon', 'p' => $mon['pokedex_id'] . '-' . $mon['pokemon_form_id']]); } // Empty backs and next keys - $keys_back = []; - $keys_next = []; + $keys_back = $keys_next = []; // Add back key. if ($limit > 0) { $new_limit = $limit - $entries; - $keys_back[0][] = [ - 'text' => getTranslation('back') . ' (-' . $entries . ')', - 'callback_data' => formatCallbackData(['pokedex', 'l' => $new_limit]) - ]; + $keys_back[0][] = button(getTranslation('back') . ' (-' . $entries . ')',['pokedex', 'l' => $new_limit]); } // Add skip back key. if ($limit - $skip > 0) { $new_limit = $limit - $skip - $entries; - $keys_back[0][] = [ - 'text' => getTranslation('back') . ' (-' . $skip . ')', - 'callback_data' => formatCallbackData(['pokedex', 'l' => $new_limit]) - ]; + $keys_back[0][] = button(getTranslation('back') . ' (-' . $skip . ')', ['pokedex', 'l' => $new_limit]); } // Add next key. if (($limit + $entries) < $count) { $new_limit = $limit + $entries; - $keys_next[0][] = [ - 'text' => getTranslation('next') . ' (+' . $entries . ')', - 'callback_data' => formatCallbackData(['pokedex', 'l' => $new_limit]) - ]; + $keys_next[0][] = button(getTranslation('next') . ' (+' . $entries . ')', ['pokedex', 'l' => $new_limit]); } // Add skip next key. if (($limit + $skip + $entries) < $count) { $new_limit = $limit + $skip + $entries; - $keys_next[0][] = [ - 'text' => getTranslation('next') . ' (+' . $skip . ')', - 'callback_data' => formatCallbackData(['pokedex', 'l' => $new_limit]) - ]; + $keys_next[0][] = button(getTranslation('next') . ' (+' . $skip . ')', ['pokedex', 'l' => $new_limit]); } // Get the inline key array. $keys = array_merge($keys_back, $pokemonKeys, $keys_next); - $keys[][] = [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ]; + $keys[][] = button(getTranslation('abort'), 'exit'); return $keys; } diff --git a/logic/group_code_keys.php b/logic/group_code_keys.php index e7e4615b..6974311e 100644 --- a/logic/group_code_keys.php +++ b/logic/group_code_keys.php @@ -8,58 +8,48 @@ */ function group_code_keys($raid_id, $action, $arg) { - global $config; - - // Get current group code - $data = explode("-", $arg); - $poke1 = $data[0]; - $poke2 = $data[1]; - $poke3 = $data[2]; - $code_action = $data[3]; - - // Send and reset values - $reset_arg = '0-0-0-add'; - $send_arg = $poke1 . '-' . $poke2 . '-' . $poke3 . '-send'; - - // Init empty keys array. - $keys = []; - - // Show group code buttons? - if($poke3 == 0) { - - // Add keys 1 to 9, where 1 = first pokemon, 9 = last pokemon - /** - * 1 2 3 - * 4 5 6 - * 7 8 9 - */ - - $rc_poke = (explode(',',$config->RAID_CODE_POKEMON)); - foreach($rc_poke as $i) { - // New code - $new_code = ($poke1 == 0) ? ($i . '-0-0-add') : (($poke2 == 0) ? ($poke1 . '-' . $i . '-0-add') : (($poke3 == 0) ? ($poke1 . '-' . $poke2 . '-' . $i . '-add') : ($poke1 . '-' . $poke2 . '-' . $poke3 . '-send'))); - // Set keys. - $keys[] = array( - 'text' => get_local_pokemon_name($i, '0'), - 'callback_data' => $raid_id . ':' . $action . ':' . $new_code - ); - } - } else { - // Send - $keys[] = array( - 'text' => EMOJI_INVITE, - 'callback_data' => $raid_id . ':' . $action . ':' . $send_arg - ); + global $config; + + // Get current group code + $data = explode('-', $arg); + $poke1 = $data[0]; + $poke2 = $data[1]; + $poke3 = $data[2]; + + // Send and reset values + $reset_arg = '0-0-0-add'; + $send_arg = $poke1 . '-' . $poke2 . '-' . $poke3 . '-send'; + + // Init empty keys array. + $keys = []; + + // Show group code buttons? + if($poke3 == 0) { + + // Add keys 1 to 9, where 1 = first pokemon, 9 = last pokemon + /** + * 1 2 3 + * 4 5 6 + * 7 8 9 + */ + + $rc_poke = (explode(',',$config->RAID_CODE_POKEMON)); + foreach($rc_poke as $i) { + // New code + $new_code = ($poke1 == 0) ? ($i . '-0-0-add') : (($poke2 == 0) ? ($poke1 . '-' . $i . '-0-add') : (($poke3 == 0) ? ($poke1 . '-' . $poke2 . '-' . $i . '-add') : ($poke1 . '-' . $poke2 . '-' . $poke3 . '-send'))); + // Set keys. + $keys[] = button(get_local_pokemon_name($i, '0'), [$action, 'r' => $raid_id, 'a' => $new_code]); } + } else { + // Send + $keys[] = button(EMOJI_INVITE, [$action, 'r' => $raid_id, 'a' => $send_arg]); + } - // Reset - $keys[] = array( - 'text' => getTranslation('reset'), - 'callback_data' => $raid_id . ':' . $action . ':' . $reset_arg - ); + // Reset + $keys[] = button(getTranslation('reset'), [$action, 'r' => $raid_id, 'a' => $reset_arg]); - // Get the inline key array. - $keys = inline_key_array($keys, 3); + // Get the inline key array. + $keys = inline_key_array($keys, 3); - return $keys; + return $keys; } diff --git a/logic/gymMenu.php b/logic/gymMenu.php index acd5d17c..352dc55d 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -53,10 +53,7 @@ function gymMenu($buttonAction, $showHidden, $stage, $firstLetter = false, $gyma if($config->RAID_VIA_LOCATION_FUNCTION == 'remote' && $buttonAction == 'list') { $query_remote = my_query('SELECT count(*) as count FROM raids LEFT JOIN gyms on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); if($query_remote->fetch()['count'] > 0) { - $keys[][] = [ - 'text' => getTranslation('remote_raids'), - 'callback_data' => 'list_remote_gyms' - ]; + $keys[][] = button(getTranslation('remote_raids'), 'list_remote_gyms'); } } // Merge keys. @@ -67,34 +64,19 @@ function gymMenu($buttonAction, $showHidden, $stage, $firstLetter = false, $gyma if($buttonAction == 'gym') { if($stage == 1 && $showHidden == 0) { // Add key for hidden gyms. - $h_keys[][] = [ - 'text' => getTranslation('hidden_gyms'), - 'callback_data' => formatCallbackData(['gymMenu', 'h' => 1, 'a' => 'gym', 'ga' => $gymareaId]) - ]; + $h_keys[][] = button(getTranslation('hidden_gyms'), ['gymMenu', 'h' => 1, 'a' => 'gym', 'ga' => $gymareaId]); $keys = array_merge($h_keys, $keys); } if($stage == 0 or $stage == 1 && $botUser->accessCheck('gym-add', true)) { - $keys[][] = [ - 'text' => getTranslation('gym_create'), - 'callback_data' => 'gym_create' - ]; + $keys[][] = button(getTranslation('gym_create'), 'gym_create'); } } if((($stage == 1 or ($stage == 2 && $firstLetter == '')) && $config->DEFAULT_GYM_AREA === false)) { - $backKey = [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['gymMenu', 'stage' => 0, 'a' => $buttonAction]) - ]; + $backKey = button(getTranslation('back'), ['gymMenu', 'stage' => 0, 'a' => $buttonAction]); }elseif($stage == 2 && $firstLetter !== '') { - $backKey = [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['gymMenu', 'stage' => 1, 'a' => $buttonAction, 'h' => $showHidden, 'ga' => $gymareaId]) - ]; + $backKey = button(getTranslation('back'), ['gymMenu', 'stage' => 1, 'a' => $buttonAction, 'h' => $showHidden, 'ga' => $gymareaId]); } - $abortKey = [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ]; + $abortKey = button(getTranslation('abort'), 'exit'); if (isset($backKey)) { $keys[] = [$backKey, $abortKey]; }else{ @@ -121,17 +103,12 @@ function getGymareas($gymareaId, $stage, $buttonAction) { if($points[0] != $points[count($points)-1]) $points[] = $points[0]; } if ($stage != 0 && $gymareaId == $area['id']) continue; - $gymareaKeys[] = [ - 'text' => $area['name'], - 'callback_data' => formatCallbackData(['gymMenu', 'a' => $buttonAction, 'stage' => 1, 'ga' => $area['id']]) - ]; + $gymareaKeys[] = button($area['name'], ['gymMenu', 'a' => $buttonAction, 'stage' => 1, 'ga' => $area['id']]); + } if(count($gymareaKeys) > 6 && $stage != 0) { // If list of area buttons is getting too large, replace it with a key that opens a submenu - $gymareaKeys = [[ - 'text' => getTranslation('gymareas'), - 'callback_data' => formatCallbackData(['gymMenu', 'a' => $buttonAction, 'stage' => 0]) - ]]; + $gymareaKeys[] = button(getTranslation('gymareas'), ['gymMenu', 'a' => $buttonAction, 'stage' => 0]); } $polygon_string = implode(',', $points); $query = count($points) > 0 ? 'AND ST_CONTAINS(ST_GEOMFROMTEXT(\'POLYGON(('.$polygon_string.'))\'), ST_GEOMFROMTEXT(CONCAT(\'POINT(\',lat,\' \',lon,\')\')))' : ''; @@ -209,10 +186,7 @@ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $s ); while ($gym = $rs->fetch()) { // Add first letter to keys array - $keys[] = array( - 'text' => $gym['first_letter'], - 'callback_data' => formatCallbackData(['gymMenu', 'a' => $buttonAction, 'stage' => $stage+1, 'fl' => $gym['first_letter'], 'ga' => $gymareaId]) - ); + $keys[] = button($gym['first_letter'], ['gymMenu', 'a' => $buttonAction, 'stage' => $stage+1, 'fl' => $gym['first_letter'], 'ga' => $gymareaId]); } // Get the inline key array. @@ -299,10 +273,7 @@ function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery 'fl' => $firstLetter, 'h' => $showHidden, ]; - $keys[] = array( - 'text' => $gym_name, - 'callback_data' => formatCallbackData($callback) - ); + $keys[] = button($gym_name, $callback); } // Get the inline key array. diff --git a/logic/history.php b/logic/history.php index d318eed0..493940a1 100644 --- a/logic/history.php +++ b/logic/history.php @@ -1,49 +1,42 @@ rowcount() == 0) return false; - while($date = $q->fetch()) { - $day_keys[] = [ - 'text' => $date['day_disp'], - 'callback_data' => $date['day'] . ':history:' . $date['current_y_m'] - ]; - if($current_y_m == '') $current_y_m = $date['current_y_m']; - if($prev == false) $prev = $date['prev']; - if($next == false) $next = $date['next']; - } - $keys = inline_key_array($day_keys,4); + if(strlen($current) == 7) { + // Reformat YYYY-MM to DATETIME + $current = '\''.$current.'-01 00:00:00\''; + } + $q = my_query(' + SELECT DISTINCT DATE_FORMAT(start_time, "%d") as day, DATE_FORMAT(start_time, "%e") as day_disp, DATE_FORMAT('.$current.', "%Y-%m") as current_y_m, + if((SELECT count(*) FROM raids left join attendance on attendance.raid_id = raids.id where end_time < UTC_TIMESTAMP() and date_format(start_time, "%Y-%m") = date_format(DATE_SUB('.$current.', INTERVAL 1 MONTH), "%Y-%m") and attendance.id is not null limit 1), date_format(DATE_SUB('.$current.', INTERVAL 1 MONTH), "%Y-%m"), 0) as prev, + if((SELECT count(*) FROM raids left join attendance on attendance.raid_id = raids.id where end_time < UTC_TIMESTAMP() and date_format(start_time, "%Y-%m") = date_format(DATE_ADD('.$current.', INTERVAL 1 MONTH), "%Y-%m") and attendance.id is not null limit 1), date_format(DATE_ADD('.$current.', INTERVAL 1 MONTH), "%Y-%m"), 0) as next + FROM raids + LEFT JOIN attendance + ON attendance.raid_id = raids.id + WHERE end_time < UTC_TIMESTAMP() + AND date_format(start_time, "%Y-%m") = DATE_FORMAT('.$current.', "%Y-%m") + AND attendance.id IS NOT NULL + ORDER BY DATE_FORMAT(start_time, "%d") ASC + '); + $day_keys = []; + $current_y_m = ''; + $prev = $next = false; + if($q->rowcount() == 0) return false; + while($date = $q->fetch()) { + $day_keys[] = button($date['day_disp'], ['history', 'd' => $date['day'], 'm' => $date['current_y_m']]); + if($current_y_m == '') $current_y_m = $date['current_y_m']; + if($prev == false) $prev = $date['prev']; + if($next == false) $next = $date['next']; + } + $keys = inline_key_array($day_keys,4); - $msg = getTranslation('history_title') . CR . CR; - $msg .= getTranslation('history_displaying_month') . ' ' . getTranslation('month_'.substr($current_y_m,5)) . CR . CR . getTranslation('raid_select_date'); + $msg = getTranslation('history_title') . CR . CR; + $msg .= getTranslation('history_displaying_month') . ' ' . getTranslation('month_'.substr($current_y_m,5)) . CR . CR . getTranslation('raid_select_date'); - $nav_keys = []; - if($prev != 0) $nav_keys[0][] = ['text' => getTranslation('month_'.substr($prev,5)),'callback_data' => '0:history:' . $prev]; - if($next != 0) $nav_keys[0][] = ['text' => getTranslation('month_'.substr($next,5)),'callback_data' => '0:history:' . $next]; + $nav_keys = []; + if($prev != 0) $nav_keys[0][] = button(getTranslation('month_'.substr($prev,5)),['history', 'm' => $prev]); + if($next != 0) $nav_keys[0][] = button(getTranslation('month_'.substr($next,5)),['history', 'm' => $next]); - $keys = array_merge($keys, $nav_keys); - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ]; - return [$msg, $keys]; + $keys = array_merge($keys, $nav_keys); + $keys[][] = button(getTranslation('abort'), 'exit'); + return [$msg, $keys]; } diff --git a/logic/key_util.php b/logic/key_util.php index f82331db..b153742a 100644 --- a/logic/key_util.php +++ b/logic/key_util.php @@ -7,159 +7,103 @@ */ function inline_key_array($buttons, $columns) { - $result = array(); - $col = 0; - $row = 0; + $result = array(); + $col = 0; + $row = 0; - foreach ($buttons as $v) { - $result[$row][$col] = $v; - $col++; + foreach ($buttons as $v) { + $result[$row][$col] = $v; + $col++; - if ($col >= $columns) { - $row++; - $col = 0; - } + if ($col >= $columns) { + $row++; + $col = 0; } - return $result; -} - - -/** - * Universal key. - * @param $keys - * @param $id - * @param $action - * @param $arg - * @param $text - * @return array - */ -function universal_inner_key($keys, $id, $action, $arg, $text = '0') -{ - $keys = array( - 'text' => $text, - 'callback_data' => $id . ':' . $action . ':' . $arg - ); - - // Write to log. - //debug_log($keys); - - return $keys; -} - -/** - * Universal key. - * @param $keys - * @param $id - * @param $action - * @param $arg - * @param $text - * @return array - */ -function universal_key($keys, $id, $action, $arg, $text = '0') -{ - $keys[] = [ - array( - 'text' => $text, - 'callback_data' => $id . ':' . $action . ':' . $arg - ) - ]; - - // Write to log. - //debug_log($keys); - - return $keys; + } + return $result; } - /** * Share keys. Has own logic for fetching chat id's if used to generate share keys for raids. - * @param int $id Id to pass to callback query + * @param int|false $id Id to pass to callback query * @param string $action Action to pass to callback query * @param array $update Update from Telegram * @param int $raidLevel Raid level if sharing a raid - * @param string $chats List of chats if using alternative list + * @param array $chats List of chats if using alternative list * @param bool $hideGeneralShare Leave out the general share button * @return array */ -function share_keys($id, $action, $update, $raidLevel = '', $chats = '', $hideGeneralShare = false) +function share_keys($id, $action, $update, $raidLevel = '', $chats = [], $hideGeneralShare = false) { - global $config, $botUser; - $keys = []; - // Check access. - $share_access = $botUser->accessCheck('share-any-chat', true); - - // Add share button if not restricted to allow sharing to any chat. - if ($share_access == true && $hideGeneralShare == false) { - debug_log('Adding general share key to inline keys'); - // Set the keys. - $keys[] = [ - [ - 'text' => getTranslation('share'), - 'switch_inline_query' => basename(ROOT_PATH) . ':' . strval($id) - ] - ]; - } + global $config, $botUser; + $keys = []; + // Check access. + $share_access = $botUser->accessCheck('share-any-chat', true); + + // Add share button if not restricted to allow sharing to any chat. + if ($share_access == true && $hideGeneralShare == false) { + debug_log('Adding general share key to inline keys'); + // Set the keys. + $keys[][] = [ + 'text' => getTranslation('share'), + 'switch_inline_query' => basename(ROOT_PATH) . ':' . strval($id) + ]; + } - // Add buttons for predefined sharing chats. - // Default SHARE_CHATS or special chat list via $chats? - if(!empty($chats)) { - debug_log($chats, 'Got specific chats to share to:'); - $chats = explode(',', $chats); + // Add buttons for predefined sharing chats. + // Default SHARE_CHATS or special chat list via $chats? + if(empty($chats)) { + if(!empty($raidLevel)) { + // find chats to share ourselves, if we can + debug_log($raidLevel, 'Did not get specific chats to share to, checking level specific for: '); + $level_chat = 'SHARE_CHATS_LEVEL_' . $raidLevel; + if(!empty($config->{$level_chat})) { + $chats = explode(',', $config->{$level_chat}); + debug_log($chats, 'Found level specific chats to share to: '); + } else { + $chats = explode(',', $config->SHARE_CHATS); + debug_log($chats, 'Chats not specified for level, sharing to globals: '); + } } else { - if(!empty($raidLevel)) { - // find chats to share ourselves, if we can - debug_log($raidLevel, 'Did not get specific chats to share to, checking level specific for: '); - $level_chat = 'SHARE_CHATS_LEVEL_' . $raidLevel; - if(!empty($config->{$level_chat})) { - $chats = explode(',', $config->{$level_chat}); - debug_log($chats, 'Found level specific chats to share to: '); - } else { - $chats = explode(',', $config->SHARE_CHATS); - debug_log($chats, 'Chats not specified for level, sharing to globals: '); - } - } else { - $chats = explode(',', $config->SHARE_CHATS); - debug_log($chats, 'Level not given, sharing to globals: '); - } + $chats = explode(',', $config->SHARE_CHATS); + debug_log($chats, 'Level not given, sharing to globals: '); } - // Add keys for each chat. - if(!empty($chats)){ - if($raidLevel == '') { - // If raid level is not set we are sharing something else than a raid. - $sharedChats = []; - } else { - $queryShared = my_query(" - SELECT DISTINCT chat_id - FROM cleanup - WHERE raid_id=?", - [ $id ] - ); - $sharedChats = $queryShared->fetchAll(PDO::FETCH_COLUMN, 0); - } - foreach($chats as $chat) { - if(in_array($chat, $sharedChats)) continue; - // Get chat object - debug_log("Getting chat object for '" . $chat . "'"); - $chat_obj = get_chat($chat); - - // Check chat object for proper response. - if ($chat_obj['ok'] == true) { - debug_log('Proper chat object received, continuing to add key for this chat: ' . $chat_obj['result']['title']); - $keys[] = [ - [ - 'text' => getTranslation('share_with') . ' ' . $chat_obj['result']['title'], - 'callback_data' => $id . ':' . $action . ':' . $chat - ] - ]; - } else { - info_log($chat, 'Invalid chat id in your configuration:'); - } - } - } else { - debug_log('Aint got any chats to share to!'); + } + // Add keys for each chat. + if(empty($chats)) { + debug_log('Aint got any chats to share to!'); + return []; + } + if($raidLevel == '') { + // If raid level is not set we are sharing something else than a raid. + $sharedChats = []; + } else { + $queryShared = my_query(' + SELECT DISTINCT chat_id + FROM cleanup + WHERE raid_id = ?', + [$id] + ); + $sharedChats = $queryShared->fetchAll(PDO::FETCH_COLUMN, 0); + } + foreach($chats as $chat) { + if(in_array($chat, $sharedChats)) continue; + // Get chat object + debug_log("Getting chat object for '" . $chat . "'"); + $chat_obj = get_chat($chat); + + // Check chat object for proper response. + if ($chat_obj['ok'] != true) { + info_log($chat, 'Invalid chat id in your configuration:'); + continue; } + debug_log('Proper chat object received, continuing to add key for this chat: ' . $chat_obj['result']['title']); + $shareData = [0 => $action, 'c' => $chat]; + if($id !== false) $shareData['r'] = $id; + $keys[][] = button(getTranslation('share_with') . ' ' . $chat_obj['result']['title'], $shareData); + } - return $keys; + return $keys; } /** @@ -172,7 +116,7 @@ function formatCallbackData($array) $return = $array[0] . '|'; unset($array[0]); foreach($array as $key => $value) { - $return .= $key . '=' . $value . '|'; + $return .= $key . '=' . $value . '|'; } return rtrim($return, '|'); } diff --git a/logic/keys_event.php b/logic/keys_event.php index 28287830..23a49a4c 100644 --- a/logic/keys_event.php +++ b/logic/keys_event.php @@ -22,18 +22,12 @@ function keys_event($callbackData, $action, $admin_access = [false,false]) { continue; } $callbackData['e'] = $event['id']; - $keys[] = array( - 'text' => $event['name'], - 'callback_data' => formatCallbackData($callbackData) - ); + $keys[] = button($event['name'], $callbackData); } } if($admin_access[0] === true) { $callbackData['e'] = 'X'; - $keys[] = array( - 'text' => getTranslation("Xstars"), - 'callback_data' => formatCallbackData($callbackData) - ); + $keys[] = button(getTranslation('Xstars'), $callbackData); } // Get the inline key array. $keys = inline_key_array($keys, 1); diff --git a/logic/keys_trainerinfo.php b/logic/keys_trainerinfo.php index a027f13e..39644437 100644 --- a/logic/keys_trainerinfo.php +++ b/logic/keys_trainerinfo.php @@ -11,14 +11,8 @@ function keys_trainerinfo($show = false) $status = 'show'; if(!$show || $config->TRAINER_BUTTONS_TOGGLE) { // Key to show/hide trainer info. - return [ - [ - [ - 'text' => getPublicTranslation('trainerinfo'), - 'callback_data' => 'trainer:vote_level:' . $status - ], - ] - ]; + $keys[][] = button(getPublicTranslation('trainerinfo'), ['vote_level', 'a' => 'trainer', 's' => $status]); + return $keys; } // Always show buttons? if(($show == true && !$config->TRAINER_BUTTONS_TOGGLE) || $config->TRAINER_BUTTONS_TOGGLE) { @@ -26,38 +20,12 @@ function keys_trainerinfo($show = false) } // Keys to set team and level - $keys = [ - [ - [ - 'text' => getPublicTranslation('trainerinfo'), - 'callback_data' => 'trainer:vote_level:' . $status - ], - ], - [ - [ - 'text' => getPublicTranslation('team') . SP . TEAM_B, - 'callback_data' => 'trainer:vote_team:mystic' - ], - [ - 'text' => getPublicTranslation('team') . SP . TEAM_R, - 'callback_data' => 'trainer:vote_team:valor' - ], - [ - 'text' => getPublicTranslation('team') . SP . TEAM_Y, - 'callback_data' => 'trainer:vote_team:instinct' - ], - ], - [ - [ - 'text' => getPublicTranslation('level') . ' +', - 'callback_data' => 'trainer:vote_level:up' - ], - [ - 'text' => getPublicTranslation('level') . ' -', - 'callback_data' => 'trainer:vote_level:down' - ] - ] - ]; + $keys[0][0] = button(getPublicTranslation('trainerinfo'), ['vote_level', 'a' => 'trainer', 's' => $status]); + $keys[1][0] = button(getPublicTranslation('team') . SP . TEAM_B, ['vote_team', 'a' => 'trainer', 't' => 'mystic']); + $keys[1][1] = button(getPublicTranslation('team') . SP . TEAM_R, ['vote_team', 'a' => 'trainer', 't' => 'valor']); + $keys[1][2] = button(getPublicTranslation('team') . SP . TEAM_Y, ['vote_team', 'a' => 'trainer', 't' => 'instinct']); + $keys[2][0] = button(getPublicTranslation('level') . ' +', ['vote_level', 'a' => 'trainer', 'l' => 'up']); + $keys[2][1] = button(getPublicTranslation('level') . ' -', ['vote_level', 'a' => 'trainer', 'l' => 'down']); return $keys; } diff --git a/logic/keys_vote.php b/logic/keys_vote.php index e8ffe675..dc96d1f7 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -22,14 +22,8 @@ function keys_vote($raid) // Raid ended already. if ($raid['raid_ended']) { if($config->RAID_ENDED_HIDE_KEYS) return []; - return [ - [ - [ - 'text' => getPublicTranslation('raid_done'), - 'callback_data' => $raid['id'] . ':vote_refresh:1' - ] - ] - ]; + $button[][] = button(getPublicTranslation('raid_done'), ['vote_refresh', 'r' => $raid['id']]); + return $button; } // Raid is still running. // Get current pokemon @@ -52,67 +46,33 @@ function keys_vote($raid) return []; } // Extra Keys - $buttons['alone'] = [ - 'text' => EMOJI_SINGLE, - 'callback_data' => $raid['id'] . ':vote_extra:0' - ]; - $buttons['extra'] = [ - 'text' => '+ ' . EMOJI_IN_PERSON, - 'callback_data' => $raid['id'] . ':vote_extra:in_person' - ]; + $buttons['alone'] = button(EMOJI_SINGLE, ['vote_extra', 'r' => $raid['id']]); + $buttons['extra'] = button('+ ' . EMOJI_IN_PERSON, ['vote_extra', 'r' => $raid['id'], 'a' => 'in_person']); // Show buttons regarding remote participation only if raid level allows it $buttons['extra_alien'] = $buttons['can_inv'] = $buttons['remote'] = $buttons['inv_plz'] = []; if(!$raid_local_only) { - $buttons['extra_alien'] = [ - 'text' => '+ ' . EMOJI_ALIEN, - 'callback_data' => $raid['id'] . ':vote_extra:alien' - ]; + $buttons['extra_alien'] = button('+ ' . EMOJI_ALIEN, ['vote_extra', 'r' => $raid['id'], 'a' => 'alien']); // Can invite key - $buttons['can_inv'] = [ - 'text' => EMOJI_CAN_INVITE, - 'callback_data' => $raid['id'] . ':vote_can_invite:0' - ]; + $buttons['can_inv'] = button(EMOJI_CAN_INVITE, ['vote_can_invite', 'r' => $raid['id']]); // Remote Raid Pass key - $buttons['remote'] = [ - 'text' => EMOJI_REMOTE, - 'callback_data' => $raid['id'] . ':vote_remote:0' - ]; + $buttons['remote'] = button(EMOJI_REMOTE, ['vote_remote', 'r' => $raid['id']]); // Want invite key - $buttons['inv_plz'] = [ - 'text' => EMOJI_WANT_INVITE, - 'callback_data' => $raid['id'] . ':vote_want_invite:0' - ]; + $buttons['inv_plz'] = button(EMOJI_WANT_INVITE, ['vote_want_invite', 'r' => $raid['id']]); } // Team and level keys. - $buttons['teamlvl'] = [ - [ - [ - 'text' => 'Team', - 'callback_data' => $raid['id'] . ':vote_team:0' - ], - [ - 'text' => 'Lvl +', - 'callback_data' => $raid['id'] . ':vote_level:up' - ], - [ - 'text' => 'Lvl -', - 'callback_data' => $raid['id'] . ':vote_level:down' - ] - ] - ]; + $buttons['teamlvl'][0][] = button('Team', ['vote_team', 'r' => $raid['id']]); + $buttons['teamlvl'][0][] = button('Lvl +', ['vote_level', 'r' => $raid['id'], 'l' => 'up']); + $buttons['teamlvl'][0][] = button('Lvl -', ['vote_level', 'r' => $raid['id'], 'l' => 'down']); // Ex-Raid Invite key $buttons['ex_inv'] = []; if ($raid['event'] == EVENT_ID_EX) { - $buttons['ex_inv'] = [ - 'text' => EMOJI_INVITE, - 'callback_data' => $raid['id'] . ':vote_invite:0' - ]; + $buttons['ex_inv'] = button(EMOJI_INVITE, ['vote_invite', 'r' => $raid['id']]); } // Show icon, icon + text or just text. @@ -137,42 +97,19 @@ function keys_vote($raid) } // Status keys. - $buttons['alarm'] = [ - 'text' => EMOJI_ALARM, - 'callback_data' => $raid['id'] . ':vote_status:alarm' - ]; - $buttons['here'] = [ - 'text' => $text_here, - 'callback_data' => $raid['id'] . ':vote_status:arrived' - ]; - $buttons['late'] = [ - 'text' => $text_late, - 'callback_data' => $raid['id'] . ':vote_status:late' - ]; - $buttons['done'] = [ - 'text' => $text_done, - 'callback_data' => $raid['id'] . ':vote_status:raid_done' - ]; - $buttons['cancel'] = [ - 'text' => $text_cancel, - 'callback_data' => $raid['id'] . ':vote_status:cancel' - ]; + $buttons['alarm'] = button(EMOJI_ALARM, ['vote_status', 'r' => $raid['id'], 'a' => 'alarm']); + $buttons['here'] = button($text_here, ['vote_status', 'r' => $raid['id'], 'a' => 'arrived']); + $buttons['late'] = button($text_late, ['vote_status', 'r' => $raid['id'], 'a' => 'late']); + $buttons['done'] = button($text_done, ['vote_status', 'r' => $raid['id'], 'a' => 'raid_done']); + $buttons['cancel'] = button($text_cancel, ['vote_status', 'r' => $raid['id'], 'a' => 'cancel']); $buttons['refresh'] = []; if(!$config->AUTO_REFRESH_POLLS) { - $buttons['refresh'] = [ - 'text' => EMOJI_REFRESH, - 'callback_data' => $raid['id'] . ':vote_refresh:0' - ]; + $buttons['refresh'] = button(EMOJI_REFRESH, ['vote_refresh', 'r' => $raid['id']]); } if($raid['event_vote_key_mode'] == 1) { - $keys_time = [ - [ - 'text' => getPublicTranslation("Participate"), - 'callback_data' => $raid['id'] . ':vote_time:' . utctime($raid['start_time'], 'YmdHis') - ] - ]; + $keys_time = button(getPublicTranslation('Participate'), ['vote_time', 'r' => $raid['id'], 't' => utctime($raid['start_time'], 'YmdHis')]); }else { $RAID_SLOTS = ($raid['event_time_slots'] > 0) ? $raid['event_time_slots'] : $config->RAID_SLOTS; $keys_time = generateTimeslotKeys($RAID_SLOTS, $raid); @@ -233,17 +170,14 @@ function keys_vote($raid) // Add key for each raid level foreach($raid_bosses as $pokemon) { if(in_array($pokemon['pokedex_id'], $GLOBALS['eggs'])) continue; - $buttons['pokemon'][] = array( - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), - 'callback_data' => $raid['id'] . ':vote_pokemon:' . $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] + $buttons['pokemon'][] = button( + get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), + ['vote_pokemon', 'r' => $raid['id'], 'p' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id']] ); } // Add button if raid boss does not matter - $buttons['pokemon'][] = array( - 'text' => getPublicTranslation('any_pokemon'), - 'callback_data' => $raid['id'] . ':vote_pokemon:0' - ); + $buttons['pokemon'][] = button(getPublicTranslation('any_pokemon'), ['vote_pokemon', 'r' => $raid['id']]); // Finally add pokemon to keys $buttons['pokemon'] = inline_key_array($buttons['pokemon'], 2); @@ -345,24 +279,15 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { $keys_time = []; // Add button for when raid starts time if($config->RAID_DIRECT_START && $direct_slot >= $dt_now) { - $keys_time[] = array( - 'text' => dt2time($direct_slot->format('Y-m-d H:i:s')), - 'callback_data' => $raid['id'] . ':vote_time:' . $direct_slot->format('YmdHis') - ); + $keys_time[] = button(dt2time($direct_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $direct_slot->format('YmdHis')]); } // Add five minutes slot if($five_slot >= $dt_now && (empty($keys_time) || (!empty($keys_time) && $direct_slot != $five_slot))) { - $keys_time[] = array( - 'text' => dt2time($five_slot->format('Y-m-d H:i:s')), - 'callback_data' => $raid['id'] . ':vote_time:' . $five_slot->format('YmdHis') - ); + $keys_time[] = button(dt2time($five_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $five_slot->format('YmdHis')]); } // Add the first normal slot if($first_slot >= $dt_now && $first_slot != $five_slot) { - $keys_time[] = array( - 'text' => dt2time($first_slot->format('Y-m-d H:i:s')), - 'callback_data' => $raid['id'] . ':vote_time:' . $first_slot->format('YmdHis') - ); + $keys_time[] = button(dt2time($first_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $first_slot->format('YmdHis')]); } // Init last slot time. @@ -378,10 +303,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { debug_log($slot, 'Regular slot:'); // Add regular slot. if($slot >= $dt_now) { - $keys_time[] = array( - 'text' => dt2time($slot->format('Y-m-d H:i:s')), - 'callback_data' => $raid['id'] . ':vote_time:' . $slot->format('YmdHis') - ); + $keys_time[] = button(dt2time($slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $slot->format('YmdHis')]); } // Set last slot for later. $last_slot = $slot; @@ -401,18 +323,12 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { // Last extra slot not conflicting with last slot if($last_extra_slot > $last_slot && $last_extra_slot >= $dt_now) { // Add last extra slot - $keys_time[] = array( - 'text' => dt2time($last_extra_slot->format('Y-m-d H:i:s')), - 'callback_data' => $raid['id'] . ':vote_time:' . $last_extra_slot->format('YmdHis') - ); + $keys_time[] = button(dt2time($last_extra_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $last_extra_slot->format('YmdHis')]); } // Attend raid at any time if($config->RAID_ANYTIME) { - $keys_time[] = array( - 'text' => getPublicTranslation('anytime'), - 'callback_data' => $raid['id'] . ':vote_time:0' - ); + $keys_time[] = button(getPublicTranslation('anytime'), ['vote_time', 'r' => $raid['id']]); } return $keys_time; } diff --git a/logic/pokemon_keys.php b/logic/pokemon_keys.php index bbc2419e..e18c5392 100644 --- a/logic/pokemon_keys.php +++ b/logic/pokemon_keys.php @@ -40,10 +40,7 @@ function pokemon_keys($callbackData, $raid_level, $action, $event_id = false) $callbackData[0] = $action; while ($pokemon = $rs->fetch()) { $callbackData['p'] = $pokemon['id']; - $keys[] = array( - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), - 'callback_data' => formatCallbackData($callbackData) - ); + $keys[] = button(get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), $callbackData); } // Get the inline key array. diff --git a/logic/raid_edit_raidlevel_keys.php b/logic/raid_edit_raidlevel_keys.php index 3abfd89c..870942de 100644 --- a/logic/raid_edit_raidlevel_keys.php +++ b/logic/raid_edit_raidlevel_keys.php @@ -44,10 +44,7 @@ function raid_edit_raidlevel_keys($callbackData, $admin_access = [false,false], $buttonData[0] = 'edit_pokemon'; $buttonData['rl'] = $level['raid_level']; // Add key for raid level - $keys[] = array( - 'text' => getTranslation($level['raid_level'] . 'stars'), - 'callback_data' => formatCallbackData($buttonData) - ); + $keys[] = button(getTranslation($level['raid_level'] . 'stars'), $buttonData); continue; } $query_mon = my_query(' @@ -70,20 +67,14 @@ function raid_edit_raidlevel_keys($callbackData, $admin_access = [false,false], $buttonData['rl'] = $level['raid_level']; $buttonData['p'] = $pokemon['id']; // Add key for pokemon - $keys[] = array( - 'text' => get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), - 'callback_data' => formatCallbackData($buttonData) - ); + $keys[] = button(get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']), $buttonData); unset($buttonData['p']); } // Add key for raid event if user allowed to create event raids if(($admin_access[1] === true or $admin_access[0] === true) && $event === false) { $eventData = $callbackData; $eventData[0] = 'edit_event'; - $keys[] = array( - 'text' => getTranslation('event'), - 'callback_data' => formatCallbackData($eventData) - ); + $keys[] = button(getTranslation('event'), $eventData); } // Get the inline key array. diff --git a/logic/raid_get_gyms_list_keys.php b/logic/raid_get_gyms_list_keys.php index 7e6f82d4..111e7f12 100644 --- a/logic/raid_get_gyms_list_keys.php +++ b/logic/raid_get_gyms_list_keys.php @@ -28,10 +28,7 @@ function raid_get_gyms_list_keys($searchterm) while ($gym = $rs->fetch()) { $first = strtoupper(substr($gym['gym_name'], 0, 1)); - $keys[] = array( - 'text' => $gym['gym_name'], - 'callback_data' => formatCallbackData(['edit_raidlevel', 'g' => $gym['id'], 'fl' => $first]) - ); + $keys[] = button($gym['gym_name'], ['edit_raidlevel', 'g' => $gym['id'], 'fl' => $first]); } // Add abort key. diff --git a/logic/weather_keys.php b/logic/weather_keys.php index 96718a8d..c52c1b45 100644 --- a/logic/weather_keys.php +++ b/logic/weather_keys.php @@ -1,21 +1,13 @@ $GLOBALS['weather'][$i], - 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_weather - ); + $keys[] = button($GLOBALS['weather'][$i], $buttonData); } } - // Get the inline key array. $keys = inline_key_array($keys, 3); + $saveData = $resetData = $data; + $saveData['a'] = 'save'; + unset($resetData['w']); // Save and Reset key $keys[] = array( - array( - 'text' => EMOJI_DISK, - 'callback_data' => $pokedex_id . ':' . $action . ':' . $save_arg - ), - array( - 'text' => getTranslation('reset'), - 'callback_data' => $pokedex_id . ':' . $action . ':' . $reset_arg - ) + button(EMOJI_DISK, $saveData), + button(getTranslation('reset'), $resetData) ); return $keys; diff --git a/mods/bot_lang.php b/mods/bot_lang.php index e4cd8178..e289a53d 100644 --- a/mods/bot_lang.php +++ b/mods/bot_lang.php @@ -23,36 +23,19 @@ ]); $new_lang_internal = $languages[$data['l']]; $msg = getTranslation('new_lang_saved', $new_lang_internal); - $keys[] = [ - [ - 'text' => getTranslation('back', $new_lang_internal), - 'callback_data' => 'trainer' - ], - [ - 'text' => getTranslation('done', $new_lang_internal), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ]; + $keys[0][] = button(getTranslation('back', $new_lang_internal), 'trainer'); + $keys[0][] = button(getTranslation('done', $new_lang_internal), ['exit', 'd' => '1']); $callback_msg = $msg; } else { $displayedLanguages = []; foreach($languages as $lang_tg => $lang_internal) { if(in_array($lang_internal, $displayedLanguages)) continue; - $keys[][] = [ - 'text' => getTranslation('lang_name', $lang_internal), - 'callback_data' => formatCallbackData(['bot_lang', 'l' => $lang_tg]) - ]; + $keys[][] = button(getTranslation('lang_name', $lang_internal), ['bot_lang', 'l' => $lang_tg]); $displayedLanguages[] = $lang_internal; } $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'trainer' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] + button(getTranslation('back'), 'trainer'), + button(getTranslation('done'), ['exit', 'd' => '1']) ]; $msg = getTranslation('change_lang').':'; $callback_msg = getTranslation('change_lang'); diff --git a/mods/change_trainercode.php b/mods/change_trainercode.php index 3da1a738..eeef962d 100644 --- a/mods/change_trainercode.php +++ b/mods/change_trainercode.php @@ -24,18 +24,8 @@ edit_message_keyboard($modifiers['old_message_id'], [], $target_user_id); // Create the keys. -$keys = [ - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'trainer' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] -]; +$keys[0][0] = button(getTranslation('back'), 'trainer'); +$keys[0][1] = button(getTranslation('done'), ['exit', 'd' => '1']); // confirm Trainercode-Change send_message($target_user_id, getTranslation('trainercode_success').' '.$trainercode.'', $keys); diff --git a/mods/change_trainername.php b/mods/change_trainername.php index be67e252..8cf9ab10 100644 --- a/mods/change_trainername.php +++ b/mods/change_trainername.php @@ -24,18 +24,8 @@ edit_message_keyboard($modifiers['old_message_id'], [], $userid); // Create the keys. -$keys = [ - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'trainer' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] -]; +$keys[0][] = button(getTranslation('back'), 'trainer'); +$keys[0][] = button(getTranslation('done'), ['exit', 'd' => '1']); // confirm Name-Change send_message($userid, getTranslation('trainername_success').' '.$trainername.'', $keys); diff --git a/mods/code.php b/mods/code.php index f1b520bf..d984497d 100644 --- a/mods/code.php +++ b/mods/code.php @@ -12,10 +12,10 @@ //$botUser->accessCheck('list'); // Set the raid id. -$raid_id = $data['id']; +$raid_id = $data['r']; // Set the arg. -$arg = $data['arg']; +$arg = $data['a'] ?? ''; // Telegram JSON array. $tg_json = array(); @@ -60,16 +60,8 @@ $keys = []; // Back and abort. - $keys[] = [ - [ - 'text' => EMOJI_INVITE, - 'callback_data' => $raid_id . ':code:public-send' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ]; + $keys[0][0] = button(EMOJI_INVITE, ['code' ,'r' => $raid_id, 'a' => 'public-send']); + $keys[0][1] = button(getTranslation('abort'), 'exit'); // Build callback message string. $callback_response = 'OK'; @@ -108,12 +100,7 @@ $keys = group_code_keys($raid_id, 'code', $arg); // Back and abort. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ]; + $keys[][] = button(getTranslation('abort'), 'exit'); // Build callback message string. $callback_response = 'OK'; diff --git a/mods/code_start.php b/mods/code_start.php index 7f704358..f1a8f479 100644 --- a/mods/code_start.php +++ b/mods/code_start.php @@ -38,24 +38,9 @@ $text .= get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . SP . '-' . SP . (($raid_day == $today) ? '' : ($raid_day . ', ')) . $start . SP . getTranslation('to') . SP . $end . CR . CR; // Add exit key. - $keys = [ - [ - [ - 'text' => getTranslation('start_raid_public'), - 'callback_data' => $raid['id'] . ':code:public-unconfirmed' - ], - [ - 'text' => getTranslation('start_raid_private'), - 'callback_data' => $raid['id'] . ':code:0-0-0-add' - ] - ], - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ] - ]; + $keys[0][] = button(getTranslation('start_raid_public'), ['code', 'r' => $raid['id'], 'a' => 'public-unconfirmed']); + $keys[0][] = button(getTranslation('start_raid_private'), ['code', 'r' => $raid['id'], 'a' => '0-0-0-add']); + $keys[1][] = button(getTranslation('abort'), 'exit'); // Build message. $msg = '' . getTranslation('start_raid_now') . ':' . CR . CR; diff --git a/mods/delete_scheduled_entry.php b/mods/delete_scheduled_entry.php index 2cd3b643..dd7bf21d 100644 --- a/mods/delete_scheduled_entry.php +++ b/mods/delete_scheduled_entry.php @@ -18,16 +18,8 @@ $msg .= getTranslation($pokemon['raid_level'] . 'stars') . ': '; $msg .= get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']); -$keys[] = [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => formatCallbackData(['delete_scheduled_entry', 'i' => $id, 's' => 1]) - ], - [ - 'text' => getTranslation('no'), - 'callback_data' => 'pokedex_list_raids' - ], -]; +$keys[0][] = button(getTranslation('yes'), ['delete_scheduled_entry', 'i' => $id, 's' => 1]); +$keys[0][] = button(getTranslation('no'), 'pokedex_list_raids'); // Build callback message string. $callback_response = 'OK'; diff --git a/mods/edit_date.php b/mods/edit_date.php index 20a4ae30..d83985c6 100644 --- a/mods/edit_date.php +++ b/mods/edit_date.php @@ -24,11 +24,7 @@ for ($i = 0; $i <= 23; $i = $i + 1) { $buttonData['t'] = $data['t'] . str_pad($i, 2, '0', STR_PAD_LEFT); // Create the keys. - $keys[] = array( - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => str_pad($i, 2, '0', STR_PAD_LEFT) . ':xx', - 'callback_data' => formatCallbackData($buttonData) - ); + $keys[] = button(str_pad($i, 2, '0', STR_PAD_LEFT) . ':xx', $buttonData); } // Set keys count and message. $keys_count = 4; @@ -42,11 +38,7 @@ for ($i = 0; $i <= 45; $i = $i + 15) { $buttonData['t'] = $data['t'] . str_pad($i, 2, '0', STR_PAD_LEFT); // Create the keys. - $keys[] = array( - // Just show the time, no text - not everyone has a phone or tablet with a large screen... - 'text' => $hour . ':' . str_pad($i, 2, '0', STR_PAD_LEFT), - 'callback_data' => formatCallbackData($buttonData) - ); + $keys[] = button($hour . ':' . str_pad($i, 2, '0', STR_PAD_LEFT), $buttonData); } // Set keys count and message. $keys_count = 4; @@ -75,10 +67,7 @@ // Adding button to continue with next step in raid creation $buttonData[0] = 'edit_time'; $buttonData['t'] = $utc_raid_time; - $keys[] = array( - 'text' => getTranslation('next'), - 'callback_data' => formatCallbackData($buttonData) - ); + $keys[] = button(getTranslation('next'), $buttonData); // Set message. $msg = getTranslation('start_date_time') . ':' . CR .'' . $text_day . SP . $text_month . SP . $text_year . ',' . SP . $time_tz . ''; @@ -95,16 +84,10 @@ $backData = $data; $backData[0] = 'edit_starttime'; unset($backData['t']); - $nav_keys[] = [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData($backData) - ]; + $nav_keys[] = button(getTranslation('back'), $backData); } -$nav_keys[] = [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' -]; +$nav_keys[] = button(getTranslation('abort'), 'exit'); $nav_keys = inline_key_array($nav_keys, 2); // Merge keys. diff --git a/mods/edit_event.php b/mods/edit_event.php index 19d4220e..209d376a 100644 --- a/mods/edit_event.php +++ b/mods/edit_event.php @@ -21,16 +21,8 @@ $backData[0] = 'edit_raidlevel'; // Add navigation keys. -$keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData($backData) - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] -]; +$keys[0][] = button(getTranslation('back'), $backData); +$keys[0][] = button(getTranslation('abort'), 'exit'); // Build callback message string. diff --git a/mods/edit_event_note.php b/mods/edit_event_note.php index 9705cef7..f6a6acdd 100644 --- a/mods/edit_event_note.php +++ b/mods/edit_event_note.php @@ -2,11 +2,10 @@ require_once(LOGIC_PATH . '/show_raid_poll_small.php'); // Set the id. -$raid_id = $data['id']; +$raid_id = $data['r']; // Set the arg. -$arg = explode(',', $data['arg']); -$mode = (isset($arg[1]) ? $arg[1] : ""); +$mode = $data['m'] ?? ''; // Set the user id. $userid = $update['callback_query']['from']['id']; @@ -23,17 +22,16 @@ $msg .= getTranslation('raid_saved') . CR; $msg .= show_raid_poll_small($raid, false) . CR2; -if($mode == 'edit') { +if($mode == 'e') { $msg.= getTranslation('event_note_edit') . ': '; // Create an entry to user_input table - $modifiers = json_encode(array("id"=>$raid_id,"old_message_id"=>$update['callback_query']['message']['message_id'])); // Save the raid id and the message id to db so we can delete it later - $handler = "save_event_note"; // call for mods/save_event_note.php after user posts the answer + $modifiers = json_encode(array('id' => $raid_id, 'old_message_id' => $update['callback_query']['message']['message_id'])); // Save the raid id and the message id to db so we can delete it later + $handler = 'save_event_note'; // call for mods/save_event_note.php after user posts the answer my_query('INSERT INTO user_input SET user_id=:userId, modifiers=:modifiers, handler=:handler', ['userId' => $userid, 'modifiers' => $modifiers, 'handler' => $handler]); -}elseif($mode == 'cancel') { +}elseif($mode == 'c') { my_query('DELETE FROM user_input WHERE user_id = ?', [$userid]); - $data['arg'] = 0; require_once('edit_save.php'); }else { if($raid['event'] == EVENT_ID_EX) { @@ -48,17 +46,12 @@ $msg.= getTranslation('event_add_note_description'); // Create an entry to user_input table - $modifiers = json_encode(array('id'=>$raid_id, 'old_message_id' => $update['callback_query']['message']['message_id'])); // Save the raid id and the message id to db so we can delete it later + $modifiers = json_encode(array('id' => $raid_id, 'old_message_id' => $update['callback_query']['message']['message_id'])); // Save the raid id and the message id to db so we can delete it later $handler = 'save_event_note'; // call for mods/save_event_note.php after user posts the answer - my_query('INSERT INTO user_input SET user_id=:userId, modifiers = :modifiers, handler = :handler', ['userId' => $userid, 'modifiers' => $modifiers, 'handler' => $handler]); + my_query('INSERT INTO user_input SET user_id = :userId, modifiers = :modifiers, handler = :handler', ['userId' => $userid, 'modifiers' => $modifiers, 'handler' => $handler]); } -$keys[] = [ - [ - 'text' => getTranslation('cancel'), - 'callback_data' => $raid_id . ':edit_event_note:'. $arg[0] . ',cancel' - ] -]; +$keys[][] = button(getTranslation('cancel'), ['edit_event_note', 'r' => $raid_id, 'm' => 'c']); // Answer callback. answerCallbackQuery($update['callback_query']['id'], $callback_response); diff --git a/mods/edit_event_raidlevel.php b/mods/edit_event_raidlevel.php index bd50e700..0f8b4822 100644 --- a/mods/edit_event_raidlevel.php +++ b/mods/edit_event_raidlevel.php @@ -30,16 +30,8 @@ $backData = $data; $backData[0] = 'edit_event'; // Add navigation keys. -$keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData($backData) - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] -]; +$keys[0][] = button(getTranslation('back'), $backData); +$keys[0][] = button(getTranslation('abort'), 'exit'); // Get event info $q = my_query('SELECT name, description FROM events WHERE id = ? LIMIT 1', [$event_id]); diff --git a/mods/edit_pokemon.php b/mods/edit_pokemon.php index 1562550f..af480315 100644 --- a/mods/edit_pokemon.php +++ b/mods/edit_pokemon.php @@ -32,14 +32,8 @@ $backData = $data; $backData[0] = $back_action; $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData($backData), - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + button(getTranslation('back'), $backData), + button(getTranslation('abort'), 'exit') ]; // Build callback message string. diff --git a/mods/edit_raidlevel.php b/mods/edit_raidlevel.php index cc5c1686..8b00281c 100644 --- a/mods/edit_raidlevel.php +++ b/mods/edit_raidlevel.php @@ -35,6 +35,7 @@ // Active raid? $duplicate_id = active_raid_duplication_check($gym_id); if ($duplicate_id > 0) { + $keys = []; // In case gym has already a normal raid saved to it and user has privileges to create an event raid, create a special menu if($admin_access[0] == true || $admin_access[1] == true) { $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . CR; @@ -45,56 +46,22 @@ $backData[0] = 'gymMenu'; $backData['stage'] = 2; $backData['a'] = 'create'; - $keys = [ - [ - [ - 'text' => getTranslation('saved_raid'), - 'callback_data' => formatCallbackData(['raids_list', 'r' => $duplicate_id]) - ] - ], - [ - [ - 'text' => getTranslation('create_event_raid'), - 'callback_data' => formatCallbackData($eventData) - ] - ], - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData($backData) - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ], - ]; + $keys[0][0] = button(getTranslation('saved_raid'), ['raids_list', 'r' => $duplicate_id]); + $keys[1][0] = button(getTranslation('create_event_raid'), $eventData); + $keys[2][0] = button(getTranslation('back'), $backData); + $keys[2][1] = button(getTranslation('abort'), 'exit'); } else { - $keys = []; $raid_id = $duplicate_id; $raid = get_raid($raid_id); $msg = EMOJI_WARN . SP . getTranslation('raid_already_exists') . SP . EMOJI_WARN . CR . show_raid_poll_small($raid); $keys = share_keys($raid_id, 'raid_share', $update, $raid['level']); if($botUser->raidaccessCheck($raid['id'], 'pokemon', true)) { - $keys[] = [ - [ - 'text' => getTranslation('update_pokemon'), - 'callback_data' => formatCallbackData(['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]), - ] - ]; + $keys[][] = button(getTranslation('update_pokemon'), ['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]); } if($botUser->raidaccessCheck($raid['id'], 'delete', true)) { - $keys[] = [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id']]) - ] - ]; + $keys[][] = button(getTranslation('delete'), ['raids_delete', 'r' => $raid['id']]); } - $keys[][] = [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ]; + $keys[][] = button(getTranslation('abort'), 'exit'); } // Answer callback. @@ -116,10 +83,7 @@ $keys = raid_edit_raidlevel_keys($data, $admin_access, false, $excludeElite); if($eliteId > 0) { - $keys[][] = [ - 'text' => getTranslation('saved_raid'), - 'callback_data' => formatCallbackData(['raids_list', 'r' => $eliteId]) - ]; + $keys[][] = button(getTranslation('saved_raid'), ['raids_list', 'r' => $eliteId]); } $lastRow = []; @@ -129,15 +93,9 @@ $backData['a'] = 'create'; $backData['stage'] = 2; // Add navigation keys. - $lastRow[] = [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData($backData) - ]; + $lastRow[] = button(getTranslation('back'), $backData); } -$lastRow[] = [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' -]; +$lastRow[] = button(getTranslation('abort'), 'exit'); $keys[] = $lastRow; // Build message. diff --git a/mods/edit_save.php b/mods/edit_save.php index e79852f8..5cac61d3 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -17,7 +17,7 @@ $userid = $update['callback_query']['from']['id']; // Update only if time is not equal to RAID_DURATION -if($data['d'] != $config->RAID_DURATION) { +if(isset($data['d']) && $data['d'] != $config->RAID_DURATION) { // Build query. my_query(' @@ -32,24 +32,12 @@ $tg_json = array(); // Add delete to keys. -$keys = [ - [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => formatCallbackData(['raids_delete', 'r' => $id]) - ] - ] -]; +$keys[][] = button(getTranslation('delete'), ['raids_delete', 'r' => $id]); // Check access level prior allowing to change raid time if($botUser->accessCheck('raid-duration', true)) { // Add time change to keys. - $keys[] = [ - [ - 'text' => getTranslation('change_raid_duration'), - 'callback_data' => formatCallbackData(['edit_time', 'r' => $id, 'o' => 'm']) - ] - ]; + $keys[][] = button(getTranslation('change_raid_duration'), ['edit_time', 'r' => $id, 'o' => 'm']); } // Get raid times. @@ -60,12 +48,7 @@ if($raid['event'] !== NULL) { $event_button_text = ($raid['event_note'] == NULL) ? getTranslation("event_note_add") : getTranslation("event_note_edit"); - $keys[] = [ - [ - 'text' => $event_button_text, - 'callback_data' => $id . ':edit_event_note:0' - ] - ]; + $keys[][] = button($event_button_text, ['edit_event_note', 'r' => $id, 'm' => 'e']); } // Add keys to share. diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index 127f2e95..89c8a362 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -47,10 +47,7 @@ // Add keys. $buttonData['t'] = $date_tz; - $keys[] = array( - 'text' => $text_day . SP . $text_month . SP . $text_year, - 'callback_data' => formatCallbackData($buttonData) - ); + $keys[] = button($text_day . SP . $text_month . SP . $text_year, $buttonData); } // Get the inline key array. @@ -99,10 +96,7 @@ $buttonText = dt2time($now_plus_i->format('Y-m-d H:i:s')); // Create the keys. - $keys[] = array( - 'text' => $buttonText, - 'callback_data' => formatCallbackData($buttonData) - ); + $keys[] = button($buttonText, $buttonData); } // Get the inline key array. diff --git a/mods/end_remote_raid.php b/mods/end_remote_raid.php index 65f9419d..bf25577e 100644 --- a/mods/end_remote_raid.php +++ b/mods/end_remote_raid.php @@ -1,6 +1,6 @@ ' . getTranslation('events_no_description') . ''; $msg .= '' . $event['name'] . '' . CR; $msg .= $event['description'] . CR . CR; - $keys[] = [ - [ - 'text' => $event['name'], - 'callback_data' => $event['id'] . ':events_manage:0', - ] - ]; + $keys[][] = button($event['name'], ['events_manage', 'e' => $event['id']]); } -$keys[] = [ - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']), - ] -]; +$keys[][] = button(getTranslation('done'), ['exit', 'd' => '1']); $tg_json = []; diff --git a/mods/events_add.php b/mods/events_add.php index dcd120b5..17a70ab6 100644 --- a/mods/events_add.php +++ b/mods/events_add.php @@ -23,12 +23,7 @@ editMessageText($modifiers['old_message_id'], getTranslation('events_created'), [], $userId); $msg = '' . getTranslation('events_created') . '' . CR; $msg .= $value; - $keys[] = [ - [ - 'text' => getTranslation('next'), - 'callback_data' => $eventId . ':events_manage:0', - ] - ]; + $keys[][] = button(getTranslation('next'), ['events_manage', 'e' => $eventId]); }else { if($abort == 0) { // Add a new event @@ -41,10 +36,7 @@ // Data for handling response from the user my_query('INSERT INTO user_input SET user_id = ?, handler = \'events_add\', modifiers = ?', [$userId, $modifiers]); - $keys[][] = [ - 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['events_add', 'a' => 1]), - ]; + $keys[][] = button(getTranslation('abort'), ['events_add', 'a' => 1]); }elseif($abort == 1) { my_query('DELETE FROM user_input WHERE user_id = ?', [$userId]); answerCallbackQuery($update['callback_query']['id'], 'OK'); diff --git a/mods/events_manage.php b/mods/events_manage.php index 2c4e6b3f..12fdefd9 100644 --- a/mods/events_manage.php +++ b/mods/events_manage.php @@ -18,9 +18,8 @@ 'poll_template' => ['nullable' => true], ]; -$eventId = $data['id'] ?? false; -$arg = $data['arg'] ?? false; -$subArg = ($arg !== false) ? explode('-', $arg) : []; +$eventId = $data['e'] ?? false; +$action = $data['a'] ?? false; $keys = []; $callback_response = 'OK'; $userId = $update['callback_query']['from']['id'] ?? $update['message']['from']['id']; @@ -31,11 +30,11 @@ if($modifiers['action'] == 1) { // User input is new event name $column = 'name'; - $arg = 0; + $action = 0; }else if($modifiers['action'] == 2) { // User input is new description $column = 'description'; - $arg = 0; + $action = 0; }else if($modifiers['action'] == 3) { // User input is raid poll settings $column = $modifiers['column']; @@ -63,7 +62,7 @@ } $value = (strtolower($value) == 'null' ? NULL : json_encode($inputArray)); } - $arg = 3; + $action = 3; } $eventId = $modifiers['eventId']; my_query('UPDATE events SET ' . $column . ' = ? WHERE id=?', [$value, $eventId]); @@ -82,42 +81,42 @@ $msg .= '' . $event['name'] . '' . CR; $msg .= $event['description'] . CR . CR; -if($arg == 0 || $arg == 'a') { - if($arg == 'a') { +if($action == 0 || $action == 'a') { + if($action == 'a') { my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); $callback_response = getTranslation('action_aborted'); } if($eventId != EVENT_ID_EX) - $keys = universal_key($keys, $eventId, 'events_manage', '1', getTranslation('events_edit_name')); - $keys = universal_key($keys, $eventId, 'events_manage', '2', getTranslation('events_edit_description')); - $keys = universal_key($keys, $eventId, 'events_manage', '3', getTranslation('events_edit_raid_poll')); + $keys[][] = button(getTranslation('events_edit_name'), ['events_manage', 'e' => $eventId, 'a' => 1]); + $keys[][] = button(getTranslation('events_edit_description'), ['events_manage', 'e' => $eventId, 'a' => 2]); + $keys[][] = button(getTranslation('events_edit_raid_poll'), ['events_manage', 'e' => $eventId, 'a' => 3]); if($eventId != EVENT_ID_EX) - $keys = universal_key($keys, $eventId, 'events_manage', '4', getTranslation('events_delete')); + $keys[][] = button(getTranslation('events_delete'), ['events_manage', 'e' => $eventId, 'a' => 4]); $keys[] = [ - universal_inner_key($keys, '0', 'events', '0', getTranslation('back')), - universal_inner_key($keys, '0', 'exit', '0', getTranslation('done')) + button(getTranslation('back'), 'events'), + button(getTranslation('done'), 'exit') ]; // Edit event name -}else if($arg == 1) { +}else if($action == 1) { $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id'],'action'=>1,'eventId'=>$eventId]); my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); $msg .= '' . getTranslation('events_edit_name') . '' . CR; $msg .= getTranslation('events_give_name') . ':' . CR; - $keys = universal_key($keys, $eventId, 'events_manage', 'a', getTranslation('abort')); + $keys[][] = button(getTranslation('abort'), ['events_manage', 'e' => $eventId, 'a' => 'a']); // Edit event description -}else if($arg == 2) { +}else if($action == 2) { $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id'],'action'=>2,'eventId'=>$eventId]); my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); $msg .= '' . getTranslation('events_edit_description') . '' . CR; $msg .= getTranslation('events_give_description') . ':'; - $keys = universal_key($keys, $eventId, 'events_manage', 'a', getTranslation('abort')); + $keys[][] = button(getTranslation('abort'), ['events_manage', 'e' => $eventId, 'a' => 'a']); // Edt event raid poll settings -}else if($arg == 3) { +}else if($action == 3) { my_query('DELETE FROM user_input WHERE user_id=?', [$userId]); $templateArray = ($event['poll_template'] == NULL) ? $config->RAID_POLL_UI_TEMPLATE : json_decode($event['poll_template'], true); $event['poll_template'] = templateJsonToString($templateArray); @@ -129,31 +128,30 @@ $msg .= $column . ': '; $msg .= ($column == 'poll_template' ? CR : ''); $msg .= '' . ($event[$column] === NULL ? 'NULL' : $event[$column]) . '' . CR; - $keys = universal_key($keys, $eventId, 'events_manage', 'e-'.$column, $column); + $keys[][] = button($column, ['events_manage', 'e' => $eventId, 'a' => 'e', 'c' => $column]); } $keys[] = [ - universal_inner_key($keys, $eventId, 'events_manage', '0', getTranslation('back')), - universal_inner_key($keys, '0', 'exit', '1', getTranslation('done')) + button(getTranslation('back'), ['events_manage', 'e' => $eventId, 'a' => 0]), + button(getTranslation('done'), ['exit', 'd' => 1]), ]; // Delete event confirmation -}else if($arg == 4) { +}else if($action == 4) { $msg .= '' . getTranslation('events_delete_confirmation') . '' . CR; $keys[] = [ - universal_inner_key($keys, $eventId, 'events_manage', 'd', getTranslation('yes')), - universal_inner_key($keys, $eventId, 'events_manage', '0', getTranslation('no')) + button(getTranslation('yes'), ['events_manage', 'e' => $eventId, 'a' => 'd']), + button(getTranslation('no'), ['events_manage', 'e' => $eventId, 'a' => 0]), ]; // Delete event -}else if($arg == 'd') { +}else if($action == 'd') { if($eventId != EVENT_ID_EX) my_query('DELETE FROM events WHERE id=?', [$eventId]); - $data['id'] = $data['arg'] = 0; include(ROOT_PATH . '/mods/events.php'); exit; // Prompt for raid poll value editing -}else if($subArg[0] == 'e') { - $valueToEdit = $subArg[1]; +}else if($action == 'e') { + $valueToEdit = $data['c']; $modifiers = json_encode(['old_message_id'=>$update['callback_query']['message']['message_id'],'action'=>3,'column'=>$valueToEdit,'eventId'=>$eventId]); my_query('INSERT INTO user_input SET user_id=?, handler=\'events_manage\', modifiers=?', [$userId, $modifiers]); @@ -166,7 +164,7 @@ $msg .= getTranslation('old_value') . CR; $msg .= '' . ($event[$valueToEdit] === NULL ? 'NULL' : $event[$valueToEdit]) . '' . CR . CR; $msg .= getTranslation('new_value'); - $keys = universal_key($keys, $eventId, 'events_manage', '3', getTranslation('back')); + $keys[][] = button(getTranslation('back'), ['events_manage', 'e' => $eventId, 'a' => 3]); } @@ -188,8 +186,7 @@ function templateJsonToString($templateArray) { $templateString = ''; foreach($templateArray as $line) { foreach($line as $button) { - $templateString .= $button; - $templateString .= ','; + $templateString .= $button . ','; } $templateString = rtrim($templateString, ',') . CR; } diff --git a/mods/gym_create.php b/mods/gym_create.php index a5850464..bb61b080 100644 --- a/mods/gym_create.php +++ b/mods/gym_create.php @@ -7,7 +7,7 @@ //debug_log($data); // Check access. -$botUser->accessCheck('gym-edit'); +$botUser->accessCheck('gym-add'); function insertUserInput($userId, $stage, $oldMessageId, $gymId = 0) { global $dbh; @@ -25,19 +25,13 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] if($editMsg != '') editMessageText($oldMessageId, $editMsg, $editKeys, $userId, ['disable_web_page_preview' => 'true']); if($sendMsg != '') send_message($userId, $sendMsg, $sendKeys, ['disable_web_page_preview' => 'true']); } -if(isset($data['arg'])) { - // Split the arg. - $split_arg = explode('-', $data['arg']); - $action = $split_arg[0] ?? false; - $deleteId = $split_arg[1] ?? false; -} // Set keys. $keys = []; $stage = $modifiers['stage'] ?? 1; -if(isset($action) && $action == 'abort') { - my_query('DELETE FROM user_input WHERE id = :deleteId', ['deleteId' => $deleteId]); +if(isset($data['a'])) { + my_query('DELETE FROM user_input WHERE id = :deleteId', ['deleteId' => $data['a']]); $msg = getTranslation('action_aborted'); editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['from']['id']); exit; @@ -51,11 +45,8 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $userInputId = insertUserInput($userId, $stage, $oldMessageId); - $editMsg = getTranslation("gym_create") . ':'; - $editKeys[0][] = [ - 'text' => getTranslation("abort"), - 'callback_data' => '0:gym_create:abort-' . $userInputId - ]; + $editMsg = getTranslation('gym_create') . ':'; + $editKeys[0][] = button(getTranslation('abort'), ['gym_create', 'a' => $userInputId]); $sendMsg = EMOJI_HERE . getTranslation('gym_gps_instructions') . CR; $sendMsg .= getTranslation('gym_gps_example'); respondToUser($userId, $oldMessageId, $editMsg, $editKeys, $sendMsg, [], $callbackResponse, $callbackId); @@ -86,12 +77,7 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] my_query('UPDATE gyms SET gym_name = :gym_name WHERE id = :gymId', [':gym_name' => $input, ':gymId' => $gymId]); $msg = getTranslation('gym_added'); - $keys[] = [ - [ - 'text' => getTranslation('show_gym_details'), - 'callback_data' => formatCallbackData(['gym_details', 'g' => $gymId]) - ] - ]; + $keys[][] = button(getTranslation('show_gym_details'), ['gym_details', 'g' => $gymId]); respondToUser($userId, $oldMessageId, 'OK', [], $msg, $keys); }else { $msg = getTranslation('gym_edit_text_too_long'); diff --git a/mods/gym_delete.php b/mods/gym_delete.php index 01842b2d..1d0b6d86 100644 --- a/mods/gym_delete.php +++ b/mods/gym_delete.php @@ -15,6 +15,7 @@ $gymId = $data['g']; $confirm = $data['c'] == 1 ? true : false; +$keys = []; if ($gymId > 0 && $confirm == false) { $gym = get_gym($gymId); @@ -23,20 +24,8 @@ $msg .= CR . get_gym_details($gym); // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => formatCallbackData(['gym_delete', 'g' => $gymId, 'c' => 1]) - ] - ], - [ - [ - 'text' => getTranslation('no'), - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gymId]) - ] - ] - ]; + $keys[][] = button(getTranslation('yes'), ['gym_delete', 'g' => $gymId, 'c' => 1]); + $keys[][] = button(getTranslation('no'), ['gym_edit_details', 'g' => $gymId]); // Delete the gym. } else if ($gymId > 0 && $confirm == true) { @@ -49,7 +38,6 @@ // Set message $msg = '' . getTranslation('deleted_this_gym') . '' . CR; $msg .= get_gym_details($gym); - $keys = []; // Delete gym. my_query(' diff --git a/mods/gym_edit_details.php b/mods/gym_edit_details.php index 96c9a34e..862f50e1 100644 --- a/mods/gym_edit_details.php +++ b/mods/gym_edit_details.php @@ -59,21 +59,12 @@ $msg .= CR . CR . '' . getTranslation($instructions) . ''; if($action == 'gps') $msg .= CR. getTranslation('gym_gps_example'); - $keys[0][] = [ - 'text' => getTranslation('abort'), - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'abort', 'd' => $dbh->lastInsertId()]) - ]; + $keys[0][] = button(getTranslation('abort'), ['gym_edit_details', 'g' => $gym_id, 'a' => 'abort', 'd' => $dbh->lastInsertId()]); if($action == 'note' && !empty($gym['gym_note'])) { - $keys[0][] = [ - 'text' => getTranslation('delete'), - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'note', 'd' => $dbh->lastInsertId()]) - ]; + $keys[0][] = button(getTranslation('delete'), ['gym_edit_details', 'g' => $gym_id, 'a' => 'note', 'd' => $dbh->lastInsertId()]); } if($action == 'addr') { - $keys[0][] = [ - 'text' => getTranslation('gym_save_lookup_result'), - 'callback_data' => formatCallbackData(['gym_edit_details', 'g' => $gym_id, 'a' => 'addr', 'd' => $dbh->lastInsertId()]) - ]; + $keys[0][] = button(getTranslation('gym_save_lookup_result'), ['gym_edit_details', 'g' => $gym_id, 'a' => 'addr', 'd' => $dbh->lastInsertId()]); } } }else { diff --git a/mods/history.php b/mods/history.php index 816d0898..539ab9fc 100644 --- a/mods/history.php +++ b/mods/history.php @@ -13,8 +13,8 @@ require_once(LOGIC_PATH .'/history.php'); -$current_day = $data['id']; -$current_year_month = $data['arg']; +$current_day = $data['d'] ?? 0; +$current_year_month = $data['m'] ?? ''; if($current_day == 0) { $msg_keys = create_history_date_msg_keys($current_year_month); @@ -44,41 +44,32 @@ $date = $current_year_month.'-'.$current_day; $rs = my_query(' - SELECT '.$select_query.' AS first_letter - FROM raids - LEFT JOIN gyms - ON raids.gym_id = gyms.id - LEFT JOIN attendance - ON attendance.raid_id = raids.id - WHERE date_format(start_time, "%Y-%m-%d") = \''.$date.'\' - AND raids.end_time < UTC_TIMESTAMP() - AND attendance.id IS NOT NULL - AND gyms.gym_name IS NOT NULL - ORDER BY first_letter - '); + SELECT '.$select_query.' AS first_letter + FROM raids + LEFT JOIN gyms + ON raids.gym_id = gyms.id + LEFT JOIN attendance + ON attendance.raid_id = raids.id + WHERE date_format(start_time, "%Y-%m-%d") = ? + AND raids.end_time < UTC_TIMESTAMP() + AND attendance.id IS NOT NULL + AND gyms.gym_name IS NOT NULL + ORDER BY first_letter + ', [$date]); // Init empty keys array. $keys = []; while ($gym = $rs->fetch()) { // Add first letter to keys array - $keys[] = array( - 'text' => $gym['first_letter'], - 'callback_data' => $date . ':history_gyms:' . $gym['first_letter'] - ); + $keys[] = button($gym['first_letter'],['history_gyms', 'd' => $date, 'fl' => $gym['first_letter']]); } // Format buttons $keys = inline_key_array($keys, 4); $nav_keys = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => '0:history:' . $current_year_month - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + button(getTranslation('back'), ['history', 'm' => $current_year_month]), + button(getTranslation('abort'), 'exit') ]; // Get the inline key array. diff --git a/mods/history_gyms.php b/mods/history_gyms.php index 48c9f7a5..f0c028e5 100644 --- a/mods/history_gyms.php +++ b/mods/history_gyms.php @@ -11,8 +11,8 @@ // Expected callback data: [Date, YYYY-MM-DD]:history_gyms:[GYM_LETTER] -$current_date = $data['id']; -$first = $data['arg']; +$current_date = $data['d']; +$first = $data['fl']; $split_date = explode('-', $current_date); $current_day = $split_date[2]; @@ -43,8 +43,7 @@ $query_collate = 'COLLATE ' . $config->MYSQL_SORT_COLLATE; } // Get gyms from database -$rs = my_query( - ' +$rs = my_query(' SELECT gyms.id, gyms.gym_name, gyms.ex_gym FROM gyms LEFT JOIN raids @@ -58,7 +57,6 @@ ' . $not . ' GROUP BY gym_name, raids.gym_id, gyms.id, gyms.ex_gym ORDER BY gym_name ' . $query_collate - ); while ($gym = $rs->fetch()) { @@ -69,20 +67,11 @@ } else { $gym_name = $gym['gym_name']; } - $keys[][] = [ - 'text' => $gym_name, - 'callback_data' => $current_date . '/' . $first . ':history_raids:' . $gym['id'] - ]; + $keys[][] = button($gym_name, ['history_raids', 'd' => $current_date, 'fl' => $first, 'g' => $gym['id']]); } $nav_keys = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $current_day.':history:' . $current_year_month - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ], + button(getTranslation('back'), ['history', 'd' => $current_day, 'm' => $current_year_month]), + button(getTranslation('abort'), 'exit') ]; $keys[] = $nav_keys; diff --git a/mods/history_raid.php b/mods/history_raid.php index 5c4d7a85..dcd519a8 100644 --- a/mods/history_raid.php +++ b/mods/history_raid.php @@ -10,11 +10,7 @@ // Check access. $botUser->accessCheck('history'); -// Expected callback data: [Date, YYYY-MM-DD]/[GYM_LETTER]:history_raid:[GYM_ID]/[RAID_ID] - -$arg_data = explode('/',$data['arg']); -$gym_id = $arg_data[0]; -$raid_id = $arg_data[1]; +$raid_id = $data['r']; $raid = get_raid($raid_id); @@ -26,15 +22,11 @@ // Answer callback. $tg_json[] = answerCallbackQuery($update['callback_query']['id'], 'OK', true); +$backData = $data; +$backData[0] = 'history_raids'; $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $data['id'] . ':history_raids:' . $gym_id - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ], + button(getTranslation('back'), $backData), + button(getTranslation('done'), ['exit', 'd' => '1']) ]; // Edit message. diff --git a/mods/history_raids.php b/mods/history_raids.php index d55f43df..996462e3 100644 --- a/mods/history_raids.php +++ b/mods/history_raids.php @@ -9,13 +9,9 @@ // Check access. $botUser->accessCheck('history'); -// Expected callback data: [Date, YYYY-MM-DD]/[GYM_LETTER]:history_raids:[GYM_ID] - -$id_data = explode('/',$data['id']); -$current_date = $id_data[0]; -$gym_first_letter = $id_data[1]; - -$gym_id = $data['arg']; +$current_date = $data['d']; +$gym_first_letter = $data['fl']; +$gym_id = $data['g']; // Get raids from database $rs = my_query(' @@ -33,22 +29,16 @@ ', [$gym_id] ); while ($raid = $rs->fetch()) { - $keys[][] = [ - 'text' => dt2time($raid['start_time']) . ': ' . get_local_pokemon_name($raid['pokemon'],$raid['pokemon_form']), - 'callback_data' => $data['id'] . ':history_raid:' . $gym_id .'/' . $raid['id'] - ]; + $newData = $data; + $newData[0] = 'history_raid'; + $newData['r'] = $raid['id']; + $keys[][] = button(dt2time($raid['start_time']) . ': ' . get_local_pokemon_name($raid['pokemon'],$raid['pokemon_form']), $newData); $gym_name = $raid['gym_name']; $start_time = $raid['start_time']; } $nav_keys = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $current_date . ':history_gyms:' . $gym_first_letter - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ], + button(getTranslation('back'), ['history_gyms', 'd' => $current_date, 'fl' => $gym_first_letter]), + button(getTranslation('abort'), 'exit') ]; $keys[] = $nav_keys; diff --git a/mods/import_future_bosses.php b/mods/import_future_bosses.php index 325e6e3d..35341716 100644 --- a/mods/import_future_bosses.php +++ b/mods/import_future_bosses.php @@ -10,68 +10,51 @@ $botUser->accessCheck('pokedex'); require_once(LOGIC_PATH . '/read_upcoming_bosses.php'); -$id = $data['id']; -$arg = $data['arg']; +$action = $data['a'] ?? 0; -if($arg == '1') { +if($action == '1') { $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1;'; $sql .= read_upcoming_bosses(true); $query = my_query($sql); $msg = getTranslation('import_done'); - $keys = []; -}else { - $list = read_upcoming_bosses(); - $msg = ''; - if(!empty($list)) { - $now = new DateTime('now', new DateTimeZone($config->TIMEZONE)); - $query = my_query(" - SELECT id, pokedex_id, pokemon_form_id, raid_level, scheduled, DATE_FORMAT(date_start, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_start, DATE_FORMAT(date_end, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_end FROM raid_bosses - WHERE date_end > '" . $now->format('Y-m-d H:i:s') . "' - AND scheduled = 1 - ORDER BY date_start, raid_level, pokedex_id, pokemon_form_id - "); - $prev_start = $prev_rl = ''; - $msg = '' . getTranslation('current_scheduled_bosses') . ':'; - foreach($query->fetchAll() as $result) { - if($prev_start != $result['date_start']) { - $msg.= CR . EMOJI_CLOCK . ' ' . $result['date_start'] . ' — ' . $result['date_end'] . ':' . CR; - $prev_rl = ''; - } - if($prev_rl != $result['raid_level']) { - $msg.= '' . getTranslation($result['raid_level'] . 'stars') .':' . CR; - } - $msg.= get_local_pokemon_name($result['pokedex_id'], $result['pokemon_form_id']) . CR; - $prev_start = $result['date_start']; - $prev_rl = $result['raid_level']; + $tg_json = array(); + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], 'OK', true); + $tg_json[] = edit_message($update, $msg, [], false, true); + curl_json_multi_request($tg_json); + exit(); +} +$list = read_upcoming_bosses(); +$msg = ''; +if(!empty($list)) { + $now = new DateTime('now', new DateTimeZone($config->TIMEZONE)); + $query = my_query(" + SELECT id, pokedex_id, pokemon_form_id, raid_level, scheduled, DATE_FORMAT(date_start, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_start, DATE_FORMAT(date_end, '%e.%c. ".getTranslation('raid_egg_opens_at')." %H:%i') as date_end FROM raid_bosses + WHERE date_end > '" . $now->format('Y-m-d H:i:s') . "' + AND scheduled = 1 + ORDER BY date_start, raid_level, pokedex_id, pokemon_form_id + "); + $prev_start = $prev_rl = ''; + $msg = '' . getTranslation('current_scheduled_bosses') . ':'; + foreach($query->fetchAll() as $result) { + if($prev_start != $result['date_start']) { + $msg.= CR . EMOJI_CLOCK . ' ' . $result['date_start'] . ' — ' . $result['date_end'] . ':' . CR; + $prev_rl = ''; + } + if($prev_rl != $result['raid_level']) { + $msg.= '' . getTranslation($result['raid_level'] . 'stars') .':' . CR; } - $msg .= CR . CR . '' . getTranslation('found_upcoming_bosses') . ':'; - $msg .= $list; - $msg .= CR . CR . getTranslation('confirm_replace_upcoming'); - $keys = [ - [ - [ - 'text' => getTranslation('replace'), - 'callback_data' => '1:import_future_bosses:1' - ] - ], - [ - [ - 'text'=>getTranslation('back'), - 'callback_data' => 'pokedex_import' - ] - ] - ]; - }else { - $msg .= getTranslation('upcoming_bosses_not_found'); - $keys = [ - [ - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] - ]; + $msg.= get_local_pokemon_name($result['pokedex_id'], $result['pokemon_form_id']) . CR; + $prev_start = $result['date_start']; + $prev_rl = $result['raid_level']; } + $msg .= CR . CR . '' . getTranslation('found_upcoming_bosses') . ':'; + $msg .= $list; + $msg .= CR . CR . getTranslation('confirm_replace_upcoming'); + $keys[][] = button(getTranslation('replace'), ['import_future_bosses', 'a' => 1]); + $keys[][] = button(getTranslation('back'), 'pokedex_import'); +}else { + $msg .= getTranslation('upcoming_bosses_not_found'); + $keys[][] = button(getTranslation('done'), ['exit', 'd' => '1']); } // Callback message string. @@ -88,5 +71,3 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -exit(); diff --git a/mods/import_shinyinfo.php b/mods/import_shinyinfo.php index 083bdeaf..6eb50f2c 100644 --- a/mods/import_shinyinfo.php +++ b/mods/import_shinyinfo.php @@ -11,11 +11,6 @@ $botUser->accessCheck('pokedex'); include(LOGIC_PATH . '/resolve_boss_name_to_ids.php'); -// Get raid levels -$id = $data['id']; - -// Exclude pokemon -$arg = $data['arg']; $link = 'https://fight.pokebattler.com/raids'; $pb_data = curl_get_contents($link); @@ -26,13 +21,11 @@ $msg = ''; $shinydata = []; foreach($pb_data['tiers'] as $tier) { - // Raid level and message. $rl = str_replace('RAID_LEVEL_','', $tier['tier']); if($rl == "MEGA") $raid_level_id = 6; else $raid_level_id = $rl; $rl_parts = explode('_', $rl); if($rl_parts[count($rl_parts)-1] == 'FUTURE') continue; - #$msg .= '' . getTranslation('pokedex_raid_level') . SP . $rl . ':' . CR; // Get raid bosses for each raid level. foreach($tier['raids'] as $raid) { @@ -48,15 +41,9 @@ } $shinydata[] = [':dex_id' => $dex_id, ':dex_form' => $dex_form]; } - $msg .= CR; } // Back button. -$keys[] = [ - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] -]; +$keys[][] = button(getTranslation('done'), ['exit', 'd' => '1']); if(count($shinydata) > 0) { $query = $dbh->prepare("UPDATE pokemon SET shiny = 1 WHERE pokedex_id = :dex_id AND pokemon_form_id = :dex_form"); foreach($shinydata as $row_data) { diff --git a/mods/importal.php b/mods/importal.php index eb05f4fb..5e6f2273 100644 --- a/mods/importal.php +++ b/mods/importal.php @@ -118,24 +118,9 @@ function escape($value){ } // Set keys. -$keys = [ - [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => $gym_name[0] . ':gym_delete:' . $gym_id . '-delete' - ], - [ - 'text' => getTranslation('show_gym'), - 'callback_data' => $gym_id . ':gym_edit_details:show-1' - ] - ], - [ - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] -]; +$keys[][] = button(getTranslation('delete'), ['gym_delete', 'fl' => $gym_name[0], 'g' => $gym_id, 'c' => 0]); +$keys[][] = button(getTranslation('show_gym'), ['gym_edit_details', 'g' => $gym_id, 'a' => 'show', 'v' => 1]); +$keys[][] = button(getTranslation('done'), ['exit', 'd' => '1']); // Send the message. send_message($update['message']['chat']['id'], $msg, $keys, ['disable_web_page_preview' => 'true']); diff --git a/mods/list_raid.php b/mods/list_raid.php index 5cc878f2..ed49d686 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -50,29 +50,13 @@ debug_log($raid); // Create keys array. - $keys = [ - [ - [ - 'text' => getTranslation('expand'), - 'callback_data' => $raid['id'] . ':vote_refresh:0', - ] - ] - ]; + $keys = []; + $keys[][] = button(getTranslation('expand'), ['vote_refresh', 'r' => $raid['id']]); if($botUser->raidaccessCheck($raid['id'], 'pokemon', true)) { - $keys[] = [ - [ - 'text' => getTranslation('update_pokemon'), - 'callback_data' => formatCallbackData(['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]), - ] - ]; + $keys[][] = button(getTranslation('update_pokemon'), ['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]); } if($botUser->raidaccessCheck($raid['id'], 'delete', true)) { - $keys[] = [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id']]) - ] - ]; + $keys[][] = button(getTranslation('delete'), ['raids_delete', 'r' => $raid['id']]); } // Add keys to share. @@ -84,10 +68,7 @@ debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key - $keys[][] = [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => 1]) -]; + $keys[][] = button(getTranslation('done'), ['exit', 'd' => 1]); // Get message. $msg = show_raid_poll_small($raid); @@ -102,28 +83,14 @@ $msg .= '' . $i .'. ' . $raid_pokemon_name . '' . CR; if(!empty($raid['event_name'])) $msg .= $raid['event_name'] . CR; $msg .= get_raid_times($raid,false, true) . CR . CR; - $keys[] = [ - [ - 'text' => $i . '. ' . $raid_pokemon_name, - 'callback_data' => formatCallbackData(['list_raid', 'r' => $raid['id']]) - ] - ]; + $keys[][] = button($i . '. ' . $raid_pokemon_name,['list_raid', 'r' => $raid['id']]); $i++; } - $callback = [ - 'gymMenu', - 'stage' => 2, - 'a' => 'list', - 'fl' => $data['fl'], - 'ga' => $data['ga'], - 'h' => $data['h'], - ]; - $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData($callback) - ] - ]; + $backData = $data; + $backData[0] = 'gymMenu'; + $backData['stage'] = 2; + $backData['a'] = 'list'; + $keys[][] = button(getTranslation('back'), $backData); } // Build callback message string. diff --git a/mods/list_remote_gyms.php b/mods/list_remote_gyms.php index 9fb90433..c7f71946 100644 --- a/mods/list_remote_gyms.php +++ b/mods/list_remote_gyms.php @@ -6,25 +6,17 @@ //debug_log($update); //debug_log($data); -// Back key id, action and arg -$back_id = 0; -$back_action = 'list_by_gym_letter'; -$back_arg = 0; - $user_id = $update['callback_query']['from']['id']; // Get the keys. $query_remote = my_query('SELECT raids.id, gyms.gym_name, raids.start_time, raids.end_time FROM gyms LEFT JOIN raids on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); while($gym = $query_remote->fetch()) { - $keys[][] = [ - 'text' => $gym['gym_name'], - 'callback_data' => $gym['id'] . ':list_raid:' - ]; + $keys[][] = button($gym['gym_name'], ['list_raid', 'r' => $gym['id']]); } // Add navigation keys. $nav_keys = []; -$nav_keys[] = universal_inner_key($nav_keys, $back_id, $back_action, $back_arg, getTranslation('back')); -$nav_keys[] = universal_inner_key($nav_keys, '0', 'exit', '0', getTranslation('abort')); +$nav_keys[] = button(getTranslation('back'), ['gymMenu', 'a' => 'list']); +$nav_keys[] = button(getTranslation('abort'), 'exit'); $nav_keys = inline_key_array($nav_keys, 2); // Merge keys. $keys = array_merge($keys, $nav_keys); diff --git a/mods/overview_delete.php b/mods/overview_delete.php index e86662fc..a36b8573 100644 --- a/mods/overview_delete.php +++ b/mods/overview_delete.php @@ -44,18 +44,8 @@ $msg = '' . getTranslation('delete_raid_overview_for_chat') . ' ' . $chat_title . '?'; // Set keys - Delete button. - $keys = [ - [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => formatCallbackData(['overview_delete', 'c' => $rowOverviews['chat_id']]) - ], - [ - 'text' => getTranslation('no'), - 'callback_data' => formatCallbackData(['overview_delete', 'c' => 1]) - ] - ] - ]; + $keys[0][0] = button(getTranslation('yes'), ['overview_delete', 'c' => $rowOverviews['chat_id']]); + $keys[0][1] = button(getTranslation('no'), ['overview_delete', 'c' => 1]); // Send the message, but disable the web preview! $tg_json[] = send_message($update['callback_query']['message']['chat']['id'], $msg, $keys, false, true); diff --git a/mods/overview_refresh.php b/mods/overview_refresh.php index bfad161c..5f90b9ab 100644 --- a/mods/overview_refresh.php +++ b/mods/overview_refresh.php @@ -10,8 +10,7 @@ //debug_log($data); // Get chat ID from data -$chat_id = 0; -$chat_id = $data['arg']; +$chat_id = $data['c'] ?? 0; // Get all or specific overview $query_chat = ''; @@ -77,14 +76,8 @@ $message_id = $update['callback_query']['message']['message_id']; $chat_id = $update['callback_query']['from']['id']; $keys[] = [ - [ - 'text' => EMOJI_REFRESH, - 'callback_data' => '0:overview_refresh:' . $overview_row['chat_id'] - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] + button(EMOJI_REFRESH, ['overview_refresh', 'c' => $overview_row['chat_id']]), + button(getTranslation('done'), ['exit', 'd' => '1']) ]; }else { $message_id = $overview_row['message_id']; diff --git a/mods/overview_share.php b/mods/overview_share.php index de95e044..9db31363 100644 --- a/mods/overview_share.php +++ b/mods/overview_share.php @@ -76,27 +76,14 @@ $keys = []; // Already shared if($rs->rowCount() > 0 ) { - $keys[] = [ - [ - 'text' => EMOJI_REFRESH, - 'callback_data' => '0:overview_refresh:' . $chat_id - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ]; + $keys[0][] = button(EMOJI_REFRESH, ['overview_refresh', 'c' => $chat_id]); + $keys[0][] = button(getTranslation('done'), ['exit', 'd' => '1']); $res = $rs->fetch(); $chat_title = $res['chat_title']; $chat_username = $res['chat_username']; }else { [$chat_title, $chat_username] = get_chat_title_username($chat_id); - $keys[] = [ - [ - 'text' => getTranslation('share_with') . ' ' . $chat_title, - 'callback_data' => formatCallbackData(['overview_share', 'c' => $chat_id]) - ] - ]; + $keys[][] = button(getTranslation('share_with') . ' ' . $chat_title, ['overview_share', 'c' => $chat_id]); } $overview_message = get_overview($active_raids[$chat_id], $chat_title, $chat_username); // Send the message, but disable the web preview! diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index 539e07ac..3a31968f 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -25,33 +25,18 @@ $keys = []; // All raid level keys. - $keys[][] = array( - 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => RAID_LEVEL_ALL]) - ); + $keys[][] = button(getTranslation('pokedex_all_raid_level'), ['pogoinfo', 'rl' => RAID_LEVEL_ALL]); // Add key for each raid level foreach($levels as $l) { - $keys[][] = array( - 'text' => getTranslation($l . 'stars'), - 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => $l]) - ); + $keys[][] = button(getTranslation($l . 'stars'), ['pogoinfo', 'rl' => $l]); } - $keys[][] = array( - 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), - 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => '1,3']) - ); + $keys[][] = button(getTranslation('1stars') . ' & ' . getTranslation('3stars'), ['pogoinfo', 'rl' => '1,3']); // Add back and abort buttons $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'pokedex_import' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + button(getTranslation('back'), 'pokedex_import'), + button(getTranslation('abort'), 'exit') ]; // Callback message string. @@ -185,13 +170,10 @@ $e = $exclusions; $e[] = $pokemon_arg; $keyAction = ($action == 's') ? - ['pokedex_edit_pokemon', 'id' => $dex_id . "-" . $dex_form, 'arg' => ''] : + ['pokedex_edit_pokemon', 'p' => $dex_id . "-" . $dex_form] : ['pogoinfo', 'rl' => $id, 'e' => implode('#', $e)]; // Add key - $keys[] = array( - 'text' => $keyText, - 'callback_data' => formatCallbackData($keyAction) - ); + $keys[] = button($keyText, $keyAction); } } $msg .= CR; @@ -206,7 +188,7 @@ $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; // Abort button. - $nav_keys = universal_key([], 0, 'exit', 0, getTranslation('done')); + $nav_keys[][] = button(getTranslation('abort'), 'exit'); // User is still on the import. } else { @@ -224,30 +206,18 @@ $nav_keys = []; // Back button. - $nav_keys[] = array( - 'text' => getTranslation('back'), - 'callback_data' => 'pogoinfo' - ); + $nav_keys[] = button(getTranslation('back'), 'pogoinfo'); // Save button. - $nav_keys[] = array( - 'text' => EMOJI_DISK, - 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]) - ); + $nav_keys[] = button(EMOJI_DISK, ['pogoinfo', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]); // Reset button. if(isset($exclusions[0])) { - $nav_keys[] = array( - 'text' => getTranslation('reset'), - 'callback_data' => formatCallbackData(['pogoinfo', 'rl' => $id]) - ); + $nav_keys[] = button(getTranslation('reset'), ['pogoinfo', 'rl' => $id]); } // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ); + $nav_keys[] = button(getTranslation('abort'), 'exit'); // Get the inline key array and merge keys. $nav_keys = inline_key_array($nav_keys, 2); diff --git a/mods/pokebattler.php b/mods/pokebattler.php index 1141bd8b..b4de2a9b 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -25,33 +25,18 @@ $keys = []; // All raid level keys. - $keys[][] = array( - 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => formatCallbackData(['pokebattler', 'rl' => implode(",", $pokebattler_levels)]) - ); + $keys[][] = button(getTranslation('pokedex_all_raid_level'), ['pokebattler', 'rl' => implode(",", $pokebattler_levels)]); // Add key for each raid level foreach($pokebattler_levels as $l) { - $keys[][] = array( - 'text' => getTranslation($l . 'stars'), - 'callback_data' => formatCallbackData(['pokebattler', 'rl' => $l]) - ); + $keys[][] = button(getTranslation($l . 'stars'), ['pokebattler', 'rl' => $l]); } - $keys[][] = array( - 'text' => getTranslation('1stars') . ' & ' . getTranslation('3stars'), - 'callback_data' => formatCallbackData(['pokebattler', 'rl' => '1,3']) - ); + $keys[][] = button(getTranslation('1stars') . ' & ' . getTranslation('3stars'), ['pokebattler', 'rl' => '1,3']); // Add back and abort buttons $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'pokedex_import' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + button(getTranslation('back'), 'pokedex_import'), + button(getTranslation('abort'), 'exit') ]; // Callback message string. $callback_response = 'OK'; @@ -194,7 +179,7 @@ // Add key to exclude pokemon from import. $button_text_prefix = ''; - if($id == implode(",", $pokebattler_levels)) { + if($id == implode(',', $pokebattler_levels)) { // Add raid level to pokemon name $button_text_prefix = '[' . ($raid_level_text) . ']'; } @@ -203,12 +188,9 @@ // Are 3 raid bosses already selected? if(count($exclusions) == 3) continue; $keyAction = ($action == 's') ? - ['pokedex_edit_pokemon', 'id' => $dex_id . "-" . $dex_form, 'arg' => ''] : + ['pokedex_edit_pokemon', 'p' => $dex_id . "-" . $dex_form] : ['pokebattler', 'rl' => $id, 'e' => implode('#', $e)]; - $keys[] = array( - 'text' => $button_text_prefix . SP . $local_pokemon, - 'callback_data' => formatCallbackData($keyAction) - ); + $keys[] = button($button_text_prefix . SP . $local_pokemon, $keyAction); } } $msg .= CR; @@ -223,7 +205,7 @@ $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; // Abort button. - $nav_keys = universal_key([], 0, 'exit', 0, getTranslation('done')); + $nav_keys[][] = button(getTranslation('done'), 'exit'); // User is still on the import. } else { @@ -241,36 +223,23 @@ $nav_keys = []; // Back button. - $nav_keys[] = array( - 'text' => getTranslation('back'), - 'callback_data' => 'pokebattler' - ); + $nav_keys[] = button(getTranslation('back'), 'pokebattler'); // Save button. - $nav_keys[] = array( - 'text' => EMOJI_DISK, - 'callback_data' => formatCallbackData(['pokebattler', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]) - ); + $nav_keys[] = button(EMOJI_DISK, ['pokebattler', 'rl' => $id, 'a' => 's', 'e' => implode('#', $exclusions)]); // Reset button. if(isset($exclusions[0])) { - $nav_keys[] = array( - 'text' => getTranslation('reset'), - 'callback_data' => formatCallbackData(['pokebattler', 'rl' => $id]) - ); + $nav_keys[] = button(getTranslation('reset'), ['pokebattler', 'rl' => $id]); } // Abort button. - $nav_keys[] = array( - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ); + $nav_keys[] = button(getTranslation('abort'), 'exit'); // Get the inline key array and merge keys. $nav_keys = inline_key_array($nav_keys, 2); } $keys = array_merge($keys, $nav_keys); - // Callback message string. $callback_response = 'OK'; diff --git a/mods/pokedex_disable_raids.php b/mods/pokedex_disable_raids.php index aa83290a..eb2d2e96 100644 --- a/mods/pokedex_disable_raids.php +++ b/mods/pokedex_disable_raids.php @@ -10,10 +10,10 @@ $botUser->accessCheck('pokedex'); // Get raid levels. -$id = $data['id']; +$id = $data['rl'] ?? 0; // Get argument. -$arg = $data['arg']; +$arg = $data['a'] ?? 0; // Specify raid levels. $levels = str_split(RAID_LEVEL_ALL); @@ -34,27 +34,15 @@ $keys = []; // All raid level keys. - $keys[] = array( - 'text' => getTranslation('pokedex_all_raid_level'), - 'callback_data' => RAID_LEVEL_ALL . ':pokedex_disable_raids:1' - ); + $keys[][] = button(getTranslation('pokedex_all_raid_level'), ['pokedex_disable_raids', 'rl' => RAID_LEVEL_ALL, 'a' => 1]); // Add key for each raid level foreach($levels as $l) { - $keys[] = array( - 'text' => getTranslation($l . 'stars'), - 'callback_data' => $l . ':pokedex_disable_raids:1' - ); + $keys[][] = button(getTranslation($l . 'stars'), ['pokedex_disable_raids', 'rl' => $l, 'a' => 1]); } // Add abort button - $keys[] = array( - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ); - - // Get the inline key array. - $keys = inline_key_array($keys, 1); + $keys[][] = button(getTranslation('abort'), 'exit'); // Confirmation to disable raid level } else if($arg == 1) { @@ -97,16 +85,10 @@ } // Disable. - $keys[] = array( - 'text' => getTranslation('yes'), - 'callback_data' => $id . ':pokedex_disable_raids:2' - ); + $keys[] = button(getTranslation('yes'), ['pokedex_disable_raids', 'rl' => $id, 'a' => 2]); // Abort. - $keys[] = array( - 'text' => getTranslation('no'), - 'callback_data' => 'exit' - ); + $keys[] = button(getTranslation('no'), 'exit'); // Inline keys array. $keys = inline_key_array($keys, 2); diff --git a/mods/pokedex_edit_pokemon.php b/mods/pokedex_edit_pokemon.php index 87dba22a..c65d796c 100644 --- a/mods/pokedex_edit_pokemon.php +++ b/mods/pokedex_edit_pokemon.php @@ -12,11 +12,8 @@ // Check access. $botUser->accessCheck('pokedex'); // Set the id. -$poke_id_form = $data['id']; -[$pokedex_id, $pokemon_form_id] = explode('-',$data['id'],2); - -// Set the arg. -$arg = $data['arg']; +$poke_id_form = $data['p']; +[$pokedex_id, $pokemon_form_id] = explode('-',$poke_id_form,2); // Set the message. $pokemon = get_pokemon_info($pokedex_id, $pokemon_form_id); @@ -29,69 +26,22 @@ $msg .= '' . getTranslation('pokedex_select_action') . ''; // Create keys array. -$keys = [ - [ - [ - 'text' => getTranslation('pokedex_raid_level'), - 'callback_data' => $poke_id_form . ':pokedex_set_raid_level:setlevel' - ] - ] -]; +$keys[][] = button(getTranslation('pokedex_raid_level'), ['pokedex_set_raid_level', 'p' => $poke_id_form]); // Raid-Egg? Hide specific options! if(!in_array($pokedex_id, $GLOBALS['eggs'])) { - $keys_cp_weather = [ - [ - [ - 'text' => getTranslation('pokedex_min_cp'), - 'callback_data' => $poke_id_form . ':pokedex_set_cp:min-20-add-0' - ] - ], - [ - [ - 'text' => getTranslation('pokedex_max_cp'), - 'callback_data' => $poke_id_form . ':pokedex_set_cp:max-20-add-0' - ] - ], - [ - [ - 'text' => getTranslation('pokedex_min_weather_cp'), - 'callback_data' => $poke_id_form . ':pokedex_set_cp:min-25-add-0' - ] - ], - [ - [ - 'text' => getTranslation('pokedex_max_weather_cp'), - 'callback_data' => $poke_id_form . ':pokedex_set_cp:max-25-add-0' - ] - ], - [ - [ - 'text' => getTranslation('pokedex_weather'), - 'callback_data' => $poke_id_form . ':pokedex_set_weather:add-0' - ] - ], - [ - [ - 'text' => getTranslation('shiny'), - 'callback_data' => $poke_id_form . ':pokedex_set_shiny:setshiny' - ] - ] - ]; - - $keys = array_merge($keys, $keys_cp_weather); + $keys[][] = button(getTranslation('pokedex_min_cp'), ['pokedex_set_cp', 'p' => $poke_id_form, 'a' => 'add', 'l' => 20, 't' => 'min']); + $keys[][] = button(getTranslation('pokedex_max_cp'), ['pokedex_set_cp', 'p' => $poke_id_form, 'a' => 'add', 'l' => 20, 't' => 'max']); + $keys[][] = button(getTranslation('pokedex_min_weather_cp'), ['pokedex_set_cp', 'p' => $poke_id_form, 'a' => 'add', 'l' => 25, 't' => 'min']); + $keys[][] = button(getTranslation('pokedex_max_weather_cp'), ['pokedex_set_cp', 'p' => $poke_id_form, 'a' => 'add', 'l' => 25, 't' => 'max']); + $keys[][] = button(getTranslation('pokedex_weather'), ['pokedex_set_weather', 'p' => $poke_id_form]); + $keys[][] = button(getTranslation('shiny'), ['pokedex_set_shiny', 'p' => $poke_id_form]); } // Back and abort. $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'pokedex' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + button(getTranslation('back'), 'pokedex'), + button(getTranslation('abort'), 'exit') ]; // Build callback message string. diff --git a/mods/pokedex_import.php b/mods/pokedex_import.php index d13ddb9e..f775e023 100644 --- a/mods/pokedex_import.php +++ b/mods/pokedex_import.php @@ -13,38 +13,11 @@ $msg.= 'ccev\'s github repository'.CR; $msg.= 'Pokebattler'; -$keys = [ - [ - [ - 'text' => getTranslation('import') . SP . '(Pokebattler)', - 'callback_data' => 'pokebattler' - ] - ], - [ - [ - 'text' => getTranslation('import') . SP . getTranslation('upcoming') . SP . '(Pokebattler)', - 'callback_data' => 'import_future_bosses' - ] - ], - [ - [ - 'text' => getTranslation('import') . SP . getTranslation('shiny') . SP . '(Pokebattler)', - 'callback_data' => 'import_shinyinfo' - ] - ], - [ - [ - 'text' => getTranslation('import') . SP . '(ccev pogoinfo)', - 'callback_data' => 'pogoinfo' - ] - ], - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ] - ]; +$keys[][] = button(getTranslation('import') . SP . '(Pokebattler)', 'pokebattler'); +$keys[][] = button(getTranslation('import') . SP . getTranslation('upcoming') . SP . '(Pokebattler)', 'import_future_bosses'); +$keys[][] = button(getTranslation('import') . SP . getTranslation('shiny') . SP . '(Pokebattler)', 'import_shinyinfo'); +$keys[][] = button(getTranslation('import') . SP . '(ccev pogoinfo)', 'pogoinfo'); +$keys[][] = button(getTranslation('abort'), 'exit'); // Callback message string. $callback_response = 'OK'; diff --git a/mods/pokedex_list_raids.php b/mods/pokedex_list_raids.php index d2fe6f4b..75cc3f6d 100644 --- a/mods/pokedex_list_raids.php +++ b/mods/pokedex_list_raids.php @@ -67,15 +67,12 @@ // Add button to edit pokemon. if($pokemon['scheduled'] == 1) { - $keys[] = array( - 'text' => EMOJI_CLOCK . ' [' . $pokemon['raid_level'] . ']' . SP . $poke_name, - 'callback_data' => formatCallbackData(['delete_scheduled_entry', 'i' => $pokemon['id']]) + $keys[] = button( + EMOJI_CLOCK . ' [' . $pokemon['raid_level'] . ']' . SP . $poke_name, + ['delete_scheduled_entry', 'i' => $pokemon['id']] ); } else { - $keys[] = array( - 'text' => '[' . $pokemon['raid_level'] . ']' . SP . $poke_name, - 'callback_data' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id'] . ':pokedex_edit_pokemon:0' - ); + $keys[] = button('[' . $pokemon['raid_level'] . ']' . SP . $poke_name, ['pokedex_edit_pokemon', 'p' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id']]); } // Prepare next run. @@ -91,12 +88,7 @@ $keys = inline_key_array($keys, 2); // Done key. - $keys[] = [ - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ]; + $keys[][] = button(getTranslation('done'), ['exit', 'd' => '1']); } else { // Set empty keys. $keys = []; diff --git a/mods/pokedex_set_cp.php b/mods/pokedex_set_cp.php index ccbcd869..b9feca5a 100644 --- a/mods/pokedex_set_cp.php +++ b/mods/pokedex_set_cp.php @@ -11,7 +11,7 @@ $botUser->accessCheck('pokedex'); // Set the id. -$pokedex_id = $data['id']; +$pokedex_id = $data['p']; // Split pokedex_id and form $dex_id_form = explode('-',$pokedex_id,2); @@ -19,17 +19,15 @@ $dex_form = $dex_id_form[1]; // Get the type, level and cp -$arg = $data['arg']; -$data = explode("-", $arg); -$cp_type = $data[0]; -$cp_level = $data[1]; -$cp_value = $data[3]; +$cp_type = $data['t']; +$cp_level = $data['l']; +$cp_value = $data['cp'] ?? 0; // Set boosted string $boosted = ($cp_level == 25) ? '_weather_cp' : '_cp'; // Action to do: Save or add digits to cp -$action = $data[2]; +$action = $data['a']; // Get current CP values $pokemon = get_pokemon_info($dex_id, $dex_form); @@ -48,18 +46,12 @@ $keys = []; // Get the keys. - $keys = cp_keys($pokedex_id, 'pokedex_set_cp', $arg); + $keys = cp_keys($data); // Back and abort. $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + button(getTranslation('back'), ['pokedex_edit_pokemon', 'p' => $pokedex_id]), + button(getTranslation('abort'), 'exit') ]; // Build callback message string. @@ -85,18 +77,8 @@ ); // Back to pokemon and done keys. - $keys = [ - [ - [ - 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] - ]; + $keys[0][0] = button(getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', ['pokedex_edit_pokemon', 'p' => $pokedex_id]); + $keys[0][1] = button(getTranslation('done') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', ['exit', 'd' => '1']); // Build callback message string. $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); @@ -119,17 +101,15 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); -function cp_keys($pokedex_id, $action, $arg) +function cp_keys($data) { // Get the type, level and cp - $data = explode("-", $arg); - $cp_type_level = $data[0] . '-' . $data[1]; - $cp_add = $data[0] . '-' . $data[1] . '-' . $data[2] . '-'; - $old_cp = $data[3]; + $old_cp = $data['cp'] ?? ''; // Save and reset values - $save_arg = $cp_type_level . '-save-' . $old_cp; - $reset_arg = $cp_add . '0'; + $saveData = $resetData = $data; + $saveData['a'] = 'save'; + unset($resetData['cp']); // Init empty keys array. $keys = []; @@ -138,7 +118,7 @@ function cp_keys($pokedex_id, $action, $arg) // Keys will be shown up to 999 and when user is adding one more number we exceed 999, so we remove the keys then // This means we do not exceed a Max CP of 9999 :) if($old_cp <= 999) { - + $buttonData = $data; // Add keys 0 to 9 /** * 7 8 9 @@ -150,36 +130,21 @@ function cp_keys($pokedex_id, $action, $arg) // 7 8 9 foreach ([7, 8, 9, 4, 5, 6, 1, 2, 3] as $i) { // Set new cp - $new_cp = $cp_add . ($old_cp == 0 ? '' : $old_cp) . $i; - + $buttonData['cp'] = $old_cp . $i; // Set keys. - $keys[] = array( - 'text' => $i, - 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_cp - ); + $keys[] = button($i, $buttonData); } // 0 - $new_cp = ($old_cp != 0) ? $cp_add . $old_cp . '0' : $reset_arg; - - // Set keys. - $keys[] = array( - 'text' => '0', - 'callback_data' => $pokedex_id . ':' . $action . ':' . $new_cp - ); + $buttonData['cp'] = $old_cp . '0'; + $keys[] = button('0', $buttonData); } // Save - $keys[] = array( - 'text' => EMOJI_DISK, - 'callback_data' => $pokedex_id . ':' . $action . ':' . $save_arg - ); + $keys[] = button(EMOJI_DISK, $saveData); // Reset - $keys[] = array( - 'text' => getTranslation('reset'), - 'callback_data' => $pokedex_id . ':' . $action . ':' . $reset_arg - ); + $keys[] = button(getTranslation('reset'), $resetData); // Get the inline key array. $keys = inline_key_array($keys, 3); diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index 1b46fde8..3540d1fa 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -11,10 +11,10 @@ $botUser->accessCheck('pokedex'); // Set the id. -$pokedex_id = $data['id']; +$pokedex_id = $data['p']; // Get the raid level. -$arg = $data['arg']; +$newLevel = $data['l'] ?? false; // Split pokedex_id and form $dex_id_form = explode('-',$pokedex_id,2); @@ -24,7 +24,7 @@ $pokemon = get_pokemon_info($dex_id, $dex_form); // Set raid level or show raid levels? -if($data['arg'] == 'setlevel') { +if($newLevel === false) { $raid_levels = str_split('0' . RAID_LEVEL_ALL); // Init empty keys array. @@ -32,24 +32,13 @@ // Create keys array. foreach($raid_levels as $lv) { - $keys[] = [ - array( - 'text' => getTranslation($lv . 'stars'), - 'callback_data' => $pokedex_id . ':pokedex_set_raid_level:' . $lv - ) - ]; + $keys[][] = button(getTranslation($lv . 'stars'), ['pokedex_set_raid_level', 'p' => $pokedex_id, 'l' => $lv]); } // Back and abort. $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + button(getTranslation('back'), ['pokedex_edit_pokemon', 'p' => $pokedex_id]), + button(getTranslation('abort'), 'exit') ]; // Build callback message string. @@ -68,26 +57,19 @@ AND scheduled = 0 ', [$dex_id, $dex_form] ); - if($arg != 0) { + if($newLevel != 0) { my_query(' INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) VALUES (?, ?, ?) - ',[$dex_id, $dex_form, $arg] + ', + [$dex_id, $dex_form, $newLevel] ); } // Back to pokemon and done keys. - $keys = [ - [ - [ - 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] + $keys[] = [ + button(getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', ['pokedex_edit_pokemon', 'p' => $pokedex_id]), + button(getTranslation('done'), ['exit', 'd' => '1']) ]; // Build callback message string. @@ -97,7 +79,7 @@ $msg = getTranslation('pokemon_saved') . CR; $msg .= '' . get_local_pokemon_name($dex_id, $dex_form) . ' (#' . $dex_id . ')' . CR . CR; $msg .= getTranslation('pokedex_new_raid_level') . ':' . CR; - $msg .= '' . getTranslation($arg . 'stars') . ''; + $msg .= '' . getTranslation($newLevel . 'stars') . ''; } // Telegram JSON array. diff --git a/mods/pokedex_set_shiny.php b/mods/pokedex_set_shiny.php index 8d421f08..adaeb604 100644 --- a/mods/pokedex_set_shiny.php +++ b/mods/pokedex_set_shiny.php @@ -11,10 +11,10 @@ $botUser->accessCheck('pokedex'); // Set the id. -$pokedex_id = $data['id']; +$pokedex_id = $data['p']; // Get the shiny status. -$arg = $data['arg']; +$arg = $data['s'] ?? 'setshiny'; // Split pokedex_id and form $dex_id_form = explode('-',$pokedex_id,2); @@ -22,7 +22,7 @@ $dex_form = $dex_id_form[1]; // Set shiny or ask to set? -if($data['arg'] == 'setshiny') { +if($arg == 'setshiny') { // Get current shiny status from database. $pokemon = get_pokemon_info($dex_id, $dex_form); @@ -31,24 +31,9 @@ $newShinyValue = ($pokemon['shiny'] == 0) ? 1 : 0; // Back and abort. - $keys = [ - [ - [ - 'text' => getTranslation($shinyText), - 'callback_data' => $pokedex_id . ':pokedex_set_shiny:' . $newShinyValue - ] - ], - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ] - ]; + $keys[][] = button(getTranslation($shinyText), ['pokedex_set_shiny', 'p' => $pokedex_id, 's' => $newShinyValue]); + $keys[][] = button(getTranslation('back'), ['pokedex_edit_pokemon', 'p' => $pokedex_id]); + $keys[][] = button(getTranslation('abort'), 'exit'); // Build callback message string. $callback_response = getTranslation('select_shiny_status'); @@ -68,18 +53,8 @@ ); // Back to pokemon and done keys. - $keys = [ - [ - [ - 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] - ]; + $keys[0][0] = button(getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', ['pokedex_edit_pokemon', 'p' => $pokedex_id]); + $keys[0][1] = button(getTranslation('done'), ['exit', 'd' => '1']); // Build callback message string. $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); diff --git a/mods/pokedex_set_weather.php b/mods/pokedex_set_weather.php index eebce178..dc803d60 100644 --- a/mods/pokedex_set_weather.php +++ b/mods/pokedex_set_weather.php @@ -13,7 +13,7 @@ $botUser->accessCheck('pokedex'); // Set the id. -$pokedex_id = $data['id']; +$pokedex_id = $data['p']; // Split pokedex_id and form $dex_id_form = explode('-',$pokedex_id,2); @@ -21,10 +21,8 @@ $dex_form = $dex_id_form[1]; // Get the action, old and new weather -$arg = $data['arg']; -$data = explode("-", $arg); -$action = $data[0]; -$new_weather = $data[1]; +$action = $data['a'] ?? 'add'; +$new_weather = $data['w'] ?? 0; $pokemon = get_pokemon_info($dex_id, $dex_form); $old_weather = $pokemon['weather']; @@ -40,21 +38,15 @@ if($action == 'add') { // Get the keys. - $keys = weather_keys($pokedex_id, 'pokedex_set_weather', $arg); + $keys = weather_keys($data); // Build callback message string. $callback_response = 'OK'; // Back and abort. $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] + button(getTranslation('back'), ['pokedex_edit_pokemon', 'p' => $pokedex_id]), + button(getTranslation('abort'), 'exit') ]; // Set the message. @@ -74,16 +66,8 @@ ); // Back to pokemon and done keys. - $keys[] = [ - [ - 'text' => getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', - 'callback_data' => $pokedex_id . ':pokedex_edit_pokemon:0' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ]; + $keys[0][0] = button(getTranslation('back') . ' (' . get_local_pokemon_name($dex_id, $dex_form) . ')', ['pokedex_edit_pokemon', 'p' => $pokedex_id]); + $keys[0][1] = button(getTranslation('abort'), ['exit', 'd' => '1']); // Build callback message string. $callback_response = getTranslation('pokemon_saved') . ' ' . get_local_pokemon_name($dex_id, $dex_form); diff --git a/mods/raid_by_location.php b/mods/raid_by_location.php index 2917bd32..84ed7bde 100644 --- a/mods/raid_by_location.php +++ b/mods/raid_by_location.php @@ -138,20 +138,8 @@ debug_log('Gym Name: ' . $gym_name); // Create the keys. -$keys = [ - [ - [ - 'text' => getTranslation('next'), - 'callback_data' => formatCallbackData(['edit_raidlevel', 'gl' => $gym_letter, 'g' => $gym_id, 'z' => 1]) - ] - ], - [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ] -]; +$keys[][] = button(getTranslation('next'), ['edit_raidlevel', 'gl' => $gym_letter, 'g' => $gym_id, 'z' => 1]); +$keys[][] = button(getTranslation('abort'), 'exit'); // Answer location message. if(isset($update['message']['location'])) { diff --git a/mods/raid_edit_poke.php b/mods/raid_edit_poke.php index c880e9a0..83b3c2af 100644 --- a/mods/raid_edit_poke.php +++ b/mods/raid_edit_poke.php @@ -23,20 +23,10 @@ // Get the keys. $keys = pokemon_keys($data, $raid_level, 'raid_set_poke'); - $keys[][] = [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ]; + $keys[][] = button(getTranslation('abort'), 'exit'); } else { // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('not_supported'), - 'callback_data' => 'exit' - ] - ] - ]; + $keys[][] = button(getTranslation('not_supported'), 'exit'); } // Build callback message string. diff --git a/mods/raid_share.php b/mods/raid_share.php index f15fa519..5240f53a 100644 --- a/mods/raid_share.php +++ b/mods/raid_share.php @@ -8,13 +8,13 @@ //debug_log($data); // Get raid id. -$raidId = $data['id']; +$raidId = $data['r']; // Access check. $botUser->raidaccessCheck($raidId, 'share'); // Get chat id. -$chat = $data['arg']; +$chat = $data['c']; $tg_json = send_raid_poll($raidId, $chat); diff --git a/mods/raids_delete.php b/mods/raids_delete.php index 89159900..e422c280 100644 --- a/mods/raids_delete.php +++ b/mods/raids_delete.php @@ -29,18 +29,8 @@ debug_log($raid); // Create keys array. - $keys = [ - [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id'], 'a' => 2]) - ], - [ - 'text' => getTranslation('no'), - 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id'], 'a' => 1]) - ] - ] - ]; + $keys[0][0] = button(getTranslation('yes'), ['raids_delete', 'r' => $raid['id'], 'a' => 2]); + $keys[0][1] = button(getTranslation('no'), ['raids_delete', 'r' => $raid['id'], 'a' => 1]); // Set message. $msg = EMOJI_WARN . ' ' . getTranslation('delete_this_raid') . ' ' . EMOJI_WARN . CR . CR; diff --git a/mods/raids_list.php b/mods/raids_list.php index 493afa6f..ce4dddb7 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -17,29 +17,12 @@ $raid = get_raid($raidId); // Create keys array. -$keys = [ - [ - [ - 'text' => getTranslation('expand'), - 'callback_data' => $raid['id'] . ':vote_refresh:0', - ] - ] -]; +$keys[][] = button(getTranslation('expand'), ['vote_refresh', 'r' => $raid['id']]); if($botUser->raidaccessCheck($raidId, 'pokemon', true)) { - $keys[] = [ - [ - 'text' => getTranslation('update_pokemon'), - 'callback_data' => formatCallbackData(['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]), - ] - ]; + $keys[][] = button(getTranslation('update_pokemon'), ['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]); } if($botUser->raidaccessCheck($raidId, 'delete', true)) { - $keys[] = [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid['id']]) - ] - ]; + $keys[][] = button(getTranslation('delete'), ['raids_delete', 'r' => $raid['id']]); } // Add keys to share. @@ -51,10 +34,7 @@ debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key -$keys[][] = [ - 'text' => getTranslation('done'), - 'callback_data' => 'exit' -]; +$keys[][] = button(getTranslation('done'), 'exit'); // Get message. $msg = show_raid_poll_small($raid); diff --git a/mods/save_event_note.php b/mods/save_event_note.php index 814181b8..34adc0a8 100644 --- a/mods/save_event_note.php +++ b/mods/save_event_note.php @@ -9,8 +9,7 @@ $user_id = $update['message']['from']['id']; // Update the event note to raid table -$query = $dbh->prepare("UPDATE raids SET event_note=:text WHERE id = :id"); -$query->execute([':text' => $update['message']['text'], ':id' => $raid_id]); +my_query('UPDATE raids SET event_note=:text WHERE id = :id', [':text' => $update['message']['text'], ':id' => $raid_id]); // Remove back button from previous message to avoid confusion edit_message_keyboard($modifiers['old_message_id'], [], $user_id); @@ -23,20 +22,8 @@ $msg .= show_raid_poll_small($raid) . CR; debug_log($msg); -$keys = [ - [ - [ - 'text' => getTranslation('event_note_edit'), - 'callback_data' => $raid_id . ':edit_event_note:edit' - ] - ], - [ - [ - 'text' => getTranslation('delete'), - 'callback_data' => formatCallbackData(['raids_delete', 'r' => $raid_id]) - ] - ] -]; +$keys[][] = button(getTranslation('event_note_edit'), ['edit_event_note', 'r' => $raid_id, 'm' => 'e']); +$keys[][] = button(getTranslation('delete'), ['raids_delete', 'r' => $raid_id]); $keys_share = share_keys($raid_id, 'raid_share', $update, $raid['level']); $keys = array_merge($keys, $keys_share); debug_log($keys); diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 7c6d4813..6549c583 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -11,8 +11,8 @@ // Check access. $botUser->accessCheck('share-all'); -if(isset($data['arg']) && $data['arg'] == 1) { - $raid_id = $data['id']; +if(isset($data['a']) && $data['a'] == 1) { + $raid_id = $data['r']; // Get raid details. $raid = get_raid($raid_id); @@ -28,10 +28,7 @@ debug_log('There are no groups to share to, is SHARE_CHATS set?'); } // Exit key - $keys[][] = [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => 1]) -]; + $keys[][] = button(getTranslation('done'), ['exit', 'd' => 1]); // Get message. $msg = show_raid_poll_small($raid); @@ -50,104 +47,95 @@ // Telegram multicurl request. curl_json_multi_request($tg_json); - -}else { - if(!isset($update['message']['location'])) { - send_message($update['message']['chat']['id'], '' . getTranslation('invalid_input') . ''); - exit(); + exit; +} +if(!isset($update['message']['location'])) { + send_message($update['message']['chat']['id'], '' . getTranslation('invalid_input') . ''); + exit(); +} +$lat = (float)$update['message']['location']['latitude']; +$lon = (float)$update['message']['location']['longitude']; +$gps_diff = (float)0.01; + +// Build query. +$rs = my_query(' + SELECT raids.*, + gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, + users.name, + TIME_FORMAT(TIMEDIFF(raids.end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left + FROM raids + LEFT JOIN gyms + ON raids.gym_id = gyms.id + LEFT JOIN users + ON raids.user_id = users.user_id + WHERE raids.end_time>UTC_TIMESTAMP() + AND gyms.lat BETWEEN \''.($lat-$gps_diff).'\' AND \''.($lat+$gps_diff).'\' + AND gyms.lon BETWEEN \''.($lon-$gps_diff).'\' AND \''.($lon+$gps_diff).'\' + ORDER BY raids.end_time ASC LIMIT 20 +'); + +// Count results. +$count = 0; + +// Init text and keys. +$text = ''; +$keys = []; + +// Get raids. +while ($raid = $rs->fetch()) { + // Set text and keys. + $gym_name = $raid['gym_name']; + if(empty($gym_name)) { + $gym_name = ''; } - $lat = (float)$update['message']['location']['latitude']; - $lon = (float)$update['message']['location']['longitude']; - $gps_diff = (float)0.01; - - // Build query. - $rs = my_query(' - SELECT raids.*, - gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, - users.name, - TIME_FORMAT(TIMEDIFF(raids.end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left - FROM raids - LEFT JOIN gyms - ON raids.gym_id = gyms.id - LEFT JOIN users - ON raids.user_id = users.user_id - WHERE raids.end_time>UTC_TIMESTAMP() - AND gyms.lat BETWEEN \''.($lat-$gps_diff).'\' AND \''.($lat+$gps_diff).'\' - AND gyms.lon BETWEEN \''.($lon-$gps_diff).'\' AND \''.($lon+$gps_diff).'\' - ORDER BY raids.end_time ASC LIMIT 20 - '); - - // Count results. - $count = 0; - - // Init text and keys. - $text = ''; - $keys = []; - // Get raids. - while ($raid = $rs->fetch()) { - // Set text and keys. - $gym_name = $raid['gym_name']; - if(empty($gym_name)) { - $gym_name = ''; - } - - $text .= $gym_name . CR; - $raid_day = dt2date($raid['start_time']); - $now = utcnow(); - $today = dt2date($now); - $start = dt2time($raid['start_time']); - $end = dt2time($raid['end_time']); - $time_left = $raid['t_left']; - if ($now < $start) { - $text .= get_raid_times($raid, true); - // Raid has started already - } else { - // Add time left message. - $text .= get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ' — ' . getPublicTranslation('still') . SP . $time_left . 'h' . CR . CR; - } - - // Split pokemon and form to get the pokedex id. - $pokedex_id = explode('-', $raid['pokemon'])[0]; - - // Pokemon is an egg? - $eggs = $GLOBALS['eggs']; - if(in_array($pokedex_id, $eggs)) { - $keys_text = EMOJI_EGG . SP . $gym_name; - } else { - $keys_text = $gym_name; - } - - $keys[] = array( - 'text' => $keys_text, - 'callback_data' => $raid['id'] . ':share_raid_by_location:1' - ); - - // Counter++ - $count = $count + 1; + $text .= $gym_name . CR; + $raid_day = dt2date($raid['start_time']); + $now = utcnow(); + $today = dt2date($now); + $start = dt2time($raid['start_time']); + $end = dt2time($raid['end_time']); + $time_left = $raid['t_left']; + if ($now < $start) { + $text .= get_raid_times($raid, true); + // Raid has started already + } else { + // Add time left message. + $text .= get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ' — ' . getPublicTranslation('still') . SP . $time_left . 'h' . CR . CR; } - // Set message. - if($count == 0) { - $msg = '' . getTranslation('no_active_raids_found') . ''; + // Split pokemon and form to get the pokedex id. + $pokedex_id = explode('-', $raid['pokemon'])[0]; + + // Pokemon is an egg? + $eggs = $GLOBALS['eggs']; + if(in_array($pokedex_id, $eggs)) { + $keys_text = EMOJI_EGG . SP . $gym_name; } else { - // Get the inline key array. - $keys = inline_key_array($keys, 1); - - // Add exit key. - $keys[] = [ - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ]; - - // Build message. - $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; - $msg .= $text; - $msg .= '' . getTranslation('select_gym_name') . '' . CR; + $keys_text = $gym_name; } - // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + $keys[] = button($keys_text, ['share_raid_by_location', 'r' => $raid['id'], 'a' => 1]); + + // Counter++ + $count = $count + 1; +} + +// Set message. +if($count == 0) { + $msg = '' . getTranslation('no_active_raids_found') . ''; +} else { + // Get the inline key array. + $keys = inline_key_array($keys, 1); + + // Add exit key. + $keys[][] = button(getTranslation('abort'), 'exit'); + + // Build message. + $msg = '' . getTranslation('list_all_active_raids') . ':' . CR; + $msg .= $text; + $msg .= '' . getTranslation('select_gym_name') . '' . CR; } + +// Send message. +send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/mods/trainer.php b/mods/trainer.php index c1e81bfc..2db8f149 100644 --- a/mods/trainer.php +++ b/mods/trainer.php @@ -24,62 +24,36 @@ $keys = []; // Create keys array. if($config->CUSTOM_TRAINERNAME) { - $keys[0][] = - [ - 'text' => getTranslation('name'), - 'callback_data' => 'trainer_name' - ]; + $keys[0][] = button(getTranslation('name'), 'trainer_name'); } if($config->RAID_POLL_SHOW_TRAINERCODE) { - $keys[0][] = - [ - 'text' => getTranslation('trainercode'), - 'callback_data' => 'trainer_code' - ]; + $keys[0][] = button(getTranslation('trainercode'), 'trainer_code'); } $keys[] = [ - [ - 'text' => getTranslation('team'), - 'callback_data' => 'trainer_team' - ], - [ - 'text' => getTranslation('level'), - 'callback_data' => 'trainer_level' - ] + button(getTranslation('team'), 'trainer_team'), + button(getTranslation('level'), 'trainer_level') ]; if($config->RAID_AUTOMATIC_ALARM == false) { $q_user = my_query('SELECT auto_alarm FROM users WHERE user_id = ? LIMIT 1', [$user_id]); $alarm_status = $q_user->fetch()['auto_alarm']; - $keys[] = [ - [ - 'text' => ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), - 'callback_data' => formatCallbackData(['trainer', 'a' => 1]) - ] - ]; + $keys[][] = button( + ($alarm_status == 1 ? getTranslation('switch_alarm_off') . ' ' . EMOJI_NO_ALARM : getTranslation('switch_alarm_on') . ' ' . EMOJI_ALARM), + ['trainer', 'a' => 1] + ); } if($config->LANGUAGE_PRIVATE == '') { - $keys[] = [ - [ - 'text' => getTranslation('bot_lang'), - 'callback_data' => 'bot_lang' - ] - ]; + $keys[][] = button(getTranslation('bot_lang'), 'bot_lang'); } if ($config->ENABLE_GYM_AREAS == true) { - $keys[] = [ - [ - 'text' => getTranslation('default_gymarea'), - 'callback_data' => 'trainerGymarea' - ] - ]; + $keys[][] = button(getTranslation('default_gymarea'), 'trainerGymarea'); } // Display sharing options for admins and users with trainer-share permissions if($botUser->accessCheck('trainer-share', true)) { // Add sharing keys. $share_keys = []; - $share_keys[] = universal_inner_key($keys, '0', 'trainer_add', '0', getTranslation('trainer_message_share')); - $share_keys[] = universal_inner_key($keys, '0', 'trainer_delete', '0', getTranslation('trainer_message_delete')); + $share_keys[] = button(getTranslation('trainer_message_share'), 'trainer_add'); + $share_keys[] = button(getTranslation('trainer_message_delete'), 'trainer_delete'); // Get the inline key array. $keys[] = $share_keys; @@ -89,10 +63,7 @@ } // Get the inline key array. -$keys[][] = [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => 1]) -]; +$keys[][] = button(getTranslation('done'), ['exit', 'd' => 1]); // Answer callback. answerCallbackQuery($update['callback_query']['id'], 'OK'); diff --git a/mods/trainerGymarea.php b/mods/trainerGymarea.php index b02503ff..7a1cbc3e 100644 --- a/mods/trainerGymarea.php +++ b/mods/trainerGymarea.php @@ -26,21 +26,13 @@ $gymareaName = ''; foreach($json as $area) { if($area['id'] == $gymarea) $gymareaName = $area['name']; - $keys[] = [ - 'text' => $area['name'], - 'callback_data' => formatCallbackData(['trainerGymarea', 'i' => $area['id']]) - ]; + $keys[] = button($area['name'], ['trainerGymarea', 'i' => $area['id']]); + } $keys = inline_key_array($keys, 2); $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['trainer', 'arg' => 0]) - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => 1]) - ] + button(getTranslation('back'), ['trainer', 'arg' => 0]), + button(getTranslation('done'), ['exit', 'd' => 1]) ]; // Set message. $msg = '' . getTranslation('trainerinfo_set_yours') . ''; diff --git a/mods/trainer_add.php b/mods/trainer_add.php index d6c81e3f..d335bc01 100644 --- a/mods/trainer_add.php +++ b/mods/trainer_add.php @@ -74,20 +74,19 @@ debug_log($log_chats_db, 'Chats already having the trainer message:'); $chats = array_diff($chats, $chats_db); -$chats = implode(',', $chats); -debug_log($chats, 'Chat list without duplicates:'); +debug_log(implode(',', $chats), 'Chat list without duplicates:'); // Create keys. if(!empty($chats)) { - $keys = share_keys('0', 'trainer_share', $update, '', $chats, true); + $keys = share_keys(false, 'trainer_share', $update, '', $chats, true); } // Add abort key. if($keys) { // Add back navigation key. $nav_keys = []; - $nav_keys[] = universal_inner_key($keys, '0', 'trainer', '0', getTranslation('back')); - $nav_keys[] = universal_inner_key($keys, '0', 'exit', '0', getTranslation('abort')); + $nav_keys[] = button(getTranslation('back'), 'trainer'); + $nav_keys[] = button(getTranslation('abort'), 'exit'); // Get the inline key array. $keys[] = $nav_keys; diff --git a/mods/trainer_code.php b/mods/trainer_code.php index 9a0380dd..2d3a7acf 100644 --- a/mods/trainer_code.php +++ b/mods/trainer_code.php @@ -57,13 +57,8 @@ $callback_response = 'OK'; $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['trainer_code', 'a' => 'cancel']) - ],[ - 'text' => getTranslation('delete'), - 'callback_data' => formatCallbackData(['trainer_code', 'a' => 'delete']) - ] + button(getTranslation('back'), ['trainer_code', 'a' => 'cancel']), + button(getTranslation('delete'), ['trainer_code', 'a' => 'delete']) ]; // Answer callback. answerCallbackQuery($update['callback_query']['id'], $callback_response); diff --git a/mods/trainer_delete.php b/mods/trainer_delete.php index a34a7ce0..383f8b7c 100644 --- a/mods/trainer_delete.php +++ b/mods/trainer_delete.php @@ -14,8 +14,8 @@ $keys = []; // Get chat id and action -$trainer_chat = $data['id']; -$action = $data['arg']; +$trainer_chat = $data['c'] ?? 0; +$action = $data['a'] ?? 0; // Show chats to delete if($action == 0 || $trainer_chat == 0) { @@ -30,7 +30,7 @@ $chat_id = $row['chat_id']; [$chat_title, $chat_username] = get_chat_title_username($chat_id); - $keys[] = universal_inner_key($keys, $chat_id, 'trainer_delete', '1', $chat_title); + $keys[] = button($chat_title, ['trainer_delete', 'c' => $chat_id, 'a' => 1]); } // Add abort key. @@ -40,8 +40,8 @@ // Add back navigation key. $nav_keys = []; - $nav_keys[] = universal_inner_key($keys, '0', 'trainer', '0', getTranslation('back')); - $nav_keys[] = universal_inner_key($keys, '0', 'exit', '0', getTranslation('abort')); + $nav_keys[] = button(getTranslation('back'), 'trainer'); + $nav_keys[] = button(getTranslation('abort'), 'exit'); // Get the inline key array. $keys[] = $nav_keys; @@ -62,20 +62,8 @@ $msg .= EMOJI_WARN . SP . '' . getTranslation('delete_trainer_message_from_chat') . '' . SP . EMOJI_WARN; // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => $trainer_chat . ':trainer_delete:2' - ] - ], - [ - [ - 'text' => getTranslation('no'), - 'callback_data' => 'exit' - ] - ] - ]; + $keys[][] = button(getTranslation('yes'), ['trainer_delete', 'c' => $trainer_chat, 'a' => 2]); + $keys[][] = button(getTranslation('no'), 'exit'); // Delete trainer message } else if($action == 2 && $trainer_chat != 0) { diff --git a/mods/trainer_level.php b/mods/trainer_level.php index 8ef8be0c..6c89f32b 100644 --- a/mods/trainer_level.php +++ b/mods/trainer_level.php @@ -25,10 +25,7 @@ // Set keys. $keys = []; for($i = 5; $i <= $config->TRAINER_MAX_LEVEL; $i++) { - $keys[] = [ - 'text' => $i, - 'callback_data' => formatCallbackData(['trainer_level', 'l' => $i]) - ]; + $keys[] = button($i, ['trainer_level', 'l' => $i]); } // Get the inline key array. @@ -36,14 +33,8 @@ // Add navigation keys. $keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'trainer' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] + button(getTranslation('back'), 'trainer'), + button(getTranslation('done'), ['exit', 'd' => '1']) ]; // Build callback message string. @@ -69,17 +60,9 @@ $callback_response = 'OK'; // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'trainer' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] + $keys[] = [ + button(getTranslation('back'), 'trainer'), + button(getTranslation('done'), ['exit', 'd' => '1']) ]; } diff --git a/mods/trainer_name.php b/mods/trainer_name.php index 05c1df12..75b23bac 100644 --- a/mods/trainer_name.php +++ b/mods/trainer_name.php @@ -67,38 +67,18 @@ $callback_response = 'OK'; if($action != 'add') { if(!empty($user_data['row']['trainername'])) { + $keys[][] = button(getTranslation('switch_display_name'), ['trainer_name', 'a' => 'switch']); $keys[] = [ - [ - 'text' => getTranslation('switch_display_name'), - 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'switch']) - ] - ]; - $keys[] = [ - [ - 'text' => getTranslation('trainername_edit'), - 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'add']) - ],[ - 'text' => getTranslation('delete'), - 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'delete']) - ] - ]; + button(getTranslation('trainername_edit'), ['trainer_name', 'a' => 'add']), + button(getTranslation('delete'), ['trainer_name', 'a' => 'delete']) + ]; }else { - $keys[] = [ - [ - 'text' => getTranslation('trainername_add'), - 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'add']) - ] - ]; + $keys[][] = button(getTranslation('trainername_add'), ['trainer_name', 'a' => 'add']); } } -$keys[] = [ - [ - 'text' => getTranslation('back'), - 'callback_data' => formatCallbackData(['trainer_name', 'a' => 'cancel']) - ] -]; +$keys[][] = button(getTranslation('back'), ['trainer_name', 'a' => 'cancel']); - // Answer callback. +// Answer callback. answerCallbackQuery($update['callback_query']['id'], $callback_response); // Edit message. diff --git a/mods/trainer_share.php b/mods/trainer_share.php index 0913c70b..0f4d3156 100644 --- a/mods/trainer_share.php +++ b/mods/trainer_share.php @@ -12,7 +12,7 @@ $botUser->accessCheck('trainer-share'); // Get chat id. -$chat = $data['arg']; +$chat = $data['c']; // Get text and keys. $text = show_trainerinfo($update); diff --git a/mods/trainer_team.php b/mods/trainer_team.php index acbea422..638d82f5 100644 --- a/mods/trainer_team.php +++ b/mods/trainer_team.php @@ -20,32 +20,11 @@ if($team == '') { // Set keys. - $keys = [ - [ - [ - 'text' => TEAM_B, - 'callback_data' => formatCallbackData(['trainer_team', 't' => 'mystic']) - ], - [ - 'text' => TEAM_R, - 'callback_data' => formatCallbackData(['trainer_team', 't' => 'valor']) - ], - [ - 'text' => TEAM_Y, - 'callback_data' => formatCallbackData(['trainer_team', 't' => 'instinct']) - ] - ], - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'trainer' - ], - [ - 'text' => getTranslation('abort'), - 'callback_data' => 'exit' - ] - ] - ]; + $keys[0][0] = button(TEAM_B, ['trainer_team', 't' => 'mystic']); + $keys[0][1] = button(TEAM_R, ['trainer_team', 't' => 'valor']); + $keys[0][2] = button(TEAM_Y, ['trainer_team', 't' => 'instinct']); + $keys[1][0] = button(getTranslation('back'), 'trainer'); + $keys[1][1] = button(getTranslation('abort'), 'exit'); // Build message string. $msg = '' . getTranslation('your_trainer_info') . '' . CR; @@ -74,19 +53,8 @@ $callback_response = 'OK'; // Create the keys. - $keys = [ - [ - [ - 'text' => getTranslation('back'), - 'callback_data' => 'trainer' - ], - [ - 'text' => getTranslation('done'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] - ]; - + $keys[0][0] = button(getTranslation('back'), 'trainer'); + $keys[0][1] = button(getTranslation('done'), ['exit', 'd' => '1']); } // Answer callback. diff --git a/mods/tutorial.php b/mods/tutorial.php index 23abf92f..8bb16999 100644 --- a/mods/tutorial.php +++ b/mods/tutorial.php @@ -13,32 +13,31 @@ if(is_file(ROOT_PATH . '/config/tutorial.php')) { require_once(ROOT_PATH . '/config/tutorial.php'); } -$action = $data['arg']; +$action = $data['p']; $user_id = $update['callback_query']['from']['id']; $new_user = new_user($user_id); $tutorial_count = count($tutorial); if($action == 'end') { - answerCallbackQuery($update['callback_query']['id'], "OK!"); + answerCallbackQuery($update['callback_query']['id'], 'OK!'); delete_message($update['callback_query']['message']['chat']['id'],$update['callback_query']['message']['message_id']); if($new_user) { - my_query('UPDATE users SET tutorial = ? WHERE user_id = ?', [$data['id'], $user_id]); - + my_query('UPDATE users SET tutorial = ? WHERE user_id = ?', [$data['l'], $user_id]); send_message($user_id, $tutorial_done, []); // Post the user id to external address if specified - if(isset($config->TUTORIAL_COMPLETED_CURL_ADDRESS) && $config->TUTORIAL_COMPLETED_CURL_ADDRESS != "") { + if(isset($config->TUTORIAL_COMPLETED_CURL_ADDRESS) && $config->TUTORIAL_COMPLETED_CURL_ADDRESS != '') { $post_array = [ - 'tutorial' => 'OK', - 'user_id' => $user_id - ]; + 'tutorial' => 'OK', + 'user_id' => $user_id + ]; $json = json_encode($post_array); $URL = $config->TUTORIAL_COMPLETED_CURL_ADDRESS; $curl = curl_init($URL); curl_setopt($curl, CURLOPT_HEADER, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json")); + curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-type: application/json')); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $json); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); @@ -56,29 +55,15 @@ curl_close($curl); } } - - $q = my_query('SELECT level, team FROM users WHERE user_id = ? LIMIT 1', [$user_id]); $row = $q->fetch(); - if($row['level'] == 0 or $row['team'] == '' or $row['team'] == NULL) { $msg = getTranslation('tutorial_no_user_info_set'); - $keys = [ - [ - [ - 'text' => getTranslation('yes'), - 'callback_data' => 'trainer' - ], - [ - 'text' => getTranslation('no'), - 'callback_data' => formatCallbackData(['exit', 'd' => '1']) - ] - ] - ]; + $keys[0][0] = button(getTranslation('yes'), 'trainer'); + $keys[0][1] = button(getTranslation('no'), ['exit', 'd' => '1']); send_message($user_id,$msg,$keys); } exit(); - } if($new_user && isset($tutorial[($action)]['msg_new'])) { @@ -89,25 +74,12 @@ $photo = $tutorial[$action]['photo']; $keys = []; if($action > 0) { - $keys = [ - [ - [ - 'text' => getTranslation("back") . " (".($action)."/".($tutorial_count).")", - 'callback_data' => "0:tutorial:".($action-1) - ] - ] - ]; + $keys[0][] = button(getTranslation('back') . ' ('.($action).'/'.($tutorial_count).')', ['tutorial', 'p' => $action-1]); } if($action < ($tutorial_count - 1)) { - $keys[0][] = [ - 'text' => getTranslation("next") . " (".($action+2)."/".($tutorial_count).")", - 'callback_data' => "0:tutorial:".($action+1) - ]; + $keys[0][] = button(getTranslation('next') . ' ('.($action+2).'/'.($tutorial_count).')', ['tutorial', 'p' => $action+1]); }else { - $keys[0][] = [ - 'text' => getTranslation("done"), - 'callback_data' => $tutorial_grant_level . ":tutorial:end" - ]; + $keys[0][] = button(getTranslation('done'), ['tutorial', 'p' => 'end', 'l' => $tutorial_grant_level]); } -answerCallbackQuery($update['callback_query']['id'], "OK!"); +answerCallbackQuery($update['callback_query']['id'], 'OK!'); editMessageMedia($update['callback_query']['message']['message_id'], $msg, $photo, false, $keys, $update['callback_query']['message']['chat']['id'], ['disable_web_page_preview' => 'true']); diff --git a/mods/update_bosses.php b/mods/update_bosses.php index da3546d8..c0ef3e32 100644 --- a/mods/update_bosses.php +++ b/mods/update_bosses.php @@ -64,7 +64,6 @@ exit(); } $count = count($add_mons); -$start = false; $sql_values = ''; if($count == 0) exit; diff --git a/mods/vote_can_invite.php b/mods/vote_can_invite.php index e8944f8c..f67d560f 100644 --- a/mods/vote_can_invite.php +++ b/mods/vote_can_invite.php @@ -8,7 +8,7 @@ //debug_log($update); //debug_log($data); -$raidId = $data['id']; +$raidId = $data['r']; $query_select = my_query(' SELECT can_invite, CASE WHEN cancel = 1 or raid_done = 1 THEN 1 ELSE 0 END as cancelOrDone diff --git a/mods/vote_extra.php b/mods/vote_extra.php index 5388c7d7..4b9c463b 100644 --- a/mods/vote_extra.php +++ b/mods/vote_extra.php @@ -10,7 +10,8 @@ //debug_log($update); //debug_log($data); -$raidId = $data['id']; +$raidId = $data['r']; +$act = $data['a'] ?? 0; // Check if the user has voted for this raid before and check if they are attending remotely. $rs = my_query(' @@ -42,7 +43,7 @@ exit; } -if($data['arg'] == '0') { +if($act == '0') { // Reset team extra people. my_query(' UPDATE attendance @@ -56,7 +57,7 @@ 'userId' => $update['callback_query']['from']['id'], ] ); - $tg_json = alarm($raidId, $update['callback_query']['from']['id'], 'extra_alone', $data['arg'], $tg_json); + $tg_json = alarm($raidId, $update['callback_query']['from']['id'], 'extra_alone', $act, $tg_json); } else if($answer['can_invite'] == 1 ) { // People who are only inviting others can't add extras $msg = getTranslation('vote_status_not_allowed'); @@ -70,19 +71,19 @@ $remote_users = get_remote_users_count($raidId, $update['callback_query']['from']['id']); // Skip remote user limit check if user is not attending remotely. // If they are, check if attend time already has max number of remote users. - if (($answer['remote'] == 1 or $data['arg'] == 'alien') && ($remote_users >= $config->RAID_REMOTEPASS_USERS_LIMIT or $answer['user_count'] >= $config->RAID_REMOTEPASS_USERS_LIMIT)) { + if (($answer['remote'] == 1 or $act == 'alien') && ($remote_users >= $config->RAID_REMOTEPASS_USERS_LIMIT or $answer['user_count'] >= $config->RAID_REMOTEPASS_USERS_LIMIT)) { // Send max remote users reached. send_vote_remote_users_limit_reached($update); exit; } // Force invite beggars to user extra_in_person even if they vote +alien - if($answer['want_invite'] == 1 && $data['arg'] == 'alien') $data['arg'] = 'in_person'; + if($answer['want_invite'] == 1 && $act == 'alien') $act = 'in_person'; - if(!in_array($data['arg'], ['in_person', 'alien'])) { - error_log('Invalid vote variable: ' . $data['arg']); + if(!in_array($act, ['in_person', 'alien'])) { + error_log('Invalid vote variable: ' . $act); exit; } - $team = 'extra_' . $data['arg']; + $team = 'extra_' . $act; // Increase team extra people. my_query(' UPDATE attendance @@ -95,7 +96,7 @@ 'userId' => $update['callback_query']['from']['id'], ] ); - $tg_json = alarm($raidId, $update['callback_query']['from']['id'], 'extra', $data['arg'], $tg_json); + $tg_json = alarm($raidId, $update['callback_query']['from']['id'], 'extra', $act, $tg_json); } // Send vote response. diff --git a/mods/vote_invite.php b/mods/vote_invite.php index c8c221f2..c0dc0392 100644 --- a/mods/vote_invite.php +++ b/mods/vote_invite.php @@ -15,13 +15,13 @@ END WHERE raid_id = ? AND user_id = ? - ', [$data['id'], $update['callback_query']['from']['id']] + ', [$data['r'], $update['callback_query']['from']['id']] ); // Send vote response. require_once(LOGIC_PATH . '/update_raid_poll.php'); -$tg_json = update_raid_poll($data['id'], false, $update); +$tg_json = update_raid_poll($data['r'], false, $update); $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); diff --git a/mods/vote_level.php b/mods/vote_level.php index 6defb5ec..cd923c93 100644 --- a/mods/vote_level.php +++ b/mods/vote_level.php @@ -8,13 +8,14 @@ //debug_log($data); // Get action. -$action = $data['arg']; +$action = $data['a'] ?? ''; +$show = $data['s'] ?? ''; +$level = $data['l'] ?? ''; // Up-vote. -if ($action == 'up') { +if ($level == 'up') { // Increase users level. - my_query( - ' + my_query(' UPDATE users SET level = IF(level = 0, 30, level+1) WHERE user_id = ? @@ -24,10 +25,9 @@ } // Down-vote. -if ($action == 'down') { +if ($level == 'down') { // Decrease users level. - my_query( - ' + my_query(' UPDATE users SET level = level-1 WHERE user_id = ? @@ -37,22 +37,20 @@ } // Message coming from raid or trainer info? -if($data['id'] == 'trainer') { - if($action == 'hide') { +if($action == 'trainer') { + if($show == 'hide') { // Send trainer info update. send_trainerinfo($update, false); } // Send trainer info update. send_trainerinfo($update, true); + exit; } // Send vote response. require_once(LOGIC_PATH . '/update_raid_poll.php'); -$tg_json = update_raid_poll($data['id'], false, $update); +$tg_json = update_raid_poll($data['r'], false, $update); $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); curl_json_multi_request($tg_json); - - -exit(); diff --git a/mods/vote_pokemon.php b/mods/vote_pokemon.php index 5f209322..4a1f1925 100644 --- a/mods/vote_pokemon.php +++ b/mods/vote_pokemon.php @@ -8,13 +8,16 @@ //debug_log($update); //debug_log($data); +$raidId = $raidId; +$pokemon = $pokemon ?? 0; + // Check if the user has voted for this raid before. $rs = my_query(' SELECT * FROM attendance WHERE raid_id = ? AND user_id = ? - ', [$data['id'], $update['callback_query']['from']['id']] + ', [$raidId, $update['callback_query']['from']['id']] ); // Init empty attendances array and counter. @@ -31,7 +34,7 @@ exit; } // Any pokemon? -if($data['arg'] == 0) { +if($pokemon == 0) { // Delete any attendances except the first one. my_query(' DELETE FROM attendance @@ -45,7 +48,7 @@ ) AND raid_id = :raidId AND user_id = :userId - ', ['raidId' => $data['id'], 'userId' => $update['callback_query']['from']['id']] + ', ['raidId' => $raidId, 'userId' => $update['callback_query']['from']['id']] ); // Update attendance. @@ -54,11 +57,11 @@ SET pokemon = ? WHERE raid_id = ? AND user_id = ? - ', [$data['arg'], $data['id'], $update['callback_query']['from']['id']] + ', [$pokemon, $raidId, $update['callback_query']['from']['id']] ); // Send alarm - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'pok_individual',$data['arg']); + $tg_json = alarm($raidId,$update['callback_query']['from']['id'],'pok_individual',$pokemon); } else { // Init found and count. $found = false; @@ -66,7 +69,7 @@ // Loop thru attendances foreach($atts as $att_row => $att_data) { // Remove vote for specific pokemon - if($att_data['pokemon'] == $data['arg']) { + if($att_data['pokemon'] == $pokemon) { // Is it the only vote? Update to "Any raid boss" instead of deleting it! if($count == 1) { my_query(' @@ -74,7 +77,7 @@ SET pokemon = 0 WHERE raid_id = ? AND user_id = ? - ', [$data['id'], $update['callback_query']['from']['id']] + ', [$raidId, $update['callback_query']['from']['id']] ); // Other votes are still there, delete this one! } else { @@ -83,11 +86,11 @@ WHERE raid_id = ? AND user_id = ? AND pokemon = ? - ', [$data['id'], $update['callback_query']['from']['id'], $data['arg']] + ', [$raidId, $update['callback_query']['from']['id'], $pokemon] ); } // Send alarm - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'pok_cancel_individual',$data['arg']); + $tg_json = alarm($raidId,$update['callback_query']['from']['id'],'pok_cancel_individual',$pokemon); // Update count. $count = $count - 1; @@ -101,7 +104,7 @@ // Not found? Insert! if(!$found) { // Send alarm - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'pok_individual',$data['arg']); + $tg_json = alarm($raidId,$update['callback_query']['from']['id'],'pok_individual',$pokemon); $keys = $values = ''; $binds = []; @@ -109,7 +112,7 @@ if($key == 'id') continue; $keys .= $key . ','; $values .= '?,'; - $binds[] = ($key == 'pokemon') ? $data['arg'] : $value; + $binds[] = ($key == 'pokemon') ? $pokemon : $value; } $keys = rtrim($keys, ','); $values = rtrim($values, ','); @@ -131,14 +134,14 @@ WHERE raid_id = ? AND user_id = ? AND pokemon = 0 - ', [$data['id'], $update['callback_query']['from']['id']] + ', [$raidId, $update['callback_query']['from']['id']] ); } } require_once(LOGIC_PATH . '/update_raid_poll.php'); -$tg_json = update_raid_poll($data['id'], false, $update, $tg_json); +$tg_json = update_raid_poll($raidId, false, $update, $tg_json); $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); diff --git a/mods/vote_refresh.php b/mods/vote_refresh.php index 85155577..cfd904d6 100644 --- a/mods/vote_refresh.php +++ b/mods/vote_refresh.php @@ -1,7 +1,7 @@ $update['callback_query']['from']['id'], 'raidId' => $data['id']] + ', ['userId' => $update['callback_query']['from']['id'], 'raidId' => $raidId] ); // Get the answer. @@ -34,7 +35,7 @@ $tg_json = array(); // Get status to update -$status = $data['arg']; +$status = $data['a']; // Make sure user has voted before. if (empty($answer)) { @@ -59,11 +60,11 @@ END WHERE raid_id = ? AND user_id = ? - ', [$data['id'], $update['callback_query']['from']['id']] + ', [$raidId, $update['callback_query']['from']['id']] ); $new_alarm_value = $answer['alarm'] = 0 ? 1 : 0; // Inform User about change - sendAlertOnOffNotice($data['id'], $update['callback_query']['from']['id'], $new_alarm_value); + sendAlertOnOffNotice($raidId, $update['callback_query']['from']['id'], $new_alarm_value); } else { // All other status-updates are using the short query my_query(' @@ -75,35 +76,27 @@ ' . $status . ' = 1 WHERE raid_id = ? AND user_id = ? - ', [$data['id'], $update['callback_query']['from']['id']] + ', [$raidId, $update['callback_query']['from']['id']] ); if($status == 'raid_done' or $status == 'cancel') { - if($status == 'cancel') $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'status',$status, $tg_json); + if($status == 'cancel') $tg_json = alarm($raidId,$update['callback_query']['from']['id'],'status',$status, $tg_json); // If the gym is a temporary remote raid gym and raid creator voted for done, send message asking for raid deletion if($answer['is_remote_gym'] == '1' && $answer['user_is_creator']) { - $keys = [[ - [ - 'text' => getTranslation('yes'), - 'callback_data' => $data['id'].':end_remote_raid:0' - ], - [ - 'text' => getTranslation('no'), - 'callback_data' => 'exit' - ], - ]]; + $keys[0][0] = button(getTranslation('yes'), ['end_remote_raid', 'r' => $raidId]); + $keys[0][0] = button(getTranslation('no'), 'exit'); if($status == 'raid_done') $msg = getTranslation("delete_remote_raid_done"); else if($status == 'cancel') $msg = getTranslation("delete_remote_raid_cancel"); $tg_json[] = send_message($update['callback_query']['from']['id'], $msg, $keys, false, true); } }elseif($status != 'arrived') { - $tg_json = alarm($data['id'],$update['callback_query']['from']['id'],'status',$status, $tg_json); + $tg_json = alarm($raidId,$update['callback_query']['from']['id'],'status',$status, $tg_json); } } // Send vote response. require_once(LOGIC_PATH . '/update_raid_poll.php'); -$tg_json = update_raid_poll($data['id'], false, $update, $tg_json); +$tg_json = update_raid_poll($raidId, false, $update, $tg_json); $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); diff --git a/mods/vote_team.php b/mods/vote_team.php index 2e5eb983..a5b475d0 100644 --- a/mods/vote_team.php +++ b/mods/vote_team.php @@ -6,14 +6,16 @@ // For debug. //debug_log($update); //debug_log($data); +$team = $data['t'] ?? ''; +$source = $data['a'] ?? ''; // Update team in users table directly. -if($data['arg'] == ('mystic' || 'valor' || 'instinct')) { +if($team == ('mystic' || 'valor' || 'instinct')) { my_query(' UPDATE users SET team = ? WHERE user_id = ? - ', [$data['arg'], $update['callback_query']['from']['id']] + ', [$team, $update['callback_query']['from']['id']] ); // No team was given - iterate thru the teams. } else { @@ -30,7 +32,7 @@ } // Message coming from raid or trainer info? -if($data['id'] == 'trainer') { +if($source == 'trainer') { // Send trainer info update. send_trainerinfo($update, true); exit; @@ -38,10 +40,8 @@ // Send vote response. require_once(LOGIC_PATH . '/update_raid_poll.php'); -$tg_json = update_raid_poll($data['id'], false, $update); +$tg_json = update_raid_poll($data['r'], false, $update); $tg_json[] = answerCallbackQuery($update['callback_query']['id'], getTranslation('vote_updated'), true); curl_json_multi_request($tg_json); - -exit(); diff --git a/mods/vote_time.php b/mods/vote_time.php index 9bb2fd61..1cbc484d 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -11,9 +11,9 @@ //debug_log($update); //debug_log($data); -$raidId = $data['id']; +$raidId = $data['r']; -$vote_time = $data['arg']; +$vote_time = $data['t'] ?? 0; // Raid anytime? $attend_time_save = $attend_time_compare = ANYTIME; if($vote_time != 0) { diff --git a/mods/vote_want_invite.php b/mods/vote_want_invite.php index 9ff93ee0..0ac4bfef 100644 --- a/mods/vote_want_invite.php +++ b/mods/vote_want_invite.php @@ -8,7 +8,7 @@ //debug_log($update); //debug_log($data); -$raidId = $data['id']; +$raidId = $data['r']; $query_select = my_query(' SELECT want_invite, CASE WHEN cancel = 1 or raid_done = 1 THEN 1 ELSE 0 END as cancelOrDone From 9caaa48459d346c2ccbe3a3eccea0719b652153c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 17 Dec 2022 16:40:36 +0200 Subject: [PATCH 209/367] Fixed raid time when raid is already running --- mods/edit_starttime.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/edit_starttime.php b/mods/edit_starttime.php index 89c8a362..f573c0bf 100644 --- a/mods/edit_starttime.php +++ b/mods/edit_starttime.php @@ -107,7 +107,7 @@ $keyData = $data; $keyData[0] = 'edit_time'; $keyData['o'] = 'm'; - $keyData['t'] = utctime($now,"H-i"); + $keyData['t'] = utctime($now,"YmdHi"); // Raid already running $keys_opt[] = button(getTranslation('is_raid_active'), $keyData); $keyData[0] = 'edit_starttime'; From 1d78dbac256194c4c8699b1310a27248f6fe95d6 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 17 Dec 2022 16:40:53 +0200 Subject: [PATCH 210/367] Fail gracefully when a raid id is unknown --- logic/get_raid.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/logic/get_raid.php b/logic/get_raid.php index a24bc028..caa86515 100644 --- a/logic/get_raid.php +++ b/logic/get_raid.php @@ -33,6 +33,11 @@ function get_raid($raid_id) // Get the row. $raid = $rs->fetch(); + if ($rs->rowCount() == 0) { + // Fail gracefully when a raid id is unknown + edit_message($GLOBALS['update'], getTranslation('internal_error'), []); + exit; + } // Resolve the boss id $resolved_boss = resolve_raid_boss($raid['pokemon'], $raid['pokemon_form'], $raid['spawn'], $raid['level']); $raid['pokemon'] = $resolved_boss['pokedex_id']; From ae15f518d198509621f1128e0379f2fc28fd630d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 18 Dec 2022 11:24:36 +0200 Subject: [PATCH 211/367] Done instead of abort --- mods/pogoinfo.php | 2 +- mods/pokebattler.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index 3a31968f..2e200a6f 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -188,7 +188,7 @@ $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; // Abort button. - $nav_keys[][] = button(getTranslation('abort'), 'exit'); + $nav_keys[][] = button(getTranslation('done'), ['exit', 'd' => 1]); // User is still on the import. } else { diff --git a/mods/pokebattler.php b/mods/pokebattler.php index b4de2a9b..c02f9da5 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -205,7 +205,7 @@ $msg .= CR . '' . getTranslation('pokedex_edit_pokemon') . ''; // Abort button. - $nav_keys[][] = button(getTranslation('done'), 'exit'); + $nav_keys[][] = button(getTranslation('done'), ['exit', 'd' => 1]); // User is still on the import. } else { From 7d60b282d193c10e70efa886f456a483146220d8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 18 Dec 2022 11:24:53 +0200 Subject: [PATCH 212/367] Set temporary gyms only for remote raids --- mods/raid_by_location.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mods/raid_by_location.php b/mods/raid_by_location.php index 84ed7bde..cc5302ae 100644 --- a/mods/raid_by_location.php +++ b/mods/raid_by_location.php @@ -112,9 +112,10 @@ // insert gym in table. debug_log('Gym not found in database gym list! Inserting gym "' . $gym_name . '" now.'); $parameters['img_url'] = 'file://' . IMAGES_PATH . '/gym_default.png'; + $parameters['temp'] = ($config->RAID_VIA_LOCATION_FUNCTION == 'remote') ? 1 : 0; $query = ' INSERT INTO gyms (gym_name, lat, lon, address, show_gym, img_url, temporary_gym) - VALUES (:gym_name, :lat, :lon, :address, 0, :img_url, 1) + VALUES (:gym_name, :lat, :lon, :address, 0, :img_url, :temp) '; } else { // Update gyms table to reflect gym changes. From 42b7747eea8ef077c6cd7369ab3f930857b66741 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 18 Dec 2022 11:53:14 +0200 Subject: [PATCH 213/367] Fixed vote_pokemon --- mods/vote_pokemon.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/vote_pokemon.php b/mods/vote_pokemon.php index 4a1f1925..cc713dc5 100644 --- a/mods/vote_pokemon.php +++ b/mods/vote_pokemon.php @@ -8,8 +8,8 @@ //debug_log($update); //debug_log($data); -$raidId = $raidId; -$pokemon = $pokemon ?? 0; +$raidId = $data['r']; +$pokemon = $data['p'] ?? 0; // Check if the user has voted for this raid before. $rs = my_query(' From 9bfb097868d8b92f67bd424848f2813480eaad9b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 18 Dec 2022 13:16:34 +0200 Subject: [PATCH 214/367] Variable names not needed --- logic/debug.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/debug.php b/logic/debug.php index 1a876434..34098356 100644 --- a/logic/debug.php +++ b/logic/debug.php @@ -84,7 +84,7 @@ function debug_log($message, $type = '*') if ($config->DEBUG === false){ return; } - generic_log($message, $type, $logfile = $config->DEBUG_LOGFILE); + generic_log($message, $type, $config->DEBUG_LOGFILE); } /** @@ -98,7 +98,7 @@ function cleanup_log($message, $type = '*'){ if ($config->CLEANUP_LOG === false){ return; } - generic_log($message, $type, $logfile = $config->CLEANUP_LOGFILE); + generic_log($message, $type, $config->CLEANUP_LOGFILE); } /** From dceabe7d1bd1779fba6f5a9010f9844baadfc026 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 18 Dec 2022 14:12:10 +0200 Subject: [PATCH 215/367] Get rid of the addressable assets folder Since there will no longer be new files with the old naming convention there is no need to maintain update logic for those and a separate folder for the actual icons we use. If you want to, you can copy the contents from the current `Addressable assets` directory to the parent directory and delete the empty folder and old `pokemon_icons_*` files. If you didn't move the existing files, you must run `getPokemonIcons.php` before raid pictures start to work again. --- getPokemonIcons.php | 12 ++++++++++-- logic/raid_picture.php | 27 +-------------------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/getPokemonIcons.php b/getPokemonIcons.php index a66ad91a..de4109ec 100644 --- a/getPokemonIcons.php +++ b/getPokemonIcons.php @@ -17,7 +17,7 @@ $repos[] = array('owner' => "PokeMiners", 'name' => "pogo_assets", 'branch' => "master", - 'subdir' => "Addressable_Assets/", + 'subdir' => "", 'dir' => "Images/Pokemon - 256x256/Addressable Assets"); // Get download function curl_get_contents @@ -108,7 +108,7 @@ function is_updated($path, $file_object) { echo "Repo content: " . $repo_content . PHP_EOL; continue; } - $count_unchanged = $count_extension = $i = $successfull_count = $files_downloaded = $chunk_start = 0; + $count_unchanged = $count_extension = $i = $successfull_count = $files_downloaded = $chunk_start = $count_naming = 0; $multi_handle = curl_multi_init(); $treecount = count($content['tree']); // Divide downloadable content into chunks. Download 20 files at a time by default @@ -137,6 +137,11 @@ function is_updated($path, $file_object) { // echo 'Skipping file: ' . $c['path'] . " (File hasn't changed.)" . PHP_EOL; continue; } + // Skip files that don't match the new addressable assets naming convention + if(substr($c['path'], 0, 2) != 'pm') { + $count_naming++; + continue; + } echo 'Downloading ' . $c['path'] . PHP_EOL; $input = $repo_raw . $c['path']; $output = $dest . $c['path']; @@ -184,6 +189,9 @@ function is_updated($path, $file_object) { if($count_extension > 0) { echo 'Skipped ' . $count_extension . ' files due to wrong file extension'. PHP_EOL; } + if($count_naming > 0) { + echo 'Skipped ' . $count_naming . ' files with old file naming convention'. PHP_EOL; + } } echo "Finished pokemon image refresh." . PHP_EOL; diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 05a40636..2adc7374 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -250,16 +250,6 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $show_boss_pokemon_types = false; // Raid running if(!$raid['raid_ended']) { - if(strlen($raid['asset_suffix']) > 2) { - $icon_suffix = $raid['asset_suffix']; - }else { - $pad_zeroes = ''; - for ($o=3-strlen($raid['pokemon']);$o>0;$o--) { - $pad_zeroes .= 0; - } - $icon_suffix = $pad_zeroes.$raid['pokemon'] . "_" . $raid['asset_suffix']; - } - // Raid Egg if($raid['pokemon'] > 9990) { // Getting the actual icon @@ -285,26 +275,19 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $uicons_icon .= '_f'.$raid['pokemon_form']; } - // Getting the actual icon filename - $p_icon = "pokemon_icon_" . $icon_suffix; - // Add costume info for every mon except megas if($raid['costume'] != 0 && $raid['pokemon_form'] >= 0) { - $p_icon .= '_' . str_pad($raid['costume'], 2, '0', STR_PAD_LEFT); - $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); $addressable_icon .= '.c' . array_search($raid['costume'],$costume); $uicons_icon .= '_c'.$raid['costume']; } if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { - $p_icon = $p_icon . "_shiny"; $addressable_icon .= '.s'; $uicons_icon .= '_s'; $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); } $addressable_icon .= '.icon.png'; - $p_icon = $p_icon . ".png"; $uicons_icon .= '.png'; foreach($p_sources as $p_dir) { @@ -314,17 +297,9 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $p_img_base_path = IMAGES_PATH . "/" . $asset_dir; // Check if file exists in this collection - // Prioritize addressable asset file if(file_exists($p_img_base_path . "/" . $addressable_icon) && filesize($p_img_base_path . "/" . $addressable_icon) > 0) { $img_file = $p_img_base_path . "/" . $addressable_icon; break; - // These elseifs become redundant after PokeMiners move the files from Addressable Assets folder to the parent directory on 1.6.2022 - }else if(file_exists($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) && filesize($p_img_base_path . "/Addressable_Assets/" . $addressable_icon) > 0) { - $img_file = $p_img_base_path . "/Addressable_Assets/" . $addressable_icon; - break; - }else if(file_exists($p_img_base_path . "/" . $p_icon) && filesize($p_img_base_path . "/" . $p_icon) > 0) { - $img_file = $p_img_base_path . "/" . $p_icon; - break; }else if(file_exists($p_img_base_path . "/" . $uicons_icon) && filesize($p_img_base_path . "/" . $uicons_icon) > 0) { $img_file = $p_img_base_path . "/" . $uicons_icon; $uicons = true; @@ -334,7 +309,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // If no image was found, substitute with a fallback if($img_file === null) { - info_log($p_icon . ' ' . $addressable_icon, 'Failed to find an image in any pokemon image collection for:'); + info_log($addressable_icon . ' ' . $uicons_icon, 'Failed to find an image in any pokemon image collection for:'); $img_fallback_file = null; // If we know the raid level, fallback to egg image if(array_key_exists('level', $raid) && $raid['level'] !== null && $raid['level'] != 0) { From f313fa671192e8314a2b1c55dca4c23fa770dc59 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 18 Dec 2022 15:14:29 +0200 Subject: [PATCH 216/367] Got rid of most of the old stuff regarding `pokemon` table - Removed `asset_suffix` column - Removed all the unnecessary logic regarding renaming pokemon or their forms - Fixed getdb --- constants.php | 1 + lang/pokemon_forms.json | 2 +- logic/raid_picture.php | 2 +- logic/resolve_boss_name_to_ids.php | 62 ++++-------------------------- mods/getdb.php | 40 +++++++------------ raidpicture.php | 2 +- sql/pokemon-raid-bot.sql | 1 - sql/upgrade/6.sql | 2 + 8 files changed, 28 insertions(+), 84 deletions(-) diff --git a/constants.php b/constants.php index 4c77c6b4..22ea4879 100644 --- a/constants.php +++ b/constants.php @@ -37,6 +37,7 @@ ]; $pokebattler_pokemon_map = [ + 'GIRATINA' => 'GIRATINA_ALTERED', 'ZACIAN' => 'ZACIAN_HERO_FORM', 'ZAMAZENTA' => 'ZAMAZENTA_HERO_FORM', ]; diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index de57bf67..4495b5ae 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -77,7 +77,7 @@ "FI": "Mega Y", "ES": "Mega Y" }, - "pokemon_form_armored": { + "pokemon_form_a": { "NL": "Armored", "DE": "Rüstungsform", "EN": "Armored", diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 2adc7374..34e46efd 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -61,7 +61,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Query missing raid info $q_pokemon_info = my_query(' SELECT - pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, asset_suffix, type, type2, + pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, type, type2, (SELECT img_url FROM gyms WHERE id=:gymId LIMIT 1) as img_url FROM pokemon WHERE pokedex_id = :pokemonId diff --git a/logic/resolve_boss_name_to_ids.php b/logic/resolve_boss_name_to_ids.php index bedb2c3f..e42b8baf 100644 --- a/logic/resolve_boss_name_to_ids.php +++ b/logic/resolve_boss_name_to_ids.php @@ -2,66 +2,20 @@ require_once(LOGIC_PATH . '/get_pokemon_id_by_name.php'); function resolve_boss_name_to_ids($pokemon_name) { + global $pokebattler_pokemon_map; + if (array_key_exists($pokemon_name, $pokebattler_pokemon_map)) + $pokemon_name = $pokebattler_pokemon_map[$pokemon_name]; + // Name and form. + $name = $pokemon_name; + $form = 'normal'; // Pokemon name ending with "_FORM" ? - if(substr_compare($pokemon_name, '_FORM', -strlen('_FORM')) === 0) { + if (preg_match('/(MEGA|MEGA_Y|MEGA_X|FORM)$/', $pokemon_name)) { debug_log('Pokemon with a special form received: ' . $pokemon_name); // Remove "_FORM" $pokemon = str_replace('_FORM', '', $pokemon_name); // Get pokemon name and form. - $name = explode("_", $pokemon, 2)[0]; - $form = explode("_", $pokemon, 2)[1]; - - // Fix for MEWTWO_A_FORM - if($name == 'MEWTWO' && $form == 'A') { - $form = 'ARMORED'; - } - - // Pokemon name ending with "_MALE" ? - } else if(substr_compare($pokemon_name, '_MALE', -strlen('_MALE')) === 0) { - debug_log('Pokemon with gender MALE received: ' . $pokemon_name); - // Remove "_MALE" - $pokemon = str_replace('_MALE', '', $pokemon_name); - - // Get pokemon name and form. - $name = explode("_", $pokemon, 2)[0] . '♂'; - $form = 'normal'; - - // Pokemon name ending with "_FEMALE" ? - } else if(substr_compare($pokemon_name, '_FEMALE', -strlen('_FEMALE')) === 0) { - debug_log('Pokemon with gender FEMALE received: ' . $pokemon_name); - // Remove "_FEMALE" - $pokemon = str_replace('_FEMALE', '', $pokemon_name); - - // Get pokemon name and form. - $name = explode("_", $pokemon, 2)[0] . '♀'; - $form = 'normal'; - - // Mega pokemon ? - }else if(substr_compare($pokemon_name, '_MEGA', -strlen('_MEGA')) === 0 or substr_compare($pokemon_name, '_MEGA_X', -strlen('_MEGA_X')) === 0 or substr_compare($pokemon_name, '_MEGA_Y', -strlen('_MEGA_Y')) === 0) { - debug_log('Mega Pokemon received: ' . $pokemon_name); - - // Get pokemon name and form. - $name_form = explode("_", $pokemon_name, 2); - $name = $name_form[0]; - $form = $name_form[1]; - - // Normal pokemon without form or gender. - } else { - // Fix pokemon like "HO_OH"... - if(substr_count($pokemon_name, '_') >= 1) { - $pokemon = str_replace('_', '-', $pokemon_name); - } else { - $pokemon = $pokemon_name; - } - // Name and form. - $name = $pokemon; - $form = 'normal'; - - // Fix for GIRATINA as the actual GIRATINA_ALTERED_FORM is just GIRATINA - if($name == 'GIRATINA' && $form == 'normal') { - $form = 'ALTERED'; - } + [$name, $form] = explode("_", $pokemon, 2); } // Get ID and form name used internally. debug_log('Getting dex id and form for pokemon ' . $name . ' with form ' . $form); diff --git a/mods/getdb.php b/mods/getdb.php index 9840879a..8697d275 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -21,11 +21,12 @@ if(file_put_contents(ROOT_PATH.'/protos/costume.json', json_encode($costume, JSON_PRETTY_PRINT))) { // Parse the game master data together with form ids into format we can use $pokemon_array = parse_master_into_pokemon_table($form_ids, $game_master_url); + info_log(print_r($pokemon_array, true)); if(!$pokemon_array) { $error = "Failed to open game master file."; } else { $PRE = 'INSERT INTO `pokemon`' . PHP_EOL; - $PRE .= '(pokedex_id, pokemon_name, pokemon_form_name, pokemon_form_id, asset_suffix, min_cp, max_cp, min_weather_cp, max_weather_cp, type, type2, weather) VALUES'; + $PRE .= '(pokedex_id, pokemon_name, pokemon_form_name, pokemon_form_id, min_cp, max_cp, min_weather_cp, max_weather_cp, type, type2, weather) VALUES'; foreach($eggs as $egg) { $pokemon_id = $egg; $form_name = 'normal'; @@ -34,7 +35,6 @@ 'pokemon_name'=>$pokemon_name, 'pokemon_form_name'=>$form_name, 'pokemon_form_id'=>0, - 'asset_suffix'=>0, 'shiny'=>0, 'min_cp'=>0, 'max_cp'=>0, @@ -54,8 +54,8 @@ if(!isset($data['weather']) || !isset($data['min_cp']) || !isset($data['max_cp']) || !isset($data['min_weather_cp']) || !isset($data['max_weather_cp']) || !isset($data['pokemon_name'])) continue; $poke_name = $data['pokemon_name']; + $poke_form = strtolower($data['pokemon_form_name']); $form_id = $data['pokemon_form_id']; - $form_asset_suffix = $data['asset_suffix']; $poke_min_cp = $data['min_cp']; $poke_max_cp = $data['max_cp']; $poke_min_weather_cp = $data['min_weather_cp']; @@ -64,25 +64,19 @@ $poke_type2 = $data['type2']; $poke_weather = $data['weather']; - if($pokemon_id == 150 && $data['pokemon_form_name']=="a") { - // Because logic and consistency - $poke_form = 'armored'; - }else { - $poke_form = strtolower($data['pokemon_form_name']); - } if($i==0) $i=1; else $SQL .= ","; - $insertData = [$pokemon_id, $poke_name, $poke_form, $form_id, $form_asset_suffix, $poke_min_cp, $poke_max_cp, $poke_min_weather_cp, $poke_max_weather_cp, $poke_type, $poke_type2, $poke_weather]; + $insertData = [$pokemon_id, $poke_name, $poke_form, $form_id, $poke_min_cp, $poke_max_cp, $poke_min_weather_cp, $poke_max_weather_cp, $poke_type, $poke_type2, $poke_weather]; $SQL .= PHP_EOL . '("' . implode('","', $insertData) . '")'; } } ## MySQL 8 compatible #$SQL = $PRE . $SQL . ' as new' . PHP_EOL; #$SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = new.pokedex_id, pokemon_name = new.pokemon_name, pokemon_form_name = new.pokemon_form_name,' . PHP_EOL; - #$SQL .= 'pokemon_form_id = new.pokemon_form_id, asset_suffix = new.asset_suffix, min_cp = new.min_cp, max_cp = new.max_cp,' . PHP_EOL; + #$SQL .= 'pokemon_form_id = new.pokemon_form_id, min_cp = new.min_cp, max_cp = new.max_cp,' . PHP_EOL; #$SQL .= 'min_weather_cp = new.min_weather_cp, max_weather_cp = new.max_weather_cp, type = new.type, type2 = new.type2, weather = new.weather;'; $SQL = $PRE . $SQL . PHP_EOL; $SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = VALUES(pokedex_id), pokemon_name = VALUES(pokemon_name), pokemon_form_name = VALUES(pokemon_form_name),' . PHP_EOL; - $SQL .= 'pokemon_form_id = VALUES(pokemon_form_id), asset_suffix = VALUES(asset_suffix), min_cp = VALUES(min_cp),' . PHP_EOL; + $SQL .= 'pokemon_form_id = VALUES(pokemon_form_id), min_cp = VALUES(min_cp),' . PHP_EOL; $SQL .= 'max_cp = VALUES(max_cp), min_weather_cp = VALUES(min_weather_cp), max_weather_cp = VALUES(max_weather_cp),' . PHP_EOL; $SQL .= 'type = VALUES(type), type2 = VALUES(type2), weather = VALUES(weather);' . PHP_EOL; try { @@ -188,7 +182,6 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { // Using negative to prevent mixup with actual form ID's // Collected from pogoprotos (hoping they won't change, so hard coding them here) $mega_ids = array('MEGA'=>-1,'MEGA_X'=>-2,'MEGA_Y'=>-3); - $mega_asset_suffixes = array('MEGA'=>51,'MEGA_X'=>51,'MEGA_Y'=>52); $weatherboost_table = array( 'POKEMON_TYPE_BUG' => '3', @@ -237,24 +230,18 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { foreach($form_data as $form) { $form_name = strtolower(str_replace($pokemon_name.'_','',$form['form'])); if($form_name == 'purified' || $form_name == 'shadow') continue; - - // Nidoran - $poke_name = ucfirst(strtolower(str_replace(['_FEMALE','_MALE'],['♀','♂'],$row['data']['formSettings']['pokemon']))); - // Ho-oh - $poke_name = str_replace('_','-',$poke_name); + $poke_name = ucfirst(strtolower($row['data']['formSettings']['pokemon'])); if(!isset($form_ids[$form['form']])) { $form_id = 0; }else { $form_id = $form_ids[$form['form']]; } - $form_asset_suffix = (isset($form['assetBundleValue']) ? $form['assetBundleValue'] : (isset($form['assetBundleSuffix'])?$form['assetBundleSuffix']:'00')); $pokemon_array[$pokemon_id][$form_name] = [ 'pokemon_name'=>$poke_name, 'pokemon_form_name'=>$form_name, 'pokemon_form_id'=>$form_id, - 'asset_suffix'=>$form_asset_suffix ]; } }else if ($part[1] == "POKEMON" && $part[0][0] == "V" && isset($row['data']['pokemonSettings'])) { @@ -262,15 +249,17 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { $pokemon_id = (int)str_replace("V","",$part[0]); $form_name = str_replace($row['data']['pokemonSettings']['pokemonId']."_","",substr($row['data']['templateId'],14)); if($form_name == 'PURIFIED' || $form_name == 'SHADOW' || $form_name == 'NORMAL' - || !isset($pokemon_array[$pokemon_id]) - || !isset($row['data']['pokemonSettings']['stats']['baseAttack']) - || !isset($row['data']['pokemonSettings']['stats']['baseDefense']) - || !isset($row['data']['pokemonSettings']['stats']['baseStamina'])) { + || !isset($pokemon_array[$pokemon_id]) + || !isset($row['data']['pokemonSettings']['stats']['baseAttack']) + || !isset($row['data']['pokemonSettings']['stats']['baseDefense']) + || !isset($row['data']['pokemonSettings']['stats']['baseStamina']) + ) { continue; } - $form_name = "normal"; if($form_name != $row['data']['pokemonSettings']['pokemonId']) { $form_name = strtolower($form_name); + }else { + $form_name = "normal"; } [$min_cp, $max_cp, $min_weather_cp, $max_weather_cp] = calculate_cps($row['data']['pokemonSettings']['stats']); @@ -323,7 +312,6 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { 'pokemon_name' => $pokemon_array[$pokemon_id][$form_name]['pokemon_name'], 'pokemon_form_name' => $mega_evolution_name, 'pokemon_form_id' => $mega_ids[$mega_evolution_name], - 'asset_suffix' => $mega_asset_suffixes[$mega_evolution_name], 'min_cp' => $min_cp, 'max_cp' => $max_cp, 'min_weather_cp' => $min_weather_cp, diff --git a/raidpicture.php b/raidpicture.php index 5efadd5a..6ae6e764 100644 --- a/raidpicture.php +++ b/raidpicture.php @@ -66,7 +66,7 @@ $raid['costume'] = preg_replace("/\D/","",$_GET['costume']); } $q_pokemon_info = my_query(' - SELECT pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, asset_suffix, type, type2 + SELECT pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, type, type2 FROM pokemon WHERE pokedex_id = ? AND pokemon_form_id = ? diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 594fcdb4..98b7c56a 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -93,7 +93,6 @@ CREATE TABLE `pokemon` ( `type` varchar(10) DEFAULT '', `type2` varchar(10) DEFAULT '', `shiny` tinyint(1) unsigned DEFAULT 0, - `asset_suffix` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_pokemon_pokedex_id_pokemon_form_id` (`pokedex_id`,`pokemon_form_id`) ) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8mb4; diff --git a/sql/upgrade/6.sql b/sql/upgrade/6.sql index df4b153b..52450718 100644 --- a/sql/upgrade/6.sql +++ b/sql/upgrade/6.sql @@ -3,3 +3,5 @@ ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `privileges` TEXT NULL AFTER `gymar ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `end_time` DATETIME NULL AFTER `ended`; ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `start_time` DATETIME NULL AFTER `ended`; + +ALTER TABLE `pokemon` DROP COLUMN IF EXISTS `asset_suffix`; From 4b773632b0806f74e3465984dd8e78d8a591c2eb Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 18 Dec 2022 17:11:00 +0200 Subject: [PATCH 217/367] Forgot to remove debug loggin. Again --- mods/getdb.php | 1 - 1 file changed, 1 deletion(-) diff --git a/mods/getdb.php b/mods/getdb.php index 8697d275..80c32175 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -21,7 +21,6 @@ if(file_put_contents(ROOT_PATH.'/protos/costume.json', json_encode($costume, JSON_PRETTY_PRINT))) { // Parse the game master data together with form ids into format we can use $pokemon_array = parse_master_into_pokemon_table($form_ids, $game_master_url); - info_log(print_r($pokemon_array, true)); if(!$pokemon_array) { $error = "Failed to open game master file."; } else { From 2f28dcb077ed7e8b5435aa33e4f5e8deda09d3c4 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 19 Dec 2022 13:24:35 +0200 Subject: [PATCH 218/367] Cleaned up getdb code --- mods/getdb.php | 274 ++++++++++++++++++------------------------------- 1 file changed, 101 insertions(+), 173 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 80c32175..3ba6ef70 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -6,125 +6,99 @@ require_once(LOGIC_PATH . '/sql_utils.php'); require_once(LOGIC_PATH . '/debug.php'); require_once(LOGIC_PATH . '/curl_get_contents.php'); -$proto_url = "https://raw.githubusercontent.com/Furtif/POGOProtos-Swift/master/Sources/POGOProtos/POGOProtos.pb.swift"; -$game_master_url = "https://raw.githubusercontent.com/PokeMiners/game_masters/master/latest/latest.json"; +$proto_url = 'https://raw.githubusercontent.com/Furtif/POGOProtos-Swift/master/Sources/POGOProtos/POGOProtos.pb.swift'; +$game_master_url = 'https://raw.githubusercontent.com/PokeMiners/game_masters/master/latest/latest.json'; $error = false; // Read the form ids from protos -if($protos = get_protos($proto_url)) { - global $dbh, $eggs; - $form_ids = $protos[0]; - $costume = $protos[1]; - - // Save costume data to json file - if(file_put_contents(ROOT_PATH.'/protos/costume.json', json_encode($costume, JSON_PRETTY_PRINT))) { - // Parse the game master data together with form ids into format we can use - $pokemon_array = parse_master_into_pokemon_table($form_ids, $game_master_url); - if(!$pokemon_array) { - $error = "Failed to open game master file."; - } else { - $PRE = 'INSERT INTO `pokemon`' . PHP_EOL; - $PRE .= '(pokedex_id, pokemon_name, pokemon_form_name, pokemon_form_id, min_cp, max_cp, min_weather_cp, max_weather_cp, type, type2, weather) VALUES'; - foreach($eggs as $egg) { - $pokemon_id = $egg; - $form_name = 'normal'; - $pokemon_name = 'Level '. $egg[3] .' Egg'; - $pokemon_array[$pokemon_id][$form_name] = [ - 'pokemon_name'=>$pokemon_name, - 'pokemon_form_name'=>$form_name, - 'pokemon_form_id'=>0, - 'shiny'=>0, - 'min_cp'=>0, - 'max_cp'=>0, - 'min_weather_cp'=>0, - 'max_weather_cp'=>0, - 'type' => '', - 'type2' => '', - 'weather'=>0 - ]; - } - $i = 0; - $SQL = ''; - foreach($pokemon_array as $id => $forms) { - $pokemon_id = $id; - foreach($forms as $form => $data) { - // Check that data is set, if not the mon is probably not in the game yet and there's no point in having them in a broken state - if(!isset($data['weather']) || !isset($data['min_cp']) || !isset($data['max_cp']) || !isset($data['min_weather_cp']) || !isset($data['max_weather_cp']) || !isset($data['pokemon_name'])) continue; +if (!$protos = get_protos($proto_url)) { + sendResults('Failed to get protos.', $update, true); +} - $poke_name = $data['pokemon_name']; - $poke_form = strtolower($data['pokemon_form_name']); - $form_id = $data['pokemon_form_id']; - $poke_min_cp = $data['min_cp']; - $poke_max_cp = $data['max_cp']; - $poke_min_weather_cp = $data['min_weather_cp']; - $poke_max_weather_cp = $data['max_weather_cp']; - $poke_type = $data['type']; - $poke_type2 = $data['type2']; - $poke_weather = $data['weather']; +[$form_ids, $costume] = $protos; - if($i==0) $i=1; else $SQL .= ","; - $insertData = [$pokemon_id, $poke_name, $poke_form, $form_id, $poke_min_cp, $poke_max_cp, $poke_min_weather_cp, $poke_max_weather_cp, $poke_type, $poke_type2, $poke_weather]; - $SQL .= PHP_EOL . '("' . implode('","', $insertData) . '")'; - } - } - ## MySQL 8 compatible - #$SQL = $PRE . $SQL . ' as new' . PHP_EOL; - #$SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = new.pokedex_id, pokemon_name = new.pokemon_name, pokemon_form_name = new.pokemon_form_name,' . PHP_EOL; - #$SQL .= 'pokemon_form_id = new.pokemon_form_id, min_cp = new.min_cp, max_cp = new.max_cp,' . PHP_EOL; - #$SQL .= 'min_weather_cp = new.min_weather_cp, max_weather_cp = new.max_weather_cp, type = new.type, type2 = new.type2, weather = new.weather;'; - $SQL = $PRE . $SQL . PHP_EOL; - $SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = VALUES(pokedex_id), pokemon_name = VALUES(pokemon_name), pokemon_form_name = VALUES(pokemon_form_name),' . PHP_EOL; - $SQL .= 'pokemon_form_id = VALUES(pokemon_form_id), min_cp = VALUES(min_cp),' . PHP_EOL; - $SQL .= 'max_cp = VALUES(max_cp), min_weather_cp = VALUES(min_weather_cp), max_weather_cp = VALUES(max_weather_cp),' . PHP_EOL; - $SQL .= 'type = VALUES(type), type2 = VALUES(type2), weather = VALUES(weather);' . PHP_EOL; - try { - $prep = $dbh->prepare($SQL); - $prep->execute(); - } catch (Exception $e) { - if(isset($update['message']['from']['id'])) $error = $e; - } - } - }else { - $error = 'Failed to write costume data to protos/costume.json'; - } -} else { - $error = 'Failed to get protos.'; +// Save costume data to json file +if(!file_put_contents(ROOT_PATH.'/protos/costume.json', json_encode($costume, JSON_PRETTY_PRINT))) { + sendResults('Failed to write costume data to protos/costume.json', $update, true); } -if(!$error) { - $msg = 'Updated successfully!' . CR; - $msg.= $prep->rowCount() . ' rows required updating!'; - // Sometimes Nia can push form id's a bit later than other stats, so the script may insert incomplete rows - // This hopefully clears those faulty rows out when the complete data is received without effecting any actual data - my_query(' - DELETE t1 FROM pokemon t1 - INNER JOIN pokemon t2 - WHERE - t1.pokedex_id = t2.pokedex_id - AND t1.pokemon_form_name = t2.pokemon_form_name - AND t1.pokemon_form_name <> \'normal\' - AND t1.pokemon_form_id = 0 - '); - $callback_msg = 'OK!'; -}else { - $msg = $error; - info_log('Pokemon table update failed: ' . $error); - $callback_msg = 'Error!'; +// Parse the game master data together with form ids into format we can use +$pokemon_array = parse_master_into_pokemon_table($form_ids, $game_master_url); +if(!$pokemon_array) { + sendResults('Failed to open game master file.', $update, true); } -if(!isset($update['callback_query']['id'])) { - info_log($msg); - exit(); +$PRE = 'INSERT INTO `pokemon`' . PHP_EOL; +$PRE .= '(pokedex_id, pokemon_name, pokemon_form_name, pokemon_form_id, min_cp, max_cp, min_weather_cp, max_weather_cp, type, type2, weather) VALUES'; +foreach($eggs as $egg) { + $pokemon_id = $egg; + $pokemon_name = 'Level '. $egg[3] .' Egg'; + $pokemon_array[$pokemon_id]['normal'] = [ + 'pokemon_name'=>$pokemon_name, + 'pokemon_form_name'=> 'normal', + 'pokemon_form_id'=>0, + 'shiny'=>0, + 'min_cp'=>0, + 'max_cp'=>0, + 'min_weather_cp'=>0, + 'max_weather_cp'=>0, + 'type' => '', + 'type2' => '', + 'weather'=>0 + ]; } -// Answer callback. -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_msg, true); - -// Edit the message. -$tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['message']['chat']['id'], false, true); - -// Telegram multicurl request. -curl_json_multi_request($tg_json); - +$i = 0; +$dataSql = ''; +foreach($pokemon_array as $pokemon_id => $forms) { + foreach($forms as $form => $data) { + // Check that data is set, if not the mon is probably not in the game yet and there's no point in having them in a broken state + if(!isset($data['weather']) || !isset($data['min_cp']) || !isset($data['max_cp']) || !isset($data['min_weather_cp']) || !isset($data['max_weather_cp']) || !isset($data['pokemon_name'])) continue; + $insertData = [$pokemon_id, $data['pokemon_name'], $data['pokemon_form_name'], $data['pokemon_form_id'], $data['min_cp'], $data['max_cp'], $data['min_weather_cp'], $data['max_weather_cp'], $data['type'], $data['type2'], $data['weather']]; + $dataSql .= PHP_EOL . '("' . implode('","', $insertData) . '"),'; + } +} +## MySQL 8 compatible +#$SQL = $PRE . $SQL . ' as new' . PHP_EOL; +#$SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = new.pokedex_id, pokemon_name = new.pokemon_name, pokemon_form_name = new.pokemon_form_name,' . PHP_EOL; +#$SQL .= 'pokemon_form_id = new.pokemon_form_id, min_cp = new.min_cp, max_cp = new.max_cp,' . PHP_EOL; +#$SQL .= 'min_weather_cp = new.min_weather_cp, max_weather_cp = new.max_weather_cp, type = new.type, type2 = new.type2, weather = new.weather;'; +$SQL = $PRE . rtrim($dataSql, ',') . PHP_EOL; +$SQL .= 'ON DUPLICATE KEY UPDATE pokedex_id = VALUES(pokedex_id), pokemon_name = VALUES(pokemon_name), pokemon_form_name = VALUES(pokemon_form_name),' . PHP_EOL; +$SQL .= 'pokemon_form_id = VALUES(pokemon_form_id), min_cp = VALUES(min_cp),' . PHP_EOL; +$SQL .= 'max_cp = VALUES(max_cp), min_weather_cp = VALUES(min_weather_cp), max_weather_cp = VALUES(max_weather_cp),' . PHP_EOL; +$SQL .= 'type = VALUES(type), type2 = VALUES(type2), weather = VALUES(weather);' . PHP_EOL; +try { + $prep = $dbh->prepare($SQL); + $prep->execute(); +} catch (Exception $e) { + sendResults($e, $update, true); +} +$msg = 'Updated successfully!' . CR; +$msg.= $prep->rowCount() . ' rows required updating!'; +// Sometimes Nia can push form id's a bit later than other stats, so the script may insert incomplete rows +// This hopefully clears those faulty rows out when the complete data is received without effecting any actual data +my_query(' + DELETE t1 FROM pokemon t1 + INNER JOIN pokemon t2 + WHERE + t1.pokedex_id = t2.pokedex_id + AND t1.pokemon_form_name = t2.pokemon_form_name + AND t1.pokemon_form_name <> \'normal\' + AND t1.pokemon_form_id = 0 +'); +sendResults($msg, $update); +function sendResults($msg, $update, $error = false) { + if($error) { + info_log('Pokemon table update failed: ' . $msg); + }else if(!isset($update['callback_query']['id'])) { + info_log($msg); + exit(); + } + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], (!$error) ? 'OK!' : 'Error!', true); + $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['message']['chat']['id'], false, true); + curl_json_multi_request($tg_json); + exit; +} function calculate_cps($base_stats) { // CP = (Attack * Defense^0.5 * Stamina^0.5 * CP_Multiplier^2) / 10 $cp_multiplier = array(20 => 0.5974 ,25 =>0.667934 ); @@ -142,15 +116,13 @@ function get_protos($proto_url) { $count = count($proto); $form_ids = $costume = array(); $data_array = false; - $data_start_line = 0; for($i=0;$i<$count;$i++) { $line = trim($proto[$i]); - if($data_array != false && $i >= $data_start_line) { + if($data_array != false) { $data = explode(':', $line, 2); // End of pokemon data, no need to loop further if(trim($data[0]) == ']') { $data_array = false; - $data_start_line = 0; if(count($form_ids) > 0 && count($costume) > 0) { // We found what we needed so we can stop looping through proto file and exit break; @@ -161,15 +133,15 @@ function get_protos($proto_url) { if(strlen($value[1]) > 0) { ${$data_array}[trim($value[1])] = trim($data[0]); } - }else { - if($line == 'extension PokemonDisplayProto.Costume: SwiftProtobuf._ProtoNameProviding {') { - $data_array = 'costume'; - $data_start_line = $i+2; - } - if($line == 'extension PokemonDisplayProto.Form: SwiftProtobuf._ProtoNameProviding {') { - $data_array = 'form_ids'; - $data_start_line = $i+2; - } + continue; + } + if($line == 'extension PokemonDisplayProto.Costume: SwiftProtobuf._ProtoNameProviding {') { + $data_array = 'costume'; + $i++; // Jump over one line + } + if($line == 'extension PokemonDisplayProto.Form: SwiftProtobuf._ProtoNameProviding {') { + $data_array = 'form_ids'; + $i++; // Jump over one line } } unset($proto); @@ -209,17 +181,10 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { $form_data = []; $pokemon_id = ''; if(count($part)<2) continue; - if($part[0] == 'FORMS' && $part[2] == 'POKEMON') { + if(preg_match('/FORMS_V([0-9]*)_POKEMON_([a-zA-Z0-9_]*)/', $row['templateId'], $matches)) { // Found Pokemon form data - - // Get pokemon ID - $pokemon_id = ltrim(str_replace('V','',$part[1]),'0'); - unset($part[0]); - unset($part[1]); - unset($part[2]); - - // Pokemon name - $pokemon_name = implode('_',$part); + $pokemon_id = (int)$matches[1]; + $pokemon_name = $matches[2]; // Get pokemon forms if(!isset($row['data']['formSettings']['forms']) or empty($row['data']['formSettings']['forms'][0])) { $form_data[] = array('form'=>$pokemon_name.'_NORMAL'); @@ -230,12 +195,7 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { $form_name = strtolower(str_replace($pokemon_name.'_','',$form['form'])); if($form_name == 'purified' || $form_name == 'shadow') continue; $poke_name = ucfirst(strtolower($row['data']['formSettings']['pokemon'])); - - if(!isset($form_ids[$form['form']])) { - $form_id = 0; - }else { - $form_id = $form_ids[$form['form']]; - } + $form_id = $form_ids[$form['form']] ?? 0; $pokemon_array[$pokemon_id][$form_name] = [ 'pokemon_name'=>$poke_name, @@ -243,10 +203,10 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { 'pokemon_form_id'=>$form_id, ]; } - }else if ($part[1] == "POKEMON" && $part[0][0] == "V" && isset($row['data']['pokemonSettings'])) { + }else if (preg_match('/V([0-9]*)_POKEMON_([a-zA-Z0-9_]*)/', $row['templateId'], $matches) && isset($row['data']['pokemonSettings'])) { // Found Pokemon data - $pokemon_id = (int)str_replace("V","",$part[0]); - $form_name = str_replace($row['data']['pokemonSettings']['pokemonId']."_","",substr($row['data']['templateId'],14)); + $pokemon_id = (int)$matches[1]; + $form_name = str_replace($row['data']['pokemonSettings']['pokemonId']."_","",$matches[2]); if($form_name == 'PURIFIED' || $form_name == 'SHADOW' || $form_name == 'NORMAL' || !isset($pokemon_array[$pokemon_id]) || !isset($row['data']['pokemonSettings']['stats']['baseAttack']) @@ -309,7 +269,7 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { } $pokemon_array[$pokemon_id][$mega_evolution_name] = [ 'pokemon_name' => $pokemon_array[$pokemon_id][$form_name]['pokemon_name'], - 'pokemon_form_name' => $mega_evolution_name, + 'pokemon_form_name' => strtolower($mega_evolution_name), 'pokemon_form_id' => $mega_ids[$mega_evolution_name], 'min_cp' => $min_cp, 'max_cp' => $max_cp, @@ -324,35 +284,3 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { } return $pokemon_array; } - -// Fetch the latest version of proto files. -// vbase.proto has only the latest fully deobfuscated protos, -// but we only need the latest form and costume data which is available in the partially obfuscated protofiles -function getProtoURL() { - $repo_owner = 'Furtif'; - $repo_name = 'POGOProtos'; - $content_dir = 'base'; - - $repo_content = 'https://api.github.com/repos/' . $repo_owner . '/' . $repo_name . '/contents/' . $content_dir; - // Git tree lookup - $tree = curl_get_contents($repo_content); - $leaf = json_decode($tree, true); - // Detect rate-limiting and die gracefully - if(is_array($leaf) && in_array('message', $leaf)) { - die('Failed to download repo index: ' . $leaf['message']); - } - $highest = 0; - $url = ''; - foreach($leaf as $l) { - $version = trim(preg_replace('/\D/', '', substr($l['name'], 3))); - if($version > $highest) { - $split = explode(".",$l['name']); - // Only allow fully or partially deobfuscated iterations of the proto file - if($split[2] == 'x' or $split[2] == 'x_p_obf') { - $highest = $version; - $url = $l['download_url']; - } - } - } - return $url; -} From 6e2ea2c7c79352e001d1ceaec39da68642a92661 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 21 Dec 2022 09:14:08 +0200 Subject: [PATCH 219/367] Fixed participate-key --- logic/keys_vote.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index dc96d1f7..fe8a5489 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -109,7 +109,7 @@ function keys_vote($raid) } if($raid['event_vote_key_mode'] == 1) { - $keys_time = button(getPublicTranslation('Participate'), ['vote_time', 'r' => $raid['id'], 't' => utctime($raid['start_time'], 'YmdHis')]); + $keys_time[] = button(getPublicTranslation('Participate'), ['vote_time', 'r' => $raid['id'], 't' => utctime($raid['start_time'], 'YmdHis')]); }else { $RAID_SLOTS = ($raid['event_time_slots'] > 0) ? $raid['event_time_slots'] : $config->RAID_SLOTS; $keys_time = generateTimeslotKeys($RAID_SLOTS, $raid); From cfa67e7434bb2a5925a1c12641c7524977913a71 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 23 Dec 2022 17:15:09 +0200 Subject: [PATCH 220/367] Fallback for some normal form icons --- logic/raid_picture.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 34e46efd..951b94c5 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -268,6 +268,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); $addressable_icon = 'pm'.$raid['pokemon']; + $addressableFallback = 'pm'.$raid['pokemon'].'.fNORMAL'; $uicons_icon = $raid['pokemon']; if($raid['pokemon_form_name'] != 'normal') { @@ -279,15 +280,18 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { if($raid['costume'] != 0 && $raid['pokemon_form'] >= 0) { $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); $addressable_icon .= '.c' . array_search($raid['costume'],$costume); + $addressableFallback .= '.c' . array_search($raid['costume'],$costume); $uicons_icon .= '_c'.$raid['costume']; } if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { $addressable_icon .= '.s'; + $addressableFallback .= '.s'; $uicons_icon .= '_s'; $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); } $addressable_icon .= '.icon.png'; + $addressableFallback .= '.icon.png'; $uicons_icon .= '.png'; foreach($p_sources as $p_dir) { @@ -300,6 +304,10 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { if(file_exists($p_img_base_path . "/" . $addressable_icon) && filesize($p_img_base_path . "/" . $addressable_icon) > 0) { $img_file = $p_img_base_path . "/" . $addressable_icon; break; + }else if(file_exists($p_img_base_path . "/" . $addressableFallback) && filesize($p_img_base_path . "/" . $addressableFallback) > 0) { + $img_file = $p_img_base_path . "/" . $addressableFallback; + $uicons = true; + break; }else if(file_exists($p_img_base_path . "/" . $uicons_icon) && filesize($p_img_base_path . "/" . $uicons_icon) > 0) { $img_file = $p_img_base_path . "/" . $uicons_icon; $uicons = true; From 5e04e302179bfe22247ea1499a700ec0cdd1ab84 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 28 Dec 2022 09:32:00 +0200 Subject: [PATCH 221/367] Added ability to configure timezone for raidhour creator --- .../automate_raid_hour_creation/config.json.example | 9 +++++---- .../automate_raid_hour_creation/raid_hour_creator.php | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/tools/automate_raid_hour_creation/config.json.example b/core/tools/automate_raid_hour_creation/config.json.example index 61312b10..4bc04876 100644 --- a/core/tools/automate_raid_hour_creation/config.json.example +++ b/core/tools/automate_raid_hour_creation/config.json.example @@ -6,10 +6,11 @@ "RAID_HOUR_EVENT_ID":"2", "RAID_CREATOR_ID":"", "CHAT_ID": "", + "TIMEZONE": "Europe/Helsinki", "GYM_INFOS": [ - [1,"<-Gym id there and event note for 1st gym here"], - [2,"<-Gym id there and event note for 2nd gym here"], - [3,"<-Gym id there and event note for 3rd gym here"] - ], + [1,"<-Gym id there and event note for 1st gym here"], + [2,"<-Gym id there and event note for 2nd gym here"], + [3,"<-Gym id there and event note for 3rd gym here"] + ], "URL": "https://www.yourhost.com/PokemonRaidBot/index.php?apikey=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" } diff --git a/core/tools/automate_raid_hour_creation/raid_hour_creator.php b/core/tools/automate_raid_hour_creation/raid_hour_creator.php index e1e81ac2..5652fc03 100644 --- a/core/tools/automate_raid_hour_creation/raid_hour_creator.php +++ b/core/tools/automate_raid_hour_creation/raid_hour_creator.php @@ -11,6 +11,9 @@ die('Config file not valid JSON, cannot continue.'); } +$tz = $config->TIMEZONE; +date_default_timezone_set($tz); + // Establish mysql connection. // TODO(artanicus): This should be centralized & imported instead of duplicated $dbh = new PDO('mysql:host=' . $config->DB_HOST . ';dbname=' . $config->DB_NAME . ';charset=utf8mb4', $config->DB_USER, $config->DB_PASSWORD, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); From ce754bc655b2450e56ff0a40486b3b55f40e2803 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 28 Dec 2022 09:51:12 +0200 Subject: [PATCH 222/367] Fixed automatic boss updater --- mods/update_bosses.php | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/mods/update_bosses.php b/mods/update_bosses.php index c0ef3e32..2dfab5bd 100644 --- a/mods/update_bosses.php +++ b/mods/update_bosses.php @@ -6,7 +6,6 @@ $levels = $data['id']; $source = $data['arg']; -$add_mons = []; if($levels != 'scheduled') { $get_levels = explode(',',$levels); @@ -23,11 +22,10 @@ $data = json_decode($data,true); debug_log('Processing received ccev pogoinfo raid bosses for each raid level'); - foreach($data as $tier => $tier_pokemon) { - // Process raid level? - if(!in_array($tier,$get_levels)) continue; - - foreach($tier_pokemon as $raid_id_form) { + $sql_values = ''; + foreach($get_levels as $level) { + // Process requested levels + foreach($data[$level] as $raid_id_form) { if(!isset($raid_id_form['id'])) continue; $dex_id = $raid_id_form['id']; $dex_form = 0; @@ -46,13 +44,13 @@ $dex_form = $result['pokemon_form_id']; } - $add_mons[] = [ - 'pokedex_id' => $dex_id, - 'pokemon_form_id' => $dex_form, - 'raid_level' => $tier, - ]; + $sql_values .= '(\'' . implode("', '", [$dex_id, $dex_form, $level]) . '\'),'; } } + if($sql_values == '') exit; + $sql_values = rtrim($sql_values, ','); + + $sql = 'INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) VALUES ' . $sql_values . ';'; }elseif($levels == 'scheduled') { require_once(LOGIC_PATH . '/read_upcoming_bosses.php'); $data = read_upcoming_bosses(true); @@ -63,15 +61,5 @@ info_log("Invalid argumens supplied to update_bosses!"); exit(); } -$count = count($add_mons); -$sql_values = ''; -if($count == 0) exit; - -$sql_cols = implode(", ", array_keys($add_mons[0])); -for($i=0;$i<$count;$i++) { - if($i > 0) $sql_values .= ','; - $sql_values .= '(\'' . implode("', '", array_values($add_mons[$i])) . '\')'; -} -$sql = 'INSERT INTO raid_bosses (' . $sql_cols . ') VALUES ' . $sql_values . ';'; my_query($sql); From 88003668d922e2255af92ec9c35cb63174dfa2f0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 28 Dec 2022 13:50:04 +0200 Subject: [PATCH 223/367] Support for multiple config files If you are running multiple Telegram bots and want to use just one endpoint on server you can create multiple config & access files by prepending them with `botname-`. You also need to update your Telegram, cron and scanner webhook urls to include `bot_name` parameter. Telegram webhook can be set using the provided webhook.html --- commands/get.php | 4 ++-- commands/raid_from_webhook.php | 4 ++-- commands/set.php | 6 +++--- core/bot/apikey.php | 13 ++----------- core/bot/config.php | 8 +++++++- core/bot/user.php | 11 +++++++++-- core/tools/webhook.html | 9 +++++++++ docs/config.rst | 16 ++++++++++++++++ logic/bot_upgrade_check.php | 2 +- logic/gymMenu.php | 2 +- mods/trainerGymarea.php | 2 +- 11 files changed, 53 insertions(+), 24 deletions(-) diff --git a/commands/get.php b/commands/get.php index e4d97a7e..86133256 100644 --- a/commands/get.php +++ b/commands/get.php @@ -20,14 +20,14 @@ $allowed_numbers = explode(',', $config->ALLOW_ONLY_NUMBERS); // Get config. -$cfile = CONFIG_PATH . '/config.json'; +$cfile = botSpecificConfigFile('config.json'); if(is_file($cfile)) { $str = file_get_contents($cfile); $json = json_decode($str, true); } // Get config aliases. -$afile = CONFIG_PATH . '/alias.json'; +$afile = botSpecificConfigFile('alias.json'); if(is_file($afile)) { $astr = file_get_contents($afile); $ajson = json_decode($astr, true); diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 13177a4e..21c3c97a 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -22,8 +22,8 @@ function isPointInsidePolygon($point, $vertices) { } // Geofences $geofences = false; -if(file_exists(CONFIG_PATH . '/geoconfig.json')) { - $raw = file_get_contents(CONFIG_PATH . '/geoconfig.json'); +if(file_exists(botSpecificConfigFile('geoconfig.json'))) { + $raw = file_get_contents(botSpecificConfigFile('geoconfig.json')); $geofences = json_decode($raw, true); $geofence_polygons = []; foreach($geofences as $geofence) { diff --git a/commands/set.php b/commands/set.php index a18f8c14..0f104431 100644 --- a/commands/set.php +++ b/commands/set.php @@ -51,7 +51,7 @@ } // Config -$cfile = CONFIG_PATH . '/config.json'; +$cfile = botSpecificConfigFile('config.json'); if(is_file($cfile)) { $str = file_get_contents($cfile); $json = json_decode($str, true); @@ -59,7 +59,7 @@ // Real config name or alias? $alias = ''; -$afile = CONFIG_PATH . '/alias.json'; +$afile = botSpecificConfigFile('alias.json'); if(is_file($afile)) { debug_log('Checking alias for config option ' . $config_name); $astr = file_get_contents($afile); @@ -126,7 +126,7 @@ // Write to file. if(json_last_error() === JSON_ERROR_NONE) { - file_put_contents(CONFIG_PATH . '/config.json', $jsonString); + file_put_contents(botSpecificConfigFile('config.json'), $jsonString); $msg = getTranslation('config_updated') . ':' . CR . CR; $msg .= '' . (empty($alias) ? $config_name : $alias) . '' . CR; $msg .= getTranslation('old_value') . SP . $old_value . CR; diff --git a/core/bot/apikey.php b/core/bot/apikey.php index 2289639a..30898380 100644 --- a/core/bot/apikey.php +++ b/core/bot/apikey.php @@ -8,16 +8,12 @@ function get_verified_update(){ global $config, $argv; // Get api key from get parameters. - if(isset($_GET['apikey'])) { - $apiKey = $_GET['apikey']; - // Get api key from argv. - } elseif(!empty($argv[1])) { - $apiKey = $argv[1]; - } else { + if(!isset($_GET['apikey'])) { debug_log('Called without apikey, returning empty content.'); http_response_code(204); // HTTP 204: No Content exit(); } + $apiKey = $_GET['apikey']; // Check if hashed api key is matching config. if (hash('sha512', $apiKey) != strtolower($config->APIKEY_HASH)) { @@ -35,11 +31,6 @@ function get_verified_update(){ if($content) { // Decode the json string. $update = json_decode($content, true); - } elseif(!empty($argv[2])) { - $update = json_decode($argv[2], true); - } - - if ($update) { debug_log_incoming($update, '<'); } diff --git a/core/bot/config.php b/core/bot/config.php index 9baca4e1..b4365a97 100644 --- a/core/bot/config.php +++ b/core/bot/config.php @@ -68,7 +68,7 @@ function build_config() { // Iterate over subconfigs getting defaults and merging in custom overrides foreach ($default_configs as $filename) { $dfile = CONFIG_PATH . '/' . $filename; // config defaults, e.g. defaults-config.json - $cfile = CONFIG_PATH . '/' . str_replace('defaults-', '', $filename); // custom config overrides e.g. config.json + $cfile = botSpecificConfigFile(str_replace('defaults-', '', $filename)); // custom config overrides e.g. config.json // Get default config as an array so we can do an array merge later $config_array = get_config_array($dfile); @@ -89,6 +89,12 @@ function build_config() { // Return the whole multi-source config as an Object return (Object)$config; } +function botSpecificConfigFile($filename) { + $prefix = ''; + if (isset($_GET['bot_name']) && !empty($_GET['bot_name'])) + $prefix = $_GET['bot_name'] . '-'; + return CONFIG_PATH . '/' . $prefix . $filename; +} // Object, access a config option with e.g. $config->VERSION $config = build_config(); diff --git a/core/bot/user.php b/core/bot/user.php index 74847875..4314efc3 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -59,9 +59,16 @@ public function privilegeCheck() { 'kicked' => 'kicked', ]; + $privilegeArray = [ + 'privileges' => [], + 'grantedBy' => '', + ]; $accessFilesList = $tg_json = []; foreach(glob(ACCESS_PATH . '/*') as $filePath) { $filename = str_replace(ACCESS_PATH . '/', '', $filePath); + // If bot name is set read only bot specific files + if (isset($_GET['bot_name']) && !empty($_GET['bot_name']) && !preg_match('/^' . $_GET['bot_name'] . '/', $filename)) + continue; // Get chat object - remove comments from filename // This way some kind of comment like the channel name can be added to the end of the filename, e.g. creator-100123456789-MyPokemonChannel to easily differ between access files :) preg_match('/(access)('.$this->userId.')|(access|creator|admins|members|restricted|kicked)(-[0-9]+)/', '-' . $filename, $result); @@ -127,14 +134,14 @@ public function privilegeCheck() { 'privileges' => $privilegeList, 'grantedBy' => $accessFile, ]; - my_query('UPDATE users SET privileges = ? WHERE user_id = ? LIMIT 1', [json_encode($privilegeArray), $this->userId]); - $this->userPrivileges = $privilegeArray; break; } // Deny access debug_log($chatId, 'Negative result on access check for chat:'); debug_log('Continuing with next chat...'); } + my_query('UPDATE users SET privileges = ? WHERE user_id = ? LIMIT 1', [json_encode($privilegeArray), $this->userId]); + $this->userPrivileges = $privilegeArray; } /** diff --git a/core/tools/webhook.html b/core/tools/webhook.html index 92bf78f3..2e03f318 100644 --- a/core/tools/webhook.html +++ b/core/tools/webhook.html @@ -15,6 +15,11 @@


+ +

+ +

+

@@ -64,6 +69,7 @@ el: '#app', data: { token: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', + botname: '', maxconnection: '80', port: '', host: 'https://' + window.location.hostname + location.pathname.replace(/[^/]*$/, '') @@ -94,6 +100,9 @@ var bot = document.createElement('a'); bot.href = this.host; bot_string = bot.origin + port_string + bot.pathname.replace(/\/?$/, '/') + 'index.php?apikey=' + this.token; + if (this.botname) { + bot_string = bot_string + '&bot_name=' + this.botname + } return bot_string } diff --git a/docs/config.rst b/docs/config.rst index be6e7aca..e67a9eb5 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -94,6 +94,22 @@ How to make a Supergroup * Once a group has been converted to a Supergroup it cannot go back to a normal Group, even if you change back the option that caused it to convert. * Be aware that the group ID will change completely when the group gets converted so you'll need to find it again! +Configuring multiple bots +------------------------- + +If you want to run multiple Telegram bots using this directory, you can create for each of them config and access files by prepending them with a unique name: + +.. code-block:: + +access/bot1-creator111222333 +access/bot2-creator111222333 +config/bot1-config.json +config/bot1-geoconfig.json +config/bot2-config.json +config/bot2-geoconfig.json + +When setting webhook to Telegram using ``webhook.html`` you must set the matching bot name. + Database connection ------------------- diff --git a/logic/bot_upgrade_check.php b/logic/bot_upgrade_check.php index f995cb0d..edf9d639 100644 --- a/logic/bot_upgrade_check.php +++ b/logic/bot_upgrade_check.php @@ -7,7 +7,7 @@ function upgrade_config_version($version) { debug_log('Bumping config.json VERSION to: ' . $version); - return write_config_array(array("VERSION" => $version), CONFIG_PATH . '/config.json'); + return write_config_array(array("VERSION" => $version), botSpecificConfigFile('config.json')); } /** diff --git a/logic/gymMenu.php b/logic/gymMenu.php index 352dc55d..5e3ae42b 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -93,7 +93,7 @@ function gymMenu($buttonAction, $showHidden, $stage, $firstLetter = false, $gyma function getGymareas($gymareaId, $stage, $buttonAction) { $gymareaKeys = $points = []; $gymareaName = ''; - $json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'), 1); + $json = json_decode(file_get_contents(botSpecificConfigFile('geoconfig_gym_areas.json')), 1); foreach($json as $area) { if($gymareaId == $area['id']) { foreach($area['path'] as $point) { diff --git a/mods/trainerGymarea.php b/mods/trainerGymarea.php index 7a1cbc3e..f011c5d3 100644 --- a/mods/trainerGymarea.php +++ b/mods/trainerGymarea.php @@ -22,7 +22,7 @@ // Init empty keys array. $keys = []; -$json = json_decode(file_get_contents(CONFIG_PATH . '/geoconfig_gym_areas.json'), 1); +$json = json_decode(file_get_contents(botSpecificConfigFile('geoconfig_gym_areas.json')), 1); $gymareaName = ''; foreach($json as $area) { if($area['id'] == $gymarea) $gymareaName = $area['name']; From fd254acc8a2e8b2527622394d34b8c270fd11589 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 9 Jan 2023 14:53:33 +0200 Subject: [PATCH 224/367] Documentation formatting fix --- docs/config.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index e67a9eb5..dfda1a87 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -101,12 +101,12 @@ If you want to run multiple Telegram bots using this directory, you can create f .. code-block:: -access/bot1-creator111222333 -access/bot2-creator111222333 -config/bot1-config.json -config/bot1-geoconfig.json -config/bot2-config.json -config/bot2-geoconfig.json + access/bot1-creator111222333 + access/bot2-creator111222333 + config/bot1-config.json + config/bot1-geoconfig.json + config/bot2-config.json + config/bot2-geoconfig.json When setting webhook to Telegram using ``webhook.html`` you must set the matching bot name. From 74b296df85d54027a10591441bf22fdac98c41e3 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 9 Jan 2023 14:58:02 +0200 Subject: [PATCH 225/367] Second try rst is stupid --- docs/config.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index dfda1a87..7b6e8fd8 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -101,12 +101,12 @@ If you want to run multiple Telegram bots using this directory, you can create f .. code-block:: - access/bot1-creator111222333 - access/bot2-creator111222333 - config/bot1-config.json - config/bot1-geoconfig.json - config/bot2-config.json - config/bot2-geoconfig.json + access/bot1-creator111222333 + access/bot2-creator111222333 + config/bot1-config.json + config/bot1-geoconfig.json + config/bot2-config.json + config/bot2-geoconfig.json When setting webhook to Telegram using ``webhook.html`` you must set the matching bot name. From 2470b0adec82f0d874e6a7c1672f4a30968537ca Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 26 Jan 2023 12:02:37 +0200 Subject: [PATCH 226/367] Support for primal raids and mons Got most of the stuff covered. Won't know for certain until primals get added to game master --- constants.php | 11 +++-- images/raid_eggs/pokemon_icon_99910_00.png | Bin 0 -> 23130 bytes lang/language.json | 26 +++++++++++ lang/pokemon_forms.json | 13 ++++++ logic/get_local_pokemon_name.php | 2 +- logic/read_upcoming_bosses.php | 8 ++-- logic/resolve_boss_name_to_ids.php | 2 +- mods/getdb.php | 52 ++++++++++----------- mods/pogoinfo.php | 6 +-- mods/pokedex_disable_raids.php | 14 +++--- mods/pokedex_set_raid_level.php | 2 +- sql/pokemon-raid-bot.sql | 4 +- sql/upgrade/5.sql | 4 +- 13 files changed, 95 insertions(+), 49 deletions(-) create mode 100644 images/raid_eggs/pokemon_icon_99910_00.png diff --git a/constants.php b/constants.php index 22ea4879..91f90af4 100644 --- a/constants.php +++ b/constants.php @@ -3,10 +3,11 @@ define('PORTAL_IMAGES_PATH', IMAGES_PATH . '/gyms'); // raid levels constant -define('RAID_LEVEL_ALL', 'X98765431'); +define('RAID_LEVEL_ALL', ['X', 10, 9, 8, 7, 6, 5, 4, 3, 1]); // Raid eggs. $eggs = array( + '99910', // Level 10 / Primal raid '9999', // Level 9 / Elite raid '9998', // Level 8 / Ultra beast '9997', // Level 7 / Legendary Mega @@ -22,7 +23,7 @@ define('RAID_LEVEL_LOCAL_ONLY', [4, 9]); // Levels available for import at PokeBattler -$pokebattler_levels = array('9', '8', '7', '6', '5', '4', '3', '1'); +$pokebattler_levels = array('10', '9', '8', '7', '6', '5', '4', '3', '1'); // Map our raid levels to tier names PokeBattler uses $pokebattler_level_map = [ @@ -34,6 +35,7 @@ '7' => 'MEGA_5', '8' => 'ULTRA_BEAST', '9' => 'ELITE', + '10' => 'PRIMAL', ]; $pokebattler_pokemon_map = [ @@ -42,8 +44,11 @@ 'ZAMAZENTA' => 'ZAMAZENTA_HERO_FORM', ]; +// Storing Primal Kyogre and Groudon for now. These are not needed if Pokebattler starts using own raid tier for primals +define('PRIMAL_MONS', [382, 383]); + // Limit the tiers of upcoming raid bosses imported from PokeBattler to legendary and mega -$pokebattler_import_future_tiers = [5, 6, 7, 8, 9]; +$pokebattler_import_future_tiers = [5, 6, 7, 8, 9, 10]; // Default language. defined('DEFAULT_LANGUAGE') or define('DEFAULT_LANGUAGE', 'EN'); diff --git a/images/raid_eggs/pokemon_icon_99910_00.png b/images/raid_eggs/pokemon_icon_99910_00.png new file mode 100644 index 0000000000000000000000000000000000000000..db4530675bbb76692100f9e207b8dded5c3f99f9 GIT binary patch literal 23130 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'Y-m-d H:i:s'); $boss = $news['pokemon']; - if(in_array($news['pokemon'], array_keys($pokebattler_pokemon_map))) { - $boss = $pokebattler_pokemon_map[$news['pokemon']]; - } $dex_id_form = resolve_boss_name_to_ids($boss); + + // In case Pokebattler keeps using RAID_LEVEL_MEGA_5 (legendary mega tier) for primal raids + if(in_array($dex_id_form[0], PRIMAL_MONS) && $raid_level_id == 7) { + $raid_level_id = 10; + } if($prev_start != $date_start or $prev_end != $date_end) { $list.= CR . EMOJI_CLOCK . ' ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; $prev_rl = ''; diff --git a/logic/resolve_boss_name_to_ids.php b/logic/resolve_boss_name_to_ids.php index e42b8baf..14ee7f3a 100644 --- a/logic/resolve_boss_name_to_ids.php +++ b/logic/resolve_boss_name_to_ids.php @@ -9,7 +9,7 @@ function resolve_boss_name_to_ids($pokemon_name) { $name = $pokemon_name; $form = 'normal'; // Pokemon name ending with "_FORM" ? - if (preg_match('/(MEGA|MEGA_Y|MEGA_X|FORM)$/', $pokemon_name)) { + if (preg_match('/(MEGA|MEGA_Y|MEGA_X|PRIMAL|FORM)$/', $pokemon_name)) { debug_log('Pokemon with a special form received: ' . $pokemon_name); // Remove "_FORM" $pokemon = str_replace('_FORM', '', $pokemon_name); diff --git a/mods/getdb.php b/mods/getdb.php index 3ba6ef70..ff377d09 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -6,7 +6,7 @@ require_once(LOGIC_PATH . '/sql_utils.php'); require_once(LOGIC_PATH . '/debug.php'); require_once(LOGIC_PATH . '/curl_get_contents.php'); -$proto_url = 'https://raw.githubusercontent.com/Furtif/POGOProtos-Swift/master/Sources/POGOProtos/POGOProtos.pb.swift'; +$proto_url = 'https://raw.githubusercontent.com/123FLO321/POGOProtos-Swift/master/Sources/POGOProtos/POGOProtos.pb.swift'; $game_master_url = 'https://raw.githubusercontent.com/PokeMiners/game_masters/master/latest/latest.json'; $error = false; @@ -31,19 +31,19 @@ $PRE .= '(pokedex_id, pokemon_name, pokemon_form_name, pokemon_form_id, min_cp, max_cp, min_weather_cp, max_weather_cp, type, type2, weather) VALUES'; foreach($eggs as $egg) { $pokemon_id = $egg; - $pokemon_name = 'Level '. $egg[3] .' Egg'; + $pokemon_name = 'Level '. str_replace('999', '', $egg) .' Egg'; $pokemon_array[$pokemon_id]['normal'] = [ - 'pokemon_name'=>$pokemon_name, - 'pokemon_form_name'=> 'normal', - 'pokemon_form_id'=>0, - 'shiny'=>0, - 'min_cp'=>0, - 'max_cp'=>0, - 'min_weather_cp'=>0, - 'max_weather_cp'=>0, + 'pokemon_name' => $pokemon_name, + 'pokemon_form_name' => 'normal', + 'pokemon_form_id' => 0, + 'shiny' => 0, + 'min_cp' => 0, + 'max_cp' => 0, + 'min_weather_cp' => 0, + 'max_weather_cp' => 0, 'type' => '', 'type2' => '', - 'weather'=>0 + 'weather' => 0, ]; } $i = 0; @@ -101,7 +101,7 @@ function sendResults($msg, $update, $error = false) { } function calculate_cps($base_stats) { // CP = (Attack * Defense^0.5 * Stamina^0.5 * CP_Multiplier^2) / 10 - $cp_multiplier = array(20 => 0.5974 ,25 =>0.667934 ); + $cp_multiplier = array(20 => 0.5974, 25 => 0.667934); $min = floor((($base_stats['baseAttack']+10)*(($base_stats['baseDefense']+10)**0.5)*(($base_stats['baseStamina']+10)**0.5)*$cp_multiplier[20]**2)/10); $max = floor((($base_stats['baseAttack']+15)*(($base_stats['baseDefense']+15)**0.5)*(($base_stats['baseStamina']+15)**0.5)*$cp_multiplier[20]**2)/10); $min_weather = floor((($base_stats['baseAttack']+10)*(($base_stats['baseDefense']+10)**0.5)*(($base_stats['baseStamina']+10)**0.5)*$cp_multiplier[25]**2)/10); @@ -152,7 +152,7 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { // Set ID's for mega evolutions // Using negative to prevent mixup with actual form ID's // Collected from pogoprotos (hoping they won't change, so hard coding them here) - $mega_ids = array('MEGA'=>-1,'MEGA_X'=>-2,'MEGA_Y'=>-3); + $mega_ids = array('MEGA' => -1, 'MEGA_X' => -2, 'MEGA_Y' => -3, 'PRIMAL' => -4); $weatherboost_table = array( 'POKEMON_TYPE_BUG' => '3', @@ -177,17 +177,17 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { if(!$master_file = curl_get_contents($game_master_url)) return false; $master = json_decode($master_file, true); foreach($master as $row) { - $part = explode('_',$row['templateId']); + $part = explode('_', $row['templateId']); $form_data = []; $pokemon_id = ''; - if(count($part)<2) continue; + if(count($part) < 2) continue; if(preg_match('/FORMS_V([0-9]*)_POKEMON_([a-zA-Z0-9_]*)/', $row['templateId'], $matches)) { // Found Pokemon form data $pokemon_id = (int)$matches[1]; $pokemon_name = $matches[2]; // Get pokemon forms if(!isset($row['data']['formSettings']['forms']) or empty($row['data']['formSettings']['forms'][0])) { - $form_data[] = array('form'=>$pokemon_name.'_NORMAL'); + $form_data[] = array('form' => $pokemon_name . '_NORMAL'); }else { $form_data = $row['data']['formSettings']['forms']; } @@ -198,15 +198,15 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { $form_id = $form_ids[$form['form']] ?? 0; $pokemon_array[$pokemon_id][$form_name] = [ - 'pokemon_name'=>$poke_name, - 'pokemon_form_name'=>$form_name, - 'pokemon_form_id'=>$form_id, + 'pokemon_name' => $poke_name, + 'pokemon_form_name' => $form_name, + 'pokemon_form_id' => $form_id, ]; } }else if (preg_match('/V([0-9]*)_POKEMON_([a-zA-Z0-9_]*)/', $row['templateId'], $matches) && isset($row['data']['pokemonSettings'])) { // Found Pokemon data $pokemon_id = (int)$matches[1]; - $form_name = str_replace($row['data']['pokemonSettings']['pokemonId']."_","",$matches[2]); + $form_name = str_replace($row['data']['pokemonSettings']['pokemonId'] . '_', '', $matches[2]); if($form_name == 'PURIFIED' || $form_name == 'SHADOW' || $form_name == 'NORMAL' || !isset($pokemon_array[$pokemon_id]) || !isset($row['data']['pokemonSettings']['stats']['baseAttack']) @@ -218,16 +218,16 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { if($form_name != $row['data']['pokemonSettings']['pokemonId']) { $form_name = strtolower($form_name); }else { - $form_name = "normal"; + $form_name = 'normal'; } [$min_cp, $max_cp, $min_weather_cp, $max_weather_cp] = calculate_cps($row['data']['pokemonSettings']['stats']); - $type = strtolower(str_replace('POKEMON_TYPE_','', $row['data']['pokemonSettings']['type'])); + $type = strtolower(str_replace('POKEMON_TYPE_', '', $row['data']['pokemonSettings']['type'])); $type2 = ''; $weather = $weatherboost_table[$row['data']['pokemonSettings']['type']]; if(isset($row['data']['pokemonSettings']['type2'])) { - $type2 = strtolower(str_replace('POKEMON_TYPE_','', $row['data']['pokemonSettings']['type2'])); + $type2 = strtolower(str_replace('POKEMON_TYPE_', '', $row['data']['pokemonSettings']['type2'])); # Add type2 weather boost only if there is a second type and it's not the same weather as the first type! if($weatherboost_table[$row['data']['pokemonSettings']['type2']] != $weatherboost_table[$row['data']['pokemonSettings']['type']]) { @@ -258,14 +258,14 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { foreach($row['data']['pokemonSettings']['tempEvoOverrides'] as $temp_evolution) { if(!isset($temp_evolution['tempEvoId'])) continue; - $mega_evolution_name = str_replace('TEMP_EVOLUTION_','',$temp_evolution['tempEvoId']); + $mega_evolution_name = str_replace('TEMP_EVOLUTION_', '', $temp_evolution['tempEvoId']); // We only override the types for megas // weather info is used to display boosts for caught mons, which often are different from mega's typing - $typeOverride = strtolower(str_replace('POKEMON_TYPE_','', $temp_evolution['typeOverride1'])); + $typeOverride = strtolower(str_replace('POKEMON_TYPE_', '', $temp_evolution['typeOverride1'])); $typeOverride2 = ''; if(isset($temp_evolution['typeOverride2'])) { - $typeOverride2 = strtolower(str_replace('POKEMON_TYPE_','', $temp_evolution['typeOverride2'])); + $typeOverride2 = strtolower(str_replace('POKEMON_TYPE_', '', $temp_evolution['typeOverride2'])); } $pokemon_array[$pokemon_id][$mega_evolution_name] = [ 'pokemon_name' => $pokemon_array[$pokemon_id][$form_name]['pokemon_name'], diff --git a/mods/pogoinfo.php b/mods/pogoinfo.php index 2e200a6f..4ee997cb 100644 --- a/mods/pogoinfo.php +++ b/mods/pogoinfo.php @@ -25,7 +25,7 @@ $keys = []; // All raid level keys. - $keys[][] = button(getTranslation('pokedex_all_raid_level'), ['pogoinfo', 'rl' => RAID_LEVEL_ALL]); + $keys[][] = button(getTranslation('pokedex_all_raid_level'), ['pogoinfo', 'rl' => 'all']); // Add key for each raid level foreach($levels as $l) { @@ -66,7 +66,7 @@ $raiddata = json_decode($raiddata,true); // All raid levels? -if($id == RAID_LEVEL_ALL) { +if($id == 'all') { $get_levels = $levels; $clear = "'6','5','3','1'"; } else { @@ -164,7 +164,7 @@ if(count($exclusions) == 3) continue; $keyText = $local_pokemon; - if($id == RAID_LEVEL_ALL) { + if($id == 'all') { $keyText = '[' . ($tier) . ']' . SP . $local_pokemon; } $e = $exclusions; diff --git a/mods/pokedex_disable_raids.php b/mods/pokedex_disable_raids.php index eb2d2e96..300324fb 100644 --- a/mods/pokedex_disable_raids.php +++ b/mods/pokedex_disable_raids.php @@ -16,10 +16,10 @@ $arg = $data['a'] ?? 0; // Specify raid levels. -$levels = str_split(RAID_LEVEL_ALL); +$levels = RAID_LEVEL_ALL; // All raid levels? -if($id == RAID_LEVEL_ALL) { +if($id == 'all') { $clear = "'" . implode("','", $levels) . "'"; } else { $clear = "'" . $id . "'"; @@ -34,7 +34,7 @@ $keys = []; // All raid level keys. - $keys[][] = button(getTranslation('pokedex_all_raid_level'), ['pokedex_disable_raids', 'rl' => RAID_LEVEL_ALL, 'a' => 1]); + $keys[][] = button(getTranslation('pokedex_all_raid_level'), ['pokedex_disable_raids', 'rl' => 'all', 'a' => 1]); // Add key for each raid level foreach($levels as $l) { @@ -103,15 +103,15 @@ $msg = '' . getTranslation('disabled_raid_level') . ':' . CR; // All levels - if($id == RAID_LEVEL_ALL) { + if($id == 'all') { foreach($levels as $lv) { $msg .= getTranslation($lv . 'stars') . CR; } - // Specific level - } else { + // Specific level + } else { $msg .= getTranslation($id . 'stars'); - } + } // Empty keys. $keys = []; diff --git a/mods/pokedex_set_raid_level.php b/mods/pokedex_set_raid_level.php index 3540d1fa..e9350057 100644 --- a/mods/pokedex_set_raid_level.php +++ b/mods/pokedex_set_raid_level.php @@ -25,7 +25,7 @@ // Set raid level or show raid levels? if($newLevel === false) { - $raid_levels = str_split('0' . RAID_LEVEL_ALL); + $raid_levels = array_merge([0], RAID_LEVEL_ALL); // Init empty keys array. $keys = []; diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 98b7c56a..847aa389 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -102,7 +102,7 @@ CREATE TABLE `raid_bosses` ( `pokemon_form_id` int(4) DEFAULT NULL, `date_start` datetime NOT NULL DEFAULT '1970-01-01 00:00:01', `date_end` datetime NOT NULL DEFAULT '2038-01-19 03:14:07', - `raid_level` enum('1','2','3','4','5','6','7','8','9','X') DEFAULT NULL, + `raid_level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL, `scheduled` TINYINT(1) NULL DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -116,7 +116,7 @@ CREATE TABLE `raids` ( `end_time` datetime DEFAULT NULL, `gym_team` enum('mystic','valor','instinct') DEFAULT NULL, `gym_id` int(10) unsigned NOT NULL, - `level` enum('1','2','3','4','5','6','7','8','9','X') DEFAULT NULL, + `level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL, `move1` varchar(255) DEFAULT NULL, `move2` varchar(255) DEFAULT NULL, `gender` varchar(255) DEFAULT NULL, diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index d6223209..d90cf1ed 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -6,8 +6,8 @@ CREATE TABLE IF NOT EXISTS `photo_cache` (`id` varchar(100) NOT NULL, `unique_id ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); -ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','8','9','X') DEFAULT NULL; -ALTER TABLE `raid_bosses` MODIFY `raid_level` enum('1','2','3','4','5','6','7','8','9','X') DEFAULT NULL; +ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; +ALTER TABLE `raid_bosses` MODIFY `raid_level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; ALTER TABLE `events` ADD COLUMN IF NOT EXISTS `pokemon_title` TINYINT(1) NULL DEFAULT 1 AFTER `hide_raid_picture`; From 4515b9df2a456116b1fd5d8c8418f58a76e0c86b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 27 Jan 2023 09:50:11 +0200 Subject: [PATCH 227/367] Increased the size of pokemon_name column --- sql/pokemon-raid-bot.sql | 2 +- sql/upgrade/5.sql | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 847aa389..48e722e7 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -82,7 +82,7 @@ CREATE TABLE `photo_cache` ( CREATE TABLE `pokemon` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `pokedex_id` int(10) unsigned NOT NULL, - `pokemon_name` varchar(12) DEFAULT NULL, + `pokemon_name` varchar(30) DEFAULT NULL, `pokemon_form_name` varchar(45) DEFAULT NULL, `pokemon_form_id` int(4) DEFAULT NULL, `min_cp` int(10) unsigned NOT NULL DEFAULT 0, diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index d90cf1ed..69f8524c 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -6,9 +6,10 @@ CREATE TABLE IF NOT EXISTS `photo_cache` (`id` varchar(100) NOT NULL, `unique_id ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); -ALTER TABLE `raids` MODIFY `level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; -ALTER TABLE `raid_bosses` MODIFY `raid_level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; +ALTER TABLE `raids` CHANGE COLUMN IF EXISTS `level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; +ALTER TABLE `raid_bosses` CHANGE COLUMN IF EXISTS `raid_level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; ALTER TABLE `events` ADD COLUMN IF NOT EXISTS `pokemon_title` TINYINT(1) NULL DEFAULT 1 AFTER `hide_raid_picture`; ALTER TABLE `pokemon` DROP COLUMN IF EXISTS `asset_suffix`; +ALTER TABLE `pokemon` CHANGE COLUMN IF EXISTS `pokemon_name` varchar(30) DEFAULT NULL; From c5f90737fd3c38bc736a99a7d1df6662fc72f3ee Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 27 Jan 2023 10:09:01 +0200 Subject: [PATCH 228/367] Fixed new_boss alert to use recipient language --- logic/alarm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/alarm.php b/logic/alarm.php index f84a50f8..4efa8cc1 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -138,7 +138,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text .= create_traincode_msg($trainercode); } else if($action == 'new_boss') { - $msg_text = '' . getTranslation('alert_raid_boss') . '' . CR; + $msg_text = '' . getTranslation('alert_raid_boss', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_EGG . SP . '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . '' . CR; From a23ef818d09605ed78332920ecb66e41ee16ebbc Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 27 Jan 2023 10:47:38 +0200 Subject: [PATCH 229/367] Fixed update queries --- sql/upgrade/5.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index 69f8524c..48504fe9 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -6,10 +6,10 @@ CREATE TABLE IF NOT EXISTS `photo_cache` (`id` varchar(100) NOT NULL, `unique_id ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); -ALTER TABLE `raids` CHANGE COLUMN IF EXISTS `level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; -ALTER TABLE `raid_bosses` CHANGE COLUMN IF EXISTS `raid_level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; +ALTER TABLE `raids` CHANGE COLUMN IF EXISTS `level` `level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; +ALTER TABLE `raid_bosses` CHANGE COLUMN IF EXISTS `raid_level` `raid_level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; ALTER TABLE `events` ADD COLUMN IF NOT EXISTS `pokemon_title` TINYINT(1) NULL DEFAULT 1 AFTER `hide_raid_picture`; ALTER TABLE `pokemon` DROP COLUMN IF EXISTS `asset_suffix`; -ALTER TABLE `pokemon` CHANGE COLUMN IF EXISTS `pokemon_name` varchar(30) DEFAULT NULL; +ALTER TABLE `pokemon` CHANGE COLUMN IF EXISTS `pokemon_name` `pokemon_name` varchar(30) DEFAULT NULL; From 142720540f919312944e044ef167a3c4c462e014 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sat, 28 Jan 2023 11:48:54 +0200 Subject: [PATCH 230/367] Write out form proto data as well since we have it. Easier to debug some issues if you have a decent data source. --- mods/getdb.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mods/getdb.php b/mods/getdb.php index ff377d09..991524ec 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -22,6 +22,9 @@ if(!file_put_contents(ROOT_PATH.'/protos/costume.json', json_encode($costume, JSON_PRETTY_PRINT))) { sendResults('Failed to write costume data to protos/costume.json', $update, true); } +if(!file_put_contents(ROOT_PATH.'/protos/form.json', json_encode($form_ids, JSON_PRETTY_PRINT))) { + sendResults('Failed to write form data to protos/form.json', $update, true); +} // Parse the game master data together with form ids into format we can use $pokemon_array = parse_master_into_pokemon_table($form_ids, $game_master_url); if(!$pokemon_array) { From 6e50a8bd538574114a3e68ddcf13387b3f854752 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sat, 28 Jan 2023 12:09:26 +0200 Subject: [PATCH 231/367] Export pokemon.json from getdb for debug purposes etc. Also allow getdb to be run cleanly with php-cli to speed up development. --- mods/getdb.php | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 991524ec..8cdcfc82 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -11,25 +11,35 @@ $error = false; +# We only have an update if the call came from TG +if(!isset($update)){ + $update = false; +} + // Read the form ids from protos if (!$protos = get_protos($proto_url)) { sendResults('Failed to get protos.', $update, true); } [$form_ids, $costume] = $protos; +// Parse the game master data together with form ids into format we can use +$pokemon_array = parse_master_into_pokemon_table($form_ids, $game_master_url); +if(!$pokemon_array) { + sendResults('Failed to open game master file.', $update, true); +} -// Save costume data to json file +// Save our core datasets to json files for further use if(!file_put_contents(ROOT_PATH.'/protos/costume.json', json_encode($costume, JSON_PRETTY_PRINT))) { sendResults('Failed to write costume data to protos/costume.json', $update, true); } if(!file_put_contents(ROOT_PATH.'/protos/form.json', json_encode($form_ids, JSON_PRETTY_PRINT))) { sendResults('Failed to write form data to protos/form.json', $update, true); } -// Parse the game master data together with form ids into format we can use -$pokemon_array = parse_master_into_pokemon_table($form_ids, $game_master_url); -if(!$pokemon_array) { - sendResults('Failed to open game master file.', $update, true); +if(!file_put_contents(ROOT_PATH.'/protos/pokemon.json', json_encode($pokemon_array, JSON_PRETTY_PRINT))) { + sendResults('Failed to write pokemon data to protos/pokemon.json', $update, true); } + +// Craft egg data $PRE = 'INSERT INTO `pokemon`' . PHP_EOL; $PRE .= '(pokedex_id, pokemon_name, pokemon_form_name, pokemon_form_id, min_cp, max_cp, min_weather_cp, max_weather_cp, type, type2, weather) VALUES'; foreach($eggs as $egg) { @@ -49,6 +59,8 @@ 'weather' => 0, ]; } + +// Craft the rest of the pokemon data $i = 0; $dataSql = ''; foreach($pokemon_array as $pokemon_id => $forms) { @@ -97,9 +109,11 @@ function sendResults($msg, $update, $error = false) { info_log($msg); exit(); } - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], (!$error) ? 'OK!' : 'Error!', true); - $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['message']['chat']['id'], false, true); - curl_json_multi_request($tg_json); + if($update){ + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], (!$error) ? 'OK!' : 'Error!', true); + $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['message']['chat']['id'], false, true); + curl_json_multi_request($tg_json); + } exit; } function calculate_cps($base_stats) { From 391ff38c0975ea42d60d4f075bd67ba9eec610df Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sun, 29 Jan 2023 12:28:01 +0200 Subject: [PATCH 232/367] Rescue v6 refugees that have a different photo_cache structure --- sql/upgrade/5.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index 48504fe9..153fb75f 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -3,6 +3,9 @@ ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `gymarea` TINYINT UNSIGNED NULL AFT ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `privileges` TEXT NULL AFTER `gymarea`; CREATE TABLE IF NOT EXISTS `photo_cache` (`id` varchar(100) NOT NULL, `unique_id` varchar(45) NOT NULL, `pokedex_id` int(10) DEFAULT NULL, `form_id` int(4) DEFAULT NULL, `raid_id` int(10) unsigned DEFAULT NULL, `ended` tinyint(1) DEFAULT NULL, `end_time` DATETIME NULL, `start_time` DATETIME NULL, `gym_id` int(10) unsigned DEFAULT NULL, `standalone` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`unique_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `end_time` DATETIME DEFAULT NULL AFTER `ended`; +ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `start_time` DATETIME DEFAULT NULL AFTER `end_time`; + ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); From f696bd9b26e948f2b492b9b28f636e72990bdc18 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sun, 29 Jan 2023 14:25:21 +0200 Subject: [PATCH 233/367] Switch htaccess logic to default deny. Some of the newer files post restructuring were not protected with the previous strategy. --- .htaccess | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/.htaccess b/.htaccess index 9db9cb98..aa828807 100644 --- a/.htaccess +++ b/.htaccess @@ -1,11 +1,23 @@ -# Block access to all dot files -RedirectMatch 404 /\..*$ +# Deny everything by default +Order deny,allow +Deny from all -# Block access to .git files and folders -RedirectMatch 404 /\.git +# Allow plain requests that get routed to index.php + + Allow from all + -# Block access to .json and .sql files -RedirectMatch 404 /*\.(json|sql)$ +# Allow endpoints we expect to be called directly + + Allow from all + -# Block access to specifc folders -RedirectMatch 404 /(access|config|custom|ddos|lang|sql|screens)/ +# Allow webhook setup, it's just static + + Allow from all + + +# Allow metrics without appending / + + Allow from all + From fd9f30b13481ec10c8e9d1b861274c7e7a283568 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 29 Jan 2023 16:23:27 +0200 Subject: [PATCH 234/367] Updated PHP version in documentation --- docs/manual_install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual_install.rst b/docs/manual_install.rst index f6edcf12..57333d5e 100644 --- a/docs/manual_install.rst +++ b/docs/manual_install.rst @@ -9,7 +9,7 @@ Webserver requirements Preferably: * Apache2 -* PHP7 +* PHP8.1 * MySQL5 or MariaDB10. MariaDB is preferred, MySQL8 will cause some warnings. * Curl * SSL Certificate ( https://www.letsencrypt.org ) From ecc74ddb7c32ae2b20668f0207750d54c8acbb32 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 29 Jan 2023 16:23:59 +0200 Subject: [PATCH 235/367] Removec unnecessary check --- mods/getdb.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 8cdcfc82..1a440ee2 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -109,11 +109,9 @@ function sendResults($msg, $update, $error = false) { info_log($msg); exit(); } - if($update){ - $tg_json[] = answerCallbackQuery($update['callback_query']['id'], (!$error) ? 'OK!' : 'Error!', true); - $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['message']['chat']['id'], false, true); - curl_json_multi_request($tg_json); - } + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], (!$error) ? 'OK!' : 'Error!', true); + $tg_json[] = editMessageText($update['callback_query']['message']['message_id'], $msg, [], $update['callback_query']['message']['chat']['id'], false, true); + curl_json_multi_request($tg_json); exit; } function calculate_cps($base_stats) { From 0a6146c3f3956df142af26010581ee3b872b302c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 30 Jan 2023 10:56:02 +0200 Subject: [PATCH 236/367] New translations --- lang/pokemon.json | 1 - lang/pokemon_moves.json | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lang/pokemon.json b/lang/pokemon.json index 551858bd..7cfada92 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -4132,7 +4132,6 @@ "RU": "Крабролер" }, "pokemon_id_740": { - "PT-BR": "Crabominável", "EN": "Crabominable", "DE": "Krawell", "IT": "Crabominabile", diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index 04c020be..9bbd178b 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -2737,6 +2737,24 @@ "RU": "Метеоритный Луч", "ES": "Rayo Meteórico" }, + "pokemon_move_374": { + "PT-BR": "Raio de Fusão", + "EN": "Fusion Bolt", + "FR": "Éclair Croix", + "DE": "Kreuzdonner", + "IT": "Incrotuono", + "RU": "Термоядерный Разряд", + "ES": "Rayo Fusión" + }, + "pokemon_move_375": { + "PT-BR": "Chama da Fusão", + "EN": "Fusion Flare", + "FR": "Flamme Croix", + "DE": "Kreuzflamme", + "IT": "Incrofiamma", + "RU": "Ядерная Вспышка", + "ES": "Llama Fusión" + }, "pokemon_move_376": { "EN": "Poltergeist", "FR": "Esprit Frappeur", @@ -2750,5 +2768,14 @@ "IT": "Forza Equina", "RU": "Лошадиная Сила", "ES": "Fuerza Equina" + }, + "pokemon_move_378": { + "PT-BR": "Glaciar", + "EN": "Glaciate", + "FR": "Ère Glaciaire", + "DE": "Eiszeit", + "IT": "Gelamondo", + "RU": "Замораживание", + "ES": "Mundo Gélido" } } \ No newline at end of file From e6a2bbdcac18929ca74d251f38c7fd6f56ad3e52 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 30 Jan 2023 10:59:07 +0200 Subject: [PATCH 237/367] Converted $eggs to an actual constant --- commands/list.php | 2 +- commands/pokemon.php | 2 +- constants.php | 6 +++--- logic/get_local_pokemon_name.php | 3 +-- logic/get_overview.php | 2 +- logic/keys_vote.php | 4 ++-- logic/show_raid_poll.php | 2 +- mods/getdb.php | 2 +- mods/pokedex_edit_pokemon.php | 2 +- mods/share_raid_by_location.php | 3 +-- mods/vote_time.php | 2 +- 11 files changed, 14 insertions(+), 16 deletions(-) diff --git a/commands/list.php b/commands/list.php index a1b7175b..fb250e69 100644 --- a/commands/list.php +++ b/commands/list.php @@ -80,7 +80,7 @@ // Pokemon is an egg? $keys_text = ''; - if(in_array($resolved_boss['pokedex_id'], $GLOBALS['eggs'])) { + if(in_array($resolved_boss['pokedex_id'], EGGS)) { $keys_text = EMOJI_EGG . SP; } $keys_text .= ($raid['ex_gym'] === 1 ? EMOJI_STAR . SP : '') . $gym_name; diff --git a/commands/pokemon.php b/commands/pokemon.php index 4228a8cf..39f2bfbd 100644 --- a/commands/pokemon.php +++ b/commands/pokemon.php @@ -50,7 +50,7 @@ // Pokemon is an egg? $keys_text = $row['gym_name']; - if(in_array($pokedex_id, $GLOBALS['eggs'])) { + if(in_array($pokedex_id, EGGS)) { $keys_text = EMOJI_EGG . SP . $row['gym_name']; } diff --git a/constants.php b/constants.php index 91f90af4..f968dc77 100644 --- a/constants.php +++ b/constants.php @@ -6,7 +6,7 @@ define('RAID_LEVEL_ALL', ['X', 10, 9, 8, 7, 6, 5, 4, 3, 1]); // Raid eggs. -$eggs = array( +define('EGGS', [ '99910', // Level 10 / Primal raid '9999', // Level 9 / Elite raid '9998', // Level 8 / Ultra beast @@ -16,8 +16,8 @@ '9994', // Level 4 '9993', // Level 3 '9992', // Level 2 - '9991' // Level 1 -); + '9991', // Level 1 +]); // Raid levels limited to local players only define('RAID_LEVEL_LOCAL_ONLY', [4, 9]); diff --git a/logic/get_local_pokemon_name.php b/logic/get_local_pokemon_name.php index 02a23490..02bd4965 100644 --- a/logic/get_local_pokemon_name.php +++ b/logic/get_local_pokemon_name.php @@ -19,10 +19,9 @@ function get_local_pokemon_name($pokemon_id, $pokemon_form_id, $override_languag // Init pokemon name and define fake pokedex ids used for raid eggs $pokemon_name = ''; - $eggs = $GLOBALS['eggs']; // Get eggs from normal translation. - $pokemon_name = (in_array($pokemon_id, $eggs)) ? $getTypeTranslation('egg_' . str_replace('999', '', $pokemon_id)) : $getTypeTranslation('pokemon_id_' . $pokemon_id); + $pokemon_name = (in_array($pokemon_id, EGGS)) ? $getTypeTranslation('egg_' . str_replace('999', '', $pokemon_id)) : $getTypeTranslation('pokemon_id_' . $pokemon_id); if ($pokemon_form_name != 'normal') { $pokemon_form_name = $getTypeTranslation('pokemon_form_' . $pokemon_form_name); diff --git a/logic/get_overview.php b/logic/get_overview.php index 1df0be46..cb9850c4 100644 --- a/logic/get_overview.php +++ b/logic/get_overview.php @@ -63,7 +63,7 @@ function get_overview( $active_raids, $chat_title, $chat_username ) $msg .= $pokemon . ' — ' . getPublicTranslation('still') . SP . $time_left . 'h' . CR; } $exclude_pokemon_sql = ''; - if(!in_array($row['pokemon'], $GLOBALS['eggs'])) { + if(!in_array($row['pokemon'], EGGS)) { $exclude_pokemon_sql = 'AND (pokemon = \''.$row['pokemon'].'-'.$row['pokemon_form'].'\' or pokemon = \'0\')'; } // Count attendances diff --git a/logic/keys_vote.php b/logic/keys_vote.php index fe8a5489..180ac5ab 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -161,7 +161,7 @@ function keys_vote($raid) // Init keys pokemon array. $buttons['pokemon'] = []; // Show pokemon keys only if the raid boss is an egg - if(in_array($raid_pokemon_id, $GLOBALS['eggs'])) { + if(in_array($raid_pokemon_id, EGGS)) { // Get pokemon from database $raid_spawn = dt2time($raid['spawn'], 'Y-m-d H:i'); // Convert utc spawntime to local time $raid_bosses = get_raid_bosses($raid_spawn, $raid_level); @@ -169,7 +169,7 @@ function keys_vote($raid) if(count($raid_bosses) > 2) { // Add key for each raid level foreach($raid_bosses as $pokemon) { - if(in_array($pokemon['pokedex_id'], $GLOBALS['eggs'])) continue; + if(in_array($pokemon['pokedex_id'], EGGS)) continue; $buttons['pokemon'][] = button( get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), ['vote_pokemon', 'r' => $raid['id'], 'p' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id']] diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index efc19f69..f3b3e222 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -116,7 +116,7 @@ function show_raid_poll($raid, $inline = false) // Remaining attendances are combined and treated as users that voted for any pokemon from now on $order_by_sql = 'pokemon,'; $combine_attendances = false; - if(!in_array($raid['pokemon'], $GLOBALS['eggs'])) { + if(!in_array($raid['pokemon'], EGGS)) { $hide_users_sql.= 'AND (pokemon = \''.$raid['pokemon'].'-'.$raid['pokemon_form'].'\' OR pokemon = \'0\')'; $order_by_sql = ''; // Remove sorting by pokemon since all attendances are combined $combine_attendances = true; diff --git a/mods/getdb.php b/mods/getdb.php index 1a440ee2..90048186 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -42,7 +42,7 @@ // Craft egg data $PRE = 'INSERT INTO `pokemon`' . PHP_EOL; $PRE .= '(pokedex_id, pokemon_name, pokemon_form_name, pokemon_form_id, min_cp, max_cp, min_weather_cp, max_weather_cp, type, type2, weather) VALUES'; -foreach($eggs as $egg) { +foreach(EGGS as $egg) { $pokemon_id = $egg; $pokemon_name = 'Level '. str_replace('999', '', $egg) .' Egg'; $pokemon_array[$pokemon_id]['normal'] = [ diff --git a/mods/pokedex_edit_pokemon.php b/mods/pokedex_edit_pokemon.php index c65d796c..aa3071af 100644 --- a/mods/pokedex_edit_pokemon.php +++ b/mods/pokedex_edit_pokemon.php @@ -29,7 +29,7 @@ $keys[][] = button(getTranslation('pokedex_raid_level'), ['pokedex_set_raid_level', 'p' => $poke_id_form]); // Raid-Egg? Hide specific options! -if(!in_array($pokedex_id, $GLOBALS['eggs'])) { +if(!in_array($pokedex_id, EGGS)) { $keys[][] = button(getTranslation('pokedex_min_cp'), ['pokedex_set_cp', 'p' => $poke_id_form, 'a' => 'add', 'l' => 20, 't' => 'min']); $keys[][] = button(getTranslation('pokedex_max_cp'), ['pokedex_set_cp', 'p' => $poke_id_form, 'a' => 'add', 'l' => 20, 't' => 'max']); $keys[][] = button(getTranslation('pokedex_min_weather_cp'), ['pokedex_set_cp', 'p' => $poke_id_form, 'a' => 'add', 'l' => 25, 't' => 'min']); diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 6549c583..3d24a0c5 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -108,8 +108,7 @@ $pokedex_id = explode('-', $raid['pokemon'])[0]; // Pokemon is an egg? - $eggs = $GLOBALS['eggs']; - if(in_array($pokedex_id, $eggs)) { + if(in_array($pokedex_id, EGGS)) { $keys_text = EMOJI_EGG . SP . $gym_name; } else { $keys_text = $gym_name; diff --git a/mods/vote_time.php b/mods/vote_time.php index 1cbc484d..77026545 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -90,7 +90,7 @@ // Update attendance. $update_pokemon_sql = ''; - if(!in_array($raid['pokemon'], $eggs)) { + if(!in_array($raid['pokemon'], EGGS)) { // If raid egg has hatched // -> clean up attendance table from votes for other pokemon // -> leave one entry remaining and set the pokemon to 0 there From 37d7d9ca0bb2e57f6381f51ffbb20317139d9492 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 4 Feb 2023 16:00:28 +0200 Subject: [PATCH 238/367] Improved logic for time voting keys Removed some duplicates and hopefully didn't break anything --- logic/keys_vote.php | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 180ac5ab..d0bf1725 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -248,9 +248,7 @@ function get_raid_bosses($time, $raid_level) function generateTimeslotKeys($RAID_SLOTS, $raid) { global $config; // Get current time. - $now_helper = new DateTimeImmutable('now', new DateTimeZone('UTC')); - $now_helper = $now_helper->format('Y-m-d H:i') . ':00'; - $dt_now = new DateTimeImmutable($now_helper, new DateTimeZone('UTC')); + $dt_now = DateTimeImmutable::createFromFormat('Y-m-d H:i', date('Y-m-d H:i')); // Get direct start slot $direct_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); @@ -263,14 +261,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { $five_slot = $five_slot->add(new DateInterval('PT'.$diff.'M')); // Get first regular raidslot - $first_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); - $minute = $directStartMinutes % $RAID_SLOTS; - - // Count minutes to next raidslot multiple minutes if necessary - if($minute != 0) { - $diff = $RAID_SLOTS - $minute; - $first_slot = $first_slot->add(new DateInterval('PT'.$diff.'M')); - } + $first_slot = $five_slot->add(new DateInterval('PT'.$RAID_SLOTS.'M')); // Write slots to log. debug_log($direct_slot, 'Direct start slot:'); From 57e06f3906a0c3a24e155f5616b46d7986f49491 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 16 Feb 2023 12:45:30 +0200 Subject: [PATCH 239/367] More tricks to get Pokebattler primals mapped to right tier --- lang/language.json | 13 +++++++++++++ mods/pokebattler.php | 18 ++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/lang/language.json b/lang/language.json index 5a41a2a4..c72ea13d 100644 --- a/lang/language.json +++ b/lang/language.json @@ -831,6 +831,19 @@ "FI": "Primal raid", "ES": "TRANSLATE" }, + "10stars_short": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Primal", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Primal", + "ES": "TRANSLATE" + }, "9stars": { "NL": "Elite raid", "DE": "TRANSLATE", diff --git a/mods/pokebattler.php b/mods/pokebattler.php index c02f9da5..4e617557 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -104,10 +104,15 @@ $starttime->setTimezone($ph); $endtime->setTimezone($ph); - if(in_array($news['tier'], $raidlevels) && $starttime->getTimestamp() < $now->getTimestamp() && $endtime->getTimestamp() > $now->getTimestamp()) { + $tierHolder = $news['tier']; + [$dex_id, $form_id] = resolve_boss_name_to_ids($news['pokemon']); + if(in_array($dex_id, PRIMAL_MONS) && $news['tier'] == 'RAID_LEVEL_MEGA_5') { + $raid_level_id = 10; + $tierHolder = 'RAID_LEVEL_PRIMAL'; + } + if(in_array($tierHolder, $raidlevels) && $starttime->getTimestamp() < $now->getTimestamp() && $endtime->getTimestamp() > $now->getTimestamp()) { $levels_processed[$raid_level_id] = $news['tier']; - $dex_id_form = resolve_boss_name_to_ids($news['pokemon']); - $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $news['shiny']]; + $bosses[$raid_level_id][] = ['dex_id' => $dex_id, 'form_id' => $form_id, 'shiny' => $news['shiny']]; } } // Process raid tier(s) @@ -126,8 +131,8 @@ debug_log('Skipping raid boss ' . $raid['pokemon'] . ' since it has no id, it\'s likely in the future!'); continue; } - $dex_id_form = resolve_boss_name_to_ids($raid['pokemon']); - $bosses[$raid_level_id][] = ['id' => $dex_id_form, 'shiny' => $raid['shiny']]; + [$dex_id, $form_id] = resolve_boss_name_to_ids($raid['pokemon']); + $bosses[$raid_level_id][] = ['dex_id' => $dex_id, 'form_id' => $form_id, 'shiny' => $raid['shiny']]; } } @@ -136,7 +141,8 @@ if($raid_level_id > 5) $raid_level_text = getTranslation($raid_level_id . 'stars_short'); else $raid_level_text = $raid_level_id; $msg .= '' . getTranslation('pokedex_raid_level') . SP . $raid_level_text . ':' . CR; foreach($bosses[$raid_level_id] as $dex_id_form) { - [$dex_id, $dex_form] = $dex_id_form['id']; + $dex_id = $dex_id_form['dex_id']; + $dex_form = $dex_id_form['form_id']; $pokemon_arg = $dex_id . (($dex_form != 'normal') ? ('-' . $dex_form) : '-0'); $local_pokemon = get_local_pokemon_name($dex_id, $dex_form); debug_log('Got this pokemon dex id: ' . $dex_id); From 6c67896fac4308ca2946ee3591934d35372cdfca Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 19 Feb 2023 17:17:28 +0200 Subject: [PATCH 240/367] Fixed buttons --- mods/edit_event.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mods/edit_event.php b/mods/edit_event.php index 209d376a..bd1caae8 100644 --- a/mods/edit_event.php +++ b/mods/edit_event.php @@ -21,8 +21,10 @@ $backData[0] = 'edit_raidlevel'; // Add navigation keys. -$keys[0][] = button(getTranslation('back'), $backData); -$keys[0][] = button(getTranslation('abort'), 'exit'); +$keys[] = [ + button(getTranslation('back'), $backData), + button(getTranslation('abort'), 'exit') +]; // Build callback message string. From bb596d66e41d5a32273caa8e0a341b0ea036cf27 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 3 Mar 2023 08:33:29 +0200 Subject: [PATCH 241/367] Changed EX raid level from X to 99 With this we get rid of the enum column in database which should provide more sturdiness with new raid levels --- constants.php | 9 +++++---- docs/config.rst | 2 +- lang/language.json | 2 +- logic/keys_event.php | 4 ++-- logic/keys_vote.php | 2 +- logic/raid_edit_raidlevel_keys.php | 6 +++--- mods/edit_event_raidlevel.php | 10 ++++++---- sql/pokemon-raid-bot.sql | 4 ++-- sql/upgrade/5.sql | 4 ++-- 9 files changed, 23 insertions(+), 20 deletions(-) diff --git a/constants.php b/constants.php index f968dc77..73990f9c 100644 --- a/constants.php +++ b/constants.php @@ -1,9 +1,13 @@ fetch(); // Build message. -if($event_id == 'X') { - $msg = '' . getTranslation('Xstars') . '' . CR; +if($event_id == EVENT_ID_EX) { + $msg = '' . getTranslation(RAID_ID_EX . 'stars') . '' . CR; }else { $msg = '' . $rs['name'] . '' . CR . $rs['description'] . CR; } diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 48e722e7..69cc460c 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -102,7 +102,7 @@ CREATE TABLE `raid_bosses` ( `pokemon_form_id` int(4) DEFAULT NULL, `date_start` datetime NOT NULL DEFAULT '1970-01-01 00:00:01', `date_end` datetime NOT NULL DEFAULT '2038-01-19 03:14:07', - `raid_level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL, + `raid_level` TINYINT UNSIGNED DEFAULT NULL, `scheduled` TINYINT(1) NULL DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -116,7 +116,7 @@ CREATE TABLE `raids` ( `end_time` datetime DEFAULT NULL, `gym_team` enum('mystic','valor','instinct') DEFAULT NULL, `gym_id` int(10) unsigned NOT NULL, - `level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL, + `level` TINYINT UNSIGNED DEFAULT NULL, `move1` varchar(255) DEFAULT NULL, `move2` varchar(255) DEFAULT NULL, `gender` varchar(255) DEFAULT NULL, diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index 153fb75f..5e8e717e 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -9,8 +9,8 @@ ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `start_time` DATETIME DEFAULT ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); -ALTER TABLE `raids` CHANGE COLUMN IF EXISTS `level` `level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; -ALTER TABLE `raid_bosses` CHANGE COLUMN IF EXISTS `raid_level` `raid_level` enum('1','2','3','4','5','6','7','8','9','10','X') DEFAULT NULL; +ALTER TABLE `raids` CHANGE COLUMN IF EXISTS `level` `level` TINYINT UNSIGNED DEFAULT NULL; +ALTER TABLE `raid_bosses` CHANGE COLUMN IF EXISTS `raid_level` `raid_level` TINYINT UNSIGNED DEFAULT NULL; ALTER TABLE `events` ADD COLUMN IF NOT EXISTS `pokemon_title` TINYINT(1) NULL DEFAULT 1 AFTER `hide_raid_picture`; From 1e067e4aa1792f17a68f4ee702e7a1944ec6a3ae Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 3 Mar 2023 08:34:36 +0200 Subject: [PATCH 242/367] New translations --- lang/pokemon.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/pokemon.json b/lang/pokemon.json index 7cfada92..65317350 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -99,7 +99,7 @@ "EN": "Pidgeotto", "FR": "Roucoups", "DE": "Tauboga", - "RU": "Пиджeотто" + "RU": "Пиджеотто" }, "pokemon_id_18": { "EN": "Pidgeot", @@ -1136,7 +1136,7 @@ "EN": "Forretress", "FR": "Foretress", "DE": "Forstellka", - "RU": "Форретресc" + "RU": "Форретресс" }, "pokemon_id_206": { "EN": "Dunsparce", From 22cb2671e18e1f2dc3e29b7bcc739585687852e0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 3 Mar 2023 13:04:36 +0200 Subject: [PATCH 243/367] Fixed raid duration --- core/bot/apikey.php | 2 +- mods/edit_save.php | 13 +++++++------ mods/edit_time.php | 3 +-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/bot/apikey.php b/core/bot/apikey.php index 30898380..e2b845cd 100644 --- a/core/bot/apikey.php +++ b/core/bot/apikey.php @@ -2,7 +2,7 @@ /** * Verify a GET param apikey and return a provided update Array - * @return Array + * @return array */ function get_verified_update(){ global $config, $argv; diff --git a/mods/edit_save.php b/mods/edit_save.php index 5cac61d3..57ae4eb6 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -16,15 +16,16 @@ // Set the user id. $userid = $update['callback_query']['from']['id']; -// Update only if time is not equal to RAID_DURATION -if(isset($data['d']) && $data['d'] != $config->RAID_DURATION) { - - // Build query. +// Update raid end time +if(isset($data['d'])) { my_query(' UPDATE raids - SET end_time = DATE_ADD(start_time, INTERVAL ' . $data['d'] . ' MINUTE) + SET end_time = DATE_ADD(start_time, INTERVAL :duration MINUTE) WHERE id = :id - ', ['id' => $id] + ', [ + 'id' => $id, + 'duration' => $data['d'] + ] ); } diff --git a/mods/edit_time.php b/mods/edit_time.php index e55205cb..d5ce479f 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -34,11 +34,10 @@ $start_date_time = substr($starttime,0,4) . '-' . substr($starttime,4,2) . '-' . substr($starttime,6,2) . ' ' . substr($starttime,8,2) . ':' . substr($starttime,10,2) . ':00'; // Event raids if($event_id != NULL) { - $event_id = ($event_id == 'X') ? EVENT_ID_EX : $event_id; debug_log('Event time :D ... Setting raid date to ' . $start_date_time); $query = my_query('SELECT raid_duration FROM events WHERE id = ? LIMIT 1', [$event_id]); $result = $query->fetch(); - $duration = $result['raid_duration'] ?? $config->RAID_DURATION; + $duration = $result['raid_duration'] == 0 ? $result['raid_duration'] : $config->RAID_DURATION; $egg_duration = $config->RAID_EGG_DURATION; // Elite raids From e90d2b35708f10c4b60c5a176bce5ddb94753322 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 5 Mar 2023 07:23:33 +0200 Subject: [PATCH 244/367] Use bot specific update_id Solves #286 --- core/bot/ddos.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/bot/ddos.php b/core/bot/ddos.php index 4ccff56d..d84b2df8 100644 --- a/core/bot/ddos.php +++ b/core/bot/ddos.php @@ -21,7 +21,8 @@ function verifyUpdate($update, $data) { debug_log('Skipping DDOS check...','!'); return; } - $id_file = DDOS_PATH . '/update_id'; + // Prepend update_id with bot name if it's set + $id_file = DDOS_PATH . '/' . (isset($_GET['bot_name']) && !empty($_GET['bot_name']) ? $_GET['bot_name'] . '-' : ''). 'update_id'; // Update the update_id and reject old updates // Get update_ids from Telegram and locally stored in the file From 921e7029e5a68adc4059e18e224cdbed3467ca94 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 5 Mar 2023 07:24:11 +0200 Subject: [PATCH 245/367] Add coree/tools/hash.php into .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b9367220..81b81617 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /access/** /custom/** /ddos/** +/core/tools/hash.php !/access/.gitkeep !/custom/.gitkeep !/ddos/.gitkeep From 4f8e7fdb801b736528d25c111f7f6cbfa79f55a7 Mon Sep 17 00:00:00 2001 From: klablabla <30940278+klablabla@users.noreply.github.com> Date: Sun, 5 Mar 2023 07:11:11 +0100 Subject: [PATCH 246/367] added NL translation --- lang/language.json | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/lang/language.json b/lang/language.json index a30bd149..c7213b28 100644 --- a/lang/language.json +++ b/lang/language.json @@ -455,7 +455,7 @@ "ES": "Añadir" }, "replace": { - "NL": "TRANSLATE", + "NL": "Vervang", "DE": "TRANSLATE", "EN": "Replace", "IT": "TRANSLATE", @@ -637,7 +637,7 @@ "ES": "Valor de la opción de configuración" }, "config_option": { - "NL": "TRANSLATE", + "NL": "Configuratie optie", "DE": "TRANSLATE", "EN": "Configuration option", "IT": "TRANSLATE", @@ -819,7 +819,7 @@ "ES": "Incursión EX" }, "10stars": { - "NL": "TRANSLATE", + "NL": "Primal raid", "DE": "TRANSLATE", "EN": "Primal raid", "IT": "TRANSLATE", @@ -832,7 +832,7 @@ "ES": "TRANSLATE" }, "10stars_short": { - "NL": "TRANSLATE", + "NL": "Primal", "DE": "TRANSLATE", "EN": "Primal", "IT": "TRANSLATE", @@ -1027,7 +1027,7 @@ "ES": "Desactivado" }, "egg_10": { - "NL": "TRANSLATE", + "NL": "Primal raid ei", "DE": "TRANSLATE", "EN": "Primal raid egg", "IT": "TRANSLATE", @@ -1950,7 +1950,7 @@ "ES": "Por favor, selecciona la zona del gimnasio:" }, "default_gymarea": { - "NL": "TRANSLATE", + "NL": "Standaard gym gebied", "DE": "TRANSLATE", "EN": "Default gymarea", "IT": "TRANSLATE", @@ -1963,7 +1963,7 @@ "ES": "TRANSLATE" }, "gymareas": { - "NL": "TRANSLATE", + "NL": "Gyn gebied", "DE": "TRANSLATE", "EN": "Gymareas", "IT": "TRANSLATE", @@ -2002,7 +2002,7 @@ "ES": "¡La incursión ya existe!" }, "inspect_raid_or_create_event": { - "NL": "TRANSLATE", + "NL": "Inspect de bestaande raid of create een new event raid", "DE": "TRANSLATE", "EN": "Inspect the existing raid or create a new event raid", "IT": "TRANSLATE", @@ -2015,7 +2015,7 @@ "ES": "TRANSLATE" }, "saved_raid": { - "NL": "TRANSLATE", + "NL": "Laat opgeslagen raid zien", "DE": "TRANSLATE", "EN": "Show saved raid", "IT": "TRANSLATE", @@ -2028,7 +2028,7 @@ "ES": "TRANSLATE" }, "create_event_raid": { - "NL": "TRANSLATE", + "NL": "Maak een event raid", "DE": "TRANSLATE", "EN": "Create event raid", "IT": "TRANSLATE", @@ -2990,7 +2990,7 @@ "ES": "TRANSLATE" }, "gym_stored_address": { - "NL": "TRANSLATE", + "NL": "Opgeslagen adres", "DE": "TRANSLATE", "EN": "Stored address", "IT": "TRANSLATE", @@ -3016,7 +3016,7 @@ "ES": "TRANSLATE" }, "gym_address_lookup_result": { - "NL": "TRANSLATE", + "NL": "Opgezochte adres", "DE": "TRANSLATE", "EN": "Address lookup result", "IT": "TRANSLATE", @@ -3029,7 +3029,7 @@ "ES": "TRANSLATE" }, "gym_save_lookup_result": { - "NL": "TRANSLATE", + "NL": "Sla opgezochte resultaat op", "DE": "TRANSLATE", "EN": "Save lookup result", "IT": "TRANSLATE", @@ -4004,7 +4004,7 @@ "ES": "Por ejemplo: /gymname Waterfall in the park" }, "gym_id_name_missing": { - "NL": "TRANSLATE", + "NL": "Error! Gym naam mist!", "DE": "TRANSLATE", "EN": "Error! Gym name is missing!", "IT": "TRANSLATE", @@ -4654,7 +4654,7 @@ "ES": "Agrega más información para este anuncio específico sobre el evento. (por ejemplo: ruta)" }, "events_manage": { - "NL": "TRANSLATE", + "NL": "Event manager", "DE": "TRANSLATE", "EN": "Manage events", "IT": "TRANSLATE", @@ -4667,7 +4667,7 @@ "ES": "TRANSLATE" }, "events_create": { - "NL": "TRANSLATE", + "NL": "Maak een nieuw event", "DE": "TRANSLATE", "EN": "Create a new event", "IT": "TRANSLATE", @@ -4680,7 +4680,7 @@ "ES": "TRANSLATE" }, "events_created": { - "NL": "TRANSLATE", + "NL": "Event succesvol aangemaakt!", "DE": "TRANSLATE", "EN": "Event created succesfully!", "IT": "TRANSLATE", @@ -4693,7 +4693,7 @@ "ES": "TRANSLATE" }, "events_give_name": { - "NL": "TRANSLATE", + "NL": "Geef het event een naam", "DE": "TRANSLATE", "EN": "Give the event a name", "IT": "TRANSLATE", @@ -4706,7 +4706,7 @@ "ES": "TRANSLATE" }, "events_give_description": { - "NL": "TRANSLATE", + "NL": "Geef de omschrijving van het event", "DE": "TRANSLATE", "EN": "Give the event a description", "IT": "TRANSLATE", @@ -4719,7 +4719,7 @@ "ES": "TRANSLATE" }, "events_no_description": { - "NL": "TRANSLATE", + "NL": "Geen omschrijving", "DE": "TRANSLATE", "EN": "No description", "IT": "TRANSLATE", @@ -4732,7 +4732,7 @@ "ES": "TRANSLATE" }, "events_edit_name": { - "NL": "TRANSLATE", + "NL": "Wijzig event naam", "DE": "TRANSLATE", "EN": "Edit event name", "IT": "TRANSLATE", @@ -4745,7 +4745,7 @@ "ES": "TRANSLATE" }, "events_edit_description": { - "NL": "TRANSLATE", + "NL": "Wijzig de event omschrijving", "DE": "TRANSLATE", "EN": "Edit event description", "IT": "TRANSLATE", @@ -4758,7 +4758,7 @@ "ES": "TRANSLATE" }, "events_edit_raid_poll": { - "NL": "TRANSLATE", + "NL": "Wijzig event raid poll", "DE": "TRANSLATE", "EN": "Edit event raid poll", "IT": "TRANSLATE", @@ -4771,7 +4771,7 @@ "ES": "TRANSLATE" }, "events_delete": { - "NL": "TRANSLATE", + "NL": "Verwijder event", "DE": "TRANSLATE", "EN": "Delete event", "IT": "TRANSLATE", @@ -4784,7 +4784,7 @@ "ES": "TRANSLATE" }, "events_delete_confirmation": { - "NL": "TRANSLATE", + "NL": "Wil je dit event echt verwijderen?", "DE": "TRANSLATE", "EN": "Do you really want to delete this event?", "IT": "TRANSLATE", From 09e97c603e83081c2a30efdaa7873e3cda774a2b Mon Sep 17 00:00:00 2001 From: klablabla <30940278+klablabla@users.noreply.github.com> Date: Sun, 5 Mar 2023 07:14:27 +0100 Subject: [PATCH 247/367] added NL translation --- lang/pokemon_forms.json | 54 ++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index cc6024d8..789870c1 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -26,7 +26,7 @@ "ES": "Galar" }, "pokemon_form_hisuian": { - "NL": "TRANSLATE", + "NL": "Hisuian", "DE": "TRANSLATE", "EN": "Hisuian", "IT": "TRANSLATE", @@ -39,7 +39,7 @@ "ES": "TRANSLATE" }, "pokemon_form_primal": { - "NL": "TRANSLATE", + "NL": "Primal", "DE": "TRANSLATE", "EN": "Primal", "IT": "TRANSLATE", @@ -52,7 +52,7 @@ "ES": "TRANSLATE" }, "pokemon_form_mega": { - "NL": "TRANSLATE", + "NL": "Mega", "DE": "TRANSLATE", "EN": "Mega", "IT": "TRANSLATE", @@ -65,7 +65,7 @@ "ES": "Mega" }, "pokemon_form_mega_x": { - "NL": "TRANSLATE", + "NL": "Mega X", "DE": "TRANSLATE", "EN": "Mega X", "IT": "TRANSLATE", @@ -78,7 +78,7 @@ "ES": "Mega X" }, "pokemon_form_mega_y": { - "NL": "TRANSLATE", + "NL": "Mega Y", "DE": "TRANSLATE", "EN": "Mega Y", "IT": "TRANSLATE", @@ -198,7 +198,7 @@ "ES": "Soleada" }, "pokemon_form_rainy": { - "NL": "TRANSLATE", + "NL": "Rainy", "DE": "TRANSLATE", "EN": "Rainy", "IT": "TRANSLATE", @@ -210,7 +210,7 @@ "ES": "TRANSLATE" }, "pokemon_form_snowy": { - "NL": "TRANSLATE", + "NL": "Snowy", "DE": "TRANSLATE", "EN": "Snowy", "IT": "TRANSLATE", @@ -426,7 +426,7 @@ "ES": "Volador" }, "pokemon_form_fighting": { - "NL": "TRANSLATE", + "NL": "Fighting", "DE": "TRANSLATE", "EN": "Fighting", "IT": "TRANSLATE", @@ -606,7 +606,7 @@ "ES": "Brío" }, "pokemon_form_burn": { - "NL": "TRANSLATE", + "NL": "Burn", "DE": "TRANSLATE", "EN": "Burn", "IT": "TRANSLATE", @@ -618,7 +618,7 @@ "ES": "TRANSLATE" }, "pokemon_form_chill": { - "NL": "TRANSLATE", + "NL": "Chill", "DE": "TRANSLATE", "EN": "Chill", "IT": "TRANSLATE", @@ -630,7 +630,7 @@ "ES": "TRANSLATE" }, "pokemon_form_douse": { - "NL": "TRANSLATE", + "NL": "Douse", "DE": "TRANSLATE", "EN": "Douse", "IT": "TRANSLATE", @@ -642,7 +642,7 @@ "ES": "TRANSLATE" }, "pokemon_form_shock": { - "NL": "TRANSLATE", + "NL": "Shock", "DE": "TRANSLATE", "EN": "Shock", "IT": "TRANSLATE", @@ -654,7 +654,7 @@ "ES": "TRANSLATE" }, "pokemon_form_black": { - "NL": "TRANSLATE", + "NL": "Black", "DE": "TRANSLATE", "EN": "Black", "IT": "TRANSLATE", @@ -666,7 +666,7 @@ "ES": "TRANSLATE" }, "pokemon_form_white": { - "NL": "TRANSLATE", + "NL": "White", "DE": "TRANSLATE", "EN": "White", "IT": "TRANSLATE", @@ -678,7 +678,7 @@ "ES": "TRANSLATE" }, "pokemon_form_hero": { - "NL": "TRANSLATE", + "NL": "Hero", "DE": "TRANSLATE", "EN": "Hero", "IT": "TRANSLATE", @@ -690,7 +690,7 @@ "ES": "TRANSLATE" }, "pokemon_form_crowned_sword": { - "NL": "TRANSLATE", + "NL": "Crowned Sword", "DE": "TRANSLATE", "EN": "Crowned Sword", "IT": "TRANSLATE", @@ -702,7 +702,7 @@ "ES": "TRANSLATE" }, "pokemon_form_crowned_shield": { - "NL": "TRANSLATE", + "NL": "Crowned Shield", "DE": "TRANSLATE", "EN": "Crowned Shield", "IT": "TRANSLATE", @@ -714,7 +714,7 @@ "ES": "TRANSLATE" }, "pokemon_form_zen": { - "NL": "TRANSLATE", + "NL": "Zen", "DE": "TRANSLATE", "EN": "Zen", "IT": "TRANSLATE", @@ -726,7 +726,7 @@ "ES": "TRANSLATE" }, "pokemon_form_galarian_zen": { - "NL": "TRANSLATE", + "NL": "Galarian Zen", "DE": "TRANSLATE", "EN": "Galarian Zen", "IT": "TRANSLATE", @@ -738,7 +738,7 @@ "ES": "TRANSLATE" }, "pokemon_form_male": { - "NL": "TRANSLATE", + "NL": "Man", "DE": "TRANSLATE", "EN": "Male", "IT": "TRANSLATE", @@ -750,7 +750,7 @@ "ES": "TRANSLATE" }, "pokemon_form_female": { - "NL": "TRANSLATE", + "NL": "Vrouw", "DE": "TRANSLATE", "EN": "Female", "IT": "TRANSLATE", @@ -762,7 +762,7 @@ "ES": "TRANSLATE" }, "pokemon_form_blue_striped": { - "NL": "TRANSLATE", + "NL": "Blue Striped", "DE": "TRANSLATE", "EN": "Blue Striped", "IT": "TRANSLATE", @@ -774,7 +774,7 @@ "ES": "TRANSLATE" }, "pokemon_form_red_striped": { - "NL": "TRANSLATE", + "NL": "Red Striped", "DE": "TRANSLATE", "EN": "Red Striped", "IT": "TRANSLATE", @@ -786,7 +786,7 @@ "ES": "TRANSLATE" }, "pokemon_form_autumn": { - "NL": "TRANSLATE", + "NL": "Herfst", "DE": "TRANSLATE", "EN": "Autumn", "IT": "TRANSLATE", @@ -798,7 +798,7 @@ "ES": "TRANSLATE" }, "pokemon_form_spring": { - "NL": "TRANSLATE", + "NL": "Lente", "DE": "TRANSLATE", "EN": "Spring", "IT": "TRANSLATE", @@ -810,7 +810,7 @@ "ES": "TRANSLATE" }, "pokemon_form_summer": { - "NL": "TRANSLATE", + "NL": "Zomer", "DE": "TRANSLATE", "EN": "Summer", "IT": "TRANSLATE", @@ -822,7 +822,7 @@ "ES": "TRANSLATE" }, "pokemon_form_winter": { - "NL": "TRANSLATE", + "NL": "Winter", "DE": "TRANSLATE", "EN": "Winter", "IT": "TRANSLATE", From 342f749d21a162e134d5218437b97f76337e160c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 5 Mar 2023 10:28:29 +0200 Subject: [PATCH 248/367] Fixed sql upgrade --- logic/bot_upgrade_check.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/bot_upgrade_check.php b/logic/bot_upgrade_check.php index edf9d639..1b6d1e82 100644 --- a/logic/bot_upgrade_check.php +++ b/logic/bot_upgrade_check.php @@ -40,11 +40,11 @@ function get_rev() * Bot upgrade check * @param $current * @param $latest - * @return bool: if a manual upgrade is needed + * @return */ function bot_upgrade_check($current, $latest) { - global $config, $metrics, $namespace; + global $config, $metrics, $namespace, $dbh; $orig = $current; // we may have to do multiple upgrades if ($metrics){ // This is the one place where we have full knowledge of version information & upgrades From c9a845b62807aa7356eaec5d35e781a5d2f33a5c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 10 Mar 2023 21:08:39 +0200 Subject: [PATCH 249/367] Exclude raid level 10 from automatic level updater Until I come up with a better way of doing this --- logic/read_upcoming_bosses.php | 8 ++++++-- mods/update_bosses.php | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index 15e5a1b9..f3fea304 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -4,9 +4,10 @@ /** * Read upcoming bosses from Pokebattlers API and return the results as a HTML formatted text list * @param bool $return_sql Return results in sql insert query instead of text list + * @param array|bool $levelsToRead Array of raid levels to include in import. Otherwise use the levels set in constants.php * @return string */ -function read_upcoming_bosses($return_sql = false) { +function read_upcoming_bosses($return_sql = false, $levelsToRead = false) { global $pokebattler_import_future_tiers, $pokebattler_level_map, $pokebattler_pokemon_map; $link = curl_get_contents('https://fight.pokebattler.com/raids'); $pb = json_decode($link, true); @@ -21,7 +22,10 @@ function read_upcoming_bosses($return_sql = false) { $rl = str_replace('RAID_LEVEL_','', $news['tier']); $raid_level_id = array_search($rl, $pokebattler_level_map); - if(!in_array($raid_level_id, $pokebattler_import_future_tiers)) continue; // Limit scheduling to tier 5 and higher only + + $levelLimiter = !$levelsToRead ? $pokebattler_import_future_tiers : $levelsToRead; + if(!in_array($raid_level_id, $levelLimiter)) continue; // Limit scheduling to tier 5 and higher only + $starttime = new DateTime("@".(substr($news['startDate'],0,10)), $standardTimezone); $endtime = new DateTime("@".(substr($news['endDate'],0,10)), $standardTimezone); diff --git a/mods/update_bosses.php b/mods/update_bosses.php index 2dfab5bd..6b49e411 100644 --- a/mods/update_bosses.php +++ b/mods/update_bosses.php @@ -53,7 +53,7 @@ $sql = 'INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) VALUES ' . $sql_values . ';'; }elseif($levels == 'scheduled') { require_once(LOGIC_PATH . '/read_upcoming_bosses.php'); - $data = read_upcoming_bosses(true); + $data = read_upcoming_bosses(true, [5,6,7,8,10]); if(empty($data)) exit; $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1;'; $sql .= $data; From 40b4fe350b38f5b99eda122ceeb33239711e759c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 10 Mar 2023 21:25:23 +0200 Subject: [PATCH 250/367] Minor bug fixes --- mods/list_remote_gyms.php | 1 + mods/update_bosses.php | 1 + mods/vote_status.php | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mods/list_remote_gyms.php b/mods/list_remote_gyms.php index c7f71946..1837f41d 100644 --- a/mods/list_remote_gyms.php +++ b/mods/list_remote_gyms.php @@ -9,6 +9,7 @@ $user_id = $update['callback_query']['from']['id']; // Get the keys. +$keys = []; $query_remote = my_query('SELECT raids.id, gyms.gym_name, raids.start_time, raids.end_time FROM gyms LEFT JOIN raids on raids.gym_id = gyms.id WHERE raids.end_time > (UTC_TIMESTAMP() - INTERVAL 10 MINUTE) AND temporary_gym = 1'); while($gym = $query_remote->fetch()) { $keys[][] = button($gym['gym_name'], ['list_raid', 'r' => $gym['id']]); diff --git a/mods/update_bosses.php b/mods/update_bosses.php index 6b49e411..346010a1 100644 --- a/mods/update_bosses.php +++ b/mods/update_bosses.php @@ -24,6 +24,7 @@ debug_log('Processing received ccev pogoinfo raid bosses for each raid level'); $sql_values = ''; foreach($get_levels as $level) { + if(!isset($data[$level])) continue; // Process requested levels foreach($data[$level] as $raid_id_form) { if(!isset($raid_id_form['id'])) continue; diff --git a/mods/vote_status.php b/mods/vote_status.php index 13d6fb72..e30f91fc 100644 --- a/mods/vote_status.php +++ b/mods/vote_status.php @@ -83,7 +83,7 @@ // If the gym is a temporary remote raid gym and raid creator voted for done, send message asking for raid deletion if($answer['is_remote_gym'] == '1' && $answer['user_is_creator']) { $keys[0][0] = button(getTranslation('yes'), ['end_remote_raid', 'r' => $raidId]); - $keys[0][0] = button(getTranslation('no'), 'exit'); + $keys[0][1] = button(getTranslation('no'), 'exit'); if($status == 'raid_done') $msg = getTranslation("delete_remote_raid_done"); else if($status == 'cancel') $msg = getTranslation("delete_remote_raid_cancel"); $tg_json[] = send_message($update['callback_query']['from']['id'], $msg, $keys, false, true); From 0adb58a9929641b8faa96e9ce93e27c864af0cd6 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 11 Mar 2023 12:55:34 +0200 Subject: [PATCH 251/367] Shorten the callback_data when creating a raid In some cases the callback_data got too long, this hopefully mitigates it a bit --- logic/gymMenu.php | 1 + logic/key_util.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/logic/gymMenu.php b/logic/gymMenu.php index 5e3ae42b..b6192dd6 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -8,6 +8,7 @@ function resolveDefaultGymarea($userId) { global $config; + if(!$config->ENABLE_GYM_AREAS) return false; $q = my_query('SELECT gymarea FROM users WHERE user_id = ? LIMIT 1', [$userId]); $userGymarea = $q->fetch()['gymarea']; return $userGymarea !== NULL ? $userGymarea : $config->DEFAULT_GYM_AREA; diff --git a/logic/key_util.php b/logic/key_util.php index b153742a..75148a0f 100644 --- a/logic/key_util.php +++ b/logic/key_util.php @@ -116,7 +116,8 @@ function formatCallbackData($array) $return = $array[0] . '|'; unset($array[0]); foreach($array as $key => $value) { - $return .= $key . '=' . $value . '|'; + if(empty($value) or $value == false) continue; + $return .= $key . '=' . $value . '|'; } return rtrim($return, '|'); } From f3d2310cbe70626c1653ba447ce6c360a608316b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 11 Mar 2023 13:12:43 +0200 Subject: [PATCH 252/367] Truthiness fix --- logic/key_util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/key_util.php b/logic/key_util.php index 75148a0f..ff9a2024 100644 --- a/logic/key_util.php +++ b/logic/key_util.php @@ -116,7 +116,7 @@ function formatCallbackData($array) $return = $array[0] . '|'; unset($array[0]); foreach($array as $key => $value) { - if(empty($value) or $value == false) continue; + if($value !== 0 && (empty($value) or $value === false)) continue; $return .= $key . '=' . $value . '|'; } return rtrim($return, '|'); From b5eb4b3f2b1f93f96f37e1af0bddff47b618be24 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 12 Mar 2023 18:13:27 +0200 Subject: [PATCH 253/367] Add limit --- logic/get_pokemon_info.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/get_pokemon_info.php b/logic/get_pokemon_info.php index b72e6b3f..340023d4 100644 --- a/logic/get_pokemon_info.php +++ b/logic/get_pokemon_info.php @@ -13,7 +13,7 @@ function get_pokemon_info($pokedex_id, $pokemon_form_id) FROM raid_bosses WHERE pokedex_id = :pokedex_id AND pokemon_form_id = :pokemon_form_id - AND scheduled = 0) as raid_level + AND scheduled = 0 LIMIT 1) as raid_level FROM pokemon WHERE pokedex_id = :pokedex_id AND pokemon_form_id = :pokemon_form_id From d7f048bd5aa6b36df66c2d9421e27f318741e2a8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 12 Mar 2023 20:08:12 +0200 Subject: [PATCH 254/367] Fixed duplicate keys on short raids --- logic/keys_vote.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index ca8d901e..3b70752b 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -271,19 +271,19 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { // Add button for when raid starts time if($config->RAID_DIRECT_START && $direct_slot >= $dt_now) { $keys_time[] = button(dt2time($direct_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $direct_slot->format('YmdHis')]); + $last_slot = $direct_slot; } // Add five minutes slot if($five_slot >= $dt_now && (empty($keys_time) || (!empty($keys_time) && $direct_slot != $five_slot))) { $keys_time[] = button(dt2time($five_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $five_slot->format('YmdHis')]); + $last_slot = $five_slot; } // Add the first normal slot if($first_slot >= $dt_now && $first_slot != $five_slot) { $keys_time[] = button(dt2time($first_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $first_slot->format('YmdHis')]); + $last_slot = $first_slot; } - // Init last slot time. - $last_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); - // Get regular slots // Start with second slot as first slot is already added to keys. $dt_end = new DateTimeImmutable($raid['end_time'], new DateTimeZone('UTC')); @@ -312,7 +312,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { debug_log($last_extra_slot, 'Last extra slot:'); // Last extra slot not conflicting with last slot - if($last_extra_slot > $last_slot && $last_extra_slot >= $dt_now) { + if($last_extra_slot > $last_slot && $last_extra_slot >= $dt_now && $last_extra_slot != $last_slot) { // Add last extra slot $keys_time[] = button(dt2time($last_extra_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $last_extra_slot->format('YmdHis')]); } From c8cef10c69b9ca93f20bc5aa2c20632be9f4a30a Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 15 Mar 2023 11:01:10 +0200 Subject: [PATCH 255/367] Initial support for shadow raids --- constants.php | 7 +- lang/language.json | 195 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 1 deletion(-) diff --git a/constants.php b/constants.php index 73990f9c..7c34ba67 100644 --- a/constants.php +++ b/constants.php @@ -7,10 +7,15 @@ define('PORTAL_IMAGES_PATH', IMAGES_PATH . '/gyms'); // raid levels constant -define('RAID_LEVEL_ALL', [RAID_ID_EX, 10, 9, 8, 7, 6, 5, 4, 3, 1]); +define('RAID_LEVEL_ALL', [RAID_ID_EX, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 1]); // Raid eggs. define('EGGS', [ + '99915', // Level 15 / Shadow 5 + '99914', // Level 14 / Shadow 4 + '99913', // Level 13 / Shadow 3 + '99912', // Level 12 / Shadow 2 + '99911', // Level 11 / Shadow 1 '99910', // Level 10 / Primal raid '9999', // Level 9 / Elite raid '9998', // Level 8 / Ultra beast diff --git a/lang/language.json b/lang/language.json index c7213b28..5995c59d 100644 --- a/lang/language.json +++ b/lang/language.json @@ -818,6 +818,136 @@ "FI": "Ex-Raidi", "ES": "Incursión EX" }, + "15stars": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "5 star shadow", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "5 tähden shadow", + "ES": "TRANSLATE" + }, + "15stars_short": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Shadow 5", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Shadow 5", + "ES": "TRANSLATE" + }, + "14stars": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "4 star shadow", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "4 tähden shadow", + "ES": "TRANSLATE" + }, + "14stars_short": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Shadow 4", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Shadow 4", + "ES": "TRANSLATE" + }, + "13stars": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "3 star shadow", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "3 tähden shadow", + "ES": "TRANSLATE" + }, + "13stars_short": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Shadow 3", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Shadow 3", + "ES": "TRANSLATE" + }, + "12stars": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "2 star shadow", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "2 tähden shadow", + "ES": "TRANSLATE" + }, + "12stars_short": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Shadow 2", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Shadow 2", + "ES": "TRANSLATE" + }, + "11stars": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "1 star shadow", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "1 tähden shadow", + "ES": "TRANSLATE" + }, + "11stars_short": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Shadow 1", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Shadow 1", + "ES": "TRANSLATE" + }, "10stars": { "NL": "Primal raid", "DE": "TRANSLATE", @@ -1026,6 +1156,71 @@ "FI": "Pois käytöstä", "ES": "Desactivado" }, + "egg_15": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Level 5 shadow egg", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tason 5 shadow muna", + "ES": "TRANSLATE" + }, + "egg_14": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Level 4 shadow egg", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tason 4 shadow muna", + "ES": "TRANSLATE" + }, + "egg_13": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Level 3 shadow egg", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tason 3 shadow muna", + "ES": "TRANSLATE" + }, + "egg_12": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Level 2 shadow egg", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tason 2 shadow muna", + "ES": "TRANSLATE" + }, + "egg_11": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Level 1 shadow egg", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Tason 1 shadow muna", + "ES": "TRANSLATE" + }, "egg_10": { "NL": "Primal raid ei", "DE": "TRANSLATE", From 573895602c96d56a7c1156f9ae65a965cc38d05c Mon Sep 17 00:00:00 2001 From: Artanicus Date: Sun, 2 Apr 2023 20:19:18 +0300 Subject: [PATCH 256/367] Don't debug_log binary blobs, compact other debug logging Also add more debug logging to raid duplication checks --- core/telegram/functions.php | 37 ++++++++++++++++++++++--- logic/active_raid_duplication_check.php | 6 +++- logic/bot_upgrade_check.php | 1 - logic/language.php | 7 ++--- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/core/telegram/functions.php b/core/telegram/functions.php index 5197d0a1..f7f56393 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -624,7 +624,10 @@ function send_photo($chat_id, $media_content, $content_type, $text = '', $inline $post_contents = array_merge_recursive($post_contents, $merge_args); } - debug_log(print_r($post_contents, true), '>'); + // Don't log the binary portion + $log_contents = array_merge(array(), $post_contents); + $log_contents['photo'] = '[binary data]'; + debug_log(print_r($log_contents, true), '>'); // Send request to telegram api. return curl_request($post_contents, $multicurl, $identifier); @@ -800,9 +803,23 @@ function curl_json_multi_request($json) // Add multi handle. curl_multi_add_handle($mh, $curly[$id]); - // Write to log. - if(is_array($data['post_contents'])) debug_log(print_r($data['post_contents'],true), '->'); - else debug_log($data['post_contents'], '->'); + // Don't log binary data as-is in nested fields. + // This only works for the first level down! + $content = $data['post_contents']; + $log_content = $content; + if(is_array($content)) { + $log_content = array_filter($content,function($v,$k){ + if(isBinary($v)) { + return '[binary content]'; + } + }, ARRAY_FILTER_USE_BOTH); + } else { + if(isBinary($content)) { + $log_content = '[binary content]'; + } + } + if(is_array($log_content)) debug_log(print_r($log_content, true), '->'); + else debug_log($log_content, '->'); } // Get content and remove handles. @@ -864,6 +881,18 @@ function curl_json_multi_request($json) $tg_response_code = $metrics->registerCounter($namespace, 'tg_response_count', 'Counters of response codes from Telegram', ['code', 'method', 'description']); } +/** + * Determine whether the given value is a binary string by checking to see if it has detectable character encoding. + * + * @param string $value + * + * @return bool + */ +function isBinary($value): bool +{ + return false === mb_detect_encoding((string)$value, null, true); +} + /** * Process response from Telegram. * @param $jsonResponse string JSON string returned by Telegram diff --git a/logic/active_raid_duplication_check.php b/logic/active_raid_duplication_check.php index bb033b2c..a9993583 100644 --- a/logic/active_raid_duplication_check.php +++ b/logic/active_raid_duplication_check.php @@ -4,11 +4,13 @@ * @param int $gym_id Internal gym id * @param int $level (optional) raid level * @param bool $returnArray Return additional info of the raid - * @return int|array + * @return int|array id or array of duplicate or 0 for no duplicates found */ function active_raid_duplication_check($gym_id, $level = false, $returnArray = false) { global $config; + require_once(ROOT_PATH . '/logic/debug.php'); + $levelSql = ''; $args = [$gym_id]; if($level !== false) { @@ -31,8 +33,10 @@ function active_raid_duplication_check($gym_id, $level = false, $returnArray = f if( ($config->RAID_EXCLUDE_EXRAID_DUPLICATION && $raid['event'] == EVENT_ID_EX) or ($level != 9 && $config->RAID_EXCLUDE_ELITE_DUPLICATION && $raid['level'] == 9) or ($config->RAID_EXCLUDE_EVENT_DUPLICATION && $raid['event'] !== NULL && $raid['event'] != EVENT_ID_EX)) { + debug_log("Ignoring any duplication at {$gym_id} due to event/ex raid: {$raid['id']}"); continue; } + debug_log("Duplicate raid found at {$gym_id}: {$raid['id']}"); if($returnArray === true) return $raid; else return $raid['id']; } diff --git a/logic/bot_upgrade_check.php b/logic/bot_upgrade_check.php index 1b6d1e82..9a8f84aa 100644 --- a/logic/bot_upgrade_check.php +++ b/logic/bot_upgrade_check.php @@ -48,7 +48,6 @@ function bot_upgrade_check($current, $latest) $orig = $current; // we may have to do multiple upgrades if ($metrics){ // This is the one place where we have full knowledge of version information & upgrades - debug_log('init upgrade metrics'); $version_info = $metrics->registerGauge($namespace, 'version_info', 'Schema and revision information', ['current_schema', 'required_schema', 'rev', 'upgraded_timestamp', 'upgraded_from']); } diff --git a/logic/language.php b/logic/language.php index 753e4680..3f3545da 100644 --- a/logic/language.php +++ b/logic/language.php @@ -71,7 +71,6 @@ function getTranslation($text, $language = false) { global $botUser; if($language === false) $language = $botUser->userLanguage; - debug_log($text,'T:'); $text = trim($text); $tfile = 'botLang'; @@ -87,9 +86,6 @@ function getTranslation($text, $language = false) // Pokemon moves? if(strpos($text, 'help_') === 0) $tfile = 'botHelp'; - // Debug log translation file - debug_log($tfile,'T:'); - $translations = getTranslationFile($tfile); // Fallback to English when there is no language key or translation is not yet done. @@ -103,6 +99,7 @@ function getTranslation($text, $language = false) $translation = false; else $translation = $text; - debug_log($translation,'T:'); + + debug_log("$text @ $tfile -> $translation", 'T:'); return $translation; } From 8547a63853afc30c8f10b3a7a1e61cb0c4717166 Mon Sep 17 00:00:00 2001 From: Artanicus Date: Mon, 3 Apr 2023 09:41:30 +0300 Subject: [PATCH 257/367] Simplify image object detection, fix a logic bug --- core/telegram/functions.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/telegram/functions.php b/core/telegram/functions.php index f7f56393..26d33ba9 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -803,16 +803,14 @@ function curl_json_multi_request($json) // Add multi handle. curl_multi_add_handle($mh, $curly[$id]); - // Don't log binary data as-is in nested fields. - // This only works for the first level down! + // Don't log the binary data of a photo $content = $data['post_contents']; $log_content = $content; if(is_array($content)) { - $log_content = array_filter($content,function($v,$k){ - if(isBinary($v)) { - return '[binary content]'; - } - }, ARRAY_FILTER_USE_BOTH); + if(is_object($content['photo']) or isBinary($content['photo']) ) { + $log_content = array_merge([],$content); + $log_content['photo'] = '[binary content]'; + } } else { if(isBinary($content)) { $log_content = '[binary content]'; @@ -883,6 +881,7 @@ function curl_json_multi_request($json) /** * Determine whether the given value is a binary string by checking to see if it has detectable character encoding. + * Non-strings are treated as binary. * * @param string $value * @@ -890,7 +889,10 @@ function curl_json_multi_request($json) */ function isBinary($value): bool { + if(is_string($value)){ return false === mb_detect_encoding((string)$value, null, true); + } + return true; } /** From 00d92847eae7f0cb4c6e68966f87b6a90a4b4680 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 19 Apr 2023 08:21:50 +0300 Subject: [PATCH 258/367] New translations --- lang/pokemon_moves.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index 9bbd178b..cda309b7 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -2777,5 +2777,23 @@ "IT": "Gelamondo", "RU": "Замораживание", "ES": "Mundo Gélido" + }, + "pokemon_move_379": { + "PT-BR": "Golpe Deslizante", + "EN": "Breaking Swipe", + "FR": "Abattage", + "DE": "Breitseite", + "IT": "Vastoimpatto", + "RU": "ломающий удар", + "ES": "Vasto Impacto" + }, + "pokemon_move_380": { + "PT-BR": "Rajada Explosiva", + "EN": "Boomburst", + "FR": "Bang Sonique", + "DE": "Überschallknall", + "IT": "Ondaboato", + "RU": "Громкий Взрыв", + "ES": "Estruendo" } } \ No newline at end of file From 31ff49bf25e69e145a3db1b9549560c47c45e5ca Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 19 Apr 2023 08:21:59 +0300 Subject: [PATCH 259/367] Fixed event raid duration on creation --- mods/edit_time.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mods/edit_time.php b/mods/edit_time.php index d5ce479f..01a5ca98 100644 --- a/mods/edit_time.php +++ b/mods/edit_time.php @@ -37,7 +37,7 @@ debug_log('Event time :D ... Setting raid date to ' . $start_date_time); $query = my_query('SELECT raid_duration FROM events WHERE id = ? LIMIT 1', [$event_id]); $result = $query->fetch(); - $duration = $result['raid_duration'] == 0 ? $result['raid_duration'] : $config->RAID_DURATION; + $duration = $result['raid_duration'] == 0 ? $config->RAID_DURATION : $result['raid_duration']; $egg_duration = $config->RAID_EGG_DURATION; // Elite raids @@ -152,7 +152,6 @@ $data = []; $data['r'] = $raid_id; $data[0] = 'edit_save'; - $data['d'] = $raidduration; // Write to log. debug_log($data, '* NEW DATA= '); From 5b4de9a8c909b9958b38a836b019271867b6de35 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 21 Apr 2023 13:30:30 +0300 Subject: [PATCH 260/367] Fixed editing of hide_raid_picture under event editor --- mods/events_manage.php | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/events_manage.php b/mods/events_manage.php index ac911e54..91d3fe3c 100644 --- a/mods/events_manage.php +++ b/mods/events_manage.php @@ -12,6 +12,7 @@ $columnSettings = [ 'vote_key_mode' => ['allowed' => [0,1], 'default' => 0, 'nullable' => false], 'pokemon_title' => ['allowed' => [0,1,2], 'default' => 1, 'nullable' => false], + 'hide_raid_picture' => ['allowed' => [0,1], 'default' => 0, 'nullable' => false], 'time_slots' => ['nullable' => true], 'raid_duration' => ['nullable' => false], 'poll_template' => ['nullable' => true], From e09679f3529f52dd12d28da37da69d8434b2c52c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 4 May 2023 10:49:24 +0300 Subject: [PATCH 261/367] User privilege logic fix --- core/bot/user.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/bot/user.php b/core/bot/user.php index 4314efc3..f7ce647d 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -17,7 +17,11 @@ class botUser public function initPrivileges() { $q = my_query('SELECT privileges FROM users WHERE user_id = ? LIMIT 1', [$this->userId]); $result = $q->fetch(); - if($result['privileges'] === NULL) return; + if($result['privileges'] === NULL) { + // New users haven't probably used any command that would trigger privilegeCheck so we run it here + $this->privilegeCheck(); + return; + } $privilegesArray = json_decode($result['privileges'], true); $this->userPrivileges['privileges'] = $privilegesArray['privileges'] ?? []; $this->userPrivileges['grantedBy'] = $privilegesArray['grantedBy'] ?? []; From 5d6c8d8f9d0f0583f93fbc18569971e3beabf9f8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 4 May 2023 10:50:04 +0300 Subject: [PATCH 262/367] New translations --- lang/pokemon.json | 12 ++++++++++++ lang/pokemon_moves.json | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/lang/pokemon.json b/lang/pokemon.json index 65317350..94c757b4 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -5098,5 +5098,17 @@ "FR": "Amovénus", "DE": "Cupidos", "RU": "Энаморус" + }, + "pokemon_id_999": { + "EN": "Gimmighoul", + "FR": "Mordudor", + "DE": "Gierspenst", + "RU": "Гиммигул" + }, + "pokemon_id_1000": { + "EN": "Gholdengo", + "FR": "Gromago", + "DE": "Monetigo", + "RU": "Голденго" } } \ No newline at end of file diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index cda309b7..1fd6f4f8 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -2795,5 +2795,14 @@ "IT": "Ondaboato", "RU": "Громкий Взрыв", "ES": "Estruendo" + }, + "pokemon_move_381": { + "PT-BR": "Pancada de Ferro Dupla", + "EN": "Double Iron Bash", + "FR": "Écrous d’Poing", + "DE": "Panzerfäuste", + "IT": "Pugni Corazzati", + "RU": "Двойной Стальной Таран", + "ES": "Ferropuño Doble" } } \ No newline at end of file From 81b204f401ac32dbad27b76775a8823aad22db07 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 18 May 2023 21:25:11 +0300 Subject: [PATCH 263/367] Fix php error --- logic/keys_vote.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 3b70752b..ee784fa1 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -308,7 +308,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { $last_extra_slot = $last_extra_slot->setTimestamp($s * floor($last_extra_slot->getTimestamp() / $s)); // Log last and last extra slot. - debug_log($last_slot, 'Last slot:'); + if(isset($last_slot)) debug_log($last_slot, 'Last slot:'); debug_log($last_extra_slot, 'Last extra slot:'); // Last extra slot not conflicting with last slot From 82a08bbb7fcbb64f362f0c64020f2239b0c8a861 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 19 May 2023 12:09:16 +0300 Subject: [PATCH 264/367] Placeholder shadow raid eggs These will probably be edited once we see what they look like in-game --- images/raid_eggs/pokemon_icon_99911_00.png | Bin 0 -> 22668 bytes images/raid_eggs/pokemon_icon_99913_00.png | Bin 0 -> 21843 bytes images/raid_eggs/pokemon_icon_99915_00.png | Bin 0 -> 21144 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/raid_eggs/pokemon_icon_99911_00.png create mode 100644 images/raid_eggs/pokemon_icon_99913_00.png create mode 100644 images/raid_eggs/pokemon_icon_99915_00.png diff --git a/images/raid_eggs/pokemon_icon_99911_00.png b/images/raid_eggs/pokemon_icon_99911_00.png new file mode 100644 index 0000000000000000000000000000000000000000..6a5db10e6c796531b4c51abd337ffc4a4ca687e1 GIT binary patch literal 22668 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 qk*}5h^7_MQRXHKzi>W5Smm$nv{SP=@O7$ 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 ! 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 U+knB%;s5{u07*qoM6N<$g2OfczW@LL literal 0 HcmV?d00001 diff --git a/images/raid_eggs/pokemon_icon_99915_00.png b/images/raid_eggs/pokemon_icon_99915_00.png new file mode 100644 index 0000000000000000000000000000000000000000..bd29f0e9ff7e25dea4e2be58895e789cf8e875d7 GIT binary patch literal 21144 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 X{&&H Date: Fri, 19 May 2023 12:14:07 +0300 Subject: [PATCH 265/367] Updated shadow raids - Correct shadow raid settings following the announcements - Edited raid picture and poll texts to mention if a raid is a shadow raid --- constants.php | 5 ++++- images/shadow.png | Bin 0 -> 3685 bytes lang/language.json | 13 +++++++++++++ logic/get_raid.php | 2 ++ logic/raid_picture.php | 20 +++++++++++++------- logic/show_raid_poll.php | 2 +- logic/show_raid_poll_small.php | 2 +- 7 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 images/shadow.png diff --git a/constants.php b/constants.php index 7c34ba67..c2d60d9c 100644 --- a/constants.php +++ b/constants.php @@ -29,7 +29,10 @@ ]); // Raid levels limited to local players only -define('RAID_LEVEL_LOCAL_ONLY', [4, 9]); +define('RAID_LEVEL_LOCAL_ONLY', [4, 9, 11, 12, 13, 14, 15]); + +// Shadow raid levels +define('RAID_LEVEL_SHADOW', [11, 12, 13, 14, 15]); // Levels available for import at PokeBattler $pokebattler_levels = array('10', '9', '8', '7', '6', '5', '4', '3', '1'); diff --git a/images/shadow.png b/images/shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..cb12a540162f1f5da31f828337bd9e1bb5ec02fc GIT binary patch literal 3685 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 DyeJr% literal 0 HcmV?d00001 diff --git a/lang/language.json b/lang/language.json index 5995c59d..1b709397 100644 --- a/lang/language.json +++ b/lang/language.json @@ -792,6 +792,19 @@ "FI": "Et voi käyttää tätä käskyä ennen kuin olet käynyt ohjeen läpi.", "ES": "No puede usar este comando antes de seguir el tutorial." }, + "shadow": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Shadow", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Shadow", + "ES": "TRANSLATE" + }, "raid": { "NL": "Raid", "DE": "Raid", diff --git a/logic/get_raid.php b/logic/get_raid.php index caa86515..0628a464 100644 --- a/logic/get_raid.php +++ b/logic/get_raid.php @@ -43,6 +43,8 @@ function get_raid($raid_id) $raid['pokemon'] = $resolved_boss['pokedex_id']; $raid['pokemon_form'] = $resolved_boss['pokemon_form_id']; + $raid['shadow'] = in_array($raid['level'], RAID_LEVEL_SHADOW) ? 1 : 0; + if (!$raid){ $rs = my_query('SELECT * FROM raids WHERE raids.id = ?', [$raid_id]); $row = json_encode($rs->fetch()); diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 951b94c5..d2397316 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -367,25 +367,31 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Add pokemon to image imagecopyresampled($canvas,$img_pokemon,$dst_x,$dst_y,0,0,$dst_w,$dst_h,$src_w,$src_h); + if($raid['shadow']) { + $img_shadow = grab_img(IMAGES_PATH . '/shadow.png'); + $icon_x = 275; + imagecopyresampled($canvas,$img_shadow,$icon_x,275,0,0,75,75,55,62); + $icon_x -= 45; + } // Add pokemon types if($config->RAID_PICTURE_POKEMON_TYPES && $show_boss_pokemon_types) { $img_type = grab_img(IMAGES_PATH . "/types/".$raid['type'].".png"); - $type1_x = 300; + $icon_x = $icon_x ?? 300; imagesavealpha($img_type, true); if($raid['type2'] != '') { $img_type2 = grab_img(IMAGES_PATH . "/types/".$raid['type2'].".png"); imagesavealpha($img_type2, true); - imagecopyresampled($canvas,$img_type2,300,300,0,0,40,40,64,64); - $type1_x -= 50; + imagecopyresampled($canvas,$img_type2,$icon_x,300,0,0,40,40,64,64); + $icon_x -= 50; } - imagecopyresampled($canvas,$img_type,$type1_x,300,0,0,40,40,64,64); + imagecopyresampled($canvas,$img_type,$icon_x,300,0,0,40,40,64,64); } if(isset($shiny_icon)) { imagesavealpha($shiny_icon,true); $light_white = imagecolorallocatealpha($canvas, 255,255,255,50); - imagefilledellipse($canvas, $type1_x-35 ,320,40,40,$light_white); - imagecopyresampled($canvas,$shiny_icon,$type1_x-52,301,0,0,35,35,100,100); + imagefilledellipse($canvas, $icon_x-35 ,320,40,40,$light_white); + imagecopyresampled($canvas,$shiny_icon,$icon_x-52,301,0,0,35,35,100,100); } // Ex-Raid? @@ -542,7 +548,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Pokemon raid boss - $pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], true); + $pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], true) . ($raid['shadow'] ? ' ' . getPublicTranslation('shadow') : ''); // Pokemon name and form? $pokemon_text_lines = array($pokemon_name); diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index f3b3e222..949dd1f9 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -89,7 +89,7 @@ function show_raid_poll($raid, $inline = false) if($raid['event_pokemon_title'] == 1) $title = getPublicTranslation('raid_boss'); elseif($raid['event_pokemon_title'] == 2) $title = getPublicTranslation('featured_pokemon'); else $title = getPublicTranslation('raid_boss'); - $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . '', true); + $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . ' ' . ($raid['shadow'] ? ' ' . getPublicTranslation('shadow') : '') . '', true); // Display raid boss weather. $msg = raid_poll_message($msg, ($raid_pokemon_info['weather'] != 0) ? (' ' . get_weather_icons($raid_pokemon_info['weather'])) : '', true); diff --git a/logic/show_raid_poll_small.php b/logic/show_raid_poll_small.php index 649c0b3d..544c8dd9 100644 --- a/logic/show_raid_poll_small.php +++ b/logic/show_raid_poll_small.php @@ -26,7 +26,7 @@ function show_raid_poll_small($raid, $override_language = false) } // Pokemon if(!empty($raid['pokemon'])) { - $msg .= '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ' ' . CR; + $msg .= '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ($raid['shadow'] ? ' ' . getTranslation('shadow') : '') . ' ' . CR; } // Start time and end time if(!empty($raid['start_time']) && !empty($raid['end_time'])) { From e3428e476d83cc493a5444fa9ade586fb64398a8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 19 May 2023 12:15:28 +0300 Subject: [PATCH 266/367] Deleted unused exgym.png --- images/exgym.png | Bin 1119 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 images/exgym.png diff --git a/images/exgym.png b/images/exgym.png deleted file mode 100644 index 18f2c229dd544ca194660c48f78268597acd1d62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1119 zcmeAS@N?(olHy`uVBq!ia0vp^bAecigBeH`rD(eVDVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMRR)HJW(J0z|AF*N28L1t28LG&3=CE?7#PI!C&eFi1FH27@CkAK|Nnp7%6*uq za_jL42hO+dKAp4v(9UZQ{{8!R=Hc@V7w_DA{eJeb%kRE^fA-zuQ{bkW(1)hf6Dr*hfcl!MKm%nS$ zj*Z5iyNzeR@%f^>k+G9sk@L^TkJGl>xZ2tKKR^8?s>pJ_(cSCcHz)Ev`K^6vZk!3iZSL7MnV*z*9q?2%*tFo8 zvsLJXgbtyl+l{yO7DT^_n7rt0mc!yt+I^F(tuE {B#__T|9!WnN3)en|LcbwQGY zQAVlSV)c~gm-nc!E@sj_t*PFjw=b%6y571RZ5~_MBRyXC(i1{{%F4d|yyESYBfOz76*$-{^1RK z{EuJM^!w7=>X%Z$zAd)veIwrq>)Am&?@3iL*vOcRcs!iQxN!=5$w3!SM;Aq#Ww8q< zYqq6-k$xd}>E@%%Nn2Gi#co8;pUkMn++M*mS$Wr_%~vZQN8O&&yK&nCd+$WMOJ{B8 zc252j6r7o#%p@G!@}RxM&+X(a0S2%8OQI{ebbX!A9xe%ARk2mK!>gUu!N0x4`A%fd z?gM2d2l)Mb-(H_F?PdOw%X>fbw%YUS#?GDg;>M!o?k_f6SvuwZ(YbnlrkM^3)yj7- ztv(%7`NVhEor?avgA5l|*`N6IM@>#cqM*-6bHa2sD>Ik2vtRRnNAC)GRm0ic=eLCE zj?B3oJ+Y?mrY`(+#InZsUi`&_7yT}Oez@UGVV<&$&-9>^57o*_uDzecwMFcr%m({~ z+4+n{{ZnhtYDaoV+h0GY9mjes`as0J0Pa;;>)iG)I@~(*jZs0;YleBe!PUWkSf$bx zO_t4>TPCEhx$oYa5>J`+6}dTi0qooT!zRplmvsD@x!O^c6kQ7$Q;YS>ew3)h%-Xs+ zBF<&=jEb1pf6cRhXV-t-^G*D5c75*tr@H@R{xRtBv Date: Mon, 22 May 2023 09:17:57 +0300 Subject: [PATCH 267/367] The shadow raid bit may not be set in incoming raids There is still a lingering issue of opening eggs showing as normal raids. It may be caused by this quick fix and needs more digging. --- logic/raid_picture.php | 4 ++-- logic/show_raid_poll.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index d2397316..3304132c 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -367,7 +367,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Add pokemon to image imagecopyresampled($canvas,$img_pokemon,$dst_x,$dst_y,0,0,$dst_w,$dst_h,$src_w,$src_h); - if($raid['shadow']) { + if(isset($raid['shadow']) && $raid['shadow']) { $img_shadow = grab_img(IMAGES_PATH . '/shadow.png'); $icon_x = 275; imagecopyresampled($canvas,$img_shadow,$icon_x,275,0,0,75,75,55,62); @@ -548,7 +548,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Pokemon raid boss - $pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], true) . ($raid['shadow'] ? ' ' . getPublicTranslation('shadow') : ''); + $pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], true) . (isset($raid['shadow']) && $raid['shadow'] ? ' ' . getPublicTranslation('shadow') : ''); // Pokemon name and form? $pokemon_text_lines = array($pokemon_name); diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index 949dd1f9..ce8b225c 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -89,7 +89,7 @@ function show_raid_poll($raid, $inline = false) if($raid['event_pokemon_title'] == 1) $title = getPublicTranslation('raid_boss'); elseif($raid['event_pokemon_title'] == 2) $title = getPublicTranslation('featured_pokemon'); else $title = getPublicTranslation('raid_boss'); - $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . ' ' . ($raid['shadow'] ? ' ' . getPublicTranslation('shadow') : '') . '', true); + $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . ' ' . (isset($raid['shadow']) && $raid['shadow'] ? ' ' . getPublicTranslation('shadow') : '') . '', true); // Display raid boss weather. $msg = raid_poll_message($msg, ($raid_pokemon_info['weather'] != 0) ? (' ' . get_weather_icons($raid_pokemon_info['weather'])) : '', true); From 2a6ea076f9cdb7ec3fac6a93df3e87257f8f94e0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 22 May 2023 09:22:49 +0300 Subject: [PATCH 268/367] Add shadow key to raid array for webhook raids also --- commands/raid_from_webhook.php | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 21c3c97a..5f9e3e59 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -308,6 +308,7 @@ function isPointInsidePolygon($point, $vertices) { 'event_pokemon_title' => NULL, 'event_poll_template' => NULL, 'raid_ended' => 0, + 'shadow' => (in_array($level, RAID_LEVEL_SHADOW) ? 1 : 0), ]); $chats_geofence = $chats_raidlevel = $webhook_chats = $chats_by_pokemon = []; From c46aec480dc04c21cd6ceb883de36fa0ea6afa69 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 22 May 2023 09:38:01 +0300 Subject: [PATCH 269/367] Fixed shadow raid pokemon name generation --- logic/raid_picture.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 3304132c..7222ce40 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -548,7 +548,8 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Pokemon raid boss - $pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], true) . (isset($raid['shadow']) && $raid['shadow'] ? ' ' . getPublicTranslation('shadow') : ''); + $pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], true); + if(!in_array($raid['pokemon'], EGGS) && isset($raid['shadow']) && $raid['shadow']) $pokemon_name .= ' ' . getPublicTranslation('shadow'); // Pokemon name and form? $pokemon_text_lines = array($pokemon_name); From 204ab5688af78d85f5436c40d0b5cfc1af944811 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 22 May 2023 10:12:47 +0300 Subject: [PATCH 270/367] Updated shadow egg icons --- images/raid_eggs/pokemon_icon_99911_00.png | Bin 22668 -> 26655 bytes images/raid_eggs/pokemon_icon_99913_00.png | Bin 21843 -> 27876 bytes images/raid_eggs/pokemon_icon_99915_00.png | Bin 21144 -> 31360 bytes logic/raid_picture.php | 7 +++++-- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/images/raid_eggs/pokemon_icon_99911_00.png b/images/raid_eggs/pokemon_icon_99911_00.png index 6a5db10e6c796531b4c51abd337ffc4a4ca687e1..5833cdadf36f150260afedefb156525aac2b6f5d 100644 GIT binary patch literal 26655 zcmV)jK%u{hP)EX>4Tx04R}tkv&MmP!xqvQ%glE4i*t{$WWc^q9Tr^6^me@v=v%)FnQ@8G-*gu zTpR`0f`dPcRR4rtTK|Hr< z>74h8!>l4H#OK6Q1{FyB$aUG}H_l~;1)do;a+w5im{=_Lu-wC}VyMKk#1Tc+C|}6C ztZ?4qtkxQ=Qz!pnsHm-ExlVf=Nh~3SG(^Z~po$tSMCsH>F_EGBxQBnt@u$fpldB3w zjs?`ALUR1zGx*(Gvotg9CWYcOmKWRpm;i#iK)Y$%-^aGyJ^}pCz?IhZ*IU5+C+W?u z7C8cjwteSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{03ZNKL_t(|+U&i1ux;6O*7qA@&b8KloyUFj?Y`ZuZmDHk zmMkL+8I^3w1l!1E0&&dKNk||`0U?y*5EDWwq*6S}A(cOzf)oJ);Ss{aq)1hG7#A2E zSt4MJg>1{Vuw+@1rB?Ut`#6t%_TFpFImgH!bM14^KHY99Wwk7|?z%N=pL@>U`|PvU zx5nce-xyQ)B0557BuEgEfQsVao8i=XcznSf@r&kzYAY&Akces!(IA4@1|9^wjhrs%!A46Wdh`5N@`1sITJv<&B508h(!{g!c@OXGUJRTko zkB7&@&WSl}nW`ZxWCpLuxZ9s=t{$4~st@BcSv^Zj2RV|-VP@vBu;+NSJ0Cxo!`|57gf z-1z9KU;Wd~di_J$!ryt*Z+iE=hrs$0J^t0-_y@0D%;&#>|As&J5LmC$Qu=@*Ka0Hk7C`HbJcD7voz=wbCqkr%lf8X!;;6q@&ijEKd)qnhLlY{n8 z-Mo48>0&iDvfw+wQnwvoiL(PNxl*%N@|EAB=b&;CNMYTA^3Nc2q?gC3n+5r~kJHS%Edh+bbH^Q#PvWpkw zoY7E$xm+%PbIT)$Lj= z%Vif>o6Qwq$u6+u3b2qJU^!*SVwvs&ORekxE0zm-WAnrlKb~^_#;1S9uXylkxDNVi z0@Z_m@PYTW?c|;3e_V*WD@L@rcodi2Rs71*mtR+2uLkOzKXPTM`_9_A5F&5cdvgBX zpLp+kuYIwe|HWbig{iZF6))fA=nr-@N(FAN!FX`HNp{U~1bIGvkw={G@-uxWZ0n5{LweAxLaRbPA}u z=R)a=r@_3GjV;fElV{)eQ@{86jq85~;QsylbobZQVofHsl+wzME0k5*b%n#Q;|hac zafMgZ3>Z7EFi6^Qg)Z?*U=?;;pI`ZZFyC>7_ZCxb-MYnMv8X)U&;R^?^44$qrvLRb zox68l`}gIn+?Qp!E9-JfVX)^mKj#lER?WplMVlziL_{V=iiIH*QbcHjG_4Y1r&9%Z z_MiOB+vZQs|4cva>8CxD)tc5KQ6jB?s==(mRk6V-Cz-s-lug3=0q=X*^vICVQV3qN zLor7MLQp7<6stckxmp&+B~UbAqPPnfs8zRz*+^BCnpNTm5E+P`h@Od7Du}Dkh7eht zoS@G=$I6VA8LxZY>;BvieBbxI{pHTuw>j&vmtEC^U+>8J0_xs*V_}CXPE>_Mp zAkXFEaRfpQ)@|3~TnWYn2jBk8!7hD`qhk1_e}Z46M>3kcD;98v`M-25mrM5d_j&u< z-~RW2TUUSnTW^1lF3Vj_wuy~Qy8ZabbRMov9kb&3!K}IE4&F%TKXdXA?MoO~$VBF0 zPp?m|$J;lrHIF_T!em;oP1N><?<(u0M18z24+$DdmdzPIkdHyacdzKy?LJ zUaq(@y#g%R1(sh0mhS*-hbfeoK+qLntyZgZHwbWYa>8sjd*l;8{^S4nZ~gi=yt{9n z<3xW}mgR0ZO?PAQzEQ%&DRa<0m9Q@^dGOv=c2+jN0!VM%|CaPKC;!mDB!SgP7p}$I z-L>Y?gZ+5pv3a=mx-KsEU1SA>WqGh!m*v?9-t+zc(_*oB!!P1ZuUM@7@)nCLz~YL< z($8SAJ_E4)ip6@-m3}j*M)6>83*Z-^Uxc%g#zrRSKNFjJciZJiy9NWO;qz2xz*b$PG`%P2PyHq^&W z8JN%K_~A8%Au(wb6=CR|Ad`2VElxjl^g&!iZbfNsH#)i9>HPLY_a2>u#jQ!$yV2^j zHEg{sN9*2KIS}$Z-Y8Gazm`v}fBZ|!Vg+d^WHAbb;>r7UX1M3jDohleecONV&R_YO zCtveN+$j)6|UC7b-_s-7F2(h_jkzQhz-K5yJSDWo4J0%-NQuO@i?(CXG+kHN| z>k9qK<4ag9cfpEKl9Gy$i_&i*o0anAZ{7Rz&;BF%1MR&glyErBo~FffQ+&|kNz9Gn zDX7G~DBY}+`5+=5r3;F#;6(zmSGUF5*cq+1p65alWmTRQ5nk}mF8GsdD0$7(HuL7&={@gwjuyhw# zmq6sB0o?xITv!#DPWIs7kdzYQUaeOaau${k27-qDK}#Gy-3%%^6C^l380E-3-_6!P ze^yS8*0vmiHgOsb7M<>CtMld0E`MnAss~o5Gl|k@lt!X7W7SO+kRVZ8owkj3li&Vd zzWv*u{_@+uX7HY_ZRy&MKp<#9h^R!g603M=2?rfAQ`Su;e)<6nJ){A0Vu}-iC`#0b zSwh5#SqY|%9~TqsPp-com6Wf>Kw+XN$+)b}io z7NwPreDiUpqUg}0jU(b{sIi?ECl7_mq2Idq$?}QejGWz4abKEq*Ib`1@aeUkJy_Yv zMy1h4r%jZ$7{0urZyUa>`*wNb{M-4+`uksfF;=HD9YKBBS7`Fy)EOeprjUnk|6Ol= z%^Sb+ncsGLaz@hxn$Xb1Obn4QYNgB_l~K5duv)E{&1PJi%|LI!-Mg&s-~X&RkIRSH zm6(XK<0@Y?_U+0y#C9#7O4%VZw)eGJV6_H|6N2yY!t*^%+n^X4jMzAndHp=5hDGPe zcl)pUz+Wl<7*vGDoe3hLOw^VKVfx%rzPrknx?(;Vd}Tw~gigEpG_#L4s?vS zERSl0VZc%%T${opdoefs48lD5kp-G)@5W2#6cvVyS)0S z7fd|Wx?B#{^=e_`N_{Y8C`B-9SS|zksb?r@!fGkFY1Q6{Bf$`@DW&6-0_`Mrc~Q!} z4^KV;-9}})jIy}j>cO48cj)l-$u%z%v?qni%NX_QFD( z$44)suSu&F&1^<<>lV#0z^z+wr;?DfUpVFH=!lR4v)Sx3TP(k7vBJxmJh7|wvkQx5 zu9(GYtyTe%1Mme$56bv`p@`EM1kY$w2tjCCWinAp629!K=U;X5@#d#i|9bvHAoePa z1&P{*66f)$aM;YHx0PidaGXXa-iDb+Y51={_*Q?_xI#fiP%$qeq97K6wsE4fW*!bF z^Kh`3g@gTX`-V6F8;{(4^xemI)@)`6XbEVe&?lq^2Jqgoi4jEWg*HbmfP0k;yH^c* zH>G5Q2gjsR)ep1l*9eORJYgIj9l?)%6zIvWyL5t%WR`FFu6jEl3Q{Y9!X>evMO+mZ z#Z(C;?NSkL63+Bw_v4Le z7iRNTC)0_}7qhUxKMRM4U;8z$|HEfz!mw^A_gBcR1=1Eo$GF#>Vuerw8e}Y=$c5$d zmte>*S+vz^1*;W%A;RGyyzQ9^t{1)TN`=REd98~g^LBx_Ru}1dVd2JX(Y=1sVoEk8 z=Z>ReBg6wlX5{;sJZQ}lO>qgJjy3^_(;U9Gm?yu653}F3j}{v0jny+MMYxR3pcv!?Gx9hVScmK$-L9q-Zbp({kz}s zhVN1qdnfk|N{i=+zp#X-CpcARQc4;7^a48CLD#Y5@-nM?DR+5vbcJNPOgVgp;QmFx z@|Oh`K(WA(8;0DFh6$SZ1P=S&IHZCs#JTSkO-!{3m zd2fGbmIVq<@f<_8@IZ&@8etV9{muPQzT;nhekM)F&!er9(Q!!2yt&anF@I|M#@o}d z_jJ^D5hPA;Jvw=6F+Kd6epP9NT!f~J4E;d7v%&V~;p8X-v9ka57NWS}f$HQM zB`D-U$w?_GU`25g;=LmdpSk;6p1<=|f2oSTi0({0%iKkd5te!2>{Bc6zxPQ`z~;L@ zDd|;Yu|yQrR=T(sZ_I9Vk3TjG2d{6W+fxbgYkpVS`J-LR~cz+};uax8WiK z909l${vl2Nz7fGyE%`q6~^tu$(Bxv9YyZqQT&_ zgJX^0;+2vcY7KpAuvrf*pB=b$7@u5y#k0R^`Ju<(FU|yK3e4R(23A1t&*U)I!b~@Xi>fX&sm>oRwdV5nF!(PdT1}8Q~6O5o27H3#F`DfOw z=1%$QLk_QXq?Bo5B)IdU-jK_cUgg4ST`^wmVgcNFQHq-2x=#T<<_VQ88vW_6blSoOIW^qXPq z)OKz?bMIT1AA0+gNi`|tkbE8`mD=ha?~u5c9cy1Tm~ z+QepdG#unZ!uciU~8v+m3#KlcU1qUu>|q!V|CEV>+FZb0(LJUMlk_ zHA@uXk|=LCUTR1E)398Qywhc%>_+Q)r6%oH-0QgpYqU6;3{Q~yz-rSnXyoX5LuLo$ zH#|XqY;4vE_e`-&-Xu1?lZHzChFI-mY!nf}Es|2fP3pZOj!VW#Y&M1VTFc&>fBv0k z|LW;~Cc<>QzI!7_4a*bb+6PyJ=gwHZ^HFYGyUuhz!_LlFuh%cOSaQL4 zU$t1na=9C0om(t>S&MZw0CTY_Q$}!<;zBCIx>xSrH~P)M@KsL`W;52$9g~t`WQJj2 zwI1kC6RUM*=|+twLB-H!ply{&+t5X&KR%{;{~ZQ| zZf_5O2T#sfEEY7g3bdva7zd#N@Y6rd{Sj2Wgax|VYvMjmo;fe;$dy`RwKOGXBt*=6 z%ri29bnAfCW=;RxUHZPTJj<*%11S%jE{%IHIA_O3zj17E=GP;$d0-eaX(+@{2au>i zDch30F`2fMXRfpS@I8t+Zat4Yk=}Irk@err$Fmm%SqdDB$X$hdjd0QlgSx+>En4yO z398CBYf;F{a)0>dcgxcU2mW}@YeFl8rlE;}CIp%oi9rb{24k>VZFdul7@e+-G@&7g z65BwtXh_SmbJw=`=Vvu2zcuzET-z=6Y)(%&7(oY+^or*F%C>dB9n5wPF4+<9X^GWU zH7%=qCwLU>t6xu9HT2J~S>0c;UJopnnR|B!j_)VZ;H=lq>5-6Dj%A3QP_j{qlao`5 zVWlQD#j4A-tf)Gt$30CKkq}s&ZP;5xVq-k9C;!Q>{8OMy5jhd$SdnFL%kITr zX~o~?-D0^|aV)RwWc}`UyyXw((Up{9=xC|B*oW#;VD zC)~f2xPLFRS`}8S!pS{Y-VLOU(+@^ThUH6V%BrH(ij$L(Lcv8r6n6zFm>D@6<)o*% zHHS|O^nE5=b8bJq`ue-Cd;U-MAA90?MV3K0RWEDvRFV(aR$KP!09J8FC_d!B{Ga_h z@0!o!8_Xk_fO)JsD;gpVBBAnCV+&Tq$*nMTrE8T&gf>?9u&&f1o@@3r*HHPaSb3^u zE~CL}cRo+f@e1K-JGwvhQ9b1~pDixbi3^Go$5E3PMQPt}Sw8;)lUp|_Z~4`fle;Wm zIH6x9PLDDVo_Efc!e$j%p9pzrl-|Zt)q2xk;vLqK+o@GvsjR$vx^|6wBp$rPS zCIWs*p>^(-d*kdh5uzYcNz*oujkqG@Vx&|Uh8ko{<_)uJ9o_405%1n*NGCk;G~asn zZ9fuL@BiAh*GO9esRrpMr*(4PruDYb>s9ixzapm;f_DF7^25_El9 zaPKj9QgWKMfGasWDH}P}8>^W_Gzuvv_70~ko_+)UhkqE+$m3u6oa5EkqFsyz1Ct?wBzwnIm%8@Se!Ze{GEl2IyL zA*QNGsTXm%+K`JA4jX2Bd&GHlpP?UW1|@BbF?Km8n~7(+5v8)LH;QZHi+Rr#^viR?Yedx|?wv-AF?udNX!8CIZQJ58Ih z1pUTI>(N?w%KVzKchHWlVu{6K%IvLQ&+`56VZMm};q2>w@Q)n*@SE;0%RNr=^PH6D zIL-ISpOwY(Q73d^B0d{%#m{Sq1@fLh`n})S?H#_gcPG%Ggc^*xlZ%cj%R0HG@rahH z3)ife4-|w>I*wOoeEM5MVu_MmLKpxJRU)zn@ zQ;g?@86V@RtzuN&urZO?t{67eN~yCxJA=2r4cZlj4FshxMoxi}8Ynj2@)cCcHWc09 zAt4&h_40NJ%bp=+2QtIjQLUXtB{`+9FYrC^gZc-wL71r09}nDm>>9KAYq@*(IbQ#| zPk!gm{?KE8>^MKqQT{Y1`3`4xM6#E+So83htnIGU@dsP;jLGOwUJhLG^I@U5q?o#K z{raUD=X$=(g_Mnw9n9)5e{~uHZhCRSah7K*+?`ubJ;i1+V|n)uvT2!iZFQGggLp;< z+;$z!{yz3ihxiNgN=5wS8N-8*?v!iCPs4q46+0wpCv(=Zgnk56zH zR_mU=hhYemq<9&-uR}o_qw5MfDQKez0X&ihAtfUZH4`lTSaH}u$pxW7rNJ}j@uQDL z>uuJWb1fmAJV=x;|4OdAare%r{)-3s&J4Z3>o! zsLHIZk$c3)i7q2|gtLF^5l$CVPM&=p>6BiCwpgVn#x7*Z_5FuoK$eLt1M^#tR(uwDiFwPLBV@}W`M zxzg?j+C@v(K@2Te!+PzkR+-JJuv$8U6!PGstZSQ*vXhh)ld%=0PG!!?8T!cb)X}+; zU;mXH7Q)-Vnoa@SqK}t^FJN>3MB9y6NZKBiaG{x#* z4!6qT)2|7kp3syF*%`Mfsn65mqq2Ua3&c2m?m1K|nD?$C{{cdL35y$dTR@XG~P=7vYBFd#jTa72tkz?zUx2#kN;LU zN$uI$hPIg@7I3RGs4OLNc7_e~tA>6x!IGXUGZDvfB?SYCeszjHw$Exk)cGC`;x^7j zaEck3GVXy>U$3HdX+SkFtjsohcTBYfft_w6#X`4XXRNhUaBkH&-Zc51w z!6M{{h){5{l}c_#qnRu7!-j+FQw|O%?C*C>+YY6L++Yc;7os%iBm39ye)@$E-M>=? zr%Wb#ZE_f2+a1Q&wllpM8<|BFZGcupLQMz9g8J6?$z{^W`DFuEy*xpK#PFW~sHU+r|)}WY;e;mhZzaNG&p?^n{`LOo>Fohdaa{U)2+%$Fk^YP;(iB{gPWW^ z7|2;_VR*DS#R|m?8~lXi>Uo-`xs(r;msK;ESal2zA^}@v%Ew+H zJ$j8en=#mg<%1Q=RiWQhU^Z=}Z6nPHs2G$Ol@Mw-K($PQ=ZFmrmSXJ&a>!mtJ|JD8 znJV*x$o}Dk!|PM_4<_vGHB4ubwoyW?ZDVLA<$>9vA)kG!{n$@;KNqDtn1vfR7V*~W zxE5>x03ZNKL_t)|S-5^}6809I?oFe1t<*MKQBkd$Rh1pWuVrYO83P>iUp5lQgzy7ITbMU^8|Go05xq#0_ zLI+kl-CNDWBPYGxey}Qc?=8y<%eCEKZ_07+vQiV1t&j*GtJm&c>J@v*tnd}HSV};p z-j9FpFZ?fWx_RyTABs^(^MIW6qooR$ViB)(vtH>p9l4)iIgHk#jt8n2)1f#<;Jyd$ zetbnUzky5^q|Jt0jA0wArCNs@lCj$2sNac`Tj2-wO;S9nqOu`3o!#`;?2*@TQ^ zu0TV|isUICIxKXoPX|tqj(G6#BTo8`tP?_LXtWu-oU4^;W_7oWVeM>|M%pN;4+t%0 z5lp~@lATl%-ezX|k;Cg9hc{;2xH04UjgI{TWpB@!Eeg|VrtK0sNw}^FO~Tlq9n2rk zANq;+KKJtoO{3HORu_k}aCmJNZd{+}!G5FDX^^%R6!V;uZOZxmCVtV#DZahE&MT#t zW#RFaNeN|)t)i+l;r3&yrC2$WhZ54la)LsP$Y7%X6AQ8%?12L&ciq~Z+8Ng)u{4LT^?U)9IG zh-!`3BnrVCUl#0c&*m&wtLarmMQ~^;A9ucu3ZRWJokbS&j{QZ$-dP}0W+x=$xoPj$5WHxPkz zvZ0hhYyz7uGYmbmd1gMZn_Nl^>^=G@XLs&!a_0_*SJV!2nPR|43umJRX-KIfm#sAc zD-CI|(NY#RDPkUJ;)K3$$Wq$3D&AodZf8YZkLKov$my|J1 zuw8JejKXSVGtAkn=k$HcFtqeTLq9aEhlbTAa<&PqHx27eM@k)~G^m8ivyJL`OVx|y zB6VDz~P8(WQYt3;6?qVf9v_1_+1q#p)Sg3Y?dNyq!wNS{8TX*zOhD7m3* zV+!9Af;CIRg<{~=L2l0PY%inh7?0Vay0O)=hkxDEzjj93ML_8G=BNvnA|VX)Lt*v) zf5r0nh^Te)o{c&#`Aine16Cqwn9vV_lwinC^1_fZn?BJerSG91B37EJQI~DjUSqpb z_duZ-3|XpmqFSt!jlL9yoJls+5|Cu3ozS$9i9ezji{@i_r;V zM~%6kf9Oq*rHMGQonnSCo7MEZd}@PPB^!Oxv)*sX-5NPQfwMcT!>74q=SO1)tMHp*TK zPC*q?uG;n0rZAL(S;5@MZe%l38A!G!vw@JAmPp$g?cYI$oOoPTKCNehkZgI2~i~HE@ zvsFNR_P}~MQ0?+pE?&pL%3u55KmO*$!Qv}6n<}l%*+{)IYyx@HB9AHdkrhM9bkm5J zG!mV1-r}^C&j^xuSKHA$+#>y+@R6;7s`jDRXy=Mzxd$S($dTq>tuRt{hI zE>tqAc~oLX%$oC zaYBu_ozFE@3K|k2BtqyZUMOCw%@qeNct~W=45d)qP`Ma#6GBU)Esad^JjI5Fp^t>9 zqngwREyUIcP3@u<3Dq4+ReEI4*jSBu{WFjK>Yvc({?SDC4;y9+_0W#>4L8p@`TA_* zCwDh?bTs(c;B~gnd4cTwhQ0`{N0z=qBL31M^6q_Z|$k9GqMU`P$?r=No?dWyRww$GmUVF#vSk{xi@a zGE{y;#|tJkO(~L@O=0$yDfXc=WLaoKByGnlXvR^@!`M8n=kber+(Oox?a1GDK&Sp&zJnA&&&_h&o~3%#hiP zs4ZfG4S^(;?g+_|CgY+cGh7QzYcvyTB_cp6)w&f24f97^Ssw(6lPZ3`n26$7G0&Uq z>(ky&&$4flVO5JFsxp@G#YOz3%Xyzu9_!pWIqrYqkNwf>ZPz@V(lB=JO6|G{bB-VlXhp zyrHB?eXba)qszOp^TY+qzAXY?`pd>aAloc4NKX?AG@A;@ZfsbU!bTh`iLMEtN)uBB z)~M(+r)v9E=nBjY)~zz@gmnsRhCm)^3h{<09kZrmGV4ZpON~LTjFF{-lt6K(Pl4=8 z(>k$pVl&X$`YN+fJCh<5A9j^v(#b2xLmC zWaQ4kjU7v3h!`;pbj^lIOmu3r!SPUN0=Na-BO4Edn29kHL!Esfmtut%0c#81%YmI= zd|xO8%}6j5BiQBF2|3q+B{BkQ5=P5rE$)Gc(l`_XgTb`POmkqJoORREZ>E$ItJNw> zygg+$Z_&|(vel_=!@toQuzgC?3dFpY^x%ybcA5WK1264oP!5J7v|W*|ndwfnJt zk9_tP>tbq64a!BwO)pi*(HIh_MDVs2ywzyJK-2*tVp?NK(VF1}0vhV&+ir(qrBdl8 zEj~b)!Q?QaYQzRY@DU`neXR0uHF&o3p}A76lnH1pQAwyPMxmR^0pbytJZ6u6(d?!{ zB(_1CMyWISmAXrNb%k52B>`8j*2_NUz}ns8%AH9&`I=k?LR8$G7$Q1x=EX3}z(6WS z7XqEMv?y*5h|?*1?>c1qV|O`v)|iCIkere(w{wk;v092IBqpJ!={Cf+)RZJD)6#*~ z2{zbr)W8>JP0v(?CI+G!kwW7cvyPgCR&K1-=3LZ=IZ1RJ<1q3?KGHX4xD|pWqLn(e z#ySR{k}V>Pz#IGc%p-+}jVwMgvU74VyGsbDG>8ULC^Sz`XhO9SO{j{os*>DxGmZKK zt6L0L`CcFmisf;-bZ|mb1A97{&SlTYB2~1*x%9HyrZz}Bi!z<4v{8wnKCj-6qcsac z3@YaC*)B>uuYfBYwc~bhaQNm*?2G}sLKK)z+S)2_&St1CDU9-#X**%P*$}5w_}WL9 z{?L6^ch`u-OVeU5QeE6HVyh<6s?jJkA}IAf6RoGC-rH+Lj9F)NK?%AYHCbCwajzeF zv|i@riWGUvypI}HH{8eV=&YRgHWq_aT5_IHN>|4X*>*tNMY+X{aS*T6fp2bO?O z6~|R1Orms)MrQLUT{|-JL0!kveg&3F4DQA4g3I#HC9wQ*(*J+|&wu3*<;m)nIp0(% zY~{ILHC3T0h*vooIKz+tA+6Sg$&~PQj}x9dMSl3K_CjCkz1zAXcSAL!lF)H*h?&n?4ej&TDf{&}1j0z<`7bw~ zN-cr;I4|D7^SFaq28*@sIa&BLE?5kwHq=H5QLTYNaM%lUxz+t;tIMN}o%G^o$+6z+ zCPcyOoc>r}ivndEI>gVGn{xk*Lp*&9^my{I$KQOxZpbJ?94873G{Nbbdg6Ul4qLW* zSC64gIa`qjqg}Mbx3|c@SYvlK_ke(Lz2;H1h@xKHiOrr%1+Ww2rY>0^0Ul#-);!G>B}cFBpSr73z(Ak+MGL{y>PH z&#Piaohy2=0ho{}V%wNM>zT!A9wUeMSf z?h{C{s;%sbQYA>M^Bby!g{kYgjJVaGdE5=h#~mP6yIYuJK8YpHfj$ z323M;U|avwOVfz9JB7)m)=RO`8f~{Bl$v3=Tw!I-lfX;U{_GM_>s5$d3HzFDw$Xq! zZBrOZU|s6;<8_*ltiimxO+1s$>cl>;1J~pYkD%(TS9LOBH;MFpuC-6|^OpQnoMBLg zjn?yM+mBbhMBOB+RMnqsryGt0izzlJN@xVtUqo4_K_~OT#bk`aVgc@jljRZ(bDF&t zzOIE2ujp4BiYX<-;X$eTc7-7IJ$-aJ0l{k#u-4$X$o96Zp^wQ%{n);{jk9m#nM;Fj z&9{l!IE1af_c#Ox(M&Ld5-2H>N{ggOE))7R!Mr6UXM?afTrk|4k%A!!EDtnV<;!Mu zjFVga+&+pqQ!-Kt484=HUd%zcME;6wX&ElX)+6_2pi#nh*0l3dl7CSZZIpHzWwIF8 zBuEopZhXUM1*~mh@#T8;mAT+5A}Z7A?4a*^TAA;Z+RCU2E4h%fQ?gKUEjVLZ2lC5B zQ;1U;lgYGp-E4AZy@WC}#Q7ASUJzt~{M=nOsqo-r!1p4#7=478owhOB2yLTm$0NAc zj%V3w)NE8yP_S(YYy{V38O2LktZij!8_H}$O3|9U7X&W>mlk|V@hPcvoUK|meM2{m zw6EP~l?!=Q+4@@Zix4uUI6BH;46tJ7+*Qs(&Q%UmvW;`I>Nv?QiCa}7eon#3)@g-W z_ztZ}jnKxq&0aTi9NT0EwX_rs53={i#q*K79lQIPx%G84+KIsH)&7Wn_# zd)HXova3As8)MG3_S&y=>zs36Rj!u}#^txMLkMj*B*6&Mh@??MXlNAW)eoX1O7bHJ zDe1I2>4d1&iV|9#D3KC%)N&d%1Y%;ao6s(Bz!2Nm#s+Nca=GlPd+R>VbHCPFbIvjP z$CzvFz0ZBry{1gM$epFBbMLKv_G9g_#vG4td>{4;$Xj;d7h~vkhl8Ufyh|utz(Z4D zJV+Q+K*@?$E!HqZ0ilB7wNuLCN$jAMH3%toINyxnH=gxP@>@yunsCM`>iGhqipDtz zF~)HK1P2WTBvd$RE6m#gRt;k?9-w}BjN}K1k+3|9-~xuca0>MaO$m5s6q-z8?8?b9 zKM@njl$dpQgtLD^4;xA_G-}ss*KR`GDYy`DVS!^dtduk~QR`*WW)-zv3gR4~Ln1ne zTAwsBn>BKLyh;a$t<2_0V=EeEW6}WvxqVi6ml~Dc<$uyvIBQorF)|!cpK#v-50mQu$X>Xs-Yw!A-_}fryCE#*lSbGD&!fMn*;nmduCz>DaIp8H+4*FLi0LAj4Kf0!qNp7yJ4NFtZabxC};0>b^#qm7!Gr^(? zUuZt^88HoT<;kx>QSO2L7-=v>TMJSMI2QvBZmtmKB@`u`XT*+;Cbwb)0HT998>V1S zYYx;LRwPwOq&_+72zfQv$TWILaDX^#AEkVRXZFAXKp-Y2?@66gNDQ)^)pC4L%kj-d zjt?819R@6BtbJtg21Of27V-qM~K$lCjizSG2WJD2Yn_hdG^2k=74T|F7 zulbt3+O7cf(mAB0n4G_aRb8NHcW`*5SS$pK8!Mc&2}uHywg%rR0jg;&y197yK zBhOXcEO$l;n6(gXu>6HDVsC#R@lCr>1)9YQ0g5V5LfiBU&g3l$O&!HgXMl==9cW<1 z)v^GZHX%iam;|NRU0aoksVC6EDOv}#L?9Lnhg10R7&P58OgJ}44)C7gn-w4n(;H+4 ziUKhugb=_)C!m0TRKvoM~!~nNn^j2SN-v##5gYij<8x(@c`}4vq7{uCWJOXqVy$*q!EjgE9;C4nx|_LnwHVjK+`zH7$FjJ`B2wT9VQG)z)d3B zf)U!>CrnmYHmp1l+l*2WHP7ivi|cY-iZbI3h_FGdY5hlL;3T1~#pF|@GTf+RreJ|iR| z=)mRzHLG02n0m@2QH6^h2!OT>Z2{GYvSD0WUzce45CS647yx4m@NY8CLso6I89MC zCYu*Z8@D~Fs*0|)%5u?0@7{#=RBe3$Hrre>lh6L51J!f(TF%IUXuzH-*CtscF+M5D zoqC%KG)1iCvIc&&#+BEMvA4H_$#jeutaU+K5dH4YW~8j>SV1z|a3@A-uroVWIhQcF zpF-6CqC_H=%RRi^x#cHLz}LTt(4_fTmHKj+PY$rGqPt zQ{94b$rX1SQf;CYHm!i_3V{+aK05^!s*Htpyy^iHkZKDE-$ZEhogS?Epn8}gJC^;tb z?9H(J^}~Z}`{&MKlsuR{SQMNXLLQEdZkqu3FU-+?VUBA59Q>v8@O!ci7(Ce+pCBOi z>RmZl;EdE}bMuTf_HmPZsGFwln&Ew?8)cROHtY9lh9r%ZumTw`mAP$35xB1tIY}tQ z^#Q>rKG>Sjsz99~($EA~Ca^FH7JzeEzzdQxVgx8r4=!xI0N!Q`2?n2V?%iRp1r zx5C_Cy7KO+%G%BS*gO$AYcSZ+XPrFq%qBR(Oa(hCok!&x=RdCi>L!335EDVkSuM94 zKn38OLrMw9*N=efM|fy@5qNvGRXW>-z0yWWEqe}dmX7PvOxl9R>&D!!+yU@In)Ojb z&bGWcctgJCX_-8m*C9z|ljD7h)!ERUP9lUE?7A{h=ERd+#FTCrL_2xIJR)cB+50v6 zx`P%61Gn6@u*e-`PqK&Fh{d{@OB=zr(?b)(!Iz$f(~73&0xeEjnxC|o(RM@n4ENeg z2#4L4yJ5_iiO3O?W2TPWqbeK?N=K!4R60ikXMY}eM}xvsWt%JikW zK4Rw(g%G1@&5%%rp#TX9&N&;R1Q6yC?H3jpoOs}250qnIPylVn$V=J!P?{A}wP)Ky z56{Minrc^Q1=DRk`+Bxlx9)1)l<)0KJO^^3n(J-rzFUVd&^+hYMnM}0=PU5o001BW zNkl#(#K(%6sXNh5eYmC z97V88AeZtqwjcti=l(#|4qGeF#wKbrYjw7WTGy(nwRkILbsyBW_ZflpL9P{x>a^# zc5njx+zBSH8UwEy1JkVDwOFEFStjXxPOmp2jdjh9ZaYAvFH!Ebfds>ei`ZS~oMFYi z2-JYM;LZSYjAo3484;R*7=WfBELMyrX4D2NB(ph-FhXR6z-WU<2xL4C8GS%(KRMs| zT3Va48_tT_i4bi2Eq1wsaGIvlUcD)?+z-Z2>$mZ!=UG$~%Zar5(! zyyNjV-2A|EAT12$kq@IXUyicP#A@n|eAdOaW;1}*=MRC;9b&jQ1)h8ecoe86Yhtw1 zQ|&l1EpABLro)7d?l7{j<;Haq*}B;{v)ZKCiAFg%u{%C#LUP9S?$`{PyYzt+0fL$e z)JZX~fs){L$0)+x886OrWLF|r1?L)}^@8kgt){UdsbsVyBQHBAr z%kzYgp&qo2*{~ z9VjqTq$*-jL@ZbljZj{dj9iU7Ly{f5F8u`7Bhz+g?ZH+<0RffRl_UyRrLNX_M9rYLDNCI zUC!UUp=31y61A@+QTABu6yOM=1jh-KrSb$BQ3~m?`)#XpL5QT*G_lq^Ie&8*ZViD319B+odQHdK&BCkDq`Uj5rSxC3}hNqI3{@KdEh(`%Yui4XP(h7zwvd9 zYB)qYs<2u%C`M&I{-pm_yUFAAh|hW$H7g)sI9z+F!_R#gdj~tf{yEIP7MM;)ePdyM zc)Y<)0eGRUH2hwaAGLoE=-HY(=H-+;A~A&7D8+rsgF1vZC{9jW9G@`evjR=+k(_y} z4hqCdTPm-jw4HY;-PY)HHwTV^!mACVs99o)W~4-b^MayOM4#4Tof)f7*`Tz4Z6HQB z%Y^8vY6GfjJFVYwmzL1F__}p8-o7kxhpcd@M3jg)GLZvel2A?sW7p9HO75$puW32Q zRIuZsU@H7?e9*n{E$>>M?o38IJKuN_s}Ft|b={&UJlsZ1q&*K6!S_bB=A_TmgZ+Ek z+uP|4tT@=g9Kh@i6HKOK>^$)*d(iPIW~XyQu+lAq+IIwM^!Y0FO(hHcb0Kmv9>aU< z8@6o&VM0iK3M5X2cG zmz;u%{O-KfqBIMtyF%f;6?mcfXwRrt&6?E=SiGBxM#Aveb4LZHA{v$iUNLb^#0`O3 zlVM;1oD#fRCp-4_LA@W3MIdp`M<#06d}-w{91AMnDHe!Io+DEwBL{Q@N10rL0HWC` zu8c;02LOtS8IOSTc4RJ>E7WxZ)z#MLELMIiD0N=eF&hCZPFDXZfeVjZ0!T1h ztuPsn;nbu~n&lGW7^~DmK6?nvDo{NDi$l9gh&efNCoPyfnkl0!&A8&UL^<#l?>IJu zo+{eLe#i3$l}plGaku!6Sm8vGigohhd>#}bpsABR9UCRLk_GfB65xP#<&Qj-tL}tT z5`oGpXt{DIY9?0`QA2RK6`n-MDdlFj^>Cx&4y?(yHLUl}zem4&@Bb17MEeSDX@nC;}V^+D=vM zYJ(O)QCcmoeZp>vva+uw)dB3-WP1rV*+UA?WQ9~Vg0qgdm@~*&S>ZUsa|B!iaDY-k zgn$czIEG+yBcYl*Dm{Tcfx+q$q1&7Yl!&mNT+oiYpRheZa39d*T8<5$L<3Ih zUe`??+9sCoYD*gi{M#SLue{^y!uRg*0GI{L-!Q>+w#00B}U-iFR9YieRGK1mN zM%jJB<;%P9p5XrFFJf`A$ch!fVzJ1jW56?^bb|e9!eFq%DmbhHqYeac0n>6KM7jO7 zZkycl`Ssi&FCFmKb8y}vgw$VG&R=UsfY!l{IP+4mv#G%NNCEfk2^_D$yn?zGN+A~y z2l-g%nE#Ang=#p!a5OMa;1yI=p=}e|Hlh6F3Cg#d?p+AoEI`NHlw&8}=+<@m*=z*2 z;0B(SU|s>#Kq#U+0_Jsd^dF#X~eF$Yi- z4pbGulLIVS>=^5Gm$O`@vPh4ONW}g>$YPFr2qQxvUBrPD?&FEooXYu5;>(F?!eJ=OtS@ z0C2hZdJ-fD;tHTCQ#oY#f;M8Qds!#TaP-zUjlQG9UB#H-3y7nLzu5e8*EN-G9{F=n>bw@p(+KAZTg4H2*-ktJ-7IW2TgON zkVxdn*|Fz4R9R+=T?Sp9)^fCn(zZ$4n3-gg=E|KR(B!t(c1OdyP`rr*(E(b4XyU0d zDGYMF?sUKOTApz8>aR;rPR8Zs4$v24LQ#0&4P(@gc;Fdp)i}?&HDa5Lp*4?(Zx&BC z>!`Z+ShO~(^*ycq-Nv#7A%xG+9xo9k3C3lEfme(w#=sL2D_n*|GZCE7nn^Iza+7S3 zu_ew0NCWh7Zn&#b9;;vXFSnX8x~|Y_M^dO_$xTwE%LU3o0nOQB*R>XFN%w{6lw#F#K| zm)PCg!SGFc7+#6M=>oE9fI+#fxTR}U!xr*~X!|InwNb5GF49-1SUQ3aYip3UV6-S) zM8Oe5-=JW-!yN&U%!?G>>TE7jPWkg7Xa}wChE@}8yq;LEG1G*L5)!iK(oMsnHJhNC zN>k;c@{NWy34O>U7ws)I0lqq6QD0^BBHn0(tQOp{)T;D29q>UOfH> z&z#oJ23^%b7j@FmHJMvMYy`0uq&jIcZ{_r)mXniK<_qH?O|srGW$m;3Gps%TS`rN| zAq)TvJr4^{1IJW)Cg;}JoR?nDJwwmE<*ob&%Ym;#h<4l&z=08F5vYOm4Hw`pPf#33 zgth^YPz7(vuUH>YU4_sp*m)?i@j$6vU=oIGG+4ERw{)`xWM2}y0LKjqSEFcB}awv#FiNT4H3YY6hl*!Iyt3?7%RxcuBOcrNYdveL9tc5eXpv$n8 zY!o7J5>Zk>i3SBVDA1xJqn8Zz9Fqy)cS|G@!?*QAS6H*;fZ#a6`xeA2xS`;o*Iq`u z<53)5#nqGNul@A1;YS29ByD2Ul>}YIq-`UJbJ1{^w7nU%zTU{`jiuZ?TFJqzmH8@a z9R)D~Nkp@8X}Y6f-7$Di+IIdS5x8ySq%LS&I;{o{zEENZA+ zuubnsn!p@0e55tXBZ}4mpgg%k0#>(mb+pSA1bu(08(Q6@z@Uw`jFKe`Oo~D{A2JD` z8pK8$=|mAx^jFP6;3=S>22P_O+C*)F zLZh{PBmtTXYIEn>gTM3GSLzbkl+cD&=1t49#_O) zWAv1iYplHX2u-F4kAQ*|j*^j%k@OUi9U7B1nZtT;-Wr(KO%kI^4wQSPHO=Mvp2%4N z7T3%Df)bc&6i%_y21&fNRtWGA6dJ*3!MYy%4@og%0MuYINN9$N)iNM;y4R5mLUSwO zeNQONxe~8PCx7$DKlWn@ZAhAeYDy|eEp%96g+onfG-)kLQ5mH=3;|FI8e-HKMNIfK=M9vX0=_VoBZJsZ*96$1r8$b1j{?Ow; z(0MKAD9;EAxD%*kpsAM_k4M;{fg{v|yZG%0bBaiDSoQMdY z{>*3oNz^t)ZDP`<6^T(*r58;%e5?{m0XebJ*d;_oVy1ILp9v=E_)71qrDF+7=q{Q9 zkf4ju$VqM3ceWvJo@jyLfKfP$JVS6ed&oykUzNxcdfyEzQFMRJ;dzh4DCqp(C!|RGLkYD%dj?U1soKf1O+Kd z04`;y04u;A6cwB^J5nGO5o|aaxBxgA^hGmMhlshCXoRuED+4bIn=-7+u}`uIZ7Ttq zAOQn|}j)>@X3e;!UuYLUZUw!Mh?)>RICX-_UMHZ3kJ5ijO zWs#*mU3tfXAPj23wNjHBYLg)JGe zimdz7Pr>I?-ne?rgH=VxgC(d_f}@C-$>Vyy`kbgZwx;y6U;5JjY(uD_5!f)QASR(G zs+;n=T~^&`*=kQ1qP;Qc#yE=TeH)f&=(^_0kQCJ=sA~<7=9$$y*3x+$cu!S<^|aev z*T;T&_@SqsJov*GE>0g;3AviCU|nN=So^8PEt$6-xv7Mm=>((ieiBcJV)0X-#)~%& zP~HUas&hTgi6y~Nf~RDjE9*&jnVd^&?J5#Af)d&c#HBYXV>UixSfE~7m&6EayPBIB zoOvY5hL?=Z){@DT{d?x$?w(KbFqPzcEC>(>mL+O1c&=nMv>}c`3LX$ckfAPn~0`K+O~oqV)ZJqx>U!*pqmBej!pG!kS->F@)cIzXYvBZe2EO` zs;0(5{oULTTR18`Q;`GtwQA1YUi7rCzxal)8-EKl<}X}LwStXsmdK7q2e$Fpj_xsI z#=F2Yu2vXKCh)Jj0DfeI@$LoG2d9u1R-l~{Wo%I*pg=+aMUm;aIa5XYV^c$!cS85x#6Os2U8ah-zHmgCG9Y@B7qqUp`3M zhJ?m6ZEdPq1VII@2wE}CK|2Do$3k};=7LU-xW5+%a#w}bA@4IFtVUNt02609DT{<0 zJCu&8@Jt=a{Ps-AZ4K+tpX`ojJC8rI`)X;UrPd0#A~P9lJ`y`B`#gW$acy-$woeYT z8;77KVlo;7uQ`w6sYh@^r}*5#HC${3UUIKYfud-^NbpcNRS35*EL#Jj8mJMA@ zbZ`<}61X7XR2ZK|H0?q}2aW&-1qXo-09q5Gl$d*!L7`C~L2TM6Bp?Vh2$HaQ$;4ps z0CD!7RtulV7$?_HaB+G8?bkmH9~}nu3O)+7ji?)-iHxWO+VTB%7r_hbz6vcKwASodC+#|lLVO8{yc`Q|JIuR`XUyqfb3lg*AID z?X-CuilPJ)A%uYC%>xXe7{2v&7#trXed#8KCBbKpSWs)U+p<dATlUAP;_RLiL-G!aAZS4MT6FHBot+V z<#LJ1XpH@LzY*!?O*po%tWAPtP}GT#pm08*7`7M<11>%?z-)GW^@soQPy9Clxw@_) z2vRr3l@HTav>yZ3yP>re_qpzBSOeZ6qX84P3YF`b3>c1x3g@}at;VfqXCS1hNb+8&%iMU(f#8XK$JY)og*$?|UQkqn|@t zFEK0&Lk(zcWd0S)$^n^}oe)i-ouYK(6B?UO*+Z&Z;k0q}6Xatz}qvH(@D|_XW7hb?bfa>i# zSbY2{B({(kFyxp?|E=X>jbh8xNE0aK;5v$F52kd+W8K}bQb6ymBnl`}Z&dbkU_}0r zfM{Ncq8S!PhRa4p!D6_YTU@+w0sG(fCfvMn6IG9H&67POU>{KqB8FAMaO7})cZ%Qq z!f*clfA}*$|8GqWE`+3QE-gqDBr$oC1VIAsK4P-j#eX>sYfNi)NhZnzMgTJ@=a|Y9 zQ^5{Zj<=jOsW-(hZ`qc7h$eaFx%la~KUP2b@Xq-0Fn93D8!|MK$>?^5mecW`pGu9b zizL@?guscx!l=emoSrT)edID`d*c2 zAN?Pqv@vOjq9G==EYRYrm_(y0;>N(+Mz{Xfecwj)l7`jl90QudAj#y6({624>xpv$ zYe|kuc2syGa_ceC+m5w&jS&^3_<>Kn@PT(dRsP}0Xm=;2+*l@tr<^TrruG~9R3?wR zsd}H;yU60T(S<4ISFeIUc@3jsmFW@)lro1xWaF{TL!%nHt+rba1Ofs<1LZ*6L8Aw9 zoP_9r(EThxsQ|hiN;CM}B-iAuc$qiUb?jYPA!9uiJ}oDh{_r;g1k{U#O)=$KRnJ1< z1%-3q%E3E_#j5_TKl-EpsOi5!(h*_E-i6Usu0QC&yjBQ#XI^~Y$A9koG*e{Tktfmt^71*J4NCeNWiB7}m2kXF%iYU^ z3L1BFym^X(t(4V|YBA**KuaC7q_=~21`NETX+af-+0kKRjg3MQHJu>rH^{U3?k$udsUPbZA>o#DT26m+89-W5lt)h7> zG^zJk2#OR2*;Cm@Tzf2y4jTNn$BIKB`F@k+S-`xZ=CNGfnI5j+3c;kDVDcm11|q`I z^=rr%)-;HM_9StDA{2Qt%oBe0Lmzn8-~EO6eo>K~ZiV0e<-3ql^Wx z0=SZ_@?~gJj?s=lAxLtdR-idk)8sIS6{MDYbTX(Z!O4S#%`n2io=0KXB?ycNMlhrT z*uZ}1WH=){5*(62Wp)X*EKu!~SjiH@ofagqXBxqt@-y&wb&_CCuJC;o-Zd)p%z!YE4aR*?`m032YMSICv~V3l(h3|`#r7}EygHNs1op)$5v zeaEGlx7+eSXALX!4EB32D~!iuEEWrl$7AgN)&B|ru(*ERP73Xy4mKhmV>JG*(h~2P zwpYJ&<@s;>?*IF5eS94^b&%ntYuSyLtW)7Xnqe^&Yd1q1`5krRTB!pb!O^;`nN@?= z-ffHN$>k(Kj5|O>6ol|IU-;D3ukrNs*FE;N?{Z9gCXr@Zgw*Tv5K8j!YP+7*ST##L z^yHI3RpID=`3cm|-`ox;o1DsbJEAu#3f9gsqp|?MY%8E8aB%RcSkrRn|D3urhQ((L zi_RDpZ#}+t5g`Ozym%3lzxFM_X~5$6c%7ANG+7o+fJje{sU<_9hoAoJr@!;Ne)4a8 zJj=ZH1oVo{79aFBHuP07rmx7b1TC0~j*GgBvvLfeSl=zV@(9gcah2_Wy)!IPqK+K5 z!{;PP8bZ`%_`vhOb@gGApSU#H`_FbJ(??V@O_6doE=JSV=&)VWix*K{+{f`3pTp{( z{d^vdJd>%+&KOprZI30`GAtqn6GK$s*=I72_4c?w!@`-zubdfG`4_**Jk`NsyWEo* zKRT7N$cn;yym)%^lb?O&^MCL=e)ezt_HB|ny)!ojUdnsDZ0o+*vdFl%7q| zIrj;Pm^?gHuB2&E@=iIRX*J~iQN??ck|)EGCRIVBfsyT~G74t$PLMRnqF%|tY%W(0 zPvUcj^K^B#l$%XVtN7tR`?vqsy}jK(e_{G0VFT@eV*880kADn{k3Dah6~DJ6;eXH4ZF(O=UacN4#jq_wPdvId>yNn>(?7!ya@akPXVvl1+KNgVqsn9 z?)X!=#jza80xI&q@BfQG`Iqm7H0K_cezm+8-S00HG+}~cN2PNpokQsvMea;{G8)O! zxUy*IE8ZUrd4D*dovP$XRnU0AC<+3(&aeRHgeJ9etVN|Q000HkNkl}~|Co{Qn zG*4GfX6Z^D(kdo2>9_yNKm8LoK6CB=IDh^;_V)Izm-%o7y#I#1v0r!^3zQgRyq@OH z91wRltaOWC-elO4TMSFj_@`~d;#&@Y8f7`@jjJ=P@x_b4fBSBrTmWA<+CD%w3`@iw z&zX?)GgqGd!PmdO?OE0-VGjAGy%O2<|sXNQ73SIlrs#KiFIY2-?p z6a|gSg2zQc)>zgm(LAdvq6z z|MD#uU%ZIL_3Ie7?HRk?Hmrs%ia4F0{)g4P{tHjM?@#~QSNfg(ZW`777}hPsQU&c~ z4V}UfyayaR6kJll8ASzx%WTR6cBt5BB!}#2=sX5FwRGfYko`w1jhuv)9JEWh*)H`c zHrhl%8xp| zM&|<2Jk}q19m>fBc-_UVtnU`Xif0VV3+D6L-#Y(e-}^s(1&-jWA4vTU4U6vdW*HR` z223a&p>Ph4J$cUB@j2^rhJ=7eN9#?S!prM`QcaY$)ufFiw5dg#T8&B2CSa92!a)Jx zSMZk}-5L5HdHt&VuYuc=2qR%G*>=kI+X9RBs!zxU677O%i{cia?pd{=shJHQj6 z%(8MNJFs))$k~WQmYnMpEDW!(CROS{za5a@kc*vOiy%otN`AXH}zYda=llxrh&=OL*%^Z#F>1NP_`i*I?$I*ytIGpOr1 zX!mDgx0se{ED&MV1r|LMy=PuI}P9lfUxLaohfxN89P2TYId`rsvFHG@U)#{F#d} zUjGgpH0PClRtJv~CE6T2mDv!l{jo=J>Cz=&{OH2%R1edV}gz|B_~Cho~kaj0QxoxTkpG z)A*j!Vf5xnIsU;%+Ua*H(&g>gLc>m zl6kB9U%!qY+}$nqzYEaszj*2Lw*x>~o~e5so%yBR-8=rheedk@3`QrluyE`B*S&3lgJ_`R?FH{bVV{2pBN)p<^$H3qaZsIHa-%H*ha z6sl~9*)JE^Y6CVt1+jr{0u?!R#D`gabm4ZlOd?_%IF0N6eI#=~U$A0}rCsBL?z zF>X~0>N|8T@M372k1n)*e-ym$;eYc-zKGxB>#Jl~XP=ig*^tfHI-Wyxr1l+2k!&(3 zd{rvL&;0R!_ZE=8YZrLi&hEK)0s8pq@#%Q?jH$KbGj*s%dDrKyiv|KTfPN{q;ZrN< zFG(9d`pA2~{TK0{*!o>Etoy2B{I0YdHrMmt`mgr`(&HDZi*JGAqNrX3(Z#{VVhBYE z!UO<9+hmOcT9VST33W}%*A=)GDs%`x^ceU;hye>z<2ziU;czxA+xe ztPj>JZ27OkbLuPHxadAU=PUU&UvY-@a$bN3$KV5x^}rY&tgmj2^;D6mlf{H#v8zP@0000Sn(_}G)V(LTwZXaH<9WeMd>=e`^5wth;h<-!-Gc|l%&Jg% zgCNV}+{Zy?yYSK#jONmEQ!|fqc9UvywwPu%#(A3EeX)4l1?(shAZ;%d&_OR{xtJtc z+0W&o6T3m7r{u=Lc78r;pcCm#hjIW^L9h;d>ezUnC3`)3T+&FtX7u_dvT&y=eRT1?Mb*KZP)xDW0Bw7rSJSyNiGOJ5xBi}( zD2rYEk*>FrH3v_}tZqh+Ia)7{`EFv*BI9ZK8dr??8asvNCr{UU=iV3`jjsrqFG<^! zxv$K9u)2GG_ThT_a&tMs@#Wi%=^tr|+dp{E8CINjnk zr$j`2Zz$@-ntVdDjSm+cr;q1ic0RSax4&>$O||lnJqQpg*;%5*&*s-|xTM9BnJuA+ ztC)}Y1``*e;~1cRs451;1*lTRTE^CxrEZReFNWexwJ2*x-3l?4GMh_8o}_U@Ux#|v z^6Er@P~+`yf!*fxc%wYxR7#3H7g?4|t;^H|;)MB4m^Ak$w4kbvmU#*=cu-h3$IO>> zZRqiSIVu2>_92#7!hFsRWH3Q#*wl>qD@3#AbNH3}rm4PVsR|3hDVOg5?)w7Tj5oFC zBok#l?X3S)kJz{bLR{MGl6dam)n4~Hf;qIIKv*pwOhHx5C3=zGcpBft6MSg2#M9QN zJHs)7yVb~4eb%87U_}rLB&-rP!x2_gZK8ZY+pqhQ?XtX_ zZ^zg+%Z7~*( z_QGLVE!y$3W6E_eMTd-Eb{bb4mgb5I8KOF{_|#l{$tc7_Z$iQxVaDlydE-;THnIRB zcobAWzxkpNP4jm!n$^nzS}b5}A9GGE{hasV)*n$JQ3YDG$`+jGy3cH$#S$`Mw!pv2 z;yy*jbP8*4Ay~5eRI0SxuL-p!g=7;Co6ZBq^KarYCj2!{tU_ghsTZ>vkoR+jCeeMS z2ab&kBRu`4ru=CedabiFEE@r%Mb*_VX9a&ZJim;W7^2)wl})u!+g=sSI@^ED_)#^R zNmn=3#O_9HL937%SdQfI3leIbx~kp&XlYL(bhNaUbNUr5^@ZIZY<9oVBv|te57;bm zA+AsPlwvNXq{VQVtx?FNTtrT0HZo!KpjFl%`if82RB^mg(Y7kiXqKritF$WV^b z_yzKv9mj=NW$+hU@KM!FXl_@j=BO7owCEkNZQJs2lOLjO71ys&q{84E z7uOF$j0Xa%VtPyeoWE_4f(LY!LM463s5$zr-YSQ=Q#$EY$9&+Qc}sZx!23;S#~&4v`eYR$5uru#Qb*;xK$U_mxi;_R=m=`W=W>+9R7>B00c>o}Z%8%v^{J>Rr2vhS zChuC;Kj9t4yZ-MJ$DSeDzgorvle@!Sfuz~)+Uh~9y{~JKU9^$~^jTj?{h^LT&1KRF zEew4ma1{efp581%Re6l2Gmyb8vAgFr9z$hvS$Jb59petRLsHL$4_r|Y(-6}U7NY}Y zC|m#JGwnvLU_!DPr3!6TS2Iy}ey6tYpx&>#^}WXs22{Xw_q-bH)f~_GQ~TDt>9qRH zQN;b=Q9MOZ4tvB7JCUc2}aj9D~AQ68=GTBpRayBeUtFp zXjo)W|MBw|27CzVYFTqU=xTuvXY&4+A|d}4XjpVC+B{-N0n(Vb$IA*KP(6(l!sE|) z!0~OVC(Ve{uqCy-wojjruO_o(eK(NS>G;jC?;Du8VqdPvc<$=-EQrP z*5&c?0Peh^iU(LC;JU@wrr}?UaeiIPRsBxc)t{xdCjp^`+be3;88AfKbu8Kl*#X$v zW% z;zoq_gO`ms^>6U)URyDsvs6aL72O!Z2>PNm1cHbU9Q^Afd-4WH>ge5;C-CcWOtl%3 zr}PK=04yc%hrQnZGYGW#(LSz^J!{0#ieEHXU8t*XCM(tDtokSnCPIi0vs_=2ga*U1 z@1-F?n1IFMa%gF}j%%9*p{IUZ~9?&~A9UU%3y` zP_dTuwUA7=Cw8WWnzDZqGO1^x4Um7b5y0XR_^d0MCS9KsL8s^N1fA{+EB1ZLgnb}- z{s0Ys_f|kV1X@HX4K1cMhnA2YK}(ZgNiDRj{%5I#i{YWu7t~P|9M|U-1d6tv?#Je5 zv$sc{Ml=chmsT_+H^T%Q(xObHCFsEG7>&!PF*jq#pb68y-~fY=Ysdw4#SmMG#|Em>>eq=_Z1o?!EiskZ+bLD#rmb8QmP-yM7W&C0!)gSKPg_-k0Q0QQYs;tBhtMu z%7n6=mLh9&LWOecKU}w3g%J@re=0HEU}l+s-A^qGryqG_0D~vwACXIR z2y<{>6Cy%aY;i`XJg5y@c;n8_o%d_1R;=@?KXg{T^_{4mVdLwa^q6fo!c1=iMb(Dq&=Tp4pg#R%Plh5BWn7Xh$<^z&|i8ljLOBhi! z(_*J{BlL90FAaY=yjupe9Nr*9=PLzLcyMce@<NHk2}gF;K_ZwJq1KL40J z%)4fHU$frZZpa(mIAKT}PN>KI)>1_%p~SzS)aD$bS58>mJjYZ^gYYXT6XE0Li;rS! z)VY<)Je(%Zm_R8n8tlm9*%8N67dYiiEC_rv;N=oc)I3x070y*kanL2LM-Ek*=RJ77 zF*-uw8BiP)P!!9NOs<@q49}@jKJ!VIyN9>MErOJagjprWj*jg~CW2xt#2#$g-YmV3 zEH6We*=jgU^STbF}hIbAf%3JC}T;%AgT>dQU*xz?>{I{>o z#&6vjb>TL>*i~2|tuw=~0~MBY`b!x6I?6pl`t5FHGew3um%bSfYfF_mK#FRi5%(w5 z8XpkI48UUUYok5_BdE|oC&|4xH*<{S<~((M4=uzOQ`2b0|4+E%9_C*fXji0VKX}^!l5>heX-1|y6|82DH;&2<%Rbe;B zqn%NLefvf#Ev1!-wPq;Mam9?|a+$*0sU%|tLfUSs0O(0pr9{bv`tNAs1VCzHQ?=&T zs<0CP*T;kOP&;FWu2JHaR`W13b!3ymY4MJ*!(`mim^e*F_XNwVa#jjGW}JSu@i_o7aZR8)?k_pwmFym6tLKFS7NpG}r( zH>Bqr)gerGxJ}o5Xr@&x9V*0{&Qwc?z>LwW5NB}Y-G{^=Dijqy;NIgDJ9 zY+wahOZ78#Yt(9W|zg#cY!}H)OoZnA;YrHI7Ce8J@Uw!uO{8GH7xr~`&j!;MTr00U^KNuYDI8t-=`Au0Uy`0P)&?hp(o|n z5sO@*%oV=8%79achFF2BT%=QprFTcG$t|i8;@qiAVo!X^9k=26LiCHjOMy9FOv(jH zCKEw(JFL>zm73CeET}tF_mJhG?k>kcF)=*;@3+7slJ9xp8g@Oi2?o=y<>qUxGjg!> zHe6@DUeI{VWaUue3ma1+fJGJNH^r&HSZs5>uCzPf#twFvf>kV8D|<*z6XvF1s~^3v z!075h>8k#?Q?6v{iu3R7n{DU_JN1xe`c6dA_nrN}!=8`IS_i9w&xjCTf@ADOnibsI zRX-?i7B;?roV$ts); zrzhAdI6TNKyKiQi_va2pCN!@CJ-CMKQ)U%wTGO*`2`3^jxSsi@-gCRV>X^6jVcD?J z@1pAoW;bf9XDAO`w_`YR_4D;d@2Lr2NcQ8T75-$C+zs^;49^jU_Q=jK9E6BbBTzRe zHcY39(66Es94<{S<0}%PRuukJ=7sxKXsS7NZ>e}1DLGyIq4X?S`7dVXo$`-MbIg>z z$H&9vv;?T$_N5g7nf2pbp1NK7N&B9;Dl^P0>PnXBu$zu9*olx2`Me1PydO< zkBYTv^bOAwvL^BWSPal-D3wmVQr_s*XcieJ>kS(x0y|ZczE!WfGVatI>xhrv@Nh~R z#$^>_sw=o4!ii!lmrgAOq&_0}@VX0L{`S`FYF*52nO(Q_8c_x%;e zEsApsMYwr;O9fUbL$S<43BW2&4pB=~J4?ZKAk?66GDZ}hS|?VS-L)pYB71jyTYTJ9 zP`LtS2P1L75>p*sBO0u*CPB*Q1o#7q)G1UoI3or}9uoDepsAA#hnI@WG;+4zL) zl*+2-p0W|$inn))psk?87xzeRodGD+r%w>Cm4eJ+#~S3_mq>apc05S+nf8B4mU*|8 z4I|r}A?`7A$nG@UEFOL9aIV@_G7$GFu?MOF?#y->8ylo$XzBMps`OCUn{7t84&v>@LSp#N)dZy@SR9GwxmbOXW`;BM;t>s5Sj+FW*5 z(DPR{oQj#zb`tG!yw4Xy4JZ5d2o~mS$IDXdEaJc>@j~c{aF{#A*C&Nu!QnlkG?~Lh zL_$Fk-UVwu;X~9q&tHFEZ~I(1|JoF4)nj5PsAvEUWA^k#1Bpw83$$JHNkVV7v*u+D z6;~;?*n|nPG}T+YGY|HNsi}wsro)a^oORleO_!w16{WV`R6^K?9SgNQrXg5bY>?yn`rG_@l0Q zS;HLHtb~64h(4inlk;g~j*y_GE=sP5i(5zQJya=rWEL40H?r;k(T;}i$gib^oVu*A zU=6aA%`hFV*}kePW5Gi+FP{PPBy5I+S;c1fSiIT_6swtkNs{o3ZGh>w)M-WU`=RfRKX+cGP8l1 zH~-9nU;hhU8s=+%v8;XCRVzG5X8f+(7C0TcGtX3eZ=wHahVVGYv$0WY49qoUm<;kv zA%E+VRv=gD^W}51b%QV8?=iJQc)^}Kp?7iLyC>MOu+Mz(jTIkbY3PTqrNOfue13Uo ztl04zb;Ls;F0Is`W+_pw;m-F7||Vf+`6O zVl$CVlaWoI3*;h279Cx#YCJ#k@iD}=-PsL1HdJRX6Rt3KGa(n@OBMPYD^;pnQYNf_ z_yLckw54f|`l|WYx^hc^@=Ne+6Pz$~p9k(^?C6|(!BR~QlWi<{pAoj$94L=%I67E%097wG$}BhhiR9BNK3T4P8@20+bpb>M))CPC!b@ckAvm%gM_Da| z2NB>>%1ojFE<^ZX(j2BaFTAL{jch>ha1sEyyNhIV|Lr$fDdFYC;2#c%*%w>iKP9GH z#7kpCl^RTlVb+qPE;H?!v!3R^6CXGljwaYw%i0)+w^*CR*3;yJ6Yv0~u3uQ~+x3 zsVDqU?zWTsC>n75iM=Akw!P#Z@^ra;tey_hU&lFoN)>$sCAvuw+K4#5)?*rs|RxELETQiSJ%?rF%2@ zHRm9Uk0XM*mtHG`5VM`QgZx;&A{Fjsc8bZ?ngG~k0=|G>no_0i7Tt`K*Tq@;2W%Sc5 z)786xx+eSf`rjg030)DQyfIvAP5y#Ww>b8ClcPAI1V4wo1{&qZI|awH(N+E%>JGB4 z^2?RU!%%A>dQ&~bX<Ef>K0k%VuNb2m|IHO1+5)7vufDkJSuRG+xzo% zc^xA(4&s-D3ws7r0}u8_Zdi0ISo`z<(0$MYAH3f+Hn^d|yh*2R4%8JK09vGAq4%Y= z?Ci7_pIiFF7Esh=aWS3#=+atLRvRt^=ioID;xdk6OO)DT7s{=h-b-I{c<$jY$5g>g zQa6;XQ7zaP$;N&C1Zs>dOv-8O6h{$|ey*xkglgVriS6#jUv%jYXy&=vIHtQ&nMI^hbd%-aPwJ2T&{lDVGkaqjMyO zZ_={D3SPGMN{!y_T{bX)DY2T2KMY@56O(Pax*E`se_3z11L-HGB#AVfE)cG=$5p}Y z7wddJ>s>t0TuXw82f0D>d*f2fQGGtFX%iqq;RfEB^{Amq9+7Wt6Ei?MQVzw?jQr1P zq|7IVfY2q8A_rkctdw|>{^R;Y*cS6w?O9E>6YHxrenk9IUzZKfAub*hTVjhP;1nhP zA7+M*w5N9eIyS&SR1%t9|@g$4&|#hB9D_#od$3;>}QPd|=}baeb_( zHC6(55zx~?wlU%ZP%yscQ{}fnP6vV`1#3z`JMn_QqP6Pq zlJ-Z%3yYF-*;3A?1YhtSDF06O-H>+1z9f1+p+jt|5mJK#Z&>8^RA+IH`4LD;zf?>! zO^$9UQ@f>AF96}c8+bMIa6UX|NO413lDFDFxc@V^N{*|KQd0`@{y%jxBEATHdL66b zF$8`pThh|BCD+u_1o3s1boLeBdH@lh>2Mp1@arp5zz3t+G>5?pwRi}q6&;!~nF-P8 z4K}7{xqDd$4&qY|$h7h3J*F{gqthheI)opOR z{&Y}z^P6)dD7p534vLQxFyW)5=tCY!bAB#P7P6c|bqBOfKarf)QjXyV2C&p-Yc*th z7n<=mUkWOm53#j?C|iCCA^hrEzu6wZ&#F%3PC0V@EStf52kmq*(EA(E77!pP)({)4 zLW?ymljobwcYxHONEcx7Wo(*L2#-pNwSi`eJ#E4t@v=^^hN=~*aQu7p3RnU8&N#P~ z!9Dcsy=M5W%@?3#9txIV-4+`T;!w=^`T!qv&B2ACQNS{rVtOYl2(LOJb=~!_ugfPF zm{yazF0{pG!Pe8y!&ZAGdMaSa_PM`;qy-mIK?3uec&piQmi|a#m$db4lZ5Jhw*+ti zBDg~VkRo1i4iRl=tTW?{ml2wtRRmrVBV?dfAIzg3wg9$i!% zs^I6KUL?~JX~H(_)Htw`iG$tkRq-^lYE{lZGFQj&+#nWnKGQCV#_^m$4~2F1|E6Mb z3M!2ean|w%m;=GNN8#ae$`@E7QRZ#1Nj^`RK8t54zMIOHAuNrH4Lu>8S1laSsZphx zSoYFes8J{iX~y%W4=1gf{lIW|7Lpn*QaIck#8(FHfu?)@paE7ZGl40qBSeV_P#fmZ z=@DtLX?c&=EBM>S!Krrz_Y_}!w5>jh~oBe*6yoK-)G1o7s{g>DJGqj$L z>a-)PFlz~bB9SI%WLt9}%F&F&xjww%yB3klN8CoeaMM!xap^Nx=NVVlmV&H?i;s8) zt7`dg9|^B1D@VrrhhV^`LLHhqp$S`Lebnr`4&Jrv#Ir~qW=yEaj<%JEt+V9 z*p#8{TMflSr1yUpbwcL+v1@!IC*G9p5b=GiuZtRyP256)pe4@0i1=U+3ZniBLBa=c zP}gFK;;j#`>%>fbiCNK!A#y&`%%|=P0;}=C#Az%)HE(Pfk8nEUhFA_lXoXt&u=B37 z@<}LV>q0dRWrmFn<|puHLuSz(sZd5h_^2)GFK%#|e-9fE5qgyk#73@+kT~h3@)k&- z{FZbfgjda`Dum$OosJg~bPJx{Rb`!MPan#J0ggf;dR9wjnLH*V?7Sd zQ6ZPL=|&;VaRR*)5%(y)9o~j{zBraeFuFnBJXU<9FG+L5Tw#k(Q>>4Ro1a&(oS+J7 zO%A9aF%Iv(CKa0YQi%HDvWZ9SBEc3OU$TX7?jgzch|Wr3Ly3jvz4~a+b(gsRN{2sV z`CWpt6-Msy)b3GRT!*~3zhy27RT}3?0w?M&9<=BmilNxnoau9rgjf7hMNrL>y#uO#lS_DyPi+$dSafo01pQaS6JcqYOA zsxw8hyFsos;LnOXM4`+0E{xc)n(Cq%^KiN865ZboJ5#B8YlRt%>em{A(?zic&+8;i za$=j2uZ9h$i@C<)qM>6Od!g%g!*->YV~eI*2boEU_MI{xGT zG`r1XRf}A_CW~+KyXdi4j7$Xvb2%r4Qr4=sO7ighv!o9!rLt%CdIpx6)P zU9AE8`udKy*NGke#T|2?kC&Q!9}msd&J>npH8lyQon0E7SI%bKm7fVPAP)OGy;uO~ zW{`7i^Njz`{KL4k|BBs;);Itj6645j7vTK)D2(q+)V%62o%uf3Q8Aa@=pE!vK|*ak zz14Hd4tI{t;VQ$%MqLYS6H(KS-;}&BnG&ye6*la4^QlqSd8;qIo1fAKdhML?&i1XB z8nZs^rU+OU@;iI)!t7XUHqJ}V?n6Hm?TTlvBk(SfN z@7eq75j3#BXC#O>2{koeQ@)W3L&4KZ8|bWB#o`UB)mP0!vy#($ZSg{luVq*iJAfG% z)id6fA6GR6;F`s-4{zcnHB&{nO;2ve0$1U#eKK#WT3{c3!d>lsEa`3z?QLI-k8I@X zN>DHeww#OHT(5YFmW&HD%Dh@Hl|aeS(A2)nO?g(^%W1sMtq^TZTwr7k!aXF0rC3(W za_#c8m1|gtd#0t`$@2gPiJgQY#E980JiXEiQUpD>KttQoK6I&?=AXWpnr%df8Gf8N z4toR;7u6vL2KSVdi6AziE>@87(brk&tjdv~2He+slAV5qFZ7B7We%?iPxa3LG~Tn_ zu6W3}HLjY$BEiFFH~sfR@P^s*wI=wLVi>S2^r3Q;v&#w@moRJ#hvM0Z^ZBz~>ZyU8 z-4E(~(5&E9Nz7EoSiBO`g(pL!=UtlFeI%|KG@t<}V$W&+C<2bjOA-Us+yo8%@!=(j zDy+RALL*WX30RQ_;2gyNEjPt?+rm-PV#>_I;qJtg_*snH|7hAC**!cly799Gl6NV8 z+LX!YE{LakUaK8`<^b5#MBuSOLDS%uG~kyGA$3=z2}l9NgvcpVS>_@oB6#ynVZsg@ z7p?dHasmyk0Vk0{L(bSXhQxp7bZMIgO^IBCAQr~K$nTtp#@X&U)L4i&nAIQGa?Vfn zSomPc<+My>;PJmO@}XA|8O?-<+1^$f_%m3nl69EIL=ikQotN~iiA9vVC2}HUcWE(b>LD1tS`)=kB7uVsu>341F;}LKKLVrj>*Na`PH}#nS0;!P#u!Oo7F=wYH#U81rtn3o0AP%A7yg8SCIJY*A1I@ zncUXV_IL5C-tH`mD{U6mGywg~jl0d8AE=%w`sTj951L&u9YsTCkUOK&NMA+tF2ujh zN>yRq!FzlqsykPB<4E9yY}D7Ra7zilfihPFxX3-^l?ud*GxYv!1HAXUR}y-V!SFc{ z#?rDH4^KL6?TSr*DgM|`^DLRAvt--l8#T53y3@DkEco=$l?Y{qAQAuaZZTjJq&9QZ z^l{&kQ1{)tt883W<3azIl+bHlh~i8^AQck&^$cggCB)!G*t(?TH0bs;jtF_iKG{Hw zxMzOxL`3m!NIHzzsW{AM2Zo_pnOEi>+6QqQ*RV|e)3K1#Y!cNrV0=fJf3}@V{Cp=7 z=H3IuQU3GEB6WBnYf<9)@XPZHKEd>#XQ@VPS6Ex)kr!v{JUsn3LT5})fAytf#i-3g z*uGnzZ-dl^6sjmr4X|4R5)PFUNy3v)OAxar339BaHe{%@Y>DWxdZbji$QDUzx@uK= z>3d425Pp()ndq!8SC{s>i*HS1FA-mI9s8%@T9vt&Nv)`>OP&oNWebr8f{z)2#scD* z5i#!*je1Yc%3!HZArimGfdkBfmR1BxOdHGGLWt}1+NbE?#OB9vzk<{Deo}Qxns!oM z%!F}Ps}hG2AN&csJdt+0v^0c+^x1oKtu8swz@7!ekV7~>ggSE!=P|IunZ zENBInX8mP7`l`5zcBw2Y?VG_m2&;@1kLoy`h!xUm^Xmp`gfZ97ku8W&@zvZHMGAgj zDS(O2m3|?$O&@>TR{8N>$(jzZN$l7`@mhx+^+J4VS9K_L_#*Bp-t!IA65DEq+v(tu z+-yL^l=FaKEsJLRI1_LlfCbdBsXl-s$WcRz>w2Ltm83MMcfzQqIW9c;{ZCTaHbU*6 z@v^z|N1GAQ1v3vMax9HF^l{N3ei%55@E%F2PbjH2q(X>MhEy+YDs@vnpl$k|=<>W= zwcoN(SjE}OeRV4cWbg?6J{$0=eL27{{Ik2wzJ$Ph0)g#ee)vHPYg5z1x^PnSbzDVj zUzjzfqwLy@fbbPaWLG)<1^HfxsJN*$A>b7WRcv=l_y+4WJMsnPlz3)7HozM$hTVJd zZMwU%Xs7CbhyAMJA{p=-)6?6bGg@>B77WV;nTN^IlT(o{&&q}BnnwOf+%??ckK7jF zp91iG?c`2pFmr*WT=U@C-1iWevQB_CKZ>(1wv1DOs|3q?B@)6$qeityb^dU*_6|MM z@mAnBq;m|BV0Yw67@;_C19@E6I#e0`0 za-B#yIi$F1u<}mhn`MlGiwE(R3B2ky$6U%$IB{_lYNyJHlL@7w_*Yv;M*L2o17lkd!=Psm2Keq2s9uzwDQ7_DHA=$(cXN zZrWj`x%j{x=MBqHXUyzq4vRgqRG(kyR>h|cV|0x*CDm{jZ<>GEPKdZpP{hbd0q8-q zpd7gzwfi!aYq6Fr7NESvTuXrvrTmB_E2RR+Z&QOE^;}_?n>oU|&!75@Q@;bgY434jPwb|5+Q!Pr;D-z>w70} z(?>~LSoDW_X_zZ~p?|EPaE?B{wP)SfU!(1*){9W z-9&*MFfA(86ak%e-M&jBM5z11qW3#xc7wjROFf?!tR>nM-d7%3x%t3>x{P$Bfj{t=unCE3?{mOL^0LztF;f3R zkR8MmEX8t#dN`)Y*&ntp49>sRxIO}~%0mX+HI9MtegYb(LO;#6luE636YI64*@n?E zb49}W5o?WB;Pgd!r=PLl*^lCZGu+i30^Apue~I5QY0NQI)94Phzag-x@%?l7vMn!C z81^&W+0@}tTg|&WdN%y#_r1qOhiwBVDV7c+f&&D5?4b9z3&B^feoZ8qK3e&0B>vF# zC4pcxmdc}_)rU;`O?(T13o1ua&q~IbB!)I$*PKmrwjqH3kaaOJ5JO2E1VkWxSv;`F zyK3Pm>39jFyCPy7W;zgE^fQPzSrjqjuu|09Z3T@Y1KCb}Q>&r0Vn&C1Fk7bgclild z2)ov$Ob2B6-n$)IH( zpvoHl2w?+XA$STKB`}%3`r=m>{HDY}rrE+}*Imi>2>C2(~&y)|ikCP8F(nHeajTFx!9+VLTR z1WUL#K!_sqOT97#yvzcp1toVwfIgicKv>FE-pSy^506tzD(>9btr%|p(8EOj8Ilg( zbv!xUWfAC7mxjx1$SiYwRveU2w*FiV8Y{uw5q`lmnW-{}l3TKYBrH10@flQt8oIqA zx_^`t43uMg0sii<5$Aut7?i=^L>ow#OsU}iUB#Yc-y_qDul;NAfN=(D%a^S4{`SIg zHGGsei}>D^Rb;!1+;zU45UyMi%6gY11$-pbu?tpQ8Y~YHc<=^@E9$Ns*3I;k6{h<% zjVZB}+t|lEtl^*s0-P2B#=_o5%1n;GDbeT=F@N-ynZum&)-L8FMjR#Lt;`7JBH47{F%wU;paGT?qg2TgoeDqy;POWq`}F& zdmb;J0P%y&WhR9h5mP^jHZ4U{=pF0yB%YtlKM8~-$XYQqzAsU~dHS11L^hixUfWS^ zMOX@R{asVo9#efWzM@!}V$zb@0{dpTLaU(h+r|6g1Q`~A1q*2I@1E@tAL z&>qnbgTL!$DibUPJZ*+OFzHc5zJy<^H2Q5XBnFi}LVzAU-B=_ zOOuRFi9t~soD1_S?ehXcCd&X{rW|dV0et2jKVB0w>wDXnGOoD82uAg3@>oM(G`=j) z(@MfR&Qk+~PeSjkG~B1m0@Wh7dpGE)O{zY;d-B8Bgm)s9O{ngZfjN&N*1*;{|CLQ@ zPuviHFjAbDD*x_}YQc+NNqU{ISOCHj_?l!-DZlwBB1nB-Og#bBe8su{>1nAf=p3T+ z?^oT^TjI$%vRw{r$^*b7cokUi-*m}8;+r9S2G*7Gjz`d{YC2jldjHYMkATy61PFd$ z8}Xh(K2KNn^}M3uG|!WRH6VJA6-@tUu*{nypK+qwL{Q%eNRbM2X-u@`gF8ADY8#O+ z+$`HTzfA%~?40bvR!F(@{%$#x1#!!(eX!)a$ul{N~-wN-ncIOvtp5wnjgPF z3Thi>X33j8s_vk-=Y|l5To4=>SQ@hm$ESZ+)JB`2tU+^Ys_VDY9yi2)ahofPvmaTuWH_xc49e5Ht%6YrG_7JLEY=jJ{7e0@2+)KR?{5cKE zgl@5N`GFD1MYGv@2MMQ-?=ru{IPYc-E4=lPK2I<2#K2BSrmYZS%%<(8tNG49nxKVh zK2vc}d0|qNKSjN#?3*o4rjsFW3Fb}sU!jByZ(uy5m)Aj z__?bWHd4X)Zk2x@E}|mIIG)&~qKDZ>^XdItU@wF7>T)y2qCX8T#C?~SsIG9XAX>tu|swa0X$h)5%`my2) zILWzp7!S>_KpH65Z*W7Z$Qx-%_LTE!5gx!c)ejynd9?7KU&egufi&rd7oY$ZN#5S3 z<}d3iABXd|}c3CFkA_nNq_=w6lmQa9z+W{bjE zq+}HF;^R*o?pNvS1fgSN`bv1AJH6mjKF<3R<1lAg&w>i(zaGu=$TisVnC?#&_Q>n7 z+Rr0z>6|E>Y}xVK^GPM&k;ceT0xUp&%#+5dsns3qT3(Mh>fpGF_#Y!;`Co1yCNuH! zj~UC0T>E5xzN2<%k{e`Zm|>>LP~<=idevIdJ-)wC-bb<=2{P$@=+R{V-#Fe|OrB4- zAYS4CUk{3fQ=PVk7Y&M83>s-|kCQPQKd87ugHp+4IyCSZEIFwIU;O6M|5nwEPTHBO zg_27MiW@~~!ee}O^E7xNG?WmZA0(#&oDq=IuL4m?*;`75kS~qc=^h5f;+*U!Q!e+( zf1Jd0A|k*K!^W{cteWMMRGp(zszf-WrB{^Pvxt)80OTTlA(NSF&`uXjfGF}zhn~Lj zZWv32~iuZG~P0* z;y0l*EQVjth<1*?2}}z@vxqu>99A=ux$aZ5d)b(8F@AGN z{1@&_zW$hB5ixTA9*vK^bqp3m+@y1TtT>la;=&Uwf2+#3A&~IeNiIdV4c6b7u4irg zRi1Z)?mK4E?Z8@WBQTfTH9!`iJ?u4)%KUJ+JG|l*oYb(adC(C(3->HESZ>x*+o?>u zZBHNm@pxBtzBz9~RJ8MSzHW19xmMcZLf;S#c0c=#3Vi|IW%gzOTMd(b<-yqqEz$|8 zAyfaQ6jWdkCd-??ewGTVz=iyHtSKjs?1m{b@@2}~TS8-E^zS=l`l6LOED%4M-%5Yw zIBhqg-utXpC-XTVs^D?D5(zw4=-LU(r&||gt}kbdQ6m@?20G+Xs<1Z-CKt0O{}idP zsx&F-OM)vz3BO-qt=*p(*9-jiy6oDcGG(Q6B$1LL{`lmzSnW_>`xF2zIg`4dsZ zAU%@p@HG!yce!q<`;6(m6&r(uz$=qM2d`p%f*F!5t-!1|rf!)feOcZLywrns5}lsP z>!+Ce!ogp9RlUEt5?o!r@nma_(rVTt>5OlJtp-E99W~ukxWaUF-o?>~s!X2e6 zgfMGvp2{EaXC;gLc{GeI6O(To0AG?E2xdp$k|DVH^$I_CP;pIVs_7@cHa#jUv6H^Q zEKF-7MgL|PPhZN%995MZWg9=(0H+Q=}a8#?1`~hhvME{Q6{Lv|N=T#jilf&{Tkd20L zt;;0meUa+bp<3_I2n+OW8{ulb!T=+RboUEw|7j{eN`pBd9=ULBB1E@)J`F7;pf*Vi;cG6 znuV@pmb>;RvD>lx8?7>AD4Sx?mk)%;N85O1YY|FcGM2fk z0xOdMdH*kX7l-I{ksP?=C4;oDKlY-j=dHKu#i@T3DKJu^N{f_edt8fsq(n~svq!}B zOfi&+`)P*zr>c-tE50X)!pEA#_jtW{pQsVfla=Cq3VBZ=?}p=}0^dx#tu<-zMZGAF@6P zJ$?v*4v3x7W7O2|Q(GV1hrm5D`5?dZ!CY}Xm?Ps4W+ODi zKu@UR;Xy}olfXHMdN6?qizl+;coHD+K?FX?<=oDBFA;h_;vNWH?wG?dLLCnv_JL#s z5{(aRk79+Mfh?;}I2N1}d<-D5+y_e(rh)_MgKM6L7 z^S+I+iQAJ}5oy1VRC_NGc`uLkUQ+8l$h?QhGzHqf79uQAqfjNZ!2<1fuu#-qj6$=I8nxkE*p_Iet#nWHV}c< z2jj(x$gu}uPOOYQ5F=yvuR|p0sxWuikROTTJ|gkHWaOCw??K>Q2)qM<-$dXyNTpxP z6zf;AsDart0xy1A|FfrlDbi^f-ppu})NU}6)FH#HSCiUgD2X{6&TnXvGaDP^)TTN^ zpmJz&DiQdUB!2d5S4cs`Uv^T$1Fdlzl^EGpgUXA<^<6?s;KS?{AGRcXq-Cifse0{dOm#Jh;VJNb9+ zMBuj(_zeVpjr;Kx(&?9XiuDVrV)=ZU4F5~|jJ)H2t>38@5;&09D#P*3Arjl9=zLwPhS2&Ch5Jd}&HP|X`RYF{Q%r`_Q8sOTHf$h(I+Mat7C zvwSZ`hQCK6^ANH~nWGQH$}sCN;)ds}li>##%#k;Wyiw$h-n&MuNVDE!ayJ6+B$6W- z{}w6qTgfv1O}f)>BJisS{4xT+fWXhEi1pvLiRE+KW%#o@WauAK40&%R@M=Pf3?($n zU_z5zNobG@iS=@JeXX2Ms+JQQDrX6-7&le?*SD(qDL;se!Z#9Vh%+TdioEoNG=s5k z?K1>A?<$SLeJ?feK5F27)WG`@NX>Il^Xw1oqV~|PQ~PXlw0);>pqYq_zF`^;+ufUq zq$G~xW%%KBGW5N5a+P)X!F34c*kG*;J+KB=iv@WWCzVK;VCHAN~!2pF`khQ^fKa?#HK@IX}5Yu6%s!TM8VCYm&jZM!6E#AeZCnk{kk9vR!spr6wv&fVQI z!Lcj1S6mFJit*9;@^d%7TTP2P>1F74#t#PeFphhe-y)c}kM8qc8kl=_%f#Kg#Bmo9 z_}wfSyNC32?@rbf8T;-I8M~86yn|;y0xfrMfJC4M-nCIi@8bBoG&J8`FC+KH$?!e# za`o;68TxLbj3RCHyK7|hP9pFQBJnOF?@sFB9kHZGy3}vL*W-~!4g611=ohJh|4yp@ zx6Lx~Iim5OHp>{&M*m^6jC^Xd4E%kvT>50PT>QIax$p_r55*cB|0DfkJUVZE{Hu6^ zn^@K%GX{~dDzQ#3t!t2Tu|!~el^jnjm%go~2DOQ~KfXWBTCrgJ<1+%Y+hjDmL#)|d zGM3#Vc2>u(ZgKAFk%^oe0>kJ72%{oZno10doGsAxUAoS@c8lvyhUD*LiR+Fmao(9u z9U=nn-cB8&4&K4~En53;XiXwQzP$mcSt{ULNiz2B^&{F#D7QPztFY*bCTFULqz>Ul2|`Q zw0|;5hCh)cLmx|$fxq1-m;Pp>T>R)px$xJlZzXU|iwv)6lA*N?a%EkuTwGfxXJd%K zxC%Lz5R#|tTd?72^Ys6Cw*JJ@K3jIDSTb5RK853evtr)O~@= zzew8rLX3?6d#u<$kGOy3_Mb!IKePW?nxTK>XFi3@Pclb-oF~D@h~~eEm%+b|m&<<@ zF9UzIUM~IRdb#-F^>X3=vA&hS*GQ$S8f9ozyZ=m@~T(u zK4G5rAK#Y$?50l}0#lo0G_^&nsckZrN*zo`Vn(;vGkV04`PKrJutZ~j`H7G`Q>6Qw zyTtvCEOFnSA?~lIiU0PU;{E1!aer$I(YT4rw~6~}TgCmKTg3h4WO0+?++W-PiNM_V zW#+!GAo433Q865^69=;FU*z};8d(VYJd*wuNuT5RbL)sOuK#STI6lMiKXCo0x&H6D z{*y%RCrGm&BU(R-^p8+a|7x9F`S3a!_|Q7J_!q2y5igfM5HA?DdTBG zVJcCWN))E_%EV4Y!elD@seK`ksd!RO$k+zP4_3(?5UFq*3@<5`s_$^}zl_KTeBam% zn_wesAo>!BzBrj6?M-}j4ae)u{aBg!a-2+lb+t@>8NL9YSGeroVrBAQVq_9oj(>_n z6ta-y_8UFAJ8U7Ib1-yTST>ijn8F>F% zx%6i-a`8{&3~?7#+@Hex7-9Y_S&qMJnXwKnYcRh2$hD+)2FKzCvA$X>S65WYz-#4l za#fK*>zZ6Sx1&PJR%C59Pxnt|8%b_H7b($}(jnt1onqfXE!;sZ+)gdrK|=$RDY_Dg zDJDBZ0wZxG_k={Yiy?7{dJ`$o`_&{^4~dW!drz!f`a@Fad*MCs2k`sR z0)xr@MifR0v@fcY(WTWgw7fzttt_1psPbCYrj+hJQ@i0vU<+m1$|0u6~7XAFrdEmER~l;|O{JYS9lqKFzciLl8p zzb2DkTrQJeS|*eK!TR|XMA=H2_}5ou;-BF&@M-wea+&!1Wis)1?0;gZjDKvojQ`Ct z8UM(uGX9rKW$gcPvOly;Mn1SquKvX`8UDaZx%%fTkhWX~-?z*VcICbBhw%GrWbpUa z%9Y=Zk;}gmCj-BoAXk1TUatH${2zFCydh7~=$kE2_s17ji)BfL3@$5`iz`C%!UEGD zT=6&NY5vJ>1ikeS#BcB{U2*!HFa;5xWBYg++SGE@ltVrezCa!b&0tDnf=ecD$dU= z7U!qolkjo)82s%baej26IRAQq*#2s<*gm{SY#&@Gwht^2%bzWl;XhqWge{gUf5Q65 z%VhA6UX?5FSt^(Ra0yXGwEZsp4*V81@ZIZV@Hb=S%CFPJyemj%Qeur1zr1FF>xg!(!{c+RitoOt}M-yaT)|4?YTAp8nIFaF-y+gr5QgC5yAovJU2$^dT`|Za`rf%- z2H%OecP7YHq>bLTDhkJkQbM1;Lzd#1hs61H;+S89yeb)5RA_L1Wr&Nh`f^$BTYuK& zC$SB$D7@fG=rbgSMY<9@WO99nxWSX8Ymc~-kd}nB4MmsluzzYbkwu#P7b`9#<} zvHltI-uH@F{upWRCEDJ*M23m3;Xim)hJT+__dCm@xbhoB7!1Kx82Hshx$>(-*RRIP z@UL?DI}+vUI}&7=Xd8J)T$DV|yOKhmfsGL8eWgw&=hldGF6nb##Z3bHmK=Wj@3jB8 zx596xyc=BWL&$r!4uyuUT`DDoq)6iq$MIPk>f;;6GO+IxUMK>3mpHO4Kn_> z%yxgvOh-F!|0t38(bq_a)V9B-uKgt`^1}j3zgz|v0Pj)mWtygy6gynx!+jyA@el;bhozqw|+v__lXjCwbdZFtlhxBx)oU0 zbV9cT*Kv6Sf?UP9s9I!){>8A1;`lx0G!y%W;-h*08X5odHDZIYKSShu=_W~uHX4qx zKOh=^cePmGz3c|Rwjv4(C*5)zbKY%hVT~cgVu;bp^jOoP3W`IJ!cfn3j3q@A-8|a6#uD#SC(=XP^)QdF|e4$E$KP)qtm{)4hKku+X{lnYd_^XqD8kp!fMYd@@!>F29t>UsT8SCK(j;Hg&*4*$%_3vbn5i~odgN$VLE=v|B?@GpU-MB!3o zzS=3*kQioiLBoy61ILGMhzsLl#)>9ZCVmUC;P^jW|L)Z?@tdo}`5Ui^0(2krqBzI z?dog&#`+)alVv~6?ZQ+0x7rqzzb>m8&Lc4&_za&;;RG!+5KfYwC@&|?OXJ|Bfe5YZ z&HW9a*F_Q&#pG?PVGXPWyvWlC3Q5)V#*-rSGjZnaV~`X-i&aq)qvUD5 z)BCUDWEC{-?LP+rII!k>7lwapX5&6h);)5{|yG z$RGlOob;fvuP0R3ICDS2TqDuzZV*6TfS(T_C&15!_H~ViM44ut=62IuHqC9Wu|^UW z7e>VysnKjyqUFI82z(rYk0J2;Hl`xN6d%& zi@SB*_VmA8zinaTtpv(Dm&~97uiy46EQ95+0#-$FLx%or0++3cB2v~Z(G*FfDe^MW z78a++$|FdNpZaiCjKY(@b&tnN=eNsx%Wr;%pv9S|kwyz4srf8~oP( z|9#>jx0AQs^RE8e9{IG2Bq}Xofiog+dl_DVxuD03XK_P*h}qX8Okb;HTrp5-W{On8 z(Ki!?vzddm2(I5>CH}jLv&Zi|{7>dX_~jPfj^Fm|?+yLhtKS>?wWZ}cEE@we!+jJC z_fhEkZ;^cZzzo4hbym~1U*|S6(w;}$Jsg`{zn{_Op>|`Pjb1MI_sO-pI>dQ@ZHw*B zvggjo-yZg)S&9>K*PyfNttM%U-f3jnb?a8h|`;%Rwygmzg6e*FYph#3+gs|D% zN}Mu%f3wARS51*hv)obk7v|mi<@R6QE`GQA6BqBU`hnx_s-4%K>^yz#$qtX>9@60~ zAsTg&%)Wj${y8n;ozoKV&S^g9y1VZ1=-suijC{M|^X5PM%k3w%UHwwt9}Ily;NN?` z(eQ}p_J;YBU$0M?yuBeCX$OLjv=*>dE1o%ZHH!Pe`XbMqhW++?DzbSJB-rn+n$P-! qk*}5hEX>4Tx04R}tkv&MmP!xqvQ%glE4i*t{$WWc^q9Tr^6^me@v=v%)FnQ@8G-*gu zTpR`0f`dPcRR4rtTK|Hr< z>74h8!>l4H#OK6Q1{FyB$aUG}H_l~;1)do;a+w5im{=_Lu-wC}VyMKk#1Tc+C|}6C ztZ?4qtkxQ=Qz!pnsHm-ExlVf=Nh~3SG(^Z~po$tSMCsH>F_EGBxQBnt@u$fpldB3w zjs?`ALUR1zGx*(Gvotg9CWYcOmKWRpm;i#iK)Y$%-^aGyJ^}pCz?IhZ*IU5+C+W?u z7C8cjwteSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{03ZNKL_t(|+U&h~ux;60-}m{gwf1m^JG{Av*XmYlYJt=Y zQji&K1u%obkdp1#7Ir}l#;%YuWe4n3oEVqE#)Kk?UF88{Cw3T;h{WJHwj+owkQG}% z1<-(mjHFhpr}z53cZW0Wz1Ld5U;bG8-gocqr6)4;G7q6UIft&?gHymaJf&H15G*@ z2qJ=r!-+EyxqAig0_%6ahO{veF%i-6@vgPHyY8;L>+ZU{?ykG*?z+3~uDk2*y1VYK zyX)@y>{xdh#yhP2cm17n8mljp$>il2mrdkyQ-#Y&I|usB5TA9%v+2?Ud(QE=YJT^n zOZB@&ULWtCy}Q6VwQl~K|L*JSo%4S%RMnR`_}sd#8QfX^xTUUZs4L=n&1UBc@G!$L z06eXF&d2|kQo`&su`ePwOzUIO(%cf z_x-8oeImdDsOy?xxJq5?spqS%P}N^styVwzl9znme{&aDpP}nL?|IMs^5w0+5thI8 zT>$e?LZTx}B}7a!mUDR&Ek*C6;&;`63&&gBaN^Y;rr)}VnjY^U6=sy3?Uz>1zW;k( z@~Yqai=PeW+I_Zw>edH;r|H6%r{?ZTMwOF44YwyFqx|`-#f1 zv2u6XVmW`xVpZqnz{9s)Y1lnwvCw$iVj1M|{g%u1zhAAF-~PD|zwQ_B0_)S%N^$Pt zpYYyq0~`Zuwi#2w4-?mGy!Rz0I_nDK>NK#BQ^3;3AG^VNJ||VDU7_anDPX0LPSYCC zy#K#?`OClh`|kql(`Y^Q)NlNi+3vmHH^O2BM?%CM?=bAKUa#4zRxk{tbO^bF)Ro7a zPXUS0g2v+=nh3)fXPx^hR_Cr9zyESrGK(bvINF$@W~i3O;1Xv1lhtqj%$r~GC4XUa zH^%yu2i1Fj^4z)I?{fmDw?DQ0Y|eB#E!HX}&@&r({yhu~<7V&YSq{r%P>pHisV!&r z_>})>_Ns4w*E|3958ZPYSf9e{#*HW5cJADLe+(u(2UyOZ+Q+oOdR@SA7FcJ1@tl2P z4a2~>5B)p<^LqXX18aQR%U|}u1Mk}Wlka@!F0eiY*Z%%9Z=20#zxVjVeH@FGS4-AM zpeknTw`Z~Lux3x30M{o7tP+#BOZ7|cf7ko|?l*nff@?mX%jL_L|OmP zs!c9YJ7e??n2s@*8Zp(!Z{-hv4cOz{>WPC7z5o3WzU+_u=)tEWu;%kQA%sue_OFZ8 z{ZcN8aVtLcyiF5_kN?6yPENk^xi-ZkxZ{1aa?beG6Qq2`{aHT!!j@0JqS+a zE^+XRKYr>n`DACnHGYrBLDybV0X_Qnc*(oZBh{J;! zP8`{i-F)lccD7Me6o}d(v8htd~&_C{k2)PTR-=MTib8^Q*U1l z11Ti}5JEuhbS7t~0%tqrd}hmEAf@4Utb{@yPFomL5O;gqXrU~D#qs^h>h||p4$IqA z!yRKRJ7ux%m{rbZr+&Wr6<_{yAN(_$! zqkh4g-tL^+Nqst(^U>K;i0PMjoUiV^x)m-w zJPYUUZ~fLb5IbFM2HkAl@t(K*@YSpLe?34NAr($}o7?olSztLISgo!TpZMkScR8Pm zk;p@FiI&I5gjl}4u>!tvYrnx%aUo!;#Emi8e>d^U>&gM8blL*yb1jyg__vBZv)PQN z%2F7l+QX~ZH05<#MkG;eLFkh!j-LX?%tU{cX1ka&(&_)CX3xh z7mFW#%kTN7`(F38e{t}hPK0Uh38XPbN(4W_iHxC)5<g@~{zXp#dt_{lp z(|~CO5>KWABr+-^tOTSAs48tcVRraY^5z;wVAE}3?w&`tuUxzJ_^<6QMdWgj>fXw= z_cm^JZ|knlfEc5=Rw{`OPGz%Bq2EmDRxQ;$eg58WoZqjceV}&J z`)b!-2vW~PoHsOQ(z45|TProh1eyAy&L4!A$fJk+Kj5I@V)?Sv$;vV_s@w> z{4#O1D(>$TvJ{4)Se>&L3XZMPF;Hzl^!7F%#xjj!s-zRleO#@W%06-a=*I-sNsDC$ z$plS8RW)p{A0sVpqS~OjA?1qIp+l%zHElQ7rkxWv6~r4hD0yEk-ALMBTjj(3jV=f8 zsxa|8^Tutt+Rc_9SpMtoGu{<8ZhDG-R#WS>OM=_9ZtAneW|?kn{?wZfzijux*F3uB zkVz+aQ>qx*bk{-tkI^Nzgb>(@!mz%KpU=t5CC&8@l1yo=lxLFXwj0w3aSY0(JgT!( zwLR~u!gFaXkEW--lP(XZse)lRQ)@b8^WcVgJ!d&AX@+p7-sp}|W=Y5<Z8qCO=C9c%<6?;*PZAyBF&zN?*btNX`PoU zBumv7Z+}nKa7ia&rvKvBe`=p`z-rvojn-05q)9GXug(|(RhLP_H~xp~D_6hqOWvFY zVQ;;`O=~I#K^z`KyvO_7<(gr+1eOeYCoIk}Q+~v%pWv;|I40p^)biwcD1sv})%EG$ zzwR%xI`;^3PUy2f#!?khgdsWN#$g714CoMWeoYk=Tu<0Nhq;!+gO&&0FudWHAG`c7 zEPE3wGg?G^Zk;Z7{N$PabYq<~Hd(D5Y^_7?eB+wg#MiNws(+#5t=}z+CF9rCm20Ji zg%a^jDj!@G9@yP#e$Tgl!G9b3z`;$y`56;Uc*%HCf`D^{Quvq?BhLa$dDHqGf;92Z&VNS! z?qlC)o%pTozxr41|7+fF?c8|EGc2|dms#c|PF7St z(*#c)!kDlnM1GKFOR{N<1srXCp`GU_JS133UoTz0HaUklwt3&Ii)y(gkgK2bb(?D-iz$BD;;Mn%DjE|x87X;ERJ;hmMI2J3F~>@TvAm;J>VG)_ z-HC#aLy3Tn^dxv6#`tUedpj!Yj0NO8x>GNO7xSUK*HL}Z7nhfZ0snz_vS)i-zI>UA ziWxK3?hsSK%%Pc*!wtgFIr_CD?V+J*zagw3;o8nyQzOE7wFX)eBzY2`{z>6c9t*w!av* z!-YxXr?c9%lh)1VQ@_1E^}D+-f8)bHusWzn%L%z_vE-owCneBE4OKz&fb$Ns5iXh2 zz%o6}q;vXw%5$VJ>CEQL-^*$Dc?77V$D^>muF1nSu732p7%u;BC#+PV6LNwSAq|e9 z7y6Z>Uwej5sjmMP-h>oup4@&tSG#u-)0)NM3Tpxo3XNip9EI9@dGwne`-b=Z(?@;^ zq!wdN@>?3WyP(Y`RDD9C;$y`12}C{KKBItD9E~`U;J5sR=6rqs`H7!htX(^6+;nT= zx3<3h+x>S8>)9-AYHZV@Lp7Fa3P?IaA##S@f5If9PlSx=#hwSd&x0RB%ps=@&fprW^0N@V7BMMlhqbBr_8^Kv<@M)st)Mf8?q~p!@Sr zNc;@4SRxMRYH7k&xG=rY+;`8^@4T#%X3L2WU-WhTo84i9ZN{+1XS|OHhVzM>JVRFz zyb*lH1;M$Zl@gzDj@yB{7QMM}RDgC^T;D#H5TI&K11qmjOO>0WU_F;$-OlifBg>yt z3C_Kj0?4?)lQ7FHp4lhgBg7v1O##tnRlpT{7cA+?QXy5a6aQgA~X>f5^|KqX(GkI zdJ)hls15|_s9lMzOH8ECr4-EWOhO%zo_1&YffE#g3*oucPtN31Y<@nm!K|gd@Bl+6 zte3Dl6uPysSru!Q21wCLGLkbn8F5fjQgSw&S4;#~E4awSRUAy;Kv?`HIfKtSmX$mP zT)evf@aKpp`g6pCgpPK5$z-;sY9gV^ zc%N}7nvED7ngheiGxQCq??+5%ah(QcdfUR;9W?ACFzyU2ck1~^pgO80x^SYo6;I{s z<5sdGi*=*{GxMl6JbC%Qpk56u_A`sUp5X{o*-%rmM*6;Iz3SO42R6&d&}9r^GOJJ; z@P=lOdPT&MlHy!MwTuivrBELz+n3X8w;tJk*YY=aZWiKBk|3SndNJ9@3@$TpwAa)2GH!0kEH6&+bbfqCNVL5C1fv zCAPw0JGngWMa%^b7d4k|`~z;C|89nEV6#{g2PLPnQ;x*ku{i9wd97!0YhZI2iR(-? z@$B9+$2X2p2XZo&-q^jc&CY&gwMdu`Wk`~FEGLjiE)Wq_Q23Z;!xv5AOnYcYvvhp7Mv(JDIBnYiC`Mpy}Wv0>ybmZ z`oPXpf-D6NMC68po0V|b2!pf2{(ag5tJn-R!DR<&nQsl>`j^{#uH5S$I#?f;Z>DtA zbs_|%3Q&iV)n!w%CCofXBGem#U(z%^m5+ECwd77t0}H(ks$+1S0oEx^`pGh2sqyjZ zSHu0^4ZtqDr=RrlAL1dt7an`;sGQ9H-WoN>t)K2ui_F+~iVfzu8b{5W)D^mC`O#1q}Dcxd`lU|Popng(9?gVehZ(WQ=4 zlhb5%T0SF9dCdp^HXx`NITyMhUHMvue&FEN0XO&dxc<}udrw3*`%1rn?v_LM1G+Ap zo9S({smahm>AS>cGZ2;zL#R!`1UGj3_iGp;kH7Vi zKj=g{PwvdRw9y5de8^xO_QE8DzdPy%Gb5Ai{J9H1Lib+k+T$c(7)c9VAXo{&N6R9j z1P_x&X{v~sU>MF6#mH8e98C$QnGihqFf!{Wwm$bn9$TpSoci+p>|gjZ>>kHaXNAOa zR-(W$dm;j=Sk7oFI}VX<)3ZA4S=<~rd?L|3tK^N4Hy(ykRNTNWGo1~udCj-}?8OiKqi^{4s)KgAV3D3> zFFnO7@00JKx_BO$)7b?7Qvq0|oHHJiJpP`a|Ejok^<~{tn?jlTa&b%&qQ!-Yl)B)N z+j35+Dm}iyDH(Av`lvX8aKt|;q?8Fpksh0lHNjlwGn@idJOUBw&UOLVtNvjL)Sq*%p0D-cw#7PTE^;c? zDkk!f8M;KbN_5LiTpK!+QAk$0X-L)+ttXpdRHuNeYo$+$Z-j#e`d$dj!siWLsh4Vo zPz%#tVQWVavGE+0fZwcPzE%Ih*M8eSdimRb?5lrknQwBKu5p;3VUccjGp@@QGv%kqNl`Vj-a2)t^E5wJhnhih2bd{pLQK$Y zYKFcd_%%%(aeiGmB@xnk$#T(-P0=OhsxE&%v&)xRUBAxk@@0l|f0Ffj&2Fs>!{Kud z*qxCj>RGT!aYHs9U#tTWBjQM=q#=?cXe=@p8FS-ok*FOxbf}MD{#bZ%V&+M)T!XR6 z&<~17z={s-sA=0~MKoA2ZkRdp(2`sxMVQS4+b`RE&obZo&VzJ~{q!`4={hUjC+hQC zteL+@HhM$K_yapK4k|LzgUTU)DTm#NX{$G z#fx|^$o1>xRdOsBID@GhB{Yztl2XDKT8DnKq?ymzzH}c47r*m(g5G5J{=)UluEYEa zHTp4S!=LC!w2_@tHL_(=%ETej_mQDfVkhVjAo>y*1(3$5=Z4Hc>I$I(tBIYEx=ikr z)GN9%G#arh=OZCF@r4W?&#vlGgS8dfAqz3KWdMq1Hk*#wR{O_Z`=9*U5B$vE@lPM* zeGcaFV!+f?C2_;r1uQrqI9}I>C7<2Oze(?{ps6ygclxENAf=5$@l)# zM}e<98OSd#{ZY2`rx=owx4xOU95_5&vOS;EpMQk9sqp&u;QIA4gk!W44o3(*Rmhl? z;UHCpZoOo(J*R)g-=MB9vvoW~R!}XO;bd|VRVBv$IgPKs?Gn`ysIrpCq*#D8^ohR9 zbSoH^f({-b<61|%%&ODh;;jzK{B}?X$TVxUqE!?m{mtn zwF5OJCC4zdhy_h0S5MQ#4~vsD&NtxaLe#!X0REb+J^TvpBHNSynm zebjRL4MmtNKTN)Lh}&dr{?bCBBqgO{ul=M51*N3qxOHTAEC99xyf9cJn72Isda2vnYg^$wMjY zlS;Ja%u8^d${~i5HCxJpOP*TnSnU?AS zIh8;?S|sl8k&-X6l8vWduSluG`32SWedbz#QYJP!q@A+4HPD{hruUh4>x)?3|CMYp zV;GE__i@hQy*~z%xN-r+IlSCH!aFTJGboMYv90C#uCB_>2Aop;#-AfS{p-|EHP|qR zdmbg-`(~!IL_15=GbOEsI#l>JP`QdAN1FX&(Y1v-2ULX|J-P~{STaH-Gl-IPC`AS@ zRMSAaElg*Dx^;vw#$ZDODIi`^CiJRE)7BLzr1btb+y~-4ePSSzSD!g z)BQBqf^35;6t5KbAfRT2b{3P-CS@()`rXM2OLK!0C*HmPe}CgQPOtss`6I6J;KCnB z72VYU03ZNKL_t(0tJ3-jri!ZKeM{f%)2)T|eoY#R2CAMW+Fqz~z_}x9=Q!N&=!YFv zvu|O(wTo^ACaz-WBO)8JR(R*I%8JzzK}>M&Hcxuedi{3YqM31h`7HN*Jf@K1h(>;4A5ni3|NFg2=~!v~LVq*NB15~L8pIK_KM)dX^K)Ro5?r4JxgCZ!1U zWCmPqgh`;C3$vYy*%nMDLRBfDGD7I_?x^c}9HyHx_q`vB+{SF#rg&SVs#*>PBjLAK`smw(}0p~KOpO75oQ=rD|?ZHRmCV_4qAxeCpW!-eAK z_i%XOkCOWxVn6a$D5@)BRED9j(m5-7BxiwRdPDATQci;FIYH{lbVLnvo{69GRP%*2 zPyHfpF_3ji)(Ke~hTr@!@#b}&TwlOqz;Ymjin=Lsn^1XtkWsB8r8J{pIUw0%ok!NC zOWF*gMzTwUsWF)e+vhyz&IfjP9a}rfd~0Aj+c24~shcG(tnlp;S8tFoP*=mf`}_Rr z-qV#2QeUjx$cwAj;SKqz8O)T%p6^ zq(njg@8ADDFBNB>Q-a)byN`pzC8{eX@Ba}}28oUXxeu9tBO(oP$T+DO*2a2~nKYN_ z_MT=K2Bx!s+kKes+&9A>^eaDJ^h_EOq4tRMs1-?z500kwOr{l89g5WmhS+Uub!5># zF-tWTeaGnJLVbxY&&hg$tPNRfa<0kRu(|=e=}Df958-E1svL@I7FT#W6)Xx_^EkNK z<5Y?jBjJNl)k4mO;PACEnF`yxW$&I-cFqlKZ4XT6E86Lrwuv~Wq-;<*@HN@h5FD?3 z&EZ48_Ri@q1lLOIw&#`1&&{NE;9}Ix!OEY%-lXjti!^;!%-u>F)gML0qIM+EMAX!> z*_cioaj7H6^}+zF=tP|e!8xh?&Z{5%Gky;1!##X6mR2<52k19zQgpeM zJ0{aW-FTX|#y1|bLQIM{^o)&apVN#Qj(O2xP~!4~NCy7DA12;#U{@Fj^cLuGxLJ#A zCiKq)W~(Ku>4fHdi+8>x78=TknJj25v6eUJ7m;)`)AW(vK{_#I*#}`VE#;f7ZDnga zGT%;2x0bZ+0ad-gg&uKAXv-LKvw+VvK5TRE!|T`Xr)S?X^Op$HOlv=%S2Er5(lnLK z&U>kMf;2mov`vr(G0)O&t&JlyUv&0nS)F+F_H-XHyG@{m7X((~#o@h^;JsA7YMQU= z`T|;}&HH6(?woGlM>l;Ft;|>-!1~aL z8;_=PSHQRyQfId(UgM4l(#_OpW=g-)GutkAN%dY3XQN#HzYws~W{GrDgHWl+( zOHPoVyoa1UDS7(j=%b@c(DfCX=XjYxu9@ujY<$c7oF8K;#j-0rTo1a*Y!->S>+roW zPXfT=yOlO(tG}BHqbvsbEhlF|`7Z%`hVRyx2gz`;rkkW>oE%$|we%UkO z*Zxi3_fpM*)RW4!lZxpyxOTgerU|ZY9ib9jFf*^pvndaTm}QGuBxQ&9V!;XS$Z8!c z?nFewCp`s3@Knx8?E_W#SO54wcuie}S9e`375hy?-#4V>$vKc?&Ct(?{S4VmNJC3L zaOlO~g8G#u15A#%fzEZrZmXoxNr)Q|3!}_roYXR|*mqRi97PBZ6b3xa$+^cls4GXP z6{l9dYE~YdlaJ{VAN$p}@zBjb#Dn>BSS-JoXP>=F$`zXLBV~sqp^w65fG!%Fjc4d4 zh)$?NMKnjVw_@!avvUooV9{`U2gGL+s^ATh`qF4IHdn-$NI7C8LNJ=vXeT;?s;6#N z_^?32A;^ksfO;T|#r!c_Oc8K=#T(i;{+nO8{;w*TE^D`SSnJky<)>3mRe7n~n)&X` zE1n>pCdHIDo4go|luEOiIKew7-aCS-MH`0`A4dz}lO41dmfML#yod{zFHGN@bBV3; z0Nr}Va%MJT6&Wwr=}+kaiJm(cQk(B83qQ&PZmz zli*#RC%PSDHW`}<#=A!1+THE1&HVxwVG%2q>ur_?7a7)b%qq+rma8(W)BMpO?IP6M z+@!lXq1tLn{djSm+$(K9r05diEG(mha22v#WH%@ zwqrJ3BKoCxYAUH%EuP}S`SW;Rm}&r?_-TgalG*j|FY=nE8M|)=ur<>Rdh%UafNe%YU})?UN)71PYf<;?~@F{>kypeP--_C z)YJ^y7Uw74g&;bXJ&r4+m>jF&GA9%epE$7OE0#HTipg{goF59#(~{M#@4Q zn$h)bVdh8OwjyD`AMv{;m^y|9RQ5Q7K0wufl)Nc26>9`nLE{8lDcF08m04%R<#E_- z8NOj-<|in_GU59}maC_!Wr9{8rSEGlFTaPK3gkeLSNyM~apJMZ*!}2V;wXHt=kwBC zYKpKTgj-bA0nTqDv|~qGY5PJV-Y2}PP!n=435W#6g^2S#MkHm(=7~7g5jLwt&XJtU zpc2hvYnb(@MJAOIf-6@qd$IVM6YdP&vda$T$ckm#kBxkk#Xypz8RO-+JMV zKl9_0cX{fW5T+Qdl4`Y#nQ3OwXd4}LqsmZXoYA5mu?`%ursC|xh(h@tyTYT?@&xEk z6`nu;byt4BpLulEGsFxMQ1fUGw=Z}Y2=x*l%4A|whvgcL4Zd#a_C2U6JUr-_%PtA4(~g%rBX~u4h^of zmZn7N6GK!qE8<5L5fFSuiRlu+hUp#nP7OLC7ec76mbc0xmc;tKudCx9VVq*;n^!f1Fb-uYb=yEWUm4cW*xf` zMcwWb!Uofd-tU54BwAIN?4(GQnOuOKi85`9cE0wBDu8zxCq-;{Z8-tp%9TgPDE{5V z<$&25lS6#CMcp>#CgpyHN=+0@ztv_`XG4#2AQagR!Ox9aZQFAs6L>I*b+Jm;#iD{kL`oT75D}BJmqcEOtngU7Ync6m zzxwdR!NYkB#GNbMyAnFY4d5D_FK)1%>{Hjb5KEX<_%PtTVtI6%>M^PBP?j1UyUX~{ zQ`HNq_JDSBix5^|f)5>7K(!%9U!LoGd>9akB^KeR;lemOo#x7wD{$pXnGZkewnREa z2Atm~RGyj*xCtgT>I3E-44#yY(A3~PRo&s69`ExgcPUA`bES=OnuO_4wCkJB(QhhJ z*P^jTtR}dIc2X(_A?SE(pCZ>W^WCUy)gRhu9 z^7OB_*9^o=Rm!ZWqgK7F$c_oZi-Oh>Xxbb?;$k1z4_3y+0aF^}dk4SFsY$PQUstr|hNIShnGr2`mA5i%< z&J9#mH%fwQ5RbSuO}j@`FYvy{xio_7Xjt2w=V|R-{c+A+`%W0%a$Acf5pf-kgcl=N zMWs`G+(n$nDC!gEODyTD0g-^_()r+UrJc(OZY+mjQY>_=v8pE1fRveURjY&=e4TN= zOgB_AqPGj|r5-Ef6iPO#9?Q2gV^vK1k8Fg7bV z*D;x0qiOc3nhj1O;!`=dtcrA5%Czt+^$OnqZ(%mxF7Tya$==>updPzpdc$M@w?Rl` zUt>YR&w!SsQ?l0MJ#-9_Vayck@s@PHbmzEo(TO(R8PQ?laU-85VuU&qS|ikgt5Z>j z9{Y#Vpkcyzakb1jO%-{lN6mdHU-^{Db#ec$&U15FWSl->SrJ5wxpK9adKzTXI;n#r z`0_mOIA-6S7lL=9W|s7JY3BuSg`@gfMdWjjwB}A=xmn}qMk^bTXA$Y>x|%8sWnP1i z;6OE?<`6SNy(EMUE({|T;W;&QT?#K$w}&*-z2XAv4I!)vVJJgyB~gV9LQ}Fp>6uNR zp>6l5LXR*G7a3pQ#Ermm$M1CR=6A4n;m6oNZlyo6%o!zNL^5%#>3P(QlxC#3O^#C} ztTB_ZT{oemGHE75wju>KSEM~ziwaa#MoX1(RmL|1VNymLIX`leXp!%r$6LoCD43K9 zH7Sr|b*z)uoN-BUl4xeBRn!YwTF7y^)c(wg_%=v0uVgw4($pg(@0~d><9+r7=bZ#^ zmQ8PSS)WvOgPkNHe)T7QylUI_RqJ&D)q1_gyE19V`wVi3vBp!PoxXBO+^?;w|B0(Of+Z+|&Ef<-$N$Gad%qUOF;~WXF?8fJM zTqvT#W-5MqNzX5?vjkH!ajt~<-eAkqq}pvSYq#9*^spCOMMHZdJ1}pUHwdN40!L|P z2fG8XJ{C81M20?p16rBNaq07~zUH_KXKT*kVtL%&E&?HB>ZZrJ%}8DvS*Mt~6WT*V z+<@~d#C4eUC4k4@Za~IxSx{4Sj5kb5+$Ao-QT${|-R@IYYlMt|OXVBGXeK96QGAthlFn;uF`P`TLoPpYemkUoJ)+BQz>4nW{ikQ zC?y{Apl;OYmszO827Is`RgFqcsQFxC21*U2sVlbn)}33V&?il0Oi9+5lJ(ipY?iZ` zI>Y3+cSz)u8@!j76WN)|EB)rZ*v=QRy#I5lKlEo&1sX6a%mvgy^Z?5ZS?B2g-`<-? z*_NI4VZZO&d!KWMy7gYYSxwK9kYtHz5gD5ZFbE7mm<4#*0TL20qq9~LXE7wi3HDkc z7y~lGBw#!c*&ql=0tGBa86hMgEFlIXy{Qt5>h;Ro&^Fv-keK{PFE`hw9fO zEo|XFT1WL>SG`-eZhd#}Z~wmEkjKzeg9zo9z6ALNeBFUV0-P9VXw=Wu1VMxfWyK>` zWLpB6R}|CIKuVZw-#IB}G#O0h{j-)lF+$a6MqBefPnWH6f6iNRX*>qTW8mFCjs5*& zsJ0kYT6mQSK!j6<;|T8;sOsw&?To>J&~-Jsl#nGOCJ%{2WVNvi!NedUf}{Y-w(OjO zTwV=H$SJ6bMu|}eNrEJb7(G&C7r2}!UA)Pn2 zm7HR#II4Jjp81wf3NmyR?F{C5QqS_xsfr|BMjPQN^2|xU7tnDL*%@JoOYmjQdj^P>K5=MAYQ_U4%MJR7_^W)fTZG; zfL<(0h-rYBc93O?taDrPp~Z38RM1Slvf3DFD_U~jlWa5y#wmh{T3`4U^vQ$!`}^h3 zc|9y6qeK%4Y{508J=AlI`5{z;DY{r;*?M%bf;MN7a%H0&0YDik11SgNX%@_nT(-hu z0Awpo&IHM1cB~>uQ4vc3fg}fsRP==zK8B#um1Si+0J)ixNGl#3l}cnYW{xQKKKU^B^+Fv z;*qNn!)k(@&Oq`6nuoT{Q3N4FP(jJV)pP9ZJzSP^LbsSea<%HSL>X;6fp5+sR11W# zg!c{DC6HLEgw2Od5krNit>{-i-O@Mr%kPNO6p|8QX~wWQ8U6c;phu2^@9htS0CQq>`y5Ti6LM zB|(ge*a6ZpG!?MQDJb`O>1uWbbb2^q>S^c5^$aw$sb9p!fpqS0(7!HTHaNz=u{6B_>V7&ZJqzC6nJci^6B#!|N zHdvqxArC=-QUJLb>hXif;?TC%PiRXPg{uTnhZqM~HfO;uK~W>6^JuFjsxU(pZlDTB zsHz(PI$ObX<7~MR1TJc|ad`L7;@sKKLsZ@3X6@hh8eBqOTw*Jtu3rJe7c2T1FHPFL9=(`w zs&i3k&D&XJEmVDm1*?R*wB_s=-VJYg@lH1wK-&(%dvslA%lwJMU@*X8{$7knuf*|j z1I;zgo*kHAGe#&8gcuPuJPkm!1iJ07pr$bl|qI5;ai*#*$7-3c&ea%+C0vNI9UeqC z%x#NnAOs?eN3LE6kFVm&mCNOXY1;{IybfotyctJ-@Y~xn2HHqI>}BwIgq-)##Vcsy zWh|R>Shf>%-56O122}b8askrS$jRG@QU#J7I608>NU;L@2v@b>&_bj&I6{;8G?YHg z1%bK=oD1MU@RhyZq6AHBz;go9sIuhf!y$A{k>H(2_UC|1Hk|+?v1Ko6c0hEcxM*wC>M9^sL%0ZH@}AT= zg`_BpX(KnTH*({kl^chxP7fpI(@tlLDDyUH(`4;BQIW@B1?ZDvH{1-qA_OvI+B2ap zB5}`5#7vI$=-s5x`Rr0uKac5j4xt%##(Owk&LA0RmM!YaeoaT|J#!!eEBs&Jl*AL-?>j%8aHx58?_CHkd&Z z7%d#n!L$TZ2T=hyV>}wI07t_M%jr@26>^g+TZ)R*`XX`2d5oAYqG>N%252ZI_)+XPutRTb(YV&fARGs%i`62I^X0u0%K#Li6b zpZ-OhZlb!9e_#TLo9MV16WCo zIxNvbr!+D&GKd^VjI5`cA%W2H*e0f_Z^|7cGbnNaLwTL1r&w+6!~}_!{i9LV6d8?8 z)~>8b2D28dR8(`!+ICsnm=W`u_ik3yx{cdBdc{&zW%2~INuS!}mk10;wf59hg0t<9 zyt6IPv!lSC2Al-5{cG1i?XuuagxM^?oh;yZh@A6E4b$Wn!!X3?!dGIr{3n=R&l_v1 zgJ^BP1@TZB0JMN}4bJcxw zSZ}4&!U2LTebc)UvaccDA?G==Ff`}FG*~l`p4WUI4hk*FPGkgDLQM9)YugB5h?pz1 z-4JcJgQguKX0bUU_cJ`hyx1|SK?n9T_^v`qgp{a6`8ue0SAy+{Q4*f-(>_uPZ?XYI+W z0x6pTT-Qn2R6LSY=+Xpj8la1WOf9%>5kgyjZnB1237kEANC?`&bv3%S0ve;#P>)#= zLxqsK65tANr#^yFPaOd+SkKr)l>Kl;3wE-(L-nYU0FoF)irlGYO)2VP(PBD}XxeNN z+9=3LHDw!E<&7L;QdM0UCY0liZ1R+ET3DV2TS%&Dn=5AWrAhBe^;}jhm*kvQ001BW zNkl!n$HqUwtSZxuP2*G1I{3cA!TX9LRAwwwhHIGmQ z5C&NK4uK9JxNIa2D7^F7sb7m`J_3;|8bzDS^=$ji9ww`YXbsf~6pEM#AO7$W+(*9} z`Ho#+a5p~izI#iI3L%S$oop*yV_5x(Fl&V*6C|l2ZVESOF&xYxXlzAE3{j7qJyNQT z)tU!T+CdhEOSH0SauvasVKoaO3$F`l^TNVln-xez4Ckm2zWR7LCPxh4Z;9-!u>Af( zeBjI^VG$VOJx)$Mb|)7Bzhi2hl3Y5ZHT#f2n8$=s7~;@>J%-^Yp@Z_Y&7d0uM(P|u z9w}x3I~WWcJX3L#xd^ImLmnLhV7N~0Bn?xm^r-b3eHWTP;|;@sbYU;N~$8C2Ps^)CTXjE3hd zm9&{cRWTf101#l#0kj(1P!C{YJu1_3yccBv-d2ucau$L~*)2t-1)(!erEd65mFIOj zuaJ2LqC+S(Ajie7(FWc^#q=#Xn*(Z@8R683d4QOAkm49Q z*Q?d3pE+!l!8M9a>v#mDT6(iAX(Zlu3Sq4hzV3HxH2;lxN?(uapeZcQ*8+@ z1RCyCd}eQ;%acxK*Bd%=8>%i^;ox|3UQahItRY`S@x3cZqW4`EVW%!!b5jc)&)@Xz^*t+k0B<>}rVcs;~&< zl`n!7%vav#Pd2P#|AjpsgRq#fy7bE{j5#w>QG^ihe{OY0=~zILEmAxu1om`E*o+$qJO| zqM{BNF*b0%Mot67!pj?tfW<=L%Wp}`Dv(syxK7@%XDy)?nHV`%Af14^A&88{>D-CU zJUPOl0ka`L2qxpoDIn${L?>v|MJ$?IFq__i<>G=3n#m+;ME!JujDjtp44WCs8meh(3KyM%bShM7!0{dnj0cwfSp4% z@H7|&8Vng#pcOj&X#caPRah6?OU(BMS}QP8*~TzPf>cYb&fZoTVGvt)iXBsURm(8=91+!2#^aXsUEdD6;{W>r*eR9lp}Divoy- zfJ_qRgM_(L69X8GVRRib0i$=GYv*}b1s>M-zIXTj+wR)8c#j<6O4BI$V7t3|oZ{k= zkShIhzZDI){>qdZ_%K8W-v;0(uv~7F_N=#~74lqy{vbCYAob=R5J1>|vjT#Waiz>D zX0tdA;ZAu6i{=uh(_1hYumxBx%_H+Ov^c@z>Y&;3jV$~yBnYL z@`LMuo(F)YNf@45v7j4#sGAfQZS+R#A7W$GqIJFH)F4ztRMppm`PEn~)_9)Pimo59 zfQPz?`N5RJo5u<5zdt9iYe23or@8*f&JZ0SE+ zXT`_?IRe>GEHt9nIeUnvx(rr=r)ap9V}lxC04jMcOpJp1Cq_KRv8QU;?{G>YP+3N; zmJXp|at#r+1Q!XK8Cis!l9st8oVokr<|3P$a-Dx^_BRyVic*(^q9|p8F&8|O4@@CA zswz))<*BY6)fH3anY<^kb)pJ9@^JX$&6o7(u)*|wzxLR>bDsiMk}I&isjmh}S!4~@ zl{-|!jW7Ibc)^QqDgDH{ub>_zq*IUkC=XSb&jc;O?gY#yAX=EPjH~{PwTnWM` zp_)XycO&ZEWcQhfEX_eioPp2~ab)tD;WDjm&IHOt5ZYLr2)u6I9|w7OOrQ6=>Mvx` z&MRa`p}RypB(Ph*`2EH9p?sH3n$2+K#aKjSQ$JIiRQr;o=7{J!vu7^%xEr!y%(t3S2f; zOx_TuNKdJ8OE`A}-d~6J*WuhTn7fsUh?JkxR&cj$571qc)v+=j3dDagf^GdW>iUBKUa@ChEao!0ztnU^sdyhNBl^DepsG zEu5c%=?1(%gmX7Qw1DGW!ZmH1Ta7(vt;{B$O~_HUOv#nm5p5o%Zt{j- z6&9~QZq!ogw`q0QXEImw(GDSnz2c!NhO~zaH;f3wgfPr-wOa2LY_-eMP2ctE2Y;cE z3%o;BGx=a|kQ5V|d6d~nr}L9eW{u4w@e@XB!HQ+}&;oAxTI@_b_}2dh8AGJFovrS}`s8tP^8X+W zGb9ss@z?D+w&tl2V@4Amz{v>!yb`yc?Gls>jH$O zNwji+NMUoTd+hh4Wr%^Jy}A6B1K>x-v;?tRq*@4bFiA&JP5BkzfvN71AgVc8<;@}!ZY zd6KTn+9flvOvM8`J-w~)Vt5G&k^^)Aq8(3zp`)rIa*U0f_{T3Slic6=Qo8Hn?YG=A zyZ$g_Ifrw!Dy+KZRdIFoi!dAw5rS=RwEKjQcWI4 zn%xVcyD=D^fe!;rPY%$v^K#D+su9>JCX)eZ{3$p){58aM0Pm0B-3i=a4(FC8)#q$k z)vT+bG1Erc6BV3{ZA&zfsF8jZ!4yS>zEdb}+l5sQxe}?IHA>L>itR)zY{nvk%)=qn zgy_boY7Z$295;yY!)PF>Cqv>LAyfgg`TV{&eBV2MD#>yw=$Zm26j_O=B1uNfS!0uQ zF>U2|8g;phx`=&2Svpa_H9o~Gouo@8Fa$|d5G&e^UWbw3oufWK>xnK~ajw1p==W~B z^W1+Hf32!H;txb)I#)4(Tn9UZm+egT8wH0?W&NST#pnG7Xzu`B_d_^2c_WzpYGhLR zCS z&URLa9+CoNF+i3I(%Fo$Z32dSLr4Z3Y!GN%5jl#oXd5{`PP%MFQ!boa0c1UO(Wjw=&e|1+H)H~LtsFOj z#+B1S?cjrwV_umFi9U*=aO(Q-`)6;w{dt3LSOQosQXgAgno+ZRw8pmsQ)ezPW!KOi zz(FWt0t@eknlntVoZ0*_gEvo|qr;3mzJZIAvk2AqufJ#Zwr}}Yqpui_ z!ro$$Fd8zJO&>K9L1>^@f~f(cErNq=$9Bh1=fUL7(*c$BEn1n>-p2JeaqG6hZ{7VE zmeXULT)%-(E$rmSEnHgQ%-Mfwru@ZOlbEn$5Tg>>yl&Mh)1t z$hr$r#c*d}mT9!c0hI{KTv&8e5@mrqKKwiRH9vaKk3?O@tU0RYtdiBZs7owys2Qzh zZA2+4qf&<<0LoEgN}7^rA6_GcrKtK?N5v;mSP(&sQ5Rh+)5c*?F$WKI1k@Fgb0stp z8)@}7z5e8$~Z(q_d)fq z;(>qvM_4W!c+cy(#fmxDZ)rBxWztm>p0mI?!D!qfgehV?gZXR-=bY^aXyAAT$t{TN zkf5u_bx`(Tu0VAHQHzw#eR+D}#b7O<=*moc%^qeZ-2TybU@@QKzN<&C{=*L~o1|^Z z+IAu-sj86n?YETgSP969nNKbt+M6upVqMbXS3OlipW2Egh-DOE2i~aj*vfHZ{S}i! zRe47PhBYHNo89Nf1vq}|AL=_^@EZP`>G?0+rF-8G?~kC8q0&K9gD|uei@4xQIjvk{ zh!xo}$SuJXpj4yItwn^$2qHB&SJv2;-Jsr0aJ+=CW(adNu`U1R_FJ)gbyexb^&3;@Y)+TsnUV`}_MiDZkPFr9H=PMUEJa$IvrB z0_T4jSFc_(T&nrksOt{Rjbm^f09aFPL){3e(`wGHJ@!SutXQ4#EGWYJ28ZW955ugO zU2iQkDr(8(0tTMoa);+U@Mbia<9rbO)W6;T$*eJEjWMH3f?hPyBW0GDD#$9OQHNO& zi?QcbfIj$A^l8y%?Bp9)6H=?}Wo-3?*Fc@A*q9wN1xG~d;(wg$y}v*E*-!sVyWdLZ z#yGigSl*$@mVb$M=i8vlMY8pC@Bk#EG_p3OcV`p_G(zkeNd9aggil~p5YFRk{2IU5Oq zt*2y8mTm1?9DmY(joZ&&z(@b&1RMsC=q%e&6K$w4yw={+Al%f1{U+C2e;Dt4;j8n@n=7C6Ja_a!DVk)(B?%;!Lqir@Wgej@+k>ci zloHI6$TeVU?LAd!YQ4DAI9D0a280D5OE9+}PPlYwh|8BQS!h&@m`o;!F|G@;_s-HK z)WJUP~dh0{&CSo{f|-iq~LdZ%9T zpHbjB$xu#N83dwEr;fF1oK`;QAULf9BUEeo{o`Nndd>A$f68C4zqh1ZmLkeP8JU3X z&*bxZ#ZoaNHR*+!(T1@c0bgbySuM>%d{O*nOTy3vNE=+bT!F}Avhx}c6H=RyQo?*b z$7C`=O3O#jS@78D_KStBWZrwEl+d>GmEQ$3mz-%W=KpU*(=6Z|z)El~+5o%sM^uP^ zwv}6I*{ZlCLn!0qx!;dlFYMvy@VK1xWQA7|n}f6q3wXc8WI}LG@xa5&zbCc@ri?CS z#H^-j7C}-$CxWykHeIzd3yP&QG8I$}L0w(v#yB)egbu8bk{q88%I+@V8-BkHlsSq8mRy zsTtrRbWoQ}Ae(DQ^3d!+uuMOd1_=#ryX$R5rcPKc33Xi~rG(@AUkRD)pt}6E*xA`B zaKcJbxngY0N>~$CGELbeXKczaZ9X{|KvmH+4Z7|XxH$R8fC3LZZ~_HzW@G+Gq-dxD zAn?La70i5P%4r8oc88dR1YI6sCkT=(;X(};2(BVP1h*VL0Np*t*}Wx3;|?b$(>MLy zAAaavy zIDb?)R14cKjd=^AjOFs1w@!ZZ`5Z)qoypFlPJ^4L!bj@|pZt|`M%y+xfBrmX{`>LK zj~#=ZQCytsGlry?>Tdpheeazc;oP|$42J_aZ$X`P9k9DQ!p?3D7ZSqN`=Hpz?%6|3 zCNq#Or?33KkG?%4c3ER58l$MBVgOR)@hSIcx^AnRA48(|uWtXVwL~~Tq`l$@`K77yQ=>9wRe*AfNPXBg{$&`#6hy|$ueMQo17Ka;HnR1zl zi2@wq-4yV)b8D6j!&3El&D-g)Q7_cDt0)hqum_V=%1aP&Rs zx(;<+K@{*iXK-}m7<*^W;D{M9b|4}QhXYiVLV_UF8M7v0FYe=Pnqg2yJhFfA@{a1@X%HOM-eVLhp4210 zFc`VZlO4WgcgTCYfd@k-=bz~LnooEWJ3X0y{nxzZn{K&u{EE!SmJ(6u!@Rcy*B1G~ zm4K+RM%`z?WoRJdpt~|`OMYi`CZ3OvvcAcJtdNcVX`{e`7s6jV2(ldI`w3 zAVU;-$z*SkVIvR{3))x_nKGc>jA~gUJe>fpL#83Jc#uYGwfZ;}5J(t=gz96j!i@)E ziK=Js+A6FUefD3*z4zXW7rp330D#~9-LJ-rUi2c|d+)ud7ykpQ%v;v!wAzO4pg!nLyEnGh-%J)lu=w@6%mSrf}Ycp*zWY{^p@_4zM#`7D%yn^u#q!(Aj<1e3jx&RtuyQ+j~wI1jT@_{cCDNO4-O7+aBu)0e-TFy{}g=u zRr{K_@tg{yX%qF)NVsw11_sMt#?|g~;apsuI#D_`d&&cZ5D@hWsCoP9`Rwi8jkxop z7>~!Rn~3nh0}r6R@BhT$k^7D4!2q)~55DiLjH}TfZAs!cWmTj$Dx}rtq!d*L)@UH>>hbJ( zbGJ=}ZW`LI`N8Ro#Af^Xx7*K!dN{GSlT7w_H*VZO^YBjrM{h$jd>Quk_7G!4TA9xo zTlUjld^;XKx)s#C9dz!0#-%&H7ds`Fnusu+PI2|>Rp3KEXgy=IKE2+UcVGBl{=mQc zBSp^UzSqYR#9jcg8poU(kZ6Hap0T2O(uEau21oUVNs?`I7U*OZX6DbNM9hx7bMW3# z<;JO>xFi29?;T>(naz$=(8dGKbckGp47yoa3P>s- zqp3{6S;{CV1DxT5f>fbNAyFY*qfPZ)tePP|R zd`fa-sjadGs5w+95tDgkh2o{RlGhMoKO(fkvKH2n>xGSF!`xWi zw#K}!#BGat2WU)!7=P;n-Srpl&VK34d3o7j5H9u2JoC1;^R(iAtFUC1wZ1Nnyj@sM z83R9nQwNQ97~d)^-u5eSJ-?~HbDyo)^U-S)O_Y00sVR?He8=YV`Av&!xPm!W{{hdr z=SOhwz4!LCUPzN5OF>@5wwvWI_$%M{wzm{@MPEn-B^R6?)8L6ufPeOdCFsBuilO+b z&st@(tlurg7P!n9b;C(_)uI)YjHoxq?S~{;vc{Nn5#RLwbp3o>{M_xg%V#msZB)Dm zXu}_b>s7~jTAMe3U~}ztVTnfjt_4+>qJHTM%h7tJ1MKm(3M*M5_r;Y;AX0z# zna}IOTD>_jpU-ji4}S}1m-hg-ybO0<|2aI;K7uo6uH)d~op|7ZH^cqjzrex4!KydR zi-f$)h|Bna#X|nd7yRJc|M(_L_G7M28}RYRyRM#^n^vHmVp|lPN97r{bErL&X95wE zho^z7Xc8*kt!kPKhJ1cB;Bz|_?+h#283Y>D7Cx)W2+ZW2AZwI)vy|)8nLKoOoE|uw z<%g#WIcQT}reFFy!|xdntM6#I1qHL~F@ucGT!hOlA(bJv-8?Scd>Pc{MQik$BDo~e zRs5Vl;Y7E)!GUf`;#oF|Sb(<4)};5w)Uy4mx|IUeZkFx$aa{?js={bAvZ40emgM=z zdeC)y1=|szX}dREJ<4DARsZ6TmQMoM{J5a%e`*}-CQZBs+ELLYnK+j=nxNJ$n>9X2 zAu&lKk)|o3jR|d6>+T@(d=O|{GeRJc>kA8D&S4i!1A?bO_n@TR2r%+VNIl(J9uy zZn`THAyI<&eudVLMvSVe&~+Uaiv{Av;>}l-N^`%lVqqAz3Jc9}3n0bZZHEgd3ybznZ4k|HYX(`x z;i*+>jOwHFAM)33`)&aE{I|R%|HrZ-JrjjRkM(3310vK+s2m|U2gjZ~JM)1rr#@#) z2zd0i-W#Kyje=EGWXvcBdYX!d790Ue49u)(9mXVE$O2j2P5chYVbR=>P#%!0NH z3#Ux0=u~0JR$&Rzsf|QVQJDCY0oJMJ9oQ}`bz6l6Wr*NU+ztKiFaE`kybhnh*E6wS zgE1yTMGQ6*cyJ#quqv!#DcPU7h*s%@syz)>H;T$oWXTCx1X0#pfSX^x{>^uO7LW3` zGUFT8#id(?Wh~%zVX5R(D~w+km0}%cRSHY#CUB6Rf;u)I?^KVa$^hZ zf8Z0npq|mfGC*vXtf|mG5R-V-Z!v9n@}bY;!K$EC`@#}rqswY8ac2<0{7LrN-3;vyAWJ`s<5zCSerybY=X4?9Z#)*S+@!+QMFxI9YKU% z&q_c3<*$F}-{8;DMbG>LZX{PA&^qIAqp(W4h4x4Kjp7m{RYdJ2NVZx%_3Jmkux_h zo_^}3ix(~ta7lqn56%}gfHUQUGO9u)2f=vHxBsp$!)>)Gq$d+{eou|9i!f?fXO@R<4uUR?APe$G$i@A(N=SkL4O@a#7D z?27elF+6*He0!{CuV=4k8||n0y6B&i@A>TY?Dg#R?Dg#R?Dg#R?Dg#R33UDc(kKfJ TWe0Pp00000NkvXXu0mjfx$~y_ literal 21843 zcmYIv2T)Vb7w%00p$kX{DI!He4@EkNN-r9EM>^7_MQRXHKzi>W5Smm$nv{SP=@O7$ z0!Z&7ApP-Yu@Op=ikv>JVPuWP~7l$jJefzc3JhQ`ce=146%6I)Oga_b9ME#WKB)S z;s}W% z{04mJpLUOlKC)-T9Ew7*Gsd;(N`adjqs6WE*+ow$!r)l^M+RTR*dY^4H*9I;pO6a?m2zCNJot z_>9iwr@tuyU8}L^_Pmi zI9YS^{QU8~hgXKsfk%iC6WeOPV$!`BAqT9Eb$)Ma;4XH47M3kLgk8|2Nr(}E#lLdi zc1Q~Gsj3^dk#)ODy#972Y2qK|1lr}-=zZ8drt-mw95XuOz)%J%dX-6<caad18g{|=Nc>CJPQE|@ zCtQBM`2kM4Tf( zDCz~=wAJkWz++gT#ruyF{X(ekwyd7>P}kY}-;;64!TsLbNYZke!-~V=A#T~ntYo2N z*!eL98t{~!G7X%|XD6lJ=fLce{pTAj?T{bX6MGW`PVO+fbm5O?)j@- z?ARj6l)Iur{hUC`*0S0J`oYiEp)nWc{3x7Q!Z?%tyVz1t9voKj&kVT1!$}DQgJ+Zg z-`5wk^6t|gpsqhJA|qIMGotMQeybJs*Yqa*YMh`$Rv_|HDo@aFPn z)@9jVh8B7pNlZ6_|pgBTc?i2;~-@Utw(kI>?GTSsj~%l^9T6^S)& zX}870t??CauWrG90fj>Fgwe6Ro}~qq_5DN!3TX}LV*@Lb3s**nl6TK1=I~( zoS)r1qBK!9vGxP&*)NfO?Zdf$AdN;n>Q8$Fx604l``~2#I07%MzYI|7{e}~wVm{%a z{na}-UiYHn=WCZz4E)ZW)Rre--|?OBOPj+N^R6qa4{le-M-{BwH$4-2+5g&ds?7m176!oGJ-nZ3ugLZU3;%k4iGtSD zCJ4LGSu;{4zU~q0hS?30-1&I=5@y{=2iH~m*ey53F!j0dX& zam1piR^lINCF&$1ycM$$3Yk!et)NktD~Fpi6K%at$O+N*SbZtdh63|xiRIuN!xT4K z^GOzDB#>5ypw2F*excd%^2*-$;YXw=E52ANf6Lvtj}y-WgX3O~c!u=X%GZT4V&q8T zUhQD<+bYS7^zk6)l$!V%f$G2Kr7Ktu<$XV&zBi)@==7QsLD~>vWP4g7P*U|g;W6Ik zJ+j%2c*<3ec6B>2d=nS1%O^8ozee6Z+Q2(JKpzHj_%~AbCNwL;mYS5<5TkP!YE3EuaE0`OyL|y5F|6?Y02wZ$d*^mAV z3fX)KwuY%tMlKd507pNG#m@AJ7n3OWXW{*YcBDceleAC7xes)6s9PTvoQafn!&ja5*lHsYSOD573ar)j<4-@h9o@_)9c~nJcMFltoU7KwyUyn@B zAu8t&0r6*Y!d8u z&!H)^oH`<40KHC{?QP5jcyx=X+qe)1Upi_*Vkc5Uc<#&eDubSdHf|`n>|`j2v8y5I zP4#iXjlDBJKYFjGMnAMTJklN@NcV<&Fxc%dF^`_~`Dynm2*i^5hT)Fs*?!JNS-2YK z<*&-@#tx|M)xr}_TeM&{gGc@(d*tkAb&?|@ra>AUr}r7WFDIUwSPZVpYK|J_FAo+ZAnjymNh6sPnMZ(+BI zx95WzS1hPVx*4VPQR8s22=X?k?6<*-6?12Q$vP6>Jr0_}MMZ5GyUBz^k`xZzT%yJ1 zS@B^K2~VEc%1|eL>rFgDMM<#4$M1Zw;W%o5cX}7_JbFFLKj%}ds=aJmH>DTAee>ap zqnSBWnUuwGZ;oFx8|SU7{zN%>`~df*fV{fCP7j-M99MS;IC-{niJ7>z{gk4)2{M`8 zUc6a0+%C?aX39GVzcIzI-Ma6UBRN>{S(uHU1AISmH0qm;=&lcgrdgl&Bj{by62KoK zihO!FLu$#7`UWZoRr`@+CJLF*V!N)6Lw>r(o|k3?2d%s@wOW1clM`#m)}oY&q)VzP&4A*b0j??qmi{`u5OkORNIOA3}-6fDSnAjoEC!Css^69pEWpEq^R)g z3gW0hWGpXQ^dW`>|Eum^?~ynX9pW>0H#oVDW09SI^Hg2^BoSIIu(}l7en`>c9vCA` z|D1O;h;vTMz#tKS{X^Z-UxLXU8X?r_87hHP_pT+8L3o!%XW%8u=PgL=0cTYhz$lZC zx7ML zm{Vb@W1z(~FE;arfY+@*PwTKLwhhxiE#fcoebD-S=>TNX^Ew@U{-;8!&DT~~@3cPmrgcbOCloHbw*{#N%X3?Ct?4~v4Y4E|=C zH{m3hszTBYA8ps?yqyI3>z&I8GPQK%Pm<C6K+t=&%-q{Gfv0zQ2eLng9szIf?)$TBu0x1<)z-^9WdpnVh!Ckcu@t#4CpBrJMmW{N`l2f%`6 zy)wpJ44l?$|Ly>8_Jh_tI=9<|e|ltzJ0F>7=_D1P6QoIFzFF19!6mG!YY9_rdbg4b zL4H!1BiB%39~QpIVB|6i<$G9OcM6^w-6TQ=pUS;ja9)Y%vm$gvP;V4M#@BebGrf>S5uiOKCRj9?QfoBetLBM`)q9F z7-ADgN_kXYYMUMNzebZ zoDiZ89eA&vKa(J^+H6tX9!@lT^E_Fe3^=FMUfs@OC7vpvA+)4Joxj4X9pSQqJug7j zX+?wmS{?6)cc8wG8l6taq$`l&esjfor+*n?Kw{w zHhtx}|7&0TOU)d)4`+D4P6<&bNCK9`OHj3g^KZrTpIg3oQ6ChYnyDnXceAJL)K1R^zC9Oa@B9O@~Uxhsa^ zeC|l3n?Y8boT@P!bwgw*PaOf`KmP{(sWjetJK1N#?MQ7ZW@d=~oBvTEg*6o{m~({- z(eND?g=l?i=@qwUQzMFi<}HwBys&KYX1qDAzcZ=65RVnZcK<8d6!<5bNNa3=eKaVQ zi@!sJ$;n&3EfOa(n)q+iE*eQ4x|>isq6CRae0J&SgYfk7D7ytt>vUc7104%v7b6YB z+fOzdcxzlZudIS+TqtS+Ll`pS-^a8%Q%sH;iB{eWU*pDp_|rgjjz8P%lolZOus(Z` zIO5H5#aG1a7n7~b?ZWy}{a1{>>UvM2b;k|Tbj8Kh%>2Lo3y?b$e*8s;>P^M?(?xbM zk5d)R&R0A$uScFtlwPj8{fZ!;<2z=B9+0vjWpT%ECkgc16<1}ox@GUM`IG-DzL-lj?DigG%R{5RuR-Ce~ctXMhAPA-kjBM^mtaH1g^$$&?l>Nn;e`Lf z7p-l1Hz!Y-v-e==3WLIdA7&fBDpqaVSC*LVm(u$`hGTESGwajUSDP@N@CC`ePv?7h z2R=P5CiF-8@U{8DH06)FqJf*eP!0QX^@1$~!#1KsW`0{D^@o&zxqV8IMA%>J^QH6e zZLZ78B#amN?NA&80Ea|N@Dv7Kzd?xsw|g|c<*GR-bk<=={MjW<_#+hZ8)!T!$o

j#B6Hf#cR{Cagc}s_R%RG;O>fOcLpW!-_n>I&y{BWQ z&nl1kgc%&X;4r}qPw9Tgxh>wKFo8^0*pf(nHZVATqB@{aY+D3MW5oNRI&J-!CFvyX z;%WZ^Jvs7zpWIOH#wr)twid0&(Q*0i5#R)r3)86F!m*v&0+cHYDcQN@&xrV8cVAPs zU($l{W!VPmwo^lhrft{KkAVu2j~1!yvloIdC(aY#`v>d>|9`QHPJMwt|ueAFu;e zz=0p6WEAEV(D*vcJMzZEr1ofa?1E%b90{$)5mB%b912sgzHB|E*ls20gJ9R2Suq5l z0046VDqMbz@&vD2Mib0cuiRnqsMc_w6R?h%RVehfs~Lv4@*O?WB|!ey#8gnuyyDmi z-aS(5K>Ln#gFl*Y4>TI@bXh8d)mp=Z94-bxyqa5v+$q0OqQ6g19|i&=1P7^rIj60( zK0a{6qep0N_YhYA$boN-a~&hR-|$;*bEGMC4uW$7wUA@{L3qP`Hr*Xat%t+?ahhO>kBu2&dtTdb6-ONneKOC`l`(&^xMGB z@nwwa00cKbaK7itV6!ZoRI3Jky~pO8@GX2cnzd6{6XzBw zrN&rbpz>sp4lQ@Wt6@0|KDYpK1e2q}eo;=UdH=5XEms=jr~6rGR%-q>JgM!}lR})o ze#o|YSZ+60;DT_u!jU!Z;knbG8fqrzTm{JAN@}2^CFs{RKDWg8^^0+Vept3>q!2Qo z@VN;`EK}yG;KRq{5K+9G$J;YhKiRf+{p8u2f?08`rh5z<$*$O6i=5f5w;)r+-uH8z z@7L!cIB(HiB0}>Dy+FO=6_m?1xsYR&gefC?Z1QDbNuJm4ali-_@;X;9HS_NY+Bt)RQnG9oMxLv`~ z+@Aas?wR&dD!uTw=?=-_mcS^;T>L+`1Sj=;VSCttlp11nixy{-coO+L*mENXbw1D~ zUash)%9`r`c+3~im;A4afdx0pMVD3H&G)01*Qk zIDBFWU(TH-*4de#<5y{}}pBxxq%`=%lBipoKnqUmBqzo&5pU}wEJ3Pa+!rp zU0OW~SD$GrZi8|%LUVqk7*6lk8Ltq1wVZRrco^&buis)4=P9|>hbnc@ev|3C3r%@f zhOkb7l*j|#zGy_v_AtiK@ZZ|v;iGBB$WHCe&83=WZ!P3Tz1HXN-SwDbN?6KTjAQG{ zN(L4<3QXlwo^%_rK{=5cwfT!r7|n@xj#EQsB_r6c*8UwW6V#QBV(^zdGOxguSEKW@ z_sw)IxOZy{2qZ)z9L4$TIFY1vT*BWNAfJtX7>Mhtz6o6Y_xUKoUhTLz-LacX__)r2dfw$!OuuqW$;FB2HHOHk3#Ee9~F-Dv!EU$rA)pq?Zoaa z2moKh;7~+ZE`cEd&K39!DxV{<)R}U2j56jRJN%#;*zW;U0&z9ZXC0;_>ojK^8tX?b zK*%SAmYXNPe2qwhub>NKD@aC|(8Eto0-8Ue%kFEO<);Fish~HKO>b?xYzGwuU*0|X zh$-y4*4z!2xiyA>B$B${@<~PnYn*T#Y{y1s+_q~S1kEAAuYM(n8v16ZqC;9c+J*Ki zF969vF^Rw>9AytuVVZx&L{=RA-hv5i$aGphV)bwPQCY<^-eKMBe9eFK@`pZ`+%t0q zz5Ko1pAN5QT8u0Fsc09k3Etiuy+7XlMV0T?#A0J7sc`b1`kp*}4L3iPz!3#uK-zvT zviisQ)#Xb?+jgQ}Efc0~1>QBy>|IUl_{76#elqM&Q@0*@5vZ|t_VjxHu9nS`oMy(d z!zT|Cw18{PPK*gmj8eJg#H8cP(#Jumc6J)d#hS8%^`hvM5A*CaFHY5MFUJtcf0TKq z&ZaDG%)b|flLR?8s70Ukf@n!g98Ub1FVk|#N|0QS9abDKih);Qcq}U7Imv%sugihR zto$FK$bbomAsu)l__%{yBCUQ95LX)cv_-4p@|V3d!W@iS0$50Js=zH2o4$sTwo_nu zyBdy^cw$?WVaqJ3{l8Puu*0zSAl1>OmPKn^InhVf*XYM})&@8vXH00?#kMMOrwF$z zEAoad_$W zmY5LDsF3J#2$Lbf3@Wm?#-up=yqW>QB(D6blU8W$MOeH#AOps%05S}iDkGP_+`zS> zny)FREoDQb;K^eiZNDD!#=R3g+JW5mU(#-VmF<_HO`!C9;De?d(+BgC25Q>FG}uhf z^uMd7%O5s>+234cUMZHe{+v)Q{8xFpU%~%Zj*6;T6OWN`i>-N|J+go*@o?wtSm}w# zkM<`|lK;BD?X4e-8?6wrc}MD&c|X*|PIdpiBldbJXw5KKxGxBGeuL3=P){DErOFOl z?{ZD5KPbg2W~e|)7bQ)$I@jJxSonNk#jpp~=qmFkmTjye`l9OCmqmH(RhLNQwfj2- z60kpb(R_a%Eq^rRT%|m%@A*s5&fdz-%)ba6OT6IY32IB^I3Q zwQ8Ivknd*i ze5B@{{7uF;n~diEx9v!+nNLpG^}bdFoY(OnlnM|#(XkTGC*#gx^|<;2WM!wAjiDn% zYrSoE`9`15f3_XfmB6`9fAV^Y?VV$(PETXB?!YGew(LZpYYV{94u<-rM z@(YMz{b39ff6mCF6js207&;!g?PI1E^jIKauSLC(d!G)Q>09%6)r_9Fq;$HUd`o__ zBXeF2ZMXVvmah>S$jVH`;Z!cR!Wq}v+B$J{X)z`8;^3uGW&$*$+^TQJ z4bmI42BuDR071~fE5HqUPzhL`z1Is4V%j~tEJ_P6l07BfbiYDKWz(spu5d?%&YJ}KN` zhgj9uADhb2U5;IOb$0O~p!aAf8S67CMWbcP) zBa9weXVtyXS|H^1;L8#gbZ(B?0o*Qh8D`*S&_~*-AZ)v1^Iw+?_SVc|74ppm__G=L zbaoe3?UadFF4ch#7wRG|UpEV`3J(*n3YT;+_0BlPc+wiSd?t|J(!qBIZ>ikN?D-@8Xl4EfE_86IedNCZTduPfdf5j zpgNlJ&4@`(f#u>T=&G9UPcZE)5*in|{i9Vy>hbpL9A%p8aN&awQ6cNX&}#s*->0zW z3&@zfH(j)`Yp}W(-=(=1bpBGyw36=w%ErVqNtEDx}&>>$lXE4 zp-veIT=cV{#1{ujK11MGVYhX!gCgNIO?)>-#=6UjUdc15JZgQ2Eda~ z(PFNEI~B^LScQuGT~9V20|tIeWp7ctPm0=Qixk3M(efuwJILszVVp%no&_$)Ba#Ea z+p@HO`_|Ro{5f0xcoUZN>`G1Tdu3um1@9B!Nd9UUO*_`s;J3bNaGbixm;G#VRIw_- z=d>Fe?;GL;o=iTH?ZNDeK!ak1557f(EXH5AxIvI9q-#OUn5y$bg*qx!CZURk*d9pb z*j6Wy;an+^>NdRu(^bH-c>ZO1@ieq|LDx)(4QU|TLZM_h)iPJ1_(ZY9w zA$2-3VXaKXYUC(rtQU;!qFxhl#dC+Cm_T@y9waCe(43rVhL4sV7Ho`7 z)PPwm`!;+wUUM#0%_mMI=lGza*-wc`|ASwuB5BsI)5hPH#Hwz@N0lC~p7!S2_%

Q?@v|n(TMssryEK&Y3}!Q{^rVN3yd=F8x5iCJh1i4sX)^pM zkX;LU_Wm^p5aP%MZHzosC=<*K?BM}e+z#GSo376e$m2nUEdVn|6u+elMMC~Y8IFy#?bjw%QR({<_txB`1*8kThI*V;b!DhvoR{7Ku#Th%fm7H~%86Lg$>w2&C;LH^_)vEPO z?E1A7|6fvIB<}Gk1N^t-llSw*1BAT=If4Ue>%8o90!_Nqm<08(W)M70H{*hdT_DD@ zaiK4ebU78c%va%ZV9>RMhHqK`M~3mbC~S;X@H>_Mm+XBX5^UL3Kg4xon14vr4RRcy zR0^@3hGRwy`GI#3ArQ6`5uf9b@mgEBLt-H$PphoLvzDgPZC0t?WE#Zbz#oupho!#5 z;htg4CMNbW5zW{LgH^#3x&z*UwUWyk9TDk2kZHmeW!O7~f9}`~N+$`sHT_%GO8Sx} zC=zl;TXFPFcTpR3$?0yO-dD7!GF>lSD06wAOIrJ{#DuB*K>m#9=h(}I9iM%%tKDa* z5Tr0lK6&`^=$1q9E0OuxeAIql_RJpqPj3@aD!;GG;GPQ$&C#)ac%utw$5W2bfn@Z0 z{&e7c`o^vt-%$})Hg>#*Y(ceNnwh44-__dNF8p(kJHjR#VCR=OlAwqMc}OCa6TXA+ z9@_FC)lp;j@WvJ4!S||^a<5*p%Es7t8j4}?igJakW5s7kEFV432I?VGZK|jGCCw8q z@5CLySSPeED>!qI1+?BK1sXl?q7u=Ou=1#^ttt#XumaM^Pc9ls>>m${dh@Zv1lIQM z0h(_Q3ETJLiMZrKt%Ltj0l^@g9-`$C$}?ZD7Vwh%%WotiQm)B*aevR{))2lkAFEPM z@&|wxLQJlTa>uEH3_(||!exdRT>t}S3{96Mmv=tT-G^G|U>KBFeNU{F@N(o3$YCou z;|3GrHGDMT7REG|@>zC6N(h8v-`>R^UKOW19r(1BrE4axm-_6N?F;X8T{Ea&s@5;G zj<=((DXapH-&ptzQ}a|Mi#tJRmYk5~vzRV)`svgBu>Nje2vV_R(pi zVyI!QVYfTV|5+*+c^@U8a`M(wL58GDbpk=VKJ~#bnWA)YZ$VH_{A8K0l=zE>ekSU|*N1 zD~#+@GAo1@#6%XvLhZoMWmC5$DmlM#;}{eWLurOIa<`T!zW|~jaRdn4ey^Su$w6_t za6ymwq;A1@>_1z?UH@`w<-iw_>}^n-BydfL`3P!3v@lgBE>|?DZVq1<@yZFTeq%AS z_tl;BY{D`%a7CHr0ES5&G7Vc4` z)vSL7Qa|Mv*fcscMa8`kh^1We;mJz?k^>ZuN*~5`fA@B+)G=)s)^FmE9e889zkKw% zMB+pJlLXCQwjrsitG3J>)(iyw4(A|vf|Ny1LQ$Nf4HPtLT;1?hQls#g%n|ZaOAsXs z_&}!cEi<(cURkqh_^#+qhs+LPDq5@pDT^>t*Mf{ZoUy0pRZkDhEDYl9^`_;@C2H?JwKO2kn?e52sEhL zE$NUtt;>u|=8-ynwr-{Fk-$tBsLZojyF%@ zp3bo?71K{G5^GD7rD^OEI*b-%*yYu>f!ySm(myY042pwBk|%d0py9fH;iRd2DYu<& zG3*IP@nDEC2s{npG~E*FkX8I4%hye)?W2z2bvai#ZgLsA+}tOhy;um@ci~KFw==`D zGRkfc>RuF8SgoK960rp>$%*GBTgqs1qnQ6&7@@bcBR^0NOnsrdrA@yuVHi(-0s4+K z8N%8oYuAXTk5BiwlV9u$OLWrV0(xltXR$WU{EIo}ZI$s$5&q8*EQEVV}_6pkG; zK+gEp%or_vJ~>stNCOqOLt(5zK;d6H!T6B76K3d-wk11k3<9f96Gjv8;Yx)`#9)0O z<*xBd9u>4@GD<%`-1t)-4cL^>3xqtITO>1QaTjP)8V;Z+6(F!S6W?y;g9(Isn@Mdq zkK^0iH+uT-9+Mj@&D0%BCRD|L-6pjZK@9=o`}jh5vExDl`n6U0#Jm;a#zU_ad8^=7 z@})R`-L4%$nwrEyc2~Id0(I$+G#HK1SYc$~ zsM8|dCb&>>^I%~pRTyfHkBip*%?vEK0qSyX7rp+#or&U`&db*$mJs_*RP-C8yw1wK@VeT&mFz^(s!6Y`5yL$Wnf|d%d&K$yQX&p-O z`ymREjSB;Pg1_bP355JtLAbT;-$RKtbJOrOcCBT$^xBS0`~?jLtxOQiLjK{2h=Q1` z>~-;1f+rUD-K_l<`$gNsQYJNy>%gOmUSIN8=ATweIlZ=;;d;^XYCg1>zfKWi9=7}} z-Y@~Myo)NWd(KUhMrOGt%A=htfbOeBi#oEn6R0?LvhzepC^57rT zcp`>R=QQ$G5i{C9HerOHrJvnV;KJBKe^)yJ&;SW#6Axyvuj=Lrx@05?lknTN2xw+F z!Ky`L@F3=^xlKMYa_WU&i&qK@ zubHi~s_*nm?27c$^M3M_5aP0`KMD*bS-em5JZ%g8Dx-e={8MH}HLnw`mxY4~@lG4S zO7yu>2O2A=H}38kXe85s^nU!)SIG3L9eE&-@Z=uOHnbNB|4|@CUsVwu988g;N|959 zkFf(X0cX6Qd_N+LCgc5LhR$O)G{$h0Oxm+{oXBLK0bQ9fan*aO96Z2nT1?U?fI+8_ z&!sG>NF(ts?H_cX2xy#EiWL(E72*J9gi+g7HvB&jZ#}AQwqX#%rtMF?{Pl;?!~rsm zVKd<;erl97)vaD(UP;UkvTc>sQr*(M4EW*~`n$0f&yMv3ZR9^(-D9YHso&^-hf^W* z^Gm-G+fq>9PDt5WBV!}6Kx*jDikz)Th>hfPc(&1wD8r$at=WHYnIp9^oa(=f=$H+g z(<{Q99|tTbD&A@a3>Uxzat5kdqNJ=s@dXm+yKt1D$|nx#k;N`Lhj&%rst_RvW~UF) zPjA@CSC{5(`Jx3p48)0Ns4!_-vRikY8CJbgW6u#<$zs@+I0^C#qjqUjihMNxkdu%5 zudfoXkL+K9k1hdDF2}7l=6Kl@fyYJ`D#thHm~O<1+>}lAl1*Y|St$D3IooEbjTgEUFu?B<+%@@c-PuC<}f^9a7i0lug<&EZ+Oh7_zNVjgpLW3H15AD?ON)b zh9}8CfzFTFV#GAhvvtt15elrR!0C4|XN`3b&RVhXqmR{1bHSB~r(ea78=-qBjf{Ld zb?e`Jj#FYfTi@+fm_>Sxx$b|9&{Cm>R|^qn9BMS0>kJ3>gZK!lvdTU~%OiDR_jroW z0}A=PgAY{xcmeh*!pR0tFT8sANW0eayw7v$mqmEWE92g7z3!{}6H#0?c!@}Sv@@!p z_8|8j??=Bams=Zrt~%YLy44o6FXY8KP?3B|+}h4RZ!T@i$-u|9`{$634<~m>9VjrB z=W;$FtF=js5*?m_xF-=aSETb4D8zszjfb!L8-s;&*H^FWMnNN9nW?Za}={?%QI=D5xND3t@NWodu4AlhYBdugeN>kR}!Vz9`#;Xq_f& z@_NCR;z4+9pSsZ>4jh*%(TXJx$-lc4A0P99g{en++h5#dUvI3wEkhirb?F%K?e()C zO&;uSe9NK!`C@JANLwEfvOnW+zD+JGMji&->Lv7xKb=!o7yMz{ESGxTTt*(ZmvM$A zF=s{I=F3pxKZSIlO!oa046e&aFz$z|@#@|t9Q>Ow?g7nQtiF_PXJD&{ZJzu4zw0_K zZ%|D|YUFxTD{O;1eh#0+^G4PQL87d(PEQU*$%JvwLg|RiyF?GTLVK-DCtr)F?A_+V z!FKu9EIb9?DK7$T>xST5eD{%seDU?FY6)EG!aV4}6qF&U6=iq_(qBCYP1mC6VL+{7 z{w#2C^%H+90U=T%Db6OF)&N#l>wFEwGBr>kOwq+oVKSgK%bUfl9Y!G2@H=^3)%A@l zp!InKI_HG1Z$EebN1=NKo8wtKUS!&>a4F&_*uq$@w7FYB_S7UX@GT>wzOcY+tGC#` zu4k0~nl!_p>}^%ZiiI}0b#bXxw)uwscMWR>a(ef2QhkuY;{m<`+mxU1j~HGK-Is#a zFYWiJHw*7ddlsp3ue_9u-4NF5Pdlb;*<{klKrnDidXPnop>tH9T3_;&M(5Cmzu7}P zNlwRa($Cuq`3$Zwo#o`IJ#4H@I&p;1c54%JGX^@pGat z6Atcws)In>y{qk=-hSTynxjEN^YxUpx@XsmtOwK2ObwDg8#&$X6M75{a{AeCKHmyl zotWE`PEH~zp8CJGe4sWGN%4QtFSObhoL6V&oNYV@jys-)EXa`iCIql$k zzmHq@rSyMFKgiUzBnsh~E(#BHQ_0{uCK@Xgh!GYce9p^{vJKI5mwfI`b)Z(>TBG=Ge(h05+DOMN01k-Vomng8NZ6TMeCrM=>)HC=>&g@#F88}5BPwlZgoIfUbGY= zx{gDc>=kubeLHl8S^$;u2eiL+pi~2s_aurjiWDLFBJe8 z$#;^qV_(w8fO=mSYTXp>x;>hWQ7je4;Ubb^Cx2}L5H3<49aBQcu#^}3jYsWtJYti-k zQB@8L@QoM!tzFCSd>h@+{`mZy36kt^A{JCK5~-EclRC{fU%6Jl%9ZVXgihpqW{*!} z(41RG^TH!65skJ?5cNMP220*b?#Gle9SWkGYQd$pZ(gK!G{=Pfb)B#hQ@v0Z6H(OU zF=zX{WAsUPVq++23w zAdy{B^?t7!_{~7g>5C?e*9@`QY@r66;2WbkDgeKBEmaD0jfo=!E#0;^om{6akWwe_*?8d|eArVsQlOO?QMp zI3XcHBQXLs4cLLx?pQ|R({D#zrFYXd|3WVqI;~9K#z;Qk+u*nXG)Knvi_nTSJd!r5 zMB8zf?0I2dzl3FUTdW+R_Ly;ST-^j;+(iGhMpLmW34a{}rl?aDOK54maE*U5r>}W`{L*`k zx>RkF4k3Ac4|7YSl}u7rG_o(_4-KT*cMgtyw#2>ZI4U|5qyrlQmU1YTwqkB?Sh~_B zig^9VOt7Nj^c`**<#UV=f#q;9V|0N;kOm+$%rI$r%ai=-S@;VMN6-e+gkFtklzkSl zwJB7RlIGQH26muA&%;`evD&=M8%{|b*IbrYH($$?ZgSM+scxk=LHYX}*hjfh?U@D^ zG85CKtxDs8PFISKrM7V0R)q}My1Ln>M(Gi}epSb#=|Yts^|g8AzSe{*o4zz*vVrER z9-68`E|5Qln6G&COyba1>hPy(M9j;3PSWGVI($?DnHw&JDm9|_=)MTDodvkwM}}c& z?Be+LQbG47rw@0GoQn|c|7~rd$7`k;g z#{Z;kpz3}})v_-{))q9@7GX*j{Vz$!Cw~XjwZOB5!Fdu={(MV~hO?ja86Etb;h-uC zA%6>nKWB4bSS4zUSA{!0NI^OXqlz;M-_#+?oBYN{ILbt9=nDF>prb(NB*#7Q-nnX6 zrZ%m*Q2lk#dk#N1=WrsYFaxE(!2O*HhuN>n(`arfTeI`m5n#-L z3t)%f=Oxc)9NyCA4V~MqOJA$qQ+6&VsPw5EHyDYR>gkwYEwp*RW5?e(3%QHZ1N1?+ zGD5U{;5jy8Pp85FU!t@bH<4~FOut4?3PJ0Y_>&B231y^G!|wI1durCr zlynA^3FXonb)}V$T9YqMeuw;E!}iepj8TLc3+03OYJm{Xt!C|1vIV{w?qBPw$sE2J z9F1d~;(|}|5e=7^<(Ug5l8QPI$)iB~SYqe>N{~lGu*QGX5zBuY^DL94{4I1$x2_oU zP+)p-DsCma-P=4fjTk^!`L1e|mZm)rv)%bfzevobj*p@N^Z`SV>YY#E52c+FX*> zN5@4I@6LYawvBBgyqlS)Hzgr$aJO7{Caji$HU;~3XHE_+6_dMV-a?ma>B(e`NSkb5 z*ZRffbAoqWyK)j7$%Asc|0LdY@PM$&{UxMfd?195hF6aR7mGq#B!Z1(;OQsP8Fm`= zPkbt^&J9}Ry{-wptEOSUFK8MKm8u7M1Z-*h@dln4xZCduzA=tYpLoahvKeV*r}F27 zs<37Q+*ehRoE1sT^Uyc)ThxS627k;l-;5n&a;nm{Mk0qcqdP;$Qz=9~e^H>@LN#wN z73s#p`4g&(ciMP6J4JUxDNgYvszU;4IeK-;b45ZJQig5&4CN#~@ib>;t2ocu-qSV;U^?Ua3J>K$_|>0#H< z9OS1?3V##YD9S%Qp_@^#l}(RsD?wvh!@c-D@E+aM>L9%9&)e5%Yp%K6FAIFVOO_Xe z2lDY6)e5EL2DYjsr%*v%mbXV|IuV^WUy|D>KBLIUxC!!6#A1}%OFL8Uc77v$;=NtE zv^7TZCwVgJwIM$yMNt7aU@n6Nc3^;8{iSet-Fd(x zYc>&^SgIC{1BBh5yfhkcnx1igd1AM}2Xw`}+2(m*Y57rtEKkCQR=k9%x;K{}sug$_sTqeX3$HaL za^}(2Ej!ySQ}j_gS8}#4f{CK*MqTxsL*Zb|nfOt^i(KvG1{IFXyi7Pg ztzezDLkxDoj1M=(J6NMTQ+r(D9={L)5V*PS|cL`No7 z|DMI7=AUrzmZEHGpZfho`e^Ccnh`P8*QIi)){%|brm3#EwG4Jr8{5MjBCfXz0(;ibYF_5Xfcy8#SgpEnIsX+t(8I*C&+|-P z<*2JI^C3bk==bgS}?wH@(fea?gn++^_ObQ+Bi?D66)>o?wgk?pS zmuoXcIAt&eYv%y2%yI%fBkldb$&=Ip28rmRE~ji@GNOR7Q-zHb~1 z@a42SJ2~g zIE5r3*Hl$U@A2?ISgl3Zy-G=%7^Jq?CFQBgyiap1QurlAbQsR_+4iyw_q(we)JQ6I z^C8$;=@n>Z#9^v-8ux0PJBoRZTVf@7DOO8CQACnMysK-3ckpG@gEx|q$^)y-GMH?f zbRyCJ30M@T>s9PbB(&q4I35VmQzbWYy5w$I=+DRgq=lUy@{3BTo;X0`sJu9;E>5By z(IJU+ME0#;zkZrU@|SJZ)w$Q`Z=V@BJD;8d;@8Ey`3w+Gk%ApZN@3(u@y0D;%05qu z(-%pxW1$r1E|B7ac~Yu~r2zT>tegqt3@NLgA-)CZe-6?QIF7eBKzq!! zA@#VWiw7?nyj@h^M8GZaTVAj@{<;mo-FEev{YU45c$RoKd7<>Ss!QaUO3REQktBlbBH@!IYv)wS z-ZotvTV{p;IzC_~sxQ?A0VV(#17HMzJ0}2^eSFt&{_2bWy6UsHf`Xk_gjC@N-vjY% z@qTh9h^L8X1BlyBkb>}Iq%h`i@g~wz(-w<2YmsU z%#AZ7YyGSMpyHVd1T7da4!kJv!ok~~;|DDJ^d51nxn5$PzIflSJp3hFU0q6pn}OH8 zcBK@4aIO@5@GZ$-ccysOoi2qNPLaZ`$4g-tfKf+)NIPYEUzAEK&7y_57`Q$2rKoVO z6qn4Fl9HKHV(_L*iH|W8#1gA2OQ_1?s;Ml9rZ~Evq>AXX zLyac(GeHgBZ}F&K5!fdupAZszR;a0A0;La*hK5IZ@T@fPWY0CpiJc)CyCz8%?J+BY z>>}ZSMeHx>T%R5Wrb2GxepFuO=2?=pake>L)fEI@Tc!d{(IjR&wJkx_xoR#f{#v> zf(<81!PetwrAJ9YahqptGZfRFf*=2W)MvHPK_cQZ@Sdjg1#bLBTf- zo*wIxMPC`v=yCA>&F2V zudKB!fM>^s)411OCXP3MX%OANKmYGjefCygpOT_gnE&n%#PjZV_-1EG-rBE9{`;p% z{>LXv{>Bxw(xW9m{BS9VK2!?hX{9L#u_jYQolMLJajq26PKyd=fjLu(ytGh#8AkU- z1k8e>=~7V0g1lg=6nMs8PqQa3cIDao4gfm<>;SL>K>any;7kPR>+9ow9kkaLv$vlx zupt%MZqd5e>I(+U04@W#3|eM}qHPC{wwb;~@uo>StutdifS&^Ru?6UJ7(CtUFC_&> z;nH3?KM=*sdH2%4|9?+jyM6Tv1@ydip19xsuH?Oaw&cD;8-3>t@x1><@qB!Ocs3p@ z9%iNa5r;_ut+bF<>PcP%;zB9NS^(la@iHcQ-K+^cv&5UvnCPME@<{;!)5B$td%AdX zS<|_wMBp^`NmaDqXMWn-Ye+SzBA*Xv!`X;-_1Osq)K;o^!GOVIUHVpqBb&k72;PS2 zlKv_8`vky`0Q_)vpz;*&^8mF16_6_Yj&<7qzMD7p^`|R7yihV&xPP z=SzI^lg0hs@#1E2@7Z<)m3SzK05UW6q%2}_y-++3KVo6-94Q2_5VS(iOeu7;&zsKm zpgE^XUgi{WrLo3Jnqyx{1Q@xhr0sBe;)z<8}>7CtPf4fhG`}lAI~z0*|0DWeepIehjFbu)g-qlJ^*Q_d=nM-&d((O zgI`L~$CopCxp>bvuKYbW0CR%@^WON1eRv#*%f++xa1fV@Cwhr^ z;z6VmJysfIRB@%UmP*oJMgJiXyHBQF!3m26o_#kCi&ZG ze&zzncg&OgoH>&3n$3QeB_4=veT62;~?%EZSx9%7akEES0 z6Hge3ks!uem6%35%~-$$VID1W4rsGEo+X~Fne1l(I9*&R(*T@m05uNB=>{?w&j$3z z53FdqSDcA}_4PR{V?LJ3%1wdjdll^H8&7OF8&Ls+)6od0&z~c%=e`n>oVQOF*LzgrM^xg5FNk~N z5#rvuOx!yU5qHF5af9eiTqN$4h2mDklzHM#o+Eilv&=L1uB4fglQ>hH@iWB{HQLLGs_H0;?@<6 ! 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 U+knB%;s5{u07*qoM6N<$g2OfczW@LL diff --git a/images/raid_eggs/pokemon_icon_99915_00.png b/images/raid_eggs/pokemon_icon_99915_00.png index bd29f0e9ff7e25dea4e2be58895e789cf8e875d7..6e48ded69ce58f3a267f73dd3df9aa9626c50722 100644 GIT binary patch literal 31360 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 T)G>z500000NkvXXu0mjfrBOx5 literal 21144 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 X{&&H Date: Sat, 27 May 2023 11:18:01 +0300 Subject: [PATCH 271/367] Fixed shadow icon logic --- logic/raid_picture.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 241b0340..c5074c61 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -370,7 +370,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Add pokemon to image imagecopyresampled($canvas,$img_pokemon,$dst_x,$dst_y,0,0,$dst_w,$dst_h,$src_w,$src_h); - if(isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['level'], RAID_LEVEL_SHADOW)) { + if(isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['pokemon'], EGGS)) { $img_shadow = grab_img(IMAGES_PATH . '/shadow.png'); $icon_x = 275; imagecopyresampled($canvas,$img_shadow,$icon_x,275,0,0,75,75,55,62); From 89dadc903fed313628747ef070b10a9daa53a3a0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 28 May 2023 15:56:53 +0300 Subject: [PATCH 272/367] Fixed sql upgrade 3 Even though no-one probably needs this anymore --- sql/upgrade/3.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/upgrade/3.sql b/sql/upgrade/3.sql index e16145ea..755e1a54 100644 --- a/sql/upgrade/3.sql +++ b/sql/upgrade/3.sql @@ -4,9 +4,9 @@ CREATE UNIQUE INDEX IF NOT EXISTS `idx_pokemon_pokedex_id_pokemon_form_id` ON `p ALTER TABLE `raids` DROP COLUMN IF EXISTS `first_seen`, -ADD COLUMN IF NOT EXISTS `spawn` DATETIME NULL DEFAULT NULL AFTER `pokemon_form`, MODIFY `pokemon` int(4) DEFAULT NULL, ADD COLUMN IF NOT EXISTS `pokemon_form` int(4) unsigned NOT NULL DEFAULT 0, +ADD COLUMN IF NOT EXISTS `spawn` DATETIME NULL DEFAULT NULL AFTER `pokemon_form`, ADD COLUMN IF NOT EXISTS `level` enum('1','2','3','4','5','6','X') DEFAULT NULL AFTER `gym_id`, ADD COLUMN IF NOT EXISTS `event` int(3) unsigned DEFAULT NULL AFTER `gender`, ADD COLUMN IF NOT EXISTS `event_note` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL AFTER `event`; From 5edd219e9a29032fc86b0f612b1032ff6044ebd9 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 28 May 2023 15:57:38 +0300 Subject: [PATCH 273/367] Fixed php error --- logic/get_pokemon_info.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/get_pokemon_info.php b/logic/get_pokemon_info.php index 340023d4..295d87fe 100644 --- a/logic/get_pokemon_info.php +++ b/logic/get_pokemon_info.php @@ -23,6 +23,6 @@ function get_pokemon_info($pokedex_id, $pokemon_form_id) 'pokemon_form_id' => $pokemon_form_id ]); $result = $query->fetch(); - if($result['raid_level'] == NULL) $result['raid_level'] = 0; + if(is_array($result) && $result['raid_level'] == NULL) $result['raid_level'] = 0; return $result; } From d5b9776c4d71a57755acfe92d6f94e37a12b1d2b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 28 May 2023 15:57:47 +0300 Subject: [PATCH 274/367] Fixed php error --- core/telegram/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/telegram/functions.php b/core/telegram/functions.php index 26d33ba9..f90af8e9 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -807,7 +807,7 @@ function curl_json_multi_request($json) $content = $data['post_contents']; $log_content = $content; if(is_array($content)) { - if(is_object($content['photo']) or isBinary($content['photo']) ) { + if(isset($content['photo']) && is_object($content['photo']) or isBinary($content['photo']) ) { $log_content = array_merge([],$content); $log_content['photo'] = '[binary content]'; } From 43545f59bff20ccf898cf58d42173a8cf6cccd68 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 28 May 2023 16:06:34 +0300 Subject: [PATCH 275/367] Added default value for page --- mods/tutorial.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/tutorial.php b/mods/tutorial.php index 8bb16999..15072224 100644 --- a/mods/tutorial.php +++ b/mods/tutorial.php @@ -13,7 +13,7 @@ if(is_file(ROOT_PATH . '/config/tutorial.php')) { require_once(ROOT_PATH . '/config/tutorial.php'); } -$action = $data['p']; +$action = $data['p'] ?? 1; $user_id = $update['callback_query']['from']['id']; $new_user = new_user($user_id); $tutorial_count = count($tutorial); From 2e4232554cdffb07a289d5b3b844d7831eed8fe7 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 28 May 2023 20:01:43 +0300 Subject: [PATCH 276/367] Fixed shadow egg name --- logic/show_raid_poll.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index ce8b225c..7283ceb2 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -89,7 +89,7 @@ function show_raid_poll($raid, $inline = false) if($raid['event_pokemon_title'] == 1) $title = getPublicTranslation('raid_boss'); elseif($raid['event_pokemon_title'] == 2) $title = getPublicTranslation('featured_pokemon'); else $title = getPublicTranslation('raid_boss'); - $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . ' ' . (isset($raid['shadow']) && $raid['shadow'] ? ' ' . getPublicTranslation('shadow') : '') . '', true); + $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . ' ' . (isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['pokemon'], EGGS) ? ' ' . getPublicTranslation('shadow') : '') . '', true); // Display raid boss weather. $msg = raid_poll_message($msg, ($raid_pokemon_info['weather'] != 0) ? (' ' . get_weather_icons($raid_pokemon_info['weather'])) : '', true); From 8a93540395b844e59c2d32dffc04cac61bae3adc Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 10 Jun 2023 09:40:47 +0300 Subject: [PATCH 277/367] Fixed shadow egg translation --- logic/show_raid_poll_small.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/show_raid_poll_small.php b/logic/show_raid_poll_small.php index 544c8dd9..6e28800e 100644 --- a/logic/show_raid_poll_small.php +++ b/logic/show_raid_poll_small.php @@ -26,7 +26,7 @@ function show_raid_poll_small($raid, $override_language = false) } // Pokemon if(!empty($raid['pokemon'])) { - $msg .= '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . ($raid['shadow'] ? ' ' . getTranslation('shadow') : '') . ' ' . CR; + $msg .= '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . (isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['pokemon'], EGGS) ? ' ' . getPublicTranslation('shadow') : '') . ' ' . CR; } // Start time and end time if(!empty($raid['start_time']) && !empty($raid['end_time'])) { From d69bde9eb390c0233809782a40e88e09905aa776 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 10 Jun 2023 09:43:38 +0300 Subject: [PATCH 278/367] Support for pokebattler shadow raids --- constants.php | 7 +++++-- logic/resolve_boss_name_to_ids.php | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/constants.php b/constants.php index c2d60d9c..f74e85b8 100644 --- a/constants.php +++ b/constants.php @@ -35,7 +35,7 @@ define('RAID_LEVEL_SHADOW', [11, 12, 13, 14, 15]); // Levels available for import at PokeBattler -$pokebattler_levels = array('10', '9', '8', '7', '6', '5', '4', '3', '1'); +$pokebattler_levels = array('15','13','11','10', '9', '8', '7', '6', '5', '4', '3', '1'); // Map our raid levels to tier names PokeBattler uses $pokebattler_level_map = [ @@ -48,6 +48,9 @@ '8' => 'ULTRA_BEAST', '9' => 'ELITE', '10' => 'PRIMAL', + '11' => '1_SHADOW', + '13' => '3_SHADOW', + '15' => '5_SHADOW', ]; $pokebattler_pokemon_map = [ @@ -60,7 +63,7 @@ define('PRIMAL_MONS', [382, 383]); // Limit the tiers of upcoming raid bosses imported from PokeBattler to legendary and mega -$pokebattler_import_future_tiers = [5, 6, 7, 8, 9, 10]; +$pokebattler_import_future_tiers = [5, 6, 7, 8, 9, 10, 15]; // Default language. defined('DEFAULT_LANGUAGE') or define('DEFAULT_LANGUAGE', 'EN'); diff --git a/logic/resolve_boss_name_to_ids.php b/logic/resolve_boss_name_to_ids.php index 14ee7f3a..2b7c9aba 100644 --- a/logic/resolve_boss_name_to_ids.php +++ b/logic/resolve_boss_name_to_ids.php @@ -9,13 +9,16 @@ function resolve_boss_name_to_ids($pokemon_name) { $name = $pokemon_name; $form = 'normal'; // Pokemon name ending with "_FORM" ? - if (preg_match('/(MEGA|MEGA_Y|MEGA_X|PRIMAL|FORM)$/', $pokemon_name)) { + if (preg_match('/(MEGA|MEGA_Y|MEGA_X|PRIMAL|FORM|SHADOW)$/', $pokemon_name)) { debug_log('Pokemon with a special form received: ' . $pokemon_name); // Remove "_FORM" $pokemon = str_replace('_FORM', '', $pokemon_name); // Get pokemon name and form. [$name, $form] = explode("_", $pokemon, 2); + + // Pokebattler uses different forms for shadow pokemon so we'll just convert those to normal + if($form == 'SHADOW') $form = 'normal'; } // Get ID and form name used internally. debug_log('Getting dex id and form for pokemon ' . $name . ' with form ' . $form); From 0d0c07fae1af8afee12b3f29057480386c5d2d74 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 12 Jun 2023 17:38:42 +0300 Subject: [PATCH 279/367] Fixed Google Maps links --- logic/mapslink.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/logic/mapslink.php b/logic/mapslink.php index f7c1f681..ad4ad728 100644 --- a/logic/mapslink.php +++ b/logic/mapslink.php @@ -21,7 +21,7 @@ function mapslink($gym, $gym_address = '0'){ switch ($gym_address) { case '1': //using gym address as maps link - $gym['address'] = 'https://maps.google.com/?daddr=' . $gym['lat'] . ',' . $gym['lon']; + $gym['address'] = 'https://maps.google.com/?daddr=' . $gym['lat'] . '%2C' . $gym['lon']; break; case '0': // do nothing -> getting default address from gym/raid @@ -33,10 +33,10 @@ function mapslink($gym, $gym_address = '0'){ if($maps_route){ // getting link for route calculation - $maps_link = '' . $gym['address'] . ''; + $maps_link = '' . $gym['address'] . ''; }else{ // getting link for normal maps point - $maps_link = '' . $gym['address'] . ''; + $maps_link = '' . $gym['address'] . ''; } // returning Maps Link From 6d87a1dc0356787fb6e013b1b175c2878f357ee7 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 6 Sep 2023 08:35:40 +0300 Subject: [PATCH 280/367] Fixed Unown raidpicture --- logic/raid_picture.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index c5074c61..8436ee67 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -275,7 +275,9 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $uicons_icon = $raid['pokemon']; if($raid['pokemon_form_name'] != 'normal') { - $addressable_icon .= '.f'.strtoupper($raid['pokemon_form_name']); + $addrFormPrefix = ''; + if($raid['pokemon'] == 201) $addrFormPrefix = 'UNOWN_'; + $addressable_icon .= '.f' . $addrFormPrefix . strtoupper($raid['pokemon_form_name']); $uicons_icon .= '_f'.$raid['pokemon_form']; } From 2f15aade54df05dcc2e86d417a148fb423fc09fd Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 6 Sep 2023 10:25:39 +0300 Subject: [PATCH 281/367] New translations --- lang/pokemon.json | 1 - lang/pokemon_moves.json | 29 ++++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lang/pokemon.json b/lang/pokemon.json index 94c757b4..2113585a 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -4144,7 +4144,6 @@ "RU": "Орикорио" }, "pokemon_id_742": { - "PT-BR": "Fofinho", "EN": "Cutiefly", "FR": "Bombydou", "DE": "Wommel", diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index 1fd6f4f8..f5970dc1 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -2784,7 +2784,7 @@ "FR": "Abattage", "DE": "Breitseite", "IT": "Vastoimpatto", - "RU": "ломающий удар", + "RU": "Разбивающий Удар", "ES": "Vasto Impacto" }, "pokemon_move_380": { @@ -2804,5 +2804,32 @@ "IT": "Pugni Corazzati", "RU": "Двойной Стальной Таран", "ES": "Ferropuño Doble" + }, + "pokemon_move_382": { + "PT-BR": "Fogo Místico", + "EN": "Mystical Fire", + "FR": "Feu Ensorcelé", + "DE": "Magieflamme", + "IT": "Magifiamma", + "RU": "Мистический Огонь", + "ES": "Llama Embrujada" + }, + "pokemon_move_383": { + "PT-BR": "Aquaríete", + "EN": "Liquidation", + "FR": "Aqua-Brèche", + "DE": "Aquadurchstoß", + "IT": "Idrobreccia", + "RU": "Ликвидация", + "ES": "Hidroariete" + }, + "pokemon_move_385": { + "PT-BR": "Folhagem", + "EN": "Leafage", + "FR": "Feuillage", + "DE": "Blattwerk", + "IT": "Fogliame", + "RU": "Облиствление", + "ES": "Follaje" } } \ No newline at end of file From ae1c1f108a49930bed123e26fcc28a0616c36a00 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 6 Sep 2023 10:27:49 +0300 Subject: [PATCH 282/367] Removed TRAINER_BUTTONS_TOGGLE Behavior is now the same as if the toggle was on. It wasn't really working and everyone probably has the toggle on anyway. --- config/defaults-config.json | 1 - docs/config.rst | 4 ---- logic/keys_trainerinfo.php | 4 ++-- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/config/defaults-config.json b/config/defaults-config.json index af1db0c0..deb15239 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -97,7 +97,6 @@ "RAID_CREATION_EX_GYM_MARKER": true, "UPGRADE_SQL_AUTO": true, "TRAINER_MAX_LEVEL":"50", - "TRAINER_BUTTONS_TOGGLE": false, "TRAINER_CHATS":"", "SHARE_CHATS":"", "SHARE_CHATS_LEVEL_X":"", diff --git a/docs/config.rst b/docs/config.rst index 05893464..e692c459 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -467,8 +467,6 @@ The command '/trainer' allows users of the bot to change their trainer data like With ``TRAINER_CHATS`` you can specify additional chats which should appear as buttons too for sharing the trainer message. -Set ``TRAINER_BUTTONS_TOGGLE`` to true to enable the toggle which shows/hides the team and level+/- buttons under the trainer message. To disable the toggle button and always show the team and level+/- buttons set it to false. - Add additional chats -100999555111 and -100888444222 to share the trainer message ``"TRAINER_CHATS":"-100999555111,-100888444222"`` @@ -1098,8 +1096,6 @@ Config reference - Timezone definition to use as per `TZ database names `_ * - TRAINER_MAX_LEVEL - Int, Maximum level a trainer can be (currently 50) - * - TRAINER_BUTTONS_TOGGLE - - Bool, true to show/hide the team and level+/- buttons below the trainer data setup messages once a users hits the "trainer info" button. False to always show the team and level+/- buttons. * - TRAINER_CHATS - List of chats where trainer data setup messages can be shared * - UPGRADE_SQL_AUTO diff --git a/logic/keys_trainerinfo.php b/logic/keys_trainerinfo.php index 39644437..4bf93c11 100644 --- a/logic/keys_trainerinfo.php +++ b/logic/keys_trainerinfo.php @@ -9,13 +9,13 @@ function keys_trainerinfo($show = false) global $config; // Toggle state. $status = 'show'; - if(!$show || $config->TRAINER_BUTTONS_TOGGLE) { + if(!$show) { // Key to show/hide trainer info. $keys[][] = button(getPublicTranslation('trainerinfo'), ['vote_level', 'a' => 'trainer', 's' => $status]); return $keys; } // Always show buttons? - if(($show == true && !$config->TRAINER_BUTTONS_TOGGLE) || $config->TRAINER_BUTTONS_TOGGLE) { + if($show == true) { $status = 'hide'; } From f172c9108b8e81ecf0bbae3c64bfda97be1cbdb6 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 15 Sep 2023 16:50:21 +0300 Subject: [PATCH 283/367] Fixed getTranslations.php Pokeminers is shutting down so the old source no longer works. Added new source and fixed the parsing --- getTranslations.php | 69 ++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/getTranslations.php b/getTranslations.php index 5c340fa2..d89ef533 100644 --- a/getTranslations.php +++ b/getTranslations.php @@ -1,30 +1,30 @@ ['PT-BR'], - 'English' => ['EN'], - 'French' => ['FR'], - 'German' => ['DE'], - 'Italian' => ['IT'], - 'Russian' => ['RU'], - 'Spanish' => ['ES'], + 'brazilianportuguese' => ['PT-BR'], + 'english' => ['EN'], + 'french' => ['FR'], + 'german' => ['DE'], + 'italian' => ['IT'], + 'russian' => ['RU'], + 'spanish' => ['ES'], ]; $move_translations_to_fetch = [ - 'BrazilianPortuguese' => ['PT-BR'], - 'English' => ['EN', 'FI', 'NL', 'NO', 'PL'], - 'French' => ['FR'], - 'German' => ['DE'], - 'Italian' => ['IT'], - 'Russian' => ['RU'], - 'Spanish' => ['ES'], + 'brazilianportuguese' => ['PT-BR'], + 'english' => ['EN', 'FI', 'NL', 'NO', 'PL'], + 'french' => ['FR'], + 'german' => ['DE'], + 'italian' => ['IT'], + 'russian' => ['RU'], + 'spanish' => ['ES'], ]; // Initialize array @@ -40,6 +40,35 @@ if( !$write_pokemon_translation && !$write_move_translation ) { continue; } + $file = curl_open_file('https://raw.githubusercontent.com/PokeMiners/pogo_assets/master/Texts/Latest%20APK/JSON/i18n_'. $language. '.json'); + $translation = json_decode($file, true); + $title = true; + foreach($translation['data'] as $row) { + // Handle resource ID rows + if($title) { + $resource_part = explode('_',$row); + // Only proceed to processing translation if it's pokemon/move name and it isn't a mega pokemon name + if(count($resource_part) == 3 && $resource_part[1] == 'name') { + $title = false; + } + continue; + } + // Handle text rows + $id = intval($resource_part[2]); // remove leading zeroes + // Save pokemon names into an array if pokemon id is larger than 0 + if($write_pokemon_translation && $resource_part[0] == 'pokemon' && $id > 0) { + foreach($pokemon_translations_to_fetch[$language] as $lan) { + $pokemon_array['pokemon_id_'.$id][$lan] = $row; + } + // Save pokemon moves into an array + }elseif($write_move_translation && $resource_part[0] == 'move') { + foreach($move_translations_to_fetch[$language] as $lan) { + $move_array['pokemon_move_'.$id][$lan] = $row; + } + } + $title = true; + } + /* // Open the file(s) and write it into an array foreach($lang_directory_url as $url) { $file = curl_open_file($url . $language . '.txt'); @@ -76,7 +105,7 @@ } unset($file); unset($data); - } + }*/ } // Bot defaults to using english translations, so no need to add duplicates for every language $pokemon_array = remove_duplicate_translations($pokemon_array); From 632242cf649dd5a4bd89e1e0ad210d2e653dd2c5 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 15 Sep 2023 16:51:09 +0300 Subject: [PATCH 284/367] New translations --- lang/pokemon.json | 305 +++++++++++++++++++++++++++++++++++++++- lang/pokemon_moves.json | 48 +++++++ 2 files changed, 352 insertions(+), 1 deletion(-) diff --git a/lang/pokemon.json b/lang/pokemon.json index 2113585a..1f5150fe 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -2938,7 +2938,7 @@ "EN": "Conkeldurr", "FR": "Bétochef", "DE": "Meistagrif", - "RU": "Конкельдар" + "RU": "Конкельдар\r\n" }, "pokemon_id_535": { "EN": "Tympole", @@ -5109,5 +5109,308 @@ "FR": "Gromago", "DE": "Monetigo", "RU": "Голденго" + }, + "pokemon_id_906": { + "EN": "Sprigatito" + }, + "pokemon_id_907": { + "EN": "Floragato" + }, + "pokemon_id_908": { + "EN": "Meowscarada" + }, + "pokemon_id_909": { + "EN": "Fuecoco" + }, + "pokemon_id_910": { + "EN": "Crocalor" + }, + "pokemon_id_911": { + "EN": "Skeledirge" + }, + "pokemon_id_912": { + "EN": "Quaxly" + }, + "pokemon_id_913": { + "EN": "Quaxwell" + }, + "pokemon_id_914": { + "EN": "Quaquaval" + }, + "pokemon_id_915": { + "EN": "Lechonk" + }, + "pokemon_id_916": { + "EN": "Oinkologne" + }, + "pokemon_id_917": { + "EN": "Tarountula" + }, + "pokemon_id_918": { + "EN": "Spidops" + }, + "pokemon_id_919": { + "EN": "Nymble" + }, + "pokemon_id_920": { + "EN": "Lokix" + }, + "pokemon_id_921": { + "EN": "Pawmi" + }, + "pokemon_id_922": { + "EN": "Pawmo" + }, + "pokemon_id_923": { + "EN": "Pawmot" + }, + "pokemon_id_924": { + "EN": "Tandemaus" + }, + "pokemon_id_925": { + "EN": "Maushold" + }, + "pokemon_id_926": { + "EN": "Fidough" + }, + "pokemon_id_927": { + "EN": "Dachsbun" + }, + "pokemon_id_928": { + "EN": "Smoliv" + }, + "pokemon_id_929": { + "EN": "Dolliv" + }, + "pokemon_id_930": { + "EN": "Arboliva" + }, + "pokemon_id_931": { + "EN": "Squawkabilly" + }, + "pokemon_id_932": { + "EN": "Nacli" + }, + "pokemon_id_933": { + "EN": "Naclstack" + }, + "pokemon_id_934": { + "EN": "Garganacl" + }, + "pokemon_id_935": { + "EN": "Charcadet" + }, + "pokemon_id_936": { + "EN": "Armarouge" + }, + "pokemon_id_937": { + "EN": "Ceruledge" + }, + "pokemon_id_938": { + "EN": "Tadbulb" + }, + "pokemon_id_939": { + "EN": "Bellibolt" + }, + "pokemon_id_940": { + "EN": "Wattrel" + }, + "pokemon_id_941": { + "EN": "Kilowattrel" + }, + "pokemon_id_942": { + "EN": "Maschiff" + }, + "pokemon_id_943": { + "EN": "Mabosstiff" + }, + "pokemon_id_944": { + "EN": "Shroodle" + }, + "pokemon_id_945": { + "EN": "Grafaiai" + }, + "pokemon_id_946": { + "EN": "Bramblin" + }, + "pokemon_id_947": { + "EN": "Brambleghast" + }, + "pokemon_id_948": { + "EN": "Toedscool" + }, + "pokemon_id_949": { + "EN": "Toedscruel" + }, + "pokemon_id_950": { + "EN": "Klawf" + }, + "pokemon_id_951": { + "EN": "Capsakid" + }, + "pokemon_id_952": { + "EN": "Scovillain" + }, + "pokemon_id_953": { + "EN": "Rellor" + }, + "pokemon_id_954": { + "EN": "Rabsca" + }, + "pokemon_id_955": { + "EN": "Flittle" + }, + "pokemon_id_956": { + "EN": "Espathra" + }, + "pokemon_id_957": { + "EN": "Tinkatink" + }, + "pokemon_id_958": { + "EN": "Tinkatuff" + }, + "pokemon_id_959": { + "EN": "Tinkaton" + }, + "pokemon_id_960": { + "EN": "Wiglett" + }, + "pokemon_id_961": { + "EN": "Wugtrio" + }, + "pokemon_id_962": { + "EN": "Bombirdier" + }, + "pokemon_id_963": { + "EN": "Finizen" + }, + "pokemon_id_964": { + "EN": "Palafin" + }, + "pokemon_id_965": { + "EN": "Varoom" + }, + "pokemon_id_966": { + "EN": "Revavroom" + }, + "pokemon_id_967": { + "EN": "Cyclizar" + }, + "pokemon_id_968": { + "EN": "Orthworm" + }, + "pokemon_id_969": { + "EN": "Glimmet" + }, + "pokemon_id_970": { + "EN": "Glimmora" + }, + "pokemon_id_971": { + "EN": "Greavard" + }, + "pokemon_id_972": { + "EN": "Houndstone" + }, + "pokemon_id_973": { + "EN": "Flamigo" + }, + "pokemon_id_974": { + "EN": "Cetoddle" + }, + "pokemon_id_975": { + "EN": "Cetitan" + }, + "pokemon_id_976": { + "EN": "Veluza" + }, + "pokemon_id_977": { + "EN": "Dondozo" + }, + "pokemon_id_978": { + "EN": "Tatsugiri" + }, + "pokemon_id_979": { + "EN": "Annihilape" + }, + "pokemon_id_980": { + "EN": "Clodsire" + }, + "pokemon_id_981": { + "EN": "Farigiraf" + }, + "pokemon_id_982": { + "EN": "Dudunsparce" + }, + "pokemon_id_983": { + "EN": "Kingambit" + }, + "pokemon_id_984": { + "EN": "Great Tusk" + }, + "pokemon_id_985": { + "EN": "Scream Tail" + }, + "pokemon_id_986": { + "EN": "Brute Bonnet" + }, + "pokemon_id_987": { + "EN": "Flutter Mane" + }, + "pokemon_id_988": { + "EN": "Slither Wing" + }, + "pokemon_id_989": { + "EN": "Sandy Shocks" + }, + "pokemon_id_990": { + "EN": "Iron Treads" + }, + "pokemon_id_991": { + "EN": "Iron Bundle" + }, + "pokemon_id_992": { + "EN": "Iron Hands" + }, + "pokemon_id_993": { + "EN": "Iron Jugulis" + }, + "pokemon_id_994": { + "EN": "Iron Moth" + }, + "pokemon_id_995": { + "EN": "Iron Thorns" + }, + "pokemon_id_996": { + "EN": "Frigibax" + }, + "pokemon_id_997": { + "EN": "Arctibax" + }, + "pokemon_id_998": { + "EN": "Baxcalibur" + }, + "pokemon_id_1001": { + "EN": "Wo-Chien" + }, + "pokemon_id_1002": { + "EN": "Chien-Pao" + }, + "pokemon_id_1003": { + "EN": "Ting-Lu" + }, + "pokemon_id_1004": { + "EN": "Chi-Yu" + }, + "pokemon_id_1005": { + "EN": "Roaring Moon" + }, + "pokemon_id_1006": { + "EN": "Iron Valiant" + }, + "pokemon_id_1007": { + "EN": "Koraidon" + }, + "pokemon_id_1008": { + "EN": "Miraidon" } } \ No newline at end of file diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index f5970dc1..f12f29d8 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -2737,6 +2737,15 @@ "RU": "Метеоритный Луч", "ES": "Rayo Meteórico" }, + "pokemon_move_373": { + "PT-BR": "Estrela Ninja de Água", + "EN": "Water Shuriken", + "FR": "Sheauriken", + "DE": "Wasser-Shuriken", + "IT": "Acqualame", + "RU": "Водяной Сюрикен", + "ES": "Shuriken de Agua" + }, "pokemon_move_374": { "PT-BR": "Raio de Fusão", "EN": "Fusion Bolt", @@ -2831,5 +2840,44 @@ "IT": "Fogliame", "RU": "Облиствление", "ES": "Follaje" + }, + "pokemon_move_386": { + "PT-BR": "Tempestade de Magma", + "EN": "Magma Storm", + "FR": "Vortex Magma", + "DE": "Lavasturm", + "IT": "Magmaclisma", + "RU": "Магма-Буря", + "ES": "Lluvia Ígnea" + }, + "pokemon_move_387": { + "PT-BR": "Geomancia", + "EN": "Geomancy", + "FR": "Géo-Contrôle", + "DE": "Geokontrolle", + "IT": "Geocontrollo", + "RU": "Геомантия", + "ES": "Geocontrol" + }, + "pokemon_move_388": { + "PT-BR": "Laceração Espacial", + "EN": "Spacial Rend", + "FR": "Spatio-Rift", + "DE": "Raumschlag", + "IT": "Fendispazio", + "RU": "Пространственный Разрыв", + "ES": "Corte Vacío" + }, + "pokemon_move_389": { + "PT-BR": "Asa do Esquecimento", + "EN": "Oblivion Wing", + "FR": "Mort-Ailes", + "DE": "Unheilsschwingen", + "IT": "Ali del Fato", + "RU": "Крылья Забвения", + "ES": "Ala Mortífera" + }, + "pokemon_move_384": { + "EN": "Dragon Ascent" } } \ No newline at end of file From 9d092759f0f8ebc5bfcfd0fb5578cc81aac31ea8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 15 Sep 2023 17:52:48 +0300 Subject: [PATCH 285/367] Fixed getdb Nia added some more inconsistencies to forms that needed fixing. Probably will break at some point again --- mods/getdb.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 90048186..888bf67f 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -21,9 +21,9 @@ sendResults('Failed to get protos.', $update, true); } -[$form_ids, $costume] = $protos; +[$form_ids, $form_names, $costume] = $protos; // Parse the game master data together with form ids into format we can use -$pokemon_array = parse_master_into_pokemon_table($form_ids, $game_master_url); +$pokemon_array = parse_master_into_pokemon_table($form_ids, $form_names, $game_master_url); if(!$pokemon_array) { sendResults('Failed to open game master file.', $update, true); } @@ -129,7 +129,7 @@ function get_protos($proto_url) { if(!$proto_file = curl_get_contents($proto_url)) return false; $proto = preg_split('/\r\n|\r|\n/', $proto_file); $count = count($proto); - $form_ids = $costume = array(); + $form_ids = $costume = $form_names = array(); $data_array = false; for($i=0;$i<$count;$i++) { $line = trim($proto[$i]); @@ -147,6 +147,9 @@ function get_protos($proto_url) { $value = explode('"', $data[1]); if(strlen($value[1]) > 0) { ${$data_array}[trim($value[1])] = trim($data[0]); + if($data_array == 'form_ids') { + $form_names[trim($data[0])] = trim($value[1]); + } } continue; } @@ -160,10 +163,10 @@ function get_protos($proto_url) { } } unset($proto); - return [$form_ids, $costume]; + return [$form_ids, $form_names, $costume]; } -function parse_master_into_pokemon_table($form_ids, $game_master_url) { +function parse_master_into_pokemon_table($form_ids, $form_names, $game_master_url) { // Set ID's for mega evolutions // Using negative to prevent mixup with actual form ID's // Collected from pogoprotos (hoping they won't change, so hard coding them here) @@ -207,10 +210,15 @@ function parse_master_into_pokemon_table($form_ids, $game_master_url) { $form_data = $row['data']['formSettings']['forms']; } foreach($form_data as $form) { - $form_name = strtolower(str_replace($pokemon_name.'_','',$form['form'])); + // This is some new niantic shit + $pokemon_form_name = $form['form']; + if(is_int($form['form'])) { + $pokemon_form_name = $form_names[$form['form']]; + } + $form_name = strtolower(str_replace($pokemon_name.'_','',$pokemon_form_name)); if($form_name == 'purified' || $form_name == 'shadow') continue; $poke_name = ucfirst(strtolower($row['data']['formSettings']['pokemon'])); - $form_id = $form_ids[$form['form']] ?? 0; + $form_id = $form_ids[$pokemon_form_name] ?? 0; $pokemon_array[$pokemon_id][$form_name] = [ 'pokemon_name' => $poke_name, From fd73aaab6b6f1582eaf43f8d7a9e907af15d9e8e Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 28 Oct 2023 16:42:47 +0300 Subject: [PATCH 286/367] New translations --- lang/pokemon.json | 566 ++++++++++++++++++++++++++++++++-------- lang/pokemon_moves.json | 35 ++- 2 files changed, 485 insertions(+), 116 deletions(-) diff --git a/lang/pokemon.json b/lang/pokemon.json index 1f5150fe..204ea242 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -2938,7 +2938,7 @@ "EN": "Conkeldurr", "FR": "Bétochef", "DE": "Meistagrif", - "RU": "Конкельдар\r\n" + "RU": "Конкельдар\n" }, "pokemon_id_535": { "EN": "Tympole", @@ -5098,319 +5098,657 @@ "DE": "Cupidos", "RU": "Энаморус" }, - "pokemon_id_999": { - "EN": "Gimmighoul", - "FR": "Mordudor", - "DE": "Gierspenst", - "RU": "Гиммигул" - }, - "pokemon_id_1000": { - "EN": "Gholdengo", - "FR": "Gromago", - "DE": "Monetigo", - "RU": "Голденго" - }, "pokemon_id_906": { - "EN": "Sprigatito" + "EN": "Sprigatito", + "FR": "Poussacha", + "DE": "Felori", + "RU": "Спригатито" }, "pokemon_id_907": { - "EN": "Floragato" + "EN": "Floragato", + "FR": "Matourgeon", + "DE": "Feliospa", + "RU": "Флорагато" }, "pokemon_id_908": { - "EN": "Meowscarada" + "EN": "Meowscarada", + "FR": "Miascarade", + "DE": "Maskagato", + "RU": "Мяускарада" }, "pokemon_id_909": { - "EN": "Fuecoco" + "EN": "Fuecoco", + "FR": "Chochodile", + "DE": "Krokel", + "RU": "Фуэкоко" }, "pokemon_id_910": { - "EN": "Crocalor" + "EN": "Crocalor", + "FR": "Crocogril", + "DE": "Lokroko", + "RU": "Крокалор" }, "pokemon_id_911": { - "EN": "Skeledirge" + "EN": "Skeledirge", + "FR": "Flâmigator", + "DE": "Skelokrok", + "RU": "Скеледирж" }, "pokemon_id_912": { - "EN": "Quaxly" + "EN": "Quaxly", + "FR": "Coiffeton", + "DE": "Kwaks", + "RU": "Куаксли" }, "pokemon_id_913": { - "EN": "Quaxwell" + "EN": "Quaxwell", + "FR": "Canarbello", + "DE": "Fuentente", + "RU": "Куаксвелл" }, "pokemon_id_914": { - "EN": "Quaquaval" + "EN": "Quaquaval", + "FR": "Palmaval", + "DE": "Bailonda", + "RU": "Куаквавал" }, "pokemon_id_915": { - "EN": "Lechonk" + "EN": "Lechonk", + "FR": "Gourmelet", + "DE": "Ferkuli", + "RU": "Лечонк" }, "pokemon_id_916": { - "EN": "Oinkologne" + "EN": "Oinkologne", + "FR": "Fragroin", + "DE": "Fragrunz", + "RU": "Ойнколон" }, "pokemon_id_917": { - "EN": "Tarountula" + "EN": "Tarountula", + "FR": "Tissenboule", + "DE": "Tarundel", + "RU": "Тараунтула" }, "pokemon_id_918": { - "EN": "Spidops" + "EN": "Spidops", + "FR": "Filentrappe", + "DE": "Spinsidias", + "RU": "Спайдопс" }, "pokemon_id_919": { - "EN": "Nymble" + "EN": "Nymble", + "FR": "Lilliterelle", + "DE": "Micrick", + "RU": "Нимбл" }, "pokemon_id_920": { - "EN": "Lokix" + "EN": "Lokix", + "FR": "Gambex", + "DE": "Lextremo", + "RU": "Локикс" }, "pokemon_id_921": { - "EN": "Pawmi" + "EN": "Pawmi", + "FR": "Pohm", + "DE": "Pamo", + "RU": "Поми" }, "pokemon_id_922": { - "EN": "Pawmo" + "EN": "Pawmo", + "FR": "Pohmotte", + "DE": "Pamamo", + "RU": "Помо" }, "pokemon_id_923": { - "EN": "Pawmot" + "EN": "Pawmot", + "FR": "Pohmarmotte", + "DE": "Pamomamo", + "RU": "Помот" }, "pokemon_id_924": { - "EN": "Tandemaus" + "EN": "Tandemaus", + "FR": "Compagnol", + "DE": "Zwieps", + "RU": "Тандемаус" }, "pokemon_id_925": { - "EN": "Maushold" + "EN": "Maushold", + "FR": "Famignol", + "DE": "Famieps", + "RU": "Маусхолд" }, "pokemon_id_926": { - "EN": "Fidough" + "EN": "Fidough", + "FR": "Pâtachiot", + "DE": "Hefel", + "RU": "Файдо" }, "pokemon_id_927": { - "EN": "Dachsbun" + "EN": "Dachsbun", + "FR": "Briochien", + "DE": "Backel", + "RU": "Даксбан" }, "pokemon_id_928": { - "EN": "Smoliv" + "EN": "Smoliv", + "FR": "Olivini", + "DE": "Olini", + "RU": "Смолив" }, "pokemon_id_929": { - "EN": "Dolliv" + "EN": "Dolliv", + "FR": "Olivado", + "DE": "Olivinio", + "RU": "Доллив" }, "pokemon_id_930": { - "EN": "Arboliva" + "EN": "Arboliva", + "DE": "Olithena", + "RU": "Арболива" }, "pokemon_id_931": { - "EN": "Squawkabilly" + "EN": "Squawkabilly", + "FR": "Tapatoès", + "DE": "Krawalloro", + "RU": "Сквакабилли" }, "pokemon_id_932": { - "EN": "Nacli" + "EN": "Nacli", + "FR": "Selutin", + "DE": "Geosali", + "RU": "Накли" }, "pokemon_id_933": { - "EN": "Naclstack" + "EN": "Naclstack", + "FR": "Amassel", + "DE": "Sedisal", + "RU": "Наклстак" }, "pokemon_id_934": { - "EN": "Garganacl" + "EN": "Garganacl", + "FR": "Gigansel", + "DE": "Saltigant", + "RU": "Гарганакл" }, "pokemon_id_935": { - "EN": "Charcadet" + "EN": "Charcadet", + "FR": "Charbambin", + "DE": "Knarbon", + "RU": "Чаркадет" }, "pokemon_id_936": { - "EN": "Armarouge" + "EN": "Armarouge", + "FR": "Carmadura", + "DE": "Crimanzo", + "RU": "Армаруж" }, "pokemon_id_937": { - "EN": "Ceruledge" + "EN": "Ceruledge", + "FR": "Malvalame", + "DE": "Azugladis", + "RU": "Серуледж" }, "pokemon_id_938": { - "EN": "Tadbulb" + "EN": "Tadbulb", + "FR": "Têtampoule", + "DE": "Blipp", + "RU": "Тадбалб" }, "pokemon_id_939": { - "EN": "Bellibolt" + "EN": "Bellibolt", + "FR": "Ampibidou", + "DE": "Wampitz", + "RU": "Беллиболт" }, "pokemon_id_940": { - "EN": "Wattrel" + "EN": "Wattrel", + "FR": "Zapétrel", + "DE": "Voltrel", + "RU": "Ваттрел" }, "pokemon_id_941": { - "EN": "Kilowattrel" + "EN": "Kilowattrel", + "FR": "Fulgulairo", + "DE": "Voltrean", + "RU": "Киловаттрел" }, "pokemon_id_942": { - "EN": "Maschiff" + "EN": "Maschiff", + "FR": "Grondogue", + "DE": "Mobtiff", + "RU": "Масчифф" }, "pokemon_id_943": { - "EN": "Mabosstiff" + "EN": "Mabosstiff", + "FR": "Dogrino", + "DE": "Mastifioso", + "RU": "Мабосстифф" }, "pokemon_id_944": { - "EN": "Shroodle" + "EN": "Shroodle", + "FR": "Gribouraigne", + "DE": "Sproxi", + "RU": "Шрудл" }, "pokemon_id_945": { - "EN": "Grafaiai" + "EN": "Grafaiai", + "FR": "Tag-Tag", + "DE": "Affiti", + "RU": "Графайай" }, "pokemon_id_946": { - "EN": "Bramblin" + "EN": "Bramblin", + "FR": "Virovent", + "DE": "Weherba", + "RU": "Брамблин" }, "pokemon_id_947": { - "EN": "Brambleghast" + "EN": "Brambleghast", + "FR": "Virevorreur", + "DE": "Horrerba", + "RU": "Брамблгаст" }, "pokemon_id_948": { - "EN": "Toedscool" + "EN": "Toedscool", + "FR": "Terracool", + "DE": "Tentagra", + "RU": "Тодскул" }, "pokemon_id_949": { - "EN": "Toedscruel" + "EN": "Toedscruel", + "FR": "Terracruel", + "DE": "Tenterra", + "RU": "Тодскрул" }, "pokemon_id_950": { - "EN": "Klawf" + "EN": "Klawf", + "FR": "Craparoi", + "DE": "Klibbe", + "RU": "Клоф" }, "pokemon_id_951": { - "EN": "Capsakid" + "EN": "Capsakid", + "FR": "Pimito", + "DE": "Chilingel", + "RU": "Капсакид" }, "pokemon_id_952": { - "EN": "Scovillain" + "EN": "Scovillain", + "FR": "Scovilain", + "DE": "Halupenjo", + "RU": "Сковиллен" }, "pokemon_id_953": { - "EN": "Rellor" + "EN": "Rellor", + "FR": "Léboulérou", + "DE": "Relluk", + "RU": "Реллор" }, "pokemon_id_954": { - "EN": "Rabsca" + "EN": "Rabsca", + "FR": "Bérasca", + "DE": "Skarabaks", + "RU": "Рабска" }, "pokemon_id_955": { - "EN": "Flittle" + "EN": "Flittle", + "FR": "Flotillon", + "DE": "Flattutu", + "RU": "Флиттл" }, "pokemon_id_956": { - "EN": "Espathra" + "EN": "Espathra", + "FR": "Cléopsytra", + "DE": "Psiopatra", + "RU": "Эспатра" }, "pokemon_id_957": { - "EN": "Tinkatink" + "EN": "Tinkatink", + "FR": "Forgerette", + "DE": "Forgita", + "RU": "Тинкатинк" }, "pokemon_id_958": { - "EN": "Tinkatuff" + "EN": "Tinkatuff", + "FR": "Forgella", + "DE": "Tafforgita", + "RU": "Тинкатафф" }, "pokemon_id_959": { - "EN": "Tinkaton" + "EN": "Tinkaton", + "FR": "Forgelina", + "DE": "Granforgita", + "RU": "Тинкатон" }, "pokemon_id_960": { - "EN": "Wiglett" + "EN": "Wiglett", + "FR": "Taupikeau", + "DE": "Schligda", + "RU": "Виглетт" }, "pokemon_id_961": { - "EN": "Wugtrio" + "EN": "Wugtrio", + "FR": "Triopikeau", + "DE": "Schligdri", + "RU": "Вагтрио" }, "pokemon_id_962": { - "EN": "Bombirdier" + "EN": "Bombirdier", + "FR": "Lestombaile", + "DE": "Adebom", + "RU": "Бомбердир" }, "pokemon_id_963": { - "EN": "Finizen" + "EN": "Finizen", + "FR": "Dofin", + "DE": "Normifin", + "RU": "Финизен" }, "pokemon_id_964": { - "EN": "Palafin" + "EN": "Palafin", + "FR": "Superdofin", + "DE": "Delfinator", + "RU": "Палафин" }, "pokemon_id_965": { - "EN": "Varoom" + "EN": "Varoom", + "FR": "Vrombi", + "DE": "Knattox", + "RU": "Варум" }, "pokemon_id_966": { - "EN": "Revavroom" + "EN": "Revavroom", + "FR": "Vrombotor", + "DE": "Knattatox", + "RU": "Реваврум" }, "pokemon_id_967": { - "EN": "Cyclizar" + "EN": "Cyclizar", + "FR": "Motorizard", + "DE": "Mopex", + "RU": "Сайклизар" }, "pokemon_id_968": { - "EN": "Orthworm" + "EN": "Orthworm", + "FR": "Ferdeter", + "DE": "Schlurm", + "RU": "Ортворм" }, "pokemon_id_969": { - "EN": "Glimmet" + "EN": "Glimmet", + "FR": "Germéclat", + "DE": "Lumispross", + "RU": "Глиммет" }, "pokemon_id_970": { - "EN": "Glimmora" + "EN": "Glimmora", + "FR": "Floréclat", + "DE": "Lumiflora", + "RU": "Глиммора" }, "pokemon_id_971": { - "EN": "Greavard" + "EN": "Greavard", + "FR": "Toutombe", + "DE": "Gruff", + "RU": "Гриверд" }, "pokemon_id_972": { - "EN": "Houndstone" + "EN": "Houndstone", + "FR": "Tomberro", + "DE": "Friedwuff", + "RU": "Хаундстоун" }, "pokemon_id_973": { - "EN": "Flamigo" + "EN": "Flamigo", + "FR": "Flamenroule", + "DE": "Flaminkno", + "RU": "Фламиго" }, "pokemon_id_974": { - "EN": "Cetoddle" + "EN": "Cetoddle", + "FR": "Piétacé", + "DE": "Flaniwal", + "RU": "Сетоддл" }, "pokemon_id_975": { - "EN": "Cetitan" + "EN": "Cetitan", + "FR": "Balbalèze", + "DE": "Kolowal", + "RU": "Сетайтан" }, "pokemon_id_976": { - "EN": "Veluza" + "EN": "Veluza", + "FR": "Délestin", + "DE": "Agiluza", + "RU": "Велуза" }, "pokemon_id_977": { - "EN": "Dondozo" + "EN": "Dondozo", + "FR": "Oyacata", + "DE": "Heerashai", + "RU": "Дондозо" }, "pokemon_id_978": { - "EN": "Tatsugiri" + "EN": "Tatsugiri", + "FR": "Nigirigon", + "DE": "Nigiragi", + "RU": "Тацугири" }, "pokemon_id_979": { - "EN": "Annihilape" + "EN": "Annihilape", + "FR": "Courrousinge", + "DE": "Epitaff", + "RU": "Аннаялейп" }, "pokemon_id_980": { - "EN": "Clodsire" + "EN": "Clodsire", + "FR": "Terraiste", + "DE": "Suelord", + "RU": "Клодсайр" }, "pokemon_id_981": { - "EN": "Farigiraf" + "EN": "Farigiraf", + "RU": "Фарижираф" }, "pokemon_id_982": { - "EN": "Dudunsparce" + "EN": "Dudunsparce", + "FR": "Deusolourdo", + "DE": "Dummimisel", + "RU": "Даданспарс" }, "pokemon_id_983": { - "EN": "Kingambit" + "EN": "Kingambit", + "FR": "Scalpereur", + "DE": "Gladimperio", + "RU": "Кингамбит" }, "pokemon_id_984": { - "EN": "Great Tusk" + "PT-BR": "Presa Grande", + "EN": "Great Tusk", + "FR": "Fort-Ivoire", + "DE": "Riesenzahn", + "IT": "Grandizanne", + "RU": "Великий Бивень", + "ES": "Colmilargo" }, "pokemon_id_985": { - "EN": "Scream Tail" + "PT-BR": "Cauda Brado", + "EN": "Scream Tail", + "FR": "Hurle-Queue", + "DE": "Brüllschweif", + "IT": "Codaurlante", + "RU": "Кричащий Хвост", + "ES": "Colagrito" }, "pokemon_id_986": { - "EN": "Brute Bonnet" + "PT-BR": "Capuz Bruto", + "EN": "Brute Bonnet", + "FR": "Fongus-Furie", + "DE": "Wutpilz", + "IT": "Fungofurioso", + "RU": "Свирепый Гриб", + "ES": "Furioseta" }, "pokemon_id_987": { - "EN": "Flutter Mane" + "PT-BR": "Juba Sopro", + "EN": "Flutter Mane", + "FR": "Flotte-Mèche", + "DE": "Flatterhaar", + "IT": "Crinealato", + "RU": "Волнистая Грива", + "ES": "Melenaleteo" }, "pokemon_id_988": { - "EN": "Slither Wing" + "PT-BR": "Asa Rasteira", + "EN": "Slither Wing", + "FR": "Rampe-Ailes", + "DE": "Kriechflügel", + "IT": "Alirasenti", + "RU": "Ползущее Крыло", + "ES": "Reptalada" }, "pokemon_id_989": { - "EN": "Sandy Shocks" + "PT-BR": "Choque Areia", + "EN": "Sandy Shocks", + "FR": "Pelage-Sablé", + "DE": "Sandfell", + "IT": "Peldisabbia", + "RU": "Магнитные Вихры", + "ES": "Pelarena" }, "pokemon_id_990": { - "EN": "Iron Treads" + "PT-BR": "Trilho Férreo", + "EN": "Iron Treads", + "FR": "Roue-de-Fer", + "DE": "Eisenrad", + "IT": "Solcoferreo", + "RU": "Железные Гусеницы", + "ES": "Ferrodada" }, "pokemon_id_991": { - "EN": "Iron Bundle" + "PT-BR": "Pacote Férreo", + "EN": "Iron Bundle", + "FR": "Hotte-de-Fer", + "DE": "Eisenbündel", + "IT": "Saccoferreo", + "RU": "Железный Мешок", + "ES": "Ferrosaco" }, "pokemon_id_992": { - "EN": "Iron Hands" + "PT-BR": "Mãos Férreas", + "EN": "Iron Hands", + "FR": "Paume-de-Fer", + "DE": "Eisenhand", + "IT": "Manoferrea", + "RU": "Железные Руки", + "ES": "Ferropalmas" }, "pokemon_id_993": { - "EN": "Iron Jugulis" + "PT-BR": "Jugulares Férreas", + "EN": "Iron Jugulis", + "FR": "Têtes-de-Fer", + "DE": "Eisenhals", + "IT": "Colloferreo", + "RU": "Железные Головы", + "ES": "Ferrocuello" }, "pokemon_id_994": { - "EN": "Iron Moth" + "PT-BR": "Mariposa Férrea", + "EN": "Iron Moth", + "FR": "Mite-de-Fer", + "DE": "Eisenfalter", + "IT": "Falenaferrea", + "RU": "Железный Мотылёк", + "ES": "Ferropolilla" }, "pokemon_id_995": { - "EN": "Iron Thorns" + "PT-BR": "Espinhos Férreos", + "EN": "Iron Thorns", + "FR": "Épine-de-Fer", + "DE": "Eisendorn", + "IT": "Spineferree", + "RU": "Железные Шипы", + "ES": "Ferropúas" }, "pokemon_id_996": { - "EN": "Frigibax" + "EN": "Frigibax", + "FR": "Frigodo", + "DE": "Frospino", + "RU": "Фриджибакс" }, "pokemon_id_997": { - "EN": "Arctibax" + "EN": "Arctibax", + "FR": "Cryodo", + "DE": "Cryospino", + "RU": "Арктибакс" }, "pokemon_id_998": { - "EN": "Baxcalibur" + "EN": "Baxcalibur", + "FR": "Glaivodo", + "DE": "Espinodon", + "RU": "Бакскалибур" + }, + "pokemon_id_999": { + "EN": "Gimmighoul", + "FR": "Mordudor", + "DE": "Gierspenst", + "RU": "Гиммигул" + }, + "pokemon_id_1000": { + "EN": "Gholdengo", + "FR": "Gromago", + "DE": "Monetigo", + "RU": "Голденго" }, "pokemon_id_1001": { - "EN": "Wo-Chien" + "EN": "Wo-Chien", + "FR": "Chongjian", + "DE": "Chongjian", + "RU": "Во-Чиен" }, "pokemon_id_1002": { - "EN": "Chien-Pao" + "EN": "Chien-Pao", + "FR": "Baojian", + "DE": "Baojian", + "RU": "Чиен-Пао" }, "pokemon_id_1003": { - "EN": "Ting-Lu" + "EN": "Ting-Lu", + "FR": "Dinglu", + "DE": "Dinglu", + "RU": "Тинг-Лу" }, "pokemon_id_1004": { - "EN": "Chi-Yu" + "EN": "Chi-Yu", + "FR": "Yuyu", + "DE": "Yuyu", + "RU": "Чи-Ю" }, "pokemon_id_1005": { - "EN": "Roaring Moon" + "PT-BR": "Lua Estrondo", + "EN": "Roaring Moon", + "FR": "Rugit-Lune", + "DE": "Donnersichel", + "IT": "Lunaruggente", + "RU": "Ревущий Месяц", + "ES": "Bramaluna" }, "pokemon_id_1006": { - "EN": "Iron Valiant" + "PT-BR": "Valentia Férrea", + "EN": "Iron Valiant", + "FR": "Garde-de-Fer", + "DE": "Eisenkrieger", + "IT": "Eroeferreo", + "RU": "Железный Воин", + "ES": "Ferropaladín" }, "pokemon_id_1007": { - "EN": "Koraidon" + "EN": "Koraidon", + "RU": "Корайдон" }, "pokemon_id_1008": { - "EN": "Miraidon" + "EN": "Miraidon", + "RU": "Мирайдон" } } \ No newline at end of file diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index f12f29d8..fa8cbdc8 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -2832,6 +2832,15 @@ "RU": "Ликвидация", "ES": "Hidroariete" }, + "pokemon_move_384": { + "PT-BR": "Ascenção do Dragão", + "EN": "Dragon Ascent", + "FR": "Draco Ascension", + "DE": "Zenitstürmer", + "IT": "Ascesa del Drago", + "RU": "Взлёт Дракона", + "ES": "Ascenso Draco" + }, "pokemon_move_385": { "PT-BR": "Folhagem", "EN": "Leafage", @@ -2877,7 +2886,29 @@ "RU": "Крылья Забвения", "ES": "Ala Mortífera" }, - "pokemon_move_384": { - "EN": "Dragon Ascent" + "pokemon_move_391": { + "PT-BR": "Pinote Triplo", + "EN": "Triple Axel", + "DE": "Dreifach-Axel", + "IT": "Triplo Axel", + "RU": "Тройной Аксель" + }, + "pokemon_move_392": { + "PT-BR": "Desbravar", + "EN": "Trailblaze", + "FR": "Désherbaffe", + "DE": "Wegbereiter", + "IT": "Apripista", + "RU": "Новый Путь", + "ES": "Abrecaminos" + }, + "pokemon_move_393": { + "PT-BR": "Areias Ardentes", + "EN": "Scorching Sands", + "FR": "Sable Ardent", + "DE": "Brandsand", + "IT": "Sabbiardente", + "RU": "Раскалённый Песок", + "ES": "Arenas Ardientes" } } \ No newline at end of file From c71fe575ba73111ea491395fffb5a9335b1efc53 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 28 Oct 2023 20:24:59 +0300 Subject: [PATCH 287/367] New feature: RAID_BOSS_LIST Adds a list of stored raid bosses to the overview message --- config/defaults-config.json | 4 ++ docs/config.rst | 8 ++++ logic/createRaidBossList.php | 73 ++++++++++++++++++++++++++++++++++++ logic/get_overview.php | 7 ++++ 4 files changed, 92 insertions(+) create mode 100644 logic/createRaidBossList.php diff --git a/config/defaults-config.json b/config/defaults-config.json index deb15239..20fee7db 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -39,6 +39,10 @@ "RAID_VIA_LOCATION_FUNCTION": "create", "RAID_EGG_DURATION":"60", "RAID_EGG_DURATION_ELITE":"1440", + "RAID_BOSS_LIST": false, + "RAID_BOSS_LIST_TITLE": "Raidbosses:", + "RAID_BOSS_LIST_RAID_LEVELS": [5,7,8,10], + "RAID_BOSS_LIST_ROW_LIMIT": "4", "RAID_DURATION":"45", "RAID_DURATION_ELITE":"30", "RAID_DURATION_CLOCK_STYLE": true, diff --git a/docs/config.rst b/docs/config.rst index e692c459..e2637f18 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -1034,6 +1034,14 @@ Config reference - Fully qualified HTTPS URL to ``raidpicture.php``\ , for example ``https://example.com/raidbot/raidpicture.php`` * - RAID_PIN_MESSAGE - Custom message added to the bottom of the raid overview messages + * - RAID_BOSS_LIST" + - Bool, adds a list of saved raid bosses to overview message + * - RAID_BOSS_LIST_TITLE + - String, title of the list + * - RAID_BOSS_LIST_RAID_LEVELS + - Array, list of raid levels included in the list + * - RAID_BOSS_LIST_ROW_LIMIT + - Int, limit the list to set number of rows * - RAID_POLL_HIDE_BUTTONS_POKEMON - List of Pokemon dex IDs for which voting buttons are disabled * - RAID_POLL_HIDE_BUTTONS_RAID_LEVEL diff --git a/logic/createRaidBossList.php b/logic/createRaidBossList.php new file mode 100644 index 00000000..428e61a8 --- /dev/null +++ b/logic/createRaidBossList.php @@ -0,0 +1,73 @@ +RAID_BOSS_LIST_RAID_LEVELS). ')'; + $q = my_query('SELECT pokedex_id,pokemon_form_id,date_start,date_end,concat(date_format(date_start,"%d%m%y%k"),date_format(date_end,"%d%m%y%k")) as arrkey,CASE WHEN date(date_start) = date(date_end) THEN 1 ELSE 0 END as sameDay FROM raid_bosses where raid_level in ' . $levelList . ' order by sameDay, date_start, date_end'); + $list = ''; + $prevStartDate = ''; + $data[0] = $data[1] = []; + // Save the results in easy to process format + foreach($q->fetchAll() as $row) { + $data[$row['sameDay']][$row['arrkey']][] = $row; + } + if(count($row) == 0) return ''; + $i = 1; + $list = $config->RAID_BOSS_LIST_TITLE; + // Print list of bosses that run for multiple days + foreach($data[0] as $tempRow) { + $list .= PHP_EOL . '- '; + foreach($tempRow as $num => $row) { + $pokemonName = get_local_pokemon_name($row['pokedex_id'], $row['pokemon_form_id']); + if($num != 0) $list .= ', '; + $list .= $pokemonName; + } + $dateStart = new dateTime($row['date_start']); + $dateEnd = new dateTime($row['date_end']); + $list .= ' ' . $dateStart->format($dateFormat) . ' - '. $dateEnd->format($dateFormat); + $i++; + if($i > $config->RAID_BOSS_LIST_ROW_LIMIT) break; + } + + // Print list of one day bosses + foreach($data[1] as $arrkey => $tempRow) { + $startDate = substr($arrkey, 0, 6); + if($list != '' && $prevStartDate != $startDate) $list.= PHP_EOL . PHP_EOL; + foreach($tempRow as $num => $row) { + $dateStart = new dateTime($row['date_start']); + $dateEnd = new dateTime($row['date_end']); + if($num == 0){ + if($prevStartDate != $startDate) { + $list .= $dateStart->format($dateFormat); + } + $list .= PHP_EOL . '- '; + } + $pokemonName = get_local_pokemon_name($row['pokedex_id'], $row['pokemon_form_id']); + if($num != 0) $list .= ', '; + $list .= $pokemonName; + $prevStartDate = $startDate; + } + $list .= ' ' . $dateStart->format($timeFormat) . ' - ' . $dateEnd->format($timeFormat); + } + return $list; +} +?> \ No newline at end of file diff --git a/logic/get_overview.php b/logic/get_overview.php index cb9850c4..a8261700 100644 --- a/logic/get_overview.php +++ b/logic/get_overview.php @@ -1,5 +1,6 @@ RAID_BOSS_LIST) { + $msg .= createRaidBossList() . CR . CR; + } //Add custom message from the config. if (!empty($config->RAID_PIN_MESSAGE)) { $msg .= $config->RAID_PIN_MESSAGE; @@ -105,6 +109,9 @@ function get_overview( $active_raids, $chat_title, $chat_username ) $msg .= (($att['count_want_invite'] > 0) ? EMOJI_WANT_INVITE . $att['count_want_invite'] : ''); $msg .= CR . CR; } + if($config->RAID_BOSS_LIST) { + $msg .= createRaidBossList() . CR . CR; + } //Add custom message from the config. if (!empty($config->RAID_PIN_MESSAGE)) { $msg .= $config->RAID_PIN_MESSAGE; From 80fb690e17ea0ca769d6a04d4da9de626e6016f5 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 31 Oct 2023 16:38:57 +0200 Subject: [PATCH 288/367] Translate anytime on alarms based on recipient language setting --- logic/alarm.php | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/logic/alarm.php b/logic/alarm.php index 4efa8cc1..5bb29b14 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -86,7 +86,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) } $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . SP . '+' . $icons[$info] . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime, $recipient_language); $msg_text .= create_traincode_msg($trainercode); // Updating status - here or cancel @@ -98,14 +98,14 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_later', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime, $recipient_language); $msg_text .= create_traincode_msg($trainercode); } else if($info == 'cancel') { debug_log('Alarm cancel: ' . $info); $msg_text = '' . getTranslation('alert_cancel', $recipient_language) . '' . CR; $msg_text .= TEAM_CANCEL . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime, $recipient_language); } // Updating pokemon @@ -123,7 +123,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) } $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime, $recipient_language); $msg_text .= create_traincode_msg($trainercode); // Cancel pokemon @@ -134,7 +134,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_cancel_individual_poke', $recipient_language) . SP . $poke_name . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime, $recipient_language); $msg_text .= create_traincode_msg($trainercode); } else if($action == 'new_boss') { @@ -149,7 +149,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_new_att', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($info); + $msg_text .= EMOJI_CLOCK . SP . check_time($info, $recipient_language); $msg_text .= create_traincode_msg($trainercode); // Attendance time change @@ -159,7 +159,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_change_time', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($info) . ''; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($info, $recipient_language) . ''; $msg_text .= create_traincode_msg($trainercode); // Attendance from remote @@ -169,7 +169,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_remote', $recipient_language) . '' . CR; $msg_text .= EMOJI_REMOTE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime, $recipient_language) . ''; $msg_text .= create_traincode_msg($trainercode); // Attendance no longer from remote @@ -179,7 +179,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_no_remote', $recipient_language) . '' . CR; $msg_text .= EMOJI_REMOTE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime, $recipient_language) . ''; // No additional trainer } else if($action == 'extra_alone') { @@ -187,7 +187,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_extra_alone', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime); + $msg_text .= EMOJI_CLOCK . SP . check_time($attendtime, $recipient_language); $msg_text .= create_traincode_msg($trainercode); // Group code public @@ -222,7 +222,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_want_invite', $recipient_language) . '' . CR; $msg_text .= EMOJI_WANT_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime, $recipient_language) . ''; $msg_text .= create_traincode_msg($trainercode); // Attendance no longer from remote @@ -231,7 +231,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_no_want_invite', $recipient_language) . '' . CR; $msg_text .= EMOJI_WANT_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime, $recipient_language) . ''; $msg_text .= create_traincode_msg($trainercode); // Let others know you are not playing, but can invite others @@ -240,7 +240,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_can_invite', $recipient_language) . '' . CR; $msg_text .= EMOJI_CAN_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime, $recipient_language) . ''; $msg_text .= create_traincode_msg($trainercode); // Let others know you are not longer able to invite them @@ -249,7 +249,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text = '' . getTranslation('alert_no_can_invite', $recipient_language) . '' . CR; $msg_text .= EMOJI_CAN_INVITE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; - $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime) . ''; + $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime, $recipient_language) . ''; $msg_text .= create_traincode_msg($trainercode); } $tg_json[] = send_message($answer['user_id'], $msg_text, false, false, true); @@ -276,12 +276,13 @@ function create_traincode_msg($trainercode){ /** * Check attendance time against anytime. * @param $time + * @param $recipientLanguage */ -function check_time($time) +function check_time($time, $recipientLanguage) { // Raid anytime? if(strcmp($time, ANYTIME)===0){ - return getTranslation('anytime'); + return getTranslation('anytime', $recipientLanguage); } return dt2time($time); } From 3e4ad4bf0729bb029f970c5409eb1d64ebda7d85 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 2 Nov 2023 11:21:13 +0200 Subject: [PATCH 289/367] Fixed how /get and /set handle true/false --- commands/get.php | 2 ++ commands/set.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/commands/get.php b/commands/get.php index 86133256..09e8ff9d 100644 --- a/commands/get.php +++ b/commands/get.php @@ -52,6 +52,8 @@ if(isset($ajson[$cfg_name])){ $alias = $ajson[$cfg_name]; } + if($cfg_value === true) $cfg_value = 'true'; + elseif($cfg_value === false) $cfg_value = 'false'; // Config name / Alias + value $msg .= (empty($alias) ? $cfg_name : $alias) . SP . (empty($cfg_value) ? '' . getTranslation('no_value') . '' : $cfg_value); diff --git a/commands/set.php b/commands/set.php index 0f104431..c1444b64 100644 --- a/commands/set.php +++ b/commands/set.php @@ -119,6 +119,8 @@ // Prepare data, replace " with ' $config_value = str_replace('"', "'", $config_value); $old_value = $json[$config_name]; + if($old_value === true) $old_value = 'true'; + elseif($old_value === false) $old_value = 'false'; $json[$config_name] = $config_value; $jsonString = json_encode($json, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT); debug_log($config_name, 'CONFIG NAME:'); From 5aeac177fc86a7a08f4f1d75482504889b481a14 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 2 Nov 2023 11:47:53 +0200 Subject: [PATCH 290/367] Improved costumed pokemon icon's fallback logic --- logic/raid_picture.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 8436ee67..202c28d0 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -284,14 +284,15 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Add costume info for every mon except megas if($raid['costume'] != 0 && $raid['pokemon_form'] >= 0) { $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); - $addressable_icon .= '.c' . array_search($raid['costume'],$costume); - $addressableFallback .= '.c' . array_search($raid['costume'],$costume); + $costumeName = array_search($raid['costume'],$costume); + if(!empty($costumeName)) { + $addressable_icon .= '.c' . array_search($raid['costume'],$costume); - $uicons_icon .= '_c'.$raid['costume']; + $uicons_icon .= '_c'.$raid['costume']; + } } if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { $addressable_icon .= '.s'; - $addressableFallback .= '.s'; $uicons_icon .= '_s'; $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); } From 7a7c5955725e3c83f9326ea8f2711844d17e9f04 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 3 Nov 2023 11:54:27 +0200 Subject: [PATCH 291/367] Exclude past bosses --- logic/createRaidBossList.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/logic/createRaidBossList.php b/logic/createRaidBossList.php index 428e61a8..cb73e298 100644 --- a/logic/createRaidBossList.php +++ b/logic/createRaidBossList.php @@ -22,7 +22,16 @@ function createRaidBossList() { $dateFormat = 'j.m.'; $timeFormat = 'H:i'; $levelList = '(' . implode(',', $config->RAID_BOSS_LIST_RAID_LEVELS). ')'; - $q = my_query('SELECT pokedex_id,pokemon_form_id,date_start,date_end,concat(date_format(date_start,"%d%m%y%k"),date_format(date_end,"%d%m%y%k")) as arrkey,CASE WHEN date(date_start) = date(date_end) THEN 1 ELSE 0 END as sameDay FROM raid_bosses where raid_level in ' . $levelList . ' order by sameDay, date_start, date_end'); + $q = my_query(' + SELECT + pokedex_id, pokemon_form_id, date_start, date_end, + CONCAT(DATE_FORMAT(date_start,"%d%m%y%k"), DATE_FORMAT(date_end,"%d%m%y%k")) AS arrkey, + CASE WHEN date(date_start) = date(date_end) THEN 1 ELSE 0 END AS sameDay + FROM raid_bosses + WHERE raid_level IN ' . $levelList . ' + AND date_end > DATE_ADD(NOW(), INTERVAL 1 HOUR) + ORDER BY sameDay, date_start, date_end + '); $list = ''; $prevStartDate = ''; $data[0] = $data[1] = []; From 6870ac69305ce50e6306d7c9fa9356634d45e4d0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 3 Nov 2023 12:25:47 +0200 Subject: [PATCH 292/367] Fixed math --- logic/createRaidBossList.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/createRaidBossList.php b/logic/createRaidBossList.php index cb73e298..254f6bf1 100644 --- a/logic/createRaidBossList.php +++ b/logic/createRaidBossList.php @@ -23,13 +23,13 @@ function createRaidBossList() { $timeFormat = 'H:i'; $levelList = '(' . implode(',', $config->RAID_BOSS_LIST_RAID_LEVELS). ')'; $q = my_query(' - SELECT + SELECT pokedex_id, pokemon_form_id, date_start, date_end, CONCAT(DATE_FORMAT(date_start,"%d%m%y%k"), DATE_FORMAT(date_end,"%d%m%y%k")) AS arrkey, CASE WHEN date(date_start) = date(date_end) THEN 1 ELSE 0 END AS sameDay FROM raid_bosses WHERE raid_level IN ' . $levelList . ' - AND date_end > DATE_ADD(NOW(), INTERVAL 1 HOUR) + AND date_end > DATE_SUB(NOW(), INTERVAL 1 HOUR) ORDER BY sameDay, date_start, date_end '); $list = ''; From 64c9855ce5bdd28edc95773693ffd43964892c9a Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 4 Dec 2023 20:57:18 +0200 Subject: [PATCH 293/367] Fixed counting of results --- logic/createRaidBossList.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/createRaidBossList.php b/logic/createRaidBossList.php index 254f6bf1..50cb9981 100644 --- a/logic/createRaidBossList.php +++ b/logic/createRaidBossList.php @@ -39,7 +39,7 @@ function createRaidBossList() { foreach($q->fetchAll() as $row) { $data[$row['sameDay']][$row['arrkey']][] = $row; } - if(count($row) == 0) return ''; + if($q->rowCount() == 0) return ''; $i = 1; $list = $config->RAID_BOSS_LIST_TITLE; // Print list of bosses that run for multiple days From f66df66ffa2a15ea96f117ef8dbf5e9247aca9ae Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 4 Dec 2023 21:26:24 +0200 Subject: [PATCH 294/367] New data source for getdb Pokemon types are no longer in their original order, but I don't think that's an issue --- mods/getdb.php | 300 ++++++++++++++++++------------------------------- 1 file changed, 111 insertions(+), 189 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 888bf67f..a983382d 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -6,8 +6,7 @@ require_once(LOGIC_PATH . '/sql_utils.php'); require_once(LOGIC_PATH . '/debug.php'); require_once(LOGIC_PATH . '/curl_get_contents.php'); -$proto_url = 'https://raw.githubusercontent.com/123FLO321/POGOProtos-Swift/master/Sources/POGOProtos/POGOProtos.pb.swift'; -$game_master_url = 'https://raw.githubusercontent.com/PokeMiners/game_masters/master/latest/latest.json'; +$game_master_url = 'https://raw.githubusercontent.com/WatWowMap/Masterfile-Generator/master/master-latest-everything.json'; $error = false; @@ -16,28 +15,16 @@ $update = false; } -// Read the form ids from protos -if (!$protos = get_protos($proto_url)) { - sendResults('Failed to get protos.', $update, true); -} - -[$form_ids, $form_names, $costume] = $protos; // Parse the game master data together with form ids into format we can use -$pokemon_array = parse_master_into_pokemon_table($form_ids, $form_names, $game_master_url); +[$pokemon_array, $costume_data] = parse_master_data($game_master_url); if(!$pokemon_array) { sendResults('Failed to open game master file.', $update, true); } // Save our core datasets to json files for further use -if(!file_put_contents(ROOT_PATH.'/protos/costume.json', json_encode($costume, JSON_PRETTY_PRINT))) { +if(!file_put_contents(ROOT_PATH.'/protos/costume.json', json_encode($costume_data, JSON_PRETTY_PRINT))) { sendResults('Failed to write costume data to protos/costume.json', $update, true); } -if(!file_put_contents(ROOT_PATH.'/protos/form.json', json_encode($form_ids, JSON_PRETTY_PRINT))) { - sendResults('Failed to write form data to protos/form.json', $update, true); -} -if(!file_put_contents(ROOT_PATH.'/protos/pokemon.json', json_encode($pokemon_array, JSON_PRETTY_PRINT))) { - sendResults('Failed to write pokemon data to protos/pokemon.json', $update, true); -} // Craft egg data $PRE = 'INSERT INTO `pokemon`' . PHP_EOL; @@ -117,193 +104,128 @@ function sendResults($msg, $update, $error = false) { function calculate_cps($base_stats) { // CP = (Attack * Defense^0.5 * Stamina^0.5 * CP_Multiplier^2) / 10 $cp_multiplier = array(20 => 0.5974, 25 => 0.667934); - $min = floor((($base_stats['baseAttack']+10)*(($base_stats['baseDefense']+10)**0.5)*(($base_stats['baseStamina']+10)**0.5)*$cp_multiplier[20]**2)/10); - $max = floor((($base_stats['baseAttack']+15)*(($base_stats['baseDefense']+15)**0.5)*(($base_stats['baseStamina']+15)**0.5)*$cp_multiplier[20]**2)/10); - $min_weather = floor((($base_stats['baseAttack']+10)*(($base_stats['baseDefense']+10)**0.5)*(($base_stats['baseStamina']+10)**0.5)*$cp_multiplier[25]**2)/10); - $max_weather = floor((($base_stats['baseAttack']+15)*(($base_stats['baseDefense']+15)**0.5)*(($base_stats['baseStamina']+15)**0.5)*$cp_multiplier[25]**2)/10); + $min = floor((($base_stats['attack']+10)*(($base_stats['defense']+10)**0.5)*(($base_stats['stamina']+10)**0.5)*$cp_multiplier[20]**2)/10); + $max = floor((($base_stats['attack']+15)*(($base_stats['defense']+15)**0.5)*(($base_stats['stamina']+15)**0.5)*$cp_multiplier[20]**2)/10); + $min_weather = floor((($base_stats['attack']+10)*(($base_stats['defense']+10)**0.5)*(($base_stats['stamina']+10)**0.5)*$cp_multiplier[25]**2)/10); + $max_weather = floor((($base_stats['attack']+15)*(($base_stats['defense']+15)**0.5)*(($base_stats['stamina']+15)**0.5)*$cp_multiplier[25]**2)/10); return [$min,$max,$min_weather,$max_weather]; } -function get_protos($proto_url) { - //Parse the form ID's from pogoprotos - if(!$proto_file = curl_get_contents($proto_url)) return false; - $proto = preg_split('/\r\n|\r|\n/', $proto_file); - $count = count($proto); - $form_ids = $costume = $form_names = array(); - $data_array = false; - for($i=0;$i<$count;$i++) { - $line = trim($proto[$i]); - if($data_array != false) { - $data = explode(':', $line, 2); - // End of pokemon data, no need to loop further - if(trim($data[0]) == ']') { - $data_array = false; - if(count($form_ids) > 0 && count($costume) > 0) { - // We found what we needed so we can stop looping through proto file and exit - break; - } - continue; - } - $value = explode('"', $data[1]); - if(strlen($value[1]) > 0) { - ${$data_array}[trim($value[1])] = trim($data[0]); - if($data_array == 'form_ids') { - $form_names[trim($data[0])] = trim($value[1]); - } - } - continue; - } - if($line == 'extension PokemonDisplayProto.Costume: SwiftProtobuf._ProtoNameProviding {') { - $data_array = 'costume'; - $i++; // Jump over one line - } - if($line == 'extension PokemonDisplayProto.Form: SwiftProtobuf._ProtoNameProviding {') { - $data_array = 'form_ids'; - $i++; // Jump over one line - } - } - unset($proto); - return [$form_ids, $form_names, $costume]; -} - -function parse_master_into_pokemon_table($form_ids, $form_names, $game_master_url) { +function parse_master_data($game_master_url) { // Set ID's for mega evolutions // Using negative to prevent mixup with actual form ID's // Collected from pogoprotos (hoping they won't change, so hard coding them here) - $mega_ids = array('MEGA' => -1, 'MEGA_X' => -2, 'MEGA_Y' => -3, 'PRIMAL' => -4); - + $mega_names = array(-1 => 'mega', -2 => 'mega_x', -3 => 'mega_y', -4 => 'primal'); + $pokemon_array = []; + $typeArray = [ + 1 => 'normal', + 2 => 'fighting', + 3 => 'flying', + 4 => 'poison', + 5 => 'ground', + 6 => 'rock', + 7 => 'bug', + 8 => 'ghost', + 9 => 'steel', + 10 => 'fire', + 11 => 'water', + 12 => 'grass', + 13 => 'electric', + 14 => 'psychic', + 15 => 'ice', + 16 => 'dragon', + 17 => 'dark', + 18 => 'fairy', + ]; $weatherboost_table = array( - 'POKEMON_TYPE_BUG' => '3', - 'POKEMON_TYPE_DARK' => '8', - 'POKEMON_TYPE_DRAGON' => '6', - 'POKEMON_TYPE_ELECTRIC' => '3', - 'POKEMON_TYPE_FAIRY' => '5', - 'POKEMON_TYPE_FIGHTING' => '5', - 'POKEMON_TYPE_FIRE' => '12', - 'POKEMON_TYPE_FLYING' => '6', - 'POKEMON_TYPE_GHOST' => '8', - 'POKEMON_TYPE_GRASS' => '12', - 'POKEMON_TYPE_GROUND' => '12', - 'POKEMON_TYPE_ICE' => '7', - 'POKEMON_TYPE_NORMAL' => '4', - 'POKEMON_TYPE_POISON' => '5', - 'POKEMON_TYPE_PSYCHIC' => '6', - 'POKEMON_TYPE_ROCK' => '4', - 'POKEMON_TYPE_STEEL' => '7', - 'POKEMON_TYPE_WATER' => '3' + 1 => '4', + 2 => '5', + 3 => '6', + 4 => '5', + 5 => '12', + 6 => '4', + 7 => '3', + 8 => '8', + 9 => '7', + 10 => '12', + 11 => '3', + 12 => '12', + 13 => '3', + 14 => '6', + 15 => '7', + 16 => '6', + 17 => '8', + 18 => '5', ); if(!$master_file = curl_get_contents($game_master_url)) return false; $master = json_decode($master_file, true); - foreach($master as $row) { - $part = explode('_', $row['templateId']); - $form_data = []; - $pokemon_id = ''; - if(count($part) < 2) continue; - if(preg_match('/FORMS_V([0-9]*)_POKEMON_([a-zA-Z0-9_]*)/', $row['templateId'], $matches)) { - // Found Pokemon form data - $pokemon_id = (int)$matches[1]; - $pokemon_name = $matches[2]; - // Get pokemon forms - if(!isset($row['data']['formSettings']['forms']) or empty($row['data']['formSettings']['forms'][0])) { - $form_data[] = array('form' => $pokemon_name . '_NORMAL'); - }else { - $form_data = $row['data']['formSettings']['forms']; - } - foreach($form_data as $form) { - // This is some new niantic shit - $pokemon_form_name = $form['form']; - if(is_int($form['form'])) { - $pokemon_form_name = $form_names[$form['form']]; - } - $form_name = strtolower(str_replace($pokemon_name.'_','',$pokemon_form_name)); - if($form_name == 'purified' || $form_name == 'shadow') continue; - $poke_name = ucfirst(strtolower($row['data']['formSettings']['pokemon'])); - $form_id = $form_ids[$pokemon_form_name] ?? 0; - - $pokemon_array[$pokemon_id][$form_name] = [ - 'pokemon_name' => $poke_name, - 'pokemon_form_name' => $form_name, - 'pokemon_form_id' => $form_id, - ]; - } - }else if (preg_match('/V([0-9]*)_POKEMON_([a-zA-Z0-9_]*)/', $row['templateId'], $matches) && isset($row['data']['pokemonSettings'])) { - // Found Pokemon data - $pokemon_id = (int)$matches[1]; - $form_name = str_replace($row['data']['pokemonSettings']['pokemonId'] . '_', '', $matches[2]); - if($form_name == 'PURIFIED' || $form_name == 'SHADOW' || $form_name == 'NORMAL' - || !isset($pokemon_array[$pokemon_id]) - || !isset($row['data']['pokemonSettings']['stats']['baseAttack']) - || !isset($row['data']['pokemonSettings']['stats']['baseDefense']) - || !isset($row['data']['pokemonSettings']['stats']['baseStamina']) - ) { + foreach($master['pokemon'] as $row) { + $pokemon_id = $row['pokedexId']; + $pokemon_name = $row['name']; + if(!isset($row['stats']['attack']) || !isset($row['stats']['defense']) || !isset($row['stats']['stamina'])) { + continue; + } + [$min_cp, $max_cp, $min_weather_cp, $max_weather_cp] = calculate_cps($row['stats']); + $type = $type2 = ''; + foreach($row['types'] as $key => $data) { + if($type == '') { + $type = $typeArray[$key]; + $weather = $weatherboost_table[$key]; continue; } - if($form_name != $row['data']['pokemonSettings']['pokemonId']) { - $form_name = strtolower($form_name); - }else { - $form_name = 'normal'; - } - [$min_cp, $max_cp, $min_weather_cp, $max_weather_cp] = calculate_cps($row['data']['pokemonSettings']['stats']); - - $type = strtolower(str_replace('POKEMON_TYPE_', '', $row['data']['pokemonSettings']['type'])); - $type2 = ''; - - $weather = $weatherboost_table[$row['data']['pokemonSettings']['type']]; - if(isset($row['data']['pokemonSettings']['type2'])) { - $type2 = strtolower(str_replace('POKEMON_TYPE_', '', $row['data']['pokemonSettings']['type2'])); - - # Add type2 weather boost only if there is a second type and it's not the same weather as the first type! - if($weatherboost_table[$row['data']['pokemonSettings']['type2']] != $weatherboost_table[$row['data']['pokemonSettings']['type']]) { - $weather .= $weatherboost_table[$row['data']['pokemonSettings']['type2']]; - } - } - if(isset($pokemon_array[$pokemon_id][$form_name])) { - $pokemon_array[$pokemon_id][$form_name]['min_cp'] = $min_cp; - $pokemon_array[$pokemon_id][$form_name]['max_cp'] = $max_cp; - $pokemon_array[$pokemon_id][$form_name]['min_weather_cp'] = $min_weather_cp; - $pokemon_array[$pokemon_id][$form_name]['max_weather_cp'] = $max_weather_cp; - $pokemon_array[$pokemon_id][$form_name]['weather'] = $weather; - $pokemon_array[$pokemon_id][$form_name]['type'] = $type; - $pokemon_array[$pokemon_id][$form_name]['type2'] = $type2; - }else { - // Fill data for Pokemon that have form data but no stats for forms specifically - foreach($pokemon_array[$pokemon_id] as $form => $data) { - $pokemon_array[$pokemon_id][$form]['min_cp'] = $min_cp; - $pokemon_array[$pokemon_id][$form]['max_cp'] = $max_cp; - $pokemon_array[$pokemon_id][$form]['min_weather_cp'] = $min_weather_cp; - $pokemon_array[$pokemon_id][$form]['max_weather_cp'] = $max_weather_cp; - $pokemon_array[$pokemon_id][$form]['weather'] = $weather; - $pokemon_array[$pokemon_id][$form]['type'] = $type; - $pokemon_array[$pokemon_id][$form]['type2'] = $type2; - } - } - if(!isset($row['data']['pokemonSettings']['tempEvoOverrides'])) continue; - foreach($row['data']['pokemonSettings']['tempEvoOverrides'] as $temp_evolution) { - if(!isset($temp_evolution['tempEvoId'])) continue; - - $mega_evolution_name = str_replace('TEMP_EVOLUTION_', '', $temp_evolution['tempEvoId']); - // We only override the types for megas - // weather info is used to display boosts for caught mons, which often are different from mega's typing - $typeOverride = strtolower(str_replace('POKEMON_TYPE_', '', $temp_evolution['typeOverride1'])); - $typeOverride2 = ''; - - if(isset($temp_evolution['typeOverride2'])) { - $typeOverride2 = strtolower(str_replace('POKEMON_TYPE_', '', $temp_evolution['typeOverride2'])); + $type2 = $typeArray[$key]; + $weather .= $weatherboost_table[$key]; + } + foreach($row['forms'] as $formId => $formData) { + if($formId == 0 || $formData['name'] == 'Shadow' || $formData['name'] == 'Purified') continue; + $form_name = strtolower(preg_replace('/\s/', '_', $formData['name'])); + $form_id = $formData['form']; + $pokemon_array[$pokemon_id][$form_name] = [ + 'pokemon_name' => $pokemon_name, + 'pokemon_form_name' => $form_name, + 'pokemon_form_id' => $form_id, + 'min_cp' => $min_cp, + 'max_cp' => $max_cp, + 'min_weather_cp' => $min_weather_cp, + 'max_weather_cp' => $max_weather_cp, + 'weather' => $weather, + 'type' => $type, + 'type2' => $type2, + ]; + } + if(!isset($row['tempEvolutions'])) continue; + foreach($row['tempEvolutions'] as $tempData) { + if(isset($tempData['unreleased']) && $tempData['unreleased']) continue; + $form_id = -$tempData['tempEvoId']; + $form_name = $mega_names[$form_id]; + if(isset($tempData['types'])) { + foreach($tempData['types'] as $key => $data) { + if($type == '') { + $type = $key; + $weather = $weatherboost_table[$key]; + continue; + } + $type2 = $key; + $weather .= $weatherboost_table[$key]; } - $pokemon_array[$pokemon_id][$mega_evolution_name] = [ - 'pokemon_name' => $pokemon_array[$pokemon_id][$form_name]['pokemon_name'], - 'pokemon_form_name' => strtolower($mega_evolution_name), - 'pokemon_form_id' => $mega_ids[$mega_evolution_name], - 'min_cp' => $min_cp, - 'max_cp' => $max_cp, - 'min_weather_cp' => $min_weather_cp, - 'max_weather_cp' => $max_weather_cp, - 'weather' => $weather, - 'type' => $typeOverride, - 'type2' => $typeOverride2, - ]; } + $pokemon_array[$pokemon_id][$form_name] = [ + 'pokemon_name' => $pokemon_name, + 'pokemon_form_name' => $form_name, + 'pokemon_form_id' => $form_id, + 'min_cp' => $min_cp, + 'max_cp' => $max_cp, + 'min_weather_cp' => $min_weather_cp, + 'max_weather_cp' => $max_weather_cp, + 'weather' => $weather, + 'type' => $type, + 'type2' => $type2, + ]; } } - return $pokemon_array; + $costume_data = []; + foreach($master['costumes'] as $costume) { + $costume_data[$costume['proto']] = $costume['id']; + } + return [$pokemon_array, $costume_data]; } From b70af9d79e189d37616c5f65af75f33b18b423c3 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 5 Dec 2023 00:03:30 +0200 Subject: [PATCH 295/367] New source for translations and stuff - New source for translations - Create Pokemon form translations automagically - Use automated shadow translation instead of manual - Use only form name if form name contains Pokemon name e.g. Black Kyurem, Frost Rotom --- getTranslations.php | 152 +- lang/language.json | 13 - lang/pokemon.json | 184 +-- lang/pokemon_forms.json | 2291 +++++++++++++++++++----------- lang/pokemon_moves.json | 62 +- logic/get_local_pokemon_name.php | 12 +- logic/raid_picture.php | 2 +- logic/show_raid_poll.php | 2 +- logic/show_raid_poll_small.php | 2 +- 9 files changed, 1652 insertions(+), 1068 deletions(-) diff --git a/getTranslations.php b/getTranslations.php index d89ef533..bb075080 100644 --- a/getTranslations.php +++ b/getTranslations.php @@ -1,127 +1,77 @@ ['PT-BR'], - 'english' => ['EN'], - 'french' => ['FR'], - 'german' => ['DE'], - 'italian' => ['IT'], - 'russian' => ['RU'], - 'spanish' => ['ES'], -]; -$move_translations_to_fetch = [ - 'brazilianportuguese' => ['PT-BR'], - 'english' => ['EN', 'FI', 'NL', 'NO', 'PL'], - 'french' => ['FR'], - 'german' => ['DE'], - 'italian' => ['IT'], - 'russian' => ['RU'], - 'spanish' => ['ES'], +$translations_to_fetch = [ + 'pt-br' => 'PT-BR', + 'en' => 'EN', + 'fr' => 'FR', + 'de' => 'DE', + 'it' => 'IT', + 'ru' => 'RU', + 'es' => 'ES', ]; // Initialize array -$move_array = []; -$pokemon_array = []; +$move_array = $pokemon_array = $form_array = []; +$gameMasterFile = curl_open_file($game_master_url); +$master = json_decode($gameMasterFile, true); +$formsToFetch = []; -// Loop through all available translations -foreach($translations_available as $language) { - $write_pokemon_translation = array_key_exists($language, $pokemon_translations_to_fetch); - $write_move_translation = array_key_exists($language, $move_translations_to_fetch); - - // Only read the file if a translation is wanted - if( !$write_pokemon_translation && !$write_move_translation ) { - continue; +// Collect form names currently in use and only translate these +// We use english names as identifiers when saving these translations so we can also use these for that +foreach($master['pokemon'] as $masterPokemon) { + if(!isset($masterPokemon['forms'])) continue; + foreach($masterPokemon['forms'] as $form) { + if($form['form'] == 0 || in_array($form['name'], $formsToFetch)) continue; + $formsToFetch[] = $form['name']; } - $file = curl_open_file('https://raw.githubusercontent.com/PokeMiners/pogo_assets/master/Texts/Latest%20APK/JSON/i18n_'. $language. '.json'); - $translation = json_decode($file, true); - $title = true; - foreach($translation['data'] as $row) { - // Handle resource ID rows - if($title) { - $resource_part = explode('_',$row); - // Only proceed to processing translation if it's pokemon/move name and it isn't a mega pokemon name - if(count($resource_part) == 3 && $resource_part[1] == 'name') { - $title = false; - } - continue; - } - // Handle text rows - $id = intval($resource_part[2]); // remove leading zeroes +} + +// Loop through translations +foreach($translations_to_fetch as $lanfile => $language) { + $file = curl_open_file('https://raw.githubusercontent.com/WatWowMap/pogo-translations/master/static/locales/'. $lanfile. '.json'); + $translationData = json_decode($file, true); + foreach($translationData as $title => $translation) { + $split = explode('_', $title, 2); + if(count($split) < 2 or intval($split[1]) <= 0) continue; + [$key, $id] = $split; // Save pokemon names into an array if pokemon id is larger than 0 - if($write_pokemon_translation && $resource_part[0] == 'pokemon' && $id > 0) { - foreach($pokemon_translations_to_fetch[$language] as $lan) { - $pokemon_array['pokemon_id_'.$id][$lan] = $row; - } + if($key == 'poke') { + $pokemon_array['pokemon_id_'.$id][$language] = $translation; // Save pokemon moves into an array - }elseif($write_move_translation && $resource_part[0] == 'move') { - foreach($move_translations_to_fetch[$language] as $lan) { - $move_array['pokemon_move_'.$id][$lan] = $row; - } + }elseif($key == 'move') { + $move_array['pokemon_move_'.$id][$language] = $translation; } - $title = true; } - /* - // Open the file(s) and write it into an array - foreach($lang_directory_url as $url) { - $file = curl_open_file($url . $language . '.txt'); - $data = preg_split('/\r\n|\r|\n/', $file); - - // Read the file line by line - foreach($data as $row) { - // Handle resource ID rows - if(substr($row, 0, 1) == 'R') { - $resource_id = substr(trim($row), 13); - $resource_part = explode('_',$resource_id); - } - // Handle text rows - if(substr($row, 0, 1) == 'T') { - $text = substr(trim($row), 6); - - // Filter out mega translations - if(count($resource_part) != 3 || $resource_part[1] != 'name') { - continue; - } - $id = intval($resource_part[2]); // remove leading zeroes - // Save pokemon names into an array if pokemon id is larger than 0 - if($write_pokemon_translation && $resource_part[0] == 'pokemon' && $id > 0) { - foreach($pokemon_translations_to_fetch[$language] as $lan) { - $pokemon_array['pokemon_id_'.$id][$lan] = $text; - } - // Save pokemon moves into an array - }elseif($write_move_translation && $resource_part[0] == 'move') { - foreach($move_translations_to_fetch[$language] as $lan) { - $move_array['pokemon_move_'.$id][$lan] = $text; - } - } - } + // This translation file uses english names as reference + $formFile = curl_open_file('https://raw.githubusercontent.com/WatWowMap/pogo-translations/master/static/englishRef/forms_'. $lanfile. '.json'); + $formTranslationData = json_decode($formFile, true); + foreach($formTranslationData as $title => $translation) { + if(in_array($title, $formsToFetch)) { + $formName = preg_replace("/\s/", "_", strtolower($title)); + $form_array['pokemon_form_'. $formName][$language] = $translation; } - unset($file); - unset($data); - }*/ + } } + // Bot defaults to using english translations, so no need to add duplicates for every language $pokemon_array = remove_duplicate_translations($pokemon_array); $move_array = remove_duplicate_translations($move_array); +$form_array = remove_duplicate_translations($form_array); -// Build the path to move translation file -$moves_translation_file = $lang_dir . 'pokemon_moves.json'; - -// Save translations to the file -file_put_contents($moves_translation_file, json_encode($move_array,JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX); - -// Build the path to translation file $pokemon_translation_file = $lang_dir . 'pokemon.json'; +$moves_translation_file = $lang_dir . 'pokemon_moves.json'; +$forms_translation_file = $lang_dir . 'pokemon_forms.json'; -// Save translations to file file_put_contents($pokemon_translation_file, json_encode($pokemon_array,JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX); +file_put_contents($moves_translation_file, json_encode($move_array,JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX); +file_put_contents($forms_translation_file, json_encode($form_array,JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX); function curl_open_file($input) { $ch = curl_init(); diff --git a/lang/language.json b/lang/language.json index 1b709397..5995c59d 100644 --- a/lang/language.json +++ b/lang/language.json @@ -792,19 +792,6 @@ "FI": "Et voi käyttää tätä käskyä ennen kuin olet käynyt ohjeen läpi.", "ES": "No puede usar este comando antes de seguir el tutorial." }, - "shadow": { - "NL": "TRANSLATE", - "DE": "TRANSLATE", - "EN": "Shadow", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Shadow", - "ES": "TRANSLATE" - }, "raid": { "NL": "Raid", "DE": "Raid", diff --git a/lang/pokemon.json b/lang/pokemon.json index 204ea242..ce815d80 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -99,7 +99,7 @@ "EN": "Pidgeotto", "FR": "Roucoups", "DE": "Tauboga", - "RU": "Пиджеотто" + "RU": "Пиджeотто" }, "pokemon_id_18": { "EN": "Pidgeot", @@ -138,7 +138,7 @@ }, "pokemon_id_24": { "EN": "Arbok", - "RU": "Арбок" + "RU": "Эрбок" }, "pokemon_id_25": { "EN": "Pikachu", @@ -199,7 +199,7 @@ "pokemon_id_37": { "EN": "Vulpix", "FR": "Goupix", - "RU": "Валпикс" + "RU": "Вульпикс" }, "pokemon_id_38": { "EN": "Ninetales", @@ -402,7 +402,7 @@ "pokemon_id_73": { "EN": "Tentacruel", "DE": "Tentoxa", - "RU": "Тентакрул" + "RU": "Тентакруэль" }, "pokemon_id_74": { "EN": "Geodude", @@ -414,7 +414,7 @@ "EN": "Graveler", "FR": "Gravalanch", "DE": "Georok", - "RU": "Гравелер" + "RU": "Грейвлер" }, "pokemon_id_76": { "EN": "Golem", @@ -461,7 +461,7 @@ "FR": "Canarticho", "DE": "Porenta", "IT": "Farfetch’d", - "RU": "Фарфетчд" + "RU": "Фарфетч'т" }, "pokemon_id_84": { "EN": "Doduo", @@ -483,7 +483,7 @@ "EN": "Dewgong", "FR": "Lamantine", "DE": "Jugong", - "RU": "Дьюгонг" + "RU": "Дюгонг" }, "pokemon_id_88": { "EN": "Grimer", @@ -534,7 +534,7 @@ "EN": "Drowzee", "FR": "Soporifik", "DE": "Traumato", - "RU": "Драузи" + "RU": "Дроузи" }, "pokemon_id_97": { "EN": "Hypno", @@ -554,7 +554,7 @@ "EN": "Voltorb", "FR": "Voltorbe", "DE": "Voltobal", - "RU": "Волторб" + "RU": "Вальторб" }, "pokemon_id_101": { "EN": "Electrode", @@ -566,7 +566,7 @@ "EN": "Exeggcute", "FR": "Noeunoeuf", "DE": "Owei", - "RU": "Эксегкьют" + "RU": "Экзегкьют" }, "pokemon_id_103": { "EN": "Exeggutor", @@ -602,7 +602,7 @@ "EN": "Lickitung", "FR": "Excelangue", "DE": "Schlurp", - "RU": "Ликитанг" + "RU": "Ликитунг" }, "pokemon_id_109": { "EN": "Koffing", @@ -727,7 +727,7 @@ "EN": "Gyarados", "FR": "Léviator", "DE": "Garados", - "RU": "Гиарадос" + "RU": "Гиардос" }, "pokemon_id_131": { "EN": "Lapras", @@ -874,7 +874,7 @@ "pokemon_id_157": { "EN": "Typhlosion", "DE": "Tornupto", - "RU": "Тайфложн" + "RU": "Тифложн" }, "pokemon_id_158": { "EN": "Totodile", @@ -892,7 +892,7 @@ "EN": "Feraligatr", "FR": "Aligatueur", "DE": "Impergator", - "RU": "Фералигейтор" + "RU": "Фералигатор" }, "pokemon_id_161": { "EN": "Sentret", @@ -971,11 +971,11 @@ }, "pokemon_id_175": { "EN": "Togepi", - "RU": "Тогэпи" + "RU": "Тогепи" }, "pokemon_id_176": { "EN": "Togetic", - "RU": "Тогэтик" + "RU": "Тогетик" }, "pokemon_id_177": { "EN": "Natu", @@ -983,7 +983,7 @@ }, "pokemon_id_178": { "EN": "Xatu", - "RU": "Ксату" + "RU": "Зату" }, "pokemon_id_179": { "EN": "Mareep", @@ -1010,7 +1010,7 @@ }, "pokemon_id_183": { "EN": "Marill", - "RU": "Мэрилл" + "RU": "Марилл" }, "pokemon_id_184": { "EN": "Azumarill", @@ -1130,13 +1130,13 @@ "EN": "Pineco", "FR": "Pomdepik", "DE": "Tannza", - "RU": "Пайнеко" + "RU": "Пинеко" }, "pokemon_id_205": { "EN": "Forretress", "FR": "Foretress", "DE": "Forstellka", - "RU": "Форретресс" + "RU": "Форретресc" }, "pokemon_id_206": { "EN": "Dunsparce", @@ -1148,7 +1148,7 @@ "EN": "Gligar", "FR": "Scorplane", "DE": "Skorgla", - "RU": "Глайгар" + "RU": "Глигар" }, "pokemon_id_208": { "EN": "Steelix", @@ -1161,7 +1161,7 @@ }, "pokemon_id_210": { "EN": "Granbull", - "RU": "Грэнбулл" + "RU": "Гранбулл" }, "pokemon_id_211": { "EN": "Qwilfish", @@ -1190,7 +1190,7 @@ "EN": "Sneasel", "FR": "Farfuret", "DE": "Sniebel", - "RU": "Снизел" + "RU": "Снизель" }, "pokemon_id_216": { "EN": "Teddiursa", @@ -1276,15 +1276,15 @@ }, "pokemon_id_231": { "EN": "Phanpy", - "RU": "Фэнпи" + "RU": "Фанпи" }, "pokemon_id_232": { "EN": "Donphan", - "RU": "Донфэн" + "RU": "Донфан" }, "pokemon_id_233": { "EN": "Porygon2", - "RU": "Поригон-2" + "RU": "Поригон2" }, "pokemon_id_234": { "EN": "Stantler", @@ -1302,7 +1302,7 @@ "EN": "Tyrogue", "FR": "Debugant", "DE": "Rabauz", - "RU": "Тайрог" + "RU": "Тироуг" }, "pokemon_id_237": { "EN": "Hitmontop", @@ -1346,7 +1346,7 @@ }, "pokemon_id_245": { "EN": "Suicune", - "RU": "Суикун" + "RU": "Суйкун" }, "pokemon_id_246": { "EN": "Larvitar", @@ -1356,7 +1356,7 @@ "pokemon_id_247": { "EN": "Pupitar", "FR": "Ymphect", - "RU": "Пьюпитар" + "RU": "Пупитар" }, "pokemon_id_248": { "EN": "Tyranitar", @@ -1452,7 +1452,7 @@ "EN": "Linoone", "FR": "Linéon", "DE": "Geradaks", - "RU": "Лайнун" + "RU": "Линун" }, "pokemon_id_265": { "EN": "Wurmple", @@ -1533,7 +1533,7 @@ "pokemon_id_278": { "EN": "Wingull", "FR": "Goélise", - "RU": "Вингалл" + "RU": "Вингулл" }, "pokemon_id_279": { "EN": "Pelipper", @@ -1544,7 +1544,7 @@ "EN": "Ralts", "FR": "Tarsal", "DE": "Trasla", - "RU": "Ролтс" + "RU": "Ральтс" }, "pokemon_id_281": { "EN": "Kirlia", @@ -1553,7 +1553,7 @@ "pokemon_id_282": { "EN": "Gardevoir", "DE": "Guardevoir", - "RU": "Гардевойр" + "RU": "Гардевуар" }, "pokemon_id_283": { "EN": "Surskit", @@ -1583,7 +1583,7 @@ "EN": "Slakoth", "FR": "Parecool", "DE": "Bummelz", - "RU": "Слакот" + "RU": "Слякот" }, "pokemon_id_288": { "EN": "Vigoroth", @@ -1645,7 +1645,7 @@ "EN": "Nosepass", "FR": "Tarinor", "DE": "Nasgnet", - "RU": "Ноузпасс" + "RU": "Ноуспасс" }, "pokemon_id_300": { "EN": "Skitty", @@ -1655,13 +1655,13 @@ "pokemon_id_301": { "EN": "Delcatty", "DE": "Enekoro", - "RU": "Делкатти" + "RU": "Деликэтти" }, "pokemon_id_302": { "EN": "Sableye", "FR": "Ténéfix", "DE": "Zobiris", - "RU": "Сэйблай" + "RU": "Сабляй" }, "pokemon_id_303": { "EN": "Mawile", @@ -1714,17 +1714,17 @@ "pokemon_id_311": { "EN": "Plusle", "FR": "Posipi", - "RU": "Пласл" + "RU": "Плюсл" }, "pokemon_id_312": { "EN": "Minun", "FR": "Négapi", - "RU": "Майнун" + "RU": "Минун" }, "pokemon_id_313": { "EN": "Volbeat", "FR": "Muciole", - "RU": "Волбит" + "RU": "Вольбит" }, "pokemon_id_314": { "EN": "Illumise", @@ -1740,7 +1740,7 @@ "EN": "Gulpin", "FR": "Gloupti", "DE": "Schluppuck", - "RU": "Гальпин" + "RU": "Гульпин" }, "pokemon_id_317": { "EN": "Swalot", @@ -1760,28 +1760,28 @@ }, "pokemon_id_320": { "EN": "Wailmer", - "RU": "Вэйлмер" + "RU": "Вейлмер" }, "pokemon_id_321": { "EN": "Wailord", - "RU": "Вэйлорд" + "RU": "Вейлорд" }, "pokemon_id_322": { "EN": "Numel", "FR": "Chamallot", "DE": "Camaub", - "RU": "Намел" + "RU": "Нумел" }, "pokemon_id_323": { "EN": "Camerupt", "FR": "Camérupt", - "RU": "Камерапт" + "RU": "Камерупт" }, "pokemon_id_324": { "EN": "Torkoal", "FR": "Chartor", "DE": "Qurtel", - "RU": "Торкол" + "RU": "Торкоал" }, "pokemon_id_325": { "EN": "Spoink", @@ -1818,7 +1818,7 @@ "pokemon_id_331": { "EN": "Cacnea", "DE": "Tuska", - "RU": "Какнея" + "RU": "Какния" }, "pokemon_id_332": { "EN": "Cacturne", @@ -1829,11 +1829,11 @@ "EN": "Swablu", "FR": "Tylton", "DE": "Wablu", - "RU": "Сваблу" + "RU": "Сваблю" }, "pokemon_id_334": { "EN": "Altaria", - "RU": "Алтария" + "RU": "Альтария" }, "pokemon_id_335": { "EN": "Zangoose", @@ -1863,7 +1863,7 @@ "EN": "Barboach", "FR": "Barloche", "DE": "Schmerbe", - "RU": "Барбоч" + "RU": "Барбоуч" }, "pokemon_id_340": { "EN": "Whiscash", @@ -1881,7 +1881,7 @@ "EN": "Crawdaunt", "FR": "Colhomard", "DE": "Krebutack", - "RU": "Крадонт" + "RU": "Краудонт" }, "pokemon_id_343": { "EN": "Baltoy", @@ -1924,7 +1924,7 @@ "pokemon_id_350": { "EN": "Milotic", "FR": "Milobellus", - "RU": "Майлотик" + "RU": "Милотик" }, "pokemon_id_351": { "EN": "Castform", @@ -1966,7 +1966,7 @@ "EN": "Chimecho", "FR": "Éoko", "DE": "Palimpalim", - "RU": "Чаймеко" + "RU": "Чимечо" }, "pokemon_id_359": { "EN": "Absol", @@ -2040,7 +2040,7 @@ "EN": "Bagon", "FR": "Draby", "DE": "Kindwurm", - "RU": "Бейгон" + "RU": "Багон" }, "pokemon_id_372": { "EN": "Shelgon", @@ -2058,7 +2058,7 @@ "EN": "Beldum", "FR": "Terhal", "DE": "Tanhel", - "RU": "Белдам" + "RU": "Белдум" }, "pokemon_id_375": { "EN": "Metang", @@ -2216,7 +2216,7 @@ "pokemon_id_405": { "EN": "Luxray", "DE": "Luxtra", - "RU": "Лаксрэй" + "RU": "Лаксрей" }, "pokemon_id_406": { "EN": "Budew", @@ -2226,7 +2226,7 @@ }, "pokemon_id_407": { "EN": "Roserade", - "RU": "Розрейд" + "RU": "Розерейд" }, "pokemon_id_408": { "EN": "Cranidos", @@ -2238,7 +2238,7 @@ "EN": "Rampardos", "FR": "Charkos", "DE": "Rameidon", - "RU": "Рэмпардос" + "RU": "Рампардос" }, "pokemon_id_410": { "EN": "Shieldon", @@ -2288,7 +2288,7 @@ "EN": "Buizel", "FR": "Mustébouée", "DE": "Bamelin", - "RU": "Буизел" + "RU": "Буизель" }, "pokemon_id_419": { "EN": "Floatzel", @@ -2300,7 +2300,7 @@ "EN": "Cherubi", "FR": "Ceribou", "DE": "Kikugi", - "RU": "Чераби" + "RU": "Черуби" }, "pokemon_id_421": { "EN": "Cherrim", @@ -2341,7 +2341,7 @@ "EN": "Buneary", "FR": "Laporeille", "DE": "Haspiror", - "RU": "Бунири" + "RU": "Банири" }, "pokemon_id_428": { "EN": "Lopunny", @@ -2359,13 +2359,13 @@ "EN": "Honchkrow", "FR": "Corboss", "DE": "Kramshef", - "RU": "Хончкроу" + "RU": "Ханчкроу" }, "pokemon_id_431": { "EN": "Glameow", "FR": "Chaglam", "DE": "Charmian", - "RU": "Глеймяу" + "RU": "Гламяу" }, "pokemon_id_432": { "EN": "Purugly", @@ -2410,7 +2410,7 @@ "pokemon_id_439": { "EN": "Mime Jr.", "DE": "Pantimimi", - "RU": "Майм-Джуниор" + "RU": "Майм-джуниор" }, "pokemon_id_440": { "EN": "Happiny", @@ -2427,7 +2427,7 @@ "pokemon_id_442": { "EN": "Spiritomb", "DE": "Kryppuk", - "RU": "Спиритум" + "RU": "Спиритомб" }, "pokemon_id_443": { "EN": "Gible", @@ -2521,7 +2521,7 @@ "EN": "Snover", "FR": "Blizzi", "DE": "Shnebedeck", - "RU": "Сноувер" + "RU": "Сновер" }, "pokemon_id_460": { "EN": "Abomasnow", @@ -2556,7 +2556,7 @@ "EN": "Tangrowth", "FR": "Bouldeneu", "DE": "Tangoloss", - "RU": "Тэнгроут" + "RU": "Тангроут" }, "pokemon_id_466": { "EN": "Electivire", @@ -2594,7 +2594,7 @@ "EN": "Gliscor", "FR": "Scorvol", "DE": "Skorgro", - "RU": "Глайскор" + "RU": "Глискор" }, "pokemon_id_473": { "EN": "Mamoswine", @@ -2604,7 +2604,7 @@ }, "pokemon_id_474": { "EN": "Porygon-Z", - "RU": "Поригон-Z" + "RU": "ПоригонZ" }, "pokemon_id_475": { "EN": "Gallade", @@ -2651,7 +2651,7 @@ "EN": "Azelf", "FR": "Créfadet", "DE": "Tobutz", - "RU": "Азелф" + "RU": "Азельф" }, "pokemon_id_483": { "EN": "Dialga", @@ -2765,7 +2765,7 @@ "EN": "Watchog", "FR": "Miradar", "DE": "Kukmarda", - "RU": "Уочхог" + "RU": "Вочхог" }, "pokemon_id_506": { "EN": "Lillipup", @@ -2777,7 +2777,7 @@ "EN": "Herdier", "FR": "Ponchien", "DE": "Terribark", - "RU": "Хардиер" + "RU": "Хердиер" }, "pokemon_id_508": { "EN": "Stoutland", @@ -2795,7 +2795,7 @@ "EN": "Liepard", "FR": "Léopardus", "DE": "Kleoparda", - "RU": "Лайпард" + "RU": "Липард" }, "pokemon_id_511": { "EN": "Pansage", @@ -2860,7 +2860,7 @@ "EN": "Unfezant", "FR": "Déflaisan", "DE": "Fasasnob", - "RU": "Унфезант" + "RU": "Анфезант" }, "pokemon_id_522": { "EN": "Blitzle", @@ -2908,7 +2908,7 @@ "EN": "Drilbur", "FR": "Rototaupe", "DE": "Rotomurf", - "RU": "Дрилбур" + "RU": "Дрильбур" }, "pokemon_id_530": { "EN": "Excadrill", @@ -2926,7 +2926,7 @@ "EN": "Timburr", "FR": "Charpenti", "DE": "Praktibalk", - "RU": "Тимбёрр" + "RU": "Тимбурр" }, "pokemon_id_533": { "EN": "Gurdurr", @@ -2938,7 +2938,7 @@ "EN": "Conkeldurr", "FR": "Bétochef", "DE": "Meistagrif", - "RU": "Конкельдар\n" + "RU": "Конкльдурр" }, "pokemon_id_535": { "EN": "Tympole", @@ -2950,13 +2950,13 @@ "EN": "Palpitoad", "FR": "Batracné", "DE": "Mebrana", - "RU": "Палпитоуд" + "RU": "Палпитоад" }, "pokemon_id_537": { "EN": "Seismitoad", "FR": "Crapustule", "DE": "Branawarz", - "RU": "Сейсмитоуд" + "RU": "Сейсмитоад" }, "pokemon_id_538": { "EN": "Throh", @@ -3064,7 +3064,7 @@ "EN": "Darmanitan", "FR": "Darumacho", "DE": "Flampivian", - "RU": "Дарманитан" + "RU": "Дармантан" }, "pokemon_id_556": { "EN": "Maractus", @@ -3174,19 +3174,19 @@ "EN": "Gothita", "FR": "Scrutella", "DE": "Mollimorba", - "RU": "Гофита" + "RU": "Готита" }, "pokemon_id_575": { "EN": "Gothorita", "FR": "Mesmérella", "DE": "Hypnomorba", - "RU": "Гофорита" + "RU": "Готорита" }, "pokemon_id_576": { "EN": "Gothitelle", "FR": "Sidérella", "DE": "Morbitesse", - "RU": "Гофителль" + "RU": "Готителль" }, "pokemon_id_577": { "EN": "Solosis", @@ -3388,13 +3388,13 @@ "EN": "Axew", "FR": "Coupenotte", "DE": "Milza", - "RU": "Эксью" + "RU": "Аксью" }, "pokemon_id_611": { "EN": "Fraxure", "FR": "Incisache", "DE": "Sharfax", - "RU": "Фрэкшур" + "RU": "Фрэксюр" }, "pokemon_id_612": { "EN": "Haxorus", @@ -3538,7 +3538,7 @@ "EN": "Hydreigon", "FR": "Trioxhydre", "DE": "Trikephalo", - "RU": "Хайдрайгон" + "RU": "Хайдрагон" }, "pokemon_id_636": { "EN": "Larvesta", @@ -3568,7 +3568,7 @@ "EN": "Virizion", "FR": "Viridium", "DE": "Viridium", - "RU": "Вирижион" + "RU": "Виризион" }, "pokemon_id_641": { "EN": "Tornadus", @@ -3598,7 +3598,7 @@ }, "pokemon_id_646": { "EN": "Kyurem", - "RU": "Курем" + "RU": "Кьюрем" }, "pokemon_id_647": { "EN": "Keldeo", @@ -3610,7 +3610,7 @@ }, "pokemon_id_649": { "EN": "Genesect", - "RU": "Дженесект" + "RU": "Генесект" }, "pokemon_id_650": { "EN": "Chespin", @@ -4388,19 +4388,19 @@ "EN": "Jangmo-o", "FR": "Bébécaille", "DE": "Miniras", - "RU": "Джангмо-о" + "RU": "Джангмоо" }, "pokemon_id_783": { "EN": "Hakamo-o", "FR": "Écaïd", "DE": "Mediras", - "RU": "Хакамо-o" + "RU": "Хакамоo" }, "pokemon_id_784": { "EN": "Kommo-o", "FR": "Ékaïser", "DE": "Grandiras", - "RU": "Коммо-o" + "RU": "Коммоo" }, "pokemon_id_785": { "EN": "Tapu Koko", diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index 789870c1..113de507 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -1,845 +1,1448 @@ { - "pokemon_form_alola": { - "NL": "Alolan", - "DE": "Alola", - "EN": "Alolan", - "IT": "TRANSLATE", - "PT-BR": "de Alola", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Alolan", - "FI": "Alolan", - "ES": "Alola" - }, - "pokemon_form_galarian": { - "NL": "Galarian", - "DE": "Galar", - "EN": "Galarian", - "IT": "Galarian", - "PT-BR": "Galarian", - "RU": "Galarian", - "NO": "Galarian", - "FR": "Galarian", - "PL": "Galarian", - "FI": "Galarian", - "ES": "Galar" - }, - "pokemon_form_hisuian": { - "NL": "Hisuian", - "DE": "TRANSLATE", - "EN": "Hisuian", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Hisuian", - "ES": "TRANSLATE" - }, - "pokemon_form_primal": { - "NL": "Primal", - "DE": "TRANSLATE", - "EN": "Primal", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Primal", - "ES": "TRANSLATE" - }, - "pokemon_form_mega": { - "NL": "Mega", - "DE": "TRANSLATE", - "EN": "Mega", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Mega", - "ES": "Mega" - }, - "pokemon_form_mega_x": { - "NL": "Mega X", - "DE": "TRANSLATE", - "EN": "Mega X", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Mega X", - "ES": "Mega X" - }, - "pokemon_form_mega_y": { - "NL": "Mega Y", - "DE": "TRANSLATE", - "EN": "Mega Y", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "FI": "Mega Y", - "ES": "Mega Y" - }, - "pokemon_form_a": { - "NL": "Armored", - "DE": "Rüstungsform", - "EN": "Armored", - "IT": "Armatura", - "PT-BR": "Armadura", - "RU": "Bronya", - "NO": "Rustning", - "FR": "Armure", - "ES": "Acorazado" - }, - "pokemon_form_attack": { - "NL": "Attack", - "DE": "Angriffsform", - "EN": "Attack", - "IT": "TRANSLATE", - "PT-BR": "Ataque", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Attack", - "ES": "Ataque" - }, - "pokemon_form_defense": { - "NL": "Defense", - "DE": "Verteidigungsform", - "EN": "Defense", - "IT": "TRANSLATE", - "PT-BR": "Defesa", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Defense", - "ES": "Defensa" - }, - "pokemon_form_speed": { - "NL": "Speed", - "DE": "Initiativeform", - "EN": "Speed", - "IT": "TRANSLATE", - "PT-BR": "Velocidade", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Speed", - "ES": "Velocidad" - }, - "pokemon_form_plant": { - "NL": "Plant", - "DE": "Pflanzenumhang", - "EN": "Plant", - "IT": "TRANSLATE", - "PT-BR": "Planta", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Plant", - "ES": "Planta" - }, - "pokemon_form_sandy": { - "NL": "Sandy", - "DE": "Sandumhang", - "EN": "Sandy", - "IT": "TRANSLATE", - "PT-BR": "Areia", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Sandy", - "ES": "Arena" - }, - "pokemon_form_trash": { - "NL": "Trash", - "DE": "Lumpenumhang", - "EN": "Trash", - "IT": "TRANSLATE", - "PT-BR": "Lixo", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Trash", - "ES": "Basura" - }, - "pokemon_form_overcast": { - "NL": "Overcast", - "DE": "Wolkenform", - "EN": "Overcast", - "IT": "TRANSLATE", - "PT-BR": "Negativo", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Overcast", - "ES": "Encapotada" - }, - "pokemon_form_sunny": { - "NL": "Sunny", - "DE": "Sonnenform", - "EN": "Sunny", - "IT": "TRANSLATE", - "PT-BR": "Positivo", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Sunny", - "ES": "Soleada" - }, - "pokemon_form_rainy": { - "NL": "Rainy", - "DE": "TRANSLATE", - "EN": "Rainy", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_snowy": { - "NL": "Snowy", - "DE": "TRANSLATE", - "EN": "Snowy", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_east_sea": { - "NL": "East", - "DE": "Ostform", - "EN": "East", - "IT": "TRANSLATE", - "PT-BR": "Leste", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "East", - "ES": "Este" - }, - "pokemon_form_west_sea": { - "NL": "West", - "DE": "Westform", - "EN": "West", - "IT": "TRANSLATE", - "PT-BR": "Oeste", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "West", - "ES": "Oeste" - }, - "pokemon_form_fan": { - "NL": "Fan", - "DE": "Wirbel-Form", - "EN": "Fan", - "IT": "TRANSLATE", - "PT-BR": "Ventilador", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Fan", - "ES": "Ventilador" - }, - "pokemon_form_frost": { - "NL": "Frost", - "DE": "Frost-Form", - "EN": "Frost", - "IT": "TRANSLATE", - "PT-BR": "Congelado", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Frost", - "ES": "Frío" - }, - "pokemon_form_heat": { - "NL": "Heat", - "DE": "Hitze-Form", - "EN": "Heat", - "IT": "TRANSLATE", - "PT-BR": "Calor", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Heat", - "ES": "Calor" - }, - "pokemon_form_mow": { - "NL": "Mow", - "DE": "Schneid-Form", - "EN": "Mow", - "IT": "TRANSLATE", - "PT-BR": "Cortador", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Mow", - "ES": "Corte" - }, - "pokemon_form_wash": { - "NL": "Wash", - "DE": "Wasch-Form", - "EN": "Wash", - "IT": "TRANSLATE", - "PT-BR": "Lavagem", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Wash", - "ES": "Lavado" - }, - "pokemon_form_altered": { - "NL": "Altered", - "DE": "Wandelform", - "EN": "Altered", - "IT": "TRANSLATE", - "PT-BR": "Alterado", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Altered", - "ES": "Modificada" - }, - "pokemon_form_origin": { - "NL": "Origin", - "DE": "Urform", - "EN": "Origin", - "IT": "TRANSLATE", - "PT-BR": "Original", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Origin", - "ES": "Origen" - }, - "pokemon_form_land": { - "NL": "Land", - "DE": "Landform", - "EN": "Land", - "IT": "TRANSLATE", - "PT-BR": "Terrestre", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Land", - "ES": "Tierra" - }, - "pokemon_form_sky": { - "NL": "Sky", - "DE": "Zenitform", - "EN": "Sky", - "IT": "TRANSLATE", - "PT-BR": "Celeste", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Sky", - "ES": "Cielo" - }, - "pokemon_form_bug": { - "NL": "Bug", - "DE": "Käfer-Form", - "EN": "Bug", - "IT": "TRANSLATE", - "PT-BR": "Inseto", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Bug", - "ES": "Bicho" - }, - "pokemon_form_dark": { - "NL": "Dark", - "DE": "Unlicht-Form", - "EN": "Dark", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Dark", - "ES": "Siniestro" - }, - "pokemon_form_dragon": { - "NL": "Dragon", - "DE": "Drache-Form", - "EN": "Dragon", - "IT": "TRANSLATE", - "PT-BR": "Dragão", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Dragon", - "ES": "Dragón" - }, - "pokemon_form_electric": { - "NL": "Electric", - "DE": "Elektro-Form", - "EN": "Electric", - "IT": "TRANSLATE", - "PT-BR": "Elétrico", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Electric", - "ES": "Eléctrico" - }, - "pokemon_form_fairy": { - "NL": "Fairy", - "DE": "Fee-Form", - "EN": "Fairy", - "IT": "TRANSLATE", - "PT-BR": "Fada", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Fairy", - "ES": "Hada" - }, - "pokemon_form_flying": { - "NL": "Flying", - "DE": "Flug-Form", - "EN": "Flying", - "IT": "TRANSLATE", - "PT-BR": "Voador", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Flying", - "ES": "Volador" - }, - "pokemon_form_fighting": { - "NL": "Fighting", - "DE": "TRANSLATE", - "EN": "Fighting", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_fire": { - "NL": "Fire", - "DE": "Feuer-Form", - "EN": "Fire", - "IT": "TRANSLATE", - "PT-BR": "Fogo", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Fire", - "ES": "Fuego" - }, - "pokemon_form_ghost": { - "NL": "Ghost", - "DE": "Geist-Form", - "EN": "Ghost", - "IT": "TRANSLATE", - "PT-BR": "Fantasma", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Ghost", - "ES": "Fantasma" - }, - "pokemon_form_grass": { - "NL": "Grass", - "DE": "Pflanze-Form", - "EN": "Grass", - "IT": "TRANSLATE", - "PT-BR": "Planta", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Grass", - "ES": "Planta" - }, - "pokemon_form_ground": { - "NL": "Ground", - "DE": "Boden-Form", - "EN": "Ground", - "IT": "TRANSLATE", - "PT-BR": "Terra", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Ground", - "ES": "Tierra" - }, - "pokemon_form_ice": { - "NL": "Ice", - "DE": "Eis-Form", - "EN": "Ice", - "IT": "TRANSLATE", - "PT-BR": "Gelo", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Ice", - "ES": "Hielo" - }, - "pokemon_form_poison": { - "NL": "Poison", - "DE": "Gift-Form", - "EN": "Poison", - "IT": "TRANSLATE", - "PT-BR": "Veneno", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Poison", - "ES": "Veneno" - }, - "pokemon_form_psychic": { - "NL": "Psychic", - "DE": "Psycho-Form", - "EN": "Psychic", - "IT": "TRANSLATE", - "PT-BR": "Psíquico", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Psychic", - "ES": "Psíquico" - }, - "pokemon_form_rock": { - "NL": "Rock", - "DE": "Gestein-Form", - "EN": "Rock", - "IT": "TRANSLATE", - "PT-BR": "Pedra", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Rock", - "ES": "Roca" - }, - "pokemon_form_steel": { - "NL": "Steel", - "DE": "Stahl-Form", - "EN": "Steel", - "IT": "TRANSLATE", - "PT-BR": "Metálico", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Steel", - "ES": "Acero" - }, - "pokemon_form_water": { - "NL": "Water", - "DE": "Wasser-Form", - "EN": "Water", - "IT": "TRANSLATE", - "PT-BR": "Água", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Water", - "ES": "Agua" - }, - "pokemon_form_incarnate": { - "NL": "Incarnate", - "DE": "Inkarnationsform", - "EN": "Incarnate", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Incarnate", - "ES": "Avatar" - }, - "pokemon_form_therian": { - "NL": "Therian", - "DE": "Tiergeistform", - "EN": "Therian", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Therian", - "ES": "Tótem" - }, - "pokemon_form_ordinary": { - "NL": "Ordinary", - "DE": "Standardform", - "EN": "Ordinary", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Ordinary", - "ES": "Normal" - }, - "pokemon_form_resolute": { - "NL": "Resolute", - "DE": "Resolutform", - "EN": "Resolute", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "Resolute", - "ES": "Brío" - }, - "pokemon_form_burn": { - "NL": "Burn", - "DE": "TRANSLATE", - "EN": "Burn", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_chill": { - "NL": "Chill", - "DE": "TRANSLATE", - "EN": "Chill", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_douse": { - "NL": "Douse", - "DE": "TRANSLATE", - "EN": "Douse", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_shock": { - "NL": "Shock", - "DE": "TRANSLATE", - "EN": "Shock", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_black": { - "NL": "Black", - "DE": "TRANSLATE", - "EN": "Black", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_white": { - "NL": "White", - "DE": "TRANSLATE", - "EN": "White", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_hero": { - "NL": "Hero", - "DE": "TRANSLATE", - "EN": "Hero", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_crowned_sword": { - "NL": "Crowned Sword", - "DE": "TRANSLATE", - "EN": "Crowned Sword", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_crowned_shield": { - "NL": "Crowned Shield", - "DE": "TRANSLATE", - "EN": "Crowned Shield", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_zen": { - "NL": "Zen", - "DE": "TRANSLATE", - "EN": "Zen", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_galarian_zen": { - "NL": "Galarian Zen", - "DE": "TRANSLATE", - "EN": "Galarian Zen", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_male": { - "NL": "Man", - "DE": "TRANSLATE", - "EN": "Male", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_female": { - "NL": "Vrouw", - "DE": "TRANSLATE", - "EN": "Female", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_blue_striped": { - "NL": "Blue Striped", - "DE": "TRANSLATE", - "EN": "Blue Striped", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_red_striped": { - "NL": "Red Striped", - "DE": "TRANSLATE", - "EN": "Red Striped", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_autumn": { - "NL": "Herfst", - "DE": "TRANSLATE", - "EN": "Autumn", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_spring": { - "NL": "Lente", - "DE": "TRANSLATE", - "EN": "Spring", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_summer": { - "NL": "Zomer", - "DE": "TRANSLATE", - "EN": "Summer", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_winter": { - "NL": "Winter", - "DE": "TRANSLATE", - "EN": "Winter", - "IT": "TRANSLATE", - "PT-BR": "TRANSLATE", - "RU": "TRANSLATE", - "NO": "TRANSLATE", - "FR": "TRANSLATE", - "PL": "TRANSLATE", - "ES": "TRANSLATE" - }, - "pokemon_form_exclamation_point": { - "EN": "!" - }, - "pokemon_form_question_mark": { - "EN": "?" - }, - "pokemon_form_unbound": { - "EN": "Unbound" - } -} + "pokemon_form_10": { + "EN": "10" + }, + "pokemon_form_11": { + "EN": "11" + }, + "pokemon_form_12": { + "EN": "12" + }, + "pokemon_form_13": { + "EN": "13" + }, + "pokemon_form_14": { + "EN": "14" + }, + "pokemon_form_15": { + "EN": "15" + }, + "pokemon_form_16": { + "EN": "16" + }, + "pokemon_form_17": { + "EN": "17" + }, + "pokemon_form_18": { + "EN": "18" + }, + "pokemon_form_19": { + "EN": "19" + }, + "pokemon_form_2020": { + "EN": "2020" + }, + "pokemon_form_2021": { + "EN": "2021" + }, + "pokemon_form_2022": { + "EN": "2022" + }, + "pokemon_form_a": { + "EN": "A" + }, + "pokemon_form_b": { + "EN": "B" + }, + "pokemon_form_c": { + "EN": "C" + }, + "pokemon_form_d": { + "EN": "D" + }, + "pokemon_form_e": { + "EN": "E" + }, + "pokemon_form_f": { + "EN": "F" + }, + "pokemon_form_g": { + "EN": "G" + }, + "pokemon_form_h": { + "EN": "H" + }, + "pokemon_form_i": { + "EN": "I" + }, + "pokemon_form_j": { + "EN": "J" + }, + "pokemon_form_k": { + "EN": "K" + }, + "pokemon_form_l": { + "EN": "L" + }, + "pokemon_form_m": { + "EN": "M" + }, + "pokemon_form_n": { + "EN": "N" + }, + "pokemon_form_o": { + "EN": "O" + }, + "pokemon_form_p": { + "EN": "P" + }, + "pokemon_form_q": { + "EN": "Q" + }, + "pokemon_form_r": { + "EN": "R" + }, + "pokemon_form_s": { + "EN": "S" + }, + "pokemon_form_t": { + "EN": "T" + }, + "pokemon_form_u": { + "EN": "U" + }, + "pokemon_form_v": { + "EN": "V" + }, + "pokemon_form_w": { + "EN": "W" + }, + "pokemon_form_x": { + "EN": "X" + }, + "pokemon_form_y": { + "EN": "Y" + }, + "pokemon_form_z": { + "EN": "Z" + }, + "pokemon_form_exclamation_point": { + "EN": "Exclamation Point", + "FR": "!", + "DE": "!", + "RU": "!" + }, + "pokemon_form_question_mark": { + "EN": "Question Mark", + "FR": "?", + "DE": "?", + "RU": "?" + }, + "pokemon_form_normal": { + "EN": "Normal", + "IT": "Normale", + "RU": "Нормальный" + }, + "pokemon_form_sunny": { + "PT-BR": "Ensolarada", + "EN": "Sunny", + "FR": "Solaire", + "DE": "Sonnenform", + "IT": "Sole", + "RU": "Солнечная форма", + "ES": "Sol" + }, + "pokemon_form_rainy": { + "EN": "Rainy", + "FR": "Eau de pluie", + "DE": "Regenform", + "RU": "Дождливая форма" + }, + "pokemon_form_snowy": { + "EN": "Snowy", + "FR": "Blizzard", + "DE": "Schneeform", + "RU": "Снежная форма" + }, + "pokemon_form_attack": { + "PT-BR": "Ataque", + "EN": "Attack", + "FR": "Attaque", + "DE": "Angriffsform", + "IT": "Attacco", + "RU": "Атакующая форма", + "ES": "Ataque" + }, + "pokemon_form_defense": { + "PT-BR": "Defesa", + "EN": "Defense", + "FR": "Défense", + "DE": "Verteidigungsform", + "IT": "Difesa", + "RU": "Защитная форма", + "ES": "Defensa" + }, + "pokemon_form_speed": { + "PT-BR": "Velocidade", + "EN": "Speed", + "FR": "Vitesse", + "DE": "Initiativeform", + "IT": "Velocità", + "RU": "Скоростная форма", + "ES": "Velocidad" + }, + "pokemon_form_00": { + "EN": "00" + }, + "pokemon_form_01": { + "EN": "01" + }, + "pokemon_form_02": { + "EN": "02" + }, + "pokemon_form_03": { + "EN": "03" + }, + "pokemon_form_04": { + "EN": "04" + }, + "pokemon_form_05": { + "EN": "05" + }, + "pokemon_form_06": { + "EN": "06" + }, + "pokemon_form_07": { + "EN": "07" + }, + "pokemon_form_alola": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_frost_rotom": { + "PT-BR": "Rotom Congelante", + "EN": "Frost Rotom", + "FR": "Motisma Froid", + "DE": "Frost", + "IT": "Rotom Gelo", + "RU": "Холодильник", + "ES": "Rotom Frío" + }, + "pokemon_form_fan_rotom": { + "PT-BR": "Rotom Ventilador", + "EN": "Fan Rotom", + "FR": "Motisma Hélice", + "DE": "Wirbel", + "IT": "Rotom Vortice", + "RU": "Вентилятор", + "ES": "Rotom Ventilador" + }, + "pokemon_form_mow_rotom": { + "PT-BR": "Rotom Corte", + "EN": "Mow Rotom", + "FR": "Motisma Tonte", + "DE": "Schneid", + "IT": "Rotom Taglio", + "RU": "Газонокосилка", + "ES": "Rotom Corte" + }, + "pokemon_form_wash_rotom": { + "PT-BR": "Rotom Lavagem", + "EN": "Wash Rotom", + "FR": "Motisma Lavage", + "DE": "Wasch", + "IT": "Rotom Lavaggio", + "RU": "Стиралка", + "ES": "Rotom Lavado" + }, + "pokemon_form_heat_rotom": { + "PT-BR": "Rotom Calor", + "EN": "Heat Rotom", + "FR": "Motisma Chaleur", + "DE": "Hitze", + "IT": "Rotom Calore", + "RU": "Обогреватель", + "ES": "Rotom Calor" + }, + "pokemon_form_plant_cloak": { + "PT-BR": "Manto Vegetal", + "EN": "Plant Cloak", + "FR": "Cape Plante", + "DE": "Pflanzenumhang", + "IT": "Manto Pianta", + "RU": "Растительный покров", + "ES": "Tronco Planta" + }, + "pokemon_form_sandy_cloak": { + "PT-BR": "Manto Arenoso", + "EN": "Sandy Cloak", + "FR": "Cape Sable", + "DE": "Sandumhang", + "IT": "Manto Sabbia", + "RU": "Песчанный покров", + "ES": "Tronco Arena" + }, + "pokemon_form_trash_cloak": { + "PT-BR": "Manto de Lixo", + "EN": "Trash Cloak", + "FR": "Cape Déchet", + "DE": "Lumpenumhang", + "IT": "Manto Scarti", + "RU": "Мусорный покров", + "ES": "Tronco Basura" + }, + "pokemon_form_altered_forme": { + "PT-BR": "Forma Alterada", + "EN": "Altered Forme", + "FR": "Forme Alternative", + "DE": "Wandel", + "IT": "Forma Alterata", + "RU": "Изменённая форма", + "ES": "Forma Modificada" + }, + "pokemon_form_origin_forme": { + "PT-BR": "Forma Origem", + "EN": "Origin Forme", + "FR": "Forme Originelle", + "DE": "Urform", + "IT": "Forma Originale", + "RU": "Исходная форма", + "ES": "Forma Origen" + }, + "pokemon_form_sky_forme": { + "PT-BR": "Forma Céu", + "EN": "Sky Forme", + "FR": "Forme Céleste", + "DE": "Zenit", + "IT": "Forma Cielo", + "RU": "Небесная форма", + "ES": "Forma Cielo" + }, + "pokemon_form_land_forme": { + "PT-BR": "Forma Terrestre", + "EN": "Land Forme", + "FR": "Forme Terrestre", + "DE": "Land", + "IT": "Forma Terra", + "RU": "Земная форма", + "ES": "Forma Tierra" + }, + "pokemon_form_overcast_form": { + "PT-BR": "Forma Nublada", + "EN": "Overcast Form", + "FR": "Temps Couvert", + "DE": "Wolkenform", + "IT": "Forma Nuvola", + "RU": "Пасмурная форма", + "ES": "Forma Encapotado" + }, + "pokemon_form_west_sea": { + "PT-BR": "Mar Ocidental", + "EN": "West Sea", + "FR": "Mer Occident", + "DE": "Westliches Meer", + "IT": "Mare Ovest", + "RU": "Западно-морская форма", + "ES": "Mar Oeste" + }, + "pokemon_form_east_sea": { + "PT-BR": "Mar Leste", + "EN": "East Sea", + "FR": "Mer Orient", + "DE": "Östliches Meer", + "IT": "Mare Est", + "RU": "Восточно-морская форма", + "ES": "Mar Este" + }, + "pokemon_form_fighting": { + "PT-BR": "Lutador", + "EN": "Fighting", + "FR": "Combat", + "DE": "Kampf", + "IT": "Lotta", + "RU": "Боевая форма", + "ES": "Lucha" + }, + "pokemon_form_flying": { + "PT-BR": "Voador", + "EN": "Flying", + "FR": "Vol", + "DE": "Flug", + "IT": "Volante", + "RU": "Летающая форма", + "ES": "Volador" + }, + "pokemon_form_poison": { + "PT-BR": "Venenoso", + "EN": "Poison", + "DE": "Gift", + "IT": "Veleno", + "RU": "Ядовитая форма", + "ES": "Veneno" + }, + "pokemon_form_ground": { + "PT-BR": "Terrestre", + "EN": "Ground", + "FR": "Sol", + "DE": "Boden", + "IT": "Terra", + "RU": "Земляная форма", + "ES": "Tierra" + }, + "pokemon_form_rock": { + "PT-BR": "Pedra", + "EN": "Rock", + "FR": "Roche", + "DE": "Gestein", + "IT": "Roccia", + "RU": "Каменная форма", + "ES": "Roca" + }, + "pokemon_form_bug": { + "PT-BR": "Inseto", + "EN": "Bug", + "FR": "Insecte", + "DE": "Käfer", + "IT": "Coleottero", + "RU": "Жучья форма", + "ES": "Bicho" + }, + "pokemon_form_ghost": { + "PT-BR": "Fantasma", + "EN": "Ghost", + "FR": "Spectre", + "DE": "Geist", + "IT": "Spettro", + "RU": "Призрачная форма", + "ES": "Fantasma" + }, + "pokemon_form_steel": { + "PT-BR": "Aço", + "EN": "Steel", + "FR": "Acier", + "DE": "Stahl", + "IT": "Acciaio", + "RU": "Стальная форма", + "ES": "Acero" + }, + "pokemon_form_fire": { + "PT-BR": "Fogo", + "EN": "Fire", + "FR": "Feu", + "DE": "Feuer", + "IT": "Fuoco", + "RU": "Огненная форма", + "ES": "Fuego" + }, + "pokemon_form_water": { + "PT-BR": "Água", + "EN": "Water", + "FR": "Eau", + "DE": "Wasser", + "IT": "Acqua", + "RU": "Водная форма", + "ES": "Agua" + }, + "pokemon_form_grass": { + "PT-BR": "Planta", + "EN": "Grass", + "FR": "Plante", + "DE": "Pflanze", + "IT": "Erba", + "RU": "Травяная форма", + "ES": "Planta" + }, + "pokemon_form_electric": { + "PT-BR": "Elétrico", + "EN": "Electric", + "FR": "Électrik", + "DE": "Elektro", + "IT": "Elettro", + "RU": "Электрическая форма", + "ES": "Eléctrico" + }, + "pokemon_form_psychic": { + "PT-BR": "Psíquico", + "EN": "Psychic", + "FR": "Psy", + "DE": "Psycho", + "IT": "Psico", + "RU": "Психическая форма", + "ES": "Psíquico" + }, + "pokemon_form_ice": { + "PT-BR": "Gelo", + "EN": "Ice", + "FR": "Glace", + "DE": "Eis", + "IT": "Ghiaccio", + "RU": "Ледяная форма", + "ES": "Hielo" + }, + "pokemon_form_dragon": { + "PT-BR": "Dragão", + "EN": "Dragon", + "DE": "Drache", + "IT": "Drago", + "RU": "Драконья форма", + "ES": "Dragón" + }, + "pokemon_form_dark": { + "PT-BR": "Sombrio", + "EN": "Dark", + "FR": "Ténèbres", + "DE": "Unlicht", + "IT": "Buio", + "RU": "Темная форма", + "ES": "Siniestro" + }, + "pokemon_form_fairy": { + "PT-BR": "Fada", + "EN": "Fairy", + "FR": "Fée", + "DE": "Fee", + "IT": "Folletto", + "RU": "Феечная форма", + "ES": "Hada" + }, + "pokemon_form_08": { + "EN": "08" + }, + "pokemon_form_09": { + "EN": "09" + }, + "pokemon_form_red-striped": { + "PT-BR": "Listras Vermelhas", + "EN": "Red-Striped", + "FR": "Motif Rouge", + "DE": "Rotlinig", + "IT": "Forma Linearossa", + "RU": "Красно-полосатая форма", + "ES": "Forma Raya Roja" + }, + "pokemon_form_blue-striped": { + "PT-BR": "Listras Azuis", + "EN": "Blue-Striped", + "FR": "Motif Bleu", + "DE": "Blaulinig", + "IT": "Forma Lineablu", + "RU": "Сине-полосатая форма", + "ES": "Forma Raya Azul" + }, + "pokemon_form_standard": { + "EN": "Standard", + "RU": "Обычная форма" + }, + "pokemon_form_zen": { + "EN": "Zen", + "DE": "Trance", + "RU": "Дзен" + }, + "pokemon_form_incarnate_forme": { + "PT-BR": "Forma Materializada", + "EN": "Incarnate Forme", + "FR": "Forme Avatar", + "DE": "Inkarnationsform", + "IT": "Forma Incarnazione", + "RU": "Воплощённая форма", + "ES": "Forma Avatar" + }, + "pokemon_form_therian_forme": { + "PT-BR": "Forma Therian", + "EN": "Therian Forme", + "FR": "Forme Totémique", + "DE": "Tiergeistform", + "IT": "Forma Totem", + "RU": "Форма Териан", + "ES": "Forma Tótem" + }, + "pokemon_form_black_kyurem": { + "PT-BR": "Kyurem Preto", + "EN": "Black Kyurem", + "FR": "Kyurem Noir", + "DE": "Schwarz", + "IT": "Kyurem Nero", + "RU": "Чёрный Кьюрем", + "ES": "Kyurem Negro" + }, + "pokemon_form_white_kyurem": { + "PT-BR": "Kyurem Branco", + "EN": "White Kyurem", + "FR": "Kyurem Blanc", + "DE": "Weiß", + "IT": "Kyurem Bianco", + "RU": "Белый Кьюрем", + "ES": "Kyurem Blanco" + }, + "pokemon_form_ordinary_form": { + "PT-BR": "Forma Comum", + "EN": "Ordinary Form", + "FR": "Aspect Normal", + "DE": "Standard", + "IT": "Forma Normale", + "RU": "Обычная форма", + "ES": "Forma Habitual" + }, + "pokemon_form_resolute_form": { + "PT-BR": "Forma Resoluta", + "EN": "Resolute Form", + "FR": "Resolute", + "DE": "Resolut", + "IT": "Forma Risoluta", + "RU": "Решительная форма", + "ES": "Forma Brío" + }, + "pokemon_form_aria_forme": { + "PT-BR": "Forma Ária", + "EN": "Aria Forme", + "FR": "Forme Chant", + "DE": "Gesang", + "IT": "Forma Canto", + "RU": "Форма Арии", + "ES": "Forma Lírica" + }, + "pokemon_form_pirouette_forme": { + "PT-BR": "Forma Pirueta", + "EN": "Pirouette Forme", + "FR": "Pirouette", + "DE": "Tanz", + "IT": "Forma Danza", + "RU": "Форма Пируэта", + "ES": "Forma Danza" + }, + "pokemon_form_shadow": { + "PT-BR": "Sombroso", + "EN": "Shadow", + "FR": "Obscur", + "DE": "Crypto", + "IT": "Ombra", + "RU": "Теневые", + "ES": "Oscuro" + }, + "pokemon_form_purified": { + "PT-BR": "Purificado", + "EN": "Purified", + "FR": "Purifié", + "DE": "Erlöst", + "IT": "Purificato", + "RU": "Очищенные", + "ES": "Purificado" + }, + "pokemon_form_spring_form": { + "PT-BR": "Forma Primavera", + "EN": "Spring Form", + "FR": "Forme Printemps", + "DE": "Frühling", + "IT": "Forma Primavera", + "RU": "Весенняя форма", + "ES": "Forma Primavera" + }, + "pokemon_form_summer_form": { + "PT-BR": "Forma Verão", + "EN": "Summer Form", + "FR": "Forme Été", + "DE": "Sommer", + "IT": "Forma Estate", + "RU": "Летняя форма", + "ES": "Forma Verano" + }, + "pokemon_form_autumn_form": { + "PT-BR": "Forma Outono", + "EN": "Autumn Form", + "FR": "Forme Automne", + "DE": "Herbst", + "IT": "Forma Autunno", + "RU": "Осенняя форма", + "ES": "Forma Otoño" + }, + "pokemon_form_winter_form": { + "PT-BR": "Forma Inverno", + "EN": "Winter Form", + "FR": "Forme Hiver", + "DE": "Winter", + "IT": "Forma Inverno", + "RU": "Зимняя форма", + "ES": "Forma Invierno" + }, + "pokemon_form_shock": { + "EN": "Shock", + "FR": "Module Choc", + "DE": "Blitzmodul", + "RU": "Электрический привод" + }, + "pokemon_form_burn": { + "EN": "Burn", + "FR": "Module Pyro", + "DE": "Flammenmodul", + "RU": "Огненный привод" + }, + "pokemon_form_chill": { + "EN": "Chill", + "FR": "Module Cryo", + "DE": "Gefriermodul", + "RU": "Ледяной привод" + }, + "pokemon_form_douse": { + "EN": "Douse", + "FR": "Module Aqua", + "DE": "Aquamodul", + "RU": "Водный привод" + }, + "pokemon_form_fall_2019": { + "EN": "Fall 2019", + "FR": "Automne 2019", + "DE": "Herbst 2019" + }, + "pokemon_form_vs_2019": { + "EN": "Vs 2019" + }, + "pokemon_form_galarian": { + "EN": "Galarian" + }, + "pokemon_form_copy_2019": { + "EN": "Copy 2019", + "FR": "Clone 2019", + "RU": "Клон 2019" + }, + "pokemon_form_spring_2020": { + "EN": "Spring 2020", + "FR": "Printemps 2020", + "DE": "Frühjahr 2020", + "RU": "Весна 2020" + }, + "pokemon_form_female": { + "PT-BR": "Fêmea", + "EN": "Female", + "FR": "Femelle", + "DE": "Weiblich", + "IT": "Femmina", + "RU": "Женский", + "ES": "Hembra" + }, + "pokemon_form_costume_2020": { + "EN": "Costume 2020", + "DE": "Kostüm 2020", + "RU": "Костюм 2020" + }, + "pokemon_form_galarian_standard": { + "EN": "Galarian Standard", + "DE": "Galar Normal", + "RU": "Галарская форма" + }, + "pokemon_form_galarian_zen": { + "EN": "Galarian Zen", + "DE": "Galar Trance", + "RU": "Галарская форма Дзен" + }, + "pokemon_form_low_key_form": { + "PT-BR": "Forma Grave", + "EN": "Low Key Form", + "DE": "Tief-Form", + "IT": "Forma Basso", + "RU": "Сдержанная форма", + "ES": "Forma Grave" + }, + "pokemon_form_amped_form": { + "PT-BR": "Forma Aguda", + "EN": "Amped Form", + "DE": "Hoch-Form", + "IT": "Forma Melodia", + "RU": "Восторженная форма", + "ES": "Forma Aguda" + }, + "pokemon_form_phony_form": { + "PT-BR": "Forma Falsificada", + "EN": "Phony Form", + "DE": "Fälschungsform", + "IT": "Forma Contraffatta", + "RU": "Фальшивая форма", + "ES": "Forma Falsificada" + }, + "pokemon_form_antique_form": { + "PT-BR": "Forma Autêntica", + "EN": "Antique Form", + "DE": "Originalform", + "IT": "Forma Autentica", + "RU": "Антикварная форма", + "ES": "Forma Genuina" + }, + "pokemon_form_ice_face": { + "PT-BR": "Cara de Gelo", + "EN": "Ice Face", + "DE": "Tiefkühlkopf", + "IT": "Gelofaccia", + "RU": "Ледяное лицо", + "ES": "Cara de Hielo" + }, + "pokemon_form_noice_face": { + "PT-BR": "Cara Degelada", + "EN": "Noice Face", + "DE": "Wohlfühlkopf", + "IT": "Liquefaccia", + "RU": "Неледяное лицо", + "ES": "Cara Deshielo" + }, + "pokemon_form_male": { + "PT-BR": "Macho", + "EN": "Male", + "FR": "Mâle", + "DE": "Männlich", + "IT": "Maschio", + "RU": "Мужская форма", + "ES": "Macho" + }, + "pokemon_form_full_belly_mode": { + "PT-BR": "Forma Saciada", + "EN": "Full Belly Mode", + "DE": "Pappsatt", + "IT": "Motivo Panciapiena", + "RU": "Режим Полный Живот", + "ES": "Forma Saciada" + }, + "pokemon_form_hangry_mode": { + "PT-BR": "Forma Voraz", + "EN": "Hangry Mode", + "DE": "Kohldampf", + "IT": "Motivo Panciavuota", + "RU": "Злоголодный режим", + "ES": "Forma Voraz" + }, + "pokemon_form_crowned_sword": { + "PT-BR": "Espada Coroada", + "EN": "Crowned Sword", + "DE": "König des Schwertes", + "IT": "Re delle Spade", + "RU": "Коронованный Меч", + "ES": "Espada Suprema" + }, + "pokemon_form_hero_of_many_battles": { + "PT-BR": "Herói Veterano", + "EN": "Hero of Many Battles", + "DE": "Heldenhafter Krieger", + "IT": "Eroe di Mille Lotte", + "RU": "Герой многих битв", + "ES": "Guerrero Avezado" + }, + "pokemon_form_crowned_shield": { + "PT-BR": "Escudo Coroado", + "EN": "Crowned Shield", + "DE": "König des Schildes", + "IT": "Re degli Scudi", + "RU": "Коронованный Щит", + "ES": "Escudo Supremo" + }, + "pokemon_form_eternamax": { + "EN": "Eternamax", + "DE": "Unendynamax", + "RU": "Этернамакс" + }, + "pokemon_form_ten_percent": { + "EN": "Ten Percent", + "DE": "10%", + "RU": "10% форма" + }, + "pokemon_form_fifty_percent": { + "EN": "Fifty Percent", + "DE": "50%", + "RU": "50% форма" + }, + "pokemon_form_complete": { + "EN": "Complete", + "DE": "Optimum", + "RU": "Завершенная форма" + }, + "pokemon_form_archipelago": { + "EN": "Archipelago" + }, + "pokemon_form_continental": { + "EN": "Continental" + }, + "pokemon_form_elegant": { + "EN": "Elegant" + }, + "pokemon_form_fancy": { + "EN": "Fancy" + }, + "pokemon_form_garden": { + "EN": "Garden" + }, + "pokemon_form_high_plains": { + "EN": "High Plains" + }, + "pokemon_form_icy_snow": { + "EN": "Icy Snow" + }, + "pokemon_form_jungle": { + "EN": "Jungle" + }, + "pokemon_form_marine": { + "EN": "Marine" + }, + "pokemon_form_meadow": { + "EN": "Meadow" + }, + "pokemon_form_modern": { + "EN": "Modern" + }, + "pokemon_form_monsoon": { + "EN": "Monsoon" + }, + "pokemon_form_ocean": { + "EN": "Ocean" + }, + "pokemon_form_pokeball": { + "EN": "Pokeball" + }, + "pokemon_form_polar": { + "EN": "Polar" + }, + "pokemon_form_river": { + "EN": "River" + }, + "pokemon_form_sandstorm": { + "EN": "Sandstorm" + }, + "pokemon_form_savanna": { + "EN": "Savanna" + }, + "pokemon_form_tundra": { + "EN": "Tundra" + }, + "pokemon_form_red_flower": { + "EN": "Red Flower", + "FR": "Red", + "DE": "Rotblütler", + "RU": "Красная форма" + }, + "pokemon_form_yellow_flower": { + "EN": "Yellow Flower", + "FR": "Yellow", + "DE": "Gelbblütler", + "RU": "Желтая форма" + }, + "pokemon_form_orange_flower": { + "EN": "Orange Flower", + "FR": "Orange", + "DE": "Orangeblütler", + "RU": "Оранжевая форма" + }, + "pokemon_form_blue_flower": { + "EN": "Blue Flower", + "FR": "Blue", + "DE": "Blaublütler", + "RU": "Синяя форма" + }, + "pokemon_form_white_flower": { + "EN": "White Flower", + "FR": "White", + "DE": "Weißblütler", + "RU": "Белая форма" + }, + "pokemon_form_natural": { + "EN": "Natural", + "DE": "Zottelform", + "RU": "Исходная форма" + }, + "pokemon_form_heart_trim": { + "EN": "Heart Trim", + "FR": "Heart", + "DE": "Herzchenschnitt", + "RU": "Сердечная форма" + }, + "pokemon_form_star_trim": { + "EN": "Star Trim", + "FR": "Star", + "DE": "Sternchenschnitt", + "RU": "Звездная форма" + }, + "pokemon_form_diamond_trim": { + "EN": "Diamond Trim", + "FR": "Diamond", + "DE": "Diamantenschnitt", + "RU": "Бриллиантовая форма" + }, + "pokemon_form_debutante_trim": { + "EN": "Debutante Trim", + "FR": "Debutante", + "DE": "Fräuleinschnitt", + "RU": "Дебютантская форма" + }, + "pokemon_form_matron_trim": { + "EN": "Matron Trim", + "FR": "Matron", + "DE": "Damenschnitt", + "RU": "Матронская форма" + }, + "pokemon_form_dandy_trim": { + "EN": "Dandy Trim", + "FR": "Dandy", + "DE": "Kavaliersschnitt", + "RU": "Светская форма" + }, + "pokemon_form_la_reine_trim": { + "EN": "La Reine Trim", + "FR": "La Reine", + "DE": "Königinnenschnitt", + "RU": "Форма Ла Рейне" + }, + "pokemon_form_kabuki_trim": { + "EN": "Kabuki Trim", + "FR": "Kabuki", + "DE": "Kabuki-Schnitt", + "RU": "Форма кабуки" + }, + "pokemon_form_pharaoh_trim": { + "EN": "Pharaoh Trim", + "FR": "Pharaoh", + "DE": "Herrscherschnitt", + "RU": "Форма фараона" + }, + "pokemon_form_shield": { + "EN": "Shield", + "DE": "Schild", + "RU": "Форма щита" + }, + "pokemon_form_blade": { + "EN": "Blade", + "DE": "Schwert", + "RU": "Форма меча" + }, + "pokemon_form_small": { + "EN": "Small", + "FR": "Mini", + "DE": "S", + "RU": "Маленькая форма" + }, + "pokemon_form_average": { + "EN": "Average", + "FR": "Normale", + "DE": "M", + "RU": "Средняя форма" + }, + "pokemon_form_large": { + "EN": "Large", + "FR": "Maxi", + "DE": "L", + "RU": "Большая форма" + }, + "pokemon_form_super": { + "EN": "Super", + "FR": "Ultra", + "DE": "XL", + "RU": "Огромная форма" + }, + "pokemon_form_neutral": { + "EN": "Neutral", + "RU": "Нейтральная форма" + }, + "pokemon_form_active": { + "EN": "Active", + "DE": "Aktiv", + "RU": "Активная форма" + }, + "pokemon_form_confined": { + "EN": "Confined", + "DE": "Beschränkt", + "RU": "Невольная форма" + }, + "pokemon_form_unbound": { + "EN": "Unbound", + "DE": "Ungebunden", + "RU": "Высвобожденная форма" + }, + "pokemon_form_costume_2020_deprecated": { + "EN": "Costume 2020 Deprecated", + "DE": "Kostüm 2020 Deprecated", + "RU": "Костюм 2020 Устаревший" + }, + "pokemon_form_adventure_hat_2020": { + "EN": "Adventure Hat 2020", + "DE": "Abenteuerhut 2020" + }, + "pokemon_form_winter_2020": { + "EN": "Winter 2020" + }, + "pokemon_form_kariyushi": { + "EN": "Kariyushi", + "RU": "Кариюши" + }, + "pokemon_form_pop_star": { + "EN": "Pop Star", + "RU": "Поп-звезда" + }, + "pokemon_form_rock_star": { + "EN": "Rock Star", + "RU": "Рок-звезда" + }, + "pokemon_form_flying_5th_anniv": { + "EN": "Flying 5th Anniv", + "DE": "Fliegendes 5. Jubiläum", + "RU": "Пятилетняя годовщина" + }, + "pokemon_form_baile_style": { + "PT-BR": "Estilo Flamenco", + "EN": "Baile Style", + "FR": "Style Flamenco", + "DE": "Flamenco", + "IT": "Stile Flamenco", + "RU": "Бальный стиль", + "ES": "Estilo Apasionado" + }, + "pokemon_form_pom-pom_style": { + "PT-BR": "Estilo Pompom", + "EN": "Pom-Pom Style", + "FR": "Style Pom-Pom", + "DE": "Cheerleading", + "IT": "Stile Cheerdance", + "RU": "Стиль Пом-Пом", + "ES": "Estilo Animado" + }, + "pokemon_form_pa’u_style": { + "PT-BR": "Estilo Hula", + "EN": "Pa’u Style", + "FR": "Style Hula", + "DE": "Hula", + "IT": "Stile Hula", + "RU": "Стиль Пау", + "ES": "Estilo Plácido" + }, + "pokemon_form_sensu_style": { + "PT-BR": "Estilo Leque", + "EN": "Sensu Style", + "FR": "Style Buyô", + "DE": "Buyo", + "IT": "Stile Buyō", + "RU": "Чувственный стиль", + "ES": "Estilo Refinado" + }, + "pokemon_form_midday_form": { + "PT-BR": "Forma Diurna", + "EN": "Midday Form", + "FR": "Forme Diurne", + "DE": "Tag", + "IT": "Forma Giorno", + "RU": "Полуденная форма", + "ES": "Forma Diurna" + }, + "pokemon_form_midnight_form": { + "PT-BR": "Forma Noturna", + "EN": "Midnight Form", + "FR": "Forme Nocturne", + "DE": "Nacht", + "IT": "Forma Notte", + "RU": "Полуночная форма", + "ES": "Forma Nocturna" + }, + "pokemon_form_dusk_form": { + "PT-BR": "Forma Crepúsculo", + "EN": "Dusk Form", + "FR": "Forme Crépusculaire", + "DE": "Zwielichtform", + "IT": "Forma Crepuscolo", + "RU": "Сумеречная форма", + "ES": "Forma Crepuscular" + }, + "pokemon_form_solo_form": { + "PT-BR": "Forma Individual", + "EN": "Solo Form", + "DE": "Einzel", + "IT": "Forma Individuale", + "RU": "Форма соло", + "ES": "Forma Individual" + }, + "pokemon_form_school_form": { + "PT-BR": "Forma Cardume", + "EN": "School Form", + "DE": "Schwarm", + "IT": "Forma Banco", + "RU": "Форма стая", + "ES": "Forma Banco" + }, + "pokemon_form_meteor_blue": { + "EN": "Meteor Blue", + "DE": "Meteor", + "RU": "Метеорная форма" + }, + "pokemon_form_blue_plumage": { + "PT-BR": "Plumagem Azul", + "EN": "Blue Plumage", + "FR": "Plumage Bleu", + "DE": "Blaugefiedert", + "IT": "Piume Azzurre", + "RU": "Синее оперение", + "ES": "Plumaje Azul" + }, + "pokemon_form_green_plumage": { + "PT-BR": "Plumagem Verde", + "EN": "Green Plumage", + "FR": "Plumage Vert", + "DE": "Grüngefiedert", + "IT": "Piume Verdi", + "RU": "Зелёное оперение", + "ES": "Plumaje Verde" + }, + "pokemon_form_indigo": { + "EN": "Indigo", + "DE": "Hellblau", + "RU": "Индиго форма" + }, + "pokemon_form_orange": { + "EN": "Orange", + "RU": "Оранжевая форма" + }, + "pokemon_form_red": { + "EN": "Red", + "DE": "Rot", + "RU": "Красная форма" + }, + "pokemon_form_violet": { + "EN": "Violet", + "DE": "Violett", + "RU": "Фиолетовая форма" + }, + "pokemon_form_yellow_plumage": { + "PT-BR": "Plumagem Amarela", + "EN": "Yellow Plumage", + "FR": "Plumage Jaune", + "DE": "Gelbgefiedert", + "IT": "Piume Gialle", + "RU": "Жёлтое оперение", + "ES": "Plumaje Amarillo" + }, + "pokemon_form_busted_form": { + "PT-BR": "Forma Desmascarada", + "EN": "Busted Form", + "DE": "Entlarvt", + "IT": "Forma Smascherata", + "RU": "Сломанная форма", + "ES": "Forma Descubierta" + }, + "pokemon_form_disguised_form": { + "PT-BR": "Forma Mascarada", + "EN": "Disguised Form", + "DE": "Standard", + "IT": "Forma Mascherata", + "RU": "Замаскированная форма", + "ES": "Forma Encubierta" + }, + "pokemon_form_dusk_mane": { + "EN": "Dusk Mane", + "DE": "Abendmähne", + "RU": "Грива заката" + }, + "pokemon_form_dawn_wings": { + "EN": "Dawn Wings", + "DE": "Morgenschwingen", + "RU": "Крылья рассвета" + }, + "pokemon_form_ultra": { + "EN": "Ultra", + "RU": "Ультра форма" + }, + "pokemon_form_original_color": { + "EN": "Original Color", + "DE": "Originalfarbe", + "RU": "Исходный цвет" + }, + "pokemon_form_single_strike": { + "EN": "Single Strike", + "DE": "Fokussierter Stil", + "RU": "Фома одного удара" + }, + "pokemon_form_rapid_strike": { + "EN": "Rapid Strike", + "DE": "Fließender Stil", + "RU": "Форма множества ударов" + }, + "pokemon_form_ice_rider": { + "EN": "Ice Rider", + "DE": "Schimmelreiter", + "RU": "Ледяной всадник" + }, + "pokemon_form_shadow_rider": { + "EN": "Shadow Rider", + "RU": "Теневой всадник" + }, + "pokemon_form_hisuian": { + "EN": "Hisuian" + }, + "pokemon_form_flying_okinawa": { + "EN": "Flying Okinawa" + }, + "pokemon_form_meteor_green": { + "EN": "Meteor Green" + }, + "pokemon_form_meteor_indigo": { + "EN": "Meteor Indigo" + }, + "pokemon_form_meteor_orange": { + "EN": "Meteor Orange" + }, + "pokemon_form_meteor_red": { + "EN": "Meteor Red" + }, + "pokemon_form_meteor_violet": { + "EN": "Meteor Violet" + }, + "pokemon_form_meteor_yellow": { + "EN": "Meteor Yellow" + }, + "pokemon_form_white-striped_form": { + "PT-BR": "Forma Listras Brancas", + "EN": "White-Striped Form", + "FR": "Motif Blanc", + "DE": "Weißlinige Form", + "IT": "Forma Lineabianca", + "RU": "Белая полосатая форма", + "ES": "Forma Raya Blanca" + }, + "pokemon_form_gofest_2022": { + "EN": "Gofest 2022" + }, + "pokemon_form_wcs_2022": { + "EN": "Wcs 2022" + }, + "pokemon_form_tshirt_01": { + "EN": "Tshirt 01" + }, + "pokemon_form_tshirt_02": { + "EN": "Tshirt 02" + }, + "pokemon_form_flying_01": { + "EN": "Flying 01" + }, + "pokemon_form_flying_02": { + "EN": "Flying 02" + }, + "pokemon_form_complete_ten_percent": { + "EN": "Complete Ten Percent" + }, + "pokemon_form_complete_fifty_percent": { + "EN": "Complete Fifty Percent" + }, + "pokemon_form_gotour_2024_a": { + "EN": "Gotour 2024 A" + }, + "pokemon_form_gotour_2024_b": { + "EN": "Gotour 2024 B" + }, + "pokemon_form_gotour_2024_a_02": { + "EN": "Gotour 2024 A 02" + }, + "pokemon_form_gotour_2024_b_02": { + "EN": "Gotour 2024 B 02" + }, + "pokemon_form_family_of_three": { + "EN": "Family Of Three" + }, + "pokemon_form_family_of_four": { + "EN": "Family Of Four" + }, + "pokemon_form_white": { + "EN": "White" + }, + "pokemon_form_zero_form": { + "PT-BR": "Forma Zero", + "EN": "Zero Form", + "FR": "Forme Ordinaire", + "DE": "Alltagsform", + "IT": "Forma Ingenua", + "RU": "Нулевая форма", + "ES": "Forma Ingenua" + }, + "pokemon_form_curly_form": { + "PT-BR": "Forma Curvada", + "EN": "Curly Form", + "FR": "Forme Courbée", + "DE": "Gebogene Form", + "IT": "Forma Arcuata", + "RU": "Изогнутая форма", + "ES": "Forma Curvada" + }, + "pokemon_form_droopy_form": { + "PT-BR": "Forma Pendular", + "EN": "Droopy Form", + "FR": "Forme Affalée", + "DE": "Hängende Form", + "IT": "Forma Adagiata", + "RU": "Свисающая форма", + "ES": "Forma Lánguida" + }, + "pokemon_form_stretchy_form": { + "PT-BR": "Forma Estendida", + "EN": "Stretchy Form", + "FR": "Forme Raide", + "DE": "Gestreckte Form", + "IT": "Forma Tesa", + "RU": "Вытянутая форма", + "ES": "Forma Recta" + }, + "pokemon_form_two-segment_form": { + "PT-BR": "Forma Bissegmentar", + "EN": "Two-Segment Form", + "FR": "Forme Double", + "DE": "Zweisegmentform", + "IT": "Forma Bimetamero", + "RU": "Двухсегментная форма", + "ES": "Forma Binodular" + }, + "pokemon_form_three-segment_form": { + "PT-BR": "Forma Trissegmentar", + "EN": "Three-Segment Form", + "FR": "Forme Triple", + "DE": "Dreisegmentform", + "IT": "Forma Trimetamero", + "RU": "Трёхсегментная форма", + "ES": "Forma Trinodular" + }, + "pokemon_form_apex_build": { + "PT-BR": "Versão Plena", + "EN": "Apex Build", + "FR": "Forme Finale", + "DE": "Vollkommene Gestalt", + "IT": "Foggia Integrale", + "RU": "Финальная форма", + "ES": "Fisonomía Plena" + }, + "pokemon_form_ultimate_mode": { + "PT-BR": "Modo Supremo", + "EN": "Ultimate Mode", + "FR": "Mode Ultime", + "DE": "Kompletter Modus", + "IT": "Assetto Completo", + "RU": "Полноценный режим", + "ES": "Modo Pleno" + }, + "pokemon_form_summer_2023": { + "EN": "Summer 2023" + }, + "pokemon_form_summer_2023_a": { + "EN": "Summer 2023 A" + }, + "pokemon_form_summer_2023_b": { + "EN": "Summer 2023 B" + }, + "pokemon_form_summer_2023_c": { + "EN": "Summer 2023 C" + }, + "pokemon_form_summer_2023_d": { + "EN": "Summer 2023 D" + }, + "pokemon_form_paldea_combat": { + "EN": "Paldea Combat" + }, + "pokemon_form_paldea_blaze": { + "EN": "Paldea Blaze" + }, + "pokemon_form_paldea_aqua": { + "EN": "Paldea Aqua" + }, + "pokemon_form_paldea": { + "EN": "Paldea" + }, + "pokemon_form_summer_2023_e": { + "EN": "Summer 2023 E" + }, + "pokemon_form_flying_03": { + "EN": "Flying 03" + }, + "pokemon_form_jeju": { + "EN": "Jeju" + }, + "pokemon_form_doctor": { + "EN": "Doctor" + }, + "pokemon_form_wcs_2023": { + "EN": "Wcs 2023" + } +} \ No newline at end of file diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index fa8cbdc8..aff40cef 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -41,7 +41,7 @@ "FR": "Fouet Lianes", "DE": "Rankenhieb", "IT": "Frustata", - "RU": "Плеть-Лиана", + "RU": "Плеть-лиана", "ES": "Látigo Cepa" }, "pokemon_move_6": { @@ -299,7 +299,7 @@ "FR": "Crève-Cœur", "DE": "Herzstempel", "IT": "Cuorestampo", - "RU": "Печать-Сердце", + "RU": "ПечатьСердце", "ES": "Arrumaco" }, "pokemon_move_35": { @@ -423,7 +423,7 @@ "FR": "Méga-Sangsue", "DE": "Megasauger", "IT": "Megassorbimento", - "RU": "Мега-Осушение", + "RU": "Мега-осушение", "ES": "Megaagotar" }, "pokemon_move_49": { @@ -522,7 +522,7 @@ "FR": "Canon Graine", "DE": "Samenbomben", "IT": "Semebomba", - "RU": "Семя-Бомба", + "RU": "Семя-бомба", "ES": "Bomba Germen" }, "pokemon_move_60": { @@ -594,7 +594,7 @@ "FR": "Poing Ombre", "DE": "Finsterfaust", "IT": "Pugnodombra", - "RU": "Теневой Кулак", + "RU": "Теневая форма Кулак", "ES": "Puño Sombra" }, "pokemon_move_68": { @@ -890,7 +890,7 @@ "FR": "Plaie Croix", "DE": "Kreuzschere", "IT": "Forbice X", - "RU": "Икс-Ножницы", + "RU": "Икс-ножницы", "ES": "Tijera X" }, "pokemon_move_101": { @@ -1016,7 +1016,7 @@ "FR": "Giga-Sangsue", "DE": "Gigasauger", "IT": "Gigassorbimento", - "RU": "Гига-Осушение", + "RU": "Гига-осушение", "ES": "Gigadrenado" }, "pokemon_move_115": { @@ -1043,7 +1043,7 @@ "FR": "Lame Feuille", "DE": "Laubklinge", "IT": "Fendifoglia", - "RU": "Лист-Лезвие", + "RU": "Лист-лезвие", "ES": "Hoja Aguda" }, "pokemon_move_118": { @@ -1356,7 +1356,7 @@ "FR": "Fouet Lianes", "DE": "Rankenhieb", "IT": "Frustata", - "RU": "Плеть-Лиана", + "RU": "Плеть-лиана", "ES": "Látigo Cepa" }, "pokemon_move_215": { @@ -1828,7 +1828,7 @@ "FR": "Gyroballe", "DE": "Gyroball", "IT": "Vortexpalla", - "RU": "Гиро-Шар", + "RU": "Гиро-шар", "ES": "Giro Bola" }, "pokemon_move_268": { @@ -2306,7 +2306,7 @@ "EN": "Giga Impact", "DE": "Gigastoß", "IT": "Gigaimpatto", - "RU": "Гига-Удар", + "RU": "Гига-удар", "ES": "Gigaimpacto" }, "pokemon_move_322": { @@ -2527,9 +2527,13 @@ "FR": "Calcination", "DE": "Einäschern", "IT": "Bruciatutto", - "RU": " Превращение в Пепел", + "RU": "Превращение в Пепел", "ES": "Calcinación" }, + "pokemon_move_347": { + "EN": "Dark Void", + "RU": "Темная Бездна" + }, "pokemon_move_348": { "PT-BR": "Dança das Penas", "EN": "Feather Dance", @@ -2539,15 +2543,23 @@ "RU": "Танец с Перьями", "ES": "Danza Pluma" }, + "pokemon_move_349": { + "EN": "Fiery Dance", + "RU": "Горячий Танец" + }, "pokemon_move_350": { "PT-BR": "Vento de Fada", "EN": "Fairy Wind", "FR": "Vent Féérique", "DE": "Feenbrise", "IT": "Vento di Fata", - "RU": "Ветер Феи", + "RU": "Ветер Фей", "ES": "Viento Feérico" }, + "pokemon_move_351": { + "EN": "Relic Song", + "RU": "Древняя Песня" + }, "pokemon_move_352": { "PT-BR": "Esfera Climática", "EN": "Weather Ball", @@ -2886,6 +2898,9 @@ "RU": "Крылья Забвения", "ES": "Ala Mortífera" }, + "pokemon_move_390": { + "EN": "Natures Madness" + }, "pokemon_move_391": { "PT-BR": "Pinote Triplo", "EN": "Triple Axel", @@ -2910,5 +2925,26 @@ "IT": "Sabbiardente", "RU": "Раскалённый Песок", "ES": "Arenas Ardientes" + }, + "pokemon_move_394": { + "PT-BR": "Rugido do Tempo", + "EN": "Roar of Time", + "FR": "Hurle-Temps", + "DE": "Zeitenlärm", + "IT": "Fragortempo", + "RU": "Рёв Времени", + "ES": "Distorsión" + }, + "pokemon_move_395": { + "EN": "Bleakwind Storm" + }, + "pokemon_move_396": { + "EN": "Sandsear Storm" + }, + "pokemon_move_397": { + "EN": "Wildbolt Storm" + }, + "pokemon_move_398": { + "EN": "Spirit Shackle" } } \ No newline at end of file diff --git a/logic/get_local_pokemon_name.php b/logic/get_local_pokemon_name.php index 02bd4965..a2bfead1 100644 --- a/logic/get_local_pokemon_name.php +++ b/logic/get_local_pokemon_name.php @@ -23,16 +23,24 @@ function get_local_pokemon_name($pokemon_id, $pokemon_form_id, $override_languag // Get eggs from normal translation. $pokemon_name = (in_array($pokemon_id, EGGS)) ? $getTypeTranslation('egg_' . str_replace('999', '', $pokemon_id)) : $getTypeTranslation('pokemon_id_' . $pokemon_id); + $skipFallback = false; if ($pokemon_form_name != 'normal') { $pokemon_form_name = $getTypeTranslation('pokemon_form_' . $pokemon_form_name); + // Use only form name if form name contains Pokemon name + // e.g. Black Kyurem, Frost Rotom + if(strpos($pokemon_form_name, $pokemon_name, 0)) { + $pokemon_name = $pokemon_form_name; + $pokemon_form_name = ''; + $skipFallback = true; + } } // If we didn't find Pokemon name or form name from translation files, use the name from database as fallback - if(empty($pokemon_name) or empty($pokemon_form_name)) { + if(empty($pokemon_name) or empty($pokemon_form_name) && !$skipFallback) { // Pokemon name $pokemon_name = (empty($pokemon_name) ? $res['pokemon_name'] : $pokemon_name); // Pokemon form if(empty($pokemon_form_name) && $res['pokemon_form_name'] != 'normal') { - $pokemon_form_name = ucfirst(str_replace('_',' ',$res['pokemon_form_name'])); + $pokemon_form_name = ucfirst(str_replace('_',' ',$res['pokemon_form_name'])); } } return $pokemon_name . ($pokemon_form_name != "normal" ? " " . $pokemon_form_name : ""); diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 202c28d0..8f7a33e9 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -555,7 +555,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Pokemon raid boss $pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], true); - if(!in_array($raid['pokemon'], EGGS) && isset($raid['shadow']) && $raid['shadow']) $pokemon_name .= ' ' . getPublicTranslation('shadow'); + if(!in_array($raid['pokemon'], EGGS) && isset($raid['shadow']) && $raid['shadow']) $pokemon_name .= ' ' . getPublicTranslation('pokemon_form_shadow'); // Pokemon name and form? $pokemon_text_lines = array($pokemon_name); diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index 7283ceb2..2cc1d503 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -89,7 +89,7 @@ function show_raid_poll($raid, $inline = false) if($raid['event_pokemon_title'] == 1) $title = getPublicTranslation('raid_boss'); elseif($raid['event_pokemon_title'] == 2) $title = getPublicTranslation('featured_pokemon'); else $title = getPublicTranslation('raid_boss'); - $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . ' ' . (isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['pokemon'], EGGS) ? ' ' . getPublicTranslation('shadow') : '') . '', true); + $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . ' ' . (isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['pokemon'], EGGS) ? ' ' . getPublicTranslation('pokemon_form_shadow') : '') . '', true); // Display raid boss weather. $msg = raid_poll_message($msg, ($raid_pokemon_info['weather'] != 0) ? (' ' . get_weather_icons($raid_pokemon_info['weather'])) : '', true); diff --git a/logic/show_raid_poll_small.php b/logic/show_raid_poll_small.php index 6e28800e..dd4b3da2 100644 --- a/logic/show_raid_poll_small.php +++ b/logic/show_raid_poll_small.php @@ -26,7 +26,7 @@ function show_raid_poll_small($raid, $override_language = false) } // Pokemon if(!empty($raid['pokemon'])) { - $msg .= '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . (isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['pokemon'], EGGS) ? ' ' . getPublicTranslation('shadow') : '') . ' ' . CR; + $msg .= '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . (isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['pokemon'], EGGS) ? ' ' . getPublicTranslation('pokemon_form_shadow') : '') . ' ' . CR; } // Start time and end time if(!empty($raid['start_time']) && !empty($raid['end_time'])) { From ecbbe688c2e64995daff46743c0dc084f3e7aa01 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 9 Dec 2023 13:34:28 +0200 Subject: [PATCH 296/367] Fixed typing for megas --- mods/getdb.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index a983382d..70335b9c 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -199,13 +199,14 @@ function parse_master_data($game_master_url) { $form_id = -$tempData['tempEvoId']; $form_name = $mega_names[$form_id]; if(isset($tempData['types'])) { + $type = ''; foreach($tempData['types'] as $key => $data) { if($type == '') { - $type = $key; + $type = $typeArray[$key]; $weather = $weatherboost_table[$key]; continue; } - $type2 = $key; + $type2 = $typeArray[$key]; $weather .= $weatherboost_table[$key]; } } From ae102ec1252f7e958474771a5a341f447c100fd7 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 22 Dec 2023 20:28:38 +0200 Subject: [PATCH 297/367] Month format from 01 to 1 --- logic/createRaidBossList.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/createRaidBossList.php b/logic/createRaidBossList.php index 50cb9981..ab0fc3b6 100644 --- a/logic/createRaidBossList.php +++ b/logic/createRaidBossList.php @@ -19,7 +19,7 @@ */ function createRaidBossList() { global $config; - $dateFormat = 'j.m.'; + $dateFormat = 'j.n.'; $timeFormat = 'H:i'; $levelList = '(' . implode(',', $config->RAID_BOSS_LIST_RAID_LEVELS). ')'; $q = my_query(' From 498296896c973ef7bd2f40b4624c5fe74d815914 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 22 Dec 2023 20:29:04 +0200 Subject: [PATCH 298/367] Improved raidpicture fallback icon logic --- logic/raid_picture.php | 70 ++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 8f7a33e9..f90e701a 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -267,18 +267,16 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { } else { // Check pokemon icon source and create image $img_file = null; - $uicons = false; + $addressableFilename = $uiconsFilename = ['','','','','']; $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); - $addressable_icon = 'pm'.$raid['pokemon']; - $addressableFallback = 'pm'.$raid['pokemon'].'.fNORMAL'; - $uicons_icon = $raid['pokemon']; - + $addressableFilename[0] = 'pm'.$raid['pokemon']; + $uiconsFilename[0] = $raid['pokemon']; if($raid['pokemon_form_name'] != 'normal') { $addrFormPrefix = ''; if($raid['pokemon'] == 201) $addrFormPrefix = 'UNOWN_'; - $addressable_icon .= '.f' . $addrFormPrefix . strtoupper($raid['pokemon_form_name']); - $uicons_icon .= '_f'.$raid['pokemon_form']; + $addressableFilename[1] = '.f' . $addrFormPrefix . strtoupper($raid['pokemon_form_name']); + $uiconsFilename[1] = '_f' . $raid['pokemon_form']; } // Add costume info for every mon except megas @@ -286,20 +284,18 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $costume = json_decode(file_get_contents(ROOT_PATH . '/protos/costume.json'), true); $costumeName = array_search($raid['costume'],$costume); if(!empty($costumeName)) { - $addressable_icon .= '.c' . array_search($raid['costume'],$costume); - - $uicons_icon .= '_c'.$raid['costume']; + $addressableFilename[2] = '.c' . $costumeName; + $uiconsFilename[2] = '_c' . $raid['costume']; } } if($raid['shiny'] == 1 && $config->RAID_PICTURE_SHOW_SHINY) { - $addressable_icon .= '.s'; - $uicons_icon .= '_s'; + $addressableFilename[3] = '.s'; + $uiconsFilename[3] = '_s'; $shiny_icon = grab_img(IMAGES_PATH . "/shinystars.png"); } - $addressable_icon .= '.icon.png'; - $addressableFallback .= '.icon.png'; - $uicons_icon .= '.png'; - + $addressableFilename[4] = '.icon.png'; + $uiconsFilename[4] = '.png'; + $imageFilenames = createFilenameList($addressableFilename, $uiconsFilename); foreach($p_sources as $p_dir) { // Icon dir named 'pokemon'? Then change path to not add '_repo-owner' to icon folder name if($p_dir == 'pokemon') $asset_dir = 'pokemon'; else $asset_dir = 'pokemon_' . $p_dir; @@ -307,23 +303,17 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $p_img_base_path = IMAGES_PATH . "/" . $asset_dir; // Check if file exists in this collection - if(file_exists($p_img_base_path . "/" . $addressable_icon) && filesize($p_img_base_path . "/" . $addressable_icon) > 0) { - $img_file = $p_img_base_path . "/" . $addressable_icon; - break; - }else if(file_exists($p_img_base_path . "/" . $addressableFallback) && filesize($p_img_base_path . "/" . $addressableFallback) > 0) { - $img_file = $p_img_base_path . "/" . $addressableFallback; - $uicons = true; - break; - }else if(file_exists($p_img_base_path . "/" . $uicons_icon) && filesize($p_img_base_path . "/" . $uicons_icon) > 0) { - $img_file = $p_img_base_path . "/" . $uicons_icon; - $uicons = true; - break; + foreach($imageFilenames as $filename) { + if(file_exists($p_img_base_path . "/" . $filename) && filesize($p_img_base_path . "/" . $filename) > 0) { + $img_file = $p_img_base_path . "/" . $filename; + break 2; + } } } // If no image was found, substitute with a fallback if($img_file === null) { - info_log($addressable_icon . ' ' . $uicons_icon, 'Failed to find an image in any pokemon image collection for:'); + info_log(join($addressableFilename) . ' ' . join($uiconsFilename), 'Failed to find an image in any pokemon image collection for:'); $img_fallback_file = null; // If we know the raid level, fallback to egg image if(array_key_exists('level', $raid) && $raid['level'] !== null && $raid['level'] != 0) { @@ -340,10 +330,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Position and size of the picture $dst_x = $dst_y = 100; $dst_w = $dst_h = 256; - $src_w = $src_h = $dst_w; - if($uicons === true) { - [$src_w, $src_h] = getimagesize($img_file); - } + [$src_w, $src_h] = getimagesize($img_file); if($raid['type'] != '') $show_boss_pokemon_types = true; } @@ -435,7 +422,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { $gym_name_words = explode(SP, $gym_name); $gym_name_word_lengths = array_map('strlen', array_map('utf8_decode', $gym_name_words)); $gym_name_word_largest = max($gym_name_word_lengths); - $gym_name_total_chars = strlen(utf8_decode($gym_name)); + $gym_name_total_chars = strlen(mb_convert_encoding($gym_name, 'ISO-8859-1', 'UTF-8')); // Number of rows based on number of words or total chars $gym_name_rows = 1; @@ -672,3 +659,20 @@ function grab_img($uri) { } return $img; } + +function createFilenameList($a, $u) { + // Full filename of addressable icon + $filenames[0] = join($a); + // Full filename of uicons icon + $filenames[1] = join($u); + // List of fallback icons for addressable assets + $filenames[2] = join([$a[0], '.fNORMAL', $a[2], $a[3], $a[4]]); + $filenames[3] = join([$a[0], $a[1], $a[2], $a[4]]); + $filenames[4] = join([$a[0], '.fNORMAL', $a[2], $a[4]]); + $filenames[5] = join([$a[0], $a[1], $a[4]]); + $filenames[6] = join([$a[0], '.fNORMAL', $a[4]]); + $filenames[7] = join([$a[0], $a[4]]); + $filenames[8] = join([$a[0], $a[4]]); + + return $filenames; +} From c71dfbe17bc52655c2424b590fe263934844d1c9 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 22 Dec 2023 20:29:37 +0200 Subject: [PATCH 299/367] Improved importing from pokebattler --- logic/get_pokemon_id_by_name.php | 6 +++--- logic/resolve_boss_name_to_ids.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/logic/get_pokemon_id_by_name.php b/logic/get_pokemon_id_by_name.php index 3d5b006b..7e2057be 100644 --- a/logic/get_pokemon_id_by_name.php +++ b/logic/get_pokemon_id_by_name.php @@ -46,13 +46,13 @@ function get_pokemon_id_by_name($pokemon_name, $get_from_db = false) SELECT pokedex_id, pokemon_form_id FROM pokemon WHERE pokemon_name = :poke_name - AND pokemon_form_name = :form_name + AND pokemon_form_name LIKE :form_name LIMIT 1 - ', ['poke_name' => $poke_name, 'form_name' => $pokemon_form] + ', ['poke_name' => $poke_name, 'form_name' => '%'.$pokemon_form.'%'] ); - $res = $query->fetch(); $pokemon_form_id = 0; if($query->rowCount() > 0) { + $res = $query->fetch(); $pokemon_form_id = $res['pokemon_form_id']; $pokemon_id = $res['pokedex_id']; } diff --git a/logic/resolve_boss_name_to_ids.php b/logic/resolve_boss_name_to_ids.php index 2b7c9aba..48ae9dd3 100644 --- a/logic/resolve_boss_name_to_ids.php +++ b/logic/resolve_boss_name_to_ids.php @@ -9,10 +9,10 @@ function resolve_boss_name_to_ids($pokemon_name) { $name = $pokemon_name; $form = 'normal'; // Pokemon name ending with "_FORM" ? - if (preg_match('/(MEGA|MEGA_Y|MEGA_X|PRIMAL|FORM|SHADOW)$/', $pokemon_name)) { + if (preg_match('/(MEGA|MEGA_Y|MEGA_X|PRIMAL|FORM|SHADOW|FORME)$/', $pokemon_name)) { debug_log('Pokemon with a special form received: ' . $pokemon_name); // Remove "_FORM" - $pokemon = str_replace('_FORM', '', $pokemon_name); + $pokemon = preg_replace('/_FORM$/', '', $pokemon_name); // Get pokemon name and form. [$name, $form] = explode("_", $pokemon, 2); From 9ee0cabfb5bb25e5bd36ec3fce6249e6923f117c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 11 Jan 2024 20:43:47 +0200 Subject: [PATCH 300/367] Fixed getdb we were missing a few hundred pokemon --- mods/getdb.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 70335b9c..84dc9a3f 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -176,9 +176,10 @@ function parse_master_data($game_master_url) { $type2 = $typeArray[$key]; $weather .= $weatherboost_table[$key]; } - foreach($row['forms'] as $formId => $formData) { - if($formId == 0 || $formData['name'] == 'Shadow' || $formData['name'] == 'Purified') continue; + foreach($row['forms'] as $formData) { + if($formData['name'] == 'Shadow' || $formData['name'] == 'Purified') continue; $form_name = strtolower(preg_replace('/\s/', '_', $formData['name'])); + if($form_name == 'unset') $form_name = 'normal'; $form_id = $formData['form']; $pokemon_array[$pokemon_id][$form_name] = [ 'pokemon_name' => $pokemon_name, From 64f352cdbfb91034d82ee7d12826f5c5bd2c936d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:50:41 +0200 Subject: [PATCH 301/367] Another rework of form translations Let's ditch translating by form name and use form id. Makes life much easier. --- getTranslations.php | 31 +- lang/pokemon_forms.json | 1780 ++++++++++++++++++++++++++++++--------- 2 files changed, 1409 insertions(+), 402 deletions(-) diff --git a/getTranslations.php b/getTranslations.php index bb075080..c97c1f7c 100644 --- a/getTranslations.php +++ b/getTranslations.php @@ -1,8 +1,6 @@ $language) { @@ -47,15 +32,8 @@ // Save pokemon moves into an array }elseif($key == 'move') { $move_array['pokemon_move_'.$id][$language] = $translation; - } - } - // This translation file uses english names as reference - $formFile = curl_open_file('https://raw.githubusercontent.com/WatWowMap/pogo-translations/master/static/englishRef/forms_'. $lanfile. '.json'); - $formTranslationData = json_decode($formFile, true); - foreach($formTranslationData as $title => $translation) { - if(in_array($title, $formsToFetch)) { - $formName = preg_replace("/\s/", "_", strtolower($title)); - $form_array['pokemon_form_'. $formName][$language] = $translation; + }elseif($key == 'form') { + $form_array['pokemon_form_'. $id][$language] = $translation; } } } @@ -86,7 +64,10 @@ function remove_duplicate_translations($array) { $new_array = []; foreach($array as $translation_id => $translations) { foreach($translations as $lang => $translation) { - if($lang == 'EN' or $translation != $array[$translation_id]['EN']) + if( + ($lang == 'EN' or $translation != $array[$translation_id]['EN']) and + !in_array($array[$translation_id]['EN'], ['Normal','Purified','Shadow']) + ) $new_array[$translation_id][$lang] = $translation; } } diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index 113de507..6ffa3651 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -1,160 +1,113 @@ { - "pokemon_form_10": { - "EN": "10" - }, - "pokemon_form_11": { - "EN": "11" - }, - "pokemon_form_12": { - "EN": "12" - }, - "pokemon_form_13": { - "EN": "13" - }, - "pokemon_form_14": { - "EN": "14" - }, - "pokemon_form_15": { - "EN": "15" - }, - "pokemon_form_16": { - "EN": "16" - }, - "pokemon_form_17": { - "EN": "17" - }, - "pokemon_form_18": { - "EN": "18" - }, - "pokemon_form_19": { - "EN": "19" - }, - "pokemon_form_2020": { - "EN": "2020" - }, - "pokemon_form_2021": { - "EN": "2021" - }, - "pokemon_form_2022": { - "EN": "2022" - }, - "pokemon_form_a": { + "pokemon_form_1": { "EN": "A" }, - "pokemon_form_b": { + "pokemon_form_2": { "EN": "B" }, - "pokemon_form_c": { + "pokemon_form_3": { "EN": "C" }, - "pokemon_form_d": { + "pokemon_form_4": { "EN": "D" }, - "pokemon_form_e": { + "pokemon_form_5": { "EN": "E" }, - "pokemon_form_f": { + "pokemon_form_6": { "EN": "F" }, - "pokemon_form_g": { + "pokemon_form_7": { "EN": "G" }, - "pokemon_form_h": { + "pokemon_form_8": { "EN": "H" }, - "pokemon_form_i": { + "pokemon_form_9": { "EN": "I" }, - "pokemon_form_j": { + "pokemon_form_10": { "EN": "J" }, - "pokemon_form_k": { + "pokemon_form_11": { "EN": "K" }, - "pokemon_form_l": { + "pokemon_form_12": { "EN": "L" }, - "pokemon_form_m": { + "pokemon_form_13": { "EN": "M" }, - "pokemon_form_n": { + "pokemon_form_14": { "EN": "N" }, - "pokemon_form_o": { + "pokemon_form_15": { "EN": "O" }, - "pokemon_form_p": { + "pokemon_form_16": { "EN": "P" }, - "pokemon_form_q": { + "pokemon_form_17": { "EN": "Q" }, - "pokemon_form_r": { + "pokemon_form_18": { "EN": "R" }, - "pokemon_form_s": { + "pokemon_form_19": { "EN": "S" }, - "pokemon_form_t": { + "pokemon_form_20": { "EN": "T" }, - "pokemon_form_u": { + "pokemon_form_21": { "EN": "U" }, - "pokemon_form_v": { + "pokemon_form_22": { "EN": "V" }, - "pokemon_form_w": { + "pokemon_form_23": { "EN": "W" }, - "pokemon_form_x": { + "pokemon_form_24": { "EN": "X" }, - "pokemon_form_y": { + "pokemon_form_25": { "EN": "Y" }, - "pokemon_form_z": { + "pokemon_form_26": { "EN": "Z" }, - "pokemon_form_exclamation_point": { + "pokemon_form_27": { "EN": "Exclamation Point", "FR": "!", "DE": "!", "RU": "!" }, - "pokemon_form_question_mark": { + "pokemon_form_28": { "EN": "Question Mark", "FR": "?", "DE": "?", "RU": "?" }, - "pokemon_form_normal": { - "EN": "Normal", - "IT": "Normale", - "RU": "Нормальный" - }, - "pokemon_form_sunny": { - "PT-BR": "Ensolarada", + "pokemon_form_30": { "EN": "Sunny", "FR": "Solaire", "DE": "Sonnenform", - "IT": "Sole", - "RU": "Солнечная форма", - "ES": "Sol" + "RU": "Солнечная форма" }, - "pokemon_form_rainy": { + "pokemon_form_31": { "EN": "Rainy", "FR": "Eau de pluie", "DE": "Regenform", "RU": "Дождливая форма" }, - "pokemon_form_snowy": { + "pokemon_form_32": { "EN": "Snowy", "FR": "Blizzard", "DE": "Schneeform", "RU": "Снежная форма" }, - "pokemon_form_attack": { + "pokemon_form_34": { "PT-BR": "Ataque", "EN": "Attack", "FR": "Attaque", @@ -163,7 +116,7 @@ "RU": "Атакующая форма", "ES": "Ataque" }, - "pokemon_form_defense": { + "pokemon_form_35": { "PT-BR": "Defesa", "EN": "Defense", "FR": "Défense", @@ -172,7 +125,7 @@ "RU": "Защитная форма", "ES": "Defensa" }, - "pokemon_form_speed": { + "pokemon_form_36": { "PT-BR": "Velocidade", "EN": "Speed", "FR": "Vitesse", @@ -181,35 +134,103 @@ "RU": "Скоростная форма", "ES": "Velocidad" }, - "pokemon_form_00": { + "pokemon_form_37": { "EN": "00" }, - "pokemon_form_01": { + "pokemon_form_38": { "EN": "01" }, - "pokemon_form_02": { + "pokemon_form_39": { "EN": "02" }, - "pokemon_form_03": { + "pokemon_form_40": { "EN": "03" }, - "pokemon_form_04": { + "pokemon_form_41": { "EN": "04" }, - "pokemon_form_05": { + "pokemon_form_42": { "EN": "05" }, - "pokemon_form_06": { + "pokemon_form_43": { "EN": "06" }, - "pokemon_form_07": { + "pokemon_form_44": { "EN": "07" }, - "pokemon_form_alola": { + "pokemon_form_46": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_48": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_50": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_52": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_54": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_56": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_58": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_60": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_62": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_64": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_66": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_68": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_70": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_72": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_74": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_76": { "EN": "Alola", "RU": "Алольская форма" }, - "pokemon_form_frost_rotom": { + "pokemon_form_78": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_80": { + "EN": "Alola", + "RU": "Алольская форма" + }, + "pokemon_form_82": { "PT-BR": "Rotom Congelante", "EN": "Frost Rotom", "FR": "Motisma Froid", @@ -218,7 +239,7 @@ "RU": "Холодильник", "ES": "Rotom Frío" }, - "pokemon_form_fan_rotom": { + "pokemon_form_83": { "PT-BR": "Rotom Ventilador", "EN": "Fan Rotom", "FR": "Motisma Hélice", @@ -227,7 +248,7 @@ "RU": "Вентилятор", "ES": "Rotom Ventilador" }, - "pokemon_form_mow_rotom": { + "pokemon_form_84": { "PT-BR": "Rotom Corte", "EN": "Mow Rotom", "FR": "Motisma Tonte", @@ -236,7 +257,7 @@ "RU": "Газонокосилка", "ES": "Rotom Corte" }, - "pokemon_form_wash_rotom": { + "pokemon_form_85": { "PT-BR": "Rotom Lavagem", "EN": "Wash Rotom", "FR": "Motisma Lavage", @@ -245,7 +266,7 @@ "RU": "Стиралка", "ES": "Rotom Lavado" }, - "pokemon_form_heat_rotom": { + "pokemon_form_86": { "PT-BR": "Rotom Calor", "EN": "Heat Rotom", "FR": "Motisma Chaleur", @@ -254,16 +275,16 @@ "RU": "Обогреватель", "ES": "Rotom Calor" }, - "pokemon_form_plant_cloak": { + "pokemon_form_87": { "PT-BR": "Manto Vegetal", "EN": "Plant Cloak", - "FR": "Cape Plante", + "FR": "Plante", "DE": "Pflanzenumhang", "IT": "Manto Pianta", "RU": "Растительный покров", "ES": "Tronco Planta" }, - "pokemon_form_sandy_cloak": { + "pokemon_form_88": { "PT-BR": "Manto Arenoso", "EN": "Sandy Cloak", "FR": "Cape Sable", @@ -272,7 +293,7 @@ "RU": "Песчанный покров", "ES": "Tronco Arena" }, - "pokemon_form_trash_cloak": { + "pokemon_form_89": { "PT-BR": "Manto de Lixo", "EN": "Trash Cloak", "FR": "Cape Déchet", @@ -281,7 +302,7 @@ "RU": "Мусорный покров", "ES": "Tronco Basura" }, - "pokemon_form_altered_forme": { + "pokemon_form_90": { "PT-BR": "Forma Alterada", "EN": "Altered Forme", "FR": "Forme Alternative", @@ -290,16 +311,16 @@ "RU": "Изменённая форма", "ES": "Forma Modificada" }, - "pokemon_form_origin_forme": { + "pokemon_form_91": { "PT-BR": "Forma Origem", "EN": "Origin Forme", "FR": "Forme Originelle", - "DE": "Urform", + "DE": "Ur", "IT": "Forma Originale", "RU": "Исходная форма", "ES": "Forma Origen" }, - "pokemon_form_sky_forme": { + "pokemon_form_92": { "PT-BR": "Forma Céu", "EN": "Sky Forme", "FR": "Forme Céleste", @@ -308,7 +329,7 @@ "RU": "Небесная форма", "ES": "Forma Cielo" }, - "pokemon_form_land_forme": { + "pokemon_form_93": { "PT-BR": "Forma Terrestre", "EN": "Land Forme", "FR": "Forme Terrestre", @@ -317,7 +338,7 @@ "RU": "Земная форма", "ES": "Forma Tierra" }, - "pokemon_form_overcast_form": { + "pokemon_form_94": { "PT-BR": "Forma Nublada", "EN": "Overcast Form", "FR": "Temps Couvert", @@ -326,7 +347,31 @@ "RU": "Пасмурная форма", "ES": "Forma Encapotado" }, - "pokemon_form_west_sea": { + "pokemon_form_95": { + "EN": "Sunny", + "FR": "Temps Ensoleillé", + "DE": "Sonnenform", + "RU": "Солнечная форма" + }, + "pokemon_form_96": { + "PT-BR": "Mar Ocidental", + "EN": "West Sea", + "FR": "Mer Occident", + "DE": "Westliches Meer", + "IT": "Mare Ovest", + "RU": "Западно-морская форма", + "ES": "Mar Oeste" + }, + "pokemon_form_97": { + "PT-BR": "Mar Leste", + "EN": "East Sea", + "FR": "Mer Orient", + "DE": "Östliches Meer", + "IT": "Mare Est", + "RU": "Восточно-морская форма", + "ES": "Mar Este" + }, + "pokemon_form_98": { "PT-BR": "Mar Ocidental", "EN": "West Sea", "FR": "Mer Occident", @@ -335,7 +380,7 @@ "RU": "Западно-морская форма", "ES": "Mar Oeste" }, - "pokemon_form_east_sea": { + "pokemon_form_99": { "PT-BR": "Mar Leste", "EN": "East Sea", "FR": "Mer Orient", @@ -344,7 +389,7 @@ "RU": "Восточно-морская форма", "ES": "Mar Este" }, - "pokemon_form_fighting": { + "pokemon_form_101": { "PT-BR": "Lutador", "EN": "Fighting", "FR": "Combat", @@ -353,7 +398,7 @@ "RU": "Боевая форма", "ES": "Lucha" }, - "pokemon_form_flying": { + "pokemon_form_102": { "PT-BR": "Voador", "EN": "Flying", "FR": "Vol", @@ -362,7 +407,7 @@ "RU": "Летающая форма", "ES": "Volador" }, - "pokemon_form_poison": { + "pokemon_form_103": { "PT-BR": "Venenoso", "EN": "Poison", "DE": "Gift", @@ -370,16 +415,16 @@ "RU": "Ядовитая форма", "ES": "Veneno" }, - "pokemon_form_ground": { + "pokemon_form_104": { "PT-BR": "Terrestre", "EN": "Ground", "FR": "Sol", "DE": "Boden", "IT": "Terra", - "RU": "Земляная форма", + "RU": "Земленая форма", "ES": "Tierra" }, - "pokemon_form_rock": { + "pokemon_form_105": { "PT-BR": "Pedra", "EN": "Rock", "FR": "Roche", @@ -388,7 +433,7 @@ "RU": "Каменная форма", "ES": "Roca" }, - "pokemon_form_bug": { + "pokemon_form_106": { "PT-BR": "Inseto", "EN": "Bug", "FR": "Insecte", @@ -397,7 +442,7 @@ "RU": "Жучья форма", "ES": "Bicho" }, - "pokemon_form_ghost": { + "pokemon_form_107": { "PT-BR": "Fantasma", "EN": "Ghost", "FR": "Spectre", @@ -406,7 +451,7 @@ "RU": "Призрачная форма", "ES": "Fantasma" }, - "pokemon_form_steel": { + "pokemon_form_108": { "PT-BR": "Aço", "EN": "Steel", "FR": "Acier", @@ -415,7 +460,7 @@ "RU": "Стальная форма", "ES": "Acero" }, - "pokemon_form_fire": { + "pokemon_form_109": { "PT-BR": "Fogo", "EN": "Fire", "FR": "Feu", @@ -424,7 +469,7 @@ "RU": "Огненная форма", "ES": "Fuego" }, - "pokemon_form_water": { + "pokemon_form_110": { "PT-BR": "Água", "EN": "Water", "FR": "Eau", @@ -433,7 +478,7 @@ "RU": "Водная форма", "ES": "Agua" }, - "pokemon_form_grass": { + "pokemon_form_111": { "PT-BR": "Planta", "EN": "Grass", "FR": "Plante", @@ -442,7 +487,7 @@ "RU": "Травяная форма", "ES": "Planta" }, - "pokemon_form_electric": { + "pokemon_form_112": { "PT-BR": "Elétrico", "EN": "Electric", "FR": "Électrik", @@ -451,7 +496,7 @@ "RU": "Электрическая форма", "ES": "Eléctrico" }, - "pokemon_form_psychic": { + "pokemon_form_113": { "PT-BR": "Psíquico", "EN": "Psychic", "FR": "Psy", @@ -460,7 +505,7 @@ "RU": "Психическая форма", "ES": "Psíquico" }, - "pokemon_form_ice": { + "pokemon_form_114": { "PT-BR": "Gelo", "EN": "Ice", "FR": "Glace", @@ -469,7 +514,7 @@ "RU": "Ледяная форма", "ES": "Hielo" }, - "pokemon_form_dragon": { + "pokemon_form_115": { "PT-BR": "Dragão", "EN": "Dragon", "DE": "Drache", @@ -477,7 +522,7 @@ "RU": "Драконья форма", "ES": "Dragón" }, - "pokemon_form_dark": { + "pokemon_form_116": { "PT-BR": "Sombrio", "EN": "Dark", "FR": "Ténèbres", @@ -486,7 +531,7 @@ "RU": "Темная форма", "ES": "Siniestro" }, - "pokemon_form_fairy": { + "pokemon_form_117": { "PT-BR": "Fada", "EN": "Fairy", "FR": "Fée", @@ -495,13 +540,75 @@ "RU": "Феечная форма", "ES": "Hada" }, - "pokemon_form_08": { + "pokemon_form_118": { + "PT-BR": "Manto Vegetal", + "EN": "Plant Cloak", + "FR": "Cape Plante", + "DE": "Pflanzenumhang", + "IT": "Manto Pianta", + "RU": "Растительный покров", + "ES": "Tronco Planta" + }, + "pokemon_form_119": { + "PT-BR": "Manto Arenoso", + "EN": "Sandy Cloak", + "FR": "Cape Sable", + "DE": "Sandumhang", + "IT": "Manto Sabbia", + "RU": "Песчанный покров", + "ES": "Tronco Arena" + }, + "pokemon_form_120": { + "PT-BR": "Manto de Lixo", + "EN": "Trash Cloak", + "FR": "Cape Déchet", + "DE": "Lumpenumhang", + "IT": "Manto Scarti", + "RU": "Мусорный покров", + "ES": "Tronco Basura" + }, + "pokemon_form_121": { "EN": "08" }, - "pokemon_form_09": { + "pokemon_form_122": { "EN": "09" }, - "pokemon_form_red-striped": { + "pokemon_form_123": { + "EN": "10" + }, + "pokemon_form_124": { + "EN": "11" + }, + "pokemon_form_125": { + "EN": "12" + }, + "pokemon_form_126": { + "EN": "13" + }, + "pokemon_form_127": { + "EN": "14" + }, + "pokemon_form_128": { + "EN": "15" + }, + "pokemon_form_129": { + "EN": "16" + }, + "pokemon_form_130": { + "EN": "17" + }, + "pokemon_form_131": { + "EN": "18" + }, + "pokemon_form_132": { + "EN": "19" + }, + "pokemon_form_133": { + "EN": "A", + "FR": "Armure", + "DE": "Rüstung" + }, + "pokemon_form_136": { "PT-BR": "Listras Vermelhas", "EN": "Red-Striped", "FR": "Motif Rouge", @@ -510,7 +617,7 @@ "RU": "Красно-полосатая форма", "ES": "Forma Raya Roja" }, - "pokemon_form_blue-striped": { + "pokemon_form_137": { "PT-BR": "Listras Azuis", "EN": "Blue-Striped", "FR": "Motif Bleu", @@ -519,34 +626,70 @@ "RU": "Сине-полосатая форма", "ES": "Forma Raya Azul" }, - "pokemon_form_standard": { + "pokemon_form_138": { "EN": "Standard", "RU": "Обычная форма" }, - "pokemon_form_zen": { + "pokemon_form_139": { "EN": "Zen", "DE": "Trance", "RU": "Дзен" }, - "pokemon_form_incarnate_forme": { + "pokemon_form_140": { "PT-BR": "Forma Materializada", "EN": "Incarnate Forme", "FR": "Forme Avatar", - "DE": "Inkarnationsform", + "DE": "Inkarnation", "IT": "Forma Incarnazione", "RU": "Воплощённая форма", "ES": "Forma Avatar" }, - "pokemon_form_therian_forme": { + "pokemon_form_141": { "PT-BR": "Forma Therian", "EN": "Therian Forme", "FR": "Forme Totémique", - "DE": "Tiergeistform", + "DE": "Tiergeist", "IT": "Forma Totem", - "RU": "Форма Териан", + "RU": "Териан форма", + "ES": "Forma Tótem" + }, + "pokemon_form_142": { + "PT-BR": "Forma Materializada", + "EN": "Incarnate Forme", + "FR": "Forme Avatar", + "DE": "Inkarnation", + "IT": "Forma Incarnazione", + "RU": "Воплощённая форма", + "ES": "Forma Avatar" + }, + "pokemon_form_143": { + "PT-BR": "Forma Therian", + "EN": "Therian Forme", + "FR": "Forme Totémique", + "DE": "Tiergeist", + "IT": "Forma Totem", + "RU": "Териан форма", + "ES": "Forma Tótem" + }, + "pokemon_form_144": { + "PT-BR": "Forma Materializada", + "EN": "Incarnate Forme", + "FR": "Forme Avatar", + "DE": "Inkarnation", + "IT": "Forma Incarnazione", + "RU": "Воплощённая форма", + "ES": "Forma Avatar" + }, + "pokemon_form_145": { + "PT-BR": "Forma Therian", + "EN": "Therian Forme", + "FR": "Forme Totémique", + "DE": "Tiergeist", + "IT": "Forma Totem", + "RU": "Териан форма", "ES": "Forma Tótem" }, - "pokemon_form_black_kyurem": { + "pokemon_form_147": { "PT-BR": "Kyurem Preto", "EN": "Black Kyurem", "FR": "Kyurem Noir", @@ -555,7 +698,7 @@ "RU": "Чёрный Кьюрем", "ES": "Kyurem Negro" }, - "pokemon_form_white_kyurem": { + "pokemon_form_148": { "PT-BR": "Kyurem Branco", "EN": "White Kyurem", "FR": "Kyurem Blanc", @@ -564,7 +707,7 @@ "RU": "Белый Кьюрем", "ES": "Kyurem Blanco" }, - "pokemon_form_ordinary_form": { + "pokemon_form_149": { "PT-BR": "Forma Comum", "EN": "Ordinary Form", "FR": "Aspect Normal", @@ -573,7 +716,7 @@ "RU": "Обычная форма", "ES": "Forma Habitual" }, - "pokemon_form_resolute_form": { + "pokemon_form_150": { "PT-BR": "Forma Resoluta", "EN": "Resolute Form", "FR": "Resolute", @@ -582,7 +725,7 @@ "RU": "Решительная форма", "ES": "Forma Brío" }, - "pokemon_form_aria_forme": { + "pokemon_form_151": { "PT-BR": "Forma Ária", "EN": "Aria Forme", "FR": "Forme Chant", @@ -591,7 +734,7 @@ "RU": "Форма Арии", "ES": "Forma Lírica" }, - "pokemon_form_pirouette_forme": { + "pokemon_form_152": { "PT-BR": "Forma Pirueta", "EN": "Pirouette Forme", "FR": "Pirouette", @@ -600,25 +743,43 @@ "RU": "Форма Пируэта", "ES": "Forma Danza" }, - "pokemon_form_shadow": { - "PT-BR": "Sombroso", - "EN": "Shadow", - "FR": "Obscur", - "DE": "Crypto", - "IT": "Ombra", - "RU": "Теневые", - "ES": "Oscuro" - }, - "pokemon_form_purified": { - "PT-BR": "Purificado", - "EN": "Purified", - "FR": "Purifié", - "DE": "Erlöst", - "IT": "Purificato", - "RU": "Очищенные", - "ES": "Purificado" - }, - "pokemon_form_spring_form": { + "pokemon_form_585": { + "PT-BR": "Forma Primavera", + "EN": "Spring Form", + "FR": "Forme Printemps", + "DE": "Frühling", + "IT": "Forma Primavera", + "RU": "Весенняя форма", + "ES": "Forma Primavera" + }, + "pokemon_form_586": { + "PT-BR": "Forma Verão", + "EN": "Summer Form", + "FR": "Forme Été", + "DE": "Sommer", + "IT": "Forma Estate", + "RU": "Летняя форма", + "ES": "Forma Verano" + }, + "pokemon_form_587": { + "PT-BR": "Forma Outono", + "EN": "Autumn Form", + "FR": "Forme Automne", + "DE": "Herbst", + "IT": "Forma Autunno", + "RU": "Осенняя форма", + "ES": "Forma Otoño" + }, + "pokemon_form_588": { + "PT-BR": "Forma Inverno", + "EN": "Winter Form", + "FR": "Forme Hiver", + "DE": "Winter", + "IT": "Forma Inverno", + "RU": "Зимняя форма", + "ES": "Forma Invierno" + }, + "pokemon_form_589": { "PT-BR": "Forma Primavera", "EN": "Spring Form", "FR": "Forme Printemps", @@ -627,7 +788,7 @@ "RU": "Весенняя форма", "ES": "Forma Primavera" }, - "pokemon_form_summer_form": { + "pokemon_form_590": { "PT-BR": "Forma Verão", "EN": "Summer Form", "FR": "Forme Été", @@ -636,7 +797,7 @@ "RU": "Летняя форма", "ES": "Forma Verano" }, - "pokemon_form_autumn_form": { + "pokemon_form_591": { "PT-BR": "Forma Outono", "EN": "Autumn Form", "FR": "Forme Automne", @@ -645,7 +806,7 @@ "RU": "Осенняя форма", "ES": "Forma Otoño" }, - "pokemon_form_winter_form": { + "pokemon_form_592": { "PT-BR": "Forma Inverno", "EN": "Winter Form", "FR": "Forme Hiver", @@ -654,77 +815,222 @@ "RU": "Зимняя форма", "ES": "Forma Invierno" }, - "pokemon_form_shock": { + "pokemon_form_594": { "EN": "Shock", "FR": "Module Choc", "DE": "Blitzmodul", "RU": "Электрический привод" }, - "pokemon_form_burn": { + "pokemon_form_595": { "EN": "Burn", "FR": "Module Pyro", "DE": "Flammenmodul", "RU": "Огненный привод" }, - "pokemon_form_chill": { + "pokemon_form_596": { "EN": "Chill", "FR": "Module Cryo", "DE": "Gefriermodul", "RU": "Ледяной привод" }, - "pokemon_form_douse": { + "pokemon_form_597": { "EN": "Douse", "FR": "Module Aqua", "DE": "Aquamodul", "RU": "Водный привод" }, - "pokemon_form_fall_2019": { - "EN": "Fall 2019", - "FR": "Automne 2019", - "DE": "Herbst 2019" + "pokemon_form_599": { + "EN": "Noevolve" }, - "pokemon_form_vs_2019": { - "EN": "Vs 2019" + "pokemon_form_601": { + "EN": "Noevolve" }, - "pokemon_form_galarian": { - "EN": "Galarian" + "pokemon_form_603": { + "EN": "Noevolve" }, - "pokemon_form_copy_2019": { - "EN": "Copy 2019", - "FR": "Clone 2019", - "RU": "Клон 2019" + "pokemon_form_604": { + "EN": "Noevolve" }, - "pokemon_form_spring_2020": { - "EN": "Spring 2020", - "FR": "Printemps 2020", - "DE": "Frühjahr 2020", - "RU": "Весна 2020" + "pokemon_form_605": { + "EN": "Noevolve" }, - "pokemon_form_female": { - "PT-BR": "Fêmea", - "EN": "Female", - "FR": "Femelle", - "DE": "Weiblich", - "IT": "Femmina", - "RU": "Женский", - "ES": "Hembra" + "pokemon_form_606": { + "EN": "Noevolve" }, - "pokemon_form_costume_2020": { - "EN": "Costume 2020", - "DE": "Kostüm 2020", - "RU": "Костюм 2020" + "pokemon_form_607": { + "EN": "Noevolve" }, - "pokemon_form_galarian_standard": { - "EN": "Galarian Standard", - "DE": "Galar Normal", - "RU": "Галарская форма" + "pokemon_form_608": { + "EN": "Noevolve" }, - "pokemon_form_galarian_zen": { + "pokemon_form_609": { + "EN": "Noevolve" + }, + "pokemon_form_894": { + "EN": "Fall 2019", + "FR": "Automne 2019", + "DE": "Herbst 2019" + }, + "pokemon_form_895": { + "EN": "Fall 2019", + "FR": "Automne 2019", + "DE": "Herbst 2019" + }, + "pokemon_form_896": { + "EN": "Fall 2019", + "FR": "Automne 2019", + "DE": "Herbst 2019" + }, + "pokemon_form_897": { + "EN": "Fall 2019", + "FR": "Automne 2019", + "DE": "Herbst 2019" + }, + "pokemon_form_901": { + "EN": "Vs 2019" + }, + "pokemon_form_944": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_946": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_948": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_949": { + "EN": "Copy 2019", + "FR": "Clone 2019", + "RU": "Клон 2019" + }, + "pokemon_form_950": { + "EN": "Copy 2019", + "FR": "Clone 2019", + "RU": "Клон 2019" + }, + "pokemon_form_951": { + "EN": "Copy 2019", + "FR": "Clone 2019", + "RU": "Клон 2019" + }, + "pokemon_form_952": { + "EN": "Copy 2019", + "FR": "Clone 2019", + "RU": "Клон 2019" + }, + "pokemon_form_2327": { + "EN": "Spring 2020", + "FR": "Printemps 2020", + "DE": "Frühjahr 2020", + "RU": "Весна 2020" + }, + "pokemon_form_2328": { + "EN": "Spring 2020", + "FR": "Printemps 2020", + "DE": "Frühjahr 2020", + "RU": "Весна 2020" + }, + "pokemon_form_2329": { + "EN": "Spring 2020", + "FR": "Printemps 2020", + "DE": "Frühjahr 2020", + "RU": "Весна 2020" + }, + "pokemon_form_2330": { + "PT-BR": "Fêmea", + "EN": "Female", + "FR": "Femelle", + "DE": "Weiblich", + "IT": "Femmina", + "RU": "Женская форма", + "ES": "Hembra" + }, + "pokemon_form_2331": { + "PT-BR": "Fêmea", + "EN": "Female", + "FR": "Femelle", + "DE": "Weiblich", + "IT": "Femmina", + "RU": "Женская форма", + "ES": "Hembra" + }, + "pokemon_form_2332": { + "EN": "Costume 2020", + "DE": "Kostüm 2020", + "RU": "Костюм 2020" + }, + "pokemon_form_2333": { + "EN": "Costume 2020", + "DE": "Kostüm 2020", + "RU": "Костюм 2020" + }, + "pokemon_form_2334": { + "EN": "Costume 2020", + "DE": "Kostüm 2020", + "RU": "Костюм 2020" + }, + "pokemon_form_2335": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2336": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2337": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2338": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2339": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2340": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2341": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2342": { + "EN": "Galarian Standard", + "DE": "Galar Normal", + "RU": "Галарская форма" + }, + "pokemon_form_2343": { "EN": "Galarian Zen", "DE": "Galar Trance", "RU": "Галарская форма Дзен" }, - "pokemon_form_low_key_form": { + "pokemon_form_2344": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2345": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2463": { "PT-BR": "Forma Grave", "EN": "Low Key Form", "DE": "Tief-Form", @@ -732,7 +1038,7 @@ "RU": "Сдержанная форма", "ES": "Forma Grave" }, - "pokemon_form_amped_form": { + "pokemon_form_2464": { "PT-BR": "Forma Aguda", "EN": "Amped Form", "DE": "Hoch-Form", @@ -740,7 +1046,23 @@ "RU": "Восторженная форма", "ES": "Forma Aguda" }, - "pokemon_form_phony_form": { + "pokemon_form_2477": { + "PT-BR": "Forma Falsificada", + "EN": "Phony Form", + "DE": "Fälschungsform", + "IT": "Forma Contraffatta", + "RU": "Фальшивая форма", + "ES": "Forma Falsificada" + }, + "pokemon_form_2478": { + "PT-BR": "Forma Autêntica", + "EN": "Antique Form", + "DE": "Originalform", + "IT": "Forma Autentica", + "RU": "Антикварная форма", + "ES": "Forma Genuina" + }, + "pokemon_form_2480": { "PT-BR": "Forma Falsificada", "EN": "Phony Form", "DE": "Fälschungsform", @@ -748,7 +1070,7 @@ "RU": "Фальшивая форма", "ES": "Forma Falsificada" }, - "pokemon_form_antique_form": { + "pokemon_form_2481": { "PT-BR": "Forma Autêntica", "EN": "Antique Form", "DE": "Originalform", @@ -756,7 +1078,7 @@ "RU": "Антикварная форма", "ES": "Forma Genuina" }, - "pokemon_form_ice_face": { + "pokemon_form_2540": { "PT-BR": "Cara de Gelo", "EN": "Ice Face", "DE": "Tiefkühlkopf", @@ -764,7 +1086,7 @@ "RU": "Ледяное лицо", "ES": "Cara de Hielo" }, - "pokemon_form_noice_face": { + "pokemon_form_2541": { "PT-BR": "Cara Degelada", "EN": "Noice Face", "DE": "Wohlfühlkopf", @@ -772,7 +1094,7 @@ "RU": "Неледяное лицо", "ES": "Cara Deshielo" }, - "pokemon_form_male": { + "pokemon_form_2542": { "PT-BR": "Macho", "EN": "Male", "FR": "Mâle", @@ -781,7 +1103,16 @@ "RU": "Мужская форма", "ES": "Macho" }, - "pokemon_form_full_belly_mode": { + "pokemon_form_2543": { + "PT-BR": "Fêmea", + "EN": "Female", + "FR": "Femelle", + "DE": "Weiblich", + "IT": "Femmina", + "RU": "Женская форма", + "ES": "Hembra" + }, + "pokemon_form_2544": { "PT-BR": "Forma Saciada", "EN": "Full Belly Mode", "DE": "Pappsatt", @@ -789,7 +1120,7 @@ "RU": "Режим Полный Живот", "ES": "Forma Saciada" }, - "pokemon_form_hangry_mode": { + "pokemon_form_2545": { "PT-BR": "Forma Voraz", "EN": "Hangry Mode", "DE": "Kohldampf", @@ -797,7 +1128,7 @@ "RU": "Злоголодный режим", "ES": "Forma Voraz" }, - "pokemon_form_crowned_sword": { + "pokemon_form_2576": { "PT-BR": "Espada Coroada", "EN": "Crowned Sword", "DE": "König des Schwertes", @@ -805,7 +1136,7 @@ "RU": "Коронованный Меч", "ES": "Espada Suprema" }, - "pokemon_form_hero_of_many_battles": { + "pokemon_form_2577": { "PT-BR": "Herói Veterano", "EN": "Hero of Many Battles", "DE": "Heldenhafter Krieger", @@ -813,7 +1144,7 @@ "RU": "Герой многих битв", "ES": "Guerrero Avezado" }, - "pokemon_form_crowned_shield": { + "pokemon_form_2578": { "PT-BR": "Escudo Coroado", "EN": "Crowned Shield", "DE": "König des Schildes", @@ -821,255 +1152,458 @@ "RU": "Коронованный Щит", "ES": "Escudo Supremo" }, - "pokemon_form_eternamax": { + "pokemon_form_2579": { + "PT-BR": "Herói Veterano", + "EN": "Hero of Many Battles", + "DE": "Heldenhafter Krieger", + "IT": "Eroe di Mille Lotte", + "RU": "Герой многих битв", + "ES": "Guerrero Avezado" + }, + "pokemon_form_2580": { "EN": "Eternamax", "DE": "Unendynamax", "RU": "Этернамакс" }, - "pokemon_form_ten_percent": { + "pokemon_form_2582": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2583": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2584": { + "EN": "Galarian", + "DE": "Galar", + "RU": "Галарская форма" + }, + "pokemon_form_2585": { + "EN": "Costume 2020", + "DE": "Kostüm 2020", + "RU": "Костюм 2020" + }, + "pokemon_form_2586": { + "EN": "Costume 2020", + "DE": "Kostüm 2020", + "RU": "Костюм 2020" + }, + "pokemon_form_2588": { + "PT-BR": "Fêmea", + "EN": "Female", + "FR": "Femelle", + "DE": "Weiblich", + "IT": "Femmina", + "RU": "Женская форма", + "ES": "Hembra" + }, + "pokemon_form_2590": { + "PT-BR": "Fêmea", + "EN": "Female", + "FR": "Femelle", + "DE": "Weiblich", + "IT": "Femmina", + "RU": "Женская форма", + "ES": "Hembra" + }, + "pokemon_form_2591": { "EN": "Ten Percent", "DE": "10%", "RU": "10% форма" }, - "pokemon_form_fifty_percent": { + "pokemon_form_2592": { "EN": "Fifty Percent", "DE": "50%", "RU": "50% форма" }, - "pokemon_form_complete": { + "pokemon_form_2593": { "EN": "Complete", "DE": "Optimum", "RU": "Завершенная форма" }, - "pokemon_form_archipelago": { - "EN": "Archipelago" - }, - "pokemon_form_continental": { - "EN": "Continental" - }, - "pokemon_form_elegant": { - "EN": "Elegant" - }, - "pokemon_form_fancy": { - "EN": "Fancy" - }, - "pokemon_form_garden": { - "EN": "Garden" - }, - "pokemon_form_high_plains": { - "EN": "High Plains" - }, - "pokemon_form_icy_snow": { - "EN": "Icy Snow" - }, - "pokemon_form_jungle": { - "EN": "Jungle" + "pokemon_form_2594": { + "EN": "Archipelago", + "DE": "Archipel", + "RU": "Островная форма" + }, + "pokemon_form_2595": { + "EN": "Continental", + "DE": "Kontinental", + "RU": "Континентальная форма" + }, + "pokemon_form_2596": { + "EN": "Elegant", + "DE": "Prunk", + "RU": "Элегантная форма" + }, + "pokemon_form_2597": { + "EN": "Fancy", + "RU": "Изысканная форма" + }, + "pokemon_form_2598": { + "EN": "Garden", + "DE": "Ziergarten", + "RU": "Садовая форма" + }, + "pokemon_form_2599": { + "EN": "High Plains", + "DE": "Dürre", + "RU": "Равнинная форма" + }, + "pokemon_form_2600": { + "EN": "Icy Snow", + "DE": "Frost", + "RU": "Ледяная форма" + }, + "pokemon_form_2601": { + "EN": "Jungle", + "DE": "Dschungel", + "RU": "Форма джунглей" + }, + "pokemon_form_2602": { + "EN": "Marine", + "DE": "Aquamarin", + "RU": "Морская форма" + }, + "pokemon_form_2603": { + "EN": "Meadow", + "DE": "Blumenmeer", + "RU": "Луговая форма" + }, + "pokemon_form_2604": { + "EN": "Modern", + "DE": "Innovation", + "RU": "Современная форма" + }, + "pokemon_form_2605": { + "EN": "Monsoon", + "DE": "Monsun", + "RU": "Муссонная форма" + }, + "pokemon_form_2606": { + "EN": "Ocean", + "DE": "Ozean", + "RU": "Океаническая форма" + }, + "pokemon_form_2607": { + "EN": "Pokeball", + "RU": "Форма покебола" + }, + "pokemon_form_2608": { + "EN": "Polar", + "DE": "Schneefeld", + "RU": "Полярная форма" + }, + "pokemon_form_2609": { + "EN": "River", + "DE": "Flussdelta", + "RU": "Речная форма" + }, + "pokemon_form_2610": { + "EN": "Sandstorm", + "DE": "Sand", + "RU": "Форма песчанной бури" + }, + "pokemon_form_2611": { + "EN": "Savanna", + "DE": "Savanne", + "RU": "Саванновая форма" + }, + "pokemon_form_2612": { + "PT-BR": "Ensolarada", + "EN": "Sunny", + "FR": "Sun", + "DE": "Sonne", + "IT": "Sole", + "RU": "Солнечная форма", + "ES": "Sol" }, - "pokemon_form_marine": { - "EN": "Marine" + "pokemon_form_2613": { + "EN": "Tundra", + "DE": "Flocke", + "RU": "Тундровая форма" }, - "pokemon_form_meadow": { - "EN": "Meadow" + "pokemon_form_2614": { + "EN": "Red Flower", + "FR": "Red", + "DE": "Rotblütler", + "RU": "Красная форма" }, - "pokemon_form_modern": { - "EN": "Modern" + "pokemon_form_2615": { + "EN": "Yellow Flower", + "FR": "Yellow", + "DE": "Gelbblütler", + "RU": "Желтая форма" }, - "pokemon_form_monsoon": { - "EN": "Monsoon" + "pokemon_form_2616": { + "EN": "Orange Flower", + "FR": "Orange", + "DE": "Orangeblütler", + "RU": "Oранжевая форма" }, - "pokemon_form_ocean": { - "EN": "Ocean" + "pokemon_form_2617": { + "EN": "Blue Flower", + "FR": "Blue", + "DE": "Blaublütler", + "RU": "Синяя форма" }, - "pokemon_form_pokeball": { - "EN": "Pokeball" + "pokemon_form_2618": { + "EN": "White Flower", + "FR": "White", + "DE": "Weißblütler", + "RU": "Белая форма" }, - "pokemon_form_polar": { - "EN": "Polar" + "pokemon_form_2619": { + "EN": "Red Flower", + "FR": "Red", + "DE": "Rotblütler", + "RU": "Красная форма" }, - "pokemon_form_river": { - "EN": "River" + "pokemon_form_2620": { + "EN": "Yellow Flower", + "FR": "Yellow", + "DE": "Gelbblütler", + "RU": "Желтая форма" }, - "pokemon_form_sandstorm": { - "EN": "Sandstorm" + "pokemon_form_2621": { + "EN": "Orange Flower", + "FR": "Orange", + "DE": "Orangeblütler", + "RU": "Оранжевая форма" }, - "pokemon_form_savanna": { - "EN": "Savanna" + "pokemon_form_2622": { + "EN": "Blue Flower", + "FR": "Blue", + "DE": "Blaublütler", + "RU": "Синяя форма" }, - "pokemon_form_tundra": { - "EN": "Tundra" + "pokemon_form_2623": { + "EN": "White Flower", + "FR": "White", + "DE": "Weißblütler", + "RU": "Белая форма" }, - "pokemon_form_red_flower": { + "pokemon_form_2624": { "EN": "Red Flower", "FR": "Red", "DE": "Rotblütler", "RU": "Красная форма" }, - "pokemon_form_yellow_flower": { + "pokemon_form_2625": { "EN": "Yellow Flower", "FR": "Yellow", "DE": "Gelbblütler", "RU": "Желтая форма" }, - "pokemon_form_orange_flower": { + "pokemon_form_2626": { "EN": "Orange Flower", "FR": "Orange", "DE": "Orangeblütler", "RU": "Оранжевая форма" }, - "pokemon_form_blue_flower": { + "pokemon_form_2627": { "EN": "Blue Flower", "FR": "Blue", "DE": "Blaublütler", "RU": "Синяя форма" }, - "pokemon_form_white_flower": { + "pokemon_form_2628": { "EN": "White Flower", "FR": "White", "DE": "Weißblütler", "RU": "Белая форма" }, - "pokemon_form_natural": { + "pokemon_form_2629": { "EN": "Natural", "DE": "Zottelform", "RU": "Исходная форма" }, - "pokemon_form_heart_trim": { + "pokemon_form_2630": { "EN": "Heart Trim", "FR": "Heart", "DE": "Herzchenschnitt", "RU": "Сердечная форма" }, - "pokemon_form_star_trim": { + "pokemon_form_2631": { "EN": "Star Trim", "FR": "Star", "DE": "Sternchenschnitt", "RU": "Звездная форма" }, - "pokemon_form_diamond_trim": { + "pokemon_form_2632": { "EN": "Diamond Trim", "FR": "Diamond", "DE": "Diamantenschnitt", "RU": "Бриллиантовая форма" }, - "pokemon_form_debutante_trim": { + "pokemon_form_2633": { "EN": "Debutante Trim", "FR": "Debutante", "DE": "Fräuleinschnitt", "RU": "Дебютантская форма" }, - "pokemon_form_matron_trim": { + "pokemon_form_2634": { "EN": "Matron Trim", "FR": "Matron", "DE": "Damenschnitt", "RU": "Матронская форма" }, - "pokemon_form_dandy_trim": { + "pokemon_form_2635": { "EN": "Dandy Trim", "FR": "Dandy", "DE": "Kavaliersschnitt", "RU": "Светская форма" }, - "pokemon_form_la_reine_trim": { + "pokemon_form_2636": { "EN": "La Reine Trim", "FR": "La Reine", "DE": "Königinnenschnitt", "RU": "Форма Ла Рейне" }, - "pokemon_form_kabuki_trim": { + "pokemon_form_2637": { "EN": "Kabuki Trim", "FR": "Kabuki", "DE": "Kabuki-Schnitt", "RU": "Форма кабуки" }, - "pokemon_form_pharaoh_trim": { + "pokemon_form_2638": { "EN": "Pharaoh Trim", "FR": "Pharaoh", "DE": "Herrscherschnitt", "RU": "Форма фараона" }, - "pokemon_form_shield": { + "pokemon_form_2639": { "EN": "Shield", "DE": "Schild", "RU": "Форма щита" }, - "pokemon_form_blade": { + "pokemon_form_2640": { "EN": "Blade", "DE": "Schwert", "RU": "Форма меча" }, - "pokemon_form_small": { + "pokemon_form_2641": { + "EN": "Small", + "FR": "Mini", + "DE": "S", + "RU": "Маленькая форма" + }, + "pokemon_form_2642": { + "EN": "Average", + "FR": "Normale", + "DE": "M", + "RU": "Средняя форма" + }, + "pokemon_form_2643": { + "EN": "Large", + "FR": "Maxi", + "DE": "L", + "RU": "Большая форма" + }, + "pokemon_form_2644": { + "EN": "Super", + "FR": "Ultra", + "DE": "XL", + "RU": "Огромная форма" + }, + "pokemon_form_2645": { "EN": "Small", "FR": "Mini", "DE": "S", "RU": "Маленькая форма" }, - "pokemon_form_average": { + "pokemon_form_2646": { "EN": "Average", "FR": "Normale", "DE": "M", "RU": "Средняя форма" }, - "pokemon_form_large": { + "pokemon_form_2647": { "EN": "Large", "FR": "Maxi", "DE": "L", "RU": "Большая форма" }, - "pokemon_form_super": { + "pokemon_form_2648": { "EN": "Super", "FR": "Ultra", "DE": "XL", "RU": "Огромная форма" }, - "pokemon_form_neutral": { + "pokemon_form_2649": { "EN": "Neutral", "RU": "Нейтральная форма" }, - "pokemon_form_active": { + "pokemon_form_2650": { "EN": "Active", "DE": "Aktiv", "RU": "Активная форма" }, - "pokemon_form_confined": { + "pokemon_form_2651": { "EN": "Confined", "DE": "Beschränkt", "RU": "Невольная форма" }, - "pokemon_form_unbound": { + "pokemon_form_2652": { "EN": "Unbound", "DE": "Ungebunden", "RU": "Высвобожденная форма" }, - "pokemon_form_costume_2020_deprecated": { + "pokemon_form_2666": { "EN": "Costume 2020 Deprecated", "DE": "Kostüm 2020 Deprecated", "RU": "Костюм 2020 Устаревший" }, - "pokemon_form_adventure_hat_2020": { + "pokemon_form_2668": { + "EN": "Costume 2020", + "DE": "Kostüm 2020", + "RU": "Костюм 2020" + }, + "pokemon_form_2669": { "EN": "Adventure Hat 2020", "DE": "Abenteuerhut 2020" }, - "pokemon_form_winter_2020": { - "EN": "Winter 2020" + "pokemon_form_2670": { + "EN": "Winter 2020", + "FR": "Hiver 2020", + "RU": "Зима 2020" }, - "pokemon_form_kariyushi": { + "pokemon_form_2671": { + "EN": "Winter 2020", + "FR": "Hiver 2020", + "RU": "Зима 2020" + }, + "pokemon_form_2672": { + "EN": "Winter 2020", + "FR": "Hiver 2020", + "RU": "Зима 2020" + }, + "pokemon_form_2673": { + "EN": "2020" + }, + "pokemon_form_2674": { + "EN": "2021" + }, + "pokemon_form_2675": { "EN": "Kariyushi", "RU": "Кариюши" }, - "pokemon_form_pop_star": { + "pokemon_form_2676": { "EN": "Pop Star", "RU": "Поп-звезда" }, - "pokemon_form_rock_star": { + "pokemon_form_2677": { "EN": "Rock Star", "RU": "Рок-звезда" }, - "pokemon_form_flying_5th_anniv": { + "pokemon_form_2678": { "EN": "Flying 5th Anniv", "DE": "Fliegendes 5. Jubiläum", "RU": "Пятилетняя годовщина" }, - "pokemon_form_baile_style": { + "pokemon_form_2679": { "PT-BR": "Estilo Flamenco", "EN": "Baile Style", "FR": "Style Flamenco", @@ -1078,7 +1612,7 @@ "RU": "Бальный стиль", "ES": "Estilo Apasionado" }, - "pokemon_form_pom-pom_style": { + "pokemon_form_2680": { "PT-BR": "Estilo Pompom", "EN": "Pom-Pom Style", "FR": "Style Pom-Pom", @@ -1087,7 +1621,7 @@ "RU": "Стиль Пом-Пом", "ES": "Estilo Animado" }, - "pokemon_form_pa’u_style": { + "pokemon_form_2681": { "PT-BR": "Estilo Hula", "EN": "Pa’u Style", "FR": "Style Hula", @@ -1096,7 +1630,7 @@ "RU": "Стиль Пау", "ES": "Estilo Plácido" }, - "pokemon_form_sensu_style": { + "pokemon_form_2683": { "PT-BR": "Estilo Leque", "EN": "Sensu Style", "FR": "Style Buyô", @@ -1105,7 +1639,7 @@ "RU": "Чувственный стиль", "ES": "Estilo Refinado" }, - "pokemon_form_midday_form": { + "pokemon_form_2684": { "PT-BR": "Forma Diurna", "EN": "Midday Form", "FR": "Forme Diurne", @@ -1114,7 +1648,7 @@ "RU": "Полуденная форма", "ES": "Forma Diurna" }, - "pokemon_form_midnight_form": { + "pokemon_form_2685": { "PT-BR": "Forma Noturna", "EN": "Midnight Form", "FR": "Forme Nocturne", @@ -1123,16 +1657,16 @@ "RU": "Полуночная форма", "ES": "Forma Nocturna" }, - "pokemon_form_dusk_form": { + "pokemon_form_2686": { "PT-BR": "Forma Crepúsculo", "EN": "Dusk Form", "FR": "Forme Crépusculaire", - "DE": "Zwielichtform", + "DE": "Zwielicht", "IT": "Forma Crepuscolo", "RU": "Сумеречная форма", "ES": "Forma Crepuscular" }, - "pokemon_form_solo_form": { + "pokemon_form_2687": { "PT-BR": "Forma Individual", "EN": "Solo Form", "DE": "Einzel", @@ -1140,7 +1674,7 @@ "RU": "Форма соло", "ES": "Forma Individual" }, - "pokemon_form_school_form": { + "pokemon_form_2688": { "PT-BR": "Forma Cardume", "EN": "School Form", "DE": "Schwarm", @@ -1148,58 +1682,209 @@ "RU": "Форма стая", "ES": "Forma Banco" }, - "pokemon_form_meteor_blue": { + "pokemon_form_2690": { + "PT-BR": "Inseto", + "EN": "Bug", + "FR": "Insecte", + "DE": "Käfer", + "IT": "Coleottero", + "RU": "Жучья форма", + "ES": "Bicho" + }, + "pokemon_form_2691": { + "PT-BR": "Sombrio", + "EN": "Dark", + "FR": "Ténèbres", + "DE": "Unlicht", + "IT": "Buio", + "RU": "Темная форма", + "ES": "Siniestro" + }, + "pokemon_form_2692": { + "PT-BR": "Dragão", + "EN": "Dragon", + "DE": "Drache", + "IT": "Drago", + "RU": "Драконья форма", + "ES": "Dragón" + }, + "pokemon_form_2693": { + "PT-BR": "Elétrico", + "EN": "Electric", + "FR": "Électrik", + "DE": "Elektro", + "IT": "Elettro", + "RU": "Электрическая форма", + "ES": "Eléctrico" + }, + "pokemon_form_2694": { + "PT-BR": "Fada", + "EN": "Fairy", + "FR": "Fée", + "DE": "Fee", + "IT": "Folletto", + "RU": "Феечная форма", + "ES": "Hada" + }, + "pokemon_form_2695": { + "PT-BR": "Lutador", + "EN": "Fighting", + "FR": "Combat", + "DE": "Kampf", + "IT": "Lotta", + "RU": "Боевая форма", + "ES": "Lucha" + }, + "pokemon_form_2696": { + "PT-BR": "Fogo", + "EN": "Fire", + "FR": "Feu", + "DE": "Feuer", + "IT": "Fuoco", + "RU": "Огненная форма", + "ES": "Fuego" + }, + "pokemon_form_2697": { + "PT-BR": "Voador", + "EN": "Flying", + "FR": "Vol", + "DE": "Flug", + "IT": "Volante", + "RU": "Летающая форма", + "ES": "Volador" + }, + "pokemon_form_2698": { + "PT-BR": "Fantasma", + "EN": "Ghost", + "FR": "Spectre", + "DE": "Geist", + "IT": "Spettro", + "RU": "Призрачная форма", + "ES": "Fantasma" + }, + "pokemon_form_2699": { + "PT-BR": "Planta", + "EN": "Grass", + "FR": "Plante", + "DE": "Pflanze", + "IT": "Erba", + "RU": "Травяная форма", + "ES": "Planta" + }, + "pokemon_form_2700": { + "PT-BR": "Terrestre", + "EN": "Ground", + "FR": "Sol", + "DE": "Boden", + "IT": "Terra", + "RU": "Земляная форма", + "ES": "Tierra" + }, + "pokemon_form_2701": { + "PT-BR": "Gelo", + "EN": "Ice", + "FR": "Glace", + "DE": "Eis", + "IT": "Ghiaccio", + "RU": "Ледяная форма", + "ES": "Hielo" + }, + "pokemon_form_2702": { + "PT-BR": "Venenoso", + "EN": "Poison", + "DE": "Gift", + "IT": "Veleno", + "RU": "Ядовитая форма", + "ES": "Veneno" + }, + "pokemon_form_2703": { + "PT-BR": "Psíquico", + "EN": "Psychic", + "FR": "Psy", + "DE": "Psycho", + "IT": "Psico", + "RU": "Психическая форма", + "ES": "Psíquico" + }, + "pokemon_form_2704": { + "PT-BR": "Pedra", + "EN": "Rock", + "FR": "Roche", + "DE": "Gestein", + "IT": "Roccia", + "RU": "Каменная форма", + "ES": "Roca" + }, + "pokemon_form_2705": { + "PT-BR": "Aço", + "EN": "Steel", + "FR": "Acier", + "DE": "Stahl", + "IT": "Acciaio", + "RU": "Стальная форма", + "ES": "Acero" + }, + "pokemon_form_2706": { + "PT-BR": "Água", + "EN": "Water", + "FR": "Eau", + "DE": "Wasser", + "IT": "Acqua", + "RU": "Водная форма", + "ES": "Agua" + }, + "pokemon_form_2707": { "EN": "Meteor Blue", "DE": "Meteor", "RU": "Метеорная форма" }, - "pokemon_form_blue_plumage": { + "pokemon_form_2708": { "PT-BR": "Plumagem Azul", "EN": "Blue Plumage", "FR": "Plumage Bleu", - "DE": "Blaugefiedert", + "DE": "Blau", "IT": "Piume Azzurre", - "RU": "Синее оперение", + "RU": "Голубая форма", "ES": "Plumaje Azul" }, - "pokemon_form_green_plumage": { + "pokemon_form_2709": { "PT-BR": "Plumagem Verde", "EN": "Green Plumage", "FR": "Plumage Vert", - "DE": "Grüngefiedert", + "DE": "Grün", "IT": "Piume Verdi", - "RU": "Зелёное оперение", + "RU": "Зеленая форма", "ES": "Plumaje Verde" }, - "pokemon_form_indigo": { + "pokemon_form_2710": { "EN": "Indigo", "DE": "Hellblau", "RU": "Индиго форма" }, - "pokemon_form_orange": { + "pokemon_form_2711": { "EN": "Orange", "RU": "Оранжевая форма" }, - "pokemon_form_red": { + "pokemon_form_2712": { "EN": "Red", "DE": "Rot", "RU": "Красная форма" }, - "pokemon_form_violet": { + "pokemon_form_2713": { "EN": "Violet", "DE": "Violett", "RU": "Фиолетовая форма" }, - "pokemon_form_yellow_plumage": { + "pokemon_form_2714": { "PT-BR": "Plumagem Amarela", "EN": "Yellow Plumage", "FR": "Plumage Jaune", - "DE": "Gelbgefiedert", + "DE": "Gelb", "IT": "Piume Gialle", - "RU": "Жёлтое оперение", + "RU": "Желтая форма", "ES": "Plumaje Amarillo" }, - "pokemon_form_busted_form": { + "pokemon_form_2715": { "PT-BR": "Forma Desmascarada", "EN": "Busted Form", "DE": "Entlarvt", @@ -1207,7 +1892,7 @@ "RU": "Сломанная форма", "ES": "Forma Descubierta" }, - "pokemon_form_disguised_form": { + "pokemon_form_2716": { "PT-BR": "Forma Mascarada", "EN": "Disguised Form", "DE": "Standard", @@ -1215,69 +1900,300 @@ "RU": "Замаскированная форма", "ES": "Forma Encubierta" }, - "pokemon_form_dusk_mane": { + "pokemon_form_2718": { "EN": "Dusk Mane", "DE": "Abendmähne", "RU": "Грива заката" }, - "pokemon_form_dawn_wings": { + "pokemon_form_2719": { "EN": "Dawn Wings", "DE": "Morgenschwingen", "RU": "Крылья рассвета" }, - "pokemon_form_ultra": { + "pokemon_form_2720": { "EN": "Ultra", "RU": "Ультра форма" }, - "pokemon_form_original_color": { + "pokemon_form_2722": { "EN": "Original Color", "DE": "Originalfarbe", "RU": "Исходный цвет" }, - "pokemon_form_single_strike": { + "pokemon_form_2723": { "EN": "Single Strike", "DE": "Fokussierter Stil", "RU": "Фома одного удара" }, - "pokemon_form_rapid_strike": { + "pokemon_form_2724": { "EN": "Rapid Strike", "DE": "Fließender Stil", "RU": "Форма множества ударов" }, - "pokemon_form_ice_rider": { + "pokemon_form_2726": { "EN": "Ice Rider", "DE": "Schimmelreiter", "RU": "Ледяной всадник" }, - "pokemon_form_shadow_rider": { + "pokemon_form_2727": { "EN": "Shadow Rider", "RU": "Теневой всадник" }, - "pokemon_form_hisuian": { + "pokemon_form_2728": { "EN": "Hisuian" }, - "pokemon_form_flying_okinawa": { + "pokemon_form_2729": { + "EN": "S" + }, + "pokemon_form_2730": { + "EN": "S" + }, + "pokemon_form_2731": { + "EN": "S" + }, + "pokemon_form_2732": { + "EN": "S" + }, + "pokemon_form_2733": { + "EN": "S" + }, + "pokemon_form_2734": { + "EN": "2022" + }, + "pokemon_form_2735": { + "EN": "Hisuian" + }, + "pokemon_form_2736": { "EN": "Flying Okinawa" }, - "pokemon_form_meteor_green": { + "pokemon_form_2737": { + "PT-BR": "Forma Crepúsculo", + "EN": "Dusk Form", + "FR": "Forme Crépusculaire", + "DE": "Zwielichtform", + "IT": "Forma Crepuscolo", + "RU": "Сумеречная форма", + "ES": "Forma Crepuscular" + }, + "pokemon_form_2739": { "EN": "Meteor Green" }, - "pokemon_form_meteor_indigo": { + "pokemon_form_2740": { "EN": "Meteor Indigo" }, - "pokemon_form_meteor_orange": { + "pokemon_form_2741": { "EN": "Meteor Orange" }, - "pokemon_form_meteor_red": { + "pokemon_form_2742": { "EN": "Meteor Red" }, - "pokemon_form_meteor_violet": { + "pokemon_form_2743": { "EN": "Meteor Violet" }, - "pokemon_form_meteor_yellow": { + "pokemon_form_2744": { "EN": "Meteor Yellow" }, - "pokemon_form_white-striped_form": { + "pokemon_form_2745": { + "EN": "Archipelago" + }, + "pokemon_form_2746": { + "EN": "Continental" + }, + "pokemon_form_2747": { + "EN": "Elegant" + }, + "pokemon_form_2748": { + "EN": "Fancy" + }, + "pokemon_form_2749": { + "EN": "Garden" + }, + "pokemon_form_2750": { + "EN": "High Plains" + }, + "pokemon_form_2751": { + "EN": "Icy Snow" + }, + "pokemon_form_2752": { + "EN": "Jungle" + }, + "pokemon_form_2753": { + "EN": "Marine" + }, + "pokemon_form_2754": { + "EN": "Meadow" + }, + "pokemon_form_2755": { + "EN": "Modern" + }, + "pokemon_form_2756": { + "EN": "Monsoon" + }, + "pokemon_form_2757": { + "EN": "Ocean" + }, + "pokemon_form_2758": { + "EN": "Pokeball" + }, + "pokemon_form_2759": { + "EN": "Polar" + }, + "pokemon_form_2760": { + "EN": "River" + }, + "pokemon_form_2761": { + "EN": "Sandstorm" + }, + "pokemon_form_2762": { + "EN": "Savanna" + }, + "pokemon_form_2763": { + "PT-BR": "Ensolarada", + "EN": "Sunny", + "FR": "Solaire", + "DE": "Sonnenform", + "IT": "Sole", + "RU": "Солнечная форма", + "ES": "Sol" + }, + "pokemon_form_2764": { + "EN": "Tundra" + }, + "pokemon_form_2765": { + "EN": "Archipelago" + }, + "pokemon_form_2766": { + "EN": "Continental" + }, + "pokemon_form_2767": { + "EN": "Elegant" + }, + "pokemon_form_2768": { + "EN": "Fancy" + }, + "pokemon_form_2769": { + "EN": "Garden" + }, + "pokemon_form_2770": { + "EN": "High Plains" + }, + "pokemon_form_2771": { + "EN": "Icy Snow" + }, + "pokemon_form_2772": { + "EN": "Jungle" + }, + "pokemon_form_2773": { + "EN": "Marine" + }, + "pokemon_form_2774": { + "EN": "Meadow" + }, + "pokemon_form_2775": { + "EN": "Modern" + }, + "pokemon_form_2776": { + "EN": "Monsoon" + }, + "pokemon_form_2777": { + "EN": "Ocean" + }, + "pokemon_form_2778": { + "EN": "Pokeball" + }, + "pokemon_form_2779": { + "EN": "Polar" + }, + "pokemon_form_2780": { + "EN": "River" + }, + "pokemon_form_2781": { + "EN": "Sandstorm" + }, + "pokemon_form_2782": { + "EN": "Savanna" + }, + "pokemon_form_2783": { + "PT-BR": "Ensolarada", + "EN": "Sunny", + "FR": "Solaire", + "DE": "Sonnenform", + "IT": "Sole", + "RU": "Солнечная форма", + "ES": "Sol" + }, + "pokemon_form_2784": { + "EN": "Tundra" + }, + "pokemon_form_2785": { + "EN": "Hisuian" + }, + "pokemon_form_2786": { + "EN": "Hisuian" + }, + "pokemon_form_2787": { + "EN": "Hisuian" + }, + "pokemon_form_2788": { + "EN": "Hisuian" + }, + "pokemon_form_2789": { + "EN": "Hisuian" + }, + "pokemon_form_2790": { + "EN": "Hisuian" + }, + "pokemon_form_2791": { + "EN": "Hisuian" + }, + "pokemon_form_2792": { + "EN": "Hisuian" + }, + "pokemon_form_2793": { + "EN": "Hisuian" + }, + "pokemon_form_2794": { + "EN": "Hisuian" + }, + "pokemon_form_2795": { + "EN": "Hisuian" + }, + "pokemon_form_2796": { + "EN": "Hisuian" + }, + "pokemon_form_2797": { + "EN": "Hisuian" + }, + "pokemon_form_2798": { + "EN": "Hisuian" + }, + "pokemon_form_2799": { + "EN": "Galarian" + }, + "pokemon_form_2800": { + "EN": "Galarian" + }, + "pokemon_form_2801": { + "EN": "Galarian" + }, + "pokemon_form_2802": { + "PT-BR": "Forma Materializada", + "EN": "Incarnate Forme", + "FR": "Forme Avatar", + "DE": "Inkarnationsform", + "IT": "Forma Incarnazione", + "RU": "Воплощённая форма", + "ES": "Forma Avatar" + }, + "pokemon_form_2803": { + "PT-BR": "Forma Therian", + "EN": "Therian Forme", + "FR": "Forme Totémique", + "DE": "Tiergeistform", + "IT": "Forma Totem", + "RU": "Форма Териан", + "ES": "Forma Tótem" + }, + "pokemon_form_2804": { "PT-BR": "Forma Listras Brancas", "EN": "White-Striped Form", "FR": "Motif Blanc", @@ -1286,52 +2202,154 @@ "RU": "Белая полосатая форма", "ES": "Forma Raya Blanca" }, - "pokemon_form_gofest_2022": { + "pokemon_form_2805": { "EN": "Gofest 2022" }, - "pokemon_form_wcs_2022": { + "pokemon_form_2806": { "EN": "Wcs 2022" }, - "pokemon_form_tshirt_01": { + "pokemon_form_2808": { + "PT-BR": "Fêmea", + "EN": "Female", + "FR": "Femelle", + "DE": "Weiblich", + "IT": "Femmina", + "RU": "Женский", + "ES": "Hembra" + }, + "pokemon_form_2813": { "EN": "Tshirt 01" }, - "pokemon_form_tshirt_02": { + "pokemon_form_2814": { "EN": "Tshirt 02" }, - "pokemon_form_flying_01": { + "pokemon_form_2815": { "EN": "Flying 01" }, - "pokemon_form_flying_02": { + "pokemon_form_2816": { "EN": "Flying 02" }, - "pokemon_form_complete_ten_percent": { + "pokemon_form_2820": { + "EN": "Winter 2020" + }, + "pokemon_form_2821": { + "EN": "S" + }, + "pokemon_form_2822": { + "EN": "S" + }, + "pokemon_form_2823": { "EN": "Complete Ten Percent" }, - "pokemon_form_complete_fifty_percent": { + "pokemon_form_2824": { "EN": "Complete Fifty Percent" }, - "pokemon_form_gotour_2024_a": { + "pokemon_form_2825": { "EN": "Gotour 2024 A" }, - "pokemon_form_gotour_2024_b": { + "pokemon_form_2826": { "EN": "Gotour 2024 B" }, - "pokemon_form_gotour_2024_a_02": { + "pokemon_form_2827": { "EN": "Gotour 2024 A 02" }, - "pokemon_form_gotour_2024_b_02": { + "pokemon_form_2828": { "EN": "Gotour 2024 B 02" }, - "pokemon_form_family_of_three": { + "pokemon_form_2829": { + "PT-BR": "Forma Origem", + "EN": "Origin Forme", + "FR": "Forme Originelle", + "DE": "Urform", + "IT": "Forma Originale", + "RU": "Исходная форма", + "ES": "Forma Origen" + }, + "pokemon_form_2830": { + "PT-BR": "Forma Origem", + "EN": "Origin Forme", + "FR": "Forme Originelle", + "DE": "Urform", + "IT": "Forma Originale", + "RU": "Исходная форма", + "ES": "Forma Origen" + }, + "pokemon_form_2832": { + "EN": "Tshirt 03" + }, + "pokemon_form_2833": { + "EN": "Flying 04" + }, + "pokemon_form_2834": { + "EN": "Tshirt 04" + }, + "pokemon_form_2835": { + "EN": "Tshirt 05" + }, + "pokemon_form_2836": { + "EN": "Tshirt 06" + }, + "pokemon_form_2837": { + "EN": "Tshirt 07" + }, + "pokemon_form_2838": { + "EN": "Flying 05" + }, + "pokemon_form_2839": { + "EN": "Flying 06" + }, + "pokemon_form_2840": { + "EN": "Flying 07" + }, + "pokemon_form_2841": { + "EN": "Flying 08" + }, + "pokemon_form_2982": { + "PT-BR": "Fêmea", + "EN": "Female", + "FR": "Femelle", + "DE": "Weiblich", + "IT": "Femmina", + "RU": "Женский", + "ES": "Hembra" + }, + "pokemon_form_2983": { "EN": "Family Of Three" }, - "pokemon_form_family_of_four": { + "pokemon_form_2984": { "EN": "Family Of Four" }, - "pokemon_form_white": { + "pokemon_form_2985": { + "PT-BR": "Plumagem Verde", + "EN": "Green Plumage", + "FR": "Plumage Vert", + "DE": "Grüngefiedert", + "IT": "Piume Verdi", + "RU": "Зелёное оперение", + "ES": "Plumaje Verde" + }, + "pokemon_form_2986": { + "PT-BR": "Plumagem Azul", + "EN": "Blue Plumage", + "FR": "Plumage Bleu", + "DE": "Blaugefiedert", + "IT": "Piume Azzurre", + "RU": "Синее оперение", + "ES": "Plumaje Azul" + }, + "pokemon_form_2987": { + "PT-BR": "Plumagem Amarela", + "EN": "Yellow Plumage", + "FR": "Plumage Jaune", + "DE": "Gelbgefiedert", + "IT": "Piume Gialle", + "RU": "Жёлтое оперение", + "ES": "Plumaje Amarillo" + }, + "pokemon_form_2988": { "EN": "White" }, - "pokemon_form_zero_form": { + "pokemon_form_2989": { "PT-BR": "Forma Zero", "EN": "Zero Form", "FR": "Forme Ordinaire", @@ -1340,7 +2358,15 @@ "RU": "Нулевая форма", "ES": "Forma Ingenua" }, - "pokemon_form_curly_form": { + "pokemon_form_2990": { + "PT-BR": "Herói Veterano", + "EN": "Hero of Many Battles", + "DE": "Heldenhafter Krieger", + "IT": "Eroe di Mille Lotte", + "RU": "Герой многих битв", + "ES": "Guerrero Avezado" + }, + "pokemon_form_2991": { "PT-BR": "Forma Curvada", "EN": "Curly Form", "FR": "Forme Courbée", @@ -1349,7 +2375,7 @@ "RU": "Изогнутая форма", "ES": "Forma Curvada" }, - "pokemon_form_droopy_form": { + "pokemon_form_2992": { "PT-BR": "Forma Pendular", "EN": "Droopy Form", "FR": "Forme Affalée", @@ -1358,7 +2384,7 @@ "RU": "Свисающая форма", "ES": "Forma Lánguida" }, - "pokemon_form_stretchy_form": { + "pokemon_form_2993": { "PT-BR": "Forma Estendida", "EN": "Stretchy Form", "FR": "Forme Raide", @@ -1367,7 +2393,7 @@ "RU": "Вытянутая форма", "ES": "Forma Recta" }, - "pokemon_form_two-segment_form": { + "pokemon_form_2994": { "PT-BR": "Forma Bissegmentar", "EN": "Two-Segment Form", "FR": "Forme Double", @@ -1376,7 +2402,7 @@ "RU": "Двухсегментная форма", "ES": "Forma Binodular" }, - "pokemon_form_three-segment_form": { + "pokemon_form_2995": { "PT-BR": "Forma Trissegmentar", "EN": "Three-Segment Form", "FR": "Forme Triple", @@ -1385,7 +2411,7 @@ "RU": "Трёхсегментная форма", "ES": "Forma Trinodular" }, - "pokemon_form_apex_build": { + "pokemon_form_2996": { "PT-BR": "Versão Plena", "EN": "Apex Build", "FR": "Forme Finale", @@ -1394,7 +2420,7 @@ "RU": "Финальная форма", "ES": "Fisonomía Plena" }, - "pokemon_form_ultimate_mode": { + "pokemon_form_2997": { "PT-BR": "Modo Supremo", "EN": "Ultimate Mode", "FR": "Mode Ultime", @@ -1403,46 +2429,46 @@ "RU": "Полноценный режим", "ES": "Modo Pleno" }, - "pokemon_form_summer_2023": { + "pokemon_form_3001": { "EN": "Summer 2023" }, - "pokemon_form_summer_2023_a": { + "pokemon_form_3002": { "EN": "Summer 2023 A" }, - "pokemon_form_summer_2023_b": { + "pokemon_form_3003": { "EN": "Summer 2023 B" }, - "pokemon_form_summer_2023_c": { + "pokemon_form_3004": { "EN": "Summer 2023 C" }, - "pokemon_form_summer_2023_d": { + "pokemon_form_3005": { "EN": "Summer 2023 D" }, - "pokemon_form_paldea_combat": { + "pokemon_form_3006": { "EN": "Paldea Combat" }, - "pokemon_form_paldea_blaze": { + "pokemon_form_3007": { "EN": "Paldea Blaze" }, - "pokemon_form_paldea_aqua": { + "pokemon_form_3008": { "EN": "Paldea Aqua" }, - "pokemon_form_paldea": { + "pokemon_form_3009": { "EN": "Paldea" }, - "pokemon_form_summer_2023_e": { + "pokemon_form_3010": { "EN": "Summer 2023 E" }, - "pokemon_form_flying_03": { + "pokemon_form_3011": { "EN": "Flying 03" }, - "pokemon_form_jeju": { + "pokemon_form_3012": { "EN": "Jeju" }, - "pokemon_form_doctor": { + "pokemon_form_3013": { "EN": "Doctor" }, - "pokemon_form_wcs_2023": { + "pokemon_form_3014": { "EN": "Wcs 2023" } } \ No newline at end of file From fd2fc1a5ff48b89982baa88e5956ec640387c65b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:54:53 +0200 Subject: [PATCH 302/367] Improved Pokemon icon fallback logic and word wrapping of Pokemon name --- logic/raid_picture.php | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/logic/raid_picture.php b/logic/raid_picture.php index f90e701a..28598e8a 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -61,7 +61,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Query missing raid info $q_pokemon_info = my_query(' SELECT - pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, type, type2, + pokemon_name, pokemon_form_name, min_cp, max_cp, min_weather_cp, max_weather_cp, weather, shiny, type, type2, (SELECT img_url FROM gyms WHERE id=:gymId LIMIT 1) as img_url FROM pokemon WHERE pokedex_id = :pokemonId @@ -267,15 +267,14 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { } else { // Check pokemon icon source and create image $img_file = null; - $addressableFilename = $uiconsFilename = ['','','','','']; + $addressableFilename = $uiconsFilename = ['','','','','','']; $p_sources = explode(',', $config->RAID_PICTURE_POKEMON_ICONS); $addressableFilename[0] = 'pm'.$raid['pokemon']; $uiconsFilename[0] = $raid['pokemon']; if($raid['pokemon_form_name'] != 'normal') { - $addrFormPrefix = ''; - if($raid['pokemon'] == 201) $addrFormPrefix = 'UNOWN_'; - $addressableFilename[1] = '.f' . $addrFormPrefix . strtoupper($raid['pokemon_form_name']); + $addressableFilename[1] = '.f' . strtoupper($raid['pokemon_form_name']); + $addressableFilename[5] = '.f' . str_replace(strtoupper($raid['pokemon_name']).'_', '', strtoupper($raid['pokemon_form_name'])); $uiconsFilename[1] = '_f' . $raid['pokemon_form']; } @@ -547,7 +546,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Pokemon name and form? $pokemon_text_lines = array($pokemon_name); if(strlen($pokemon_name) > 20) { - $pokemon_text_lines = explode(SP,$pokemon_name); + $pokemon_text_lines = explode(SP,$pokemon_name, 2); if(count($pokemon_text_lines) == 1) { // Wrapping the time text if too long (to 20 letters) $pokemon_text_lines = explode(PHP_EOL,wordwrap(trim($pokemon_name),20,PHP_EOL)); @@ -662,17 +661,18 @@ function grab_img($uri) { function createFilenameList($a, $u) { // Full filename of addressable icon - $filenames[0] = join($a); + $filenames[] = join([$a[0], $a[1], $a[2], $a[3], $a[5]]); // Full filename of uicons icon - $filenames[1] = join($u); + $filenames[] = join($u); // List of fallback icons for addressable assets - $filenames[2] = join([$a[0], '.fNORMAL', $a[2], $a[3], $a[4]]); - $filenames[3] = join([$a[0], $a[1], $a[2], $a[4]]); - $filenames[4] = join([$a[0], '.fNORMAL', $a[2], $a[4]]); - $filenames[5] = join([$a[0], $a[1], $a[4]]); - $filenames[6] = join([$a[0], '.fNORMAL', $a[4]]); - $filenames[7] = join([$a[0], $a[4]]); - $filenames[8] = join([$a[0], $a[4]]); + $filenames[] = join([$a[0], $a[5], $a[2], $a[3], $a[4]]); + $filenames[] = join([$a[0], '.fNORMAL', $a[2], $a[3], $a[4]]); + $filenames[] = join([$a[0], $a[1], $a[2], $a[4]]); + $filenames[] = join([$a[0], '.fNORMAL', $a[2], $a[4]]); + $filenames[] = join([$a[0], $a[1], $a[4]]); + $filenames[] = join([$a[0], '.fNORMAL', $a[4]]); + $filenames[] = join([$a[0], $a[4]]); + $filenames[] = join([$a[0], $a[4]]); return $filenames; } From ee205a1400ac64ff8572c76ebb1277b1847d32dc Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:55:42 +0200 Subject: [PATCH 303/367] Use Pokemon form id instead of form name for translation --- logic/get_local_pokemon_name.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/get_local_pokemon_name.php b/logic/get_local_pokemon_name.php index a2bfead1..3b767365 100644 --- a/logic/get_local_pokemon_name.php +++ b/logic/get_local_pokemon_name.php @@ -25,7 +25,7 @@ function get_local_pokemon_name($pokemon_id, $pokemon_form_id, $override_languag $skipFallback = false; if ($pokemon_form_name != 'normal') { - $pokemon_form_name = $getTypeTranslation('pokemon_form_' . $pokemon_form_name); + $pokemon_form_name = $getTypeTranslation('pokemon_form_' . $pokemon_form_id); // Use only form name if form name contains Pokemon name // e.g. Black Kyurem, Frost Rotom if(strpos($pokemon_form_name, $pokemon_name, 0)) { From 873ba7de94944aa56e681535f678ff5a1fee77be Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:56:27 +0200 Subject: [PATCH 304/367] Fixed stats and missing Pokemon --- mods/getdb.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mods/getdb.php b/mods/getdb.php index 84dc9a3f..948dc71a 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -165,7 +165,6 @@ function parse_master_data($game_master_url) { if(!isset($row['stats']['attack']) || !isset($row['stats']['defense']) || !isset($row['stats']['stamina'])) { continue; } - [$min_cp, $max_cp, $min_weather_cp, $max_weather_cp] = calculate_cps($row['stats']); $type = $type2 = ''; foreach($row['types'] as $key => $data) { if($type == '') { @@ -177,9 +176,17 @@ function parse_master_data($game_master_url) { $weather .= $weatherboost_table[$key]; } foreach($row['forms'] as $formData) { - if($formData['name'] == 'Shadow' || $formData['name'] == 'Purified') continue; - $form_name = strtolower(preg_replace('/\s/', '_', $formData['name'])); - if($form_name == 'unset') $form_name = 'normal'; + if(($formData['name'] == 'Unset' && count($row['forms']) > 1) || $formData['name'] == 'Shadow' || $formData['name'] == 'Purified') continue; + if($formData['name'] == 'Normal') { + $pokemon_array[$pokemon_id]['protoName'] = str_replace('_NORMAL', '', $formData['proto']); + $form_name = 'normal'; + }else { + if(isset($pokemon_array[$pokemon_id]['protoName'])) + $form_name = str_replace($pokemon_array[$pokemon_id]['protoName'].'_', '', $formData['proto']); + else + $form_name = ($formData['proto'] == 'FORM_UNSET') ? 'normal' : $formData['proto']; + } + [$min_cp, $max_cp, $min_weather_cp, $max_weather_cp] = (isset($formData['stats'])) ? calculate_cps($formData['stats']) : calculate_cps($row['stats']); $form_id = $formData['form']; $pokemon_array[$pokemon_id][$form_name] = [ 'pokemon_name' => $pokemon_name, @@ -211,6 +218,7 @@ function parse_master_data($game_master_url) { $weather .= $weatherboost_table[$key]; } } + [$min_cp, $max_cp, $min_weather_cp, $max_weather_cp] = calculate_cps($row['stats']); $pokemon_array[$pokemon_id][$form_name] = [ 'pokemon_name' => $pokemon_name, 'pokemon_form_name' => $form_name, From 4a338d93666ee6c46cc3f115c96abbde4f09f060 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:58:14 +0200 Subject: [PATCH 305/367] =?UTF-8?q?Another=20getdb=20fix=20-=20Fixed=20dup?= =?UTF-8?q?licate=20weatherboost=20indicators=20-=20Simplified=20Pok=C3=A9?= =?UTF-8?q?mon=20type=20storing=20logic.=20The=20type=20is=20now=20stored?= =?UTF-8?q?=20as=20int=20instead=20of=20string,=20so=20the=20db=20column?= =?UTF-8?q?=20data=20type=20probably=20should=20be=20changed=20some=20day?= =?UTF-8?q?=20also.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- images/types/{normal.png => 1.png} | Bin images/types/{fire.png => 10.png} | Bin images/types/{water.png => 11.png} | Bin images/types/{grass.png => 12.png} | Bin images/types/{electric.png => 13.png} | Bin images/types/{psychic.png => 14.png} | Bin images/types/{ice.png => 15.png} | Bin images/types/{dragon.png => 16.png} | Bin images/types/{dark.png => 17.png} | Bin images/types/{fairy.png => 18.png} | Bin images/types/{fighting.png => 2.png} | Bin images/types/{flying.png => 3.png} | Bin images/types/{poison.png => 4.png} | Bin images/types/{ground.png => 5.png} | Bin images/types/{rock.png => 6.png} | Bin images/types/{bug.png => 7.png} | Bin images/types/{ghost.png => 8.png} | Bin images/types/{steel.png => 9.png} | Bin mods/getdb.php | 60 +++++++------------------- 19 files changed, 16 insertions(+), 44 deletions(-) rename images/types/{normal.png => 1.png} (100%) rename images/types/{fire.png => 10.png} (100%) rename images/types/{water.png => 11.png} (100%) rename images/types/{grass.png => 12.png} (100%) rename images/types/{electric.png => 13.png} (100%) rename images/types/{psychic.png => 14.png} (100%) rename images/types/{ice.png => 15.png} (100%) rename images/types/{dragon.png => 16.png} (100%) rename images/types/{dark.png => 17.png} (100%) rename images/types/{fairy.png => 18.png} (100%) rename images/types/{fighting.png => 2.png} (100%) rename images/types/{flying.png => 3.png} (100%) rename images/types/{poison.png => 4.png} (100%) rename images/types/{ground.png => 5.png} (100%) rename images/types/{rock.png => 6.png} (100%) rename images/types/{bug.png => 7.png} (100%) rename images/types/{ghost.png => 8.png} (100%) rename images/types/{steel.png => 9.png} (100%) diff --git a/images/types/normal.png b/images/types/1.png similarity index 100% rename from images/types/normal.png rename to images/types/1.png diff --git a/images/types/fire.png b/images/types/10.png similarity index 100% rename from images/types/fire.png rename to images/types/10.png diff --git a/images/types/water.png b/images/types/11.png similarity index 100% rename from images/types/water.png rename to images/types/11.png diff --git a/images/types/grass.png b/images/types/12.png similarity index 100% rename from images/types/grass.png rename to images/types/12.png diff --git a/images/types/electric.png b/images/types/13.png similarity index 100% rename from images/types/electric.png rename to images/types/13.png diff --git a/images/types/psychic.png b/images/types/14.png similarity index 100% rename from images/types/psychic.png rename to images/types/14.png diff --git a/images/types/ice.png b/images/types/15.png similarity index 100% rename from images/types/ice.png rename to images/types/15.png diff --git a/images/types/dragon.png b/images/types/16.png similarity index 100% rename from images/types/dragon.png rename to images/types/16.png diff --git a/images/types/dark.png b/images/types/17.png similarity index 100% rename from images/types/dark.png rename to images/types/17.png diff --git a/images/types/fairy.png b/images/types/18.png similarity index 100% rename from images/types/fairy.png rename to images/types/18.png diff --git a/images/types/fighting.png b/images/types/2.png similarity index 100% rename from images/types/fighting.png rename to images/types/2.png diff --git a/images/types/flying.png b/images/types/3.png similarity index 100% rename from images/types/flying.png rename to images/types/3.png diff --git a/images/types/poison.png b/images/types/4.png similarity index 100% rename from images/types/poison.png rename to images/types/4.png diff --git a/images/types/ground.png b/images/types/5.png similarity index 100% rename from images/types/ground.png rename to images/types/5.png diff --git a/images/types/rock.png b/images/types/6.png similarity index 100% rename from images/types/rock.png rename to images/types/6.png diff --git a/images/types/bug.png b/images/types/7.png similarity index 100% rename from images/types/bug.png rename to images/types/7.png diff --git a/images/types/ghost.png b/images/types/8.png similarity index 100% rename from images/types/ghost.png rename to images/types/8.png diff --git a/images/types/steel.png b/images/types/9.png similarity index 100% rename from images/types/steel.png rename to images/types/9.png diff --git a/mods/getdb.php b/mods/getdb.php index 948dc71a..ada36dc7 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -117,26 +117,6 @@ function parse_master_data($game_master_url) { // Collected from pogoprotos (hoping they won't change, so hard coding them here) $mega_names = array(-1 => 'mega', -2 => 'mega_x', -3 => 'mega_y', -4 => 'primal'); $pokemon_array = []; - $typeArray = [ - 1 => 'normal', - 2 => 'fighting', - 3 => 'flying', - 4 => 'poison', - 5 => 'ground', - 6 => 'rock', - 7 => 'bug', - 8 => 'ghost', - 9 => 'steel', - 10 => 'fire', - 11 => 'water', - 12 => 'grass', - 13 => 'electric', - 14 => 'psychic', - 15 => 'ice', - 16 => 'dragon', - 17 => 'dark', - 18 => 'fairy', - ]; $weatherboost_table = array( 1 => '4', 2 => '5', @@ -165,16 +145,12 @@ function parse_master_data($game_master_url) { if(!isset($row['stats']['attack']) || !isset($row['stats']['defense']) || !isset($row['stats']['stamina'])) { continue; } - $type = $type2 = ''; - foreach($row['types'] as $key => $data) { - if($type == '') { - $type = $typeArray[$key]; - $weather = $weatherboost_table[$key]; - continue; - } - $type2 = $typeArray[$key]; - $weather .= $weatherboost_table[$key]; - } + $pokemon_types = array_keys($row['types']); + $weather = $weatherboost_table[$pokemon_types[0]]; + if(!isset($pokemon_types[1])) + $pokemon_types[1] = ''; + elseif($weatherboost_table[$pokemon_types[0]] != $weatherboost_table[$pokemon_types[1]]) + $weather .= $weatherboost_table[$pokemon_types[1]]; foreach($row['forms'] as $formData) { if(($formData['name'] == 'Unset' && count($row['forms']) > 1) || $formData['name'] == 'Shadow' || $formData['name'] == 'Purified') continue; if($formData['name'] == 'Normal') { @@ -197,8 +173,8 @@ function parse_master_data($game_master_url) { 'min_weather_cp' => $min_weather_cp, 'max_weather_cp' => $max_weather_cp, 'weather' => $weather, - 'type' => $type, - 'type2' => $type2, + 'type' => $pokemon_types[0], + 'type2' => $pokemon_types[1], ]; } if(!isset($row['tempEvolutions'])) continue; @@ -207,16 +183,12 @@ function parse_master_data($game_master_url) { $form_id = -$tempData['tempEvoId']; $form_name = $mega_names[$form_id]; if(isset($tempData['types'])) { - $type = ''; - foreach($tempData['types'] as $key => $data) { - if($type == '') { - $type = $typeArray[$key]; - $weather = $weatherboost_table[$key]; - continue; - } - $type2 = $typeArray[$key]; - $weather .= $weatherboost_table[$key]; - } + $pokemon_types = array_keys($tempData['types']); + $weather = $weatherboost_table[$pokemon_types[0]]; + if(!isset($pokemon_types[1])) + $pokemon_types[1] = ''; + elseif($weatherboost_table[$pokemon_types[0]] != $weatherboost_table[$pokemon_types[1]]) + $weather .= $weatherboost_table[$pokemon_types[1]]; } [$min_cp, $max_cp, $min_weather_cp, $max_weather_cp] = calculate_cps($row['stats']); $pokemon_array[$pokemon_id][$form_name] = [ @@ -228,8 +200,8 @@ function parse_master_data($game_master_url) { 'min_weather_cp' => $min_weather_cp, 'max_weather_cp' => $max_weather_cp, 'weather' => $weather, - 'type' => $type, - 'type2' => $type2, + 'type' => $pokemon_types[0], + 'type2' => $pokemon_types[1], ]; } } From 7b6a912b413534f81f6dc75e00953df3da3f0c4c Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 9 Feb 2024 22:30:30 +0200 Subject: [PATCH 306/367] Share chats config rework Added a new way of configuring share chats. This new way adds support to threads in super groups. Code should be backwards compatible with the old config also, but haven't tested that yet. This is what the new config looks like: ``` "CHATS_SHARE": { "manual_share": { "all": [ {"id": -1001123321, "thread": 123, "title": "Chat title"}, {"id": -1001321123} ], "11": [ {"id": -1001567765, "thread": 321, "title": "Title of chat"} ] }, "after_attendance": [ {"id":-10019999} ], "webhook": { "all": [ {"id": -1001321123} ], "by_pokemon": [ {"pokemon_id":150, "chats":[{"id": -1001567765, "thread": 321}]} ], "geofences":{ "0": { // Geofence id "all": [ {"id": -1001567765} ], "1": [ // Raid level {"id": -1001567765} ] } } } }, ``` The chat object inside each section requires `id`. `thread` and `title` are optional. Title was added since Telegram API doesn't allow bots to get the thread title for existing threads. --- commands/delete.php | 4 +- commands/events.php | 2 +- commands/exreport.php | 2 +- commands/friendsearch.php | 2 +- commands/get.php | 4 +- commands/gym.php | 2 +- commands/gymname.php | 2 +- commands/help.php | 2 +- commands/history.php | 2 +- commands/list.php | 4 +- commands/listall.php | 2 +- commands/overview.php | 2 +- commands/pokedex.php | 2 +- commands/pokemon.php | 4 +- commands/raid_from_webhook.php | 94 +++++++++++++++++++++++---------- commands/set.php | 2 +- commands/start.php | 4 +- commands/trainer.php | 2 +- core/bot/commands.php | 4 +- core/bot/importal.php | 2 +- core/telegram/functions.php | 53 +++++++++++-------- logic/key_util.php | 67 +++++++++++++++-------- logic/send_raid_poll.php | 33 ++++++------ logic/update_raid_poll.php | 2 +- mods/code_start.php | 2 +- mods/events_add.php | 2 +- mods/events_manage.php | 2 +- mods/importal.php | 4 +- mods/raid_by_location.php | 8 +-- mods/raid_share.php | 5 +- mods/share_raid_by_location.php | 4 +- mods/vote_time.php | 18 +++++-- 32 files changed, 216 insertions(+), 128 deletions(-) diff --git a/commands/delete.php b/commands/delete.php index 3fd087ec..06083353 100644 --- a/commands/delete.php +++ b/commands/delete.php @@ -29,7 +29,7 @@ if($query->rowCount() == 0) { $msg = '' . getTranslation('no_active_raids_found') . ''; - send_message($update['message']['chat']['id'], $msg); + send_message(create_chat_object([$update['message']['chat']['id']]), $msg); exit; } @@ -66,4 +66,4 @@ $callback_response = 'OK'; // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/events.php b/commands/events.php index 874f8594..458a30a5 100644 --- a/commands/events.php +++ b/commands/events.php @@ -25,4 +25,4 @@ $keys[][] = button(getTranslation('done'), ['exit', 'd' => '1']); // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/exreport.php b/commands/exreport.php index 2df2d625..6d818307 100644 --- a/commands/exreport.php +++ b/commands/exreport.php @@ -85,4 +85,4 @@ $msg = 'EX Raid Report'; // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/friendsearch.php b/commands/friendsearch.php index a0707cd0..77afa818 100644 --- a/commands/friendsearch.php +++ b/commands/friendsearch.php @@ -23,4 +23,4 @@ }else { $msg = $searchterm.CR. getTranslation('trainer_not_found'); } -send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, [], ['reply_markup' => ['selective' => true]]); diff --git a/commands/get.php b/commands/get.php index 09e8ff9d..df31fbb1 100644 --- a/commands/get.php +++ b/commands/get.php @@ -41,7 +41,7 @@ // Any configs allowed? if(empty($allowed)) { - send_message($update['message']['chat']['id'], getTranslation('not_supported')); + send_message(create_chat_object([$update['message']['chat']['id']]), getTranslation('not_supported')); exit; } foreach($json as $cfg_name => $cfg_value) { @@ -69,4 +69,4 @@ $msg .= CR; } } -send_message($update['message']['chat']['id'], $msg); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg); diff --git a/commands/gym.php b/commands/gym.php index 29850775..3da5d685 100644 --- a/commands/gym.php +++ b/commands/gym.php @@ -20,4 +20,4 @@ $msg.= $keys_and_gymarea['gymareaTitle']; // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); diff --git a/commands/gymname.php b/commands/gymname.php index 335250ed..330f653e 100644 --- a/commands/gymname.php +++ b/commands/gymname.php @@ -50,4 +50,4 @@ } // Send message. -send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); diff --git a/commands/help.php b/commands/help.php index 3ab5b021..1e9a79bc 100644 --- a/commands/help.php +++ b/commands/help.php @@ -67,4 +67,4 @@ } // Send message. -send_message($update['message']['from']['id'], $msg); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg); diff --git a/commands/history.php b/commands/history.php index 60722539..ef41ea1c 100644 --- a/commands/history.php +++ b/commands/history.php @@ -20,4 +20,4 @@ $keys = $msg_keys[1]; } -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); diff --git a/commands/list.php b/commands/list.php index fb250e69..9474d199 100644 --- a/commands/list.php +++ b/commands/list.php @@ -45,7 +45,7 @@ // Did we get any raids? if(count($raids) == 0) { $msg = '' . getTranslation('no_active_raids_found') . ''; - send_message($update['message']['chat']['id'], $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + send_message(create_chat_object([$update['message']['chat']['id']]), $msg, [], ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); exit(); } @@ -98,4 +98,4 @@ $msg .= '' . getTranslation('select_gym_name') . '' . CR; // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/listall.php b/commands/listall.php index af8f8db4..4a286b89 100644 --- a/commands/listall.php +++ b/commands/listall.php @@ -20,4 +20,4 @@ $msg.= $keys_and_gymarea['gymareaTitle']; // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true], 'disable_web_page_preview' => 'true']); diff --git a/commands/overview.php b/commands/overview.php index c5e71ced..4aca3d1c 100644 --- a/commands/overview.php +++ b/commands/overview.php @@ -17,4 +17,4 @@ $msg = '' . getTranslation('raids_share_overview') . ':'; // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/pokedex.php b/commands/pokedex.php index f3bf495c..677f5a86 100644 --- a/commands/pokedex.php +++ b/commands/pokedex.php @@ -50,4 +50,4 @@ $keys[][] = button(getTranslation('abort'), 'exit'); // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/pokemon.php b/commands/pokemon.php index 39f2bfbd..f58ab5e7 100644 --- a/commands/pokemon.php +++ b/commands/pokemon.php @@ -29,7 +29,7 @@ if($query->rowCount() == 0) { $msg = '' . getTranslation('no_active_raids_found') . ''; - send_message($update['message']['chat']['id'], $msg); + send_message(create_chat_object([$update['message']['chat']['id']]), $msg); exit; } @@ -72,4 +72,4 @@ $msg .= '' . getTranslation('select_gym_name') . '' . CR; // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 5f9e3e59..8b812c0b 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -313,51 +313,92 @@ function isPointInsidePolygon($point, $vertices) { $chats_geofence = $chats_raidlevel = $webhook_chats = $chats_by_pokemon = []; if($send_updates == true) { + // Update raid polls and send alerts of updates require_once(LOGIC_PATH .'/update_raid_poll.php'); $tg_json = update_raid_poll($raid_id, $raid, false, $tg_json, true); if($wasBossUpdated) $tg_json = alarm($raid, false, 'new_boss', '', $tg_json); - if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0]) && !$no_auto_posting) { - foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { - if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { - foreach($rule['chats'] as $rule_chat) { - // If the raid isn't already posted to the chats specified in WEBHOOK_CHATS_BY_POKEMON, we add it to the array - if(!isset($cleanup_data[$raid_id]) or !in_array($rule_chat, $cleanup_data[$raid_id])) { - $chats_by_pokemon[] = $rule_chat; + // Post hatched Pokemon to their respective chats if configured + // Start share_chats backwards compatibility + if(!$config->CHATS_SHARE) { + if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0]) && !$no_auto_posting) { + foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { + if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { + foreach($rule['chats'] as $rule_chat) { + // If the raid isn't already posted to the chats specified in WEBHOOK_CHATS_BY_POKEMON, we add it to the array + if(!isset($cleanup_data[$raid_id]) or !in_array($rule_chat, $cleanup_data[$raid_id])) { + $chats_by_pokemon[] = $rule_chat; + } + } + } + } + } + // End chats_share backwards compatibility + }else { + if(!empty($config->CHATS_SHARE['webhook']['by_pokemon']) && !$no_auto_posting) { + foreach($config->CHATS_SHARE['webhook']['by_pokemon'] as $rule) { + if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['FORM_ID'] == $form))) { + foreach($rule['chats'] as $rule_chat) { + if(!isset($cleanup_data[$raid_id]) or !in_array($rule_chat['id'], $cleanup_data[$raid_id])) { + $chats_by_pokemon[] = $rule_chat; + } } } } } } + if(empty($chats_by_pokemon)) continue; }else { - // Get chats to share to by raid level and geofence id - if($geofences != false) { - foreach($inside_geofences as $geofence_id) { - $const_geofence = 'WEBHOOK_CHATS_LEVEL_' . $level . '_' . $geofence_id; - $const_geofence_chats = $config->{$const_geofence} ?? []; - - if(!empty($const_geofence_chats)) { - $chats_geofence = explode(',', $const_geofence_chats); + // Start share_chats backwards compatibility + if(!$config->CHATS_SHARE) { + // Get chats to share to by raid level and geofence id + if($geofences != false) { + foreach($inside_geofences as $geofence_id) { + $const_geofence = 'WEBHOOK_CHATS_LEVEL_' . $level . '_' . $geofence_id; + $const_geofence_chats = $config->{$const_geofence} ?? []; + + if(!empty($const_geofence_chats)) { + $chats_geofence = explode(',', $const_geofence_chats); + } } } - } - // Get chats to share to by raid level - $const = 'WEBHOOK_CHATS_LEVEL_' . $level; - $const_chats = $config->{$const} ?? []; + // Get chats to share to by raid level + $const = 'WEBHOOK_CHATS_LEVEL_' . $level; + $const_chats = $config->{$const} ?? []; - if(!empty($const_chats)) { - $chats_raidlevel = explode(',', $const_chats); - } + if(!empty($const_chats)) { + $chats_raidlevel = explode(',', $const_chats); + } - // Get chats - if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { - $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); + // Get chats + if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { + $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); + } + // End chats_share backwards compatibility + }else { + if($geofences != false) { + foreach($inside_geofences as $geofence_id) { + $geofence_chats_all = $config->CHATS_SHARE['webhook']['geofences'][$geofence_id]['all'] ?? []; + $geofence_chats_by_level = $config->CHATS_SHARE['webhook']['geofences'][$geofence_id][$level] ?? []; + + if(!empty($geofence_chats_all)) { + $chats_geofence = array_merge($chats_geofence, $geofence_chats_all); + } + if(!empty($geofence_chats_by_level)) { + $chats_geofence = array_merge($chats_geofence, $geofence_chats_by_level); + } + } + } + // Get chats to share to by raid level + $chats_raidlevel = $config->CHATS_SHARE['webhook'][$level] ?? []; + + // Get chats + $webhook_chats = $config->CHATS_SHARE['webhook']['all'] ?? []; } } $chats = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats, $chats_by_pokemon); - require_once(LOGIC_PATH .'/send_raid_poll.php'); if($metrics) { $webhook_raids_posted_total->inc(); @@ -366,6 +407,5 @@ function isPointInsidePolygon($point, $vertices) { $tg_json = send_raid_poll($raid_id, $chats, $raid, $tg_json); } } - // Telegram multicurl request. curl_json_multi_request($tg_json); diff --git a/commands/set.php b/commands/set.php index c1444b64..bf88f9e0 100644 --- a/commands/set.php +++ b/commands/set.php @@ -177,4 +177,4 @@ } // Send message. -send_message($update['message']['chat']['id'], $msg); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg); diff --git a/commands/start.php b/commands/start.php index 84d15a3b..67b450c2 100644 --- a/commands/start.php +++ b/commands/start.php @@ -16,7 +16,7 @@ require('list.php'); }else { $response_msg = '' . getTranslation('bot_access_denied') . ''; - send_message($update['message']['from']['id'], $response_msg); + send_message(create_chat_object([$update['message']['chat']['id']]), $response_msg); } exit; } @@ -60,4 +60,4 @@ } // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/commands/trainer.php b/commands/trainer.php index 73280de4..a46237d5 100644 --- a/commands/trainer.php +++ b/commands/trainer.php @@ -67,4 +67,4 @@ $keys[] = $nav_keys; // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/core/bot/commands.php b/core/bot/commands.php index 3d98a3aa..d3219f3b 100644 --- a/core/bot/commands.php +++ b/core/bot/commands.php @@ -13,7 +13,7 @@ } if(isset($update['message']['chat']['id']) && new_user($update['message']['chat']['id']) && $com != 'start' && $com != 'tutorial') { - send_message($update['message']['chat']['id'], getTranslation("tutorial_command_failed")); + send_message(create_chat_object([$update['message']['chat']['id']]), getTranslation("tutorial_command_failed")); exit(); } @@ -33,6 +33,6 @@ // Include start file and exit. include_once($startcommand); } else { - send_message($update['message']['chat']['id'], '' . getTranslation('not_supported') . ''); + send_message(create_chat_object([$update['message']['chat']['id']]), '' . getTranslation('not_supported') . ''); } } diff --git a/core/bot/importal.php b/core/bot/importal.php index f8a2436b..560e7ec6 100644 --- a/core/bot/importal.php +++ b/core/bot/importal.php @@ -5,7 +5,7 @@ // Invalid input or unknown bot - send message and end. $msg = '' . getTranslation('invalid_input') . ''; $msg .= CR . CR . getTranslation('not_supported') . SP . getTranslation('or') . SP . getTranslation('internal_error'); - send_message($update['message']['from']['id'], $msg); + send_message(create_chat_object([$update['message']['chat']['id']]), $msg); exit(); } diff --git a/core/telegram/functions.php b/core/telegram/functions.php index f90af8e9..8cd278bd 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -24,10 +24,15 @@ function is_valid_target($chat_id, $message_id, $no_chat = false, $no_message = info_log("chat_id:{$chat_id}, message_id:{$message_id}", 'ERROR: Unhandled pair of chat_id & message_id, this is a bug:'); return true; } - +function create_chat_object($arr) { + $return = []; + $return['id'] = $arr[0] ?? 0; + $return['thread'] = $arr[1] ?? 0; + return $return; +} /** * Send message. - * @param int $chat_id + * @param array $chatObj * @param string $text * @param mixed $inline_keyboard * @param array|bool $merge_args @@ -35,17 +40,18 @@ function is_valid_target($chat_id, $message_id, $no_chat = false, $no_message = * @param int|string $identifier * @return mixed */ -function send_message($chat_id, $text = [], $inline_keyboard = false, $merge_args = [], $multicurl = false, $identifier = false) +function send_message($chatObj, $text = [], $inline_keyboard = false, $merge_args = [], $multicurl = false, $identifier = false) { // Create response content array. $reply_content = [ 'method' => 'sendMessage', - 'chat_id' => $chat_id, + 'chat_id' => $chatObj['id'], 'parse_mode' => 'HTML', 'text' => $text ]; - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); + if(isset($chatObj['thread'])) $reply_content['message_thread_id'] = $chatObj['thread']; + if(!is_valid_target($chatObj['id'], null, false, true)){ + info_log($chatObj['id'], 'ERROR: Cannot send to invalid chat id:'); info_log($reply_content, 'ERROR: data would have been:'); exit(); } @@ -77,7 +83,7 @@ function send_message($chat_id, $text = [], $inline_keyboard = false, $merge_arg /** * Send venue. - * @param $chat_id + * @param $chatObj * @param $lat * @param $lon * @param $title @@ -87,19 +93,20 @@ function send_message($chat_id, $text = [], $inline_keyboard = false, $merge_arg * @param $identifier * @return mixed */ -function send_venue($chat_id, $lat, $lon, $title, $address, $inline_keyboard = false, $multicurl = false, $identifier = false) +function send_venue($chatObj, $lat, $lon, $title, $address, $inline_keyboard = false, $multicurl = false, $identifier = false) { // Create reply content array. $reply_content = [ 'method' => 'sendVenue', - 'chat_id' => $chat_id, + 'chat_id' => $chatObj['id'], 'latitude' => $lat, 'longitude' => $lon, 'title' => $title, 'address' => $address ]; - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); + if(isset($chatObj['thread'])) $reply_content['message_thread_id'] = $chatObj['thread']; + if(!is_valid_target($chatObj['id'], null, false, true)){ + info_log($chatObj['id'], 'ERROR: Cannot send to invalid chat id:'); info_log($reply_content, 'ERROR: data would have been:'); exit(); } @@ -127,20 +134,21 @@ function send_venue($chat_id, $lat, $lon, $title, $address, $inline_keyboard = f /** * Echo message. - * @param $chat_id + * @param $chatObj * @param $text */ -function sendMessageEcho($chat_id, $text) +function sendMessageEcho($chatObj, $text) { // Create reply content array. $reply_content = [ 'method' => 'sendMessage', - 'chat_id' => $chat_id, + 'chat_id' => $chatObj['id'], 'parse_mode' => 'HTML', 'text' => $text ]; - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); + if(isset($chatObj['thread'])) $reply_content['message_thread_id'] = $chatObj['thread']; + if(!is_valid_target($chatObj['id'], null, false, true)){ + info_log($chatObj['id'], 'ERROR: Cannot send to invalid chat id:'); info_log($reply_content, 'ERROR: data would have been:'); exit(); } @@ -589,7 +597,7 @@ function get_chatmember($chat_id, $user_id, $multicurl = false) /** * Send photo. - * @param $chat_id + * @param $chatObj * @param string $media_content content of the media file. * @param bool $content_type true = photo file, false = file_id * @param string|bool $text @@ -598,20 +606,21 @@ function get_chatmember($chat_id, $user_id, $multicurl = false) * @param array|bool $multicurl * @param int|bool $identifier */ -function send_photo($chat_id, $media_content, $content_type, $text = '', $inline_keyboard = false, $merge_args = [], $multicurl = false, $identifier = false) +function send_photo($chatObj, $media_content, $content_type, $text = '', $inline_keyboard = false, $merge_args = [], $multicurl = false, $identifier = false) { // Create response content array. $post_contents = [ 'method' => 'sendPhoto', - 'chat_id' => $chat_id, + 'chat_id' => $chatObj['id'], 'reply_markup' => json_encode(['inline_keyboard' => $inline_keyboard]), ]; if($text != '') { $post_contents['caption'] = $text; $post_contents['parse_mode'] = 'HTML'; } - if(!is_valid_target($chat_id, null, false, true)){ - info_log($chat_id, 'ERROR: Cannot send to invalid chat id:'); + if(isset($chatObj['thread'])) $post_contents['message_thread_id'] = $chatObj['thread']; + if(!is_valid_target($chatObj['id'], null, false, true)){ + info_log($chatObj['id'], 'ERROR: Cannot send to invalid chat id:'); info_log(print_r($post_contents, true), 'ERROR: data would have been:'); exit(); } @@ -684,7 +693,7 @@ function editMessageMedia($id_val, $text_val, $media_content, $content_type, $in $post_contents['media']['media'] = $media_content; } $post_contents['media'] = json_encode($post_contents['media']); - debug_log("Editing message ${post_contents['message_id']} media: ${post_contents['media']}", '->'); + debug_log("Editing message ".$post_contents['message_id']." media: ".$post_contents['media'], '->'); // Send request to telegram api. return curl_request($post_contents, $multicurl, $identifier); diff --git a/logic/key_util.php b/logic/key_util.php index ff9a2024..cd8518e5 100644 --- a/logic/key_util.php +++ b/logic/key_util.php @@ -50,23 +50,46 @@ function share_keys($id, $action, $update, $raidLevel = '', $chats = [], $hideGe ]; } - // Add buttons for predefined sharing chats. - // Default SHARE_CHATS or special chat list via $chats? - if(empty($chats)) { - if(!empty($raidLevel)) { - // find chats to share ourselves, if we can - debug_log($raidLevel, 'Did not get specific chats to share to, checking level specific for: '); - $level_chat = 'SHARE_CHATS_LEVEL_' . $raidLevel; - if(!empty($config->{$level_chat})) { - $chats = explode(',', $config->{$level_chat}); - debug_log($chats, 'Found level specific chats to share to: '); + // Start share_chats backwards compatibility + if(!$config->CHATS_SHARE) { + // Add buttons for predefined sharing chats. + // Default SHARE_CHATS or special chat list via $chats? + if(empty($chats)) { + if(!empty($raidLevel)) { + // find chats to share ourselves, if we can + debug_log($raidLevel, 'Did not get specific chats to share to, checking level specific for: '); + $level_chat = 'SHARE_CHATS_LEVEL_' . $raidLevel; + $chats = []; + if(!empty($config->{$level_chat})) { + $chat_array = explode(',', $config->{$level_chat}); + debug_log($config->{$level_chat}, 'Found level specific chats to share to: '); + } else { + $chat_array = explode(',', $config->SHARE_CHATS); + debug_log($config->SHARE_CHATS, 'Chats not specified for level, sharing to globals: '); + } + } else { + $chat_array = explode(',', $config->SHARE_CHATS); + debug_log($config->SHARE_CHATS, 'Level not given, sharing to globals: '); + } + foreach($chat_array as $chat) { + $chats[] = ['id' => $chat]; + } + } + // End chats_share backwards compatibility + } else { + if(empty($chats)) { + if(!empty($raidLevel)) { + // find chats to share ourselves, if we can + debug_log($raidLevel, 'Did not get specific chats to share to, checking level specific for: '); + $chats = []; + if(!empty($config->CHATS_SHARE['manual_share'][$raidLevel])) { + $chats = $config->CHATS_SHARE['manual_share'][$raidLevel]; + } else { + $chats = $config->CHATS_SHARE['manual_share']['all']; + } } else { - $chats = explode(',', $config->SHARE_CHATS); - debug_log($chats, 'Chats not specified for level, sharing to globals: '); + $chats = $config->CHATS_SHARE['manual_share']['all']; } - } else { - $chats = explode(',', $config->SHARE_CHATS); - debug_log($chats, 'Level not given, sharing to globals: '); } } // Add keys for each chat. @@ -87,20 +110,22 @@ function share_keys($id, $action, $update, $raidLevel = '', $chats = [], $hideGe $sharedChats = $queryShared->fetchAll(PDO::FETCH_COLUMN, 0); } foreach($chats as $chat) { - if(in_array($chat, $sharedChats)) continue; + if(in_array($chat['id'], $sharedChats)) continue; // Get chat object - debug_log("Getting chat object for '" . $chat . "'"); - $chat_obj = get_chat($chat); + debug_log("Getting chat object for '" . $chat['id'] . "'"); + $chat_obj = get_chat($chat['id']); // Check chat object for proper response. if ($chat_obj['ok'] != true) { info_log($chat, 'Invalid chat id in your configuration:'); continue; } - debug_log('Proper chat object received, continuing to add key for this chat: ' . $chat_obj['result']['title']); - $shareData = [0 => $action, 'c' => $chat]; + $chatTitle = $chat['title'] ?? $chat_obj['result']['title']; + debug_log('Proper chat object received, continuing to add key for this chat: ' . $chatTitle); + $shareData = [0 => $action, 'c' => $chat['id']]; + $shareData['t'] = $chat['thread'] ?? ''; if($id !== false) $shareData['r'] = $id; - $keys[][] = button(getTranslation('share_with') . ' ' . $chat_obj['result']['title'], $shareData); + $keys[][] = button(getTranslation('share_with') . ' ' . $chatTitle, $shareData); } return $keys; diff --git a/logic/send_raid_poll.php b/logic/send_raid_poll.php index a6f5098e..4106ef1e 100644 --- a/logic/send_raid_poll.php +++ b/logic/send_raid_poll.php @@ -5,30 +5,31 @@ /** * Post a raid poll to all relevant chats * @param int $raid_id ID of the raid - * @param int|array $shareChats chat ID or array of IDs + * @param array $shareChatObjs Array of chat objects * @param array|false $raid Array received from get_raid() (optional). * @param array|false $tg_json multicurl array * @return array multicurl array */ -function send_raid_poll($raid_id, $shareChats, $raid = false, $tg_json = false) { +function send_raid_poll($raid_id, $shareChatObjs, $raid = false, $tg_json = false) { global $config; // Telegram JSON array. if($tg_json == false) $tg_json = []; - if(!is_array($shareChats)) $shareChats = [$shareChats]; - // Check if Raid has been posted to target chat + $shareChatIDs = []; + foreach($shareChatObjs as $chatObj) { + $shareChatIDs[] = $chatObj['id']; + } + // Fetch chat id's to which the raid has already been posted $resultChats = my_query(' SELECT DISTINCT chat_id FROM cleanup WHERE raid_id = :raidId - AND chat_id IN ("' . implode('","',$shareChats) . '") + AND chat_id IN ("' . implode('","',$shareChatIDs) . '") ', [ 'raidId' => $raid_id, ]); $chatsAlreadySharedTo = $resultChats->fetchAll(PDO::FETCH_COLUMN, 0); - $chats = array_diff($shareChats, $chatsAlreadySharedTo); - if(count($chats) == 0) return $tg_json; // Get raid data. if($raid == false) $raid = get_raid($raid_id); @@ -39,7 +40,7 @@ function send_raid_poll($raid_id, $shareChats, $raid = false, $tg_json = false) $post_text = false; if(array_key_exists('short', $text)) { - $msg_short_len = strlen(utf8_decode($text['short'])); + $msg_short_len = strlen(mb_convert_encoding($text['short'], 'ISO-8859-1')); debug_log($msg_short_len, 'Raid poll short message length:'); // Message short enough? if($msg_short_len >= 1024) { @@ -61,29 +62,31 @@ function send_raid_poll($raid_id, $shareChats, $raid = false, $tg_json = false) $raid_pokemon_form_name = get_pokemon_form_name($raid_pokemon_id,$raid['pokemon_form']); $raid_pokemon = $raid_pokemon_id . "-" . $raid_pokemon_form_name; - foreach($chats as $chat_id) { + foreach($shareChatObjs as $chatObj) { + // Check if Raid has been posted to target chat + if(in_array($chatObj['id'], $chatsAlreadySharedTo)) continue; if ($config->RAID_LOCATION) { // Send location. $msg_text = !empty($raid['address']) ? $raid['address'] : $raid['pokemon']; // Sending venue together with raid poll can't be multicurled since they would appear to the chat in random order - send_venue($chat_id, $raid['lat'], $raid['lon'], '', $msg_text, false, false, $raid_id); - send_message($chat_id, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); + send_venue($chatObj, $raid['lat'], $raid['lon'], '', $msg_text, false, false, $raid_id); + send_message($chatObj, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); continue; } if(!$config->RAID_PICTURE || $raid['event_hide_raid_picture'] == 1 || in_array($raid_level, $raid_picture_hide_level) || in_array($raid_pokemon, $raid_picture_hide_pokemon) || in_array($raid_pokemon_id, $raid_picture_hide_pokemon)) { - $tg_json[] = send_message($chat_id, $text['full'], $keys, ['disable_web_page_preview' => 'true'], true, $raid_id); + $tg_json[] = send_message($chatObj, $text['full'], $keys, ['disable_web_page_preview' => 'true'], true, $raid_id); continue; } require_once(LOGIC_PATH . '/raid_picture.php'); if(!($config->RAID_PICTURE_AUTOEXTEND && !in_array($raid['level'], $raid_poll_hide_buttons_levels)) && $post_text == false) { $media_content = get_raid_picture($raid); - $tg_json[] = send_photo($chat_id, $media_content[1], $media_content[0], $text['short'], $keys, ['disable_web_page_preview' => 'true'], true, $raid); + $tg_json[] = send_photo($chatObj, $media_content[1], $media_content[0], $text['short'], $keys, ['disable_web_page_preview' => 'true'], true, $raid); continue; } $media_content = get_raid_picture($raid, true); $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache - send_photo($chat_id, $media_content[1], $media_content[0], '', [], [], false, $raid); - send_message($chat_id, $text['short'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); + send_photo($chatObj, $media_content[1], $media_content[0], '', [], [], false, $raid); + send_message($chatObj, $text['short'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); } return $tg_json; } diff --git a/logic/update_raid_poll.php b/logic/update_raid_poll.php index dacd0a61..c4662fb1 100644 --- a/logic/update_raid_poll.php +++ b/logic/update_raid_poll.php @@ -76,7 +76,7 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f $text = show_raid_poll($raid); $post_text = false; if(array_key_exists('short', $text)) { - $msg_short_len = strlen(utf8_decode($text['short'])); + $msg_short_len = strlen(mb_convert_encoding($text['short'], 'ISO-8859-1')); debug_log($msg_short_len, 'Raid poll short message length:'); // Message short enough? if($msg_short_len >= 1024) { diff --git a/mods/code_start.php b/mods/code_start.php index f1a8f479..f69849b1 100644 --- a/mods/code_start.php +++ b/mods/code_start.php @@ -51,4 +51,4 @@ } // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/mods/events_add.php b/mods/events_add.php index 17a70ab6..c489110f 100644 --- a/mods/events_add.php +++ b/mods/events_add.php @@ -53,7 +53,7 @@ // Edit the message. $tg_json[] = edit_message($update, $msg, $keys, false, true); }else { - $tg_json[] = send_message($update['message']['chat']['id'], $msg, $keys, false, true); + $tg_json[] = send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, false, true); } // Telegram multicurl request. diff --git a/mods/events_manage.php b/mods/events_manage.php index 91d3fe3c..97cb6906 100644 --- a/mods/events_manage.php +++ b/mods/events_manage.php @@ -176,7 +176,7 @@ // Edit the message. $tg_json[] = edit_message($update, $msg, $keys, false, true); }else { - $tg_json[] = send_message($update['message']['chat']['id'], $msg, $keys, false, true); + $tg_json[] = send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, false, true); } // Telegram multicurl request. diff --git a/mods/importal.php b/mods/importal.php index 5e6f2273..621c3d15 100644 --- a/mods/importal.php +++ b/mods/importal.php @@ -23,7 +23,7 @@ function escape($value){ if(!$config->PORTAL_IMPORT) { $msg = getTranslation('bot_access_denied'); $keys = []; - send_message($update['message']['chat']['id'], $msg, $keys, ['disable_web_page_preview' => 'true']); + send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['disable_web_page_preview' => 'true']); exit; } @@ -123,4 +123,4 @@ function escape($value){ $keys[][] = button(getTranslation('done'), ['exit', 'd' => '1']); // Send the message. -send_message($update['message']['chat']['id'], $msg, $keys, ['disable_web_page_preview' => 'true']); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['disable_web_page_preview' => 'true']); diff --git a/mods/raid_by_location.php b/mods/raid_by_location.php index cc5302ae..f0761373 100644 --- a/mods/raid_by_location.php +++ b/mods/raid_by_location.php @@ -15,7 +15,7 @@ // Enabled? if(!$config->RAID_VIA_LOCATION) { debug_log('Creating raids by sharing a location is not enabled in config! Exiting!'); - send_message($update['message']['chat']['id'], '' . getTranslation('bot_access_denied') . ''); + send_message(create_chat_object([$update['message']['chat']['id']]), '' . getTranslation('bot_access_denied') . ''); exit(); } $reg_exp_coordinates = '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$^'; @@ -28,7 +28,7 @@ $lat = $data['id']; $lon = $data['arg']; } else { - send_message($update['message']['chat']['id'], '' . getTranslation('invalid_input') . ''); + send_message(create_chat_object([$update['message']['chat']['id']]), '' . getTranslation('invalid_input') . ''); exit(); } @@ -78,7 +78,7 @@ $keys = []; // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); exit(); } else { @@ -148,7 +148,7 @@ $msg = getTranslation('create_raid') . ': ' . $address . ''; // Send message. - send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); + send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); // Answer forwarded location message from geo_create. } else if(isset($update['callback_query'])) { diff --git a/mods/raid_share.php b/mods/raid_share.php index 5240f53a..5588cf2b 100644 --- a/mods/raid_share.php +++ b/mods/raid_share.php @@ -15,8 +15,9 @@ // Get chat id. $chat = $data['c']; - -$tg_json = send_raid_poll($raidId, $chat); +$thread = $data['t'] ?? ''; +$chatObj = [['id' => $chat, 'thread' => $thread]]; +$tg_json = send_raid_poll($raidId, $chatObj); // Set callback keys and message $callback_msg = getTranslation('successfully_shared'); diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 3d24a0c5..54fb133b 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -50,7 +50,7 @@ exit; } if(!isset($update['message']['location'])) { - send_message($update['message']['chat']['id'], '' . getTranslation('invalid_input') . ''); + send_message(create_chat_object([$update['message']['chat']['id']]), '' . getTranslation('invalid_input') . ''); exit(); } $lat = (float)$update['message']['location']['latitude']; @@ -137,4 +137,4 @@ } // Send message. -send_message($update['message']['chat']['id'], $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); +send_message(create_chat_object([$update['message']['chat']['id']]), $msg, $keys, ['reply_markup' => ['selective' => true, 'one_time_keyboard' => true]]); diff --git a/mods/vote_time.php b/mods/vote_time.php index 77026545..c20accc5 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -158,10 +158,20 @@ // Check if RAID has no participants AND Raid should be shared to another chat at first participant // AND target chat was set in config AND Raid was not shared to target chat before - if($count_att == 0 && $config->SHARE_AFTER_ATTENDANCE && !empty($config->SHARE_CHATS_AFTER_ATTENDANCE)){ - // Send the message. - require_once(LOGIC_PATH . '/send_raid_poll.php'); - $tg_json = send_raid_poll($raidId, $config->SHARE_CHATS_AFTER_ATTENDANCE, $raid, $tg_json); + // Start share_chats backwards compatibility + if(!$config->CHATS_SHARE) { + if($count_att == 0 && $config->SHARE_AFTER_ATTENDANCE && !empty($config->SHARE_CHATS_AFTER_ATTENDANCE)){ + // Send the message. + require_once(LOGIC_PATH . '/send_raid_poll.php'); + $tg_json = send_raid_poll($raidId, $config->SHARE_CHATS_AFTER_ATTENDANCE, $raid, $tg_json); + } + // End share_chats backwards compatibility + }else { + if($count_att == 0 && isset($config->CHATS_SHARE['after_attendance'][0]['id'])){ + // Send the message. + require_once(LOGIC_PATH . '/send_raid_poll.php'); + $tg_json = send_raid_poll($raidId, $config->CHATS_SHARE['after_attendance'], $raid, $tg_json); + } } } From 961e9f6f175080e5f94fbf346cb73a1275a31c9a Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 11 Feb 2024 16:43:14 +0200 Subject: [PATCH 307/367] send_message fixes --- core/bot/user.php | 2 +- logic/alarm.php | 2 +- logic/sendalarmnotice.php | 2 +- mods/change_trainercode.php | 4 ++-- mods/change_trainername.php | 4 ++-- mods/gym_create.php | 5 ++++- mods/save_event_note.php | 2 +- mods/save_gym_info.php | 4 ++-- mods/tutorial.php | 4 ++-- mods/vote_status.php | 2 +- 10 files changed, 17 insertions(+), 14 deletions(-) diff --git a/core/bot/user.php b/core/bot/user.php index f7ce647d..95bfc674 100644 --- a/core/bot/user.php +++ b/core/bot/user.php @@ -176,7 +176,7 @@ public function denyAccess() { $response_msg = '' . getTranslation('bot_access_denied') . ''; // Edit message or send new message based on type of received call if ($update['type'] != 'callback_query') { - send_message($update['message']['from']['id'], $response_msg); + send_message(create_chat_object([$update['message']['chat']['id']]), $response_msg); exit; } $keys = []; diff --git a/logic/alarm.php b/logic/alarm.php index 5bb29b14..a0867339 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -252,7 +252,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $msg_text .= EMOJI_CLOCK . SP . '' . check_time($attendtime, $recipient_language) . ''; $msg_text .= create_traincode_msg($trainercode); } - $tg_json[] = send_message($answer['user_id'], $msg_text, false, false, true); + $tg_json[] = send_message(create_chat_object([$answer['user_id']]), $msg_text, false, false, true); } return $tg_json; } diff --git a/logic/sendalarmnotice.php b/logic/sendalarmnotice.php index ddd4cd50..dbf232dd 100644 --- a/logic/sendalarmnotice.php +++ b/logic/sendalarmnotice.php @@ -43,5 +43,5 @@ function sendAlertOnOffNotice($raid_id, $user_id, $alarm = null, $raid = null){ $msg_text = EMOJI_NO_ALARM . SP . '' . getTranslation('alert_no_updates') . '' . CR; } $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')'; - send_message($user_id, $msg_text); + send_message(create_chat_object([$user_id]), $msg_text); } diff --git a/mods/change_trainercode.php b/mods/change_trainercode.php index eeef962d..f3a0141b 100644 --- a/mods/change_trainercode.php +++ b/mods/change_trainercode.php @@ -9,7 +9,7 @@ // Check that Code is 12 digits long if(strlen($trainercode) != 12){ // Trainer Code got unallowed Chars -> Error-Message - send_message($target_user_id, getTranslation('trainercode_fail')); + send_message(create_chat_object([$target_user_id]), getTranslation('trainercode_fail')); exit(); } // Store new Trainercode to DB @@ -28,4 +28,4 @@ $keys[0][1] = button(getTranslation('done'), ['exit', 'd' => '1']); // confirm Trainercode-Change -send_message($target_user_id, getTranslation('trainercode_success').' '.$trainercode.'', $keys); +send_message(create_chat_object([$target_user_id]), getTranslation('trainercode_success').' '.$trainercode.'', $keys); diff --git a/mods/change_trainername.php b/mods/change_trainername.php index 8cf9ab10..02c35bfd 100644 --- a/mods/change_trainername.php +++ b/mods/change_trainername.php @@ -7,7 +7,7 @@ // Only numbers and alphabetic character allowed if(!$returnValue){ // Trainer Name got unallowed Chars -> Error-Message - send_message($userid, getTranslation('trainername_fail')); + send_message(create_chat_object([$userid]), getTranslation('trainername_fail')); exit(); } $trainername = $update['message']['text']; @@ -28,4 +28,4 @@ $keys[0][] = button(getTranslation('done'), ['exit', 'd' => '1']); // confirm Name-Change -send_message($userid, getTranslation('trainername_success').' '.$trainername.'', $keys); +send_message(create_chat_object([$userid]), getTranslation('trainername_success').' '.$trainername.'', $keys); diff --git a/mods/gym_create.php b/mods/gym_create.php index bb61b080..df2629a2 100644 --- a/mods/gym_create.php +++ b/mods/gym_create.php @@ -23,7 +23,7 @@ function insertUserInput($userId, $stage, $oldMessageId, $gymId = 0) { function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [], $sendMsg = '', $sendKeys = [], $callbackMsg = '', $callbackId = 0) { if($callbackId != 0) answerCallbackQuery($callbackId, $callbackMsg); if($editMsg != '') editMessageText($oldMessageId, $editMsg, $editKeys, $userId, ['disable_web_page_preview' => 'true']); - if($sendMsg != '') send_message($userId, $sendMsg, $sendKeys, ['disable_web_page_preview' => 'true']); + if($sendMsg != '') send_message(create_chat_object([$userId]), $sendMsg, $sendKeys, ['disable_web_page_preview' => 'true']); } // Set keys. $keys = []; @@ -50,6 +50,7 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $sendMsg = EMOJI_HERE . getTranslation('gym_gps_instructions') . CR; $sendMsg .= getTranslation('gym_gps_example'); respondToUser($userId, $oldMessageId, $editMsg, $editKeys, $sendMsg, [], $callbackResponse, $callbackId); + exit; } $userId = $update['message']['from']['id']; $oldMessageId = $modifiers['oldMessageId']; @@ -69,6 +70,7 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $msg = getTranslation('gym_gps_coordinates_format_error'); respondToUser($userId, 0, '', [], $msg); } + exit; } if($stage == 3) { $input = trim($update['message']['text']); @@ -83,4 +85,5 @@ function respondToUser($userId, $oldMessageId = 0, $editMsg = '', $editKeys = [] $msg = getTranslation('gym_edit_text_too_long'); respondToUser($userId, 0, '', [], $msg); } + exit; } diff --git a/mods/save_event_note.php b/mods/save_event_note.php index 34adc0a8..43be6af5 100644 --- a/mods/save_event_note.php +++ b/mods/save_event_note.php @@ -29,4 +29,4 @@ debug_log($keys); // Send response message to user -send_message($user_id, $msg, $keys, []); +send_message(create_chat_object([$user_id]), $msg, $keys, []); diff --git a/mods/save_gym_info.php b/mods/save_gym_info.php index d0496d2c..2d8140da 100644 --- a/mods/save_gym_info.php +++ b/mods/save_gym_info.php @@ -18,7 +18,7 @@ if($action == 'gps') { $reg_exp_coordinates = '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$^'; if(!preg_match($reg_exp_coordinates, $input)) { - send_message($user_id, getTranslation("gym_gps_coordinates_format_error") . CR . getTranslation("gym_gps_example")); + send_message(create_chat_object([$user_id]), getTranslation("gym_gps_coordinates_format_error") . CR . getTranslation("gym_gps_example")); exit(); } [$lat, $lon] = explode(',', $input, 2); @@ -32,7 +32,7 @@ $gym['lon'] = $lon; }else if(in_array($action, ['addr','name','note'])) { if(strlen($input) > 255) { - send_message($user_id, getTranslation('gym_edit_text_too_long')); + send_message(create_chat_object([$user_id]), getTranslation('gym_edit_text_too_long')); exit(); } $column_map = ['addr' => 'address', 'name' => 'gym_name', 'note' => 'gym_note']; diff --git a/mods/tutorial.php b/mods/tutorial.php index 15072224..a3be6404 100644 --- a/mods/tutorial.php +++ b/mods/tutorial.php @@ -23,7 +23,7 @@ delete_message($update['callback_query']['message']['chat']['id'],$update['callback_query']['message']['message_id']); if($new_user) { my_query('UPDATE users SET tutorial = ? WHERE user_id = ?', [$data['l'], $user_id]); - send_message($user_id, $tutorial_done, []); + send_message(create_chat_object([$user_id]), $tutorial_done, []); // Post the user id to external address if specified if(isset($config->TUTORIAL_COMPLETED_CURL_ADDRESS) && $config->TUTORIAL_COMPLETED_CURL_ADDRESS != '') { @@ -61,7 +61,7 @@ $msg = getTranslation('tutorial_no_user_info_set'); $keys[0][0] = button(getTranslation('yes'), 'trainer'); $keys[0][1] = button(getTranslation('no'), ['exit', 'd' => '1']); - send_message($user_id,$msg,$keys); + send_message(create_chat_object([$user_id]),$msg,$keys); } exit(); } diff --git a/mods/vote_status.php b/mods/vote_status.php index e30f91fc..86ca0ba4 100644 --- a/mods/vote_status.php +++ b/mods/vote_status.php @@ -86,7 +86,7 @@ $keys[0][1] = button(getTranslation('no'), 'exit'); if($status == 'raid_done') $msg = getTranslation("delete_remote_raid_done"); else if($status == 'cancel') $msg = getTranslation("delete_remote_raid_cancel"); - $tg_json[] = send_message($update['callback_query']['from']['id'], $msg, $keys, false, true); + $tg_json[] = send_message(create_chat_object([$update['callback_query']['from']['id']]), $msg, $keys, false, true); } }elseif($status != 'arrived') { $tg_json = alarm($raidId,$update['callback_query']['from']['id'],'status',$status, $tg_json); From b9ee65914bb51ce30b97a432babd1cde88ac76bf Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 12 Feb 2024 21:46:18 +0200 Subject: [PATCH 308/367] Only process raid webhook --- commands/raid_from_webhook.php | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index 8b812c0b..b8abf44a 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -49,6 +49,7 @@ function isPointInsidePolygon($point, $vertices) { $webhook_raids_received_total->incBy(count($update)); } foreach($update as $raid) { + if($raid['type'] != 'raid') continue; // Skip posting if create only -mode is set or raid time is greater than value set in config $no_auto_posting = ($config->WEBHOOK_CREATE_ONLY or ($raid['message']['end']-$raid['message']['start']) > ($config->WEBHOOK_EXCLUDE_AUTOSHARE_DURATION * 60)); From 46380504f8f8f3baac1c03596abbcf36dce23d99 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 12 Feb 2024 21:47:39 +0200 Subject: [PATCH 309/367] Added a few more create_chat_object --- commands/help.php | 2 +- commands/tutorial.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/help.php b/commands/help.php index 1e9a79bc..ddc1478c 100644 --- a/commands/help.php +++ b/commands/help.php @@ -58,7 +58,7 @@ } $keys[][] = button(getTranslation('next'), 'tutorial'); $photo = $tutorial[0]['photo']; - send_photo($update['message']['from']['id'],$photo, false, $msg, $keys, ['disable_web_page_preview' => 'true']); + send_photo(create_chat_object([$update['message']['from']['id']]),$photo, false, $msg, $keys, ['disable_web_page_preview' => 'true']); exit(); // No help for the user. diff --git a/commands/tutorial.php b/commands/tutorial.php index a6601b3e..6be95479 100644 --- a/commands/tutorial.php +++ b/commands/tutorial.php @@ -18,4 +18,4 @@ $msg = ($new_user) ? $tutorial[0]['msg_new'] : $tutorial[0]['msg']; $keys[][] = button(getTranslation('next'), ['tutorial', 'p' => 1]); $photo = $tutorial[0]['photo']; -send_photo($update['message']['from']['id'], $photo, false, $msg, $keys, ['disable_web_page_preview' => 'true'],false); +send_photo(create_chat_object([$update['message']['from']['id']]), $photo, false, $msg, $keys, ['disable_web_page_preview' => 'true'],false); From 28fb58ca19f27b1719d2310743ab811b0c682675 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 12 Feb 2024 21:48:13 +0200 Subject: [PATCH 310/367] More thread_id support Added thread_id columns to cleanup, overview and trainderinfo tables. Almost everything but overview sharing should now fully support threads. Working on that --- logic/collectCleanup.php | 8 ++-- logic/config_chats.php | 77 +++++++++++++++++++++++++++++++++ logic/insert_cleanup.php | 16 ++++--- logic/insert_overview.php | 13 +++--- logic/insert_trainerinfo.php | 12 +++--- logic/update_raid_poll.php | 7 +-- mods/refresh_polls.php | 2 +- mods/trainer_add.php | 84 ++++++++++++------------------------ mods/trainer_share.php | 5 ++- sql/pokemon-raid-bot.sql | 3 ++ sql/upgrade/5.sql | 5 +++ 11 files changed, 150 insertions(+), 82 deletions(-) create mode 100644 logic/config_chats.php diff --git a/logic/collectCleanup.php b/logic/collectCleanup.php index 1e6854ae..719905b6 100644 --- a/logic/collectCleanup.php +++ b/logic/collectCleanup.php @@ -21,10 +21,12 @@ function collectCleanup($response, $request, $identifier = false) // Set chat and message_id $chat_id = $response['result']['chat']['id']; $message_id = $response['result']['message_id']; + $thread_id = $response['result']['message_thread_id'] ?? null; + debug_log('Return data: Chat id: '.$chat_id.', message_id: '.$message_id.', type: '.(is_array($identifier) ? print_r($identifier,true) : $identifier)); if($identifier == 'trainer') { debug_log('Adding trainermessage info to database now!'); - insert_trainerinfo($chat_id, $message_id); + insert_trainerinfo($chat_id, $message_id, $thread_id); return $response; } if ($identifier == 'overview') { @@ -32,7 +34,7 @@ function collectCleanup($response, $request, $identifier = false) $chat_title = $response['result']['chat']['title']; $chat_username = $response['result']['chat']['username'] ?? ''; - insert_overview($chat_id, $message_id, $chat_title, $chat_username); + insert_overview($chat_id, $message_id, $thread_id, $chat_title, $chat_username); return $response; } @@ -73,7 +75,7 @@ function collectCleanup($response, $request, $identifier = false) ); } $raid_id = is_array($identifier) ? $identifier['id'] : $identifier; - insert_cleanup($chat_id, $message_id, $raid_id, $type, $unique_id); + insert_cleanup($chat_id, $message_id, $thread_id, $raid_id, $type, $unique_id); // Return response. return $response; } diff --git a/logic/config_chats.php b/logic/config_chats.php new file mode 100644 index 00000000..820a1ddf --- /dev/null +++ b/logic/config_chats.php @@ -0,0 +1,77 @@ +CHATS_SHARE)) { + $chat_vars = ['TRAINER_CHATS','SHARE_CHATS','WEBHOOK_CHATS']; + $chatsTemp = []; + foreach(array_keys($config) as $var) { + foreach($chat_vars as $start) { + if(!strpos($var, $start)) continue; + if(is_string($config->{$var})) { + array_merge($chatsTemp, explode(',', $config->{$var})); + continue; + } + array_merge($chatsTemp, $config->{$var}); + } + } + $chats = []; + foreach($chatsTemp as $chat) { + $chats[] = create_chat_object($chat); + } + }else { + $chats = []; + if(isset($config->CHATS_SHARE['manual_share'])) { + foreach($config->CHATS_SHARE['manual_share'] as $chatGroup) { + foreach($chatGroup as $chat) { + $chats = add_chat($chats, $chat); + } + } + } + if(isset($config->CHATS_SHARE['after_attendance'])) { + foreach($config->CHATS_SHARE['after_attendance'] as $chat) { + $chats = add_chat($chats, $chat); + } + } + if(isset($config->CHATS_SHARE['webhook'])) { + if(isset($config->CHATS_SHARE['webhook']['all'])) { + foreach($config->CHATS_SHARE['webhook']['all'] as $chat) { + $chats = add_chat($chats, $chat); + } + } + if(isset($config->CHATS_SHARE['webhook']['by_pokemon'])) { + foreach($config->CHATS_SHARE['webhook']['by_pokemon'] as $chatGroup) { + foreach($chatGroup['chats'] as $chat) { + $chats = add_chat($chats, $chat); + } + } + } + if(isset($config->CHATS_SHARE['webhook']['geofences'])) { + foreach($config->CHATS_SHARE['webhook']['geofences'] as $geofence) { + foreach($geofence as $chatGroup) { + foreach($chatGroup as $chat) { + $chats = add_chat($chats, $chat); + } + } + } + } + } + } + return $chats; +} + +function add_chat($chats, $chatToAdd) { + foreach($chats as $chat) { + if( + $chat['id'] == $chatToAdd['id'] && !isset($chat['thread']) || + $chat['id'] == $chatToAdd['id'] && isset($chat['thread']) && isset($chatToAdd['thread']) && $chat['thread'] == $chatToAdd['thread'] + ) return $chats; + } + $chats[] = $chatToAdd; + return $chats; +} + +function get_config_chat_by_short_id($id) { + $chats = list_config_chats_by_short_id(); + return $chats[$id]; +} diff --git a/logic/insert_cleanup.php b/logic/insert_cleanup.php index 4835cb74..6d3f04ef 100644 --- a/logic/insert_cleanup.php +++ b/logic/insert_cleanup.php @@ -1,18 +1,20 @@ $raid_id, ':chat_id' => $chat_id, ':message_id' => $message_id, + ':thread_id' => $thread_id, ':type' => $type, ':media_unique_id' => $photo_id, ] diff --git a/logic/insert_overview.php b/logic/insert_overview.php index dedbcfc8..60a6b553 100644 --- a/logic/insert_overview.php +++ b/logic/insert_overview.php @@ -1,12 +1,13 @@ $chat_id, 'message_id' => $message_id, + 'thread_id' => $thread_id, 'chat_title' => $chat_title, 'chat_username' => $chat_username, ] diff --git a/logic/insert_trainerinfo.php b/logic/insert_trainerinfo.php index f485d682..351a4dd6 100644 --- a/logic/insert_trainerinfo.php +++ b/logic/insert_trainerinfo.php @@ -1,10 +1,11 @@ RAID_PICTURE_HIDE_LEVEL); @@ -120,8 +121,8 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f $media_content = get_raid_picture($raid, true); $raid['standalone_photo'] = true; // Inject this into raid array so we can pass it all the way to photo cache // Resend raid poll as text message. - send_photo($chat, $media_content[1], $media_content[0], '', [], [], false, $raid); - send_message($chat, $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); + send_photo(create_chat_object([$chat, $thread_id]), $media_content[1], $media_content[0], '', [], [], false, $raid); + send_message(create_chat_object([$chat, $thread_id]), $text['full'], $keys, ['disable_web_page_preview' => 'true'], false, $raid_id); continue; } $media_content = get_raid_picture($raid); diff --git a/mods/refresh_polls.php b/mods/refresh_polls.php index c0179c46..acac4e23 100644 --- a/mods/refresh_polls.php +++ b/mods/refresh_polls.php @@ -8,7 +8,7 @@ if(strlen($data['id']) > 5) $where_chat = 'chat_id = '.$data['id']; else $where_chat = 'chat_id != 0'; if(!empty($config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL)) $level_exclude = 'AND raids.level NOT IN ('.$config->RAID_POLL_HIDE_BUTTONS_RAID_LEVEL.')'; else $level_exclude = ''; $query_messages = my_query(' - SELECT cleanup.raid_id, cleanup.chat_id, cleanup.message_id, cleanup.type, cleanup.media_unique_id + SELECT cleanup.raid_id, cleanup.chat_id, cleanup.thread_id, cleanup.message_id, cleanup.type, cleanup.media_unique_id FROM cleanup LEFT JOIN raids ON cleanup.raid_id = raids.id diff --git a/mods/trainer_add.php b/mods/trainer_add.php index d335bc01..d83ac3f0 100644 --- a/mods/trainer_add.php +++ b/mods/trainer_add.php @@ -1,6 +1,7 @@ TRAINER_CHATS ? -if(!empty($config->TRAINER_CHATS)) { - $chat_list = $config->TRAINER_CHATS; - debug_log($chat_list, 'Added trainer chats to the chat list:'); -} - -// $config->SHARE_CHATS ? -if(!empty($config->SHARE_CHATS) && !empty($chat_list)) { - $chat_list .= ',' . $config->SHARE_CHATS; - debug_log($chat_list, 'Added share chats to the chat list:'); -} else if(!empty($config->SHARE_CHATS) && empty($chat_list)) { - $chat_list = $config->SHARE_CHATS; - debug_log($chat_list, 'Added share chats to the chat list:'); -} - -// Get chats from config and add to keys. -for($i = 1; $i <= 10; $i++) { - // Raid level adjustment - if($i == 10) { - $raid_level = 'X'; - } else { - $raid_level = $i; - } - $const = 'SHARE_CHATS_LEVEL_' . $raid_level; - $const_chats = $config->{$const}; - - // Sharing keys for this raid level? - if(!empty($const_chats)) { - debug_log('Found chats by level, adding them'); - // Add chats. - if(!empty($chat_list)) { - $chat_list .= ',' . $const_chats; - debug_log($chat_list, 'Added ' . $const . ' chats to the chat list:'); - } else { - $chat_list = $const_chats; - debug_log($chat_list, 'Added ' . $const . ' chats to the chat list:'); - } - } -} - -// Delete duplicate chats. -debug_log($chat_list, 'Searching and removing duplicates from chat list:'); -$chat_list = explode(',', $chat_list); -$chats = array_unique($chat_list); +$chats = list_config_chats_by_short_id(); // Get chats already in the database. debug_log('Searching and removing chats already having the trainer message'); $rs = my_query(' - SELECT chat_id + SELECT chat_id, thread_id FROM trainerinfo '); -$chats_db = []; -while ($row = $rs->fetch()) { - $chats_db[] = $row['chat_id']; +$chats_db = $rs->fetchAll(); +for($i=0;$i $chat) { + // Get chat object + debug_log("Getting chat object for '" . $chat['id'] . "'"); + $chat_obj = get_chat($chat['id']); + + // Check chat object for proper response. + if ($chat_obj['ok'] != true) { + info_log($chat, 'Invalid chat id in your configuration:'); + continue; + } + $chatTitle = $chat['title'] ?? $chat_obj['result']['title']; + debug_log('Proper chat object received, continuing to add key for this chat: ' . $chatTitle); + $shareData = [0 => 'trainer_share', 'c' => $chatShortId]; + $keys[][] = button(getTranslation('share_with') . ' ' . $chatTitle, $shareData); } // Add abort key. diff --git a/mods/trainer_share.php b/mods/trainer_share.php index 0f4d3156..8433890d 100644 --- a/mods/trainer_share.php +++ b/mods/trainer_share.php @@ -3,6 +3,7 @@ debug_log('trainer_share()'); require_once(LOGIC_PATH . '/keys_trainerinfo.php'); require_once(LOGIC_PATH . '/show_trainerinfo.php'); +require_once(LOGIC_PATH . '/config_chats.php'); // For debug. //debug_log($update); @@ -11,8 +12,8 @@ // Access check. $botUser->accessCheck('trainer-share'); -// Get chat id. -$chat = $data['c']; +// Get chat object by chat short id +$chat = get_config_chat_by_short_id($data['c']); // Get text and keys. $text = show_trainerinfo($update); diff --git a/sql/pokemon-raid-bot.sql b/sql/pokemon-raid-bot.sql index 69cc460c..ee7ad515 100644 --- a/sql/pokemon-raid-bot.sql +++ b/sql/pokemon-raid-bot.sql @@ -23,6 +23,7 @@ CREATE TABLE `cleanup` ( `raid_id` int(10) unsigned NOT NULL, `chat_id` bigint(20) NOT NULL, `message_id` bigint(20) unsigned NOT NULL, + `thread_id` int(10) UNSIGNED NULL, `type` VARCHAR(20) NULL, `date_of_posting` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `media_unique_id` varchar(45) DEFAULT NULL, @@ -61,6 +62,7 @@ CREATE TABLE `overview` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `chat_id` bigint(20) NOT NULL, `message_id` bigint(20) unsigned NOT NULL, + `thread_id` int(10) UNSIGNED NULL, `chat_title` varchar(128) DEFAULT NULL, `chat_username` varchar(32) DEFAULT NULL, `updated` date DEFAULT NULL, @@ -131,6 +133,7 @@ CREATE TABLE `trainerinfo` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `chat_id` bigint(20) NOT NULL, `message_id` bigint(20) unsigned NOT NULL, + `thread_id` int(10) UNSIGNED NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `user_input` ( diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index 5e8e717e..3aa0ab5a 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -7,8 +7,13 @@ ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `end_time` DATETIME DEFAULT N ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `start_time` DATETIME DEFAULT NULL AFTER `end_time`; ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; +ALTER TABLE `cleanup` ADD COLUMN `thread_id` INT UNSIGNED NULL AFTER `message_id`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); +ALTER TABLE `overview` ADD COLUMN `thread_id` INT UNSIGNED NULL AFTER `message_id`; + +ALTER TABLE `trainerinfo` ADD COLUMN `thread_id` INT UNSIGNED NULL AFTER `message_id`; + ALTER TABLE `raids` CHANGE COLUMN IF EXISTS `level` `level` TINYINT UNSIGNED DEFAULT NULL; ALTER TABLE `raid_bosses` CHANGE COLUMN IF EXISTS `raid_level` `raid_level` TINYINT UNSIGNED DEFAULT NULL; From 24056065ba27a8e0b4dcf09fb2547bbdf69f03ad Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 12 Feb 2024 22:05:37 +0200 Subject: [PATCH 311/367] Again I forgot if not exists --- sql/upgrade/5.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/upgrade/5.sql b/sql/upgrade/5.sql index 3aa0ab5a..ef26c0fb 100644 --- a/sql/upgrade/5.sql +++ b/sql/upgrade/5.sql @@ -7,12 +7,12 @@ ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `end_time` DATETIME DEFAULT N ALTER TABLE `photo_cache` ADD COLUMN IF NOT EXISTS `start_time` DATETIME DEFAULT NULL AFTER `end_time`; ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `media_unique_id` varchar(45) DEFAULT NULL AFTER `date_of_posting`; -ALTER TABLE `cleanup` ADD COLUMN `thread_id` INT UNSIGNED NULL AFTER `message_id`; +ALTER TABLE `cleanup` ADD COLUMN IF NOT EXISTS `thread_id` INT UNSIGNED NULL AFTER `message_id`; CREATE UNIQUE INDEX IF NOT EXISTS `unique_chat_msg` ON `cleanup` (chat_id, message_id); -ALTER TABLE `overview` ADD COLUMN `thread_id` INT UNSIGNED NULL AFTER `message_id`; +ALTER TABLE `overview` ADD COLUMN IF NOT EXISTS `thread_id` INT UNSIGNED NULL AFTER `message_id`; -ALTER TABLE `trainerinfo` ADD COLUMN `thread_id` INT UNSIGNED NULL AFTER `message_id`; +ALTER TABLE `trainerinfo` ADD COLUMN IF NOT EXISTS `thread_id` INT UNSIGNED NULL AFTER `message_id`; ALTER TABLE `raids` CHANGE COLUMN IF EXISTS `level` `level` TINYINT UNSIGNED DEFAULT NULL; ALTER TABLE `raid_bosses` CHANGE COLUMN IF EXISTS `raid_level` `raid_level` TINYINT UNSIGNED DEFAULT NULL; From abeb5c2bb2e6dff8e16655d0b0fc820af027f98d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 13 Feb 2024 20:26:57 +0200 Subject: [PATCH 312/367] Renamed variable for consistency --- mods/trainer_share.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/trainer_share.php b/mods/trainer_share.php index 8433890d..c1ac5ca4 100644 --- a/mods/trainer_share.php +++ b/mods/trainer_share.php @@ -13,7 +13,7 @@ $botUser->accessCheck('trainer-share'); // Get chat object by chat short id -$chat = get_config_chat_by_short_id($data['c']); +$chatObj = get_config_chat_by_short_id($data['c']); // Get text and keys. $text = show_trainerinfo($update); @@ -23,7 +23,7 @@ $tg_json = array(); // Send the message. -$tg_json[] = send_message($chat, $text, $keys, ['disable_web_page_preview' => 'true'], true, 'trainer'); +$tg_json[] = send_message($chatObj, $text, $keys, ['disable_web_page_preview' => 'true'], true, 'trainer'); // Set callback keys and message $callback_msg = getTranslation('successfully_shared'); From 5bd74382f8ac51f9d823f99c4c49705182dffc70 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 13 Feb 2024 20:27:28 +0200 Subject: [PATCH 313/367] Added thread support to overview management --- commands/overview.php | 1 + logic/config_chats.php | 7 +++ logic/insert_overview.php | 10 +++- mods/overview_delete.php | 54 ++++++++++---------- mods/overview_share.php | 102 ++++++++++++++++++++------------------ 5 files changed, 98 insertions(+), 76 deletions(-) diff --git a/commands/overview.php b/commands/overview.php index 4aca3d1c..cb60f82d 100644 --- a/commands/overview.php +++ b/commands/overview.php @@ -12,6 +12,7 @@ // Create keys array. $keys[][] = button(getTranslation('overview_share'), 'overview_share'); $keys[][] = button(getTranslation('overview_delete'), 'overview_delete'); +$keys[][] = button(getTranslation('abort'), ['exit', 'd' => '0']); // Set message. $msg = '' . getTranslation('raids_share_overview') . ':'; diff --git a/logic/config_chats.php b/logic/config_chats.php index 820a1ddf..7220c76d 100644 --- a/logic/config_chats.php +++ b/logic/config_chats.php @@ -60,6 +60,13 @@ function list_config_chats_by_short_id() { return $chats; } +function get_config_chat_by_chat_and_thread_id($chat_id, $thread_id) { + foreach(list_config_chats_by_short_id() as $chat) { + if($chat['id'] == $chat_id && ($thread_id == NULL && !isset($chat['thread']) || (isset($chat['thread']) && $chat['thread'] == $thread_id))) + return $chat; + } +} + function add_chat($chats, $chatToAdd) { foreach($chats as $chat) { if( diff --git a/logic/insert_overview.php b/logic/insert_overview.php index 60a6b553..425c4106 100644 --- a/logic/insert_overview.php +++ b/logic/insert_overview.php @@ -10,11 +10,19 @@ function insert_overview($chat_id, $message_id, $thread_id, $chat_title, $chat_username) { // Build query to check if overview details are already in database or not + $binds = [$chat_id]; + $threadQuery = ' = ?'; + if(!isset($thread_id)) { + $threadQuery = 'IS NULL'; + }else { + $binds[] = $thread_id; + } $rs = my_query(' SELECT COUNT(*) AS count FROM overview WHERE chat_id = ? - ', [$chat_id] + AND thread_id ' . $threadQuery . ' + ', $binds ); $row = $rs->fetch(); diff --git a/mods/overview_delete.php b/mods/overview_delete.php index a36b8573..ed20c4a8 100644 --- a/mods/overview_delete.php +++ b/mods/overview_delete.php @@ -1,13 +1,15 @@ accessCheck('overview'); @@ -16,63 +18,61 @@ $tg_json = array(); // Get all or specific overview -if ($chat_id == 0) { +if ($action == 0) { $request_overviews = my_query(' SELECT * FROM overview '); - // Count results. - $count = 0; - while ($rowOverviews = $request_overviews->fetch()) { - // Counter++ - $count = $count + 1; // Get info about chat for title. debug_log('Getting chat object for chat_id: ' . $rowOverviews['chat_id']); - $chat_obj = get_chat($rowOverviews['chat_id']); - $chat_title = ''; - - // Set title. - if ($chat_obj['ok'] == 'true') { - $chat_title = $chat_obj['result']['title']; - debug_log('Title of the chat: ' . $chat_obj['result']['title']); + $chat_obj = get_config_chat_by_chat_and_thread_id($rowOverviews['chat_id'], $rowOverviews['thread_id']); + if(!isset($chat_obj['title'])) { + $chat_info = get_chat($rowOverviews['chat_id']); + $chat_title = ''; + + // Set title. + if ($chat_info['ok'] == 'true') { + $chat_title = $chat_info['result']['title']; + debug_log('Title of the chat: ' . $chat_info['result']['title']); + } + }else { + $chat_title = $chat_obj['title']; } // Build message string. $msg = '' . getTranslation('delete_raid_overview_for_chat') . ' ' . $chat_title . '?'; // Set keys - Delete button. - $keys[0][0] = button(getTranslation('yes'), ['overview_delete', 'c' => $rowOverviews['chat_id']]); - $keys[0][1] = button(getTranslation('no'), ['overview_delete', 'c' => 1]); + $keys[0][0] = button(getTranslation('yes'), ['overview_delete', 'o' => $rowOverviews['id'], 'a' => 3]); + $keys[0][1] = button(getTranslation('no'), ['overview_delete', 'a' => 1]); // Send the message, but disable the web preview! - $tg_json[] = send_message($update['callback_query']['message']['chat']['id'], $msg, $keys, false, true); + $tg_json[] = send_message(create_chat_object([$update['callback_query']['message']['chat']['id']]), $msg, $keys, false, true); } // Set message. - if($count == 0) { + if($request_overviews->rowCount() == 0) { $callback_msg = '' . getTranslation('no_overviews_found') . ''; } else { $callback_msg = '' . getTranslation('list_all_overviews') . ':'; } -} else if ($chat_id == 1) { +} else if ($action == 1) { // Write to log. debug_log('Deletion of the raid overview was canceled!'); // Set message. $callback_msg = '' . getTranslation('overview_deletion_was_canceled') . ''; } else { - // Write to log. - debug_log('Triggering deletion of overview for Chat_ID ' . $chat_id); // Get chat and message ids for overview. $request_overviews = my_query(' SELECT * FROM overview - WHERE chat_id = ? - ', [$chat_id] + WHERE id = ? + ', [$overview_id] ); $overview = $request_overviews->fetch(); @@ -80,17 +80,19 @@ // Delete overview $chat_id = $overview['chat_id']; $message_id = $overview['message_id']; + // Write to log. + debug_log('Triggering deletion of overview for Chat_ID ' . $chat_id); // Delete telegram message. debug_log('Deleting overview telegram message ' . $message_id . ' from chat ' . $chat_id); delete_message($chat_id, $message_id); // Delete overview from database. - debug_log('Deleting overview information from database for Chat_ID: ' . $chat_id); + debug_log('Deleting overview information from database for Chat_ID: ' . $chat_id . ', thread_id: ' . $overview['thread_id']); $rs = my_query(' DELETE FROM overview - WHERE chat_id = ? - ', [$chat_id] + WHERE id = ? + ', [$overview_id] ); // Set message. diff --git a/mods/overview_share.php b/mods/overview_share.php index 9db31363..047db516 100644 --- a/mods/overview_share.php +++ b/mods/overview_share.php @@ -3,6 +3,7 @@ debug_log('overview_share()'); require_once(LOGIC_PATH . '/get_chat_title_username.php'); require_once(LOGIC_PATH . '/get_overview.php'); +require_once(LOGIC_PATH . '/config_chats.php'); // For debug. //debug_log($update); @@ -12,38 +13,41 @@ $botUser->accessCheck('overview'); // Get chat ID from data -$chat_id = $data['c'] ?? 0; - -// Get all or specific overview -$query_chat = ''; -if ($chat_id != 0) { - $query_chat = 'AND chat_id = \'' . $chat_id . '\''; -} -// Get active raids. -$request_active_raids = my_query(' - SELECT - cleanup.chat_id, cleanup.message_id, - raids.*, - gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, - TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left - FROM cleanup - LEFT JOIN raids - ON raids.id = cleanup.raid_id - LEFT JOIN gyms - ON raids.gym_id = gyms.id - WHERE raids.end_time>UTC_TIMESTAMP() - ' . $query_chat . ' - ORDER BY cleanup.chat_id, raids.end_time ASC, gyms.gym_name -'); -// Collect results in an array -$active_raids = $request_active_raids->fetchAll(PDO::FETCH_GROUP); +$chat_id = $data['c'] ?? NULL; $tg_json = []; // Share an overview -if($chat_id != 0) { - [$chat_title, $chat_username] = get_chat_title_username($chat_id); - $overview_message = get_overview($active_raids[$chat_id], $chat_title, $chat_username); +if($chat_id != NULL) { + $query_chat = ''; + $chatObj = get_config_chat_by_short_id($chat_id); + $query_chat = 'AND chat_id = ?'; + $binds[] = $chatObj['id']; + if(isset($chatObj['thread'])) { + $query_chat .= ' AND thread_id = ?'; + $binds[] = $chatObj['thread']; + } + // Get active raids. + $request_active_raids = my_query(' + SELECT + cleanup.chat_id, cleanup.thread_id, cleanup.message_id, + raids.*, + gyms.lat, gyms.lon, gyms.address, gyms.gym_name, gyms.ex_gym, + TIME_FORMAT(TIMEDIFF(end_time, UTC_TIMESTAMP()) + INTERVAL 1 MINUTE, \'%k:%i\') AS t_left + FROM cleanup + LEFT JOIN raids + ON raids.id = cleanup.raid_id + LEFT JOIN gyms + ON raids.gym_id = gyms.id + WHERE raids.end_time>UTC_TIMESTAMP() + ' . $query_chat . ' + ORDER BY cleanup.chat_id, raids.end_time ASC, gyms.gym_name + ', $binds); + // Collect results in an array + $active_raids = $request_active_raids->fetchAll(); + [$chat_title, $chat_username] = get_chat_title_username($chatObj['id']); + $title = $chatObj['title'] ?? $chat_title; + $overview_message = get_overview($active_raids, $title, $chat_username); // Shared overview $keys = []; @@ -57,47 +61,47 @@ $tg_json[] = edit_message($update, $msg_callback, $keys, ['disable_web_page_preview' => 'true'], true); // Send the message, but disable the web preview! - $tg_json[] = send_message($chat_id, $overview_message, $keys, ['disable_web_page_preview' => 'true'], true, 'overview'); + $tg_json[] = send_message($chatObj, $overview_message, $keys, ['disable_web_page_preview' => 'true'], true, 'overview'); // Telegram multicurl request. curl_json_multi_request($tg_json); exit; } +$keys = []; // List all overviews to user -foreach( array_keys($active_raids) as $chat_id ) { +foreach( list_config_chats_by_short_id() as $short_id => $chat ) { + $binds = [$chat['id']]; + $threadQuery = ' = ?'; + if(!isset($chat['thread'])) { + $threadQuery = 'IS NULL'; + }else { + $binds[] = $chat['thread']; + } // Make sure it's not already shared $rs = my_query(' - SELECT chat_id, message_id, chat_title, chat_username + SELECT chat_id, thread_id, message_id, chat_title, chat_username FROM overview WHERE chat_id = ? + AND thread_id ' . $threadQuery . ' LIMIT 1 - ', [$chat_id] + ', $binds ); - $keys = []; // Already shared - if($rs->rowCount() > 0 ) { - $keys[0][] = button(EMOJI_REFRESH, ['overview_refresh', 'c' => $chat_id]); - $keys[0][] = button(getTranslation('done'), ['exit', 'd' => '1']); - $res = $rs->fetch(); - $chat_title = $res['chat_title']; - $chat_username = $res['chat_username']; - }else { - [$chat_title, $chat_username] = get_chat_title_username($chat_id); - $keys[][] = button(getTranslation('share_with') . ' ' . $chat_title, ['overview_share', 'c' => $chat_id]); - } - $overview_message = get_overview($active_raids[$chat_id], $chat_title, $chat_username); - // Send the message, but disable the web preview! - $tg_json[] = send_message($update['callback_query']['message']['chat']['id'], $overview_message, $keys, ['disable_web_page_preview' => 'true'], true); + if($rs->rowCount() > 0 ) continue; + + [$chat_title, $chat_username] = get_chat_title_username($chat['id']); + $title = $chat['title'] ?? $chat_title; + $keys[][] = button(getTranslation('share_with') . ' ' . $title, ['overview_share', 'c' => $short_id]); } // Set the callback message and keys -$callback_keys = []; -$callback_msg = '' . getTranslation('list_all_overviews') . ':'; +$msg = '' . getTranslation('list_all_overviews') . ':'; +$keys[][] = button(getTranslation('abort'), ['exit', 'd' => '0']); // Answer the callback. $tg_json[] = answerCallbackQuery($update['callback_query']['id'], 'OK', true); // Edit the message. -$tg_json[] = edit_message($update, $callback_msg, $callback_keys, false, true); +$tg_json[] = edit_message($update, $msg, $keys, false, true); // Telegram multicurl request. curl_json_multi_request($tg_json); From e521073d0aed26e10cd9b2ec0ab4ca5e1a4d2746 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 16 Feb 2024 23:52:48 +0200 Subject: [PATCH 314/367] Added fallback for thread_id --- logic/update_raid_poll.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/update_raid_poll.php b/logic/update_raid_poll.php index 885a7516..4357d518 100644 --- a/logic/update_raid_poll.php +++ b/logic/update_raid_poll.php @@ -36,7 +36,7 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f WHERE raid_id = ? ' . $photo_query,[$raid_id] ); - if ($rs_chann->rowCount() > 0) { + if ($rs_chann->rowCount() > 0 || false) { while($chat = $rs_chann->fetch()) { $chat_and_message[] = $chat; } @@ -95,7 +95,7 @@ function update_raid_poll($raid_id, $raid = false, $update = false, $tg_json = f foreach($chat_and_message as $chat_id_msg_id) { $chat = $chat_id_msg_id['chat_id']; $message = $chat_id_msg_id['message_id']; - $thread_id = $chat_id_msg_id['thread_id']; + $thread_id = $chat_id_msg_id['thread_id'] ?? null; $type = $chat_id_msg_id['type']; if ($type == 'poll_text') { $raid_picture_hide_level = explode(",",$config->RAID_PICTURE_HIDE_LEVEL); From c024a0dd10f094d8ef4a87e2a9e367abbce1cbfb Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:16:08 +0200 Subject: [PATCH 315/367] Hide the expand button This feature hasn't worked for a while and no-one probably is missing it --- mods/list_raid.php | 3 ++- mods/raids_list.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mods/list_raid.php b/mods/list_raid.php index ed49d686..c61aa52a 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -51,7 +51,8 @@ // Create keys array. $keys = []; - $keys[][] = button(getTranslation('expand'), ['vote_refresh', 'r' => $raid['id']]); + // Probably unused feature. Will fix if someone needs this + // $keys[][] = button(getTranslation('expand'), ['vote_refresh', 'r' => $raid['id']]); if($botUser->raidaccessCheck($raid['id'], 'pokemon', true)) { $keys[][] = button(getTranslation('update_pokemon'), ['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]); } diff --git a/mods/raids_list.php b/mods/raids_list.php index ce4dddb7..1bb602c5 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -17,7 +17,8 @@ $raid = get_raid($raidId); // Create keys array. -$keys[][] = button(getTranslation('expand'), ['vote_refresh', 'r' => $raid['id']]); +// Probably unused feature. Will fix if someone needs this +// $keys[][] = button(getTranslation('expand'), ['vote_refresh', 'r' => $raid['id']]); if($botUser->raidaccessCheck($raidId, 'pokemon', true)) { $keys[][] = button(getTranslation('update_pokemon'), ['raid_edit_poke', 'r' => $raid['id'], 'rl' => $raid['level']]); } From 5dcfef4f6e68af34ce24f7ff43c05b56bc4679eb Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:16:40 +0200 Subject: [PATCH 316/367] Fixed vote time key logic --- logic/keys_vote.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index ee784fa1..75bbd856 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -312,7 +312,8 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { debug_log($last_extra_slot, 'Last extra slot:'); // Last extra slot not conflicting with last slot - if($last_extra_slot > $last_slot && $last_extra_slot >= $dt_now && $last_extra_slot != $last_slot) { + if((isset($last_slot) && $last_extra_slot > $last_slot && $last_extra_slot != $last_slot && $last_extra_slot >= $dt_now) || + (!isset($last_slot) && $last_extra_slot >= $dt_now)) { // Add last extra slot $keys_time[] = button(dt2time($last_extra_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $last_extra_slot->format('YmdHis')]); } From 32ce9dc4ac73ba048c52f257268b58d327ca8248 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 17 Feb 2024 12:16:16 +0200 Subject: [PATCH 317/367] Backwards compatibility fixes --- commands/raid_from_webhook.php | 18 ++++++++++++------ logic/key_util.php | 2 +- mods/vote_time.php | 5 +++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/commands/raid_from_webhook.php b/commands/raid_from_webhook.php index b8abf44a..b63c668e 100644 --- a/commands/raid_from_webhook.php +++ b/commands/raid_from_webhook.php @@ -312,7 +312,7 @@ function isPointInsidePolygon($point, $vertices) { 'shadow' => (in_array($level, RAID_LEVEL_SHADOW) ? 1 : 0), ]); - $chats_geofence = $chats_raidlevel = $webhook_chats = $chats_by_pokemon = []; + $chats_geofence = $chats_raidlevel = $webhook_chats = $chats_by_pokemon = $chats = []; if($send_updates == true) { // Update raid polls and send alerts of updates require_once(LOGIC_PATH .'/update_raid_poll.php'); @@ -320,14 +320,14 @@ function isPointInsidePolygon($point, $vertices) { if($wasBossUpdated) $tg_json = alarm($raid, false, 'new_boss', '', $tg_json); // Post hatched Pokemon to their respective chats if configured // Start share_chats backwards compatibility - if(!$config->CHATS_SHARE) { + if(!isset($config->CHATS_SHARE)) { if(!empty($config->WEBHOOK_CHATS_BY_POKEMON[0]) && !$no_auto_posting) { foreach($config->WEBHOOK_CHATS_BY_POKEMON as $rule) { if(isset($rule['pokemon_id']) && $rule['pokemon_id'] == $pokemon && (!isset($rule['form_id']) or (isset($rule['form_id']) && $rule['form_id'] == $form))) { foreach($rule['chats'] as $rule_chat) { // If the raid isn't already posted to the chats specified in WEBHOOK_CHATS_BY_POKEMON, we add it to the array if(!isset($cleanup_data[$raid_id]) or !in_array($rule_chat, $cleanup_data[$raid_id])) { - $chats_by_pokemon[] = $rule_chat; + $chats_by_pokemon[] = create_chat_object([$rule_chat]); } } } @@ -351,7 +351,7 @@ function isPointInsidePolygon($point, $vertices) { if(empty($chats_by_pokemon)) continue; }else { // Start share_chats backwards compatibility - if(!$config->CHATS_SHARE) { + if(!isset($config->CHATS_SHARE)) { // Get chats to share to by raid level and geofence id if($geofences != false) { foreach($inside_geofences as $geofence_id) { @@ -376,7 +376,11 @@ function isPointInsidePolygon($point, $vertices) { if(!empty($config->WEBHOOK_CHATS_ALL_LEVELS)) { $webhook_chats = explode(',', $config->WEBHOOK_CHATS_ALL_LEVELS); } - // End chats_share backwards compatibility + $chats_combined = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats); + foreach($chats_combined as $chat) { + $chats[] = create_chat_object([$chat]); + } + // End chats_share backwards compatibility }else { if($geofences != false) { foreach($inside_geofences as $geofence_id) { @@ -396,16 +400,18 @@ function isPointInsidePolygon($point, $vertices) { // Get chats $webhook_chats = $config->CHATS_SHARE['webhook']['all'] ?? []; + $chats = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats); } } - $chats = array_merge($chats_geofence, $chats_raidlevel, $webhook_chats, $chats_by_pokemon); require_once(LOGIC_PATH .'/send_raid_poll.php'); if($metrics) { $webhook_raids_posted_total->inc(); } if(count($chats) > 0) { $tg_json = send_raid_poll($raid_id, $chats, $raid, $tg_json); + }elseif(count($chats_by_pokemon) > 0) { + $tg_json = send_raid_poll($raid_id, $chats_by_pokemon, $raid, $tg_json); } } // Telegram multicurl request. diff --git a/logic/key_util.php b/logic/key_util.php index cd8518e5..775eeabb 100644 --- a/logic/key_util.php +++ b/logic/key_util.php @@ -51,7 +51,7 @@ function share_keys($id, $action, $update, $raidLevel = '', $chats = [], $hideGe } // Start share_chats backwards compatibility - if(!$config->CHATS_SHARE) { + if(!isset($config->CHATS_SHARE)) { // Add buttons for predefined sharing chats. // Default SHARE_CHATS or special chat list via $chats? if(empty($chats)) { diff --git a/mods/vote_time.php b/mods/vote_time.php index c20accc5..46f9c0b9 100644 --- a/mods/vote_time.php +++ b/mods/vote_time.php @@ -159,11 +159,12 @@ // Check if RAID has no participants AND Raid should be shared to another chat at first participant // AND target chat was set in config AND Raid was not shared to target chat before // Start share_chats backwards compatibility - if(!$config->CHATS_SHARE) { + if(!isset($config->CHATS_SHARE)) { if($count_att == 0 && $config->SHARE_AFTER_ATTENDANCE && !empty($config->SHARE_CHATS_AFTER_ATTENDANCE)){ // Send the message. require_once(LOGIC_PATH . '/send_raid_poll.php'); - $tg_json = send_raid_poll($raidId, $config->SHARE_CHATS_AFTER_ATTENDANCE, $raid, $tg_json); + $chats = [create_chat_object([$config->SHARE_CHATS_AFTER_ATTENDANCE])]; + $tg_json = send_raid_poll($raidId, $chats, $raid, $tg_json); } // End share_chats backwards compatibility }else { From 2a842aaf4ad8adb3538c43a34cc119584b718f90 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 20 Feb 2024 18:41:22 +0200 Subject: [PATCH 318/367] Switched to using mb_convert_encoding --- logic/gymMenu.php | 6 +++--- logic/raid_picture.php | 4 ++-- mods/history.php | 2 +- mods/history_gyms.php | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/logic/gymMenu.php b/logic/gymMenu.php index b6192dd6..77336070 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -172,7 +172,7 @@ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $s $letter = trim($letter); debug_log($letter, 'Special gym letter:'); // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); + $length = strlen(mb_convert_encoding($letter, 'ISO-8859-1')); $select .= SP . 'WHEN UPPER(LEFT(gym_name, ' . $length . ')) = \'' . $letter . '\' THEN UPPER(LEFT(gym_name, ' . $length . '))' . SP; } $select .= 'ELSE UPPER(LEFT(gym_name, 1)) END AS first_letter'; @@ -205,7 +205,7 @@ function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery global $config, $menuActions, $botUser; // Length of first letter. // Fix chinese chars, prior: $first_length = strlen($first); - $first_length = strlen(utf8_decode($firstLetter)); + $first_length = strlen(mb_convert_encoding($firstLetter, 'ISO-8859-1')); // Special/Custom gym letters? $not = ''; @@ -218,7 +218,7 @@ function createGymListKeysByFirstLetter($firstLetter, $showHidden, $gymareaQuery $letter = trim($letter); debug_log($letter, 'Special gym letter:'); // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); + $length = strlen(mb_convert_encoding($letter, 'ISO-8859-1')); $not .= SP . 'AND UPPER(LEFT(gym_name, ' . $length . ')) != UPPER(\'' . $letter . '\')' . SP; } } diff --git a/logic/raid_picture.php b/logic/raid_picture.php index 28598e8a..ee001997 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -415,11 +415,11 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Gym name // Largest gym name we found so far for testing: //$gym_name = 'Zentrum für Junge Erwachsene der Kirche Jesu Christi der Heiligen der Letzten Tage Pfahl Düsseldorf'; - $gym_name = $raid['gym_name']; + $gym_name = mb_convert_encoding($raid['gym_name'], 'ISO-8859-1'); // Get length, the shortest and largest word of the gym name $gym_name_words = explode(SP, $gym_name); - $gym_name_word_lengths = array_map('strlen', array_map('utf8_decode', $gym_name_words)); + $gym_name_word_lengths = array_map('strlen', $gym_name_words); $gym_name_word_largest = max($gym_name_word_lengths); $gym_name_total_chars = strlen(mb_convert_encoding($gym_name, 'ISO-8859-1', 'UTF-8')); diff --git a/mods/history.php b/mods/history.php index 539ab9fc..331beee3 100644 --- a/mods/history.php +++ b/mods/history.php @@ -34,7 +34,7 @@ $letter = trim($letter); debug_log($letter, 'Special gym letter:'); // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); + $length = strlen(mb_convert_encoding($letter, 'ISO-8859-1')); $select_query .= SP . "WHEN UPPER(LEFT(gym_name, " . $length . ")) = '" . $letter . "' THEN UPPER(LEFT(gym_name, " . $length . "))" . SP; } $select_query .= 'ELSE UPPER(LEFT(gym_name, 1)) END'; diff --git a/mods/history_gyms.php b/mods/history_gyms.php index f0c028e5..ebea6a5d 100644 --- a/mods/history_gyms.php +++ b/mods/history_gyms.php @@ -20,7 +20,7 @@ // Length of first letter. // Fix chinese chars, prior: $first_length = strlen($first); -$first_length = strlen(utf8_decode($first)); +$first_length = strlen(mb_convert_encoding($first, 'ISO-8859-1')); // Special/Custom gym letters? $not = ''; @@ -33,7 +33,7 @@ $letter = trim($letter); debug_log($letter, 'Special gym letter:'); // Fix chinese chars, prior: $length = strlen($letter); - $length = strlen(utf8_decode($letter)); + $length = strlen(mb_convert_encoding($letter, 'ISO-8859-1')); $not .= SP . "AND UPPER(LEFT(gym_name, " . $length . ")) != UPPER('" . $letter . "')" . SP; } } From f8e78140e9245894a7c432c5cfd95e241dc13beb Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 20 Feb 2024 20:21:05 +0200 Subject: [PATCH 319/367] Fixed cleanup logic --- core/bot/cleanup_collect.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/bot/cleanup_collect.php b/core/bot/cleanup_collect.php index 92beb425..d9e11ab6 100644 --- a/core/bot/cleanup_collect.php +++ b/core/bot/cleanup_collect.php @@ -18,12 +18,16 @@ // Get chat_id and message_id $chat_id = $message['chat']['id']; $message_id = $message['message_id']; + $thread_id = $message['message_thread_id'] ?? NULL; if(isset($message['reply_markup']['inline_keyboard'])) { $split_data = explode(':', $message['reply_markup']['inline_keyboard'][0][0]['callback_data']); $cleanup_id = $split_data[0]; }else { // Get id from text. - $cleanup_id = substr($message['text'],strpos($message['text'], substr(strtoupper($config->BOT_ID), 0, 1) . '-ID = ') + 7); + $idFromText = substr($message['text'],strpos($message['text'], substr(strtoupper($config->BOT_ID), 0, 1) . '-ID = ') + 7); + if(preg_match("^[0-9]+^", $idFromText)) { + $cleanup_id = $idFromText; + } } // Write cleanup info to database. @@ -31,6 +35,6 @@ cleanup_log('Cleanup_ID: ' . $cleanup_id); if($cleanup_id != 0) { require_once(LOGIC_PATH . '/insert_cleanup.php'); - insert_cleanup($chat_id, $message_id, $cleanup_id, 'inline_poll_text'); + insert_cleanup($chat_id, $message_id, $thread_id, $cleanup_id, 'inline_poll_text'); } } From 5afd453666331f79dd1b93d401304d2ebc49ba87 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 20 Feb 2024 20:46:45 +0200 Subject: [PATCH 320/367] More cleanup logic fixing --- core/bot/cleanup_collect.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/core/bot/cleanup_collect.php b/core/bot/cleanup_collect.php index d9e11ab6..68364e53 100644 --- a/core/bot/cleanup_collect.php +++ b/core/bot/cleanup_collect.php @@ -20,8 +20,15 @@ $message_id = $message['message_id']; $thread_id = $message['message_thread_id'] ?? NULL; if(isset($message['reply_markup']['inline_keyboard'])) { - $split_data = explode(':', $message['reply_markup']['inline_keyboard'][0][0]['callback_data']); - $cleanup_id = $split_data[0]; + $splitData = explode('|', $message['reply_markup']['inline_keyboard'][0][0]['callback_data']); + // Search for raid id in the first button of the message + for($i=1;$iBOT_ID), 0, 1) . '-ID = ') + 7); @@ -31,9 +38,9 @@ } // Write cleanup info to database. - cleanup_log('Calling cleanup preparation now!'); - cleanup_log('Cleanup_ID: ' . $cleanup_id); if($cleanup_id != 0) { + cleanup_log('Calling cleanup preparation now!'); + cleanup_log('Cleanup_ID: ' . $cleanup_id); require_once(LOGIC_PATH . '/insert_cleanup.php'); insert_cleanup($chat_id, $message_id, $thread_id, $cleanup_id, 'inline_poll_text'); } From 797b0256f8c000f23dee9725ea4dd7a5de670e75 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:37:08 +0200 Subject: [PATCH 321/367] Use actual null --- logic/collectCleanup.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/collectCleanup.php b/logic/collectCleanup.php index 719905b6..b6a321a5 100644 --- a/logic/collectCleanup.php +++ b/logic/collectCleanup.php @@ -67,8 +67,8 @@ function collectCleanup($response, $request, $identifier = false) ':form_id' => $identifier['pokemon_form'], ':raid_id' => ($identifier['raid_ended'] ? 0 : $identifier['id']), // No need to save raid id if raid has ended ':ended' => $identifier['raid_ended'], - ':start_time' => ($identifier['raid_ended'] ? 'NULL' : $identifier['start_time']), - ':end_time' => ($identifier['raid_ended'] ? 'NULL' : $identifier['end_time']), + ':start_time' => ($identifier['raid_ended'] ? NULL : $identifier['start_time']), + ':end_time' => ($identifier['raid_ended'] ? NULL : $identifier['end_time']), ':gym_id' => $identifier['gym_id'], ':standalone' => $standalone_photo, ] From b826f649f45ece3c50e6afdbd9998ad533ba920d Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:55:59 +0200 Subject: [PATCH 322/367] Backwards compatibility fixes --- logic/config_chats.php | 13 ++++++++----- mods/overview_share.php | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/logic/config_chats.php b/logic/config_chats.php index 7220c76d..468a4894 100644 --- a/logic/config_chats.php +++ b/logic/config_chats.php @@ -5,19 +5,22 @@ function list_config_chats_by_short_id() { if(!isset($config->CHATS_SHARE)) { $chat_vars = ['TRAINER_CHATS','SHARE_CHATS','WEBHOOK_CHATS']; $chatsTemp = []; - foreach(array_keys($config) as $var) { + foreach(get_object_vars($config) as $var => $value) { foreach($chat_vars as $start) { - if(!strpos($var, $start)) continue; + if(!is_string($var) || strpos(trim($var), $start) === false) continue; + if($var == 'WEBHOOK_CHATS_BY_POKEMON') continue; if(is_string($config->{$var})) { array_merge($chatsTemp, explode(',', $config->{$var})); continue; + }elseif(is_int($config->{$var})) { + $chatsTemp[] = $config->{$var}; + continue; } array_merge($chatsTemp, $config->{$var}); } } - $chats = []; - foreach($chatsTemp as $chat) { - $chats[] = create_chat_object($chat); + foreach(array_unique($chatsTemp) as $chat) { + $chats[] = create_chat_object([$chat]); } }else { $chats = []; diff --git a/mods/overview_share.php b/mods/overview_share.php index 047db516..6bc7d2ee 100644 --- a/mods/overview_share.php +++ b/mods/overview_share.php @@ -72,7 +72,7 @@ foreach( list_config_chats_by_short_id() as $short_id => $chat ) { $binds = [$chat['id']]; $threadQuery = ' = ?'; - if(!isset($chat['thread'])) { + if(!isset($chat['thread']) or $chat['thread'] == 0) { $threadQuery = 'IS NULL'; }else { $binds[] = $chat['thread']; From 06aa625e922ed8e15b3df837cbdf1d5c588eb5ee Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:49:27 +0200 Subject: [PATCH 323/367] Improved pokemon name lookup logic --- logic/get_pokemon_id_by_name.php | 69 +++++++++++++++--------------- logic/resolve_boss_name_to_ids.php | 2 +- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/logic/get_pokemon_id_by_name.php b/logic/get_pokemon_id_by_name.php index 7e2057be..12a53c92 100644 --- a/logic/get_pokemon_id_by_name.php +++ b/logic/get_pokemon_id_by_name.php @@ -1,23 +1,50 @@ $pokemon_name, 'form_name' => '%'.$pokemon_form_name.'%'] + ); + $pokemon_form_id = 0; + if($query->rowCount() > 0) { + $res = $query->fetch(); + $pokemon_form_id = $res['pokemon_form_id']; + $pokemon_id = $res['pokedex_id']; + } + // Write to log. + debug_log($pokemon_id,'P:'); + debug_log($pokemon_form_name.' (ID: '.$pokemon_form_id.')','P:'); + + // Return pokemon_id and pokemon_form_id + return [$pokemon_id, $pokemon_form_id]; + } debug_log($pokemon_name,'P:'); // Explode pokemon name in case we have a form too. $delimiter = ''; - if(strpos($pokemon_name, ' ') !== false) { - $delimiter = ' '; - } else if (strpos($pokemon_name, '-') !== false) { + if (strpos($pokemon_name, '-') !== false) { $delimiter = '-'; } else if (strpos($pokemon_name, ',') !== false) { $delimiter = ','; + } else if (strpos($pokemon_name, '_') !== false) { + $delimiter = '_'; } // Explode if delimiter was found. @@ -33,37 +60,11 @@ function get_pokemon_id_by_name($pokemon_name, $get_from_db = false) debug_log($poke_form,'P FORM:'); } - // Init id and write name to search to log. - $pokemon_id = 0; - $pokemon_form = ($poke_form!="")?$poke_form:"normal"; + $pokemon_form = ($poke_form != "") ? $poke_form : "normal"; // Set language $language = $botUser->userLanguage; - if($get_from_db) { - // Fetch Pokemon form ID from database - $query = my_query(' - SELECT pokedex_id, pokemon_form_id - FROM pokemon - WHERE pokemon_name = :poke_name - AND pokemon_form_name LIKE :form_name - LIMIT 1 - ', ['poke_name' => $poke_name, 'form_name' => '%'.$pokemon_form.'%'] - ); - $pokemon_form_id = 0; - if($query->rowCount() > 0) { - $res = $query->fetch(); - $pokemon_form_id = $res['pokemon_form_id']; - $pokemon_id = $res['pokedex_id']; - } - // Write to log. - debug_log($pokemon_id,'P:'); - debug_log($pokemon_form.' (ID: '.$pokemon_form_id.')','P:'); - - // Return pokemon_id and pokemon_form_id - return [$pokemon_id, $pokemon_form_id]; - } - // Get translation file $str = file_get_contents(BOT_LANG_PATH . '/pokemon.json'); $json = json_decode($str, true); diff --git a/logic/resolve_boss_name_to_ids.php b/logic/resolve_boss_name_to_ids.php index 48ae9dd3..25f2da5f 100644 --- a/logic/resolve_boss_name_to_ids.php +++ b/logic/resolve_boss_name_to_ids.php @@ -22,5 +22,5 @@ function resolve_boss_name_to_ids($pokemon_name) { } // Get ID and form name used internally. debug_log('Getting dex id and form for pokemon ' . $name . ' with form ' . $form); - return get_pokemon_id_by_name($name . ' ' . $form, true); + return get_pokemon_id_by_name($name, $form, true); } From f9e6ff6bf63cdf1b8111c06693eac2b5ff7e2d03 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 3 Mar 2024 16:29:03 +0200 Subject: [PATCH 324/367] Set description to empty by default --- mods/events_add.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/events_add.php b/mods/events_add.php index 17a70ab6..932878ad 100644 --- a/mods/events_add.php +++ b/mods/events_add.php @@ -17,7 +17,7 @@ if(isset($modifiers)) { $value = htmlspecialchars(trim($update['message']['text'])); - my_query('INSERT INTO events SET name=?',[$value]); + my_query('INSERT INTO events SET name=?, description=""',[$value]); $eventId = $dbh->lastInsertId(); $callback_response = getTranslation('done'); editMessageText($modifiers['old_message_id'], getTranslation('events_created'), [], $userId); From 1c938fc3c3bb323241334d437ee26bf218786d61 Mon Sep 17 00:00:00 2001 From: Ossi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 4 Mar 2024 10:32:29 +0200 Subject: [PATCH 325/367] Update raids_list.php Initialize keys array --- mods/raids_list.php | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/raids_list.php b/mods/raids_list.php index 1bb602c5..b14c9e97 100644 --- a/mods/raids_list.php +++ b/mods/raids_list.php @@ -17,6 +17,7 @@ $raid = get_raid($raidId); // Create keys array. +$keys = []; // Probably unused feature. Will fix if someone needs this // $keys[][] = button(getTranslation('expand'), ['vote_refresh', 'r' => $raid['id']]); if($botUser->raidaccessCheck($raidId, 'pokemon', true)) { From 0d6b8604997b78c4254fdea1af5cd3fa7c356210 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:01:37 +0200 Subject: [PATCH 326/367] Fixed post_raid --- mods/post_raid.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/post_raid.php b/mods/post_raid.php index a5463c12..6de616c8 100644 --- a/mods/post_raid.php +++ b/mods/post_raid.php @@ -14,7 +14,7 @@ $chat = $data['arg']; require_once(LOGIC_PATH . '/send_raid_poll.php'); -$tg_json = send_raid_poll($id, $chat); +$tg_json = send_raid_poll($id, [create_chat_object([$chat])]); // Telegram multicurl request. curl_json_multi_request($tg_json); From ad68b56f31077f59daaee78ee8e3c35b2f24be2b Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:01:56 +0200 Subject: [PATCH 327/367] Fixed funny behavior of cancel key in edit_event_node and added done key to edit_save --- mods/edit_event_note.php | 1 + mods/edit_save.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mods/edit_event_note.php b/mods/edit_event_note.php index f6a6acdd..cee3f3ba 100644 --- a/mods/edit_event_note.php +++ b/mods/edit_event_note.php @@ -33,6 +33,7 @@ }elseif($mode == 'c') { my_query('DELETE FROM user_input WHERE user_id = ?', [$userid]); require_once('edit_save.php'); + exit(); }else { if($raid['event'] == EVENT_ID_EX) { $event_name = getTranslation('Xstars'); diff --git a/mods/edit_save.php b/mods/edit_save.php index 57ae4eb6..92dd8647 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -32,8 +32,9 @@ // Telegram JSON array. $tg_json = array(); -// Add delete to keys. +// Add delete and done to keys. $keys[][] = button(getTranslation('delete'), ['raids_delete', 'r' => $id]); +$keys[][] = button(getTranslation('done'), ['exit', 'd' => 1]); // Check access level prior allowing to change raid time if($botUser->accessCheck('raid-duration', true)) { From b1f9b6ab3e6d64769d1122e9c735de812a39fb3f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 9 Mar 2024 10:57:39 +0200 Subject: [PATCH 328/367] Add raid level 7 to automatic raid hour creator --- core/tools/automate_raid_hour_creation/raid_hour_creator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/tools/automate_raid_hour_creation/raid_hour_creator.php b/core/tools/automate_raid_hour_creation/raid_hour_creator.php index 5652fc03..f1faf3f6 100644 --- a/core/tools/automate_raid_hour_creation/raid_hour_creator.php +++ b/core/tools/automate_raid_hour_creation/raid_hour_creator.php @@ -112,7 +112,7 @@ function get_current_bosses($spawn) { global $dbh; $i = 0; - $levels = [5, 8]; // Search potential raid hour bosses from these raid levels + $levels = [5, 7, 8]; // Search potential raid hour bosses from these raid levels $pokemon = $pokemon_form = false; do { $pk = $dbh->prepare('SELECT pokedex_id,pokemon_form_id FROM raid_bosses WHERE raid_level = ? AND ? BETWEEN date_start AND date_end'); From 016b2c168dfc8019e4e8a43b958cf781519532e3 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 9 Mar 2024 10:58:00 +0200 Subject: [PATCH 329/367] Don't update chat info to db if request from TG failed --- mods/overview_refresh.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/mods/overview_refresh.php b/mods/overview_refresh.php index 5f90b9ab..1cb76fbd 100644 --- a/mods/overview_refresh.php +++ b/mods/overview_refresh.php @@ -56,14 +56,16 @@ if($overview_row['update_needed'] == 1) { [$chat_title, $chat_username] = get_chat_title_username($overview_row['chat_id']); - my_query(' - UPDATE overview - SET chat_title = ?, - chat_username = ?, - updated = DATE(NOW()) - WHERE chat_id = ? - ',[$chat_title, $chat_username, $overview_row['chat_id']] - ); + if($chat_title == '' && $chat_username == '') { + my_query(' + UPDATE overview + SET chat_title = ?, + chat_username = ?, + updated = DATE(NOW()) + WHERE chat_id = ? + ',[$chat_title, $chat_username, $overview_row['chat_id']] + ); + } }else { $chat_title = $overview_row['chat_title']; $chat_username = $overview_row['chat_username']; From 8dda690c84001b254e99c53039a0c4c023c0b83f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 10 Mar 2024 11:13:52 +0200 Subject: [PATCH 330/367] Fixed logic --- mods/overview_refresh.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/overview_refresh.php b/mods/overview_refresh.php index 1cb76fbd..9fc18d8e 100644 --- a/mods/overview_refresh.php +++ b/mods/overview_refresh.php @@ -56,7 +56,7 @@ if($overview_row['update_needed'] == 1) { [$chat_title, $chat_username] = get_chat_title_username($overview_row['chat_id']); - if($chat_title == '' && $chat_username == '') { + if($chat_title != '' && $chat_username != '') { my_query(' UPDATE overview SET chat_title = ?, From 2f45619da303f3c66f02be8ab587dd4afe0b67b1 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 12 Mar 2024 19:08:10 +0200 Subject: [PATCH 331/367] Fixed Pokemon translation in alarm --- logic/alarm.php | 2 +- logic/get_local_pokemon_name.php | 19 ++++++++++--------- logic/get_overview.php | 2 +- logic/keys_vote.php | 2 +- logic/raid_list.php | 3 ++- logic/raid_picture.php | 2 +- logic/show_raid_poll.php | 2 +- 7 files changed, 17 insertions(+), 15 deletions(-) diff --git a/logic/alarm.php b/logic/alarm.php index a0867339..2bcfc65f 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -140,7 +140,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) } else if($action == 'new_boss') { $msg_text = '' . getTranslation('alert_raid_boss', $recipient_language) . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; - $msg_text .= EMOJI_EGG . SP . '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']) . '' . CR; + $msg_text .= EMOJI_EGG . SP . '' . get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], $recipient_language) . '' . CR; // New attendance } else if($action == 'new_att') { diff --git a/logic/get_local_pokemon_name.php b/logic/get_local_pokemon_name.php index 3b767365..f5118775 100644 --- a/logic/get_local_pokemon_name.php +++ b/logic/get_local_pokemon_name.php @@ -1,31 +1,32 @@ fetch(); $pokemon_form_name = $res['pokemon_form_name'] ?? 'normal'; debug_log('Pokemon_form: ' . $pokemon_form_name); - - // Get translation type - $getTypeTranslation = ($override_language == true) ? 'getPublicTranslation' : 'getTranslation'; + if($language === null) $language = $botUser->userLanguage; // Init pokemon name and define fake pokedex ids used for raid eggs $pokemon_name = ''; // Get eggs from normal translation. - $pokemon_name = (in_array($pokemon_id, EGGS)) ? $getTypeTranslation('egg_' . str_replace('999', '', $pokemon_id)) : $getTypeTranslation('pokemon_id_' . $pokemon_id); + $pokemon_name = (in_array($pokemon_id, EGGS)) ? + getTranslation('egg_' . str_replace('999', '', $pokemon_id), $language) : + getTranslation('pokemon_id_' . $pokemon_id, $language); $skipFallback = false; if ($pokemon_form_name != 'normal') { - $pokemon_form_name = $getTypeTranslation('pokemon_form_' . $pokemon_form_id); + $pokemon_form_name = getTranslation('pokemon_form_' . $pokemon_form_id, $language); // Use only form name if form name contains Pokemon name // e.g. Black Kyurem, Frost Rotom if(strpos($pokemon_form_name, $pokemon_name, 0)) { diff --git a/logic/get_overview.php b/logic/get_overview.php index a8261700..7621bb63 100644 --- a/logic/get_overview.php +++ b/logic/get_overview.php @@ -32,7 +32,7 @@ function get_overview( $active_raids, $chat_title, $chat_username ) $resolved_boss = resolve_raid_boss($row['pokemon'], $row['pokemon_form'], $row['spawn'], $row['level']); $row['pokemon'] = $resolved_boss['pokedex_id']; $row['pokemon_form'] = $resolved_boss['pokemon_form_id']; - $pokemon = get_local_pokemon_name($row['pokemon'], $row['pokemon_form'], true); + $pokemon = get_local_pokemon_name($row['pokemon'], $row['pokemon_form'], $config->LANGUAGE_PUBLIC); $gym = $row['gym_name']; $ex_raid_gym_marker = (strtolower($config->RAID_EX_GYM_MARKER) == 'icon') ? EMOJI_STAR : '' . $config->RAID_EX_GYM_MARKER . ''; $start_time = $row['start_time']; diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 75bbd856..db49ef86 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -171,7 +171,7 @@ function keys_vote($raid) foreach($raid_bosses as $pokemon) { if(in_array($pokemon['pokedex_id'], EGGS)) continue; $buttons['pokemon'][] = button( - get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], true), + get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id'], $config->LANGUAGE_PUBLIC), ['vote_pokemon', 'r' => $raid['id'], 'p' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id']] ); } diff --git a/logic/raid_list.php b/logic/raid_list.php index bd2727fe..e9eab645 100644 --- a/logic/raid_list.php +++ b/logic/raid_list.php @@ -7,6 +7,7 @@ */ function raid_list($update) { + global $config; // Init raid id. $iqq = 0; @@ -42,7 +43,7 @@ function raid_list($update) $contents[$i]['text'] = show_raid_poll($row, true)['full']; // Set the title. - $contents[$i]['title'] = get_local_pokemon_name($row['pokemon'],$row['pokemon_form'], true) . ' ' . getPublicTranslation('from') . ' ' . dt2time($row['start_time']) . ' ' . getPublicTranslation('to') . ' ' . dt2time($row['end_time']); + $contents[$i]['title'] = get_local_pokemon_name($row['pokemon'],$row['pokemon_form'], $config->LANGUAGE_PUBLIC) . ' ' . getPublicTranslation('from') . ' ' . dt2time($row['start_time']) . ' ' . getPublicTranslation('to') . ' ' . dt2time($row['end_time']); // Get inline keyboard. $contents[$i]['keyboard'] = keys_vote($row); diff --git a/logic/raid_picture.php b/logic/raid_picture.php index ee001997..c0024410 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -540,7 +540,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Pokemon raid boss - $pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], true); + $pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], $config->LANGUAGE_PUBLIC); if(!in_array($raid['pokemon'], EGGS) && isset($raid['shadow']) && $raid['shadow']) $pokemon_name .= ' ' . getPublicTranslation('pokemon_form_shadow'); // Pokemon name and form? diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index 2cc1d503..bfc0c36b 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -89,7 +89,7 @@ function show_raid_poll($raid, $inline = false) if($raid['event_pokemon_title'] == 1) $title = getPublicTranslation('raid_boss'); elseif($raid['event_pokemon_title'] == 2) $title = getPublicTranslation('featured_pokemon'); else $title = getPublicTranslation('raid_boss'); - $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], true) . ' ' . (isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['pokemon'], EGGS) ? ' ' . getPublicTranslation('pokemon_form_shadow') : '') . '', true); + $msg = raid_poll_message($msg, $title . ': ' . get_local_pokemon_name($raid_pokemon_id, $raid['pokemon_form'], $config->LANGUAGE_PUBLIC) . ' ' . (isset($raid['shadow']) && $raid['shadow'] && !in_array($raid['pokemon'], EGGS) ? ' ' . getPublicTranslation('pokemon_form_shadow') : '') . '', true); // Display raid boss weather. $msg = raid_poll_message($msg, ($raid_pokemon_info['weather'] != 0) ? (' ' . get_weather_icons($raid_pokemon_info['weather'])) : '', true); From 0c42762646bace15b03718f92488045acb356137 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 12 Mar 2024 19:14:47 +0200 Subject: [PATCH 332/367] =?UTF-8?q?French=20translation=20Thanks=20to=20Mi?= =?UTF-8?q?kael=20and=20Rapha=C3=ABl!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lang/help.json | 50 ++-- lang/language.json | 638 ++++++++++++++++++++++----------------------- 2 files changed, 344 insertions(+), 344 deletions(-) diff --git a/lang/help.json b/lang/help.json index 3485edf9..3fcefb18 100644 --- a/lang/help.json +++ b/lang/help.json @@ -7,7 +7,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "true/false ou 0/1 uniquement", "PL": "TRANSLATE", "FI": "vain true/false tai 0/1", "ES": "solo true/false o 0/1" @@ -20,7 +20,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "nombres uniquement", "PL": "TRANSLATE", "FI": "vain numeroita", "ES": "solo números" @@ -33,7 +33,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Valeurs autorisées: true/false ou 0/1", "PL": "TRANSLATE", "FI": "Sallitut arvot: true/false tai 0/1", "ES": "Valores validos: true/false o 0/1" @@ -46,7 +46,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Valeurs autorisées: nombres supérieurs à 0", "PL": "TRANSLATE", "FI": "Sallittu arvo: 0 suuremmat luvut", "ES": "Valores validos: Números mayores que 0" @@ -59,7 +59,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Partager la position - Créer un raid", "PL": "TRANSLATE", "FI": "Jaa sijainti - Luo raidi", "ES": "Compartir ubicación - Crear incursión" @@ -72,7 +72,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/start - Créer un raid", "PL": "TRANSLATE", "FI": "/start - Luo raidi", "ES": "/start - Crear incursión" @@ -85,7 +85,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/start - Créer un raid EX", "PL": "TRANSLATE", "FI": "/start - Luo ex-raidi", "ES": "/start - Crear incursión EX" @@ -98,7 +98,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/start - Modifier la durée du raid", "PL": "TRANSLATE", "FI": "/start - Vaihda raidin kestoa", "ES": "/start - Cambiar duración de la incursión" @@ -111,7 +111,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/list - Afficher les 12 derniers raids en cours", "PL": "TRANSLATE", "FI": "/list - Edelliset 12 aktiivista raidia", "ES": "/list - Últimas 12 incursiones activas" @@ -124,7 +124,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/listall - Afficher tous les raids en cours", "PL": "TRANSLATE", "FI": "/listall - Kaikki aktiiviset raidit", "ES": "/listall - Todas las incursiones activas" @@ -137,7 +137,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/overview - Gérer l'aperçu de raid", "PL": "TRANSLATE", "FI": "/overview - Hallinnoi raidiyhteenvetoa", "ES": "/overview - Administrar descripción general de la incursión" @@ -150,7 +150,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/delete - Supprimer vos propres raids", "PL": "TRANSLATE", "FI": "/delete - Poista omia raidejasi", "ES": "/delete - Eliminar incursiones propias" @@ -163,7 +163,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/delete - Supprimer tous les raids", "PL": "TRANSLATE", "FI": "/delete - Poista kaikki raidit", "ES": "/delete - eliminar incursiones" @@ -176,7 +176,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/pokemon - Actualiser le Pokémon (propres raids)", "PL": "TRANSLATE", "FI": "/pokemon - Muuta pokemonia (omat raidisi)", "ES": "/pokemon - Actualizar Pokémon (incursiones propias)" @@ -189,7 +189,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/pokemon - Actualiser le Pokémon (tous les raids)", "PL": "TRANSLATE", "FI": "/pokemon - Muuta pokemonia (kaikki raidit)", "ES": "/pokemon - Actualizar Pokémon (todas incursiones)" @@ -202,7 +202,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/trainer - Modifier vos informations de dresseur", "PL": "TRANSLATE", "FI": "/trainer - Muuta kouluttajatietojasi", "ES": "/trainer - Editar datos del entrenador" @@ -215,7 +215,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/gym - Afficher les détails de l'arène", "PL": "TRANSLATE", "FI": "/gym - Näytä salin tiedot", "ES": "/gym - Ver detalles del gimnasio" @@ -228,7 +228,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/gym - Modifier les informations détaillées de l'arène", "PL": "TRANSLATE", "FI": "/gym - Muuta salin lisätietoja", "ES": "/gym - Editar detalles extendidos del gimnasio" @@ -241,7 +241,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "@Ingressportalbot - Importer l'arène", "PL": "TRANSLATE", "FI": "@Ingressportalbot - Tuo sali", "ES": "@Ingressportalbot - Importar gimnasio" @@ -254,7 +254,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/pokedex - Gérer les boss de raid", "PL": "TRANSLATE", "FI": "/pokedex - Hallinnoi raidibosseja", "ES": "/pokedex - Gestionar jefes de incursión" @@ -267,7 +267,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/get - Afficher la configuration du bot", "PL": "TRANSLATE", "FI": "/get - Näytä botin asetukset", "ES": "/get - Ver configuración del bot" @@ -280,7 +280,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/set - Modifier la configuration du bot", "PL": "TRANSLATE", "FI": "/set - Muuta botin asetuksia", "ES": "/set - Editar configuración del bot" @@ -293,7 +293,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/help - Afficher l'aide", "PL": "TRANSLATE", "FI": "/help - Näytä ohjeet", "ES": "/help - Ver ayuda" @@ -306,7 +306,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/history - Afficher l'historique des raids avec participants", "PL": "TRANSLATE", "FI": "/history - Listaa päättyneet raidit joissa oli osallistujia", "ES": "TRANSLATE" @@ -319,7 +319,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "/events - Gérer les événements de raid", "PL": "TRANSLATE", "FI": "/events - Hallitse raiditapahtumia", "ES": "TRANSLATE" diff --git a/lang/language.json b/lang/language.json index 5995c59d..54a77334 100644 --- a/lang/language.json +++ b/lang/language.json @@ -267,7 +267,7 @@ "PT-BR": "Você não tem permissão para utilizar esse comando ou bot!", "RU": "Вы не можете использовать эту команду или бота!", "NO": "Du har ikke tillatelse til å bruke denne kommandoen eller boten!", - "FR": "Tu n'es pas autorisé à utiliser cette commande !", + "FR": "Vous n'êtes pas autorisé à utiliser le bot ou cette commande!", "PL": "Nie masz uprawnień do korzystania z tej komendy lub bota!", "FI": "Sinulla ei ole oikeutta tähän komentoon tai bottiin!", "ES": "¡No está autorizado a utilizar este comando o bot!" @@ -280,7 +280,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Itinéraire", "PL": "TRANSLATE", "FI": "Reittiohje", "ES": "Abrir mapa" @@ -293,7 +293,7 @@ "PT-BR": "Pokemon", "RU": "Pokemon", "NO": "Pokemon", - "FR": "Pokemon", + "FR": "Pokémon", "PL": "Pokemon", "FI": "Pokemon", "ES": "Pokémon" @@ -306,7 +306,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Types de Pokémon", "PL": "TRANSLATE", "FI": "Pokemon Tyypit", "ES": "Tipos de Pokémon" @@ -345,7 +345,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "ou", "PL": "TRANSLATE", "FI": "tai", "ES": "o" @@ -384,7 +384,7 @@ "PT-BR": "O processo foi abortado!", "RU": "Процесс был прерван!", "NO": "Handlingen ble avbrutt!", - "FR": "Le processus à échoué !", + "FR": "Le processus a été interrompu!", "PL": "Zadanie zostało anulowane", "FI": "Prosessi peruutettiin!", "ES": "¡El proceso fue cancelado!" @@ -397,7 +397,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Sélectionnez l'action:", "PL": "TRANSLATE", "FI": "Valitse toiminto:", "ES": "Selecciona la acción:" @@ -462,7 +462,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Remplacer", "PL": "TRANSLATE", "FI": "Korvaa", "ES": "Reemplazar" @@ -488,7 +488,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier", "PL": "TRANSLATE", "FI": "Muokkaa", "ES": "Editar" @@ -514,7 +514,7 @@ "PT-BR": "Resetar", "RU": "Сброс", "NO": "Reset", - "FR": "Remise à zéro", + "FR": "Réinitialiser", "PL": "Resetuj", "FI": "Resetoi", "ES": "Reiniciar" @@ -579,7 +579,7 @@ "PT-BR": "Compartilhado com sucesso!", "RU": "Успешно отправлено!", "NO": "Deling velykket!", - "FR": "Partagé avec succès !", + "FR": "Partagé avec succès!", "PL": "Pomyślnie udostępniono", "FI": "Jaettu onnistuneesti!", "ES": "¡Compartido con éxito!" @@ -592,7 +592,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Configuration", "PL": "TRANSLATE", "FI": "Asetukset", "ES": "Configuración" @@ -605,7 +605,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Configuration mise à jour", "PL": "TRANSLATE", "FI": "Asetukset päivitetty", "ES": "Configuración actualizada" @@ -618,7 +618,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Réinitialisé", "PL": "TRANSLATE", "FI": "Resetoitu", "ES": "Reiniciado" @@ -631,7 +631,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Valeur de l'option de configuration", "PL": "TRANSLATE", "FI": "Asetuksen arvo", "ES": "Valor de la opción de configuración" @@ -644,7 +644,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Option de configuration", "PL": "TRANSLATE", "FI": "Asetuksen nimi", "ES": "TRANSLATE" @@ -657,7 +657,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Aucune valeur", "PL": "TRANSLATE", "FI": "Ei arvoa", "ES": "Sin valor" @@ -670,7 +670,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Nouvelle valeur:", "PL": "TRANSLATE", "FI": "Uusi arvo:", "ES": "Nuevo valor:" @@ -683,7 +683,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ancienne valeur:", "PL": "TRANSLATE", "FI": "Vanha arvo:", "ES": "Antiguo valor:" @@ -696,7 +696,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Aide personnalisée du bot:", "PL": "TRANSLATE", "FI": "Henkilökohtainen bottiapu:", "ES": "Tu bot personal ayuda:" @@ -709,7 +709,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Entrée invalide!", "PL": "TRANSLATE", "FI": "Epäkelpo arvo!", "ES": "¡Entrada inválida!" @@ -722,7 +722,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Erreur interne!", "PL": "TRANSLATE", "FI": "Sisäinen virhe!", "ES": "¡Error interno!" @@ -748,7 +748,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Aucun", "PL": "TRANSLATE", "FI": "ei mitään", "ES": "Nada" @@ -761,7 +761,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Autres", "PL": "TRANSLATE", "FI": "Muu", "ES": "Otro" @@ -774,7 +774,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vous ne pouvez pas voter avant d'avoir suivi le tutoriel.", "PL": "TRANSLATE", "FI": "Et voi äänestää ennen kuin olet käynyt ohjeen läpi.", "ES": "No puedes votar antes de seguir el tutorial." @@ -787,7 +787,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vous ne pouvez pas utiliser cette commande avant d'avoir suivi le tutoriel.", "PL": "TRANSLATE", "FI": "Et voi käyttää tätä käskyä ennen kuin olet käynyt ohjeen läpi.", "ES": "No puede usar este comando antes de seguir el tutorial." @@ -813,7 +813,7 @@ "PT-BR": "Ex-Raid", "RU": "Экс-Рейд", "NO": "Ex-Raid", - "FR": "Raid Ex", + "FR": "Raid EX", "PL": "Ex-Rajd", "FI": "Ex-Raidi", "ES": "Incursión EX" @@ -826,7 +826,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur niveau 5", "PL": "TRANSLATE", "FI": "5 tähden shadow", "ES": "TRANSLATE" @@ -839,7 +839,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur 5", "PL": "TRANSLATE", "FI": "Shadow 5", "ES": "TRANSLATE" @@ -852,7 +852,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur niveau 4", "PL": "TRANSLATE", "FI": "4 tähden shadow", "ES": "TRANSLATE" @@ -865,7 +865,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur 4", "PL": "TRANSLATE", "FI": "Shadow 4", "ES": "TRANSLATE" @@ -878,7 +878,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur niveau 3", "PL": "TRANSLATE", "FI": "3 tähden shadow", "ES": "TRANSLATE" @@ -891,7 +891,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur 3", "PL": "TRANSLATE", "FI": "Shadow 3", "ES": "TRANSLATE" @@ -904,7 +904,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur niveau 2", "PL": "TRANSLATE", "FI": "2 tähden shadow", "ES": "TRANSLATE" @@ -917,7 +917,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur 2", "PL": "TRANSLATE", "FI": "Shadow 2", "ES": "TRANSLATE" @@ -930,7 +930,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur niveau 1", "PL": "TRANSLATE", "FI": "1 tähden shadow", "ES": "TRANSLATE" @@ -943,7 +943,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Obscur 1", "PL": "TRANSLATE", "FI": "Shadow 1", "ES": "TRANSLATE" @@ -956,7 +956,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Primo-raid", "PL": "TRANSLATE", "FI": "Primal raid", "ES": "TRANSLATE" @@ -969,7 +969,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Primo", "PL": "TRANSLATE", "FI": "Primal", "ES": "TRANSLATE" @@ -982,7 +982,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Raid d'élite", "PL": "TRANSLATE", "FI": "Elite raid", "ES": "TRANSLATE" @@ -995,7 +995,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Élite", "PL": "TRANSLATE", "FI": "Elite", "ES": "TRANSLATE" @@ -1008,7 +1008,7 @@ "PT-BR": "Ultrafenda Espacial", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "Ultra-Brèche ", + "FR": "Raid Ultra-Chimère", "PL": "Ultratunel", "FI": "Ultramadonreikä", "ES": "Ultraumbral" @@ -1021,7 +1021,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ultra", "PL": "TRANSLATE", "FI": "TRANSLATE", "ES": "TRANSLATE" @@ -1034,7 +1034,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Méga-raid légendaire", "PL": "TRANSLATE", "FI": "Legendaarinen Mega-Raidi", "ES": "TRANSLATE" @@ -1047,7 +1047,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Méga lég", "PL": "TRANSLATE", "FI": "Lege Mega", "ES": "TRANSLATE" @@ -1060,7 +1060,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Méga-raid", "PL": "TRANSLATE", "FI": "Mega-Raidi", "ES": "Mega Incursión" @@ -1073,7 +1073,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Méga", "PL": "TRANSLATE", "FI": "Mega", "ES": "Mega" @@ -1164,7 +1164,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Oeuf obscur niveau 5", "PL": "TRANSLATE", "FI": "Tason 5 shadow muna", "ES": "TRANSLATE" @@ -1177,7 +1177,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Oeuf obscur niveau 4", "PL": "TRANSLATE", "FI": "Tason 4 shadow muna", "ES": "TRANSLATE" @@ -1190,7 +1190,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Oeuf obscur niveau 3", "PL": "TRANSLATE", "FI": "Tason 3 shadow muna", "ES": "TRANSLATE" @@ -1203,7 +1203,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Oeuf obscur niveau 2", "PL": "TRANSLATE", "FI": "Tason 2 shadow muna", "ES": "TRANSLATE" @@ -1216,7 +1216,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Oeuf obscur niveau 1", "PL": "TRANSLATE", "FI": "Tason 1 shadow muna", "ES": "TRANSLATE" @@ -1229,7 +1229,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Oeuf Primo-raid", "PL": "TRANSLATE", "FI": "Primal raid -muna", "ES": "TRANSLATE" @@ -1242,7 +1242,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Oeuf raid d'élite", "PL": "TRANSLATE", "FI": "Elite raid -muna", "ES": "TRANSLATE" @@ -1255,7 +1255,7 @@ "PT-BR": "Ultrafenda Espacial", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "Ultra-Brèche ", + "FR": "Ultra-Brèche", "PL": "Ultratunel", "FI": "Ultramadonreikä", "ES": "Ultraumbral" @@ -1268,7 +1268,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Oeuf Méga-raid légendaire", "PL": "TRANSLATE", "FI": "Legendaarinen Mega-Raid Muna", "ES": "TRANSLATE" @@ -1281,7 +1281,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Oeuf Méga-raid", "PL": "TRANSLATE", "FI": "Mega-Raid Muna", "ES": "Huevo Mega Incursión" @@ -1294,7 +1294,7 @@ "PT-BR": "Ovo de Nível 5", "RU": "Яйцо уровня 5", "NO": "Level 5 Egg", - "FR": "Oeuf 5", + "FR": "Oeuf niveau 5", "PL": "Jajko 5 poziom", "FI": "Tason 5 muna", "ES": "Huevo nivel 5" @@ -1307,7 +1307,7 @@ "PT-BR": "Ovo de Nível 4", "RU": "Яйцо уровня 4", "NO": "Level 4 Egg", - "FR": "Oeuf 4", + "FR": "Oeuf niveau 4", "PL": "Jajko 4 poziom", "FI": "Tason 4 muna", "ES": "Huevo nivel 4" @@ -1320,7 +1320,7 @@ "PT-BR": "Ovo de Nível 3", "RU": "Яйцо уровня 3", "NO": "Level 3 Egg", - "FR": "Oeuf 3", + "FR": "Oeuf niveau 3", "PL": "Jajko 3 poziom", "FI": "Tason 3 muna", "ES": "Huevo nivel 3" @@ -1333,7 +1333,7 @@ "PT-BR": "Ovo de Nível 2", "RU": "Яйцо уровня 2", "NO": "Level 2 Egg", - "FR": "Oeuf 2", + "FR": "Oeuf niveau 2", "PL": "Jajko 2 poziom", "FI": "Tason 2 muna", "ES": "Huevo nivel 2" @@ -1346,7 +1346,7 @@ "PT-BR": "Ovo de Nível 1", "RU": "Яйцо уровня 1", "NO": "Level 1 Egg", - "FR": "Oeuf 1", + "FR": "Oeuf niveau 1", "PL": "Jajko 1 poziom", "FI": "Tason 1 muna", "ES": "Huevo nivel 1" @@ -1359,7 +1359,7 @@ "PT-BR": "Reide Ovo", "RU": "Рейдовое Яйцо", "NO": "Level 0 Egg", - "FR": "Oeuf 0", + "FR": "Oeuf raid", "PL": "Jajo", "FI": "Raid-muna", "ES": "Huevo Incursión" @@ -1372,7 +1372,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "à venir", "PL": "TRANSLATE", "FI": "tulevat", "ES": "próximo" @@ -1385,7 +1385,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Aucune information sur les prochains boss n'a été trouvée!", "PL": "TRANSLATE", "FI": "Tietoa tulevista bosseista ei löytynyt!", "ES": "¡No se encontró información de los próximos jefes!" @@ -1398,7 +1398,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Boss de raid planifiés dans la base de données", "PL": "TRANSLATE", "FI": "Tallennetut tulevat raidibossit", "ES": "Jefes de incursión programados de la base de datos" @@ -1411,7 +1411,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Boss de raid non planifiés", "PL": "TRANSLATE", "FI": "Ajastamattomat bossit", "ES": "Jefes no programados" @@ -1424,7 +1424,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Voulez-vous supprimer cette entrée planifiée?", "PL": "TRANSLATE", "FI": "Haluatko poistaa tämän ajastuksen?", "ES": "¿Quieres eliminar esta entrada programada?" @@ -1437,7 +1437,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Prochains boss de raid planifiés trouvés", "PL": "TRANSLATE", "FI": "Löydetyt tulevat raidibossit", "ES": "Próximos jefes encontrado" @@ -1450,7 +1450,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Voulez-vous remplacer les données actuelles par celles que nous avons trouvées?", "PL": "TRANSLATE", "FI": "Haluatko korvata nykyiset tiedot nyt löydetyillä?", "ES": "¿Quieres reemplazar los datos actuales con los encontrados?" @@ -1463,7 +1463,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Chromatique", "PL": "TRANSLATE", "FI": "Shiny", "ES": "Shiny" @@ -1476,7 +1476,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Pas chromatique", "PL": "TRANSLATE", "FI": "Ei shiny", "ES": "No shiny" @@ -1528,7 +1528,7 @@ "PT-BR": "Cancelado", "RU": "Отмена", "NO": "Avlysning", - "FR": "Finalement je ne viens pas", + "FR": "Annulation", "PL": "Nie mogę przyjsć", "FI": "Peru", "ES": "Cancelar" @@ -1541,7 +1541,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Annulé", "PL": "TRANSLATE", "FI": "Perunut", "ES": "Cancelado" @@ -1567,7 +1567,7 @@ "PT-BR": "Votos atualizados", "RU": "Голосование обновлено", "NO": "Stemme oppdatert", - "FR": "Mise à jour du vote", + "FR": "Vote mis à jour", "PL": "Głos zaktualizowany", "FI": "Äänestys päivitetty", "ES": "Voto actualizado" @@ -1580,7 +1580,7 @@ "PT-BR": "Vote por um horário primeiro!", "RU": "Сначала выберите время!", "NO": "Foreslå tid først", - "FR": "Votez pour une heure en premier !", + "FR": "Votez d'abord pour une heure!", "PL": "Wybierz najpierw godzinę", "FI": "Äänestä ensin aikaa!", "ES": "¡Primero selecciona un horario!" @@ -1593,7 +1593,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Votez pour une heure dans le futur!", "PL": "TRANSLATE", "FI": "Äänestä tulevaa aikaa!", "ES": "¡Vota por un tiempo futuro!" @@ -1606,7 +1606,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "La participation à distance n'est plus possible!", "PL": "TRANSLATE", "FI": "Osallistuminen etänä ei ole enää mahdollista!", "ES": "¡Asistir a distancia ya no es posible!" @@ -1619,7 +1619,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vous ne pouvez pas faire ce choix.", "PL": "TRANSLATE", "FI": "Et voi tehdä tätä valintaa.", "ES": "No puedes realizar esta selección." @@ -1632,7 +1632,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ceci est une information de raid. Le vote n'est pas disponible!", "PL": "TRANSLATE", "FI": "Tämä on raid-tiedote, ei äänestystä.", "ES": "Esta es una información de incursión. ¡No es posible votar!" @@ -1658,7 +1658,7 @@ "PT-BR": "Ovo eclode", "RU": "Откроется", "NO": "Egget klekker", - "FR": "POP", + "FR": "Éclosion", "PL": "Wyklucie", "FI": "Avautuu", "ES": "Abre" @@ -1671,7 +1671,7 @@ "PT-BR": "Ovo eclode em", "RU": "Откроется", "NO": "Klekker", - "FR": "RDV", + "FR": "Éclot le", "PL": "Wykluje się", "FI": "Avautuu", "ES": "Apre en" @@ -1697,7 +1697,7 @@ "PT-BR": "Reide até", "RU": "Рейд до", "NO": "Raid fram til", - "FR": "DEPOP", + "FR": "Raid jusqu'à", "PL": "Rajd trwa do", "FI": "Raidi kunnes", "ES": "Incursión hasta" @@ -1710,7 +1710,7 @@ "PT-BR": "PARTICIPAÇÃO APENAS COM PASSE EX", "RU": "УЧАСТИЕ ВОЗМОЖНО ТОЛЬКО С ПРОПУСКОМ НА ЭКС-РЕЙД", "NO": "DET ER BARE MULIG Å DELTA OM DU HAR ETT EX-RAID PASS FOR DENNE GYMMEN", - "FR": "PARTICIPATION POSSIBLE SEULEMENT SI VOUS AVEZ UN PASS RAID EX", + "FR": "PARTICIPATION POSSIBLE UNIQUEMENT AVEC UN PASS RAID EX", "PL": "Rajdowanie możliwe tylko z zaproszeniem na EX-Rajd", "FI": "VOIT OSALLISTUA VAIN EX-RAIDI PASSILLA", "ES": "PARTICIPACIÓN SOLO ES POSIBLE CON PASE EX" @@ -1723,7 +1723,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Il n'est pas possible de participer à ce raid avec un passe à distance!", "PL": "TRANSLATE", "FI": "Tähän raidiin ei voi osallistua etäpassilla!", "ES": "TRANSLATE" @@ -1736,7 +1736,7 @@ "PT-BR": "Ainda sem participantes", "RU": "Пока нет участников", "NO": "Ingen deltaker ennå", - "FR": "Aucun participant", + "FR": "Aucun participant actuellement", "PL": "Brak chętnych", "FI": "Ei osallistujia", "ES": "No hay participantes" @@ -1749,7 +1749,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Importer", "PL": "TRANSLATE", "FI": "Tuo", "ES": "Importar" @@ -1762,7 +1762,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Mettre à jour le tableau des Pokémon", "PL": "TRANSLATE", "FI": "Päivitä Pokemon-taulu", "ES": "Actualizar tabla Pokémon" @@ -1775,7 +1775,7 @@ "PT-BR": "Finalizada", "RU": "Закончено", "NO": "Ferdig", - "FR": "terminé", + "FR": "Terminé", "PL": "Skończony", "FI": "Valmis", "ES": "Finalizado" @@ -1814,7 +1814,7 @@ "PT-BR": "até", "RU": "к", "NO": "til", - "FR": "DEPOP", + "FR": "à", "PL": "do", "FI": "-", "ES": "a" @@ -1840,7 +1840,7 @@ "PT-BR": "Alguns participantes estão atrasados.", "RU": "Некоторые участники задерживаются.", "NO": "Noen deltakere er forsinket", - "FR": "Certains participants sont en retard", + "FR": "Certains participants sont en retard.", "PL": "Ktoś się spóźni", "FI": "Osa osallistujista on myöhässä.", "ES": "Algunos participantes llegan tarde." @@ -1853,7 +1853,7 @@ "PT-BR": "Por favor espere RAID_LATE_TIME minutos!", "RU": "Пожалуйста подождите RAID_LATE_TIME минут!", "NO": "Vær grei og vent RAID_LATE_TIME minutter!", - "FR": "Attendez s'il vous plaît RAID_LATE_TIME minutes !", + "FR": "Attendez RAID_LATE_TIME minutes s'il vous plaît!", "PL": "Poczekaj RAID_LATE_TIME minut!", "FI": "Odottakaa RAID_LATE_TIME minuuttia!", "ES": "¡Por favor, esperar RAID_LATE_TIME minutos!" @@ -1866,7 +1866,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "START_CODE le raid", "PL": "TRANSLATE", "FI": "START_CODE raidi", "ES": "START_CODE incursión" @@ -1879,7 +1879,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Informer tous les participants du commencement du raid", "PL": "TRANSLATE", "FI": "Ilmoita kaikille osallistujille raidin alkamisesta", "ES": "Notificar a todos los participantes del inicio de la incursión" @@ -1892,7 +1892,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "(notifier les participants)", "PL": "TRANSLATE", "FI": "(viesti kaikille)", "ES": "(Mensaje a todos)" @@ -1905,7 +1905,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Groupe privé", "PL": "TRANSLATE", "FI": "Privaattiryhmä", "ES": "Grupo privado" @@ -1918,7 +1918,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Publique", "PL": "TRANSLATE", "FI": "Julkinen", "ES": "Público" @@ -1931,7 +1931,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Raid à distance", "PL": "TRANSLATE", "FI": "Etäraidi", "ES": "Incursión remota" @@ -1944,7 +1944,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Raids à distance", "PL": "TRANSLATE", "FI": "Etäraidit", "ES": "Incursiones remotas" @@ -1957,7 +1957,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Participants à distance!", "PL": "TRANSLATE", "FI": "Etäosallistujia!", "ES": "¡Participantes remotos!" @@ -1970,7 +1970,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "(max. REMOTE_MAX_USERS à la fois)", "PL": "TRANSLATE", "FI": "(max. REMOTE_MAX_USERS kerrallaan)", "ES": "(máx. REMOTE_MAX_USERS cada vez)" @@ -1983,7 +1983,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vous avez participé au raid à distance que vous avez créé. Voulez-vous supprimer l'annonce du raid?", "PL": "TRANSLATE", "FI": "Olet pelannut luomasi etäraidin. Saako raidi-ilmoituksen poistaa?", "ES": "Has participado en la incursión remota que creaste. ¿Quieres eliminar el anuncio de la incursión?" @@ -1996,7 +1996,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vous avez annulé votre participation au raid à distance que vous avez créé. Voulez-vous supprimer l'annonce du raid?", "PL": "TRANSLATE", "FI": "Olet perunut osallistumisesi luomaasi etäraidin. Saako raidi-ilmoituksen poistaa?", "ES": "Has cancelado tu participación a la incursión remota que creaste. ¿Quieres eliminar el anuncio de la incursión?" @@ -2009,7 +2009,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Merci! Raid à distance indiqué comme terminé!", "PL": "TRANSLATE", "FI": "Kiitos! Etäraidi merkattu päättyneeksi!", "ES": "¡Gracias! ¡Incursión remota marcada como finalizada!" @@ -2022,7 +2022,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Code de groupe", "PL": "TRANSLATE", "FI": "Ryhmäkoodi", "ES": "Código de grupo" @@ -2035,7 +2035,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "(aucun code de groupe requis)", "PL": "TRANSLATE", "FI": "(ei ryhmäkoodia)", "ES": "(no se necesita código de grupo)" @@ -2048,7 +2048,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vous n'êtes PAS inscrit en tant que participant à distance. Demandez le code de groupe sur place!", "PL": "TRANSLATE", "FI": "Et ole rekisteröity etäosallistujaksi. Pyydä koodi paikanpäällä!", "ES": "NO estás registrado como participante remoto. ¡Solicita el código de grupo en el sitio!" @@ -2061,7 +2061,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Partager le code de groupe", "PL": "TRANSLATE", "FI": "Jaa ryhmäkoodi", "ES": "Compartir código de grupo" @@ -2074,7 +2074,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Code de groupe envoyé!", "PL": "TRANSLATE", "FI": "Lähetä ryhmäkoodi!", "ES": "¡Código de grupo enviado!" @@ -2087,7 +2087,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "COMMENCER", "PL": "TRANSLATE", "FI": "ALOITA", "ES": "INICIAR" @@ -2100,7 +2100,7 @@ "PT-BR": "Por favor escolha a primeira letra do ginásio:", "RU": "Пожалуйста, выберите первую букву гима:", "NO": "Hva er den første bokstaven i gym navnet", - "FR": "Sélectionne la première lettre de l'arène", + "FR": "Sélectionnez la première lettre de l'arène:", "PL": "Wybierz pierwszą litere nazwy Areny", "FI": "Valitse salin ensimmäinen kirjain:", "ES": "Por favor, selecciona la primera letra del gimnasio:" @@ -2113,7 +2113,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Sélectionnez la première lettre de l'arène ou de la zone:", "PL": "TRANSLATE", "FI": "Valitse salin ensimmäinen kirjain tai alue:", "ES": "Seleccione la primera letra del gimnasio o la zona del gimnasio:" @@ -2126,7 +2126,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Sélectionnez l'arène ou la zone:", "PL": "TRANSLATE", "FI": "Valitse sali tai alue:", "ES": "Seleccione gimnasio o zona de gimnasio:" @@ -2139,7 +2139,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Sélectionnez la zone:", "PL": "TRANSLATE", "FI": "Valitse salialue:", "ES": "Por favor, selecciona la zona del gimnasio:" @@ -2152,7 +2152,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Zone par défaut", "PL": "TRANSLATE", "FI": "Oletussalialue", "ES": "TRANSLATE" @@ -2165,7 +2165,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Zones", "PL": "TRANSLATE", "FI": "Salialueet", "ES": "TRANSLATE" @@ -2178,7 +2178,7 @@ "PT-BR": "Primeira letra escolhida.:", "RU": "Первая буква вабрана.", "NO": "Første bokstav er valgt", - "FR": "Première lettre sélectionnée", + "FR": "Première lettre sélectionnée.", "PL": "Pierwsza litera wybrana", "FI": "Ensimmäinen kirjain valittu.", "ES": "Primera letra seleccionada." @@ -2191,7 +2191,7 @@ "PT-BR": "A raid já existe!", "RU": "Рейд уже существует!", "NO": "Raidet finnes allerede!", - "FR": "Ce raid existe déjà", + "FR": "Ce raid existe déjà!", "PL": "Rajd już istnieje", "FI": "Raidi on jo olemassa!", "ES": "¡La incursión ya existe!" @@ -2204,7 +2204,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Afficher un raid enregistré ou créer un événement de raid", "PL": "TRANSLATE", "FI": "Tarkaste tallennettua raidia tai luo tapahtuma", "ES": "TRANSLATE" @@ -2217,7 +2217,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Afficher le raid enregistré", "PL": "TRANSLATE", "FI": "Tallennettu raidi", "ES": "TRANSLATE" @@ -2230,7 +2230,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Créer un événement de raid", "PL": "TRANSLATE", "FI": "Luo raiditapahtuma", "ES": "TRANSLATE" @@ -2243,7 +2243,7 @@ "PT-BR": "Criar raid em", "RU": "Создать рейд в", "NO": "Opprett raid i", - "FR": "Créer un raid", + "FR": "Créer un raid dans", "PL": "Utwórz Rajd w", "FI": "Luo Raidi", "ES": "Crear incursión en" @@ -2256,7 +2256,7 @@ "PT-BR": "Para continuar, escolha o nível da raid", "RU": "Чтобы продолжить, пожалуйста, укажите уровень рейда", "NO": "Velg raid level for å fortsette", - "FR": "Pour continuer, sélectionne un niveau de raid", + "FR": "Pour continuer, sélectionnez un niveau de raid", "PL": "Żeby kontynuować, wybierz poziom Rajdu", "FI": "Jatkaaksesi valitse raidin taso", "ES": "Para continuar, selecciona el nivel de incursión" @@ -2269,7 +2269,7 @@ "PT-BR": "Escolha o nível da raid", "RU": "Укажите уровень рейда", "NO": "Velg raid level", - "FR": "Sélectionne un niveau de raid", + "FR": "Sélectionnez un niveau de raid", "PL": "Wybierz poziom Rajdu", "FI": "Valitse raidin taso", "ES": "Selecciona el nivel de la incursión" @@ -2282,7 +2282,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Désactiver le niveau de raid", "PL": "TRANSLATE", "FI": "Poista raidi taso käytöstä", "ES": "Desactivar el nivel de incursión" @@ -2295,7 +2295,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Niveau de raid désactivé", "PL": "TRANSLATE", "FI": "Raidi taso ei käytössä", "ES": "Nivel de incursión desactivado" @@ -2308,7 +2308,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Informations de dresseur", "PL": "TRANSLATE", "FI": "Kouluttajatieto", "ES": "Información del entrenador" @@ -2321,7 +2321,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vos données de dresseur:", "PL": "TRANSLATE", "FI": "Kouluttajatietosi:", "ES": "Tús datos de entrenador:" @@ -2334,7 +2334,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Partager le message de dresseur", "PL": "TRANSLATE", "FI": "Jaa kouluttajaviesti", "ES": "Compartir mensaje de entrenador" @@ -2347,7 +2347,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Supprimer le message de dresseur", "PL": "TRANSLATE", "FI": "Poista kouluttajaviesti", "ES": "Eliminar mensaje de entrenador" @@ -2360,7 +2360,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Supprimer le message de dresseur de la conversation?", "PL": "TRANSLATE", "FI": "Poista kouluttajaviesti chatista?", "ES": "¿Eliminar mensaje de entrenador del chat?" @@ -2373,7 +2373,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Message de dresseur supprimé!", "PL": "TRANSLATE", "FI": "Kouluttajaviesti poistettu!", "ES": "¡Mensaje de entrenador eliminado!" @@ -2386,7 +2386,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vous pouvez également partager ou supprimer le message de dresseur dans une conversation.", "PL": "TRANSLATE", "FI": "Voit myos jakaa kouluttajaviestin chatin kanssa.", "ES": "También puedes compartir o eliminar el mensaje de entrenador en un chat." @@ -2399,7 +2399,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifiez vos informations de dresseur:", "PL": "TRANSLATE", "FI": "Aseta trainer datasi:", "ES": "Edita tus datos de entrenador:" @@ -2412,7 +2412,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Via 'Informations de dresseur' vous pouvez afficher vos données. Modifiez-les avec les boutons 'Équipe' et 'Niveau'.", "PL": "TRANSLATE", "FI": "Voit tarkastella kouluttajatietojasi 'kouluttajatieto' komennolla. Muuta tietojasi 'Joukkue' ja 'Taso' -napeilla.", "ES": "Con 'Información del entrenador' puedes ver los datos de tu entrenador. Cambia los datos con los botones 'Equipo' y 'Nivel'." @@ -2425,7 +2425,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Une fois terminé, cliquez à nouveau sur 'Informations de dresseur'. Les données de votre dresseur seront à nouveau masquées.", "PL": "TRANSLATE", "FI": "Kun olet valmis, paina uudelleen 'Kouluttajatieto'. Kouluttajatietosi ovat jälleen piilossa.", "ES": "Una vez que termines, presiona nuevamente en 'Información del entrenador'. Los datos de tu entrenador se volverán a ocultar." @@ -2438,7 +2438,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Partagez dans une conversation le message pour afficher et modifier les informations de dresseur:", "PL": "TRANSLATE", "FI": "Jaa viesti kouluttajatietojen näyttämistä ja muuttamista varten chatin kanssa:", "ES": "Comparte el mensaje para mostrar y editar los datos del entrenador con un chat:" @@ -2451,7 +2451,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Aucune conversation trouvée! Impossible de partager le message pour afficher et modifier les informations de dresseur!", "PL": "TRANSLATE", "FI": "Chatteja ei löytynyt! Et voi jakaa viestiä tietojen näyttämiseen ja muuttamiseen!", "ES": "¡No se encontraron chats! ¡No se puede compartir el mensaje para mostrar y editar los datos del entrenador!" @@ -2464,7 +2464,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Nom de dresseur", "PL": "TRANSLATE", "FI": "Pelinimi", "ES": "Nombre de entrenador" @@ -2477,7 +2477,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ajouter le nom de dresseur", "PL": "TRANSLATE", "FI": "Lisää pelinimi", "ES": "Añadir nombre de entrenador" @@ -2490,7 +2490,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier le nom de dresseur", "PL": "TRANSLATE", "FI": "Muokkaa pelinimeä", "ES": "Editar nombre de entrenador" @@ -2503,7 +2503,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Entrez votre nom de dresseur", "PL": "TRANSLATE", "FI": "Kirjoita pelinimesi:", "ES": "Escribe tu nombre de entrenador" @@ -2516,7 +2516,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Merci. Votre nom est désormais:", "PL": "TRANSLATE", "FI": "Kiitos. Pelinimesi on nyt:", "ES": "Gracias. Ahora tu nombre es:" @@ -2529,7 +2529,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Veuillez utiliser uniquement des caractères alphanumériques. Réessayez", "PL": "TRANSLATE", "FI": "Pelinimessä voi olla pelkästään numeroita ja kirjaimia. Yritä uudelleen.", "ES": "Por favor, usa solo caracteres alfanuméricos. Intentalo otra vez" @@ -2542,7 +2542,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier l'affichage du nom", "PL": "TRANSLATE", "FI": "Vaihda näyttönimeä", "ES": "Cambiar nombre para mostrar" @@ -2555,7 +2555,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Code de dresseur", "PL": "TRANSLATE", "FI": "Kaverikoodi", "ES": "Código de entrenador" @@ -2568,7 +2568,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "indéfini", "PL": "TRANSLATE", "FI": "Ei asetettu", "ES": "no establecido" @@ -2581,7 +2581,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Entrez votre code de dresseur", "PL": "TRANSLATE", "FI": "Kirjoita kaverikoodisi:", "ES": "Pon tu código de entrenador" @@ -2594,7 +2594,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Merci. Votre code de dresseur est désormais:", "PL": "TRANSLATE", "FI": "Kiitos. Kaverikoodisi on nyt:", "ES": "Gracias. Ahora tu código de entrenador es:" @@ -2607,7 +2607,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Votre code de dresseur ne contient pas 12 chiffres. Réessayez", "PL": "TRANSLATE", "FI": "Annetussa kaverikoodissa ei ole 12 numeroa. Yritä uudelleen.", "ES": "El código de entrenador que pustiste no tiene 12 numeros. Intentalo otra vez" @@ -2620,7 +2620,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Dresseur introuvable!", "PL": "TRANSLATE", "FI": "Kouluttajaa ei löytynyt!", "ES": "¡Entrenador no encontrado!" @@ -2633,7 +2633,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Langue du bot", "PL": "TRANSLATE", "FI": "Botin kieli", "ES": "Idioma del bot" @@ -2646,7 +2646,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifiez la langue du bot", "PL": "TRANSLATE", "FI": "Vaihda botin kieli", "ES": "Cambiar el idioma del bot" @@ -2659,7 +2659,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Nouvelle langue enregistrée!", "PL": "TRANSLATE", "FI": "Kieli vaihdettu!", "ES": "¡Nuevo idioma guardado!" @@ -2672,7 +2672,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "La flèche (->) indique quel nom est affiché dans les annonces de raid. Vous pouvez modifier le nom dans les paramètres.", "PL": "TRANSLATE", "FI": "Nuoli (->) osoittaa raidi-ilmoituksissa käytettävää nimeä. Voit vaihtaa näyttönimeä nimiasetuksista.", "ES": "La flecha (->) indica el nombre que se muestra en los anuncios de incursiones. Puedes cambiar el nombre en los ajustes." @@ -2685,7 +2685,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Nom", "PL": "TRANSLATE", "FI": "Nimi", "ES": "Nombre" @@ -2698,7 +2698,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Équipe", "PL": "TRANSLATE", "FI": "Joukkue", "ES": "Equipo" @@ -2711,7 +2711,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Équipe enregistrée!", "PL": "TRANSLATE", "FI": "Joukkue tallennettu!", "ES": "¡Equipo guardado!" @@ -2724,7 +2724,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Sélectionnez votre équipe:", "PL": "TRANSLATE", "FI": "Valitse joukkueesi:", "ES": "Selecciona tu equipo:" @@ -2737,7 +2737,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Niveau", "PL": "TRANSLATE", "FI": "Taso", "ES": "Nivel" @@ -2750,7 +2750,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Niveau enregistré!", "PL": "TRANSLATE", "FI": "Taso tallennettu!", "ES": "¡Nivel guardado!" @@ -2763,7 +2763,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Sélectionnez votre niveau:", "PL": "TRANSLATE", "FI": "Valitse tasosi:", "ES": "Selecciona tu nivel:" @@ -2789,7 +2789,7 @@ "PT-BR": "Ginásio salvo.", "RU": "Гим сохранен", "NO": "Gym lagret", - "FR": "Arène sauvegardée", + "FR": "Arène enregistrée.", "PL": "Arena zapisana", "FI": "Sali tallennettu.", "ES": "Gimnasio guardado." @@ -2802,7 +2802,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Arène masquée", "PL": "TRANSLATE", "FI": "Piilotettu sali", "ES": "Gimnasio oculto" @@ -2815,7 +2815,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Arènes masquées", "PL": "TRANSLATE", "FI": "Piilotetut salit", "ES": "Gimnasios ocultos" @@ -2828,7 +2828,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Aucune arène masquée trouvée!", "PL": "TRANSLATE", "FI": "Piilotettuja saleja ei löytynyt!", "ES": "¡No se encontraron gimnasios ocultos!" @@ -2841,7 +2841,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Afficher l'arène", "PL": "TRANSLATE", "FI": "Näytä sali", "ES": "Ver gimnasio" @@ -2854,7 +2854,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Masquer l'arène", "PL": "TRANSLATE", "FI": "Piilota sali", "ES": "Ocultar gimnasio" @@ -2867,7 +2867,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Arène normale", "PL": "TRANSLATE", "FI": "Tavallinen sali", "ES": "Gimnasio normal" @@ -2880,7 +2880,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Arène EX", "PL": "TRANSLATE", "FI": "Ex-raidi sali", "ES": "Gimnasio EX" @@ -2893,7 +2893,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Informations détaillées de l'arène:", "PL": "TRANSLATE", "FI": "Salin lisätiedot:", "ES": "Detalles ampliados del gimnasio:" @@ -2906,7 +2906,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Enregistrer les informations détaillées de l'arène?", "PL": "TRANSLATE", "FI": "Tallenna salin lisätiedot?", "ES": "¿Guardar detalles ampliados del gimnasio?" @@ -2919,7 +2919,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Nouvelles informations détaillées de l'arène:", "PL": "TRANSLATE", "FI": "Salin uudet lisätiedot:", "ES": "Nuevo detalle ampliado del gimnasio:" @@ -2932,7 +2932,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Erreur! Arène introuvable!", "PL": "TRANSLATE", "FI": "Virhe! Salia ei löytynyt!", "ES": "¡Error! ¡Gimnasio no encontrado!" @@ -2945,7 +2945,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Coordonnées", "PL": "TRANSLATE", "FI": "Koordinaatit", "ES": "TRANSLATE" @@ -2958,7 +2958,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier les coordonnées", "PL": "TRANSLATE", "FI": "Muokkaa koordinaatteja", "ES": "TRANSLATE" @@ -2971,7 +2971,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Erreur! Insérez les coordonnées au format Latitude,Longitude pour ajouter une nouvelle arène!", "PL": "TRANSLATE", "FI": "Virhe! Anna koordinaatit muotossa Leveysaste,Pituusaste lisätäksesi uuden salin!", "ES": "¡Error! ¡Envía las coordenadas en el formato latitud,longitud para agregar un nuevo gimnasio!" @@ -2984,7 +2984,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Erreur! Inscrivez les coordonnées au format suivant: Latitude,Longitude", "PL": "TRANSLATE", "FI": "Virhe! Anna koordinaatit seuraavassa muodossa: Leveysaste,Pituusaste", "ES": "¡Error! Envía las coordenadas en el siguiente formato: latitud,longitud" @@ -2997,7 +2997,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Envoyez-moi les coordonnées de l'arène au format suivant: Latitude,Longitude", "PL": "TRANSLATE", "FI": "Lähetä minulle salin koordinaatit muodossa: Leveysaste,Pituusaste", "ES": "TRANSLATE" @@ -3010,7 +3010,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Par exemple: 52.516263,13.377755", "PL": "TRANSLATE", "FI": "Esimerkiksi: 52.516263,13.377755", "ES": "Por ejemplo: 52.516263,13.377755" @@ -3023,7 +3023,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Utilisez la commande /gymname Nom de l'arène pour définir un nom d'arène pour les coordonnées soumises précédemment. Vous pourrez ensuite envoyer une nouvelle position!", "PL": "TRANSLATE", "FI": "Käytä komentoa /gymname Salin nimi asettaaksesi salinimen aiemmin annetuille koordinaateille. Sitten voit antaa jälleen sijainnin!", "ES": "Utiliza el comando /gymname Nombre del gimnasio para establecer un nombre de gimnasio para las coordenadas enviadas recientemente. ¡Entonces podrás volver a enviar una ubicación!" @@ -3036,7 +3036,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Arène ajoutée avec succès!", "PL": "TRANSLATE", "FI": "Sali lisätty onnistuneesti!", "ES": "¡Se agregó con éxito el gimnasio!" @@ -3049,7 +3049,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Créer une nouvelle arène", "PL": "TRANSLATE", "FI": "Luo uusi sali", "ES": "TRANSLATE" @@ -3062,7 +3062,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Arène mise à jour avec succès!", "PL": "TRANSLATE", "FI": "Sali päivitetty onnistuneesti!", "ES": "¡Se actualizó con éxito el gimnasio!" @@ -3075,7 +3075,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Supprimer l'arène", "PL": "TRANSLATE", "FI": "Poista sali", "ES": "Eliminar gimnasio" @@ -3088,7 +3088,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vraiment supprimer cette arène?", "PL": "TRANSLATE", "FI": "Vahvista salin poisto?", "ES": "¿De verdad eliminar este gimnasio?" @@ -3101,7 +3101,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Arène supprimée avec succès!", "PL": "TRANSLATE", "FI": "Sali poistettu onnistuneesti!", "ES": "¡Se eliminó con éxito este gimnasio!" @@ -3114,7 +3114,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Détails de l'arène", "PL": "TRANSLATE", "FI": "Salin yksityiskohdat", "ES": "Detalles del gimnasio" @@ -3127,7 +3127,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Afficher les détails de l'arène", "PL": "TRANSLATE", "FI": "Näytä salin yksityiskohdat", "ES": "Ver detalles del gimnasio" @@ -3140,7 +3140,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Erreur! La longueur maximale du texte est de 255 caractères!", "PL": "TRANSLATE", "FI": "Virhe! Tekstin enimmäispituus on 255 merkkiä!", "ES": "TRANSLATE" @@ -3153,7 +3153,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Notice d'arène", "PL": "TRANSLATE", "FI": "lisätietoja", "ES": "TRANSLATE" @@ -3166,7 +3166,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Envoyez-moi la nouvelle notice d'arène (max 255 caractères):", "PL": "TRANSLATE", "FI": "Lähetä minulle salin uudet lisätiedot (max 255 merkkiä):", "ES": "TRANSLATE" @@ -3179,7 +3179,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Adresse de l'arène", "PL": "TRANSLATE", "FI": "salin osoite", "ES": "TRANSLATE" @@ -3192,7 +3192,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Adresse enregistrée", "PL": "TRANSLATE", "FI": "Tallennettu osoite", "ES": "TRANSLATE" @@ -3205,7 +3205,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Envoyez-moi l'adresse de la nouvelle arène:", "PL": "TRANSLATE", "FI": "Lähetä minulle salin uusi osoite:", "ES": "TRANSLATE" @@ -3218,7 +3218,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Résultat de la recherche d'adresse", "PL": "TRANSLATE", "FI": "Osoitehaun tulos", "ES": "TRANSLATE" @@ -3231,7 +3231,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Enregistrer le résultat de la recherche d'adresse", "PL": "TRANSLATE", "FI": "Tallenna osoitehaun tulos", "ES": "TRANSLATE" @@ -3244,7 +3244,7 @@ "PT-BR": "Escolha o Pokémon chefe da raid", "RU": "Выберите Рейд босса", "NO": "Velg raid boss", - "FR": "Sélectionne un boss de raid", + "FR": "Sélectionnez un boss de raid", "PL": "Wybierz Bossa Rajdu", "FI": "Valitse raidibossi", "ES": "Selecciona el jefe de incursión" @@ -3257,7 +3257,7 @@ "PT-BR": "Escolha o Pokémon", "RU": "Укажите Покемона", "NO": "Velg Pokemon", - "FR": "Sélectionne un Pokémon", + "FR": "Sélectionnez un Pokémon", "PL": "Wybierz Pokemona", "FI": "Valitse Pokemoni", "ES": "Selecciona Pokémon" @@ -3270,7 +3270,7 @@ "PT-BR": "Raid salva:", "RU": "Рейд сохранен:", "NO": "Raid lagret", - "FR": "Raid sauvegardé", + "FR": "Raid enregistré:", "PL": "Rajd zapisany", "FI": "Raidi tallennettu:", "ES": "Incursión guardada:" @@ -3283,7 +3283,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Pokémon vedette", "PL": "TRANSLATE", "FI": "Tapahtuman Pokemon", "ES": "TRANSLATE" @@ -3309,7 +3309,7 @@ "PT-BR": "Chefe da raid salvo!", "RU": "Рейд Босс сохранен!", "NO": "Raid boss lagret!", - "FR": "Boss de raid sauvegardé", + "FR": "Boss de raid enregistré!", "PL": "Boss Rajdu zapisany!", "FI": "Raidibossi tallennettu!", "ES": "¡Jefe de incursión guardado!" @@ -3322,7 +3322,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Boss de raid exclus de l'importation:", "PL": "TRANSLATE", "FI": "Tuonnista poissuljetut raidibossit:", "ES": "Jefes de incursión excluidos de importación:" @@ -3335,7 +3335,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Sélectionnez le boss de raid à exclure de l'importation ou terminez l'importation avec 'Enregistrer'", "PL": "TRANSLATE", "FI": "Valitse tuonnista poissuljettavat raidibossit tai lopeta tuonti valitsemalla 'Tallenna'", "ES": "Selecciona el jefe de incursión a excluir de la importación o finaliza la importación con 'Guardar'" @@ -3348,7 +3348,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Importer les boss de raid?", "PL": "TRANSLATE", "FI": "Tuo raidibossit?", "ES": "¿Importar jefes de incursión?" @@ -3361,7 +3361,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Importation terminée!", "PL": "TRANSLATE", "FI": "Tuonti valmis!", "ES": "¡Importación finalizada!" @@ -3374,7 +3374,7 @@ "PT-BR": "Opcional - Nome do gínasio e nome do time", "RU": "Опционально - Название Гима и Команда Гима", "NO": "Valgfri - Gym navn og gym team:", - "FR": "Optionnel - Couleur de l'arène", + "FR": "Optionnel - Nom et équipe de l'arène:", "PL": "Opcjonalnie - Nazwa Areny i kolor Areny", "FI": "Valinnainen - Salin nimi ja salin joukkue:", "ES": "Opcional - Nombre del gimnasio y equipo del gimnasio:" @@ -3439,7 +3439,7 @@ "PT-BR": "Hora de começar determinada para", "RU": "Установить время начала", "NO": "Startid satt til", - "FR": "Heure de début réglée à", + "FR": "Heure de commencement réglée à", "PL": "Czas startu ustawiony na", "FI": "Aloitusaika asetettu klo", "ES": "Hora de inicio establecida en" @@ -3465,7 +3465,7 @@ "PT-BR": "Select the date of the raid:", "RU": "Указать дату рейда:", "NO": "Velg dato for raidet:", - "FR": "Sélectionne la date du raid", + "FR": "Sélectionnez la date du raid:", "PL": "Wybierz date Rajdu", "FI": "Valitse raidin päivämäärä:", "ES": "Selecciona la fecha de la incursión:" @@ -3478,7 +3478,7 @@ "PT-BR": "Select the hour of the raid:", "RU": "Указать час рейда:", "NO": "Velg tid>/b> for raidet:", - "FR": "Sélectionne l'heure du raid", + "FR": "Sélectionnez l'heure du raid:", "PL": "Wybierz godzinę rajdu:", "FI": "Valitse raidin tunti:", "ES": "Selecciona la hora de la incursión:" @@ -3491,7 +3491,7 @@ "PT-BR": "Select the start time of the raid:", "RU": "Указать Время начала рейда:", "NO": "Velg når raidet starter:", - "FR": "Sélectionne l'heure de POP du raid", + "FR": "Sélectionnez l'heure de commencement du raid:", "PL": "WYbierz czas startu Rajdu", "FI": "Valitse raidin aloitusaika:", "ES": "Selecciona la hora de inicio de la incursión:" @@ -3530,7 +3530,7 @@ "PT-BR": "Quando a raid irá começar?", "RU": "Когда начало рейда?", "NO": "Når starter raidet?", - "FR": "Quand démarre le raid ?", + "FR": "Quand commence le raid?", "PL": "Kiedy Rajd się zaczyna?", "FI": "Mihin aikaan raidi alkaa?", "ES": "¿Cuando va a empezar la incursión?" @@ -3543,7 +3543,7 @@ "PT-BR": "Em quantos minutos a raid irá começar?", "RU": "Через сколько минут рейд начинается?", "NO": "Hvor mange minutter til raidet starter?", - "FR": "Dans combien de minutes le raid commence ?", + "FR": "Dans combien de minutes le raid commence?", "PL": "Za ile minut zacznie się Rajd?", "FI": "Monenko minuutin päästä raidi alkaa?", "ES": "¿En cuantos minutos va empezar la incursión?" @@ -3556,7 +3556,7 @@ "PT-BR": "Ver horário", "RU": "Просмотр времени", "NO": "Klokkevisning", - "FR": "Voir l'heure", + "FR": "Vue horaire", "PL": "Widok zegara", "FI": "Kellonaika näkymä", "ES": "Ver horario" @@ -3569,7 +3569,7 @@ "PT-BR": "Ver minutos", "RU": "Просмотр минут", "NO": "Minuttvisning", - "FR": "Voir les minutes", + "FR": "Afficher les minutes", "PL": "Pokaż minuty", "FI": "Minuutti näkymä", "ES": "Ver minutos" @@ -3582,7 +3582,7 @@ "PT-BR": "Visualização mudou!", "RU": "Просмотр изменен!", "NO": "Visning endret!", - "FR": "L'affichage du temps à changé !", + "FR": "La vue horaire a changé!", "PL": "Widok zmieniony!", "FI": "Näkymä vaihdettu!", "ES": "¡Vista cambiada!" @@ -3595,7 +3595,7 @@ "PT-BR": "A raid já está ativa!", "RU": "Рейд уже активен!", "NO": "Raidet er allerede aktivt!", - "FR": "Le raid est déjà en cours", + "FR": "Le raid est déjà en cours!", "PL": "Rajd się już zaczął", "FI": "Raidi on jo aktiivinen!", "ES": "¡Ya está activa!" @@ -3608,7 +3608,7 @@ "PT-BR": "Você não tem permissão para editar esta raid!", "RU": "Вы не можете редактировать этот рейд!", "NO": "Du har ikke tillatelse til å redigere dette raidet!", - "FR": "Tu n'es pas autorisé à modifier ce raid", + "FR": "Vous n'êtes pas autorisé à modifier ce raid!", "PL": "Nie masz uprawnień aby edytować Rajd!", "FI": "Et voi muuttaa tätä raidia!", "ES": "¡No tienes permiso para editar esta incursión!" @@ -3621,7 +3621,7 @@ "PT-BR": "Nenhuma raid ativa encontrada no sistema!", "RU": "Не найдено активных рейдов в системе!", "NO": "Ingen aktive raid i systemet!", - "FR": "Aucun raid en cours trouvé dans le système", + "FR": "Aucun raid en cours n'a été trouvé dans le système!", "PL": "W tym momencie nie ma żadnych aktywnych Rajdów w systemie", "FI": "Järjestelmästä ei löytynyt aktiivisia raideja!", "ES": "¡No se han encontrado incursiones activas en el sistema!" @@ -3634,7 +3634,7 @@ "PT-BR": "Nenhuma das raids ativas foi compartilhada!", "RU": "Активными рейдами не делились!", "NO": "Ingen av de aktive raidene ble delt!", - "FR": "Aucun raid en cours n'a été partagé", + "FR": "Aucun raid en cours n'a été partagé!", "PL": "Żaden z aktywnych rajdów nie został udostępniony!", "FI": "Yhtäkään aktiivista raidia ei ole jaettu!", "ES": "¡Ninguna de las incursiones activas fue compartida!" @@ -3647,7 +3647,7 @@ "PT-BR": "Nenhuma raid ativa no momento!", "RU": "Нету текущих активных рейдов!", "NO": "Det er ingen aktive raid akkurat nå!", - "FR": "Aucun raid en cours", + "FR": "Aucun raid en cours actuellement!", "PL": "Brak aktywnych Rajdów w tej chwili!", "FI": "Ei aktiivisia raideja tällä hetkellä!", "ES": "¡Actualmente no hay incursiones activas!" @@ -3660,7 +3660,7 @@ "PT-BR": "Pokemon salvo ", "RU": "Покемон сохранен:", "NO": "Pokemon lagret:", - "FR": "Pokémon enregistré", + "FR": "Pokémon enregistré: ", "PL": "Pokemon zapisany:", "FI": "Pokemoni tallennettu:", "ES": "Pokémon guardado:" @@ -3673,7 +3673,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier Pokémon", "PL": "TRANSLATE", "FI": "Muuta Pokemonia", "ES": "Editar Pokémon" @@ -3686,7 +3686,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Afficher, modifier et importer des boss de raid", "PL": "TRANSLATE", "FI": "Listaa, muuta ja tuo raidibosseja", "ES": "Ver, editar e importar jefes de incursión" @@ -3699,7 +3699,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Afficher les boss de raid actuels", "PL": "TRANSLATE", "FI": "Listaa tämänhetkiset raidibossit", "ES": "Ver actuales jefes de incursión" @@ -3712,7 +3712,7 @@ "PT-BR": "Lista de todos os Pokémon.", "RU": "Список всех покемонов", "NO": "Liste over alle pokemon", - "FR": "Liste de tous les Pokémon", + "FR": "Liste de tous les Pokémon.", "PL": "Lista wszystkich Pokemonów.", "FI": "Listaa kaikki Pokemonit.", "ES": "Lista de todos los Pokémon." @@ -3725,7 +3725,7 @@ "PT-BR": "Erro! Nenhum pokemon encontrado!", "RU": "Ошибка! Покемон не найден!", "NO": "Feil: Ingen pokemon funnet!", - "FR": "Erreur, aucun Pokémon trouvé !", + "FR": "Erreur! Aucun Pokémon trouvé!", "PL": "Błąd! Pokemona nie znaleziono!", "FI": "Virhe! Pokemoneja ei löytynyt!", "ES": "¡Error! ¡No se encontró ningún Pokémon!" @@ -3738,7 +3738,7 @@ "PT-BR": "Selecione o chefe de raid para modificar:", "RU": "Выберите рейд босса для редактирования", "NO": "Velg raid boss som skal redigeres:", - "FR": "Sélectionne un boss de raid à modifier", + "FR": "Sélectionnez un boss de raid à modifier:", "PL": "Wybierz Bossa Rajdu żeby edytować:", "FI": "Valitse raidibossi muokattavaksi:", "ES": "Selecciona jefe de incursión para editar:" @@ -3751,7 +3751,7 @@ "PT-BR": "Nível da reide", "RU": "Уровень рейда", "NO": "Raid level", - "FR": "Niveau du raid", + "FR": "Niveau de raid", "PL": "Poziom Rajdu", "FI": "Raidin taso", "ES": "Nivel de incursión" @@ -3764,7 +3764,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Tous les niveaux de raid", "PL": "TRANSLATE", "FI": "Kaikki raiditasot", "ES": "Todos niveles de incursión" @@ -3790,7 +3790,7 @@ "PT-BR": "Nível atual da reide", "RU": "Текущий уровень рейда", "NO": "Nåværende raid level:", - "FR": "Niveau actuel du raid", + "FR": "Niveau actuel de raid:", "PL": "Aktualny poziom Rajdu:", "FI": "Nykyinen raiditaso:", "ES": "Nivel de incursión actual:" @@ -3803,7 +3803,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Nouveau statut", "PL": "TRANSLATE", "FI": "Uusi arvo", "ES": "Nuevo estado" @@ -3816,7 +3816,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Statut actuel:", "PL": "TRANSLATE", "FI": "Nykyinen arvo:", "ES": "Estado actual:" @@ -3829,7 +3829,7 @@ "PT-BR": "Selecione a opção para modificar:", "RU": "Выберите функцию для изменения:", "NO": "Velg egenskap som skal endres:", - "FR": "Sélectionne l'option à changer", + "FR": "Sélectionnez l'option à modifier:", "PL": "Wybierz aby edytować:", "FI": "Valitse muutettava ominaisuus:", "ES": "Selecciona la característica a cambiar:" @@ -3842,7 +3842,7 @@ "PT-BR": "PC:", "RU": "CP", "NO": "CP:", - "FR": "PC", + "FR": "PC:", "PL": "CP", "FI": "CP:", "ES": "PC:" @@ -3855,7 +3855,7 @@ "PT-BR": "Min PC", "RU": "Min CP", "NO": "Min CP", - "FR": "PC Min", + "FR": "PC min.", "PL": "Min CP", "FI": "Min CP", "ES": "Mín. PC" @@ -3868,7 +3868,7 @@ "PT-BR": "Max PC", "RU": "Max CP", "NO": "Maks CP", - "FR": "PC Max", + "FR": "PC max.", "PL": "Max CP", "FI": "Max CP", "ES": "Máx. PC" @@ -3881,7 +3881,7 @@ "PT-BR": "PC mín. potenciado", "RU": "Min boosted CP", "NO": "Min boostet CP", - "FR": "PC Min boosté", + "FR": "PC min. renforcés", "PL": "Min boosted CP", "FI": "Min buustattu CP", "ES": "Mín. PC potenciado" @@ -3894,7 +3894,7 @@ "PT-BR": "PC máx. potenciado", "RU": "Max boosted CP", "NO": "Maks boostet CP", - "FR": "PC Max boosté", + "FR": "PC max. renforcés", "PL": "Max Boosted CP", "FI": "Max buustattu CP", "ES": "Máx. PC potenciado" @@ -3907,7 +3907,7 @@ "PT-BR": "PC atual:", "RU": "Текущий CP:", "NO": "Nåværende CP:", - "FR": "PC actuel", + "FR": "PC actuels:", "PL": "Aktualne CP", "FI": "Nykyinen CP:", "ES": "PC actual:" @@ -3933,7 +3933,7 @@ "PT-BR": "Clima atual:", "RU": "Текущая погода:", "NO": "Værforhold:", - "FR": "Météo actuelle", + "FR": "Météo actuelle:", "PL": "Aktualna pogoda:", "FI": "Tämänhetkinen sää:", "ES": "Clima actual:" @@ -3946,7 +3946,7 @@ "PT-BR": "Novo clima:", "RU": "Новая погода:", "NO": "Været har endret seg:", - "FR": "Nouvelle météo", + "FR": "Nouvelle météo:", "PL": "Nowa pogoda:", "FI": "Uusi sää:", "ES": "Nuevo clima:" @@ -3959,7 +3959,7 @@ "PT-BR": "Quanto tempo a reide vai durar", "RU": "Как долго рейд будет идти?", "NO": "Hvor lenge varer raidet?", - "FR": "Dans combien de temps termine le raid ?", + "FR": "Dans combien de temps se termine le raid?", "PL": "Jak długo Rajd będzie trwać?", "FI": "Kauanko raidi kestää?", "ES": "¿Cuánto durará la incursión?" @@ -3985,7 +3985,7 @@ "PT-BR": "Escolha o ginásio:", "RU": "Выберите Гим:", "NO": "Velg Gym:", - "FR": "Sélectionne l'arène", + "FR": "Sélectionnez l'arène:", "PL": "Wybierz Arene:", "FI": "Valitse sali:", "ES": "Por favor, selecciona el gimnasio:" @@ -3998,7 +3998,7 @@ "PT-BR": "Bora arrasar!", "RU": "А вот и мы!", "NO": "Kjør på!", - "FR": "C'est parti !", + "FR": "C'est parti!", "PL": "Zaczynamy!", "FI": "Nyt mennään!", "ES": "¡Aquí vamos!" @@ -4024,7 +4024,7 @@ "PT-BR": "Coordenadas enviadas com sucesso!", "RU": "Координаты успешно отправлены!", "NO": "Koordinater ble lagt til!", - "FR": "Coordonnées créés avec succès ", + "FR": "Coordonnées envoyées avec succès!", "PL": "Koordynaty dodano pomyślnie!", "FI": "Koordinaatit lähetetty onnistuneesti!", "ES": "¡Coordenadas enviadas con éxito!" @@ -4037,7 +4037,7 @@ "PT-BR": "Atualizar chefe da reide", "RU": "Обновить рейд босса", "NO": "Oppdater raid boss", - "FR": "Mise à jour boss de raid", + "FR": "Mettre à jour boss de raid", "PL": "Aktualizacja Bossa Rajdu", "FI": "Päivitä raidibossi", "ES": "Actualizar jefe de incursión" @@ -4050,7 +4050,7 @@ "PT-BR": "Atualizar Pokemon", "RU": "Обновить Покемона", "NO": "Oppdater Pokemon", - "FR": "Mise à jour Pokémon", + "FR": "Mettre à jour Pokémon", "PL": "Aktualizacja Pokemona", "FI": "Päivitä Pokemoni", "ES": "Actualizar Pokémon" @@ -4076,7 +4076,7 @@ "PT-BR": "Por favor, antes me envie a localização.", "RU": "Или отправить мне локацию", "NO": "Eller send meg lokasjonen din ved å trykke på bindersen", - "FR": "Ou envoi moi la localisation", + "FR": "Ou envoyez-moi la localisation.", "PL": "Albo wyślij mi swoje położenie", "FI": "Tai lähetä minulle sijainti.", "ES": "O envíame una ubicación." @@ -4089,7 +4089,7 @@ "PT-BR": "Ou escolha uma raid por ginásio:", "RU": "Сделать рейд, выбрав гим:", "NO": "Opprett raid ved å velge fra gym listen", - "FR": "Faire une sélection de raid par arène", + "FR": "Créer un raid en sélectionnant une arène:", "PL": "Wygeneruj nowy Rajd, wybierając Arene:", "FI": "Luo raidi salivalinnan mukaan:", "ES": "Crear incursión con selección de gimnasio:" @@ -4141,7 +4141,7 @@ "PT-BR": "Time do ginásio escolhido para", "RU": "Команду гима:", "NO": "Gym Team endret til:", - "FR": "Couleur d'arène réglée sur", + "FR": "Équipe d'arène réglée sur:", "PL": "Kolor Areny zmieniony na:", "FI": "Salin joukkueeksi asetettu:", "ES": "Equipo de gimnasio puesto en:" @@ -4154,7 +4154,7 @@ "PT-BR": "Nome de time inválido - escreva: Mystic, Valor, Instinct ou Blue, Red, Yellow", "RU": "Неверное имя команд - напишите: Mystic, Valor, Instinct или Синий, Красный, Желтый", "NO": "Ugyldig team navn - skriv: Mystic, Valor, Instinct or Blue, Red, Yellow", - "FR": "Couleur invalide - écrit : Sagesse, Bravoure, Intuition ou Bleu, Rouge, Jaune", + "FR": "Équipe invalide - écrivez : Sagesse, Bravoure, Intuition ou Bleu, Rouge, Jaune ", "PL": "Zła nazwa Teamu - napisz: niebieski, czerwony albo żółty", "FI": "Virheellinen joukkueen nimi - kirjoita: Mystic, Valor, Instinct tai Blue, Red, Yellow", "ES": "Nombre de equipo invalido - escribe: Sabiduría, Valor, Instinto o Azul, Rojo, Amarillo" @@ -4167,7 +4167,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Utilisez les commandes suivantes pour modifier davantage l'arène:", "PL": "TRANSLATE", "FI": "Käytä seuraavia komentoja muokataksesi salia enemmän:", "ES": "Utiliza los siguientes comandos para editar más el gimnasio:" @@ -4180,7 +4180,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Pour obtenir l'identifiant de l'arène et plus de détails, utilisez la commande /gym.", "PL": "TRANSLATE", "FI": "Saataksesi salin id numeron tai muita tietoja, käytä /gym -komentoa.", "ES": "Para obtener la identificación y más detalles del gimnasio, usa el comando /gym." @@ -4193,7 +4193,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Par exemple: /gymname Fontaine du parc!", "PL": "TRANSLATE", "FI": "Esimerkiksi: /gymname Vapauden Muistomerkki!", "ES": "Por ejemplo: /gymname Waterfall in the park" @@ -4206,7 +4206,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Erreur! Le nom de l'arène est manquant!", "PL": "TRANSLATE", "FI": "Virhe! Salin nimi puuttuu!", "ES": "TRANSLATE" @@ -4219,7 +4219,7 @@ "PT-BR": "Nome do ginásio atualizado.", "RU": "Название гима обновлено.", "NO": "Gym navn oppdatert.", - "FR": "Nom de l'arène mis à jour", + "FR": "Nom de l'arène mis à jour.", "PL": "Nazwa Areny zaktualizowana", "FI": "Salin nimi päivitetty.", "ES": "Nombre del gimnasio actualizado." @@ -4232,7 +4232,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier le nom de l'arène", "PL": "TRANSLATE", "FI": "Muokkaa salin nimeä", "ES": "TRANSLATE" @@ -4245,7 +4245,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Envoyez-moi le nom de l'arène:", "PL": "TRANSLATE", "FI": "Lähetä minulle salin nimi:", "ES": "TRANSLATE" @@ -4284,7 +4284,7 @@ "PT-BR": "Mostrar raids ativas como lista", "RU": "Показать активные рейды списком", "NO": "Vis aktive raid som liste", - "FR": "Voir les raids en cours", + "FR": "Afficher les raids en cours sous forme de liste", "PL": "Pokaż liste aktywnych rajdów", "FI": "Näytä aktiiviset raidit listana", "ES": "Mostrar incursiones activas como lista" @@ -4297,7 +4297,7 @@ "PT-BR": "Compartilhar / deletar detalhes de raid por chat", "RU": "поделиться / удалить обзор рейда через чат", "NO": "Del / slett raid oversikten per chat", - "FR": "Partager / supprimer l'aperçu des raids par conversation", + "FR": "Partager / supprimer l'aperçu de raid par conversation", "PL": "Udostępnij / usuń liste przez czat", "FI": "Jaa / poista raidiyleiskatsaus per chatti", "ES": "Compartir / eliminar la descripción general de la incursión por chat" @@ -4336,7 +4336,7 @@ "PT-BR": "Deletar detalhe de raid para", "RU": "Удалить обзор рейда для", "NO": "Slett raid oversikt for", - "FR": "Supprimer l'aperçu du raid pour", + "FR": "Supprimer l'aperçu de raid pour", "PL": "Usuń podgląd Rajdu dla", "FI": "Poista raidiyleiskatsaus chatista", "ES": "Eliminar descripción general de incursión para" @@ -4349,7 +4349,7 @@ "PT-BR": "Nenhum detalhe de raid encontrado no sistema!", "RU": "В системе нет обзора рейдов!", "NO": "Ingen oppsummering funnet i systemet!", - "FR": "Aucun aperçu de raid trouvé dans le système", + "FR": "Aucun aperçu de raid trouvé dans le système!", "PL": "Brak podglądów Rajdów w systemie!", "FI": "Järjestelmästä ei löytynyt raidi yleiskatsauksia!", "ES": "¡No se han encontrado descripciones generales en el sistema!" @@ -4362,7 +4362,7 @@ "PT-BR": "Detalhe de raid deletado com sucesso!", "RU": "Обзор рейдов успешно удален!", "NO": "Raid oppsummeringen ble slettet!", - "FR": "L'aperçu de raid a été supprimé", + "FR": "L'aperçu de raid a été supprimé!", "PL": "Podgląd Rajdu usunięty!", "FI": "Raidi yleiskatsaus poistettu onnistuneesti!", "ES": "¡Descripción general eliminada con éxito!" @@ -4375,7 +4375,7 @@ "PT-BR": "O deletamento dos detalhes da raid foi cancelado!", "RU": "Удаление обзора рейда было отменено!", "NO": "Sletting av raid oppsummeringen ble avbrutt!", - "FR": "La suppression de l'aperçu du raid a été annulée", + "FR": "La suppression de l'aperçu de raid a été annulée!", "PL": "Usuwanie podglądu anulowane!", "FI": "Raidi yleiskatsauksen poisto peruutettiin!", "ES": "¡Eliminación de la descripción general de la incursión cancelada!" @@ -4401,7 +4401,7 @@ "PT-BR": "Realmente deletar esta raid?", "RU": "Действительно удалить этот рейд?", "NO": "Skal du virkelig slette raidet?", - "FR": "Supprimer ce raid ?", + "FR": "Vraiment supprimer ce raid?", "PL": "Na pewno usunąć ten Rajd?", "FI": "Varmasti poista tämä raidi?", "ES": "¿De verdad eliminar esta incursión?" @@ -4414,7 +4414,7 @@ "PT-BR": "O deletamento da raid foi cancelado!", "RU": "Удаление рейда было отменено!", "NO": "Sletting av raidet ble avbrutt!", - "FR": "La suppression du raid a été annulée", + "FR": "La suppression du raid a été annulée!", "PL": "Usuwanie Rajdu anulowane!", "FI": "Raidin poisto peruutettiin!", "ES": "¡Eliminación de la incursión fue cancelada!" @@ -4427,7 +4427,7 @@ "PT-BR": "Raid deletado com sucesso!", "RU": "Рейд был успешно удален!", "NO": "Raidet ble slettet", - "FR": "Le raid a été annulé", + "FR": "Le raid a été supprimé avec succès!", "PL": "Rajd usunięty!", "FI": "Raidi poistettiin onnistuneesti!", "ES": "¡Incursión eliminada con éxito!" @@ -4440,7 +4440,7 @@ "PT-BR": "A qualquer momento", "RU": "В любое время", "NO": "Alle tider passer", - "FR": "A tout moment", + "FR": "À tout moment", "PL": "W każdej chwili", "FI": "Milloin tahansa", "ES": "Cualquiera hora" @@ -4466,7 +4466,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Notifications de raid désactivées!", "PL": "TRANSLATE", "FI": "Raidihäly pois käytöstä!", "ES": "¡Alertas de incursión desactivadas!" @@ -4479,7 +4479,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Notifications de raid activées!", "PL": "TRANSLATE", "FI": "Raidihäly käytössä!", "ES": "¡Alertas de incursión activadas!" @@ -4492,7 +4492,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Activer les notifications de raid automatiques", "PL": "TRANSLATE", "FI": "Automaattinen raidihäly päälle", "ES": "Activar alertas automáticas de incursiones" @@ -4505,7 +4505,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Désactiver les notifications de raid automatiques", "PL": "TRANSLATE", "FI": "Automaattinen raidihäly pois päältä", "ES": "Desactivar alertas automáticas de incursiones" @@ -4518,7 +4518,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Dresseur supplémentaire!", "PL": "TRANSLATE", "FI": "Uusi osallistuja!", "ES": "¡Entrenador adicional!" @@ -4531,7 +4531,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "L'utilisateur invite un dresseur en dehors du groupe!", "PL": "TRANSLATE", "FI": "Pelaaja kutsuu kaverin ryhmän ulkopuolelta!", "ES": "¡Usuario está invitando a un entrenador fuera del grupo!" @@ -4544,7 +4544,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Dresseur en retard!", "PL": "TRANSLATE", "FI": "Myöhästyvä osallistuja!", "ES": "¡Entrenador tarda!" @@ -4557,7 +4557,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Annulation!", "PL": "TRANSLATE", "FI": "Peruutus!", "ES": "¡Cancelación!" @@ -4570,7 +4570,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vient pour", "PL": "TRANSLATE", "FI": "Ilmoittautuneet,", "ES": "Viene para" @@ -4583,7 +4583,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ne vient PAS pour", "PL": "TRANSLATE", "FI": "Peruuttaneet,", "ES": "NO viene para" @@ -4596,7 +4596,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vient pour", "PL": "TRANSLATE", "FI": "Ilmoittautuneet,", "ES": "Viene para" @@ -4609,7 +4609,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Nouvelle participation!", "PL": "TRANSLATE", "FI": "Uusi osallistuja!", "ES": "¡Nueva participación!" @@ -4622,7 +4622,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Participation à distance!", "PL": "TRANSLATE", "FI": "Etäosallistuminen!", "ES": "¡Participación remota!" @@ -4635,7 +4635,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Pas plus de participants à distance!", "PL": "TRANSLATE", "FI": "Ei enää etäosallistujia!", "ES": "¡No más participación remota!" @@ -4648,7 +4648,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Le raid commence maintenant!", "PL": "TRANSLATE", "FI": "Raidi alkaa nyt!", "ES": "¡La incursión empieza ahora!" @@ -4661,7 +4661,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Voici comment participer au combat:", "PL": "TRANSLATE", "FI": "Näin pääset taisteluun:", "ES": "Cómo entrar en la batalla:" @@ -4674,7 +4674,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Groupe de raid privé!", "PL": "TRANSLATE", "FI": "Yksityinen raidiryhmä!", "ES": "¡Grupo de incursión privado!" @@ -4687,7 +4687,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Groupe de raid publique!", "PL": "TRANSLATE", "FI": "Julkinen raidiryhmä!", "ES": "¡Grupo de incursión público!" @@ -4700,7 +4700,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Nouvelle heure de participation!", "PL": "TRANSLATE", "FI": "Uusi aika!", "ES": "¡Nueva hora de participación!" @@ -4713,7 +4713,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Boss de raid mis à jour!", "PL": "TRANSLATE", "FI": "Raidibossi päivitetty!", "ES": "¡Jefe de incursión actualizado!" @@ -4726,7 +4726,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Pas plus de dresseurs supplémentaires!", "PL": "TRANSLATE", "FI": "Ei ylimääräisiä kouluttajia!", "ES": "¡Sin entrenadores adicionales!" @@ -4739,7 +4739,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Souhaite être invité.", "PL": "TRANSLATE", "FI": "Toivoo tulevansa kutsutuksi.", "ES": "Desea ser invitado." @@ -4752,7 +4752,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ne souhaite plus être invité.", "PL": "TRANSLATE", "FI": "Ei enää toivo kutsua.", "ES": "Ya no desea ser invitado." @@ -4765,7 +4765,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ne participe pas mais peut envoyer des invitations.", "PL": "TRANSLATE", "FI": "Ei osallistu raidiin, mutta voi lähettää kutsuja.", "ES": "No asiste pero puede enviar invitaciones." @@ -4778,7 +4778,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ne peut plus envoyer des invitations.", "PL": "TRANSLATE", "FI": "Ei enää pysty kutsumaan muita.", "ES": "Ya no puede invitar a otros." @@ -4791,7 +4791,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Événement", "PL": "TRANSLATE", "FI": "Tapahtuma", "ES": "Evento" @@ -4804,7 +4804,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Notice d'événement", "PL": "TRANSLATE", "FI": "Tapahtuman lisätiedot", "ES": "Nota de evento" @@ -4817,7 +4817,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ajouter notice d'événement", "PL": "TRANSLATE", "FI": "Lisää raiditapahtumaan lisätietoja", "ES": "Añadir nota de evento" @@ -4830,7 +4830,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier notice d'événement", "PL": "TRANSLATE", "FI": "Muokkaa raiditapahtuman lisätietoja", "ES": "Editar nota de evento" @@ -4843,7 +4843,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Ajouter plus d'informations pour cette annonce d'événement. (par exemple: itinéraire)", "PL": "TRANSLATE", "FI": "Lisää ilmoituskohtaisia lisätietoja tapahtumaan liittyen. (esim. reitti)", "ES": "Agrega más información para este anuncio específico sobre el evento. (por ejemplo: ruta)" @@ -4856,7 +4856,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Gérer les événements", "PL": "TRANSLATE", "FI": "Hallitse tapahtumia", "ES": "TRANSLATE" @@ -4869,7 +4869,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Créer un nouvel événement", "PL": "TRANSLATE", "FI": "Luo uusi tapahtuma", "ES": "TRANSLATE" @@ -4882,7 +4882,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Événement créé avec succès!", "PL": "TRANSLATE", "FI": "Tapahtuma luotu onnistuneesti!", "ES": "TRANSLATE" @@ -4895,7 +4895,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Nommer l'événement", "PL": "TRANSLATE", "FI": "Anna tapahtuman nimi", "ES": "TRANSLATE" @@ -4908,7 +4908,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Décrire l'événement", "PL": "TRANSLATE", "FI": "Anna tapahtuman lisätiedot", "ES": "TRANSLATE" @@ -4921,7 +4921,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Aucune description", "PL": "TRANSLATE", "FI": "Ei kuvausta", "ES": "TRANSLATE" @@ -4934,7 +4934,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier le nom de l'événement", "PL": "TRANSLATE", "FI": "Muokkaa tapahtuman nimeä", "ES": "TRANSLATE" @@ -4947,7 +4947,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier la description de l'événement", "PL": "TRANSLATE", "FI": "Muokkaa tapahtuman kuvausta", "ES": "TRANSLATE" @@ -4960,7 +4960,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Modifier l'annonce de l'événement de raid", "PL": "TRANSLATE", "FI": "Muokkaa tapahtuman raidi-ilmoitusta", "ES": "TRANSLATE" @@ -4973,7 +4973,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Supprimer l'événement", "PL": "TRANSLATE", "FI": "Poista tapahtuma", "ES": "TRANSLATE" @@ -4986,7 +4986,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vraiment supprimer cet événement?", "PL": "TRANSLATE", "FI": "Haluatko varmasti poistaa tämän tapahtuman?", "ES": "TRANSLATE" @@ -4999,7 +4999,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Participer", "PL": "TRANSLATE", "FI": "Osallistu", "ES": "Participar" @@ -5012,7 +5012,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Participe", "PL": "TRANSLATE", "FI": "Osallistuu", "ES": "Participando" @@ -5025,7 +5025,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Vous n'avez pas encore enregistré vos informations de dresseur. Voulez-vous le faire maintenant?", "PL": "TRANSLATE", "FI": "Et ole vielä tallentanut tietoja pelihahmostasi. Haluaisitko tehdä sen nyt?", "ES": "Aún no has guardado la información de tu entrenador. ¿Te gustaría hacerlo ahora?" @@ -5038,7 +5038,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Afficher l'historique des annonces de raid.", "PL": "TRANSLATE", "FI": "Katsele vanhoja raidi-ilmoituksia.", "ES": "Ver historial de anuncios de incursiones." @@ -5051,7 +5051,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Affichage en cours des raids pour", "PL": "TRANSLATE", "FI": "Tällä hetkellä näytetään", "ES": "Actualmente se muestran incursiones para" @@ -5064,7 +5064,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Choisir un raid", "PL": "TRANSLATE", "FI": "Valitse raidi", "ES": "Selecciona incursión" @@ -5077,7 +5077,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Aucun raid avec participants trouvé!", "PL": "TRANSLATE", "FI": "Yhtään raidia ei löytynyt jossa olisi osallistujia!", "ES": "¡No se encontraron incursiones con los asistentes!" @@ -5090,7 +5090,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Date", "PL": "TRANSLATE", "FI": "Päivämäärä", "ES": "Fecha" @@ -5103,7 +5103,7 @@ "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "TRANSLATE", + "FR": "Zone actuelle", "PL": "TRANSLATE", "FI": "Salit alueelta", "ES": "Zona de gimnasio actual" From 3bb253f975b44b62f36a3ed2a6fe64b61a90f2a8 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:14:52 +0200 Subject: [PATCH 333/367] Improved logic on mapping Pokebattler names to pokemon_id and form_id --- constants.php | 25 +++++++++++-- logic/read_upcoming_bosses.php | 3 ++ logic/resolvePokebattlerNameToIds.php | 51 +++++++++++++++++++++++++++ mods/import_shinyinfo.php | 5 ++- 4 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 logic/resolvePokebattlerNameToIds.php diff --git a/constants.php b/constants.php index f74e85b8..d01c501b 100644 --- a/constants.php +++ b/constants.php @@ -65,6 +65,27 @@ // Limit the tiers of upcoming raid bosses imported from PokeBattler to legendary and mega $pokebattler_import_future_tiers = [5, 6, 7, 8, 9, 10, 15]; +define('TYPE_MAP_PROTO_TO_ID', [ + 'POKEMON_TYPE_NORMAL' => 1, + 'POKEMON_TYPE_FIGHTING' => 2, + 'POKEMON_TYPE_FLYING' => 3, + 'POKEMON_TYPE_POISON' => 4, + 'POKEMON_TYPE_GROUND' => 5, + 'POKEMON_TYPE_ROCK' => 6, + 'POKEMON_TYPE_BUG' => 7, + 'POKEMON_TYPE_GHOST' => 8, + 'POKEMON_TYPE_STEEL' => 9, + 'POKEMON_TYPE_FIRE' => 10, + 'POKEMON_TYPE_WATER' => 11, + 'POKEMON_TYPE_GRASS' => 12, + 'POKEMON_TYPE_ELECTRIC' => 13, + 'POKEMON_TYPE_PSYCHIC' => 14, + 'POKEMON_TYPE_ICE' => 15, + 'POKEMON_TYPE_DRAGON' => 16, + 'POKEMON_TYPE_DARK' => 17, + 'POKEMON_TYPE_FAIRY' => 18, +]); + // Default language. defined('DEFAULT_LANGUAGE') or define('DEFAULT_LANGUAGE', 'EN'); @@ -83,7 +104,7 @@ // Value used for denoting anytime attendance define('ANYTIME', '1970-01-01 00:00:00'); -define('ANYTIME_TS', preg_replace("/[^0-9]/", "", ANYTIME)); +define('ANYTIME_TS', preg_replace('/[^0-9]/', '', ANYTIME)); // Icons. defined('TEAM_B') or define('TEAM_B', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F499))); @@ -135,7 +156,7 @@ defined('CR') or define('CR', "\n"); defined('CR2') or define('CR2', "\n"); // Space. -defined('SP') or define('SP', " "); +defined('SP') or define('SP', ' '); // Weather. $weather = array( diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index f3fea304..8fb9a95d 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -44,6 +44,9 @@ function read_upcoming_bosses($return_sql = false, $levelsToRead = false) { $boss = $news['pokemon']; $dex_id_form = resolve_boss_name_to_ids($boss); + // Exit if resolving boss failed + if($dex_id_form[0] == 0) continue; + // In case Pokebattler keeps using RAID_LEVEL_MEGA_5 (legendary mega tier) for primal raids if(in_array($dex_id_form[0], PRIMAL_MONS) && $raid_level_id == 7) { $raid_level_id = 10; diff --git a/logic/resolvePokebattlerNameToIds.php b/logic/resolvePokebattlerNameToIds.php new file mode 100644 index 00000000..a5fb8ab3 --- /dev/null +++ b/logic/resolvePokebattlerNameToIds.php @@ -0,0 +1,51 @@ + [29, 776], + 'WURMPLE_NOEVOLVE_FORM' => [265, 600], + ]; + if(isset($hardCoded[$protoName])) return $hardCoded[$protoName]; + $data = createProtoNames(); + if(isset($data[$protoName])) return $data[$protoName]; + return false; +} + +function createProtoNames() { + static $result = []; + if($result !== []) return $result; + + $megaForms = ['','MEGA','MEGA_X','MEGA_Y','PRIMAL']; + $data = json_decode(curl_get_contents('https://raw.githubusercontent.com/WatWowMap/Masterfile-Generator/master/master-latest.json'), true); + foreach($data['pokemon'] as $pokemon) { + $protoNameBase = str_replace("♂","_MALE",str_replace("♀","_FEMALE",preg_replace("/\s/","_",strtoupper($pokemon['name'])))); + $formCount = count($pokemon['forms']); + $i = 1; + foreach($pokemon['forms'] as $formId => $form) { + if($formId == "0" && $formCount > 1) continue; + if($formId == (string)$pokemon['default_form_id']) { + $result[$protoNameBase] = [$pokemon['pokedex_id'], (int)$formId]; + $result[$form['proto'].'_FORM'] = [$pokemon['pokedex_id'], (int)$formId]; + }elseif($i == $formCount-1 && $pokemon['default_form_id'] == 0) { // Some random logic for Xerneas + $result[$protoNameBase] = [$pokemon['pokedex_id'], (int)$formId]; + }else { + if($form['proto'] == $protoNameBase.'_NORMAL') $protoName = $protoNameBase; + else $protoName = $form['proto'].'_FORM'; + $result[$protoName] = [$pokemon['pokedex_id'], (int)$formId]; + } + $i++; + } + if(!isset($pokemon['temp_evolutions'])) continue; + foreach($pokemon['temp_evolutions'] as $evoId => $evo) { + $result[$protoNameBase.'_'.$megaForms[(int)$evoId]] = [$pokemon['pokedex_id'], (int)$evoId]; + } + } + return $result; +} diff --git a/mods/import_shinyinfo.php b/mods/import_shinyinfo.php index 6eb50f2c..b1185809 100644 --- a/mods/import_shinyinfo.php +++ b/mods/import_shinyinfo.php @@ -2,6 +2,7 @@ // Write to log. debug_log('pokebattler()'); require_once(LOGIC_PATH . '/curl_get_contents.php'); +require_once(LOGIC_PATH . '/resolvePokebattlerNameToIds.php'); // For debug. //debug_log($update); @@ -10,8 +11,6 @@ // Check access. $botUser->accessCheck('pokedex'); -include(LOGIC_PATH . '/resolve_boss_name_to_ids.php'); - $link = 'https://fight.pokebattler.com/raids'; $pb_data = curl_get_contents($link); $pb_data = json_decode($pb_data,true); @@ -32,7 +31,7 @@ if(!isset($raid['pokemon']) || $raid['shiny'] != 'true') continue; // Get ID and form name used internally. - [$dex_id, $dex_form] = resolve_boss_name_to_ids($raid['pokemon']); + [$dex_id, $dex_form] = resolvePokebattlerNameToIds($raid['pokemon']); // Make sure we received a valid dex id. if(!is_numeric($dex_id) || $dex_id == 0) { From f4c7dce20644f691cad698a462515051d702fa00 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:16:26 +0200 Subject: [PATCH 334/367] Some error handling on curl timeout --- core/bot/cleanup_run.php | 4 ++-- core/telegram/functions.php | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/bot/cleanup_run.php b/core/bot/cleanup_run.php index 0e124a42..5df8138b 100644 --- a/core/bot/cleanup_run.php +++ b/core/bot/cleanup_run.php @@ -57,12 +57,12 @@ function perform_cleanup(){ cleanup_log('Telegram cleanup starting. Found ' . $rs->rowCount() . ' entries for cleanup.'); if($rs->rowCount() > 0) { while($row = $rs->fetch()) { - $cleanup_ids[] = $row['id']; if($row['skip_del_message'] == 1) { cleanup_log('Chat message for raid '.$row['raid_id'].' in chat '.$row['chat_id'].' is over 48 hours old. It can\'t be deleted by the bot. Skipping deletion and removing database entry.'); continue; } - delete_message($row['chat_id'], $row['message_id']); + if(delete_message($row['chat_id'], $row['message_id']) === false) continue; + $cleanup_ids[] = $row['id']; cleanup_log('Deleting raid: '.$row['raid_id'].' from chat '.$row['chat_id'].' (message_id: '.$row['message_id'].')'); if ($metrics){ $cleanup_total->inc(['telegram']); diff --git a/core/telegram/functions.php b/core/telegram/functions.php index 8cd278bd..9291f1cc 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -751,7 +751,9 @@ function curl_json_request($post_contents, $identifier) $json_response = curl_exec($curl); if($json_response === false) { - info_log(curl_error($curl)); + info_log(curl_error($curl)); + curl_close($curl); + return false; } // Close connection. From 55bfbef31c54927c0417622ba2142df069309df1 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 15 Mar 2024 18:16:41 +0200 Subject: [PATCH 335/367] Translation fixes --- logic/alarm.php | 6 +++--- logic/createRaidBossList.php | 6 ++---- logic/get_overview.php | 2 +- logic/get_raid_times.php | 20 +++++++------------- logic/raid_picture.php | 2 +- logic/sendalarmnotice.php | 5 +++-- logic/show_raid_poll.php | 4 ++-- logic/show_raid_poll_small.php | 6 +++--- mods/edit_event_note.php | 2 +- mods/edit_save.php | 2 +- mods/list_raid.php | 2 +- mods/share_raid_by_location.php | 2 +- 12 files changed, 26 insertions(+), 33 deletions(-) diff --git a/logic/alarm.php b/logic/alarm.php index 2bcfc65f..ca242ed8 100644 --- a/logic/alarm.php +++ b/logic/alarm.php @@ -36,7 +36,6 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) $raid_id = $raid['id']; $gymname = $raid['gym_name']; - $raidtimes = str_replace(CR, '', str_replace(' ', '', get_raid_times($raid, false, true))); // Get attend time. if(!in_array($action, ['new_att','new_boss','change_time','group_code_private','group_code_public'])) { @@ -73,6 +72,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) { if(!isset($answer['lang']) or empty($answer['lang'])) $recipient_language = $config->LANGUAGE_PUBLIC; else $recipient_language = $GLOBALS['languages'][$answer['lang']]; + $raidtimes = str_replace(CR, '', str_replace(' ', '', get_raid_times($raid, $recipient_language, true))); // Adding a guest if($action == 'extra') { debug_log('Alarm additional trainer: ' . $info); @@ -115,7 +115,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) if($info != '0') { // Only a specific pokemon $pokemon = explode("-",$info,2); - $poke_name = get_local_pokemon_name($pokemon[0],$pokemon[1]); + $poke_name = get_local_pokemon_name($pokemon[0], $pokemon[1], $recipient_language); $msg_text = '' . getTranslation('alert_individual_poke', $recipient_language) . SP . $poke_name . '' . CR; } else { // Any pokemon @@ -130,7 +130,7 @@ function alarm($raid_id_array, $user_id, $action, $info = '', $tg_json = []) } else if($action == 'pok_cancel_individual') { debug_log('Alarm Pokemon: ' . $info); $pokemon = explode("-",$info,2); - $poke_name = get_local_pokemon_name($pokemon[0],$pokemon[1]); + $poke_name = get_local_pokemon_name($pokemon[0], $pokemon[1], $recipient_language); $msg_text = '' . getTranslation('alert_cancel_individual_poke', $recipient_language) . SP . $poke_name . '' . CR; $msg_text .= EMOJI_HERE . SP . $gymname . SP . '(' . $raidtimes . ')' . CR; $msg_text .= EMOJI_SINGLE . SP . $username . CR; diff --git a/logic/createRaidBossList.php b/logic/createRaidBossList.php index ab0fc3b6..bda93c23 100644 --- a/logic/createRaidBossList.php +++ b/logic/createRaidBossList.php @@ -1,6 +1,4 @@ $row) { - $pokemonName = get_local_pokemon_name($row['pokedex_id'], $row['pokemon_form_id']); + $pokemonName = get_local_pokemon_name($row['pokedex_id'], $row['pokemon_form_id'], $config->LANGUAGE_PUBLIC); if($num != 0) $list .= ', '; $list .= $pokemonName; } @@ -70,7 +68,7 @@ function createRaidBossList() { } $list .= PHP_EOL . '- '; } - $pokemonName = get_local_pokemon_name($row['pokedex_id'], $row['pokemon_form_id']); + $pokemonName = get_local_pokemon_name($row['pokedex_id'], $row['pokemon_form_id'], $config->LANGUAGE_PUBLIC); if($num != 0) $list .= ', '; $list .= $pokemonName; $prevStartDate = $startDate; diff --git a/logic/get_overview.php b/logic/get_overview.php index 7621bb63..966ed576 100644 --- a/logic/get_overview.php +++ b/logic/get_overview.php @@ -60,7 +60,7 @@ function get_overview( $active_raids, $chat_title, $chat_username ) // Raid has not started yet - adjust time left message if ($now < $start_time) { - $msg .= get_raid_times($row, true); + $msg .= get_raid_times($row, $config->LANGUAGE_PUBLIC); // Raid has started already } else { // Add time left message. diff --git a/logic/get_raid_times.php b/logic/get_raid_times.php index a8fc8dd0..6f408e6e 100644 --- a/logic/get_raid_times.php +++ b/logic/get_raid_times.php @@ -2,19 +2,13 @@ /** * Get raid time message. * @param array $raid - * @param bool $override_language + * @param bool $language * @param bool $unformatted * @return string */ -function get_raid_times($raid, $override_language = true, $unformatted = false) +function get_raid_times($raid, $language = null, $unformatted = false) { global $config; - // Get translation type - if($override_language == true) { - $getTypeTranslation = 'getPublicTranslation'; - } else { - $getTypeTranslation = 'getTranslation'; - } // Init empty message string. $msg = ''; @@ -31,8 +25,8 @@ function get_raid_times($raid, $override_language = true, $unformatted = false) $year_start = utctime($raid['start_time'], 'Y'); // Translation for raid day and month - $raid_day = $getTypeTranslation('weekday_' . $weekday_start); - $raid_month = $getTypeTranslation('month_' . $month_start); + $raid_day = getTranslation('weekday_' . $weekday_start, $language); + $raid_month = getTranslation('month_' . $month_start, $language); // Days until the raid starts $dt_now = utcdate('now'); @@ -44,9 +38,9 @@ function get_raid_times($raid, $override_language = true, $unformatted = false) // Raid times. if($unformatted == false) { if($config->RAID_POLL_POKEMON_NAME_FIRST_LINE == true) { - $msg .= get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], $override_language) . ':' . SP; + $msg .= get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form'], $language) . ':' . SP; } else { - $msg .= $getTypeTranslation('raid') . ':' . SP; + $msg .= getTranslation('raid', $language) . ':' . SP; } } // Is the raid in the same week? @@ -66,7 +60,7 @@ function get_raid_times($raid, $override_language = true, $unformatted = false) // Adds 'at 17:00' to the output. if($unformatted == false) { - $msg .= SP . $getTypeTranslation('raid_egg_opens_at'); + $msg .= SP . getTranslation('raid_egg_opens_at', $language); } $msg .= SP . dt2time($raid['start_time']); } else { diff --git a/logic/raid_picture.php b/logic/raid_picture.php index c0024410..44218d9c 100644 --- a/logic/raid_picture.php +++ b/logic/raid_picture.php @@ -489,7 +489,7 @@ function create_raid_picture($raid, $standalone_photo = false, $debug = false) { // Raid times if(!$raid['raid_ended']) { - $time_text = get_raid_times($raid, true, true); + $time_text = get_raid_times($raid, $config->LANGUAGE_PUBLIC, true); } else { $time_text = getPublicTranslation('raid_done'); } diff --git a/logic/sendalarmnotice.php b/logic/sendalarmnotice.php index dbf232dd..cd263f6b 100644 --- a/logic/sendalarmnotice.php +++ b/logic/sendalarmnotice.php @@ -8,7 +8,8 @@ * @param boolean $alarm * @param array $raid Raid array from get_raid() */ -function sendAlertOnOffNotice($raid_id, $user_id, $alarm = null, $raid = null){ +function sendAlertOnOffNotice($raid_id, $user_id, $alarm = null, $raid = null) { + global $botUser; if(empty($raid)){ // Request limited raid info $request = my_query(' @@ -22,7 +23,7 @@ function sendAlertOnOffNotice($raid_id, $user_id, $alarm = null, $raid = null){ } $gymname = '' . $raid['gym_name'] . ''; // parse raidtimes - $raidtimes = str_replace(CR, '', str_replace(' ', '', get_raid_times($raid, false, true))); + $raidtimes = str_replace(CR, '', str_replace(' ', '', get_raid_times($raid, $botUser->userLanguage, true))); if(empty($alarm)){ // Get the new value diff --git a/logic/show_raid_poll.php b/logic/show_raid_poll.php index bfc0c36b..26ace6aa 100644 --- a/logic/show_raid_poll.php +++ b/logic/show_raid_poll.php @@ -37,7 +37,7 @@ function show_raid_poll($raid, $inline = false) } // Get raid times. - $msg = raid_poll_message($msg, get_raid_times($raid, true, ($raid['event_pokemon_title'] == 0 ? true : false)), true); + $msg = raid_poll_message($msg, get_raid_times($raid, $config->LANGUAGE_PUBLIC, ($raid['event_pokemon_title'] == 0 ? true : false)), true); // Get current time and time left. $time_now = utcnow(); @@ -373,7 +373,7 @@ function show_raid_poll($raid, $inline = false) if($cnt_array[$current_att_time]['other_pokemon'] > 0 ) { // Add pokemon name. $pokemon_id_form = explode("-",$current_pokemon,2); - $msg = raid_poll_message($msg, ($current_pokemon == 0) ? ('' . getPublicTranslation('any_pokemon') . '') : ('' . get_local_pokemon_name($pokemon_id_form[0],$pokemon_id_form[1], true) . '')); + $msg = raid_poll_message($msg, ($current_pokemon == 0) ? ('' . getPublicTranslation('any_pokemon') . '') : ('' . get_local_pokemon_name($pokemon_id_form[0],$pokemon_id_form[1], $config->LANGUAGE_PUBLIC) . '')); // Add counts to message. $msg = raid_poll_print_counts($msg, $cnt_array[$current_att_time][$current_pokemon]); diff --git a/logic/show_raid_poll_small.php b/logic/show_raid_poll_small.php index dd4b3da2..6f328709 100644 --- a/logic/show_raid_poll_small.php +++ b/logic/show_raid_poll_small.php @@ -3,11 +3,11 @@ /** * Show small raid poll. * @param $raid - * @param $override_language * @return string */ -function show_raid_poll_small($raid, $override_language = false) +function show_raid_poll_small($raid) { + global $botUser; // Build message string. $msg = ''; @@ -31,7 +31,7 @@ function show_raid_poll_small($raid, $override_language = false) // Start time and end time if(!empty($raid['start_time']) && !empty($raid['end_time'])) { // Get raid times message. - $msg .= get_raid_times($raid, $override_language); + $msg .= get_raid_times($raid, $botUser->userLanguage); } // Count attendances diff --git a/mods/edit_event_note.php b/mods/edit_event_note.php index cee3f3ba..c24ae268 100644 --- a/mods/edit_event_note.php +++ b/mods/edit_event_note.php @@ -20,7 +20,7 @@ $msg = ''; $msg .= getTranslation('raid_saved') . CR; -$msg .= show_raid_poll_small($raid, false) . CR2; +$msg .= show_raid_poll_small($raid) . CR2; if($mode == 'e') { $msg.= getTranslation('event_note_edit') . ': '; diff --git a/mods/edit_save.php b/mods/edit_save.php index 92dd8647..56d6b02b 100644 --- a/mods/edit_save.php +++ b/mods/edit_save.php @@ -60,7 +60,7 @@ // Build message string. $msg = ''; $msg .= getTranslation('raid_saved') . CR; -$msg .= show_raid_poll_small($raid, false) . CR; +$msg .= show_raid_poll_small($raid) . CR; // User_id tag. $user_id_tag = '#' . $update['callback_query']['from']['id']; diff --git a/mods/list_raid.php b/mods/list_raid.php index c61aa52a..0dcf85ba 100644 --- a/mods/list_raid.php +++ b/mods/list_raid.php @@ -83,7 +83,7 @@ $raid_pokemon_name = get_local_pokemon_name($raid['pokemon'], $raid['pokemon_form']); $msg .= '' . $i .'. ' . $raid_pokemon_name . '' . CR; if(!empty($raid['event_name'])) $msg .= $raid['event_name'] . CR; - $msg .= get_raid_times($raid,false, true) . CR . CR; + $msg .= get_raid_times($raid, $botUser->userLanguage, true) . CR . CR; $keys[][] = button($i . '. ' . $raid_pokemon_name,['list_raid', 'r' => $raid['id']]); $i++; } diff --git a/mods/share_raid_by_location.php b/mods/share_raid_by_location.php index 54fb133b..2435d262 100644 --- a/mods/share_raid_by_location.php +++ b/mods/share_raid_by_location.php @@ -97,7 +97,7 @@ $end = dt2time($raid['end_time']); $time_left = $raid['t_left']; if ($now < $start) { - $text .= get_raid_times($raid, true); + $text .= get_raid_times($raid, $botUser->userLanguage); // Raid has started already } else { // Add time left message. From 26eb802c9fb2dcbad7e9e2d4049052cb22b29321 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:43:42 +0200 Subject: [PATCH 336/367] Updated the alert_every_poke translations --- lang/language.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lang/language.json b/lang/language.json index 54a77334..485e362c 100644 --- a/lang/language.json +++ b/lang/language.json @@ -4591,14 +4591,14 @@ "alert_every_poke": { "NL": "Komt voor", "DE": "Kommt für jeden Raid-Boss", - "EN": "Coming for", + "EN": "Coming for any boss", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", "RU": "TRANSLATE", "NO": "TRANSLATE", - "FR": "Vient pour", + "FR": "Vient pour tout boss de raid", "PL": "TRANSLATE", - "FI": "Ilmoittautuneet,", + "FI": "Osallistuu mihin tahansa bossiin", "ES": "Viene para" }, "alert_new_att": { From 71c3ccb3e295815f6848669dcb2e7300769ec477 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:55:41 +0200 Subject: [PATCH 337/367] Added a config var ``CURL_IPRESOLVE_V4`` for forcing curl to ipv4 Experimenting with this. Maybe this helps with timeouts --- config/defaults-config.json | 1 + core/telegram/functions.php | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/config/defaults-config.json b/config/defaults-config.json index 20fee7db..3e0840f3 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -16,6 +16,7 @@ "APIKEY_HASH":"", "ENABLE_DDOS_PROTECTION": true, "DDOS_MAXIMUM":"10", + "CURL_IPRESOLVE_V4": false, "CURL_USEPROXY": false, "CURL_PROXYSERVER":"http://example.com:8080", "MAINTAINER":"", diff --git a/core/telegram/functions.php b/core/telegram/functions.php index 9291f1cc..88de4c5b 100644 --- a/core/telegram/functions.php +++ b/core/telegram/functions.php @@ -268,7 +268,7 @@ function edit_message($update, $message, $keys, $merge_args = false, $multicurl * @param $id_val * @param $text_val * @param $markup_val - * @param null $chat_id + * @param int|null $chat_id * @param mixed $merge_args * @param $multicurl */ @@ -341,7 +341,7 @@ function edit_caption($update, $message, $keys, $merge_args = false, $multicurl * @param $id_val * @param $text_val * @param $markup_val - * @param null $chat_id + * @param int|null $chat_id * @param mixed $merge_args * @param $multicurl */ @@ -649,7 +649,7 @@ function send_photo($chatObj, $media_content, $content_type, $text = '', $inline * @param string $media_content content of the media file. * @param bool $content_type true = photo file, false = file_id/url * @param $markup_val - * @param null $chat_id + * @param int|null $chat_id * @param mixed $merge_args * @param $multicurl */ @@ -742,6 +742,10 @@ function curl_json_request($post_contents, $identifier) if ($config->CURL_USEPROXY && !empty($config->CURL_PROXYSERVER)) { curl_setopt($curl, CURLOPT_PROXY, $config->CURL_PROXYSERVER); } + // Use only ipv4 if configured + if($config->CURL_IPRESOLVE_V4) { + curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + } // Write to log. if(is_array($post_contents)) debug_log(print_r($post_contents,true), '->'); @@ -806,6 +810,10 @@ function curl_json_multi_request($json) if($config->CURL_USEPROXY && !empty($config->CURL_PROXYSERVER)) { curl_setopt($curly[$id], CURLOPT_PROXY, $config->CURL_PROXYSERVER); } + // Use only ipv4 if configured + if($config->CURL_IPRESOLVE_V4) { + curl_setopt($curly[$id], CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + } // Curl post. curl_setopt($curly[$id], CURLOPT_POST, true); From 6b668aadd047447383f30d235faacb636f8e52b0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 15 Mar 2024 22:30:49 +0200 Subject: [PATCH 338/367] Updated translations --- lang/pokemon.json | 51 +++++++++++++++++++++++++ lang/pokemon_forms.json | 15 +++++--- lang/pokemon_moves.json | 85 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 140 insertions(+), 11 deletions(-) diff --git a/lang/pokemon.json b/lang/pokemon.json index ce815d80..948b63ae 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -5750,5 +5750,56 @@ "pokemon_id_1008": { "EN": "Miraidon", "RU": "Мирайдон" + }, + "pokemon_id_1009": { + "EN": "Walking-wake" + }, + "pokemon_id_1010": { + "EN": "Iron-leaves" + }, + "pokemon_id_1011": { + "EN": "Dipplin" + }, + "pokemon_id_1012": { + "EN": "Poltchageist" + }, + "pokemon_id_1013": { + "EN": "Sinistcha" + }, + "pokemon_id_1014": { + "EN": "Okidogi" + }, + "pokemon_id_1015": { + "EN": "Munkidori" + }, + "pokemon_id_1016": { + "EN": "Fezandipiti" + }, + "pokemon_id_1017": { + "EN": "Ogerpon" + }, + "pokemon_id_1018": { + "EN": "Archaludon" + }, + "pokemon_id_1019": { + "EN": "Hydrapple" + }, + "pokemon_id_1020": { + "EN": "Gouging-fire" + }, + "pokemon_id_1021": { + "EN": "Raging-bolt" + }, + "pokemon_id_1022": { + "EN": "Iron-boulder" + }, + "pokemon_id_1023": { + "EN": "Iron-crown" + }, + "pokemon_id_1024": { + "EN": "Terapagos" + }, + "pokemon_id_1025": { + "EN": "Pecharunt" } } \ No newline at end of file diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index 6ffa3651..2dfc6844 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -1613,7 +1613,7 @@ "ES": "Estilo Apasionado" }, "pokemon_form_2680": { - "PT-BR": "Estilo Pompom", + "PT-BR": "Estilo Animado", "EN": "Pom-Pom Style", "FR": "Style Pom-Pom", "DE": "Cheerleading", @@ -1631,7 +1631,7 @@ "ES": "Estilo Plácido" }, "pokemon_form_2683": { - "PT-BR": "Estilo Leque", + "PT-BR": "Estilo Elegante", "EN": "Sensu Style", "FR": "Style Buyô", "DE": "Buyo", @@ -2194,13 +2194,13 @@ "ES": "Forma Tótem" }, "pokemon_form_2804": { - "PT-BR": "Forma Listras Brancas", - "EN": "White-Striped Form", + "PT-BR": "Listras Brancas", + "EN": "White-Striped", "FR": "Motif Blanc", - "DE": "Weißlinige Form", + "DE": "Weißlinig", "IT": "Forma Lineabianca", "RU": "Белая полосатая форма", - "ES": "Forma Raya Blanca" + "ES": "Raya Blanca" }, "pokemon_form_2805": { "EN": "Gofest 2022" @@ -2304,6 +2304,9 @@ "pokemon_form_2841": { "EN": "Flying 08" }, + "pokemon_form_2842": { + "EN": "Horizons" + }, "pokemon_form_2982": { "PT-BR": "Fêmea", "EN": "Female", diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index aff40cef..aefec69e 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -2899,7 +2899,13 @@ "ES": "Ala Mortífera" }, "pokemon_move_390": { - "EN": "Natures Madness" + "PT-BR": "Ira da Natureza", + "EN": "Nature’s Madness", + "FR": "Ire de la Nature", + "DE": "Naturzorn", + "IT": "Ira della Natura", + "RU": "Безумие Природы", + "ES": "Furia Natural" }, "pokemon_move_391": { "PT-BR": "Pinote Triplo", @@ -2936,15 +2942,84 @@ "ES": "Distorsión" }, "pokemon_move_395": { - "EN": "Bleakwind Storm" + "PT-BR": "Tempestade Álgida", + "EN": "Bleakwind Storm", + "FR": "Typhon Hivernal", + "DE": "Polarorkan", + "IT": "Tempesta Boreale", + "RU": "Ледяная Буря", + "ES": "Vendaval Gélido" }, "pokemon_move_396": { - "EN": "Sandsear Storm" + "PT-BR": "Tempestade Saibrosa", + "EN": "Sandsear Storm", + "FR": "Typhon Pyrosable", + "DE": "Wüstenorkan", + "IT": "Tempesta Ardente", + "RU": "Обжигающая Буря", + "ES": "Simún de Arena" }, "pokemon_move_397": { - "EN": "Wildbolt Storm" + "PT-BR": "Tempestade Chocante", + "EN": "Wildbolt Storm", + "FR": "Typhon Fulgurant", + "DE": "Donnerorkan", + "IT": "Tempesta Tonante", + "RU": "Громовая Буря", + "ES": "Electormenta" }, "pokemon_move_398": { - "EN": "Spirit Shackle" + "PT-BR": "Manilha Sombria", + "EN": "Spirit Shackle", + "FR": "Tisse Ombre", + "DE": "Schattenfessel", + "IT": "Cucitura d’Ombra", + "RU": "Спиритические Оковы", + "ES": "Puntada Sombría" + }, + "pokemon_move_399": { + "PT-BR": "Investida Trovão", + "EN": "Volt Tackle", + "FR": "Électacle", + "DE": "Volttackle", + "IT": "Locomovolt", + "RU": "Вольт-Бросок", + "ES": "Placaje Eléctrico" + }, + "pokemon_move_400": { + "PT-BR": "Lariat Escuro", + "EN": "Darkest Lariat", + "FR": "Dark Lariat", + "DE": "Dark Lariat", + "IT": "Braccioteso", + "RU": "Тёмное Лассо", + "ES": "Lariat Oscuro" + }, + "pokemon_move_401": { + "PT-BR": "Onda Psíquica", + "EN": "Psywave", + "FR": "Vague Psy", + "DE": "Psywelle", + "IT": "Psiconda", + "RU": "Психоволны", + "ES": "Psicoonda" + }, + "pokemon_move_402": { + "PT-BR": "Som de Metal", + "EN": "Metal Sound", + "FR": "Strido-Son", + "DE": "Metallsound", + "IT": "Ferrostrido", + "RU": "Металлический Звук", + "ES": "Eco Metálico" + }, + "pokemon_move_403": { + "PT-BR": "Ataque de Areia", + "EN": "Sand Attack", + "FR": "Jet de Sable", + "DE": "Sandwirbel", + "IT": "Turbosabbia", + "RU": "Песчаная Атака", + "ES": "Ataque Arena" } } \ No newline at end of file From 614d5944ce62d8414d2cff69184feb45fedc5d53 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 17 Mar 2024 11:27:35 +0200 Subject: [PATCH 339/367] Fixed vote key time slot logic --- logic/keys_vote.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index db49ef86..13ef7e47 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -261,7 +261,11 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { $five_slot = $five_slot->add(new DateInterval('PT'.$diff.'M')); // Get first regular raidslot - $first_slot = $five_slot->add(new DateInterval('PT'.$RAID_SLOTS.'M')); + $first_slot = + ($minute == 0) ? + $direct_slot->add(new DateInterval('PT'.$RAID_SLOTS.'M')) : + $five_slot->add(new DateInterval('PT'.$RAID_SLOTS.'M') + ); // Write slots to log. debug_log($direct_slot, 'Direct start slot:'); @@ -274,7 +278,10 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { $last_slot = $direct_slot; } // Add five minutes slot - if($five_slot >= $dt_now && (empty($keys_time) || (!empty($keys_time) && $direct_slot != $five_slot))) { + if($five_slot >= $dt_now && + (empty($keys_time) || (!empty($keys_time) && $direct_slot != $five_slot)) && + $raid['event_vote_key_mode'] !== 0 + ) { $keys_time[] = button(dt2time($five_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $five_slot->format('YmdHis')]); $last_slot = $five_slot; } From 4867cf695b360f525415e2a851c9f005e5b0a2d7 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:30:23 +0300 Subject: [PATCH 340/367] Maybe fixed the hidden gyms menu --- logic/gymMenu.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/gymMenu.php b/logic/gymMenu.php index 77336070..f97ab654 100644 --- a/logic/gymMenu.php +++ b/logic/gymMenu.php @@ -187,7 +187,7 @@ function createGymKeys($buttonAction, $showHidden, $gymareaId, $gymareaQuery, $s ); while ($gym = $rs->fetch()) { // Add first letter to keys array - $keys[] = button($gym['first_letter'], ['gymMenu', 'a' => $buttonAction, 'stage' => $stage+1, 'fl' => $gym['first_letter'], 'ga' => $gymareaId]); + $keys[] = button($gym['first_letter'], ['gymMenu', 'a' => $buttonAction, 'stage' => $stage+1, 'fl' => $gym['first_letter'], 'h' => $showHidden, 'ga' => $gymareaId]); } // Get the inline key array. From e9ee40ad89baadee99d85c803525506834eddba0 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:32:21 +0300 Subject: [PATCH 341/367] Added error message on curl fail --- mods/import_shinyinfo.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mods/import_shinyinfo.php b/mods/import_shinyinfo.php index b1185809..233de82d 100644 --- a/mods/import_shinyinfo.php +++ b/mods/import_shinyinfo.php @@ -13,6 +13,11 @@ $link = 'https://fight.pokebattler.com/raids'; $pb_data = curl_get_contents($link); +if($pb_data === false) { + $callback_response = getTranslation('internal_error'); + answerCallbackQuery($update['callback_query']['id'], $callback_response); + exit(); +} $pb_data = json_decode($pb_data,true); // Init empty keys array. From 7659df09850930ffd104d611fa72ead94f42b9e7 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:32:41 +0300 Subject: [PATCH 342/367] Added shadow to boss' name in raidbosslist --- logic/createRaidBossList.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logic/createRaidBossList.php b/logic/createRaidBossList.php index bda93c23..91cc8de7 100644 --- a/logic/createRaidBossList.php +++ b/logic/createRaidBossList.php @@ -22,7 +22,7 @@ function createRaidBossList() { $levelList = '(' . implode(',', $config->RAID_BOSS_LIST_RAID_LEVELS). ')'; $q = my_query(' SELECT - pokedex_id, pokemon_form_id, date_start, date_end, + pokedex_id, pokemon_form_id, date_start, date_end, raid_level, CONCAT(DATE_FORMAT(date_start,"%d%m%y%k"), DATE_FORMAT(date_end,"%d%m%y%k")) AS arrkey, CASE WHEN date(date_start) = date(date_end) THEN 1 ELSE 0 END AS sameDay FROM raid_bosses @@ -45,6 +45,7 @@ function createRaidBossList() { $list .= PHP_EOL . '- '; foreach($tempRow as $num => $row) { $pokemonName = get_local_pokemon_name($row['pokedex_id'], $row['pokemon_form_id'], $config->LANGUAGE_PUBLIC); + if(in_array($row['raid_level'], RAID_LEVEL_SHADOW)) $pokemonName .= ' ' . getPublicTranslation('shadow'); if($num != 0) $list .= ', '; $list .= $pokemonName; } From 23bd489b2794481890f0473dd58a25ff51c7e7c0 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 23 Apr 2024 13:23:34 +0200 Subject: [PATCH 343/367] Update docker-compose.yml Improvements for docker-compose.yml Added gym images dir to volumes Added custom dir to volumes Changed config dir to only config.json, so default files like default-config.json from docker image are used Added container-names Updated mariadb to 10.11 --- docker/docker-compose.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index d37257ee..727b33fb 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,7 +1,6 @@ -version: "3.7" - services: raidbot: + container_name: raidbot ports: - 8088:80 depends_on: @@ -9,8 +8,10 @@ services: restart: always volumes: # These are just example paths, change them to where you have stored the data! - - ./PokemonRaidBot/config/:/var/www/html/config/ - ./PokemonRaidBot/access/:/var/www/html/access/ + - ./PokemonRaidBot/config/config.json:/var/www/html/config/config.json + - ./PokemonRaidBot/custom/:/var/www/html/custom/ + - ./PokemonRaidBot/images/gyms/:/var/www/html/images/gyms - ./PokemonRaidBot/images/pokemon_PokeMiners/:/var/www/html/images/pokemon_PokeMiners - ./tg-logs/:/var/log/tg-bots/ environment: @@ -26,7 +27,8 @@ services: ofelia.job-exec.raidbot-overview.command: /usr/bin/curl -s -k -d '{"callback_query":{"data":"0:overview_refresh:0"}}' https://raidbot.example.com/index.php?apikey=changeme raidbot-db: - image: mariadb:10.3 + container_name: raidbot-db + image: mariadb:10.11 restart: always command: ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] volumes: @@ -41,6 +43,7 @@ services: MYSQL_PASSWORD: ofelia: + container_name: raidbot-ofelia image: mcuadros/ofelia:latest depends_on: - raidbot From 249f739717f5cf26e9ded5cf649fa4c4898b3e68 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 23 Apr 2024 13:24:59 +0200 Subject: [PATCH 344/367] Update entrypoint.sh Added images/gyms to chown command --- docker/entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index acb25a8c..3eb00bd1 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -34,7 +34,7 @@ env | egrep -q '^POKEMONRAIDBOT_' && \ | tee -a config/config.json) # Do some permission setting for any data that might've been volume mounted in, otherwise stuff will fail in weird ways. -chown -R www-data:www-data config/config.json access/ custom/ images/pokemon* +chown -R www-data:www-data config/config.json access/ custom/ images/gyms/ images/pokemon* # Ensure we now have a valid config if [[ ! -a /var/www/html/config/config.json ]]; then From 0e7f254a67d9cf331c879bea8dfd2db93ee35e91 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 23 Apr 2024 14:04:13 +0200 Subject: [PATCH 345/367] Update publish-image.yml Offer "latest" for each branch --- .github/workflows/publish-image.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml index 925cb180..352698f6 100644 --- a/.github/workflows/publish-image.yml +++ b/.github/workflows/publish-image.yml @@ -25,6 +25,7 @@ jobs: echo ::set-output name=channel::"latest" echo ::set-output name=version::main_$(cat VERSION)-${GITHUB_SHA::6} elif [[ "$GITHUB_REF" == "refs/heads/"* ]]; then + echo ::set-output name=channel::${GITHUB_REF/refs\/heads\//}-"latest" echo ::set-output name=version::${GITHUB_REF/refs\/heads\//}-$(cat VERSION)-${GITHUB_SHA::6} elif [[ "$GITHUB_REF" == "refs/tags/"* ]]; then echo ::set-output name=channel::${GITHUB_REF/refs\/tags\//} From 1c8d8739ac59c4cd71c3e619e3e87a549d470a13 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 23 Apr 2024 14:10:33 +0200 Subject: [PATCH 346/367] Rename pokemon-raid-bot.sql to 0-pokemon-raid-bot.sql When setting up via docker the pokemon-raid-bot.sql is processed after the events sql file due to the file names which causes an error. Therefore renamed it, so the pokemon raidbot sql file is processed first to avoid that error. --- sql/{pokemon-raid-bot.sql => 0-pokemon-raid-bot.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename sql/{pokemon-raid-bot.sql => 0-pokemon-raid-bot.sql} (100%) diff --git a/sql/pokemon-raid-bot.sql b/sql/0-pokemon-raid-bot.sql similarity index 100% rename from sql/pokemon-raid-bot.sql rename to sql/0-pokemon-raid-bot.sql From 5c5ae52cde0d3e9019af2d6f6186b9a7580b2855 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 23 Apr 2024 14:18:48 +0200 Subject: [PATCH 347/367] Update help.json Update German translation --- lang/help.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/help.json b/lang/help.json index 3fcefb18..86f59bb4 100644 --- a/lang/help.json +++ b/lang/help.json @@ -300,7 +300,7 @@ }, "help_history": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "/history - Historie von Raids mit Teilnehmern ansehen", "EN": "/history - View history of raids that had attendees", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -313,7 +313,7 @@ }, "help_event-manage": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "/events - Raid-Events verwalten", "EN": "/events - Manage raid events", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", From 785b1e4bdd3cc3c84062fea2fbea71e01c0f406e Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 23 Apr 2024 17:17:41 +0200 Subject: [PATCH 348/367] Update language.json Start updating German translation --- lang/language.json | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lang/language.json b/lang/language.json index 485e362c..b9f743dc 100644 --- a/lang/language.json +++ b/lang/language.json @@ -456,7 +456,7 @@ }, "replace": { "NL": "Vervang", - "DE": "TRANSLATE", + "DE": "Ersetzen", "EN": "Replace", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -638,7 +638,7 @@ }, "config_option": { "NL": "Configuratie optie", - "DE": "TRANSLATE", + "DE": "Konfigurationsoption", "EN": "Configuration option", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -768,7 +768,7 @@ }, "tutorial_vote_failed": { "NL": "Je kan niet meedoen voordat je de tutorial hebt doorlopen.", - "DE": "TRANSLATE", + "DE": "Du kannst nicht abstimmen, bevor du das Tutorial durchlaufen hast.", "EN": "You can't vote before going through the tutorial.", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -781,7 +781,7 @@ }, "tutorial_command_failed": { "NL": "Je kan dit commando niet gebruiken voordat je de tutorial hebt doorlopen.", - "DE": "TRANSLATE", + "DE": "Du kannst diesen Befehl nicht verwenden, bevor du das Tutorial durchlaufen hast.", "EN": "You can't use this command before going through the tutorial.", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -820,7 +820,7 @@ }, "15stars": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "5 Sterne Shadow", "EN": "5 star shadow", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -833,7 +833,7 @@ }, "15stars_short": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Shadow 5", "EN": "Shadow 5", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -846,7 +846,7 @@ }, "14stars": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "4 Sterne Shadow", "EN": "4 star shadow", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -859,7 +859,7 @@ }, "14stars_short": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Shadow 4", "EN": "Shadow 4", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -872,7 +872,7 @@ }, "13stars": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "3 Sterne Shadow", "EN": "3 star shadow", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -885,7 +885,7 @@ }, "13stars_short": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Shadow 3", "EN": "Shadow 3", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -898,7 +898,7 @@ }, "12stars": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "2 Sterne Shadow", "EN": "2 star shadow", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -911,7 +911,7 @@ }, "12stars_short": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Shadow 2", "EN": "Shadow 2", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -924,7 +924,7 @@ }, "11stars": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "1 Stern Shadow", "EN": "1 star shadow", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -937,7 +937,7 @@ }, "11stars_short": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Shadow 1", "EN": "Shadow 1", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -950,7 +950,7 @@ }, "10stars": { "NL": "Primal raid", - "DE": "TRANSLATE", + "DE": "Primal-Raid", "EN": "Primal raid", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -963,7 +963,7 @@ }, "10stars_short": { "NL": "Primal", - "DE": "TRANSLATE", + "DE": "Primal", "EN": "Primal", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -976,7 +976,7 @@ }, "9stars": { "NL": "Elite raid", - "DE": "TRANSLATE", + "DE": "Elite-Raid", "EN": "Elite raid", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -989,7 +989,7 @@ }, "9stars_short": { "NL": "Elite", - "DE": "TRANSLATE", + "DE": "Elite", "EN": "Elite", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1015,7 +1015,7 @@ }, "8stars_short": { "NL": "Ultra", - "DE": "TRANSLATE", + "DE": "Ultra", "EN": "Ultra", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1028,7 +1028,7 @@ }, "7stars": { "NL": "Legendary Mega-Raid", - "DE": "TRANSLATE", + "DE": "Legendäres Mega-Raid", "EN": "Legendary Mega-Raid", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1041,7 +1041,7 @@ }, "7stars_short": { "NL": "Lege Mega", - "DE": "TRANSLATE", + "DE": "Legend Mega", "EN": "Lege Mega", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", From 68dec2214084def108b3657d809f8cc78546c476 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 24 Apr 2024 10:36:14 +0200 Subject: [PATCH 349/367] Update language.json Finished adding the missing German translations Minor changes to existing translations --- lang/language.json | 164 ++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/lang/language.json b/lang/language.json index b9f743dc..b2747542 100644 --- a/lang/language.json +++ b/lang/language.json @@ -1158,7 +1158,7 @@ }, "egg_15": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Level 5 Shadow Ei", "EN": "Level 5 shadow egg", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1171,7 +1171,7 @@ }, "egg_14": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Level 4 Shadow Ei", "EN": "Level 4 shadow egg", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1184,7 +1184,7 @@ }, "egg_13": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Level 3 Shadow Ei", "EN": "Level 3 shadow egg", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1197,7 +1197,7 @@ }, "egg_12": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Level 2 Shadow Ei", "EN": "Level 2 shadow egg", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1210,7 +1210,7 @@ }, "egg_11": { "NL": "TRANSLATE", - "DE": "TRANSLATE", + "DE": "Level 1 Shadow Ei", "EN": "Level 1 shadow egg", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1223,7 +1223,7 @@ }, "egg_10": { "NL": "Primal raid ei", - "DE": "TRANSLATE", + "DE": "Primal Raid Ei", "EN": "Primal raid egg", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1236,7 +1236,7 @@ }, "egg_9": { "NL": "Elite raid egg", - "DE": "TRANSLATE", + "DE": "Elite Raid Ei", "EN": "Elite raid egg", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1262,7 +1262,7 @@ }, "egg_7": { "NL": "Legendary Mega-Raid Ei", - "DE": "TRANSLATE", + "DE": "Legendäres Mega-Raid Ei", "EN": "Legendary Mega-Raid Egg", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1366,7 +1366,7 @@ }, "upcoming": { "NL": "geplande", - "DE": "TRANSLATE", + "DE": "Bevorstehend", "EN": "upcoming", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1379,7 +1379,7 @@ }, "upcoming_bosses_not_found": { "NL": "Geen informatie gevonden voor geplande raid bazen!", - "DE": "TRANSLATE", + "DE": "Keine Info zu bevorstehenden Raid-Bossen gefunden!", "EN": "No info of upcoming bosses was found!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1392,7 +1392,7 @@ }, "current_scheduled_bosses": { "NL": "Geplande raid bazen van de database", - "DE": "TRANSLATE", + "DE": "Geplante Raid-Bosse von der Datenbank", "EN": "Scheduled raid bosses from database", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1405,7 +1405,7 @@ }, "unscheduled_bosses": { "NL": "Ongeplande bazen", - "DE": "TRANSLATE", + "DE": "Ungeplante Raid-Bosse", "EN": "Unscheduled bosses", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1418,7 +1418,7 @@ }, "delete_scheduled_confirmation": { "NL": "Wil je de geplande baas verwijderen?", - "DE": "TRANSLATE", + "DE": "Diesen geplanten Eintrag löschen?", "EN": "Do you want to delete this scheduled entry?", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1431,7 +1431,7 @@ }, "found_upcoming_bosses": { "NL": "Volgende geplande raid bazen gevonden", - "DE": "TRANSLATE", + "DE": "Folgende bevorstehende Raid-Bosse gefunden", "EN": "Found following upcoming bosses", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1444,7 +1444,7 @@ }, "confirm_replace_upcoming": { "NL": "Wil je de data vervangen met wat we gevonden hebben?", - "DE": "TRANSLATE", + "DE": "Aktuell vorhandene Daten durch die gefundenen Daten ersetzen?", "EN": "Would you like to replace the current data with what we found?", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1717,7 +1717,7 @@ }, "no_remote_parcipants": { "NL": "Deze raid kan alleen lokaal gespeeld worden!", - "DE": "TRANSLATE", + "DE": "Teilnahme am Raid ist nur vor Ort möglich!", "EN": "This raid can not be participated using a Remote Raid Pass!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1756,7 +1756,7 @@ }, "update_pokemon_table": { "NL": "Update Pokemon tabel", - "DE": "TRANSLATE", + "DE": "Pokemon-Tabelle aktualisieren", "EN": "Update Pokemon table", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1925,7 +1925,7 @@ }, "remote_raid": { "NL": "Remote Raid", - "DE": "TRANSLATE", + "DE": "Fern-Raid", "EN": "Remote raid", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1938,7 +1938,7 @@ }, "remote_raids": { "NL": "Remote raids", - "DE": "TRANSLATE", + "DE": "Fern-Raids", "EN": "Remote raids", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1977,7 +1977,7 @@ }, "delete_remote_raid_done": { "NL": "Je hebt de raid gespeeld die je hebt aangemaakt. Kan deze verwijderd worden?", - "DE": "TRANSLATE", + "DE": "Du hast deinen erstellten Fern-Raid fertig gespielt. Raid-Abstimmung löschen?", "EN": "You have played the remote raid you created. Can we delete the raid poll?", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -1990,7 +1990,7 @@ }, "delete_remote_raid_cancel": { "NL": "Je hebt je aanwezigheid bij de remote raid afgezegd. Kunnen we het raid overzicht verwijderen?", - "DE": "TRANSLATE", + "DE": "Du hast deine Teilnahme an deinem erstellten Fern-Raid abgesagt. Raid-Abstimmung löschen?", "EN": "You have canceled your attendance to the remote raid you created. Can we delete the raid poll?", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2003,7 +2003,7 @@ }, "remote_raid_marked_ended": { "NL": "Bedankt! Remote raid is geëindigd", - "DE": "TRANSLATE", + "DE": "Danke! Fern-Raid als Beendet markiert!", "EN": "Thank you! Remote raid marked as ended!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2107,7 +2107,7 @@ }, "select_gym_first_letter_or_gym_area": { "NL": "Selecteer de eerste letter van de gym of gym gebied:", - "DE": "TRANSLATE", + "DE": "Bitte Anfangsbuchstaben der Arena oder des Arena-Gebiets auswählen:", "EN": "Please select the first letter of the gym or gym area:", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2120,7 +2120,7 @@ }, "select_gym_name_or_gym_area": { "NL": "Selecteer gym of gym gebied:", - "DE": "TRANSLATE", + "DE": "Bitte Arena oder Arena-Gebiet auswählen:", "EN": "Please select gym or gym area:", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2133,7 +2133,7 @@ }, "select_gym_area": { "NL": "Selecteer gym gebied:", - "DE": "TRANSLATE", + "DE": "Bitte Arena-Gebiet auswählen:", "EN": "Please select the gymarea:", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2146,7 +2146,7 @@ }, "default_gymarea": { "NL": "Standaard gym gebied", - "DE": "TRANSLATE", + "DE": "Standard Arena-Gebiet", "EN": "Default gymarea", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2159,7 +2159,7 @@ }, "gymareas": { "NL": "Gyn gebied", - "DE": "TRANSLATE", + "DE": "Arena-Gebiete", "EN": "Gymareas", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2198,7 +2198,7 @@ }, "inspect_raid_or_create_event": { "NL": "Inspect de bestaande raid of create een new event raid", - "DE": "TRANSLATE", + "DE": "Existierenden Raid untersuchen oder neuen Event-Raid erstellen", "EN": "Inspect the existing raid or create a new event raid", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2211,7 +2211,7 @@ }, "saved_raid": { "NL": "Laat opgeslagen raid zien", - "DE": "TRANSLATE", + "DE": "Gespeicherten Raid anzeigen", "EN": "Show saved raid", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2224,7 +2224,7 @@ }, "create_event_raid": { "NL": "Maak een event raid", - "DE": "TRANSLATE", + "DE": "Event-Raid erstellen", "EN": "Create event raid", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2458,7 +2458,7 @@ }, "trainername": { "NL": "Trainernaam", - "DE": "TRANSLATE", + "DE": "Trainername", "EN": "Trainername", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2471,7 +2471,7 @@ }, "trainername_add": { "NL": "Trainernaam toevoegen", - "DE": "TRANSLATE", + "DE": "Trainername hinzufügen", "EN": "Add trainername", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2484,7 +2484,7 @@ }, "trainername_edit": { "NL": "Trainernaam aanpassen", - "DE": "TRANSLATE", + "DE": "Trainername bearbeiten", "EN": "Edit trainername", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2536,7 +2536,7 @@ }, "switch_display_name": { "NL": "Wissel display naam", - "DE": "TRANSLATE", + "DE": "Anzeigename wechseln", "EN": "Switch display name", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2614,7 +2614,7 @@ }, "trainer_not_found": { "NL": "Trainer niet gevonden!", - "DE": "TRANSLATE", + "DE": "Trainer nicht gefunden!", "EN": "Trainer not found!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2627,7 +2627,7 @@ }, "bot_lang": { "NL": "Bot taal", - "DE": "TRANSLATE", + "DE": "Bot-Sprache", "EN": "Bot language", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2640,7 +2640,7 @@ }, "change_lang": { "NL": "Verander de bot taal", - "DE": "TRANSLATE", + "DE": "Bot-Sprache ändern", "EN": "Change the bot's language", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2653,7 +2653,7 @@ }, "new_lang_saved": { "NL": "Nieuwe taal opgeslagen!", - "DE": "TRANSLATE", + "DE": "Neue Sprache gespeichert!", "EN": "New language saved!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2666,7 +2666,7 @@ }, "display_name_explanation": { "NL": "De pijl (->) geeft aan welke naam er in de raid poll wordt gebruikt. Je kan dit aanpassen in de instellingen.", - "DE": "TRANSLATE", + "DE": "Der Pfeil (->) zeigt deinen Namen für Raid-Abstimmungen. Du kannst deinen Anzeigenamen in den Einstellungen anpassen.", "EN": "The arrow (->) marks the name displayed in raid polls. You can change your displayname from name settings.", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2900,7 +2900,7 @@ }, "change_extended_gym_details": { "NL": "Verander de extra gym informatie?", - "DE": "Erweiterte Arena Details ändern?", + "DE": "Erweiterte Arena Details speichern?", "EN": "Save extended gym details?", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2939,7 +2939,7 @@ }, "gym_coordinates": { "NL": "Coordinaten", - "DE": "TRANSLATE", + "DE": "Koordinaten", "EN": "Coordinates", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2952,7 +2952,7 @@ }, "gym_edit_coordinates": { "NL": "Wijzig coordinaten", - "DE": "TRANSLATE", + "DE": "Koordinaten bearbeiten", "EN": "Edit coordinates", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -2991,7 +2991,7 @@ }, "gym_gps_instructions": { "NL": "Stuur me de gym coordinaten in de volgende format: Latitude,Longitude", - "DE": "TRANSLATE", + "DE": "Bitte die Arena-Koordinaten in folgendem Format senden: Latitude,Longitude", "EN": "Send me the gym coordinates in the following format: Latitude,Longitude", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3043,7 +3043,7 @@ }, "gym_create": { "NL": "Maak een nieuwe gym", - "DE": "TRANSLATE", + "DE": "Neue Arena erstellen", "EN": "Create a new gym", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3134,7 +3134,7 @@ }, "gym_edit_text_too_long": { "NL": "Error! niet meer dan 255 tekens!", - "DE": "TRANSLATE", + "DE": "Fehler! Es sind maximal 255 Zeichen erlaubt!", "EN": "Error! The maximum text length is 255 characters!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3147,7 +3147,7 @@ }, "gym_add_edit_note": { "NL": "gym note", - "DE": "TRANSLATE", + "DE": "Arena-Notiz", "EN": "gym note", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3160,7 +3160,7 @@ }, "gym_note_instructions": { "NL": "Stuur me een nieuwe gym notitie (maximaal 255 tekens):", - "DE": "TRANSLATE", + "DE": "Neue Arena-Notiz eingeben (max. 255 Zeichen)", "EN": "Send me the new gym note (max 255 characters):", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3173,7 +3173,7 @@ }, "gym_address": { "NL": "Gym adres", - "DE": "TRANSLATE", + "DE": "Arena-Adresse", "EN": "gym address", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3186,7 +3186,7 @@ }, "gym_stored_address": { "NL": "Opgeslagen adres", - "DE": "TRANSLATE", + "DE": "Gespeicherte Adresse", "EN": "Stored address", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3199,7 +3199,7 @@ }, "gym_address_instructions": { "NL": "Stuur me het nieuwe gym adres:", - "DE": "TRANSLATE", + "DE": "Neue Arena-Adresse eingeben:", "EN": "Send me the new gym address:", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3212,7 +3212,7 @@ }, "gym_address_lookup_result": { "NL": "Opgezochte adres", - "DE": "TRANSLATE", + "DE": "Ergebnis der Adresssuche", "EN": "Address lookup result", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3225,7 +3225,7 @@ }, "gym_save_lookup_result": { "NL": "Sla opgezochte resultaat op", - "DE": "TRANSLATE", + "DE": "Ergebnis der Adresssuche speichern", "EN": "Save lookup result", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -3277,7 +3277,7 @@ }, "featured_pokemon": { "NL": "Pokemon", - "DE": "TRANSLATE", + "DE": "Rampenlicht-Pokemon", "EN": "Featured Pokemon", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4200,7 +4200,7 @@ }, "gym_id_name_missing": { "NL": "Error! Gym naam mist!", - "DE": "TRANSLATE", + "DE": "Fehler! Arena-Name fehlt!", "EN": "Error! Gym name is missing!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4226,7 +4226,7 @@ }, "gym_name_edit": { "NL": "Gym naam aanpassen", - "DE": "TRANSLATE", + "DE": "Arena-Name bearbeiten", "EN": "Edit gym name", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4239,7 +4239,7 @@ }, "gym_name_instructions": { "NL": "Stuur me de gym naam:", - "DE": "TRANSLATE", + "DE": "Arena-Name eingeben:", "EN": "Send me the gym name:", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4486,7 +4486,7 @@ }, "switch_alarm_on": { "NL": "Zet automatische raid alarm aan", - "DE": "TRANSLATE", + "DE": "Automatische Raid-Alarme aktivieren", "EN": "Enable automatic raid alerts", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4499,7 +4499,7 @@ }, "switch_alarm_off": { "NL": "Zet automatisch raid alarm uit", - "DE": "TRANSLATE", + "DE": "Automatische Raid-Alarme deaktivieren", "EN": "Disable automatic raid alerts", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4525,7 +4525,7 @@ }, "alert_add_alien_trainer": { "NL": "Een gebruiker is uitgenodigd buiten deze groep!", - "DE": "TRANSLATE", + "DE": "Trainer lädt Spieler außerhalb der Gruppe ein!", "EN": "User is inviting a player from outside the group!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4733,7 +4733,7 @@ }, "alert_want_invite": { "NL": "Wenst uitgenodigd te worden.", - "DE": "TRANSLATE", + "DE": "Möchte eingeladen werden.", "EN": "Wishes to be invited.", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4746,7 +4746,7 @@ }, "alert_no_want_invite": { "NL": "Wil niet langer worden uitgenodigd.", - "DE": "TRANSLATE", + "DE": "Möchte nicht länger eingeladen werden.", "EN": "No longer wishes to be invited.", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4759,7 +4759,7 @@ }, "alert_can_invite": { "NL": "Doet niet mee, maar kan wel invites versturen.", - "DE": "TRANSLATE", + "DE": "Spielt selbst nicht mit, kann aber einladen.", "EN": "Is not attending but can send invites.", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4772,7 +4772,7 @@ }, "alert_no_can_invite": { "NL": "Kan niet langer andere uitnodigingen versturen.", - "DE": "TRANSLATE", + "DE": "Kann nicht länger andere einladen.", "EN": "Is no longer able to invite others.", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4798,7 +4798,7 @@ }, "event_note": { "NL": "Event info", - "DE": "Event Notiz", + "DE": "Event-Notiz", "EN": "Event note", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4811,7 +4811,7 @@ }, "event_note_add": { "NL": "Voeg event infot toe", - "DE": "Event Notiz hinzufügen", + "DE": "Event-Notiz hinzufügen", "EN": "Add event note", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4824,7 +4824,7 @@ }, "event_note_edit": { "NL": "Wijzig de event info", - "DE": "Event Notiz ändern", + "DE": "Event-Notiz bearbeiten", "EN": "Edit event note", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4850,7 +4850,7 @@ }, "events_manage": { "NL": "Event manager", - "DE": "TRANSLATE", + "DE": "Event verwalten", "EN": "Manage events", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4863,7 +4863,7 @@ }, "events_create": { "NL": "Maak een nieuw event", - "DE": "TRANSLATE", + "DE": "Neues Event erstellen", "EN": "Create a new event", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4876,7 +4876,7 @@ }, "events_created": { "NL": "Event succesvol aangemaakt!", - "DE": "TRANSLATE", + "DE": "Event erfolgreich erstellt!", "EN": "Event created succesfully!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4889,7 +4889,7 @@ }, "events_give_name": { "NL": "Geef het event een naam", - "DE": "TRANSLATE", + "DE": "Event-Name eingeben", "EN": "Give the event a name", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4902,7 +4902,7 @@ }, "events_give_description": { "NL": "Geef de omschrijving van het event", - "DE": "TRANSLATE", + "DE": "Event-Beschreibung eingeben", "EN": "Give the event a description", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4915,7 +4915,7 @@ }, "events_no_description": { "NL": "Geen omschrijving", - "DE": "TRANSLATE", + "DE": "Keine Beschreibung", "EN": "No description", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4928,7 +4928,7 @@ }, "events_edit_name": { "NL": "Wijzig event naam", - "DE": "TRANSLATE", + "DE": "Event-Name bearbeiten", "EN": "Edit event name", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4941,7 +4941,7 @@ }, "events_edit_description": { "NL": "Wijzig de event omschrijving", - "DE": "TRANSLATE", + "DE": "Event-Beschreibung bearbeiten", "EN": "Edit event description", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4954,7 +4954,7 @@ }, "events_edit_raid_poll": { "NL": "Wijzig event raid poll", - "DE": "TRANSLATE", + "DE": "Event-Raid-Abstimmung bearbeiten", "EN": "Edit event raid poll", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4967,7 +4967,7 @@ }, "events_delete": { "NL": "Verwijder event", - "DE": "TRANSLATE", + "DE": "Event löschen", "EN": "Delete event", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -4980,7 +4980,7 @@ }, "events_delete_confirmation": { "NL": "Wil je dit event echt verwijderen?", - "DE": "TRANSLATE", + "DE": "Dieses Event wirklich löschen?", "EN": "Do you really want to delete this event?", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -5032,7 +5032,7 @@ }, "history_title": { "NL": "Zie raid poll geschiedenis", - "DE": "TRANSLATE", + "DE": "Raid-Historie ansehen", "EN": "View raid poll history.", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -5045,7 +5045,7 @@ }, "history_displaying_month": { "NL": "Momenteel worden er raids weergegeven voor", - "DE": "TRANSLATE", + "DE": "Zeigt derzeit Raids an für", "EN": "Currently displaying raids for", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -5058,7 +5058,7 @@ }, "history_select_raid": { "NL": "Selecteer raid", - "DE": "TRANSLATE", + "DE": "Raid auswählen", "EN": "Select raid", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -5071,7 +5071,7 @@ }, "history_no_raids_found": { "NL": "Geen raids met spelers gevonden!", - "DE": "TRANSLATE", + "DE": "Keine Raids mit Teilnehmern gefunden!", "EN": "No raids with attendees found!", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", @@ -5097,7 +5097,7 @@ }, "current_gymarea": { "NL": "Gym gebied", - "DE": "TRANSLATE", + "DE": "Aktuelles Arena-Gebiet", "EN": "Current gymarea", "IT": "TRANSLATE", "PT-BR": "TRANSLATE", From 0807150cbbd0611f9a856a492072fe029604e5e9 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 24 Apr 2024 17:57:58 +0200 Subject: [PATCH 350/367] Update language.json Small fix --- lang/language.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/language.json b/lang/language.json index b2747542..a38de54b 100644 --- a/lang/language.json +++ b/lang/language.json @@ -3979,7 +3979,7 @@ }, "select_gym_name": { "NL": "Selecteer Gym:", - "DE": "Bitte Gym auswählen:", + "DE": "Bitte Arena auswählen:", "EN": "Please select Gym:", "IT": "Seleziona Palestra:", "PT-BR": "Escolha o ginásio:", From 8caa37cce39e7598f207af8f23f86850d811886f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 26 Apr 2024 20:44:10 +0300 Subject: [PATCH 351/367] Fixed gym letter 0 not working --- logic/key_util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/key_util.php b/logic/key_util.php index 775eeabb..9fe14a68 100644 --- a/logic/key_util.php +++ b/logic/key_util.php @@ -141,7 +141,7 @@ function formatCallbackData($array) $return = $array[0] . '|'; unset($array[0]); foreach($array as $key => $value) { - if($value !== 0 && (empty($value) or $value === false)) continue; + if($value !== 0 && (!isset($value) or $value === false)) continue; $return .= $key . '=' . $value . '|'; } return rtrim($return, '|'); From 369d1d84e2765b8d4fbbb1876ff00b51b3ad95c6 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 30 Apr 2024 20:30:26 +0300 Subject: [PATCH 352/367] Another vote key refactor Brought back the old vote key logic, but more compact. --- logic/keys_vote.php | 47 +++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 13ef7e47..ab9e8790 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -255,46 +255,39 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { $directStartMinutes = $direct_slot->format('i'); // Get first raidslot rounded up to the next 5 minutes - $five_slot = new DateTimeImmutable($raid['start_time'], new DateTimeZone('UTC')); $minute = $directStartMinutes % 5; - $diff = ($minute != 0) ? 5 - $minute : 5; - $five_slot = $five_slot->add(new DateInterval('PT'.$diff.'M')); + $diff = ($minute != 0) ? 5 - $minute : 0; + $five_slot = $direct_slot->add(new DateInterval('PT'.$diff.'M')); + + // Add $config->RAID_FIRST_START minutes to five minutes slot + $five_plus_slot = $five_slot; + $five_plus_slot = $five_plus_slot->add(new DateInterval("PT".$config->RAID_FIRST_START."M")); // Get first regular raidslot - $first_slot = - ($minute == 0) ? - $direct_slot->add(new DateInterval('PT'.$RAID_SLOTS.'M')) : - $five_slot->add(new DateInterval('PT'.$RAID_SLOTS.'M') - ); + $firstSlotMinute = $directStartMinutes % $RAID_SLOTS; + $firstSlotDiff = ($firstSlotMinute != 0) ? $RAID_SLOTS - ($firstSlotMinute) : 0; + $first_slot = $direct_slot->add(new DateInterval('PT'.$firstSlotDiff.'M')); // Write slots to log. debug_log($direct_slot, 'Direct start slot:'); debug_log($five_slot, 'Next 5 Minute slot:'); debug_log($first_slot, 'First regular slot:'); $keys_time = []; - // Add button for when raid starts time - if($config->RAID_DIRECT_START && $direct_slot >= $dt_now) { + + // Add button for direct start if needed + if($config->RAID_DIRECT_START && $direct_slot != $five_slot && $direct_slot >= $dt_now) { $keys_time[] = button(dt2time($direct_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $direct_slot->format('YmdHis')]); - $last_slot = $direct_slot; } - // Add five minutes slot - if($five_slot >= $dt_now && - (empty($keys_time) || (!empty($keys_time) && $direct_slot != $five_slot)) && - $raid['event_vote_key_mode'] !== 0 - ) { + + // Add button for first five minutes if needed + if($five_slot < $first_slot && $five_plus_slot <= $first_slot && $five_slot >= $dt_now) { $keys_time[] = button(dt2time($five_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $five_slot->format('YmdHis')]); - $last_slot = $five_slot; - } - // Add the first normal slot - if($first_slot >= $dt_now && $first_slot != $five_slot) { - $keys_time[] = button(dt2time($first_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $first_slot->format('YmdHis')]); - $last_slot = $first_slot; } // Get regular slots // Start with second slot as first slot is already added to keys. $dt_end = new DateTimeImmutable($raid['end_time'], new DateTimeZone('UTC')); - $regular_slots = new DatePeriod($first_slot, new DateInterval('PT'.$RAID_SLOTS.'M'), $dt_end->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')), DatePeriod::EXCLUDE_START_DATE); + $regular_slots = new DatePeriod($first_slot, new DateInterval('PT'.$RAID_SLOTS.'M'), $dt_end->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M'))); // Add regular slots. foreach($regular_slots as $slot){ @@ -309,8 +302,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { // Add raid last start slot // Set end_time to last extra slot, subtract $config->RAID_LAST_START minutes and round down to earlier 5 minutes. - $last_extra_slot = $dt_end; - $last_extra_slot = $last_extra_slot->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')); + $last_extra_slot = $dt_end->sub(new DateInterval('PT'.$config->RAID_LAST_START.'M')); $s = 5 * 60; $last_extra_slot = $last_extra_slot->setTimestamp($s * floor($last_extra_slot->getTimestamp() / $s)); @@ -319,8 +311,9 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { debug_log($last_extra_slot, 'Last extra slot:'); // Last extra slot not conflicting with last slot - if((isset($last_slot) && $last_extra_slot > $last_slot && $last_extra_slot != $last_slot && $last_extra_slot >= $dt_now) || - (!isset($last_slot) && $last_extra_slot >= $dt_now)) { + if($last_extra_slot >= $dt_now && + ((isset($last_slot) && $last_extra_slot > $last_slot && $last_extra_slot != $last_slot) || + !isset($last_slot))) { // Add last extra slot $keys_time[] = button(dt2time($last_extra_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $last_extra_slot->format('YmdHis')]); } From 217220e5897a69ceb7f29287dd47e4091644f069 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 30 Apr 2024 20:34:50 +0300 Subject: [PATCH 353/367] Fixed getTranslation.php Exclude mega evolution translations for now. We could use those if someone wants to edit the translation logic to support them. --- getTranslations.php | 4 ++-- lang/pokemon_forms.json | 18 ++++++++++++++++++ lang/pokemon_moves.json | 9 +++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/getTranslations.php b/getTranslations.php index c97c1f7c..172ed745 100644 --- a/getTranslations.php +++ b/getTranslations.php @@ -23,8 +23,8 @@ $file = curl_open_file('https://raw.githubusercontent.com/WatWowMap/pogo-translations/master/static/locales/'. $lanfile. '.json'); $translationData = json_decode($file, true); foreach($translationData as $title => $translation) { - $split = explode('_', $title, 2); - if(count($split) < 2 or intval($split[1]) <= 0) continue; + $split = explode('_', $title); + if(count($split) != 2 or intval($split[1]) <= 0) continue; [$key, $id] = $split; // Save pokemon names into an array if pokemon id is larger than 0 if($key == 'poke') { diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index 2dfc6844..e1c5574a 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -2307,6 +2307,24 @@ "pokemon_form_2842": { "EN": "Horizons" }, + "pokemon_form_2843": { + "EN": "Gofest 2024 Stiara" + }, + "pokemon_form_2844": { + "EN": "Gofest 2024 Mtiara" + }, + "pokemon_form_2845": { + "EN": "Gofest 2024 Stiara" + }, + "pokemon_form_2846": { + "EN": "Gofest 2024 Mtiara" + }, + "pokemon_form_2847": { + "EN": "Gofest 2024 Sscarf" + }, + "pokemon_form_2848": { + "EN": "Gofest 2024 Mscarf" + }, "pokemon_form_2982": { "PT-BR": "Fêmea", "EN": "Female", diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index aefec69e..da29fa38 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -3021,5 +3021,14 @@ "IT": "Turbosabbia", "RU": "Песчаная Атака", "ES": "Ataque Arena" + }, + "pokemon_move_404": { + "EN": "Sunsteel Strike" + }, + "pokemon_move_405": { + "EN": "Moongeist Beam" + }, + "pokemon_move_408": { + "EN": "High Jump Kick" } } \ No newline at end of file From 7b54eb5f1b8595aa826c18647c33d5e4bc03994a Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 8 May 2024 20:58:00 +0300 Subject: [PATCH 354/367] New feature: enable/disable scheduled raid bosses Added the ability to enable and disable scheduled raid bosses. Makes managing regional raid bosses easier if using automatic updating of upcoming bosses. --- VERSION | 2 +- constants.php | 1 + lang/language.json | 65 ++++++++++++++++++++++++++++++ logic/createRaidBossList.php | 1 + logic/read_upcoming_bosses.php | 17 ++++++-- logic/resolve_raid_boss.php | 1 + mods/delete_scheduled_entry.php | 37 ----------------- mods/edit_scheduled_entry.php | 70 +++++++++++++++++++++++++++++++++ mods/import_future_bosses.php | 2 +- mods/pokedex_list_raids.php | 7 ++-- mods/update_bosses.php | 33 ++++++++++++++-- sql/0-pokemon-raid-bot.sql | 1 + sql/upgrade/6.sql | 1 + 13 files changed, 188 insertions(+), 50 deletions(-) delete mode 100644 mods/delete_scheduled_entry.php create mode 100644 mods/edit_scheduled_entry.php create mode 100644 sql/upgrade/6.sql diff --git a/VERSION b/VERSION index 7813681f..62f94575 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5 \ No newline at end of file +6 \ No newline at end of file diff --git a/constants.php b/constants.php index d01c501b..4c792b7d 100644 --- a/constants.php +++ b/constants.php @@ -151,6 +151,7 @@ defined('EMOJI_DISK') or define('EMOJI_DISK', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F4BE))); defined('EMOJI_NEW') or define('EMOJI_NEW', iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F195))); defined('EMOJI_CLIPPY') or define('EMOJI_CLIPPY',iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F4CE))); +defined('EMOJI_DISABLED') or define('EMOJI_DISABLED',iconv('UCS-4LE', 'UTF-8', pack('V', 0x1F645))); // Carriage return. defined('CR') or define('CR', "\n"); diff --git a/lang/language.json b/lang/language.json index a38de54b..d3de5135 100644 --- a/lang/language.json +++ b/lang/language.json @@ -480,6 +480,58 @@ "FI": "Poista", "ES": "Borrar" }, + "disabled": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Disabled", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Pois käytöstä", + "ES": "TRANSLATE" + }, + "enabled": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Enabled", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Käytössä", + "ES": "TRANSLATE" + }, + "disable": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Disable", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Poista käytöstä", + "ES": "TRANSLATE" + }, + "enable": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Enable", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Ota käyttöön", + "ES": "TRANSLATE" + }, "edit": { "NL": "Bewerken", "DE": "Bearbeiten", @@ -1429,6 +1481,19 @@ "FI": "Haluatko poistaa tämän ajastuksen?", "ES": "¿Quieres eliminar esta entrada programada?" }, + "edit_scheduled_entry": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "Edit scheduled entry", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "Muokkaa ajastusta", + "ES": "TRANSLATE" + }, "found_upcoming_bosses": { "NL": "Volgende geplande raid bazen gevonden", "DE": "Folgende bevorstehende Raid-Bosse gefunden", diff --git a/logic/createRaidBossList.php b/logic/createRaidBossList.php index 91cc8de7..c5f4a9c9 100644 --- a/logic/createRaidBossList.php +++ b/logic/createRaidBossList.php @@ -28,6 +28,7 @@ function createRaidBossList() { FROM raid_bosses WHERE raid_level IN ' . $levelList . ' AND date_end > DATE_SUB(NOW(), INTERVAL 1 HOUR) + AND disabled = 0 ORDER BY sameDay, date_start, date_end '); $list = ''; diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index 8fb9a95d..c8eda99b 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -3,11 +3,11 @@ require_once(LOGIC_PATH . '/curl_get_contents.php'); /** * Read upcoming bosses from Pokebattlers API and return the results as a HTML formatted text list - * @param bool $return_sql Return results in sql insert query instead of text list + * @param string $returnFormat Defines the format in which result are returned. sql, list or array * @param array|bool $levelsToRead Array of raid levels to include in import. Otherwise use the levels set in constants.php - * @return string + * @return string|array */ -function read_upcoming_bosses($return_sql = false, $levelsToRead = false) { +function read_upcoming_bosses($returnFormat = 'list', $levelsToRead = false) { global $pokebattler_import_future_tiers, $pokebattler_level_map, $pokebattler_pokemon_map; $link = curl_get_contents('https://fight.pokebattler.com/raids'); $pb = json_decode($link, true); @@ -17,6 +17,7 @@ function read_upcoming_bosses($return_sql = false, $levelsToRead = false) { $standardTimezone = new dateTimeZone('UTC'); $count = 0; $sql = $list = $prev_start = $prev_end = $prev_rl = ''; + $returnArr = []; foreach($pb['breakingNews'] as $news) { if($news['type'] != 'RAID_TYPE_RAID') continue; @@ -70,9 +71,17 @@ function read_upcoming_bosses($return_sql = false, $levelsToRead = false) { }else { $sql .= ',("'.$dex_id_form[0].'","'.$dex_id_form[1].'","'.$date_start.'","'.$date_end.'","'.$raid_level_id.'", 1)'; } + $returnArr[] = [ + 'pokedex_id' => $dex_id_form[0], + 'pokemon_form_id' => $dex_id_form[1], + 'date_start' => $date_start, + 'date_end' => $date_end, + 'raid_level' => $raid_level_id, + ]; } if($count > 0) $sql.=';'; - if($return_sql) return $sql; + if($returnFormat == 'sql') return $sql; + elseif($returnFormat == 'array') return $returnArr; else return $list; } diff --git a/logic/resolve_raid_boss.php b/logic/resolve_raid_boss.php index 8d964fb5..335ec78c 100644 --- a/logic/resolve_raid_boss.php +++ b/logic/resolve_raid_boss.php @@ -15,6 +15,7 @@ function resolve_raid_boss($pokemon, $pokemon_form, $spawn, $raid_level) { FROM raid_bosses WHERE raid_level = :raidLevel AND scheduled = 1 + AND disabled = 0 AND convert_tz(:spawn, "+00:00", :tzDiff) BETWEEN date_start AND date_end ', ['raidLevel' => $raid_level, 'spawn' => $spawn, 'tzDiff' => $tz_diff]); // Return egg diff --git a/mods/delete_scheduled_entry.php b/mods/delete_scheduled_entry.php deleted file mode 100644 index dd7bf21d..00000000 --- a/mods/delete_scheduled_entry.php +++ /dev/null @@ -1,37 +0,0 @@ -accessCheck('pokedex'); -$id = $data['i']; - -if(isset($data['s']) && $data['s'] == 1) { - my_query('DELETE FROM raid_bosses WHERE id = ?', [$id]); - include(ROOT_PATH . '/mods/pokedex_list_raids.php'); - exit(); -} -$query = my_query('SELECT pokedex_id, pokemon_form_id, date_start, date_end, raid_level FROM raid_bosses WHERE id = ? LIMIT 1', [$id]); -$pokemon = $query->fetch(); -$msg = getTranslation('delete_scheduled_confirmation') . CR . CR; -$msg .= $pokemon['date_start'] . ' - ' . $pokemon['date_end'] . ':' . CR; -$msg .= getTranslation($pokemon['raid_level'] . 'stars') . ': '; -$msg .= get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']); - -$keys[0][] = button(getTranslation('yes'), ['delete_scheduled_entry', 'i' => $id, 's' => 1]); -$keys[0][] = button(getTranslation('no'), 'pokedex_list_raids'); - -// Build callback message string. -$callback_response = 'OK'; - -// Telegram JSON array. -$tg_json = array(); - -// Answer callback. -$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); - -// Edit message. -$tg_json[] = edit_message($update, $msg, $keys, false, true); - -// Telegram multicurl request. -curl_json_multi_request($tg_json); diff --git a/mods/edit_scheduled_entry.php b/mods/edit_scheduled_entry.php new file mode 100644 index 00000000..6ef5e98d --- /dev/null +++ b/mods/edit_scheduled_entry.php @@ -0,0 +1,70 @@ +accessCheck('pokedex'); +$id = $data['i']; + +$query = my_query('SELECT pokedex_id, pokemon_form_id, date_start, date_end, raid_level, disabled FROM raid_bosses WHERE id = ? LIMIT 1', [$id]); +$pokemon = $query->fetch(); +if(isset($data['s']) && $data['s'] == 1) { + my_query('UPDATE raid_bosses SET disabled = NOT disabled WHERE id = ?', [$id]); + $pokemon['disabled'] = ($pokemon['disabled'] == 1) ? 0 : 1; +} +if(isset($data['s']) && $data['s'] == 2) { + $msg = getTranslation('delete_scheduled_confirmation') . CR . CR; + $msg .= $pokemon['date_start'] . ' - ' . $pokemon['date_end'] . ':' . CR; + $msg .= getTranslation($pokemon['raid_level'] . 'stars') . ': '; + $msg .= get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']) . CR; + $msg .= '' . ($pokemon['disabled'] ? getTranslation('disabled') : getTranslation('enabled')) .''; + $keys[0][0] = button(getTranslation('yes'), ['edit_scheduled_entry', 'i' => $id, 's' => 3]); + $keys[0][1] = button(getTranslation('no'), ['edit_scheduled_entry', 'i' => $id]); + // Build callback message string. + $callback_response = 'OK'; + + // Telegram JSON array. + $tg_json = array(); + + // Answer callback. + $tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + + // Edit message. + $tg_json[] = edit_message($update, $msg, $keys, false, true); + + // Telegram multicurl request. + curl_json_multi_request($tg_json); + exit(); +} +if(isset($data['s']) && $data['s'] == 3) { + my_query('DELETE FROM raid_bosses WHERE id = ?', [$id]); + include(ROOT_PATH . '/mods/pokedex_list_raids.php'); + exit(); +} +$msg = getTranslation('edit_scheduled_entry') . ':' . CR . CR; +$msg .= EMOJI_CLOCK . SP . $pokemon['date_start'] . ' - ' . $pokemon['date_end'] . CR; +$msg .= getTranslation($pokemon['raid_level'] . 'stars') . ': '; +$msg .= get_local_pokemon_name($pokemon['pokedex_id'], $pokemon['pokemon_form_id']) . CR; +$msg .= '' . ($pokemon['disabled'] ? getTranslation('disabled') : getTranslation('enabled')) .''; + +$keys[0][] = button( + ($pokemon['disabled'] ? getTranslation('enable') : getTranslation('disable')), + ['edit_scheduled_entry', 'i' => $id, 's' => 1] +); +$keys[1][] = button(getTranslation('delete'), ['edit_scheduled_entry', 'i' => $id, 's' => 2]); +$keys[2][] = button(getTranslation('back'), 'pokedex_list_raids'); + +// Build callback message string. +$callback_response = 'OK'; + +// Telegram JSON array. +$tg_json = array(); + +// Answer callback. +$tg_json[] = answerCallbackQuery($update['callback_query']['id'], $callback_response, true); + +// Edit message. +$tg_json[] = edit_message($update, $msg, $keys, false, true); + +// Telegram multicurl request. +curl_json_multi_request($tg_json); diff --git a/mods/import_future_bosses.php b/mods/import_future_bosses.php index 35341716..25462d3d 100644 --- a/mods/import_future_bosses.php +++ b/mods/import_future_bosses.php @@ -14,7 +14,7 @@ if($action == '1') { $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1;'; - $sql .= read_upcoming_bosses(true); + $sql .= read_upcoming_bosses('sql'); $query = my_query($sql); $msg = getTranslation('import_done'); $tg_json = array(); diff --git a/mods/pokedex_list_raids.php b/mods/pokedex_list_raids.php index 75cc3f6d..e6dac581 100644 --- a/mods/pokedex_list_raids.php +++ b/mods/pokedex_list_raids.php @@ -17,7 +17,8 @@ raid_bosses.raid_level, DATE_FORMAT(date_start, \'%e.%c. ' . getTranslation('raid_egg_opens_at') . ' %H:%i\') as date_start, DATE_FORMAT(date_end, \'%e.%c. ' . getTranslation('raid_egg_opens_at') . ' %H:%i\') as date_end, - raid_bosses.scheduled + raid_bosses.scheduled, + raid_bosses.disabled FROM raid_bosses LEFT JOIN pokemon ON raid_bosses.pokedex_id = pokemon.pokedex_id @@ -68,8 +69,8 @@ // Add button to edit pokemon. if($pokemon['scheduled'] == 1) { $keys[] = button( - EMOJI_CLOCK . ' [' . $pokemon['raid_level'] . ']' . SP . $poke_name, - ['delete_scheduled_entry', 'i' => $pokemon['id']] + EMOJI_CLOCK . ($pokemon['disabled'] == 1 ? EMOJI_DISABLED : '').' [' . $pokemon['raid_level'] . ']' . SP . $poke_name, + ['edit_scheduled_entry', 'i' => $pokemon['id']] ); } else { $keys[] = button('[' . $pokemon['raid_level'] . ']' . SP . $poke_name, ['pokedex_edit_pokemon', 'p' => $pokemon['pokedex_id'] . '-' . $pokemon['pokemon_form_id']]); diff --git a/mods/update_bosses.php b/mods/update_bosses.php index 346010a1..c69da62b 100644 --- a/mods/update_bosses.php +++ b/mods/update_bosses.php @@ -54,10 +54,35 @@ $sql = 'INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, raid_level) VALUES ' . $sql_values . ';'; }elseif($levels == 'scheduled') { require_once(LOGIC_PATH . '/read_upcoming_bosses.php'); - $data = read_upcoming_bosses(true, [5,6,7,8,10]); - if(empty($data)) exit; - $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1;'; - $sql .= $data; + $upcoming = read_upcoming_bosses('array', [5,6,7,8,10]); + if(empty($upcoming)) exit; + $idArray = []; + $updateRows = ''; + $updateCount = 0; + // Exclude existing entries from deletion + foreach($upcoming as $row) { + $data = my_query(' + SELECT + id, pokedex_id, pokemon_form_id, date_start, date_end, raid_level + FROM raid_bosses + WHERE pokedex_id = :pokedex_id + AND pokemon_form_id = :pokemon_form_id + AND date_start = :date_start + AND date_end = :date_end + AND scheduled = 1' + ,['pokedex_id' => $row['pokedex_id'], 'pokemon_form_id' => $row['pokemon_form_id'], 'date_start'=>$row['date_start'], 'date_end'=>$row['date_end']]); + $result = $data->fetchAll(PDO::FETCH_COLUMN, 0); + if($data->rowCount() == 0) { + $updateRows .= '(\'' . implode("', '", $row) . '\', \'1\'),'; + $updateCount++; + }else { + $idArray[] = $result[0]; + } + } + $updateRows = rtrim($updateRows, ','); + + $sql = 'DELETE FROM raid_bosses WHERE scheduled = 1 AND id NOT IN ('.implode(',', $idArray).'); '; + if($updateCount > 0) $sql .= 'INSERT INTO raid_bosses (pokedex_id, pokemon_form_id, date_start, date_end, raid_level, scheduled) VALUES ' . $updateRows.';'; }else { info_log("Invalid argumens supplied to update_bosses!"); exit(); diff --git a/sql/0-pokemon-raid-bot.sql b/sql/0-pokemon-raid-bot.sql index ee7ad515..9dd0601d 100644 --- a/sql/0-pokemon-raid-bot.sql +++ b/sql/0-pokemon-raid-bot.sql @@ -106,6 +106,7 @@ CREATE TABLE `raid_bosses` ( `date_end` datetime NOT NULL DEFAULT '2038-01-19 03:14:07', `raid_level` TINYINT UNSIGNED DEFAULT NULL, `scheduled` TINYINT(1) NULL DEFAULT 0, + `disabled` TINYINT(1) UNSIGNED DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `raids` ( diff --git a/sql/upgrade/6.sql b/sql/upgrade/6.sql new file mode 100644 index 00000000..ef70b947 --- /dev/null +++ b/sql/upgrade/6.sql @@ -0,0 +1 @@ +ALTER TABLE `raid_bosses` ADD COLUMN IF NOT EXISTS `disabled` TINYINT(1) UNSIGNED DEFAULT 0 AFTER `scheduled`; From 4648990ddc7e4c46a3b6d579712bced2b3a4cfbf Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sat, 25 May 2024 10:02:15 +0300 Subject: [PATCH 355/367] New translations --- lang/pokemon_moves.json | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index da29fa38..b7f86006 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -3023,12 +3023,30 @@ "ES": "Ataque Arena" }, "pokemon_move_404": { - "EN": "Sunsteel Strike" + "PT-BR": "Ataque Solaraço", + "EN": "Sunsteel Strike", + "FR": "Choc Météore", + "DE": "Stahlgestirn", + "IT": "Astrocarica", + "RU": "Солнечно-Стальной Удар", + "ES": "Meteoimpacto" }, "pokemon_move_405": { - "EN": "Moongeist Beam" + "PT-BR": "Feixe Espectral", + "EN": "Moongeist Beam", + "FR": "Rayon Spectral", + "DE": "Schattenstrahl", + "IT": "Raggio d’Ombra", + "RU": "Луч Лунного Духа", + "ES": "Rayo Umbrío" }, "pokemon_move_408": { - "EN": "High Jump Kick" + "PT-BR": "Chute de Pulo Alto", + "EN": "High Jump Kick", + "FR": "Pied Voltige", + "DE": "Turmkick", + "IT": "Calcinvolo", + "RU": "Прыжок-Удар", + "ES": "Patada Salto Alta" } } \ No newline at end of file From 75fd157b6dc01793972d42f865908540492c80c1 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Wed, 29 May 2024 17:26:04 +0300 Subject: [PATCH 356/367] Another wormhole fix to raid_hour_creator --- .../raid_hour_creator.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/core/tools/automate_raid_hour_creation/raid_hour_creator.php b/core/tools/automate_raid_hour_creation/raid_hour_creator.php index f1faf3f6..e3bce56c 100644 --- a/core/tools/automate_raid_hour_creation/raid_hour_creator.php +++ b/core/tools/automate_raid_hour_creation/raid_hour_creator.php @@ -114,19 +114,20 @@ function get_current_bosses($spawn) { $i = 0; $levels = [5, 7, 8]; // Search potential raid hour bosses from these raid levels $pokemon = $pokemon_form = false; - do { - $pk = $dbh->prepare('SELECT pokedex_id,pokemon_form_id FROM raid_bosses WHERE raid_level = ? AND ? BETWEEN date_start AND date_end'); - $pk->execute([$levels[$i], $spawn]); + foreach($levels as $level) { + $pk = $dbh->prepare('SELECT pokedex_id,pokemon_form_id FROM raid_bosses WHERE raid_level = ? AND ? BETWEEN date_start AND date_end and disabled = 0'); + $pk->execute([$level, $spawn]); $res = $pk->fetch(); if($pk->rowCount() == 1) { $pokemon = $res['pokedex_id']; $pokemon_form = $res['pokemon_form_id']; + break; }elseif($pk->rowCount() > 1) { - $pokemon = 999 . $levels[$i]; + $pokemon = 999 . $level; $pokemon_form = 0; + break; } - $i++; - } while($pk->rowcount() > 0 or $i <= 1); + } if($pokemon === false) return false; return [$pokemon,$pokemon_form]; } From dce4491dea8defd647418ca89021fa3b9c5ac8ba Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:42:41 +0300 Subject: [PATCH 357/367] Added Ho-oh to pokebattler_pokemon_map --- constants.php | 1 + 1 file changed, 1 insertion(+) diff --git a/constants.php b/constants.php index 4c792b7d..8e986538 100644 --- a/constants.php +++ b/constants.php @@ -54,6 +54,7 @@ ]; $pokebattler_pokemon_map = [ + 'HO_OH' => 'HO-OH', 'GIRATINA' => 'GIRATINA_ALTERED', 'ZACIAN' => 'ZACIAN_HERO_FORM', 'ZAMAZENTA' => 'ZAMAZENTA_HERO_FORM', From bd34bec80c6320a44cdb2737ffced8db1aa02960 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:59:18 +0300 Subject: [PATCH 358/367] getdb fix --- mods/getdb.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/getdb.php b/mods/getdb.php index ada36dc7..03309505 100644 --- a/mods/getdb.php +++ b/mods/getdb.php @@ -152,7 +152,7 @@ function parse_master_data($game_master_url) { elseif($weatherboost_table[$pokemon_types[0]] != $weatherboost_table[$pokemon_types[1]]) $weather .= $weatherboost_table[$pokemon_types[1]]; foreach($row['forms'] as $formData) { - if(($formData['name'] == 'Unset' && count($row['forms']) > 1) || $formData['name'] == 'Shadow' || $formData['name'] == 'Purified') continue; + if($formData['name'] == 'Shadow' || $formData['name'] == 'Purified') continue; if($formData['name'] == 'Normal') { $pokemon_array[$pokemon_id]['protoName'] = str_replace('_NORMAL', '', $formData['proto']); $form_name = 'normal'; From b147c8db98e17a6b4ff9fe139e6194ada8530b68 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:59:40 +0300 Subject: [PATCH 359/367] Added EXTRA_DATES config option for automatic raid hour creator --- .../config.json.example | 3 ++- .../raid_hour_creator.php | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/tools/automate_raid_hour_creation/config.json.example b/core/tools/automate_raid_hour_creation/config.json.example index 4bc04876..8c8d7da3 100644 --- a/core/tools/automate_raid_hour_creation/config.json.example +++ b/core/tools/automate_raid_hour_creation/config.json.example @@ -12,5 +12,6 @@ [2,"<-Gym id there and event note for 2nd gym here"], [3,"<-Gym id there and event note for 3rd gym here"] ], - "URL": "https://www.yourhost.com/PokemonRaidBot/index.php?apikey=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" + "URL": "https://www.yourhost.com/PokemonRaidBot/index.php?apikey=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11", + "EXTRA_DATES":[] } diff --git a/core/tools/automate_raid_hour_creation/raid_hour_creator.php b/core/tools/automate_raid_hour_creation/raid_hour_creator.php index e3bce56c..b5f9f4c8 100644 --- a/core/tools/automate_raid_hour_creation/raid_hour_creator.php +++ b/core/tools/automate_raid_hour_creation/raid_hour_creator.php @@ -41,7 +41,7 @@ $end->sub($interval); $event_start = $start->format('Y-m-d H:i:s'); $event_end = $end->format('Y-m-d H:i:s'); - if($event['type'] == 'raid-hour' && (($raids->rowcount() > 0 && !in_array($event_start, $raids_res)) || $raids->rowcount() === 0)) { + if($event['type'] == 'raid-hour' && $event_start > $now && (($raids->rowcount() > 0 && !in_array($event_start, $raids_res)) || $raids->rowcount() === 0)) { $mon_name = trim(str_replace('Raid Hour','',str_replace('Forme','',$event['name']))); $mon_split = explode(' ',$mon_name); $part_count = count($mon_split); @@ -71,15 +71,15 @@ $pokemon = $mon[0]; $pokemon_form = $mon[1]; } - $raid_to_create[] = [$pokemon, $pokemon_form,$event_start,$event_end]; + $raid_to_create[] = [$pokemon, $pokemon_form,$event_start,$event_end, '5']; $datesToCreate[] = $event_start; } } - if($now->format('w') == 3 && !in_array($now->format('Y-m-d H:i:s'), $raids_res) && !in_array($now->format('Y-m-d H:i:s'), $datesToCreate)) { + if(($now->format('w') == 3 || in_array($now->format('Y-m-d'), $config->EXTRA_DATES)) && !in_array($now->format('Y-m-d H:i:s'), $raids_res) && !in_array($now->format('Y-m-d H:i:s'), $datesToCreate)) { $start_time = gmdate('Y-m-d H:i:s',mktime(18,0,0)); $end_time = gmdate('Y-m-d H:i:s',mktime(19,0,0)); $mon = get_current_bosses($start_time); - if($mon !== false) $raid_to_create[] = [$mon[0], $mon[1] ,$start_time, $end_time]; + if($mon !== false) $raid_to_create[] = [$mon[0], $mon[1] ,$start_time, $end_time, $mon[2]]; } } try { @@ -98,10 +98,10 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) '); + $now = gmdate('Y-m-d H:i:s'); foreach($raid_to_create as $raid_info) { foreach($config->GYM_INFOS as $t) { - $now = gmdate('Y-m-d H:i:s'); - $query->execute([$config->RAID_CREATOR_ID,$raid_info[0],$raid_info[1],$now,'5',$raid_info[2],$raid_info[3],$t[0],$config->RAID_HOUR_EVENT_ID,$t[1]]); + $query->execute([$config->RAID_CREATOR_ID,$raid_info[0],$raid_info[1],$now,$raid_info[4],$raid_info[2],$raid_info[3],$t[0],$config->RAID_HOUR_EVENT_ID,$t[1]]); } } } @@ -129,7 +129,7 @@ function get_current_bosses($spawn) { } } if($pokemon === false) return false; - return [$pokemon,$pokemon_form]; + return [$pokemon, $pokemon_form, $level]; } function curl_get_contents($url) { From b99632915d87b86f55f91a0bceed627a6e8ec84f Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:00:00 +0300 Subject: [PATCH 360/367] Updated translations --- getTranslations.php | 2 +- lang/pokemon_forms.json | 216 ++++++++----- lang/pokemon_moves.json | 687 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 822 insertions(+), 83 deletions(-) diff --git a/getTranslations.php b/getTranslations.php index 172ed745..62e6cf30 100644 --- a/getTranslations.php +++ b/getTranslations.php @@ -65,7 +65,7 @@ function remove_duplicate_translations($array) { foreach($array as $translation_id => $translations) { foreach($translations as $lang => $translation) { if( - ($lang == 'EN' or $translation != $array[$translation_id]['EN']) and + ($lang == 'EN' or (isset($array[$translation_id]['EN']) && $translation != $array[$translation_id]['EN'])) and !in_array($array[$translation_id]['EN'], ['Normal','Purified','Shadow']) ) $new_array[$translation_id][$lang] = $translation; diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index e1c5574a..28565b7f 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -135,28 +135,28 @@ "ES": "Velocidad" }, "pokemon_form_37": { - "EN": "00" + "EN": "01" }, "pokemon_form_38": { - "EN": "01" + "EN": "02" }, "pokemon_form_39": { - "EN": "02" + "EN": "03" }, "pokemon_form_40": { - "EN": "03" + "EN": "04" }, "pokemon_form_41": { - "EN": "04" + "EN": "05" }, "pokemon_form_42": { - "EN": "05" + "EN": "06" }, "pokemon_form_43": { - "EN": "06" + "EN": "07" }, "pokemon_form_44": { - "EN": "07" + "EN": "08" }, "pokemon_form_46": { "EN": "Alola", @@ -568,40 +568,40 @@ "ES": "Tronco Basura" }, "pokemon_form_121": { - "EN": "08" + "EN": "09" }, "pokemon_form_122": { - "EN": "09" + "EN": "10" }, "pokemon_form_123": { - "EN": "10" + "EN": "11" }, "pokemon_form_124": { - "EN": "11" + "EN": "12" }, "pokemon_form_125": { - "EN": "12" + "EN": "13" }, "pokemon_form_126": { - "EN": "13" + "EN": "14" }, "pokemon_form_127": { - "EN": "14" + "EN": "15" }, "pokemon_form_128": { - "EN": "15" + "EN": "16" }, "pokemon_form_129": { - "EN": "16" + "EN": "17" }, "pokemon_form_130": { - "EN": "17" + "EN": "18" }, "pokemon_form_131": { - "EN": "18" + "EN": "19" }, "pokemon_form_132": { - "EN": "19" + "EN": "20" }, "pokemon_form_133": { "EN": "A", @@ -1049,6 +1049,7 @@ "pokemon_form_2477": { "PT-BR": "Forma Falsificada", "EN": "Phony Form", + "FR": "Forme Contrefaçon", "DE": "Fälschungsform", "IT": "Forma Contraffatta", "RU": "Фальшивая форма", @@ -1057,6 +1058,7 @@ "pokemon_form_2478": { "PT-BR": "Forma Autêntica", "EN": "Antique Form", + "FR": "Forme Authentique", "DE": "Originalform", "IT": "Forma Autentica", "RU": "Антикварная форма", @@ -1065,6 +1067,7 @@ "pokemon_form_2480": { "PT-BR": "Forma Falsificada", "EN": "Phony Form", + "FR": "Forme Contrefaçon", "DE": "Fälschungsform", "IT": "Forma Contraffatta", "RU": "Фальшивая форма", @@ -1073,6 +1076,7 @@ "pokemon_form_2481": { "PT-BR": "Forma Autêntica", "EN": "Antique Form", + "FR": "Forme Authentique", "DE": "Originalform", "IT": "Forma Autentica", "RU": "Антикварная форма", @@ -1113,52 +1117,34 @@ "ES": "Hembra" }, "pokemon_form_2544": { - "PT-BR": "Forma Saciada", - "EN": "Full Belly Mode", + "EN": "Full Belly", "DE": "Pappsatt", - "IT": "Motivo Panciapiena", - "RU": "Режим Полный Живот", - "ES": "Forma Saciada" + "RU": "Режим Полный Живот" }, "pokemon_form_2545": { - "PT-BR": "Forma Voraz", - "EN": "Hangry Mode", + "EN": "Hangry", "DE": "Kohldampf", - "IT": "Motivo Panciavuota", - "RU": "Злоголодный режим", - "ES": "Forma Voraz" + "RU": "Злоголодный режим" }, "pokemon_form_2576": { - "PT-BR": "Espada Coroada", "EN": "Crowned Sword", "DE": "König des Schwertes", - "IT": "Re delle Spade", - "RU": "Коронованный Меч", - "ES": "Espada Suprema" + "RU": "Коронованный Меч" }, "pokemon_form_2577": { - "PT-BR": "Herói Veterano", - "EN": "Hero of Many Battles", + "EN": "Hero", "DE": "Heldenhafter Krieger", - "IT": "Eroe di Mille Lotte", - "RU": "Герой многих битв", - "ES": "Guerrero Avezado" + "RU": "Герой многих битв" }, "pokemon_form_2578": { - "PT-BR": "Escudo Coroado", "EN": "Crowned Shield", "DE": "König des Schildes", - "IT": "Re degli Scudi", - "RU": "Коронованный Щит", - "ES": "Escudo Supremo" + "RU": "Коронованный Щит" }, "pokemon_form_2579": { - "PT-BR": "Herói Veterano", - "EN": "Hero of Many Battles", + "EN": "Hero", "DE": "Heldenhafter Krieger", - "IT": "Eroe di Mille Lotte", - "RU": "Герой многих битв", - "ES": "Guerrero Avezado" + "RU": "Герой многих битв" }, "pokemon_form_2580": { "EN": "Eternamax", @@ -1920,14 +1906,22 @@ "RU": "Исходный цвет" }, "pokemon_form_2723": { - "EN": "Single Strike", + "PT-BR": "Estilo Golpe Decisivo", + "EN": "Single Strike Style", + "FR": "Style Poing Final", "DE": "Fokussierter Stil", - "RU": "Фома одного удара" + "IT": "Stile Singolcolpo", + "RU": "Фома одного удара", + "ES": "Estilo Brusco" }, "pokemon_form_2724": { - "EN": "Rapid Strike", + "PT-BR": "Estilo Golpe Fluido", + "EN": "Rapid Strike Style", + "FR": "Style Mille Poings", "DE": "Fließender Stil", - "RU": "Форма множества ударов" + "IT": "Stile Pluricolpo", + "RU": "Форма множества ударов", + "ES": "Estilo Fluido" }, "pokemon_form_2726": { "EN": "Ice Rider", @@ -1971,7 +1965,7 @@ "FR": "Forme Crépusculaire", "DE": "Zwielichtform", "IT": "Forma Crepuscolo", - "RU": "Сумеречная форма", + "RU": "Сумеречная Форма", "ES": "Forma Crepuscular" }, "pokemon_form_2739": { @@ -2052,7 +2046,7 @@ "FR": "Solaire", "DE": "Sonnenform", "IT": "Sole", - "RU": "Солнечная форма", + "RU": "Солнечная Форма", "ES": "Sol" }, "pokemon_form_2764": { @@ -2118,7 +2112,7 @@ "FR": "Solaire", "DE": "Sonnenform", "IT": "Sole", - "RU": "Солнечная форма", + "RU": "Солнечная Форма", "ES": "Sol" }, "pokemon_form_2784": { @@ -2181,7 +2175,7 @@ "FR": "Forme Avatar", "DE": "Inkarnationsform", "IT": "Forma Incarnazione", - "RU": "Воплощённая форма", + "RU": "Воплощённая Форма", "ES": "Forma Avatar" }, "pokemon_form_2803": { @@ -2190,7 +2184,7 @@ "FR": "Forme Totémique", "DE": "Tiergeistform", "IT": "Forma Totem", - "RU": "Форма Териан", + "RU": "Териан-Форма", "ES": "Forma Tótem" }, "pokemon_form_2804": { @@ -2199,7 +2193,7 @@ "FR": "Motif Blanc", "DE": "Weißlinig", "IT": "Forma Lineabianca", - "RU": "Белая полосатая форма", + "RU": "Белая Полосатая Форма", "ES": "Raya Blanca" }, "pokemon_form_2805": { @@ -2214,7 +2208,7 @@ "FR": "Femelle", "DE": "Weiblich", "IT": "Femmina", - "RU": "Женский", + "RU": "Женская Особь", "ES": "Hembra" }, "pokemon_form_2813": { @@ -2262,7 +2256,7 @@ "FR": "Forme Originelle", "DE": "Urform", "IT": "Forma Originale", - "RU": "Исходная форма", + "RU": "Исходная Форма", "ES": "Forma Origen" }, "pokemon_form_2830": { @@ -2271,7 +2265,7 @@ "FR": "Forme Originelle", "DE": "Urform", "IT": "Forma Originale", - "RU": "Исходная форма", + "RU": "Исходная Форма", "ES": "Forma Origen" }, "pokemon_form_2832": { @@ -2325,13 +2319,55 @@ "pokemon_form_2848": { "EN": "Gofest 2024 Mscarf" }, + "pokemon_form_2849": { + "EN": "Wildarea 2024" + }, + "pokemon_form_2850": { + "EN": "Diwali 2024" + }, + "pokemon_form_2856": { + "EN": "Gotour 2025 A" + }, + "pokemon_form_2857": { + "EN": "Gotour 2025 B" + }, + "pokemon_form_2858": { + "EN": "Gotour 2025 A 02" + }, + "pokemon_form_2859": { + "EN": "Gotour 2025 B 02" + }, + "pokemon_form_2863": { + "EN": "Kurta" + }, + "pokemon_form_2864": { + "EN": "Gofest 2025 Goggles Red" + }, + "pokemon_form_2865": { + "EN": "Gofest 2025 Goggles Blue" + }, + "pokemon_form_2866": { + "EN": "Gofest 2025 Goggles Yellow" + }, + "pokemon_form_2867": { + "EN": "Gofest 2025 Monocle Red" + }, + "pokemon_form_2868": { + "EN": "Gofest 2025 Monocle Blue" + }, + "pokemon_form_2869": { + "EN": "Gofest 2025 Monocle Yellow" + }, + "pokemon_form_2870": { + "EN": "Gofest 2025 Train Conductor" + }, "pokemon_form_2982": { "PT-BR": "Fêmea", "EN": "Female", "FR": "Femelle", "DE": "Weiblich", "IT": "Femmina", - "RU": "Женский", + "RU": "Женская Особь", "ES": "Hembra" }, "pokemon_form_2983": { @@ -2346,7 +2382,7 @@ "FR": "Plumage Vert", "DE": "Grüngefiedert", "IT": "Piume Verdi", - "RU": "Зелёное оперение", + "RU": "Зелёное Оперение", "ES": "Plumaje Verde" }, "pokemon_form_2986": { @@ -2355,7 +2391,7 @@ "FR": "Plumage Bleu", "DE": "Blaugefiedert", "IT": "Piume Azzurre", - "RU": "Синее оперение", + "RU": "Синее Оперение", "ES": "Plumaje Azul" }, "pokemon_form_2987": { @@ -2364,7 +2400,7 @@ "FR": "Plumage Jaune", "DE": "Gelbgefiedert", "IT": "Piume Gialle", - "RU": "Жёлтое оперение", + "RU": "Жёлтое Оперение", "ES": "Plumaje Amarillo" }, "pokemon_form_2988": { @@ -2376,16 +2412,11 @@ "FR": "Forme Ordinaire", "DE": "Alltagsform", "IT": "Forma Ingenua", - "RU": "Нулевая форма", + "RU": "Нулевая Форма", "ES": "Forma Ingenua" }, "pokemon_form_2990": { - "PT-BR": "Herói Veterano", - "EN": "Hero of Many Battles", - "DE": "Heldenhafter Krieger", - "IT": "Eroe di Mille Lotte", - "RU": "Герой многих битв", - "ES": "Guerrero Avezado" + "EN": "Hero" }, "pokemon_form_2991": { "PT-BR": "Forma Curvada", @@ -2393,7 +2424,7 @@ "FR": "Forme Courbée", "DE": "Gebogene Form", "IT": "Forma Arcuata", - "RU": "Изогнутая форма", + "RU": "Изогнутая Форма", "ES": "Forma Curvada" }, "pokemon_form_2992": { @@ -2402,7 +2433,7 @@ "FR": "Forme Affalée", "DE": "Hängende Form", "IT": "Forma Adagiata", - "RU": "Свисающая форма", + "RU": "Свисающая Форма", "ES": "Forma Lánguida" }, "pokemon_form_2993": { @@ -2411,7 +2442,7 @@ "FR": "Forme Raide", "DE": "Gestreckte Form", "IT": "Forma Tesa", - "RU": "Вытянутая форма", + "RU": "Вытянутая Форма", "ES": "Forma Recta" }, "pokemon_form_2994": { @@ -2420,7 +2451,7 @@ "FR": "Forme Double", "DE": "Zweisegmentform", "IT": "Forma Bimetamero", - "RU": "Двухсегментная форма", + "RU": "Двухсегментная Форма", "ES": "Forma Binodular" }, "pokemon_form_2995": { @@ -2429,7 +2460,7 @@ "FR": "Forme Triple", "DE": "Dreisegmentform", "IT": "Forma Trimetamero", - "RU": "Трёхсегментная форма", + "RU": "Трёхсегментная Форма", "ES": "Forma Trinodular" }, "pokemon_form_2996": { @@ -2438,7 +2469,7 @@ "FR": "Forme Finale", "DE": "Vollkommene Gestalt", "IT": "Foggia Integrale", - "RU": "Финальная форма", + "RU": "Финальная Форма", "ES": "Fisonomía Plena" }, "pokemon_form_2997": { @@ -2447,7 +2478,7 @@ "FR": "Mode Ultime", "DE": "Kompletter Modus", "IT": "Assetto Completo", - "RU": "Полноценный режим", + "RU": "Полноценный Режим", "ES": "Modo Pleno" }, "pokemon_form_3001": { @@ -2466,13 +2497,31 @@ "EN": "Summer 2023 D" }, "pokemon_form_3006": { - "EN": "Paldea Combat" + "PT-BR": "Espécie de Combate", + "EN": "Combat Breed", + "FR": "Race Combative", + "DE": "Gefechtvariante", + "IT": "Varietà Combattiva", + "RU": "Порода Сражение", + "ES": "Variedad Combatiente" }, "pokemon_form_3007": { - "EN": "Paldea Blaze" + "PT-BR": "Espécie Labareda", + "EN": "Blaze Breed", + "FR": "Race Flamboyante", + "DE": "Flammenvariante", + "IT": "Varietà Infuocata", + "RU": "Порода Пламя", + "ES": "Variedad Ardiente" }, "pokemon_form_3008": { - "EN": "Paldea Aqua" + "PT-BR": "Espécie Aquática", + "EN": "Aqua Breed", + "FR": "Race Aquatique", + "DE": "Flutenvariante", + "IT": "Varietà Acquatica", + "RU": "Порода Аква", + "ES": "Variedad Acuática" }, "pokemon_form_3009": { "EN": "Paldea" @@ -2491,5 +2540,8 @@ }, "pokemon_form_3014": { "EN": "Wcs 2023" + }, + "pokemon_form_3015": { + "EN": "Wcs 2024" } } \ No newline at end of file diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index b7f86006..6f7d6dc3 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -3040,6 +3040,24 @@ "RU": "Луч Лунного Духа", "ES": "Rayo Umbrío" }, + "pokemon_move_406": { + "PT-BR": "Roda de Aura", + "EN": "Aura Wheel", + "FR": "Roue Libre", + "DE": "Aura-Rad", + "IT": "Ruota d’Aura", + "RU": "Колесо Ауры", + "ES": "Rueda Aural" + }, + "pokemon_move_407": { + "PT-BR": "Roda de Aura", + "EN": "Aura Wheel", + "FR": "Roue Libre", + "DE": "Aura-Rad", + "IT": "Ruota d’Aura", + "RU": "Колесо Ауры", + "ES": "Rueda Aural" + }, "pokemon_move_408": { "PT-BR": "Chute de Pulo Alto", "EN": "High Jump Kick", @@ -3048,5 +3066,674 @@ "IT": "Calcinvolo", "RU": "Прыжок-Удар", "ES": "Patada Salto Alta" + }, + "pokemon_move_409": { + "PT-BR": "Chama Max", + "EN": "Max Flare", + "FR": "Pyromax", + "DE": "Dyna-Brand", + "IT": "Dynafiammata", + "RU": "Вспышка Макс", + "ES": "Maxignición" + }, + "pokemon_move_410": { + "PT-BR": "Nuvem de Inseto Max", + "EN": "Max Flutterby", + "FR": "Insectomax", + "DE": "Dyna-Schwarm", + "IT": "Dynainsetto", + "RU": "Бабочка Макс", + "ES": "Maxinsecto" + }, + "pokemon_move_411": { + "PT-BR": "Raio Max", + "EN": "Max Lightning", + "FR": "Fulguromax", + "DE": "Dyna-Gewitter", + "IT": "Dynasaetta", + "RU": "Молния Макс", + "ES": "Maxitormenta" + }, + "pokemon_move_412": { + "PT-BR": "Golpe Max", + "EN": "Max Strike", + "FR": "Normalomax", + "DE": "Dyna-Angriff", + "IT": "Dynattacco", + "RU": "Удар Макс", + "ES": "Maxiataque" + }, + "pokemon_move_413": { + "PT-BR": "Punho Max", + "EN": "Max Knuckle", + "FR": "Pugilomax", + "DE": "Dyna-Faust", + "IT": "Dynapugno", + "RU": "Кулак Макс", + "ES": "Maxipuño" + }, + "pokemon_move_414": { + "PT-BR": "Espectro Max", + "EN": "Max Phantasm", + "FR": "Spectromax", + "DE": "Dyna-Spuk", + "IT": "Dynavuoto", + "RU": "Иллюзия Макс", + "ES": "Maxiespectro" + }, + "pokemon_move_415": { + "PT-BR": "Temporal de Granizo Max", + "EN": "Max Hailstorm", + "FR": "Cryomax", + "DE": "Dyna-Frost", + "IT": "Dynagelo", + "RU": "Град Макс", + "ES": "Maxihelada" + }, + "pokemon_move_416": { + "PT-BR": "Corrosão Max", + "EN": "Max Ooze", + "FR": "Toxinomax", + "DE": "Dyna-Giftschwall", + "IT": "Dynacorrosione", + "RU": "Токсины Макс", + "ES": "Maxiácido" + }, + "pokemon_move_417": { + "PT-BR": "Gêiser Max", + "EN": "Max Geyser", + "FR": "Hydromax", + "DE": "Dyna-Flut", + "IT": "Dynaflusso", + "RU": "Гейзер Макс", + "ES": "Maxichorro" + }, + "pokemon_move_418": { + "PT-BR": "Corrente de Ar Max", + "EN": "Max Airstream", + "FR": "Aéromax", + "DE": "Dyna-Düse", + "IT": "Dynajet", + "RU": "Вихрь Макс", + "ES": "Maxiciclón" + }, + "pokemon_move_419": { + "PT-BR": "Queda Estelar Max", + "EN": "Max Starfall", + "FR": "Enchantomax", + "DE": "Dyna-Zauber", + "IT": "Dynafata", + "RU": "Волшебство Макс", + "ES": "Maxiestela" + }, + "pokemon_move_420": { + "PT-BR": "Bafo Dracônico Max", + "EN": "Max Wyrmwind", + "FR": "Dracomax", + "DE": "Dyna-Wyrm", + "IT": "Dynadragone", + "RU": "Дракон Макс", + "ES": "Maxidraco" + }, + "pokemon_move_421": { + "PT-BR": "Tempestade Mental Max", + "EN": "Max Mindstorm", + "FR": "Psychomax", + "DE": "Dyna-Kinese", + "IT": "Dynapsiche", + "RU": "Психокинез Макс", + "ES": "Maxionda" + }, + "pokemon_move_422": { + "PT-BR": "Desabamento Max", + "EN": "Max Rockfall", + "FR": "Lithomax", + "DE": "Dyna-Brocken", + "IT": "Dynamacigno", + "RU": "Камнепад Макс", + "ES": "Maxilito" + }, + "pokemon_move_423": { + "PT-BR": "Oscilação Max", + "EN": "Max Quake", + "FR": "Sismomax", + "DE": "Dyna-Erdstoß", + "IT": "Dynasisma", + "RU": "Землетрясение Макс", + "ES": "Maxitemblor" + }, + "pokemon_move_424": { + "PT-BR": "Escuridão Max", + "EN": "Max Darkness", + "FR": "Sinistromax", + "DE": "Dyna-Dunkel", + "IT": "Dynatenebre", + "RU": "Темнота Макс", + "ES": "Maxisombra" + }, + "pokemon_move_425": { + "PT-BR": "Flora Max", + "EN": "Max Overgrowth", + "FR": "Phytomax", + "DE": "Dyna-Flora", + "IT": "Dynaflora", + "RU": "Рост Макс", + "ES": "Maxiflora" + }, + "pokemon_move_426": { + "PT-BR": "Espinho de Aço Max", + "EN": "Max Steelspike", + "FR": "Métallomax", + "DE": "Dyna-Stahlzacken", + "IT": "Dynametallo", + "RU": "Остриё Макс", + "ES": "Maximetal" + }, + "pokemon_move_427": { + "PT-BR": "Queimada G-Max", + "EN": "G-Max Wildfire", + "FR": "Fournaise G-Max", + "DE": "Giga-Feuerflug", + "IT": "Gigavampa", + "RU": "Лесной Пожар G-Макс", + "ES": "Gigallamarada" + }, + "pokemon_move_428": { + "PT-BR": "Perturbação G-Max", + "EN": "G-Max Befuddle", + "FR": "Illusion G-Max", + "DE": "Giga-Benebelung", + "IT": "Gigastupore", + "RU": "Одурманивание G-Макс", + "ES": "Gigaestupor" + }, + "pokemon_move_429": { + "PT-BR": "Trovoada G-Max", + "EN": "G-Max Volt Crash", + "FR": "Foudre G-Max", + "DE": "Giga-Blitzhagel", + "IT": "Gigapikafolgori", + "RU": "Вольт-Таран G-Макс", + "ES": "Gigatronada" + }, + "pokemon_move_430": { + "PT-BR": "Corrida do Ouro G-Max", + "EN": "G-Max Gold Rush", + "FR": "Pactole G-Max", + "DE": "Giga-Münzregen", + "IT": "Gigamonete", + "RU": "Золотая Лихорадка G-Макс", + "ES": "Gigamonedas" + }, + "pokemon_move_431": { + "PT-BR": "Golpe Chi G-Max", + "EN": "G-Max Chi Strike", + "FR": "Frappe G-Max", + "DE": "Giga-Fokusschlag", + "IT": "Gigapugnointuito", + "RU": "Кулак G-Макс", + "ES": "Gigapuñición" + }, + "pokemon_move_432": { + "PT-BR": "Terror G-Max", + "EN": "G-Max Terror", + "FR": "Hantise G-Max", + "DE": "Giga-Spuksperre", + "IT": "Gigaillusione", + "RU": "Ужас G-Макс", + "ES": "Gigaaparición" + }, + "pokemon_move_433": { + "PT-BR": "Explosão de Espuma G-Max", + "EN": "G-Max Foam Burst", + "FR": "Bulles G-Max", + "DE": "Giga-Schaumbad", + "IT": "Gigaschiuma", + "RU": "Пена G-Макс", + "ES": "Gigaespuma" + }, + "pokemon_move_434": { + "PT-BR": "Ressonância G-Max", + "EN": "G-Max Resonance", + "FR": "Résonance G-Max", + "DE": "Giga-Melodie", + "IT": "Gigamelodia", + "RU": "Мелодия G-Макс", + "ES": "Gigamelodía" + }, + "pokemon_move_435": { + "PT-BR": "Ternura G-Max", + "EN": "G-Max Cuddle", + "FR": "Câlin G-Max", + "DE": "Giga-Gekuschel", + "IT": "Gigabbraccio", + "RU": "Обнимашки G-Макс", + "ES": "Gigaternura" + }, + "pokemon_move_436": { + "PT-BR": "Reabastecer G-Max", + "EN": "G-Max Replenish", + "FR": "Récolte G-Max", + "DE": "Giga-Recycling", + "IT": "Gigarinnovamento", + "RU": "Пополнение Запаса G-Макс", + "ES": "Gigarreciclaje" + }, + "pokemon_move_437": { + "PT-BR": "Pestilência G-Max", + "EN": "G-Max Malodor", + "FR": "Pestilence G-Max", + "DE": "Giga-Gestank", + "IT": "Gigafetore", + "RU": "Зловоние G-Макс", + "ES": "Gigapestilencia" + }, + "pokemon_move_438": { + "PT-BR": "Derretimento G-Max", + "EN": "G-Max Meltdown", + "FR": "Fonte G-Max", + "DE": "Giga-Schmelze", + "IT": "Gigaliquefazione", + "RU": "Разрушение G-Макс", + "ES": "Gigafundido" + }, + "pokemon_move_439": { + "PT-BR": "Intempérie G-Max", + "EN": "G-Max Wind Rage", + "FR": "Rafale G-Max", + "DE": "Giga-Sturmstoß", + "IT": "Gigaciclone", + "RU": "Ярость Ветра G-Макс", + "ES": "Gigahuracán" + }, + "pokemon_move_440": { + "PT-BR": "Seriedade G-Max", + "EN": "G-Max Gravitas", + "FR": "Ondes G-Max", + "DE": "Giga-Astrowellen", + "IT": "Gigagravitoforza", + "RU": "Сила Тяжести G-Макс", + "ES": "Gigabóveda" + }, + "pokemon_move_441": { + "PT-BR": "Enxurrada de Rochas", + "EN": "G-Max Stonesurge", + "FR": "Récif G-Max", + "DE": "Giga-Geröll", + "IT": "Gigarocciagetto", + "RU": "Каменный Импульс G-Макс", + "ES": "Gigatrampa Rocas" + }, + "pokemon_move_442": { + "PT-BR": "Rocha Vulcânica G-Max", + "EN": "G-Max Volcalith", + "FR": "Téphra G-Max", + "DE": "Giga-Schlacke", + "IT": "Gigalapilli", + "RU": "Вулкалит G-Макс", + "ES": "Gigarroca Ígnea" + }, + "pokemon_move_443": { + "PT-BR": "Acidez G-Max", + "EN": "G-Max Tartness", + "FR": "Corrosion G-Max", + "DE": "Giga-Säureguss", + "IT": "Gigattaccoacido", + "RU": "Кислотность G-Макс", + "ES": "Gigacorrosión" + }, + "pokemon_move_444": { + "PT-BR": "Néctar G-Max", + "EN": "G-Max Sweetness", + "FR": "Nectar G-Max", + "DE": "Giga-Nektarflut", + "IT": "Gigambrosia", + "RU": "Сладость G-Макс", + "ES": "Giganéctar" + }, + "pokemon_move_445": { + "PT-BR": "Jorro de Areia G-Max", + "EN": "G-Max Sandblast", + "FR": "Enlisement G-Max", + "DE": "Giga-Sandstoß", + "IT": "Gigavortisabbia", + "RU": "Песчаная Струя G-Макс", + "ES": "Gigapolvareda" + }, + "pokemon_move_446": { + "PT-BR": "Eletrocutar G-Max", + "EN": "G-Max Stun Shock", + "FR": "Choc G-Max", + "DE": "Giga-Voltschlag", + "IT": "Gigatoxiscossa", + "RU": "Ошеломление G-Макс", + "ES": "Gigadescarga" + }, + "pokemon_move_447": { + "PT-BR": "Centiferno G-Max", + "EN": "G-Max Centiferno", + "FR": "Combustion G-Max", + "DE": "Giga-Feuerkessel", + "IT": "Gigamillefiamme", + "RU": "Сентиферно G-Макс", + "ES": "Gigacienfuegos" + }, + "pokemon_move_448": { + "PT-BR": "Castigo G-Max", + "EN": "G-Max Smite", + "FR": "Sentence G-Max", + "DE": "Giga-Sanktion", + "IT": "Gigacastigo", + "RU": "Наказание G-Макс", + "ES": "Gigacastigo" + }, + "pokemon_move_449": { + "PT-BR": "Cochilo G-Max", + "EN": "G-Max Snooze", + "FR": "Torpeur G-Max", + "DE": "Giga-Gähnzwang", + "IT": "Gigatorpore", + "RU": "Дрёма G-Макс", + "ES": "Gigasopor" + }, + "pokemon_move_450": { + "PT-BR": "Grande Final G-Max", + "EN": "G-Max Finale", + "FR": "Cure G-Max", + "DE": "Giga-Lichtblick", + "IT": "Gigagranfinale", + "RU": "Финал G-Макс", + "ES": "Gigacolofón" + }, + "pokemon_move_451": { + "PT-BR": "Enxurrada de Aço G-Max", + "EN": "G-Max Steelsurge", + "FR": "Percée G-Max", + "DE": "Giga-Stahlschlag", + "IT": "Gigaferroaculei", + "RU": "Стальные Шипы G-Макс", + "ES": "Gigatrampa Acero" + }, + "pokemon_move_452": { + "PT-BR": "Esgotamento G-Max", + "EN": "G-Max Depletion", + "FR": "Usure G-Max", + "DE": "Giga-Dämpfer", + "IT": "Gigalogoramento", + "RU": "Опустошение G-Макс", + "ES": "Gigadesgaste" + }, + "pokemon_move_453": { + "PT-BR": "Chicotada G-Max", + "EN": "G-Max Vine Lash", + "FR": "Fouet G-Max", + "DE": "Giga-Geißel", + "IT": "Gigasferzata", + "RU": "Удар Лозами G-Макс", + "ES": "Gigalianas" + }, + "pokemon_move_454": { + "PT-BR": "Bombardeamento G-Max", + "EN": "G-Max Cannonade", + "FR": "Canonnade G-Max", + "DE": "Giga-Beschuss", + "IT": "Gigacannonata", + "RU": "Канонада G-Макс", + "ES": "Gigacañonazo" + }, + "pokemon_move_455": { + "PT-BR": "Solo de Tambores G-Max", + "EN": "G-Max Drum Solo", + "FR": "Percussion G-Max", + "DE": "Giga-Getrommel", + "IT": "Gigarullio", + "RU": "Соло на Барабанах G-Макс", + "ES": "Gigarredoble" + }, + "pokemon_move_456": { + "PT-BR": "Bola de Chamas G-Max", + "EN": "G-Max Fireball", + "FR": "Pyroball G-Max", + "DE": "Giga-Brandball", + "IT": "Gigafiammopalla", + "RU": "Огненный Шар G-Макс", + "ES": "Gigaesfera Ígnea" + }, + "pokemon_move_457": { + "PT-BR": "Hidroatirador G-Max", + "EN": "G-Max Hydrosnipe", + "FR": "Gâchette G-Max", + "DE": "Giga-Schütze", + "IT": "Gigasparomirato", + "RU": "Гидроснайпер G-Макс", + "ES": "Gigadisparo" + }, + "pokemon_move_458": { + "PT-BR": "Golpe Único G-Max", + "EN": "G-Max One Blow", + "FR": "Coup Final G-Max", + "DE": "Giga-Einzelhieb", + "IT": "Gigasingolcolpo", + "RU": "Единый Удар G-Макс", + "ES": "Gigagolpe Brusco" + }, + "pokemon_move_459": { + "PT-BR": "Fluxo Veloz G-Max", + "EN": "G-Max Rapid Flow", + "FR": "Multicoup G-Max", + "DE": "Giga-Multihieb", + "IT": "Gigapluricolpo", + "RU": "Серийный Поток G-Макс", + "ES": "Gigagolpe Fluido" + }, + "pokemon_move_460": { + "EN": "Vn Bm 052" + }, + "pokemon_move_461": { + "EN": "Vn Bm 053" + }, + "pokemon_move_462": { + "PT-BR": "Palma da Força", + "EN": "Force Palm", + "FR": "Forte-Paume", + "DE": "Kraftwelle", + "IT": "Palmoforza", + "RU": "Сильная Ладонь", + "ES": "Palmeo" + }, + "pokemon_move_463": { + "PT-BR": "Aria Cintilante", + "EN": "Sparkling Aria", + "FR": "Aria de l’Écume", + "DE": "Schaumserenade", + "IT": "Canto Effimero", + "RU": "Искрящаяся Ария", + "ES": "Aria Burbuja" + }, + "pokemon_move_464": { + "PT-BR": "Punho Feroz", + "EN": "Rage Fist", + "FR": "Poing de Colère", + "DE": "Zornesfaust", + "IT": "Pugno Furibondo", + "RU": "Кулак Ярости", + "ES": "Puño Furia" + }, + "pokemon_move_465": { + "PT-BR": "Truque Floral", + "EN": "Flower Trick", + "FR": "Magie Florale", + "DE": "Blumentrick", + "IT": "Prestigiafiore", + "RU": "Цветочный Фокус", + "ES": "Truco Floral" + }, + "pokemon_move_466": { + "PT-BR": "Choque Congelante", + "EN": "Freeze Shock", + "FR": "Éclair Gelé", + "DE": "Frostvolt", + "IT": "Elettrogelo", + "RU": "Холодовой Удар", + "ES": "Rayo Gélido" + }, + "pokemon_move_467": { + "PT-BR": "Queimadura de Gelo", + "EN": "Ice Burn", + "FR": "Feu Glacé", + "DE": "Frosthauch", + "IT": "Vampagelida", + "RU": "Ледяной Ожог", + "ES": "Llama Gélida" + }, + "pokemon_move_468": { + "PT-BR": "Canção Ardente", + "EN": "Torch Song", + "FR": "Chant Flamboyant", + "DE": "Loderlied", + "IT": "Canzone Ardente", + "RU": "Пение Пламени", + "ES": "Canto Ardiente" + }, + "pokemon_move_469": { + "PT-BR": "Espada Colossal", + "EN": "Behemoth Blade", + "FR": "Gladius Maximus", + "DE": "Gigantenhieb", + "IT": "Taglio Maestoso", + "RU": "Меч Левиафана", + "ES": "Tajo Supremo" + }, + "pokemon_move_470": { + "PT-BR": "Pancada Colossal", + "EN": "Behemoth Bash", + "FR": "Aegis Maxima", + "DE": "Gigantenstoß", + "IT": "Colpo Maestoso", + "RU": "Удар Левиафана", + "ES": "Embate Supremo" + }, + "pokemon_move_471": { + "PT-BR": "Supermão", + "EN": "Upper Hand", + "FR": "Prio-Parade", + "DE": "Schnellkonter", + "IT": "Colpo di Mano", + "RU": "Тыльная Сторона Ладони", + "ES": "Palma Rauda" + }, + "pokemon_move_472": { + "PT-BR": "Prisão Elétrica", + "EN": "Thunder Cage", + "FR": "Voltageôle", + "DE": "Blitzgefängnis", + "IT": "Elettrogabbia", + "RU": "Громовая Клетка", + "ES": "Electrojaula" + }, + "pokemon_move_473": { + "PT-BR": "Indefeso", + "EN": "Guard", + "FR": "Garde", + "DE": "Wall", + "IT": "Barriera", + "RU": "Защита", + "ES": "Barrera" + }, + "pokemon_move_474": { + "PT-BR": "Espírito", + "EN": "Spirit", + "FR": "Régé", + "DE": "Kampfgeist", + "IT": "Spirito", + "RU": "Дух", + "ES": "Espíritu" + }, + "pokemon_move_475": { + "PT-BR": "Indefeso", + "EN": "Guard", + "FR": "Garde", + "DE": "Wall", + "IT": "Barriera", + "RU": "Защита", + "ES": "Barrera" + }, + "pokemon_move_476": { + "PT-BR": "Espírito", + "EN": "Spirit", + "FR": "Régé", + "DE": "Kampfgeist", + "IT": "Spirito", + "RU": "Дух", + "ES": "Espíritu" + }, + "pokemon_move_477": { + "PT-BR": "Indefeso", + "EN": "Guard", + "FR": "Garde", + "DE": "Wall", + "IT": "Barriera", + "RU": "Защита", + "ES": "Barrera" + }, + "pokemon_move_478": { + "PT-BR": "Espírito", + "EN": "Spirit", + "FR": "Régé", + "DE": "Kampfgeist", + "IT": "Spirito", + "RU": "Дух", + "ES": "Espíritu" + }, + "pokemon_move_479": { + "PT-BR": "Espada Colossal", + "EN": "Behemoth Blade", + "FR": "Gladius Maximus", + "DE": "Gigantenhieb", + "IT": "Taglio Maestoso", + "RU": "Меч Левиафана", + "ES": "Tajo Supremo" + }, + "pokemon_move_480": { + "PT-BR": "Pancada Colossal", + "EN": "Behemoth Bash", + "FR": "Aegis Maxima", + "DE": "Gigantenstoß", + "IT": "Colpo Maestoso", + "RU": "Удар Левиафана", + "ES": "Embate Supremo" + }, + "pokemon_move_481": { + "EN": "Thunder Cage Fast" + }, + "pokemon_move_483": { + "EN": "Vn Bm 062" + }, + "pokemon_move_484": { + "PT-BR": "Batida de Escamas", + "EN": "Clanging Scales", + "FR": "Vibrécaille", + "DE": "Schuppenrasseln", + "IT": "Clamorsquame", + "RU": "Лязгающая Чешуя", + "ES": "Fragor Escamas" + }, + "pokemon_move_485": { + "PT-BR": "Aperto Esmagador", + "EN": "Crush Grip", + "FR": "Presse", + "DE": "Quetschgriff", + "IT": "Sbriciolmano", + "RU": "Сокрушительная Хватка", + "ES": "Agarrón" + }, + "pokemon_move_486": { + "PT-BR": "Energia Dracônica", + "EN": "Dragon Energy", + "FR": "Draco-Énergie", + "DE": "Drachenkräfte", + "IT": "Dragoenergia", + "RU": "Энергия Дракона", + "ES": "Dracoenergía" } } \ No newline at end of file From 77b68aaf8f127daa3319b00ca94437b58181b456 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:14:05 +0300 Subject: [PATCH 361/367] Removed shadow raids from 'local only' --- constants.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constants.php b/constants.php index 8e986538..c44a958c 100644 --- a/constants.php +++ b/constants.php @@ -29,7 +29,7 @@ ]); // Raid levels limited to local players only -define('RAID_LEVEL_LOCAL_ONLY', [4, 9, 11, 12, 13, 14, 15]); +define('RAID_LEVEL_LOCAL_ONLY', [4, 9]); // Shadow raid levels define('RAID_LEVEL_SHADOW', [11, 12, 13, 14, 15]); From 6ceb4bbfc02a206801ce528fc8d9c4a5c8016d53 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 26 Sep 2025 19:43:15 +0300 Subject: [PATCH 362/367] Finally fixed automatic raid hour creation - Added new source for event info - Added logic to automatically create raid egg if there is an ampersand (&) in the event name --- .../raid_hour_creator.php | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/core/tools/automate_raid_hour_creation/raid_hour_creator.php b/core/tools/automate_raid_hour_creation/raid_hour_creator.php index b5f9f4c8..95bfcb78 100644 --- a/core/tools/automate_raid_hour_creation/raid_hour_creator.php +++ b/core/tools/automate_raid_hour_creation/raid_hour_creator.php @@ -20,7 +20,7 @@ $dbh->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING); $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); -$link = 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/events.json'; +$link = 'https://raw.githubusercontent.com/bigfoott/ScrapedDuck/refs/heads/data/events.min.json'; $data = curl_get_contents($link); $raids = $dbh->prepare("SELECT start_time FROM raids WHERE event = '" . $config->RAID_HOUR_EVENT_ID . "'"); $raids->execute(); @@ -41,8 +41,15 @@ $end->sub($interval); $event_start = $start->format('Y-m-d H:i:s'); $event_end = $end->format('Y-m-d H:i:s'); - if($event['type'] == 'raid-hour' && $event_start > $now && (($raids->rowcount() > 0 && !in_array($event_start, $raids_res)) || $raids->rowcount() === 0)) { - $mon_name = trim(str_replace('Raid Hour','',str_replace('Forme','',$event['name']))); + $notePrefix = null; + if($event['eventType'] == 'raid-hour' && $start > $now && (($raids->rowcount() > 0 && !in_array($event_start, $raids_res)) || $raids->rowcount() === 0)) { + if(preg_match('/&/', $event['name'])) { + $notePrefix = $event['name'] . PHP_EOL; + $raid_to_create[] = [9995, 0, $event_start, $event_end, '5', $notePrefix]; + $datesToCreate[] = $event_start; + continue; + } + $mon_name = trim(preg_replace('/Forme|Form|Raid Hour|[()]/','',$event['name'])); $mon_split = explode(' ',$mon_name); $part_count = count($mon_split); $mon_query_input = []; @@ -70,8 +77,9 @@ if($mon === false) continue; $pokemon = $mon[0]; $pokemon_form = $mon[1]; + $notePrefix = $event['name'] . PHP_EOL; } - $raid_to_create[] = [$pokemon, $pokemon_form,$event_start,$event_end, '5']; + $raid_to_create[] = [$pokemon, $pokemon_form,$event_start,$event_end, '5', $notePrefix]; $datesToCreate[] = $event_start; } } @@ -79,29 +87,41 @@ $start_time = gmdate('Y-m-d H:i:s',mktime(18,0,0)); $end_time = gmdate('Y-m-d H:i:s',mktime(19,0,0)); $mon = get_current_bosses($start_time); - if($mon !== false) $raid_to_create[] = [$mon[0], $mon[1] ,$start_time, $end_time, $mon[2]]; + if($mon !== false) $raid_to_create[] = [$mon[0], $mon[1] ,$start_time, $end_time, $mon[2], null]; } } try { - $query = $dbh->prepare('INSERT INTO raids ( - user_id, - pokemon, - pokemon_form, - spawn, - level, - start_time, - end_time, - gym_id, - event, - event_note - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - '); + $query = $dbh->prepare(' + INSERT INTO raids ( + user_id, + pokemon, + pokemon_form, + spawn, + level, + start_time, + end_time, + gym_id, + event, + event_note + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + '); $now = gmdate('Y-m-d H:i:s'); foreach($raid_to_create as $raid_info) { foreach($config->GYM_INFOS as $t) { - $query->execute([$config->RAID_CREATOR_ID,$raid_info[0],$raid_info[1],$now,$raid_info[4],$raid_info[2],$raid_info[3],$t[0],$config->RAID_HOUR_EVENT_ID,$t[1]]); + $query->execute([ + $config->RAID_CREATOR_ID, + $raid_info[0], + $raid_info[1], + $now, + $raid_info[4], + $raid_info[2], + $raid_info[3], + $t[0], + $config->RAID_HOUR_EVENT_ID, + $raid_info[5] . $t[1] + ]); } } } From 73d62a486fbc8f359a6e90d7e40dbe8a9ec1ef25 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 16 Oct 2025 15:29:41 +0200 Subject: [PATCH 363/367] Bump max trainer level to 80 in defaults-config.json --- config/defaults-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/defaults-config.json b/config/defaults-config.json index 3e0840f3..bdec4e3b 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -101,7 +101,7 @@ "RAID_EX_GYM_MARKER":"icon", "RAID_CREATION_EX_GYM_MARKER": true, "UPGRADE_SQL_AUTO": true, - "TRAINER_MAX_LEVEL":"50", + "TRAINER_MAX_LEVEL":"80", "TRAINER_CHATS":"", "SHARE_CHATS":"", "SHARE_CHATS_LEVEL_X":"", From 006cfa0bdf7ca31e4067df5b8d77a3fff9d84fb7 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 9 Dec 2025 20:27:06 +0200 Subject: [PATCH 364/367] New translations --- lang/pokemon.json | 31 +++++++++++++++------- lang/pokemon_forms.json | 57 ++++++++++++++++++++++++++++++++++++++++ lang/pokemon_moves.json | 58 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 134 insertions(+), 12 deletions(-) diff --git a/lang/pokemon.json b/lang/pokemon.json index 948b63ae..4b25fdc3 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -5752,19 +5752,27 @@ "RU": "Мирайдон" }, "pokemon_id_1009": { - "EN": "Walking-wake" + "EN": "Walkingwake" }, "pokemon_id_1010": { - "EN": "Iron-leaves" + "EN": "Ironleaves" }, "pokemon_id_1011": { - "EN": "Dipplin" + "EN": "Dipplin", + "FR": "Pomdramour", + "DE": "Sirapfel", + "RU": "Дипплин" }, "pokemon_id_1012": { - "EN": "Poltchageist" + "EN": "Poltchageist", + "DE": "Mortcha", + "RU": "Полчагейст" }, "pokemon_id_1013": { - "EN": "Sinistcha" + "EN": "Sinistcha", + "FR": "Théffroyable", + "DE": "Fatalitcha", + "RU": "Синисча" }, "pokemon_id_1014": { "EN": "Okidogi" @@ -5782,19 +5790,22 @@ "EN": "Archaludon" }, "pokemon_id_1019": { - "EN": "Hydrapple" + "EN": "Hydrapple", + "FR": "Pomdorochi", + "DE": "Hydrapfel", + "RU": "Гидраппл" }, "pokemon_id_1020": { - "EN": "Gouging-fire" + "EN": "Gougingfire" }, "pokemon_id_1021": { - "EN": "Raging-bolt" + "EN": "Ragingbolt" }, "pokemon_id_1022": { - "EN": "Iron-boulder" + "EN": "Ironboulder" }, "pokemon_id_1023": { - "EN": "Iron-crown" + "EN": "Ironcrown" }, "pokemon_id_1024": { "EN": "Terapagos" diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index 28565b7f..f8d2069a 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -2361,6 +2361,36 @@ "pokemon_form_2870": { "EN": "Gofest 2025 Train Conductor" }, + "pokemon_form_2871": { + "EN": "Counterfeit" + }, + "pokemon_form_2872": { + "EN": "Artisan" + }, + "pokemon_form_2873": { + "EN": "Unremarkable" + }, + "pokemon_form_2874": { + "EN": "Masterpiece" + }, + "pokemon_form_2875": { + "EN": "Teal" + }, + "pokemon_form_2876": { + "EN": "Wellspring" + }, + "pokemon_form_2877": { + "EN": "Hearthflame" + }, + "pokemon_form_2879": { + "EN": "Cornerstone" + }, + "pokemon_form_2881": { + "EN": "Terastal" + }, + "pokemon_form_2882": { + "EN": "Stellar" + }, "pokemon_form_2982": { "PT-BR": "Fêmea", "EN": "Female", @@ -2543,5 +2573,32 @@ }, "pokemon_form_3015": { "EN": "Wcs 2024" + }, + "pokemon_form_3017": { + "EN": "Wcs 2025" + }, + "pokemon_form_3018": { + "EN": "Coin A1" + }, + "pokemon_form_3019": { + "EN": "Swim 2025" + }, + "pokemon_form_3021": { + "EN": "Wildarea 2025" + }, + "pokemon_form_3315": { + "EN": "Winter 2025" + }, + "pokemon_form_3316": { + "EN": "Winter 2025" + }, + "pokemon_form_3317": { + "EN": "Winter 2025" + }, + "pokemon_form_3322": { + "EN": "Gotour 2026 C" + }, + "pokemon_form_3323": { + "EN": "Gotour 2026 C 02" } } \ No newline at end of file diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index 6f7d6dc3..3e6a67a7 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -3619,7 +3619,7 @@ "FR": "Prio-Parade", "DE": "Schnellkonter", "IT": "Colpo di Mano", - "RU": "Тыльная Сторона Ладони", + "RU": "Ручной Выстрел", "ES": "Palma Rauda" }, "pokemon_move_472": { @@ -3706,8 +3706,23 @@ "pokemon_move_481": { "EN": "Thunder Cage Fast" }, + "pokemon_move_482": { + "PT-BR": "Canhão Dinamax", + "EN": "Dynamax Cannon", + "FR": "Canon Dynamax", + "DE": "Dynamax-Kanone", + "IT": "Cannone Dynamax", + "RU": "Динамакс-Пушка", + "ES": "Cañón Dinamax" + }, "pokemon_move_483": { - "EN": "Vn Bm 062" + "PT-BR": "Canhão Dinamax", + "EN": "Dynamax Cannon", + "FR": "Canon Dynamax", + "DE": "Dynamax-Kanone", + "IT": "Cannone Dynamax", + "RU": "Динамакс-Пушка", + "ES": "Cañón Dinamax" }, "pokemon_move_484": { "PT-BR": "Batida de Escamas", @@ -3735,5 +3750,44 @@ "IT": "Dragoenergia", "RU": "Энергия Дракона", "ES": "Dracoenergía" + }, + "pokemon_move_487": { + "PT-BR": "Passo Aquático", + "EN": "Aqua Step", + "FR": "Danse Aquatique", + "DE": "Wogentanz", + "IT": "Idroballetto", + "RU": "Танец Воды", + "ES": "Danza Acuática" + }, + "pokemon_move_488": { + "PT-BR": "Água Fria", + "EN": "Chilling Water", + "FR": "Douche Froide", + "DE": "Kalte Dusche", + "IT": "Doccia Fredda", + "RU": "Холодный Душ", + "ES": "Agua Fría" + }, + "pokemon_move_489": { + "PT-BR": "Espada Secreta", + "EN": "Secret Sword", + "FR": "Lame Ointe", + "DE": "Mystoschwert", + "IT": "Spadamistica", + "RU": "Тайный Меч", + "ES": "Sable Místico" + }, + "pokemon_move_490": { + "PT-BR": "Bico Explosivo", + "EN": "Beak Blast", + "FR": "Bec-Canon", + "DE": "Schnabelkanone", + "IT": "Cannonbecco", + "RU": "Взрывоопасный Клюв", + "ES": "Pico Cañón" + }, + "pokemon_move_491": { + "EN": "Mind Blown" } } \ No newline at end of file From 5a891887bd20fd17806a4285c512b9d6876036f5 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Tue, 9 Dec 2025 20:27:24 +0200 Subject: [PATCH 365/367] Support RSVP time slots in vote keys --- config/defaults-config.json | 1 + logic/keys_vote.php | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/config/defaults-config.json b/config/defaults-config.json index bdec4e3b..977fbb50 100644 --- a/config/defaults-config.json +++ b/config/defaults-config.json @@ -54,6 +54,7 @@ "RAID_LOCATION": false, "RAID_SLOTS":"15", "RAID_DIRECT_START": false, + "RAID_RSVP_SLOTS": false, "RAID_FIRST_START":"5", "RAID_LAST_START":"5", "RAID_ANYTIME": false, diff --git a/logic/keys_vote.php b/logic/keys_vote.php index ab9e8790..78d7581c 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -273,15 +273,14 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { debug_log($five_slot, 'Next 5 Minute slot:'); debug_log($first_slot, 'First regular slot:'); $keys_time = []; - // Add button for direct start if needed - if($config->RAID_DIRECT_START && $direct_slot != $five_slot && $direct_slot >= $dt_now) { - $keys_time[] = button(dt2time($direct_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $direct_slot->format('YmdHis')]); + if(($config->RAID_DIRECT_START && !$config->RAID_RSVP_SLOTS) && $direct_slot != $five_slot && $direct_slot >= $dt_now) { + $keys_time[$direct_slot->format('YmdHi')] = button($direct_slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $direct_slot->format('YmdHis')]); } // Add button for first five minutes if needed if($five_slot < $first_slot && $five_plus_slot <= $first_slot && $five_slot >= $dt_now) { - $keys_time[] = button(dt2time($five_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $five_slot->format('YmdHis')]); + $keys_time[$five_slot->format('YmdHi')] = button($five_slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $five_slot->format('YmdHis')]); } // Get regular slots @@ -294,7 +293,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { debug_log($slot, 'Regular slot:'); // Add regular slot. if($slot >= $dt_now) { - $keys_time[] = button(dt2time($slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $slot->format('YmdHis')]); + $keys_time[$slot->format('YmdHi')] = button($slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $slot->format('YmdHis')]); } // Set last slot for later. $last_slot = $slot; @@ -315,12 +314,27 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { ((isset($last_slot) && $last_extra_slot > $last_slot && $last_extra_slot != $last_slot) || !isset($last_slot))) { // Add last extra slot - $keys_time[] = button(dt2time($last_extra_slot->format('Y-m-d H:i:s')), ['vote_time', 'r' => $raid['id'], 't' => $last_extra_slot->format('YmdHis')]); + $keys_time[$last_extra_slot->format('YmdHi')] = button($last_extra_slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $last_extra_slot->format('YmdHis')]); + } + + if($config->RAID_RSVP_SLOTS) { + $rsvp_slots = new DatePeriod($direct_slot, new DateInterval('PT15M'), 2); + foreach($rsvp_slots as $slot){ + debug_log($slot, 'RSVP slot:'); + // Add RSVP slot. + if($slot >= $dt_now) { + $keys_time[$slot->format('YmdHi')] = button($slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $slot->format('YmdHis')]); + } + } } + // Sort keys by time and reindex array + asort($keys_time); + $keys_time = array_values($keys_time); + // Attend raid at any time if($config->RAID_ANYTIME) { $keys_time[] = button(getPublicTranslation('anytime'), ['vote_time', 'r' => $raid['id']]); } return $keys_time; -} +} \ No newline at end of file From b2c0d35e45a525820a4e94e6823cb5e54ccdf6bc Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Sun, 14 Dec 2025 21:52:34 +0200 Subject: [PATCH 366/367] Fixed vote keys only showing UTC times --- logic/keys_vote.php | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/logic/keys_vote.php b/logic/keys_vote.php index 78d7581c..95adc12c 100644 --- a/logic/keys_vote.php +++ b/logic/keys_vote.php @@ -275,12 +275,12 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { $keys_time = []; // Add button for direct start if needed if(($config->RAID_DIRECT_START && !$config->RAID_RSVP_SLOTS) && $direct_slot != $five_slot && $direct_slot >= $dt_now) { - $keys_time[$direct_slot->format('YmdHi')] = button($direct_slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $direct_slot->format('YmdHis')]); + $keys_time[$direct_slot->format('YmdHi')] = button(timeslot_label($direct_slot), ['vote_time', 'r' => $raid['id'], 't' => $direct_slot->format('YmdHis')]); } // Add button for first five minutes if needed if($five_slot < $first_slot && $five_plus_slot <= $first_slot && $five_slot >= $dt_now) { - $keys_time[$five_slot->format('YmdHi')] = button($five_slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $five_slot->format('YmdHis')]); + $keys_time[$five_slot->format('YmdHi')] = button(timeslot_label($five_slot), ['vote_time', 'r' => $raid['id'], 't' => $five_slot->format('YmdHis')]); } // Get regular slots @@ -293,7 +293,7 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { debug_log($slot, 'Regular slot:'); // Add regular slot. if($slot >= $dt_now) { - $keys_time[$slot->format('YmdHi')] = button($slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $slot->format('YmdHis')]); + $keys_time[$slot->format('YmdHi')] = button(timeslot_label($slot), ['vote_time', 'r' => $raid['id'], 't' => $slot->format('YmdHis')]); } // Set last slot for later. $last_slot = $slot; @@ -314,17 +314,16 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { ((isset($last_slot) && $last_extra_slot > $last_slot && $last_extra_slot != $last_slot) || !isset($last_slot))) { // Add last extra slot - $keys_time[$last_extra_slot->format('YmdHi')] = button($last_extra_slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $last_extra_slot->format('YmdHis')]); + $keys_time[$last_extra_slot->format('YmdHi')] = button(timeslot_label($last_extra_slot), ['vote_time', 'r' => $raid['id'], 't' => $last_extra_slot->format('YmdHis')]); } if($config->RAID_RSVP_SLOTS) { $rsvp_slots = new DatePeriod($direct_slot, new DateInterval('PT15M'), 2); foreach($rsvp_slots as $slot){ debug_log($slot, 'RSVP slot:'); + if($slot < $dt_now) continue; // Add RSVP slot. - if($slot >= $dt_now) { - $keys_time[$slot->format('YmdHi')] = button($slot->format('H:i'), ['vote_time', 'r' => $raid['id'], 't' => $slot->format('YmdHis')]); - } + $keys_time[$slot->format('YmdHi')] = button(timeslot_label($slot), ['vote_time', 'r' => $raid['id'], 't' => $slot->format('YmdHis')]); } } @@ -337,4 +336,18 @@ function generateTimeslotKeys($RAID_SLOTS, $raid) { $keys_time[] = button(getPublicTranslation('anytime'), ['vote_time', 'r' => $raid['id']]); } return $keys_time; +} + +/** + * Generate timeslot label in local time. + * @param DateTime $datetime + * @return string + */ +function timeslot_label($datetime) +{ + global $config; + $tz = $config->TIMEZONE; + // Change the timezone of the object without changing it's time + $new = $datetime->setTimezone(new DateTimeZone($tz)); + return $new->format('H:i'); } \ No newline at end of file From d67422ed9220868a2b3e3b24dc059dc173c94617 Mon Sep 17 00:00:00 2001 From: ninjasoturi <52629375+Ninjasoturi@users.noreply.github.com> Date: Fri, 27 Feb 2026 21:41:45 +0200 Subject: [PATCH 367/367] Support super mega raids Added support for super mega raids. Updated translations. --- constants.php | 7 +- images/raid_eggs/pokemon_icon_99916_00.png | Bin 0 -> 25836 bytes lang/language.json | 38 ++++++++++ lang/pokemon.json | 78 +++++++++++++++++---- lang/pokemon_forms.json | 27 +++++++ lang/pokemon_moves.json | 26 ++++++- logic/read_upcoming_bosses.php | 2 + mods/pokebattler.php | 5 +- 8 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 images/raid_eggs/pokemon_icon_99916_00.png diff --git a/constants.php b/constants.php index c44a958c..41eafe8c 100644 --- a/constants.php +++ b/constants.php @@ -7,10 +7,11 @@ define('PORTAL_IMAGES_PATH', IMAGES_PATH . '/gyms'); // raid levels constant -define('RAID_LEVEL_ALL', [RAID_ID_EX, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 1]); +define('RAID_LEVEL_ALL', [RAID_ID_EX, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 1]); // Raid eggs. define('EGGS', [ + '99916', // Level 16 / Super Mega '99915', // Level 15 / Shadow 5 '99914', // Level 14 / Shadow 4 '99913', // Level 13 / Shadow 3 @@ -35,7 +36,7 @@ define('RAID_LEVEL_SHADOW', [11, 12, 13, 14, 15]); // Levels available for import at PokeBattler -$pokebattler_levels = array('15','13','11','10', '9', '8', '7', '6', '5', '4', '3', '1'); +$pokebattler_levels = array('16','15','13','11','10', '9', '8', '7', '6', '5', '4', '3', '1'); // Map our raid levels to tier names PokeBattler uses $pokebattler_level_map = [ @@ -51,6 +52,8 @@ '11' => '1_SHADOW', '13' => '3_SHADOW', '15' => '5_SHADOW', + '16' => 'SUPER_MEGA_4', // Pokebattler currently uses MEGA_5 for super mega raids. This needs to be changed if they start using their own tier for super mega raids + '17' => 'SUPER_MEGA_5', // Pokebattler currently uses MEGA_5 for super mega raids. This needs to be changed if they start using their own tier for super mega raids ]; $pokebattler_pokemon_map = [ diff --git a/images/raid_eggs/pokemon_icon_99916_00.png b/images/raid_eggs/pokemon_icon_99916_00.png new file mode 100644 index 0000000000000000000000000000000000000000..c5efafa764933367934b203eeb9ff08298ce5152 GIT binary patch literal 25836 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 Hu0mjfJ&Xz` literal 0 HcmV?d00001 diff --git a/lang/language.json b/lang/language.json index d3de5135..ab2fdc75 100644 --- a/lang/language.json +++ b/lang/language.json @@ -870,6 +870,18 @@ "FI": "Ex-Raidi", "ES": "Incursión EX" }, + "17stars": { + "EN": "5 Super Mega Raid" + }, + "17stars_short": { + "EN": "5 Super Mega" + }, + "16stars": { + "EN": "4 Super Mega Raid" + }, + "16stars_short": { + "EN": "4 Super Mega" + }, "15stars": { "NL": "TRANSLATE", "DE": "5 Sterne Shadow", @@ -1208,6 +1220,32 @@ "FI": "Pois käytöstä", "ES": "Desactivado" }, + "egg_17": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "5 Mega Enhanced Egg", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "TRANSLATE", + "ES": "TRANSLATE" + }, + "egg_16": { + "NL": "TRANSLATE", + "DE": "TRANSLATE", + "EN": "4 Mega Enhanced Egg", + "IT": "TRANSLATE", + "PT-BR": "TRANSLATE", + "RU": "TRANSLATE", + "NO": "TRANSLATE", + "FR": "TRANSLATE", + "PL": "TRANSLATE", + "FI": "TRANSLATE", + "ES": "TRANSLATE" + }, "egg_15": { "NL": "TRANSLATE", "DE": "Level 5 Shadow Ei", diff --git a/lang/pokemon.json b/lang/pokemon.json index 4b25fdc3..e524d521 100644 --- a/lang/pokemon.json +++ b/lang/pokemon.json @@ -5752,10 +5752,22 @@ "RU": "Мирайдон" }, "pokemon_id_1009": { - "EN": "Walkingwake" + "PT-BR": "Onda Ando", + "EN": "Walking Wake", + "FR": "Serpente-Eau", + "DE": "Windewoge", + "IT": "Acquecrespe", + "RU": "Вздымающаяся Волна", + "ES": "Ondulagua" }, "pokemon_id_1010": { - "EN": "Ironleaves" + "PT-BR": "Folhas Férreas", + "EN": "Iron Leaves", + "FR": "Vert-de-Fer", + "DE": "Eisenblatt", + "IT": "Fogliaferrea", + "RU": "Железные Листья", + "ES": "Ferroverdor" }, "pokemon_id_1011": { "EN": "Dipplin", @@ -5775,19 +5787,32 @@ "RU": "Синисча" }, "pokemon_id_1014": { - "EN": "Okidogi" + "EN": "Okidogi", + "FR": "Félicanis", + "DE": "Boninu", + "RU": "Окидоги" }, "pokemon_id_1015": { - "EN": "Munkidori" + "EN": "Munkidori", + "FR": "Fortusimia", + "DE": "Benesaru", + "RU": "Манкидори" }, "pokemon_id_1016": { - "EN": "Fezandipiti" + "EN": "Fezandipiti", + "FR": "Favianos", + "DE": "Beatori", + "RU": "Фезандипити" }, "pokemon_id_1017": { - "EN": "Ogerpon" + "EN": "Ogerpon", + "RU": "Огерпон" }, "pokemon_id_1018": { - "EN": "Archaludon" + "EN": "Archaludon", + "FR": "Pondralugon", + "DE": "Briduradon", + "RU": "Архалюдон" }, "pokemon_id_1019": { "EN": "Hydrapple", @@ -5796,21 +5821,48 @@ "RU": "Гидраппл" }, "pokemon_id_1020": { - "EN": "Gougingfire" + "PT-BR": "Fogo Corrosão", + "EN": "Gouging Fire", + "DE": "Keilflamme", + "IT": "Vampeaguzze", + "RU": "Пронзающее Пламя", + "ES": "Flamariete" }, "pokemon_id_1021": { - "EN": "Ragingbolt" + "PT-BR": "Raio Fúria", + "EN": "Raging Bolt", + "FR": "Ire-Foudre", + "DE": "Furienblitz", + "IT": "Furiatonante", + "RU": "Яростная Молния", + "ES": "Electrofuria" }, "pokemon_id_1022": { - "EN": "Ironboulder" + "PT-BR": "Rocha Férrea", + "EN": "Iron Boulder", + "FR": "Roc-de-Fer", + "DE": "Eisenfels", + "IT": "Massoferreo", + "RU": "Железный Валун", + "ES": "Ferromole" }, "pokemon_id_1023": { - "EN": "Ironcrown" + "PT-BR": "Chifres Férreos", + "EN": "Iron Crown", + "FR": "Chef-de-Fer", + "DE": "Eisenhaupt", + "IT": "Capoferreo", + "RU": "Железный Вождь", + "ES": "Ferrotesta" }, "pokemon_id_1024": { - "EN": "Terapagos" + "EN": "Terapagos", + "RU": "Терапагос" }, "pokemon_id_1025": { - "EN": "Pecharunt" + "EN": "Pecharunt", + "FR": "Pêchaminus", + "DE": "Infamomo", + "RU": "Печарант" } } \ No newline at end of file diff --git a/lang/pokemon_forms.json b/lang/pokemon_forms.json index f8d2069a..d17afe1d 100644 --- a/lang/pokemon_forms.json +++ b/lang/pokemon_forms.json @@ -2595,10 +2595,37 @@ "pokemon_form_3317": { "EN": "Winter 2025" }, + "pokemon_form_3318": { + "EN": "Gotour 2026 A" + }, + "pokemon_form_3319": { + "EN": "Gotour 2026 A 02" + }, + "pokemon_form_3320": { + "EN": "Gotour 2026 B" + }, + "pokemon_form_3321": { + "EN": "Gotour 2026 B 02" + }, "pokemon_form_3322": { "EN": "Gotour 2026 C" }, "pokemon_form_3323": { "EN": "Gotour 2026 C 02" + }, + "pokemon_form_3337": { + "EN": "Spring 2026 A" + }, + "pokemon_form_3338": { + "EN": "Spring 2026 B" + }, + "pokemon_form_3339": { + "EN": "Spring 2026" + }, + "pokemon_form_3340": { + "EN": "Bb 2026" + }, + "pokemon_form_3341": { + "EN": "Visor 2026" } } \ No newline at end of file diff --git a/lang/pokemon_moves.json b/lang/pokemon_moves.json index 3e6a67a7..2f0bafb6 100644 --- a/lang/pokemon_moves.json +++ b/lang/pokemon_moves.json @@ -3788,6 +3788,30 @@ "ES": "Pico Cañón" }, "pokemon_move_491": { - "EN": "Mind Blown" + "PT-BR": "Explosão Mental", + "EN": "Mind Blown", + "FR": "Caboche-Kaboum", + "DE": "Knallkopf", + "IT": "Sbalorditesta", + "RU": "Взрыв Разума", + "ES": "Cabeza Sorpresa" + }, + "pokemon_move_492": { + "PT-BR": "Toque do Tambor", + "EN": "Drum Beating", + "FR": "Tambour Battant", + "DE": "Trommelschläge", + "IT": "Tamburattacco", + "RU": "Барабанный Бой", + "ES": "Batería Asalto" + }, + "pokemon_move_493": { + "PT-BR": "Bola Incendiária", + "EN": "Pyro Ball", + "FR": "Ballon Brûlant", + "DE": "Feuerball", + "IT": "Palla Infuocata", + "RU": "Огнешар", + "ES": "Balón Ígneo" } } \ No newline at end of file diff --git a/logic/read_upcoming_bosses.php b/logic/read_upcoming_bosses.php index c8eda99b..7b5ff297 100644 --- a/logic/read_upcoming_bosses.php +++ b/logic/read_upcoming_bosses.php @@ -51,6 +51,8 @@ function read_upcoming_bosses($returnFormat = 'list', $levelsToRead = false) { // In case Pokebattler keeps using RAID_LEVEL_MEGA_5 (legendary mega tier) for primal raids if(in_array($dex_id_form[0], PRIMAL_MONS) && $raid_level_id == 7) { $raid_level_id = 10; + }elseif(in_array($dex_id_form[1], [-1,-2,-3]) && $raid_level_id == 7) { + $raid_level_id = 16; } if($prev_start != $date_start or $prev_end != $date_end) { $list.= CR . EMOJI_CLOCK . ' ' . $starttime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $starttime->format(' H:i') . ' — ' . $endtime->format('j.n. ') . getTranslation('raid_egg_opens_at') . $endtime->format(' H:i') . ':' . CR; diff --git a/mods/pokebattler.php b/mods/pokebattler.php index 4e617557..b1b1b14f 100644 --- a/mods/pokebattler.php +++ b/mods/pokebattler.php @@ -109,6 +109,9 @@ if(in_array($dex_id, PRIMAL_MONS) && $news['tier'] == 'RAID_LEVEL_MEGA_5') { $raid_level_id = 10; $tierHolder = 'RAID_LEVEL_PRIMAL'; + }elseif(in_array($form_id, [-1,-2,-3]) && $news['tier'] == 'RAID_LEVEL_MEGA_5') { + $raid_level_id = 16; + $tierHolder = 'RAID_LEVEL_SUPER_MEGA_4'; } if(in_array($tierHolder, $raidlevels) && $starttime->getTimestamp() < $now->getTimestamp() && $endtime->getTimestamp() > $now->getTimestamp()) { $levels_processed[$raid_level_id] = $news['tier']; @@ -127,7 +130,7 @@ // Get raid bosses for each raid level. foreach($tier['raids'] as $raid) { // Raid level - if ($raid['id'] == 0) { + if (!array_key_exists('id', $raid) or $raid['id'] == 0) { debug_log('Skipping raid boss ' . $raid['pokemon'] . ' since it has no id, it\'s likely in the future!'); continue; }