rewrite client function compiler

This commit is contained in:
Martin Michelsen
2026-05-11 07:29:25 -07:00
parent 2f2a0bcf2b
commit e78e2ba887
174 changed files with 3931 additions and 5807 deletions
@@ -1,18 +1,14 @@
# This patch changes the amount of items and Meseta that can be stored in the
# bank. If the bank item limit is increased beyond 200, this patch requires
# server support for extended bank data stored outside of the player's data.
# newserv has support for this, but you must set the BBBankItemLimit and
# BBBankMesetaLimit values in config.json to match the values used here.
# This patch changes the amount of items and Meseta that can be stored in the bank. If the bank item limit is increased
# beyond 200, this patch requires server support for extended bank data stored outside of the player's data. newserv
# has support for this, but you must set the BBBankItemLimit and BBBankMesetaLimit values in config.json to match the
# values used here.
# As written, this changes the meseta limit to 2000000000 and the item limit to
# 1000. The meseta limit can be any value up to 2147483647, and the item limit
# can be any value up to 1321. To use different values than the defaults, first
# compute the data size as ((slot count * 0x18) + 8), then replace each value
# below appropriately.
# As written, this changes the meseta limit to 2000000000 and the item limit to 1000. The meseta limit can be any value
# up to 2147483647, and the item limit can be any value up to 1321. To use different values than the defaults, first
# compute the data size as ((slot count * 0x18) + 8), then replace each value below appropriately.
.meta name="More bank slots"
.meta description=""
.meta hide_from_patches_menu
.versions 59NJ 59NL
@@ -21,7 +17,7 @@ reloc0:
.offsetof start
start:
.include WriteCodeBlocksBB
.include WriteCodeBlocks
.data <VERS 0x006C8C53 0x006C8C0F>
.data 4
@@ -1,14 +1,11 @@
# This patch disables the logic that causes all unlockable areas to be open by
# default for all players, instead restoring the logic that checks quest flags
# to open areas (as previous PSO versions used).
# This patch disables the logic that causes all unlockable areas to be open by default for all players, instead
# restoring the logic that checks quest flags to open areas (as previous PSO versions used).
# This patch is intended to be used in the BBRequiredPatches field in
# config.json if you want the classic behavior, hence the presence of the
# hide_from_patches_menu directive here.
# This patch is intended to be used in the BBRequiredPatches field in config.json if you want the classic behavior,
# hence the visibility setting here.
.meta name="Classic main warp behavior"
.meta description=""
.meta hide_from_patches_menu
.versions 59NJ 59NL
@@ -16,7 +13,7 @@ entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksBB
.include WriteCodeBlocks
.data <VERS 0x0064A642 0x0064A5DE> # Episode 1
.data 1
.binary 01
@@ -1,14 +1,11 @@
# It would be a bad idea to remove `.meta hide_from_patches_menu` to make this
# patch an option for players to be able to select; either all players on the
# server should have this patch, or none should have it.
# It would be a bad idea to change this function's visibility; either all players on the server should have this patch,
# or none should have it.
# This patch clears the list of unreleased items on the client, so the client
# never creates buggy items when the server generates an item that wasn't
# released on the official servers.
# This patch clears the list of unreleased items on the client, so the client never creates buggy items when the server
# generates an item that wasn't released on the official servers.
.meta name="Clear unreleased item list"
.meta description=""
.meta hide_from_patches_menu
.versions 59NJ 59NL
@@ -1,3 +1,4 @@
.meta visibility="all"
.meta name="Item exch. fix"
.meta description="Fixes some quest item\nexchange opcodes"
@@ -7,7 +8,7 @@ entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksBB
.include WriteCodeBlocks
@@ -1,624 +0,0 @@
# This patch changes the number of BB character save slots from 4 to any number
# up to 127.
# This patch is for documentation purposes only; it works when used as a server
# patch via newserv, but is decidedly inconvenient to use via this method. This
# is because it affects logic that runs before any patches can be sent by the
# server, so the player has to connect once to get the patch, then disconnect
# and connect again to use the additional slots.
# As written, this patch changes the slot count from 4 to 12. To use a
# different slot count, first compute the following values:
# slot count = your desired number of player slots (must be >= 4, <= 127)
# total file size = (slot count * 0x2EA4) + 0x14
# bgm_test_songs_unlocked offset = total file size - 0x10
# save_count offset = total file size - 8
# round2_seed offset = total file size - 4
# Then, for each of the above, search for the string to the left of the = sign
# and change the values used in all of the matching lines.
.meta name="More save slots"
.meta description=""
.meta hide_from_patches_menu
entry_ptr:
reloc0:
.offsetof start
# Include a few functions first
write_call_to_code:
.include WriteCallToCode-59NJ
memcpy:
.include CopyData
ret
start:
# Apply all necessary patches
call apply_enable_scroll_patch
call apply_fix_scroll_patch1
call apply_fix_scroll_patch2
call apply_fix_file_index
call apply_preview_window_fix
call apply_static_patches
# Rewrite the existing char file regions to have the appropriate size; this
# must be done after the patches are applied because we call the checksum
# function, which is patched by one of the above calls
call update_existing_char_file_list
jmp update_existing_char_file_list_memcard
apply_enable_scroll_patch:
# This patch enables scrolling behavior within the character list
push -5 # Jump size (negative = jmp instead of call)
push 0x00413B77 # Jump address
call get_code_size_for_enable_scroll
.deltaof enable_scroll_start, enable_scroll_end
get_code_size_for_enable_scroll:
pop eax
push dword [eax]
call enable_scroll_end
enable_scroll_start:
mov eax, dword ptr [edi + 0x28] # cursor = char_select_menu->cursor_obj (TAdSelectCurGC*)
or dword [eax + 0x01F8], 3 # cursor->flags |= 3 # Enable scrolling
mov eax, [0x00A38BD0] # scroll_bar = TAdScrollBarXb_objs[0]
mov ecx, [eax + 0xEC] # ecx = scroll_bar->client_id
imul ecx, ecx, 0x24
# Set up scroll bar graphics (in struct at scroll_bar + 0x1C)
mov dword [eax + ecx + 0x1C], 0x439D0000
mov dword [eax + ecx + 0x20], 0x43360000
mov dword [eax + ecx + 0x24], 0x439D0000
mov dword [eax + ecx + 0x28], 0x4392AB85
mov dword [eax + ecx + 0x2C], 0x40400000
mov dword [eax + ecx + 0x30], 0x425EA3D7
mov dword [eax + ecx + 0x34], 0x00000008
mov dword [eax + ecx + 0x38], 0x00000000
mov dword [eax + ecx + 0x3C], 0x00000000
or dword [eax + 0xF0], 1 # scroll_bar->flags |= 1
mov ecx, [eax + 0xEC]
shl ecx, 4
mov dword [eax + ecx + 0xAC], 0 # scroll_bar->selection_state[client_id].scroll_offset = 0
mov dword [eax + ecx + 0xB0], 0 # scroll_bar->selection_state[client_id].selected_index = 0
mov dword [eax + ecx + 0xB4], 4 # scroll_bar->selection_state[client_id].num_items_in_view = 4
mov dword [eax + ecx + 0xB8], 0x0B # scroll_bar->selection_state[client_id].last_item_index = (slot count - 1)
pop edi
ret
enable_scroll_end:
call write_call_to_code
ret
apply_fix_scroll_patch1:
# This patch fixes character selection cursor object so it will take the
# scroll offset into account
push 6 # Call size
push 0x00413C30 # Call address
call get_code_size_for_fix_scroll_patch1
.deltaof fix_scroll_patch1_start, fix_scroll_patch1_end
get_code_size_for_fix_scroll_patch1:
pop eax
push dword [eax]
call fix_scroll_patch1_end
fix_scroll_patch1_start:
mov edx, [edi + 0x28] # cursor = this->ad_select_cur_obj (TAdSelectCurGC*)
mov ebp, [edx + 0x44] # ebp = cursor->selected_index_within_view
mov eax, [0x00A38BD0] # scroll_bar = TAdScrollBarXb_objs[0]
add ebp, [eax + 0xAC] # ebp += scroll_bar->selection_state[0].scroll_offset
ret
fix_scroll_patch1_end:
call write_call_to_code
ret
apply_fix_scroll_patch2:
# This patch changes the TAdSinglePlyChrSelectGC::selected_index_within_view
# to be the selected character's absolute index (including scroll_offset),
# not the index only within the displayed four characters
push 6 # Call size
push 0x00413CD0 # Call address
call get_code_size_for_fix_scroll_patch2
.deltaof fix_scroll_patch2_start, fix_scroll_patch2_end
get_code_size_for_fix_scroll_patch2:
pop eax
push dword [eax]
call fix_scroll_patch2_end
fix_scroll_patch2_start:
mov eax, [0x00A38BD0] # scroll_bar = TAdScrollBarXb_objs[0]
mov eax, [eax + 0xAC] # eax = scroll_bar->selection_state[0].scroll_offset
mov edx, [edi + 0x28] # cursor = this->ad_select_cur_obj (TAdSelectCurGC*)
add eax, [edx + 0x44] # eax += cursor->selected_index_within_view
ret
fix_scroll_patch2_end:
call write_call_to_code
ret
apply_fix_file_index:
# This patch fixes the character file indexing so it will account for the
# scroll position
push 5 # Call size
push 0x00413CE8 # Call address
call get_code_size_for_selection_index_fix2
.deltaof selection_index_fix2_start, selection_index_fix2_end
get_code_size_for_selection_index_fix2:
pop eax
push dword [eax]
call selection_index_fix2_end
selection_index_fix2_start:
mov eax, [0x00A38BD0]
mov eax, [eax + 0xAC] # eax = TAdScrollBarXb_objs[0]->selection_state[0].scroll_offset
add ebp, eax # arg0 += eax
mov [esp + 4], ebp
mov eax, 0x006C1ABC
jmp eax # set_current_char_slot
selection_index_fix2_end:
call write_call_to_code
ret
apply_preview_window_fix:
# This patch fixes the preview display so it will show the correct section
# ID, level, etc.
push 5 # Call size
push 0x0040216C # Call address
call get_code_size_for_preview_window_fix
.deltaof preview_window_fix_start, preview_window_fix_end
get_code_size_for_preview_window_fix:
pop eax
push dword [eax]
call preview_window_fix_end
preview_window_fix_start:
mov eax, [0x00A38BD0] # scroll_bar = TAdScrollBarXb_objs[0]
mov eax, [eax + 0xAC] # eax = scroll_bar->selection_state[0].scroll_offset
add [esp + 4], eax
mov eax, 0x006C4514 # get_player_preview_info
jmp eax
preview_window_fix_end:
# This patch applies in two places, so push the second set of args now, then
# apply it twice
push 5 # Call size
push 0x00401842 # Call address
push dword [esp + 0x10] # Code size
push dword [esp + 0x10] # Code address
call write_call_to_code
call write_call_to_code
ret
apply_static_patches:
.include WriteCodeBlocksBB
# These patches change various places where the character data size and slot
# count are referenced
.data 0x00475294
.data 0x00000001
.binary 0C # slot count; TDataProtocol::handle_E5
.data 0x0047534B
.data 0x00000001
.binary 0C # slot count; import_player_preview
.data 0x004786D1
.data 0x00000001
.binary 0C # slot count; TDataProtocol::handle_E4
.data 0x00482559
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C17FB
.data 0x00000001
.binary 0C # slot count
.data 0x006C1D07
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C1D3A
.data 0x00000001
.binary 0C # slot count
.data 0x006C1D58
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C1E13
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C226A
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C22A9
.data 0x00000001
.binary 0C # slot count
.data 0x006C22CA
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C22DA
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C2517
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C267F
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C2689
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C272B
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C2741
.data 0x00000004
.data 0x00022FC0 # round2_seed offset
.data 0x006C27CF
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C28A8
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C314F
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C357B
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C35BA
.data 0x00000001
.binary 0C # slot count
.data 0x006C35E6
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C35F3
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C360E
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C3617
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C371C
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C3B5A
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C424D
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4833
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C486A
.data 0x00000001
.binary 0C # slot count
.data 0x006C49A6
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C49DD
.data 0x00000001
.binary 0C # slot count
.data 0x006C4AC5
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4AFE
.data 0x00000001
.binary 0C # slot count
.data 0x006C4CDE
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4D15
.data 0x00000001
.binary 0C # slot count
.data 0x006C4DFD
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4E36
.data 0x00000001
.binary 0C # slot count
.data 0x006C4F9C
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4FD7
.data 0x00000001
.binary 0C # slot count
.data 0x006C51C5
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5201
.data 0x00000001
.binary 0C # slot count
.data 0x006C5376
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C53B0
.data 0x00000001
.binary 0C # slot count
.data 0x006C5545
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5581
.data 0x00000001
.binary 0C # slot count
.data 0x006C56F6
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5730
.data 0x00000001
.binary 0C # slot count
.data 0x006C58B6
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C58F0
.data 0x00000001
.binary 0C # slot count
.data 0x006C5A85
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5AC1
.data 0x00000001
.binary 0C # slot count
.data 0x006C5BB2
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5BEC
.data 0x00000001
.binary 0C # slot count
.data 0x006C5D72
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5DAC
.data 0x00000001
.binary 0C # slot count
.data 0x006C5F32
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5F6C
.data 0x00000001
.binary 0C # slot count
.data 0x006C60F2
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C612C
.data 0x00000001
.binary 0C # slot count
.data 0x006C6346
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C6381
.data 0x00000001
.binary 0C # slot count
.data 0x006C6505
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C6541
.data 0x00000001
.binary 0C # slot count
.data 0x006C6632
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C666C
.data 0x00000001
.binary 0C # slot count
.data 0x006C67F2
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C682C
.data 0x00000001
.binary 0C # slot count
.data 0x006C69B2
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C69EC
.data 0x00000001
.binary 0C # slot count
.data 0x006C6B87
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C6BB8
.data 0x00000004
.data 0x0000005D # memcard block count
.data 0x006C6C3A
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C6C74
.data 0x00000001
.binary 0C # slot count
.data 0x006C6E82
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C6EBC
.data 0x00000001
.binary 0C # slot count
.data 0x006C70B9
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C70F3
.data 0x00000001
.binary 0C # slot count
.data 0x006C7A46
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C7D66
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C7D7C
.data 0x00000001
.binary 0C # slot count
.data 0x006C7DC0
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x0077CC72
.data 0x00000004
.data 0x00022FB4 # bgm_test_songs_unlocked offset
# Signature check on all save files (rewritten as loop)
.data 0x006C1C69
.deltaof sig_check_begin, sig_check_end
sig_check_begin:
mov edx, 0xC87ED5B1 # Expected signature value
add eax, 0x04E8 # &char_file_list->chars[0].part2.signature
mov ecx, 0x0C # slot count
again:
cmp dword [eax], 0 # signature == 0 (no char in slot)
je sig_ok
cmp dword [eax], edx # signature == expected value
jne sig_bad
sig_ok:
add eax, 0x2EA4 # Advance to next slot
dec ecx
jnz again
xor eax, eax # All signatures OK (eax = 0)
jmp sig_check_end
sig_bad:
xor eax, eax # Bad signature (eax = 1)
inc eax
jmp sig_check_end
.binary CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
sig_check_end: # 006C1CB2
# Send slot count in E3 command
.data 0x0046EC10 # TDataProtocol::send_E3_for_index
.deltaof send_slot_count_in_E3_begin, send_slot_count_in_E3_end
send_slot_count_in_E3_begin:
# ecx = this (TDataProtocol*)
# [esp + 4] = slot_index
push 0
push dword [esp + 8] # slot_index
push 0x0C # slot count
push 0x00E30010
mov eax, esp
push 0x10
push eax
mov eax, [ecx]
call [eax + 0x20] # this->send_command(&cmd, 0x10) // ret 8
add esp, 8
mov eax, 0x006C1ABC
call eax # set_current_char_slot(slot_index) // ret 0
add esp, 8
ret 4
send_slot_count_in_E3_end:
# Show slot number in each menu item
.data 0x00401D57
.deltaof show_slot_number_begin, show_slot_number_end
show_slot_number_begin:
# Original call (sprintf(line_buf, "LV%d", preview_info->visual.disp.level + 1))
lea edx, [esp + 0x02C4]
mov ebx, [ebx + 8]
inc ebx
push ebx
mov ecx, esi
push edx
mov eax, 0x00402604
call eax
# Find the end of the string
lea eax, [esp + 0x02C4]
show_slot_number_strend_again:
cmp word [eax], 0
je show_slot_number_strend_done
add eax, 2
jmp show_slot_number_strend_again
show_slot_number_strend_done:
# Format the slot number and append it to the string
mov ecx, [0x00A38BD0] # scroll_bar = TAdScrollBarXb_objs[0]
mov ecx, [ecx + 0xAC] # ecx = scroll_bar->selection_state[0].scroll_offset
lea ecx, [ecx + ebp + 1]
push ecx # Slot number (scroll_offset + z)
call get_show_slot_number_suffix_fmt
.binary 20002800230025006400290020000000 # L" (#%d) "
get_show_slot_number_suffix_fmt:
push eax # Destination buffer
mov eax, 0x00835578 # _swprintf
call eax
add esp, 0x0C
jmp show_slot_number_end
.zero 0x96
show_slot_number_end: # 00401E4D
# End static patches
.data 0x00000000
.data 0x00000000
update_existing_char_file_list:
# Replace the existing character list with an appropriately-longer one. This
# part does not need to be done if the patch is applied statically to the
# executable; this is only necessary when used as a server patch because the
# character list is already allocated at the time the patch is applied.
push 0x00022FC4 # total file size
mov eax, 0x00835915 # operator_new
call eax
add esp, 4
mov edx, [0x00A939C4] # edx = old char_file_list
mov [0x00A939C4], eax
mov ecx, [edx + 0xBA94] # Copy bgm_test_songs_unlocked_high to new file
mov [eax + 0x00022FB4], ecx
mov ecx, [edx + 0xBA98] # Copy bgm_test_songs_unlocked_low to new file
mov [eax + 0x00022FB8], ecx
mov ecx, [edx + 0xBA9C] # Copy save_count to new file
mov [eax + 0x00022FBC], ecx
mov ecx, [edx + 0xBAA0] # Copy round2_seed to new file
mov [eax + 0x00022FC0], ecx
add eax, 4
add edx, 4
mov ecx, 0xBA90
call memcpy # Copy the existing 4 characters over
mov eax, [0x00A939C4]
add eax, 0xBA94
mov ecx, 4
clear_next_char:
cmp ecx, 0x0C # slot count
jge clear_next_char_done
lea edx, [eax + 0x2EA4] # edx = ptr to next char (or footer)
clear_next_char_write_again:
mov dword [eax], 0
add eax, 4
cmp eax, edx
jl clear_next_char_write_again
clear_next_char_done:
# Call eh_vector_constructor_iterator(
# &char_file_list.chars[4],
# sizeof(char_file_list.chars[0]),
# countof(char_file_list.chars) - 4,
# PSOCharacterFile::init,
# PSOCharacterFile::destroy)
push 0x006C197C # PSOCharacterFile::destroy
push 0x006C182C # PSOCharacterFile::init
push 0x08 # slot count - 4
push 0x2EA4 # sizeof(PSOCharacterFile)
mov eax, [0x00A939C4]
add eax, 0xBA94
push eax
mov eax, 0x00835E86
call eax
# Fix the file's checksum
mov eax, [0x00A939C4]
mov ecx, 0x006C2738
jmp ecx # PSOBBCharacterFileList::checksum(char_file_list)
update_existing_char_file_list_memcard:
# Allocate a new memory card file area and copy the data there too. It seems
# Sega didn't fully strip out the local saving code from PSOBB; instead, they
# just made it write to a heap-allocated buffer. Since the file is much
# bigger now, we also have to make that heap-allocated buffer larger. We add
# a few "blocks" on the end, since the original code in the game does that
# too, but it's probably not strictly necessary.
# Like the above, this part is not necessary if this patch is statically
# applied to the executable.
mov eax, 0x00022FC4 # total file size
add eax, 0x0000FFFF
and eax, 0xFFFFC000
push eax
mov eax, 0x0084F258
call eax # malloc10(total file size)
add esp, 4
mov [0x00A939AC], eax
mov edx, [0x00A939C4]
mov ecx, 0x00022FC4 # total file size
jmp memcpy
@@ -1,25 +1,24 @@
# This patch changes the number of BB character save slots from 4 to any number
# up to 127.
# This patch changes the number of BB character save slots from 4 to any number up to 127.
# This patch is for documentation purposes only; it works when used as a server
# patch via newserv, but is decidedly inconvenient to use via this method. This
# is because it affects logic that runs before any patches can be sent by the
# server, so the player has to connect once to get the patch, then disconnect
# and connect again to use the additional slots.
# This patch is for documentation purposes only; it works when used as a server patch via newserv, but is decidedly
# inconvenient to use via this method. This is because it affects logic that runs before any patches can be sent by the
# server, so the player has to connect once to get the patch, then disconnect and connect again to use the additional
# slots.
# As written, this patch changes the slot count from 4 to 12. To use a
# different slot count, first compute the following values:
# As written, this patch changes the slot count from 4 to 12. To use a different slot count, first compute the
# following values:
# slot count = your desired number of player slots (must be >= 4, <= 127)
# total file size = (slot count * 0x2EA4) + 0x14
# bgm_test_songs_unlocked offset = total file size - 0x10
# save_count offset = total file size - 8
# round2_seed offset = total file size - 4
# Then, for each of the above, search for the string to the left of the = sign
# and change the values used in all of the matching lines.
# Then, for each of the above, search for the string to the left of the = sign and change the values used in all of the
# matching lines.
.meta name="More save slots"
.meta description=""
.meta hide_from_patches_menu
.versions 59NJ 59NL
entry_ptr:
reloc0:
@@ -27,7 +26,7 @@ reloc0:
# Include a few functions first
write_call_to_code:
.include WriteCallToCode-59NL
.include WriteCallToCode
memcpy:
.include CopyData
ret
@@ -53,7 +52,7 @@ start:
apply_enable_scroll_patch:
# This patch enables scrolling behavior within the character list
push -5 # Jump size (negative = jmp instead of call)
push 0x00413B7F # Jump address
push <VERS 0x00413B77 0x00413B7F> # Jump address
call get_code_size_for_enable_scroll
.deltaof enable_scroll_start, enable_scroll_end
get_code_size_for_enable_scroll:
@@ -63,7 +62,7 @@ get_code_size_for_enable_scroll:
enable_scroll_start:
mov eax, dword ptr [edi + 0x28] # cursor = char_select_menu->cursor_obj (TAdSelectCurGC*)
or dword [eax + 0x01F8], 3 # cursor->flags |= 3 # Enable scrolling
mov eax, [0x00A3B050] # scroll_bar = TAdScrollBarXb_objs[0]
mov eax, [<VERS 0x00A38BD0 0x00A3B050>] # scroll_bar = TAdScrollBarXb_objs[0]
mov ecx, [eax + 0xEC] # ecx = scroll_bar->client_id
imul ecx, ecx, 0x24
# Set up scroll bar graphics (in struct at scroll_bar + 0x1C)
@@ -92,10 +91,9 @@ enable_scroll_end:
apply_fix_scroll_patch1:
# This patch fixes character selection cursor object so it will take the
# scroll offset into account
# This patch fixes character selection cursor object so it will take the scroll offset into account
push 6 # Call size
push 0x00413C38 # Call address
push <VERS 0x00413C30 0x00413C38> # Call address
call get_code_size_for_fix_scroll_patch1
.deltaof fix_scroll_patch1_start, fix_scroll_patch1_end
get_code_size_for_fix_scroll_patch1:
@@ -105,7 +103,7 @@ get_code_size_for_fix_scroll_patch1:
fix_scroll_patch1_start:
mov edx, [edi + 0x28] # cursor = this->ad_select_cur_obj (TAdSelectCurGC*)
mov ebp, [edx + 0x44] # ebp = cursor->selected_index_within_view
mov eax, [0x00A3B050] # scroll_bar = TAdScrollBarXb_objs[0]
mov eax, [<VERS 0x00A38BD0 0x00A3B050>] # scroll_bar = TAdScrollBarXb_objs[0]
add ebp, [eax + 0xAC] # ebp += scroll_bar->selection_state[0].scroll_offset
ret
fix_scroll_patch1_end:
@@ -115,11 +113,10 @@ fix_scroll_patch1_end:
apply_fix_scroll_patch2:
# This patch changes the TAdSinglePlyChrSelectGC::selected_index_within_view
# to be the selected character's absolute index (including scroll_offset),
# not the index only within the displayed four characters
# This patch changes the TAdSinglePlyChrSelectGC::selected_index_within_view to be the selected character's absolute
# index (including scroll_offset), not the index only within the displayed four characters
push 6 # Call size
push 0x00413CD8 # Call address
push <VERS 0x00413CD0 0x00413CD8> # Call address
call get_code_size_for_fix_scroll_patch2
.deltaof fix_scroll_patch2_start, fix_scroll_patch2_end
get_code_size_for_fix_scroll_patch2:
@@ -127,7 +124,7 @@ get_code_size_for_fix_scroll_patch2:
push dword [eax]
call fix_scroll_patch2_end
fix_scroll_patch2_start:
mov eax, [0x00A3B050] # scroll_bar = TAdScrollBarXb_objs[0]
mov eax, [<VERS 0x00A38BD0 0x00A3B050>] # scroll_bar = TAdScrollBarXb_objs[0]
mov eax, [eax + 0xAC] # eax = scroll_bar->selection_state[0].scroll_offset
mov edx, [edi + 0x28] # cursor = this->ad_select_cur_obj (TAdSelectCurGC*)
add eax, [edx + 0x44] # eax += cursor->selected_index_within_view
@@ -139,10 +136,9 @@ fix_scroll_patch2_end:
apply_fix_file_index:
# This patch fixes the character file indexing so it will account for the
# scroll position
# This patch fixes the character file indexing so it will account for the scroll position
push 5 # Call size
push 0x00413CF0 # Call address
push <VERS 0x00413CE8 0x00413CF0> # Call address
call get_code_size_for_selection_index_fix2
.deltaof selection_index_fix2_start, selection_index_fix2_end
get_code_size_for_selection_index_fix2:
@@ -150,11 +146,11 @@ get_code_size_for_selection_index_fix2:
push dword [eax]
call selection_index_fix2_end
selection_index_fix2_start:
mov eax, [0x00A3B050]
mov eax, [<VERS 0x00A38BD0 0x00A3B050>]
mov eax, [eax + 0xAC] # eax = TAdScrollBarXb_objs[0]->selection_state[0].scroll_offset
add ebp, eax # arg0 += eax
mov [esp + 4], ebp
mov eax, 0x006C1A80
mov eax, <VERS 0x006C1ABC 0x006C1A80>
jmp eax # set_current_char_slot
selection_index_fix2_end:
call write_call_to_code
@@ -163,10 +159,9 @@ selection_index_fix2_end:
apply_preview_window_fix:
# This patch fixes the preview display so it will show the correct section
# ID, level, etc.
# This patch fixes the preview display so it will show the correct section ID, level, etc.
push 5 # Call size
push 0x0040216C # Call address
push 0x0040216C
call get_code_size_for_preview_window_fix
.deltaof preview_window_fix_start, preview_window_fix_end
get_code_size_for_preview_window_fix:
@@ -174,10 +169,10 @@ get_code_size_for_preview_window_fix:
push dword [eax]
call preview_window_fix_end
preview_window_fix_start:
mov eax, [0x00A3B050] # scroll_bar = TAdScrollBarXb_objs[0]
mov eax, [<VERS 0x00A38BD0 0x00A3B050>] # scroll_bar = TAdScrollBarXb_objs[0]
mov eax, [eax + 0xAC] # eax = scroll_bar->selection_state[0].scroll_offset
add [esp + 4], eax
mov eax, 0x006C44D0 # get_player_preview_info
mov eax, <VERS 0x006C4514 0x006C44D0> # get_player_preview_info
jmp eax
preview_window_fix_end:
# This patch applies in two places, so push the second set of args now, then
@@ -193,267 +188,266 @@ preview_window_fix_end:
apply_static_patches:
.include WriteCodeBlocksBB
# These patches change various places where the character data size and slot
# count are referenced
.data 0x004751A4
.include WriteCodeBlocks
# These patches change various places where the character data size and slot count are referenced
.data <VERS 0x00475294 0x004751A4>
.data 0x00000001
.binary 0C # slot count; TDataProtocol::handle_E5
.data 0x0047525B
.data <VERS 0x0047534B 0x0047525B>
.data 0x00000001
.binary 0C # slot count; import_player_preview
.data 0x004785E1
.data <VERS 0x004786D1 0x004785E1>
.data 0x00000001
.binary 0C # slot count; TDataProtocol::handle_E4
.data 0x0048242D
.data <VERS 0x00482559 0x0048242D>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C17BF
.data <VERS 0x006C17FB 0x006C17BF>
.data 0x00000001
.binary 0C # slot count
.data 0x006C1CCB
.data <VERS 0x006C1D07 0x006C1CCB>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C1CFE
.data <VERS 0x006C1D3A 0x006C1CFE>
.data 0x00000001
.binary 0C # slot count
.data 0x006C1D1C
.data <VERS 0x006C1D58 0x006C1D1C>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C1DD7
.data <VERS 0x006C1E13 0x006C1DD7>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C222E
.data <VERS 0x006C226A 0x006C222E>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C226D
.data <VERS 0x006C22A9 0x006C226D>
.data 0x00000001
.binary 0C # slot count
.data 0x006C228E
.data <VERS 0x006C22CA 0x006C228E>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C229E
.data <VERS 0x006C22DA 0x006C229E>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C24DB
.data <VERS 0x006C2517 0x006C24DB>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C2643
.data <VERS 0x006C267F 0x006C2643>
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C264D
.data <VERS 0x006C2689 0x006C264D>
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C26EF
.data <VERS 0x006C272B 0x006C26EF>
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C2705
.data <VERS 0x006C2741 0x006C2705>
.data 0x00000004
.data 0x00022FC0 # round2_seed offset
.data 0x006C2793
.data <VERS 0x006C27CF 0x006C2793>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C286C
.data <VERS 0x006C28A8 0x006C286C>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C3113
.data <VERS 0x006C314F 0x006C3113>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C353F
.data <VERS 0x006C357B 0x006C353F>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C357E
.data <VERS 0x006C35BA 0x006C357E>
.data 0x00000001
.binary 0C # slot count
.data 0x006C35AA
.data <VERS 0x006C35E6 0x006C35AA>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C35B7
.data <VERS 0x006C35F3 0x006C35B7>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C35D2
.data <VERS 0x006C360E 0x006C35D2>
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C35DB
.data <VERS 0x006C3617 0x006C35DB>
.data 0x00000004
.data 0x00022FBC # save_count offset
.data 0x006C36E0
.data <VERS 0x006C371C 0x006C36E0>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C3B1E
.data <VERS 0x006C3B5A 0x006C3B1E>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4209
.data <VERS 0x006C424D 0x006C4209>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C47EF
.data <VERS 0x006C4833 0x006C47EF>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4826
.data <VERS 0x006C486A 0x006C4826>
.data 0x00000001
.binary 0C # slot count
.data 0x006C4962
.data <VERS 0x006C49A6 0x006C4962>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4999
.data <VERS 0x006C49DD 0x006C4999>
.data 0x00000001
.binary 0C # slot count
.data 0x006C4A81
.data <VERS 0x006C4AC5 0x006C4A81>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4ABA
.data <VERS 0x006C4AFE 0x006C4ABA>
.data 0x00000001
.binary 0C # slot count
.data 0x006C4C9A
.data <VERS 0x006C4CDE 0x006C4C9A>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4CD1
.data <VERS 0x006C4D15 0x006C4CD1>
.data 0x00000001
.binary 0C # slot count
.data 0x006C4DB9
.data <VERS 0x006C4DFD 0x006C4DB9>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4DF2
.data <VERS 0x006C4E36 0x006C4DF2>
.data 0x00000001
.binary 0C # slot count
.data 0x006C4F58
.data <VERS 0x006C4F9C 0x006C4F58>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C4F94
.data <VERS 0x006C4FD7 0x006C4F94>
.data 0x00000001
.binary 0C # slot count
.data 0x006C5181
.data <VERS 0x006C51C5 0x006C5181>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C51BD
.data <VERS 0x006C5201 0x006C51BD>
.data 0x00000001
.binary 0C # slot count
.data 0x006C5332
.data <VERS 0x006C5376 0x006C5332>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C536C
.data <VERS 0x006C53B0 0x006C536C>
.data 0x00000001
.binary 0C # slot count
.data 0x006C5501
.data <VERS 0x006C5545 0x006C5501>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C553D
.data <VERS 0x006C5581 0x006C553D>
.data 0x00000001
.binary 0C # slot count
.data 0x006C56B2
.data <VERS 0x006C56F6 0x006C56B2>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C56EC
.data <VERS 0x006C5730 0x006C56EC>
.data 0x00000001
.binary 0C # slot count
.data 0x006C5872
.data <VERS 0x006C58B6 0x006C5872>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C58AC
.data <VERS 0x006C58F0 0x006C58AC>
.data 0x00000001
.binary 0C # slot count
.data 0x006C5A41
.data <VERS 0x006C5A85 0x006C5A41>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5A7D
.data <VERS 0x006C5AC1 0x006C5A7D>
.data 0x00000001
.binary 0C # slot count
.data 0x006C5B6E
.data <VERS 0x006C5BB2 0x006C5B6E>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5BA8
.data <VERS 0x006C5BEC 0x006C5BA8>
.data 0x00000001
.binary 0C # slot count
.data 0x006C5D2E
.data <VERS 0x006C5D72 0x006C5D2E>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5D68
.data <VERS 0x006C5DAC 0x006C5D68>
.data 0x00000001
.binary 0C # slot count
.data 0x006C5EEE
.data <VERS 0x006C5F32 0x006C5EEE>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C5F28
.data <VERS 0x006C5F6C 0x006C5F28>
.data 0x00000001
.binary 0C # slot count
.data 0x006C60AE
.data <VERS 0x006C60F2 0x006C60AE>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C60E8
.data <VERS 0x006C612C 0x006C60E8>
.data 0x00000001
.binary 0C # slot count
.data 0x006C6303
.data <VERS 0x006C6346 0x006C6303>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C633D
.data <VERS 0x006C6381 0x006C633D>
.data 0x00000001
.binary 0C # slot count
.data 0x006C64C1
.data <VERS 0x006C6505 0x006C64C1>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C64FD
.data <VERS 0x006C6541 0x006C64FD>
.data 0x00000001
.binary 0C # slot count
.data 0x006C65EE
.data <VERS 0x006C6632 0x006C65EE>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C6628
.data <VERS 0x006C666C 0x006C6628>
.data 0x00000001
.binary 0C # slot count
.data 0x006C67AE
.data <VERS 0x006C67F2 0x006C67AE>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C67E8
.data <VERS 0x006C682C 0x006C67E8>
.data 0x00000001
.binary 0C # slot count
.data 0x006C696E
.data <VERS 0x006C69B2 0x006C696E>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C69A8
.data <VERS 0x006C69EC 0x006C69A8>
.data 0x00000001
.binary 0C # slot count
.data 0x006C6B43
.data <VERS 0x006C6B87 0x006C6B43>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C6B74
.data <VERS 0x006C6BB8 0x006C6B74>
.data 0x00000004
.data 0x0000005D # memcard block count
.data 0x006C6BF6
.data <VERS 0x006C6C3A 0x006C6BF6>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C6C30
.data <VERS 0x006C6C74 0x006C6C30>
.data 0x00000001
.binary 0C # slot count
.data 0x006C6E3E
.data <VERS 0x006C6E82 0x006C6E3E>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C6E78
.data <VERS 0x006C6EBC 0x006C6E78>
.data 0x00000001
.binary 0C # slot count
.data 0x006C7075
.data <VERS 0x006C70B9 0x006C7075>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C70AF
.data <VERS 0x006C70F3 0x006C70AF>
.data 0x00000001
.binary 0C # slot count
.data 0x006C7A02
.data <VERS 0x006C7A46 0x006C7A02>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C7D22
.data <VERS 0x006C7D66 0x006C7D22>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x006C7D5E
.data <VERS 0x006C7D7C 0x006C7D5E>
.data 0x00000001
.binary 0C # slot count
.data 0x006C7D7C
.data <VERS 0x006C7DC0 0x006C7D7C>
.data 0x00000004
.data 0x00022FC4 # total file size
.data 0x0077BE92
.data <VERS 0x0077CC72 0x0077BE92>
.data 0x00000004
.data 0x00022FB4 # bgm_test_songs_unlocked offset
# Signature check on all save files (rewritten as loop)
.data 0x006C1C2D
.data <VERS 0x006C1C69 0x006C1C2D>
.deltaof sig_check_begin, sig_check_end
sig_check_begin:
mov edx, 0xC87ED5B1 # Expected signature value
@@ -475,10 +469,10 @@ sig_bad:
inc eax
jmp sig_check_end
.binary CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
sig_check_end: # 006C1C76
sig_check_end: # <VERS 006C1CB2 006C1C76>
# Send slot count in E3 command
.data 0x0046EB20 # TDataProtocol::send_E3_for_index
.data <VERS 0x0046EC10 0x0046EB20> # TDataProtocol::send_E3_for_index
.deltaof send_slot_count_in_E3_begin, send_slot_count_in_E3_end
send_slot_count_in_E3_begin:
# ecx = this (TDataProtocol*)
@@ -493,7 +487,7 @@ send_slot_count_in_E3_begin:
mov eax, [ecx]
call [eax + 0x20] # this->send_command(&cmd, 0x10) // ret 8
add esp, 8
mov eax, 0x006C1A80
mov eax, <VERS 0x006C1ABC 0x006C1A80>
call eax # set_current_char_slot(slot_index) // ret 0
add esp, 8
ret 4
@@ -521,7 +515,7 @@ show_slot_number_strend_again:
jmp show_slot_number_strend_again
show_slot_number_strend_done:
# Format the slot number and append it to the string
mov ecx, [0x00A3B050] # scroll_bar = TAdScrollBarXb_objs[0]
mov ecx, [<VERS 0x00A38BD0 0x00A3B050>] # scroll_bar = TAdScrollBarXb_objs[0]
mov ecx, [ecx + 0xAC] # ecx = scroll_bar->selection_state[0].scroll_offset
lea ecx, [ecx + ebp + 1]
push ecx # Slot number (scroll_offset + z)
@@ -529,7 +523,7 @@ show_slot_number_strend_done:
.binary 20002800230025006400290020000000 # L" (#%d) "
get_show_slot_number_suffix_fmt:
push eax # Destination buffer
mov eax, 0x00857E29 # _swprintf
mov eax, <VERS 0x00835578 0x00857E29> # _swprintf
call eax
add esp, 0x0C
jmp show_slot_number_end
@@ -543,16 +537,15 @@ show_slot_number_end: # 00401E4D
update_existing_char_file_list:
# Replace the existing character list with an appropriately-longer one. This
# part does not need to be done if the patch is applied statically to the
# executable; this is only necessary when used as a server patch because the
# Replace the existing character list with an appropriately-longer one. This part does not need to be done if the
# patch is applied statically to the executable; this is only necessary when used as a server patch because the
# character list is already allocated at the time the patch is applied.
push 0x00022FC4 # total file size
mov eax, 0x008581C5 # operator_new
mov eax, <VERS 0x00835915 0x008581C5> # operator_new
call eax
add esp, 4
mov edx, [0x00A95E44] # edx = old char_file_list
mov [0x00A95E44], eax
mov edx, [<VERS 0x00A939C4 0x00A95E44>] # edx = old char_file_list
mov [<VERS 0x00A939C4 0x00A95E44>], eax
mov ecx, [edx + 0xBA94] # Copy bgm_test_songs_unlocked_high to new file
mov [eax + 0x00022FB4], ecx
mov ecx, [edx + 0xBA98] # Copy bgm_test_songs_unlocked_low to new file
@@ -565,7 +558,7 @@ update_existing_char_file_list:
add edx, 4
mov ecx, 0xBA90
call memcpy # Copy the existing 4 characters over
mov eax, [0x00A95E44]
mov eax, [<VERS 0x00A939C4 0x00A95E44>]
add eax, 0xBA94
mov ecx, 4
clear_next_char:
@@ -585,40 +578,37 @@ clear_next_char_done:
# countof(char_file_list.chars) - 4,
# PSOCharacterFile::init,
# PSOCharacterFile::destroy)
push 0x006C1940 # PSOCharacterFile::destroy
push 0x006C17F0 # PSOCharacterFile::init
push <VERS 0x006C197C 0x006C1940> # PSOCharacterFile::destroy
push <VERS 0x006C182C 0x006C17F0> # PSOCharacterFile::init
push 0x08 # slot count - 4
push 0x2EA4 # sizeof(PSOCharacterFile)
mov eax, [0x00A95E44]
mov eax, [<VERS 0x00A939C4 0x00A95E44>]
add eax, 0xBA94
push eax
mov eax, 0x00858736
mov eax, <VERS 0x00835E86 0x00858736>
call eax
# Fix the file's checksum
mov eax, [0x00A95E44]
mov ecx, 0x006C26FC
mov eax, [<VERS 0x00A939C4 0x00A95E44>]
mov ecx, <VERS 0x006C2738 0x006C26FC>
jmp ecx # PSOBBCharacterFileList::checksum(char_file_list)
update_existing_char_file_list_memcard:
# Allocate a new memory card file area and copy the data there too. It seems
# Sega didn't fully strip out the local saving code from PSOBB; instead, they
# just made it write to a heap-allocated buffer. Since the file is much
# bigger now, we also have to make that heap-allocated buffer larger. We add
# a few "blocks" on the end, since the original code in the game does that
# too, but it's probably not strictly necessary.
# Like the above, this part is not necessary if this patch is statically
# applied to the executable.
# Allocate a new memory card file area and copy the data there too. It seems Sega didn't fully strip out the local
# saving code from PSOBB; instead, they just made it write to a heap-allocated buffer. Since the file is much bigger
# now, we also have to make that heap-allocated buffer larger. We add a few "blocks" on the end, since the original
# code in the game does that too, but it's probably not strictly necessary. Like the above, this part is not
# necessary if this patch is statically applied to the executable.
mov eax, 0x00022FC4 # total file size
add eax, 0x0000FFFF
and eax, 0xFFFFC000
push eax
mov eax, 0x0082E940
mov eax, <VERS 0x0084F258 0x0082E940>
call eax # malloc10(total file size)
add esp, 4
mov [0x00A95E2C], eax
mov edx, [0x00A95E44]
mov [<VERS 0x00A939AC 0x00A95E2C>], eax
mov edx, [<VERS 0x00A939C4 0x00A95E44>]
mov ecx, 0x00022FC4 # total file size
jmp memcpy
@@ -1,103 +0,0 @@
# This patch causes the client not to generate its own EXP text and instead use
# the EXP values generated by the server when showing the purple text for enemy
# deaths. This makes EXP gained via EXP share visible, as well as makes
# fractional EXP multiplers (in config.json) display properly.
.meta name="Server EXP display"
.meta description=""
.meta hide_from_patches_menu
entry_ptr:
reloc0:
.offsetof start
start:
call install_hook
call apply_static_patches
ret
install_hook:
pop ecx
push 0 # Write address instead of a call/jmp opcode
push 0x00A0FC54
call get_code_size
.deltaof handle_6xBF_start, handle_6xBF_end
get_code_size:
pop eax
push dword [eax]
call handle_6xBF_end
handle_6xBF_start: # [std](G_6xBF* cmd @ [esp + 4]) -> void
mov edx, [esp + 4]
mov ecx, [0x00A9C4F4] # local_client_id
cmp [edx + 2], cx
jne skip_text
cmp byte [edx + 1], 3
jl skip_text
movzx eax, word [edx + 8] # cmd.from_enemy_id
cmp eax, 0x1000
jl skip_text
cmp eax, 0x1B50
jge skip_text
call get_enemy_entity
test eax, eax
jnz enemy_entity_ok
# Use player entity if enemy entity is already gone
mov eax, 0x0068D5AC
xchg eax, ecx
call ecx # eax = TObjPlayer::for_client_id(local_client_id); conveniently, this function preserves all regs except eax
enemy_entity_ok:
push 0x0000FFFF # entity_id; ignored by TFontSmallTask if not a player
push dword [edx + 4] # amount = cmd.amount
push 0x009783A0 # prefix = L"EXP"
push 0x14
push 0x14
push 0xFFFF00FF # color (ARGB)
add eax, 0x300
push eax # position
mov eax, 0x0078AABC
call eax # TFontSmallTask___new__(...)
add esp, 0x1C
skip_text:
mov eax, 0x006928C0 # Original handle_6xBF
jmp eax # original_handle_6xBF(cmd)
get_enemy_entity:
.include GetEnemyEntity-59NL
ret
handle_6xBF_end:
push ecx
.include WriteCallToCode-59NL
apply_static_patches:
.include WriteCodeBlocksBB
.data 0x0078749D
.deltaof disable_kill_enemy_callsite_start, disable_kill_enemy_callsite_end
disable_kill_enemy_callsite_start:
nop
nop
nop
nop
nop
disable_kill_enemy_callsite_end:
.data 0x007765A5
.deltaof disable_exp_steal_callsite_start, disable_exp_steal_callsite_end
disable_exp_steal_callsite_start:
add esp, 0x0C # Original function has `ret 0x0C`
nop
nop
disable_exp_steal_callsite_end:
.data 0x00000000
.data 0x00000000
@@ -1,11 +1,11 @@
# This patch causes the client not to generate its own EXP text and instead use
# the EXP values generated by the server when showing the purple text for enemy
# deaths. This makes EXP gained via EXP share visible, as well as makes
# This patch causes the client not to generate its own EXP text and instead use the EXP values generated by the server
# when showing the purple text for enemy deaths. This makes EXP gained via EXP share visible, as well as makes
# fractional EXP multiplers (in config.json) display properly.
.meta name="Server EXP display"
.meta description=""
.meta hide_from_patches_menu
.versions 59NJ 59NL
entry_ptr:
reloc0:
@@ -20,7 +20,7 @@ start:
install_hook:
pop ecx
push 0 # Write address instead of a call/jmp opcode
push 0x00A0DC54
push <VERS 0x00A0DC54 0x00A0FC54>
call get_code_size
.deltaof handle_6xBF_start, handle_6xBF_end
get_code_size:
@@ -30,7 +30,7 @@ get_code_size:
handle_6xBF_start: # [std](G_6xBF* cmd @ [esp + 4]) -> void
mov edx, [esp + 4]
mov ecx, [0x00A9A074] # local_client_id
mov ecx, [<VERS 0x00A9A074 0x00A9C4F4>] # local_client_id
cmp [edx + 2], cx
jne skip_text
@@ -47,41 +47,41 @@ handle_6xBF_start: # [std](G_6xBF* cmd @ [esp + 4]) -> void
jnz enemy_entity_ok
# Use player entity if enemy entity is already gone
mov eax, 0x0068D618
mov eax, <VERS 0x0068D618 0x0068D5AC>
xchg eax, ecx
call ecx # eax = TObjPlayer::for_client_id(local_client_id); conveniently, this function preserves all regs except eax
enemy_entity_ok:
push 0x0000FFFF # entity_id; ignored by TFontSmallTask if not a player
push dword [edx + 4] # amount = cmd.amount
push 0x00976380 # prefix = L"EXP"
push <VERS 0x00976380 0x009783A0> # prefix = L"EXP"
push 0x14
push 0x14
push 0xFFFF00FF # color (ARGB)
add eax, 0x300
push eax # position
mov eax, 0x0078B8E8
mov eax, <VERS 0x0078B8E8 0x0078AABC>
call eax # TFontSmallTask___new__(...)
add esp, 0x1C
skip_text:
mov eax, 0x0069292C # Original handle_6xBF
mov eax, <VERS 0x0069292C 0x006928C0> # Original handle_6xBF
jmp eax # original_handle_6xBF(cmd)
get_enemy_entity:
.include GetEnemyEntity-59NJ
.include GetEnemyEntity
ret
handle_6xBF_end:
push ecx
.include WriteCallToCode-59NJ
.include WriteCallToCode
apply_static_patches:
.include WriteCodeBlocksBB
.include WriteCodeBlocks
.data 0x0078827D
.data <VERS 0x0078827D 0x0078749D>
.deltaof disable_kill_enemy_callsite_start, disable_kill_enemy_callsite_end
disable_kill_enemy_callsite_start:
nop
@@ -91,7 +91,7 @@ disable_kill_enemy_callsite_start:
nop
disable_kill_enemy_callsite_end:
.data 0x00777381
.data <VERS 0x00777381 0x007765A5>
.deltaof disable_exp_steal_callsite_start, disable_exp_steal_callsite_end
disable_exp_steal_callsite_start:
add esp, 0x0C # Original function has `ret 0x0C`
@@ -1,14 +1,11 @@
# It would be a bad idea to remove `.meta hide_from_patches_menu` to make this
# patch an option for players to be able to select; either all players on the
# server should have this patch, or none should have it.
# It would be a bad idea to change this function's visibility; either all players on the server should have this patch,
# or none should have it.
# If you change the stack limits in config.json away from the defaults, you
# should change the limits array below to match config.json and add this patch
# to the BBRequiredPatches list.
# If you change the stack limits in config.json away from the defaults, you should change the limits array below to
# match config.json and add this patch to the BBRequiredPatches list.
.meta name="Item stacks"
.meta description=""
.meta hide_from_patches_menu
.versions 59NJ 59NL
@@ -16,7 +13,7 @@ entry_ptr:
reloc0:
.offsetof start
start:
.include WriteCodeBlocksBB
.include WriteCodeBlocks
# Patch 1: rewrite item_is_stackable
.data <VERS 0x005C5020 0x005C502C>
@@ -63,10 +60,8 @@ max_stack_size_for_tool_start:
# declare return values array
call data_end
# This array specifies the stack limits for each tool class. The array index
# is the second byte of the item data (see names-v4.json for the values; for
# e.g. tech disks this would be 02). For classes beyond 15, the value for 15
# is used.
# This array specifies the stack limits for each tool class. The array index is the second byte of the item data (see
# names-v4.json for the values; for e.g. tech disks this is 02). For classes beyond 15, the value for 15 is used.
# Index: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15
.binary 0A 0A 01 0A 0A 0A 0A 0A 0A 01 01 01 01 01 01 01 63 01 01 01 01 01
data_end: