Add proper mail data handling

Closes #11 .
Also adds proper egg handling (by making sure received eggs have 0 HPs).
This commit is contained in:
Lorenzo Carletti 2022-04-28 05:07:45 +02:00
parent 4ce0f979bc
commit a811470c94
13 changed files with 327 additions and 51 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -98,6 +98,7 @@ class GSCTradingClient:
if val is not None:
updating_mon = self.trader.other_pokemon.pokemon[self.trader.other_pokemon.get_last_mon_index()]
data = [updating_mon.get_species()] + val
self.trader.checks.prepare_species_buffer()
data = self.trader.checks.apply_checks_to_data(self.trader.checks.moves_checks_map, data)
for i in range(4):
updating_mon.set_move(i, data[i+1], max_pp=False)
@ -437,7 +438,7 @@ class GSCTrading:
Checks if the transfer dropped any bytes.
"""
if byte_index >= self.drop_bytes_checks[0][section_index]:
if byte_index < self.special_sections_len[section_index]:
if byte_index < self.get_section_length(section_index):
if byte == self.drop_bytes_checks[1][section_index]:
return True
else:
@ -461,13 +462,32 @@ class GSCTrading:
elif not self.printed_warning_drop:
self.verbose_print(GSCTradingStrings.warning_byte_dropped_str)
self.printed_warning_drop = True
def get_mail_section_id(self):
return 2
def get_printable_index(self, index):
return index+1
def get_section_length(self, index):
return self.special_sections_len[index]
def get_checker(self, index):
return self.checks.checks_map[index]
def convert_mail_data(self, data, to_device):
"""
Handles converting the mail data.
"""
return data
def read_section(self, index, send_data, buffered):
"""
Reads a data section and sends it to the device.
"""
length = self.special_sections_len[index]
length = self.get_section_length(index)
next = self.next_section
checker = self.get_checker(index)
# Prepare sanity checks stuff
self.checks.prepare_text_buffer()
@ -486,6 +506,9 @@ class GSCTrading:
recv_buf = self.read_entire_data(received)
if recv_buf[1] is not None and recv_buf[1][0] == 0xFFFF and recv_buf[2][0] == index:
found = True
elif recv_buf[1] is not None and recv_buf[1][0] == 0xFFFF:
self.verbose_print(GSCTradingStrings.incompatible_trade_str)
self.kill_function()
if not found:
self.sleep_func()
self.swap_byte(self.no_input)
@ -505,12 +528,12 @@ class GSCTrading:
i = 0
while i < (length-1):
if send_data is not None:
next = self.checks.checks_map[index][i](send_data[i])
next = checker[i](send_data[i])
send_data[i] = next
next_i = i+1
if next_i not in self.fillers[index].keys():
next = self.swap_byte(next)
self.verbose_print(GSCTradingStrings.transfer_to_hardware_str.format(index=index+1, completion=GSCTradingStrings.x_out_of_y_str(next_i, length)), end='')
self.verbose_print(GSCTradingStrings.transfer_to_hardware_str.format(index=self.get_printable_index(index), completion=GSCTradingStrings.x_out_of_y_str(next_i, length)), end='')
buf += [next]
# Handle fillers
else:
@ -518,17 +541,17 @@ class GSCTrading:
filler_val = self.fillers[index][next_i][1]
if send_data is not None:
for j in range(filler_len):
send_data[next_i + j] = self.checks.checks_map[index][next_i + j](send_data[next_i + j])
send_data[next_i + j] = checker[next_i + j](send_data[next_i + j])
buf += ([filler_val] * filler_len)
i += (filler_len - 1)
i += 1
if send_data is not None:
# Send the last byte too
next = self.checks.checks_map[index][length-1](send_data[length-1])
next = checker[length-1](send_data[length-1])
send_data[length-1] = next
self.swap_byte(next)
self.verbose_print(GSCTradingStrings.transfer_to_hardware_str.format(index=index+1, completion=GSCTradingStrings.x_out_of_y_str(length, length)), end='')
self.verbose_print(GSCTradingStrings.transfer_to_hardware_str.format(index=self.get_printable_index(index), completion=GSCTradingStrings.x_out_of_y_str(length, length)), end='')
for j in range(self.drop_bytes_checks[2][index]):
self.swap_byte(self.no_data)
other_buf = send_data
@ -554,7 +577,7 @@ class GSCTrading:
recv_data = self.get_swappable_bytes(recv_buf, length, index)
if i in recv_data.keys() and (i < length):
# Clean it and send it
cleaned_byte = self.checks.checks_map[index][i](recv_data[i])
cleaned_byte = checker[i](recv_data[i])
next_i = i+1
# Handle fillers
if next_i in self.fillers[index].keys():
@ -564,11 +587,11 @@ class GSCTrading:
send_buf[(next_i)&1][1] = filler_val
buf += ([filler_val] * filler_len)
for j in range(filler_len):
other_buf += [self.checks.checks_map[index][next_i + j](filler_val)]
other_buf += [checker[next_i + j](filler_val)]
i += (filler_len - 1)
else:
next = self.swap_byte(cleaned_byte)
self.verbose_print(GSCTradingStrings.transfer_to_hardware_str.format(index=index+1, completion=GSCTradingStrings.x_out_of_y_str(next_i, length)), end='')
self.verbose_print(GSCTradingStrings.transfer_to_hardware_str.format(index=self.get_printable_index(index), completion=GSCTradingStrings.x_out_of_y_str(next_i, length)), end='')
# Fillers aren't needed anymore, but their last byte may be needed
self.remove_filler(send_buf, i)
# This will, in turn, get the next byte
@ -607,7 +630,7 @@ class GSCTrading:
Tries to read a single synchronous entry.
"""
if recv_buf[scanning_index] is not None:
if recv_buf[2][0] == (index + 1):
if recv_buf[2][0] >= (index + 1):
ret[length] = 0
else:
byte_num = recv_buf[scanning_index][0]
@ -913,6 +936,8 @@ class GSCTrading:
if necessary and in the way which requires less packet transfers.
Returns the player's data and the other player's data.
"""
# Prepare checks
self.checks.reset_species_item_list()
# Send and get the first two sections
random_data, random_data_other = self.read_section(0, send_data[0], buffered)
pokemon_data, pokemon_data_other = self.read_section(1, send_data[1], buffered)
@ -924,7 +949,9 @@ class GSCTrading:
# Trade mail data only if needed
if (pokemon_own_mail and pokemon_other_mail) or buffered:
mail_data, mail_data_other = self.read_section(2, send_data[2], buffered)
send_data[2] = self.convert_mail_data(send_data[2], True)
mail_data, mail_data_other = self.read_section(self.get_mail_section_id(), send_data[2], buffered)
mail_data = self.convert_mail_data(mail_data, False)
else:
send_data[2] = self.utils_class.no_mail_section
# Get mail data if only the other client has it
@ -935,7 +962,9 @@ class GSCTrading:
self.verbose_print(GSCTradingStrings.no_mail_other_data_str)
# Exchange mail data with the device
mail_data, mail_data_other = self.read_section(2, send_data[2], True)
send_data[2] = self.convert_mail_data(send_data[2], True)
mail_data, mail_data_other = self.read_section(self.get_mail_section_id(), send_data[2], True)
mail_data = self.convert_mail_data(mail_data, False)
# Send mail data if only this client has it
if pokemon_own_mail:

View File

@ -91,6 +91,12 @@ class GSCUtilsLoaders:
ret[i] = data[(i)*num_stats:(i+1)*num_stats]
return ret
def prepare_functions_map(data, functions):
call_map = [None] * len(data)
for i in range(len(data)):
call_map[i] = functions[data[i]]
return call_map
def load_trading_data(target, lengths):
data = None
try:
@ -231,10 +237,25 @@ class GSCUtils:
ret = None
# Prepare sanity checks stuff
checks.reset_species_item_list()
checks.set_single_team_size()
checks.prepare_text_buffer()
checks.prepare_species_buffer()
checker = checks.single_pokemon_checks_map
if len(data) > len(checker):
# Handle getting/sending eggs. That requires one extra byte
is_egg = False
if data[len(checker)] == GSCUtils.egg_value:
is_egg = True
# Prepare for further checks
if is_egg:
checks.species_cleaner(GSCUtils.egg_id)
else:
checks.species_cleaner(data[0])
checks.prepare_species_buffer()
# Applies the checks to the received data.
# If the sanity checks are off, this will be a simple copy
purified_data = checks.apply_checks_to_data(checker, data)
@ -244,11 +265,6 @@ class GSCUtils:
raw = GSCTradingPokémonInfo.set_data(data)
mon = GSCTradingPokémonInfo.set_data(purified_data)
# Handle getting/sending eggs. That requires one extra byte
is_egg = False
if purified_data[len(checker)] == GSCUtils.egg_value:
is_egg = True
# If the sanity checks are on, has the pokémon changed
# too much from the cleaning?
if not mon.has_changed_significantly(raw):
@ -440,7 +456,7 @@ class GSCTradingPokémonInfo:
self.mail = self.text_class(data, start, length=self.mail_len)
def add_mail_sender(self, data, start):
self.mail_sender = self.text_class(data, start, length=self.sender_len, data_start=3)
self.mail_sender = self.text_class(data, start, length=self.sender_len, data_start=0)
def is_nicknamed(self):
return not self.nickname.values_equal(self.utils_class.pokemon_names[self.get_species()])
@ -804,14 +820,24 @@ class GSCTradingData:
"""
Trades a pokémon between two parties.
"""
# Prepare checks
checks.reset_species_item_list()
checks.set_single_team_size()
checks.prepare_text_buffer()
checks.prepare_species_buffer()
# Apply checks
own_id = checks.species_cleaner(self.party_info.get_id(own_index))
checks.prepare_species_buffer()
own = self.mon_generator_class().set_data(checks.apply_checks_to_data(checks.single_pokemon_checks_map, self.pokemon[own_index].get_data()))
# Actually trade the Pokémon
self.reorder_party(own_index)
other.reorder_party(other_index)
own = self.mon_generator_class().set_data(checks.apply_checks_to_data(checks.single_pokemon_checks_map, self.pokemon[self.get_last_mon_index()].get_data()))
self.pokemon[self.get_last_mon_index()] = other.pokemon[other.get_last_mon_index()]
other.pokemon[other.get_last_mon_index()] = own
checks.curr_species_pos = self.get_last_mon_index()
checks.team_size = self.get_party_size()
own_id = checks.species_cleaner(self.party_info.get_id(self.get_last_mon_index()))
self.party_info.set_id(self.get_last_mon_index(), other.party_info.get_id(other.get_last_mon_index()))
other.party_info.set_id(other.get_last_mon_index(), own_id)
@ -867,10 +893,12 @@ class GSCChecks:
moves_checks_map_path = "moves_checks_map.bin"
curr_exp_pos_masks = [0, 0xFF0000, 0xFFFF00]
free_value_species = 0xFF
empty_value_species = 0
free_value_moves = 0
tackle_id = 0x21
rattata_id = 0x13
question_mark = 0xE6
newline = 0x4E
def __init__(self, section_sizes, do_sanity_checks):
self.utils_class = self.get_utils_class()
@ -896,11 +924,17 @@ class GSCChecks:
self.clean_pp,
self.clean_experience,
self.clean_egg_cycles_friendship,
self.clean_type
self.clean_type,
self.clean_text_newline,
self.clean_text_final_no_end,
self.clean_species_force_terminate,
self.clean_mail_species,
self.clean_mail_item,
self.clean_mail_same_species
]
self.checks_map = self.prepare_checks_map(GSCUtilsMisc.read_data(self.get_path(self.checks_map_path)), section_sizes)
self.single_pokemon_checks_map = self.prepare_basic_checks_map(GSCUtilsMisc.read_data(self.get_path(self.single_pokemon_checks_map_path)))
self.moves_checks_map = self.prepare_basic_checks_map(GSCUtilsMisc.read_data(self.get_path(self.moves_checks_map_path)))
self.checks_map = self.prepare_checks_map(GSCUtilsMisc.read_data(self.get_path(self.checks_map_path)), section_sizes, self.check_functions)
self.single_pokemon_checks_map = GSCUtilsLoaders.prepare_functions_map(GSCUtilsMisc.read_data(self.get_path(self.single_pokemon_checks_map_path)), self.check_functions)
self.moves_checks_map = GSCUtilsLoaders.prepare_functions_map(GSCUtilsMisc.read_data(self.get_path(self.moves_checks_map_path)), self.check_functions)
self.species_cleaner = self.clean_species_sp
def get_path(self, target):
@ -937,20 +971,27 @@ class GSCChecks:
def prepare_text_buffer(self):
self.curr_text = []
def reset_species_item_list(self):
self.species_list = []
self.species_list_size = 0
self.item_list = []
def set_single_team_size(self):
self.team_size = 1
def add_to_species_list(self, species):
if (species != self.free_value_species) and (species != self.empty_value_species):
self.species_list_size += 1
self.species_list += [species]
def prepare_species_buffer(self):
self.curr_species_pos = 0
def prepare_checks_map(self, data, lengths):
def prepare_checks_map(self, data, lengths, functions_list):
raw_data_sections = GSCUtilsMisc.divide_data(data, lengths)
call_map = [[],[],[]]
for i in range(len(raw_data_sections)):
call_map[i] = self.prepare_basic_checks_map(raw_data_sections[i])
return call_map
def prepare_basic_checks_map(self, data):
call_map = [None] * len(data)
for i in range(len(data)):
call_map[i] = self.check_functions[data[i]]
call_map[i] = GSCUtilsLoaders.prepare_functions_map(raw_data_sections[i], functions_list)
return call_map
@clean_check_sanity_checks
@ -987,7 +1028,9 @@ class GSCChecks:
@clean_check_sanity_checks
def clean_item(self, item):
return self.clean_value(item, self.is_item_valid, 0)
cleaned_item = self.clean_value(item, self.is_item_valid, 0)
self.item_list += [cleaned_item]
return cleaned_item
@clean_check_sanity_checks
def clean_pp(self, pp):
@ -1017,6 +1060,7 @@ class GSCChecks:
@clean_check_sanity_checks
def clean_species(self, species):
self.curr_species = self.clean_value(species, self.is_species_valid, self.rattata_id)
self.curr_species_pos += 1
self.curr_stat_id = 0
self.iv = [0,0,0,0]
self.stat_exp = [0,0,0,0,0]
@ -1035,15 +1079,22 @@ class GSCChecks:
@clean_check_sanity_checks
def clean_species_sp(self, species):
if species == self.free_value_species or self.curr_species_pos >= self.team_size:
if species == self.free_value_species or self.species_list_size >= self.team_size:
self.add_to_species_list(self.free_value_species)
self.curr_species_pos += 1
return self.free_value_species
found_species = self.clean_value(species, self.is_species_valid, self.rattata_id)
if species == self.utils_class.egg_id:
found_species = species
self.add_to_species_list(found_species)
self.curr_species_pos += 1
return found_species
@clean_check_sanity_checks
def clean_species_force_terminate(self, species):
self.prepare_species_buffer()
return self.free_value_species
@clean_check_sanity_checks
def load_stat_exp(self, val):
calc_val = val << (8 * self.curr_stat_exp_pos)
@ -1064,6 +1115,19 @@ class GSCChecks:
self.curr_iv_pos += 1
return val
@clean_check_sanity_checks
def clean_mail_species(self, species):
self.curr_species_pos += 1
return self.species_list[self.curr_species_pos-1]
@clean_check_sanity_checks
def clean_mail_same_species(self, species):
return self.species_list[self.curr_species_pos-1]
@clean_check_sanity_checks
def clean_mail_item(self, item):
return self.item_list[self.curr_species_pos-1]
@clean_check_sanity_checks
def clean_text(self, char):
char_val = self.clean_value(char, self.is_char_valid, self.question_mark)
@ -1079,6 +1143,21 @@ class GSCChecks:
self.prepare_text_buffer()
return char_val
@clean_check_sanity_checks
def clean_text_newline(self, char):
char_val = self.newline
self.curr_text += [char_val]
# Possibility to put bad words filters here
return char_val
@clean_check_sanity_checks
def clean_text_final_no_end(self, char):
char_val = self.clean_value(char, self.is_char_valid, self.question_mark)
self.curr_text += [char_val]
# Possibility to put bad words filters here
self.prepare_text_buffer()
return char_val
@clean_check_sanity_checks
def clean_type(self, typing):
return typing
@ -1091,13 +1170,16 @@ class GSCChecks:
return curr_stat
@clean_check_sanity_checks
def check_stat(self, val, zero_min=False):
def check_stat(self, val, zero_min=False, zero_max=False):
if self.curr_pos == 0:
self.stat = 0
min_stat = self.utils_class.stat_calculation(self.curr_stat_id, self.curr_species, self.iv, self.stat_exp, self.level, self.utils_class, do_exp=False)
if zero_min:
max_stat = self.utils_class.stat_calculation(self.curr_stat_id, self.curr_species, self.iv, self.stat_exp, self.level, self.utils_class)
if zero_min or zero_max:
min_stat = 0
self.stat_range = [min_stat, self.utils_class.stat_calculation(self.curr_stat_id, self.curr_species, self.iv, self.stat_exp, self.level, self.utils_class)]
if zero_max:
max_stat = 0
self.stat_range = [min_stat, max_stat]
curr_read_val = val << (8 * (1 - (self.curr_pos & 1)))
self.stat = self.check_range(self.stat_range, (self.stat & 0xFF00) | curr_read_val)
val = (self.stat >> (8 * (1 - (self.curr_pos & 1)))) & 0xFF
@ -1107,12 +1189,19 @@ class GSCChecks:
self.curr_pos = 0
return val
def is_egg(self):
if self.species_list[self.curr_species_pos-1] == self.utils_class.egg_id:
return True
return False
@clean_check_sanity_checks
def check_hp(self, val):
start_zero = False
max_zero = False
if self.curr_hp == 0:
start_zero = True
val = self.check_stat(val, zero_min=start_zero)
max_zero = self.is_egg()
val = self.check_stat(val, zero_min=start_zero, zero_max=max_zero)
if self.curr_pos == 0:
if self.curr_hp == 0:
self.hps = [0,0]

View File

@ -1,4 +1,129 @@
from .gsc_trading import GSCTrading
from .gsc_trading_data_utils import GSCUtilsLoaders, GSCUtilsMisc
class GSCJPMailConverter:
"""
Class which handles converting the GSC Japanese mail data
to the international format.
"""
base_folder = "useful_data/gsc/"
table_to_jp_path = "mail_conversion_table_en_to_jp.bin"
table_to_int_path = "mail_conversion_table_jp_to_en.bin"
mail_jp_checks_path = "mail_checks_jp.bin"
end_of_line = 0x50
extra_distance_jp = 5
extra_distance_int = 0xA
full_mail_jp_len = 0x2A
mail_len = 0x21
sender_int_len = 0xE
mail_pos_jp = [
0xCB + (0*full_mail_jp_len),
0xCB + (1*full_mail_jp_len),
0xCB + (2*full_mail_jp_len),
0xCB + (3*full_mail_jp_len),
0xCB + (4*full_mail_jp_len),
0xCB + (5*full_mail_jp_len)
]
mail_pos_int = [
0xCB + (0*mail_len),
0xCB + (1*mail_len),
0xCB + (2*mail_len),
0xCB + (3*mail_len),
0xCB + (4*mail_len),
0xCB + (5*mail_len)
]
sender_pos_jp = [
0xEC + (0*full_mail_jp_len),
0xEC + (1*full_mail_jp_len),
0xEC + (2*full_mail_jp_len),
0xEC + (3*full_mail_jp_len),
0xEC + (4*full_mail_jp_len),
0xEC + (5*full_mail_jp_len)
]
sender_pos_int = [
0x191 + (0*sender_int_len),
0x191 + (1*sender_int_len),
0x191 + (2*sender_int_len),
0x191 + (3*sender_int_len),
0x191 + (4*sender_int_len),
0x191 + (5*sender_int_len)
]
def __init__(self, checks):
self.conversion_functions = [
self.do_zero,
self.mail_conversion,
self.sender_conversion,
self.extra_conversion,
self.do_ff,
self.do_20,
self.start_mail_conversion,
self.do_eol,
self.start_sender_conversion
]
self.mail_conversion_table_jp = GSCUtilsLoaders.prepare_functions_map(GSCUtilsMisc.read_data(self.get_path(self.table_to_jp_path)), self.conversion_functions)
self.mail_conversion_table_int = GSCUtilsLoaders.prepare_functions_map(GSCUtilsMisc.read_data(self.get_path(self.table_to_int_path)), self.conversion_functions)
self.mail_checker = GSCUtilsLoaders.prepare_functions_map(GSCUtilsMisc.read_data(self.get_path(self.mail_jp_checks_path)), checks.check_functions)
def get_path(self, target):
return self.base_folder + target
def convert_to_jp(self, data):
self.mail_converter_pos = self.mail_pos_int
self.sender_converter_pos = self.sender_pos_int
self.extra_distance = self.extra_distance_int
return self.convert(data, self.mail_conversion_table_jp)
def convert_to_int(self, data):
self.mail_converter_pos = self.mail_pos_jp
self.sender_converter_pos = self.sender_pos_jp
self.extra_distance = self.extra_distance_jp
return self.convert(data, self.mail_conversion_table_int)
def convert(self, to_convert, converter):
ret = [0] * len(converter)
for i in range(len(converter)):
ret[i] = converter[i](to_convert)
return ret
def do_zero(self, data):
return 0
def mail_conversion(self, data):
self.single_mail_pos += 1
return data[self.mail_converter_pos[self.mail_conv_pos] + self.single_mail_pos]
def sender_conversion(self, data):
self.single_sender_pos += 1
return data[self.sender_converter_pos[self.sender_conv_pos] + self.single_sender_pos]
def extra_conversion(self, data):
self.extra_conversion_pos += 1
return data[self.sender_converter_pos[self.sender_conv_pos] + self.extra_distance + self.extra_conversion_pos]
def start_mail_conversion(self, data):
self.mail_conv_pos += 1
self.single_mail_pos = 0
return data[self.mail_converter_pos[self.mail_conv_pos] + self.single_mail_pos]
def start_sender_conversion(self, data):
self.sender_conv_pos += 1
self.single_sender_pos = 0
self.extra_conversion_pos = -1
return data[self.sender_converter_pos[self.sender_conv_pos] + self.single_sender_pos]
def do_ff(self, data):
return 0xFF
def do_eol(self, data):
return self.end_of_line
def do_20(self, data):
self.mail_conv_pos = -1
self.sender_conv_pos = -1
return 0x20
class GSCTradingJP(GSCTrading):
"""
@ -23,17 +148,38 @@ class GSCTradingJP(GSCTrading):
0x13B + (single_text_len * 9): [5, end_of_line],
0x13B + (single_text_len * 10): [5, end_of_line],
0x13B + (single_text_len * 11): [5, end_of_line]
}, {
0x19A + (mail_sender_len * 0): [5, end_of_line],
0x19A + (mail_sender_len * 1): [5, end_of_line],
0x19A + (mail_sender_len * 2): [5, end_of_line],
0x19A + (mail_sender_len * 3): [5, end_of_line],
0x19A + (mail_sender_len * 4): [5, end_of_line],
0x19A + (mail_sender_len * 5): [5, end_of_line],
0x205: [0x46, 0]
}]
drop_bytes_checks = [[0xA, 0x1B9, 0x1E6], [next_section, next_section, no_input], [0,4,0]]
}, {}, {}]
drop_bytes_checks = [[0xA, 0x1B9, 0x1E6, 0x1B8], [next_section, next_section, no_input, no_input], [0,4,0,0]]
def __init__(self, sending_func, receiving_func, connection, menu, kill_function):
super(GSCTradingJP, self).__init__(sending_func, receiving_func, connection, menu, kill_function)
self.jp_mail_converter = GSCJPMailConverter(self.checks)
def get_mail_section_id(self):
return 3
def get_printable_index(self, index):
if index != self.get_mail_section_id():
return index+1
return index
def get_section_length(self, index):
if index != self.get_mail_section_id():
return self.special_sections_len[index]
return len(self.jp_mail_converter.mail_checker)
def get_checker(self, index):
if index != self.get_mail_section_id():
return self.checks.checks_map[index]
return self.jp_mail_converter.mail_checker
def convert_mail_data(self, data, to_device):
"""
Handles converting the mail data.
"""
if data is not None:
if to_device:
data = self.jp_mail_converter.convert_to_jp(data)
else:
data = self.jp_mail_converter.convert_to_int(data)
return data

