From e28dcce8507763c9dc07f61934aef9f71ceeb77b Mon Sep 17 00:00:00 2001 From: ubergeek77 Date: Tue, 21 May 2019 20:28:16 -0500 Subject: [PATCH] =?UTF-8?q?Gen=204=20Pok=C3=A9mon=20Mystery=20Gift=20Overh?= =?UTF-8?q?aul?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added many missing Game IDs to the list of valid games to receive DLC Gen 4 Mystery Gifts will now be distributed based on their original release dates --- other/dlc.py | 441 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 425 insertions(+), 16 deletions(-) diff --git a/other/dlc.py b/other/dlc.py index 6be8d7b..e9466bc 100644 --- a/other/dlc.py +++ b/other/dlc.py @@ -21,35 +21,107 @@ import os import random import time +from datetime import date from gamespy.gs_database import GamespyDatabase +""" + Pokemon Gen 4 Region Codes: + + Diamond: + ADAE (US) + ADAP (ENG-EUR) + ADAF (FRA) + ADAD (GER) + ADAI (ITA) + ADAS (SPA) + ADAJ (JPN) + ADAK (KOR) + Pearl: + APAE (US) + APAP (ENG-EUR) + APAF (FRA) + APAD (GER) + APAI (ITA) + APAS (SPA) + APAJ (JPN) + APAK (KOR) + Platinum: + CPUE (US) + CPUP (ENG-EUR) + CPUF (FRA) + CPUD (GER) + CPUI (ITA) + CPUS (SPA) + CPUJ (JPN) + CPUK (KOR) + HeartGold: + IPKE (US) + IPKP (ENG-EUR) + IPKF (FRA) + IPKD (GER) + IPKI (ITA) + IPKS (SPA) + IPKJ (JPN) + IPKK (KOR) + SoulSilver: + IPGE (US) + IPGP (ENG-EUR) + IPGF (FRA) + IPGD (GER) + IPGI (ITA) + IPGS (SPA) + IPGJ (JPN) + IPGK (KOR) + """ -# If a game from this list requests a file listing, the server will return -# that only one exists and return a random one. -# This is used for Mystery Gift distribution on Generation 4 Pokemon games -gamecodes_return_random_file = [ - 'ADAD', +# Gen 4 Pokemon Games (for Mystery Gift Distribution) +# If a game from this list requests a file listing, the server will compare +# the client Nintendo DS's date setting to the list of Mystery Gifts +# that were actually distributed in real life at the given time. +# This way, if someone knows exactly when an event happened in real life, +# they know exactly which date to change to in order to receive a particular gift. +gen_4_pokemon_gamecodes = [ 'ADAE', + 'ADAP', 'ADAF', + 'ADAD', 'ADAI', + 'ADAS', 'ADAJ', 'ADAK', - 'ADAS', - 'CPUD', + 'APAE', + 'APAP', + 'APAF', + 'APAD', + 'APAI', + 'APAS', + 'APAJ', + 'APAK', 'CPUE', + 'CPUP', 'CPUF', + 'CPUD', 'CPUI', + 'CPUS', 'CPUJ', 'CPUK', - 'CPUS', - 'IPGD', + 'IPKE', + 'IPKP', + 'IPKF', + 'IPKD', + 'IPKI', + 'IPKS', + 'IPKJ', + 'IPKK', 'IPGE', + 'IPGP', 'IPGF', + 'IPGD', 'IPGI', + 'IPGS', 'IPGJ', - 'IPGK', - 'IPGS' + 'IPGK' ] filter_bit_g5 = { @@ -102,6 +174,335 @@ def filter_list_random_files(data, count): samples = random.sample(data.splitlines(), count) return '\r\n'.join(samples) + '\r\n' +def todays_g4_event_filename(today, gamecd): + # Pokemon Diamond/Pearl/Platinum/HeartGold/SoulSilver Events + if (gamecd.endswith("J") or gamecd.endswith("K")) == False: + # International Events + + # Secret Key, WC 17, Platinum Only (First and Second Distributions) + if(date(2009, 4, 20) <= today <= date(2009, 5, 12)) or (date(2009, 6, 8) <= today <= date(2009, 7, 19)): + if gamecd in ['CPUE', 'CPUP']: + return "ENG_017_Plat_SecretKey.myg" + elif gamecd == "CPUF": + return "FRA_017_Plat_SecretKey.myg" + elif gamecd == "CPUD": + return "GER_017_Plat_SecretKey.myg" + elif gamecd == "CPUI": + return "ITA_017_Plat_SecretKey.myg" + elif gamecd == "CPUS": + return "SPN_017_Plat_SecretKey.myg" + + # Member Card, WC 18, Platinum Only + if date(2009, 8, 3) <= today <= date(2009, 9, 13): + if gamecd in ['CPUE', 'CPUP']: + return "ENG_018_Plat_MemberCard.myg" + elif gamecd == "CPUF": + return "FRA_018_Plat_MemberCard.myg" + elif gamecd == "CPUD": + return "GER_018_Plat_MemberCard.myg" + elif gamecd == "CPUI": + return "ITA_018_Plat_MemberCard.myg" + elif gamecd == "CPUS": + return "SPN_018_Plat_MemberCard.myg" + + # Oak's Letter, WC 20, Platinum Only + if date(2009, 9, 28) <= today <= date(2009, 11, 8): + if gamecd in ['CPUE', 'CPUP']: + return "ENG_020_Plat_OaksLetter.myg" + elif gamecd == "CPUF": + return "FRA_020_Plat_OaksLetter.myg" + elif gamecd == "CPUD": + return "GER_020_Plat_OaksLetter.myg" + elif gamecd == "CPUI": + return "ITA_020_Plat_OaksLetter.myg" + elif gamecd == "CPUS": + return "SPN_020_Plat_OaksLetter.myg" + + # Azure Flute, WC 119, Platinum Only (Custom, never released) + # Distribution time is set to around the same time as + # the real-life Arceus distribution in the US, with an extension past the movie airdate + if date(2009, 11, 9) <= today <= date(2009, 11, 30): + if gamecd in ['CPUE', 'CPUP']: + return "ENG_119_Plat_AzureFlute.myg" + elif gamecd == "CPUF": + return "FRA_119_Plat_AzureFlute.myg" + elif gamecd == "CPUD": + return "GER_119_Plat_AzureFlute.myg" + elif gamecd == "CPUI": + return "ITA_119_Plat_AzureFlute.myg" + elif gamecd == "CPUS": + return "SPN_119_Plat_AzureFlute.myg" + + # Pikachu-Colored Pichu, WC 21, D/P/Pt + if date(2010, 3, 5) <= today <= date(2010, 3, 25): + if gamecd in ['CPUE', 'CPUP', 'ADAE', 'ADAP', 'APAE', 'APAP']: + return "ENG_021_DPPt_ShinyPichu.myg" + elif gamecd in ['ADAF','APAF', 'CPUF']: + return "FRA_021_DPPt_ShinyPichu.myg" + elif gamecd in ['ADAD','APAD', 'CPUD']: + return "GER_021_DPPt_ShinyPichu.myg" + elif gamecd in ['ADAI','APAI', 'CPUI']: + return "ITA_021_DPPt_ShinyPichu.myg" + elif gamecd in ['ADAS','APAS', 'CPUS']: + return "SPN_021_DPPt_ShinyPichu.myg" + + # Yellow Forest Pokewalker Route, WC 48, HG/SS + if date(2010, 4, 1) <= today <= date(2010, 5, 5): + if gamecd in ['IPKE', 'IPGE', 'IPKP', 'IPGP']: + return "ENG_048_HGSS_YForest.myg" + elif gamecd in ['IPKF', 'IPGF', 'IPKF', 'IPGF']: + return "FRA_048_HGSS_YForest.myg" + elif gamecd in ['IPKD', 'IPGD', 'IPKD', 'IPGD']: + return "GER_048_HGSS_YForest.myg" + elif gamecd in ['IPKI', 'IPGI', 'IPKI', 'IPGI']: + return "ITA_048_HGSS_YForest.myg" + elif gamecd in ['IPKS', 'IPGS', 'IPKS', 'IPGS']: + return "SPN_048_HGSS_YForest.myg" + + # Winner's Path Pokewalker Route, WC 51, HG/SS + if date(2010, 5, 6) <= today <= date(2010, 6, 25): + if gamecd in ['IPKE', 'IPGE', 'IPKP', 'IPGP']: + return "ENG_051_HGSS_WinPath.myg" + elif gamecd in ['IPKF', 'IPGF', 'IPKF', 'IPGF']: + return "FRA_051_HGSS_WinPath.myg" + elif gamecd in ['IPKD', 'IPGD', 'IPKD', 'IPGD']: + return "GER_051_HGSS_WinPath.myg" + elif gamecd in ['IPKI', 'IPGI', 'IPKI', 'IPGI']: + return "ITA_051_HGSS_WinPath.myg" + elif gamecd in ['IPKS', 'IPGS', 'IPKS', 'IPGS']: + return "SPN_051_HGSS_WinPath.myg" + + # Summer 2010 Jirachi (Night Sky), WC 24, D/P/Pt/HG/SS + if date(2010, 6, 26) <= today <= date(2010, 7, 16): + if gamecd in ['CPUE', 'CPUP', 'ADAE', 'ADAP', 'APAE', 'APAP', 'IPKE', 'IPGE', 'IPKP', 'IPGP']: + return "ENG_024_ALL_Jirachi_NightSky.myg" + elif gamecd in ['ADAF','APAF', 'CPUF', 'IPKF', 'IPGF', 'IPKF', 'IPGF']: + return "FRA_024_ALL_Jirachi_NightSky.myg" + elif gamecd in ['ADAD','APAD', 'CPUD', 'IPKD', 'IPGD', 'IPKD', 'IPGD']: + return "GER_024_ALL_Jirachi_NightSky.myg" + elif gamecd in ['ADAI','APAI', 'CPUI', 'IPKI', 'IPGI', 'IPKI', 'IPGI']: + return "ITA_024_ALL_Jirachi_NightSky.myg" + elif gamecd in ['ADAS','APAS', 'CPUS', 'IPKS', 'IPGS', 'IPKS', 'IPGS']: + return "SPN_024_ALL_Jirachi_NightSky.myg" + + # Engima Stone, WC 54, HG/SS + if date(2010, 7, 31) <= today <= date(2010, 8, 27): + if gamecd in ['IPKE', 'IPGE', 'IPKP', 'IPGP']: + return "ENG_054_HGSS_EnigmaStone.myg" + elif gamecd in ['IPKF', 'IPGF', 'IPKF', 'IPGF']: + return "FRA_054_HGSS_EnigmaStone.myg" + elif gamecd in ['IPKD', 'IPGD', 'IPKD', 'IPGD']: + return "GER_054_HGSS_EnigmaStone.myg" + elif gamecd in ['IPKI', 'IPGI', 'IPKI', 'IPGI']: + return "ITA_054_HGSS_EnigmaStone.myg" + elif gamecd in ['IPKS', 'IPGS', 'IPKS', 'IPGS']: + return "SPN_054_HGSS_EnigmaStone.myg" + + # Fall 2010/10th Anniversary Mew, WC 53, HG/SS + if date(2010, 10, 15) <= today <= date(2010, 10, 30): + if gamecd in ['IPKE', 'IPGE', 'IPKP', 'IPGP']: + return "ENG_053_HGSS_10AnnivMew.myg" + elif gamecd in ['IPKF', 'IPGF', 'IPKF', 'IPGF']: + return "FRA_053_HGSS_10AnnivMew.myg" + elif gamecd in ['IPKD', 'IPGD', 'IPKD', 'IPGD']: + return "GER_053_HGSS_10AnnivMew.myg" + elif gamecd in ['IPKI', 'IPGI', 'IPKI', 'IPGI']: + return "ITA_053_HGSS_10AnnivMew.myg" + elif gamecd in ['IPKS', 'IPGS', 'IPKS', 'IPGS']: + return "SPN_053_HGSS_10AnnivMew.myg" + + # Winter 2011 Shiny Raikou, WC 59, D/P/Pt/HG/SS + if date(2011, 2, 7) <= today <= date(2011, 2, 13): + if gamecd in ['CPUE', 'CPUP', 'ADAE', 'ADAP', 'APAE', 'APAP', 'IPKE', 'IPGE', 'IPKP', 'IPGP']: + return "ENG_059_ALL_ShinyRaikou.myg" + elif gamecd in ['ADAF','APAF', 'CPUF', 'IPKF', 'IPGF', 'IPKF', 'IPGF']: + return "FRA_059_ALL_ShinyRaikou.myg" + elif gamecd in ['ADAD','APAD', 'CPUD', 'IPKD', 'IPGD', 'IPKD', 'IPGD']: + return "GER_059_ALL_ShinyRaikou.myg" + elif gamecd in ['ADAI','APAI', 'CPUI', 'IPKI', 'IPGI', 'IPKI', 'IPGI']: + return "ITA_059_ALL_ShinyRaikou.myg" + elif gamecd in ['ADAS','APAS', 'CPUS', 'IPKS', 'IPGS', 'IPKS', 'IPGS']: + return "SPN_059_ALL_ShinyRaikou.myg" + + # Winter 2011 Shiny Entei, WC 60, D/P/Pt/HG/SS + if date(2011, 2, 14) <= today <= date(2011, 2, 20): + if gamecd in ['CPUE', 'CPUP', 'ADAE', 'ADAP', 'APAE', 'APAP', 'IPKE', 'IPGE', 'IPKP', 'IPGP']: + return "ENG_060_ALL_ShinyEntei.myg" + elif gamecd in ['ADAF','APAF', 'CPUF', 'IPKF', 'IPGF', 'IPKF', 'IPGF']: + return "FRA_060_ALL_ShinyEntei.myg" + elif gamecd in ['ADAD','APAD', 'CPUD', 'IPKD', 'IPGD', 'IPKD', 'IPGD']: + return "GER_060_ALL_ShinyEntei.myg" + elif gamecd in ['ADAI','APAI', 'CPUI', 'IPKI', 'IPGI', 'IPKI', 'IPGI']: + return "ITA_060_ALL_ShinyEntei.myg" + elif gamecd in ['ADAS','APAS', 'CPUS', 'IPKS', 'IPGS', 'IPKS', 'IPGS']: + return "SPN_060_ALL_ShinyEntei.myg" + + #Winter 2011 Shiny Suicune, WC 61, D/P/Pt/HG/SS + if date(2011, 2, 21) <= today <= date(2011, 2, 27): + if gamecd in ['CPUE', 'CPUP', 'ADAE', 'ADAP', 'APAE', 'APAP', 'IPKE', 'IPGE', 'IPKP', 'IPGP']: + return "ENG_061_ALL_ShinySuicune.myg" + elif gamecd in ['ADAF','APAF', 'CPUF', 'IPKF', 'IPGF', 'IPKF', 'IPGF']: + return "FRA_061_ALL_ShinySuicune.myg" + elif gamecd in ['ADAD','APAD', 'CPUD', 'IPKD', 'IPGD', 'IPKD', 'IPGD']: + return "GER_061_ALL_ShinySuicune.myg" + elif gamecd in ['ADAI','APAI', 'CPUI', 'IPKI', 'IPGI', 'IPKI', 'IPGI']: + return "ITA_061_ALL_ShinySuicune.myg" + elif gamecd in ['ADAS','APAS', 'CPUS', 'IPKS', 'IPGS', 'IPKS', 'IPGS']: + return "SPN_061_ALL_ShinySuicune.myg" + + # If we reach this point without returning an event, no event was found + return "null" + elif gamecd.endswith("J"): + # Japanese Events + # Secret Key, WC 156, Platinum Only (First Distribution) + if date(2008, 9, 28) <= today <= date(2008, 11, 14): + if gamecd == "CPUJ": + return "JPN_156_Plat_SecretKey.myg" + + # Member Card, WC 36, Platinum Only + if date(2008, 12, 1) <= today <= date(2009, 1, 15): + if gamecd == "CPUJ": + return "JPN_036_Plat_MemberCard.myg" + + # Secret Key, WC 156, Platinum Only (Second Distribution) + if date(2009, 1, 16) <= today <= date(2009, 3, 2): + if gamecd == "CPUJ": + return "JPN_156_Plat_SecretKey.myg" + + # Oak's Letter, WC 44, Platinum Only + if date(2009, 4, 18) <= today <= date(2009, 5, 11): + if gamecd == "CPUJ": + return "JPN_044_Plat_OaksLetter.myg" + + # Nintendo Zone Jirachi, WC 46, D/P/Pt + if date(2009, 6, 19) <= today <= date(2009, 7, 17): + if gamecd in ['ADAJ', 'APAJ', 'CPUJ']: + return "JPN_046_DPPt_NZ_Jirachi.myg" + + # Azure Flute, WC 119, Platinum Only (Custom, never released) + # Distribution time is set to nearly the same date range as the real-life + # Japanese Arceus distribution, apart from being cut short for the + # Pokewalker distribution directly below this code block + if date(2009, 7, 18) <= today <= date(2009, 9, 17): + if gamecd in ['CPUJ']: + return "JPN_119_Plat_AzureFlute.myg" + + # Yellow Forest Pokewalker Route, WC 48, HG/SS (First Distribution) + if date(2009, 9, 18) <= today <= date(2009, 11, 10): + if gamecd in ['IPKJ', 'IPGJ']: + return "JPN_048_HGSS_YForest.myg" + + # 10th Anniversary Mew, WC 53, HG/SS (First Distribution) + if date(2009, 11, 11) <= today <= date(2009, 11, 23): + if gamecd in ['IPKJ', 'IPGJ']: + return "JPN_053_HGSS_10AnnivMew.myg" + + # Engima Stone, WC 54, HG/SS + if date(2009, 11, 27) <= today <= date(2010, 1, 11): + if gamecd in ['IPKJ', 'IPGJ']: + return "JPN_054_HGSS_EnigmaStone.myg" + + # Winner's Path Pokewalker Route, WC 51, HG/SS + if date(2010, 1, 13) <= today <= date(2010, 1, 27): + if gamecd in ['IPKJ', 'IPGJ']: + return "JPN_051_HGSS_WinPath.myg" + + # 10th Anniversary Mew, WC 53, D/P/Pt/HG/SS (Second Distribution) + if date(2010, 1, 29) <= today <= date(2010, 2, 14): + if gamecd in ['IPKJ', 'IPGJ']: + return "JPN_053_ALL_10AnnivMew.myg" + + # Yellow Forest Pokewalker Route, WC 48, HG/SS (Second Distribution) + if date(2010, 2, 16) <= today <= date(2010, 2, 28): + if gamecd in ['IPKJ', 'IPGJ']: + return "JPN_048_HGSS_YForest.myg" + + # Goone's Scizor, WC 63, D/P/Pt/HG/SS + if date(2010, 6, 18) <= today <= date(2010, 7, 14): + if gamecd in ['ADAJ', 'APAJ', 'CPUJ', 'IPKJ', 'IPGJ']: + return "JPN_063_ALL_GooneScizor.myg" + + # Ash's Pikachu, WC 65, D/P/Pt/HG/SS + if date(2010, 7, 15) <= today <= date(2010, 8, 10): + if gamecd in ['ADAJ', 'APAJ', 'CPUJ', 'IPKJ', 'IPGJ']: + return "JPN_065_ALL_AshPikachu.myg" + + # Nintendo Zone Manaphy, WC 66, D/P/Pt/HG/SS + if date(2010, 8, 14) <= today <= date(2010, 9, 12): + if gamecd in ['ADAJ', 'APAJ', 'CPUJ', 'IPKJ', 'IPGJ']: + return "JPN_066_ALL_NZ_Manaphy.myg" + + # If we reach this point without returning an event, no event was found + return "null" + elif gamecd.endswith("K"): + # Korean Events + + # Azure Flute, WC 119, Platinum Only (Custom, never released) + # Distribution time is set to the same date range as the real-life + # Korean Arceus distribution, which was distributed at showings of + # "Arceus and the Jewel of Life" + if date(2009, 12, 24) <= today <= date(2010, 1, 31): + if gamecd in ['CPUK']: + return "KOR_119_Plat_AzureFlute.myg" + + # Yellow Forest Pokewalker Route, WC 22, HG/SS + if date(2010, 2, 4) <= today <= date(2010, 3, 31): + if gamecd in ['IPKK', 'IPGK']: + return "KOR_022_HGSS_YForest.myg" + + # Enigma Stone, WC 26, HG/SS + if date(2010, 7, 26) <= today <= date(2010, 8, 31): + if gamecd in ['IPKK', 'IPGK']: + return "KOR_026_HGSS_EnigmaStone.myg" + + # Winner's Path Pokewalker Route, WC 25, HG/SS + if date(2010, 9, 1) <= today <= date(2010, 10, 31): + if gamecd in ['IPKK', 'IPGK']: + return "KOR_025_HGSS_WinPath.myg" + + # Goone's Scizor, WC 63, D/P/Pt/HG/SS + if date(2011, 1, 7) <= today <= date(2011, 1, 31): + if gamecd in ['ADAK', 'APAK', 'CPUK', 'IPKK', 'IPGK']: + return "KOR_063_ALL_GooneScizor.myg" + + # Ash's Pikachu, WC 65, D/P/Pt/HG/SS + if date(2011, 2, 1) <= today <= date(2011, 2, 28): + if gamecd in ['ADAK', 'APAK', 'CPUK', 'IPKK', 'IPGK']: + return "KOR_065_ALL_AshPikachu.myg" + + # If we reach this point without returning an event, no event was found + return "null" + else: + return "null" + +def filter_list_g4_mystery_gift(data, token, gamecd, dlc_path): + """Allow user to control which file to receive by setting the local date. + + Selected file will be served according to that file's original real-life Mystery Gift release date, + on a per-gameid basis. For example, the Member Card will be served to gameid CPUJ between the local + dates of December 1st 2008 and January 15th 2009, and to the gameid CPUE between the local dates of + August 3rd 2009 and September 13th 2009. + + All Mystery Gift release timings were sourced from Bulbapedia and Serebii. They are defined in + the function `todays_g4_event_filename()` + + I've done my best to include all events across all regions, however only Wi-Fi events have been included. + However, I have also included my own custom-made Azure Flute distributions for all regions as well; we all + know that the Azure Flute was never distributed, but I think we can all agree it absolutely should have been!""" + try: + userData = GamespyDatabase().get_nas_login(token) + time_struct = time.strptime(userData['devtime'], '%y%m%d%H%M%S') + ds_date = date(time_struct.tm_year, time_struct.tm_mon, time_struct.tm_mday) + event_filename = todays_g4_event_filename(ds_date, gamecd) + if event_filename != "null": + event_size = str(os.path.getsize(os.path.join(dlc_path, event_filename))) + ret = event_filename + "\t\t\t\t\t" + event_size + '\r\n' + else: + files = data.splitlines() + ret = files[(int(ds_date.tm_yday) - 1) % len(files)] + '\r\n' + except: + ret = filter_list_random_files(data, 1) + return ret def filter_list_by_date(data, token): """Allow user to control which file to receive by setting @@ -151,8 +552,17 @@ def safeloadfi(dlc_path, name, mode='rb'): def download_count(dlc_path, post): """Handle download count request.""" - if post["gamecd"] in gamecodes_return_random_file: + gamecd = post["gamecd"] + + if gamecd in gen_4_pokemon_gamecodes: + userData = GamespyDatabase().get_nas_login(post["token"]) + time_struct = time.strptime(userData['devtime'], '%y%m%d%H%M%S') + ds_date = date(time_struct.tm_year, time_struct.tm_mon, time_struct.tm_mday) + event_filename = todays_g4_event_filename(ds_date, gamecd) + if todays_g4_event_filename(ds_date, gamecd) != "null": return "1" + else: + return "0" if os.path.exists(dlc_path): attr1 = post.get("attr1", None) attr2 = post.get("attr2", None) @@ -205,10 +615,9 @@ def download_list(dlc_path, post): ret = filter_list(list_data, attr1, attr2, attr3) ret = filter_list_g5_mystery_gift(ret, post["rhgamecd"]) return filter_list_by_date(ret, post["token"]) - elif post["gamecd"] in gamecodes_return_random_file: - # Pokemon Gen 4 Mystery Gifts, same here - ret = filter_list(list_data, attr1, attr2, attr3) - return filter_list_by_date(ret, post["token"]) + elif post["gamecd"] in gen_4_pokemon_gamecodes: + ret = filter_list(list_data, attr1, attr2, attr3) + return filter_list_g4_mystery_gift(ret, post["token"], post["gamecd"], dlc_path) else: # Default case for most games num = post.get("num", None)