Adding PCCS

This commit is contained in:
The Gears of Progress 2025-10-12 15:08:33 -04:00
parent ccaf1e28ae
commit ba1a075701
63 changed files with 13189 additions and 4348 deletions

View File

@ -30,8 +30,8 @@ LIBTONC := $(DEVKITPRO)/libtonc
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))_mb
BUILD := build
SOURCES := source
INCLUDES := include
SOURCES := source source/pccs
INCLUDES := include include/pccs
DATA := data
MUSIC := audio
GRAPHICS := graphics

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,10 @@
#ifndef BACKGROUND_ENGINE_H
#define BACKGROUND_ENGINE_H
#include "sprite_data.h"
#include "text_engine.h"
#include "global_frame_controller.h"
void background_frame(int global_frame_count);
void create_textbox(int startTileX, int startTileY, int text_space_width, int text_space_height, bool eraseMainBox);
void reset_textbox();

View File

@ -4,7 +4,6 @@
#include <tonc.h>
#include "string.h"
#include "button_handler.h"
#include "pokemon.h"
#include "string_view"
#include "pokemon_party.h"
#include "button_handler.h"
@ -27,7 +26,7 @@ class Box_Menu
{
public:
Box_Menu();
int box_main(Pokemon_Party party_data);
int box_main(PokeBox* box);
private:
int curr_button;
int x;

View File

@ -2,19 +2,19 @@
#define DEBUG_MODE_H
#define VERSION "v1.2.0b"
#define PTGB_BUILD_LANGUAGE ENG_ID
#define PTGB_BUILD_LANGUAGE 2
#define DEBUG_MODE true
#define PRINT_LINK_DATA (false && DEBUG_MODE) // This is currently broken... not sure why
#define PRINT_LINK_DATA (true && DEBUG_MODE)
#define INSTANT_TEXT_SPEED (false && DEBUG_MODE)
#define IGNORE_GAME_PAK (false && DEBUG_MODE)
#define IGNORE_GAME_PAK_SPRITES (false && DEBUG_MODE)
#define IGNORE_GAME_PAK (true && DEBUG_MODE)
#define IGNORE_GAME_PAK_SPRITES (true && DEBUG_MODE)
#define IGNORE_LINK_CABLE (true && DEBUG_MODE)
#define IGNORE_MG_E4_FLAGS (true && DEBUG_MODE)
#define IGNORE_UNRECEIVED_PKMN (true && DEBUG_MODE)
#define FORCE_TUTORIAL (false && DEBUG_MODE)
#define DONT_REMOVE_PKMN (true && DEBUG_MODE)
#define DONT_REMOVE_PKMN (false && DEBUG_MODE)
#define DONT_HIDE_INVALID_PKMN (false && DEBUG_MODE)
#define IGNORE_DEX_COMPLETION (false && DEBUG_MODE)
#define FORCE_ALL_CAUGHT (false && DEBUG_MODE)
@ -28,7 +28,6 @@
#define DEBUG_LANG LANG_ENG
#define ENABLE_MATCH_PID true
#define ENABLE_OLD_EVENT false
#define ENABLE_DEBUG_SCREEN true
#define USE_CUSTOM_MALLOC 1

View File

@ -1,7 +1,6 @@
#ifndef MIRROR_H
#define MIRROR_H
#include <tonc.h>
#include "pokemon.h"
#include "rom_data.h"
#define SAVE_A_OFFSET 0x00000000 // Offset of Game Save A
@ -14,7 +13,7 @@ extern vu32 newest_save_offset;
extern vu32 memory_section_array[];
extern char mem_name;
extern u8 global_memory_buffer[0x1000];
extern rom_data curr_rom;
extern rom_data curr_GBA_rom;
void initalize_memory_locations();
void print_mem_section();

View File

@ -31,10 +31,10 @@
#define SLOW_SPEED 1000
void setup(const u16 *debug_charset);
byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, Simplified_Pokemon *curr_simple_array, const u16 *debug_charset, bool cancel_connection);
int loop(byte *box_data_storage, byte *curr_payload, GB_ROM *curr_rom, Simplified_Pokemon *curr_simple_array, const u16 *debug_charset, bool cancel_connection);
byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, PokeBox* box, const u16 *debug_charset, bool cancel_connection);
int loop(byte *box_data_storage, byte *curr_payload, GB_ROM *curr_rom, PokeBox* box, const u16 *debug_charset, bool cancel_connection);
byte exchange_parties(byte curr_in, byte *curr_payload);
byte exchange_boxes(byte curr_in, byte *party_data, GB_ROM *curr_gb_rom);
byte exchange_remove_array(byte curr_in, Simplified_Pokemon *curr_simple_array, bool cancel_connection);
byte exchange_remove_array(byte curr_in, PokeBox* box, bool cancel_connection);
#endif /* GAMEBOY_COLOUR_H_ */

View File

@ -1,10 +1,24 @@
#ifndef GLOBAL_FRAME_CONTROLLER_H
#define GLOBAL_FRAME_CONTROLLER_H
#include <cstring>
#define STATE_CONNECTION 1
#define STATE_TRANSFER 2
#define STATE_NO_ANIM 3
// TODO: This is kinda a silly spot for this
// make sure outBuffer is large enough! Should be at least hex_len + 1
template <typename I>
void n2hexstr(char *outBuffer, I w, size_t hex_len = sizeof(I) << 1)
{
static const char *digits = "0123456789ABCDEF";
memset(outBuffer, '0', hex_len);
outBuffer[hex_len] = '\0'; // we must make sure to terminate the string
for (size_t i = 0, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4)
outBuffer[i] = digits[(w >> j) & 0x0f];
}
void global_next_frame();
int get_frame_count();
void set_menu_sprite_pal(int frame);
@ -15,7 +29,7 @@ void set_missingno(bool val);
bool get_missingno_enabled();
void set_treecko(bool val);
bool get_treecko_enabled();
u32 fnv1a_hash(unsigned char* data, size_t length);
u32 fnv1a_hash(unsigned char *data, size_t length);
int get_string_length(const byte *str);
void convert_int_to_ptgb_str(int val, byte str[]);
void convert_int_to_ptgb_str(int val, byte str[], int min_length);

View File

@ -55,199 +55,199 @@
#define rlist_r7 0b010000001
#define rlist_lr 0b100000000
#define MOVEMENT_ACTION_FACE_DOWN curr_rom.is_hoenn() ? 0x0 : 0x0
#define MOVEMENT_ACTION_FACE_UP curr_rom.is_hoenn() ? 0x1 : 0x1
#define MOVEMENT_ACTION_FACE_LEFT curr_rom.is_hoenn() ? 0x2 : 0x2
#define MOVEMENT_ACTION_FACE_RIGHT curr_rom.is_hoenn() ? 0x3 : 0x3
#define MOVEMENT_ACTION_WALK_SLOW_DOWN curr_rom.is_hoenn() ? 0x4 : 0xC
#define MOVEMENT_ACTION_WALK_SLOW_UP curr_rom.is_hoenn() ? 0x5 : 0xD
#define MOVEMENT_ACTION_WALK_SLOW_LEFT curr_rom.is_hoenn() ? 0x6 : 0xE
#define MOVEMENT_ACTION_WALK_SLOW_RIGHT curr_rom.is_hoenn() ? 0x7 : 0xF
#define MOVEMENT_ACTION_WALK_NORMAL_DOWN curr_rom.is_hoenn() ? 0x8 : 0x10
#define MOVEMENT_ACTION_WALK_NORMAL_UP curr_rom.is_hoenn() ? 0x9 : 0x11
#define MOVEMENT_ACTION_WALK_NORMAL_LEFT curr_rom.is_hoenn() ? 0xA : 0x12
#define MOVEMENT_ACTION_WALK_NORMAL_RIGHT curr_rom.is_hoenn() ? 0xB : 0x13
#define MOVEMENT_ACTION_JUMP_2_DOWN curr_rom.is_hoenn() ? 0xC : 0x14
#define MOVEMENT_ACTION_JUMP_2_UP curr_rom.is_hoenn() ? 0xD : 0x15
#define MOVEMENT_ACTION_JUMP_2_LEFT curr_rom.is_hoenn() ? 0xE : 0x16
#define MOVEMENT_ACTION_JUMP_2_RIGHT curr_rom.is_hoenn() ? 0xF : 0x17
#define MOVEMENT_ACTION_DELAY_1 curr_rom.is_hoenn() ? 0x10 : 0x18
#define MOVEMENT_ACTION_DELAY_2 curr_rom.is_hoenn() ? 0x11 : 0x19
#define MOVEMENT_ACTION_DELAY_4 curr_rom.is_hoenn() ? 0x12 : 0x1A
#define MOVEMENT_ACTION_DELAY_8 curr_rom.is_hoenn() ? 0x13 : 0x1B
#define MOVEMENT_ACTION_DELAY_16 curr_rom.is_hoenn() ? 0x14 : 0x1C
#define MOVEMENT_ACTION_WALK_FAST_DOWN curr_rom.is_hoenn() ? 0x15 : 0x1D
#define MOVEMENT_ACTION_WALK_FAST_UP curr_rom.is_hoenn() ? 0x16 : 0x1E
#define MOVEMENT_ACTION_WALK_FAST_LEFT curr_rom.is_hoenn() ? 0x17 : 0x1F
#define MOVEMENT_ACTION_WALK_FAST_RIGHT curr_rom.is_hoenn() ? 0x18 : 0x20
#define MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_DOWN curr_rom.is_hoenn() ? 0x19 : 0x21
#define MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_UP curr_rom.is_hoenn() ? 0x1A : 0x22
#define MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_LEFT curr_rom.is_hoenn() ? 0x1B : 0x23
#define MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_RIGHT curr_rom.is_hoenn() ? 0x1C : 0x24
#define MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_DOWN curr_rom.is_hoenn() ? 0x1D : 0x25
#define MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_UP curr_rom.is_hoenn() ? 0x1E : 0x26
#define MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_LEFT curr_rom.is_hoenn() ? 0x1F : 0x27
#define MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_RIGHT curr_rom.is_hoenn() ? 0x20 : 0x28
#define MOVEMENT_ACTION_WALK_IN_PLACE_FAST_DOWN curr_rom.is_hoenn() ? 0x21 : 0x29
#define MOVEMENT_ACTION_WALK_IN_PLACE_FAST_UP curr_rom.is_hoenn() ? 0x22 : 0x2A
#define MOVEMENT_ACTION_WALK_IN_PLACE_FAST_LEFT curr_rom.is_hoenn() ? 0x23 : 0x2B
#define MOVEMENT_ACTION_WALK_IN_PLACE_FAST_RIGHT curr_rom.is_hoenn() ? 0x24 : 0x2C
#define MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_DOWN curr_rom.is_hoenn() ? 0x25 : 0x2D
#define MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_UP curr_rom.is_hoenn() ? 0x26 : 0x2E
#define MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_LEFT curr_rom.is_hoenn() ? 0x27 : 0x2F
#define MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_RIGHT curr_rom.is_hoenn() ? 0x28 : 0x30
#define MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN curr_rom.is_hoenn() ? 0x29 : 0x31
#define MOVEMENT_ACTION_RIDE_WATER_CURRENT_UP curr_rom.is_hoenn() ? 0x2A : 0x32
#define MOVEMENT_ACTION_RIDE_WATER_CURRENT_LEFT curr_rom.is_hoenn() ? 0x2B : 0x33
#define MOVEMENT_ACTION_RIDE_WATER_CURRENT_RIGHT curr_rom.is_hoenn() ? 0x2C : 0x34
#define MOVEMENT_ACTION_WALK_FASTER_DOWN curr_rom.is_hoenn() ? 0x2D : 0x35
#define MOVEMENT_ACTION_WALK_FASTER_UP curr_rom.is_hoenn() ? 0x2E : 0x36
#define MOVEMENT_ACTION_WALK_FASTER_LEFT curr_rom.is_hoenn() ? 0x2F : 0x37
#define MOVEMENT_ACTION_WALK_FASTER_RIGHT curr_rom.is_hoenn() ? 0x30 : 0x38
#define MOVEMENT_ACTION_SLIDE_DOWN curr_rom.is_hoenn() ? 0x31 : 0x39
#define MOVEMENT_ACTION_SLIDE_UP curr_rom.is_hoenn() ? 0x32 : 0x3A
#define MOVEMENT_ACTION_SLIDE_LEFT curr_rom.is_hoenn() ? 0x33 : 0x3B
#define MOVEMENT_ACTION_SLIDE_RIGHT curr_rom.is_hoenn() ? 0x34 : 0x3C
#define MOVEMENT_ACTION_PLAYER_RUN_DOWN curr_rom.is_hoenn() ? 0x35 : 0x3D
#define MOVEMENT_ACTION_PLAYER_RUN_UP curr_rom.is_hoenn() ? 0x36 : 0x3E
#define MOVEMENT_ACTION_PLAYER_RUN_LEFT curr_rom.is_hoenn() ? 0x37 : 0x3F
#define MOVEMENT_ACTION_PLAYER_RUN_RIGHT curr_rom.is_hoenn() ? 0x38 : 0x40
#define MOVEMENT_ACTION_START_ANIM_IN_DIRECTION curr_rom.is_hoenn() ? 0x39 : 0x45
#define MOVEMENT_ACTION_JUMP_SPECIAL_DOWN curr_rom.is_hoenn() ? 0x3A : 0x46
#define MOVEMENT_ACTION_JUMP_SPECIAL_UP curr_rom.is_hoenn() ? 0x3B : 0x47
#define MOVEMENT_ACTION_JUMP_SPECIAL_LEFT curr_rom.is_hoenn() ? 0x3C : 0x48
#define MOVEMENT_ACTION_JUMP_SPECIAL_RIGHT curr_rom.is_hoenn() ? 0x3D : 0x49
#define MOVEMENT_ACTION_FACE_PLAYER curr_rom.is_hoenn() ? 0x3E : 0x4A
#define MOVEMENT_ACTION_FACE_AWAY_PLAYER curr_rom.is_hoenn() ? 0x3F : 0x4B
#define MOVEMENT_ACTION_LOCK_FACING_DIRECTION curr_rom.is_hoenn() ? 0x40 : 0x4C
#define MOVEMENT_ACTION_UNLOCK_FACING_DIRECTION curr_rom.is_hoenn() ? 0x41 : 0x4D
#define MOVEMENT_ACTION_JUMP_DOWN curr_rom.is_hoenn() ? 0x42 : 0x4E
#define MOVEMENT_ACTION_JUMP_UP curr_rom.is_hoenn() ? 0x43 : 0x4F
#define MOVEMENT_ACTION_JUMP_LEFT curr_rom.is_hoenn() ? 0x44 : 0x50
#define MOVEMENT_ACTION_JUMP_RIGHT curr_rom.is_hoenn() ? 0x45 : 0x51
#define MOVEMENT_ACTION_JUMP_IN_PLACE_DOWN curr_rom.is_hoenn() ? 0x46 : 0x52
#define MOVEMENT_ACTION_JUMP_IN_PLACE_UP curr_rom.is_hoenn() ? 0x47 : 0x53
#define MOVEMENT_ACTION_JUMP_IN_PLACE_LEFT curr_rom.is_hoenn() ? 0x48 : 0x54
#define MOVEMENT_ACTION_JUMP_IN_PLACE_RIGHT curr_rom.is_hoenn() ? 0x49 : 0x55
#define MOVEMENT_ACTION_JUMP_IN_PLACE_DOWN_UP curr_rom.is_hoenn() ? 0x4A : 0x56
#define MOVEMENT_ACTION_JUMP_IN_PLACE_UP_DOWN curr_rom.is_hoenn() ? 0x4B : 0x57
#define MOVEMENT_ACTION_JUMP_IN_PLACE_LEFT_RIGHT curr_rom.is_hoenn() ? 0x4C : 0x58
#define MOVEMENT_ACTION_JUMP_IN_PLACE_RIGHT_LEFT curr_rom.is_hoenn() ? 0x4D : 0x59
#define MOVEMENT_ACTION_FACE_ORIGINAL_DIRECTION curr_rom.is_hoenn() ? 0x4E : 0x5A
#define MOVEMENT_ACTION_NURSE_JOY_BOW_DOWN curr_rom.is_hoenn() ? 0x4F : 0x5B
#define MOVEMENT_ACTION_ENABLE_JUMP_LANDING_GROUND_EFFECT curr_rom.is_hoenn() ? 0x50 : 0x5C
#define MOVEMENT_ACTION_DISABLE_JUMP_LANDING_GROUND_EFFECT curr_rom.is_hoenn() ? 0x51 : 0x5D
#define MOVEMENT_ACTION_DISABLE_ANIMATION curr_rom.is_hoenn() ? 0x52 : 0x5E
#define MOVEMENT_ACTION_RESTORE_ANIMATION curr_rom.is_hoenn() ? 0x53 : 0x5F
#define MOVEMENT_ACTION_SET_INVISIBLE curr_rom.is_hoenn() ? 0x54 : 0x60
#define MOVEMENT_ACTION_SET_VISIBLE curr_rom.is_hoenn() ? 0x55 : 0x61
#define MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK curr_rom.is_hoenn() ? 0x56 : 0x62
#define MOVEMENT_ACTION_EMOTE_QUESTION_MARK curr_rom.is_hoenn() ? 0x57 : 0x63
#define MOVEMENT_ACTION_EMOTE_HEART curr_rom.is_hoenn() ? 0x58 : 0xFF
#define MOVEMENT_ACTION_REVEAL_TRAINER curr_rom.is_hoenn() ? 0x59 : 0x67
#define MOVEMENT_ACTION_ROCK_SMASH_BREAK curr_rom.is_hoenn() ? 0x5A : 0x68
#define MOVEMENT_ACTION_CUT_TREE curr_rom.is_hoenn() ? 0x5B : 0x69
#define MOVEMENT_ACTION_SET_FIXED_PRIORITY curr_rom.is_hoenn() ? 0x5C : 0x6A
#define MOVEMENT_ACTION_CLEAR_FIXED_PRIORITY curr_rom.is_hoenn() ? 0x5D : 0x6B
#define MOVEMENT_ACTION_INIT_AFFINE_ANIM curr_rom.is_hoenn() ? 0x5E : 0x6C
#define MOVEMENT_ACTION_CLEAR_AFFINE_ANIM curr_rom.is_hoenn() ? 0x5F : 0x6D
#define MOVEMENT_ACTION_HIDE_REFLECTION curr_rom.is_hoenn() ? 0x60 : 0xFF
#define MOVEMENT_ACTION_SHOW_REFLECTION curr_rom.is_hoenn() ? 0x61 : 0xFF
#define MOVEMENT_ACTION_WALK_DOWN_START_AFFINE curr_rom.is_hoenn() ? 0x62 : 0x6E
#define MOVEMENT_ACTION_WALK_DOWN_AFFINE curr_rom.is_hoenn() ? 0x63 : 0x6F
#define MOVEMENT_ACTION_ACRO_WHEELIE_FACE_DOWN curr_rom.is_hoenn() ? 0x64 : 0x70
#define MOVEMENT_ACTION_ACRO_WHEELIE_FACE_UP curr_rom.is_hoenn() ? 0x65 : 0x71
#define MOVEMENT_ACTION_ACRO_WHEELIE_FACE_LEFT curr_rom.is_hoenn() ? 0x66 : 0x72
#define MOVEMENT_ACTION_ACRO_WHEELIE_FACE_RIGHT curr_rom.is_hoenn() ? 0x67 : 0x73
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_DOWN curr_rom.is_hoenn() ? 0x68 : 0x74
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_UP curr_rom.is_hoenn() ? 0x69 : 0x75
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_LEFT curr_rom.is_hoenn() ? 0x6A : 0x76
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_RIGHT curr_rom.is_hoenn() ? 0x6B : 0x77
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_DOWN curr_rom.is_hoenn() ? 0x6C : 0x78
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_UP curr_rom.is_hoenn() ? 0x6D : 0x79
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_LEFT curr_rom.is_hoenn() ? 0x6E : 0x7A
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_RIGHT curr_rom.is_hoenn() ? 0x6F : 0x7B
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_DOWN curr_rom.is_hoenn() ? 0x70 : 0x7C
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_UP curr_rom.is_hoenn() ? 0x71 : 0x7D
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_LEFT curr_rom.is_hoenn() ? 0x72 : 0x7E
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_RIGHT curr_rom.is_hoenn() ? 0x73 : 0x7F
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_DOWN curr_rom.is_hoenn() ? 0x74 : 0x80
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_UP curr_rom.is_hoenn() ? 0x75 : 0x81
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_LEFT curr_rom.is_hoenn() ? 0x76 : 0x82
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_RIGHT curr_rom.is_hoenn() ? 0x77 : 0x83
#define MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_DOWN curr_rom.is_hoenn() ? 0x78 : 0x84
#define MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_UP curr_rom.is_hoenn() ? 0x79 : 0x85
#define MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_LEFT curr_rom.is_hoenn() ? 0x7A : 0x86
#define MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_RIGHT curr_rom.is_hoenn() ? 0x7B : 0x87
#define MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_DOWN curr_rom.is_hoenn() ? 0x7C : 0x88
#define MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_UP curr_rom.is_hoenn() ? 0x7D : 0x89
#define MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_LEFT curr_rom.is_hoenn() ? 0x7E : 0x8A
#define MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_RIGHT curr_rom.is_hoenn() ? 0x7F : 0x8B
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_DOWN curr_rom.is_hoenn() ? 0x80 : 0x8C
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_UP curr_rom.is_hoenn() ? 0x81 : 0x8D
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_LEFT curr_rom.is_hoenn() ? 0x82 : 0x8E
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_RIGHT curr_rom.is_hoenn() ? 0x83 : 0x8F
#define MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_DOWN curr_rom.is_hoenn() ? 0x84 : 0x90
#define MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_UP curr_rom.is_hoenn() ? 0x85 : 0x91
#define MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_LEFT curr_rom.is_hoenn() ? 0x86 : 0x92
#define MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_RIGHT curr_rom.is_hoenn() ? 0x87 : 0x93
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_DOWN curr_rom.is_hoenn() ? 0x88 : 0xFF
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_UP curr_rom.is_hoenn() ? 0x89 : 0xFF
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_LEFT curr_rom.is_hoenn() ? 0x8A : 0xFF
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_RIGHT curr_rom.is_hoenn() ? 0x8B : 0xFF
#define MOVEMENT_ACTION_WALK_NORMAL_DIAGONAL_UP_LEFT curr_rom.is_hoenn() ? 0x8C : 0xFF
#define MOVEMENT_ACTION_WALK_NORMAL_DIAGONAL_UP_RIGHT curr_rom.is_hoenn() ? 0x8D : 0xFF
#define MOVEMENT_ACTION_WALK_NORMAL_DIAGONAL_DOWN_LEFT curr_rom.is_hoenn() ? 0x8E : 0xFF
#define MOVEMENT_ACTION_WALK_NORMAL_DIAGONAL_DOWN_RIGHT curr_rom.is_hoenn() ? 0x8F : 0xFF
#define MOVEMENT_ACTION_WALK_SLOW_DIAGONAL_UP_LEFT curr_rom.is_hoenn() ? 0x90 : 0xFF
#define MOVEMENT_ACTION_WALK_SLOW_DIAGONAL_UP_RIGHT curr_rom.is_hoenn() ? 0x91 : 0xFF
#define MOVEMENT_ACTION_WALK_SLOW_DIAGONAL_DOWN_LEFT curr_rom.is_hoenn() ? 0x92 : 0xFF
#define MOVEMENT_ACTION_WALK_SLOW_DIAGONAL_DOWN_RIGHT curr_rom.is_hoenn() ? 0x93 : 0xFF
#define MOVEMENT_ACTION_LOCK_ANIM curr_rom.is_hoenn() ? 0x94 : 0xFF
#define MOVEMENT_ACTION_UNLOCK_ANIM curr_rom.is_hoenn() ? 0x95 : 0xFF
#define MOVEMENT_ACTION_WALK_LEFT_AFFINE curr_rom.is_hoenn() ? 0x96 : 0xFF
#define MOVEMENT_ACTION_WALK_RIGHT_AFFINE curr_rom.is_hoenn() ? 0x97 : 0xFF
#define MOVEMENT_ACTION_LEVITATE curr_rom.is_hoenn() ? 0x98 : 0xFF
#define MOVEMENT_ACTION_STOP_LEVITATE curr_rom.is_hoenn() ? 0x99 : 0xFF
#define MOVEMENT_ACTION_STOP_LEVITATE_AT_TOP curr_rom.is_hoenn() ? 0x9A : 0xFF
#define MOVEMENT_ACTION_FIGURE_8 curr_rom.is_hoenn() ? 0x9B : 0xFF
#define MOVEMENT_ACTION_FLY_UP curr_rom.is_hoenn() ? 0x9C : 0xA4
#define MOVEMENT_ACTION_FLY_DOWN curr_rom.is_hoenn() ? 0x9D : 0xA5
#define MOVEMENT_ACTION_FACE_DOWN_FAST curr_rom.is_hoenn() ? 0xFF : 0x4
#define MOVEMENT_ACTION_FACE_UP_FAST curr_rom.is_hoenn() ? 0xFF : 0x5
#define MOVEMENT_ACTION_FACE_LEFT_FAST curr_rom.is_hoenn() ? 0xFF : 0x6
#define MOVEMENT_ACTION_FACE_RIGHT_FAST curr_rom.is_hoenn() ? 0xFF : 0x7
#define MOVEMENT_ACTION_WALK_SLOWER_DOWN curr_rom.is_hoenn() ? 0xFF : 0x8
#define MOVEMENT_ACTION_WALK_SLOWER_UP curr_rom.is_hoenn() ? 0xFF : 0x9
#define MOVEMENT_ACTION_WALK_SLOWER_LEFT curr_rom.is_hoenn() ? 0xFF : 0xA
#define MOVEMENT_ACTION_WALK_SLOWER_RIGHT curr_rom.is_hoenn() ? 0xFF : 0xB
#define MOVEMENT_ACTION_PLAYER_RUN_DOWN_SLOW curr_rom.is_hoenn() ? 0xFF : 0x41
#define MOVEMENT_ACTION_PLAYER_RUN_UP_SLOW curr_rom.is_hoenn() ? 0xFF : 0x42
#define MOVEMENT_ACTION_PLAYER_RUN_LEFT_SLOW curr_rom.is_hoenn() ? 0xFF : 0x43
#define MOVEMENT_ACTION_PLAYER_RUN_RIGHT_SLOW curr_rom.is_hoenn() ? 0xFF : 0x44
#define MOVEMENT_ACTION_EMOTE_X curr_rom.is_hoenn() ? 0xFF : 0x64
#define MOVEMENT_ACTION_EMOTE_DOUBLE_EXCL_MARK curr_rom.is_hoenn() ? 0xFF : 0x65
#define MOVEMENT_ACTION_EMOTE_SMILE curr_rom.is_hoenn() ? 0xFF : 0x66
#define MOVEMENT_ACTION_SPIN_DOWN curr_rom.is_hoenn() ? 0xFF : 0x94
#define MOVEMENT_ACTION_SPIN_UP curr_rom.is_hoenn() ? 0xFF : 0x95
#define MOVEMENT_ACTION_SPIN_LEFT curr_rom.is_hoenn() ? 0xFF : 0x96
#define MOVEMENT_ACTION_SPIN_RIGHT curr_rom.is_hoenn() ? 0xFF : 0x97
#define MOVEMENT_ACTION_RAISE_HAND_AND_STOP curr_rom.is_hoenn() ? 0xFF : 0x98
#define MOVEMENT_ACTION_RAISE_HAND_AND_JUMP curr_rom.is_hoenn() ? 0xFF : 0x99
#define MOVEMENT_ACTION_RAISE_HAND_AND_SWIM curr_rom.is_hoenn() ? 0xFF : 0x9A
#define MOVEMENT_ACTION_WALK_SLOWEST_DOWN curr_rom.is_hoenn() ? 0xFF : 0x9B
#define MOVEMENT_ACTION_WALK_SLOWEST_UP curr_rom.is_hoenn() ? 0xFF : 0x9C
#define MOVEMENT_ACTION_WALK_SLOWEST_LEFT curr_rom.is_hoenn() ? 0xFF : 0x9D
#define MOVEMENT_ACTION_WALK_SLOWEST_RIGHT curr_rom.is_hoenn() ? 0xFF : 0x9E
#define MOVEMENT_ACTION_SHAKE_HEAD_OR_WALK_IN_PLACE curr_rom.is_hoenn() ? 0xFF : 0x9F
#define MOVEMENT_ACTION_GLIDE_DOWN curr_rom.is_hoenn() ? 0xFF : 0xA0
#define MOVEMENT_ACTION_GLIDE_UP curr_rom.is_hoenn() ? 0xFF : 0xA1
#define MOVEMENT_ACTION_GLIDE_LEFT curr_rom.is_hoenn() ? 0xFF : 0xA2
#define MOVEMENT_ACTION_GLIDE_RIGHT curr_rom.is_hoenn() ? 0xFF : 0xA3
#define MOVEMENT_ACTION_JUMP_SPECIAL_WITH_EFFECT_DOWN curr_rom.is_hoenn() ? 0xFF : 0xA6
#define MOVEMENT_ACTION_JUMP_SPECIAL_WITH_EFFECT_UP curr_rom.is_hoenn() ? 0xFF : 0xA7
#define MOVEMENT_ACTION_JUMP_SPECIAL_WITH_EFFECT_LEFT curr_rom.is_hoenn() ? 0xFF : 0xA8
#define MOVEMENT_ACTION_JUMP_SPECIAL_WITH_EFFECT_RIGHT curr_rom.is_hoenn() ? 0xFF : 0xA9
#define MOVEMENT_ACTION_FACE_DOWN curr_GBA_rom.is_hoenn() ? 0x0 : 0x0
#define MOVEMENT_ACTION_FACE_UP curr_GBA_rom.is_hoenn() ? 0x1 : 0x1
#define MOVEMENT_ACTION_FACE_LEFT curr_GBA_rom.is_hoenn() ? 0x2 : 0x2
#define MOVEMENT_ACTION_FACE_RIGHT curr_GBA_rom.is_hoenn() ? 0x3 : 0x3
#define MOVEMENT_ACTION_WALK_SLOW_DOWN curr_GBA_rom.is_hoenn() ? 0x4 : 0xC
#define MOVEMENT_ACTION_WALK_SLOW_UP curr_GBA_rom.is_hoenn() ? 0x5 : 0xD
#define MOVEMENT_ACTION_WALK_SLOW_LEFT curr_GBA_rom.is_hoenn() ? 0x6 : 0xE
#define MOVEMENT_ACTION_WALK_SLOW_RIGHT curr_GBA_rom.is_hoenn() ? 0x7 : 0xF
#define MOVEMENT_ACTION_WALK_NORMAL_DOWN curr_GBA_rom.is_hoenn() ? 0x8 : 0x10
#define MOVEMENT_ACTION_WALK_NORMAL_UP curr_GBA_rom.is_hoenn() ? 0x9 : 0x11
#define MOVEMENT_ACTION_WALK_NORMAL_LEFT curr_GBA_rom.is_hoenn() ? 0xA : 0x12
#define MOVEMENT_ACTION_WALK_NORMAL_RIGHT curr_GBA_rom.is_hoenn() ? 0xB : 0x13
#define MOVEMENT_ACTION_JUMP_2_DOWN curr_GBA_rom.is_hoenn() ? 0xC : 0x14
#define MOVEMENT_ACTION_JUMP_2_UP curr_GBA_rom.is_hoenn() ? 0xD : 0x15
#define MOVEMENT_ACTION_JUMP_2_LEFT curr_GBA_rom.is_hoenn() ? 0xE : 0x16
#define MOVEMENT_ACTION_JUMP_2_RIGHT curr_GBA_rom.is_hoenn() ? 0xF : 0x17
#define MOVEMENT_ACTION_DELAY_1 curr_GBA_rom.is_hoenn() ? 0x10 : 0x18
#define MOVEMENT_ACTION_DELAY_2 curr_GBA_rom.is_hoenn() ? 0x11 : 0x19
#define MOVEMENT_ACTION_DELAY_4 curr_GBA_rom.is_hoenn() ? 0x12 : 0x1A
#define MOVEMENT_ACTION_DELAY_8 curr_GBA_rom.is_hoenn() ? 0x13 : 0x1B
#define MOVEMENT_ACTION_DELAY_16 curr_GBA_rom.is_hoenn() ? 0x14 : 0x1C
#define MOVEMENT_ACTION_WALK_FAST_DOWN curr_GBA_rom.is_hoenn() ? 0x15 : 0x1D
#define MOVEMENT_ACTION_WALK_FAST_UP curr_GBA_rom.is_hoenn() ? 0x16 : 0x1E
#define MOVEMENT_ACTION_WALK_FAST_LEFT curr_GBA_rom.is_hoenn() ? 0x17 : 0x1F
#define MOVEMENT_ACTION_WALK_FAST_RIGHT curr_GBA_rom.is_hoenn() ? 0x18 : 0x20
#define MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_DOWN curr_GBA_rom.is_hoenn() ? 0x19 : 0x21
#define MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_UP curr_GBA_rom.is_hoenn() ? 0x1A : 0x22
#define MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_LEFT curr_GBA_rom.is_hoenn() ? 0x1B : 0x23
#define MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_RIGHT curr_GBA_rom.is_hoenn() ? 0x1C : 0x24
#define MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_DOWN curr_GBA_rom.is_hoenn() ? 0x1D : 0x25
#define MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_UP curr_GBA_rom.is_hoenn() ? 0x1E : 0x26
#define MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_LEFT curr_GBA_rom.is_hoenn() ? 0x1F : 0x27
#define MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_RIGHT curr_GBA_rom.is_hoenn() ? 0x20 : 0x28
#define MOVEMENT_ACTION_WALK_IN_PLACE_FAST_DOWN curr_GBA_rom.is_hoenn() ? 0x21 : 0x29
#define MOVEMENT_ACTION_WALK_IN_PLACE_FAST_UP curr_GBA_rom.is_hoenn() ? 0x22 : 0x2A
#define MOVEMENT_ACTION_WALK_IN_PLACE_FAST_LEFT curr_GBA_rom.is_hoenn() ? 0x23 : 0x2B
#define MOVEMENT_ACTION_WALK_IN_PLACE_FAST_RIGHT curr_GBA_rom.is_hoenn() ? 0x24 : 0x2C
#define MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_DOWN curr_GBA_rom.is_hoenn() ? 0x25 : 0x2D
#define MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_UP curr_GBA_rom.is_hoenn() ? 0x26 : 0x2E
#define MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_LEFT curr_GBA_rom.is_hoenn() ? 0x27 : 0x2F
#define MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_RIGHT curr_GBA_rom.is_hoenn() ? 0x28 : 0x30
#define MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN curr_GBA_rom.is_hoenn() ? 0x29 : 0x31
#define MOVEMENT_ACTION_RIDE_WATER_CURRENT_UP curr_GBA_rom.is_hoenn() ? 0x2A : 0x32
#define MOVEMENT_ACTION_RIDE_WATER_CURRENT_LEFT curr_GBA_rom.is_hoenn() ? 0x2B : 0x33
#define MOVEMENT_ACTION_RIDE_WATER_CURRENT_RIGHT curr_GBA_rom.is_hoenn() ? 0x2C : 0x34
#define MOVEMENT_ACTION_WALK_FASTER_DOWN curr_GBA_rom.is_hoenn() ? 0x2D : 0x35
#define MOVEMENT_ACTION_WALK_FASTER_UP curr_GBA_rom.is_hoenn() ? 0x2E : 0x36
#define MOVEMENT_ACTION_WALK_FASTER_LEFT curr_GBA_rom.is_hoenn() ? 0x2F : 0x37
#define MOVEMENT_ACTION_WALK_FASTER_RIGHT curr_GBA_rom.is_hoenn() ? 0x30 : 0x38
#define MOVEMENT_ACTION_SLIDE_DOWN curr_GBA_rom.is_hoenn() ? 0x31 : 0x39
#define MOVEMENT_ACTION_SLIDE_UP curr_GBA_rom.is_hoenn() ? 0x32 : 0x3A
#define MOVEMENT_ACTION_SLIDE_LEFT curr_GBA_rom.is_hoenn() ? 0x33 : 0x3B
#define MOVEMENT_ACTION_SLIDE_RIGHT curr_GBA_rom.is_hoenn() ? 0x34 : 0x3C
#define MOVEMENT_ACTION_PLAYER_RUN_DOWN curr_GBA_rom.is_hoenn() ? 0x35 : 0x3D
#define MOVEMENT_ACTION_PLAYER_RUN_UP curr_GBA_rom.is_hoenn() ? 0x36 : 0x3E
#define MOVEMENT_ACTION_PLAYER_RUN_LEFT curr_GBA_rom.is_hoenn() ? 0x37 : 0x3F
#define MOVEMENT_ACTION_PLAYER_RUN_RIGHT curr_GBA_rom.is_hoenn() ? 0x38 : 0x40
#define MOVEMENT_ACTION_START_ANIM_IN_DIRECTION curr_GBA_rom.is_hoenn() ? 0x39 : 0x45
#define MOVEMENT_ACTION_JUMP_SPECIAL_DOWN curr_GBA_rom.is_hoenn() ? 0x3A : 0x46
#define MOVEMENT_ACTION_JUMP_SPECIAL_UP curr_GBA_rom.is_hoenn() ? 0x3B : 0x47
#define MOVEMENT_ACTION_JUMP_SPECIAL_LEFT curr_GBA_rom.is_hoenn() ? 0x3C : 0x48
#define MOVEMENT_ACTION_JUMP_SPECIAL_RIGHT curr_GBA_rom.is_hoenn() ? 0x3D : 0x49
#define MOVEMENT_ACTION_FACE_PLAYER curr_GBA_rom.is_hoenn() ? 0x3E : 0x4A
#define MOVEMENT_ACTION_FACE_AWAY_PLAYER curr_GBA_rom.is_hoenn() ? 0x3F : 0x4B
#define MOVEMENT_ACTION_LOCK_FACING_DIRECTION curr_GBA_rom.is_hoenn() ? 0x40 : 0x4C
#define MOVEMENT_ACTION_UNLOCK_FACING_DIRECTION curr_GBA_rom.is_hoenn() ? 0x41 : 0x4D
#define MOVEMENT_ACTION_JUMP_DOWN curr_GBA_rom.is_hoenn() ? 0x42 : 0x4E
#define MOVEMENT_ACTION_JUMP_UP curr_GBA_rom.is_hoenn() ? 0x43 : 0x4F
#define MOVEMENT_ACTION_JUMP_LEFT curr_GBA_rom.is_hoenn() ? 0x44 : 0x50
#define MOVEMENT_ACTION_JUMP_RIGHT curr_GBA_rom.is_hoenn() ? 0x45 : 0x51
#define MOVEMENT_ACTION_JUMP_IN_PLACE_DOWN curr_GBA_rom.is_hoenn() ? 0x46 : 0x52
#define MOVEMENT_ACTION_JUMP_IN_PLACE_UP curr_GBA_rom.is_hoenn() ? 0x47 : 0x53
#define MOVEMENT_ACTION_JUMP_IN_PLACE_LEFT curr_GBA_rom.is_hoenn() ? 0x48 : 0x54
#define MOVEMENT_ACTION_JUMP_IN_PLACE_RIGHT curr_GBA_rom.is_hoenn() ? 0x49 : 0x55
#define MOVEMENT_ACTION_JUMP_IN_PLACE_DOWN_UP curr_GBA_rom.is_hoenn() ? 0x4A : 0x56
#define MOVEMENT_ACTION_JUMP_IN_PLACE_UP_DOWN curr_GBA_rom.is_hoenn() ? 0x4B : 0x57
#define MOVEMENT_ACTION_JUMP_IN_PLACE_LEFT_RIGHT curr_GBA_rom.is_hoenn() ? 0x4C : 0x58
#define MOVEMENT_ACTION_JUMP_IN_PLACE_RIGHT_LEFT curr_GBA_rom.is_hoenn() ? 0x4D : 0x59
#define MOVEMENT_ACTION_FACE_ORIGINAL_DIRECTION curr_GBA_rom.is_hoenn() ? 0x4E : 0x5A
#define MOVEMENT_ACTION_NURSE_JOY_BOW_DOWN curr_GBA_rom.is_hoenn() ? 0x4F : 0x5B
#define MOVEMENT_ACTION_ENABLE_JUMP_LANDING_GROUND_EFFECT curr_GBA_rom.is_hoenn() ? 0x50 : 0x5C
#define MOVEMENT_ACTION_DISABLE_JUMP_LANDING_GROUND_EFFECT curr_GBA_rom.is_hoenn() ? 0x51 : 0x5D
#define MOVEMENT_ACTION_DISABLE_ANIMATION curr_GBA_rom.is_hoenn() ? 0x52 : 0x5E
#define MOVEMENT_ACTION_RESTORE_ANIMATION curr_GBA_rom.is_hoenn() ? 0x53 : 0x5F
#define MOVEMENT_ACTION_SET_INVISIBLE curr_GBA_rom.is_hoenn() ? 0x54 : 0x60
#define MOVEMENT_ACTION_SET_VISIBLE curr_GBA_rom.is_hoenn() ? 0x55 : 0x61
#define MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK curr_GBA_rom.is_hoenn() ? 0x56 : 0x62
#define MOVEMENT_ACTION_EMOTE_QUESTION_MARK curr_GBA_rom.is_hoenn() ? 0x57 : 0x63
#define MOVEMENT_ACTION_EMOTE_HEART curr_GBA_rom.is_hoenn() ? 0x58 : 0xFF
#define MOVEMENT_ACTION_REVEAL_TRAINER curr_GBA_rom.is_hoenn() ? 0x59 : 0x67
#define MOVEMENT_ACTION_ROCK_SMASH_BREAK curr_GBA_rom.is_hoenn() ? 0x5A : 0x68
#define MOVEMENT_ACTION_CUT_TREE curr_GBA_rom.is_hoenn() ? 0x5B : 0x69
#define MOVEMENT_ACTION_SET_FIXED_PRIORITY curr_GBA_rom.is_hoenn() ? 0x5C : 0x6A
#define MOVEMENT_ACTION_CLEAR_FIXED_PRIORITY curr_GBA_rom.is_hoenn() ? 0x5D : 0x6B
#define MOVEMENT_ACTION_INIT_AFFINE_ANIM curr_GBA_rom.is_hoenn() ? 0x5E : 0x6C
#define MOVEMENT_ACTION_CLEAR_AFFINE_ANIM curr_GBA_rom.is_hoenn() ? 0x5F : 0x6D
#define MOVEMENT_ACTION_HIDE_REFLECTION curr_GBA_rom.is_hoenn() ? 0x60 : 0xFF
#define MOVEMENT_ACTION_SHOW_REFLECTION curr_GBA_rom.is_hoenn() ? 0x61 : 0xFF
#define MOVEMENT_ACTION_WALK_DOWN_START_AFFINE curr_GBA_rom.is_hoenn() ? 0x62 : 0x6E
#define MOVEMENT_ACTION_WALK_DOWN_AFFINE curr_GBA_rom.is_hoenn() ? 0x63 : 0x6F
#define MOVEMENT_ACTION_ACRO_WHEELIE_FACE_DOWN curr_GBA_rom.is_hoenn() ? 0x64 : 0x70
#define MOVEMENT_ACTION_ACRO_WHEELIE_FACE_UP curr_GBA_rom.is_hoenn() ? 0x65 : 0x71
#define MOVEMENT_ACTION_ACRO_WHEELIE_FACE_LEFT curr_GBA_rom.is_hoenn() ? 0x66 : 0x72
#define MOVEMENT_ACTION_ACRO_WHEELIE_FACE_RIGHT curr_GBA_rom.is_hoenn() ? 0x67 : 0x73
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_DOWN curr_GBA_rom.is_hoenn() ? 0x68 : 0x74
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_UP curr_GBA_rom.is_hoenn() ? 0x69 : 0x75
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_LEFT curr_GBA_rom.is_hoenn() ? 0x6A : 0x76
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_RIGHT curr_GBA_rom.is_hoenn() ? 0x6B : 0x77
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_DOWN curr_GBA_rom.is_hoenn() ? 0x6C : 0x78
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_UP curr_GBA_rom.is_hoenn() ? 0x6D : 0x79
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_LEFT curr_GBA_rom.is_hoenn() ? 0x6E : 0x7A
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_RIGHT curr_GBA_rom.is_hoenn() ? 0x6F : 0x7B
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_DOWN curr_GBA_rom.is_hoenn() ? 0x70 : 0x7C
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_UP curr_GBA_rom.is_hoenn() ? 0x71 : 0x7D
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_LEFT curr_GBA_rom.is_hoenn() ? 0x72 : 0x7E
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_RIGHT curr_GBA_rom.is_hoenn() ? 0x73 : 0x7F
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_DOWN curr_GBA_rom.is_hoenn() ? 0x74 : 0x80
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_UP curr_GBA_rom.is_hoenn() ? 0x75 : 0x81
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_LEFT curr_GBA_rom.is_hoenn() ? 0x76 : 0x82
#define MOVEMENT_ACTION_ACRO_WHEELIE_HOP_RIGHT curr_GBA_rom.is_hoenn() ? 0x77 : 0x83
#define MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_DOWN curr_GBA_rom.is_hoenn() ? 0x78 : 0x84
#define MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_UP curr_GBA_rom.is_hoenn() ? 0x79 : 0x85
#define MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_LEFT curr_GBA_rom.is_hoenn() ? 0x7A : 0x86
#define MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_RIGHT curr_GBA_rom.is_hoenn() ? 0x7B : 0x87
#define MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_DOWN curr_GBA_rom.is_hoenn() ? 0x7C : 0x88
#define MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_UP curr_GBA_rom.is_hoenn() ? 0x7D : 0x89
#define MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_LEFT curr_GBA_rom.is_hoenn() ? 0x7E : 0x8A
#define MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_RIGHT curr_GBA_rom.is_hoenn() ? 0x7F : 0x8B
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_DOWN curr_GBA_rom.is_hoenn() ? 0x80 : 0x8C
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_UP curr_GBA_rom.is_hoenn() ? 0x81 : 0x8D
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_LEFT curr_GBA_rom.is_hoenn() ? 0x82 : 0x8E
#define MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_RIGHT curr_GBA_rom.is_hoenn() ? 0x83 : 0x8F
#define MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_DOWN curr_GBA_rom.is_hoenn() ? 0x84 : 0x90
#define MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_UP curr_GBA_rom.is_hoenn() ? 0x85 : 0x91
#define MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_LEFT curr_GBA_rom.is_hoenn() ? 0x86 : 0x92
#define MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_RIGHT curr_GBA_rom.is_hoenn() ? 0x87 : 0x93
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_DOWN curr_GBA_rom.is_hoenn() ? 0x88 : 0xFF
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_UP curr_GBA_rom.is_hoenn() ? 0x89 : 0xFF
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_LEFT curr_GBA_rom.is_hoenn() ? 0x8A : 0xFF
#define MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_RIGHT curr_GBA_rom.is_hoenn() ? 0x8B : 0xFF
#define MOVEMENT_ACTION_WALK_NORMAL_DIAGONAL_UP_LEFT curr_GBA_rom.is_hoenn() ? 0x8C : 0xFF
#define MOVEMENT_ACTION_WALK_NORMAL_DIAGONAL_UP_RIGHT curr_GBA_rom.is_hoenn() ? 0x8D : 0xFF
#define MOVEMENT_ACTION_WALK_NORMAL_DIAGONAL_DOWN_LEFT curr_GBA_rom.is_hoenn() ? 0x8E : 0xFF
#define MOVEMENT_ACTION_WALK_NORMAL_DIAGONAL_DOWN_RIGHT curr_GBA_rom.is_hoenn() ? 0x8F : 0xFF
#define MOVEMENT_ACTION_WALK_SLOW_DIAGONAL_UP_LEFT curr_GBA_rom.is_hoenn() ? 0x90 : 0xFF
#define MOVEMENT_ACTION_WALK_SLOW_DIAGONAL_UP_RIGHT curr_GBA_rom.is_hoenn() ? 0x91 : 0xFF
#define MOVEMENT_ACTION_WALK_SLOW_DIAGONAL_DOWN_LEFT curr_GBA_rom.is_hoenn() ? 0x92 : 0xFF
#define MOVEMENT_ACTION_WALK_SLOW_DIAGONAL_DOWN_RIGHT curr_GBA_rom.is_hoenn() ? 0x93 : 0xFF
#define MOVEMENT_ACTION_LOCK_ANIM curr_GBA_rom.is_hoenn() ? 0x94 : 0xFF
#define MOVEMENT_ACTION_UNLOCK_ANIM curr_GBA_rom.is_hoenn() ? 0x95 : 0xFF
#define MOVEMENT_ACTION_WALK_LEFT_AFFINE curr_GBA_rom.is_hoenn() ? 0x96 : 0xFF
#define MOVEMENT_ACTION_WALK_RIGHT_AFFINE curr_GBA_rom.is_hoenn() ? 0x97 : 0xFF
#define MOVEMENT_ACTION_LEVITATE curr_GBA_rom.is_hoenn() ? 0x98 : 0xFF
#define MOVEMENT_ACTION_STOP_LEVITATE curr_GBA_rom.is_hoenn() ? 0x99 : 0xFF
#define MOVEMENT_ACTION_STOP_LEVITATE_AT_TOP curr_GBA_rom.is_hoenn() ? 0x9A : 0xFF
#define MOVEMENT_ACTION_FIGURE_8 curr_GBA_rom.is_hoenn() ? 0x9B : 0xFF
#define MOVEMENT_ACTION_FLY_UP curr_GBA_rom.is_hoenn() ? 0x9C : 0xA4
#define MOVEMENT_ACTION_FLY_DOWN curr_GBA_rom.is_hoenn() ? 0x9D : 0xA5
#define MOVEMENT_ACTION_FACE_DOWN_FAST curr_GBA_rom.is_hoenn() ? 0xFF : 0x4
#define MOVEMENT_ACTION_FACE_UP_FAST curr_GBA_rom.is_hoenn() ? 0xFF : 0x5
#define MOVEMENT_ACTION_FACE_LEFT_FAST curr_GBA_rom.is_hoenn() ? 0xFF : 0x6
#define MOVEMENT_ACTION_FACE_RIGHT_FAST curr_GBA_rom.is_hoenn() ? 0xFF : 0x7
#define MOVEMENT_ACTION_WALK_SLOWER_DOWN curr_GBA_rom.is_hoenn() ? 0xFF : 0x8
#define MOVEMENT_ACTION_WALK_SLOWER_UP curr_GBA_rom.is_hoenn() ? 0xFF : 0x9
#define MOVEMENT_ACTION_WALK_SLOWER_LEFT curr_GBA_rom.is_hoenn() ? 0xFF : 0xA
#define MOVEMENT_ACTION_WALK_SLOWER_RIGHT curr_GBA_rom.is_hoenn() ? 0xFF : 0xB
#define MOVEMENT_ACTION_PLAYER_RUN_DOWN_SLOW curr_GBA_rom.is_hoenn() ? 0xFF : 0x41
#define MOVEMENT_ACTION_PLAYER_RUN_UP_SLOW curr_GBA_rom.is_hoenn() ? 0xFF : 0x42
#define MOVEMENT_ACTION_PLAYER_RUN_LEFT_SLOW curr_GBA_rom.is_hoenn() ? 0xFF : 0x43
#define MOVEMENT_ACTION_PLAYER_RUN_RIGHT_SLOW curr_GBA_rom.is_hoenn() ? 0xFF : 0x44
#define MOVEMENT_ACTION_EMOTE_X curr_GBA_rom.is_hoenn() ? 0xFF : 0x64
#define MOVEMENT_ACTION_EMOTE_DOUBLE_EXCL_MARK curr_GBA_rom.is_hoenn() ? 0xFF : 0x65
#define MOVEMENT_ACTION_EMOTE_SMILE curr_GBA_rom.is_hoenn() ? 0xFF : 0x66
#define MOVEMENT_ACTION_SPIN_DOWN curr_GBA_rom.is_hoenn() ? 0xFF : 0x94
#define MOVEMENT_ACTION_SPIN_UP curr_GBA_rom.is_hoenn() ? 0xFF : 0x95
#define MOVEMENT_ACTION_SPIN_LEFT curr_GBA_rom.is_hoenn() ? 0xFF : 0x96
#define MOVEMENT_ACTION_SPIN_RIGHT curr_GBA_rom.is_hoenn() ? 0xFF : 0x97
#define MOVEMENT_ACTION_RAISE_HAND_AND_STOP curr_GBA_rom.is_hoenn() ? 0xFF : 0x98
#define MOVEMENT_ACTION_RAISE_HAND_AND_JUMP curr_GBA_rom.is_hoenn() ? 0xFF : 0x99
#define MOVEMENT_ACTION_RAISE_HAND_AND_SWIM curr_GBA_rom.is_hoenn() ? 0xFF : 0x9A
#define MOVEMENT_ACTION_WALK_SLOWEST_DOWN curr_GBA_rom.is_hoenn() ? 0xFF : 0x9B
#define MOVEMENT_ACTION_WALK_SLOWEST_UP curr_GBA_rom.is_hoenn() ? 0xFF : 0x9C
#define MOVEMENT_ACTION_WALK_SLOWEST_LEFT curr_GBA_rom.is_hoenn() ? 0xFF : 0x9D
#define MOVEMENT_ACTION_WALK_SLOWEST_RIGHT curr_GBA_rom.is_hoenn() ? 0xFF : 0x9E
#define MOVEMENT_ACTION_SHAKE_HEAD_OR_WALK_IN_PLACE curr_GBA_rom.is_hoenn() ? 0xFF : 0x9F
#define MOVEMENT_ACTION_GLIDE_DOWN curr_GBA_rom.is_hoenn() ? 0xFF : 0xA0
#define MOVEMENT_ACTION_GLIDE_UP curr_GBA_rom.is_hoenn() ? 0xFF : 0xA1
#define MOVEMENT_ACTION_GLIDE_LEFT curr_GBA_rom.is_hoenn() ? 0xFF : 0xA2
#define MOVEMENT_ACTION_GLIDE_RIGHT curr_GBA_rom.is_hoenn() ? 0xFF : 0xA3
#define MOVEMENT_ACTION_JUMP_SPECIAL_WITH_EFFECT_DOWN curr_GBA_rom.is_hoenn() ? 0xFF : 0xA6
#define MOVEMENT_ACTION_JUMP_SPECIAL_WITH_EFFECT_UP curr_GBA_rom.is_hoenn() ? 0xFF : 0xA7
#define MOVEMENT_ACTION_JUMP_SPECIAL_WITH_EFFECT_LEFT curr_GBA_rom.is_hoenn() ? 0xFF : 0xA8
#define MOVEMENT_ACTION_JUMP_SPECIAL_WITH_EFFECT_RIGHT curr_GBA_rom.is_hoenn() ? 0xFF : 0xA9
#define CPU_SET_16BIT 0x00000000
#define CPU_SET_32BIT 0x04000000
@ -272,7 +272,7 @@ public:
* You're in control!
*/
mystery_gift_script(u8 *save_section_30_buffer);
void build_script(Pokemon_Party &incoming_box_data);
void build_script(PokeBox *box);
//void build_script_old(Pokemon_Party &incoming_box_data);
const u8 *get_script() const;
const u8 * get_section30() const;

View File

@ -4,6 +4,6 @@
#include "pokemon_party.h"
#include "pokemon_data.h"
bool inject_mystery(Pokemon_Party &incoming_box_data);
bool inject_mystery(PokeBox* box);
#endif

152
include/pccs/GBPokemon.h Normal file
View File

@ -0,0 +1,152 @@
#ifndef GBPOKEMON_H
#define GBPOKEMON_H
#include "Pokemon.h"
#include "Gen3Pokemon.h"
class GBPokemon : public Pokemon // The class for gen 1 and 2 Pokemon, since they share some conversion functions
{
protected:
GBPokemon();
void updateValidity();
// These store the data bytes
byte nicknameArray[11];
byte OTArray[11];
byte externalIndexNumber;
Language lang = (Language)0;
static const DataVarInfo
// All of the data info variables
speciesIndexNumber[2],
level[2],
moveOne[2], moveTwo[2], moveThree[2], moveFour[2],
trainerID[2],
expPoints[2],
hpStatExp[2], atkStatExp[2], defStatExp[2], speStatExp[2], spcStatExp[2],
atkDV[2], defDV[2], speDV[2], spcDV[2],
ppUpNumMoveOne[2], ppUpNumMoveTwo[2], ppUpNumMoveThree[2], ppUpNumMoveFour[2],
ppNumTotalMoveOne[2], ppNumTotalMoveTwo[2], ppNumTotalMoveThree[2], ppNumTotalMoveFour[2];
static const DataVarInfo
// and the convenient arrays of some of the variable groups:
*moves[4],
*statExps[5],
*DVs[5],
*PPUpNums[4],
*PPUpTotals[4];
// This is used to easily print out a Pokemon, when using a standard C++ terminal
#if ON_GBA
#else
std::string parentPrint();
#endif
public:
virtual void loadData(Language nLang, byte nDataArray[], byte nNicknameArray[], byte nOTArray[], byte nExternalIndexNum);
// All of the simple getters and setters are defined here
u32 getLevel() { return getVar(level[generation - 1]); }
u32 getTrainerID() { return getVar(trainerID[generation - 1]); }
u32 getExpPoints() { return getVar(expPoints[generation - 1]); }
bool setLevel(byte newVal) { return setVar(level[generation - 1], newVal); }
bool setOriginalTrainerID(byte newVal) { return setVar(trainerID[generation - 1], newVal); }
bool setExpPoints(u32 newVal) { return setVar(expPoints[generation - 1], newVal); }
// The ones that access arrays are defined here:
u32 getMove(int moveIndex) { return getVar(moves[moveIndex][generation - 1]); }
u32 getStatExp(Stat currStat) { return getVar(statExps[currStat][generation - 1]); }
u32 getPPUpNum(int moveIndex) { return getVar(PPUpNums[moveIndex][generation - 1]); }
u32 getPPTotal(int moveIndex) { return getVar(PPUpTotals[moveIndex][generation - 1]); }
bool setMove(int moveIndex, byte newVal) { return setVar(moves[moveIndex][generation - 1], newVal); }
bool setStatExp(Stat currStat, byte newVal) { return setVar(statExps[currStat][generation - 1], newVal); }
bool setPPUpNum(int moveIndex, byte newVal) { return setVar(PPUpNums[moveIndex][generation - 1], newVal); }
bool setPPTotal(int moveIndex, byte newVal) { return setVar(PPUpTotals[moveIndex][generation - 1], newVal); }
// These are all replaced in the child classes, but give a default value or do nothing here
// ---- Gen 1
virtual u32 getSpeciesIndexNumber() { return getVar(*speciesIndexNumber); }
virtual u32 getCurrentHP() { return 0; }
virtual u32 getStatusCondition() { return 0; }
virtual u32 getCatchRate() { return 0; }
virtual u32 getType(int typeIndex) { return NORMAL; }
virtual bool setSpeciesIndexNumber(byte newVal) { return setVar(*speciesIndexNumber, newVal); }
virtual bool setCurrentHP(byte newVal) { return false; }
virtual bool setStatusCondition(byte newVal) { return false; }
virtual bool setCatchRate(byte newVal) { return false; }
virtual bool setType(int typeIndex, Gen1Types newVal) { return false; }
// ---- Gen 2
virtual u32 getHeldItem() { return 0; } // no item
virtual u32 getFriendship() { return 70; } // default friendship - make this different for Pikachu in Yellow???
virtual u32 getPokerusStrain() { return 0; }
virtual u32 getPokerusDaysRemaining() { return 0; }
virtual u32 getCaughtDataTime() { return 0; }
virtual u32 getCaughtDataLevel() { return 0; }
virtual u32 getCaughtDataGender() { return 0; }
virtual u32 getCaughtDataLocation() { return 0; }
virtual bool setHeldItem(byte newVal) { return false; } // This could *technically* be seen as setting the catch rate but...
virtual bool setFriendship(byte newVal) { return false; }
virtual bool setPokerusStrain(byte newVal) { return false; }
virtual bool setPokerusDaysRemaining(byte newVal) { return false; }
virtual bool setCaughtDataTime(byte newVal) { return false; }
virtual bool setCaughtDataLevel(byte newVal) { return false; }
virtual bool setCaughtDataGender(byte newVal) { return false; }
virtual bool setCaughtDataLocation(byte newVal) { return false; }
// These all have special implementations
u32 getDV(Stat currStat);
bool setDV(Stat currStat, byte newVal);
// These is virtual so it can be overwitten in Gen 1
// These aren't direct variables, but they're useful to have
Language getLanguage() { return lang; };
byte getUnownLetter();
Gender getGender();
Nature getVirtualConsoleNature();
bool getIsShiny();
bool externalConvertNickname(byte outputArray[]);
// And this is for all the conversion stuff
bool convertToGen3(Gen3Pokemon *newPkmn, bool sanitizeMythicals);
bool loadEvent(Gen3Pokemon *newPkmn);
bool generatePersonalityValue(Gen3Pokemon *newPkmn, RNGMethod rng);
bool convertTrainerID(Gen3Pokemon *newPkmn);
bool convertNickname(Gen3Pokemon *newPkmn);
bool convertLanguage(Gen3Pokemon *newPkmn);
bool convertMiscFlags(Gen3Pokemon *newPkmn);
bool convertTrainerNickname(Gen3Pokemon *newPkmn);
bool convertMarkings(Gen3Pokemon *newPkmn);
// Data
bool convertSpeciesIndexNumber(Gen3Pokemon *newPkmn);
bool convertItem(Gen3Pokemon *newPkmn);
bool convertEXP(Gen3Pokemon *newPkmn);
bool convertFriendship(Gen3Pokemon *newPkmn);
bool convertMoves(Gen3Pokemon *newPkmn);
bool convertEVs(Gen3Pokemon *newPkmn);
bool convertContestConditions(Gen3Pokemon *newPkmn);
bool convertPokerus(Gen3Pokemon *newPkmn);
bool convertMetLocation(Gen3Pokemon *newPkmn);
bool convertMetLevel(Gen3Pokemon *newPkmn);
bool convertGameOfOrigin(Gen3Pokemon *newPkmn);
bool convertPokeball(Gen3Pokemon *newPkmn);
bool convertTrainerGender(Gen3Pokemon *newPkmn);
bool convertIVs(Gen3Pokemon *newPkmn);
bool convertAbilityFlag(Gen3Pokemon *newPkmn);
bool convertRibbonsAndObedience(Gen3Pokemon *newPkmn);
bool convertShininess(Gen3Pokemon *newPkmn);
// Extra
bool setRequestedLetter(Gen3Pokemon *newPkmn);
bool setRequestedNature(Gen3Pokemon *newPkmn);
bool setRequestedGender(Gen3Pokemon *newPkmn);
bool setRequestedAbility(Gen3Pokemon *newPkmn);
bool setRequestedSize(Gen3Pokemon *newPkmn);
};
#endif

View File

@ -0,0 +1,39 @@
#ifndef GEN1POKEMON_H
#define GEN1POKEMON_H
#include "GBPokemon.h"
class Gen1Pokemon : public GBPokemon // The class for gen 1 Pokemon
{
public:
Gen1Pokemon(PokemonTables *table);
byte dataArray[33];
u32 getSpeciesIndexNumber();
u32 getCurrentHP() { return getVar(g1_currentHP); }
u32 getStatusCondition() { return getVar(g1_statusCondition); }
u32 getCatchRate() { return getVar(g1_catchRate); }
u32 getType(int typeIndex) { return getVar(*g1_types[typeIndex]); }
bool setSpeciesIndexNumber(byte newVal);
bool setCurrentHP(byte newVal) { return setVar(g1_currentHP, newVal); }
bool setStatusCondition(byte newVal) { return setVar(g1_statusCondition, newVal); }
bool setCatchRate(byte newVal) { return setVar(g1_catchRate, newVal); }
bool setType(int typeIndex, Gen1Types newVal) { return setVar(*g1_types[typeIndex], newVal); }
protected:
static const DataVarInfo
// Gen 1 specific data
g1_currentHP,
g1_statusCondition,
g1_typeOne, g1_typeTwo,
g1_catchRate,
*g1_types[2];
#if ON_GBA
#else
void print(std::ostream &os);
#endif
};
#endif

View File

@ -0,0 +1,47 @@
#ifndef GEN2POKEMON_H
#define GEN2POKEMON_H
#include "GBPokemon.h"
class Gen2Pokemon : public GBPokemon // The class for gen 2 Pokemon
{
public:
Gen2Pokemon(PokemonTables *table);
byte dataArray[32];
u32 getHeldItem() { return getVar(g2_heldItem); }
u32 getFriendship() { return getVar(g2_friendship); }
u32 getPokerusStrain() { return getVar(g2_pokerusStrain); }
u32 getPokerusDaysRemaining() { return getVar(g2_pokerusDaysRemaining); }
u32 getCaughtDataTime() { return getVar(g2_caughtDataTime); }
u32 getCaughtDataLevel() { return getVar(g2_caughtDataLevel); }
u32 getCaughtDataGender() { return getVar(g2_caughtDataGender); }
u32 getCaughtDataLocation() { return getVar(g2_caughtDataLocation); }
bool setHeldItem(byte newVal) { return setVar(g2_heldItem, newVal); }
bool setFriendship(byte newVal) { return setVar(g2_friendship, newVal); }
bool setPokerusStrain(byte newVal) { return setVar(g2_pokerusStrain, newVal); }
bool setPokerusDaysRemaining(byte newVal) { return setVar(g2_pokerusDaysRemaining, newVal); }
bool setCaughtDataTime(byte newVal) { return setVar(g2_caughtDataTime, newVal); }
bool setCaughtDataLevel(byte newVal) { return setVar(g2_caughtDataLevel, newVal); }
bool setCaughtDataGender(byte newVal) { return setVar(g2_caughtDataGender, newVal); }
bool setCaughtDataLocation(byte newVal) { return setVar(g2_caughtDataLocation, newVal); }
protected:
static const DataVarInfo
g2_heldItem,
g2_friendship,
g2_pokerusStrain,
g2_pokerusDaysRemaining,
g2_caughtDataTime,
g2_caughtDataLevel,
g2_caughtDataGender,
g2_caughtDataLocation;
#if ON_GBA
#else
void print(std::ostream &os);
#endif
};
#endif

295
include/pccs/Gen3Pokemon.h Normal file
View File

@ -0,0 +1,295 @@
#ifndef GEN3POKEMON_H
#define GEN3POKEMON_H
#include "Pokemon.h"
class Gen3Pokemon : public Pokemon // The class for gen 3 Pokemon
{
public:
Gen3Pokemon(PokemonTables *table);
bool convertToGen3(Gen3Pokemon *g3p);
u32 currRand;
u32 getNextRand_u32();
u32 getPrevRand_u32();
u16 getNextRand_u16();
u16 getPrevRand_u16();
// These are stored internally so that they can be set by different functions
byte internalUnownLetter;
Nature internalNature;
Gender internalGender;
int internalSize;
u32 internalAbility;
protected:
// These store the data bytes
byte dataArray[80] = {0};
// This stores if the data is current encrypted or not
bool isEncrypted;
// These store the offsets of the various data substructures:
int substructOffsets[4] = {0, 12, 24, 36};
int currSubstructureShift = 0;
void swapSubstructures(int indexOne, int indexTwo);
#pragma region
// Since there is only the Pokemon parent class, we can directly define these directly
static const DataVarInfo
// All of the data info variables
personalityValue,
trainerID,
secretID,
nicknameLetterOne, // This is silly. Change this.
nicknameLetterTwo,
nicknameLetterThree,
nicknameLetterFour,
nicknameLetterFive,
nicknameLetterSix,
nicknameLetterSeven,
nicknameLetterEight,
nicknameLetterNine,
nicknameLetterTen,
language,
isBadEgg,
hasSpecies,
useEggName,
blockBoxRS,
// unusedFlags,
originalTrainerNameLetterOne, // This is also silly. Change this.
originalTrainerNameLetterTwo,
originalTrainerNameLetterThree,
originalTrainerNameLetterFour,
originalTrainerNameLetterFive,
originalTrainerNameLetterSix,
originalTrainerNameLetterSeven,
markings,
checksum;
// unknown;
static const DataVarInfo
*nickname[10],
*originalTrainerName[7];
// data section G
static const DataVarInfo
speciesIndexNumber,
heldItem,
expPoints,
ppUpNumMoveOne,
ppUpNumMoveTwo,
ppUpNumMoveThree,
ppUpNumMoveFour,
friendship;
// unused;
static const DataVarInfo
*ppUpNums[4];
// data section A
static const DataVarInfo
moveOne,
moveTwo,
moveThree,
moveFour,
moveOnePP,
moveTwoPP,
moveThreePP,
moveFourPP;
static const DataVarInfo
*moves[4],
*ppUpTotals[4];
// data section E
static const DataVarInfo
hpEVs,
attackEVs,
defenseEVs,
speedEVs,
specialAttackEVs,
specialDefenseEVs,
coolnessCondition,
beautyCondition,
cutenessCondition,
smartnessCondition,
toughnessCondition,
sheen;
static const DataVarInfo
*EVs[6],
*contestConditions[5];
static const DataVarInfo
// data section M
pokerusStrain,
pokerusDaysRemaining,
metLocation,
levelMet,
gameOfOrigin,
pokeballCaughtIn,
originalTrainerGender,
hpIVs,
attackIVs,
defenseIVs,
speedIVs,
specialAttackIVs,
specialDefenseIVs,
isEgg,
ability,
coolNormalContestRibbon, // This is also very silly. Change it.
coolSuperContestRibbon,
coolHyperContestRibbon,
coolMasterContestRibbon,
beautyNormalContestRibbon,
beautySuperContestRibbon,
beautyHyperContestRibbon,
beautyMasterContestRibbon,
cuteNormalContestRibbon,
cuteSuperContestRibbon,
cuteHyperContestRibbon,
cuteMasterContestRibbon,
smartNormalContestRibbon,
smartSuperContestRibbon,
smartHyperContestRibbon,
smartMasterContestRibbon,
toughNormalContestRibbon,
toughSuperContestRibbon,
toughHyperContestRibbon,
toughMasterContestRibbon,
championRibbon,
winningRibbon,
victoryRibbon,
artistRibbon,
effortRibbon,
battleChampionRibbon,
regionalChampionRibbon,
nationalChampionRibbon,
countryRibbon,
nationalRibbon,
earthRibbon,
unusedRibbons,
fatefulEncounterObedience;
static const DataVarInfo
*IVs[6],
*ribbons[31];
#pragma endregion
// This is used to easily print out a Pokemon, when using a standard C++ terminal
#if ON_GBA
#else
public:
void print(std::ostream &os);
std::string printDataArray(bool encrypedData);
#endif
public:
// All of the simple getters and setters are defined here
u32 getPersonalityValue() { return getVar(personalityValue); }
u32 getTrainerID() { return getVar(trainerID); }
u32 getSecretID() { return getVar(secretID); }
u32 getLanguage() { return getVar(language); }
u32 getIsBadEgg() { return getVar(isBadEgg); }
u32 getHasSpecies() { return getVar(hasSpecies); }
u32 getUseEggName() { return getVar(useEggName); }
u32 getBlockBoxRS() { return getVar(blockBoxRS); }
u32 getMarkings() { return getVar(markings); }
u32 getChecksum() { return getVar(checksum); }
u32 getSpeciesIndexNumber() { return getVar(speciesIndexNumber, substructOffsets[SUB_G]); }
u32 getHeldItem() { return getVar(heldItem, substructOffsets[SUB_G]); }
u32 getExpPoints() { return getVar(expPoints, substructOffsets[SUB_G]); }
u32 getFriendship() { return getVar(friendship, substructOffsets[SUB_G]); }
u32 getSheen() { return getVar(sheen, substructOffsets[SUB_E]); }
u32 getPokerusStrain() { return getVar(pokerusStrain, substructOffsets[SUB_M]); }
u32 getPokerusDaysRemaining() { return getVar(pokerusDaysRemaining, substructOffsets[SUB_M]); }
u32 getMetLocation() { return getVar(metLocation, substructOffsets[SUB_M]); }
u32 getLevelMet() { return getVar(levelMet, substructOffsets[SUB_M]); }
u32 getGameOfOrigin() { return getVar(gameOfOrigin, substructOffsets[SUB_M]); }
u32 getPokeballCaughtIn() { return getVar(pokeballCaughtIn, substructOffsets[SUB_M]); }
u32 getOriginalTrainerGender() { return getVar(originalTrainerGender, substructOffsets[SUB_M]); }
u32 getIsEgg() { return getVar(isEgg, substructOffsets[SUB_M]); }
u32 getAbility() { return getVar(ability, substructOffsets[SUB_M]); }
u32 getFatefulEncounterObedience() { return getVar(fatefulEncounterObedience, substructOffsets[SUB_M]); }
bool setTrainerID(u32 newVal) { return setVar(trainerID, newVal); }
bool setSecretID(u32 newVal) { return setVar(secretID, newVal); }
bool setLanguage(u32 newVal) { return setVar(language, newVal); }
bool setIsBadEgg(u32 newVal) { return setVar(isBadEgg, newVal); }
bool setHasSpecies(u32 newVal) { return setVar(hasSpecies, newVal); }
bool setUseEggName(u32 newVal) { return setVar(useEggName, newVal); }
bool setBlockBoxRS(u32 newVal) { return setVar(blockBoxRS, newVal); }
bool setMarkings(u32 newVal) { return setVar(markings, newVal); }
bool setChecksum(u32 newVal) { return setVar(checksum, newVal); }
bool setSpeciesIndexNumber(u32 newVal) { return setVar(speciesIndexNumber, substructOffsets[SUB_G], newVal); }
bool setHeldItem(Item newVal) { return setVar(heldItem, substructOffsets[SUB_G], newVal); }
bool setExpPoints(u32 newVal) { return setVar(expPoints, substructOffsets[SUB_G], newVal); }
bool setFriendship(u32 newVal) { return setVar(friendship, substructOffsets[SUB_G], newVal); }
bool setSheen(u32 newVal) { return setVar(sheen, substructOffsets[SUB_E], newVal); }
bool setPokerusStrain(u32 newVal) { return setVar(pokerusStrain, substructOffsets[SUB_M], newVal); }
bool setPokerusDaysRemaining(u32 newVal) { return setVar(pokerusDaysRemaining, substructOffsets[SUB_M], newVal); }
bool setMetLocation(u32 newVal) { return setVar(metLocation, substructOffsets[SUB_M], newVal); }
bool setLevelMet(u32 newVal) { return setVar(levelMet, substructOffsets[SUB_M], newVal); }
bool setGameOfOrigin(Game newVal) { return setVar(gameOfOrigin, substructOffsets[SUB_M], newVal); }
bool setPokeballCaughtIn(u32 newVal) { return setVar(pokeballCaughtIn, substructOffsets[SUB_M], newVal); }
bool setOriginalTrainerGender(u32 newVal) { return setVar(originalTrainerGender, substructOffsets[SUB_M], newVal); }
bool setIsEgg(u32 newVal) { return setVar(isEgg, substructOffsets[SUB_M], newVal); }
bool setFatefulEncounterObedience(u32 newVal) { return setVar(fatefulEncounterObedience, substructOffsets[SUB_M], newVal); }
// The ones that access arrays are defined here:
u32 getPPUpNum(int moveIndex) { return getVar(*ppUpNums[moveIndex], substructOffsets[SUB_G]); }
u32 getMove(int moveIndex) { return getVar(*moves[moveIndex], substructOffsets[SUB_A]); }
u32 getPPTotal(int moveIndex) { return getVar(*ppUpTotals[moveIndex], substructOffsets[SUB_A]); }
u32 getEV(Stat currStat) { return getVar(*EVs[currStat], substructOffsets[SUB_E]); }
u32 getContestCondition(Condition currCondition) { return getVar(*contestConditions[currCondition], substructOffsets[SUB_E]); }
u32 getIV(Stat currStat) { return getVar(*IVs[currStat], substructOffsets[SUB_M]); }
u32 getRibbons(Ribbon currRibbon) { return getVar(*ribbons[currRibbon], substructOffsets[SUB_M]); }
u32 getNicknameLetter(int index) { return getVar(*nickname[index]); };
u32 getOTLetter(int index) { return getVar(*originalTrainerName[index]); };
bool setPPUpNum(int moveIndex, u32 newVal) { return setVar(*ppUpNums[moveIndex], substructOffsets[SUB_G], newVal); }
bool setMove(int moveIndex, u32 newVal) { return setVar(*moves[moveIndex], substructOffsets[SUB_A], newVal); }
bool setPPTotal(int moveIndex, u32 newVal) { return setVar(*ppUpTotals[moveIndex], substructOffsets[SUB_A], newVal); }
bool setEV(Stat currStat, u32 newVal) { return setVar(*EVs[currStat], substructOffsets[SUB_E], newVal); }
bool setContestCondition(Condition currCondition, u32 newVal) { return setVar(*contestConditions[currCondition], substructOffsets[SUB_E], newVal); }
bool setIV(Stat currStat, u32 newVal) { return setVar(*IVs[currStat], substructOffsets[SUB_M], newVal); }
bool setRibbons(Ribbon currRibbon, u32 newVal) { return setVar(*ribbons[currRibbon], substructOffsets[SUB_M], newVal); }
bool setNicknameLetter(int index, u32 newVal) { return setVar(*nickname[index], newVal); };
bool setOTLetter(int index, u32 newVal) { return setVar(*originalTrainerName[index], newVal); };
bool setPersonalityValue(u32 newVal);
bool setAbility(u32 newVal);
// This is used to load our data in from an array and decrypt it
void loadData(byte incomingArray[]);
// And then some general functions
void decryptSubstructures();
void encryptSubstructures();
void updateChecksum();
void updateSubstructureShift();
void resetSubstructureShift();
void updateSecurityData();
byte getUnownLetter();
Nature getNature();
Gender getGender();
int getAbilityFromPersonalityValue();
int getSize();
bool getIsShiny();
bool setNicknameArray(byte nameArr[], int nameArrSize);
bool setOTArray(byte nameArr[], int nameArrSize);
};
#endif

49
include/pccs/PokeBox.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef POKEBOX_H
#define POKEBOX_H
#include "Gen1Pokemon.h"
#include "Gen2Pokemon.h"
#include "Gen3Pokemon.h"
class PokeBox // Stores up to 30 Pokemon in a box
{
private:
void convertPkmn(int index);
PokemonTables *table;
Pokemon *boxStorage[30];
Pokemon *nullMon;
int currIndex = 0;
public:
PokeBox();
PokeBox(PokemonTables *nTable);
void setTable(PokemonTables *nTable);
bool addPokemon(Pokemon *currPkmn);
Pokemon *getPokemon(int index);
GBPokemon *getGBPokemon(int index);
Gen3Pokemon *getGen3Pokemon(int index);
bool removePokemon(int index);
void loadData(int generation, Language nLang, byte nDataArray[]);
void convertAll();
int getNumInBox();
int getNumValid();
bool stabilize_mythical = false;
#if ON_GBA
#else
friend std::ostream &operator<<(std::ostream &os, PokeBox &pc)
{
for (int i = 0; i < pc.currIndex; i++)
{
os << "\n"
<< "---------------- " << "POKEMON #" << i << " ----------------" << "\n"
<< *pc.boxStorage[i] << "\n";
}
return os;
}
std::string printDataArray();
#endif
};
#endif

105
include/pccs/Pokemon.h Normal file
View File

@ -0,0 +1,105 @@
#ifndef POKEMON_H
#define POKEMON_H
#include "pokemon_data.h"
#if ON_GBA
#else
#include <iostream>
#include <sstream>
#include <iomanip>
#endif
#if !USE_EXTERNALDATA
// #include "pokemonData.h"
#endif
#if USE_CPP_RAND
#else
#include "random.h"
#endif
// Avoid having to import math
inline u32 sizeToMask(int len)
{
u32 out = 1;
for (int i = 0; i < len; i++)
{
out *= 2;
}
return (out - 1);
}
inline u32 getPureRand() // Gets a random number from the device itself
{
#if USE_CPP_RAND
srand(time(0));
return rand() << 16 | rand();
#else
return get_rand_u32();
#endif
}
// FNV-1a 32-bit hash function for byte arrays
inline u32 fnv1a_hash(unsigned char *data, size_t length)
{
const uint32_t fnv_prime = 0x01000193;
const uint32_t fnv_offset_basis = 0x811C9DC5;
uint32_t hash = fnv_offset_basis;
for (size_t i = 0; i < length; ++i)
{
hash ^= data[i];
hash *= fnv_prime;
}
return hash;
}
class Pokemon // The base Pokemon class
{
public:
Pokemon();
virtual ~Pokemon() {};
virtual u32 getSpeciesIndexNumber();
#if ON_GBA
#else
virtual void print(std::ostream &os)
{
os << "This is a base Pokemon, it has no info!";
};
friend std::ostream &operator<<(std::ostream &os, Pokemon &p)
{
p.print(os);
return os;
}
#endif
int dataArraySize;
int nicknameArraySize;
int OTArraySize;
// Will be set by child classes
byte *dataArrayPtr;
byte *nicknameArrayPtr;
byte *OTArrayPtr;
byte *externalIndexNumberPtr;
// This is extra information that's nice to hold on to
int generation = 0;
bool isValid;
protected:
PokemonTables *pokeTable;
bool isBigEndian;
u32 getVar(DataVarInfo dataVar);
u32 getVar(DataVarInfo dataVar, int extraByteOffset);
bool setVar(DataVarInfo dataVar, u32 newValue);
bool setVar(DataVarInfo dataVar, int extraByteOffset, u32 newValue);
};
#endif

View File

@ -0,0 +1,9 @@
#ifndef PCCS_SETTINGS_H
#define PCCS_SETTINGS_H
#define ON_GBA true
#define USE_COMPRESSED_DATA true
#define USE_CPP_RAND false
#define ACCESS_POKEDEX true
#endif

1703
include/pccs/pokemon_data.h Normal file

File diff suppressed because it is too large Load Diff

671
include/pccs/typeDefs.h Normal file
View File

@ -0,0 +1,671 @@
#ifndef TYPEDEFS_H
#define TYPEDEFS_H
#include "pccs_settings.h"
#if ON_GBA
#include <tonc.h>
#else
typedef unsigned char u8, byte, uchar, echar;
typedef unsigned short u16, hword, ushort, eshort;
typedef unsigned int u32, word, uint, eint;
typedef unsigned long long u64;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;
#endif
// byte offset, data length (in bits), and bit offset
struct DataVarInfo
{
int byteOffset; // The offset of the value
int dataLength; // The length of the data in bits
int bitOffset; // The offset of where the bits are in the array
};
enum Stat
{
HP,
ATTACK,
DEFENSE,
SPEED,
SPECIAL_ATTACK,
SPECIAL_DEFENSE,
SPECIAL = SPECIAL_ATTACK,
};
enum Condition
{
COOLNESS,
BEAUTY,
CUTENESS,
SMARTNESS,
TOUGHNESS,
};
enum Gen1Types
{
NORMAL,
FIGHTING,
FLYING,
POISON,
GROUND,
ROCK,
BIRD,
BUG,
GHOST,
NINE,
TEN,
ELEVEN,
TWELVE,
THIRTEEN,
FOURTEEN,
FIFTEEN,
SIXTEEN,
SEVENTEEN,
EIGHTEEN,
NINETEEN,
FIRE,
WATER,
GRASS,
ELECTRIC,
PSYCHIC,
ICE,
DRAGON,
};
enum Ribbon
{
COOL_NORMAL_CONTEST,
COOL_SUPER_CONTEST,
COOL_HYPER_CONTEST,
COOL_MASTER_CONTEST,
BEAUTY_NORMAL_CONTEST,
BEAUTY_SUPER_CONTEST,
BEAUTY_HYPER_CONTEST,
BEAUTY_MASTER_CONTEST,
CUTE_NORMAL_CONTEST,
CUTE_SUPER_CONTEST,
CUTE_HYPER_CONTEST,
CUTE_MASTER_CONTEST,
SMART_NORMAL_CONTEST,
SMART_SUPER_CONTEST,
SMART_HYPER_CONTEST,
SMART_MASTER_CONTEST,
TOUGH_NORMAL_CONTEST,
TOUGH_SUPER_CONTEST,
TOUGH_HYPER_CONTEST,
TOUGH_MASTER_CONTEST,
CHAMPION,
WINNING,
VICTORY,
ARTIST,
EFFORT,
BATTLECHAMPION,
REGIONALCHAMPION,
NATIONALCHAMPION,
COUNTRY,
NATIONAL,
EARTH,
};
enum Gender
{
MALE,
FEMALE,
GENDERLESS,
};
enum Nature
{
HARDY,
LONELY,
BRAVE,
ADAMANT,
NAUGHTY,
BOLD,
DOCILE,
RELAXED,
IMPISH,
LAX,
TIMID,
HASTY,
SERIOUS,
JOLLY,
NAIVE,
MODEST,
MILD,
QUIET,
BASHFUL,
RASH,
CALM,
GENTLE,
SASSY,
CAREFUL,
QUIRKY,
};
enum Species
{
BULBASAUR = 1,
IVYSAUR,
VENUSAUR,
CHARMANDER,
CHARMELEON,
CHARIZARD,
SQUIRTLE,
WARTORTLE,
BLASTOISE,
CATERPIE,
METAPOD,
BUTTERFREE,
WEEDLE,
KAKUNA,
BEEDRILL,
PIDGEY,
PIDGEOTTO,
PIDGEOT,
RATTATA,
RATICATE,
SPEAROW,
FEAROW,
EKANS,
ARBOK,
PIKACHU,
RAICHU,
SANDSHREW,
SANDSLASH,
NIDORAN_F,
NIDORINA,
NIDOQUEEN,
NIDORAN_M,
NIDORINO,
NIDOKING,
CLEFAIRY,
CLEFABLE,
VULPIX,
NINETALES,
JIGGLYPUFF,
WIGGLYTUFF,
ZUBAT,
GOLBAT,
ODDISH,
GLOOM,
VILEPLUME,
PARAS,
PARASECT,
VENONAT,
VENOMOTH,
DIGLETT,
DUGTRIO,
MEOWTH,
PERSIAN,
PSYDUCK,
GOLDUCK,
MANKEY,
PRIMEAPE,
GROWLITHE,
ARCANINE,
POLIWAG,
POLIWHIRL,
POLIWRATH,
ABRA,
KADABRA,
ALAKAZAM,
MACHOP,
MACHOKE,
MACHAMP,
BELLSPROUT,
WEEPINBELL,
VICTREEBEL,
TENTACOOL,
TENTACRUEL,
GEODUDE,
GRAVELER,
GOLEM,
PONYTA,
RAPIDASH,
SLOWPOKE,
SLOWBRO,
MAGNEMITE,
MAGNETON,
FARFETCHD,
DODUO,
DODRIO,
SEEL,
DEWGONG,
GRIMER,
MUK,
SHELLDER,
CLOYSTER,
GASTLY,
HAUNTER,
GENGAR,
ONIX,
DROWZEE,
HYPNO,
KRABBY,
KINGLER,
VOLTORB,
ELECTRODE,
EXEGGCUTE,
EXEGGUTOR,
CUBONE,
MAROWAK,
HITMONLEE,
HITMONCHAN,
LICKITUNG,
KOFFING,
WEEZING,
RHYHORN,
RHYDON,
CHANSEY,
TANGELA,
KANGASKHAN,
HORSEA,
SEADRA,
GOLDEEN,
SEAKING,
STARYU,
STARMIE,
MR_MIME,
SCYTHER,
JYNX,
ELECTABUZZ,
MAGMAR,
PINSIR,
TAUROS,
MAGIKARP,
GYARADOS,
LAPRAS,
DITTO,
EEVEE,
VAPOREON,
JOLTEON,
FLAREON,
PORYGON,
OMANYTE,
OMASTAR,
KABUTO,
KABUTOPS,
AERODACTYL,
SNORLAX,
ARTICUNO,
ZAPDOS,
MOLTRES,
DRATINI,
DRAGONAIR,
DRAGONITE,
MEWTWO,
MEW,
CHIKORITA,
BAYLEEF,
MEGANIUM,
CYNDAQUIL,
QUILAVA,
TYPHLOSION,
TOTODILE,
CROCONAW,
FERALIGATR,
SENTRET,
FURRET,
HOOTHOOT,
NOCTOWL,
LEDYBA,
LEDIAN,
SPINARAK,
ARIADOS,
CROBAT,
CHINCHOU,
LANTURN,
PICHU,
CLEFFA,
IGGLYBUFF,
TOGEPI,
TOGETIC,
NATU,
XATU,
MAREEP,
FLAAFFY,
AMPHAROS,
BELLOSSOM,
MARILL,
AZUMARILL,
SUDOWOODO,
POLITOED,
HOPPIP,
SKIPLOOM,
JUMPLUFF,
AIPOM,
SUNKERN,
SUNFLORA,
YANMA,
WOOPER,
QUAGSIRE,
ESPEON,
UMBREON,
MURKROW,
SLOWKING,
MISDREAVUS,
UNOWN,
WOBBUFFET,
GIRAFARIG,
PINECO,
FORRETRESS,
DUNSPARCE,
GLIGAR,
STEELIX,
SNUBBULL,
GRANBULL,
QWILFISH,
SCIZOR,
SHUCKLE,
HERACROSS,
SNEASEL,
TEDDIURSA,
URSARING,
SLUGMA,
MAGCARGO,
SWINUB,
PILOSWINE,
CORSOLA,
REMORAID,
OCTILLERY,
DELIBIRD,
MANTINE,
SKARMORY,
HOUNDOUR,
HOUNDOOM,
KINGDRA,
PHANPY,
DONPHAN,
PORYGON2,
STANTLER,
SMEARGLE,
TYROGUE,
HITMONTOP,
SMOOCHUM,
ELEKID,
MAGBY,
MILTANK,
BLISSEY,
RAIKOU,
ENTEI,
SUICUNE,
LARVITAR,
PUPITAR,
TYRANITAR,
LUGIA,
HO_OH,
CELEBI,
TREECKO,
MISSINGNO = 0xFF,
};
enum PokeBall
{
MASTER = 1,
ULTRA,
GREAT,
POKE,
SAFARI,
NET,
DIVE,
NEST,
REPEAT,
TIMER,
LUXURY,
PREMIER,
};
enum Game
{
SAPPHIRE = 1,
RUBY,
EMERALD,
FIRERED,
LEAFGREEN,
HEARTGOLD = 7,
SOULSILVER,
DIAMOND = 10,
PEARL,
PLATINUM,
COlOSSEUM_XD = 15,
};
enum Item
{
NONE,
MASTER_BALL,
ULTRA_BALL,
GREAT_BALL,
POKE_BALL,
SAFARI_BALL,
NET_BALL,
DIVE_BALL,
NEST_BALL,
REPEAT_BALL,
TIMER_BALL,
LUXURY_BALL,
PREMIER_BALL,
POTION,
ANTIDOTE,
BURN_HEAL,
ICE_HEAL,
AWAKENING,
PARLYZ_HEAL,
FULL_RESTORE,
MAX_POTION,
HYPER_POTION,
SUPER_POTION,
FULL_HEAL,
REVIVE,
MAX_REVIVE,
FRESH_WATER,
SODA_POP,
LEMONADE,
MOOMOO_MILK,
ENERGYPOWDER,
ENERGY_ROOT,
HEAL_POWDER,
REVIVAL_HERB,
ETHER,
MAX_ETHER,
ELIXIR,
MAX_ELIXIR,
LAVA_COOKIE,
BLUE_FLUTE,
YELLOW_FLUTE,
RED_FLUTE,
BLACK_FLUTE,
WHITE_FLUTE,
BERRY_JUICE,
SACRED_ASH,
SHOAL_SALT,
SHOAL_SHELL,
RED_SHARD,
BLUE_SHARD,
YELLOW_SHARD,
GREEN_SHARD,
HP_UP = 0x3F,
PROTEIN,
IRON,
CARBOS,
CALCIUM,
RARE_CANDY,
PP_UP,
ZINC,
PP_MAX,
GUARD_SPEC = 0x49,
DIRE_HIT,
X_ATTACK,
X_DEFEND,
X_SPEED,
X_ACCURACY,
X_SPECIAL,
POKE_DOLL,
FLUFFY_TAIL,
SUPER_REPEL = 0x53,
MAX_REPEL,
ESCAPE_ROPE,
REPEL,
SUN_STONE = 0x5D,
MOON_STONE,
FIRE_STONE,
THUNDERSTONE,
WATER_STONE,
LEAF_STONE,
TINYMUSHROOM = 0x67,
BIG_MUSHROOM,
NORMAL_PEARL = 0x6A,
BIG_PEARL,
STARDUST,
STAR_PIECE,
NUGGET,
HEART_SCALE,
ORANGE_MAIL = 0x79,
HARBOR_MAIL,
GLITTER_MAIL,
MECH_MAIL,
WOOD_MAIL,
WAVE_MAIL,
BEAD_MAIL,
SHADOW_MAIL,
TROPIC_MAIL,
DREAM_MAIL,
FAB_MAIL,
RETRO_MAIL,
CHERI_BERRY,
CHESTO_BERRY,
PECHA_BERRY,
RAWST_BERRY,
ASPEAR_BERRY,
LEPPA_BERRY,
ORAN_BERRY,
PERSIM_BERRY,
LUM_BERRY,
SITRUS_BERRY,
FIGY_BERRY,
WIKI_BERRY,
MAGO_BERRY,
AGUAV_BERRY,
IAPAPA_BERRY,
RAZZ_BERRY,
BLUK_BERRY,
NANAB_BERRY,
WEPEAR_BERRY,
PINAP_BERRY,
POMEG_BERRY,
KELPSY_BERRY,
QUALOT_BERRY,
HONDEW_BERRY,
GREPA_BERRY,
TAMATO_BERRY,
CORNN_BERRY,
MAGOST_BERRY,
RABUTA_BERRY,
NOMEL_BERRY,
SPELON_BERRY,
PAMTRE_BERRY,
WATMEL_BERRY,
DURIN_BERRY,
BELUE_BERRY,
LIECHI_BERRY,
GANLON_BERRY,
SALAC_BERRY,
PETAYA_BERRY,
APICOT_BERRY,
LANSAT_BERRY,
STARF_BERRY,
ENIGMA_BERRY,
BRIGHTPOWDER = 0xB3,
WHITE_HERB,
MACHO_BRACE,
EXP_SHARE,
QUICK_CLAW,
SOOTHE_BELL,
MENTAL_HERB,
CHOICE_BAND,
KINGS_ROCK,
SILVERPOWDER,
AMULET_COIN,
CLEANSE_TAG,
SOUL_DEW,
DEEPSEATOOTH,
DEEPSEASCALE,
SMOKE_BALL,
EVERSTONE,
FOCUS_BAND,
LUCKY_EGG,
SCOPE_LENS,
METAL_COAT,
LEFTOVERS,
DRAGON_SCALE,
LIGHT_BALL,
SOFT_SAND,
HARD_STONE,
MIRACLE_SEED,
BLACKGLASSES,
BLACK_BELT,
MAGNET,
MYSTIC_WATER,
SHARP_BEAK,
POISON_BARB,
NEVERMELTICE,
SPELL_TAG,
TWISTEDSPOON,
CHARCOAL,
DRAGON_FANG,
SILK_SCARF,
UPGRADE,
SHELL_BELL,
SEA_INCENSE,
LAX_INCENSE,
LUCKY_PUNCH,
METAL_POWDER,
THICK_CLUB,
STICK,
RED_SCARF = 0xFE,
BLUE_SCARF,
PINK_SCARF,
GREEN_SCARF,
YELLOW_SCARF
};
enum Substructure
{
SUB_G,
SUB_A,
SUB_E,
SUB_M,
};
enum Language
{
JAPANESE = 1,
ENGLISH,
FRENCH,
ITALIAN,
GERMAN,
SPANISH,
KOREAN,
};
enum RNGMethod
{
ABCD_U, // Normal method
BACD_R, // Used for calculating events
};
#endif

View File

@ -1,114 +0,0 @@
#ifndef POKEMON_H
#define POKEMON_H
#include <tonc.h>
#include "random.h"
#include "global_frame_controller.h"
#define POKEMON_SIZE 80
// How much trade data is sent for each langauge and generation,
// sarts at OT name and ends after the 3 buffer bytes
#define GEN1_JPN_SIZE 353
#define GEN1_INT_SIZE 418
#define GEN2_JPN_SIZE 383
#define GEN2_INT_SIZE 444
class PokemonTables;
struct Simplified_Pokemon
{
byte dex_number;
byte met_level;
byte nickname[10];
bool is_valid;
bool is_transferred;
bool is_shiny;
int unown_letter;
bool is_missingno;
};
enum Conversion_Types
{
Faithful,
Legal,
Virtual,
};
class Pokemon
{
public:
int pkmn_size = 0;
int ot_and_party = 0;
int ot_size = 0;
int nickname_size = 0;
int nature_mod = 0;
int unown_letter = -1;
Pokemon();
void load_data(int index, const byte *party_data, int game, int lang);
void convert_to_gen_three(PokemonTables& data_tables, Conversion_Types conv_type, bool simplified, bool stabilize_mythical);
void copy_from_to(const byte *source, byte *destination, int size, bool reverse_endian);
void alocate_data_chunks(byte *G, byte *A, byte *E, byte *M);
void insert_data(byte *first, byte *second, byte *third, byte *fourth);
byte get_gen_3_data(int index);
byte *get_full_gen_3_array();
byte get_unencrypted_data(int index);
byte *convert_text(PokemonTables& data_tables, byte *text_array, int size);
u32 generate_pid_save_iv(PokemonTables& data_tables, byte pid_species_index, byte nature, byte *pid_dvs);
u32 generate_pid_iv_match(PokemonTables& data_tables, byte pid_species_index, byte nature, byte *pid_dvs);
u32 generate_pid_iv_legendary(byte pid_species_index, byte *pid_dvs, byte *out_ivs);
byte rand_reverse_mod(byte modulo_divisor, byte target_mod);
byte get_rand_gender_byte(PokemonTables &data_tables, byte index_num, byte attack_DVs);
byte get_dex_number();
bool get_validity();
bool get_is_new();
bool get_is_shiny();
Simplified_Pokemon get_simple_pkmn();
u8 get_letter_from_pid(u32 pid);
u8 get_nature_from_pid(u32 pid);
u8 get_gender_from_pid(u32 pid);
void set_to_event(PokemonTables &data_tables, byte nature);
int num_in_box;
int index_in_box;
bool is_missingno = false;
private:
byte gen = 2;
byte language;
byte species_index_party; // The species ID stored in the party. Really only used for egg detection
byte species_index_struct; // The species ID stored in the pkmn strucutre. The main one to use.
byte moves[4];
byte trainer_id[2];
byte secret_id[2];
u32 exp;
byte nickname[10];
byte trainer_name[7];
byte pokerus;
byte caught_data[2];
byte met_level;
byte item;
byte gen_3_pkmn[80];
byte unencrypted_data[49]; // Contains the 48 GAEM bytes, along with the modulo int
byte pid[4] = {0, 0, 0, 0}; // Little Endian, reverse of Bulbapedia
byte blank_word[4] = {0};
byte data_section_G[12];
byte data_section_A[12];
byte data_section_E[12];
byte data_section_M[12];
hword checksum;
byte encryption_key[4];
hword origin_info = 0;
bool is_shiny = false;
byte pp_values[4];
byte pp_bonus[4];
byte pure_pp_values[4];
byte dvs[2];
byte ivs[6];
byte ribbons[4] = {0, 0, 0, 0};
u32 iv_egg_ability;
bool is_valid;
bool is_new = false;
int box_size;
};
#endif

View File

@ -1,143 +0,0 @@
#ifndef POKEMON_DATA_H
#define POKEMON_DATA_H
#include <tonc.h>
#define med_fast_max (u32)1000000
// Slightly Fast goes unused
// Slightly Slow goes unused
#define med_slow_max (u32)1059860
#define fast_max (u32)800000
#define slow_max (u32)1250000
// Erractic is Gen 3+
// Fluctuating is Gen 3+
#define EXP_FAST 0
// Slightly Fast goes unused
// Slightly Slow goes unused
#define EXP_MED_SLOW 3
#define EXP_MED_FAST 4
#define EXP_SLOW 5
// Erractic is Gen 3+
// Fluctuating is Gen 3+
#define JPN_ID 1
#define ENG_ID 2
#define FRE_ID 3
#define ITA_ID 4
#define GER_ID 5
#define SPA_ID 7
#define KOR_ID 8
#define GREEN_ID 0
#define RED_ID 1
#define BLUE_ID 2
#define YELLOW_ID 3
#define GOLD_ID 4
#define SILVER_ID 5
#define CRYSTAL_ID 6
#define EVENT_MEW_JPN 0
#define EVENT_MEW_ENG 1
#define EVENT_MEW_FRE 2
#define EVENT_MEW_ITA 3
#define EVENT_MEW_GER 4
#define EVENT_MEW_SPA 5
#define EVENT_CELEBI 6
#define MAX_PKMN_IN_BOX 30
#define NUM_POKEMON 252
#define POKEMON_ARRAY_SIZE NUM_POKEMON + 1
// these arrays are too small to compress
extern const u32 EXP_MAXIMUMS[6];
extern const int GENDER_THRESHOLDS[2][8];
// the next arrays don't compress well at all. Not worth the decompression overhead.
extern const byte gen_1_index_array[191];
extern const u8 EVOLUTIONS[POKEMON_ARRAY_SIZE];
// Unfortunately we can't compress this 8 KB MOVESETS array.
// I mean, we physically can, but decompressing it means storing it in IWRAM,
// at a moment (during convert_to_gen_three()) at which we are using a LOT of IWRAM already.
// By keeping it uncompressed, it gets stored in EWRAM, where it won't hinder us.
// But it does mean that it still takes up 8 KB in the rom.
// Just for reference: when compressing it with ZX0 AND only storing the "changed" bits for PKMN
// evolutions in relation to their base forms, we could bring the size down to 4641 bytes.
// But alas, the IWRAM consumption at a critical point in time made this approach unviable.
// TODO: we might be able to load similar data from the game cartridges.
// However, it turns out the data is different between the R/S/E and FR/LG games.
// So we would have to store "patches"/differences if we go this route.
// It also means we'd have to figure out rom offsets for every single gen III game variant/localization.
extern const byte MOVESETS[POKEMON_ARRAY_SIZE][32];
/**
* Okay, here's the thing: to reduce the rom size, we compressed a bunch of data with ZX0
* Among this data are various data tables that were previously just stored as const arrays.
*
* But, during the mystery_gift_builder/mystery_gift_injector execution,
* these data tables are used intensely, because you're not using them for single pokémon, but rather for boxes of pokémon.
*
* Decompression is not cheap, so we can't afford to decompress the tables again and again for every pokémon we deal with
* during this flow.
*
* This is where this class comes in. It is basically a holder of these tables. The idea is to pass it along with the mystery_gift_builder
* and have it lazy decompress the tables AND charsets it needs. This way when we are dealing with multiple pokémon, we are not decompressing
* the same data every time and thereby make performance suffer.
*
* It DOES have a significant IWRAM cost though. The intention is to just allocate this struct on the stack.
* As far as I can tell, our stack is not really restricted at all. It just fills up the IWRAM as needed. So we need to be careful not to
* overwrite/corrupt any code or data we specifically tagged to be stored in IWRAM.
*/
class PokemonTables
{
public:
bool exp_groups_loaded;
bool gender_ratios_loaded;
bool num_abilities_loaded;
bool first_moves_loaded;
bool power_points_loaded;
bool event_pkmn_loaded;
bool types_loaded;
// a number representing the unique combination of gen 1/2 and the specific language
// 0 means not loaded
u8 input_charset_type;
// 0 means not loaded, 1=JPN, 2=Intern
u8 gen3_charset_type;
u8 EXP_GROUPS[POKEMON_ARRAY_SIZE];
u8 GENDER_RATIO[POKEMON_ARRAY_SIZE];
bool NUM_ABILITIES[POKEMON_ARRAY_SIZE];
byte FIRST_MOVES[POKEMON_ARRAY_SIZE];
u8 POWER_POINTS[252];
byte EVENT_PKMN[8][80];
u8 TYPES[POKEMON_ARRAY_SIZE][2];
u16 input_charset[256];
u16 gen3_charset[256];
PokemonTables();
void load_exp_groups();
void load_gender_ratios();
void load_num_abilities();
void load_first_moves();
void load_power_points();
void load_event_pkmn();
void load_types();
void load_input_charset(byte gen, byte lang);
void load_gen3_charset(byte lang);
u32 get_max_exp(int index_num);
u8 get_gender_threshold(int index_num, bool is_gen_3);
bool get_num_abilities(int index_num);
bool can_learn_move(int pkmn_index, int move_index);
byte get_earliest_move(int index_num);
byte get_gen_3_char(u16 input_char);
};
/**
* Loads the charset for <gen> and <lang> into <output_char_array>
*/
void load_localized_charset(u16 *output_char_array, byte gen, byte lang);
byte get_char_from_charset(const u16 *charset, u16 input_char);
#endif

View File

@ -2,16 +2,17 @@
#define POKEMON_PARTY_H
#include <tonc.h>
#include "pokemon.h"
#include "pccs/PokeBox.h"
#include "gb_rom_values/base_gb_rom_struct.h"
class Pokemon_Party
{
public:
Pokemon_Party();
PokemonTables table;
void start_link();
void continue_link(bool cancel_connection);
int get_last_error();
Pokemon get_converted_pkmn(PokemonTables &data_tables, int index);
bool load_gb_rom(Language lang, Game game);
bool get_has_new_pkmn();
void set_game(int nGame);
void set_lang(int nLang);
@ -19,17 +20,13 @@ public:
bool load_gb_rom();
GB_ROM curr_gb_rom;
void show_sprites();
Simplified_Pokemon simple_pkmn_array[30];
Simplified_Pokemon get_simple_pkmn(int index);
bool fill_simple_pkmn_array(PokemonTables &data_tables);
bool get_contains_mythical();
void set_mythic_stabilization(bool stabilize);
bool contains_valid = false;
bool contains_invalid = false;
int get_game_gen();
int get_num_pkmn();
bool get_contains_invalid();
bool get_contains_missingno();
PokeBox box;
byte box_data_array[0x462];
private:
@ -37,10 +34,7 @@ private:
u8 current_payload[PAYLOAD_SIZE];
int last_error;
bool has_new_pkmn = false;
bool contains_mythical = false;
bool stabilize_mythic = false;
bool contains_missingno = false;
int game;
char lang;
};

View File

@ -17,7 +17,7 @@
#define DEFAULT_LANGUAGE 0x21 // | 0x22 | 1 | Default international language
#define SAVE_DATA_SIZE 0x22
extern rom_data curr_rom;
extern rom_data curr_GBA_rom;
void load_custom_save_data();
void write_custom_save_data();

View File

@ -23,7 +23,7 @@
#define CMD_CONTINUE_LINK DIA_END + 13
#define CMD_BOX_MENU DIA_END + 14
#define CMD_MYTHIC_MENU DIA_END + 15
#define CMD_LOAD_SIMP DIA_END + 16
#define CMD_IS_A_VALID_PKMN DIA_END + 16
#define CMD_CANCEL_LINK DIA_END + 17
#define CMD_END_MISSINGNO DIA_END + 18
@ -61,7 +61,7 @@
extern const script_obj_params transfer_script_params[];
extern const script_obj_params event_script_params[];
extern rom_data curr_rom;
extern rom_data curr_GBA_rom;
void populate_lang_menu();
void populate_game_menu(int lang);

View File

@ -2,8 +2,6 @@
#define SPRITE_DATA_H
#include <tonc.h>
#include "pokemon.h"
#include "pokemon_data.h"
#include "pokemon_party.h"
#include "rom_data.h"
#include "box_menu.h"
@ -112,7 +110,7 @@ extern OBJ_ATTR *grabbed_front_sprite;
#define BG_MAIN_MENU 3
#define BG_BOX 4
extern rom_data curr_rom;
extern rom_data curr_GBA_rom;
void load_sprite(OBJ_ATTR *sprite, const unsigned int objTiles[], int objTilesLen,
u32 &tile_id, u32 pal_bank, int attr0, int attr1, u32 priority);
@ -124,7 +122,7 @@ void set_background_pal(int curr_rom_id, bool dark, bool fade);
void load_textbox_background();
void load_flex_background(int background_id, int layer);
void load_eternal_sprites();
void load_temp_box_sprites(Pokemon_Party *party_data);
void load_temp_box_sprites(PokeBox* box);
void load_type_sprites(const u8* pkmn_type_table, int pkmn_index, int dex_offset, bool is_caught);
void add_menu_box(int options, int startTileX, int startTileY);
void add_menu_box(int startTileX, int startTileY, int width, int height);
@ -135,6 +133,6 @@ void fennel_speak(int frame);
int get_curr_flex_background();
void update_y_offset();
void erase_textbox_tiles();
void update_front_box_sprite(Simplified_Pokemon *curr_pkmn);
void update_menu_sprite(Pokemon_Party *party_data, int index, int frame);
void update_front_box_sprite(GBPokemon *curr_pkmn);
void update_menu_sprite(PokeBox* box, int index, int frame);
#endif

996
payload_builder copy.cpp Normal file
View File

@ -0,0 +1,996 @@
#include "payloads/payload_builder.h"
#include "gb_rom_values/base_gb_rom_struct.h"
#include "payloads/z80_asm.h"
#include "../../../include/debug_mode.h"
#include <cstring>
#define DATA_LOC (SHOW_DATA_PACKETS ? curr_rom.transferStringLocation : curr_rom.wEnemyMonSpecies)
#define DEBUG_PAYLOADS (false && DEBUG_MODE)
void init_payload(byte *payload_buffer, const GB_ROM &curr_rom, int type, bool debug)
{
if (DEBUG_PAYLOADS)
{
debug = true;
}
(void)type;
/* 10 RNG bytes
8 Preamble bytes
418 / 441 Party bytes
7 Preamble bytes
194 Patch list bytes (last 2 are unused)
637 / 660 total bytes
*/
if ((curr_rom.generation == 1 && curr_rom.version != YELLOW_ID))
{
std::vector<z80_jump *> jump_vector;
std::vector<z80_variable *> var_vector;
z80_asm_handler z80_rng_seed(0x0A, curr_rom.wSerialOtherGameboyRandomNumberListBlock + 8);
z80_asm_handler z80_payload(0x1AA, curr_rom.wSerialEnemyDataBlock);
z80_asm_handler z80_patchlist(0xC9, curr_rom.wSerialEnemyMonsPatchList);
z80_jump asm_start(&jump_vector);
z80_jump save_box(&jump_vector);
z80_jump remove_array_loop(&jump_vector);
z80_jump packet_loop(&jump_vector);
z80_jump fe_bypass(&jump_vector);
z80_jump send_packet_loop(&jump_vector);
z80_variable array_counter(&var_vector, 1, 0x00); // 1 byte to store the current array counter
z80_variable removal_array(&var_vector); // 40 byte storage for list of Pokemon to remove, plus a permanent array terminator
byte removal_array_data[41];
for (int i = 0; i < 41; i++)
{
if (debug)
{
removal_array_data[i] = (i < 30 ? (29 - i) : 0xFF);
}
else
{
removal_array_data[i] = (i < 30 ? 0xFD : 0xFF);
}
}
removal_array.load_data(41, removal_array_data);
z80_variable transfer_wait_string(&var_vector, 13, // SENDING DATA
0x92, 0x84, 0x8D, 0x83, 0x88, 0x8D, 0x86, 0x7F, 0x83, 0x80, 0x93, 0x80, 0x50);
z80_variable custom_name(&var_vector, 11, // FENNEL
0x85, 0x84, 0x8D, 0x8D, 0x84, 0x8B, 0x50, 0x50, 0x50, 0x50, 0x50);
// RNG Seed
// Location of the entrance vector
z80_rng_seed.index = 5; // Set the entrance vector
z80_rng_seed.JP(asm_start.place_direct_jump(&z80_rng_seed) | T_U16);
// Preamble
// At 0x00, 0x07 in length
// Must be filled with 0xFD
for (int i = 0; i < 7; i++)
{
z80_payload.add_byte(0xFD);
}
// Rival name
// At 0x07, 0x0B in length
// Set to stored name
z80_payload.index = 0x07;
custom_name.insert_variable(&z80_payload);
// Number of Pokemon
// At 0x12, 0x01 in length
// Does not need to be set
z80_payload.index = 0x12;
z80_payload.add_byte(0x06);
// Pokemon list
// At 0x13, can be up to 0x1A2 / 0x1B9 bytes in length.
// Calculate the number of Pokemon names that need to be printed,
// and add them to the list. Then terminate the list.
z80_payload.index = 0x13;
int distance = curr_rom.stack_overwrite_location - curr_rom.print_string_start;
distance /= 20; // Automatically truncated, so it won't overshoot
for (int i = 0; i < distance; i++)
{
z80_payload.add_byte(curr_rom.short_pkmn_name);
}
z80_payload.add_byte(curr_rom.pointer_pkmn_name);
z80_payload.add_byte(0xFF);
// Patchlist preamble
// At 0x1B4 / 0x1D7, 0x07 in length
// Set as five 0xFD and two 0xFF
for (int i = 0; i < 7; i++)
{
z80_patchlist.add_byte(i < 5 ? 0xFD : 0xFF);
}
// Patchlist
// At 0x1BB / 0x1DE, 0xC2 in length (0xC4, but the last 2 are unused)
// Fill with custom code
asm_start.set_start(&z80_patchlist);
/* Write transferring message to screen: */
// call ClearScreen
z80_patchlist.CALL(curr_rom.clearScreen | T_U16);
z80_patchlist.LD(HL, curr_rom.textBorderUppLeft | T_U16);
z80_patchlist.LD(C, curr_rom.textBorderWidth | T_U8);
z80_patchlist.LD(B, curr_rom.textBorderHeight | T_U8);
z80_patchlist.CALL(curr_rom.CableClub_TextBoxBorder | T_U16);
z80_patchlist.LD(HL, curr_rom.transferStringLocation | T_U16);
z80_patchlist.LD(DE, transfer_wait_string.place_ptr(&z80_patchlist) | T_U16);
z80_patchlist.CALL(curr_rom.placeString | T_U16);
/* Build the packet */
// HL is the current data pointer
// DE is the destination pointer
// A is the checksum
// B is the 0xFE flag byte
// C is the counter
send_packet_loop.set_start(&z80_patchlist);
z80_patchlist.LD(HL, (DATA_LOC + PACKET_SIZE + 3) | T_U16); // Load the next data location into HL
z80_patchlist.LD(A, HLI_PTR);
z80_patchlist.LD(H, HL_PTR);
z80_patchlist.LD(L, A);
z80_patchlist.LD(DE, (DATA_LOC + 2) | T_U16); // Enemy Pokemon data, should be unused
z80_patchlist.XOR(A, A); // Clear the register
z80_patchlist.LD(B, A); // Clear B as well
z80_patchlist.LD(C, A); // Clear C as well
z80_patchlist.PUSH(AF);
packet_loop.set_start(&z80_patchlist);
z80_patchlist.LD(B, 0x00 | T_U8); // Reset the flag byte
z80_patchlist.POP(AF);
z80_patchlist.ADD(A, HL_PTR); // Add the current data to the checksum
z80_patchlist.PUSH(AF);
z80_patchlist.LD(A, 0xFE);
z80_patchlist.CP(A, HL_PTR); // Compare the current data to 0xFE
z80_patchlist.LD(A, HLI_PTR); // Load HL's data into A for modification (if need be)
// If HL's data is 0xFE
z80_patchlist.JR(NZ_F, fe_bypass.place_relative_jump(&z80_patchlist) | T_I8);
z80_patchlist.DEC(A);
z80_patchlist.INC(B); // Set flag
fe_bypass.set_start(&z80_patchlist);
z80_patchlist.LD(DE_PTR, A); // Place the data in
z80_patchlist.INC(DE);
z80_patchlist.PUSH(AF);
z80_patchlist.LD(A, B);
z80_patchlist.LD(DE_PTR, A); // Place the flag in as well
z80_patchlist.POP(AF);
z80_patchlist.INC(DE);
z80_patchlist.INC(C);
z80_patchlist.LD(A, DATA_PER_PACKET - 1);
z80_patchlist.CP(A, C);
z80_patchlist.JR(NC_F, packet_loop.place_relative_jump(&z80_patchlist) | T_I8); // If all the data has been set, send the rest of the data
z80_patchlist.POP(AF);
z80_patchlist.RES(7 | T_BIT, A); // Reset bit 7 of the checksum, guaranteeing that it will never be 0xFE
z80_patchlist.LD(DE_PTR, A);
z80_patchlist.INC(DE);
z80_patchlist.LD(A, H);
z80_patchlist.LD(DE_PTR, A);
z80_patchlist.INC(DE);
z80_patchlist.LD(A, L);
z80_patchlist.LD(DE_PTR, A);
// z80_patchlist.LD(HL, curr_rom.garbageDataLocation | T_U16);
/* Transfer box data packet: */
z80_patchlist.LD(A, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug
z80_patchlist.LDH((curr_rom.hSerialConnectionStatus & 0xFF) | T_U8, A); // Since hSerialConnectionStatus is at 0xFFxx we can use this method instead
z80_patchlist.LD(HL, DATA_LOC | T_U16);
z80_patchlist.LD(HL_PTR, 0xFD | T_U8); // set the start of the data to 0xFD so Serial_ExchangeBytes is happy
z80_patchlist.INC(HL);
z80_patchlist.LD(HL_PTR, 0x00 | T_U8); // add a 0x00 after the 0xFD to prevent further 0xFDs from being interpreted as part of the preamble
z80_patchlist.DEC(HL); // Reset HL back so it points to 0xFD
z80_patchlist.LD(DE, (DATA_LOC + PACKET_SIZE) | T_U16); // location to put stored data
z80_patchlist.LD(BC, PACKET_SIZE | T_U16);
if (debug) // Don't call serialExchangeBytes if debug is enabled
{
z80_patchlist.index += 3;
}
else
{
z80_patchlist.CALL(curr_rom.Serial_ExchangeBytes | T_U16);
}
z80_patchlist.LD(A, (DATA_LOC + PACKET_SIZE + 3 + 1) | T_U16);
z80_patchlist.CP(A, 0xFF);
z80_patchlist.JR(NZ_F, send_packet_loop.place_relative_jump(&z80_patchlist) | T_I8);
/* Recieve the Pokemon to remove */
z80_patchlist.LD(HL, curr_rom.hSerialConnectionStatus | T_U16); // This can also be shortened
z80_patchlist.LD(HL_PTR, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug
z80_patchlist.LD(HL, curr_rom.garbageDataLocation | T_U16);
z80_patchlist.LD(DE, removal_array.place_ptr(&z80_patchlist) | T_U16);
z80_patchlist.LD(BC, 0x001E | T_U16); // Preamble does *not* count
if (debug) // Don't add in the Serial_ExchangeBytes call if in debug
{
z80_patchlist.index += 3;
}
else
{
z80_patchlist.CALL(curr_rom.Serial_ExchangeBytes | T_U16);
}
/* Remove the transfered Pokemon */
z80_patchlist.LD(HL, curr_rom.wRemoveMonFromBox | T_U16);
z80_patchlist.LD(HL_PTR, 0x01 | T_U8); // != 0x00 specifies the current box
remove_array_loop.set_start(&z80_patchlist);
z80_patchlist.LD(A, array_counter.place_ptr(&z80_patchlist) | T_U16);
z80_patchlist.LD(E, A);
z80_patchlist.LD(D, 0x00 | T_U8);
z80_patchlist.LD(HL, removal_array.place_ptr(&z80_patchlist) | T_U16);
z80_patchlist.ADD(HL, DE);
z80_patchlist.INC(A);
z80_patchlist.LD(array_counter.place_ptr(&z80_patchlist) | T_U16, A);
z80_patchlist.LD(A, curr_rom.wBoxCount | T_U16);
z80_patchlist.LD(B, A);
z80_patchlist.LD(A, HL_PTR);
z80_patchlist.CP(A, 0xFF | T_U8);
z80_patchlist.JR(Z_F, save_box.place_relative_jump(&z80_patchlist) | T_I8);
z80_patchlist.CP(A, B);
z80_patchlist.JR(NC_F, remove_array_loop.place_relative_jump(&z80_patchlist) | T_I8);
z80_patchlist.LD(HL, curr_rom.wWhichPokemon | T_U16);
z80_patchlist.LD(HL_PTR, A);
if (DONT_REMOVE_PKMN)
{
z80_patchlist.index += 3;
}
else
{
z80_patchlist.CALL(curr_rom._RemovePokemon | T_U16);
}
z80_patchlist.JR((remove_array_loop.place_relative_jump(&z80_patchlist) & 0xFF) | T_I8);
/* Save the current box */
save_box.set_start(&z80_patchlist);
z80_patchlist.LD(B, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8); // Load ROM Bank
z80_patchlist.LD(HL, curr_rom.SaveSAVtoSRAM1 | T_U16);
z80_patchlist.CALL(curr_rom.Bankswitch | T_U16);
z80_patchlist.LD(B, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8); // Load ROM Bank
z80_patchlist.LD(HL, curr_rom.SaveSAVtoSRAM2 | T_U16); // TODO: We probably don't have to load the ROM bank twice
z80_patchlist.CALL(curr_rom.Bankswitch | T_U16);
z80_patchlist.JP(curr_rom.SoftReset | T_U16);
// z80_patchlist.index += 5;
array_counter.insert_variable(&z80_patchlist);
removal_array.insert_variable(&z80_payload);
transfer_wait_string.insert_variable(&z80_patchlist);
// This payload works by placing Pokemon ID 0xFC's name in the stack, and causing a return to CD8E,
// which is part of the RNG seed. From there we can jump anywhere- and we choose to jump to D887,
// which is the rival's name. This code fixes the stack and jumps to the patchlist, which is where
// our final code is.
// Update all the pointers
for (unsigned int i = 0; i < var_vector.size(); i++)
{
var_vector.at(i)->update_ptrs();
}
for (unsigned int i = 0; i < jump_vector.size(); i++)
{
jump_vector.at(i)->update_jumps();
}
// Combine the vectors into the full payload
u8 *cur_out = payload_buffer;
memcpy(cur_out, z80_rng_seed.data_vector.data(), z80_rng_seed.data_vector.size());
cur_out += z80_rng_seed.data_vector.size();
memcpy(cur_out, z80_payload.data_vector.data(), z80_payload.data_vector.size());
cur_out += z80_payload.data_vector.size();
memcpy(cur_out, z80_patchlist.data_vector.data(), z80_patchlist.data_vector.size());
cur_out += z80_patchlist.data_vector.size();
return;
}
else if ((curr_rom.generation == 1 && curr_rom.version == YELLOW_ID))
{
std::vector<z80_jump *> jump_vector;
std::vector<z80_variable *> var_vector;
z80_asm_handler z80_rng_seed(0x0A, curr_rom.wSerialOtherGameboyRandomNumberListBlock + 8);
z80_asm_handler z80_payload(0x1AA, curr_rom.wSerialEnemyDataBlock - 8); // Subtracting 8 is because the data is shifted after patching, removing part of the enemy name. May change depending on language
z80_asm_handler z80_patchlist(0xC9, curr_rom.wSerialEnemyMonsPatchList);
z80_jump asm_start(&jump_vector);
z80_jump save_box(&jump_vector);
z80_jump remove_array_loop(&jump_vector);
z80_jump packet_loop(&jump_vector);
z80_jump fe_bypass(&jump_vector);
z80_jump send_packet_loop(&jump_vector);
z80_jump skip_enemy_write(&jump_vector);
z80_jump test_loop(&jump_vector);
z80_variable array_counter(&var_vector, 1, 0x00); // 1 byte to store the current array counter
z80_variable removal_array(&var_vector); // 40 byte storage for list of Pokemon to remove, plus a permanent array terminator
byte removal_array_data[41];
for (int i = 0; i < 41; i++)
{
if (debug)
{
removal_array_data[i] = (i < 30 ? (29 - i) : 0xFF);
}
else
{
removal_array_data[i] = (i < 30 ? 0xFD : 0xFF);
}
}
removal_array.load_data(41, removal_array_data);
z80_variable transfer_wait_string(&var_vector, 13, // SENDING DATA
0x92, 0x84, 0x8D, 0x83, 0x88, 0x8D, 0x86, 0x7F, 0x83, 0x80, 0x93, 0x80, 0x50);
z80_variable custom_name(&var_vector, 11, // FENNEL
0x85, 0x84, 0x8D, 0x8D, 0x84, 0x8B, 0x50, 0x50, 0x50, 0x50, 0x50);
// RNG Seed:
// at 0x00, 0x0A in length
// Can be empty
// Preamble
// At 0x00, 0x07 in length
// Must be filled with 0xFD
for (int i = 0; i < 7; i++)
{
z80_payload.add_byte(0xFD);
}
// Rival name
// At 0x07, 0x0B in length
// Set to stored name
z80_payload.index = 0x07;
custom_name.insert_variable(&z80_payload);
// Number of Pokemon
// At 0x12, 0x01 in length
// 2 or higher, 0xE8 for JPN
z80_payload.index = 0x12;
z80_payload.add_byte(0x02);
// Pokemon list
// At 0x13, is usually 6 bytes and 1 terminator
for (int i = 0; i < 7; i++)
{
z80_payload.add_byte(i < 6 ? i + 1 : 0xFF);
}
// Pokemon data
// Specific for each language
// Mon #1 HP
z80_payload.add_bytes(2,
0x00, 0x00);
// Mon #2 data
z80_payload.index = 0x46;
z80_payload.add_bytes(9,
0x4E, 0x4E, 0x4E, 0x00, 0x01, 0x80, 0x80, 0xD4, 0xCF);
z80_payload.add_bytes(2, asm_start.place_pointer(&z80_payload), 0x00); // These values must not have any control characters in them.
z80_payload.add_bytes(33,
0x4E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4E, 0x50, 0x00, 0x00,
0x00, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x59);
// Mon #2 name
z80_payload.index = 0x16F;
for (int i = 0; i < 11; i++)
{
z80_payload.add_byte(0x4E);
}
// Now that the ACE has been set up, we can use the space between Mon #2's data and Mon #2's name to put our code.
// Since this space is larger than the patchlist, we will be able to fit everything in it
// Patchlist preamble
// At 0x1B4 0x07 in length
// Set as five 0xFD, the 0xFF will be added as part of the patch list.
for (int i = 0; i < 5; i++)
{
z80_patchlist.add_byte(0xFD);
}
z80_payload.index = 0x72;
array_counter.insert_variable(&z80_payload);
removal_array.insert_variable(&z80_payload);
transfer_wait_string.insert_variable(&z80_payload);
asm_start.set_start(&z80_payload);
z80_payload.CALL(0x2233 | T_U16); // Stop the battle music
/* Write transferring message to screen: */
// call ClearScreen
z80_payload.CALL(curr_rom.clearScreen | T_U16);
z80_payload.LD(HL, curr_rom.textBorderUppLeft | T_U16);
z80_payload.LD(C, curr_rom.textBorderWidth | T_U8);
z80_payload.LD(B, curr_rom.textBorderHeight | T_U8);
z80_payload.CALL(curr_rom.CableClub_TextBoxBorder | T_U16);
z80_payload.LD(HL, curr_rom.transferStringLocation | T_U16);
z80_payload.LD(DE, transfer_wait_string.place_ptr(&z80_payload) | T_U16);
z80_payload.CALL(curr_rom.placeString | T_U16);
z80_payload.JR(skip_enemy_write.place_relative_jump(&z80_payload) | T_I8); // This is a simple way to avoid the enemy name placement. Might have to modify for other languages
z80_payload.index = 0xCA;
skip_enemy_write.set_start(&z80_payload);
// Reload the save data to remove any data that was overwritten during exploit entry
z80_payload.LD(B, (curr_rom.LoadCurrentBoxData >> 16) | T_U8);
z80_payload.LD(HL, curr_rom.LoadCurrentBoxData | T_U16);
z80_payload.CALL(curr_rom.Bankswitch | T_U16);
if (!debug)
{
/* Build the packet */
// HL is the current data pointer
// DE is the destination pointer
// A is the checksum
// B is the 0xFE flag byte
// C is the counter
send_packet_loop.set_start(&z80_payload);
z80_payload.LD(HL, (DATA_LOC + PACKET_SIZE + 3) | T_U16); // Load the next data location into HL
z80_payload.LD(A, HLI_PTR);
z80_payload.LD(H, HL_PTR);
z80_payload.LD(L, A);
z80_payload.LD(DE, (DATA_LOC + 2) | T_U16); // Enemy Pokemon data, should be unused
z80_payload.XOR(A, A); // Clear the register
z80_payload.LD(B, A); // Clear B as well
z80_payload.LD(C, A); // Clear C as well
z80_payload.PUSH(AF);
packet_loop.set_start(&z80_payload);
z80_payload.LD(B, 0x00 | T_U8); // Reset the flag byte
z80_payload.POP(AF);
z80_payload.ADD(A, HL_PTR); // Add the current data to the checksum
z80_payload.PUSH(AF);
z80_payload.LD(A, 0xFE);
z80_payload.CP(A, HL_PTR); // Compare the current data to 0xFE
z80_payload.LD(A, HLI_PTR); // Load HL's data into A for modification (if need be)
// If HL's data is 0xFE
z80_payload.JR(NZ_F, fe_bypass.place_relative_jump(&z80_payload) | T_I8);
z80_payload.DEC(A);
z80_payload.INC(B); // Set flag
fe_bypass.set_start(&z80_payload);
z80_payload.LD(DE_PTR, A); // Place the data in
z80_payload.INC(DE);
z80_payload.PUSH(AF);
z80_payload.LD(A, B);
z80_payload.LD(DE_PTR, A); // Place the flag in as well
z80_payload.POP(AF);
z80_payload.INC(DE);
z80_payload.INC(C);
z80_payload.LD(A, DATA_PER_PACKET - 1);
z80_payload.CP(A, C);
z80_payload.JR(NC_F, packet_loop.place_relative_jump(&z80_payload) | T_I8); // If all the data has been set, send the rest of the data
z80_payload.POP(AF);
z80_payload.RES(7 | T_BIT, A); // Reset bit 7 of the checksum, guaranteeing that it will never be 0xFE
z80_payload.LD(DE_PTR, A);
z80_payload.INC(DE);
z80_payload.LD(A, H);
z80_payload.LD(DE_PTR, A);
z80_payload.INC(DE);
z80_payload.LD(A, L);
z80_payload.LD(DE_PTR, A);
/* Transfer box data packet: */
z80_payload.LD(A, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug
z80_payload.LDH((curr_rom.hSerialConnectionStatus & 0xFF) | T_U8, A); // Since hSerialConnectionStatus is at 0xFFxx we can use this method instead
z80_payload.LD(HL, DATA_LOC | T_U16);
z80_payload.LD(HL_PTR, 0xFD | T_U8); // set the start of the data to 0xFD so Serial_ExchangeBytes is happy
z80_payload.INC(HL);
z80_payload.LD(HL_PTR, 0x00 | T_U8); // add a 0x00 after the 0xFD to prevent further 0xFDs from being interpreted as part of the preamble
z80_payload.DEC(HL); // Reset HL back so it points to 0xFD
z80_payload.LD(DE, (DATA_LOC + PACKET_SIZE) | T_U16); // location to put stored data
z80_payload.LD(BC, PACKET_SIZE | T_U16);
if (debug) // Don't call serialExchangeBytes if debug is enabled
{
z80_payload.index += 3;
}
else
{
z80_payload.CALL(curr_rom.Serial_ExchangeBytes | T_U16);
}
z80_payload.LD(A, (DATA_LOC + PACKET_SIZE + 3 + 1) | T_U16);
z80_payload.CP(A, 0xFF);
if (debug && false) // Don't compare the "recieved" data if in debug
{
z80_payload.index += 2;
}
else
{
z80_payload.JR(NZ_F, send_packet_loop.place_relative_jump(&z80_payload) | T_I8);
}
}
/* Recieve the Pokemon to remove */
z80_payload.LD(HL, curr_rom.hSerialConnectionStatus | T_U16); // This can also be shortened
z80_payload.LD(HL_PTR, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug
z80_payload.LD(HL, curr_rom.garbageDataLocation | T_U16);
z80_payload.LD(DE, removal_array.place_ptr(&z80_payload) | T_U16);
z80_payload.LD(BC, 0x001E | T_U16); // Preamble does *not* count
if (debug) // Don't add in the Serial_ExchangeBytes call if in debug
{
z80_payload.index += 3;
}
else
{
z80_payload.CALL(curr_rom.Serial_ExchangeBytes | T_U16);
}
/* Remove the transfered Pokemon */
z80_payload.LD(HL, curr_rom.wRemoveMonFromBox | T_U16);
z80_payload.LD(HL_PTR, 0x01 | T_U8); // != 0x00 specifies the current box
remove_array_loop.set_start(&z80_payload);
z80_payload.LD(A, array_counter.place_ptr(&z80_payload) | T_U16);
z80_payload.LD(E, A);
z80_payload.LD(D, 0x00 | T_U8);
z80_payload.LD(HL, removal_array.place_ptr(&z80_payload) | T_U16);
z80_payload.ADD(HL, DE);
z80_payload.INC(A);
z80_payload.LD(array_counter.place_ptr(&z80_payload) | T_U16, A);
z80_payload.LD(A, curr_rom.wBoxCount | T_U16);
z80_payload.LD(B, A);
z80_payload.LD(A, HL_PTR);
z80_payload.CP(A, 0xFF | T_U8);
z80_payload.JR(Z_F, save_box.place_relative_jump(&z80_payload) | T_I8);
z80_payload.CP(A, B);
z80_payload.JR(NC_F, remove_array_loop.place_relative_jump(&z80_payload) | T_I8);
z80_payload.LD(HL, curr_rom.wWhichPokemon | T_U16);
z80_payload.LD(HL_PTR, A);
if (DONT_REMOVE_PKMN)
{
z80_payload.index += 3;
}
else
{
z80_payload.LD(B, (curr_rom._RemovePokemon >> 16) | T_U8); // Load ROM Bank
z80_payload.LD(HL, curr_rom._RemovePokemon | T_U16);
z80_payload.CALL(curr_rom.Bankswitch | T_U16);
}
z80_payload.JR((remove_array_loop.place_relative_jump(&z80_payload) & 0xFF) | T_I8);
// We need to move this in order to not corrupt the 4E's
z80_payload.JR((save_box.place_relative_jump(&z80_payload) & 0xFF) | T_I8);
z80_payload.index = 0x17A;
/* Save the current box */
save_box.set_start(&z80_payload);
z80_payload.LD(B, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8); // Load ROM Bank
z80_payload.LD(HL, curr_rom.SaveSAVtoSRAM1 | T_U16);
z80_payload.CALL(curr_rom.Bankswitch | T_U16);
z80_payload.CALL(curr_rom.SaveSAVtoSRAM2 | T_U16); // The bank is already loaded, we don't have to load it again
z80_payload.JP(curr_rom.SoftReset | T_U16);
// z80_payload.index += 5;
// Patchlist
// At 0x1BB / 0x1DE, 0xC2 in length (0xC4, but the last 2 are unused)
z80_patchlist.generate_patchlist(&z80_payload);
// This payload works by placing Pokemon ID 0xFC's name in the stack, and causing a return to CD8E,
// which is part of the RNG seed. From there we can jump anywhere- and we choose to jump to D887,
// which is the rival's name. This code fixes the stack and jumps to the patchlist, which is where
// our final code is.
// Update all the pointers
for (unsigned int i = 0; i < var_vector.size(); i++)
{
var_vector.at(i)->update_ptrs();
}
for (unsigned int i = 0; i < jump_vector.size(); i++)
{
jump_vector.at(i)->update_jumps();
}
// Combine the vectors into the full payload
u8 *cur_out = payload_buffer;
memcpy(cur_out, z80_rng_seed.data_vector.data(), z80_rng_seed.data_vector.size());
cur_out += z80_rng_seed.data_vector.size();
memcpy(cur_out, z80_payload.data_vector.data(), z80_payload.data_vector.size());
cur_out += z80_payload.data_vector.size();
memcpy(cur_out, z80_patchlist.data_vector.data(), z80_patchlist.data_vector.size());
cur_out += z80_patchlist.data_vector.size();
return;
/*
else if (type == EVENT)
{
// ld a, $03
payload_storage[offset++] = 0x3A;
payload_storage[offset++] = 0x03;
// call OpenSRAM
payload_storage[offset++] = 0xC3;
payload_storage[offset++] = (curr_rom.OpenSRAM >> 0) & 0xFF;
payload_storage[offset++] = (curr_rom.OpenSRAM >> 8) & 0xFF;
// ld de, $BEB0
payload_storage[offset++] = 0x11;
payload_storage[offset++] = 0xB0;
payload_storage[offset++] = 0xBE;
// ld bc, $150
payload_storage[offset++] = 0x01;
payload_storage[offset++] = 0x50;
payload_storage[offset++] = 0x01;
// ld hl, ???
payload_storage[offset++] = 0x21;
payload_storage[offset++] = 0x00;
payload_storage[offset++] = 0x00;
// CUSTOM EVENT SCRIPT:
// Start with the table data
int init_offset = offset;
insert_ext_copy_cmd(&offset, 0x11410E, 0xD930, 18); // Copy text pointers
insert_ext_copy_cmd(&offset, 0x00C120, 0xC140, 10); //
insert_ext_copy_cmd(&offset, 0x00C220, 0xC240, 16); //
byte temp[] = {0xD0, 0x0A};
insert_int_copy_cmd(&offset, 0xD4E9, 2, temp); //
byte temp1[] = {0x15, 0x05};
insert_int_copy_cmd(&offset, 0xD517, 2, temp1); //
byte temp2[] = {0x30, 0xD9};
insert_int_copy_cmd(&offset, 0xD36B, 2, temp2); //
byte temp3[] = {0x0B, 0xF0, 0xFF};
insert_int_copy_cmd(&offset, 0xD5D3, 3, temp3); //
byte temp4[] = {0x05};
insert_int_copy_cmd(&offset, 0xD4E0, 1, temp4); //
byte temp5[] = {0x44, 0xD9, 0x08, 0x21, 0x54, 0xD9, 0xCD, 0x68, 0x31, 0x21, 0xB0, 0xC1, 0x00, 0x00, 0xC3, 0xD2, 0x23, 0x01, 0x00, 0x5E, 0xD8, 0xD8, 0xC9, 0xD8, 0xC9, 0xD8, 0xC9, 0xD8, 0xC9, 0x00, 0x8C, 0xB8, 0xB4, 0xB4, 0xE7, 0x50, 0x08, 0x3E, 0x83, 0xCD, 0x8B, 0x11, 0xCD, 0x3E, 0x37, 0xC3, 0xD2, 0x23};
insert_int_copy_cmd(&offset, 0xD942, 48, temp5); //
payload_storage[offset++] = 0xFF;
// call CloseSRAM
payload_storage[offset++] = 0xC3;
payload_storage[offset++] = (curr_rom.CloseSRAM >> 0) & 0xFF;
payload_storage[offset++] = (curr_rom.CloseSRAM >> 8) & 0xFF;
// call SoftReset
payload_storage[offset++] = 0xC3;
payload_storage[offset++] = (curr_rom.SoftReset >> 0) & 0xFF;
payload_storage[offset++] = (curr_rom.SoftReset >> 8) & 0xFF;
}*/
}
else if (curr_rom.generation == 2)
{
std::vector<z80_jump *> jump_vector;
std::vector<z80_variable *> var_vector;
z80_asm_handler z80_rng_seed(0x0A, curr_rom.wSerialOtherGameboyRandomNumberListBlock);
z80_asm_handler z80_payload(0x1CD, curr_rom.wSerialEnemyDataBlock); // wOTPartyData
z80_asm_handler z80_patchlist(0xC9, curr_rom.wSerialEnemyMonsPatchList); // wOTPatchLists
/*
Initally the entire wLinkData is copied into the data section at D26B.
then, CopyBytes is called four times within link.skip_mail:
1. It copies 0xB bytes from wLinkData to wOTPlayerName (D26B)
2. It copies 0x8 bytes from where the previous one ended (D280) to wOTPartyCount
3. It copies 0x2 bytes from where the previous one ended (D276) to wOTPlayerID
4. It copies 0x1A4 bytes from where the previous one ended (D288) to wOTPartyMons
8 bytes aren't overwritten when copied over (D278-D28F), which is where the weird offset comes from. These bytes are index 0xE through 0x15 in the original data
By having 9 bytes of 0xFD, the offset ends up working out correctly.
*/
z80_jump asm_start(&jump_vector);
z80_jump save_box(&jump_vector);
z80_jump remove_array_loop(&jump_vector);
z80_jump jump_to_party(&jump_vector);
z80_jump jump_to_payload(&jump_vector);
z80_jump packet_loop(&jump_vector);
z80_jump fe_bypass(&jump_vector);
z80_jump send_packet_loop(&jump_vector);
z80_variable array_counter(&var_vector, 1, 0x00); // 1 byte to store the current array counter
z80_variable removal_array(&var_vector); // 40 byte storage for list of Pokemon to remove, plus a permanent array terminator
byte removal_array_data[41];
for (int i = 0; i < 41; i++)
{
if (debug)
{
removal_array_data[i] = (i < 30 ? (29 - i) : 0xFF);
}
else
{
removal_array_data[i] = (i < 30 ? 0xFD : 0xFF);
}
}
removal_array.load_data(41, removal_array_data);
z80_variable transfer_wait_string(&var_vector, 13, // SENDING DATA
0x92, 0x84, 0x8D, 0x83, 0x88, 0x8D, 0x86, 0x7F, 0x83, 0x80, 0x93, 0x80, 0x50);
z80_variable custom_name(&var_vector, 11, // FENNEL
0x85, 0x84, 0x8D, 0x8D, 0x84, 0x8B, 0x50, 0x50, 0x50, 0x50, 0x50);
// RNG Seed:
// at 0x00, 0x0A in length
// Does not need to be set
// Preamble
// At 0x00, 0x09 in length
// Must be filled with 0xFD
for (int i = 0; i < 9; i++)
{
z80_payload.add_byte(0xFD);
}
// Preamble/Rival name
// At 0x00, 0x1C5 in length
// Set to stored name
int distance = curr_rom.stack_overwrite_location - curr_rom.print_string_start;
int remainder = distance % 40;
distance /= 40; // Automatically truncated, so it won't overshoot
distance -= 8; // There will be 8 extra bytes due to how the copy functions work.
for (int i = 0; i < distance; i++)
{
z80_payload.add_byte(curr_rom.short_pkmn_name);
}
for (int i = 0; i < remainder; i++)
{
z80_payload.add_byte(0x80);
}
z80_payload.index -= 1; // Prep for the direct jump, since it usually has to jump forward one for the ASM call
jump_to_payload.place_direct_jump(&z80_payload);
z80_payload.index += 3;
z80_payload.add_byte(0x50); // String terminator
// Saving the box overwrites our code, so we need to move it here.
jump_to_party.set_start(&z80_payload);
z80_payload.LD(A, curr_rom.SaveBox >> 16 | T_U8);
z80_payload.RST(0x10); // Bank switch
z80_payload.CALL(curr_rom.SaveBox | T_U16);
z80_payload.JP(curr_rom.SoftReset | T_U16);
// Patchlist preamble
// At 0x1B4 / 0x1D7, 0x07 in length
// Set as five 0xFD and two 0xFF
for (int i = 0; i < 7; i++)
{
z80_patchlist.add_byte(i < 5 ? 0xFD : 0xFF);
}
// Patchlist
// At 0x1DE, 194 in length
// Fill with custom code
// Write transferring message to screen:
// call ClearScreen
jump_to_payload.set_start(&z80_patchlist);
z80_patchlist.CALL(curr_rom.clearScreen | T_U16);
z80_patchlist.LD(HL, curr_rom.textBorderUppLeft | T_U16);
z80_patchlist.LD(C, curr_rom.textBorderWidth | T_U8);
z80_patchlist.LD(B, curr_rom.textBorderHeight | T_U8);
z80_patchlist.LD(A, curr_rom.CableClub_TextBoxBorder >> 16 | T_U8);
z80_patchlist.RST(0x10); // Bank switch
z80_patchlist.CALL(curr_rom.CableClub_TextBoxBorder | T_U16);
z80_patchlist.LD(HL, curr_rom.transferStringLocation | T_U16);
z80_patchlist.LD(DE, transfer_wait_string.place_ptr(&z80_patchlist) | T_U16);
// call PlaceString
z80_patchlist.CALL(curr_rom.placeString | T_U16);
// call OpenSRAM
z80_patchlist.LD(A, 0x01 | T_U8);
z80_patchlist.CALL(curr_rom.OpenSRAM | T_U16);
/* Build the packet */
// HL is the current data pointer
// DE is the destination pointer
// A is the checksum
// B is the 0xFE flag byte
// C is the counter
send_packet_loop.set_start(&z80_patchlist);
z80_patchlist.LD(HL, (DATA_LOC + PACKET_SIZE + 3) | T_U16); // Load the next data location into HL
z80_patchlist.LD(A, HLI_PTR);
z80_patchlist.LD(H, HL_PTR);
z80_patchlist.LD(L, A);
z80_patchlist.LD(DE, (DATA_LOC + 2) | T_U16); // Enemy Pokemon data, should be unused
z80_patchlist.XOR(A, A); // Clear the register
z80_patchlist.LD(B, A); // Clear B as well
z80_patchlist.LD(C, A); // Clear C as well
z80_patchlist.PUSH(AF);
packet_loop.set_start(&z80_patchlist);
z80_patchlist.LD(B, 0x00 | T_U8); // Reset the flag byte
z80_patchlist.POP(AF);
z80_patchlist.ADD(A, HL_PTR); // Add the current data to the checksum
z80_patchlist.PUSH(AF);
z80_patchlist.LD(A, 0xFE);
z80_patchlist.CP(A, HL_PTR); // Compare the current data to 0xFE
z80_patchlist.LD(A, HLI_PTR); // Load HL's data into A for modification (if need be)
// If HL's data is 0xFE
z80_patchlist.JR(NZ_F, fe_bypass.place_relative_jump(&z80_patchlist) | T_I8);
z80_patchlist.DEC(A);
z80_patchlist.INC(B); // Set flag
fe_bypass.set_start(&z80_patchlist);
z80_patchlist.LD(DE_PTR, A); // Place the data in
z80_patchlist.INC(DE);
z80_patchlist.PUSH(AF);
z80_patchlist.LD(A, B);
z80_patchlist.LD(DE_PTR, A); // Place the flag in as well
z80_patchlist.POP(AF);
z80_patchlist.INC(DE);
z80_patchlist.INC(C);
z80_patchlist.LD(A, DATA_PER_PACKET - 1);
z80_patchlist.CP(A, C);
z80_patchlist.JR(NC_F, packet_loop.place_relative_jump(&z80_patchlist) | T_I8); // If all the data has been set, send the rest of the data
z80_patchlist.POP(AF);
z80_patchlist.RES(7 | T_BIT, A); // Reset bit 7 of the checksum, guaranteeing that it will never be 0xFE
z80_patchlist.LD(DE_PTR, A);
z80_patchlist.INC(DE);
z80_patchlist.LD(A, H);
z80_patchlist.LD(DE_PTR, A);
z80_patchlist.INC(DE);
z80_patchlist.LD(A, L);
z80_patchlist.LD(DE_PTR, A);
/* Transfer box data packet: */
z80_patchlist.LD(A, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug
z80_patchlist.LDH((curr_rom.hSerialConnectionStatus & 0xFF) | T_U8, A); // Since hSerialConnectionStatus is at 0xFFxx we can use this method instead
z80_patchlist.LD(HL, DATA_LOC | T_U16);
z80_patchlist.LD(HL_PTR, 0xFD | T_U8); // set the start of the data to 0xFD so Serial_ExchangeBytes is happy
z80_patchlist.INC(HL);
z80_patchlist.LD(HL_PTR, 0x00 | T_U8); // add a 0x00 after the 0xFD to prevent further 0xFDs from being interpreted as part of the preamble
z80_patchlist.DEC(HL); // Reset HL back so it points to 0xFD
z80_patchlist.LD(DE, (DATA_LOC + PACKET_SIZE) | T_U16); // location to put stored data
z80_patchlist.LD(BC, PACKET_SIZE | T_U16);
if (debug) // Don't call serialExchangeBytes if debug is enabled
{
z80_patchlist.index += 3;
}
else
{
z80_patchlist.CALL(curr_rom.Serial_ExchangeBytes | T_U16);
}
z80_patchlist.LD(A, (DATA_LOC + PACKET_SIZE + 3 + 1) | T_U16);
z80_patchlist.CP(A, 0xFF);
z80_patchlist.JR(NZ_F, send_packet_loop.place_relative_jump(&z80_patchlist) | T_I8);
// Recieve the Pokemon to remove
z80_patchlist.LD(HL, curr_rom.hSerialConnectionStatus | T_U16); // This can also be shortened
z80_patchlist.LD(HL_PTR, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug
z80_patchlist.LD(HL, curr_rom.garbageDataLocation | T_U16);
z80_patchlist.LD(DE, removal_array.place_ptr(&z80_patchlist) | T_U16);
z80_patchlist.LD(BC, 0x001E | T_U16); // Preamble does *not* count
if (debug) // Don't add in the Serial_ExchangeBytes call if in debug
{
z80_patchlist.index += 3;
}
else
{
z80_patchlist.CALL(curr_rom.Serial_ExchangeBytes | T_U16);
}
// Remove the transfered Pokemon
z80_patchlist.LD(HL, curr_rom.wRemoveMonFromBox | T_U16);
z80_patchlist.LD(HL_PTR, 0x01 | T_U8); // != 0x00 specifies the current box
remove_array_loop.set_start(&z80_patchlist);
z80_patchlist.LD(A, array_counter.place_ptr(&z80_patchlist) | T_U16);
z80_patchlist.LD(E, A);
z80_patchlist.LD(D, 0x00 | T_U8);
z80_patchlist.LD(HL, removal_array.place_ptr(&z80_patchlist) | T_U16);
z80_patchlist.ADD(HL, DE);
z80_patchlist.INC(A);
z80_patchlist.LD(array_counter.place_ptr(&z80_patchlist) | T_U16, A);
z80_patchlist.LD(A, curr_rom.wBoxCount | T_U16);
z80_patchlist.LD(B, A);
z80_patchlist.LD(A, HL_PTR);
z80_patchlist.CP(A, 0xFF | T_U8);
z80_patchlist.JR(Z_F, save_box.place_relative_jump(&z80_patchlist) | T_I8);
z80_patchlist.CP(A, B);
z80_patchlist.JR(NC_F, remove_array_loop.place_relative_jump(&z80_patchlist) | T_I8);
z80_patchlist.LD(HL, curr_rom.wWhichPokemon | T_U16);
z80_patchlist.LD(HL_PTR, A);
if (DONT_REMOVE_PKMN)
{
z80_patchlist.index += 6;
}
else
{
z80_patchlist.LD(A, curr_rom._RemovePokemon >> 16 | T_U8);
z80_patchlist.RST(0x10); // Bank switch
z80_patchlist.CALL(curr_rom._RemovePokemon | T_U16);
}
z80_patchlist.JR(remove_array_loop.place_relative_jump(&z80_patchlist) | T_I8);
save_box.set_start(&z80_patchlist);
z80_patchlist.JP(jump_to_party.place_direct_jump(&z80_patchlist) | T_U16); // jp pkmn list (because saving the box overwrites the data)
array_counter.insert_variable(&z80_patchlist);
removal_array.insert_variable(&z80_payload);
transfer_wait_string.insert_variable(&z80_patchlist);
// This payload works by placing Pokemon ID 0xFC's name in the stack, and causing a return to CD8E,
// which is part of the RNG seed. From there we can jump anywhere- and we choose to jump to D887,
// which is the rival's name. This code fixes the stack and jumps to the patchlist, which is where
// our final code is.
// Update all the pointers
for (unsigned int i = 0; i < var_vector.size(); i++)
{
var_vector.at(i)->update_ptrs();
}
for (unsigned int i = 0; i < jump_vector.size(); i++)
{
jump_vector.at(i)->update_jumps();
}
// Combine the vectors into the full payload
u8 *cur_out = payload_buffer;
memcpy(cur_out, z80_rng_seed.data_vector.data(), z80_rng_seed.data_vector.size());
cur_out += z80_rng_seed.data_vector.size();
memcpy(cur_out, z80_payload.data_vector.data(), z80_payload.data_vector.size());
cur_out += z80_payload.data_vector.size();
memcpy(cur_out, z80_patchlist.data_vector.data(), z80_patchlist.data_vector.size());
cur_out += z80_patchlist.data_vector.size();
return;
// This payload works by placing Pokemon ID 0xFC's name in the stack, and causing a return to CD8E,
// which is part of the RNG seed. From there we can jump anywhere- and we choose to jump to D887,
// which is the rival's name. This code fixes the stack and jumps to the patchlist, which is where
// our final code is.
}
memset(payload_buffer, 0x00, PAYLOAD_SIZE);
};
#if PAYLOAD_EXPORT_TEST
#include <cstdio>
#include "gb_rom_values/gb_rom_values.h"
int main() // Rename to "main" to send the payload to test_payload.txt
{
byte buffer[672] = {0};
freopen("test_payload.txt", "w", stdout);
printf("\n");
init_payload(buffer, gb_rom_values_eng[RED_ID], TRANSFER, true);
if (true)
{
for (int i = 0; i < 0x2A0; i++)
{
printf("0x%02X, ", (unsigned int)buffer[i]);
if (i % 0x10 == 0xF)
{
printf("\n# 0x%X\n", i + 1);
}
}
return 0;
}
else
{
for (int i = 0; i < 0x150; i++)
{
printf("%02X ", (unsigned int)buffer[i + ((0x10 * 28) + 9)]);
if (i % 0x10 == 0xF)
{
printf("\n");
}
}
return 0;
}
}
#endif

View File

@ -1,7 +1,6 @@
#include <tonc.h>
#include "sprite_data.h"
#include "text_engine.h"
#include "pokemon_data.h"
#include "background_engine.h"
#define CBB 0
#define SBB 24

View File

@ -1,4 +1,5 @@
#include <tonc.h>
#include "pccs/typeDefs.h"
#include "button_menu.h"
#include "button_handler.h"
#include "save_data_manager.h"
@ -6,14 +7,13 @@
#include "string"
#include "sprite_data.h"
#include "box_menu.h"
#include "pokemon_data.h"
#include "text_engine.h"
#include "translated_text.h"
#include "text_data_table.h"
Box_Menu::Box_Menu() {};
int Box_Menu::box_main(Pokemon_Party party_data)
int Box_Menu::box_main(PokeBox* box)
{
u8 names_decompression_buffer[3072];
text_data_table PKMN_NAMES(names_decompression_buffer);
@ -22,7 +22,7 @@ int Box_Menu::box_main(Pokemon_Party party_data)
load_flex_background(BG_BOX, 2);
REG_BG1VOFS = 0;
REG_BG1HOFS = 0;
load_temp_box_sprites(&party_data);
load_temp_box_sprites(box);
Button cancel_button(button_cancel_left, button_cancel_right, 64);
Button confirm_button(button_confirm_left, button_confirm_right, 64);
cancel_button.set_location(88, 124);
@ -42,9 +42,9 @@ int Box_Menu::box_main(Pokemon_Party party_data)
{
if (get_frame_count() % 20 == 0)
{
for (int i = 0; i < 30; i++)
for (int i = 0; i < box->getNumInBox(); i++)
{
update_menu_sprite(&party_data, i, get_frame_count() % 40);
update_menu_sprite(box, i, get_frame_count() % 40);
}
}
if (curr_button == 0)
@ -128,15 +128,15 @@ int Box_Menu::box_main(Pokemon_Party party_data)
index = x + (y * BOXMENU_HNUM);
obj_set_pos(box_select, BOXMENU_LEFT + (x * (BOXMENU_SPRITE_WIDTH + BOXMENU_HSPACE)), BOXMENU_TOP + (y * (BOXMENU_SPRITE_HEIGHT + BOXMENU_VSPACE)));
tte_erase_rect(6, 16, 80, 152);
Simplified_Pokemon curr_pkmn = party_data.get_simple_pkmn(index);
GBPokemon* curr_pkmn = box->getGBPokemon(index);
obj_hide(grabbed_front_sprite);
if (curr_pkmn.is_valid)
if (index < box->getNumInBox() && curr_pkmn->isValid)
{
byte val[11];
tte_set_pos(6, 88);
ptgb_write(curr_pkmn.nickname, true);
if (curr_pkmn.is_shiny)
curr_pkmn->externalConvertNickname(val);
ptgb_write(val, true);
if (curr_pkmn->getIsShiny())
{
tte_set_pos(64, 16);
val[0] = 0xF9;
@ -144,14 +144,14 @@ int Box_Menu::box_main(Pokemon_Party party_data)
ptgb_write(val, true);
}
tte_set_pos(14, 98);
if (curr_pkmn.is_missingno)
if (curr_pkmn->getSpeciesIndexNumber() == MISSINGNO)
{
ptgb_write(PKMN_NAMES.get_text_entry(0), true);
}
else
{
ptgb_write(PKMN_NAMES.get_text_entry(curr_pkmn.dex_number), true);
ptgb_write(PKMN_NAMES.get_text_entry(curr_pkmn->getSpeciesIndexNumber()), true);
}
tte_set_pos(6, 108);
val[0] = 0xC6; // L
@ -160,10 +160,10 @@ int Box_Menu::box_main(Pokemon_Party party_data)
val[3] = 0x00; // " "
val[4] = 0xFF; // endline
ptgb_write(val, true);
convert_int_to_ptgb_str(curr_pkmn.met_level, val); // Val should never go out of bounds
convert_int_to_ptgb_str(curr_pkmn->getLevel(), val); // Val should never go out of bounds
ptgb_write(val, true);
update_front_box_sprite(&curr_pkmn);
update_front_box_sprite(curr_pkmn);
obj_unhide(grabbed_front_sprite, 0);
update_pos = false;
}

View File

@ -1,7 +1,6 @@
#include <tonc.h>
#include "libstd_replacements.h"
#include "flash_mem.h"
#include "pokemon.h"
#include "pokemon_data.h"
#include "rom_data.h"
#include "libraries/Pokemon-Gen3-to-Gen-X/include/save.h"
@ -97,16 +96,18 @@ void initalize_memory_locations()
void print_mem_section()
{
return; // This function isn't really needed now
/*
uint16_t charset[256];
byte out[4] = {0, 0, 0, 0xFF};
load_localized_charset(charset, 3, ENG_ID);
load_localized_charset(charset, 3, ENGLISH);
out[0] = get_char_from_charset(charset, mem_name);
out[1] = get_char_from_charset(charset, '-');
out[2] = get_char_from_charset(charset, mem_id + 0xA1); // Kinda a dumb way to
tte_set_pos(0, 0);
ptgb_write(out, true);
*/
}
// Reverses the endian of the given array
@ -158,29 +159,29 @@ bool read_flag(u16 flag_id)
{
tte_set_pos(0, 0);
tte_write("#{cx:0xD000}Attempting to read byte ");
tte_write(ptgb::to_string((curr_rom.offset_flags + (flag_id / 8)) % 0xF80));
tte_write(ptgb::to_string((curr_GBA_rom.offset_flags + (flag_id / 8)) % 0xF80));
tte_write(" of memory section ");
tte_write(ptgb::to_string(1 + ((curr_rom.offset_flags + (flag_id / 8)) / 0xF80)));
tte_write(ptgb::to_string(1 + ((curr_GBA_rom.offset_flags + (flag_id / 8)) / 0xF80)));
tte_write(" for flag ");
tte_write(ptgb::to_string(flag_id));
tte_write(". Flag is ");
copy_save_to_ram(memory_section_array[1 + ((curr_rom.offset_flags + (flag_id / 8)) / 0xF80)], &global_memory_buffer[0], 0x1000);
u8 flags = global_memory_buffer[(curr_rom.offset_flags + (flag_id / 8)) % 0xF80];
copy_save_to_ram(memory_section_array[1 + ((curr_GBA_rom.offset_flags + (flag_id / 8)) / 0xF80)], &global_memory_buffer[0], 0x1000);
u8 flags = global_memory_buffer[(curr_GBA_rom.offset_flags + (flag_id / 8)) % 0xF80];
tte_write(ptgb::to_string((flags >> (flag_id % 8)) & 0b1));
while (true)
{
};
}
copy_save_to_ram(memory_section_array[1 + ((curr_rom.offset_flags + (flag_id / 8)) / 0xF80)], &global_memory_buffer[0], 0x1000);
u8 flags = global_memory_buffer[(curr_rom.offset_flags + (flag_id / 8)) % 0xF80];
copy_save_to_ram(memory_section_array[1 + ((curr_GBA_rom.offset_flags + (flag_id / 8)) / 0xF80)], &global_memory_buffer[0], 0x1000);
u8 flags = global_memory_buffer[(curr_GBA_rom.offset_flags + (flag_id / 8)) % 0xF80];
return (flags >> (flag_id % 8)) & 0b1;
}
bool compare_map_and_npc_data(int map_bank, int map_id, int npc_id)
{
copy_save_to_ram(memory_section_array[4], &global_memory_buffer[0], 0x1000);
return (global_memory_buffer[curr_rom.offset_script + 5] == map_bank &&
global_memory_buffer[curr_rom.offset_script + 6] == map_id &&
global_memory_buffer[curr_rom.offset_script + 7] == npc_id);
return (global_memory_buffer[curr_GBA_rom.offset_script + 5] == map_bank &&
global_memory_buffer[curr_GBA_rom.offset_script + 6] == map_id &&
global_memory_buffer[curr_GBA_rom.offset_script + 7] == npc_id);
}

View File

@ -88,7 +88,7 @@ byte data_packet[PACKET_SIZE];
// Here's a compilation check to ensure that the size of these structs match our expectations.
// Just update it if you changed the struct members. The data-generator process prints their actual sizes.
static_assert(sizeof(struct GB_ROM) == 132);
static_assert(sizeof(struct GB_ROM) == 136);
static_assert(sizeof(struct ROM_DATA) == 160);
void print(const char *format, ...)
@ -169,7 +169,7 @@ void setup(const u16 *debug_charset)
}
}
byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, Simplified_Pokemon *curr_simple_array, const u16 *debug_charset, bool cancel_connection)
byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, PokeBox *box, const u16 *debug_charset, bool cancel_connection)
{
// TODO: Change to a switch statement
if (state == hs)
@ -224,7 +224,7 @@ byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_
text_data_table general_text(general_text_table_buffer);
general_text.decompress(get_compressed_general_table());
ptgb_write(general_text.get_text_entry(curr_gb_rom->version != YELLOW_ID ? GENERAL_link_success_yellow : GENERAL_link_success), true);
ptgb_write(general_text.get_text_entry(curr_gb_rom->version != YELLOW_ID ? GENERAL_link_success : GENERAL_link_success_yellow), true);
}
link_animation_state(STATE_NO_ANIM);
@ -340,7 +340,7 @@ byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_
if (in != 0xFD)
{
state = send_remove_array;
return exchange_remove_array(in, curr_simple_array, cancel_connection);
return exchange_remove_array(in, box, cancel_connection);
}
return in;
}
@ -352,27 +352,61 @@ byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_
state = end2;
}
data_counter++;
return exchange_remove_array(in, curr_simple_array, cancel_connection);
return exchange_remove_array(in, box, cancel_connection);
}
return in;
}
int loop(byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, Simplified_Pokemon *curr_simple_array, const u16 *debug_charset, bool cancel_connection)
int loop(byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, PokeBox *box, const u16 *debug_charset, bool cancel_connection)
{
#define LINE_WIDTH 21
#define NUM_LINES 8
int counter = 0;
char stuff[NUM_LINES][LINE_WIDTH];
while (true)
{
if (PRINT_LINK_DATA && key_held(KEY_L))
{
while (!key_hit(KEY_R))
{
global_next_frame();
}
global_next_frame();
}
// TODO: Restore Errors
in_data = linkSPI->transfer(out_data);
if (PRINT_LINK_DATA && false)
if (PRINT_LINK_DATA && !key_held(KEY_DOWN))
{
tte_set_margins(0, 0, H_MAX, V_MAX);
print("%d: [%d][%d][%" PRIu8 "][%" PRIu8 "]\n\n", counter, data_counter, state, in_data, out_data);
// tte_set_margins(0, 0, H_MAX, V_MAX);
// print("%d: [%d][%d][%" PRIu8 "][%" PRIu8 "]\n\n", counter, data_counter, state, in_data, out_data);
for (int i = 0; i < NUM_LINES; i++)
{
// ptgb_write_debug(debug_charset, "\n", true);
for (int j = 0; j < LINE_WIDTH; j++)
{
stuff[i][j] = stuff[i + 1][j];
}
stuff[i][20] = '\n';
}
n2hexstr(&stuff[NUM_LINES - 1][0], counter & 0xFFFFFF, 6);
stuff[NUM_LINES - 1][6] = ':';
n2hexstr(&stuff[NUM_LINES - 1][7], data_counter & 0xFFFF, 4);
stuff[NUM_LINES - 1][11] = '|';
n2hexstr(&stuff[NUM_LINES - 1][12], state & 0xFF, 2);
stuff[NUM_LINES - 1][14] = '|';
n2hexstr(&stuff[NUM_LINES - 1][15], in_data & 0xFF, 2);
stuff[NUM_LINES - 1][17] = '|';
n2hexstr(&stuff[NUM_LINES - 1][18], out_data & 0xFF, 2);
stuff[NUM_LINES - 1][20] = '\0';
create_textbox(0, 0, 125, 80, false);
ptgb_write_debug(debug_charset, *stuff, true);
}
out_data = handleIncomingByte(in_data, box_data_storage, curr_payload, curr_gb_rom, curr_simple_array, debug_charset, cancel_connection);
out_data = handleIncomingByte(in_data, box_data_storage, curr_payload, curr_gb_rom, box, debug_charset, cancel_connection);
if (FF_count > (15 * 60))
{
@ -557,13 +591,13 @@ byte exchange_boxes(byte curr_in, byte *box_data_storage, GB_ROM *curr_gb_rom)
}
};
byte exchange_remove_array(byte curr_in, Simplified_Pokemon *curr_simple_array, bool cancel_connection)
byte exchange_remove_array(byte curr_in, PokeBox *box, bool cancel_connection)
{
for (int i = 29; i >= 0; i--)
{
if (curr_simple_array[i].is_valid && !curr_simple_array[i].is_transferred && !cancel_connection)
if (box->getGen3Pokemon(i)->isValid && !cancel_connection)
{
curr_simple_array[i].is_transferred = true;
box->removePokemon(i);
return i;
}
}

View File

@ -48,7 +48,7 @@ void global_next_frame()
if (global_frame_count % 60 == 0)
{
set_menu_sprite_pal(0);
if (!curr_rom.verify_rom())
if (!curr_GBA_rom.verify_rom())
{
REG_BG0CNT = (REG_BG0CNT & ~BG_PRIO_MASK) | BG_PRIO(2);
REG_BG2CNT = (REG_BG2CNT & ~BG_PRIO_MASK) | BG_PRIO(1);
@ -247,7 +247,7 @@ void set_missingno(bool val)
missingno_enabled = val;
if (val == false)
{
set_background_pal(curr_rom.gamecode, false, false);
set_background_pal(curr_GBA_rom.gamecode, false, false);
fennel_blink_timer = 0;
}
}
@ -267,21 +267,6 @@ bool get_treecko_enabled()
return treecko_enabled;
}
// FNV-1a 32-bit hash function for byte arrays
u32 fnv1a_hash(unsigned char *data, size_t length)
{
const uint32_t fnv_prime = 0x01000193;
const uint32_t fnv_offset_basis = 0x811C9DC5;
uint32_t hash = fnv_offset_basis;
for (size_t i = 0; i < length; ++i)
{
hash ^= data[i];
hash *= fnv_prime;
}
return hash;
}
int get_string_length(const byte *str)
{
int size = 0;

View File

@ -6,7 +6,6 @@
#include "interrupt.h"
#include "gb_link.h"
#include "gameboy_colour.h"
#include "pokemon.h"
#include "random.h"
#include "text_engine.h"
#include "background_engine.h"
@ -51,7 +50,7 @@ TODO:
int delay_counter = 0;
int curr_selection = 0;
bool skip = true;
rom_data curr_rom;
rom_data curr_GBA_rom;
Button_Menu yes_no_menu(1, 2, 40, 24, false);
/*
@ -87,18 +86,6 @@ int test_main(void) Music
// (R + G*32 + B*1024)
#define RGB(r, g, b) (r + (g * 32) + (b * 1024))
// make sure outBuffer is large enough! Should be at least hex_len + 1
template <typename I>
void n2hexstr(char* outBuffer, I w, size_t hex_len = sizeof(I) << 1)
{
static const char *digits = "0123456789ABCDEF";
memset(outBuffer, '0', hex_len);
outBuffer[hex_len] = '\0'; // we must make sure to terminate the string
for (size_t i = 0, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4)
outBuffer[i] = digits[(w >> j) & 0x0f];
}
void load_graphics()
{
@ -253,18 +240,18 @@ int credits()
{
char hexBuffer[16];
uint16_t charset[256];
load_localized_charset(charset, 3, ENG_ID);
load_localized_charset(charset, 3, ENGLISH);
if (key_held(KEY_UP) && key_held(KEY_L) && key_held(KEY_R))
{
set_treecko(true);
}
u32 pkmn_flags = 0;
bool e4_flag = read_flag(curr_rom.e4_flag);
bool mg_flag = read_flag(curr_rom.mg_flag);
bool all_collected_flag = read_flag(curr_rom.all_collected_flag);
bool e4_flag = read_flag(curr_GBA_rom.e4_flag);
bool mg_flag = read_flag(curr_GBA_rom.mg_flag);
bool all_collected_flag = read_flag(curr_GBA_rom.all_collected_flag);
for (int i = 0; i < 30; i++)
{
pkmn_flags |= (read_flag(curr_rom.pkmn_collected_flag_start + i) << i);
pkmn_flags |= (read_flag(curr_GBA_rom.pkmn_collected_flag_start + i) << i);
}
bool tutorial = get_tutorial_flag();
@ -272,8 +259,8 @@ int credits()
create_textbox(4, 1, 160, 80, true);
ptgb_write_debug(charset, "Debug info:\n\nG: ", true);
ptgb_write_debug(charset, ptgb::to_string(curr_rom.language), true);
switch (curr_rom.gamecode)
ptgb_write_debug(charset, ptgb::to_string(curr_GBA_rom.language), true);
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
ptgb_write_debug(charset, "-R-", true);
@ -292,7 +279,7 @@ int credits()
break;
}
ptgb_write_debug(charset, ptgb::to_string(curr_rom.version), true);
ptgb_write_debug(charset, ptgb::to_string(curr_GBA_rom.version), true);
ptgb_write_debug(charset, "\nF: ", true);
ptgb_write_debug(charset, ptgb::to_string(e4_flag), true);
@ -455,7 +442,7 @@ static void __attribute__((noinline)) show_intro()
REG_BG1CNT = REG_BG1CNT | BG_PRIO(3);
key_poll(); // Reset the keys
curr_rom.load_rom();
curr_GBA_rom.load_rom();
obj_set_pos(ptgb_logo_l, 56, 12);
obj_set_pos(ptgb_logo_r, 56 + 64, 12);
@ -501,7 +488,7 @@ int main(void)
REG_BLDALPHA = BLDA_BUILD(0b10000, 0); // Reset fade
// Check if the game has been loaded correctly.
while (!curr_rom.load_rom())
while (!curr_GBA_rom.load_rom())
{
obj_hide_multi(ptgb_logo_l, 2);
global_next_frame();
@ -516,13 +503,14 @@ int main(void)
initalize_memory_locations();
load_custom_save_data();
set_background_pal(curr_rom.gamecode, false, true);
set_background_pal(curr_GBA_rom.gamecode, false, true);
if (!IGNORE_MG_E4_FLAGS && (!get_tutorial_flag() || FORCE_TUTORIAL))
{
obj_hide_multi(ptgb_logo_l, 2);
text_loop(BTN_TRANSFER);
initalize_save_data();
// TODO: We should be able to test for a Bootleg rom in here- if the save data isn't written, then it is bootleg.
}
obj_unhide_multi(ptgb_logo_l, 1, 2);
@ -533,7 +521,7 @@ int main(void)
if (DEBUG_MODE && false) // This isn't really needed anymore
{
print_mem_section();
curr_rom.print_rom_info();
curr_GBA_rom.print_rom_info();
}
load_flex_background(BG_MAIN_MENU, 2);
@ -555,10 +543,10 @@ int main(void)
obj_hide_multi(ptgb_logo_l, 2);
global_next_frame();
load_flex_background(BG_DEX, 2);
set_background_pal(curr_rom.gamecode, true, false);
set_background_pal(curr_GBA_rom.gamecode, true, false);
pokedex_loop();
load_flex_background(BG_DEX, 3);
set_background_pal(curr_rom.gamecode, false, false);
set_background_pal(curr_GBA_rom.gamecode, false, false);
}
break;
case (BTN_CREDITS):

View File

@ -10,7 +10,7 @@
#define MG_SCRIPT false
#define S30_SCRIPT true
extern rom_data curr_rom;
extern rom_data curr_GBA_rom;
bool asm_payload_location;
// These are static variables
@ -75,60 +75,55 @@ union decompressed_data_storage_union
// constructor and destructor are needed to make the compiler stop complaining
// about the decompressed_data_tables struct not being trivial
decompressed_data_storage_union(){}
~decompressed_data_storage_union(){}
decompressed_data_storage_union() {}
~decompressed_data_storage_union() {}
};
mystery_gift_script::mystery_gift_script(u8 *save_section_30_buffer)
: curr_mg_index(NPC_LOCATION_OFFSET)
, curr_section30_index(0)
, save_section_30(save_section_30_buffer)
, mg_script()
, value_buffer()
, four_align_value(0)
: curr_mg_index(NPC_LOCATION_OFFSET), curr_section30_index(0), save_section_30(save_section_30_buffer), mg_script(), value_buffer(), four_align_value(0)
{
ptr_call_check_flag = (curr_rom.loc_gSpecialVar_0x8000 + 0x08);
ptr_call_return_2 = (curr_rom.loc_gSpecialVar_0x8000 + 0x0A);
ptr_box_return = (curr_rom.loc_gSpecialVar_0x8000 + 0x0C);
ptr_dex_seen_caught = (curr_rom.loc_gSpecialVar_0x8000 + 0x0E);
ptr_index = (curr_rom.loc_gSpecialVar_0x8000 + 0x12);
ptr_pkmn_offset = (curr_rom.loc_gSpecialVar_0x8000 + 0x14);
ptr_call_check_flag = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x08);
ptr_call_return_2 = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x0A);
ptr_box_return = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x0C);
ptr_dex_seen_caught = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x0E);
ptr_index = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x12);
ptr_pkmn_offset = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x14);
// TODO: For old script, can be removed later
ptr_callASM = (curr_rom.loc_gSpecialVar_0x8000 + 0x00);
ptr_script_ptr_low = (curr_rom.loc_gSpecialVar_0x8000 + 0x02);
ptr_script_ptr_high = (curr_rom.loc_gSpecialVar_0x8000 + 0x04);
ptr_call_return_1 = (curr_rom.loc_gSpecialVar_0x8000 + 0x06);
ptr_block_ptr_low = (curr_rom.loc_gSaveBlock1PTR + 0x00);
ptr_block_ptr_high = (curr_rom.loc_gSaveBlock1PTR + 0x02);
ptr_callASM = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x00);
ptr_script_ptr_low = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x02);
ptr_script_ptr_high = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x04);
ptr_call_return_1 = (curr_GBA_rom.loc_gSpecialVar_0x8000 + 0x06);
ptr_block_ptr_low = (curr_GBA_rom.loc_gSaveBlock1PTR + 0x00);
ptr_block_ptr_high = (curr_GBA_rom.loc_gSaveBlock1PTR + 0x02);
}
void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
void mystery_gift_script::build_script(PokeBox *box)
{
decompressed_data_storage_union decompressed_store;
text_data_table decompressed_text_table(decompressed_store.text.buffer);
ptgb::vector<script_var *> mg_variable_list;
ptgb::vector<script_var *> sec30_variable_list;
asm_var sendMonToPC_ptr(curr_rom.loc_sendMonToPC + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var sendMonToPC_ptr(curr_GBA_rom.loc_sendMonToPC + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var returned_box_success_ptr(ptr_box_return, sec30_variable_list, &curr_section30_index);
asm_var curr_pkmn_index_ptr(ptr_pkmn_offset, sec30_variable_list, &curr_section30_index);
asm_var setPokedexFlag_ptr(curr_rom.loc_setPokedexFlag + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var setPokedexFlag_ptr(curr_GBA_rom.loc_setPokedexFlag + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var dexSeenCaught_ptr(ptr_dex_seen_caught, sec30_variable_list, &curr_section30_index);
asm_var currPkmnIndex_ptr(ptr_index, sec30_variable_list, &curr_section30_index);
asm_var pkmnStruct(curr_rom.loc_gSaveDataBuffer, sec30_variable_list, &curr_section30_index);
asm_var dexStruct(curr_rom.loc_gSaveDataBuffer + (MAX_PKMN_IN_BOX * POKEMON_SIZE), sec30_variable_list, &curr_section30_index);
asm_var m4aMPlayStop_ptr(curr_rom.loc_m4aMPlayStop + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var gMPlayInfo_BGM_ptr(curr_rom.loc_gMPlayInfo_BGM, sec30_variable_list, &curr_section30_index);
asm_var gMPlayInfo_SE2_ptr(curr_rom.loc_gMPlayInfo_SE2, sec30_variable_list, &curr_section30_index);
asm_var MPlayStart_ptr(curr_rom.loc_MPlayStart + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var CreateFanfareTask_ptr(curr_rom.loc_CreateFanfareTask + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var sFanfareCounter_ptr(curr_rom.loc_sFanfareCounter, sec30_variable_list, &curr_section30_index);
asm_var gPlttBufferFaded_ptr(curr_rom.loc_gPlttBufferFaded + (32 * 0x1A), sec30_variable_list, &curr_section30_index); // 0x1A is the pallet number
asm_var copySizeControl(CPU_SET_32BIT | ((32) / (32 / 8) & 0x1FFFFF), sec30_variable_list, &curr_section30_index); // CPU_SET_32BIT | ((size)/(32/8) & 0x1FFFFF)
asm_var pkmnStruct(curr_GBA_rom.loc_gSaveDataBuffer, sec30_variable_list, &curr_section30_index);
asm_var dexStruct(curr_GBA_rom.loc_gSaveDataBuffer + (MAX_PKMN_IN_BOX * POKEMON_SIZE), sec30_variable_list, &curr_section30_index);
asm_var m4aMPlayStop_ptr(curr_GBA_rom.loc_m4aMPlayStop + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var gMPlayInfo_BGM_ptr(curr_GBA_rom.loc_gMPlayInfo_BGM, sec30_variable_list, &curr_section30_index);
asm_var gMPlayInfo_SE2_ptr(curr_GBA_rom.loc_gMPlayInfo_SE2, sec30_variable_list, &curr_section30_index);
asm_var MPlayStart_ptr(curr_GBA_rom.loc_MPlayStart + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var CreateFanfareTask_ptr(curr_GBA_rom.loc_CreateFanfareTask + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var sFanfareCounter_ptr(curr_GBA_rom.loc_sFanfareCounter, sec30_variable_list, &curr_section30_index);
asm_var gPlttBufferFaded_ptr(curr_GBA_rom.loc_gPlttBufferFaded + (32 * 0x1A), sec30_variable_list, &curr_section30_index); // 0x1A is the pallet number
asm_var copySizeControl(CPU_SET_32BIT | ((32) / (32 / 8) & 0x1FFFFF), sec30_variable_list, &curr_section30_index); // CPU_SET_32BIT | ((size)/(32/8) & 0x1FFFFF)
asm_var flashBuffer_ptr(curr_rom.loc_gSaveDataBuffer, mg_variable_list, &curr_mg_index);
asm_var readFlashSector_ptr(curr_rom.loc_readFlashSector + READ_AS_THUMB, mg_variable_list, &curr_mg_index);
asm_var flashBuffer_ptr(curr_GBA_rom.loc_gSaveDataBuffer, mg_variable_list, &curr_mg_index);
asm_var readFlashSector_ptr(curr_GBA_rom.loc_readFlashSector + READ_AS_THUMB, mg_variable_list, &curr_mg_index);
asm_var mainAsmStart(sec30_variable_list, &curr_section30_index);
asm_var dexAsmStart(sec30_variable_list, &curr_section30_index);
@ -249,7 +244,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
const int movementWalkBackArrayFRLG[2] = {MOVEMENT_ACTION_WALK_FAST_DOWN, MOVEMENT_ACTION_WALK_FAST_DOWN};
const int movementWalkBackArrayE[4] = {MOVEMENT_ACTION_WALK_FAST_RIGHT, MOVEMENT_ACTION_WALK_FAST_RIGHT, MOVEMENT_ACTION_WALK_FAST_RIGHT, MOVEMENT_ACTION_WALK_FAST_DOWN};
switch (curr_rom.gamecode)
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -304,7 +299,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
// songLooker.add_track(track_7, sizeof(track_7));
unsigned char instrument;
switch (curr_rom.gamecode)
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -331,14 +326,23 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
// placement new is required to run the constructor of PokemonTables for the decompressed_store's instance
// it won't get called automatically because it's part of the union (and neither will the destructor)
new (&decompressed_store.tables.data) PokemonTables();
// TODO make it so that the table is added here(?)
box->setTable(&decompressed_store.tables.data);
box->convertAll();
for (int i = 0; i < MAX_PKMN_IN_BOX; i++) // Add in the Pokemon data
{
Pokemon curr_pkmn = incoming_box_data.get_converted_pkmn(decompressed_store.tables.data, i);
if (curr_pkmn.get_validity())
Gen3Pokemon *curr_pkmn = box->getGen3Pokemon(i);
if (curr_pkmn->isValid)
{
memcpy(save_section_30 + curr_section30_index, curr_pkmn.get_full_gen_3_array(), POKEMON_SIZE);
for (int j = 0; j < POKEMON_SIZE; j++)
{
*(save_section_30 + curr_section30_index + j) = curr_pkmn->dataArrayPtr[j];
}
// memcpy(save_section_30 + curr_section30_index, curr_pkmn->dataArrayPtr, POKEMON_SIZE);
curr_section30_index += POKEMON_SIZE;
dex_nums[i] = curr_pkmn.get_dex_number();
dex_nums[i] = curr_pkmn->getSpeciesIndexNumber();
}
else
{
@ -347,7 +351,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
}
// the PokemonTables instance is no longer needed, but we do need to keep the english gen3 charset around
// for our insert_text() calls
decompressed_store.tables.data.load_gen3_charset(ENG_ID);
decompressed_store.tables.data.load_gen3_charset(ENGLISH);
// we specifically defined the decompressed_text_data struct to ensure the memcpy shouldn't overlap
memcpy(decompressed_store.text.gen3_charset, decompressed_store.tables.data.gen3_charset, sizeof(decompressed_store.text.gen3_charset));
// calling the destructor is nothing more than a formality for our PokemonTables class,
@ -375,7 +379,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
// this decompresses the ZX0 compressed text table into the buffer inside of the decompressed_store union
// thereby reusing the stack (=IWRAM) memory used earlier for the PokemonTables instance we used above
decompressed_text_table.decompress(get_compressed_rsefrlg_table());
switch (curr_rom.gamecode)
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
textGreet.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textGreet_rse));
@ -433,7 +437,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
curr_section30_index++; // Align the code so that it is byte aligned
}
songLooker.insert_music_data(save_section_30, 0, 0, 0, curr_rom.loc_voicegroup);
songLooker.insert_music_data(save_section_30, 0, 0, 0, curr_GBA_rom.loc_voicegroup);
asm_var customSong(songLooker.get_loc_in_sec30(), sec30_variable_list, &curr_section30_index);
asm_var customSongDuration(119, sec30_variable_list, &curr_section30_index);
@ -445,7 +449,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
#include "lookerFRLG.h"
#include "lookerRSE.h"
if (curr_rom.is_hoenn())
if (curr_GBA_rom.is_hoenn())
{
spriteLooker.insert_sprite_data(save_section_30, lookerRSETiles, 256, lookerRSEPal);
}
@ -453,7 +457,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
{
spriteLooker.insert_sprite_data(save_section_30, lookerFRLGTiles, 256, lookerFRLGPal);
}
asm_var paletteData(curr_rom.loc_gSaveDataBuffer + (curr_section30_index - 32), sec30_variable_list, &curr_section30_index);
asm_var paletteData(curr_GBA_rom.loc_gSaveDataBuffer + (curr_section30_index - 32), sec30_variable_list, &curr_section30_index);
asm_payload_location = S30_SCRIPT;
@ -574,47 +578,47 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
asm_payload_location = MG_SCRIPT;
// Located at 0x?8A8 in the .sav
init_npc_location(curr_rom.map_bank, curr_rom.map_id, curr_rom.npc_id); // Set the location of the NPC
setvirtualaddress(VIRTUAL_ADDRESS); // Set virtual address
if (curr_rom.gamecode == RUBY_ID || curr_rom.gamecode == SAPPHIRE_ID)
init_npc_location(curr_GBA_rom.map_bank, curr_GBA_rom.map_id, curr_GBA_rom.npc_id); // Set the location of the NPC
setvirtualaddress(VIRTUAL_ADDRESS); // Set virtual address
if (curr_GBA_rom.gamecode == RUBY_ID || curr_GBA_rom.gamecode == SAPPHIRE_ID)
{
callASM(loadSec30.add_reference(1));
}
else
{
callASM(curr_rom.loc_loadSaveSection30 + READ_AS_THUMB); // Load save section 30 into saveDataBuffer
callASM(curr_GBA_rom.loc_loadSaveSection30 + READ_AS_THUMB); // Load save section 30 into saveDataBuffer
}
lock(); // Lock the player
faceplayer(); // Have the NPC face the player
virtualmsgbox(textGreet.add_reference(1)); // Start the dialouge
waitmsg();
waitkeypress();
applymovement(curr_rom.npc_id, movementExclaim.get_loc_in_sec30());
applymovement(curr_GBA_rom.npc_id, movementExclaim.get_loc_in_sec30());
playse(0x15);
waitse();
waitmovement(curr_rom.npc_id);
waitmovement(curr_GBA_rom.npc_id);
virtualmsgbox(textYouMustBe.add_reference(1));
waitmsg();
waitkeypress();
applymovement(curr_rom.npc_id, movementSlowSpin.get_loc_in_sec30());
waitmovement(curr_rom.npc_id);
applymovement(curr_rom.npc_id, movementFastSpin.get_loc_in_sec30());
waitmovement(curr_rom.npc_id);
applymovement(curr_GBA_rom.npc_id, movementSlowSpin.get_loc_in_sec30());
waitmovement(curr_GBA_rom.npc_id);
applymovement(curr_GBA_rom.npc_id, movementFastSpin.get_loc_in_sec30());
waitmovement(curr_GBA_rom.npc_id);
changeSpriteMacro(1, spriteLooker.get_loc_in_sec30());
callASM(loadPalette.get_loc_in_sec30());
changePaletteMacro(curr_rom.npc_id, 0xA);
applymovement(curr_rom.npc_id, movementLookDown.get_loc_in_sec30());
changePaletteMacro(curr_GBA_rom.npc_id, 0xA);
applymovement(curr_GBA_rom.npc_id, movementLookDown.get_loc_in_sec30());
callASM(customSoundASM.get_loc_in_sec30());
waitfanfare();
virtualmsgbox(textIAm.add_reference(1));
waitmsg();
waitkeypress();
changeSpriteMacro(1, curr_rom.loc_sPicTable_NPC);
changePaletteMacro(curr_rom.npc_id, curr_rom.npc_palette);
applymovement(curr_rom.npc_id, movementFastSpin.get_loc_in_sec30());
waitmovement(curr_rom.npc_id);
applymovement(curr_rom.npc_id, movementSlowSpin.get_loc_in_sec30());
waitmovement(curr_rom.npc_id);
changeSpriteMacro(1, curr_GBA_rom.loc_sPicTable_NPC);
changePaletteMacro(curr_GBA_rom.npc_id, curr_GBA_rom.npc_palette);
applymovement(curr_GBA_rom.npc_id, movementFastSpin.get_loc_in_sec30());
waitmovement(curr_GBA_rom.npc_id);
applymovement(curr_GBA_rom.npc_id, movementSlowSpin.get_loc_in_sec30());
waitmovement(curr_GBA_rom.npc_id);
faceplayer();
msgboxMacro(textWeHere.get_loc_in_sec30());
compare(0x800C, 1); // 0x800C == SpecialVar_Facing
@ -622,13 +626,13 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
applymovement(0xFF, movementOutOfWay.get_loc_in_sec30());
waitmovement(0xFF);
jumpNotInWay.set_start();
applymovement(curr_rom.npc_id, movementToBoxes.get_loc_in_sec30());
waitmovement(curr_rom.npc_id);
applymovement(curr_GBA_rom.npc_id, movementToBoxes.get_loc_in_sec30());
waitmovement(curr_GBA_rom.npc_id);
playse(0x15);
waitse();
msgboxMacro(textMoveBox.get_loc_in_sec30());
fadeScreen(1);
switch (curr_rom.gamecode)
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -646,11 +650,11 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
setMetaTile(3, 2, 566, 1);
setMetaTile(1, 1, 531, 1);
setMetaTile(1, 2, 539, 0);
applymovement(curr_rom.npc_id, movementGoUp.get_loc_in_sec30());
applymovement(curr_GBA_rom.npc_id, movementGoUp.get_loc_in_sec30());
break;
}
special(curr_rom.special_DrawWholeMapView);
switch (curr_rom.gamecode)
special(curr_GBA_rom.special_DrawWholeMapView);
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -664,7 +668,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
}
waitse();
fadeScreen(0);
switch (curr_rom.gamecode)
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -678,41 +682,41 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
setMetaTile(3, 1, 5, 1);
break;
}
special(curr_rom.special_DrawWholeMapView);
special(curr_GBA_rom.special_DrawWholeMapView);
playse(0x2);
waitse();
msgboxMacro(textPCConvo.get_loc_in_sec30());
// -- POKEMON INJECTION START--
setvar(var_index, 0); // set the index to 0
setvar(var_pkmn_offset, 0); // Set the Pokemon struct offset to 0
setvar(var_call_check_flag, rev_endian(0x2B00)); // Set the variable to 0x2B. 0x2B = CHECK FLAG
addvar(var_call_check_flag, rev_endian(curr_rom.pkmn_collected_flag_start)); // Add the starting flag ID (plus one to ignore the is collected flag) to the check flag ASM variable
setvar(var_call_return_2, rev_endian(0x0003)); // Set the variable to 0x03. 0x03 = RETURN
jumpLoop.set_start(); // Set the jump destination for the JUMP_LOOP
call(ptr_call_check_flag); // Call the check flag ASM
virtualgotoif(COND_FLAGFALSE, jumpPkmnCollected.add_reference(2)); // If the "pokemon collected" flag is false, jump to the end of the loop
callASM(mainAsmStart.get_loc_in_sec30()); // Call SendMonToPC ASM
compare(var_box_return, 2); // Compare the resulting return to #2
virtualgotoif(COND_EQUALS, jumpBoxFull.add_reference(2)); // If the return value was #2, jump to the box full message
setvar(var_dex_seen_caught, 2); // set the seen caught variable to 2, so that the Pokemon is set to "seen"
callASM(dexAsmStart.get_loc_in_sec30()); // call "PTR_DEX_START"
addvar(var_dex_seen_caught, 1); // add 1 to the seen caught variable so that the Pokemon will be "Caught"
callASM(dexAsmStart.get_loc_in_sec30()); // Call "PTR_DEX_START" again
jumpPkmnCollected.set_start(); // Set the jump destination for if the Pokemon has already been collected
addvar(var_pkmn_offset, POKEMON_SIZE); // Add the size of one Pokmeon to the Pokemon offset
addvar(var_index, 1); // Add one to the index
addvar(var_call_check_flag, rev_endian(1)); // Add one to the flag index
compare(var_index, MAX_PKMN_IN_BOX); // Compare the index to 30
virtualgotoif(COND_LESSTHAN, jumpLoop.add_reference(2)); // if index is less than six, jump to the start of the loop
setflag(curr_rom.all_collected_flag); // Set the "all collected" flag
fanfare(257); // Play the received fanfare
msgboxMacro(textReceived.get_loc_in_sec30()); // Display the recieved text
waitfanfare(); // Wait for the fanfare
setvar(var_index, 0); // set the index to 0
setvar(var_pkmn_offset, 0); // Set the Pokemon struct offset to 0
setvar(var_call_check_flag, rev_endian(0x2B00)); // Set the variable to 0x2B. 0x2B = CHECK FLAG
addvar(var_call_check_flag, rev_endian(curr_GBA_rom.pkmn_collected_flag_start)); // Add the starting flag ID (plus one to ignore the is collected flag) to the check flag ASM variable
setvar(var_call_return_2, rev_endian(0x0003)); // Set the variable to 0x03. 0x03 = RETURN
jumpLoop.set_start(); // Set the jump destination for the JUMP_LOOP
call(ptr_call_check_flag); // Call the check flag ASM
virtualgotoif(COND_FLAGFALSE, jumpPkmnCollected.add_reference(2)); // If the "pokemon collected" flag is false, jump to the end of the loop
callASM(mainAsmStart.get_loc_in_sec30()); // Call SendMonToPC ASM
compare(var_box_return, 2); // Compare the resulting return to #2
virtualgotoif(COND_EQUALS, jumpBoxFull.add_reference(2)); // If the return value was #2, jump to the box full message
setvar(var_dex_seen_caught, 2); // set the seen caught variable to 2, so that the Pokemon is set to "seen"
callASM(dexAsmStart.get_loc_in_sec30()); // call "PTR_DEX_START"
addvar(var_dex_seen_caught, 1); // add 1 to the seen caught variable so that the Pokemon will be "Caught"
callASM(dexAsmStart.get_loc_in_sec30()); // Call "PTR_DEX_START" again
jumpPkmnCollected.set_start(); // Set the jump destination for if the Pokemon has already been collected
addvar(var_pkmn_offset, POKEMON_SIZE); // Add the size of one Pokmeon to the Pokemon offset
addvar(var_index, 1); // Add one to the index
addvar(var_call_check_flag, rev_endian(1)); // Add one to the flag index
compare(var_index, MAX_PKMN_IN_BOX); // Compare the index to 30
virtualgotoif(COND_LESSTHAN, jumpLoop.add_reference(2)); // if index is less than six, jump to the start of the loop
setflag(curr_GBA_rom.all_collected_flag); // Set the "all collected" flag
fanfare(257); // Play the received fanfare
msgboxMacro(textReceived.get_loc_in_sec30()); // Display the recieved text
waitfanfare(); // Wait for the fanfare
// -- POKEMON INJECTION END --
jumpAllCollected.set_start(); // Set the destination for if all the Pokemon have already been collected
msgboxMacro(textPCThanks.get_loc_in_sec30()); // Display the thank text
switch (curr_rom.gamecode)
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -726,12 +730,12 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
setMetaTile(3, 1, 4, 0);
break;
}
special(curr_rom.special_DrawWholeMapView);
special(curr_GBA_rom.special_DrawWholeMapView);
playse(0x3);
waitse();
fadeScreen(1);
// Place the PC and boxes
switch (curr_rom.gamecode)
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -749,11 +753,11 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
setMetaTile(3, 2, 539, 1);
setMetaTile(1, 1, 525, 1);
setMetaTile(1, 2, 566, 0);
applymovement(curr_rom.npc_id, movementGoDown.get_loc_in_sec30());
applymovement(curr_GBA_rom.npc_id, movementGoDown.get_loc_in_sec30());
break;
}
special(curr_rom.special_DrawWholeMapView);
switch (curr_rom.gamecode)
special(curr_GBA_rom.special_DrawWholeMapView);
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -767,8 +771,8 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
}
waitse();
fadeScreen(0);
applymovement(curr_rom.npc_id, movementWalkBack.get_loc_in_sec30());
waitmovement(curr_rom.npc_id);
applymovement(curr_GBA_rom.npc_id, movementWalkBack.get_loc_in_sec30());
waitmovement(curr_GBA_rom.npc_id);
compare(0x800C, 1); // 0x800C == SpecialVar_Facing
virtualgotoif(COND_NOTEQUAL, jumpNotToSide.add_reference(2));
applymovement(0xFF, movementInWay.get_loc_in_sec30());
@ -783,7 +787,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
jumpBoxFull.set_start(); // Set the destination for if the box is full
msgboxMacro(textPCFull.get_loc_in_sec30()); // Display the thank text
setMetaTile(4, 1, 98, 0);
special(curr_rom.special_DrawWholeMapView);
special(curr_GBA_rom.special_DrawWholeMapView);
playse(0x3);
waitse();
fadeScreen(1);
@ -792,8 +796,8 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
// Place the boxes
setMetaTile(2, 1, 272, 1);
setMetaTile(2, 2, 273, 0);
special(curr_rom.special_DrawWholeMapView);
switch (curr_rom.gamecode)
special(curr_GBA_rom.special_DrawWholeMapView);
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -807,8 +811,8 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
}
waitse();
fadeScreen(0);
applymovement(curr_rom.npc_id, movementWalkBack.get_loc_in_sec30());
waitmovement(curr_rom.npc_id);
applymovement(curr_GBA_rom.npc_id, movementWalkBack.get_loc_in_sec30());
waitmovement(curr_GBA_rom.npc_id);
compare(0x800C, 1); // 0x800C == SpecialVar_Facing
virtualgotoif(COND_NOTEQUAL, jumpNotToSideFull.add_reference(2));
applymovement(0xFF, movementInWay.get_loc_in_sec30());
@ -1094,12 +1098,12 @@ void mystery_gift_script::build_script_old(Pokemon_Party &incoming_box_data)
};
*/
const u8* mystery_gift_script::get_script() const
const u8 *mystery_gift_script::get_script() const
{
return mg_script;
}
const u8* mystery_gift_script::get_section30() const
const u8 *mystery_gift_script::get_section30() const
{
return save_section_30;
}
@ -1487,15 +1491,15 @@ void mystery_gift_script::msgboxMacro(u32 location)
void mystery_gift_script::changeSpriteMacro(u8 npcId, u32 spriteTablePtr)
{
writebytetooffset(spriteTablePtr >> 0, curr_rom.loc_gSprites + (0x44 * npcId) + 0xC + 0);
writebytetooffset(spriteTablePtr >> 8, curr_rom.loc_gSprites + (0x44 * npcId) + 0xC + 1);
writebytetooffset(spriteTablePtr >> 16, curr_rom.loc_gSprites + (0x44 * npcId) + 0xC + 2);
writebytetooffset(spriteTablePtr >> 24, curr_rom.loc_gSprites + (0x44 * npcId) + 0xC + 3);
writebytetooffset(spriteTablePtr >> 0, curr_GBA_rom.loc_gSprites + (0x44 * npcId) + 0xC + 0);
writebytetooffset(spriteTablePtr >> 8, curr_GBA_rom.loc_gSprites + (0x44 * npcId) + 0xC + 1);
writebytetooffset(spriteTablePtr >> 16, curr_GBA_rom.loc_gSprites + (0x44 * npcId) + 0xC + 2);
writebytetooffset(spriteTablePtr >> 24, curr_GBA_rom.loc_gSprites + (0x44 * npcId) + 0xC + 3);
}
void mystery_gift_script::changePaletteMacro(u8 npcId, u8 palNum)
{
writebytetooffset((palNum << 4) | 0x08, curr_rom.loc_gSprites + (0x44 * npcId) + 0x5);
writebytetooffset((palNum << 4) | 0x08, curr_GBA_rom.loc_gSprites + (0x44 * npcId) + 0x5);
}
// ASM Commands

View File

@ -14,36 +14,7 @@ static const u8 em_wonder_card[0x14E] = {
static const u8 frlg_wonder_card[0x14E] = {
0x67, 0x18, 0x00, 0x00, 0xBA, 0xB4, 0xBE, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xCA, 0xCC, 0xC9, 0xC0, 0xBF, 0xCD, 0xCD, 0xC9, 0xCC, 0x00, 0xC0, 0xBF, 0xC8, 0xC8, 0xBF, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xE6, 0xD5, 0xE2, 0xE7, 0xDA, 0xD9, 0xE6, 0x00, 0xBD, 0xD9, 0xE6, 0xE8, 0xDD, 0xDA, 0xDD, 0xD7, 0xD5, 0xE8, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xDD, 0xE7, 0xDD, 0xE8, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xDC, 0xE3, 0xE9, 0xE7, 0xD9, 0x00, 0xE7, 0xE3, 0xE9, 0xE8, 0xDC, 0x00, 0xE3, 0xDA, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xCA, 0xC9, 0xC5, 0x1B, 0xC7, 0xC9, 0xC8, 0x00, 0x00, 0x00, 0x00, 0xBD, 0xBF, 0xC8, 0xCE, 0xBF, 0xCC, 0x00, 0xE3, 0xE2, 0x00, 0xCD, 0xD9, 0xEA, 0xD9, 0xE2, 0x00, 0xC3, 0xE7, 0xE0, 0xD5, 0xE2, 0xD8, 0x00, 0xE8, 0xE3, 0x00, 0xE6, 0xD9, 0xD7, 0xDD, 0xD9, 0xEA, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xE3, 0xE9, 0xE6, 0x00, 0xE8, 0xE6, 0xD5, 0xE2, 0xE7, 0xDA, 0xD9, 0xE6, 0xD9, 0xD8, 0x00, 0xCA, 0xC9, 0xC5, 0x1B, 0xC7, 0xC9, 0xC8, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xE3, 0x00, 0xE2, 0xE3, 0xE8, 0x00, 0xE8, 0xE3, 0xE7, 0xE7, 0x00, 0xE8, 0xDC, 0xDD, 0xE7, 0x00, 0xBF, 0xEC, 0xD7, 0xDC, 0xD5, 0xE2, 0xDB, 0xD9, 0x00, 0xBD, 0xD5, 0xE6, 0xD8, 0x00, 0xD6, 0xD9, 0xDA, 0xE3, 0xE6, 0xD9, 0x00, 0x00, 0x00, 0xE6, 0xD9, 0xD7, 0xD9, 0xDD, 0xEA, 0xDD, 0xE2, 0xDB, 0x00, 0xED, 0xE3, 0xE9, 0xE6, 0x00, 0xE8, 0xE6, 0xD5, 0xE2, 0xE7, 0xDA, 0xD9, 0xE6, 0xD9, 0xD8, 0x00, 0xCA, 0xC9, 0xC5, 0x1B, 0xC7, 0xC9, 0xC8, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // checksum
// noinline to ensure the scope of data_tables remains limited to this function
static void __attribute__((noinline)) handle_old_event(Pokemon_Party &incoming_box_data, int &curr_index, int *dex_nums)
{
PokemonTables data_tables;
for (int i = 0; i < MAX_PKMN_IN_BOX; i++) // Add in the Pokemon data
{
Pokemon curr_pkmn = incoming_box_data.get_converted_pkmn(data_tables, i);
if (curr_pkmn.get_validity())
{
for (int curr_byte = 0; curr_byte < POKEMON_SIZE; curr_byte++)
{
global_memory_buffer[curr_index] = curr_pkmn.get_gen_3_data(curr_byte);
curr_index++;
}
dex_nums[i] = curr_pkmn.get_dex_number();
}
else
{
curr_index += POKEMON_SIZE;
}
}
for (int i = 0; i < MAX_PKMN_IN_BOX; i++) // Add in the dex numbers
{
global_memory_buffer[curr_index] = dex_nums[i];
curr_index++;
}
}
bool inject_mystery(Pokemon_Party &incoming_box_data)
bool inject_mystery(PokeBox* box)
{
// WARNING: Look right here: we're passing global_memory_buffer to mystery_gift_script to be used as its save_section_30 buffer.
// Since we're going to be reusing global_memory_buffer later, we need to be careful about the timing/sequence of operations.
@ -51,16 +22,9 @@ bool inject_mystery(Pokemon_Party &incoming_box_data)
mystery_gift_script script(global_memory_buffer);
u32 checksum = 0;
if (ENABLE_OLD_EVENT)
{
// script.build_script_old(incoming_box_data);
}
else
{
script.build_script(incoming_box_data);
}
script.build_script(box);
if (curr_rom.is_ruby_sapphire())
if (curr_GBA_rom.is_ruby_sapphire())
{
checksum = script.calc_checksum32();
}
@ -73,17 +37,8 @@ bool inject_mystery(Pokemon_Party &incoming_box_data)
// We need to do this NOW, because mystery_gift_script::build_script() actually fills the global_memory_buffer.
// In the steps after this, we will be recycling the global_memory_buffer to read and write data to other sections of the save.
// So we really MUST write the generated data now, before we lose it.
if (ENABLE_OLD_EVENT)
{
int dex_nums[MAX_PKMN_IN_BOX] = {};
int curr_index = 0;
copy_save_to_ram(0x1E000, &global_memory_buffer[0], 0x1000);
handle_old_event(incoming_box_data, curr_index, dex_nums);
}
else
{
memcpy(global_memory_buffer, script.get_section30(), 0x1000);
}
memcpy(global_memory_buffer, script.get_section30(), 0x1000);
update_memory_buffer_checksum(false);
erase_sector(0x1E000);
@ -91,10 +46,10 @@ bool inject_mystery(Pokemon_Party &incoming_box_data)
// section_30 data has been stored, so now we can safely re-use the global_memory_buffer for other sections.
// Let's move on to the next step.
// Add in Wonder Card
copy_save_to_ram(memory_section_array[4], &global_memory_buffer[0], 0x1000);
switch (curr_rom.gamecode)
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
case SAPPHIRE_ID:
@ -102,22 +57,22 @@ bool inject_mystery(Pokemon_Party &incoming_box_data)
break;
case FIRERED_ID:
case LEAFGREEN_ID:
memcpy(global_memory_buffer + curr_rom.offset_wondercard, frlg_wonder_card, 0x14E);
memcpy(global_memory_buffer + curr_GBA_rom.offset_wondercard, frlg_wonder_card, 0x14E);
break;
case EMERALD_ID:
default:
memcpy(global_memory_buffer + curr_rom.offset_wondercard, em_wonder_card, 0x14E);
memcpy(global_memory_buffer + curr_GBA_rom.offset_wondercard, em_wonder_card, 0x14E);
break;
}
// Set checksum and padding
global_memory_buffer[curr_rom.offset_script] = checksum >> 0;
global_memory_buffer[curr_rom.offset_script + 1] = checksum >> 8;
global_memory_buffer[curr_rom.offset_script + 2] = checksum >> 16;
global_memory_buffer[curr_rom.offset_script + 3] = checksum >> 24;
global_memory_buffer[curr_GBA_rom.offset_script] = checksum >> 0;
global_memory_buffer[curr_GBA_rom.offset_script + 1] = checksum >> 8;
global_memory_buffer[curr_GBA_rom.offset_script + 2] = checksum >> 16;
global_memory_buffer[curr_GBA_rom.offset_script + 3] = checksum >> 24;
// Add in Mystery Script data
memcpy(global_memory_buffer + curr_rom.offset_script + 4, script.get_script(), MG_SCRIPT_SIZE);
memcpy(global_memory_buffer + curr_GBA_rom.offset_script + 4, script.get_script(), MG_SCRIPT_SIZE);
update_memory_buffer_checksum(false);
erase_sector(memory_section_array[4]);
@ -127,7 +82,9 @@ bool inject_mystery(Pokemon_Party &incoming_box_data)
{
for (int i = 0; i < 1122; i++)
{
global_memory_buffer[i] = incoming_box_data.box_data_array[i];
// global_memory_buffer[i] = incoming_box_data.box_data_array[i];
while(true){}
// This is currently not possible(?)
}
for (int i = 0; i < 0x1000 - 1122; i++)
{
@ -137,18 +94,18 @@ bool inject_mystery(Pokemon_Party &incoming_box_data)
}
// Set flags
int memory_section = 1 + ((curr_rom.offset_flags + (curr_rom.unused_flag_start / 8)) / 0xF80); // This sets the correct memory section, since flags stretch between section 1 and 2.
int memory_section = 1 + ((curr_GBA_rom.offset_flags + (curr_GBA_rom.unused_flag_start / 8)) / 0xF80); // This sets the correct memory section, since flags stretch between section 1 and 2.
copy_save_to_ram(memory_section_array[memory_section], &global_memory_buffer[0], 0x1000);
global_memory_buffer[(curr_rom.offset_flags + (curr_rom.all_collected_flag / 8)) % 0xF80] &= ~(1 << (curr_rom.all_collected_flag % 8)); // Set "collected all" flag to 0
global_memory_buffer[(curr_GBA_rom.offset_flags + (curr_GBA_rom.all_collected_flag / 8)) % 0xF80] &= ~(1 << (curr_GBA_rom.all_collected_flag % 8)); // Set "collected all" flag to 0
for (int i = 0; i < MAX_PKMN_IN_BOX; i++)
{
int curr_flag;
curr_flag = curr_rom.pkmn_collected_flag_start + i;
global_memory_buffer[(curr_rom.offset_flags + (curr_flag / 8)) % 0xF80] &= ~(1 << (curr_flag % 8)); // Reset the flag
if (incoming_box_data.get_simple_pkmn(i).is_valid)
curr_flag = curr_GBA_rom.pkmn_collected_flag_start + i;
global_memory_buffer[(curr_GBA_rom.offset_flags + (curr_flag / 8)) % 0xF80] &= ~(1 << (curr_flag % 8)); // Reset the flag
if (box->getGen3Pokemon(i)->isValid)
{
global_memory_buffer[(curr_rom.offset_flags + (curr_flag / 8)) % 0xF80] |= (1 << (curr_flag % 8)); // Set flag accordingly
global_memory_buffer[(curr_GBA_rom.offset_flags + (curr_flag / 8)) % 0xF80] |= (1 << (curr_flag % 8)); // Set flag accordingly
}
}

818
source/pccs/GBPokemon.cpp Normal file
View File

@ -0,0 +1,818 @@
#include "GBPokemon.h"
// This constructor fills all our convenience arrays
GBPokemon::GBPokemon()
{
nicknameArrayPtr = nicknameArray;
nicknameArraySize = 11;
OTArrayPtr = OTArray;
OTArraySize = 11;
externalIndexNumberPtr = &externalIndexNumber;
isBigEndian = true;
generation = 0;
}
// This is used to load our data in from an array
void GBPokemon::loadData(Language nLang, byte nDataArray[], byte nNicknameArray[], byte nOTArray[], byte nExternalIndexNum)
{
for (int i = 0; i < dataArraySize; i++)
{
dataArrayPtr[i] = nDataArray[i];
}
for (int i = 0; i < nicknameArraySize; i++)
{
nicknameArray[i] = nNicknameArray[i];
}
for (int i = 0; i < OTArraySize; i++)
{
OTArray[i] = nOTArray[i];
}
if (generation == 1)
{
externalIndexNumber = gen_1_index_array[nExternalIndexNum];
}
else
{
externalIndexNumber = nExternalIndexNum;
}
lang = nLang;
updateValidity();
}
// This is used to easily print out a Pokemon, when using a standard C++ terminal
#if ON_GBA
#else
std::string GBPokemon::parentPrint()
{
pokeTable->load_input_charset(generation, ENGLISH);
std::stringstream os;
os << "Species Index Number: " << getSpeciesIndexNumber() << "\n"
<< "Nickname: [";
for (int i = 0; i < 10; i++)
{
os << "0x" << std::setfill('0') << std::setw(2) << std::right << std::hex << (int)nicknameArray[i] << (i < 9 ? ", " : "");
}
os << "] (";
for (int i = 0; i < 10; i++)
{
os << (char)(pokeTable->input_charset[(int)nicknameArray[i]]);
}
os << ")" << "\n"
<< "Original Trainer: [";
for (int i = 0; i < 7; i++)
{
os << "0x" << std::setfill('0') << std::setw(2) << std::right << std::hex << (int)OTArray[i] << (i < 6 ? ", " : "");
}
os << "] (";
for (int i = 0; i < 7; i++)
{
os << (char)(pokeTable->input_charset[(int)OTArray[i]]);
}
os << ")" << "\n"
<< std::dec
<< "Trainer ID: " << getTrainerID() << "\n"
<< "Level: " << getLevel() << "\n"
<< "Exp: " << getExpPoints() << "\n"
<< "Moves: "
<< "\n\t" << getMove(0) << " (" << getPPTotal(0) << " PP, " << getPPUpNum(0) << " PP Ups" << ")"
<< "\n\t" << getMove(1) << " (" << getPPTotal(1) << " PP, " << getPPUpNum(1) << " PP Ups" << ")"
<< "\n\t" << getMove(2) << " (" << getPPTotal(2) << " PP, " << getPPUpNum(2) << " PP Ups" << ")"
<< "\n\t" << getMove(3) << " (" << getPPTotal(3) << " PP, " << getPPUpNum(3) << " PP Ups" << ")" << "\n"
<< "Is Shiny: " << getIsShiny() << "\n";
return os.str();
}
#endif
u32 GBPokemon::getDV(Stat currStat)
{
if (currStat == HP)
{
return ((getVar(DVs[ATTACK][generation - 1]) & 0x1) << 3) |
((getVar(DVs[DEFENSE][generation - 1]) & 0x1) << 2) |
((getVar(DVs[SPEED][generation - 1]) & 0x1) << 1) |
((getVar(DVs[SPECIAL][generation - 1]) & 0x1) << 0);
}
else
{
return getVar(DVs[currStat][generation - 1]);
}
}
bool GBPokemon::setDV(Stat currStat, byte newVal)
{
if (currStat == HP)
{
return setVar(DVs[ATTACK][generation - 1], (getVar(DVs[ATTACK][generation - 1]) & 0b1110) | ((newVal >> 3) & 0x1)) &&
setVar(DVs[DEFENSE][generation - 1], (getVar(DVs[DEFENSE][generation - 1]) & 0b1110) | ((newVal >> 2) & 0x1)) &&
setVar(DVs[SPEED][generation - 1], (getVar(DVs[SPEED][generation - 1]) & 0b1110) | ((newVal >> 1) & 0x1)) &&
setVar(DVs[SPECIAL][generation - 1], (getVar(DVs[SPECIAL][generation - 1]) & 0b1110) | ((newVal >> 0) & 0x1));
}
else
{
return setVar(DVs[currStat][generation - 1], newVal);
}
}
byte GBPokemon::getUnownLetter()
{
if (getSpeciesIndexNumber() == 201)
{
byte letter = 0;
letter |= ((getDV(ATTACK) & 0b0110) >> 1) << 6;
letter |= ((getDV(DEFENSE) & 0b0110) >> 1) << 4;
letter |= ((getDV(SPEED) & 0b0110) >> 1) << 2;
letter |= ((getDV(SPECIAL) & 0b0110) >> 1) << 0;
letter = letter / 10;
return letter;
}
return 255;
}
Gender GBPokemon::getGender()
{
byte index = getSpeciesIndexNumber();
u32 threshold = pokeTable->get_gender_threshold(index, false);
if (threshold == 255)
{
return GENDERLESS;
}
else
{
if (getDV(ATTACK) <= threshold)
{
return FEMALE;
}
return MALE;
}
}
Nature GBPokemon::getVirtualConsoleNature()
{
return (Nature)(getExpPoints() % 25);
}
bool GBPokemon::getIsShiny()
{
return ((getDV(ATTACK) & 0b0010) == 0b0010) &&
getDV(DEFENSE) == 10 &&
getDV(SPEED) == 10 &&
getDV(SPECIAL) == 10;
}
bool GBPokemon::convertToGen3(Gen3Pokemon *newPkmn, bool sanitizeMythicals)
{
if (!isValid)
{
return false;
}
bool valid =
// Start with things that effect the PID
convertSpeciesIndexNumber(newPkmn) &&
setRequestedLetter(newPkmn) &&
setRequestedNature(newPkmn) &&
setRequestedGender(newPkmn) &&
setRequestedAbility(newPkmn) &&
setRequestedSize(newPkmn) &&
// Then set the PID
generatePersonalityValue(newPkmn, ABCD_U) &&
// Then set everything else
convertTrainerID(newPkmn) &&
convertNickname(newPkmn) &&
convertLanguage(newPkmn) &&
convertMiscFlags(newPkmn) &&
convertTrainerNickname(newPkmn) &&
convertMarkings(newPkmn) &&
convertItem(newPkmn) &&
convertEXP(newPkmn) &&
convertFriendship(newPkmn) &&
convertMoves(newPkmn) &&
convertEVs(newPkmn) &&
convertContestConditions(newPkmn) &&
convertPokerus(newPkmn) &&
convertMetLocation(newPkmn) &&
convertMetLevel(newPkmn) &&
convertGameOfOrigin(newPkmn) &&
convertPokeball(newPkmn) &&
convertTrainerGender(newPkmn) &&
convertIVs(newPkmn) &&
convertRibbonsAndObedience(newPkmn) &&
convertShininess(newPkmn);
if (sanitizeMythicals && (getSpeciesIndexNumber() == MEW || getSpeciesIndexNumber() == CELEBI))
{
// Modify the required data for the event
valid &= loadEvent(newPkmn);
}
newPkmn->isValid = valid;
return valid;
};
bool GBPokemon::loadEvent(Gen3Pokemon *newPkmn)
{
bool valid =
generatePersonalityValue(newPkmn, BACD_R) &&
convertEVs(newPkmn) &&
convertIVs(newPkmn);
if (!valid)
{
return false;
}
if (getSpeciesIndexNumber() == MEW)
{
newPkmn->setGameOfOrigin(RUBY);
newPkmn->setFatefulEncounterObedience(true);
newPkmn->setMetLocation(0xFF); // Fateful Encounter
newPkmn->setLevelMet(10);
newPkmn->setSecretID(00000);
if (newPkmn->getExpPoints() < 560) // 560 is level 10 for Mew
{
newPkmn->setExpPoints(560);
}
byte jpnOT[] = {0x6A, 0x95, 0x53, 0xFF, 0xFF, 0xFF, 0xFF};
byte engOT[] = {0xBB, 0xE9, 0xE6, 0xD5, 0xFF, 0x00, 0x00};
switch (getLanguage())
{
case JAPANESE:
case KOREAN:
newPkmn->setTrainerID(50716);
newPkmn->setOTArray(jpnOT, 7);
break;
case ENGLISH:
case FRENCH:
case ITALIAN:
case GERMAN:
case SPANISH:
default:
newPkmn->setTrainerID(20078);
newPkmn->setOTArray(engOT, 7);
break;
}
}
else if (getSpeciesIndexNumber() == CELEBI)
{
newPkmn->setGameOfOrigin(RUBY);
newPkmn->setFatefulEncounterObedience(false);
newPkmn->setMetLocation(0xFF); // Fateful Encounter
newPkmn->setSecretID(0);
byte jpnOT[] = {0x70, 0x62, 0x78, 0x7E, 0xFF, 0x00, 0x00};
byte engOT[] = {0xA2, 0xA1, 0x00, 0xBB, 0xC8, 0xC3, 0xD0};
switch (getLanguage())
{
case JAPANESE:
case KOREAN:
newPkmn->setLevelMet(10);
if (newPkmn->getExpPoints() < 560) // 560 is level 10 for Celebi
{
newPkmn->setExpPoints(560);
}
newPkmn->setTrainerID(60720);
newPkmn->setOTArray(jpnOT, 7);
break;
case ENGLISH:
case FRENCH:
case ITALIAN:
case GERMAN:
case SPANISH:
default:
newPkmn->setLanguage(ENGLISH);
newPkmn->setLevelMet(70);
if (newPkmn->getExpPoints() < 344960) // 344960 is level 70 for Celebi
{
newPkmn->setExpPoints(344960);
}
newPkmn->setTrainerID(10);
newPkmn->setOTArray(engOT, 7);
break;
}
}
int val = getExpPoints();
if (val < 560) // Mew and Celebi are both Medium Slow, 560 is level 10
{
setExpPoints(560);
}
return true;
}
void GBPokemon::updateValidity()
{
byte currSpeciesIndexNumber = getSpeciesIndexNumber();
isValid = ((currSpeciesIndexNumber <= CELEBI || // Checks if the Pokemon is beyond the spported Pokemon, excluding Treecko for now
(currSpeciesIndexNumber == MISSINGNO && generation == 1)) && // But keep MissingNo
currSpeciesIndexNumber != 0 && // Makes sure the Pokemon isn't a blank party space
currSpeciesIndexNumber == externalIndexNumber && // Checks that the Pokemon isn't a hybrid or an egg
getHeldItem() == 0 // Makes sure the current Pokemon doesn't have a held item
);
};
bool GBPokemon::externalConvertNickname(byte outputArray[])
{
pokeTable->load_input_charset(generation, ENGLISH);
pokeTable->load_gen3_charset(ENGLISH);
for (int i = 0; i < 10; i++)
{
outputArray[i] = pokeTable->get_gen_3_char(pokeTable->input_charset[nicknameArray[i]]);
}
outputArray[10] = 0xFF;
return true;
};
bool GBPokemon::generatePersonalityValue(Gen3Pokemon *newPkmn, RNGMethod rng)
{
newPkmn->currRand = getPureRand();
u32 pid = 0;
u16 seedA = 0;
u16 seedB = 0;
do
{
if (rng == ABCD_U)
{
seedA = newPkmn->getNextRand_u16();
seedB = newPkmn->getNextRand_u16();
pid = seedA | (seedB << 16);
}
else if (rng == BACD_R)
{
newPkmn->currRand &= 0xFFFF; // Restrict the seed to 16 bits
seedA = newPkmn->getNextRand_u16();
seedB = newPkmn->getNextRand_u16();
pid = seedB | (seedA << 16);
}
newPkmn->setPersonalityValue(pid);
// std::cout << "Testing PID: " << std::hex << pid << "\n";
/*
std::cout << "PV: " << newPkmn->getPersonalityValue() << "\n"
<< "Letter: " << newPkmn->getUnownLetter() << " | " << getUnownLetter() << "\n"
<< "Nature: " << newPkmn->getNature() << " | " << getVirtualConsoleNature() << "\n"
<< "Gender: " << newPkmn->getGender() << " | " << getGender() << "\n";
*/
} while (!(
newPkmn->getAbilityFromPersonalityValue() == newPkmn->internalAbility &&
newPkmn->getUnownLetter() == newPkmn->internalUnownLetter &&
newPkmn->getNature() == newPkmn->internalNature &&
newPkmn->getGender() == newPkmn->internalGender &&
newPkmn->getSize() == newPkmn->internalSize));
return true;
};
bool GBPokemon::convertTrainerID(Gen3Pokemon *newPkmn)
{
newPkmn->setTrainerID(getTrainerID());
return true;
}
bool GBPokemon::convertNickname(Gen3Pokemon *newPkmn)
{
pokeTable->load_input_charset(generation, ENGLISH);
pokeTable->load_gen3_charset(ENGLISH);
for (int i = 0; i < 10; i++)
{
newPkmn->setNicknameLetter(i, pokeTable->get_gen_3_char(pokeTable->input_charset[nicknameArray[i]]));
}
return true;
};
bool GBPokemon::convertLanguage(Gen3Pokemon *newPkmn)
{
newPkmn->setLanguage(getLanguage());
return true;
}
bool GBPokemon::convertMiscFlags(Gen3Pokemon *newPkmn)
{
newPkmn->setIsBadEgg(false);
newPkmn->setHasSpecies(true);
newPkmn->setUseEggName(false);
newPkmn->setIsEgg(false);
return true;
}
bool GBPokemon::convertTrainerNickname(Gen3Pokemon *newPkmn)
{
pokeTable->load_input_charset(1, ENGLISH);
pokeTable->load_gen3_charset(ENGLISH);
for (int i = 0; i < 6; i++)
{
newPkmn->setOTLetter(i, pokeTable->get_gen_3_char(pokeTable->input_charset[OTArray[i]]));
}
return true;
};
bool GBPokemon::convertMarkings(Gen3Pokemon *newPkmn)
{
newPkmn->setMarkings(0b0000);
return true;
}
bool GBPokemon::convertSpeciesIndexNumber(Gen3Pokemon *newPkmn)
{
switch (getSpeciesIndexNumber())
{
case TREECKO:
newPkmn->setSpeciesIndexNumber(0x115);
break;
case MISSINGNO:
newPkmn->setSpeciesIndexNumber(PORYGON);
break;
default:
newPkmn->setSpeciesIndexNumber(getSpeciesIndexNumber());
break;
}
return true;
}
bool GBPokemon::convertItem(Gen3Pokemon *newPkmn)
{
#if ACCESS_POKEDEX
#include "save_data_manager.h"
if (!is_caught(newPkmn->getSpeciesIndexNumber()))
{
newPkmn->setHeldItem(RARE_CANDY);
set_caught(newPkmn->getSpeciesIndexNumber());
}
else
{
newPkmn->setHeldItem(NONE);
}
#else
newPkmn->setHeldItem(NONE);
#endif
return true;
}
bool GBPokemon::convertEXP(Gen3Pokemon *newPkmn)
{
// As per Poke Transporter, the level will be based on the level value, not the EXP
// Make sure Level is not over 100
int speciesIndex = getSpeciesIndexNumber();
int currLevel = getLevel();
if (currLevel > 100)
{
currLevel = 100;
}
// Truncate the EXP down to the current level
pokeTable->load_exp_groups();
switch (pokeTable->EXP_GROUPS[speciesIndex])
{
case EXP_FAST:
newPkmn->setExpPoints((4 * (currLevel * currLevel * currLevel)) / 5);
break;
default: // MissingNo is the only one that should hit default, so match it to Porygon
case EXP_MED_FAST:
newPkmn->setExpPoints(currLevel * currLevel * currLevel);
break;
case EXP_MED_SLOW:
newPkmn->setExpPoints(((6 * currLevel * currLevel * currLevel) / 5) - (15 * currLevel * currLevel) + (100 * currLevel) - 140);
break;
case EXP_SLOW:
newPkmn->setExpPoints((5 * (currLevel * currLevel * currLevel)) / 4);
break;
}
return true;
};
bool GBPokemon::convertFriendship(Gen3Pokemon *newPkmn)
{
newPkmn->setFriendship(70);
return true;
}
bool GBPokemon::convertMoves(Gen3Pokemon *newPkmn)
{
Species speciesIndexNum = (Species)getSpeciesIndexNumber();
// Check that the moves are valid
if ((speciesIndexNum != SMEARGLE) &&
(speciesIndexNum != MISSINGNO) &&
(speciesIndexNum != TREECKO)) // Ignore Smeargle, MissingNo, and Treecko
{
for (int i = 0; i < 4; i++)
{
if (pokeTable->can_learn_move(speciesIndexNum, getMove(i)))
{
newPkmn->setMove(i, getMove(i)); // Add the move
newPkmn->setPPUpNum(i, getPPUpNum(i)); // Add the PP Bonuses
}
}
}
// Make sure it has at least one move
int count = 0;
for (int i = 0; i < 4; i++)
{
count += (newPkmn->getMove(i) != 0);
}
if (count == 0)
{
newPkmn->setMove(0, pokeTable->get_earliest_move(speciesIndexNum));
}
// Bubble valid moves to the top
int i, j;
bool swapped;
for (i = 0; i < 3; i++)
{
swapped = false;
for (j = 0; j < 3 - i; j++)
{
if (newPkmn->getMove(j) == 0 && newPkmn->getMove(j + 1) != 0)
{
// Move the move *and* PP bonus up if there is a blank space
newPkmn->setMove(j, newPkmn->getMove(j + 1));
newPkmn->setPPUpNum(j, newPkmn->getPPUpNum(j + 1));
newPkmn->setMove(j + 1, 0);
newPkmn->setPPUpNum(j + 1, 0);
swapped = true;
}
}
// If no two elements were swapped
// by inner loop, then break
if (swapped == false)
break;
}
// Restore the PP values
pokeTable->load_power_points();
for (int i = 0; i < 4; i++)
{
int move = newPkmn->getMove(i);
newPkmn->setPPTotal(i, pokeTable->POWER_POINTS[move] + ((pokeTable->POWER_POINTS[move] / 5) * newPkmn->getPPUpNum(i)));
}
return true;
};
bool GBPokemon::convertEVs(Gen3Pokemon *newPkmn)
{
for (int i = 0; i < 6; i++)
{
newPkmn->setEV((Stat)i, 0);
}
return true;
};
bool GBPokemon::convertContestConditions(Gen3Pokemon *newPkmn)
{
for (int i = 0; i < 5; i++)
{
newPkmn->setContestCondition((Condition)i, 0);
}
newPkmn->setSheen(0);
return true;
};
bool GBPokemon::convertPokerus(Gen3Pokemon *newPkmn)
{
newPkmn->setPokerusStrain(getPokerusStrain());
newPkmn->setPokerusDaysRemaining(getPokerusDaysRemaining());
return true;
}
bool GBPokemon::convertMetLocation(Gen3Pokemon *newPkmn)
{
newPkmn->setMetLocation(0xFF); // A fateful encounter
return true;
}
bool GBPokemon::convertMetLevel(Gen3Pokemon *newPkmn)
{
newPkmn->setLevelMet(getLevel());
return true;
}
bool GBPokemon::convertGameOfOrigin(Gen3Pokemon *newPkmn)
{
switch (generation)
{
case 1:
newPkmn->setGameOfOrigin(FIRERED);
break;
case 2:
newPkmn->setGameOfOrigin(HEARTGOLD);
break;
default:
return false;
}
return true;
}
bool GBPokemon::convertPokeball(Gen3Pokemon *newPkmn)
{
if (getSpeciesIndexNumber() == MISSINGNO)
{
newPkmn->setPokeballCaughtIn(MASTER);
}
else
{
newPkmn->setPokeballCaughtIn(POKE);
}
return true;
}
bool GBPokemon::convertTrainerGender(Gen3Pokemon *newPkmn)
{
newPkmn->setOriginalTrainerGender(getCaughtDataGender());
return true;
};
bool GBPokemon::convertIVs(Gen3Pokemon *newPkmn)
{
u16 currRand;
currRand = newPkmn->getNextRand_u16();
newPkmn->setIV(HP, (currRand >> 0) & 0b11111);
newPkmn->setIV(ATTACK, (currRand >> 5) & 0b11111);
newPkmn->setIV(DEFENSE, (currRand >> 10) & 0b11111);
currRand = newPkmn->getNextRand_u16();
newPkmn->setIV(SPEED, (currRand >> 0) & 0b11111);
newPkmn->setIV(SPECIAL_ATTACK, (currRand >> 5) & 0b11111);
newPkmn->setIV(SPECIAL_DEFENSE, (currRand >> 10) & 0b11111);
return true;
};
bool GBPokemon::convertAbilityFlag(Gen3Pokemon *newPkmn)
{
newPkmn->setAbility(newPkmn->getPersonalityValue() & 0b1);
return true;
}
bool GBPokemon::convertRibbonsAndObedience(Gen3Pokemon *newPkmn)
{
Species speciesIndexNumber = (Species)getSpeciesIndexNumber();
if (speciesIndexNumber == MEW || speciesIndexNumber == CELEBI)
{
newPkmn->setFatefulEncounterObedience(true);
}
return true;
};
bool GBPokemon::setRequestedLetter(Gen3Pokemon *newPkmn)
{
newPkmn->internalUnownLetter = getUnownLetter();
return true;
};
bool GBPokemon::setRequestedNature(Gen3Pokemon *newPkmn)
{
newPkmn->internalNature = getVirtualConsoleNature();
return true;
};
bool GBPokemon::setRequestedGender(Gen3Pokemon *newPkmn)
{
newPkmn->internalGender = getGender();
return true;
};
bool GBPokemon::setRequestedAbility(Gen3Pokemon *newPkmn)
{
newPkmn->internalAbility = 255;
return true;
};
bool GBPokemon::setRequestedSize(Gen3Pokemon *newPkmn)
{
newPkmn->internalSize = 255;
return true;
};
bool GBPokemon::convertShininess(Gen3Pokemon *newPkmn)
{
byte nickname[10] = {};
byte trainerName[7] = {};
for (int i = 0; i < 10; i++)
{
nickname[i] = newPkmn->getNicknameLetter(i);
}
for (int i = 0; i < 7; i++)
{
trainerName[i] = newPkmn->getOTLetter(i);
}
if ((getSpeciesIndexNumber() == 52) &&
fnv1a_hash(trainerName, 7) == 1342961308 &&
(fnv1a_hash(nickname, 7) == 1515822901 || fnv1a_hash(nickname, 8) == 2671449886))
{
for (int i = 1; i <= 4; i++)
{
setDV((Stat)i, 15);
}
}
u16 shinyTest = newPkmn->getTrainerID() ^
(newPkmn->getPersonalityValue() >> 0 & 0xFFFF) ^
(newPkmn->getPersonalityValue() >> 16 & 0xFFFF);
if (getIsShiny())
{ // Make shiny
newPkmn->setSecretID(shinyTest);
}
else
{ // Make sure it isn't shiny
if (shinyTest < 8)
{ // It became shiny, fix that
newPkmn->setSecretID(51691);
}
else
{
newPkmn->setSecretID(0);
}
}
return true;
};
const DataVarInfo
GBPokemon::speciesIndexNumber[2] = {{0x00, 8, 0}, {0x00, 8, 0}},
GBPokemon::level[2] = {{0x03, 8, 0}, {0x1F, 8, 0}},
GBPokemon::moveOne[2] = {{0x08, 8, 0}, {0x02, 8, 0}},
GBPokemon::moveTwo[2] = {{0x09, 8, 0}, {0x03, 8, 0}},
GBPokemon::moveThree[2] = {{0x0A, 8, 0}, {0x04, 8, 0}},
GBPokemon::moveFour[2] = {{0x0B, 8, 0}, {0x05, 8, 0}},
GBPokemon::trainerID[2] = {{0x0C, 16, 0}, {0x06, 16, 0}},
GBPokemon::expPoints[2] = {{0x0E, 24, 0}, {0x08, 24, 0}},
GBPokemon::hpStatExp[2] = {{0x11, 16, 0}, {0x0B, 16, 0}},
GBPokemon::atkStatExp[2] = {{0x13, 16, 0}, {0x0D, 16, 0}},
GBPokemon::defStatExp[2] = {{0x15, 16, 0}, {0x0F, 16, 0}},
GBPokemon::speStatExp[2] = {{0x17, 16, 0}, {0x11, 16, 0}},
GBPokemon::spcStatExp[2] = {{0x19, 16, 0}, {0x13, 16, 0}},
GBPokemon::atkDV[2] = {{0x1B, 4, 4}, {0x15, 4, 4}},
GBPokemon::defDV[2] = {{0x1B, 4, 0}, {0x15, 4, 0}},
GBPokemon::speDV[2] = {{0x1C, 4, 4}, {0x16, 4, 4}},
GBPokemon::spcDV[2] = {{0x1C, 4, 0}, {0x16, 4, 0}},
GBPokemon::ppUpNumMoveOne[2] = {{0x1D, 2, 6}, {0x17, 2, 6}},
GBPokemon::ppNumTotalMoveOne[2] = {{0x1D, 6, 0}, {0x17, 6, 0}},
GBPokemon::ppUpNumMoveTwo[2] = {{0x1E, 2, 6}, {0x18, 2, 6}},
GBPokemon::ppNumTotalMoveTwo[2] = {{0x1E, 6, 0}, {0x18, 6, 0}},
GBPokemon::ppUpNumMoveThree[2] = {{0x1F, 2, 6}, {0x19, 2, 6}},
GBPokemon::ppNumTotalMoveThree[2] = {{0x1F, 6, 0}, {0x19, 6, 0}},
GBPokemon::ppUpNumMoveFour[2] = {{0x20, 2, 6}, {0x1A, 2, 6}},
GBPokemon::ppNumTotalMoveFour[2] = {{0x20, 6, 0}, {0x1A, 6, 0}};
const DataVarInfo
*GBPokemon::moves[4] = {
GBPokemon::moveOne,
GBPokemon::moveTwo,
GBPokemon::moveThree,
GBPokemon::moveFour,
},
*GBPokemon::statExps[5] = {
GBPokemon::hpStatExp,
GBPokemon::atkStatExp,
GBPokemon::defStatExp,
GBPokemon::speStatExp,
GBPokemon::spcStatExp,
},
*GBPokemon::DVs[5] = {
GBPokemon::atkDV, // This is wrong, but it will never be accessed anyway.
GBPokemon::atkDV,
GBPokemon::defDV,
GBPokemon::speDV,
GBPokemon::spcDV,
},
*GBPokemon::PPUpNums[4] = {
GBPokemon::ppUpNumMoveOne,
GBPokemon::ppUpNumMoveTwo,
GBPokemon::ppUpNumMoveThree,
GBPokemon::ppUpNumMoveFour,
},
*GBPokemon::PPUpTotals[4] = {
GBPokemon::ppNumTotalMoveOne,
GBPokemon::ppNumTotalMoveTwo,
GBPokemon::ppNumTotalMoveThree,
GBPokemon::ppNumTotalMoveFour,
};

View File

@ -0,0 +1,60 @@
#include "Gen1Pokemon.h"
Gen1Pokemon::Gen1Pokemon(PokemonTables *table)
{
pokeTable = table;
dataArrayPtr = dataArray;
dataArraySize = 33;
generation = 1;
}
#if ON_GBA
#else
void Gen1Pokemon::print(std::ostream &os)
{
os << parentPrint()
<< "Stats: "
<< "\n\tHP: " << getStatExp(HP) << " Stat EXP, " << getDV(HP) << " DVs"
<< "\n\tAttack: " << getStatExp(ATTACK) << " Stat EXP, " << getDV(ATTACK) << " DVs"
<< "\n\tDefense: " << getStatExp(DEFENSE) << " Stat EXP, " << getDV(DEFENSE) << " DVs"
<< "\n\tSpeed: " << getStatExp(SPEED) << " Stat EXP, " << getDV(SPEED) << " DVs"
<< "\n\tSpecial: " << getStatExp(SPECIAL) << " Stat EXP, " << getDV(SPECIAL) << " DVs" << "\n"
<< "Types: "
<< "\n\t" << getType(0)
<< "\n\t" << getType(1) << "\n"
<< "Current HP: " << getCurrentHP() << "\n"
<< "Status Condition: " << getStatusCondition() << "\n"
<< "Catch Rate: " << getCatchRate() << "\n";
}
#endif
u32 Gen1Pokemon::getSpeciesIndexNumber()
{
return gen_1_index_array[getVar(speciesIndexNumber[1])];
}
bool Gen1Pokemon::setSpeciesIndexNumber(byte newVal)
{
for (int i = 0; i < 191; i++)
{
if (gen_1_index_array[i] == newVal)
{
return setVar(speciesIndexNumber[1], newVal);
}
}
return setVar(speciesIndexNumber[1], newVal);
}
const DataVarInfo
Gen1Pokemon::g1_currentHP = {0x01, 16, 0},
Gen1Pokemon::g1_statusCondition = {0x04, 8, 0},
Gen1Pokemon::g1_typeOne = {0x05, 8, 0},
Gen1Pokemon::g1_typeTwo = {0x06, 8, 0},
Gen1Pokemon::g1_catchRate = {0x07, 8, 0};
const DataVarInfo
*Gen1Pokemon::g1_types[2] =
{
&Gen1Pokemon::g1_typeOne,
&Gen1Pokemon::g1_typeTwo,
};

View File

@ -0,0 +1,44 @@
#include "Gen2Pokemon.h"
Gen2Pokemon::Gen2Pokemon(PokemonTables *table)
{
pokeTable = table;
dataArrayPtr = dataArray;
dataArraySize = 32;
generation = 2;
}
#if ON_GBA
#else
void Gen2Pokemon::print(std::ostream &os)
{
os << parentPrint()
<< "Stats: "
<< "\n\tHP: " << getStatExp(HP) << " Stat EXP, " << getDV(HP) << " DVs"
<< "\n\tAttack: " << getStatExp(ATTACK) << " Stat EXP, " << getDV(ATTACK) << " DVs"
<< "\n\tDefense: " << getStatExp(DEFENSE) << " Stat EXP, " << getDV(DEFENSE) << " DVs"
<< "\n\tSpeed: " << getStatExp(SPEED) << " Stat EXP, " << getDV(SPEED) << " DVs"
<< "\n\tSpecial Attack: " << getStatExp(SPECIAL) << " Stat EXP, " << getDV(SPECIAL) << " DVs"
<< "\n\tSpecial Defense: " << getStatExp(SPECIAL) << " Stat EXP, " << getDV(SPECIAL) << " DVs" << "\n" // Special Attack and Special Defense are the same
<< "Held Item: " << getHeldItem() << "\n"
<< "Friendship: " << getFriendship() << "\n"
<< "Pokerus: "
<< "\n\tStrain: " << getPokerusStrain()
<< "\n\tDays Remaining: " << getPokerusDaysRemaining() << "\n"
<< "Caught Data: "
<< "\n\tTime: " << getCaughtDataTime()
<< "\n\tLevel: " << getCaughtDataLevel()
<< "\n\tTrainer Gender: " << getCaughtDataGender()
<< "\n\tLocation: " << getCaughtDataLocation() << "\n";
}
#endif
const DataVarInfo
Gen2Pokemon::g2_heldItem = {0x01, 8, 0},
Gen2Pokemon::g2_friendship = {0x1B, 8, 0},
Gen2Pokemon::g2_pokerusStrain = {0x1C, 4, 4},
Gen2Pokemon::g2_pokerusDaysRemaining = {0x1C, 4, 0},
Gen2Pokemon::g2_caughtDataTime = {0x1D, 2, 6},
Gen2Pokemon::g2_caughtDataLevel = {0x1D, 6, 0},
Gen2Pokemon::g2_caughtDataGender = {0x1E, 1, 7},
Gen2Pokemon::g2_caughtDataLocation = {0x1E, 7, 0};

743
source/pccs/Gen3Pokemon.cpp Normal file
View File

@ -0,0 +1,743 @@
#include "Gen3Pokemon.h"
Gen3Pokemon::Gen3Pokemon(PokemonTables *table)
{
pokeTable = table;
dataArrayPtr = dataArray;
dataArraySize = 80;
nicknameArrayPtr = &dataArray[0x8];
OTArrayPtr = &dataArray[0x14];
isBigEndian = false;
isEncrypted = false;
generation = 3;
};
bool Gen3Pokemon::convertToGen3(Gen3Pokemon *g3p)
{
return false;
}
// This is used to easily print out a Pokemon, when using a standard C++ terminal
#if ON_GBA
#else
void Gen3Pokemon::print(std::ostream &os)
{
updateChecksum();
updateSubstructureShift();
pokeTable->load_gen3_charset(ENGLISH);
if (!isValid)
{
os << "ERROR: POKEMON IS INVALID\n";
}
else
{
os
<< "Personality Value: " << std::hex << getPersonalityValue() << std::dec
<< "\n\tLetter: " << (int)getUnownLetter()
<< "\n\tNature: " << getNature()
<< "\n\tGender: " << getGender() << '\n'
<< "Trainer ID: " << getTrainerID() << "\n"
<< "Secret ID: " << getSecretID() << "\n"
<< "Nickname: [";
for (int i = 0; i < 10; i++)
{
os << "0x" << std::setfill('0') << std::setw(2) << std::right << std::hex << (int)getNicknameLetter(i) << (i < 9 ? ", " : "");
}
os << "] (";
for (int i = 0; i < 10; i++)
{
os << (char)(pokeTable->gen3_charset[(int)getNicknameLetter(i)]);
}
os << ")" << "\n"
<< "Original Trainer: [";
for (int i = 0; i < 7; i++)
{
os << "0x" << std::setfill('0') << std::setw(2) << std::right << std::hex << (int)getOTLetter(i) << (i < 6 ? ", " : "");
}
os << "] (";
for (int i = 0; i < 7; i++)
{
os << (char)(pokeTable->gen3_charset[(int)getOTLetter(i)]);
}
os << ")" << "\n"
<< std::dec
<< "Language: " << getLanguage() << "\n"
<< "Is Bad Egg: " << getIsBadEgg() << "\n"
<< "Has Species: " << getHasSpecies() << "\n"
<< "Use Egg Name: " << getUseEggName() << "\n"
<< "Block Box RS: " << getBlockBoxRS() << "\n"
<< "Markings: " << getMarkings() << "\n"
<< "Checksum: " << getChecksum() << "\n"
<< "Species Index Number: " << getSpeciesIndexNumber() << "\n"
<< "Held Item: " << getHeldItem() << "\n"
<< "Experience: " << getExpPoints() << "\n"
<< "Friendship: " << getFriendship() << "\n"
<< "Stats: "
<< "\n\tHP: " << getEV(HP) << " EVs, " << getIV(HP) << " IVs"
<< "\n\tAttack: " << getEV(ATTACK) << " EVs, " << getIV(ATTACK) << " IVs"
<< "\n\tDefense: " << getEV(DEFENSE) << " EVs, " << getIV(DEFENSE) << " IVs"
<< "\n\tSpecial Attack: " << getEV(SPECIAL_ATTACK) << " EVs, " << getIV(SPECIAL_ATTACK) << " IVs"
<< "\n\tSpecial Defense: " << getEV(SPECIAL_DEFENSE) << " EVs, " << getIV(SPECIAL_DEFENSE) << " IVs"
<< "\n\tSpeed: " << getEV(SPEED) << " EVs, " << getIV(SPEED) << " IVs" << "\n"
<< "Contest Stats: "
<< "\n\tCoolness: " << getContestCondition(COOLNESS)
<< "\n\tBeauty: " << getContestCondition(BEAUTY)
<< "\n\tCuteness: " << getContestCondition(CUTENESS)
<< "\n\tSmartness: " << getContestCondition(SMARTNESS)
<< "\n\tToughness: " << getContestCondition(TOUGHNESS)
<< "\n\tSheen: " << getSheen() << "\n"
<< "Moves: "
<< "\n\t" << getMove(0) << " (" << getPPTotal(0) << " PP, " << getPPUpNum(0) << " PP Ups" << ")"
<< "\n\t" << getMove(1) << " (" << getPPTotal(1) << " PP, " << getPPUpNum(1) << " PP Ups" << ")"
<< "\n\t" << getMove(2) << " (" << getPPTotal(2) << " PP, " << getPPUpNum(2) << " PP Ups" << ")"
<< "\n\t" << getMove(3) << " (" << getPPTotal(3) << " PP, " << getPPUpNum(3) << " PP Ups" << ")" << "\n"
<< "Pokerus: "
<< "\n\tStrain: " << getPokerusStrain()
<< "\n\tDays Remaining: " << getPokerusDaysRemaining() << "\n"
<< "Met Location: " << getMetLocation() << "\n"
<< "Level Met: " << getLevelMet() << "\n"
<< "Game of Origin: " << getGameOfOrigin() << "\n"
<< "Pokeball Caught In: " << getPokeballCaughtIn() << "\n"
<< "Original Trainer Gender: " << getOriginalTrainerGender() << "\n"
<< "Is Egg: " << getIsEgg() << "\n"
<< "Ability: " << getAbility() << "\n"
<< "Fateful Encounter/Obedience: " << getFatefulEncounterObedience() << "\n"
<< "Is Shiny: " << getIsShiny() << "\n"
<< "\n"
<< "Substructure Perm: " << currSubstructureShift << "\n"
<< "Encryption Key: " << std::hex << ((getTrainerID() | getSecretID() << 16) ^ getPersonalityValue()) << std::dec << "\n"
<< "Substructure offsets:"
<< "\n\tG: " << substructOffsets[SUB_G]
<< "\n\tA: " << substructOffsets[SUB_A]
<< "\n\tE: " << substructOffsets[SUB_E]
<< "\n\tM: " << substructOffsets[SUB_M]
<< "\n";
}
};
std::string Gen3Pokemon::printDataArray(bool encrypedData)
{
updateSubstructureShift();
updateChecksum();
encryptSubstructures();
std::stringstream ss;
for (int i = 0; i < 80; i++)
{
ss << std::hex << std::setw(2) << std::setfill('0') << (int)dataArray[i] << (i < 79 ? " " : "");
}
return ss.str();
}
#endif
// Get Nickname is different
// u32 getNickname() {};
// u32 getOriginalTrainerName() {}
u32 Gen3Pokemon::getNextRand_u32()
{
currRand = (0x41C64E6D * currRand) + 0x6073;
// std::cout << "Rolled: " << std::hex << currRand << "\n";
return currRand;
}
u32 Gen3Pokemon::getPrevRand_u32()
{
currRand = (currRand - 24691) * 4005161829;
return currRand;
}
u16 Gen3Pokemon::getNextRand_u16()
{
return getNextRand_u32() >> 16;
}
u16 Gen3Pokemon::getPrevRand_u16()
{
return getPrevRand_u32() >> 16;
}
bool Gen3Pokemon::setPersonalityValue(u32 newVal) // Setting the Personality Value should modify some other values as well
{
bool successful = setVar(personalityValue, newVal);
if (successful)
{
//successful &= setAbility(getPersonalityValue() & 0b1);
}
return successful;
}
bool Gen3Pokemon::setAbility(u32 newVal) // We need to check if they have two abilities
{
if (pokeTable->get_num_abilities(getSpeciesIndexNumber()) == 0)
{
newVal = 0;
}
internalAbility = newVal;
return setVar(ability, substructOffsets[SUB_M], newVal);
}
// This is used to load our data in from an array and mark it as encrypted
void Gen3Pokemon::loadData(byte incomingArray[])
{
for (int i = 0; i < dataArraySize; i++)
{
dataArrayPtr[i] = incomingArray[i];
}
isEncrypted = true;
}
// And then some general functions
void Gen3Pokemon::decryptSubstructures()
{
if (isEncrypted)
{
u32 key = (getTrainerID() | getSecretID() << 16) ^ getPersonalityValue();
for (int i = 0; i < 48; i++)
{
dataArrayPtr[0x20 + i] ^= ((key >> (8 * (i % 4))) & 0xFF);
}
}
};
void Gen3Pokemon::encryptSubstructures()
{
if (!isEncrypted)
{
u32 key = (getTrainerID() | getSecretID() << 16) ^ getPersonalityValue();
for (int i = 0; i < 48; i++)
{
dataArrayPtr[0x20 + i] ^= ((key >> (8 * (i % 4))) & 0xFF);
}
}
};
void Gen3Pokemon::updateChecksum()
{
bool encryptionState = isEncrypted;
decryptSubstructures();
int checksum = 0x0000;
for (int i = 0; i < 48; i = i + 2)
{
checksum = checksum + ((dataArrayPtr[0x20 + i + 1] << 8) | dataArrayPtr[0x20 + i]);
}
setChecksum(checksum);
if (encryptionState)
{
encryptSubstructures();
}
}
void Gen3Pokemon::updateSubstructureShift()
{
int structureVal = getPersonalityValue() % 24;
if (structureVal == currSubstructureShift)
{
return;
}
currSubstructureShift = structureVal;
resetSubstructureShift();
#define MAX_LEN 4
int index = 0;
while (index < MAX_LEN)
{
int len = MAX_LEN - index;
int factorial = 1;
for (int i = 1; i < len; i++)
{
factorial *= i;
}
int swapLoc = (structureVal / factorial) + index;
for (int i = index; i < swapLoc; i++)
{
swapSubstructures(index, (i + 1));
}
index += 1;
structureVal %= factorial;
}
}
void Gen3Pokemon::resetSubstructureShift()
{
for (int currDest = 0; currDest < 4; currDest++)
{
for (int i = 0; i < 4; i++)
{
if ((substructOffsets[i] / 12) == currDest)
{
swapSubstructures(currDest, i);
}
}
}
}
void Gen3Pokemon::swapSubstructures(int indexOne, int indexTwo)
{
if (indexOne == indexTwo)
{
return;
}
byte tempByte;
for (int i = 0; i < 12; i++)
{
tempByte = dataArrayPtr[0x20 + (indexOne * 12) + i];
dataArrayPtr[0x20 + (indexOne * 12) + i] = dataArrayPtr[0x20 + (indexTwo * 12) + i];
dataArrayPtr[0x20 + (indexTwo * 12) + i] = tempByte;
}
int valOne = 0;
int valTwo = 0;
int tempInt;
for (int i = 0; i < 4; i++)
{
if (substructOffsets[i] == indexOne * 12)
{
valOne = i;
}
if (substructOffsets[i] == indexTwo * 12)
{
valTwo = i;
}
}
tempInt = substructOffsets[valOne];
substructOffsets[valOne] = substructOffsets[valTwo];
substructOffsets[valTwo] = tempInt;
}
void Gen3Pokemon::updateSecurityData()
{
updateSubstructureShift();
updateChecksum();
encryptSubstructures();
}
byte Gen3Pokemon::getUnownLetter()
{
if (getSpeciesIndexNumber() == 201)
{
u32 personalityValue = getPersonalityValue();
return (
((personalityValue & 0x03000000) >> 18) +
((personalityValue & 0x00030000) >> 12) +
((personalityValue & 0x00000300) >> 6) +
((personalityValue & 0x00000003) >> 0)) %
28;
}
else
{
return 255;
}
};
Nature Gen3Pokemon::getNature()
{
return (Nature)(getPersonalityValue() % 25);
};
Gender Gen3Pokemon::getGender()
{
byte index = getSpeciesIndexNumber();
u32 threshold = pokeTable->get_gender_threshold(index, true);
switch (threshold)
{
case 0:
return MALE;
case 254:
return FEMALE;
case 255:
return GENDERLESS;
default:
if ((getPersonalityValue() & 0xFF) >= threshold)
{
return MALE;
}
return FEMALE;
}
}
int Gen3Pokemon::getAbilityFromPersonalityValue()
{
if (internalAbility == 255)
{
return 255;
}
return getPersonalityValue() & 0b1;
}
int Gen3Pokemon::getSize()
{
return 255;
}
bool Gen3Pokemon::getIsShiny()
{
return (getTrainerID() ^
getSecretID() ^
(getPersonalityValue() >> 0 & 0xFFFF) ^
(getPersonalityValue() >> 16 & 0xFFFF)) < 8;
}
bool Gen3Pokemon::setNicknameArray(byte nameArr[], int nameArrSize)
{
for (int i = 0; i < nameArrSize; i++)
{
setNicknameLetter(i, nameArr[i]);
}
return true;
}
bool Gen3Pokemon::setOTArray(byte otArr[], int otArrSize)
{
for (int i = 0; i < otArrSize; i++)
{
setOTLetter(i, otArr[i]);
}
return true;
}
#pragma region
// Since there is only the Pokemon parent class, we can directly define these directly
const DataVarInfo
// All of the data info variables
Gen3Pokemon::personalityValue =
{0x00, 32, 0},
Gen3Pokemon::trainerID =
{0x04, 16, 0},
Gen3Pokemon::secretID =
{0x06, 16, 0},
Gen3Pokemon::nicknameLetterOne =
{0x08, 8, 0}, // This is silly. Change this.
Gen3Pokemon::nicknameLetterTwo =
{0x09, 8, 0},
Gen3Pokemon::nicknameLetterThree =
{0x0A, 8, 0},
Gen3Pokemon::nicknameLetterFour =
{0x0B, 8, 0},
Gen3Pokemon::nicknameLetterFive =
{0x0C, 8, 0},
Gen3Pokemon::nicknameLetterSix =
{0x0D, 8, 0},
Gen3Pokemon::nicknameLetterSeven =
{0x0E, 8, 0},
Gen3Pokemon::nicknameLetterEight =
{0x0F, 8, 0},
Gen3Pokemon::nicknameLetterNine =
{0x10, 8, 0},
Gen3Pokemon::nicknameLetterTen =
{0x11, 8, 0},
Gen3Pokemon::language =
{0x12, 8, 0},
Gen3Pokemon::isBadEgg =
{0x13, 1, 0},
Gen3Pokemon::hasSpecies =
{0x13, 1, 1},
Gen3Pokemon::useEggName =
{0x13, 1, 2},
Gen3Pokemon::blockBoxRS =
{0x13, 1, 3},
// Gen3Pokemon::unusedFlags =
// {0x13, 4, 4},
Gen3Pokemon::originalTrainerNameLetterOne =
{0x14, 8, 0}, // This is also silly. Change this.
Gen3Pokemon::originalTrainerNameLetterTwo =
{0x15, 8, 0},
Gen3Pokemon::originalTrainerNameLetterThree =
{0x16, 8, 0},
Gen3Pokemon::originalTrainerNameLetterFour =
{0x17, 8, 0},
Gen3Pokemon::originalTrainerNameLetterFive =
{0x18, 8, 0},
Gen3Pokemon::originalTrainerNameLetterSix =
{0x19, 8, 0},
Gen3Pokemon::originalTrainerNameLetterSeven =
{0x1A, 8, 0},
Gen3Pokemon::markings =
{0x1B, 4, 0},
Gen3Pokemon::checksum =
{0x1C, 16, 0};
// Gen3Pokemon::unknown =
// {0x1E, 16, 0};
const DataVarInfo
*Gen3Pokemon::nickname[10] = {
&Gen3Pokemon::nicknameLetterOne,
&Gen3Pokemon::nicknameLetterTwo,
&Gen3Pokemon::nicknameLetterThree,
&Gen3Pokemon::nicknameLetterFour,
&Gen3Pokemon::nicknameLetterFive,
&Gen3Pokemon::nicknameLetterSix,
&Gen3Pokemon::nicknameLetterSeven,
&Gen3Pokemon::nicknameLetterEight,
&Gen3Pokemon::nicknameLetterNine,
&Gen3Pokemon::nicknameLetterTen,
},
*Gen3Pokemon::originalTrainerName[7] = {
&Gen3Pokemon::originalTrainerNameLetterOne,
&Gen3Pokemon::originalTrainerNameLetterTwo,
&Gen3Pokemon::originalTrainerNameLetterThree,
&Gen3Pokemon::originalTrainerNameLetterFour,
&Gen3Pokemon::originalTrainerNameLetterFive,
&Gen3Pokemon::originalTrainerNameLetterSix,
&Gen3Pokemon::originalTrainerNameLetterSeven,
};
// data section G
const DataVarInfo
Gen3Pokemon::speciesIndexNumber =
{0x20 + 0x00, 16, 0},
Gen3Pokemon::heldItem =
{0x20 + 0x02, 16, 0},
Gen3Pokemon::expPoints =
{0x20 + 0x04, 32, 0},
Gen3Pokemon::ppUpNumMoveOne =
{0x20 + 0x08, 2, 0},
Gen3Pokemon::ppUpNumMoveTwo =
{0x20 + 0x08, 2, 2},
Gen3Pokemon::ppUpNumMoveThree =
{0x20 + 0x08, 2, 4},
Gen3Pokemon::ppUpNumMoveFour =
{0x20 + 0x08, 2, 6},
Gen3Pokemon::friendship =
{0x20 + 0x09, 8, 0};
// Gen3Pokemon::unused =
// {0x20 + 0x0A, 16, 0};
const DataVarInfo
*Gen3Pokemon::ppUpNums[4] = {
&Gen3Pokemon::ppUpNumMoveOne,
&Gen3Pokemon::ppUpNumMoveTwo,
&Gen3Pokemon::ppUpNumMoveThree,
&Gen3Pokemon::ppUpNumMoveFour,
};
// data section A
const DataVarInfo
Gen3Pokemon::moveOne =
{0x20 + 0x00, 16, 0},
Gen3Pokemon::moveTwo =
{0x20 + 0x02, 16, 0},
Gen3Pokemon::moveThree =
{0x20 + 0x04, 16, 0},
Gen3Pokemon::moveFour =
{0x20 + 0x06, 16, 0},
Gen3Pokemon::moveOnePP =
{0x20 + 0x08, 8, 0},
Gen3Pokemon::moveTwoPP =
{0x20 + 0x09, 8, 0},
Gen3Pokemon::moveThreePP =
{0x20 + 0x0A, 8, 0},
Gen3Pokemon::moveFourPP =
{0x20 + 0x0B, 8, 0};
const DataVarInfo
*Gen3Pokemon::moves[4] = {
&Gen3Pokemon::moveOne,
&Gen3Pokemon::moveTwo,
&Gen3Pokemon::moveThree,
&Gen3Pokemon::moveFour,
},
*Gen3Pokemon::ppUpTotals[4] = {
&Gen3Pokemon::moveOnePP,
&Gen3Pokemon::moveTwoPP,
&Gen3Pokemon::moveThreePP,
&Gen3Pokemon::moveFourPP,
};
// data section E
const DataVarInfo
Gen3Pokemon::hpEVs =
{0x20 + 0x00, 8, 0},
Gen3Pokemon::attackEVs =
{0x20 + 0x01, 8, 0},
Gen3Pokemon::defenseEVs =
{0x20 + 0x02, 8, 0},
Gen3Pokemon::speedEVs =
{0x20 + 0x03, 8, 0},
Gen3Pokemon::specialAttackEVs =
{0x20 + 0x04, 8, 0},
Gen3Pokemon::specialDefenseEVs =
{0x20 + 0x05, 8, 0},
Gen3Pokemon::coolnessCondition =
{0x20 + 0x06, 8, 0},
Gen3Pokemon::beautyCondition =
{0x20 + 0x07, 8, 0},
Gen3Pokemon::cutenessCondition =
{0x20 + 0x08, 8, 0},
Gen3Pokemon::smartnessCondition =
{0x20 + 0x09, 8, 0},
Gen3Pokemon::toughnessCondition =
{0x20 + 0x0A, 8, 0},
Gen3Pokemon::sheen =
{0x20 + 0x0B, 8, 0};
const DataVarInfo
*Gen3Pokemon::EVs[6] = {
&Gen3Pokemon::hpEVs,
&Gen3Pokemon::attackEVs,
&Gen3Pokemon::defenseEVs,
&Gen3Pokemon::speedEVs,
&Gen3Pokemon::specialAttackEVs,
&Gen3Pokemon::specialDefenseEVs,
},
*Gen3Pokemon::contestConditions[5] = {
&Gen3Pokemon::coolnessCondition,
&Gen3Pokemon::beautyCondition,
&Gen3Pokemon::cutenessCondition,
&Gen3Pokemon::smartnessCondition,
&Gen3Pokemon::toughnessCondition,
};
const DataVarInfo
// data section M
Gen3Pokemon::pokerusStrain =
{0x20 + 0x00, 4, 0},
Gen3Pokemon::pokerusDaysRemaining =
{0x20 + 0x00, 4, 4},
Gen3Pokemon::metLocation =
{0x20 + 0x01, 8, 0},
Gen3Pokemon::levelMet =
{0x20 + 0x02, 7, 0},
Gen3Pokemon::gameOfOrigin =
{0x20 + 0x02, 4, 7},
Gen3Pokemon::pokeballCaughtIn =
{0x20 + 0x02, 4, 11},
Gen3Pokemon::originalTrainerGender =
{0x20 + 0x02, 1, 15},
Gen3Pokemon::hpIVs =
{0x20 + 0x04, 5, 0},
Gen3Pokemon::attackIVs =
{0x20 + 0x04, 5, 5},
Gen3Pokemon::defenseIVs =
{0x20 + 0x04, 5, 10},
Gen3Pokemon::speedIVs =
{0x20 + 0x04, 5, 15},
Gen3Pokemon::specialAttackIVs =
{0x20 + 0x04, 5, 20},
Gen3Pokemon::specialDefenseIVs =
{0x20 + 0x04, 5, 25},
Gen3Pokemon::isEgg =
{0x20 + 0x04, 1, 30},
Gen3Pokemon::ability =
{0x20 + 0x04, 1, 31},
Gen3Pokemon::coolNormalContestRibbon =
{0x20 + 0x08, 1, 0}, // This is also very silly. Change it.
Gen3Pokemon::coolSuperContestRibbon =
{0x20 + 0x08, 1, 0},
Gen3Pokemon::coolHyperContestRibbon =
{0x20 + 0x08, 1, 1},
Gen3Pokemon::coolMasterContestRibbon =
{0x20 + 0x08, 1, 2},
Gen3Pokemon::beautyNormalContestRibbon =
{0x20 + 0x08, 1, 3},
Gen3Pokemon::beautySuperContestRibbon =
{0x20 + 0x08, 1, 4},
Gen3Pokemon::beautyHyperContestRibbon =
{0x20 + 0x08, 1, 5},
Gen3Pokemon::beautyMasterContestRibbon =
{0x20 + 0x08, 1, 6},
Gen3Pokemon::cuteNormalContestRibbon =
{0x20 + 0x08, 1, 7},
Gen3Pokemon::cuteSuperContestRibbon =
{0x20 + 0x08, 1, 8},
Gen3Pokemon::cuteHyperContestRibbon =
{0x20 + 0x08, 1, 9},
Gen3Pokemon::cuteMasterContestRibbon =
{0x20 + 0x08, 1, 10},
Gen3Pokemon::smartNormalContestRibbon =
{0x20 + 0x08, 1, 11},
Gen3Pokemon::smartSuperContestRibbon =
{0x20 + 0x08, 1, 12},
Gen3Pokemon::smartHyperContestRibbon =
{0x20 + 0x08, 1, 13},
Gen3Pokemon::smartMasterContestRibbon =
{0x20 + 0x08, 1, 14},
Gen3Pokemon::toughNormalContestRibbon =
{0x20 + 0x08, 1, 15},
Gen3Pokemon::toughSuperContestRibbon =
{0x20 + 0x08, 1, 16},
Gen3Pokemon::toughHyperContestRibbon =
{0x20 + 0x08, 1, 17},
Gen3Pokemon::toughMasterContestRibbon =
{0x20 + 0x08, 1, 18},
Gen3Pokemon::championRibbon =
{0x20 + 0x08, 1, 19},
Gen3Pokemon::winningRibbon =
{0x20 + 0x08, 1, 20},
Gen3Pokemon::victoryRibbon =
{0x20 + 0x08, 1, 21},
Gen3Pokemon::artistRibbon =
{0x20 + 0x08, 1, 22},
Gen3Pokemon::effortRibbon =
{0x20 + 0x08, 1, 23},
Gen3Pokemon::battleChampionRibbon =
{0x20 + 0x08, 1, 24},
Gen3Pokemon::regionalChampionRibbon =
{0x20 + 0x08, 1, 25},
Gen3Pokemon::nationalChampionRibbon =
{0x20 + 0x08, 1, 26},
Gen3Pokemon::countryRibbon =
{0x20 + 0x08, 1, 27},
Gen3Pokemon::nationalRibbon =
{0x20 + 0x08, 1, 28},
Gen3Pokemon::earthRibbon =
{0x20 + 0x08, 1, 29},
Gen3Pokemon::unusedRibbons =
{0x20 + 0x08, 1, 30},
Gen3Pokemon::fatefulEncounterObedience =
{0x20 + 0x08, 1, 31};
const DataVarInfo
*Gen3Pokemon::IVs[6] = {
&Gen3Pokemon::hpIVs,
&Gen3Pokemon::attackIVs,
&Gen3Pokemon::defenseIVs,
&Gen3Pokemon::speedIVs,
&Gen3Pokemon::specialAttackIVs,
&Gen3Pokemon::specialDefenseIVs,
},
*Gen3Pokemon::ribbons[31] = {
&Gen3Pokemon::coolNormalContestRibbon,
&Gen3Pokemon::coolSuperContestRibbon,
&Gen3Pokemon::coolHyperContestRibbon,
&Gen3Pokemon::coolMasterContestRibbon,
&Gen3Pokemon::beautyNormalContestRibbon,
&Gen3Pokemon::beautySuperContestRibbon,
&Gen3Pokemon::beautyHyperContestRibbon,
&Gen3Pokemon::beautyMasterContestRibbon,
&Gen3Pokemon::cuteNormalContestRibbon,
&Gen3Pokemon::cuteSuperContestRibbon,
&Gen3Pokemon::cuteHyperContestRibbon,
&Gen3Pokemon::cuteMasterContestRibbon,
&Gen3Pokemon::smartNormalContestRibbon,
&Gen3Pokemon::smartSuperContestRibbon,
&Gen3Pokemon::smartHyperContestRibbon,
&Gen3Pokemon::smartMasterContestRibbon,
&Gen3Pokemon::toughNormalContestRibbon,
&Gen3Pokemon::toughSuperContestRibbon,
&Gen3Pokemon::toughHyperContestRibbon,
&Gen3Pokemon::toughMasterContestRibbon,
&Gen3Pokemon::championRibbon,
&Gen3Pokemon::winningRibbon,
&Gen3Pokemon::victoryRibbon,
&Gen3Pokemon::artistRibbon,
&Gen3Pokemon::effortRibbon,
&Gen3Pokemon::battleChampionRibbon,
&Gen3Pokemon::regionalChampionRibbon,
&Gen3Pokemon::nationalChampionRibbon,
&Gen3Pokemon::countryRibbon,
&Gen3Pokemon::nationalRibbon,
&Gen3Pokemon::earthRibbon,
};
#pragma endregion

165
source/pccs/PokeBox.cpp Normal file
View File

@ -0,0 +1,165 @@
#include "PokeBox.h"
#include <string>
#if ON_GBA
#include "global_frame_controller.h"
#include "text_engine.h"
#endif
PokeBox::PokeBox()
{
nullMon = new Pokemon();
}
PokeBox::PokeBox(PokemonTables *nTable)
{
table = nTable;
}
void PokeBox::setTable(PokemonTables *nTable)
{
table = nTable;
}
bool PokeBox::addPokemon(Pokemon *currPkmn)
{
if (currIndex < 30)
{
boxStorage[currIndex] = currPkmn;
currIndex++;
return true;
}
return false;
}
Pokemon *PokeBox::getPokemon(int index)
{
if (index < currIndex)
{
return boxStorage[index];
}
return nullMon;
}
GBPokemon *PokeBox::getGBPokemon(int index)
{
Pokemon *currPkmn = getPokemon(index);
GBPokemon *currGBPkmn = (GBPokemon *)currPkmn;
return currGBPkmn;
}
Gen3Pokemon *PokeBox::getGen3Pokemon(int index)
{
Pokemon *currPkmn = getPokemon(index);
Gen3Pokemon *currGen3Pkmn = (Gen3Pokemon *)currPkmn;
currGen3Pkmn->updateSecurityData();
return currGen3Pkmn;
}
bool PokeBox::removePokemon(int index)
{
if (index < currIndex)
{
for (int i = index; i < currIndex; i++)
{
boxStorage[i] = boxStorage[i + 1];
}
currIndex -= 1;
return true;
}
return false;
}
// This is used to load our data in from an array
void PokeBox::loadData(int generation, Language nLang, byte nDataArray[])
{
if (nLang != ENGLISH)
{
return; // Other languages are not supported yet
}
for (int pkmnIndex = 0; pkmnIndex < nDataArray[0]; pkmnIndex++)
{
GBPokemon *newPkmn = nullptr;
if (generation == 1)
{
newPkmn = new Gen1Pokemon(table);
}
else if (generation == 2)
{
newPkmn = new Gen2Pokemon(table);
}
int externalIDOffset = 1;
int dataOffset = externalIDOffset + (20 * 1) + 1;
int trainerNameOffset = dataOffset + (20 * newPkmn->dataArraySize);
int nicknameOffset = trainerNameOffset + (20 * newPkmn->OTArraySize);
externalIDOffset += pkmnIndex * 1;
dataOffset += pkmnIndex * newPkmn->dataArraySize;
trainerNameOffset += pkmnIndex * newPkmn->OTArraySize;
nicknameOffset += pkmnIndex * newPkmn->nicknameArraySize;
newPkmn->loadData(
nLang,
&nDataArray[dataOffset], // Pokemon Data
&nDataArray[nicknameOffset], // Nickname
&nDataArray[trainerNameOffset], // Trainer Name
nDataArray[externalIDOffset] // External ID Number
);
addPokemon(newPkmn);
}
}
void PokeBox::convertPkmn(int index)
{
Gen3Pokemon *convertedPkmn = new Gen3Pokemon(table);
Pokemon *basePkmn = getPokemon(index);
GBPokemon *oldPkmn = (GBPokemon *)(basePkmn);
oldPkmn->convertToGen3(convertedPkmn, stabilize_mythical);
delete boxStorage[index];
boxStorage[index] = convertedPkmn;
}
void PokeBox::convertAll()
{
for (int i = 0; i < currIndex; i++)
{
convertPkmn(i);
}
}
int PokeBox::getNumInBox()
{
return currIndex;
}
int PokeBox::getNumValid()
{
int numValid = 0;
for (int i = 0; i < currIndex; i++)
{
if (getPokemon(i)->isValid)
{
numValid++;
}
}
return numValid;
}
#if ON_GBA
#else
std::string PokeBox::printDataArray()
{
std::stringstream ss;
for (int i = 0; i < currIndex; i++)
{
if (boxStorage[i]->generation == 3)
{
ss << ((Gen3Pokemon *)boxStorage[i])->printDataArray(true) << "\n";
}
}
return ss.str();
}
#endif

99
source/pccs/Pokemon.cpp Normal file
View File

@ -0,0 +1,99 @@
#include "Pokemon.h"
Pokemon::Pokemon()
{
isValid = false;
}
u32 Pokemon::getSpeciesIndexNumber()
{
return 0;
}
u32 Pokemon::getVar(DataVarInfo dataVar)
{
return getVar(dataVar, 0);
}
u32 Pokemon::getVar(DataVarInfo dataVar, int extraByteOffset)
{
u32 out = 0;
if (dataVar.dataLength < 8)
{ // is less than a byte, do bitwise stuff on a single byte
// ... but we can't assume that the data is within a single byte (thanks gen 3)
if (dataVar.dataLength + dataVar.bitOffset > 8)
{
int numBytes = (dataVar.dataLength + dataVar.bitOffset) / 8 + 1;
if (numBytes > 4)
{
numBytes = 4; // This avoids importing math for rounding. Silly though.
}
int arrayIndex;
for (int i = 0; i < numBytes; i++)
{
arrayIndex = (isBigEndian ? i : numBytes - (i + 1));
out = (out << 8) | dataArrayPtr[dataVar.byteOffset + extraByteOffset + arrayIndex];
}
out = (out >> dataVar.bitOffset) & sizeToMask(dataVar.dataLength);
}
else
{
out = (dataArrayPtr[dataVar.byteOffset + extraByteOffset] >> dataVar.bitOffset) & sizeToMask(dataVar.dataLength);
}
}
else
{ // is larger than a byte, will have to access multiple parts of the array
int numBytes = dataVar.dataLength / 8;
int arrayIndex;
for (int i = 0; i < numBytes; i++)
{
arrayIndex = (isBigEndian ? i : numBytes - (i + 1));
out = (out << 8) | dataArrayPtr[dataVar.byteOffset + extraByteOffset + arrayIndex];
}
}
return out;
}
bool Pokemon::setVar(DataVarInfo dataVar, u32 newValue)
{
return setVar(dataVar, 0, newValue);
}
bool Pokemon::setVar(DataVarInfo dataVar, int extraByteOffset, u32 newValue)
{
if (dataVar.dataLength < 8)
{ // is less than a byte, do bitwise stuff on a single byte
// ... but we can't assume that the data is within a single byte (thanks gen 3)
if (dataVar.dataLength + dataVar.bitOffset > 8)
{
int numBytes = (dataVar.dataLength + dataVar.bitOffset) / 8 + 1;
if (numBytes > 4)
{
numBytes = 4; // This avoids importing math for rounding. Silly though.
}
int arrayIndex;
for (int i = 0; i < numBytes; i++)
{
arrayIndex = (isBigEndian ? i : numBytes - (i + 1));
dataArrayPtr[dataVar.byteOffset + arrayIndex + extraByteOffset] &= ~((sizeToMask(dataVar.dataLength) << dataVar.bitOffset) >> (arrayIndex * 8));
dataArrayPtr[dataVar.byteOffset + arrayIndex + extraByteOffset] |= ((newValue & sizeToMask(dataVar.dataLength)) << dataVar.bitOffset) >> (arrayIndex * 8);
}
}
else
{
dataArrayPtr[dataVar.byteOffset + extraByteOffset] &= ~(sizeToMask(dataVar.dataLength) << dataVar.bitOffset);
dataArrayPtr[dataVar.byteOffset + extraByteOffset] |= (newValue & sizeToMask(dataVar.dataLength)) << dataVar.bitOffset;
}
}
else
{ // is larger than a byte, will have to access multiple parts of the array
int numBytes = dataVar.dataLength / 8;
int arrayIndex;
for (int i = 0; i < numBytes; i++)
{
arrayIndex = (isBigEndian ? i : numBytes - (i + 1));
dataArrayPtr[dataVar.byteOffset + arrayIndex + extraByteOffset] = (newValue >> (8 * ((numBytes - 1) - i)));
}
}
return true;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
#include "gameboy_colour.h"
#include "pokemon_party.h"
#include "pokemon.h"
#include "flash_mem.h"
#include "debug_mode.h"
#include "mystery_gift_injector.h"
@ -13,8 +12,9 @@
#include "gb_gen1_payloads_RB_lz10_bin.h"
#include "gb_gen1_payloads_Y_lz10_bin.h"
#include "gb_gen2_payloads_lz10_bin.h"
#include "save_data_manager.h"
static const byte gen1_rb_debug_box_data[0x462] = {
static byte gen1_rb_debug_box_data[0x462] = {
// Num of Pokemon
0x14,
// Pokemon 1-20
@ -83,7 +83,7 @@ static const byte gen1_rb_debug_box_data[0x462] = {
0x91, 0x80, 0x93, 0x93, 0x80, 0x93, 0x80, 0x50, 0x50, 0x50, 0x50,
0x8F, 0x88, 0x83, 0x86, 0x84, 0x98, 0x50, 0x50, 0x50, 0x50, 0x50};
static const byte gen2_debug_box_data[0x44E] = {
static byte gen2_debug_box_data[0x44E] = {
// Num of Pokemon
0x14,
// Pokemon 1-20
@ -152,7 +152,9 @@ static const byte gen2_debug_box_data[0x44E] = {
0x92, 0x87, 0x94, 0x82, 0x8A, 0x8B, 0x84, 0x50, 0x50, 0x50, 0x50,
0x92, 0x87, 0x94, 0x82, 0x8A, 0x8B, 0x84, 0x50, 0x50, 0x50, 0x50};
Pokemon_Party::Pokemon_Party() {};
Pokemon_Party::Pokemon_Party() {
box.setTable(&table);
};
void Pokemon_Party::start_link()
{
@ -160,30 +162,27 @@ void Pokemon_Party::start_link()
{
if (curr_gb_rom.generation == 1 && curr_gb_rom.version)
{
for (int i = 0; i < 0x462; i++)
{
box_data_array[i] = gen1_rb_debug_box_data[i];
}
box.loadData(1, ENGLISH, gen1_rb_debug_box_data);
}
else
{
for (int i = 0; i < 0x44E; i++)
{
box_data_array[i] = gen2_debug_box_data[i];
}
box.loadData(2, ENGLISH, gen2_debug_box_data);
}
}
else
{
u16 debug_charset[256];
load_localized_charset(debug_charset, 3, ENG_ID);
load_localized_charset(debug_charset, 3, ENGLISH);
init_payload();
setup(debug_charset);
memset(box_data_array, 0, curr_gb_rom.box_data_size);
last_error = loop(&box_data_array[0], current_payload, &curr_gb_rom, simple_pkmn_array, debug_charset, false);
// This used to clear out the box data, probably isn't needed anymore
// memset(box_data_array, 0, curr_gb_rom.box_data_size);
last_error = loop(&box_data_array[0], current_payload, &curr_gb_rom, &box, debug_charset, false);
box.loadData(curr_gb_rom.generation, (Language)curr_gb_rom.language, box_data_array);
}
}
@ -193,9 +192,9 @@ void Pokemon_Party::continue_link(bool cancel_connection)
{
u16 debug_charset[256];
load_localized_charset(debug_charset, 3, ENG_ID);
load_localized_charset(debug_charset, 3, ENGLISH);
last_error = loop(&box_data_array[0], current_payload, &curr_gb_rom, simple_pkmn_array, debug_charset, cancel_connection);
last_error = loop(&box_data_array[0], current_payload, &curr_gb_rom, &box, debug_charset, cancel_connection);
}
}
@ -204,29 +203,30 @@ int Pokemon_Party::get_last_error()
return last_error;
}
Pokemon Pokemon_Party::get_converted_pkmn(PokemonTables& data_tables, int index)
{
Pokemon converted_mon;
converted_mon.load_data(index, box_data_array, game, lang);
converted_mon.convert_to_gen_three(data_tables, Legal, false, stabilize_mythic);
has_new_pkmn = has_new_pkmn || converted_mon.get_is_new();
simple_pkmn_array[index] = converted_mon.get_simple_pkmn();
return converted_mon;
}
bool Pokemon_Party::get_has_new_pkmn() // If Pokemon is not in the dex
{
return has_new_pkmn;
bool out = false;
for (int i = 0; i < box.getNumInBox(); i++)
{
out |= !is_caught(box.getPokemon(i)->getSpeciesIndexNumber());
}
return out;
}
bool Pokemon_Party::get_contains_mythical()
{
return contains_mythical;
bool out = false;
for (int i = 0; i < box.getNumInBox(); i++)
{
out |= (box.getPokemon(i)->getSpeciesIndexNumber() == MEW || box.getPokemon(i)->getSpeciesIndexNumber() == CELEBI);
}
return out;
}
void Pokemon_Party::set_mythic_stabilization(bool stabilize)
{
stabilize_mythic = stabilize;
box.stabilize_mythical = stabilize;
}
void Pokemon_Party::set_game(int nGame)
@ -269,7 +269,7 @@ bool Pokemon_Party::load_gb_rom()
u32 rom_table_size;
const u8 *cur;
switch(lang)
switch (lang)
{
case ENG_ID:
compressed_rom_table = gb_rom_values_eng_lz10_bin;
@ -287,7 +287,7 @@ bool Pokemon_Party::load_gb_rom()
LZ77UnCompWram(compressed_rom_table, gb_rom_table_buffer);
cur = gb_rom_table_buffer;
while(cur < gb_rom_table_buffer + rom_table_size)
while (cur < gb_rom_table_buffer + rom_table_size)
{
const GB_ROM *rom_values = reinterpret_cast<const GB_ROM *>(cur);
if (lang == rom_values->language &&
@ -302,44 +302,30 @@ bool Pokemon_Party::load_gb_rom()
return false;
}
Simplified_Pokemon Pokemon_Party::get_simple_pkmn(int index)
{
return simple_pkmn_array[index];
}
bool Pokemon_Party::fill_simple_pkmn_array(PokemonTables &data_tables)
{
contains_mythical = false;
for (int index = 0; index < get_num_pkmn(); index++)
{
Pokemon converted_mon;
converted_mon.load_data(index, box_data_array, game, lang);
converted_mon.convert_to_gen_three(data_tables, Legal, true, stabilize_mythic);
has_new_pkmn = has_new_pkmn || converted_mon.get_is_new();
contains_mythical = contains_mythical ||
converted_mon.get_dex_number() == 151 || converted_mon.get_dex_number() == 251;
simple_pkmn_array[index] = converted_mon.get_simple_pkmn();
contains_valid |= converted_mon.get_validity();
contains_invalid |= !converted_mon.get_validity();
contains_missingno |= converted_mon.is_missingno;
}
return contains_valid || DONT_HIDE_INVALID_PKMN;
}
int Pokemon_Party::get_num_pkmn()
{
return box_data_array[0];
return box.getNumInBox();
}
bool Pokemon_Party::get_contains_invalid()
{
return contains_invalid;
}
bool out = false;
for (int i = 0; i < box.getNumInBox(); i++)
{
out |= !box.getGBPokemon(i)->isValid;
}
return out;
}
bool Pokemon_Party::get_contains_missingno()
{
return contains_missingno;
bool out = false;
for (int i = 0; i < box.getNumInBox(); i++)
{
out |= box.getPokemon(i)->getSpeciesIndexNumber() == MISSINGNO;
}
return out;
}
void Pokemon_Party::init_payload()
@ -348,11 +334,11 @@ void Pokemon_Party::init_payload()
const u8 *payload_src;
u32 payload_file_size;
//WARNING: Ensure sure decompression_buffer is large enough!
// WARNING: Ensure sure decompression_buffer is large enough!
if(curr_gb_rom.generation == 1)
if (curr_gb_rom.generation == 1)
{
if(curr_gb_rom.version == YELLOW_ID)
if (curr_gb_rom.version == YELLOW_ID)
{
payload_src = gb_gen1_payloads_Y_lz10_bin;
}

View File

@ -1,11 +1,11 @@
#include "random.h"
#include <tonc.h>
#include "random.h"
unsigned int u32_rand;
void rand_set_seed(unsigned int init_seed)
{
u32_rand = init_seed;
u32_rand = init_seed + 1;
}
unsigned int rand_get_seed()

View File

@ -12,7 +12,7 @@
#include "gba_rom_values_jpn_lz10_bin.h"
#include "gba_rom_values_spa_lz10_bin.h"
extern rom_data curr_rom;
extern rom_data curr_GBA_rom;
rom_data::rom_data() {}
bool rom_data::load_rom()
@ -124,9 +124,9 @@ void rom_data::fill_values(const ROM_DATA *rom_values)
all_collected_flag = rom_values->unused_flag_start; // The flag for if everything has been collected
pkmn_collected_flag_start = rom_values->unused_flag_start + 1; // The beginning of the flags for each of the Pokemon
map_bank = (ENABLE_OLD_EVENT ? rom_values->old_map_bank : rom_values->map_bank);
map_id = (ENABLE_OLD_EVENT ? rom_values->old_map_id : rom_values->map_id);
npc_id = (ENABLE_OLD_EVENT ? rom_values->old_npc_id : rom_values->npc_id);
map_bank = rom_values->map_bank;
map_id = rom_values->map_id;
npc_id = rom_values->npc_id;
npc_palette = rom_values->npc_palette;
def_map_bank = rom_values->def_map_bank;

View File

@ -67,7 +67,7 @@ Box_Menu box_viewer;
// DIA_ERROR_DISCONNECT
//
// Pause the transfer and show the user their box data
// CMD_LOAD_SIMP
// CMD_IS_A_VALID_PKMN
// DIA_NO_VALID_PKMN
// COND_SOME_INVALID_PKMN
// DIA_SOME_INVALID_PKMN
@ -364,9 +364,9 @@ const script_obj_params transfer_script_params[SCRIPT_SIZE] = {
.conditional_index = CMD_MYTHIC_MENU,
.next_if_true = COND_CHECK_MISSINGNO
},
// CMD_LOAD_SIMP
// CMD_IS_A_VALID_PKMN
{
.conditional_index = CMD_LOAD_SIMP,
.conditional_index = CMD_IS_A_VALID_PKMN,
.next_if_true = COND_SOME_INVALID_PKMN,
.next_if_false = DIA_NO_VALID_PKMN
},
@ -389,7 +389,7 @@ const script_obj_params transfer_script_params[SCRIPT_SIZE] = {
// COND_ERROR_DISCONNECT
{
.conditional_index = COND_ERROR_DISCONNECT,
.next_if_true = CMD_LOAD_SIMP,
.next_if_true = CMD_IS_A_VALID_PKMN,
.next_if_false = DIA_ERROR_DISCONNECT
},
// COND_ERROR_COM_ENDED
@ -640,7 +640,7 @@ const script_obj_params event_script_params[SCRIPT_SIZE] = {
{}, // CMD_CONTINUE_LINK
{}, // CMD_BOX_MENU
{}, // CMD_MYTHIC_MENU
{}, // CMD_LOAD_SIMP
{}, // CMD_IS_A_VALID_PKMN
{}, // CMD_CANCEL_LINK
{}, // CMD_END_MISSINGNO
{}, // COND_ERROR_TIMEOUT_ONE
@ -689,7 +689,7 @@ void populate_lang_menu()
langs.add_option(GENERAL_option_german, GER_ID);
langs.add_option(GENERAL_option_italian, ITA_ID);
langs.add_option(GENERAL_option_korean, KOR_ID);
// Removing the cancel option for the time being, since canceling the
// TODO: Removing the cancel option for the time being, since canceling the
// link trade when there is no link connection crashes the game
// langs.add_option(GENERAL_option_cancel, UINT8_MAX);
}
@ -727,12 +727,6 @@ void populate_game_menu(int lang)
}
}
static bool __attribute__((noinline)) load_simple_party_data()
{
PokemonTables data_tables;
return party_data.fill_simple_pkmn_array(data_tables);
}
bool run_conditional(int index)
{
// Here is most of the logic that drives what lines show up where. It's probably not the best way to code it, but it works
@ -758,10 +752,10 @@ bool run_conditional(int index)
return party_data.get_last_error() != COND_ERROR_COLOSSEUM;
case COND_BEAT_E4:
return read_flag(curr_rom.e4_flag) || IGNORE_MG_E4_FLAGS;
return read_flag(curr_GBA_rom.e4_flag) || IGNORE_MG_E4_FLAGS;
case COND_MG_ENABLED:
return read_flag(curr_rom.mg_flag) || IGNORE_MG_E4_FLAGS;
return read_flag(curr_GBA_rom.mg_flag) || IGNORE_MG_E4_FLAGS;
case COND_TUTORIAL_COMPLETE:
return get_tutorial_flag() && !FORCE_TUTORIAL;
@ -770,16 +764,16 @@ bool run_conditional(int index)
return party_data.get_has_new_pkmn();
case COND_IS_HOENN_RS:
return curr_rom.is_ruby_sapphire();
return curr_GBA_rom.is_ruby_sapphire();
case COND_IS_FRLGE:
return !curr_rom.is_ruby_sapphire();
return !curr_GBA_rom.is_ruby_sapphire();
case COND_MG_OTHER_EVENT:
return compare_map_and_npc_data(curr_rom.def_map_bank, curr_rom.def_map_id, curr_rom.def_npc_id) && !IGNORE_MG_E4_FLAGS;
return compare_map_and_npc_data(curr_GBA_rom.def_map_bank, curr_GBA_rom.def_map_id, curr_GBA_rom.def_npc_id) && !IGNORE_MG_E4_FLAGS;
case COND_PKMN_TO_COLLECT:
return compare_map_and_npc_data(curr_rom.map_bank, curr_rom.map_id, curr_rom.npc_id) && !read_flag(curr_rom.all_collected_flag) && !IGNORE_UNRECEIVED_PKMN;
return compare_map_and_npc_data(curr_GBA_rom.map_bank, curr_GBA_rom.map_id, curr_GBA_rom.npc_id) && !read_flag(curr_GBA_rom.all_collected_flag) && !IGNORE_UNRECEIVED_PKMN;
case COND_GB_ROM_EXISTS:
return party_data.load_gb_rom();
@ -804,7 +798,7 @@ bool run_conditional(int index)
return party_data.get_contains_invalid();
case COND_IS_HOENN_E:
return curr_rom.gamecode == EMERALD_ID;
return curr_GBA_rom.gamecode == EMERALD_ID;
case COND_CHECK_MISSINGNO:
if (party_data.get_contains_missingno())
@ -824,7 +818,7 @@ bool run_conditional(int index)
return true;
case CMD_IMPORT_POKEMON:
inject_mystery(party_data);
inject_mystery(&party_data.box);
return true;
case CMD_BACK_TO_MENU:
@ -901,7 +895,7 @@ bool run_conditional(int index)
case CMD_BOX_MENU:
hide_text_box();
ret = (box_viewer.box_main(party_data) == CONFIRM_BUTTON);
ret = (box_viewer.box_main(&party_data.box) == CONFIRM_BUTTON);
show_text_box();
return ret;
@ -909,8 +903,8 @@ bool run_conditional(int index)
party_data.set_mythic_stabilization(yes_no_menu.button_main());
return true;
case CMD_LOAD_SIMP:
return load_simple_party_data();
case CMD_IS_A_VALID_PKMN:
return party_data.box.getNumValid() > 0;
case CMD_CANCEL_LINK:
party_data.continue_link(true);

View File

@ -5,7 +5,7 @@
#include "debug_mode.h"
#include "global_frame_controller.h"
extern rom_data curr_rom;
extern rom_data curr_GBA_rom;
script_var::script_var(u32 nValue, ptgb::vector<script_var *> &var_list_ref, int *nCurr_loc_ptr)
{
@ -77,7 +77,7 @@ void asm_var::fill_refrences(u8 mg_array[])
{
for (int j = 0; j < 4; j++)
{
mg_array[location_list[i] + j] += (start_location_in_script + curr_rom.loc_gSaveBlock1 + curr_rom.offset_ramscript + 7) >> (j * 8);
mg_array[location_list[i] + j] += (start_location_in_script + curr_GBA_rom.loc_gSaveBlock1 + curr_GBA_rom.offset_ramscript + 7) >> (j * 8);
}
}
else
@ -89,7 +89,7 @@ void asm_var::fill_refrences(u8 mg_array[])
u32 asm_var::get_loc_in_sec30()
{
return start_location_in_script + curr_rom.loc_gSaveDataBuffer + 3; // plus 3 to offset the -2 in set_start, and one for reading as thumb
return start_location_in_script + curr_GBA_rom.loc_gSaveDataBuffer + 3; // plus 3 to offset the -2 in set_start, and one for reading as thumb
}
// XSE VAR ----------------
@ -132,7 +132,7 @@ void xse_var::fill_refrences(u8 mg_array[])
u32 xse_var::get_loc_in_sec30()
{
return start_location_in_script + curr_rom.loc_gSaveDataBuffer;
return start_location_in_script + curr_GBA_rom.loc_gSaveDataBuffer;
}
// TEXTBOX VAR
@ -145,7 +145,7 @@ void textbox_var::set_text(const byte nText[])
void textbox_var::set_start()
{
start_location_in_script = *curr_loc_ptr - (ENABLE_OLD_EVENT * 4);
start_location_in_script = *curr_loc_ptr;
}
void textbox_var::set_virtual_start()
@ -166,7 +166,7 @@ void textbox_var::insert_text(const u16 *charset, u8 mg_array[], bool should_set
for (int parser = 0; parser < text_length; parser++)
{
if (curr_rom.is_hoenn() && (text[parser] == 0xFC) && (get_char_from_charset(charset, (char16_t)(text[parser + 1])) == 0x01)) // Removes colored text
if (curr_GBA_rom.is_hoenn() && (text[parser] == 0xFC) && (get_char_from_charset(charset, (char16_t)(text[parser + 1])) == 0x01)) // Removes colored text
{
parser += 2;
}
@ -216,7 +216,7 @@ void sprite_var::insert_sprite_data(u8 mg_array[], const unsigned int sprite_arr
{
set_start();
u32 pointer = curr_rom.loc_gSaveDataBuffer + *curr_loc_ptr + 8;
u32 pointer = curr_GBA_rom.loc_gSaveDataBuffer + *curr_loc_ptr + 8;
for (int i = 0; i < 4; i++)
{
mg_array[*curr_loc_ptr] = pointer >> (8 * i);
@ -255,7 +255,7 @@ void music_var::insert_music_data(u8 mg_array[], u8 blockCount, u8 priority, u8
{
for (unsigned int i = 0; i < trackArrays.size(); i++)
{
trackPointers.push_back(*curr_loc_ptr + curr_rom.loc_gSaveDataBuffer);
trackPointers.push_back(*curr_loc_ptr + curr_GBA_rom.loc_gSaveDataBuffer);
for (unsigned int j = 0; j < trackArrays[i].size(); j++)
{
mg_array[(*curr_loc_ptr)++] = trackArrays[i][j];

View File

@ -2,6 +2,7 @@
#include "sprite_data.h"
#include "translated_text.h"
#include "text_data_table.h"
#include "global_frame_controller.h"
#define TEXT_HEIGHT 10
#define TEXT_WIDTH 8

View File

@ -3,6 +3,7 @@
#include "sprite_data.h"
#include "debug_mode.h"
#include "gba_rom_values/base_gba_rom_struct.h"
#include "global_frame_controller.h"
#define SPRITE_CHAR_BLOCK 4
@ -464,7 +465,7 @@ void load_eternal_sprites()
obj_set_pos(up_arrow, 14 * 8, 3 * 8);
}
void load_temp_box_sprites(Pokemon_Party *party_data)
void load_temp_box_sprites(PokeBox *box)
{
u32 curr_tile_id = global_tile_id_end;
@ -472,21 +473,21 @@ void load_temp_box_sprites(Pokemon_Party *party_data)
{
for (int i = 0; i < 30; i++)
{
if (party_data->get_simple_pkmn(i).is_valid || DONT_HIDE_INVALID_PKMN)
GBPokemon *curr_pkmn = box->getGBPokemon(i);
if (curr_pkmn->isValid || DONT_HIDE_INVALID_PKMN)
{
Simplified_Pokemon curr_pkmn = party_data->get_simple_pkmn(i);
int dex_num = curr_pkmn.dex_number;
int dex_num = curr_pkmn->getSpeciesIndexNumber();
if (dex_num == 201)
{
dex_num = POKEMON_ARRAY_SIZE + curr_pkmn.unown_letter;
dex_num = POKEMON_ARRAY_SIZE + curr_pkmn->getUnownLetter();
}
else if (curr_pkmn.is_missingno)
else if (curr_pkmn->getSpeciesIndexNumber() == MISSINGNO)
{
dex_num = 0;
}
u32 sprite_location = (*(u32 *)(curr_rom.loc_gMonIconTable + (dex_num * 4)));
int pal_num = *(byte *)(curr_rom.loc_gMonIconPaletteIndices + dex_num);
u32 sprite_location = (*(u32 *)(curr_GBA_rom.loc_gMonIconTable + (dex_num * 4)));
int pal_num = *(byte *)(curr_GBA_rom.loc_gMonIconPaletteIndices + dex_num);
load_sprite(party_sprites[i], (const unsigned int *)sprite_location, 512, curr_tile_id, MENU_PAL_RED + pal_num, ATTR0_SQUARE, ATTR1_SIZE_32x32, 1);
obj_set_pos(party_sprites[i], ((BOXMENU_SPRITE_WIDTH + BOXMENU_HSPACE) * (i % BOXMENU_HNUM)) + (BOXMENU_LEFT + BOXMENU_SPRITE_HOFFSET), ((BOXMENU_SPRITE_HEIGHT + BOXMENU_VSPACE) * (i / BOXMENU_HNUM)) + (BOXMENU_TOP + BOXMENU_SPRITE_VOFFSET));
obj_unhide(party_sprites[i], 0);
@ -499,10 +500,10 @@ void load_temp_box_sprites(Pokemon_Party *party_data)
// Load the menu sprite palettes. Should this be done somewhere else?
for (int i = 0; i < 3; i++)
{
tonccpy((pal_obj_mem + ((MENU_PAL_RED + i) * 16)), (const unsigned short *)(curr_rom.loc_gMonIconPalettes + (i * 32)), 32);
tonccpy((pal_obj_mem + ((MENU_PAL_RED + i) * 16)), (const unsigned short *)(curr_GBA_rom.loc_gMonIconPalettes + (i * 32)), 32);
}
load_sprite_compressed(grabbed_front_sprite, (const unsigned int *)*(u32 *)(curr_rom.loc_gMonFrontPicTable + (0 * 8)), curr_tile_id, PULLED_SPRITE_PAL, ATTR0_SQUARE, ATTR1_SIZE_64x64, 1);
load_sprite_compressed(grabbed_front_sprite, (const unsigned int *)*(u32 *)(curr_GBA_rom.loc_gMonFrontPicTable + (0 * 8)), curr_tile_id, PULLED_SPRITE_PAL, ATTR0_SQUARE, ATTR1_SIZE_64x64, 1);
obj_set_pos(grabbed_front_sprite, 8, 16);
}
@ -721,7 +722,7 @@ void load_select_sprites(u8 game_id, u8 lang)
const unsigned int *gba_cart_tiles = 0;
const unsigned short *gba_cart_palette = 0;
switch (curr_rom.gamecode)
switch (curr_GBA_rom.gamecode)
{
case RUBY_ID:
@ -852,7 +853,7 @@ void update_y_offset()
obj_set_pos(flag, (8 * 11) + 4, (8 * 4) + 19 + y_offset);
}
void update_front_box_sprite(Simplified_Pokemon *curr_pkmn)
void update_front_box_sprite(GBPokemon *curr_pkmn)
{
if (IGNORE_GAME_PAK || IGNORE_GAME_PAK_SPRITES)
{
@ -860,23 +861,26 @@ void update_front_box_sprite(Simplified_Pokemon *curr_pkmn)
}
u32 curr_tile_id = global_tile_id_end + (30 * 16);
int dex_num = 0;
if (curr_pkmn->unown_letter > 1)
int dex_num = curr_pkmn->getSpeciesIndexNumber();
if (dex_num == 201)
{
dex_num = 412 + curr_pkmn->unown_letter;
if (curr_pkmn->getUnownLetter() > 1)
{
dex_num = 412 + curr_pkmn->getUnownLetter();
}
}
else if (curr_pkmn->is_missingno)
else if (curr_pkmn->getSpeciesIndexNumber() == MISSINGNO)
{
dex_num = 0;
}
else
else if (curr_pkmn->getSpeciesIndexNumber() == TREECKO)
{
dex_num = curr_pkmn->dex_number;
dex_num = 277;
}
u32 sprite_location = *(u32 *)(curr_rom.loc_gMonFrontPicTable + (dex_num * 8));
u32 palette_location = *(u32 *)((curr_pkmn->is_shiny ? curr_rom.loc_gMonShinyPaletteTable : curr_rom.loc_gMonPaletteTable) + (curr_pkmn->dex_number * 8));
u32 sprite_location = *(u32 *)(curr_GBA_rom.loc_gMonFrontPicTable + (dex_num * 8));
u32 palette_location = *(u32 *)((curr_pkmn->getIsShiny() ? curr_GBA_rom.loc_gMonShinyPaletteTable : curr_GBA_rom.loc_gMonPaletteTable) + (curr_pkmn->getSpeciesIndexNumber() * 8));
unsigned short buffer[16];
LZ77UnCompWram((const unsigned short *)palette_location, buffer); // This is a little silly, but it's being weird with bytes vs shorts when we copy it directly
@ -894,7 +898,7 @@ void update_front_box_sprite(Simplified_Pokemon *curr_pkmn)
LZ77UnCompVram((const unsigned int *)sprite_location, &tile_mem[SPRITE_CHAR_BLOCK][curr_tile_id]);
}
void update_menu_sprite(Pokemon_Party *party_data, int index, int frame)
void update_menu_sprite(PokeBox *box, int index, int frame)
{
if (IGNORE_GAME_PAK || IGNORE_GAME_PAK_SPRITES)
{
@ -903,20 +907,25 @@ void update_menu_sprite(Pokemon_Party *party_data, int index, int frame)
u32 curr_tile_id = global_tile_id_end + (index * 16);
Simplified_Pokemon curr_pkmn = party_data->get_simple_pkmn(index);
int dex_num = curr_pkmn.dex_number;
GBPokemon *curr_pkmn = box->getGBPokemon(index);
int dex_num = curr_pkmn->getSpeciesIndexNumber();
if (dex_num == 201)
{
if (curr_pkmn.unown_letter != 0)
if (curr_pkmn->getUnownLetter() > 1)
{
dex_num = 0x19C + curr_pkmn.unown_letter;
dex_num = 412 + curr_pkmn->getUnownLetter();
}
}
else if (curr_pkmn.is_missingno)
else if (curr_pkmn->getSpeciesIndexNumber() == MISSINGNO)
{
dex_num = 0;
}
else if (curr_pkmn->getSpeciesIndexNumber() == TREECKO)
{
dex_num = 277;
}
u32 sprite_location = (*(u32 *)(curr_rom.loc_gMonIconTable + (dex_num * 4))) + (frame == 0 ? 0 : 512);
u32 sprite_location = (*(u32 *)(curr_GBA_rom.loc_gMonIconTable + (dex_num * 4))) + (frame == 0 ? 0 : 512);
tonccpy(&tile_mem[SPRITE_CHAR_BLOCK][curr_tile_id], (const unsigned int *)sprite_location, 512);
}

View File

@ -174,6 +174,7 @@ int ptgb_write(const byte *text, bool instant)
// Re-implementing TTE's "tte_write" to use the gen 3 character encoding chart
int ptgb_write(const byte *text, bool instant, int length)
{
instant = instant || INSTANT_TEXT_SPEED;
if (text == NULL)
return 0;

View File

@ -20,6 +20,7 @@ if (update == True):
new_file_path = 'text_helper/new_text.xlsx'
old_file_path = 'text_helper/text.xlsx'
json_file_path = 'text_helper/output.json'
no_file = False
try:
response = requests.get(url, timeout=5)
@ -31,22 +32,26 @@ if (update == True):
except requests.exceptions.ReadTimeout as errrt:
if os.path.exists(old_file_path):
print("Connection timed out. Continuing with locally downloaded file.")
no_file = True
else:
print("xlsx file is missing and connection timed out. Exiting...")
except requests.exceptions.ConnectionError as conerr:
if os.path.exists(old_file_path):
print("Connection error. Continuing with locally downloaded file.")
no_file = True
else:
print("xlsx file is missing and connection timed out. Exiting...")
if os.path.exists(old_file_path):
new_file = pd.read_excel(new_file_path, sheet_name="Translations")
old_file = pd.read_excel(old_file_path, sheet_name="Translations")
if new_file.equals(old_file):
if (not no_file):
new_file = pd.read_excel(new_file_path, sheet_name="Translations")
old_file = pd.read_excel(old_file_path, sheet_name="Translations")
if no_file or new_file.equals(old_file):
if os.path.exists(json_file_path):
print("Downloaded file is identical. Skipping parse\n")
os.remove(new_file_path)
if (not no_file):
os.remove(new_file_path)
exit()
print("json file missing - forcing rebuild.")
os.remove(old_file_path)
@ -516,7 +521,7 @@ for lang in Languages:
# now generate the cpp file.
with open(os.curdir + '/source/translated_text.cpp', 'w') as cppFile:
cppFile.write("#include \"translated_text.h\"\n#include \"debug_mode.h\"\n#include \"pokemon_data.h\"\n")
cppFile.write("#include \"translated_text.h\"\n#include \"debug_mode.h\"\n#include \"extern_pokemon_data.h\"\n")
# generate includes for each language
for lang in Languages:
for cat in mainDict[lang.name]:

View File

@ -5,5 +5,6 @@
#include <cstddef>
void writeTable(const char *input_path, const char *output_path, const char *filename, const char *buffer, size_t buffer_size);
void generate_pokemon_data(const char *output_path);
#endif

View File

@ -16,7 +16,7 @@ typedef int32_t i32;
#else
extern "C"
{
#include <tonc_types.h>
#include <tonc_types.h>
}
#endif
@ -79,6 +79,7 @@ public:
u32 _RemovePokemon; // location of the _RemovePokemon function in the ROM
u32 SaveSAVtoSRAM1; // location of the SaveSAVtoSRAM1 function in the ROM
u32 SaveSAVtoSRAM2; // location of the SaveSAVtoSRAM2 function in the ROM
u32 LoadCurrentBoxData; // location of the LoadCurrentBoxData function in the ROM
u32 OpenSRAM; // location of the OpenSRAM function in the ROM
u32 SaveBox; // location of the SaveBox function in the ROM
u32 Bankswitch; // location of the BankswitchCommon function in the ROM
@ -86,22 +87,22 @@ public:
u32 CloseSRAM; // location of the OpenSRAM function in the ROM
u32 garbageDataLocation; // location of random data starting with 0xFD in the ROM
u32 wRemoveMonFromBox; // location of wRemoveMonFromBox in RAM
u32 wBoxCount; // location of wBoxCount in RAM
u32 wWhichPokemon; // location of wWhichPokemon in RAM
u32 wBoxDataStart; // location of wBoxDataStart in RAM
u32 wBoxDataEnd; // location of wBoxDataEnd in RAM
u32 wSerialEnemyDataBlock; // location of wSerialEnemyDataBlock in RAM
u32 wEnemyMonSpecies; // location of wEnemyMonSpecies in RAM
u32 wRemoveMonFromBox; // location of wRemoveMonFromBox in RAM
u32 wBoxCount; // location of wBoxCount in RAM
u32 wWhichPokemon; // location of wWhichPokemon in RAM
u32 wBoxDataStart; // location of wBoxDataStart in RAM
u32 wBoxDataEnd; // location of wBoxDataEnd in RAM
u32 wSerialEnemyDataBlock; // location of wSerialEnemyDataBlock in RAM
u32 wEnemyMonSpecies; // location of wEnemyMonSpecies in RAM
u32 wSerialEnemyMonsPatchList; // location of wSerialEnemyMonsPatchList in RAM
u32 wSerialOtherGameboyRandomNumberListBlock; // location of wSerialOtherGameboyRandomNumberListBlock in RAM
u32 hSerialConnectionStatus; // location of hSerialConnectionStatus in RAM
u16 transferStringLocation; // location in VRAM to start writing the transfer string to
u16 textBorderUppLeft; // location in VRAM to put the upper left corner of the border
u8 textBorderWidth; // the width of the text box border
u8 textBorderHeight; // the height of the text box border
u16 transferStringLocation; // location in VRAM to start writing the transfer string to
u16 textBorderUppLeft; // location in VRAM to put the upper left corner of the border
u8 textBorderWidth; // the width of the text box border
u8 textBorderHeight; // the height of the text box border
u16 padding_2;
};

View File

@ -1,4 +1,5 @@
#include "common.h"
#include "extern_pokemon_data.h"
#include <cstdio>
#include <cstring>

View File

@ -0,0 +1,80 @@
import socket
import sys
def format_data(string) -> int:
result = 0
for c in string:
result = (result << 8) | c
return result
def send_data(sock, b1: int, b2: int, b3: int, b4: int, time) -> None:
data = bytearray()
data.append(b1)
data.append(b2)
data.append(b3)
data.append(b4)
data.append((time >> 24) & 0xff)
data.append((time >> 16) & 0xff)
data.append((time >> 8) & 0xff)
data.append(time & 0xff)
sock.send(data)
def connect(port, callback) -> None:
sock = socket.socket()
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY,
1) # requires nodelay
sock.connect(("localhost", port))
send_data(sock, 1, 1, 4, 0, 0) # send version
try:
while 1:
# data packet will be 8 byte long
raw = format_data(sock.recv(8))
if raw == 0:
continue
b1 = cmd = raw >> 56
b2 = (raw >> 48) & 0xff
b3 = (raw >> 40) & 0xff
b4 = (raw >> 32) & 0xff
time = raw & 0xffffffff
# print("%.2x %.2x %.2x %.2x %.8x" % (b1, b2, b3, b4, time))
if cmd == 1:
# handshake (version)
pass
# send_data(sock, 0x01, 0x01, 0x04, 0x00, time)
# send_data(sock, b1, b2, b3, b4, time)
elif cmd == 101:
# sync gamepad
pass
elif cmd == 104:
# byte received from master
result = callback(b2)
if not result == None:
# send data
send_data(sock, 105, result, 0x80, 0, 0)
else:
# send ack
send_data(sock, 106, 1, 00, 0, 0)
elif cmd == 106:
send_data(sock, b1, b2, b3, b4, time)
elif cmd == 108:
send_data(sock, 108, 1, 0, 0, 0)
except Exception as e:
sock.close()
raise e
print("Connection closed.")

View File

@ -0,0 +1,99 @@
#!/usr/bin/env python3
import bgb_link
import numpy as np
from io import BufferedReader
from typing import List
hs: int
ack: int
menu: int
trade: int
colosseum: int
cancel: int
preamble: int
trade_data: int
done: int
hs, ack, menu, trade, colosseum, cancel, preamble, trade_data, done = list(
range(9))
state: int = hs
counter = 0
file_path = "to_compress/gb_gen1_payloads_Y.bin"
try:
data = np.fromfile(file_path, dtype=np.uint8)
except FileNotFoundError:
print(f"Error: The file '{file_path}' was not found.")
except Exception as e:
print(f"An error occurred: {e}")
def cable_club(byte):
global state, hs, ack, menu, trade, colosseum, cancel, trade_data
if state == hs:
if byte == 0x01:
state = ack
print("Connection established")
return 0x02
elif state == ack:
if byte == 0x00:
state = menu
print("Menu")
return 0x00
elif state == menu:
# 0xd1 battle
# 0xd5 battle selected
if byte == 0xd0:
print("Battle")
state = trade
return 0xd5
else:
return byte
elif state == trade:
if byte == 0xfd:
state = preamble
return byte
elif state == preamble:
if byte != 0xfd:
print("Sending data...")
state = trade_data
return exchange_parties(byte)
return byte
elif state == trade_data:
# 0xfd = Preamble byte for array
# 0xfe = No data
return exchange_parties(byte)
elif state == done:
# Refill the code section
return exchange_parties(byte)
return byte
def exchange_parties(byte):
global counter, data, state, done
if counter < len(data):
ret = data[counter]
counter += 1
print(hex(ret))
return ret
else:
while(True):
1==1
state = done
print("Restarting!")
counter = 436
ret = data[counter]
counter += 1
print(hex(ret))
return ret
bgb_link.connect(8765, cable_club)

View File

@ -1,4 +1,4 @@
#include "pokemon_data.h"
#include "extern_pokemon_data.h"
#include "common.h"
#include <cstdio>
@ -4705,16 +4705,16 @@ const u8 TYPES[POKEMON_ARRAY_SIZE][2]{
void generate_pokemon_data(const char *output_path)
{
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "gen_1_charsets.bin", (const char*)gen_1_charsets, sizeof(gen_1_charsets));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "gen_2_charsets.bin", (const char*)gen_2_charsets, sizeof(gen_2_charsets));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "gen_3_charsets.bin", (const char*)gen_3_charsets, sizeof(gen_3_charsets));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "EXP_GROUPS.bin", (const char*)EXP_GROUPS, sizeof(EXP_GROUPS));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "GENDER_RATIO.bin", (const char*)GENDER_RATIO, sizeof(GENDER_RATIO));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "NUM_ABILITIES.bin", (const char*)(NUM_ABILITIES), sizeof(NUM_ABILITIES));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "FIRST_MOVES.bin", (const char*)FIRST_MOVES, sizeof(FIRST_MOVES));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "JPN_NAMES.bin", (const char*)JPN_NAMES, sizeof(JPN_NAMES));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "POWER_POINTS.bin", (const char*)POWER_POINTS, sizeof(POWER_POINTS));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "MENU_SPRITE_PALS.bin", (const char*)MENU_SPRITE_PALS, sizeof(MENU_SPRITE_PALS));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "EVENT_PKMN.bin", (const char*)EVENT_PKMN, sizeof(EVENT_PKMN));
writeTable("tools/data-generator/src/pokemon_data.cpp", output_path, "TYPES.bin", (const char*)TYPES, sizeof(TYPES));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "gen_1_charsets.bin", (const char*)gen_1_charsets, sizeof(gen_1_charsets));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "gen_2_charsets.bin", (const char*)gen_2_charsets, sizeof(gen_2_charsets));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "gen_3_charsets.bin", (const char*)gen_3_charsets, sizeof(gen_3_charsets));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "EXP_GROUPS.bin", (const char*)EXP_GROUPS, sizeof(EXP_GROUPS));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "GENDER_RATIO.bin", (const char*)GENDER_RATIO, sizeof(GENDER_RATIO));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "NUM_ABILITIES.bin", (const char*)(NUM_ABILITIES), sizeof(NUM_ABILITIES));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "FIRST_MOVES.bin", (const char*)FIRST_MOVES, sizeof(FIRST_MOVES));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "JPN_NAMES.bin", (const char*)JPN_NAMES, sizeof(JPN_NAMES));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "POWER_POINTS.bin", (const char*)POWER_POINTS, sizeof(POWER_POINTS));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "MENU_SPRITE_PALS.bin", (const char*)MENU_SPRITE_PALS, sizeof(MENU_SPRITE_PALS));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "EVENT_PKMN.bin", (const char*)EVENT_PKMN, sizeof(EVENT_PKMN));
writeTable("tools/data-generator/src/extern_pokemon_data.cpp", output_path, "TYPES.bin", (const char*)TYPES, sizeof(TYPES));
}

View File

@ -1,282 +1,281 @@
#include "gb_rom_values/gb_rom_values.h"
const struct GB_ROM gb_rom_values_eng[] = {
{ // ENG_RED
.language = ENG_ID,
.version = RED_ID,
.generation = 1,
.method = METHOD_NEWLINE,
.payload_size = 637,
.box_data_size = 0x462,
{// ENG_RED
.language = ENG_ID,
.version = RED_ID,
.generation = 1,
.method = METHOD_NEWLINE,
.payload_size = 637,
.box_data_size = 0x462,
.print_string_start = 0xC456,
.stack_overwrite_location = 0xDFDD,
.short_pkmn_name = 0xE3,
.pointer_pkmn_name = 0xFC,
.padding_1 = 0,
.print_string_start = 0xC456,
.stack_overwrite_location = 0xDFDD,
.short_pkmn_name = 0xE3,
.pointer_pkmn_name = 0xFC,
.padding_1 = 0,
.clearScreen = 0x190F,
.CableClub_TextBoxBorder = 0x5AB3,
.placeString = 0x1955,
.Serial_ExchangeBytes = 0x216F,
._RemovePokemon = 0x7B68,
.SaveSAVtoSRAM1 = 0x1C77E2,
.SaveSAVtoSRAM2 = 0x1C780F,
.OpenSRAM = 0,
.SaveBox = 0,
.Bankswitch = 0x35D6,
.SoftReset = 0x1F49,
.CloseSRAM = 0,
.garbageDataLocation = 0x0316,
.clearScreen = 0x190F,
.CableClub_TextBoxBorder = 0x5AB3,
.placeString = 0x1955,
.Serial_ExchangeBytes = 0x216F,
._RemovePokemon = 0x7B68,
.SaveSAVtoSRAM1 = 0x1C77E2,
.SaveSAVtoSRAM2 = 0x1C780F,
.LoadCurrentBoxData = 0,
.OpenSRAM = 0,
.SaveBox = 0,
.Bankswitch = 0x35D6,
.SoftReset = 0x1F49,
.CloseSRAM = 0,
.garbageDataLocation = 0x0316,
.wRemoveMonFromBox = 0xCF95,
.wBoxCount = 0xDA80,
.wWhichPokemon = 0xCF92,
.wBoxDataStart = 0xDA80,
.wBoxDataEnd = 0xDEE2,
.wSerialEnemyDataBlock = 0xD893,
.wEnemyMonSpecies = 0xCFE5,
.wRemoveMonFromBox = 0xCF95,
.wBoxCount = 0xDA80,
.wWhichPokemon = 0xCF92,
.wBoxDataStart = 0xDA80,
.wBoxDataEnd = 0xDEE2,
.wSerialEnemyDataBlock = 0xD893,
.wEnemyMonSpecies = 0xCFE5,
.wSerialEnemyMonsPatchList = 0xC5D0,
.wSerialOtherGameboyRandomNumberListBlock = 0xCD81,
.hSerialConnectionStatus = 0xFFAA,
.wSerialEnemyMonsPatchList = 0xC5D0,
.wSerialOtherGameboyRandomNumberListBlock = 0xCD81,
.hSerialConnectionStatus = 0xFFAA,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0
},
{ // ENG_BLUE
.language = ENG_ID,
.version = BLUE_ID,
.generation = 1,
.method = METHOD_NEWLINE,
.payload_size = 637,
.box_data_size = 0x462,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0},
{// ENG_BLUE
.language = ENG_ID,
.version = BLUE_ID,
.generation = 1,
.method = METHOD_NEWLINE,
.payload_size = 637,
.box_data_size = 0x462,
.print_string_start = 0xC456,
.stack_overwrite_location = 0xDFDD,
.short_pkmn_name = 0xE3,
.pointer_pkmn_name = 0xFC,
.padding_1 = 0,
.print_string_start = 0xC456,
.stack_overwrite_location = 0xDFDD,
.short_pkmn_name = 0xE3,
.pointer_pkmn_name = 0xFC,
.padding_1 = 0,
.clearScreen = 0x190F,
.CableClub_TextBoxBorder = 0x5AB3,
.placeString = 0x1955,
.Serial_ExchangeBytes = 0x216F,
._RemovePokemon = 0x7B68,
.SaveSAVtoSRAM1 = 0x1C77E2,
.SaveSAVtoSRAM2 = 0x1C780F,
.OpenSRAM = 0,
.SaveBox = 0,
.Bankswitch = 0x35D6,
.SoftReset = 0x1F49,
.CloseSRAM = 0,
.garbageDataLocation = 0x0316,
.clearScreen = 0x190F,
.CableClub_TextBoxBorder = 0x5AB3,
.placeString = 0x1955,
.Serial_ExchangeBytes = 0x216F,
._RemovePokemon = 0x7B68,
.SaveSAVtoSRAM1 = 0x1C77E2,
.SaveSAVtoSRAM2 = 0x1C780F,
.LoadCurrentBoxData = 0,
.OpenSRAM = 0,
.SaveBox = 0,
.Bankswitch = 0x35D6,
.SoftReset = 0x1F49,
.CloseSRAM = 0,
.garbageDataLocation = 0x0316,
.wRemoveMonFromBox = 0xCF95,
.wBoxCount = 0xDA80,
.wWhichPokemon = 0xCF92,
.wBoxDataStart = 0xDA80,
.wBoxDataEnd = 0xDEE2,
.wSerialEnemyDataBlock = 0xD893,
.wEnemyMonSpecies = 0xCFE5,
.wRemoveMonFromBox = 0xCF95,
.wBoxCount = 0xDA80,
.wWhichPokemon = 0xCF92,
.wBoxDataStart = 0xDA80,
.wBoxDataEnd = 0xDEE2,
.wSerialEnemyDataBlock = 0xD893,
.wEnemyMonSpecies = 0xCFE5,
.wSerialEnemyMonsPatchList = 0xC5D0,
.wSerialOtherGameboyRandomNumberListBlock = 0xCD81,
.hSerialConnectionStatus = 0xFFAA,
.wSerialEnemyMonsPatchList = 0xC5D0,
.wSerialOtherGameboyRandomNumberListBlock = 0xCD81,
.hSerialConnectionStatus = 0xFFAA,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0
},
{ // ENG_YELLOW
.language = ENG_ID,
.version = YELLOW_ID,
.generation = 1,
.method = METHOD_MEW,
.payload_size = 637,
.box_data_size = 0x462,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0},
{// ENG_YELLOW
.language = ENG_ID,
.version = YELLOW_ID,
.generation = 1,
.method = METHOD_MEW,
.payload_size = 637,
.box_data_size = 0x462,
.print_string_start = 0xC456,
.stack_overwrite_location = 0xDFDD,
.short_pkmn_name = 0x15,
.pointer_pkmn_name = 0xE3,
.padding_1 = 0,
.print_string_start = 0xC456,
.stack_overwrite_location = 0xDFDD,
.short_pkmn_name = 0x15,
.pointer_pkmn_name = 0xE3,
.padding_1 = 0,
.clearScreen = 0x16DD,
.CableClub_TextBoxBorder = 0x16F0, // TextBoxBoarder, since the Cable Club isn't loaded
.placeString = 0x1723,
.Serial_ExchangeBytes = 0x1FCB,
._RemovePokemon = 0x7A0F,
.SaveSAVtoSRAM1 = 0x1C7B32,
.SaveSAVtoSRAM2 = 0x1C7B56,
.OpenSRAM = 0x3E99,
.SaveBox = 0,
.Bankswitch = 0x3E7E, // BankswitchCommon
.SoftReset = 0x1D05,
.CloseSRAM = 0x3EA9,
.garbageDataLocation = 0x0161,
.clearScreen = 0x16DD,
.CableClub_TextBoxBorder = 0x16F0, // TextBoxBoarder, since the Cable Club isn't loaded
.placeString = 0x1723,
.Serial_ExchangeBytes = 0x1FCB,
._RemovePokemon = 0x017A0F,
.SaveSAVtoSRAM1 = 0x1C7B32,
.SaveSAVtoSRAM2 = 0x1C7B56,
.LoadCurrentBoxData = 0x1C79FC,
.OpenSRAM = 0x3E99,
.SaveBox = 0,
.Bankswitch = 0x3E84,
.SoftReset = 0x1D05,
.CloseSRAM = 0x3EA9,
.garbageDataLocation = 0x0161,
.wRemoveMonFromBox = 0xCF94,
.wBoxCount = 0xDA7F,
.wWhichPokemon = 0xCF91,
.wBoxDataStart = 0xDA7F,
.wBoxDataEnd = 0xDEE1,
.wSerialEnemyDataBlock = 0xD892,
.wEnemyMonSpecies = 0xCFE4,
.wRemoveMonFromBox = 0xCF94,
.wBoxCount = 0xDA7F,
.wWhichPokemon = 0xCF91,
.wBoxDataStart = 0xDA7F,
.wBoxDataEnd = 0xDEE1,
.wSerialEnemyDataBlock = 0xD892,
.wEnemyMonSpecies = 0xCFE4,
.wSerialEnemyMonsPatchList = 0xC5D0,
.wSerialOtherGameboyRandomNumberListBlock = 0xCD81,
.hSerialConnectionStatus = 0xFFAA,
.wSerialEnemyMonsPatchList = 0xC5D0,
.wSerialOtherGameboyRandomNumberListBlock = 0xCD81,
.hSerialConnectionStatus = 0xFFAA,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0
},
{ // ENG_GOLD
.language = ENG_ID,
.version = GOLD_ID,
.generation = 2,
.method = METHOD_GEN2,
.payload_size = 672,
.box_data_size = 0x44E,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0},
{// ENG_GOLD
.language = ENG_ID,
.version = GOLD_ID,
.generation = 2,
.method = METHOD_GEN2,
.payload_size = 672,
.box_data_size = 0x44E,
.print_string_start = 0xC442,
.stack_overwrite_location = 0xDFCB, // Found by seeing where 772C is stored in the stack, 772C is the code that calls PlaceString
.short_pkmn_name = 0x4E,
.pointer_pkmn_name = 0,
.padding_1 = 0,
.print_string_start = 0xC442,
.stack_overwrite_location = 0xDFCB, // Found by seeing where 772C is stored in the stack, 772C is the code that calls PlaceString
.short_pkmn_name = 0x4E,
.pointer_pkmn_name = 0,
.padding_1 = 0,
.clearScreen = 0x000EE2,
.CableClub_TextBoxBorder = 0x0A4D88, // LinkTextboxAtHL
.placeString = 0x000F74,
.Serial_ExchangeBytes = 0x0710,
._RemovePokemon = 0x03603F, // RemoveMonFromPartyOrBox
.SaveSAVtoSRAM1 = 0,
.SaveSAVtoSRAM2 = 0,
.OpenSRAM = 0x0030E1,
.SaveBox = 0x054DF6,
.Bankswitch = 0,
.SoftReset = 0x05B0,
.CloseSRAM = 0,
.garbageDataLocation = 0x0654,
.clearScreen = 0x000EE2,
.CableClub_TextBoxBorder = 0x0A4D88, // LinkTextboxAtHL
.placeString = 0x000F74,
.Serial_ExchangeBytes = 0x0710,
._RemovePokemon = 0x03603F, // RemoveMonFromPartyOrBox
.SaveSAVtoSRAM1 = 0,
.SaveSAVtoSRAM2 = 0,
.LoadCurrentBoxData = 0,
.OpenSRAM = 0x0030E1,
.SaveBox = 0x054DF6,
.Bankswitch = 0,
.SoftReset = 0x05B0,
.CloseSRAM = 0,
.garbageDataLocation = 0x0654,
.wRemoveMonFromBox = 0x01D008, // wPokemonWithdrawDepositParameter
.wBoxCount = 0x01AD6C, // sBoxCount
.wWhichPokemon = 0x01D005, // wCurPartyMon
.wBoxDataStart = 0xAD6C, // sBoxStart
.wBoxDataEnd = 0xB1BA, // sBoxEnd
.wSerialEnemyDataBlock = 0xDD40, // wOTPartyData
.wEnemyMonSpecies = 0x01D0EF,
.wRemoveMonFromBox = 0x01D008, // wPokemonWithdrawDepositParameter
.wBoxCount = 0x01AD6C, // sBoxCount
.wWhichPokemon = 0x01D005, // wCurPartyMon
.wBoxDataStart = 0xAD6C, // sBoxStart
.wBoxDataEnd = 0xB1BA, // sBoxEnd
.wSerialEnemyDataBlock = 0xDD40, // wOTPartyData
.wEnemyMonSpecies = 0x01D0EF,
.wSerialEnemyMonsPatchList = 0xC5D0, // wOTPatchLists
.wSerialOtherGameboyRandomNumberListBlock = 0xD0EF, // wOTLinkBattleRNData
.hSerialConnectionStatus = 0xFFCD,
.wSerialEnemyMonsPatchList = 0xC5D0, // wOTPatchLists
.wSerialOtherGameboyRandomNumberListBlock = 0xD0EF, // wOTLinkBattleRNData
.hSerialConnectionStatus = 0xFFCD,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0
},
{ // ENG_SILVER
.language = ENG_ID,
.version = SILVER_ID,
.generation = 2,
.method = METHOD_GEN2,
.payload_size = 672,
.box_data_size = 0x44E,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0},
{// ENG_SILVER
.language = ENG_ID,
.version = SILVER_ID,
.generation = 2,
.method = METHOD_GEN2,
.payload_size = 672,
.box_data_size = 0x44E,
.print_string_start = 0xC442,
.stack_overwrite_location = 0xDFCB, // Found by seeing where 772C is stored in the stack, 772C is the code that calls PlaceString
.short_pkmn_name = 0x4E,
.pointer_pkmn_name = 0,
.padding_1 = 0,
.print_string_start = 0xC442,
.stack_overwrite_location = 0xDFCB, // Found by seeing where 772C is stored in the stack, 772C is the code that calls PlaceString
.short_pkmn_name = 0x4E,
.pointer_pkmn_name = 0,
.padding_1 = 0,
.clearScreen = 0x000EE2,
.CableClub_TextBoxBorder = 0x0A4D88, // LinkTextboxAtHL
.placeString = 0x000F74,
.Serial_ExchangeBytes = 0x0710,
._RemovePokemon = 0x03603D, // RemoveMonFromPartyOrBox
.SaveSAVtoSRAM1 = 0,
.SaveSAVtoSRAM2 = 0,
.OpenSRAM = 0x0030E1,
.SaveBox = 0x054DF6,
.Bankswitch = 0,
.SoftReset = 0x05B0,
.CloseSRAM = 0,
.garbageDataLocation = 0x0654,
.clearScreen = 0x000EE2,
.CableClub_TextBoxBorder = 0x0A4D88, // LinkTextboxAtHL
.placeString = 0x000F74,
.Serial_ExchangeBytes = 0x0710,
._RemovePokemon = 0x03603D, // RemoveMonFromPartyOrBox
.SaveSAVtoSRAM1 = 0,
.SaveSAVtoSRAM2 = 0,
.LoadCurrentBoxData = 0,
.OpenSRAM = 0x0030E1,
.SaveBox = 0x054DF6,
.Bankswitch = 0,
.SoftReset = 0x05B0,
.CloseSRAM = 0,
.garbageDataLocation = 0x0654,
.wRemoveMonFromBox = 0x01D008, // wPokemonWithdrawDepositParameter
.wBoxCount = 0x01AD6C, // sBoxCount
.wWhichPokemon = 0x01D005, // wCurPartyMon
.wBoxDataStart = 0xAD6C, // sBoxStart
.wBoxDataEnd = 0xB1BA, // sBoxEnd
.wSerialEnemyDataBlock = 0xDD40, // wOTPartyData
.wEnemyMonSpecies = 0x01D0EF,
.wRemoveMonFromBox = 0x01D008, // wPokemonWithdrawDepositParameter
.wBoxCount = 0x01AD6C, // sBoxCount
.wWhichPokemon = 0x01D005, // wCurPartyMon
.wBoxDataStart = 0xAD6C, // sBoxStart
.wBoxDataEnd = 0xB1BA, // sBoxEnd
.wSerialEnemyDataBlock = 0xDD40, // wOTPartyData
.wEnemyMonSpecies = 0x01D0EF,
.wSerialEnemyMonsPatchList = 0xC5D0, // wOTPatchLists
.wSerialOtherGameboyRandomNumberListBlock = 0xD0EF, // wOTLinkBattleRNData
.hSerialConnectionStatus = 0xFFCD,
.wSerialEnemyMonsPatchList = 0xC5D0, // wOTPatchLists
.wSerialOtherGameboyRandomNumberListBlock = 0xD0EF, // wOTLinkBattleRNData
.hSerialConnectionStatus = 0xFFCD,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0
},
{ // ENG_CRYSTAL
.language = ENG_ID,
.version = CRYSTAL_ID,
.generation = 2,
.method = METHOD_GEN2,
.payload_size = 672,
.box_data_size = 0x44E,
.transferStringLocation = 0xC444,
.textBorderUppLeft = 0xC42F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0},
{// ENG_CRYSTAL
.language = ENG_ID,
.version = CRYSTAL_ID,
.generation = 2,
.method = METHOD_GEN2,
.payload_size = 672,
.box_data_size = 0x44E,
.print_string_start = 0xC544,
.stack_overwrite_location = 0xE0BB, // Found by seeing where 7622 is stored in the stack, 7622 is the code that calls PlaceString (PlaceTradePartnerNamesAndParty)
.short_pkmn_name = 0x4E,
.pointer_pkmn_name = 0,
.padding_1 = 0,
.print_string_start = 0xC544,
.stack_overwrite_location = 0xE0BB, // Found by seeing where 7622 is stored in the stack, 7622 is the code that calls PlaceString (PlaceTradePartnerNamesAndParty)
.short_pkmn_name = 0x4E,
.pointer_pkmn_name = 0,
.padding_1 = 0,
.clearScreen = 0x000FDB,
.CableClub_TextBoxBorder = 0x0A4EEF, // LinkTextboxAtHL
.placeString = 0x001078,
.Serial_ExchangeBytes = 0x075F,
._RemovePokemon = 0x036039, // RemoveMonFromPartyOrBox
.SaveSAVtoSRAM1 = 0,
.SaveSAVtoSRAM2 = 0,
.OpenSRAM = 0x002FCB,
.SaveBox = 0x054E0C,
.Bankswitch = 0,
.SoftReset = 0x0150, // Reset
.CloseSRAM = 0,
.garbageDataLocation = 0x0770,
.clearScreen = 0x000FDB,
.CableClub_TextBoxBorder = 0x0A4EEF, // LinkTextboxAtHL
.placeString = 0x001078,
.Serial_ExchangeBytes = 0x075F,
._RemovePokemon = 0x036039, // RemoveMonFromPartyOrBox
.SaveSAVtoSRAM1 = 0,
.SaveSAVtoSRAM2 = 0,
.LoadCurrentBoxData = 0,
.OpenSRAM = 0x002FCB,
.SaveBox = 0x054E0C,
.Bankswitch = 0,
.SoftReset = 0x0150, // Reset
.CloseSRAM = 0,
.garbageDataLocation = 0x0770,
.wRemoveMonFromBox = 0x01D10B, // wPokemonWithdrawDepositParameter
.wBoxCount = 0x01AD10, // sBoxCount
.wWhichPokemon = 0x01D109, // wCurPartyMon
.wBoxDataStart = 0x01AD10, // sBox
.wBoxDataEnd = 0x01B15E, // sBoxEnd
.wSerialEnemyDataBlock = 0xD26B, // wOTPartyData
.wEnemyMonSpecies = 0x01D206,
.wRemoveMonFromBox = 0x01D10B, // wPokemonWithdrawDepositParameter
.wBoxCount = 0x01AD10, // sBoxCount
.wWhichPokemon = 0x01D109, // wCurPartyMon
.wBoxDataStart = 0x01AD10, // sBox
.wBoxDataEnd = 0x01B15E, // sBoxEnd
.wSerialEnemyDataBlock = 0xD26B, // wOTPartyData
.wEnemyMonSpecies = 0x01D206,
.wSerialEnemyMonsPatchList = 0xC6D0, // wOTPatchLists
.wSerialOtherGameboyRandomNumberListBlock = 0xD206, // wOTLinkBattleRNData
.hSerialConnectionStatus = 0xFFCB,
.wSerialEnemyMonsPatchList = 0xC6D0, // wOTPatchLists
.wSerialOtherGameboyRandomNumberListBlock = 0xD206, // wOTLinkBattleRNData
.hSerialConnectionStatus = 0xFFCB,
.transferStringLocation = 0xC544,
.textBorderUppLeft = 0xC52F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0
}
};
.transferStringLocation = 0xC544,
.textBorderUppLeft = 0xC52F,
.textBorderWidth = 12,
.textBorderHeight = 1,
.padding_2 = 0}};
const u16 gb_rom_values_eng_size = static_cast<u16>(sizeof(gb_rom_values_eng) / sizeof(struct GB_ROM));

View File

@ -1,4 +1,4 @@
#include "pokemon_data.h"
//#include "pokemon_data.h"
#include "common.h"
#include "gba_rom_values/gba_rom_values.h"
#include "gb_rom_values/gb_rom_values.h"

View File

@ -5,9 +5,15 @@
#include <cstring>
#define DATA_LOC (SHOW_DATA_PACKETS ? curr_rom.transferStringLocation : curr_rom.wEnemyMonSpecies)
#define DEBUG_PAYLOADS (false && DEBUG_MODE)
void init_payload(byte *payload_buffer, const GB_ROM& curr_rom, int type, bool debug)
void init_payload(byte *payload_buffer, const GB_ROM &curr_rom, int type, bool debug)
{
if (DEBUG_PAYLOADS)
{
debug = true;
}
(void)type;
/* 10 RNG bytes
8 Preamble bytes
@ -420,94 +426,95 @@ void init_payload(byte *payload_buffer, const GB_ROM& curr_rom, int type, bool d
skip_enemy_write.set_start(&z80_payload);
// Reload the save data to remove any data that was overwritten during exploit entry
z80_payload.LD(A, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8);
z80_payload.LD(B, (curr_rom.LoadCurrentBoxData >> 16) | T_U8);
z80_payload.LD(HL, curr_rom.LoadCurrentBoxData | T_U16);
z80_payload.CALL(curr_rom.Bankswitch | T_U16);
z80_payload.CALL(0x79FC | T_U16); // Call LoadSAV1 TODO FIX THIS BAD BAD NO BAD
/* Build the packet */
// HL is the current data pointer
// DE is the destination pointer
// A is the checksum
// B is the 0xFE flag byte
// C is the counter
send_packet_loop.set_start(&z80_payload);
z80_payload.LD(HL, (DATA_LOC + PACKET_SIZE + 3) | T_U16); // Load the next data location into HL
z80_payload.LD(A, HLI_PTR);
z80_payload.LD(H, HL_PTR);
z80_payload.LD(L, A);
z80_payload.LD(DE, (DATA_LOC + 2) | T_U16); // Enemy Pokemon data, should be unused
z80_payload.XOR(A, A); // Clear the register
z80_payload.LD(B, A); // Clear B as well
z80_payload.LD(C, A); // Clear C as well
z80_payload.PUSH(AF);
packet_loop.set_start(&z80_payload);
z80_payload.LD(B, 0x00 | T_U8); // Reset the flag byte
z80_payload.POP(AF);
z80_payload.ADD(A, HL_PTR); // Add the current data to the checksum
z80_payload.PUSH(AF);
z80_payload.LD(A, 0xFE);
z80_payload.CP(A, HL_PTR); // Compare the current data to 0xFE
z80_payload.LD(A, HLI_PTR); // Load HL's data into A for modification (if need be)
// If HL's data is 0xFE
z80_payload.JR(NZ_F, fe_bypass.place_relative_jump(&z80_payload) | T_I8);
z80_payload.DEC(A);
z80_payload.INC(B); // Set flag
fe_bypass.set_start(&z80_payload);
z80_payload.LD(DE_PTR, A); // Place the data in
z80_payload.INC(DE);
z80_payload.PUSH(AF);
z80_payload.LD(A, B);
z80_payload.LD(DE_PTR, A); // Place the flag in as well
z80_payload.POP(AF);
z80_payload.INC(DE);
z80_payload.INC(C);
z80_payload.LD(A, DATA_PER_PACKET - 1);
z80_payload.CP(A, C);
z80_payload.JR(NC_F, packet_loop.place_relative_jump(&z80_payload) | T_I8); // If all the data has been set, send the rest of the data
z80_payload.POP(AF);
z80_payload.RES(7 | T_BIT, A); // Reset bit 7 of the checksum, guaranteeing that it will never be 0xFE
z80_payload.LD(DE_PTR, A);
z80_payload.INC(DE);
z80_payload.LD(A, H);
z80_payload.LD(DE_PTR, A);
z80_payload.INC(DE);
z80_payload.LD(A, L);
z80_payload.LD(DE_PTR, A);
/* Transfer box data packet: */
z80_payload.LD(A, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug
z80_payload.LDH((curr_rom.hSerialConnectionStatus & 0xFF) | T_U8, A); // Since hSerialConnectionStatus is at 0xFFxx we can use this method instead
z80_payload.LD(HL, DATA_LOC | T_U16);
z80_payload.LD(HL_PTR, 0xFD | T_U8); // set the start of the data to 0xFD so Serial_ExchangeBytes is happy
z80_payload.INC(HL);
z80_payload.LD(HL_PTR, 0x00 | T_U8); // add a 0x00 after the 0xFD to prevent further 0xFDs from being interpreted as part of the preamble
z80_payload.DEC(HL); // Reset HL back so it points to 0xFD
z80_payload.LD(DE, (DATA_LOC + PACKET_SIZE) | T_U16); // location to put stored data
z80_payload.LD(BC, PACKET_SIZE | T_U16);
if (debug) // Don't call serialExchangeBytes if debug is enabled
if (!debug)
{
z80_payload.index += 3;
}
else
{
z80_payload.CALL(curr_rom.Serial_ExchangeBytes | T_U16);
}
/* Build the packet */
// HL is the current data pointer
// DE is the destination pointer
// A is the checksum
// B is the 0xFE flag byte
// C is the counter
send_packet_loop.set_start(&z80_payload);
z80_payload.LD(A, (DATA_LOC + PACKET_SIZE + 3 + 1) | T_U16);
z80_payload.CP(A, 0xFF);
if (debug && false) // Don't compare the "recieved" data if in debug
{
z80_payload.index += 2;
}
else
{
z80_payload.JR(NZ_F, send_packet_loop.place_relative_jump(&z80_payload) | T_I8);
}
z80_payload.LD(HL, (DATA_LOC + PACKET_SIZE + 3) | T_U16); // Load the next data location into HL
z80_payload.LD(A, HLI_PTR);
z80_payload.LD(H, HL_PTR);
z80_payload.LD(L, A);
z80_payload.LD(DE, (DATA_LOC + 2) | T_U16); // Enemy Pokemon data, should be unused
z80_payload.XOR(A, A); // Clear the register
z80_payload.LD(B, A); // Clear B as well
z80_payload.LD(C, A); // Clear C as well
z80_payload.PUSH(AF);
packet_loop.set_start(&z80_payload);
z80_payload.LD(B, 0x00 | T_U8); // Reset the flag byte
z80_payload.POP(AF);
z80_payload.ADD(A, HL_PTR); // Add the current data to the checksum
z80_payload.PUSH(AF);
z80_payload.LD(A, 0xFE);
z80_payload.CP(A, HL_PTR); // Compare the current data to 0xFE
z80_payload.LD(A, HLI_PTR); // Load HL's data into A for modification (if need be)
// If HL's data is 0xFE
z80_payload.JR(NZ_F, fe_bypass.place_relative_jump(&z80_payload) | T_I8);
z80_payload.DEC(A);
z80_payload.INC(B); // Set flag
fe_bypass.set_start(&z80_payload);
z80_payload.LD(DE_PTR, A); // Place the data in
z80_payload.INC(DE);
z80_payload.PUSH(AF);
z80_payload.LD(A, B);
z80_payload.LD(DE_PTR, A); // Place the flag in as well
z80_payload.POP(AF);
z80_payload.INC(DE);
z80_payload.INC(C);
z80_payload.LD(A, DATA_PER_PACKET - 1);
z80_payload.CP(A, C);
z80_payload.JR(NC_F, packet_loop.place_relative_jump(&z80_payload) | T_I8); // If all the data has been set, send the rest of the data
z80_payload.POP(AF);
z80_payload.RES(7 | T_BIT, A); // Reset bit 7 of the checksum, guaranteeing that it will never be 0xFE
z80_payload.LD(DE_PTR, A);
z80_payload.INC(DE);
z80_payload.LD(A, H);
z80_payload.LD(DE_PTR, A);
z80_payload.INC(DE);
z80_payload.LD(A, L);
z80_payload.LD(DE_PTR, A);
/* Transfer box data packet: */
z80_payload.LD(A, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug
z80_payload.LDH((curr_rom.hSerialConnectionStatus & 0xFF) | T_U8, A); // Since hSerialConnectionStatus is at 0xFFxx we can use this method instead
z80_payload.LD(HL, DATA_LOC | T_U16);
z80_payload.LD(HL_PTR, 0xFD | T_U8); // set the start of the data to 0xFD so Serial_ExchangeBytes is happy
z80_payload.INC(HL);
z80_payload.LD(HL_PTR, 0x00 | T_U8); // add a 0x00 after the 0xFD to prevent further 0xFDs from being interpreted as part of the preamble
z80_payload.DEC(HL); // Reset HL back so it points to 0xFD
z80_payload.LD(DE, (DATA_LOC + PACKET_SIZE) | T_U16); // location to put stored data
z80_payload.LD(BC, PACKET_SIZE | T_U16);
if (debug) // Don't call serialExchangeBytes if debug is enabled
{
z80_payload.index += 3;
}
else
{
z80_payload.CALL(curr_rom.Serial_ExchangeBytes | T_U16);
}
z80_payload.LD(A, (DATA_LOC + PACKET_SIZE + 3 + 1) | T_U16);
z80_payload.CP(A, 0xFF);
if (debug && false) // Don't compare the "recieved" data if in debug
{
z80_payload.index += 2;
}
else
{
z80_payload.JR(NZ_F, send_packet_loop.place_relative_jump(&z80_payload) | T_I8);
}
}
/* Recieve the Pokemon to remove */
z80_payload.LD(HL, curr_rom.hSerialConnectionStatus | T_U16); // This can also be shortened
z80_payload.LD(HL_PTR, (debug ? 0x02 : 0x01) | T_U8); // Make sure GB is the slave, master if debug
@ -549,16 +556,22 @@ void init_payload(byte *payload_buffer, const GB_ROM& curr_rom, int type, bool d
}
else
{
z80_payload.CALL(curr_rom._RemovePokemon | T_U16);
z80_payload.LD(B, (curr_rom._RemovePokemon >> 16) | T_U8); // Load ROM Bank
z80_payload.LD(HL, curr_rom._RemovePokemon | T_U16);
z80_payload.CALL(curr_rom.Bankswitch | T_U16);
}
z80_payload.JR((remove_array_loop.place_relative_jump(&z80_payload) & 0xFF) | T_I8);
// We need to move this in order to not corrupt the 4E's
z80_payload.JR((save_box.place_relative_jump(&z80_payload) & 0xFF) | T_I8);
z80_payload.index = 0x17A;
/* Save the current box */
save_box.set_start(&z80_payload);
z80_payload.LD(A, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8); // Load ROM Bank
z80_payload.LD(B, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8); // Load ROM Bank
z80_payload.LD(HL, curr_rom.SaveSAVtoSRAM1 | T_U16);
z80_payload.CALL(curr_rom.Bankswitch | T_U16);
z80_payload.LD(A, (curr_rom.SaveSAVtoSRAM1 >> 16) | T_U8); // Load ROM Bank
z80_payload.LD(B, (curr_rom.SaveSAVtoSRAM2 >> 16) | T_U8); // Load ROM Bank
z80_payload.LD(HL, curr_rom.SaveSAVtoSRAM2 | T_U16);
z80_payload.CALL(curr_rom.Bankswitch | T_U16);
z80_payload.JP(curr_rom.SoftReset | T_U16);
@ -949,17 +962,19 @@ void init_payload(byte *payload_buffer, const GB_ROM& curr_rom, int type, bool d
#if PAYLOAD_EXPORT_TEST
#include <cstdio>
#include "gb_rom_values/gb_rom_values.h"
int main() // Rename to "main" to send the payload to test_payload.txt
{
byte buffer[672] = {0};
freopen("test_payload.txt", "w", stdout);
printf("\n");
init_payload(ENG_GOLD, TRANSFER, true);
byte *payload = get_payload();
init_payload(buffer, gb_rom_values_eng[RED_ID], TRANSFER, true);
if (true)
{
for (int i = 0; i < 0x2A0; i++)
{
printf("0x%02X, ", (unsigned int)payload[i]);
printf("0x%02X, ", (unsigned int)buffer[i]);
if (i % 0x10 == 0xF)
{
printf("\n# 0x%X\n", i + 1);
@ -971,7 +986,7 @@ int main() // Rename to "main" to send the payload to test_payload.txt
{
for (int i = 0; i < 0x150; i++)
{
printf("%02X ", (unsigned int)payload[i + ((0x10 * 28) + 9)]);
printf("%02X ", (unsigned int)buffer[i + ((0x10 * 28) + 9)]);
if (i % 0x10 == 0xF)
{
printf("\n");