diff --git a/data/sprites_cmp.bin b/data/sprites_cmp.bin
index 5ef0ef5..518ee55 100644
Binary files a/data/sprites_cmp.bin and b/data/sprites_cmp.bin differ
diff --git a/data/sprites_info.bin b/data/sprites_info.bin
new file mode 100644
index 0000000..28b09ea
--- /dev/null
+++ b/data/sprites_info.bin
@@ -0,0 +1 @@
+UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
\ No newline at end of file
diff --git a/data_raw/sprites_uncmp.bin b/data_raw/sprites_uncmp.bin
new file mode 100644
index 0000000..3ee7e2a
Binary files /dev/null and b/data_raw/sprites_uncmp.bin differ
diff --git a/dump_reader.py b/dump_reader.py
deleted file mode 100644
index 65b16b6..0000000
--- a/dump_reader.py
+++ /dev/null
@@ -1,211 +0,0 @@
-import usb.core
-import usb.util
-import signal
-import sys
-import traceback
-import time
-import os
-
-dev = None
-sleep_timer = 0.01
-sram_transfer_val = 2
-rom_transfer_val = 1
-rom_bank_size = 0x40
-rom_banks = [2,4,8,16,32,64,128,256,512,0,0,0,0,0,0,0,0,0,72,80,96]
-sram_banks_sizes = [0,8,0x20,0x20,0x20,0x20,2]
-sram_banks = [0,1,1,4,16,8,1]
-section_size = 0x100
-normal_nybble = 0x10
-check_nybble = 0x40
-
-def rom_transfer(data, transfer_size):
-    print("Starting ROM dump...")
-    size = rom_bank_size
-    banks = rom_banks[transfer_size]
-    
-    return transfer_bank(data, size, banks)
-    
-def sram_transfer(data, transfer_size):
-    print("Starting SRAM dump...")
-    size = sram_banks_sizes[transfer_size]
-    banks = sram_banks[transfer_size]
-        
-    return transfer_bank(data, size, banks)
-
-def transfer_bank(data, size, banks):
-    if(banks == 0):
-        print("Nothing to dump!")
-        return None
-        
-    res = []
-    for i in range(banks):
-        print("Bank " + str(i+ 1) + " out of " + str(banks) + "!")
-        for j in range(size):
-            print("Section " + str(j+ 1) + " out of " + str(size) + "!")
-            res += read_section(data)
-    return res
-
-def read_section(data):
-    buf = []
-    checked = False
-    half = False
-    
-    while(not checked):
-        for i in range(2):
-            accepted = False
-            while not accepted:
-                sleep_func()
-                sendByte(data[i])
-                recv = receiveByte()
-                high_recv = recv & 0xF0
-                if(high_recv == check_nybble or high_recv == normal_nybble):
-                    #print("send: 0x%02x" % data[i])
-                    #print("recv: 0x%02x" % recv)
-                    if(high_recv == check_nybble):
-                        if(half):
-                            checked = True
-                        half = True
-                    accepted = True
-                    data[i] = recv & 0xF;
-                #else:
-                    #print("BAD RECV: 0x%02x" % recv)
-        val = (data[1] | (data[0] << 4))
-        if(checked):
-            if(val == 0):
-                checked = False
-                buf = []
-        else:
-            buf += [val]
-            #print("Data: 0x%02x" % val)
-            if(half):
-                # Handle a "nybble" desync
-                sleep_func()
-                sendByte(data[0])
-                recv = receiveByte()
-        half = False
-        
-    return buf[0:len(buf)-1] # There is an extra transfer in order to ensure the last byte is correct. Discard it
-
-def transfer_func():
-    print("Waiting for the transfer to start...")
-    
-    data = [0,0]
-    buf = read_section(data) # Read the starting information
-    
-    if(len(buf) > 2):
-        print("The transfer was previously interrupted. Please reset the GameBoy!")
-        return
-        
-    transfer_type = buf[0]
-    transfer_size = buf[1]
-    if(transfer_type == rom_transfer_val):
-        res = rom_transfer(data, transfer_size)
-    elif(transfer_type == sram_transfer_val):
-        res = sram_transfer(data, transfer_size)
-    
-    if res is not None:
-        if(len(sys.argv) > 1):
-            target = sys.argv[1]
-        else:
-            target = input("Please enter where to save the dump: ")
-        
-        newFile = open(target, "wb")
-        newFile.write(bytearray(res))
-        newFile.close()
-    return
-    
-# Function needed in order to make sure there is enough time for the slave to prepare the next byte.
-def sleep_func():
-    time.sleep(sleep_timer)
-
-# Code dependant on this connection method
-def sendByte(byte_to_send):
-    epOut.write(byte_to_send.to_bytes(1, byteorder='big'))
-    return
-
-def receiveByte():
-    return int.from_bytes(epIn.read(epIn.wMaxPacketSize, 100), byteorder='big')
-
-# Things for the USB connection part
-def exit_gracefully():
-    if dev is not None:
-        usb.util.dispose_resources(dev)
-        if(os.name != "nt"):
-            if reattach:
-                dev.attach_kernel_driver(0)
-    print('Done.')
-
-def signal_handler(sig, frame):
-    print('You pressed Ctrl+C!')
-    exit_gracefully()
-
-signal.signal(signal.SIGINT, signal_handler)
-
-# The execution path
-try:
-    devices = list(usb.core.find(find_all=True,idVendor=0xcafe, idProduct=0x4011))
-    for d in devices:
-        #print('Device: %s' % d.product)
-        dev = d
-
-    if dev is None:
-        raise ValueError('Device not found')
-
-    reattach = False
-    if(os.name != "nt"):
-        if dev.is_kernel_driver_active(0):
-            try:
-                reattach = True
-                dev.detach_kernel_driver(0)
-                print("kernel driver detached")
-            except usb.core.USBError as e:
-                sys.exit("Could not detach kernel driver: %s" % str(e))
-        else:
-            print("no kernel driver attached")
-
-    dev.reset()
-
-    dev.set_configuration()
-
-    cfg = dev.get_active_configuration()
-
-    #print('Configuration: %s' % cfg)
-
-    intf = cfg[(2,0)]   # Or find interface with class 0xff
-
-    #print('Interface: %s' % intf)
-
-    epIn = usb.util.find_descriptor(
-        intf,
-        custom_match = \
-        lambda e: \
-            usb.util.endpoint_direction(e.bEndpointAddress) == \
-            usb.util.ENDPOINT_IN)
-
-    assert epIn is not None
-
-    #print('EP In: %s' % epIn)
-
-    epOut = usb.util.find_descriptor(
-        intf,
-        # match the first OUT endpoint
-        custom_match = \
-        lambda e: \
-            usb.util.endpoint_direction(e.bEndpointAddress) == \
-            usb.util.ENDPOINT_OUT)
-
-    assert epOut is not None
-
-    #print('EP Out: %s' % epOut)
-
-    # Control transfer to enable webserial on device
-    #print("control transfer out...")
-    dev.ctrl_transfer(bmRequestType = 1, bRequest = 0x22, wIndex = 2, wValue = 0x01)
-
-    transfer_func()
-    
-    exit_gracefully()
-except:
-    #traceback.print_exc()
-    print("Unexpected exception: ", sys.exc_info()[0])
-    exit_gracefully()
\ No newline at end of file
diff --git a/source/graphics_handler.c b/source/graphics_handler.c
index f064150..f64f376 100644
--- a/source/graphics_handler.c
+++ b/source/graphics_handler.c
@@ -3,23 +3,55 @@
 
 #include "gender_symbols_bin.h"
 
