mirror of
https://github.com/Lorenzooone/PokemonGB_Online_Trades.git
synced 2026-03-21 18:04:50 -05:00
304 lines
12 KiB
Python
304 lines
12 KiB
Python
import threading
|
|
from random import Random
|
|
from .trading_version import TradingVersion
|
|
from .gsc_trading_strings import GSCTradingStrings
|
|
from argparse import ArgumentParser
|
|
|
|
class GSCTradingMenu:
|
|
"""
|
|
Class used to handle the various possible menus.
|
|
"""
|
|
default_server = ["pokemon-gb-online-trades.herokuapp.com", None]
|
|
default_emulator = ["localhost", 8765]
|
|
default_max_level = 100
|
|
|
|
def __init__(self, kill_function, is_emulator=False):
|
|
try:
|
|
args = self.handle_args(is_emulator)
|
|
except SystemExit as e:
|
|
kill_function()
|
|
|
|
# Initialize the menu
|
|
self.server = [args.server_host, args.server_port]
|
|
self.buffered = args.buffered
|
|
self.japanese = args.japanese
|
|
self.max_level = args.max_level
|
|
self.egg = args.egg
|
|
self.is_emulator = is_emulator
|
|
self.multiboot = False
|
|
if is_emulator:
|
|
self.emulator = [args.emulator_host, args.emulator_port]
|
|
self.do_sanity_checks = args.do_sanity_checks
|
|
self.kill_on_byte_drops = args.kill_on_byte_drops
|
|
self.verbose = args.verbose
|
|
self.gen = args.gen_number
|
|
self.trade_type = args.trade_type
|
|
self.room = args.room
|
|
self.toppest_menu_handlers = {
|
|
"1": self.start_gen1_trading,
|
|
"2": self.start_gen2_trading,
|
|
"3": self.start_gen1_trading,
|
|
"4": self.start_gen3_trading,
|
|
"m": self.start_multiboot_gen3
|
|
}
|
|
self.top_menu_handlers = {
|
|
"0": self.start_2p_trading,
|
|
"1": self.start_2p_trading,
|
|
"2": self.start_pool_trading,
|
|
"3": self.handle_options
|
|
}
|
|
self.options_menu_handlers = {
|
|
"0": self.handle_exit_option,
|
|
"1": self.handle_server_option,
|
|
"2": self.handle_port_option,
|
|
"3": self.handle_japanese_option,
|
|
"4": self.handle_sanity_option,
|
|
"5": self.handle_verbose_option,
|
|
"6": self.handle_buffered_option,
|
|
"7": self.handle_kill_on_byte_drop_option,
|
|
"8": self.handle_max_level_option,
|
|
"9": self.handle_eggs_option
|
|
}
|
|
if is_emulator:
|
|
self.options_menu_handlers["10"] = self.handle_emulator_host_option
|
|
self.options_menu_handlers["11"] = self.handle_emulator_port_option
|
|
|
|
def get_int(self, default_value):
|
|
x = input()
|
|
try:
|
|
ret_val = int(x)
|
|
except ValueError:
|
|
ret_val = default_value
|
|
return ret_val
|
|
|
|
def handle_buffered_change_offer(self, buffered):
|
|
decided = False
|
|
while not decided:
|
|
GSCTradingStrings.buffered_negotiation_print(buffered)
|
|
x = input().lower()
|
|
if x == "y" or x == "yes":
|
|
buffered = not buffered
|
|
decided = True
|
|
elif x == "n" or x == "no":
|
|
decided = True
|
|
return buffered
|
|
|
|
def handle_game_selector(self):
|
|
if self.gen is None or ((self.gen != 1) and (self.gen != 2) and (self.gen != 3)):
|
|
ret_val = None
|
|
while ret_val is None:
|
|
GSCTradingStrings.game_selector_menu_print()
|
|
GSCTradingStrings.choice_print()
|
|
ret_val = self.toppest_menu_handlers.get(input(), None)
|
|
if ret_val is not None:
|
|
ret_val = ret_val()
|
|
|
|
def handle_menu(self):
|
|
GSCTradingStrings.version_print(TradingVersion.version_major, TradingVersion.version_minor, TradingVersion.version_build)
|
|
if self.multiboot:
|
|
self.start_pool_trading()
|
|
elif self.trade_type is None or ((self.trade_type != GSCTradingStrings.two_player_trade_str) and (self.trade_type != GSCTradingStrings.pool_trade_str)):
|
|
self.handle_game_selector()
|
|
if not self.multiboot:
|
|
ret_val = False
|
|
while not ret_val:
|
|
GSCTradingStrings.top_menu_print()
|
|
GSCTradingStrings.choice_print()
|
|
ret_val = self.top_menu_handlers.get(input(), self.top_menu_handlers["0"])()
|
|
else:
|
|
if self.trade_type == GSCTradingStrings.two_player_trade_str:
|
|
self.start_2p_trading()
|
|
elif self.trade_type == GSCTradingStrings.pool_trade_str:
|
|
self.start_pool_trading()
|
|
|
|
def get_default_room(self):
|
|
r = Random()
|
|
return r.randint(0,99999)
|
|
|
|
def start_2p_trading(self):
|
|
self.trade_type = GSCTradingStrings.two_player_trade_str
|
|
if self.room is None:
|
|
self.room = self.get_default_room()
|
|
GSCTradingStrings.change_room_print(self.room)
|
|
self.room = self.get_int(self.room)
|
|
return True
|
|
|
|
def start_pool_trading(self):
|
|
self.trade_type = GSCTradingStrings.pool_trade_str
|
|
return True
|
|
|
|
def start_gen1_trading(self):
|
|
self.gen = 1
|
|
return True
|
|
|
|
def start_gen2_trading(self):
|
|
self.gen = 2
|
|
return True
|
|
|
|
def start_gen3_trading(self):
|
|
self.gen = 3
|
|
return True
|
|
|
|
def start_multiboot_gen3(self):
|
|
self.gen = 3
|
|
self.multiboot = True
|
|
return True
|
|
|
|
def handle_options(self):
|
|
ret_val = False
|
|
while not ret_val:
|
|
GSCTradingStrings.options_menu_print(self)
|
|
GSCTradingStrings.choice_print()
|
|
ret_val = self.options_menu_handlers.get(input(), self.options_menu_handlers["0"])()
|
|
return False
|
|
|
|
def handle_exit_option(self):
|
|
return True
|
|
|
|
def handle_server_option(self):
|
|
GSCTradingStrings.change_server_print()
|
|
self.server[0] = input()
|
|
return False
|
|
|
|
def handle_port_option(self):
|
|
GSCTradingStrings.change_port_print()
|
|
self.server[1] = self.get_int(self.server[1])
|
|
return False
|
|
|
|
def handle_emulator_host_option(self):
|
|
GSCTradingStrings.change_emu_server_print()
|
|
self.emulator[0] = input()
|
|
return False
|
|
|
|
def handle_emulator_port_option(self):
|
|
GSCTradingStrings.change_emu_port_print()
|
|
self.emulator[1] = self.get_int(self.emulator[1])
|
|
return False
|
|
|
|
def handle_buffered_option(self):
|
|
self.buffered = not self.buffered
|
|
return False
|
|
|
|
def handle_max_level_option(self):
|
|
GSCTradingStrings.change_max_level_print(self.max_level)
|
|
self.max_level = self.get_int(self.max_level)
|
|
if self.max_level < 2:
|
|
self.max_level = 2
|
|
if self.max_level > 100:
|
|
self.max_level = 100
|
|
return False
|
|
|
|
def handle_eggs_option(self):
|
|
self.egg = not self.egg
|
|
return False
|
|
|
|
def handle_japanese_option(self):
|
|
self.japanese = not self.japanese
|
|
return False
|
|
|
|
def handle_sanity_option(self):
|
|
self.do_sanity_checks = not self.do_sanity_checks
|
|
return False
|
|
|
|
def handle_kill_on_byte_drop_option(self):
|
|
self.kill_on_byte_drops = not self.kill_on_byte_drops
|
|
return False
|
|
|
|
def handle_verbose_option(self):
|
|
self.verbose = not self.verbose
|
|
return False
|
|
|
|
def handle_args(self, is_emulator):
|
|
# Parse program's arguments
|
|
parser = ArgumentParser()
|
|
parser.add_argument("-g", "--generation", dest="gen_number", default = None,
|
|
help="generation (1 = RBY/Timecapsule, 2 = GSC, 3 = RSE Special)", type=int)
|
|
parser.add_argument("-t", "--trade_type", dest="trade_type", default = None,
|
|
help="trade type (" + GSCTradingStrings.two_player_trade_str + " = 2-Player Trade, " + GSCTradingStrings.pool_trade_str + " = Pool Trade)")
|
|
parser.add_argument("-r", "--room", dest="room", default = None,
|
|
help="2-Player Trade's room", type=int)
|
|
parser.add_argument("-b", "--buffered",
|
|
action="store_true", dest="buffered", default=False,
|
|
help="default to buffered trading instead of synchronous")
|
|
parser.add_argument("-j", "--japanese",
|
|
action="store_true", dest="japanese", default=False,
|
|
help="use it if your game is Japanese")
|
|
parser.add_argument("-dsc", "--disable_sanity_checks",
|
|
action="store_false", dest="do_sanity_checks", default=True,
|
|
help="don't perform sanity checks for data sent to the device")
|
|
parser.add_argument("-dkb", "--disable_kill_drops",
|
|
action="store_false", dest="kill_on_byte_drops", default=True,
|
|
help="don't kill the process for dropped bytes")
|
|
parser.add_argument("-mlp", "--max_level_pool", dest="max_level", default = self.default_max_level,
|
|
help="Pool's max level", type=int)
|
|
parser.add_argument("-egp", "--eggify_pool",
|
|
action="store_true", dest="egg", default=False,
|
|
help="turns Pool Pokémon into ready-to-hatch eggs")
|
|
parser.add_argument("-q", "--quiet",
|
|
action="store_false", dest="verbose", default=True,
|
|
help="don't print status messages to stdout")
|
|
parser.add_argument("-sh", "--server_host", dest="server_host", default = self.default_server[0],
|
|
help="server's host")
|
|
parser.add_argument("-sp", "--server_port", dest="server_port", default = self.default_server[1],
|
|
help="server's port", type=int)
|
|
if is_emulator:
|
|
parser.add_argument("-eh", "--emulator_host", dest="emulator_host", default = self.default_emulator[0],
|
|
help="emulator's local host")
|
|
parser.add_argument("-ep", "--emulator_port", dest="emulator_port", default = self.default_emulator[1],
|
|
help="emulator's local port", type=int)
|
|
return parser.parse_args()
|
|
|
|
class GSCBufferedNegotiator(threading.Thread):
|
|
"""
|
|
Class used to handle the negotiation when the two clients'
|
|
buffered variable doesn't match up
|
|
"""
|
|
|
|
def __init__(self, menu, comms, buffered, sleep_func):
|
|
threading.Thread.__init__(self)
|
|
self.daemon=True
|
|
self.comms = comms
|
|
self.menu = menu
|
|
self.final_buffered = None
|
|
self.buffered = buffered
|
|
self.sleep_func = sleep_func
|
|
|
|
def force_receive(self, fun):
|
|
received = None
|
|
while received is None:
|
|
self.sleep_func()
|
|
received = fun()
|
|
return received
|
|
|
|
def choose_if_buffered(self):
|
|
buffered = self.buffered
|
|
self.comms.send_buffered_data(buffered)
|
|
other_buffered = self.force_receive(self.comms.get_buffered_data)
|
|
if buffered == other_buffered:
|
|
return buffered
|
|
change_buffered = None
|
|
while change_buffered is None:
|
|
own_val = self.comms.send_negotiation_data()
|
|
other_val = self.force_receive(self.comms.get_negotiation_data)
|
|
if other_val > own_val:
|
|
change_buffered = True
|
|
elif other_val < own_val:
|
|
change_buffered = False
|
|
while buffered != other_buffered:
|
|
if not change_buffered:
|
|
GSCTradingStrings.buffered_other_negotiation_print(buffered)
|
|
other_buffered = self.force_receive(self.comms.get_buffered_data)
|
|
else:
|
|
buffered = self.menu.handle_buffered_change_offer(buffered)
|
|
self.comms.send_buffered_data(buffered)
|
|
change_buffered = not change_buffered
|
|
return buffered
|
|
|
|
def get_chosen_buffered(self):
|
|
return self.final_buffered
|
|
|
|
def run(self):
|
|
self.final_buffered = self.choose_if_buffered()
|
|
if self.menu.verbose:
|
|
GSCTradingStrings.chosen_buffered_print(self.final_buffered)
|