View File

@ -55,6 +55,7 @@ class GSCTradingStrings:
arrived_synchro_str = "\nThe other player arrived. Starting party information trading..."
transfer_to_hardware_str = "\rSection {index}: {completion}"
restart_trade_str = "\nStarting a new trade."
incompatible_trade_str = "\nIt looks like the requested trade is not possible.\nYou can't do a synchronous trade when both the International version and the Japanese version\nrequire Mail data from the other.\nEither do a Buffered trade, or remove mail from one of the two.\nShutting down..."
separate_section_str = "\n"
buffered_negotiation_str = '\nThe other player wants to do a {other_buffered} trade.\nWould you like to switch to a {other_buffered} trade?'
buffered_other_negotiation_str = "\nAsking the other player whether they're willing to do a {own_buffered} trade..."

View File

@ -47,6 +47,7 @@ class RBYTradingClient(GSCTradingClient):
val = self.get_with_counter(self.moves_transfer)
if val is not None:
updating_mon = self.trader.other_pokemon.pokemon[self.trader.other_pokemon.get_last_mon_index()]
self.trader.checks.prepare_species_buffer()
data = self.trader.checks.apply_checks_to_data(self.trader.checks.moves_checks_map, val)
for i in range(4):
updating_mon.set_move(i, data[i+1], max_pp=False)

View File

@ -56,12 +56,17 @@ class RBYUtils(GSCUtils):
ret = None
# Prepare sanity checks stuff
checks.reset_species_item_list()
checks.set_single_team_size()
checks.prepare_text_buffer()
checks.prepare_species_buffer()
checker = checks.single_pokemon_checks_map
if len(data) >= len(checker):
# Applies the checks to the received data.
# If the sanity checks are off, this will be a simple copy
checks.species_cleaner(data[0])
checks.prepare_species_buffer()
purified_data = checks.apply_checks_to_data(checker, data)
# Prepares the pokémon data. For both the cleaned one and
@ -250,12 +255,17 @@ class RBYChecks(GSCChecks):
self.level = self.utils_class.max_level
return val
def is_egg(self):
return False
@GSCChecks.clean_check_sanity_checks
def clean_species_sp(self, species):
if species == self.free_value_species or self.curr_species_pos >= self.team_size:
if species == self.free_value_species or self.species_list_size >= self.team_size:
self.add_to_species_list(self.free_value_species)
self.curr_species_pos += 1
return self.free_value_species
found_species = self.clean_value(species, self.is_species_valid, self.rattata_id)
self.add_to_species_list(found_species)
self.curr_species_pos += 1
return found_species