+#define MAX_SIZE_POKEMON_SPRITE 0x400
 #define GRAPHICS_BUFFER_SHIFT 10
 #define GRAPHICS_BUFFER_SIZE (1 << GRAPHICS_BUFFER_SHIFT)
 
+#define CPUFASTSET_FILL (0x1000000)
+
 void init_gender_symbols(){
     u8 colors[] = {0,1};
     convert_1bpp(gender_symbols_bin, (u32*)(VRAM+(0x88<<5)), gender_symbols_bin_size, colors, 1);
 }
 
+void load_pokemon_sprite_gfx(u32 src, u32 dst, u8 info){
+    u8 is_3bpp = info&2;
+    u8 zero_fill = info&1;
+    u32 zero = 0;
+    
+    u32 buffer[2][MAX_SIZE_POKEMON_SPRITE>>2];
+    LZ77UnCompWram(src, buffer[0]);
+    
+    if(is_3bpp) {
+        u8 colors[8];
+        for(int i = 0; i < 8; i++)
+            colors[i] = (buffer[0][0]>>(4*i))&0xF;
+        if(zero_fill) {
+            CpuFastSet(&zero, buffer[1], (MAX_SIZE_POKEMON_SPRITE>>2)|CPUFASTSET_FILL);
+            convert_3bpp(buffer[0]+1, (u32*)(((u32)buffer[1])+0x80), (((MAX_SIZE_POKEMON_SPRITE>>2)*3)>>1)-0x60, colors, 0);
+            convert_3bpp(buffer[0]+1+(((((MAX_SIZE_POKEMON_SPRITE>>2)*3)>>1)-0x60)>>2), (u32*)(((u32)buffer[1])+0x280), (((MAX_SIZE_POKEMON_SPRITE>>2)*3)>>1)-0x60, colors, 0);
+            CpuFastSet(buffer[1], dst, (MAX_SIZE_POKEMON_SPRITE>>2));
+        }
+        else
+            convert_3bpp(buffer[0]+1, dst, (MAX_SIZE_POKEMON_SPRITE>>2)*3, colors, 0);
+    }
+    else {
+        if(zero_fill) {
+            CpuFastSet(&zero, buffer[1], (MAX_SIZE_POKEMON_SPRITE>>2)|CPUFASTSET_FILL);
+            CpuFastSet(buffer[0], ((u32)buffer[1])+0x80, ((MAX_SIZE_POKEMON_SPRITE>>1)-0x80)>>2);
+            CpuFastSet(buffer[0]+(((MAX_SIZE_POKEMON_SPRITE>>1)-0x80)>>2), ((u32)buffer[1])+0x280, ((MAX_SIZE_POKEMON_SPRITE>>1)-0x80)>>2);
+            CpuFastSet(buffer[1], dst, (MAX_SIZE_POKEMON_SPRITE>>2));
+        }
+        else
+            CpuFastSet(buffer[0], dst, MAX_SIZE_POKEMON_SPRITE>>2);
+    }
+}
+
 void convert_xbpp(u8* src, u32* dst, u16 src_size, u8* colors, u8 is_forward, u8 num_bpp) {
-    const u16 buffer_size = GRAPHICS_BUFFER_SIZE>>2;
-    u32 buffer[buffer_size];
     if(num_bpp == 0 || num_bpp > 4)
         return;
-    const u16 limit = buffer_size-1;
-    u16 base = 0;
     u16 num_rows = Div(src_size, num_bpp);
-    if(DivMod(src_size, 8*num_bpp))
+    if(DivMod(src_size, num_bpp))
         num_rows += 1;
     for(int i = 0; i < num_rows; i++) {
         u32 src_data = 0;
@@ -31,15 +63,8 @@ void convert_xbpp(u8* src, u32* dst, u16 src_size, u8* colors, u8 is_forward, u8
                 row |= (colors[(src_data>>(num_bpp*j))&((1<<num_bpp)-1)]&0xF) << (4*j);
             else
                 row |= (colors[(src_data>>(num_bpp*j))&((1<<num_bpp)-1)]&0xF) << (4*(7-j));
-        buffer[i-base] = row;
-        if((i-base) == limit) {
-            CpuFastSet(buffer, dst + (base<<2), buffer_size);
-            base += buffer_size;
-        }
+        dst[i] = row;
     }
-    u16 remaining = num_rows-base;
-    if(remaining)
-        CpuFastSet(buffer, dst + (base<<2), remaining);
 }
 
 void convert_1bpp(u8* src, u32* dst, u16 src_size, u8* colors, u8 is_forward) {
diff --git a/source/graphics_handler.h b/source/graphics_handler.h
index 7fea956..e4c84c4 100644
--- a/source/graphics_handler.h
+++ b/source/graphics_handler.h
@@ -3,6 +3,8 @@
 
 void init_gender_symbols();
 
+void load_pokemon_sprite_gfx(u32, u32, u8);
+
 void convert_xbpp(u8*, u32*, u16, u8*, u8, u8);
 void convert_1bpp(u8*, u32*, u16, u8*, u8);
 void convert_2bpp(u8*, u32*, u16, u8*, u8);
diff --git a/source/main.c b/source/main.c
index 060094a..2bbe359 100644
--- a/source/main.c
+++ b/source/main.c
@@ -118,6 +118,8 @@ void start_gen2_slave(void)
 #define E_MAIN_GAME_CODE 0x2
 #define E_SUB_GAME_CODE 0x0
 
+#define VALID_MAPS 36
+
 #include "party_handler.h"
 #include "text_handler.h"
 #include "sprite_handler.h"
@@ -131,6 +133,8 @@ const u16 pokedex_extra_pos_1 [] = {0x938, 0x5F8, 0x988};
 const u16 pokedex_extra_pos_2 [] = {0xC0C, 0xB98, 0xCA4};
 const u16 mail_pos [] = {0xC4C, 0xDD0, 0xCE0};
 const u16 ribbon_pos [] = {0x290, 0x21C, 0x328};
+const u16 special_area [] = {0, 9, 9};
+const u16 rs_valid_maps[VALID_MAPS] = {0x0202, 0x0203, 0x0301, 0x0302, 0x0405, 0x0406, 0x0503, 0x0504, 0x0603, 0x0604, 0x0700, 0x0701, 0x0804, 0x0805, 0x090a, 0x090b, 0x0a05, 0x0a06, 0x0b05, 0x0b06, 0x0c02, 0x0c03, 0x0d06, 0x0d07, 0x0e03, 0x0e04, 0x0f02, 0x0f03, 0x100c, 0x100d, 0x100a, 0x1918, 0x1919, 0x191a, 0x191b, 0x1a05};
 
 u8 game_is_jp;
 u8 game_main_version;
@@ -785,6 +789,7 @@ int main(void)
                 returned_val = handle_input_main_menu(&cursor_y_pos, keys, &update, &target, &region, &master);
                 print_main_menu(update, target, region, master);
                 //print_pokemon_page1(update, 1, &parties_3[0].mons[0]);
+                //print_trade_menu(update, 2, 1);
                 update_cursor_y(BASE_Y_CURSOR_MAIN_MENU + (BASE_Y_CURSOR_INCREMENT_MAIN_MENU * cursor_y_pos));
                 if(returned_val == START_MULTIBOOT) {
                     curr_state = MULTIBOOT;
diff --git a/source/party_handler.c b/source/party_handler.c
index 394d71b..b704f3e 100644
--- a/source/party_handler.c
+++ b/source/party_handler.c
@@ -2,6 +2,26 @@
 #include "party_handler.h"
 #include "text_handler.h"
 #include "sprite_handler.h"
+#include "graphics_handler.h"
+
+#include "pokemon_moves_pp_gen1_bin.h"
+#include "pokemon_moves_pp_bin.h"
+#include "pokemon_gender_bin.h"
+#include "pokemon_names_bin.h"
+#include "item_names_bin.h"
+#include "gen2_names_jap_bin.h"
+#include "sprites_cmp_bin.h"
+#include "sprites_info_bin.h"
+#include "palettes_references_bin.h"
+#include "item_gen3_to_12_bin.h"
+#include "gen3_to_1_conv_table_bin.h"
+#include "gen1_to_3_conv_table_bin.h"
+#include "pokemon_exp_groups_bin.h"
+#include "exp_table_bin.h"
+#include "pokemon_stats_bin.h"
+#include "pokemon_stats_gen1_bin.h"
+#include "pokemon_types_gen1_bin.h"
+#include "pokemon_natures_bin.h"
 
 u8 decrypt_data(struct gen3_mon*, u32*);
 u8 is_egg_gen3(struct gen3_mon*, struct gen3_mon_misc*);
@@ -32,24 +52,7 @@ u8 gender_thresholds_gen12[] = {8, 0, 2, 4, 12, 14, 16, 17};
 #define UNOWN_V_LETTER 21
 #define INITIAL_MAIL_GEN3 121
 #define LAST_MAIL_GEN3 132
-const u8 pokemon_moves_pp_gen1_bin[];
-const u8 pokemon_moves_pp_bin[];
-const u8 pokemon_gender_bin[];
-const u8 pokemon_names_bin[];
-const u8 item_names_bin[];
-const u8 gen2_names_international_bin[];
-const u8 gen2_names_jap_bin[];
-const u8 sprites_cmp_bin[];
-const u8 palettes_references_bin[];
-const u8 item_gen3_to_12_bin[];
-const u8 gen3_to_1_conv_table_bin[];
-const u8 gen1_to_3_conv_table_bin[];
-const u8 pokemon_exp_groups_bin[];
-const u8 exp_table_bin[];
-const u8 pokemon_stats_bin[];
-const u8 pokemon_stats_gen1_bin[];
-const u8 pokemon_types_gen1_bin[];
-const u8 pokemon_natures_bin[];
+
 const struct exp_level* exp_table = (const struct exp_level*)exp_table_bin;
 const struct stats_gen_23* stats_table = (const struct stats_gen_23*)pokemon_stats_bin;
 const struct stats_gen_1* stats_table_gen1 = (const struct stats_gen_1*)pokemon_stats_gen1_bin;
@@ -184,6 +187,11 @@ const u8* get_pokemon_sprite_pointer(int index, u32 pid, u8 is_egg){
     return get_table_pointer(sprites_cmp_bin, get_mon_index(index, pid, is_egg));
 }
 
+u8 get_pokemon_sprite_info(int index, u32 pid, u8 is_egg){
+    u16 mon_index = get_mon_index(index, pid, is_egg);
+    return (sprites_info_bin[mon_index>>2]>>(2*(mon_index&3)))&3;
+}
+
 u8 get_palette_references(int index, u32 pid, u8 is_egg){
     return palettes_references_bin[get_mon_index(index, pid, is_egg)];
 }
@@ -192,7 +200,7 @@ void load_pokemon_sprite(int index, u32 pid, u8 is_egg, u8 has_item, u16 y, u16
     u8 sprite_counter = get_sprite_counter();
     u32 address = get_pokemon_sprite_pointer(index, pid, is_egg);
     u8 palette = get_palette_references(index, pid, is_egg);
-    LZ77UnCompVram(address, get_vram_pos());
+    load_pokemon_sprite_gfx(address, get_vram_pos(), get_pokemon_sprite_info(index, pid, is_egg));
     set_attributes(y, x |(1<<15), (32*sprite_counter)|(palette<<12));
     inc_sprite_counter();
     if(!is_egg && has_item)
diff --git a/source/sprite_handler.c b/source/sprite_handler.c
index d01b4be..19323d2 100644
--- a/source/sprite_handler.c
+++ b/source/sprite_handler.c
@@ -4,6 +4,7 @@
 #define OAM 0x7000000
 #define BASE_CURSOR_X 2
 #define BASE_CURSOR_Y 8
+#define CPUFASTSET_FILL (0x1000000)
 
 const u8 sprite_cursor_bin[];
 const u32 sprite_cursor_bin_size;
