rewrite client function compiler
This commit is contained in:
+2
-1
@@ -60,10 +60,12 @@ set(SOURCES
|
||||
src/ChatCommands.cc
|
||||
src/ChoiceSearch.cc
|
||||
src/Client.cc
|
||||
src/ClientFunctionIndex.cc
|
||||
src/CommonItemSet.cc
|
||||
src/Compression.cc
|
||||
src/DCSerialNumbers.cc
|
||||
src/DNSServer.cc
|
||||
src/DOLFileIndex.cc
|
||||
src/DownloadSession.cc
|
||||
src/EnemyType.cc
|
||||
src/Episode3/AssistServer.cc
|
||||
@@ -79,7 +81,6 @@ set(SOURCES
|
||||
src/Episode3/Server.cc
|
||||
src/Episode3/Tournament.cc
|
||||
src/FileContentsCache.cc
|
||||
src/FunctionCompiler.cc
|
||||
src/GameServer.cc
|
||||
src/GSLArchive.cc
|
||||
src/HTTPServer.cc
|
||||
|
||||
@@ -594,6 +594,7 @@ Some commands only work for clients not in proxy sessions. The chat commands are
|
||||
* You'll see in-game messages from the server when you take some actions, like killing enemies, opening boxes, or flipping switches.
|
||||
* You'll see the rare seed value and floor variations when you join a game.
|
||||
* You'll be placed into the last available slot in lobbies and games instead of the first, unless you're joining a BB solo-mode game.
|
||||
* You'll be able to run any client function with `$patch`, not only those that are marked visible.
|
||||
* You'll be able to join games with any PSO version, not only those for which cross-version play is normally enabled. See the "Cross-version play" section above for details on this.
|
||||
* `$readmem <address>`: Read 4 bytes from the given address and show you the values.
|
||||
* `$writemem <address> <data>`: Write data to the given address. Data is not required to be any specific size.
|
||||
@@ -622,7 +623,7 @@ Some commands only work for clients not in proxy sessions. The chat commands are
|
||||
* `$ln [name-or-type]`: Set the lobby number. Visible only to you. This command exists because some non-lobby maps can be loaded as lobbies with invalid lobby numbers. See the "GC lobby types" and "Ep3 lobby types" entries in the information menu for acceptable values here. Note that non-lobby maps do not have a lobby counter, so there's no way to exit the lobby without using either `$ln` again or `$exit`. On the game server, `$ln` reloads the lobby immediately; on the proxy, it doesn't take effect until you load another lobby yourself (which means you'll like have to use `$exit` to escape). Run this command with no argument to return to the default lobby.
|
||||
* `$swa`: Enable or disable switch assist. When enabled, the server will unlock two-player and four-player doors in non-quest games when you step on any of the required switches.
|
||||
* `$exit`: If you're in a lobby, send you to the main menu (which ends your proxy session, if you're in one). If you're in a game or spectator team, send you to the lobby (but does not end your proxy session if you're in one). Does nothing if you're in a non-Episode 3 game and no quest is in progress.
|
||||
* `$patch <name>`: Run a patch on your client. `<name>` must exactly match the name of a patch on the server.
|
||||
* `$patch <name>`: Run a client function. `<name>` must exactly match the name of a client function on the server.
|
||||
|
||||
* Character data commands (non-proxy only)
|
||||
* `$switchchar <slot>` (BB only): Switch to a different character from your account without logging out.
|
||||
|
||||
@@ -4,7 +4,6 @@ import subprocess
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
version_tokens = ("3OJ2", "3OJ3", "3OJ4", "3OJ5", "3OE0", "3OE1", "3OE2", "3OP0")
|
||||
|
||||
|
||||
@@ -62,7 +61,7 @@ def write_patches_for_code(
|
||||
f.write("reloc0:\n")
|
||||
f.write(" .offsetof start\n")
|
||||
f.write("start:\n")
|
||||
f.write(" .include WriteCodeBlocksGC\n")
|
||||
f.write(" .include WriteCodeBlocks\n")
|
||||
for region in write_regions:
|
||||
f.write(
|
||||
f" # region @ {region.address:08X} ({len(region.data) * 4} bytes)\n"
|
||||
|
||||
+27
-25
@@ -1111,9 +1111,9 @@ ChatCommandDefinition cc_exit(
|
||||
a.c->check_flag(Client::Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE)) {
|
||||
co_await prepare_client_for_patches(a.c);
|
||||
auto s = a.c->require_server_state();
|
||||
shared_ptr<const CompiledFunctionCode> fn;
|
||||
shared_ptr<const ClientFunctionIndex::Function> fn;
|
||||
try {
|
||||
fn = s->function_code_index->get_patch("ExitAnywhere", a.c->specific_version);
|
||||
fn = s->client_functions->get("ExitAnywhere", a.c->specific_version);
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
if (fn) {
|
||||
@@ -1571,7 +1571,7 @@ ChatCommandDefinition cc_loadchar(
|
||||
auto send_set_extended_player_info = [&a, &s]<typename CharT>(const CharT& char_file) -> asio::awaitable<void> {
|
||||
co_await prepare_client_for_patches(a.c);
|
||||
try {
|
||||
auto fn = s->function_code_index->get_patch("SetExtendedPlayerInfo", a.c->specific_version);
|
||||
auto fn = s->client_functions->get("SetExtendedPlayerInfo", a.c->specific_version);
|
||||
co_await send_function_call(a.c, fn, {}, &char_file, sizeof(CharT));
|
||||
auto l = a.c->lobby.lock();
|
||||
if (l) {
|
||||
@@ -1707,7 +1707,7 @@ ChatCommandDefinition cc_makeobj(
|
||||
|
||||
co_await prepare_client_for_patches(a.c);
|
||||
auto s = a.c->require_server_state();
|
||||
auto fn = s->function_code_index->get_patch("CreateObject", a.c->specific_version);
|
||||
auto fn = s->client_functions->get("CreateObject", a.c->specific_version);
|
||||
co_await send_function_call(a.c, fn, label_writes);
|
||||
});
|
||||
|
||||
@@ -1847,14 +1847,31 @@ ChatCommandDefinition cc_patch(
|
||||
try {
|
||||
auto s = a.c->require_server_state();
|
||||
// Note: We can't look this up before prepare_client_for_patches because specific_version may not be set
|
||||
auto fn = s->function_code_index->get_patch(patch_name, a.c->specific_version);
|
||||
auto fn = s->client_functions->get(patch_name, a.c->specific_version);
|
||||
|
||||
switch (fn->visibility) {
|
||||
case ClientFunctionIndex::Function::Visibility::DEBUG_ONLY:
|
||||
case ClientFunctionIndex::Function::Visibility::PATCHES_MENU_ONLY:
|
||||
a.check_debug_enabled();
|
||||
break;
|
||||
case ClientFunctionIndex::Function::Visibility::CHAT_COMMAND_ONLY_WITH_CHEAT_MODE:
|
||||
a.check_cheats_enabled_or_allowed(true);
|
||||
break;
|
||||
case ClientFunctionIndex::Function::Visibility::CHAT_COMMAND_ONLY:
|
||||
case ClientFunctionIndex::Function::Visibility::PATCHES_MENU_AND_CHAT_COMMAND:
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("Invalid client function visibility");
|
||||
}
|
||||
|
||||
auto ret = co_await send_function_call(a.c, fn, label_writes);
|
||||
if (fn->show_return_value) {
|
||||
send_text_message_fmt(a.c, "$C6Return value:$C7\nInt: {}\nHex: {:08X}\nFloat: {:g}",
|
||||
ret.return_value.load(), ret.return_value.load(), std::bit_cast<float>(ret.return_value.load()));
|
||||
}
|
||||
|
||||
} catch (const out_of_range&) {
|
||||
send_text_message(a.c, "$C6Invalid patch name");
|
||||
send_text_message(a.c, "$C6Invalid function");
|
||||
}
|
||||
co_return;
|
||||
});
|
||||
@@ -2277,15 +2294,10 @@ ChatCommandDefinition cc_readmem(
|
||||
|
||||
co_await prepare_client_for_patches(a.c);
|
||||
|
||||
shared_ptr<const CompiledFunctionCode> fn;
|
||||
shared_ptr<const ClientFunctionIndex::Function> fn;
|
||||
try {
|
||||
auto s = a.c->require_server_state();
|
||||
const char* function_name = is_dc(a.c->version())
|
||||
? "ReadMemoryWordDC"
|
||||
: is_gc(a.c->version())
|
||||
? "ReadMemoryWordGC"
|
||||
: "ReadMemoryWordX86";
|
||||
fn = s->function_code_index->name_to_function.at(function_name);
|
||||
fn = s->client_functions->get("ReadMemoryWord", a.c->specific_version);
|
||||
} catch (const out_of_range&) {
|
||||
throw precondition_failed("Invalid patch name");
|
||||
}
|
||||
@@ -3139,12 +3151,7 @@ ChatCommandDefinition cc_writemem(
|
||||
|
||||
try {
|
||||
auto s = a.c->require_server_state();
|
||||
const char* function_name = is_dc(a.c->version())
|
||||
? "WriteMemoryDC"
|
||||
: is_gc(a.c->version())
|
||||
? "WriteMemoryGC"
|
||||
: "WriteMemoryX86";
|
||||
auto fn = s->function_code_index->name_to_function.at(function_name);
|
||||
auto fn = s->client_functions->get("WriteMemory", a.c->specific_version);
|
||||
unordered_map<string, uint32_t> label_writes{{"dest_addr", addr}, {"size", data.size()}};
|
||||
co_await send_function_call(a.c, fn, label_writes, data.data(), data.size());
|
||||
} catch (const out_of_range&) {
|
||||
@@ -3184,12 +3191,7 @@ ChatCommandDefinition cc_nativecall(
|
||||
|
||||
try {
|
||||
auto s = a.c->require_server_state();
|
||||
const char* function_name = is_dc(a.c->version())
|
||||
? "CallNativeFunctionDC"
|
||||
: is_gc(a.c->version())
|
||||
? "CallNativeFunctionGC"
|
||||
: "CallNativeFunctionX86";
|
||||
auto fn = s->function_code_index->name_to_function.at(function_name);
|
||||
auto fn = s->client_functions->get("CallNativeFunction", a.c->specific_version);
|
||||
co_await send_function_call(a.c, fn, label_writes);
|
||||
} catch (const out_of_range&) {
|
||||
throw precondition_failed("Invalid patch name");
|
||||
|
||||
+1
-1
@@ -6,11 +6,11 @@
|
||||
#include "Account.hh"
|
||||
#include "AsyncUtils.hh"
|
||||
#include "Channel.hh"
|
||||
#include "ClientFunctionIndex.hh"
|
||||
#include "CommandFormats.hh"
|
||||
#include "Episode3/BattleRecord.hh"
|
||||
#include "Episode3/Tournament.hh"
|
||||
#include "FileContentsCache.hh"
|
||||
#include "FunctionCompiler.hh"
|
||||
#include "PSOEncryption.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "PatchFileIndex.hh"
|
||||
|
||||
@@ -0,0 +1,558 @@
|
||||
#include "ClientFunctionIndex.hh"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Hash.hh>
|
||||
#include <phosg/Time.hh>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <resource_file/Emulators/PPC32Emulator.hh>
|
||||
#include <resource_file/Emulators/SH4Emulator.hh>
|
||||
#include <resource_file/Emulators/X86Emulator.hh>
|
||||
|
||||
#include "CommandFormats.hh"
|
||||
#include "CommonFileFormats.hh"
|
||||
#include "Compression.hh"
|
||||
#include "Loggers.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using Arch = ClientFunctionIndex::Function::Architecture;
|
||||
|
||||
const char* name_for_architecture(Arch arch) {
|
||||
switch (arch) {
|
||||
case Arch::SH4:
|
||||
return "SH-4";
|
||||
case Arch::POWERPC:
|
||||
return "PowerPC";
|
||||
case Arch::X86:
|
||||
return "x86";
|
||||
default:
|
||||
throw logic_error("invalid architecture");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t specific_version_for_architecture(Arch arch) {
|
||||
switch (arch) {
|
||||
case Arch::SH4:
|
||||
return SPECIFIC_VERSION_SH4_INDETERMINATE;
|
||||
case Arch::POWERPC:
|
||||
return SPECIFIC_VERSION_PPC_INDETERMINATE;
|
||||
case Arch::X86:
|
||||
return SPECIFIC_VERSION_X86_INDETERMINATE;
|
||||
default:
|
||||
throw logic_error("invalid architecture");
|
||||
}
|
||||
}
|
||||
|
||||
Arch architecture_for_specific_version(uint32_t specific_version) {
|
||||
if (specific_version == SPECIFIC_VERSION_SH4_INDETERMINATE) {
|
||||
return Arch::SH4;
|
||||
} else if (specific_version == SPECIFIC_VERSION_PPC_INDETERMINATE) {
|
||||
return Arch::POWERPC;
|
||||
} else if (specific_version == SPECIFIC_VERSION_X86_INDETERMINATE) {
|
||||
return Arch::X86;
|
||||
} else if (specific_version_is_dc(specific_version)) {
|
||||
return Arch::SH4;
|
||||
} else if (specific_version_is_gc(specific_version)) {
|
||||
return Arch::POWERPC;
|
||||
} else {
|
||||
return Arch::X86;
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::string cache_key(const std::string& name, uint32_t specific_version) {
|
||||
return std::format("{}-{:08X}", name, specific_version);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& get_with_sv_fallback(
|
||||
const std::unordered_map<std::string, T>& index, const std::string& name, uint32_t specific_version) {
|
||||
try {
|
||||
return index.at(cache_key(name, specific_version));
|
||||
} catch (const std::out_of_range&) {
|
||||
}
|
||||
uint32_t arch_specific_version = specific_version_for_architecture(architecture_for_specific_version(
|
||||
specific_version));
|
||||
if (arch_specific_version != specific_version) {
|
||||
try {
|
||||
return index.at(cache_key(name, arch_specific_version));
|
||||
} catch (const std::out_of_range&) {
|
||||
}
|
||||
}
|
||||
return index.at(name);
|
||||
}
|
||||
|
||||
template <bool BE>
|
||||
string ClientFunctionIndex::Function::generate_client_command_t(
|
||||
const unordered_map<string, uint32_t>& label_writes,
|
||||
const void* suffix_data,
|
||||
size_t suffix_size,
|
||||
uint32_t override_relocations_offset) const {
|
||||
using FooterT = RELFileFooterT<BE>;
|
||||
|
||||
FooterT footer;
|
||||
footer.num_relocations = this->relocation_deltas.size();
|
||||
footer.unused1.clear(0);
|
||||
footer.root_offset = this->entrypoint_offset_offset;
|
||||
footer.unused2.clear(0);
|
||||
|
||||
phosg::StringWriter w;
|
||||
if (!label_writes.empty()) {
|
||||
string modified_code = this->code;
|
||||
for (const auto& it : label_writes) {
|
||||
size_t offset = this->label_offsets.at(it.first);
|
||||
if (offset > modified_code.size() - 4) {
|
||||
throw runtime_error("label out of range");
|
||||
}
|
||||
*reinterpret_cast<U32T<FooterT::IsBE>*>(modified_code.data() + offset) = it.second;
|
||||
}
|
||||
w.write(modified_code);
|
||||
} else {
|
||||
w.write(this->code);
|
||||
}
|
||||
if (suffix_size) {
|
||||
w.write(suffix_data, suffix_size);
|
||||
}
|
||||
while (w.size() & 3) {
|
||||
w.put_u8(0);
|
||||
}
|
||||
|
||||
footer.relocations_offset = w.size();
|
||||
|
||||
// Always write at least 4 bytes even if there are no relocations
|
||||
if (this->relocation_deltas.empty()) {
|
||||
w.put_u32(0);
|
||||
}
|
||||
|
||||
if (override_relocations_offset) {
|
||||
footer.relocations_offset = override_relocations_offset;
|
||||
} else {
|
||||
for (uint16_t delta : this->relocation_deltas) {
|
||||
w.put<U16T<FooterT::IsBE>>(delta);
|
||||
}
|
||||
if (this->relocation_deltas.size() & 1) {
|
||||
w.put_u16(0);
|
||||
}
|
||||
}
|
||||
|
||||
w.put(footer);
|
||||
return std::move(w.str());
|
||||
}
|
||||
|
||||
string ClientFunctionIndex::Function::generate_client_command(
|
||||
const unordered_map<string, uint32_t>& label_writes,
|
||||
const void* suffix_data,
|
||||
size_t suffix_size,
|
||||
uint32_t override_relocations_offset) const {
|
||||
if (this->is_big_endian()) {
|
||||
return this->generate_client_command_t<true>(label_writes, suffix_data, suffix_size, override_relocations_offset);
|
||||
} else if ((this->arch == Architecture::X86) || (this->arch == Architecture::SH4)) {
|
||||
return this->generate_client_command_t<false>(label_writes, suffix_data, suffix_size, override_relocations_offset);
|
||||
} else {
|
||||
throw logic_error("invalid architecture");
|
||||
}
|
||||
}
|
||||
|
||||
static unordered_map<uint32_t, std::string> preprocess_function_code(const std::string& text) {
|
||||
std::unordered_set<uint32_t> all_specific_versions;
|
||||
struct Line {
|
||||
std::string text;
|
||||
std::unordered_map<uint32_t, size_t> new_specific_versions; // Nonempty iff line is a .versions directive
|
||||
bool enable_all_versions = false;
|
||||
};
|
||||
|
||||
std::vector<Line> lines;
|
||||
for (auto& line_text : phosg::split(text, '\n')) {
|
||||
auto& line = lines.emplace_back();
|
||||
line.text = std::move(line_text);
|
||||
|
||||
string stripped_line = line.text;
|
||||
phosg::strip_whitespace(stripped_line);
|
||||
|
||||
if (stripped_line == ".all_versions") {
|
||||
line.enable_all_versions = true;
|
||||
} else if (stripped_line.starts_with(".versions ")) {
|
||||
for (auto& vers_token : phosg::split(stripped_line.substr(10), ' ')) {
|
||||
phosg::strip_whitespace(vers_token);
|
||||
if (!vers_token.empty()) {
|
||||
uint32_t specific_version = specific_version_for_str(vers_token);
|
||||
size_t version_index = line.new_specific_versions.size();
|
||||
all_specific_versions.emplace(specific_version);
|
||||
line.new_specific_versions.emplace(std::move(specific_version), version_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const std::string empty_str = "";
|
||||
|
||||
unordered_map<uint32_t, std::string> ret;
|
||||
for (uint32_t specific_version : all_specific_versions) {
|
||||
std::deque<std::string> version_lines;
|
||||
bool include_current_line = true;
|
||||
size_t current_vers_index = all_specific_versions.size();
|
||||
for (size_t line_znum = 0; line_znum < lines.size(); line_znum++) {
|
||||
const auto& line = lines[line_znum];
|
||||
|
||||
if (line.enable_all_versions) {
|
||||
include_current_line = true;
|
||||
current_vers_index = all_specific_versions.size();
|
||||
version_lines.emplace_back(empty_str);
|
||||
|
||||
} else if (!line.new_specific_versions.empty()) {
|
||||
auto it = line.new_specific_versions.find(specific_version);
|
||||
if (it == line.new_specific_versions.end()) {
|
||||
include_current_line = false;
|
||||
current_vers_index = all_specific_versions.size();
|
||||
} else {
|
||||
include_current_line = true;
|
||||
current_vers_index = it->second;
|
||||
}
|
||||
version_lines.emplace_back(empty_str);
|
||||
|
||||
} else if (!include_current_line) {
|
||||
version_lines.emplace_back(empty_str);
|
||||
|
||||
} else {
|
||||
std::string line_text = line.text;
|
||||
size_t vers_offset = line_text.find("<VERS ");
|
||||
while (vers_offset != string::npos) {
|
||||
size_t end_offset = line_text.find('>', vers_offset + 6);
|
||||
if (end_offset == string::npos) {
|
||||
throw runtime_error(std::format("(version {}) (line {}) unterminated <VERS> replacement",
|
||||
str_for_specific_version(specific_version), line_znum + 1));
|
||||
}
|
||||
auto tokens = phosg::split(line_text.substr(vers_offset + 6, end_offset - vers_offset - 6), ' ');
|
||||
if (current_vers_index >= tokens.size()) {
|
||||
throw runtime_error(std::format("(version {}) (line {}) invalid <VERS> replacement",
|
||||
str_for_specific_version(specific_version), line_znum + 1));
|
||||
}
|
||||
line_text = line_text.substr(0, vers_offset) + tokens[current_vers_index] + line_text.substr(end_offset + 1);
|
||||
vers_offset = line_text.find("<VERS ");
|
||||
}
|
||||
version_lines.emplace_back(std::move(line_text));
|
||||
}
|
||||
}
|
||||
ret.emplace(specific_version, phosg::join(version_lines, "\n"));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ClientFunctionIndex::ClientFunctionIndex(const string& root_dir, bool raise_on_any_failure) {
|
||||
map<string, string> source_files;
|
||||
std::function<void(const std::string&)> add_directory = [&](const std::string& dir) -> void {
|
||||
for (const auto& item : std::filesystem::directory_iterator(dir)) {
|
||||
string item_name = item.path().filename().string();
|
||||
string item_path = dir.ends_with("/") ? (dir + item_name) : (dir + "/" + item_name);
|
||||
if (std::filesystem::is_directory(item_path)) {
|
||||
add_directory(item_path);
|
||||
} else if (item_path.ends_with(".s") && std::filesystem::is_regular_file(item_path)) {
|
||||
client_functions_log.debug_f("Adding {} from {}", item_name, item_path);
|
||||
if (!source_files.emplace(item_name, phosg::load_file(item_path)).second) {
|
||||
throw std::runtime_error(std::format("Duplicate source filename: {}", item_name));
|
||||
}
|
||||
} else if (item_path.ends_with(".bin") && std::filesystem::is_regular_file(item_path)) {
|
||||
client_functions_log.debug_f("Adding {} from {}", item_name, item_path);
|
||||
if (!source_files.emplace(item_name, phosg::load_file(item_path)).second) {
|
||||
throw std::runtime_error(std::format("Duplicate binary filename: {}", item_name));
|
||||
}
|
||||
} else {
|
||||
client_functions_log.debug_f("Ignoring {}", item_path);
|
||||
}
|
||||
}
|
||||
};
|
||||
add_directory(root_dir);
|
||||
|
||||
unordered_map<string, string> include_cache;
|
||||
uint32_t last_menu_item_id = 0;
|
||||
for (const auto& [source_filename, source] : source_files) {
|
||||
if (!source_filename.ends_with(".s")) {
|
||||
client_functions_log.debug_f("Skipping root compile for {} because it is not a .s file", source_filename);
|
||||
continue;
|
||||
}
|
||||
if (source_filename.ends_with(".inc.s")) {
|
||||
client_functions_log.debug_f("Skipping root compile for {} because it is an include", source_filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unordered_map<uint32_t, std::string> preprocessed;
|
||||
try {
|
||||
preprocessed = preprocess_function_code(source);
|
||||
} catch (const std::exception& e) {
|
||||
throw std::runtime_error(std::format("({} preprocessing) {}", source_filename, e.what()));
|
||||
}
|
||||
|
||||
for (const auto& [specific_version, source] : preprocessed) {
|
||||
shared_ptr<Function> fn = make_shared<Function>();
|
||||
fn->short_name = source_filename.substr(0, source_filename.size() - 2);
|
||||
fn->specific_version = specific_version;
|
||||
fn->menu_item_id = ++last_menu_item_id;
|
||||
fn->arch = architecture_for_specific_version(fn->specific_version);
|
||||
|
||||
try {
|
||||
unordered_set<string> get_include_stack;
|
||||
function<string(const string&, uint32_t)> get_include_for_sv = [&include_cache, &source_files, &get_include_stack, &get_include_for_sv](const string& name, uint32_t specific_version) -> string {
|
||||
try {
|
||||
return get_with_sv_fallback(include_cache, name, specific_version);
|
||||
} catch (const std::out_of_range&) {
|
||||
}
|
||||
if (client_functions_log.should_log(phosg::LogLevel::L_DEBUG)) {
|
||||
client_functions_log.debug_f("({}) Include {}-{} needs to be compiled",
|
||||
get_include_stack.size(), name, str_for_specific_version(specific_version));
|
||||
}
|
||||
|
||||
auto it = source_files.find(name + ".inc.s");
|
||||
if (it != source_files.end()) {
|
||||
if (!get_include_stack.emplace(name).second) {
|
||||
throw runtime_error("Mutual recursion between includes: " + name);
|
||||
}
|
||||
for (const auto& [include_specific_version, include_source] : preprocess_function_code(it->second)) {
|
||||
ResourceDASM::EmulatorBase::AssembleResult ret;
|
||||
auto get_include = std::bind(get_include_for_sv, std::placeholders::_1, include_specific_version);
|
||||
switch (architecture_for_specific_version(include_specific_version)) {
|
||||
case Arch::POWERPC:
|
||||
ret = ResourceDASM::PPC32Emulator::assemble(include_source, get_include);
|
||||
break;
|
||||
case Arch::X86:
|
||||
ret = ResourceDASM::X86Emulator::assemble(include_source, get_include);
|
||||
break;
|
||||
case Arch::SH4:
|
||||
ret = ResourceDASM::SH4Emulator::assemble(include_source, get_include);
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("unknown architecture");
|
||||
}
|
||||
if (client_functions_log.should_log(phosg::LogLevel::L_DEBUG)) {
|
||||
client_functions_log.debug_f("({}) Compiled include {}-{}",
|
||||
get_include_stack.size(), name, str_for_specific_version(include_specific_version));
|
||||
}
|
||||
include_cache.emplace(cache_key(name, include_specific_version), std::move(ret.code));
|
||||
}
|
||||
get_include_stack.erase(name);
|
||||
|
||||
} else {
|
||||
it = source_files.find(name + ".inc.bin");
|
||||
if (it != source_files.end()) {
|
||||
include_cache.emplace(name, it->second).first->second;
|
||||
client_functions_log.debug_f("({}) Cached binary include {}", get_include_stack.size(), name);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return get_with_sv_fallback(include_cache, name, specific_version);
|
||||
} catch (const std::out_of_range&) {
|
||||
}
|
||||
throw runtime_error(std::format(
|
||||
"Data not found for include {} ({})", name, str_for_specific_version(specific_version)));
|
||||
};
|
||||
|
||||
try {
|
||||
ResourceDASM::EmulatorBase::AssembleResult assembled;
|
||||
auto get_include = std::bind(get_include_for_sv, std::placeholders::_1, specific_version);
|
||||
switch (fn->arch) {
|
||||
case Arch::POWERPC:
|
||||
assembled = ResourceDASM::PPC32Emulator::assemble(source, get_include);
|
||||
break;
|
||||
case Arch::X86:
|
||||
assembled = ResourceDASM::X86Emulator::assemble(source, get_include);
|
||||
break;
|
||||
case Arch::SH4:
|
||||
assembled = ResourceDASM::SH4Emulator::assemble(source, get_include);
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("invalid architecture");
|
||||
}
|
||||
|
||||
fn->code = std::move(assembled.code);
|
||||
fn->label_offsets = std::move(assembled.label_offsets);
|
||||
for (const auto& [key, value] : assembled.metadata_keys) {
|
||||
if (key == "visibility") {
|
||||
if (value == "hidden") {
|
||||
fn->visibility = Function::Visibility::DEBUG_ONLY;
|
||||
} else if (value == "cheat") {
|
||||
fn->visibility = Function::Visibility::CHAT_COMMAND_ONLY_WITH_CHEAT_MODE;
|
||||
} else if (value == "chat") {
|
||||
fn->visibility = Function::Visibility::CHAT_COMMAND_ONLY;
|
||||
} else if (value == "menu") {
|
||||
fn->visibility = Function::Visibility::PATCHES_MENU_ONLY;
|
||||
} else if (value == "all") {
|
||||
fn->visibility = Function::Visibility::PATCHES_MENU_AND_CHAT_COMMAND;
|
||||
} else {
|
||||
throw std::runtime_error("Invalid visibility value");
|
||||
}
|
||||
} else if (key == "key") {
|
||||
fn->short_name = value;
|
||||
} else if (key == "name") {
|
||||
fn->long_name = value;
|
||||
} else if (key == "description") {
|
||||
fn->description = value;
|
||||
} else if (key == "client_flag") {
|
||||
fn->client_flag = stoull(value, nullptr, 0);
|
||||
} else if (key == "show_return_value") {
|
||||
fn->show_return_value = true;
|
||||
} else {
|
||||
throw runtime_error("unknown metadata key: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
fn->entrypoint_offset_offset = fn->label_offsets.at("entry_ptr");
|
||||
} catch (const out_of_range&) {
|
||||
throw runtime_error("code does not contain entry_ptr label");
|
||||
}
|
||||
|
||||
set<uint32_t> reloc_indexes;
|
||||
for (const auto& it : fn->label_offsets) {
|
||||
if (it.first.starts_with("reloc")) {
|
||||
reloc_indexes.emplace(it.second / 4);
|
||||
}
|
||||
}
|
||||
uint32_t prev_index = 0;
|
||||
for (const auto& it : reloc_indexes) {
|
||||
uint32_t delta = it - prev_index;
|
||||
if (delta > 0xFFFF) {
|
||||
throw runtime_error("relocation delta too far away");
|
||||
}
|
||||
fn->relocation_deltas.emplace_back(delta);
|
||||
prev_index = it;
|
||||
}
|
||||
|
||||
} catch (const exception& e) {
|
||||
if (raise_on_any_failure) {
|
||||
throw;
|
||||
}
|
||||
client_functions_log.warning_f("Failed to compile function {} ({}): {}",
|
||||
fn->short_name, str_for_specific_version(specific_version), e.what());
|
||||
}
|
||||
|
||||
auto key = cache_key(fn->short_name, specific_version);
|
||||
if (!this->all_functions.emplace(key, fn).second) {
|
||||
throw std::runtime_error("Duplicate function key: " + key);
|
||||
}
|
||||
this->functions_by_specific_version[specific_version].emplace(key, fn);
|
||||
this->functions_by_menu_item_id.emplace(fn->menu_item_id, fn);
|
||||
|
||||
client_functions_log.debug_f("Compiled function {} ({}; {}; {})",
|
||||
fn->short_name, str_for_specific_version(fn->specific_version), name_for_architecture(fn->arch),
|
||||
phosg::name_for_enum(fn->visibility));
|
||||
} catch (const std::exception& e) {
|
||||
throw std::runtime_error(std::format(
|
||||
"({}-{}) {}", fn->short_name, str_for_specific_version(specific_version), e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<const Menu> ClientFunctionIndex::patch_switches_menu(
|
||||
uint32_t specific_version,
|
||||
const std::unordered_set<std::string>& server_auto_patches_enabled,
|
||||
const std::unordered_set<std::string>& client_auto_patches_enabled) const {
|
||||
auto ret = make_shared<Menu>(MenuID::PATCH_SWITCHES, "Patches");
|
||||
ret->items.emplace_back(PatchesMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0);
|
||||
|
||||
auto map_it = this->functions_by_specific_version.find(specific_version);
|
||||
if (map_it != this->functions_by_specific_version.end()) {
|
||||
for (auto [name, fn] : map_it->second) {
|
||||
if (fn->appears_in_patches_menu() && server_auto_patches_enabled.count(fn->short_name)) {
|
||||
string item_text;
|
||||
item_text.push_back(client_auto_patches_enabled.count(fn->short_name) ? '*' : '-');
|
||||
item_text += fn->long_name.empty() ? fn->short_name : fn->long_name;
|
||||
ret->items.emplace_back(
|
||||
fn->menu_item_id, item_text, fn->description, MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ClientFunctionIndex::patch_menu_empty(uint32_t specific_version) const {
|
||||
uint32_t mask = specific_version_is_indeterminate(specific_version) ? 0xFF000000 : 0xFFFFFFFF;
|
||||
auto it = this->functions_by_specific_version.lower_bound(specific_version & mask);
|
||||
return ((it == this->functions_by_specific_version.end()) || ((it->first & mask) != (specific_version & mask)));
|
||||
}
|
||||
|
||||
std::shared_ptr<const ClientFunctionIndex::Function> ClientFunctionIndex::get(
|
||||
const std::string& name, uint32_t specific_version) const {
|
||||
return get_with_sv_fallback(this->all_functions, name, specific_version);
|
||||
}
|
||||
|
||||
std::shared_ptr<const ClientFunctionIndex::Function> ClientFunctionIndex::get(
|
||||
const std::string& name, Arch arch) const {
|
||||
return get_with_sv_fallback(this->all_functions, name, specific_version_for_architecture(arch));
|
||||
}
|
||||
|
||||
std::shared_ptr<const ClientFunctionIndex::Function> ClientFunctionIndex::get(const std::string& name) const {
|
||||
return this->all_functions.at(name);
|
||||
}
|
||||
|
||||
std::shared_ptr<const ClientFunctionIndex::Function> ClientFunctionIndex::get_by_menu_item_id(
|
||||
uint32_t menu_item_id) const {
|
||||
return this->functions_by_menu_item_id.at(menu_item_id);
|
||||
}
|
||||
|
||||
uint32_t specific_version_for_gc_header_checksum(uint32_t header_checksum) {
|
||||
static unordered_map<uint32_t, uint32_t> checksum_to_specific_version;
|
||||
if (checksum_to_specific_version.empty()) {
|
||||
struct {
|
||||
char system_code = 'G';
|
||||
char game_code1 = 'P';
|
||||
char game_code2;
|
||||
char region_code;
|
||||
char developer_code1 = '8';
|
||||
char developer_code2 = 'P';
|
||||
uint8_t disc_number = 0;
|
||||
uint8_t version_code;
|
||||
} __attribute__((packed)) data;
|
||||
for (const char* game_code2 = "OS"; *game_code2; game_code2++) {
|
||||
data.game_code2 = *game_code2;
|
||||
for (const char* region_code = "JEP"; *region_code; region_code++) {
|
||||
data.region_code = *region_code;
|
||||
for (uint8_t version_code = 0; version_code < 8; version_code++) {
|
||||
data.version_code = version_code;
|
||||
uint32_t checksum = phosg::crc32(&data, sizeof(data));
|
||||
uint32_t specific_version = 0x33000030 | (*game_code2 << 16) | (*region_code << 8) | version_code;
|
||||
if (!checksum_to_specific_version.emplace(checksum, specific_version).second) {
|
||||
throw logic_error("multiple specific_versions have same header checksum");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// Generate entries for Trial Editions
|
||||
data.region_code = 'J';
|
||||
data.system_code = 'D';
|
||||
data.version_code = 0;
|
||||
uint32_t checksum = phosg::crc32(&data, sizeof(data));
|
||||
uint32_t specific_version = 0x33004A54 | (*game_code2 << 16);
|
||||
if (!checksum_to_specific_version.emplace(checksum, specific_version).second) {
|
||||
throw logic_error("multiple specific_versions have same header checksum");
|
||||
}
|
||||
data.system_code = 'G';
|
||||
}
|
||||
}
|
||||
}
|
||||
return checksum_to_specific_version.at(header_checksum);
|
||||
}
|
||||
|
||||
template <>
|
||||
const char* phosg::name_for_enum<ClientFunctionIndex::Function::Visibility>(
|
||||
ClientFunctionIndex::Function::Visibility vis) {
|
||||
switch (vis) {
|
||||
case ClientFunctionIndex::Function::Visibility::DEBUG_ONLY:
|
||||
return "DEBUG_ONLY";
|
||||
case ClientFunctionIndex::Function::Visibility::CHAT_COMMAND_ONLY_WITH_CHEAT_MODE:
|
||||
return "CHAT_COMMAND_ONLY_WITH_CHEAT_MODE";
|
||||
case ClientFunctionIndex::Function::Visibility::CHAT_COMMAND_ONLY:
|
||||
return "CHAT_COMMAND_ONLY";
|
||||
case ClientFunctionIndex::Function::Visibility::PATCHES_MENU_ONLY:
|
||||
return "PATCHES_MENU_ONLY";
|
||||
case ClientFunctionIndex::Function::Visibility::PATCHES_MENU_AND_CHAT_COMMAND:
|
||||
return "PATCHES_MENU_AND_CHAT_COMMAND";
|
||||
default:
|
||||
throw std::logic_error("Invalid client function visibility");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "Menu.hh"
|
||||
|
||||
class ClientFunctionIndex {
|
||||
public:
|
||||
struct Function {
|
||||
enum class Architecture {
|
||||
UNKNOWN = 0,
|
||||
POWERPC, // GC
|
||||
X86, // PC, XB, BB
|
||||
SH4, // Dreamcast
|
||||
};
|
||||
Architecture arch = Architecture::UNKNOWN;
|
||||
std::string code;
|
||||
std::vector<uint16_t> relocation_deltas;
|
||||
std::unordered_map<std::string, uint32_t> label_offsets;
|
||||
uint32_t entrypoint_offset_offset = 0;
|
||||
std::string short_name; // Based on filename
|
||||
std::string long_name; // From .meta name directive
|
||||
std::string description; // From .meta description directive
|
||||
uint64_t client_flag = 0; // From .meta client_flag directive
|
||||
uint32_t menu_item_id = 0;
|
||||
enum class Visibility {
|
||||
DEBUG_ONLY = 0,
|
||||
CHAT_COMMAND_ONLY_WITH_CHEAT_MODE,
|
||||
CHAT_COMMAND_ONLY,
|
||||
PATCHES_MENU_ONLY,
|
||||
PATCHES_MENU_AND_CHAT_COMMAND,
|
||||
};
|
||||
Visibility visibility;
|
||||
bool show_return_value = false;
|
||||
uint32_t specific_version;
|
||||
|
||||
inline bool appears_in_patches_menu() const {
|
||||
return (this->visibility == Visibility::PATCHES_MENU_ONLY) ||
|
||||
(this->visibility == Visibility::PATCHES_MENU_AND_CHAT_COMMAND);
|
||||
}
|
||||
inline bool allowed_via_chat_command(bool cheat_mode_enabled) const {
|
||||
return (cheat_mode_enabled && (this->visibility == Visibility::CHAT_COMMAND_ONLY_WITH_CHEAT_MODE)) ||
|
||||
(this->visibility == Visibility::CHAT_COMMAND_ONLY) ||
|
||||
(this->visibility == Visibility::PATCHES_MENU_AND_CHAT_COMMAND);
|
||||
}
|
||||
|
||||
inline bool is_big_endian() const {
|
||||
return (this->arch == Architecture::POWERPC);
|
||||
}
|
||||
|
||||
template <bool BE>
|
||||
std::string generate_client_command_t(
|
||||
const std::unordered_map<std::string, uint32_t>& label_writes,
|
||||
const void* suffix_data = nullptr,
|
||||
size_t suffix_size = 0,
|
||||
uint32_t override_relocations_offset = 0) const;
|
||||
std::string generate_client_command(
|
||||
const std::unordered_map<std::string, uint32_t>& label_writes = {},
|
||||
const void* suffix_data = nullptr,
|
||||
size_t suffix_size = 0,
|
||||
uint32_t override_relocations_offset = 0) const;
|
||||
};
|
||||
|
||||
ClientFunctionIndex() = default;
|
||||
ClientFunctionIndex(const std::string& directory, bool raise_on_any_failure);
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<Function>> all_functions; // Key is "PatchName-SpecificVersion"
|
||||
std::map<uint32_t, std::map<std::string, std::shared_ptr<Function>>> functions_by_specific_version;
|
||||
std::map<uint32_t, std::shared_ptr<Function>> functions_by_menu_item_id;
|
||||
|
||||
std::shared_ptr<const Menu> patch_switches_menu(
|
||||
uint32_t specific_version,
|
||||
const std::unordered_set<std::string>& server_auto_patches_enabled,
|
||||
const std::unordered_set<std::string>& client_auto_patches_enabled) const;
|
||||
bool patch_menu_empty(uint32_t specific_version) const;
|
||||
|
||||
std::shared_ptr<const Function> get(const std::string& name, uint32_t specific_version) const;
|
||||
std::shared_ptr<const Function> get(const std::string& name, Function::Architecture arch) const;
|
||||
std::shared_ptr<const Function> get(const std::string& name) const;
|
||||
std::shared_ptr<const Function> get_by_menu_item_id(uint32_t menu_item_id) const;
|
||||
};
|
||||
|
||||
const char* name_for_architecture(ClientFunctionIndex::Function::Architecture arch);
|
||||
uint32_t specific_version_for_gc_header_checksum(uint32_t header_checksum);
|
||||
|
||||
template <>
|
||||
const char* phosg::name_for_enum<ClientFunctionIndex::Function::Visibility>(
|
||||
ClientFunctionIndex::Function::Visibility vis);
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "DOLFileIndex.hh"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Hash.hh>
|
||||
#include <phosg/Time.hh>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <resource_file/Emulators/PPC32Emulator.hh>
|
||||
#include <resource_file/Emulators/SH4Emulator.hh>
|
||||
#include <resource_file/Emulators/X86Emulator.hh>
|
||||
|
||||
#include "CommandFormats.hh"
|
||||
#include "CommonFileFormats.hh"
|
||||
#include "Compression.hh"
|
||||
#include "Loggers.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
DOLFileIndex::DOLFileIndex(const string& directory) {
|
||||
if (!std::filesystem::is_directory(directory)) {
|
||||
client_functions_log.info_f("DOL file directory is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto menu = make_shared<Menu>(MenuID::PROGRAMS, "Programs");
|
||||
this->menu = menu;
|
||||
menu->items.emplace_back(ProgramsMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0);
|
||||
|
||||
uint32_t next_menu_item_id = 0;
|
||||
for (const auto& item : std::filesystem::directory_iterator(directory)) {
|
||||
string filename = item.path().filename().string();
|
||||
bool is_dol = filename.ends_with(".dol");
|
||||
bool is_compressed_dol = filename.ends_with(".dol.prs");
|
||||
if (!is_dol && !is_compressed_dol) {
|
||||
continue;
|
||||
}
|
||||
string name = filename.substr(0, filename.size() - (is_compressed_dol ? 8 : 4));
|
||||
|
||||
try {
|
||||
auto dol = make_shared<File>();
|
||||
dol->menu_item_id = next_menu_item_id++;
|
||||
dol->name = name;
|
||||
|
||||
string path = directory + "/" + filename;
|
||||
string file_data = phosg::load_file(path);
|
||||
|
||||
string description;
|
||||
if (is_compressed_dol) {
|
||||
size_t decompressed_size = prs_decompress_size(file_data);
|
||||
|
||||
phosg::StringWriter w;
|
||||
w.put_u32b(file_data.size());
|
||||
w.put_u32b(decompressed_size);
|
||||
w.write(file_data);
|
||||
while (w.size() & 3) {
|
||||
w.put_u8(0);
|
||||
}
|
||||
dol->data = std::move(w.str());
|
||||
|
||||
string compressed_size_str = phosg::format_size(file_data.size());
|
||||
string decompressed_size_str = phosg::format_size(decompressed_size);
|
||||
client_functions_log.debug_f("Loaded compressed DOL file {} ({} -> {})",
|
||||
dol->name, compressed_size_str, decompressed_size_str);
|
||||
description = std::format("$C6{}$C7\n{}\n{} (orig)", dol->name, compressed_size_str, decompressed_size_str);
|
||||
|
||||
} else {
|
||||
phosg::StringWriter w;
|
||||
w.put_u32b(0);
|
||||
w.put_u32b(file_data.size());
|
||||
w.write(file_data);
|
||||
while (w.size() & 3) {
|
||||
w.put_u8(0);
|
||||
}
|
||||
dol->data = std::move(w.str());
|
||||
|
||||
string size_str = phosg::format_size(dol->data.size());
|
||||
client_functions_log.debug_f("Loaded DOL file {} ({})", filename, size_str);
|
||||
description = std::format("$C6{}$C7\n{}", dol->name, size_str);
|
||||
}
|
||||
|
||||
this->name_to_file.emplace(dol->name, dol);
|
||||
this->item_id_to_file.emplace_back(dol);
|
||||
|
||||
menu->items.emplace_back(dol->menu_item_id, dol->name, description, MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
|
||||
} catch (const exception& e) {
|
||||
client_functions_log.warning_f("Failed to load DOL file {}: {}", filename, e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "Menu.hh"
|
||||
|
||||
struct DOLFileIndex {
|
||||
struct File {
|
||||
uint32_t menu_item_id;
|
||||
std::string name;
|
||||
std::string data;
|
||||
bool is_compressed;
|
||||
};
|
||||
|
||||
std::vector<std::shared_ptr<File>> item_id_to_file;
|
||||
std::unordered_map<std::string, std::shared_ptr<File>> name_to_file;
|
||||
std::shared_ptr<const Menu> menu;
|
||||
|
||||
DOLFileIndex() = default;
|
||||
explicit DOLFileIndex(const std::string& directory);
|
||||
|
||||
inline bool empty() const {
|
||||
return this->name_to_file.empty() && this->item_id_to_file.empty();
|
||||
}
|
||||
};
|
||||
@@ -1,612 +0,0 @@
|
||||
#include "FunctionCompiler.hh"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Hash.hh>
|
||||
#include <phosg/Time.hh>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <resource_file/Emulators/PPC32Emulator.hh>
|
||||
#include <resource_file/Emulators/SH4Emulator.hh>
|
||||
#include <resource_file/Emulators/X86Emulator.hh>
|
||||
|
||||
#include "CommandFormats.hh"
|
||||
#include "CommonFileFormats.hh"
|
||||
#include "Compression.hh"
|
||||
#include "Loggers.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
const char* name_for_architecture(CompiledFunctionCode::Architecture arch) {
|
||||
switch (arch) {
|
||||
case CompiledFunctionCode::Architecture::POWERPC:
|
||||
return "PowerPC";
|
||||
case CompiledFunctionCode::Architecture::X86:
|
||||
return "x86";
|
||||
case CompiledFunctionCode::Architecture::SH4:
|
||||
return "SH-4";
|
||||
default:
|
||||
throw logic_error("invalid architecture");
|
||||
}
|
||||
}
|
||||
|
||||
template <bool BE>
|
||||
string CompiledFunctionCode::generate_client_command_t(
|
||||
const unordered_map<string, uint32_t>& label_writes,
|
||||
const void* suffix_data,
|
||||
size_t suffix_size,
|
||||
uint32_t override_relocations_offset) const {
|
||||
using FooterT = RELFileFooterT<BE>;
|
||||
|
||||
FooterT footer;
|
||||
footer.num_relocations = this->relocation_deltas.size();
|
||||
footer.unused1.clear(0);
|
||||
footer.root_offset = this->entrypoint_offset_offset;
|
||||
footer.unused2.clear(0);
|
||||
|
||||
phosg::StringWriter w;
|
||||
if (!label_writes.empty()) {
|
||||
string modified_code = this->code;
|
||||
for (const auto& it : label_writes) {
|
||||
size_t offset = this->label_offsets.at(it.first);
|
||||
if (offset > modified_code.size() - 4) {
|
||||
throw runtime_error("label out of range");
|
||||
}
|
||||
*reinterpret_cast<U32T<FooterT::IsBE>*>(modified_code.data() + offset) = it.second;
|
||||
}
|
||||
w.write(modified_code);
|
||||
} else {
|
||||
w.write(this->code);
|
||||
}
|
||||
if (suffix_size) {
|
||||
w.write(suffix_data, suffix_size);
|
||||
}
|
||||
while (w.size() & 3) {
|
||||
w.put_u8(0);
|
||||
}
|
||||
|
||||
footer.relocations_offset = w.size();
|
||||
|
||||
// Always write at least 4 bytes even if there are no relocations
|
||||
if (this->relocation_deltas.empty()) {
|
||||
w.put_u32(0);
|
||||
}
|
||||
|
||||
if (override_relocations_offset) {
|
||||
footer.relocations_offset = override_relocations_offset;
|
||||
} else {
|
||||
for (uint16_t delta : this->relocation_deltas) {
|
||||
w.put<U16T<FooterT::IsBE>>(delta);
|
||||
}
|
||||
if (this->relocation_deltas.size() & 1) {
|
||||
w.put_u16(0);
|
||||
}
|
||||
}
|
||||
|
||||
w.put(footer);
|
||||
return std::move(w.str());
|
||||
}
|
||||
|
||||
string CompiledFunctionCode::generate_client_command(
|
||||
const unordered_map<string, uint32_t>& label_writes,
|
||||
const void* suffix_data,
|
||||
size_t suffix_size,
|
||||
uint32_t override_relocations_offset) const {
|
||||
if (this->arch == Architecture::POWERPC) {
|
||||
return this->generate_client_command_t<true>(label_writes, suffix_data, suffix_size, override_relocations_offset);
|
||||
} else if ((this->arch == Architecture::X86) || (this->arch == Architecture::SH4)) {
|
||||
return this->generate_client_command_t<false>(label_writes, suffix_data, suffix_size, override_relocations_offset);
|
||||
} else {
|
||||
throw logic_error("invalid architecture");
|
||||
}
|
||||
}
|
||||
|
||||
bool CompiledFunctionCode::is_big_endian() const {
|
||||
return (this->arch == Architecture::POWERPC);
|
||||
}
|
||||
|
||||
static unordered_map<uint32_t, std::string> preprocess_function_code(const std::string& text) {
|
||||
auto parse_specific_version_list = +[](std::string&& text) -> vector<uint32_t> {
|
||||
phosg::strip_whitespace(text);
|
||||
vector<uint32_t> ret;
|
||||
for (auto& vers_token : phosg::split(text, ' ')) {
|
||||
phosg::strip_whitespace(vers_token);
|
||||
if (vers_token.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (vers_token.size() != 4) {
|
||||
throw std::runtime_error("invalid specific_version: " + vers_token);
|
||||
}
|
||||
ret.emplace_back(*reinterpret_cast<const be_uint32_t*>(vers_token.data()));
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
// Find a .versions directive and populate specific_versions
|
||||
vector<uint32_t> specific_versions;
|
||||
auto lines = phosg::split(text, '\n');
|
||||
for (auto& line : lines) {
|
||||
if (line.starts_with(".versions ")) {
|
||||
if (!specific_versions.empty()) {
|
||||
throw std::runtime_error("multiple .versions directives in file");
|
||||
}
|
||||
specific_versions = parse_specific_version_list(line.substr(10));
|
||||
if (specific_versions.empty()) {
|
||||
throw std::runtime_error(".versions directive does not specify any versions");
|
||||
}
|
||||
line.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// If there's no .versions directive, just return the text as-is
|
||||
if (specific_versions.empty()) {
|
||||
return {{0, std::move(text)}};
|
||||
}
|
||||
|
||||
vector<deque<string>> version_lines;
|
||||
version_lines.resize(specific_versions.size());
|
||||
|
||||
size_t line_num = 1;
|
||||
vector<uint32_t> current_only_versions;
|
||||
unordered_set<uint32_t> current_only_versions_set;
|
||||
auto add_blank_line = [&]() -> void {
|
||||
for (size_t vers_index = 0; vers_index < specific_versions.size(); vers_index++) {
|
||||
version_lines[vers_index].emplace_back("");
|
||||
}
|
||||
};
|
||||
for (auto& line : lines) {
|
||||
phosg::strip_whitespace(line);
|
||||
if (line.starts_with(".only_versions ")) {
|
||||
current_only_versions = parse_specific_version_list(line.substr(15));
|
||||
current_only_versions_set.clear();
|
||||
for (uint32_t specific_version : current_only_versions) {
|
||||
current_only_versions_set.emplace(specific_version);
|
||||
}
|
||||
add_blank_line();
|
||||
|
||||
} else if (line == ".all_versions") {
|
||||
current_only_versions.clear();
|
||||
current_only_versions_set.clear();
|
||||
add_blank_line();
|
||||
|
||||
} else {
|
||||
size_t vers_offset = line.find("<VERS ");
|
||||
if (vers_offset == string::npos) {
|
||||
for (size_t vers_index = 0; vers_index < specific_versions.size(); vers_index++) {
|
||||
if (current_only_versions.empty() || current_only_versions_set.count(specific_versions[vers_index])) {
|
||||
version_lines[vers_index].emplace_back(line);
|
||||
} else {
|
||||
version_lines[vers_index].emplace_back("");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
size_t token_index = 0;
|
||||
for (size_t vers_index = 0; vers_index < specific_versions.size(); vers_index++) {
|
||||
if (current_only_versions.empty() || current_only_versions_set.count(specific_versions[vers_index])) {
|
||||
string version_line = line;
|
||||
size_t vers_offset = line.find("<VERS ");
|
||||
while (vers_offset != string::npos) {
|
||||
size_t end_offset = version_line.find('>', vers_offset + 6);
|
||||
if (end_offset == string::npos) {
|
||||
throw runtime_error(std::format("(line {}) unterminated <VERS> replacement", line_num));
|
||||
}
|
||||
auto tokens = phosg::split(version_line.substr(vers_offset + 6, end_offset - vers_offset - 6), ' ');
|
||||
if (tokens.size() <= token_index) {
|
||||
throw runtime_error(std::format("(line {}) invalid <VERS> replacement", line_num));
|
||||
}
|
||||
version_line = version_line.substr(0, vers_offset) + tokens.at(token_index) + version_line.substr(end_offset + 1);
|
||||
vers_offset = version_line.find("<VERS ");
|
||||
}
|
||||
version_lines[vers_index].emplace_back(version_line);
|
||||
token_index++;
|
||||
} else {
|
||||
version_lines[vers_index].emplace_back("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line_num++;
|
||||
}
|
||||
|
||||
unordered_map<uint32_t, string> ret;
|
||||
for (size_t z = 0; z < specific_versions.size(); z++) {
|
||||
ret.emplace(specific_versions[z], phosg::join(version_lines.at(z), "\n"));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static vector<shared_ptr<CompiledFunctionCode>> compile_function_code(
|
||||
CompiledFunctionCode::Architecture arch,
|
||||
const string& function_directory,
|
||||
const string& system_directory,
|
||||
const string& name,
|
||||
const string& text,
|
||||
bool raise_on_any_failure) {
|
||||
unordered_set<string> get_include_stack;
|
||||
function<string(const string&)> get_include = [&](const string& name) -> string {
|
||||
const char* arch_name_token;
|
||||
switch (arch) {
|
||||
case CompiledFunctionCode::Architecture::POWERPC:
|
||||
arch_name_token = "ppc";
|
||||
break;
|
||||
case CompiledFunctionCode::Architecture::X86:
|
||||
arch_name_token = "x86";
|
||||
break;
|
||||
case CompiledFunctionCode::Architecture::SH4:
|
||||
arch_name_token = "sh4";
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("unknown architecture");
|
||||
}
|
||||
|
||||
// Look in the function directory first, then the system directory
|
||||
string asm_filename = std::format("{}/{}.{}.inc.s", function_directory, name, arch_name_token);
|
||||
if (!std::filesystem::is_regular_file(asm_filename)) {
|
||||
asm_filename = std::format("{}/{}.{}.inc.s", system_directory, name, arch_name_token);
|
||||
}
|
||||
if (std::filesystem::is_regular_file(asm_filename)) {
|
||||
if (!get_include_stack.emplace(name).second) {
|
||||
throw runtime_error("mutual recursion between includes: " + name);
|
||||
}
|
||||
ResourceDASM::EmulatorBase::AssembleResult ret;
|
||||
switch (arch) {
|
||||
case CompiledFunctionCode::Architecture::POWERPC:
|
||||
ret = ResourceDASM::PPC32Emulator::assemble(phosg::load_file(asm_filename), get_include);
|
||||
break;
|
||||
case CompiledFunctionCode::Architecture::X86:
|
||||
ret = ResourceDASM::X86Emulator::assemble(phosg::load_file(asm_filename), get_include);
|
||||
break;
|
||||
case CompiledFunctionCode::Architecture::SH4:
|
||||
ret = ResourceDASM::SH4Emulator::assemble(phosg::load_file(asm_filename), get_include);
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("unknown architecture");
|
||||
}
|
||||
get_include_stack.erase(name);
|
||||
return ret.code;
|
||||
}
|
||||
|
||||
string bin_filename = function_directory + "/" + name + ".inc.bin";
|
||||
if (std::filesystem::is_regular_file(bin_filename)) {
|
||||
return phosg::load_file(bin_filename);
|
||||
}
|
||||
bin_filename = system_directory + "/" + name + ".inc.bin";
|
||||
if (std::filesystem::is_regular_file(bin_filename)) {
|
||||
return phosg::load_file(bin_filename);
|
||||
}
|
||||
throw runtime_error("data not found for include: " + name + " (from " + asm_filename + " or " + bin_filename + ")");
|
||||
};
|
||||
|
||||
auto version_texts = preprocess_function_code(text);
|
||||
|
||||
vector<shared_ptr<CompiledFunctionCode>> ret;
|
||||
for (const auto& [specific_version, version_text] : version_texts) {
|
||||
try {
|
||||
ResourceDASM::EmulatorBase::AssembleResult assembled;
|
||||
if (arch == CompiledFunctionCode::Architecture::POWERPC) {
|
||||
assembled = ResourceDASM::PPC32Emulator::assemble(version_text, get_include);
|
||||
} else if (arch == CompiledFunctionCode::Architecture::X86) {
|
||||
assembled = ResourceDASM::X86Emulator::assemble(version_text, get_include);
|
||||
} else if (arch == CompiledFunctionCode::Architecture::SH4) {
|
||||
assembled = ResourceDASM::SH4Emulator::assemble(version_text, get_include);
|
||||
} else {
|
||||
throw runtime_error("invalid architecture");
|
||||
}
|
||||
|
||||
auto compiled = ret.emplace_back(make_shared<CompiledFunctionCode>());
|
||||
compiled->arch = arch;
|
||||
compiled->short_name = name;
|
||||
compiled->specific_version = specific_version;
|
||||
compiled->code = std::move(assembled.code);
|
||||
compiled->label_offsets = std::move(assembled.label_offsets);
|
||||
for (const auto& it : assembled.metadata_keys) {
|
||||
if (it.first == "hide_from_patches_menu") {
|
||||
compiled->hide_from_patches_menu = true;
|
||||
} else if (it.first == "name") {
|
||||
compiled->long_name = it.second;
|
||||
} else if (it.first == "description") {
|
||||
compiled->description = it.second;
|
||||
} else if (it.first == "client_flag") {
|
||||
compiled->client_flag = stoull(it.second, nullptr, 0);
|
||||
} else if (it.first == "show_return_value") {
|
||||
compiled->show_return_value = true;
|
||||
} else {
|
||||
throw runtime_error("unknown metadata key: " + it.first);
|
||||
}
|
||||
}
|
||||
|
||||
set<uint32_t> reloc_indexes;
|
||||
for (const auto& it : compiled->label_offsets) {
|
||||
if (it.first.starts_with("reloc")) {
|
||||
reloc_indexes.emplace(it.second / 4);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
compiled->entrypoint_offset_offset = compiled->label_offsets.at("entry_ptr");
|
||||
} catch (const out_of_range&) {
|
||||
throw runtime_error("code does not contain entry_ptr label");
|
||||
}
|
||||
|
||||
uint32_t prev_index = 0;
|
||||
for (const auto& it : reloc_indexes) {
|
||||
uint32_t delta = it - prev_index;
|
||||
if (delta > 0xFFFF) {
|
||||
throw runtime_error("relocation delta too far away");
|
||||
}
|
||||
compiled->relocation_deltas.emplace_back(delta);
|
||||
prev_index = it;
|
||||
}
|
||||
|
||||
} catch (const exception& e) {
|
||||
string version_str = specific_version ? (" (" + str_for_specific_version(specific_version) + ")") : "";
|
||||
if (raise_on_any_failure) {
|
||||
throw;
|
||||
}
|
||||
function_compiler_log.warning_f("Failed to compile function {}{}: {}", name, version_str, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FunctionCodeIndex::FunctionCodeIndex(const string& directory, bool raise_on_any_failure) {
|
||||
string system_dir_path = directory.ends_with("/") ? (directory + "System") : (directory + "/System");
|
||||
|
||||
uint32_t next_menu_item_id = 1;
|
||||
for (const auto& item : std::filesystem::directory_iterator(directory)) {
|
||||
string subdir_name = item.path().filename().string();
|
||||
string subdir_path = directory.ends_with("/") ? (directory + subdir_name) : (directory + "/" + subdir_name);
|
||||
|
||||
auto add_file = [&](string filename) -> void {
|
||||
try {
|
||||
if (!filename.ends_with(".s")) {
|
||||
return;
|
||||
}
|
||||
|
||||
string name = filename.substr(0, filename.size() - 2);
|
||||
if (name.ends_with(".inc")) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_patch = name.ends_with(".patch");
|
||||
if (is_patch) {
|
||||
name.resize(name.size() - 6);
|
||||
}
|
||||
|
||||
// Figure out the version or specific_version
|
||||
CompiledFunctionCode::Architecture arch = CompiledFunctionCode::Architecture::UNKNOWN;
|
||||
uint32_t specific_version = 0;
|
||||
string short_name = name;
|
||||
if (name.ends_with(".ppc")) {
|
||||
arch = CompiledFunctionCode::Architecture::POWERPC;
|
||||
name.resize(name.size() - 4);
|
||||
short_name = name;
|
||||
} else if (name.ends_with(".x86")) {
|
||||
arch = CompiledFunctionCode::Architecture::X86;
|
||||
name.resize(name.size() - 4);
|
||||
short_name = name;
|
||||
} else if (name.ends_with(".sh4")) {
|
||||
arch = CompiledFunctionCode::Architecture::SH4;
|
||||
name.resize(name.size() - 4);
|
||||
short_name = name;
|
||||
} else if (is_patch && (name.size() >= 5) && (name[name.size() - 5] == '.')) {
|
||||
specific_version = (name[name.size() - 4] << 24) | (name[name.size() - 3] << 16) | (name[name.size() - 2] << 8) | name[name.size() - 1];
|
||||
if (specific_version_is_dc(specific_version)) {
|
||||
arch = CompiledFunctionCode::Architecture::SH4;
|
||||
} else if (specific_version_is_gc(specific_version)) {
|
||||
arch = CompiledFunctionCode::Architecture::POWERPC;
|
||||
} else if (specific_version_is_pc_v2(specific_version) ||
|
||||
specific_version_is_xb(specific_version) ||
|
||||
specific_version_is_bb(specific_version)) {
|
||||
arch = CompiledFunctionCode::Architecture::X86;
|
||||
} else {
|
||||
throw runtime_error("unable to determine architecture from specific_version");
|
||||
}
|
||||
short_name = name.substr(0, name.size() - 5);
|
||||
}
|
||||
|
||||
if (arch == CompiledFunctionCode::Architecture::UNKNOWN) {
|
||||
throw runtime_error("unable to determine architecture");
|
||||
}
|
||||
|
||||
string path = subdir_path + "/" + filename;
|
||||
string text = phosg::load_file(path);
|
||||
for (auto code : compile_function_code(arch, subdir_path, system_dir_path, name, text, raise_on_any_failure)) {
|
||||
if (code->specific_version == 0) {
|
||||
code->specific_version = specific_version;
|
||||
}
|
||||
code->source_path = path;
|
||||
code->short_name = short_name;
|
||||
this->name_to_function.emplace(name, code);
|
||||
if (is_patch) {
|
||||
code->menu_item_id = next_menu_item_id++;
|
||||
this->menu_item_id_and_specific_version_to_patch_function.emplace(
|
||||
static_cast<uint64_t>(code->menu_item_id) << 32 | code->specific_version, code);
|
||||
this->name_and_specific_version_to_patch_function.emplace(
|
||||
std::format("{}-{:08X}", code->short_name, code->specific_version), code);
|
||||
}
|
||||
|
||||
string patch_prefix = is_patch ? std::format("[{:08X}] ", code->menu_item_id) : "";
|
||||
function_compiler_log.debug_f("Compiled function {}{} ({}; {})",
|
||||
patch_prefix, name, str_for_specific_version(code->specific_version), name_for_architecture(code->arch));
|
||||
}
|
||||
|
||||
} catch (const exception& e) {
|
||||
if (raise_on_any_failure) {
|
||||
throw runtime_error(format("({}) {}", filename, e.what()));
|
||||
}
|
||||
function_compiler_log.warning_f("Failed to compile function {}: {}", filename, e.what());
|
||||
}
|
||||
};
|
||||
|
||||
if (std::filesystem::is_regular_file(subdir_path)) {
|
||||
add_file(subdir_path);
|
||||
} else if (std::filesystem::is_directory(subdir_path)) {
|
||||
for (const auto& item : std::filesystem::directory_iterator(subdir_path)) {
|
||||
string filename = item.path().filename().string();
|
||||
add_file(filename);
|
||||
}
|
||||
} else {
|
||||
function_compiler_log.warning_f("Skipping {} (unknown file type)", subdir_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<const Menu> FunctionCodeIndex::patch_switches_menu(
|
||||
uint32_t specific_version,
|
||||
const std::unordered_set<std::string>& server_auto_patches_enabled,
|
||||
const std::unordered_set<std::string>& client_auto_patches_enabled) const {
|
||||
auto suffix = std::format("-{:08X}", specific_version);
|
||||
|
||||
auto ret = make_shared<Menu>(MenuID::PATCH_SWITCHES, "Patches");
|
||||
ret->items.emplace_back(PatchesMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0);
|
||||
for (const auto& it : this->name_and_specific_version_to_patch_function) {
|
||||
const auto& fn = it.second;
|
||||
if (fn->hide_from_patches_menu || !it.first.ends_with(suffix) || server_auto_patches_enabled.count(fn->short_name)) {
|
||||
continue;
|
||||
}
|
||||
string name;
|
||||
name.push_back(client_auto_patches_enabled.count(fn->short_name) ? '*' : '-');
|
||||
name += fn->long_name.empty() ? fn->short_name : fn->long_name;
|
||||
ret->items.emplace_back(fn->menu_item_id, name, fn->description, MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool FunctionCodeIndex::patch_menu_empty(uint32_t specific_version) const {
|
||||
uint32_t mask = specific_version_is_indeterminate(specific_version) ? 0xFF000000 : 0xFFFFFFFF;
|
||||
for (const auto& it : this->menu_item_id_and_specific_version_to_patch_function) {
|
||||
if ((it.first & mask) == (specific_version & mask)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<const CompiledFunctionCode> FunctionCodeIndex::get_patch(
|
||||
const std::string& name, uint32_t specific_version) const {
|
||||
return this->name_and_specific_version_to_patch_function.at(std::format("{}-{:08X}", name, specific_version));
|
||||
}
|
||||
|
||||
DOLFileIndex::DOLFileIndex(const string& directory) {
|
||||
if (!std::filesystem::is_directory(directory)) {
|
||||
function_compiler_log.info_f("DOL file directory is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto menu = make_shared<Menu>(MenuID::PROGRAMS, "Programs");
|
||||
this->menu = menu;
|
||||
menu->items.emplace_back(ProgramsMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0);
|
||||
|
||||
uint32_t next_menu_item_id = 0;
|
||||
for (const auto& item : std::filesystem::directory_iterator(directory)) {
|
||||
string filename = item.path().filename().string();
|
||||
bool is_dol = filename.ends_with(".dol");
|
||||
bool is_compressed_dol = filename.ends_with(".dol.prs");
|
||||
if (!is_dol && !is_compressed_dol) {
|
||||
continue;
|
||||
}
|
||||
string name = filename.substr(0, filename.size() - (is_compressed_dol ? 8 : 4));
|
||||
|
||||
try {
|
||||
auto dol = make_shared<File>();
|
||||
dol->menu_item_id = next_menu_item_id++;
|
||||
dol->name = name;
|
||||
|
||||
string path = directory + "/" + filename;
|
||||
string file_data = phosg::load_file(path);
|
||||
|
||||
string description;
|
||||
if (is_compressed_dol) {
|
||||
size_t decompressed_size = prs_decompress_size(file_data);
|
||||
|
||||
phosg::StringWriter w;
|
||||
w.put_u32b(file_data.size());
|
||||
w.put_u32b(decompressed_size);
|
||||
w.write(file_data);
|
||||
while (w.size() & 3) {
|
||||
w.put_u8(0);
|
||||
}
|
||||
dol->data = std::move(w.str());
|
||||
|
||||
string compressed_size_str = phosg::format_size(file_data.size());
|
||||
string decompressed_size_str = phosg::format_size(decompressed_size);
|
||||
function_compiler_log.debug_f("Loaded compressed DOL file {} ({} -> {})",
|
||||
dol->name, compressed_size_str, decompressed_size_str);
|
||||
description = std::format("$C6{}$C7\n{}\n{} (orig)", dol->name, compressed_size_str, decompressed_size_str);
|
||||
|
||||
} else {
|
||||
phosg::StringWriter w;
|
||||
w.put_u32b(0);
|
||||
w.put_u32b(file_data.size());
|
||||
w.write(file_data);
|
||||
while (w.size() & 3) {
|
||||
w.put_u8(0);
|
||||
}
|
||||
dol->data = std::move(w.str());
|
||||
|
||||
string size_str = phosg::format_size(dol->data.size());
|
||||
function_compiler_log.debug_f("Loaded DOL file {} ({})", filename, size_str);
|
||||
description = std::format("$C6{}$C7\n{}", dol->name, size_str);
|
||||
}
|
||||
|
||||
this->name_to_file.emplace(dol->name, dol);
|
||||
this->item_id_to_file.emplace_back(dol);
|
||||
|
||||
menu->items.emplace_back(dol->menu_item_id, dol->name, description, MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
|
||||
} catch (const exception& e) {
|
||||
function_compiler_log.warning_f("Failed to load DOL file {}: {}", filename, e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t specific_version_for_gc_header_checksum(uint32_t header_checksum) {
|
||||
static unordered_map<uint32_t, uint32_t> checksum_to_specific_version;
|
||||
if (checksum_to_specific_version.empty()) {
|
||||
struct {
|
||||
char system_code = 'G';
|
||||
char game_code1 = 'P';
|
||||
char game_code2;
|
||||
char region_code;
|
||||
char developer_code1 = '8';
|
||||
char developer_code2 = 'P';
|
||||
uint8_t disc_number = 0;
|
||||
uint8_t version_code;
|
||||
} __attribute__((packed)) data;
|
||||
for (const char* game_code2 = "OS"; *game_code2; game_code2++) {
|
||||
data.game_code2 = *game_code2;
|
||||
for (const char* region_code = "JEP"; *region_code; region_code++) {
|
||||
data.region_code = *region_code;
|
||||
for (uint8_t version_code = 0; version_code < 8; version_code++) {
|
||||
data.version_code = version_code;
|
||||
uint32_t checksum = phosg::crc32(&data, sizeof(data));
|
||||
uint32_t specific_version = 0x33000030 | (*game_code2 << 16) | (*region_code << 8) | version_code;
|
||||
if (!checksum_to_specific_version.emplace(checksum, specific_version).second) {
|
||||
throw logic_error("multiple specific_versions have same header checksum");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// Generate entries for Trial Editions
|
||||
data.region_code = 'J';
|
||||
data.system_code = 'D';
|
||||
data.version_code = 0;
|
||||
uint32_t checksum = phosg::crc32(&data, sizeof(data));
|
||||
uint32_t specific_version = 0x33004A54 | (*game_code2 << 16);
|
||||
if (!checksum_to_specific_version.emplace(checksum, specific_version).second) {
|
||||
throw logic_error("multiple specific_versions have same header checksum");
|
||||
}
|
||||
data.system_code = 'G';
|
||||
}
|
||||
}
|
||||
}
|
||||
return checksum_to_specific_version.at(header_checksum);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "Menu.hh"
|
||||
|
||||
// TODO: Support x86 and SH4 function calls in the future. Currently we only
|
||||
// support PPC32 because I haven't written an appropriate x86 assembler yet.
|
||||
|
||||
struct CompiledFunctionCode {
|
||||
enum class Architecture {
|
||||
UNKNOWN = 0,
|
||||
POWERPC, // GC
|
||||
X86, // PC, XB, BB
|
||||
SH4, // Dreamcast
|
||||
};
|
||||
Architecture arch;
|
||||
std::string code;
|
||||
std::vector<uint16_t> relocation_deltas;
|
||||
std::unordered_map<std::string, uint32_t> label_offsets;
|
||||
uint32_t entrypoint_offset_offset = 0;
|
||||
std::string source_path; // Path to source file from newserv root
|
||||
std::string short_name; // Based on filename
|
||||
std::string long_name; // From .meta name directive
|
||||
std::string description; // From .meta description directive
|
||||
uint64_t client_flag = 0; // From .meta client_flag directive
|
||||
uint32_t menu_item_id = 0;
|
||||
bool hide_from_patches_menu = false;
|
||||
bool show_return_value = false;
|
||||
uint32_t specific_version = 0; // 0 = not a client-selectable patch
|
||||
|
||||
bool is_big_endian() const;
|
||||
|
||||
template <bool BE>
|
||||
std::string generate_client_command_t(
|
||||
const std::unordered_map<std::string, uint32_t>& label_writes,
|
||||
const void* suffix_data = nullptr,
|
||||
size_t suffix_size = 0,
|
||||
uint32_t override_relocations_offset = 0) const;
|
||||
std::string generate_client_command(
|
||||
const std::unordered_map<std::string, uint32_t>& label_writes = {},
|
||||
const void* suffix_data = nullptr,
|
||||
size_t suffix_size = 0,
|
||||
uint32_t override_relocations_offset = 0) const;
|
||||
};
|
||||
|
||||
const char* name_for_architecture(CompiledFunctionCode::Architecture arch);
|
||||
|
||||
struct FunctionCodeIndex {
|
||||
FunctionCodeIndex() = default;
|
||||
FunctionCodeIndex(const std::string& directory, bool raise_on_any_failure);
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<CompiledFunctionCode>> name_to_function;
|
||||
std::unordered_map<uint8_t, std::shared_ptr<CompiledFunctionCode>> index_to_function;
|
||||
std::unordered_map<uint64_t, std::shared_ptr<CompiledFunctionCode>> menu_item_id_and_specific_version_to_patch_function;
|
||||
// Key here is e.g. "PATCHNAME-SPECIFICVERSION", with the latter in hex
|
||||
std::map<std::string, std::shared_ptr<CompiledFunctionCode>> name_and_specific_version_to_patch_function;
|
||||
|
||||
std::shared_ptr<const Menu> patch_switches_menu(
|
||||
uint32_t specific_version,
|
||||
const std::unordered_set<std::string>& server_auto_patches_enabled,
|
||||
const std::unordered_set<std::string>& client_auto_patches_enabled) const;
|
||||
bool patch_menu_empty(uint32_t specific_version) const;
|
||||
|
||||
std::shared_ptr<const CompiledFunctionCode> get_patch(const std::string& name, uint32_t specific_version) const;
|
||||
};
|
||||
|
||||
struct DOLFileIndex {
|
||||
struct File {
|
||||
uint32_t menu_item_id;
|
||||
std::string name;
|
||||
std::string data;
|
||||
bool is_compressed;
|
||||
};
|
||||
|
||||
std::vector<std::shared_ptr<File>> item_id_to_file;
|
||||
std::unordered_map<std::string, std::shared_ptr<File>> name_to_file;
|
||||
std::shared_ptr<const Menu> menu;
|
||||
|
||||
DOLFileIndex() = default;
|
||||
explicit DOLFileIndex(const std::string& directory);
|
||||
|
||||
inline bool empty() const {
|
||||
return this->name_to_file.empty() && this->item_id_to_file.empty();
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t specific_version_for_gc_header_checksum(uint32_t header_checksum);
|
||||
+3
-3
@@ -5,11 +5,11 @@
|
||||
using namespace std;
|
||||
|
||||
phosg::PrefixedLogger channel_exceptions_log("[Channel] ", phosg::LogLevel::L_USE_DEFAULT);
|
||||
phosg::PrefixedLogger client_functions_log("[ClientFunctionIndex] ", phosg::LogLevel::L_USE_DEFAULT);
|
||||
phosg::PrefixedLogger client_log("", phosg::LogLevel::L_USE_DEFAULT);
|
||||
phosg::PrefixedLogger command_data_log("[Commands] ", phosg::LogLevel::L_USE_DEFAULT);
|
||||
phosg::PrefixedLogger config_log("[Config] ", phosg::LogLevel::L_USE_DEFAULT);
|
||||
phosg::PrefixedLogger dns_server_log("[DNSServer] ", phosg::LogLevel::L_USE_DEFAULT);
|
||||
phosg::PrefixedLogger function_compiler_log("[FunctionCompiler] ", phosg::LogLevel::L_USE_DEFAULT);
|
||||
phosg::PrefixedLogger ip_stack_simulator_log("[IPStackSimulator] ", phosg::LogLevel::L_USE_DEFAULT);
|
||||
phosg::PrefixedLogger lobby_log("", phosg::LogLevel::L_USE_DEFAULT);
|
||||
phosg::PrefixedLogger patch_index_log("[PatchFileIndex] ", phosg::LogLevel::L_USE_DEFAULT);
|
||||
@@ -30,11 +30,11 @@ static void set_log_level_from_json(
|
||||
|
||||
void set_all_log_levels(phosg::LogLevel level) {
|
||||
channel_exceptions_log.min_level = level;
|
||||
client_functions_log.min_level = level;
|
||||
client_log.min_level = level;
|
||||
command_data_log.min_level = level;
|
||||
config_log.min_level = level;
|
||||
dns_server_log.min_level = level;
|
||||
function_compiler_log.min_level = level;
|
||||
ip_stack_simulator_log.min_level = level;
|
||||
lobby_log.min_level = level;
|
||||
patch_index_log.min_level = level;
|
||||
@@ -47,11 +47,11 @@ void set_all_log_levels(phosg::LogLevel level) {
|
||||
|
||||
void set_log_levels_from_json(const phosg::JSON& json) {
|
||||
set_log_level_from_json(channel_exceptions_log, json, "ChannelExceptions");
|
||||
set_log_level_from_json(client_functions_log, json, "ClientFunctionIndex");
|
||||
set_log_level_from_json(client_log, json, "Clients");
|
||||
set_log_level_from_json(command_data_log, json, "CommandData");
|
||||
set_log_level_from_json(config_log, json, "Config");
|
||||
set_log_level_from_json(dns_server_log, json, "DNSServer");
|
||||
set_log_level_from_json(function_compiler_log, json, "FunctionCompiler");
|
||||
set_log_level_from_json(ip_stack_simulator_log, json, "IPStackSimulator");
|
||||
set_log_level_from_json(lobby_log, json, "Lobbies");
|
||||
set_log_level_from_json(patch_index_log, json, "PatchFileIndex");
|
||||
|
||||
+1
-1
@@ -4,11 +4,11 @@
|
||||
#include <phosg/Strings.hh>
|
||||
|
||||
extern phosg::PrefixedLogger channel_exceptions_log;
|
||||
extern phosg::PrefixedLogger client_functions_log;
|
||||
extern phosg::PrefixedLogger client_log;
|
||||
extern phosg::PrefixedLogger command_data_log;
|
||||
extern phosg::PrefixedLogger config_log;
|
||||
extern phosg::PrefixedLogger dns_server_log;
|
||||
extern phosg::PrefixedLogger function_compiler_log;
|
||||
extern phosg::PrefixedLogger ip_stack_simulator_log;
|
||||
extern phosg::PrefixedLogger lobby_log;
|
||||
extern phosg::PrefixedLogger patch_index_log;
|
||||
|
||||
+18
-29
@@ -27,6 +27,7 @@
|
||||
#include "Compression.hh"
|
||||
#include "DCSerialNumbers.hh"
|
||||
#include "DNSServer.hh"
|
||||
#include "DOLFileIndex.hh"
|
||||
#include "DownloadSession.hh"
|
||||
#include "GSLArchive.hh"
|
||||
#include "GameServer.hh"
|
||||
@@ -1751,18 +1752,22 @@ Action a_assemble_quest_script(
|
||||
write_output_data(args, result_data.data(), result_data.size(), compress ? "bin" : "bind");
|
||||
});
|
||||
|
||||
Action a_assemble_all_patches(
|
||||
"assemble-all-patches", "\
|
||||
assemble-all-patches [--skip-encrypted]\n\
|
||||
Action a_assemble_all_client_functions(
|
||||
"assemble-all-client-functions", "\
|
||||
assemble-all-client-functions [--skip-encrypted] OUTPUT-DIRECTORY\n\
|
||||
Assemble all patches in the system/client-functions directory, and produce\n\
|
||||
two compiled .bin files for each patch (one unencrypted, for most PSO\n\
|
||||
two compiled .bin files for each patch: one unencrypted, for most PSO\n\
|
||||
versions, and one encrypted, for PSO GC JP v1.4, JP Ep3, and Ep3 Trial\n\
|
||||
Edition). The output files are saved in system/client-functions.\n",
|
||||
Edition. If --skip-encrypted is given, only the unencrypted .bin files are\n\
|
||||
created.\n",
|
||||
+[](phosg::Arguments& args) {
|
||||
auto fci = make_shared<FunctionCodeIndex>("system/client-functions", false);
|
||||
auto fci = make_shared<ClientFunctionIndex>("system/client-functions", false);
|
||||
|
||||
const std::string& output_dir = args.get<string>(1);
|
||||
std::filesystem::create_directories(output_dir);
|
||||
|
||||
bool skip_encrypted = args.get<bool>("skip-encrypted");
|
||||
auto process_code = [&](shared_ptr<const CompiledFunctionCode> code,
|
||||
auto process_code = [&](shared_ptr<const ClientFunctionIndex::Function> code,
|
||||
uint32_t checksum_addr,
|
||||
uint32_t checksum_size,
|
||||
uint32_t override_start_addr) -> void {
|
||||
@@ -1775,34 +1780,18 @@ Action a_assemble_all_patches(
|
||||
code, {}, nullptr, 0, checksum_addr, checksum_size, override_start_addr, encrypted);
|
||||
w.put(PSOCommandHeaderDCV3{.command = 0xB2, .flag = 0x00, .size = data.size() + 4});
|
||||
w.write(data);
|
||||
string out_path = std::format("{}.{}.{}.bin",
|
||||
code->source_path, str_for_specific_version(code->specific_version), (encrypted ? "enc" : "std"));
|
||||
string out_path = std::format("{}/{}.{}.{}.bin",
|
||||
output_dir, code->short_name, str_for_specific_version(code->specific_version), (encrypted ? "enc" : "std"));
|
||||
phosg::save_file(out_path, w.str());
|
||||
phosg::fwrite_fmt(stderr, "... {}\n", out_path);
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto& it : fci->name_and_specific_version_to_patch_function) {
|
||||
process_code(it.second, 0, 0, 0);
|
||||
for (const auto& [_, fn] : fci->all_functions) {
|
||||
process_code(fn, 0, 0, 0);
|
||||
}
|
||||
try {
|
||||
process_code(fci->name_to_function.at("VersionDetectDC"), 0, 0, 0);
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
try {
|
||||
process_code(fci->name_to_function.at("VersionDetectGC"), 0, 0, 0);
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
try {
|
||||
process_code(fci->name_to_function.at("VersionDetectXB"), 0, 0, 0);
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
try {
|
||||
process_code(fci->name_to_function.at("CacheClearFix-Phase1"), 0x80000000, 8, 0x7F2734EC);
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
try {
|
||||
process_code(fci->name_to_function.at("CacheClearFix-Phase2"), 0, 0, 0);
|
||||
process_code(fci->get("CacheClearFix-Phase1", SPECIFIC_VERSION_PPC_INDETERMINATE), 0x80000000, 8, 0x7F2734EC);
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
});
|
||||
@@ -3685,7 +3674,7 @@ Action a_check_client_functions(
|
||||
"check-client-functions", nullptr,
|
||||
+[](phosg::Arguments&) {
|
||||
set_all_log_levels(phosg::LogLevel::L_DEBUG);
|
||||
FunctionCodeIndex fci("system/client-functions", true);
|
||||
ClientFunctionIndex index("system/client-functions", true);
|
||||
phosg::fwrite_fmt(stdout, "All client functions compiled\n");
|
||||
});
|
||||
|
||||
|
||||
+16
-16
@@ -132,7 +132,7 @@ static void send_main_menu(shared_ptr<Client> c) {
|
||||
|
||||
main_menu->items.emplace_back(MainMenuItemID::DOWNLOAD_QUESTS, "Download quests",
|
||||
"Download quests", MenuItem::Flag::INVISIBLE_ON_DC_PROTOS | MenuItem::Flag::INVISIBLE_ON_PC_NTE | MenuItem::Flag::INVISIBLE_ON_BB);
|
||||
if (!s->function_code_index->patch_menu_empty(c->specific_version)) {
|
||||
if (!s->client_functions->patch_menu_empty(c->specific_version)) {
|
||||
main_menu->items.emplace_back(MainMenuItemID::PATCH_SWITCHES, "Patches",
|
||||
"Change game\nbehaviors", MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
}
|
||||
@@ -240,14 +240,14 @@ static asio::awaitable<void> send_auto_patches_if_needed(shared_ptr<Client> c) {
|
||||
c->set_flag(Client::Flag::HAS_AUTO_PATCHES);
|
||||
co_await prepare_client_for_patches(c);
|
||||
|
||||
unordered_set<shared_ptr<const CompiledFunctionCode>> functions_to_send;
|
||||
unordered_set<shared_ptr<const ClientFunctionIndex::Function>> functions_to_send;
|
||||
if (c->version() == Version::BB_V4) {
|
||||
for (const auto& patch_name : s->bb_required_patches) {
|
||||
try {
|
||||
functions_to_send.emplace(s->function_code_index->get_patch(patch_name, c->specific_version));
|
||||
functions_to_send.emplace(s->client_functions->get(patch_name, c->specific_version));
|
||||
} catch (const out_of_range&) {
|
||||
string message = std::format(
|
||||
"Your client is not compatible with a\nrequired patch on this server.\n\nClient version: {:08X}\nPatch name: {}", c->specific_version, patch_name);
|
||||
"Your client is not compatible with a\nrequired patch on this server.\n\nClient version: {}\nPatch name: {}", str_for_specific_version(c->specific_version), patch_name);
|
||||
send_message_box(c, message);
|
||||
c->channel->disconnect();
|
||||
co_return;
|
||||
@@ -256,18 +256,18 @@ static asio::awaitable<void> send_auto_patches_if_needed(shared_ptr<Client> c) {
|
||||
}
|
||||
for (const auto& patch_name : s->auto_patches) {
|
||||
try {
|
||||
functions_to_send.emplace(s->function_code_index->get_patch(patch_name, c->specific_version));
|
||||
functions_to_send.emplace(s->client_functions->get(patch_name, c->specific_version));
|
||||
} catch (const out_of_range&) {
|
||||
c->log.warning_f("Server has auto patch {} enabled, but it is not available for specific_version {:08X}",
|
||||
patch_name, c->specific_version);
|
||||
c->log.warning_f("Server has auto patch {} enabled, but it is not available for specific_version {}",
|
||||
patch_name, str_for_specific_version(c->specific_version));
|
||||
}
|
||||
}
|
||||
for (const auto& patch_name : c->login->account->auto_patches_enabled) {
|
||||
try {
|
||||
functions_to_send.emplace(s->function_code_index->get_patch(patch_name, c->specific_version));
|
||||
functions_to_send.emplace(s->client_functions->get(patch_name, c->specific_version));
|
||||
} catch (const out_of_range&) {
|
||||
c->log.warning_f("Client has auto patch {} enabled, but it is not available for specific_version {:08X}",
|
||||
patch_name, c->specific_version);
|
||||
c->log.warning_f("Client has auto patch {} enabled, but it is not available for specific_version {}",
|
||||
patch_name, str_for_specific_version(c->specific_version));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1319,7 +1319,7 @@ static asio::awaitable<void> on_9D_9E(shared_ptr<Client> c, Channel::Message& ms
|
||||
// not; we'll call on_login_complete once we receive the B3 response
|
||||
if (c->version() == Version::PC_V2) {
|
||||
try {
|
||||
auto code = s->function_code_index->name_to_function.at("ReturnTokenX86");
|
||||
auto code = s->client_functions->get("ReturnToken", SPECIFIC_VERSION_X86_INDETERMINATE);
|
||||
unordered_map<string, uint32_t> label_writes{{"token", c->login->account->account_id}};
|
||||
auto resp = co_await send_function_call(c, code, label_writes, nullptr, 0, 0x00400000, 0x0000E000, 0, true);
|
||||
|
||||
@@ -1342,7 +1342,8 @@ static asio::awaitable<void> on_9D_9E(shared_ptr<Client> c, Channel::Message& ms
|
||||
c->specific_version = SPECIFIC_VERSION_PC_V2_INDETERMINATE;
|
||||
c->log.info_f("Version cannot be determined from PE header checksum {:08X}", resp.checksum);
|
||||
}
|
||||
} catch (const out_of_range&) {
|
||||
} catch (const out_of_range& e) {
|
||||
c->log.info_f("Cannot determine PSO PC specific version: {}", e.what());
|
||||
}
|
||||
}
|
||||
co_await on_login_complete(c);
|
||||
@@ -2560,7 +2561,7 @@ static asio::awaitable<void> on_10_main_menu(shared_ptr<Client> c, uint32_t item
|
||||
// We have to prepare the client for patches here, even though we don't send them from this mennu, because we
|
||||
// need to know the client's specific_version before sending the menu.
|
||||
co_await prepare_client_for_patches(c);
|
||||
send_menu(c, c->require_server_state()->function_code_index->patch_switches_menu(c->specific_version, s->auto_patches, c->login->account->auto_patches_enabled));
|
||||
send_menu(c, c->require_server_state()->client_functions->patch_switches_menu(c->specific_version, s->auto_patches, c->login->account->auto_patches_enabled));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2914,13 +2915,12 @@ static void on_10_patch_switches(shared_ptr<Client> c, uint32_t item_id) {
|
||||
}
|
||||
|
||||
auto s = c->require_server_state();
|
||||
uint64_t key = (static_cast<uint64_t>(item_id) << 32) | c->specific_version;
|
||||
auto fn = s->function_code_index->menu_item_id_and_specific_version_to_patch_function.at(key);
|
||||
auto fn = s->client_functions->get_by_menu_item_id(item_id);
|
||||
if (!c->login->account->auto_patches_enabled.emplace(fn->short_name).second) {
|
||||
c->login->account->auto_patches_enabled.erase(fn->short_name);
|
||||
}
|
||||
c->login->account->save();
|
||||
send_menu(c, s->function_code_index->patch_switches_menu(c->specific_version, s->auto_patches, c->login->account->auto_patches_enabled));
|
||||
send_menu(c, s->client_functions->patch_switches_menu(c->specific_version, s->auto_patches, c->login->account->auto_patches_enabled));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-18
@@ -335,7 +335,7 @@ asio::awaitable<void> prepare_client_for_patches(shared_ptr<Client> c) {
|
||||
auto s = c->require_server_state();
|
||||
|
||||
if (!c->check_flag(Client::Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH)) {
|
||||
auto fn = s->function_code_index->name_to_function.at("CacheClearFix-Phase1");
|
||||
auto fn = s->client_functions->get("CacheClearFix-Phase1", ClientFunctionIndex::Function::Architecture::POWERPC);
|
||||
unordered_map<string, uint32_t> label_writes;
|
||||
auto call1_res = co_await send_function_call(c, fn, label_writes, nullptr, 0, 0x80000000, 8, 0x7F2734EC);
|
||||
try {
|
||||
@@ -344,29 +344,29 @@ asio::awaitable<void> prepare_client_for_patches(shared_ptr<Client> c) {
|
||||
} catch (const out_of_range&) {
|
||||
c->log.info_f("Could not detect specific version from header checksum {:08X}", call1_res.checksum);
|
||||
}
|
||||
co_await send_function_call(c, s->function_code_index->name_to_function.at("CacheClearFix-Phase2"));
|
||||
co_await send_function_call(c, s->client_functions->get("CacheClearFix-Phase2", ClientFunctionIndex::Function::Architecture::POWERPC));
|
||||
c->log.info_f("Client cache behavior patched");
|
||||
c->set_flag(Client::Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
}
|
||||
|
||||
const char* version_detect_name = nullptr;
|
||||
ClientFunctionIndex::Function::Architecture arch = ClientFunctionIndex::Function::Architecture::UNKNOWN;
|
||||
if (c->version() == Version::DC_V2) {
|
||||
version_detect_name = "VersionDetectDC";
|
||||
arch = ClientFunctionIndex::Function::Architecture::SH4;
|
||||
} else if (is_gc(c->version())) {
|
||||
version_detect_name = "VersionDetectGC";
|
||||
arch = ClientFunctionIndex::Function::Architecture::POWERPC;
|
||||
} else if (c->version() == Version::XB_V3) {
|
||||
version_detect_name = "VersionDetectXB";
|
||||
arch = ClientFunctionIndex::Function::Architecture::X86;
|
||||
}
|
||||
if (version_detect_name && specific_version_is_indeterminate(c->specific_version)) {
|
||||
auto vers_detect_res = co_await send_function_call(
|
||||
c, s->function_code_index->name_to_function.at(version_detect_name));
|
||||
if ((arch != ClientFunctionIndex::Function::Architecture::UNKNOWN) &&
|
||||
specific_version_is_indeterminate(c->specific_version)) {
|
||||
auto vers_detect_res = co_await send_function_call(c, s->client_functions->get("VersionDetect", arch));
|
||||
c->specific_version = vers_detect_res.return_value;
|
||||
c->log.info_f("Version detected as {:08X}", c->specific_version);
|
||||
}
|
||||
}
|
||||
|
||||
string prepare_send_function_call_data(
|
||||
shared_ptr<const CompiledFunctionCode> code,
|
||||
shared_ptr<const ClientFunctionIndex::Function> code,
|
||||
const unordered_map<string, uint32_t>& label_writes,
|
||||
const void* suffix_data,
|
||||
size_t suffix_size,
|
||||
@@ -416,7 +416,7 @@ string prepare_send_function_call_data(
|
||||
|
||||
asio::awaitable<C_ExecuteCodeResult_B3> send_function_call(
|
||||
shared_ptr<Client> c,
|
||||
shared_ptr<const CompiledFunctionCode> code,
|
||||
shared_ptr<const ClientFunctionIndex::Function> code,
|
||||
const unordered_map<string, uint32_t>& label_writes,
|
||||
const void* suffix_data,
|
||||
size_t suffix_size,
|
||||
@@ -445,7 +445,7 @@ asio::awaitable<C_ExecuteCodeResult_B3> send_function_call(
|
||||
}
|
||||
|
||||
asio::awaitable<void> send_function_call_multi(
|
||||
shared_ptr<Client> c, unordered_set<shared_ptr<const CompiledFunctionCode>> codes) {
|
||||
shared_ptr<Client> c, unordered_set<shared_ptr<const ClientFunctionIndex::Function>> codes) {
|
||||
if (codes.empty()) {
|
||||
co_return;
|
||||
}
|
||||
@@ -468,7 +468,7 @@ asio::awaitable<void> send_function_call_multi(
|
||||
void send_function_call(
|
||||
shared_ptr<Channel> ch,
|
||||
uint64_t client_enabled_flags,
|
||||
shared_ptr<const CompiledFunctionCode> code,
|
||||
shared_ptr<const ClientFunctionIndex::Function> code,
|
||||
const unordered_map<string, uint32_t>& label_writes,
|
||||
const void* suffix_data,
|
||||
size_t suffix_size,
|
||||
@@ -525,7 +525,7 @@ asio::awaitable<bool> send_protected_command(std::shared_ptr<Client> c, const vo
|
||||
co_await prepare_client_for_patches(c);
|
||||
|
||||
try {
|
||||
auto fn = s->function_code_index->get_patch("CallProtectedHandler", c->specific_version);
|
||||
auto fn = s->client_functions->get("CallProtectedHandler", c->specific_version);
|
||||
unordered_map<string, uint32_t> label_writes{{"size", size}};
|
||||
co_await send_function_call(c, fn, label_writes, data, size);
|
||||
auto l = echo_to_lobby ? c->lobby.lock() : nullptr;
|
||||
@@ -549,7 +549,7 @@ asio::awaitable<void> send_dol_file(shared_ptr<Client> c, shared_ptr<DOLFileInde
|
||||
// Determine the necessary start address for the data
|
||||
unordered_map<string, uint32_t> label_writes{{"address", 0x80000034}}; // ArenaHigh from GC globals
|
||||
auto addr_ret = co_await send_function_call(
|
||||
c, s->function_code_index->name_to_function.at("ReadMemoryWordGC"), label_writes);
|
||||
c, s->client_functions->get("ReadMemoryWord", c->specific_version), label_writes);
|
||||
uint32_t dol_base_addr = (addr_ret.return_value - dol->data.size()) & (~3);
|
||||
|
||||
// Write the file in multiple chunks
|
||||
@@ -561,7 +561,7 @@ asio::awaitable<void> send_dol_file(shared_ptr<Client> c, shared_ptr<DOLFileInde
|
||||
string data_to_send = dol->data.substr(offset, bytes_to_send);
|
||||
|
||||
auto s = c->require_server_state();
|
||||
auto fn = s->function_code_index->name_to_function.at("WriteMemoryGC");
|
||||
auto fn = s->client_functions->get("WriteMemory", c->specific_version);
|
||||
label_writes = {{"dest_addr", (dol_base_addr + offset)}, {"size", bytes_to_send}};
|
||||
co_await send_function_call(c, fn, label_writes, data_to_send.data(), data_to_send.size());
|
||||
|
||||
@@ -572,7 +572,7 @@ asio::awaitable<void> send_dol_file(shared_ptr<Client> c, shared_ptr<DOLFileInde
|
||||
}
|
||||
|
||||
// Send the final function, which moves the DOL's sections into place and calls the entrypoint
|
||||
auto fn = s->function_code_index->name_to_function.at("RunDOL");
|
||||
auto fn = s->client_functions->get("RunDOL", c->specific_version);
|
||||
label_writes = {{"dol_base_ptr", dol_base_addr}};
|
||||
co_await send_function_call(c, fn, label_writes);
|
||||
// The client will stop running PSO after this, so disconnect them
|
||||
@@ -2456,7 +2456,7 @@ asio::awaitable<GetPlayerInfoResult> send_get_player_info(shared_ptr<Client> c,
|
||||
}
|
||||
try {
|
||||
auto s = c->require_server_state();
|
||||
auto fn = s->function_code_index->get_patch("GetExtendedPlayerInfo", c->specific_version);
|
||||
auto fn = s->client_functions->get("GetExtendedPlayerInfo", c->specific_version);
|
||||
send_function_call(c->channel, c->enabled_flags, fn);
|
||||
c->function_call_response_queue.emplace_back(make_shared<AsyncPromise<C_ExecuteCodeResult_B3>>());
|
||||
full_req_sent = true;
|
||||
|
||||
+5
-5
@@ -9,8 +9,8 @@
|
||||
#include <unordered_set>
|
||||
|
||||
#include "Client.hh"
|
||||
#include "ClientFunctionIndex.hh"
|
||||
#include "CommandFormats.hh"
|
||||
#include "FunctionCompiler.hh"
|
||||
#include "Lobby.hh"
|
||||
#include "Menu.hh"
|
||||
#include "Quest.hh"
|
||||
@@ -150,7 +150,7 @@ void send_patch_change_to_directory(
|
||||
|
||||
asio::awaitable<void> prepare_client_for_patches(std::shared_ptr<Client> c);
|
||||
std::string prepare_send_function_call_data(
|
||||
std::shared_ptr<const CompiledFunctionCode> code,
|
||||
std::shared_ptr<const ClientFunctionIndex::Function> code,
|
||||
const std::unordered_map<std::string, uint32_t>& label_writes,
|
||||
const void* suffix_data,
|
||||
size_t suffix_size,
|
||||
@@ -163,7 +163,7 @@ std::string prepare_send_function_call_data(
|
||||
void send_function_call(
|
||||
std::shared_ptr<Channel> ch,
|
||||
uint64_t client_enabled_flags,
|
||||
std::shared_ptr<const CompiledFunctionCode> code,
|
||||
std::shared_ptr<const ClientFunctionIndex::Function> code,
|
||||
const std::unordered_map<std::string, uint32_t>& label_writes = {},
|
||||
const void* suffix_data = nullptr,
|
||||
size_t suffix_size = 0,
|
||||
@@ -173,7 +173,7 @@ void send_function_call(
|
||||
bool ignore_actually_runs_code_flag = false);
|
||||
asio::awaitable<C_ExecuteCodeResult_B3> send_function_call(
|
||||
std::shared_ptr<Client> c,
|
||||
std::shared_ptr<const CompiledFunctionCode> code,
|
||||
std::shared_ptr<const ClientFunctionIndex::Function> code,
|
||||
const std::unordered_map<std::string, uint32_t>& label_writes = {},
|
||||
const void* suffix_data = nullptr,
|
||||
size_t suffix_size = 0,
|
||||
@@ -182,7 +182,7 @@ asio::awaitable<C_ExecuteCodeResult_B3> send_function_call(
|
||||
uint32_t override_relocations_offset = 0,
|
||||
bool ignore_actually_runs_code_flag = false);
|
||||
asio::awaitable<void> send_function_call_multi(
|
||||
std::shared_ptr<Client> c, std::unordered_set<std::shared_ptr<const CompiledFunctionCode>> codes);
|
||||
std::shared_ptr<Client> c, std::unordered_set<std::shared_ptr<const ClientFunctionIndex::Function>> codes);
|
||||
asio::awaitable<bool> send_protected_command(std::shared_ptr<Client> c, const void* data, size_t size, bool echo_to_lobby);
|
||||
asio::awaitable<void> send_dol_file(std::shared_ptr<Client> c, std::shared_ptr<DOLFileIndex::File> dol);
|
||||
|
||||
|
||||
+1
-1
@@ -2231,7 +2231,7 @@ void ServerState::load_quest_index(bool raise_on_any_failure) {
|
||||
|
||||
void ServerState::compile_functions(bool raise_on_any_failure) {
|
||||
config_log.info_f("Compiling client functions");
|
||||
this->function_code_index = make_shared<FunctionCodeIndex>("system/client-functions", raise_on_any_failure);
|
||||
this->client_functions = make_shared<ClientFunctionIndex>("system/client-functions", raise_on_any_failure);
|
||||
}
|
||||
|
||||
void ServerState::load_dol_files() {
|
||||
|
||||
+3
-2
@@ -11,11 +11,12 @@
|
||||
|
||||
#include "Account.hh"
|
||||
#include "Client.hh"
|
||||
#include "ClientFunctionIndex.hh"
|
||||
#include "CommonItemSet.hh"
|
||||
#include "DNSServer.hh"
|
||||
#include "DOLFileIndex.hh"
|
||||
#include "Episode3/DataIndexes.hh"
|
||||
#include "Episode3/Tournament.hh"
|
||||
#include "FunctionCompiler.hh"
|
||||
#include "GSLArchive.hh"
|
||||
#include "IPV4RangeSet.hh"
|
||||
#include "ItemNameIndex.hh"
|
||||
@@ -183,7 +184,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
std::vector<std::shared_ptr<const PSOBBEncryption::KeyFile>> bb_private_keys;
|
||||
std::shared_ptr<const parray<uint8_t, 0x16C>> bb_default_keyboard_config;
|
||||
std::shared_ptr<const parray<uint8_t, 0x38>> bb_default_joystick_config;
|
||||
std::shared_ptr<const FunctionCodeIndex> function_code_index;
|
||||
std::shared_ptr<const ClientFunctionIndex> client_functions;
|
||||
std::shared_ptr<const PatchFileIndex> pc_patch_file_index;
|
||||
std::shared_ptr<const PatchFileIndex> bb_patch_file_index;
|
||||
std::unordered_map<uint64_t, std::shared_ptr<const MapFile>> map_file_for_source_hash;
|
||||
|
||||
+22
-5
@@ -140,7 +140,7 @@ uint32_t default_sub_version_for_version(Version version) {
|
||||
uint32_t default_specific_version_for_version(Version version, int64_t sub_version) {
|
||||
// For versions that don't support send_function_call by default, we need to set the specific_version based on
|
||||
// sub_version. Fortunately, all versions that share sub_version values also support send_function_call, so for those
|
||||
// versions we get the specific_version later by sending VersionDetectDC, VersionDetectGC, or VersionDetectXB.
|
||||
// versions we get the specific_version later by sending VersionDetect.
|
||||
switch (version) {
|
||||
case Version::DC_NTE:
|
||||
return SPECIFIC_VERSION_DC_NTE; // 1OJ1 (NTE)
|
||||
@@ -159,7 +159,7 @@ uint32_t default_specific_version_for_version(Version version, int64_t sub_versi
|
||||
return SPECIFIC_VERSION_DC_V1_INDETERMINATE;
|
||||
}
|
||||
case Version::DC_V2:
|
||||
return SPECIFIC_VERSION_DC_V2_INDETERMINATE; // 2___; need to send VersionDetectDC
|
||||
return SPECIFIC_VERSION_DC_V2_INDETERMINATE; // 2___; need to send VersionDetect
|
||||
case Version::PC_NTE:
|
||||
return SPECIFIC_VERSION_PC_V2_NTE; // 2OJT
|
||||
case Version::PC_V2:
|
||||
@@ -184,7 +184,7 @@ uint32_t default_specific_version_for_version(Version version, int64_t sub_versi
|
||||
case 0x30: // GC Ep1&2 GameJam demo, GC Ep1&2 Trial Edition, GC Ep1&2 JP v1.2, at least one version of PSO XB
|
||||
case 0x31: // GC Ep1&2 US v1.0, GC US v1.1, XB US
|
||||
default:
|
||||
return SPECIFIC_VERSION_GC_V3_INDETERMINATE; // 3O__; need to send VersionDetectGC
|
||||
return SPECIFIC_VERSION_GC_V3_INDETERMINATE; // 3O__; need to send VersionDetect
|
||||
}
|
||||
throw logic_error("this should be impossible");
|
||||
case Version::GC_EP3_NTE:
|
||||
@@ -199,10 +199,10 @@ uint32_t default_specific_version_for_version(Version version, int64_t sub_versi
|
||||
case -1: // Initial check (before sub_version recognition)
|
||||
case 0x40: // GC Ep3 trial and GC Ep3 JP
|
||||
default:
|
||||
return SPECIFIC_VERSION_GC_EP3_INDETERMINATE; // 3SJ_; need to send VersionDetectGC
|
||||
return SPECIFIC_VERSION_GC_EP3_INDETERMINATE; // 3SJ_; need to send VersionDetect
|
||||
}
|
||||
case Version::XB_V3:
|
||||
return SPECIFIC_VERSION_XB_V3_INDETERMINATE; // 4O__; need to send VersionDetectXB
|
||||
return SPECIFIC_VERSION_XB_V3_INDETERMINATE; // 4O__; need to send VersionDetect
|
||||
case Version::BB_V4:
|
||||
return SPECIFIC_VERSION_BB_V4_INDETERMINATE; // 5___; we should be able to determine version from initial login
|
||||
default:
|
||||
@@ -244,6 +244,23 @@ bool specific_version_is_bb(uint32_t specific_version) {
|
||||
return ((specific_version & 0xFF000000) == 0x35000000);
|
||||
}
|
||||
|
||||
uint32_t specific_version_for_str(const std::string& s) {
|
||||
switch (s.size()) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return (s[0] << 24);
|
||||
case 2:
|
||||
return (s[0] << 24) | (s[1] << 16);
|
||||
case 3:
|
||||
return (s[0] << 24) | (s[1] << 16) | (s[2] << 8);
|
||||
case 4:
|
||||
return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
default:
|
||||
throw std::runtime_error("Invalid specific_version string");
|
||||
}
|
||||
}
|
||||
|
||||
string str_for_specific_version(uint32_t specific_version) {
|
||||
string ret;
|
||||
for (size_t z = 0; z < 4; z++) {
|
||||
|
||||
@@ -184,6 +184,10 @@ constexpr bool uses_utf16(Version version) {
|
||||
(version == Version::BB_V4);
|
||||
}
|
||||
|
||||
constexpr uint32_t SPECIFIC_VERSION_SH4_INDETERMINATE = 0x53483400; // SH4_
|
||||
constexpr uint32_t SPECIFIC_VERSION_PPC_INDETERMINATE = 0x50504300; // PPC_
|
||||
constexpr uint32_t SPECIFIC_VERSION_X86_INDETERMINATE = 0x58383600; // X86_
|
||||
|
||||
constexpr uint32_t SPECIFIC_VERSION_DC_NTE = 0x314F4A31; // 1OJ1
|
||||
constexpr uint32_t SPECIFIC_VERSION_DC_11_2000_PROTOTYPE = 0x314F4A32; // 1OJ2
|
||||
constexpr uint32_t SPECIFIC_VERSION_DC_V1_JP = 0x314F4A46; // 1OJF
|
||||
@@ -220,6 +224,7 @@ bool specific_version_is_gc(uint32_t specific_version);
|
||||
bool specific_version_is_xb(uint32_t specific_version);
|
||||
bool specific_version_is_bb(uint32_t specific_version);
|
||||
|
||||
uint32_t specific_version_for_str(const std::string& specific_version);
|
||||
std::string str_for_specific_version(uint32_t specific_version);
|
||||
|
||||
enum class ServerBehavior {
|
||||
|
||||
+65
-7
@@ -1,16 +1,76 @@
|
||||
.meta visibility="all"
|
||||
.meta name="Kill count fix"
|
||||
.meta description="Fixes client-side\nkill counts when\nmultiple enemies are\nkilled on the same\nframe"
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksBB
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label TItemWeapon_SealedJSword_count_kill_loc, <VERS 0x8012D2D4 0x8012D518 0x8012D550 0x8012D4B0 0x8012D578 0x8012D578 0x8012D4C0 0x8012D698>
|
||||
.data TItemWeapon_SealedJSword_count_kill_loc
|
||||
.deltaof TItemWeapon_SealedJSword_count_kill, TItemWeapon_SealedJSword_count_kill_end
|
||||
.address TItemWeapon_SealedJSword_count_kill_loc
|
||||
TItemWeapon_SealedJSword_count_kill: # [std](TItemWeapon_SealedJSword* this @ r3) -> void
|
||||
lwz r4, [r3 + 0xF0] # r4 = this->owner_player
|
||||
lha r5, [r4 + 0x11A] # r5 = this->owner_player->num_kills_since_map_load
|
||||
lha r6, [r3 + 0x1F8] # r6 = this->last_owner_player_kill_count
|
||||
lhz r7, [r3 + 0xE8] # r7 = this->kill_count
|
||||
cmp r6, r5
|
||||
bge TItemWeapon_SealedJSword_count_kill_skip_update
|
||||
lwz r8, [r3 + 0xDC]
|
||||
andi. r8, r8, 0x100
|
||||
beq TItemWeapon_SealedJSword_count_kill_skip_incr # if (!(flags & 0x100)) don't incr kill count
|
||||
sub r8, r5, r6
|
||||
add r7, r7, r8
|
||||
sth [r3 + 0xE8], r7
|
||||
TItemWeapon_SealedJSword_count_kill_skip_incr:
|
||||
sth [r3 + 0x1F8], r5
|
||||
TItemWeapon_SealedJSword_count_kill_skip_update:
|
||||
cmplwi r7, 23000
|
||||
blt TItemWeapon_SealedJSword_count_kill_skip_set_flag
|
||||
lwz r8, [r3 + 0xDC]
|
||||
ori r8, r8, 0x200
|
||||
stw [r3 + 0xDC], r8
|
||||
TItemWeapon_SealedJSword_count_kill_skip_set_flag:
|
||||
blr
|
||||
TItemWeapon_SealedJSword_count_kill_end:
|
||||
|
||||
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x00197610 0x001977A0 0x00197920 0x00197880 0x00197810 0x001978A0 0x00197840>
|
||||
.deltaof TItemWeapon_SealedJSword_count_kill, TItemWeapon_SealedJSword_count_kill_end
|
||||
.address <VERS 0x00197610 0x001977A0 0x00197920 0x00197880 0x00197810 0x001978A0 0x00197840>
|
||||
TItemWeapon_SealedJSword_count_kill:
|
||||
mov eax, [ecx + 0xF0]
|
||||
movsx eax, word [eax + 0x11A]
|
||||
movsx edx, word [ecx + 0x1F8]
|
||||
sub edx, eax
|
||||
jge TItemWeapon_SealedJSword_count_kill_skip_update
|
||||
test dword [ecx + 0xDC], 0x100
|
||||
jz TItemWeapon_SealedJSword_count_kill_skip_incr
|
||||
sub [ecx + 0xE8], dx
|
||||
TItemWeapon_SealedJSword_count_kill_skip_incr:
|
||||
mov [ecx + 0x1F8], ax
|
||||
TItemWeapon_SealedJSword_count_kill_skip_update:
|
||||
cmp word [ecx + 0xE8], 23000
|
||||
jb TItemWeapon_SealedJSword_count_kill_skip_set_flag
|
||||
or dword [ecx + 0xDC], 0x200
|
||||
TItemWeapon_SealedJSword_count_kill_skip_set_flag:
|
||||
ret
|
||||
TItemWeapon_SealedJSword_count_kill_end:
|
||||
|
||||
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
.data <VERS 0x005E32A4 0x005E32C8>
|
||||
.deltaof TItemUnitUnsealable_count_kill, TItemUnitUnsealable_count_kill_end
|
||||
.address <VERS 0x005E32A4 0x005E32C8>
|
||||
@@ -34,8 +94,6 @@ TItemUnitUnsealable_count_kill_skip_update:
|
||||
jmp <VERS 0x005E2C10 0x005E2C34>
|
||||
TItemUnitUnsealable_count_kill_end:
|
||||
|
||||
|
||||
|
||||
.data <VERS 0x005F3E94 0x005F3EFC>
|
||||
.deltaof TItemWeapon_LameDArgent_count_kill, TItemWeapon_LameDArgent_count_kill_end
|
||||
.address <VERS 0x005F3E94 0x005F3EFC>
|
||||
@@ -59,8 +117,6 @@ TItemWeapon_LameDArgent_count_kill_skip_update:
|
||||
ret
|
||||
TItemWeapon_LameDArgent_count_kill_end:
|
||||
|
||||
|
||||
|
||||
.data <VERS 0x005FC95C 0x005FCA74>
|
||||
.deltaof TItemWeapon_SealedJSword_count_kill, TItemWeapon_SealedJSword_count_kill_end
|
||||
.address <VERS 0x005FC95C 0x005FCA74>
|
||||
@@ -86,5 +142,7 @@ TItemWeapon_SealedJSword_count_kill_end:
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,42 +0,0 @@
|
||||
.meta name="Kill count fix"
|
||||
.meta description="Fixes client-side\nkill counts when\nmultiple enemies are\nkilled on the same\nframe"
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
|
||||
.label TItemWeapon_SealedJSword_count_kill_loc, <VERS 0x8012D2D4 0x8012D518 0x8012D550 0x8012D4B0 0x8012D578 0x8012D578 0x8012D4C0 0x8012D698>
|
||||
.data TItemWeapon_SealedJSword_count_kill_loc
|
||||
.deltaof TItemWeapon_SealedJSword_count_kill, TItemWeapon_SealedJSword_count_kill_end
|
||||
.address TItemWeapon_SealedJSword_count_kill_loc
|
||||
TItemWeapon_SealedJSword_count_kill: # [std](TItemWeapon_SealedJSword* this @ r3) -> void
|
||||
lwz r4, [r3 + 0xF0] # r4 = this->owner_player
|
||||
lha r5, [r4 + 0x11A] # r5 = this->owner_player->num_kills_since_map_load
|
||||
lha r6, [r3 + 0x1F8] # r6 = this->last_owner_player_kill_count
|
||||
lhz r7, [r3 + 0xE8] # r7 = this->kill_count
|
||||
cmp r6, r5
|
||||
bge TItemWeapon_SealedJSword_count_kill_skip_update
|
||||
lwz r8, [r3 + 0xDC]
|
||||
andi. r8, r8, 0x100
|
||||
beq TItemWeapon_SealedJSword_count_kill_skip_incr # if (!(flags & 0x100)) don't incr kill count
|
||||
sub r8, r5, r6
|
||||
add r7, r7, r8
|
||||
sth [r3 + 0xE8], r7
|
||||
TItemWeapon_SealedJSword_count_kill_skip_incr:
|
||||
sth [r3 + 0x1F8], r5
|
||||
TItemWeapon_SealedJSword_count_kill_skip_update:
|
||||
cmplwi r7, 23000
|
||||
blt TItemWeapon_SealedJSword_count_kill_skip_set_flag
|
||||
lwz r8, [r3 + 0xDC]
|
||||
ori r8, r8, 0x200
|
||||
stw [r3 + 0xDC], r8
|
||||
TItemWeapon_SealedJSword_count_kill_skip_set_flag:
|
||||
blr
|
||||
TItemWeapon_SealedJSword_count_kill_end:
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,35 +0,0 @@
|
||||
.meta name="Kill count fix"
|
||||
.meta description="Fixes client-side\nkill counts when\nmultiple enemies are\nkilled on the same\nframe"
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
|
||||
.data <VERS 0x00197610 0x001977A0 0x00197920 0x00197880 0x00197810 0x001978A0 0x00197840>
|
||||
.deltaof TItemWeapon_SealedJSword_count_kill, TItemWeapon_SealedJSword_count_kill_end
|
||||
.address <VERS 0x00197610 0x001977A0 0x00197920 0x00197880 0x00197810 0x001978A0 0x00197840>
|
||||
TItemWeapon_SealedJSword_count_kill:
|
||||
mov eax, [ecx + 0xF0]
|
||||
movsx eax, word [eax + 0x11A]
|
||||
movsx edx, word [ecx + 0x1F8]
|
||||
sub edx, eax
|
||||
jge TItemWeapon_SealedJSword_count_kill_skip_update
|
||||
test dword [ecx + 0xDC], 0x100
|
||||
jz TItemWeapon_SealedJSword_count_kill_skip_incr
|
||||
sub [ecx + 0xE8], dx
|
||||
TItemWeapon_SealedJSword_count_kill_skip_incr:
|
||||
mov [ecx + 0x1F8], ax
|
||||
TItemWeapon_SealedJSword_count_kill_skip_update:
|
||||
cmp word [ecx + 0xE8], 23000
|
||||
jb TItemWeapon_SealedJSword_count_kill_skip_set_flag
|
||||
or dword [ecx + 0xDC], 0x200
|
||||
TItemWeapon_SealedJSword_count_kill_skip_set_flag:
|
||||
ret
|
||||
TItemWeapon_SealedJSword_count_kill_end:
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
+8
-12
@@ -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
|
||||
+5
-8
@@ -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
|
||||
+4
-7
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
+142
-152
@@ -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 0x00A0DC54
|
||||
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, [0x00A9A074] # 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, 0x0068D618
|
||||
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 0x14
|
||||
push 0x14
|
||||
push 0xFFFF00FF # color (ARGB)
|
||||
add eax, 0x300
|
||||
push eax # position
|
||||
mov eax, 0x0078B8E8
|
||||
call eax # TFontSmallTask___new__(...)
|
||||
add esp, 0x1C
|
||||
|
||||
skip_text:
|
||||
mov eax, 0x0069292C # Original handle_6xBF
|
||||
jmp eax # original_handle_6xBF(cmd)
|
||||
|
||||
get_enemy_entity:
|
||||
.include GetEnemyEntity-59NJ
|
||||
ret
|
||||
|
||||
handle_6xBF_end:
|
||||
push ecx
|
||||
.include WriteCallToCode-59NJ
|
||||
|
||||
|
||||
|
||||
apply_static_patches:
|
||||
.include WriteCodeBlocksBB
|
||||
|
||||
.data 0x0078827D
|
||||
.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 0x00777381
|
||||
.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
|
||||
+15
-15
@@ -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 0x00A0FC54
|
||||
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, [0x00A9C4F4] # 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, 0x0068D5AC
|
||||
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 0x009783A0 # 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, 0x0078AABC
|
||||
mov eax, <VERS 0x0078B8E8 0x0078AABC>
|
||||
call eax # TFontSmallTask___new__(...)
|
||||
add esp, 0x1C
|
||||
|
||||
skip_text:
|
||||
mov eax, 0x006928C0 # Original handle_6xBF
|
||||
mov eax, <VERS 0x0069292C 0x006928C0> # Original handle_6xBF
|
||||
jmp eax # original_handle_6xBF(cmd)
|
||||
|
||||
get_enemy_entity:
|
||||
.include GetEnemyEntity-59NL
|
||||
.include GetEnemyEntity
|
||||
ret
|
||||
|
||||
handle_6xBF_end:
|
||||
push ecx
|
||||
.include WriteCallToCode-59NL
|
||||
.include WriteCallToCode
|
||||
|
||||
|
||||
|
||||
apply_static_patches:
|
||||
.include WriteCodeBlocksBB
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.data 0x0078749D
|
||||
.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 0x007765A5
|
||||
.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`
|
||||
+7
-12
@@ -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:
|
||||
+237
-18
@@ -1,21 +1,27 @@
|
||||
.meta name="Bug fixes"
|
||||
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
|
||||
# Most original codes by Ralf @ GC-Forever and Aleron Ives, except where noted
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# Xbox ports by fuzziqersoftware
|
||||
# TODO: Port the rest of the GC patches to Xbox
|
||||
|
||||
.meta visibility="all"
|
||||
.meta name="Bug fixes"
|
||||
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
|
||||
# Olga Flow Barta Bug Fix (makes barta work on ice weakness Olga Flow instead of damaging player)
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g1_hook_call, <VERS 0x802BB4B0 0x802BC3E0 0x802BD528 0x802BD2C0 0x802BBEF4 0x802BBF38 0x802BD474 0x802BCC08>
|
||||
.label g1_hook_loc, 0x8000D980
|
||||
.data g1_hook_loc
|
||||
@@ -34,10 +40,34 @@ g1_hook_end:
|
||||
.address g1_hook_call
|
||||
bl g1_hook_loc
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.label g1_hook_call, <VERS 0x000970E0 0x000973F0 0x00097460 0x00097140 0x000970E0 0x00097160 0x00096FE0>
|
||||
.label g1_hook_loc, <VERS 0x00097124 0x00097434 0x000974A4 0x00097184 0x00097124 0x000971A4 0x00097024>
|
||||
.data g1_hook_call
|
||||
.data 6
|
||||
.address g1_hook_call
|
||||
mov eax, esi
|
||||
cmp al, 19
|
||||
jmp g1_hook_loc
|
||||
g1_hook_call_end:
|
||||
.data g1_hook_loc
|
||||
.deltaof g1_hook_start, g1_hook_end
|
||||
.address g1_hook_loc
|
||||
g1_hook_start:
|
||||
jne g1_hook_skip_replace_value
|
||||
mov al, 2
|
||||
g1_hook_skip_replace_value:
|
||||
cmp eax, [ebx + 0x440] // Original opcode
|
||||
jmp g1_hook_call_end
|
||||
g1_hook_end:
|
||||
|
||||
|
||||
|
||||
# Morfos Frozen Player Bug Fix (stops Morfos Laser multi-hitting when player is frozen)
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g2_hook_call, <VERS 0x80335060 0x803360CC 0x803375E8 0x8033739C 0x80335A50 0x80335A94 0x80337570 0x803369B4>
|
||||
.label g2_hook_loc, 0x8000D9A0
|
||||
.data g2_hook_loc
|
||||
@@ -57,18 +87,62 @@ g2_hook_end:
|
||||
.address g2_hook_call
|
||||
bl g2_hook_loc
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.label g2_hook_call, <VERS 0x0012E257 0x0012E387 0x0012E4E7 0x0012E537 0x0012E567 0x0012E557 0x0012E5A7>
|
||||
.label g2_hook_loc1, <VERS 0x0012E5F4 0x0012E724 0x0012E884 0x0012E8D4 0x0012E904 0x0012E8F4 0x0012E944>
|
||||
.label g2_hook_loc2, <VERS 0x0012E622 0x0012E752 0x0012E8B2 0x0012E902 0x0012E932 0x0012E922 0x0012E972>
|
||||
.data g2_hook_call
|
||||
.data 6
|
||||
.address g2_hook_call
|
||||
call g2_hook_loc1
|
||||
nop
|
||||
.data g2_hook_loc1
|
||||
.deltaof g2_hook_start1, g2_hook_end1
|
||||
.address g2_hook_loc1
|
||||
g2_hook_start1:
|
||||
fld1 st0 // st = [1.0, speed]
|
||||
fld1 st0 // st = [1.0, 1.0, speed]
|
||||
fadd st0, st1 // st = [2.0, 1.0, speed]
|
||||
fdivp st1, st0 // st = [0.5, speed]
|
||||
jmp g2_hook_loc2
|
||||
g2_hook_end1:
|
||||
|
||||
.data g2_hook_loc2
|
||||
.deltaof g2_hook_start2, g2_hook_end2
|
||||
.address g2_hook_loc2
|
||||
g2_hook_start2:
|
||||
test byte [esi + 0x30], 0x20 // If not set, use 1.5; if set, use 0.5
|
||||
jnz g2_hook_entity_is_frozen
|
||||
fld1 st0 // st = [1, 0.5, speed]
|
||||
faddp st1, st0 // st = [1.5, speed]
|
||||
g2_hook_entity_is_frozen:
|
||||
fmulp st1, st0 // st = [((game_flags & 0x20) ? 0.5 : 1.5) * speed]
|
||||
ret
|
||||
g2_hook_end2:
|
||||
|
||||
|
||||
|
||||
# Tiny Grass Assassins Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x800BC750 0x800BCA58 0x800BCBD0 0x800BCB80 0x800BC9E8 0x800BC9E8 0x800BCB90 0x800BCB58>
|
||||
.data 4
|
||||
b +0x10
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x0016227A 0x0016238A 0x0016232A 0x0016240A 0x0016229A 0x0016242A 0x0016225A>
|
||||
.data 0x00000002
|
||||
.binary EB0E
|
||||
|
||||
|
||||
|
||||
# Bulclaw HP Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80091528 0x80091814 0x8009198C 0x8009193C 0x800917B4 0x800917B4 0x8009194C 0x80091914>
|
||||
.data 8
|
||||
bl +0x024C
|
||||
@@ -78,6 +152,8 @@ g2_hook_end:
|
||||
|
||||
# Control Tower: Delbiter Death SFX Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g3_patch_loc, <VERS 0x80301600 0x803025CC 0x80303A1C 0x803037D0 0x80301F58 0x80301F9C 0x8030398C 0x80302D64>
|
||||
.data g3_patch_loc
|
||||
.deltaof g3_code_start, g3_code_end
|
||||
@@ -101,6 +177,8 @@ g3_code_end:
|
||||
|
||||
# Weapon Attributes Patch (allows attributes to work on minibosses and Olga Flow)
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g4_hook_call1, <VERS 0x800142DC 0x8001430C 0x800146A4 0x800142BC 0x800142F4 0x800142F4 0x800142BC 0x80014334>
|
||||
.label g4_hook_call2, <VERS 0x80015D04 0x80015D34 0x80016174 0x80015CE4 0x80015D1C 0x80015D1C 0x80015CE4 0x80015D5C>
|
||||
.label g4_hook_loc, 0x8000C8C0
|
||||
@@ -129,6 +207,8 @@ g4_hook_end:
|
||||
|
||||
# Ruins Laser Fence SFX Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80166324 0x801666D8 0x80166848 0x8016679C 0x801666E0 0x801666E0 0x80166800 0x80166CC4>
|
||||
.data 8
|
||||
lis r3, 0x4005
|
||||
@@ -142,6 +222,8 @@ g4_hook_end:
|
||||
|
||||
# SFX Cancellation Distance Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x805CB608 0x805D5C08 0x805DD0A8 0x805DCE48 0x805CBF10 0x805D2F30 0x805DC750 0x805D8990>
|
||||
.data 4
|
||||
.float 22500
|
||||
@@ -154,6 +236,8 @@ g4_hook_end:
|
||||
|
||||
# Foie SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x8022E2A8 0x8022EC44 0x8022FB30 0x8022F8E4 0x8022EB64 0x8022EB64 0x8022FC18 0x8022F4B0>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -170,6 +254,8 @@ g4_hook_end:
|
||||
|
||||
# Gifoie SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x802300B8 0x80230A54 0x80231940 0x802316F4 0x80230974 0x80230974 0x80231A28 0x802312C0>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -186,6 +272,8 @@ g4_hook_end:
|
||||
|
||||
# Rafoie SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x802365AC 0x80236F68 0x80237E54 0x80237C08 0x80236E88 0x80236E88 0x80237F3C 0x802377D4>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -214,6 +302,8 @@ g4_hook_end:
|
||||
|
||||
# Barta SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80229B54 0x8022A4F0 0x8022B3E0 0x8022B190 0x8022A410 0x8022A410 0x8022B4C4 0x8022AD5C>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -230,6 +320,8 @@ g4_hook_end:
|
||||
|
||||
# Gibarta SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x8022EAB4 0x8022F450 0x80230340 0x802300F0 0x8022F370 0x8022F370 0x80230424 0x8022FCBC>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -246,6 +338,8 @@ g4_hook_end:
|
||||
|
||||
# Rabarta SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80235DD4 0x80236790 0x8023767C 0x80237430 0x802366B0 0x802366B0 0x80237764 0x80236FFC>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -262,6 +356,8 @@ g4_hook_end:
|
||||
|
||||
# Zonde SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x8023B2C8 0x8023BC84 0x8023CB70 0x8023C924 0x8023BBA4 0x8023BBA4 0x8023CC58 0x8023C4F0>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -278,6 +374,8 @@ g4_hook_end:
|
||||
|
||||
# Gizonde SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80230E08 0x802317C4 0x802326B0 0x80232464 0x802316E4 0x802316E4 0x80232798 0x80232030>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -294,6 +392,8 @@ g4_hook_end:
|
||||
|
||||
# Razonde SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80237998 0x80238354 0x80239240 0x80238FF4 0x80238274 0x80238274 0x80239328 0x80238BC0>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -310,6 +410,8 @@ g4_hook_end:
|
||||
|
||||
# Grants SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x802316FC 0x802320B8 0x80232FA4 0x80232D58 0x80231FD8 0x80231FD8 0x8023308C 0x80232924>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -326,6 +428,8 @@ g4_hook_end:
|
||||
|
||||
# Megid SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x802337A8 0x80234164 0x80235050 0x80234E04 0x80234084 0x80234084 0x80235138 0x802349D0>
|
||||
.data 4
|
||||
li r4, 0xFFFFFF00
|
||||
@@ -342,6 +446,8 @@ g4_hook_end:
|
||||
|
||||
# Anti SFX Pitch Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80229354 0x80229CF0 0x8022ABDC 0x8022A990 0x80229C10 0x80229C10 0x8022ACC4 0x8022A55C>
|
||||
.data 4
|
||||
cmpwi r0, 1
|
||||
@@ -350,26 +456,46 @@ g4_hook_end:
|
||||
|
||||
# Shield DFP/EVP Bug Fix (allows shields to reach true max DFP/EVP values)
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x801185B0 0x801187CC 0x8011885C 0x80118764 0x80118854 0x80118854 0x80118774 0x8011894C>
|
||||
.data 4
|
||||
lbz r0, [r4 + 0x0016]
|
||||
|
||||
.data <VERS 0x801185BC 0x801187D8 0x80118868 0x80118770 0x80118860 0x80118860 0x80118780 0x80118958>
|
||||
.data 4
|
||||
lbz r0, [r4 + 0x0017]
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x00185D8E 0x00185F4E 0x0018600E 0x00185F0E 0x00185F6E 0x00185F2E 0x00185F2E>
|
||||
.data 0x00000001
|
||||
.binary 16
|
||||
.data <VERS 0x00185D97 0x00185F57 0x00186017 0x00185F17 0x00185F77 0x00185F37 0x00185F37>
|
||||
.data 0x00000001
|
||||
.binary 17
|
||||
|
||||
|
||||
|
||||
# VR Spaceship Item Drop Bug Fix (allows items to drop from enemies above a certain Y position)
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x805C996C 0x805D3F6C 0x805DB40C 0x805DB1AC 0x805CA274 0x805D1294 0x805DAAB4 0x805D6CF4>
|
||||
.data 4
|
||||
.float 220
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x00175D75 0x00175E55 0x00175F35 0x00175EC5 0x00175ED5 0x00175EE5 0x00175E95>
|
||||
.data 0x00000002
|
||||
.data 0x435C0000
|
||||
|
||||
|
||||
|
||||
# Invalid Items Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x8011CA90 0x8011CCD4 0x8011CD0C 0x8011CC6C 0x8011CD34 0x8011CD34 0x8011CC7C 0x8011CE54>
|
||||
.data 0x0C
|
||||
mr r3, r0
|
||||
@@ -392,6 +518,8 @@ g4_hook_end:
|
||||
|
||||
# Item Removal Maxed Stats Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g5_hook1_call, <VERS 0x801B9A88 0x801B9EF4 0x801BCF6C 0x801B9FC0 0x801B9E74 0x801B9E74 0x801BA024 0x801BA4E0>
|
||||
.label g5_hook1_ret, <VERS 0x801B9A8C 0x801B9EF8 0x801BCF70 0x801B9FC4 0x801B9E78 0x801B9E78 0x801BA028 0x801BA4E4>
|
||||
.label g5_hook2_call, <VERS 0x8010B970 0x8010BB70 0x8010BC04 0x8010BAF0 0x8010BC14 0x8010BC14 0x8010BB00 0x8010BCF0>
|
||||
@@ -498,6 +626,8 @@ g5_hook4_end:
|
||||
|
||||
# Unit Present Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g6_hook_loc, 0x8000C640
|
||||
.label g6_hook_call, <VERS 0x80118CE0 0x80118EFC 0x80118FD8 0x80118E94 0x80118F84 0x80118F84 0x80118EA4 0x8011907C>
|
||||
.data g6_hook_loc
|
||||
@@ -521,6 +651,8 @@ g6_hook_end:
|
||||
|
||||
# Bank Item Stacking Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g7_hook1_loc, 0x8000C6D0
|
||||
.label g7_hook1_call, <VERS 0x8021D098 0x8021D9FC 0x8021E8E8 0x8021E69C 0x8021D91C 0x8021D91C 0x8021E9D0 0x8021E268>
|
||||
.label g7_hook2_call, <VERS 0x80220528 0x80220EBC 0x80221DA8 0x80221B5C 0x80220DDC 0x80220DDC 0x80221E90 0x80221728>
|
||||
@@ -553,14 +685,27 @@ g7_hooks_end:
|
||||
|
||||
# Dropped Mag Color Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80114378 0x8011458C 0x80114634 0x80114524 0x8011461C 0x8011461C 0x80114534 0x8011470C>
|
||||
.data 4
|
||||
li r0, 0x12
|
||||
|
||||
.versions 4OJB
|
||||
|
||||
.data 0x001759E6
|
||||
.data 1
|
||||
.binary 12
|
||||
.data 0x00180898
|
||||
.data 1
|
||||
.binary 12
|
||||
|
||||
|
||||
|
||||
# Meseta Drop System Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80107478 0x80107654 0x80107708 0x801075D4 0x8010771C 0x8010771C 0x801075E4 0x801077D4>
|
||||
.data 4
|
||||
b +0x0C
|
||||
@@ -573,16 +718,18 @@ g7_hooks_end:
|
||||
|
||||
# Present Color Bug Fix
|
||||
|
||||
.only_versions 3OJ2 3OE0 3OE1
|
||||
.versions 3OJ2 3OE0 3OE1
|
||||
|
||||
.data <VERS 0x80101C14 0x80101EB8 0x80101EB8>
|
||||
.data 4
|
||||
nop
|
||||
.all_versions
|
||||
|
||||
|
||||
|
||||
# Offline Quests Drop Table Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80104B48 0x80104D24 0x80104DE0 0x80104CA4 0x80104DEC 0x80104DEC 0x80104CB4 0x80104EA4>
|
||||
.data 4
|
||||
beq +0x0C
|
||||
@@ -591,6 +738,8 @@ g7_hooks_end:
|
||||
|
||||
# Mag Revival Priority Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g8_hook_loc, 0x8000C8A0
|
||||
.label g8_hook_call, <VERS 0x80112664 0x80112864 0x80112A3C 0x801127F0 0x80112908 0x80112908 0x80112800 0x801129E4>
|
||||
.data g8_hook_loc
|
||||
@@ -613,6 +762,8 @@ g8_hook_end:
|
||||
|
||||
# Mag Revival Challenge & Quest Mode Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x801CA1F4 0x801CA6E0 0x801CB5EC 0x801CA7AC 0x801CA610 0x801CA610 0x801CA810 0x801CACCC>
|
||||
.data 4
|
||||
b +0x10
|
||||
@@ -621,6 +772,8 @@ g8_hook_end:
|
||||
|
||||
# Chat Bubble Window TAB Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80250264 0x80250CB0 0x80251CA4 0x802519A4 0x80250AEC 0x80250AEC 0x80251C68 0x802514B0>
|
||||
.data 4
|
||||
nop
|
||||
@@ -629,6 +782,8 @@ g8_hook_end:
|
||||
|
||||
# Chat Log Window LF/Tab Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80267DDC 0x80268A88 0x80269AE4 0x80269898 0x80268788 0x80268788 0x80269B5C 0x802693A4>
|
||||
.data 4
|
||||
nop
|
||||
@@ -637,6 +792,8 @@ g8_hook_end:
|
||||
|
||||
# Dark/Hell Special GFX Bug Fix (makes Dark/Hell display graphic on success like in PSO BB)
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g9_hook_loc, 0x8000E1E0
|
||||
.label g9_hook_call1, <VERS 0x80355984 0x80356D88 0x803582E4 0x80358098 0x80356838 0x8035687C 0x80358464 0x80357858>
|
||||
.label g9_hook_call2, <VERS 0x80355A04 0x80356E08 0x80358364 0x80358118 0x803568B8 0x803568FC 0x803584E4 0x803578D8>
|
||||
@@ -675,14 +832,24 @@ g9_hook_end:
|
||||
|
||||
# Gol Dragon Camera Bug Fix (makes the camera after Gol Dragon display "normally")
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x802FB99C 0x802FC968 0x802FDE60 0x802FDB6C 0x802FC2F4 0x802FC338 0x802FDD28 0x802FD100>
|
||||
.data 4
|
||||
cmpwi r3, 1
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x000A8AE1 0x000A8C51 0x000A8BD1 0x000A89C1 0x000A8961 0x000A89E1 0x000A8921>
|
||||
.data 0x00000002
|
||||
.binary 01
|
||||
|
||||
|
||||
|
||||
# Box/Fence Fadeout Bug Fix (stops boxes and other environmental objects fading in and out as you approach)
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80189A54 0x80189E2C 0x80189F90 0x80189EF0 0x80189E20 0x80189E20 0x80189F54 0x8018A418>
|
||||
.data 4
|
||||
nop
|
||||
@@ -691,30 +858,62 @@ g9_hook_end:
|
||||
.data 4
|
||||
nop
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x001D229B 0x001D244B 0x001D295B 0x001D241B 0x001D26AB 0x001D243B 0x001D26DB>
|
||||
.data 2
|
||||
nop
|
||||
nop
|
||||
|
||||
.data <VERS 0x001DF7C4 0x001DF924 0x001DFD94 0x001DF964 0x001DFB04 0x001DF984 0x001DFA74>
|
||||
.data 6
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
|
||||
|
||||
# TP Bar Color Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x8026DA74 0x8026E738 0x8026F794 0x8026F548 0x8026E2D4 0x8026E2D4 0x8026F6FC 0x8026EF44>
|
||||
.data 4
|
||||
subi r4, r4, 0x5506
|
||||
|
||||
.data <VERS 0x8026DB88 0x8026E84C 0x8026F8A8 0x8026F65C 0x8026E3E8 0x8026E3E8 0x8026F810 0x8026F058>
|
||||
.data 4
|
||||
subi r3, r3, 0x5506
|
||||
|
||||
.data <VERS 0x8026DC10 0x8026E8D4 0x8026F930 0x8026F6E4 0x8026E470 0x8026E470 0x8026F898 0x8026F0E0>
|
||||
.data 4
|
||||
subi r4, r3, 0x5506
|
||||
|
||||
.data <VERS 0x804CBB40 0x804CF290 0x804D17E0 0x804D1580 0x804CC310 0x804CC7F0 0x804D0E58 0x804D1248>
|
||||
.data 4
|
||||
.data 0xFF0074EE
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x002779CE 0x00277C7E 0x0027808E 0x00277DAE 0x00277ECE 0x00277DCE 0x00277F9E>
|
||||
.data 0x00000004
|
||||
.data 0xFF00AAFA
|
||||
.data <VERS 0x002779DE 0x00277C8E 0x0027809E 0x00277DBE 0x00277EDE 0x00277DDE 0x00277FAE>
|
||||
.data 0x00000004
|
||||
.data 0xFF00AAFA
|
||||
.data <VERS 0x00277A24 0x00277CD4 0x002780E4 0x00277E04 0x00277F24 0x00277E24 0x00277FF4>
|
||||
.data 0x00000004
|
||||
.data 0xFF00AAFA
|
||||
.data <VERS 0x0054543C 0x00545ACC 0x0054D5B4 0x0054AA34 0x0054A2D4 0x0054AA34 0x0054ADD4>
|
||||
.data 0x00000004
|
||||
.data 0xFF0074EE
|
||||
|
||||
|
||||
|
||||
# Devil's and Demon's Special Damage Display Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x8001306C 0x8001309C 0x80013364 0x8001304C 0x80013084 0x80013084 0x8001304C 0x800130C4>
|
||||
.data 4
|
||||
b -0x0340
|
||||
@@ -723,6 +922,8 @@ g9_hook_end:
|
||||
|
||||
# Christmas Trees Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g10_hook_loc, 0x8000B5C8
|
||||
.label g10_hook_call, <VERS 0x80183E94 0x8018425C 0x801843C0 0x80184320 0x80184250 0x80184250 0x80184384 0x80184848>
|
||||
.label g10_hook_ret, <VERS 0x80183E98 0x80184260 0x801843C4 0x80184324 0x80184254 0x80184254 0x80184388 0x8018484C>
|
||||
@@ -750,15 +951,25 @@ g10_hook_end:
|
||||
|
||||
# Rain Drops Color Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x804B3738 0x804B6E58 0x804B92F8 0x804B90B8 0x804B3EF0 0x804B43D0 0x804B8990 0x804B8E10>
|
||||
.data 8
|
||||
.data 0x70808080
|
||||
.data 0x60707070
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x0054D670 0x0054DD00 0x005557E8 0x00552C68 0x00552508 0x00552C68 0x00553008>
|
||||
.data 0x00000008
|
||||
.binary 7080808060707070
|
||||
|
||||
|
||||
|
||||
# Reverser Target Lock Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x801C5EA4 0x801C6360 0x801C6604 0x801C642C 0x801C62C0 0x801C62C0 0x801C6490 0x801C694C>
|
||||
.data 4
|
||||
addi r4, r31, 0x02FC
|
||||
@@ -767,11 +978,13 @@ g10_hook_end:
|
||||
|
||||
# Deband/Shifta/Resta Target Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x8022CF84 0x8022D920 0x8022E85C 0x8022E5C0 0x8022D840 0x8022D840 0x8022E8F4 0x8022E18C>
|
||||
.data 4
|
||||
bgt +0x0630
|
||||
|
||||
.only_versions 3OJ2 3OE0 3OE1
|
||||
.versions 3OJ2 3OE0 3OE1
|
||||
.data <VERS 0x8022D278 0x8022DB34 0x8022DB34>
|
||||
.data 4
|
||||
bgt +0x033C
|
||||
@@ -779,12 +992,13 @@ g10_hook_end:
|
||||
.data <VERS 0x8022D36C 0x8022DC28 0x8022DC28>
|
||||
.data 4
|
||||
bgt +0x0248
|
||||
.all_versions
|
||||
|
||||
|
||||
|
||||
# Tech Auto Targeting Bug Fix
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x8022C850 0x8022D1EC 0x8022E128 0x8022DE8C 0x8022D10C 0x8022D10C 0x8022E1C0 0x8022DA58>
|
||||
.data 4
|
||||
nop
|
||||
@@ -817,6 +1031,8 @@ g10_hook_end:
|
||||
|
||||
# Enable Trap Animations
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label g11_hook_loc, 0x8000BBD0
|
||||
.label g11_hook_call, <VERS 0x80170C54 0x80171008 0x80171260 0x801710CC 0x80171010 0x80171010 0x80171130 0x801715F4>
|
||||
.data g11_hook_loc
|
||||
@@ -846,7 +1062,8 @@ g11_hook_end:
|
||||
|
||||
# Belra arm bug fix (this part by fuzziqersoftware)
|
||||
|
||||
.only_versions 3OJ2 3OE0 3OE1
|
||||
.versions 3OJ2 3OE0 3OE1
|
||||
|
||||
.label g12_hook1_call, <VERS 0x80095724 0x800959B0 0x800959B0>
|
||||
.label g12_hook2_call, <VERS 0x80095734 0x800959C0 0x800959C0>
|
||||
.label g12_hook_loc, 0x8000B06C
|
||||
@@ -874,12 +1091,12 @@ g12_hook_end:
|
||||
.address g12_hook2_call
|
||||
bl g12_hook2_start
|
||||
|
||||
.all_versions
|
||||
|
||||
|
||||
|
||||
# Tsumikiri J-Sword special attack + rapid weapon switch bug fix (this part by fuzziqersoftware)
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label tjs_switch_fix_hook_call, <VERS 0x8034CFA8 0x8034E3AC 0x8034F908 0x8034F6BC 0x8034DE5C 0x8034DEA0 0x8034FA88 0x8034EE7C>
|
||||
.label tjs_switch_fix_hook_loc, 0x8000B050
|
||||
.data tjs_switch_fix_hook_loc
|
||||
@@ -905,7 +1122,8 @@ tjs_switch_fix_hook_end:
|
||||
|
||||
# Battle param reload bug fix (this part by fuzziqersoftware)
|
||||
|
||||
.only_versions 3OJ2 3OE0 3OE1
|
||||
.versions 3OJ2 3OE0 3OE1
|
||||
|
||||
.label end_loading_screen, <VERS 0x8001C6D0 0x8001C8F0 0x8001C8F0>
|
||||
.label load_battle_params, <VERS 0x8001DA48 0x8001DC68 0x8001DC68>
|
||||
.label bp_reload_hook_loc, 0x8000E1BC
|
||||
@@ -928,9 +1146,10 @@ bp_reload_hook_end:
|
||||
.data 4
|
||||
.address bp_reload_hook_call
|
||||
bl bp_reload_hook_start
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
|
||||
|
||||
|
||||
.data 0
|
||||
.data 0
|
||||
@@ -1,213 +0,0 @@
|
||||
.meta name="Bug fixes"
|
||||
.meta description="Fixes many minor\ngameplay, sound,\nand graphical bugs"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# Xbox port by fuzziqersoftware
|
||||
|
||||
# This patch is a collection of many smaller patches, most of which are not yet ported.
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
|
||||
|
||||
|
||||
# Tiny Grass Assassins Bug Fix
|
||||
|
||||
.data <VERS 0x0016227A 0x0016238A 0x0016232A 0x0016240A 0x0016229A 0x0016242A 0x0016225A>
|
||||
.data 0x00000002
|
||||
.binary EB0E
|
||||
|
||||
|
||||
|
||||
# Shield DFP/EVP Bug Fix (allows shields to reach true max DFP/EVP values)
|
||||
|
||||
.data <VERS 0x00185D8E 0x00185F4E 0x0018600E 0x00185F0E 0x00185F6E 0x00185F2E 0x00185F2E>
|
||||
.data 0x00000001
|
||||
.binary 16
|
||||
.data <VERS 0x00185D97 0x00185F57 0x00186017 0x00185F17 0x00185F77 0x00185F37 0x00185F37>
|
||||
.data 0x00000001
|
||||
.binary 17
|
||||
|
||||
|
||||
|
||||
# VR Spaceship Item Drop Bug Fix (allows items to drop from enemies above a certain Y position)
|
||||
|
||||
.data <VERS 0x00175D75 0x00175E55 0x00175F35 0x00175EC5 0x00175ED5 0x00175EE5 0x00175E95>
|
||||
.data 0x00000002
|
||||
.data 0x435C0000
|
||||
|
||||
|
||||
|
||||
# Gol Dragon Camera Bug Fix (makes the camera after Gol Dragon display "normally")
|
||||
|
||||
.data <VERS 0x000A8AE1 0x000A8C51 0x000A8BD1 0x000A89C1 0x000A8961 0x000A89E1 0x000A8921>
|
||||
.data 0x00000002
|
||||
.binary 01
|
||||
|
||||
|
||||
|
||||
# Rain Drops Color Bug Fix
|
||||
|
||||
.data <VERS 0x0054D670 0x0054DD00 0x005557E8 0x00552C68 0x00552508 0x00552C68 0x00553008>
|
||||
.data 0x00000008
|
||||
.binary 7080808060707070
|
||||
|
||||
|
||||
|
||||
# TP Bar Color Bug Fix
|
||||
|
||||
.data <VERS 0x002779CE 0x00277C7E 0x0027808E 0x00277DAE 0x00277ECE 0x00277DCE 0x00277F9E>
|
||||
.data 0x00000004
|
||||
.data 0xFF00AAFA
|
||||
.data <VERS 0x002779DE 0x00277C8E 0x0027809E 0x00277DBE 0x00277EDE 0x00277DDE 0x00277FAE>
|
||||
.data 0x00000004
|
||||
.data 0xFF00AAFA
|
||||
.data <VERS 0x00277A24 0x00277CD4 0x002780E4 0x00277E04 0x00277F24 0x00277E24 0x00277FF4>
|
||||
.data 0x00000004
|
||||
.data 0xFF00AAFA
|
||||
.data <VERS 0x0054543C 0x00545ACC 0x0054D5B4 0x0054AA34 0x0054A2D4 0x0054AA34 0x0054ADD4>
|
||||
.data 0x00000004
|
||||
.data 0xFF0074EE
|
||||
|
||||
|
||||
|
||||
# Olga Flow Barta Bug Fix
|
||||
|
||||
.label g1_hook_call, <VERS 0x000970E0 0x000973F0 0x00097460 0x00097140 0x000970E0 0x00097160 0x00096FE0>
|
||||
.label g1_hook_loc, <VERS 0x00097124 0x00097434 0x000974A4 0x00097184 0x00097124 0x000971A4 0x00097024>
|
||||
.data g1_hook_call
|
||||
.data 6
|
||||
.address g1_hook_call
|
||||
mov eax, esi
|
||||
cmp al, 19
|
||||
jmp g1_hook_loc
|
||||
g1_hook_call_end:
|
||||
.data g1_hook_loc
|
||||
.deltaof g1_hook_start, g1_hook_end
|
||||
.address g1_hook_loc
|
||||
g1_hook_start:
|
||||
jne g1_hook_skip_replace_value
|
||||
mov al, 2
|
||||
g1_hook_skip_replace_value:
|
||||
cmp eax, [ebx + 0x440] // Original opcode
|
||||
jmp g1_hook_call_end
|
||||
g1_hook_end:
|
||||
|
||||
|
||||
|
||||
# Morfos Frozen Player Bug Fix
|
||||
|
||||
.label g2_hook_call, <VERS 0x0012E257 0x0012E387 0x0012E4E7 0x0012E537 0x0012E567 0x0012E557 0x0012E5A7>
|
||||
.label g2_hook_loc1, <VERS 0x0012E5F4 0x0012E724 0x0012E884 0x0012E8D4 0x0012E904 0x0012E8F4 0x0012E944>
|
||||
.label g2_hook_loc2, <VERS 0x0012E622 0x0012E752 0x0012E8B2 0x0012E902 0x0012E932 0x0012E922 0x0012E972>
|
||||
.data g2_hook_call
|
||||
.data 6
|
||||
.address g2_hook_call
|
||||
call g2_hook_loc1
|
||||
nop
|
||||
.data g2_hook_loc1
|
||||
.deltaof g2_hook_start1, g2_hook_end1
|
||||
.address g2_hook_loc1
|
||||
g2_hook_start1:
|
||||
fld1 st0 // st = [1.0, speed]
|
||||
fld1 st0 // st = [1.0, 1.0, speed]
|
||||
fadd st0, st1 // st = [2.0, 1.0, speed]
|
||||
fdivp st1, st0 // st = [0.5, speed]
|
||||
jmp g2_hook_loc2
|
||||
g2_hook_end1:
|
||||
|
||||
.data g2_hook_loc2
|
||||
.deltaof g2_hook_start2, g2_hook_end2
|
||||
.address g2_hook_loc2
|
||||
g2_hook_start2:
|
||||
test byte [esi + 0x30], 0x20 // If not set, use 1.5; if set, use 0.5
|
||||
jnz g2_hook_entity_is_frozen
|
||||
fld1 st0 // st = [1, 0.5, speed]
|
||||
faddp st1, st0 // st = [1.5, speed]
|
||||
g2_hook_entity_is_frozen:
|
||||
fmulp st1, st0 // st = [((game_flags & 0x20) ? 0.5 : 1.5) * speed]
|
||||
ret
|
||||
g2_hook_end2:
|
||||
|
||||
|
||||
|
||||
# Dropped Mag Color Bug Fix (only needed on beta version)
|
||||
|
||||
.only_versions 4OJB
|
||||
.data 0x001759E6
|
||||
.data 1
|
||||
.binary 12
|
||||
.data 0x00180898
|
||||
.data 1
|
||||
.binary 12
|
||||
.all_versions
|
||||
|
||||
|
||||
|
||||
# Box/Fence Fadeout Bug Fix
|
||||
|
||||
.data <VERS 0x001D229B 0x001D244B 0x001D295B 0x001D241B 0x001D26AB 0x001D243B 0x001D26DB>
|
||||
.data 2
|
||||
nop
|
||||
nop
|
||||
|
||||
.data <VERS 0x001DF7C4 0x001DF924 0x001DFD94 0x001DF964 0x001DFB04 0x001DF984 0x001DFA74>
|
||||
.data 6
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
|
||||
|
||||
# TODO: Port the rest of the patches in the GC version of BugFixes:
|
||||
|
||||
# Bulclaw HP Bug Fix
|
||||
# Weapon Attributes Patch
|
||||
# Invalid Items Bug Fix
|
||||
# Item Removal Maxed Stats Bug Fix
|
||||
# Unit Present Bug Fix
|
||||
# Bank Item Stacking Bug Fix
|
||||
# Meseta Drop System Bug Fix
|
||||
# Offline Quests Drop Table Bug Fix
|
||||
# Mag Revival Priority Bug Fix
|
||||
# Mag Revival Challenge & Quest Mode Bug Fix
|
||||
# Reverser Target Lock Bug Fix
|
||||
# Deband/Shifta/Resta Target Bug Fix
|
||||
# Tech Auto Targeting Bug Fix
|
||||
# Enable Trap Animations
|
||||
# Tsumikiri J-Sword special attack + rapid weapon switch bug fix
|
||||
|
||||
# Control Tower: Delbiter Death SFX Bug Fix
|
||||
# Ruins Laser Fence SFX Bug Fix
|
||||
# SFX Cancellation Distance Bug Fix
|
||||
# Foie SFX Pitch Bug Fix
|
||||
# Gifoie SFX Pitch Bug Fix
|
||||
# Rafoie SFX Pitch Bug Fix
|
||||
# Barta SFX Pitch Bug Fix
|
||||
# Gibarta SFX Pitch Bug Fix
|
||||
# Rabarta SFX Pitch Bug Fix
|
||||
# Zonde SFX Pitch Bug Fix
|
||||
# Gizonde SFX Pitch Bug Fix
|
||||
# Razonde SFX Pitch Bug Fix
|
||||
# Grants SFX Pitch Bug Fix
|
||||
# Megid SFX Pitch Bug Fix
|
||||
# Anti SFX Pitch Bug Fix
|
||||
# Present Color Bug Fix
|
||||
# Chat Bubble Window TAB Bug Fix
|
||||
# Chat Log Window LF/Tab Bug Fix
|
||||
# Dark/Hell Special GFX Bug Fix
|
||||
# Devil's and Demon's Special Damage Display Bug Fix
|
||||
# Christmas Trees Bug Fix
|
||||
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -0,0 +1,115 @@
|
||||
.meta name="CallProtectedHandler"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
|
||||
|
||||
.versions 3OJT 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
start:
|
||||
stwu [r1 - 0x10], r1
|
||||
mflr r0
|
||||
stw [r1 + 0x14], r0
|
||||
stw [r1 + 0x08], r31
|
||||
stw [r1 + 0x0C], r30
|
||||
|
||||
b get_data_addr
|
||||
resume:
|
||||
mflr r31
|
||||
|
||||
lwz r30, [r31]
|
||||
li r0, 1
|
||||
stw [r30], r0
|
||||
|
||||
addi r3, r31, 0x0C
|
||||
lwz r4, [r31 + 8]
|
||||
lwz r0, [r31 + 4]
|
||||
mtctr r0
|
||||
bctrl
|
||||
|
||||
li r0, 0
|
||||
stw [r30], r0
|
||||
|
||||
lwz r30, [r1 + 0x0C]
|
||||
lwz r31, [r1 + 0x08]
|
||||
lwz r0, [r1 + 0x14]
|
||||
mtlr r0
|
||||
addi r1, r1, 0x10
|
||||
blr
|
||||
|
||||
get_data_addr:
|
||||
bl resume
|
||||
# allow_local_client_commands
|
||||
.data <VERS 0x8065F458 0x805C4D58 0x805CF320 0x805D67A0 0x805D6540 0x805C5650 0x805CC630 0x805D5E50 0x805D2090>
|
||||
# RcvPsoData2
|
||||
.data <VERS 0x80236F24 0x801E3B38 0x801E40BC 0x801E4290 0x801E4008 0x801E3F9C 0x801E3F9C 0x801E405C 0x801E4698>
|
||||
|
||||
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
start:
|
||||
jmp get_data_addr
|
||||
resume:
|
||||
xchg ebx, [esp]
|
||||
|
||||
mov edx, [ebx]
|
||||
mov dword [edx], 1
|
||||
|
||||
mov edx, [ebx + 4]
|
||||
lea ecx, [ebx + 0x0C]
|
||||
mov eax, [ebx + 8]
|
||||
call edx
|
||||
|
||||
mov edx, [ebx]
|
||||
mov dword [edx], 0
|
||||
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
get_data_addr:
|
||||
call resume
|
||||
.data <VERS 0x0071E8C8 0x0071EF28 0x00726A68 0x00723F68 0x007237E8 0x00723F68 0x007242E8>
|
||||
.data <VERS 0x002DBBA0 0x002DC720 0x002DDFE0 0x002DDB00 0x002DE000 0x002DDB30 0x002DE030>
|
||||
|
||||
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
start:
|
||||
jmp get_data_addr
|
||||
resume:
|
||||
xchg ebx, [esp]
|
||||
|
||||
mov edx, [ebx]
|
||||
mov dword [edx], 1
|
||||
|
||||
mov edx, [ebx + 4]
|
||||
push dword [ebx + 8]
|
||||
lea ecx, [ebx + 0x0C]
|
||||
push ecx
|
||||
call edx # RcvPsoData2(data, size)
|
||||
add esp, 8
|
||||
|
||||
mov edx, [ebx]
|
||||
mov dword [edx], 0
|
||||
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
get_data_addr:
|
||||
call resume
|
||||
|
||||
.data <VERS 0x00AAC870 0x00AAECF0> # should_allow_protected_commands
|
||||
.data <VERS 0x008015D0 0x00800860> # RcvPsoData2[std](void* data @ [esp + 4], uint32_t size @ [esp + 8])
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
|
||||
size:
|
||||
.data 0x00000000
|
||||
data:
|
||||
@@ -1,50 +0,0 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="CallProtectedHandler"
|
||||
.meta description=""
|
||||
|
||||
.versions 3OJT 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
stwu [r1 - 0x10], r1
|
||||
mflr r0
|
||||
stw [r1 + 0x14], r0
|
||||
stw [r1 + 0x08], r31
|
||||
stw [r1 + 0x0C], r30
|
||||
|
||||
b get_data_addr
|
||||
resume:
|
||||
mflr r31
|
||||
|
||||
lwz r30, [r31]
|
||||
li r0, 1
|
||||
stw [r30], r0
|
||||
|
||||
addi r3, r31, 0x0C
|
||||
lwz r4, [r31 + 8]
|
||||
lwz r0, [r31 + 4]
|
||||
mtctr r0
|
||||
bctrl
|
||||
|
||||
li r0, 0
|
||||
stw [r30], r0
|
||||
|
||||
lwz r30, [r1 + 0x0C]
|
||||
lwz r31, [r1 + 0x08]
|
||||
lwz r0, [r1 + 0x14]
|
||||
mtlr r0
|
||||
addi r1, r1, 0x10
|
||||
blr
|
||||
|
||||
get_data_addr:
|
||||
bl resume
|
||||
# allow_local_client_commands
|
||||
.data <VERS 0x8065F458 0x805C4D58 0x805CF320 0x805D67A0 0x805D6540 0x805C5650 0x805CC630 0x805D5E50 0x805D2090>
|
||||
# RcvPsoData2
|
||||
.data <VERS 0x80236F24 0x801E3B38 0x801E40BC 0x801E4290 0x801E4008 0x801E3F9C 0x801E3F9C 0x801E405C 0x801E4698>
|
||||
|
||||
size:
|
||||
.data 0x00000000
|
||||
data:
|
||||
@@ -1,36 +0,0 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="CallProtectedHandler"
|
||||
.meta description=""
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
jmp get_data_addr
|
||||
resume:
|
||||
xchg ebx, [esp]
|
||||
|
||||
mov edx, [ebx]
|
||||
mov dword [edx], 1
|
||||
|
||||
mov edx, [ebx + 4]
|
||||
lea ecx, [ebx + 0x0C]
|
||||
mov eax, [ebx + 8]
|
||||
call edx
|
||||
|
||||
mov edx, [ebx]
|
||||
mov dword [edx], 0
|
||||
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
get_data_addr:
|
||||
call resume
|
||||
.data <VERS 0x0071E8C8 0x0071EF28 0x00726A68 0x00723F68 0x007237E8 0x00723F68 0x007242E8>
|
||||
.data <VERS 0x002DBBA0 0x002DC720 0x002DDFE0 0x002DDB00 0x002DE000 0x002DDB30 0x002DE030>
|
||||
|
||||
size:
|
||||
.data 0x00000000
|
||||
data:
|
||||
@@ -1,38 +0,0 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="CallProtectedHandler"
|
||||
.meta description=""
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
jmp get_data_addr
|
||||
resume:
|
||||
xchg ebx, [esp]
|
||||
|
||||
mov edx, [ebx]
|
||||
mov dword [edx], 1
|
||||
|
||||
mov edx, [ebx + 4]
|
||||
push dword [ebx + 8]
|
||||
lea ecx, [ebx + 0x0C]
|
||||
push ecx
|
||||
call edx # RcvPsoData2(data, size)
|
||||
add esp, 8
|
||||
|
||||
mov edx, [ebx]
|
||||
mov dword [edx], 0
|
||||
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
get_data_addr:
|
||||
call resume
|
||||
|
||||
.data <VERS 0x00AAC870 0x00AAECF0> # should_allow_protected_commands
|
||||
.data <VERS 0x008015D0 0x00800860> # RcvPsoData2[std](void* data @ [esp + 4], uint32_t size @ [esp + 8])
|
||||
size:
|
||||
.data 0x00000000
|
||||
data:
|
||||
+5
-3
@@ -1,16 +1,18 @@
|
||||
.meta name="Chat"
|
||||
.meta description="Enables extended\nWord Select and\nstops the Log\nWindow from\nscrolling with L+R"
|
||||
# Original codes by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.meta visibility="all"
|
||||
.meta name="Chat"
|
||||
.meta description="Enables extended\nWord Select and\nstops the Log\nWindow from\nscrolling with L+R"
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0 3SJT 3SJ0 3SE0 3SP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
# Extended Word Select Menu (PSO PCv2 Style)
|
||||
.data <VERS 0x8034445C 0x803457AC 0x80346CCC 0x80346A80 0x8034525C 0x803452A0 0x80346E4C 0x8034627C 0x801D9B30 0x801C7CFC 0x801C7D88 0x801C83FC>
|
||||
+5
-3
@@ -1,16 +1,18 @@
|
||||
.meta name="Common bank"
|
||||
.meta description="Hold L and open\nthe bank to use a\ncommon bank stored\nin temp character\n3's data"
|
||||
# Original code by Ralf @ GC-Forever ("Common Bank (Hold L And Open Bank)")
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.meta visibility="all"
|
||||
.meta name="Common bank"
|
||||
.meta description="Hold L and open\nthe bank to use a\ncommon bank stored\nin temp character\n3's data"
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.data 0x8000BAB4
|
||||
.deltaof hook1, hooks_end
|
||||
+56
-4
@@ -1,16 +1,21 @@
|
||||
.meta name="DC targets"
|
||||
.meta description="Changes the target\nreticle colors to\nthose used on the\nDreamcast"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
.meta visibility="all"
|
||||
.meta name="DC targets"
|
||||
.meta description="Changes the target\nreticle colors to\nthose used on the\nDreamcast"
|
||||
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x802AB3FC 0x802AC2A4 0x802AD3D0 0x802AD184 0x802ABDB8 0x802ABDFC 0x802AD338 0x802ACACC>
|
||||
.data 0x00000004
|
||||
@@ -54,5 +59,52 @@ start:
|
||||
.float 0.1
|
||||
.float 0.1
|
||||
|
||||
|
||||
|
||||
.versions 4OED 4OEU 4OJB 4OJD 4OJU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x0025BD09 0x0025BE29 0x0025B889 0x0025BC39 0x0025BFB9 0x0025BD29 0x0025BE59>
|
||||
.data 0x00000004
|
||||
.data 0x00FF0000
|
||||
|
||||
.data <VERS 0x0025BD17 0x0025BE37 0x0025B897 0x0025BC47 0x0025BFC7 0x0025BD37 0x0025BE67>
|
||||
.data 0x00000004
|
||||
.data 0x000000FF
|
||||
|
||||
.data <VERS 0x0025BD25 0x0025BE45 0x0025B8A5 0x0025BC55 0x0025BFD5 0x0025BD45 0x0025BE75>
|
||||
.data 0x00000004
|
||||
.data 0x00FFFF00
|
||||
|
||||
.data <VERS 0x005427A0 0x00542040 0x0053D788 0x0053DE00 0x00545320 0x005427A0 0x00542B40>
|
||||
.data 0x00000060
|
||||
.data 0x3F800000
|
||||
.data 0x3F800000
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
.data 0x3F800000
|
||||
.data 0x3F800000
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
.data 0x3F800000
|
||||
.data 0x3F800000
|
||||
.data 0x3F800000
|
||||
.data 0x00000000
|
||||
.data 0x3F800000
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
.data 0x3F800000
|
||||
.data 0x3F800000
|
||||
.data 0x3ECCCCCD
|
||||
.data 0x3DCCCCCD
|
||||
.data 0x3DCCCCCD
|
||||
.data 0x3F800000
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,52 +0,0 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="CreateObject"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
mflr r0
|
||||
b get_data
|
||||
get_data_ret:
|
||||
mflr r3
|
||||
mtlr r0
|
||||
lwz r0, [r3]
|
||||
mtctr r0
|
||||
addi r3, r3, 4
|
||||
bctr
|
||||
|
||||
get_data:
|
||||
bl get_data_ret
|
||||
.data 0x8020C158 # construct_dat_object_from_args
|
||||
base_type_high:
|
||||
.data 0xFFFF0000 # base_type, set_flags
|
||||
floor_low:
|
||||
.data 0x0000FFFF # index, floor
|
||||
.data 0x00000000 # entity_id, group
|
||||
.data 0x00000000 # room, unknown_a3
|
||||
pos_x:
|
||||
.float 0.0 # pos.x
|
||||
pos_y:
|
||||
.float 0.0 # pos.y
|
||||
pos_z:
|
||||
.float 0.0 # pos.z
|
||||
angle_x:
|
||||
.data 0x00000000 # angle.x
|
||||
angle_y:
|
||||
.data 0x00000000 # angle.y
|
||||
angle_z:
|
||||
.data 0x00000000 # angle.z
|
||||
param1:
|
||||
.float 0.0 # param1
|
||||
param2:
|
||||
.float 0.0 # param2
|
||||
param3:
|
||||
.float 0.0 # param3
|
||||
param4:
|
||||
.data 0 # param4
|
||||
param5:
|
||||
.data 0 # param5
|
||||
param6:
|
||||
.data 0 # param6
|
||||
.data 0 # unused_obj_ptr
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="CreateObject"
|
||||
.meta description=""
|
||||
|
||||
.versions 3OE1 3SE0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
@@ -18,7 +19,7 @@ get_data_ret:
|
||||
|
||||
get_data:
|
||||
bl get_data_ret
|
||||
.data 0x80056D6C # construct_dat_object_from_args
|
||||
.data <VERS 0x8020C158 0x80056D6C> # construct_dat_object_from_args
|
||||
base_type_high:
|
||||
.data 0xFFFF0000 # base_type, set_flags
|
||||
floor_low:
|
||||
+3
-2
@@ -1,12 +1,13 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="Player flags"
|
||||
.meta description=""
|
||||
|
||||
.versions 3OE1
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.label check_controller_button, 0x801A6C68 # [std](ControllerState* st, uint32_t flags) -> bool
|
||||
.label TFogCtrl_change_fog, 0x800FB10C # [std](TFogCtrl* this, uint32_t fog_num, uint32_t instant_transition) -> void
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="MovementDebug"
|
||||
.meta description=""
|
||||
.meta show_return_value
|
||||
|
||||
.versions 3OE1
|
||||
|
||||
# Usage examples:
|
||||
# Read movement data 09 fparam1:
|
||||
# $patch MovementDebug e=0x09 f=1 r=1
|
||||
+3
-2
@@ -1,12 +1,13 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="Player flags"
|
||||
.meta description=""
|
||||
|
||||
.versions 3OE1
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.label TObjPlayer_for_client_id, 0x801BA59C # [std](uint32_t client_id)
|
||||
.label render_debug_printf, 0x803D4E3C # [std](uint32_t coords, const char* fmt, ...);
|
||||
+61
-5
@@ -1,17 +1,69 @@
|
||||
.meta name="Decoction"
|
||||
.meta description="Makes the Decoction\nitem reset your\nmaterial usage"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# Xbox port by fuzziqersoftware
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
.meta visibility="all"
|
||||
.meta name="Decoction"
|
||||
.meta description="Makes the Decoction\nitem reset your\nmaterial usage"
|
||||
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x80350740 0x80351B44 0x803530A0 0x80352E54 0x803515F4 0x80351638 0x80353220 0x80352614>
|
||||
.data 0x00000098
|
||||
.address <VERS 0x80350740 0x80351B44 0x803530A0 0x80352E54 0x803515F4 0x80351638 0x80353220 0x80352614>
|
||||
lbz r0, [r3 + 0xEE]
|
||||
cmplwi r0, 11
|
||||
bne +0x144
|
||||
lwz r31, [r3 + 0xF0]
|
||||
li r0, 0
|
||||
nop
|
||||
li r4, 0x0374
|
||||
li r5, 0x0D38
|
||||
bl +0x58
|
||||
li r5, 0x0D3A
|
||||
bl +0x50
|
||||
li r5, 0x0D3C
|
||||
bl +0x48
|
||||
li r5, 0x0D40
|
||||
bl +0x40
|
||||
li r5, 0x0D44
|
||||
bl +0x38
|
||||
mr r3, r31
|
||||
.data <VERS 0x4BE656A1 0x4BE646F1 0x4BE654CD 0x4BE634AD 0x4BE64BD9 0x4BE64B95 0x4BE63145 0x4BE6420D>
|
||||
lhz r0, [r31 + 0x032C]
|
||||
lhz r3, [r31 + 0x02B8]
|
||||
cmpl r0, r3
|
||||
ble +0x08
|
||||
sth [r31 + 0x032C], r3
|
||||
lhz r0, [r31 + 0x032E]
|
||||
lhz r3, [r31 + 0x02BA]
|
||||
cmpl r0, r3
|
||||
ble +0x08
|
||||
sth [r31 + 0x032E], r3
|
||||
b +0xD8
|
||||
lbzx r6, [r31 + r4]
|
||||
lhzx r7, [r31 + r5]
|
||||
rlwinm r6, r6, 1, 0, 30
|
||||
subf r7, r6, r7
|
||||
sthx [r31 + r5], r7
|
||||
stbx [r31 + r4], r0
|
||||
addi r4, r4, 0x0001
|
||||
blr
|
||||
|
||||
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x00184160 0x00184350 0x00184400 0x00184340 0x00184310 0x00184360 0x001842D0>
|
||||
.deltaof code_start, code_end
|
||||
.address <VERS 0x00184160 0x00184350 0x00184400 0x00184340 0x00184310 0x00184360 0x001842D0>
|
||||
@@ -63,7 +115,11 @@ next_stat:
|
||||
pop esi
|
||||
skip_all:
|
||||
ret
|
||||
|
||||
code_end:
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,58 +0,0 @@
|
||||
.meta name="Decoction"
|
||||
.meta description="Makes the Decoction\nitem reset your\nmaterial usage"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
|
||||
.data <VERS 0x80350740 0x80351B44 0x803530A0 0x80352E54 0x803515F4 0x80351638 0x80353220 0x80352614>
|
||||
.data 0x00000098
|
||||
.address <VERS 0x80350740 0x80351B44 0x803530A0 0x80352E54 0x803515F4 0x80351638 0x80353220 0x80352614>
|
||||
lbz r0, [r3 + 0xEE]
|
||||
cmplwi r0, 11
|
||||
bne +0x144
|
||||
lwz r31, [r3 + 0xF0]
|
||||
li r0, 0
|
||||
nop
|
||||
li r4, 0x0374
|
||||
li r5, 0x0D38
|
||||
bl +0x58
|
||||
li r5, 0x0D3A
|
||||
bl +0x50
|
||||
li r5, 0x0D3C
|
||||
bl +0x48
|
||||
li r5, 0x0D40
|
||||
bl +0x40
|
||||
li r5, 0x0D44
|
||||
bl +0x38
|
||||
mr r3, r31
|
||||
.data <VERS 0x4BE656A1 0x4BE646F1 0x4BE654CD 0x4BE634AD 0x4BE64BD9 0x4BE64B95 0x4BE63145 0x4BE6420D>
|
||||
lhz r0, [r31 + 0x032C]
|
||||
lhz r3, [r31 + 0x02B8]
|
||||
cmpl r0, r3
|
||||
ble +0x08
|
||||
sth [r31 + 0x032C], r3
|
||||
lhz r0, [r31 + 0x032E]
|
||||
lhz r3, [r31 + 0x02BA]
|
||||
cmpl r0, r3
|
||||
ble +0x08
|
||||
sth [r31 + 0x032E], r3
|
||||
b +0xD8
|
||||
lbzx r6, [r31 + r4]
|
||||
lhzx r7, [r31 + r5]
|
||||
rlwinm r6, r6, 1, 0, 30
|
||||
subf r7, r6, r7
|
||||
sthx [r31 + r5], r7
|
||||
stbx [r31 + r4], r0
|
||||
addi r4, r4, 0x0001
|
||||
blr
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -0,0 +1,47 @@
|
||||
.meta visibility="all"
|
||||
.meta name="Disable idle DC"
|
||||
.meta description="Disables the idle\ndisconnect timeout"
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
.versions 1OJ3 1OJ4 1OJF 1OEF 1OPF 2OJ4 2OJ5 2OJF 2OEF 2OPF
|
||||
.align 4
|
||||
.data <VERS 0x8C01A454 0x8C01A6D0 0x8C01A414 0x8C01A6C8 0x8C01A6DC 0x8C01B6A4 0x8C01B6A4 0x8C01B684 0x8C01B6A4 0x8C01B6A8>
|
||||
.data 0x00000002
|
||||
mov r0, 0
|
||||
.align 4
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0 3SJT 3SJ0 3SE0 3SP0
|
||||
.data <VERS 0x80134D3C 0x80134FA0 0x80135108 0x80135040 0x80134FE0 0x80134FE0 0x80135050 0x801352D0 0x80092C78 0x8009242C 0x80092380 0x80092588>
|
||||
.data 0x00000004
|
||||
li r3, 0
|
||||
|
||||
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
.data <VERS 0x002C0AEE 0x002C167E 0x002C2BEE 0x002C272E 0x002C291E 0x002C275E 0x002C2A7E>
|
||||
.data 0x00000004
|
||||
xor ecx, ecx
|
||||
jmp +3
|
||||
|
||||
|
||||
|
||||
.versions 59NJ 59NL
|
||||
.data <VERS 0x007A1233 0x007A03F7>
|
||||
.data 0x00000005
|
||||
mov eax, 0
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,19 +0,0 @@
|
||||
.meta name="Disable idle DC"
|
||||
.meta description="Disables the idle\ndisconnect timeout"
|
||||
|
||||
.versions 1OJ3 1OJ4 1OJF 1OEF 1OPF 2OJ4 2OJ5 2OJF 2OEF 2OPF
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksDC
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C01A454 0x8C01A6D0 0x8C01A414 0x8C01A6C8 0x8C01A6DC 0x8C01B6A4 0x8C01B6A4 0x8C01B684 0x8C01B6A4 0x8C01B6A8>
|
||||
.data 0x00000002
|
||||
mov r0, 0
|
||||
|
||||
.align 4
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,17 +0,0 @@
|
||||
.meta name="Disable idle DC"
|
||||
.meta description="Disables the idle\ndisconnect timeout"
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0 3SJT 3SJ0 3SE0 3SP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
|
||||
.data <VERS 0x80134D3C 0x80134FA0 0x80135108 0x80135040 0x80134FE0 0x80134FE0 0x80135050 0x801352D0 0x80092C78 0x8009242C 0x80092380 0x80092588>
|
||||
.data 0x00000004
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,18 +0,0 @@
|
||||
.meta name="Disable idle DC"
|
||||
.meta description="Disables the idle\ndisconnect timeout"
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
|
||||
.data <VERS 0x002C0AEE 0x002C167E 0x002C2BEE 0x002C272E 0x002C291E 0x002C275E 0x002C2A7E>
|
||||
.data 0x00000004
|
||||
xor ecx, ecx
|
||||
jmp +3
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,17 +0,0 @@
|
||||
.meta name="Disable idle DC"
|
||||
.meta description="Disables the idle\ndisconnect timeout"
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksBB
|
||||
|
||||
.data <VERS 0x007A1233 0x007A03F7>
|
||||
.data 0x00000005
|
||||
mov eax, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -0,0 +1,367 @@
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# Xbox port by fuzziqersoftware
|
||||
|
||||
# BB notes:
|
||||
# Currently beta quality, map objects that fade like boxes, and Pioneer's background billboards and elevators still
|
||||
# have regular draw distance.
|
||||
# TODO: 90% of stuff is included, bring home the last 10%.
|
||||
|
||||
.meta visibility="all"
|
||||
.meta name="Draw Distance"
|
||||
.meta description="Extends the draw\ndistance of many\nobjects"
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
start:
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.data 0x8000DFA0
|
||||
.deltaof hook_start, hook_end
|
||||
.address 0x8000DFA0
|
||||
hook_start:
|
||||
hook1:
|
||||
lfs f30, [r2 - <VERS 0x3E08 0x3E08 0x3E08 0x3E08 0x3E00 0x3E00 0x3E00 0x3E00>]
|
||||
fmuls f30, f30, f1
|
||||
blr
|
||||
hook2:
|
||||
lfs f2, [r2 - <VERS 0x3E08 0x3E08 0x3E08 0x3E08 0x3E00 0x3E00 0x3E00 0x3E00>]
|
||||
lfs f0, [r30 + 0x001C]
|
||||
fmuls f0, f0, f2
|
||||
blr
|
||||
hook3:
|
||||
lfs f28, [r2 - <VERS 0x3E08 0x3E08 0x3E08 0x3E08 0x3E00 0x3E00 0x3E00 0x3E00>]
|
||||
fmuls f28, f28, f2
|
||||
blr
|
||||
hook4:
|
||||
lfs f0, [r2 - <VERS 0x3E08 0x3E08 0x3E08 0x3E08 0x3E00 0x3E00 0x3E00 0x3E00>]
|
||||
lfs f1, [r3 + 0x000C]
|
||||
fmuls f0, f0, f1
|
||||
stfs [r3 + 0x000C], f0
|
||||
lis r3, <VERS 0x804C 0x804C 0x804D 0x804D 0x804C 0x804C 0x804D 0x804D>
|
||||
blr
|
||||
hook_end:
|
||||
|
||||
.data <VERS 0x801008E8 0x80100AD0 0x80100B74 0x80100A50 0x80100B8C 0x80100B8C 0x80100A60 0x80100C50>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x801008E8 0x80100AD0 0x80100B74 0x80100A50 0x80100B8C 0x80100B8C 0x80100A60 0x80100C50>
|
||||
bl hook1
|
||||
|
||||
.data <VERS 0x8015671C 0x80156AD0 0x80156C34 0x80156B94 0x80156AD8 0x80156AD8 0x80156BF8 0x801570BC>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x8015671C 0x80156AD0 0x80156C34 0x80156B94 0x80156AD8 0x80156AD8 0x80156BF8 0x801570BC>
|
||||
bl hook2
|
||||
|
||||
.data <VERS 0x801A1C64 0x801A203C 0x801A21A0 0x801A2100 0x801A2040 0x801A2040 0x801A2164 0x801A2628>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x801A1C64 0x801A203C 0x801A21A0 0x801A2100 0x801A2040 0x801A2040 0x801A2164 0x801A2628>
|
||||
bl hook3
|
||||
|
||||
.data <VERS 0x801A1E64 0x801A223C 0x801A23A0 0x801A2300 0x801A2240 0x801A2240 0x801A2364 0x801A2828>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x801A1E64 0x801A223C 0x801A23A0 0x801A2300 0x801A2240 0x801A2240 0x801A2364 0x801A2828>
|
||||
bl hook1
|
||||
|
||||
.data <VERS 0x80205044 0x802058B8 0x80206640 0x802063F4 0x80205840 0x80205840 0x80206728 0x80206124>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x80205044 0x802058B8 0x80206640 0x802063F4 0x80205840 0x80205840 0x80206728 0x80206124>
|
||||
bl hook4
|
||||
|
||||
.data <VERS 0x802057E8 0x8020605C 0x80206DE4 0x80206B98 0x80205FE4 0x80205FE4 0x80206ECC 0x802068C8>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x802057E8 0x8020605C 0x80206DE4 0x80206B98 0x80205FE4 0x80205FE4 0x80206ECC 0x802068C8>
|
||||
bl hook4
|
||||
|
||||
.data <VERS 0x805C83A8 0x805D29A8 0x805D9E48 0x805D9BE8 0x805C8CB0 0x805CFCD0 0x805D94F0 0x805D5730>
|
||||
.data 0x00000004
|
||||
.float 90000
|
||||
|
||||
.data <VERS 0x805C9254 0x805D3854 0x805DACF4 0x805DAA94 0x805C9B5C 0x805D0B7C 0x805DA39C 0x805D65DC>
|
||||
.data 0x00000004
|
||||
.float 62500
|
||||
|
||||
.data <VERS 0x805C987C 0x805D3E7C 0x805DB31C 0x805DB0BC 0x805CA184 0x805D11A4 0x805DA9C4 0x805D6C04>
|
||||
.data 0x00000004
|
||||
.float 640000
|
||||
|
||||
.data <VERS 0x805CA708 0x805D4D08 0x805DC1A8 0x805DBF48 0x805CB010 0x805D2030 0x805DB850 0x805D7A90>
|
||||
.data 0x00000004
|
||||
.float 90000
|
||||
|
||||
.data <VERS 0x805CAC98 0x805D5298 0x805DC738 0x805DC4D8 0x805CB5A0 0x805D25C0 0x805DBDE0 0x805D8020>
|
||||
.data 0x00000004
|
||||
.float 1400
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
|
||||
|
||||
.versions 4OED 4OEU 4OJB 4OJD 4OJU 4OPD 4OPU
|
||||
|
||||
start:
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.data <VERS 0x001737C2 0x001737D2 0x00173692 0x00173782 0x00173862 0x001737E2 0x00173792> # From 3OE1:80100B8C
|
||||
.deltaof p1_1s, p1_1e
|
||||
.address <VERS 0x001737C2 0x001737D2 0x00173692 0x00173782 0x00173862 0x001737E2 0x00173792> # From 3OE1:80100B8C
|
||||
p1_1s:
|
||||
call p1_2s
|
||||
nop
|
||||
p1_1e:
|
||||
.data <VERS 0x00173A42 0x00173A52 0x00173912 0x00173A02 0x00173AE2 0x00173A62 0x00173A12>
|
||||
.deltaof p1_2s, p1_2e
|
||||
.address <VERS 0x00173A42 0x00173A52 0x00173912 0x00173A02 0x00173AE2 0x00173A62 0x00173A12>
|
||||
p1_2s:
|
||||
fld st0, dword [esp + 0x1C]
|
||||
fadd st0, st0
|
||||
fchs st0
|
||||
ret
|
||||
p1_2e:
|
||||
|
||||
.data <VERS 0x001A3DEF 0x001A3EEF 0x001A3BBF 0x001A3DBF 0x001A3FDF 0x001A3E0F 0x001A3ECF> # From 3OE1:80156AD8
|
||||
.deltaof p2_1s, p2_1e
|
||||
.address <VERS 0x001A3DEF 0x001A3EEF 0x001A3BBF 0x001A3DBF 0x001A3FDF 0x001A3E0F 0x001A3ECF> # From 3OE1:80156AD8
|
||||
p2_1s:
|
||||
call p2_2s
|
||||
p2_1e:
|
||||
.data <VERS 0x001A3E38 0x001A3F38 0x001A3C08 0x001A3E08 0x001A4028 0x001A3E58 0x001A3F18>
|
||||
.deltaof p2_2s, p2_2e
|
||||
.address <VERS 0x001A3E38 0x001A3F38 0x001A3C08 0x001A3E08 0x001A4028 0x001A3E58 0x001A3F18>
|
||||
p2_2s:
|
||||
fld st0, dword [ecx + 0x1C]
|
||||
fadd st0, st0
|
||||
fld st0, st1
|
||||
ret
|
||||
p2_2e:
|
||||
|
||||
.data <VERS 0x002D2DC8 0x002D3148 0x002D0E68 0x002D1A28 0x002D32F8 0x002D2DF8 0x002D31C8> # From 3OE1:801A2040
|
||||
.deltaof p3_1s, p3_1e
|
||||
.address <VERS 0x002D2DC8 0x002D3148 0x002D0E68 0x002D1A28 0x002D32F8 0x002D2DF8 0x002D31C8> # From 3OE1:801A2040
|
||||
p3_1s:
|
||||
call p3_2s
|
||||
nop
|
||||
p3_1e:
|
||||
.data <VERS 0x002D2EA7 0x002D3227 0x002D0F47 0x002D1B07 0x002D33D7 0x002D2ED7 0x002D32A7>
|
||||
.deltaof p3_2s, p3_2e
|
||||
.address <VERS 0x002D2EA7 0x002D3227 0x002D0F47 0x002D1B07 0x002D33D7 0x002D2ED7 0x002D32A7>
|
||||
p3_2s:
|
||||
fld st0, dword [esp + 0x24]
|
||||
fadd st0, st0
|
||||
fchs st0
|
||||
ret
|
||||
p3_2e:
|
||||
|
||||
.data <VERS 0x00156AC8 0x002D32A8 0x001569E8 0x00156A78 0x00156AB8 0x00156AE8 0x002D3328> # From 3OE1:801A2240
|
||||
.deltaof p4_1s, p4_1e
|
||||
.address <VERS 0x00156AC8 0x002D32A8 0x001569E8 0x00156A78 0x00156AB8 0x00156AE8 0x002D3328> # From 3OE1:801A2240
|
||||
p4_1s:
|
||||
call p4_2s
|
||||
nop
|
||||
p4_1e:
|
||||
.data <VERS 0x00156C44 0x002D33B4 0x00156B64 0x00156BF4 0x00156C34 0x00156C64 0x002D3434>
|
||||
.deltaof p4_2s, p4_2e
|
||||
.address <VERS 0x00156C44 0x002D33B4 0x00156B64 0x00156BF4 0x00156C34 0x00156C64 0x002D3434>
|
||||
p4_2s:
|
||||
fld st0, dword [esp + 0x28]
|
||||
fadd st0, st0
|
||||
fchs st0
|
||||
ret
|
||||
p4_2e:
|
||||
|
||||
.data <VERS 0x002E2B93 0x002E2E8C 0x002E0C33 0x002E17B3 0x002E2E6C 0x002E2BC3 0x002E2EBC> # From 3OE1:80205840
|
||||
.deltaof p5_1s, p5_1e
|
||||
.address <VERS 0x002E2B93 0x002E2E8C 0x002E0C33 0x002E17B3 0x002E2E6C 0x002E2BC3 0x002E2EBC> # From 3OE1:80205840
|
||||
p5_1s:
|
||||
call p5_3s
|
||||
p5_1e:
|
||||
.data <VERS 0x002E1FD1 0x002E2404 0x002E0071 0x002E0BF1 0x002E23E4 0x002E2001 0x002E2434> # From 3OE1:80205FE4
|
||||
.deltaof p5_2s, p5_2e
|
||||
.address <VERS 0x002E1FD1 0x002E2404 0x002E0071 0x002E0BF1 0x002E23E4 0x002E2001 0x002E2434> # From 3OE1:80205FE4
|
||||
p5_2s:
|
||||
call p5_3s
|
||||
p5_2e:
|
||||
.data <VERS 0x002E2C82 0x002E2FD1 0x002E0D22 0x002E18A2 0x002E2FB1 0x002E2CB2 0x002E3001>
|
||||
.deltaof p5_3s, p5_3e
|
||||
.address <VERS 0x002E2C82 0x002E2FD1 0x002E0D22 0x002E18A2 0x002E2FB1 0x002E2CB2 0x002E3001>
|
||||
p5_3s:
|
||||
fld st0, dword [eax + 0x0C]
|
||||
fadd st0, st0
|
||||
fstp dword [eax + 0x0C], st0
|
||||
mov eax, [<VERS 0x0053A9CC 0x0053A26C 0x00535BAC 0x0053622C 0x0053D54C 0x0053A9CC 0x0053AD6C>]
|
||||
ret
|
||||
p5_3e:
|
||||
|
||||
.data <VERS 0x004920A0 0x00491940 0x0048D4F0 0x0048DC88 0x00494C30 0x004920A8 0x00492440> # From 3OE1:805CFCD0
|
||||
.data 0x00000004
|
||||
.data 0x47AFC800
|
||||
|
||||
.data <VERS 0x0042D0A0 0x0042C940 0x00428DC0 0x00429130 0x0042C940 0x0042D0C0 0x0042D450> # From 3OE1:805D0B7C
|
||||
.data 0x00000004
|
||||
.data 0x437A0000
|
||||
|
||||
.data <VERS 0x0049222C 0x00491ACC 0x0048D67C 0x0048DE14 0x00494DBC 0x00492234 0x004925CC> # From 3OE1:805D11A4
|
||||
.data 0x00000004
|
||||
.data 0x491C4000
|
||||
|
||||
.data <VERS 0x0042B838 0x0042B0D8 0x00427558 0x004278C8 0x0042B0D8 0x0042B858 0x0042BBE8> # From 3OE1:805D2030
|
||||
.data 0x00000004
|
||||
.data 0x47AFC800
|
||||
|
||||
.data <VERS 0x001D9736 0x001D9936 0x001D95F6 0x001D9746 0x001D9BC6 0x001D9756 0x001D98A6> # From 3OE1:805D25C0
|
||||
.data 0x00000004
|
||||
.data 0x44AF0000
|
||||
|
||||
.data <VERS 0x001D9748 0x001D9948 0x001D9608 0x001D9758 0x001D9BD8 0x001D9768 0x001D98B8> # From 3OE1:805D25C0
|
||||
.data 0x00000004
|
||||
.data 0x44AF0000
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
write_call_func:
|
||||
.include WriteCallToCode
|
||||
|
||||
start:
|
||||
mov eax, 0x41800000 # Environment clip distance mod 16.0f
|
||||
mov [<VERS 0x0097D198 0x0097F1B8>], eax # This affects mostly static map objects
|
||||
mov [<VERS 0x0097D19C 0x0097F1BC>], eax
|
||||
mov [<VERS 0x0097D1A0 0x0097F1C0>], eax
|
||||
|
||||
mov ax, 0x9090
|
||||
mov [<VERS 0x00689BC7 0x00689B5B>], ax # Players draw distance 10000.0f always
|
||||
mov eax, 0x41000000 # Use newly acquired skipped branch room
|
||||
mov [<VERS 0x00689BD1 0x00689B65>], eax # to store our float multiplier
|
||||
|
||||
call patch_func_1 # Floor items
|
||||
call patch_func_2 # Whole bunch of stuff, including NPCs
|
||||
call patch_func_3 # Duplicate function from above, reuse same hook
|
||||
call patch_func_4 # TODO: Which objects this affects?
|
||||
call patch_func_5 # TODO: This one too?
|
||||
call patch_func_6 # TODO: And this one?
|
||||
ret
|
||||
|
||||
# Floor items
|
||||
patch_func_1:
|
||||
pop ecx
|
||||
push 8
|
||||
push <VERS 0x005C525B 0x005C5267>
|
||||
call get_code_size1
|
||||
.deltaof patch_code1, patch_code_end1
|
||||
get_code_size1:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end1
|
||||
patch_code1:
|
||||
mov edx, [esp + 0x18]
|
||||
fld st0, dword [<VERS 0x00689BD1 0x00689B65>]
|
||||
fld st0, dword [esp + 0x14]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end1:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# Whole bunch of stuff, including NPCs
|
||||
patch_func_2:
|
||||
pop ecx
|
||||
push 9
|
||||
push <VERS 0x007BB21E 0x007BA472>
|
||||
call get_code_size2
|
||||
.deltaof patch_code2, patch_code_end2
|
||||
get_code_size2:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end2
|
||||
patch_code2:
|
||||
test eax, 0x400
|
||||
fld st0, dword [<VERS 0x00689BD1 0x00689B65>]
|
||||
fld st0, dword [esp + 0x2C]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end2:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# Duplicate function from above, reuse same hook
|
||||
patch_func_3:
|
||||
mov eax, dword [<VERS 0x007BB21F 0x007BA473>]
|
||||
add eax, 0x002A1C74
|
||||
mov dword [<VERS 0x00518843 0x005187FF>], eax
|
||||
mov byte [<VERS 0x00518842 0x005187FE>], 0xE8
|
||||
mov dword [<VERS 0x00518847 0x00518803>], 0x90909090
|
||||
ret
|
||||
|
||||
# TOComputerMachine01
|
||||
patch_func_4:
|
||||
pop ecx
|
||||
push 7
|
||||
push <VERS 0x00616FF4 0x00616FFC>
|
||||
call get_code_size4
|
||||
.deltaof patch_code4, patch_code_end4
|
||||
get_code_size4:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end4
|
||||
patch_code4:
|
||||
lea edx, [edi + 0x38]
|
||||
fld st0, dword [<VERS 0x00689BD1 0x00689B65>]
|
||||
fld st0, dword [esp + 0x14]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end4:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# TObjCamera
|
||||
patch_func_5:
|
||||
pop ecx
|
||||
push 6
|
||||
push <VERS 0x006439A8 0x0064394C>
|
||||
call get_code_size5
|
||||
.deltaof patch_code5, patch_code_end5
|
||||
get_code_size5:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end5
|
||||
patch_code5:
|
||||
fld st0, dword [<VERS 0x00689BD1 0x00689B65>]
|
||||
fld st0, dword [esp + 0x28]
|
||||
fmulp st1, st0
|
||||
fchs st0
|
||||
ret
|
||||
patch_code_end5:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# TODO: And this one?
|
||||
patch_func_6:
|
||||
pop ecx
|
||||
push 6
|
||||
push <VERS 0x0065B959 0x0065B985>
|
||||
call get_code_size6
|
||||
.deltaof patch_code6, patch_code_end6
|
||||
get_code_size6:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end6
|
||||
patch_code6:
|
||||
mov ebp, ecx
|
||||
fld st0, dword [<VERS 0x00689BD1 0x00689B65>]
|
||||
fld st0, dword [esp + 0x30]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end6:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
@@ -1,92 +0,0 @@
|
||||
.meta name="Draw Distance"
|
||||
.meta description="Extends the draw\ndistance of many\nobjects"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
|
||||
.data 0x8000DFA0
|
||||
.deltaof hook_start, hook_end
|
||||
.address 0x8000DFA0
|
||||
hook_start:
|
||||
hook1:
|
||||
lfs f30, [r2 - <VERS 0x3E08 0x3E08 0x3E08 0x3E08 0x3E00 0x3E00 0x3E00 0x3E00>]
|
||||
fmuls f30, f30, f1
|
||||
blr
|
||||
hook2:
|
||||
lfs f2, [r2 - <VERS 0x3E08 0x3E08 0x3E08 0x3E08 0x3E00 0x3E00 0x3E00 0x3E00>]
|
||||
lfs f0, [r30 + 0x001C]
|
||||
fmuls f0, f0, f2
|
||||
blr
|
||||
hook3:
|
||||
lfs f28, [r2 - <VERS 0x3E08 0x3E08 0x3E08 0x3E08 0x3E00 0x3E00 0x3E00 0x3E00>]
|
||||
fmuls f28, f28, f2
|
||||
blr
|
||||
hook4:
|
||||
lfs f0, [r2 - <VERS 0x3E08 0x3E08 0x3E08 0x3E08 0x3E00 0x3E00 0x3E00 0x3E00>]
|
||||
lfs f1, [r3 + 0x000C]
|
||||
fmuls f0, f0, f1
|
||||
stfs [r3 + 0x000C], f0
|
||||
lis r3, <VERS 0x804C 0x804C 0x804D 0x804D 0x804C 0x804C 0x804D 0x804D>
|
||||
blr
|
||||
hook_end:
|
||||
|
||||
.data <VERS 0x801008E8 0x80100AD0 0x80100B74 0x80100A50 0x80100B8C 0x80100B8C 0x80100A60 0x80100C50>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x801008E8 0x80100AD0 0x80100B74 0x80100A50 0x80100B8C 0x80100B8C 0x80100A60 0x80100C50>
|
||||
bl hook1
|
||||
|
||||
.data <VERS 0x8015671C 0x80156AD0 0x80156C34 0x80156B94 0x80156AD8 0x80156AD8 0x80156BF8 0x801570BC>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x8015671C 0x80156AD0 0x80156C34 0x80156B94 0x80156AD8 0x80156AD8 0x80156BF8 0x801570BC>
|
||||
bl hook2
|
||||
|
||||
.data <VERS 0x801A1C64 0x801A203C 0x801A21A0 0x801A2100 0x801A2040 0x801A2040 0x801A2164 0x801A2628>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x801A1C64 0x801A203C 0x801A21A0 0x801A2100 0x801A2040 0x801A2040 0x801A2164 0x801A2628>
|
||||
bl hook3
|
||||
|
||||
.data <VERS 0x801A1E64 0x801A223C 0x801A23A0 0x801A2300 0x801A2240 0x801A2240 0x801A2364 0x801A2828>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x801A1E64 0x801A223C 0x801A23A0 0x801A2300 0x801A2240 0x801A2240 0x801A2364 0x801A2828>
|
||||
bl hook1
|
||||
|
||||
.data <VERS 0x80205044 0x802058B8 0x80206640 0x802063F4 0x80205840 0x80205840 0x80206728 0x80206124>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x80205044 0x802058B8 0x80206640 0x802063F4 0x80205840 0x80205840 0x80206728 0x80206124>
|
||||
bl hook4
|
||||
|
||||
.data <VERS 0x802057E8 0x8020605C 0x80206DE4 0x80206B98 0x80205FE4 0x80205FE4 0x80206ECC 0x802068C8>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x802057E8 0x8020605C 0x80206DE4 0x80206B98 0x80205FE4 0x80205FE4 0x80206ECC 0x802068C8>
|
||||
bl hook4
|
||||
|
||||
.data <VERS 0x805C83A8 0x805D29A8 0x805D9E48 0x805D9BE8 0x805C8CB0 0x805CFCD0 0x805D94F0 0x805D5730>
|
||||
.data 0x00000004
|
||||
.float 90000
|
||||
|
||||
.data <VERS 0x805C9254 0x805D3854 0x805DACF4 0x805DAA94 0x805C9B5C 0x805D0B7C 0x805DA39C 0x805D65DC>
|
||||
.data 0x00000004
|
||||
.float 62500
|
||||
|
||||
.data <VERS 0x805C987C 0x805D3E7C 0x805DB31C 0x805DB0BC 0x805CA184 0x805D11A4 0x805DA9C4 0x805D6C04>
|
||||
.data 0x00000004
|
||||
.float 640000
|
||||
|
||||
.data <VERS 0x805CA708 0x805D4D08 0x805DC1A8 0x805DBF48 0x805CB010 0x805D2030 0x805DB850 0x805D7A90>
|
||||
.data 0x00000004
|
||||
.float 90000
|
||||
|
||||
.data <VERS 0x805CAC98 0x805D5298 0x805DC738 0x805DC4D8 0x805CB5A0 0x805D25C0 0x805DBDE0 0x805D8020>
|
||||
.data 0x00000004
|
||||
.float 1400
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,131 +0,0 @@
|
||||
.meta name="Draw Distance"
|
||||
.meta description="Extends the draw\ndistance of many\nobjects"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# Xbox port by fuzziqersoftware
|
||||
|
||||
.versions 4OED 4OEU 4OJB 4OJD 4OJU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
|
||||
.data <VERS 0x001737C2 0x001737D2 0x00173692 0x00173782 0x00173862 0x001737E2 0x00173792> # From 3OE1:80100B8C
|
||||
.deltaof p1_1s, p1_1e
|
||||
.address <VERS 0x001737C2 0x001737D2 0x00173692 0x00173782 0x00173862 0x001737E2 0x00173792> # From 3OE1:80100B8C
|
||||
p1_1s:
|
||||
call p1_2s
|
||||
nop
|
||||
p1_1e:
|
||||
.data <VERS 0x00173A42 0x00173A52 0x00173912 0x00173A02 0x00173AE2 0x00173A62 0x00173A12>
|
||||
.deltaof p1_2s, p1_2e
|
||||
.address <VERS 0x00173A42 0x00173A52 0x00173912 0x00173A02 0x00173AE2 0x00173A62 0x00173A12>
|
||||
p1_2s:
|
||||
fld st0, dword [esp + 0x1C]
|
||||
fadd st0, st0
|
||||
fchs st0
|
||||
ret
|
||||
p1_2e:
|
||||
|
||||
.data <VERS 0x001A3DEF 0x001A3EEF 0x001A3BBF 0x001A3DBF 0x001A3FDF 0x001A3E0F 0x001A3ECF> # From 3OE1:80156AD8
|
||||
.deltaof p2_1s, p2_1e
|
||||
.address <VERS 0x001A3DEF 0x001A3EEF 0x001A3BBF 0x001A3DBF 0x001A3FDF 0x001A3E0F 0x001A3ECF> # From 3OE1:80156AD8
|
||||
p2_1s:
|
||||
call p2_2s
|
||||
p2_1e:
|
||||
.data <VERS 0x001A3E38 0x001A3F38 0x001A3C08 0x001A3E08 0x001A4028 0x001A3E58 0x001A3F18>
|
||||
.deltaof p2_2s, p2_2e
|
||||
.address <VERS 0x001A3E38 0x001A3F38 0x001A3C08 0x001A3E08 0x001A4028 0x001A3E58 0x001A3F18>
|
||||
p2_2s:
|
||||
fld st0, dword [ecx + 0x1C]
|
||||
fadd st0, st0
|
||||
fld st0, st1
|
||||
ret
|
||||
p2_2e:
|
||||
|
||||
.data <VERS 0x002D2DC8 0x002D3148 0x002D0E68 0x002D1A28 0x002D32F8 0x002D2DF8 0x002D31C8> # From 3OE1:801A2040
|
||||
.deltaof p3_1s, p3_1e
|
||||
.address <VERS 0x002D2DC8 0x002D3148 0x002D0E68 0x002D1A28 0x002D32F8 0x002D2DF8 0x002D31C8> # From 3OE1:801A2040
|
||||
p3_1s:
|
||||
call p3_2s
|
||||
nop
|
||||
p3_1e:
|
||||
.data <VERS 0x002D2EA7 0x002D3227 0x002D0F47 0x002D1B07 0x002D33D7 0x002D2ED7 0x002D32A7>
|
||||
.deltaof p3_2s, p3_2e
|
||||
.address <VERS 0x002D2EA7 0x002D3227 0x002D0F47 0x002D1B07 0x002D33D7 0x002D2ED7 0x002D32A7>
|
||||
p3_2s:
|
||||
fld st0, dword [esp + 0x24]
|
||||
fadd st0, st0
|
||||
fchs st0
|
||||
ret
|
||||
p3_2e:
|
||||
|
||||
.data <VERS 0x00156AC8 0x002D32A8 0x001569E8 0x00156A78 0x00156AB8 0x00156AE8 0x002D3328> # From 3OE1:801A2240
|
||||
.deltaof p4_1s, p4_1e
|
||||
.address <VERS 0x00156AC8 0x002D32A8 0x001569E8 0x00156A78 0x00156AB8 0x00156AE8 0x002D3328> # From 3OE1:801A2240
|
||||
p4_1s:
|
||||
call p4_2s
|
||||
nop
|
||||
p4_1e:
|
||||
.data <VERS 0x00156C44 0x002D33B4 0x00156B64 0x00156BF4 0x00156C34 0x00156C64 0x002D3434>
|
||||
.deltaof p4_2s, p4_2e
|
||||
.address <VERS 0x00156C44 0x002D33B4 0x00156B64 0x00156BF4 0x00156C34 0x00156C64 0x002D3434>
|
||||
p4_2s:
|
||||
fld st0, dword [esp + 0x28]
|
||||
fadd st0, st0
|
||||
fchs st0
|
||||
ret
|
||||
p4_2e:
|
||||
|
||||
.data <VERS 0x002E2B93 0x002E2E8C 0x002E0C33 0x002E17B3 0x002E2E6C 0x002E2BC3 0x002E2EBC> # From 3OE1:80205840
|
||||
.deltaof p5_1s, p5_1e
|
||||
.address <VERS 0x002E2B93 0x002E2E8C 0x002E0C33 0x002E17B3 0x002E2E6C 0x002E2BC3 0x002E2EBC> # From 3OE1:80205840
|
||||
p5_1s:
|
||||
call p5_3s
|
||||
p5_1e:
|
||||
.data <VERS 0x002E1FD1 0x002E2404 0x002E0071 0x002E0BF1 0x002E23E4 0x002E2001 0x002E2434> # From 3OE1:80205FE4
|
||||
.deltaof p5_2s, p5_2e
|
||||
.address <VERS 0x002E1FD1 0x002E2404 0x002E0071 0x002E0BF1 0x002E23E4 0x002E2001 0x002E2434> # From 3OE1:80205FE4
|
||||
p5_2s:
|
||||
call p5_3s
|
||||
p5_2e:
|
||||
.data <VERS 0x002E2C82 0x002E2FD1 0x002E0D22 0x002E18A2 0x002E2FB1 0x002E2CB2 0x002E3001>
|
||||
.deltaof p5_3s, p5_3e
|
||||
.address <VERS 0x002E2C82 0x002E2FD1 0x002E0D22 0x002E18A2 0x002E2FB1 0x002E2CB2 0x002E3001>
|
||||
p5_3s:
|
||||
fld st0, dword [eax + 0x0C]
|
||||
fadd st0, st0
|
||||
fstp dword [eax + 0x0C], st0
|
||||
mov eax, [<VERS 0x0053A9CC 0x0053A26C 0x00535BAC 0x0053622C 0x0053D54C 0x0053A9CC 0x0053AD6C>]
|
||||
ret
|
||||
p5_3e:
|
||||
|
||||
.data <VERS 0x004920A0 0x00491940 0x0048D4F0 0x0048DC88 0x00494C30 0x004920A8 0x00492440> # From 3OE1:805CFCD0
|
||||
.data 0x00000004
|
||||
.data 0x47AFC800
|
||||
|
||||
.data <VERS 0x0042D0A0 0x0042C940 0x00428DC0 0x00429130 0x0042C940 0x0042D0C0 0x0042D450> # From 3OE1:805D0B7C
|
||||
.data 0x00000004
|
||||
.data 0x437A0000
|
||||
|
||||
.data <VERS 0x0049222C 0x00491ACC 0x0048D67C 0x0048DE14 0x00494DBC 0x00492234 0x004925CC> # From 3OE1:805D11A4
|
||||
.data 0x00000004
|
||||
.data 0x491C4000
|
||||
|
||||
.data <VERS 0x0042B838 0x0042B0D8 0x00427558 0x004278C8 0x0042B0D8 0x0042B858 0x0042BBE8> # From 3OE1:805D2030
|
||||
.data 0x00000004
|
||||
.data 0x47AFC800
|
||||
|
||||
.data <VERS 0x001D9736 0x001D9936 0x001D95F6 0x001D9746 0x001D9BC6 0x001D9756 0x001D98A6> # From 3OE1:805D25C0
|
||||
.data 0x00000004
|
||||
.data 0x44AF0000
|
||||
|
||||
.data <VERS 0x001D9748 0x001D9948 0x001D9608 0x001D9758 0x001D9BD8 0x001D9768 0x001D98B8> # From 3OE1:805D25C0
|
||||
.data 0x00000004
|
||||
.data 0x44AF0000
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,146 +0,0 @@
|
||||
# Currently beta quality, map objects that fade like boxes, and Pioneer's
|
||||
# background billboards and elevators still have regular draw distance.
|
||||
# TODO: 90% of stuff is included, bring home the last 10%.
|
||||
|
||||
.meta name="Draw Distance"
|
||||
.meta description="Extends the draw\ndistance of many\nobjects"
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
write_call_func:
|
||||
.include WriteCallToCode-59NJ
|
||||
|
||||
start:
|
||||
mov eax, 0x41800000 # Environment clip distance mod 16.0f
|
||||
mov [0x0097D198], eax # This affects mostly static map objects
|
||||
mov [0x0097D19C], eax
|
||||
mov [0x00097D1A0], eax
|
||||
|
||||
mov ax, 0x9090
|
||||
mov [0x00689BC7], ax # Players draw distance 10000.0f always
|
||||
mov eax, 0x41000000 # Use newly acquired skipped branch room
|
||||
mov [0x00689BD1], eax # to store our float multiplier
|
||||
|
||||
call patch_func_1 # Floor items
|
||||
call patch_func_2 # Whole bunch of stuff, including NPCs
|
||||
call patch_func_3 # Duplicate function from above, reuse same hook
|
||||
call patch_func_4 # TODO: Which objects this affects?
|
||||
call patch_func_5 # TODO: This one too?
|
||||
call patch_func_6 # TODO: And this one?
|
||||
ret
|
||||
|
||||
# Floor items
|
||||
patch_func_1:
|
||||
pop ecx
|
||||
push 8
|
||||
push 0x005C525B
|
||||
call get_code_size1
|
||||
.deltaof patch_code1, patch_code_end1
|
||||
get_code_size1:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end1
|
||||
patch_code1:
|
||||
mov edx, [esp + 0x18]
|
||||
fld st0, dword [0x00689BD1]
|
||||
fld st0, dword [esp + 0x14]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end1:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# Whole bunch of stuff, including NPCs
|
||||
patch_func_2:
|
||||
pop ecx
|
||||
push 9
|
||||
push 0x007BB21E
|
||||
call get_code_size2
|
||||
.deltaof patch_code2, patch_code_end2
|
||||
get_code_size2:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end2
|
||||
patch_code2:
|
||||
test eax, 0x400
|
||||
fld st0, dword [0x00689BD1]
|
||||
fld st0, dword [esp + 0x2C]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end2:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# Duplicate function from above, reuse same hook
|
||||
patch_func_3:
|
||||
mov eax, dword [0x007BB21F]
|
||||
add eax, 0x002A1C74
|
||||
mov dword [0x00518843], eax
|
||||
mov byte [0x00518842], 0xE8
|
||||
mov dword [0x00518847], 0x90909090
|
||||
ret
|
||||
|
||||
# TOComputerMachine01
|
||||
patch_func_4:
|
||||
pop ecx
|
||||
push 7
|
||||
push 0x00616FF4
|
||||
call get_code_size4
|
||||
.deltaof patch_code4, patch_code_end4
|
||||
get_code_size4:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end4
|
||||
patch_code4:
|
||||
lea edx, [edi + 0x38]
|
||||
fld st0, dword [0x00689BD1]
|
||||
fld st0, dword [esp + 0x14]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end4:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# TObjCamera
|
||||
patch_func_5:
|
||||
pop ecx
|
||||
push 6
|
||||
push 0x006439A8
|
||||
call get_code_size5
|
||||
.deltaof patch_code5, patch_code_end5
|
||||
get_code_size5:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end5
|
||||
patch_code5:
|
||||
fld st0, dword [0x00689BD1]
|
||||
fld st0, dword [esp + 0x28]
|
||||
fmulp st1, st0
|
||||
fchs st0
|
||||
ret
|
||||
patch_code_end5:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# TODO: And this one?
|
||||
patch_func_6:
|
||||
pop ecx
|
||||
push 6
|
||||
push 0x0065B959
|
||||
call get_code_size6
|
||||
.deltaof patch_code6, patch_code_end6
|
||||
get_code_size6:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end6
|
||||
patch_code6:
|
||||
mov ebp, ecx
|
||||
fld st0, dword [0x00689BD1]
|
||||
fld st0, dword [esp + 0x30]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end6:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
@@ -1,146 +0,0 @@
|
||||
# Currently beta quality, map objects that fade like boxes, and Pioneer's
|
||||
# background billboards and elevators still have regular draw distance.
|
||||
# TODO: 90% of stuff is included, bring home the last 10%.
|
||||
|
||||
.meta name="Draw Distance"
|
||||
.meta description="Extends the draw\ndistance of many\nobjects"
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
write_call_func:
|
||||
.include WriteCallToCode-59NL
|
||||
|
||||
start:
|
||||
mov eax, 0x41800000 # Environment clip distance mod 16.0f
|
||||
mov [0x0097F1B8], eax # This affects mostly static map objects
|
||||
mov [0x0097F1BC], eax
|
||||
mov [0x0097F1C0], eax
|
||||
|
||||
mov ax, 0x9090
|
||||
mov [0x00689B5B], ax # Players draw distance 10000.0f always
|
||||
mov eax, 0x41000000 # Use newly acquired skipped branch room
|
||||
mov [0x00689B65], eax # to store our float multiplier
|
||||
|
||||
call patch_func_1 # Floor items
|
||||
call patch_func_2 # Whole bunch of stuff, including NPCs
|
||||
call patch_func_3 # Duplicate function from above, reuse same hook
|
||||
call patch_func_4 # TODO: Which objects this affects?
|
||||
call patch_func_5 # TODO: This one too?
|
||||
call patch_func_6 # TODO: And this one?
|
||||
ret
|
||||
|
||||
# Floor items
|
||||
patch_func_1:
|
||||
pop ecx
|
||||
push 8
|
||||
push 0x005C5267
|
||||
call get_code_size1
|
||||
.deltaof patch_code1, patch_code_end1
|
||||
get_code_size1:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end1
|
||||
patch_code1:
|
||||
mov edx, [esp + 0x18]
|
||||
fld st0, dword [0x00689B65]
|
||||
fld st0, dword [esp + 0x14]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end1:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# Whole bunch of stuff, including NPCs
|
||||
patch_func_2:
|
||||
pop ecx
|
||||
push 9
|
||||
push 0x007BA472
|
||||
call get_code_size2
|
||||
.deltaof patch_code2, patch_code_end2
|
||||
get_code_size2:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end2
|
||||
patch_code2:
|
||||
test eax, 0x400
|
||||
fld st0, dword [0x00689B65]
|
||||
fld st0, dword [esp + 0x2C]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end2:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# Duplicate function from above, reuse same hook
|
||||
patch_func_3:
|
||||
mov eax, dword [0x007BA473]
|
||||
add eax, 0x002A1C74
|
||||
mov dword [0x005187FF], eax
|
||||
mov byte [0x005187FE], 0xE8
|
||||
mov dword [0x00518803], 0x90909090
|
||||
ret
|
||||
|
||||
# TOComputerMachine01
|
||||
patch_func_4:
|
||||
pop ecx
|
||||
push 7
|
||||
push 0x00616FFC
|
||||
call get_code_size4
|
||||
.deltaof patch_code4, patch_code_end4
|
||||
get_code_size4:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end4
|
||||
patch_code4:
|
||||
lea edx, [edi + 0x38]
|
||||
fld st0, dword [0x00689B65]
|
||||
fld st0, dword [esp + 0x14]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end4:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# TObjCamera
|
||||
patch_func_5:
|
||||
pop ecx
|
||||
push 6
|
||||
push 0x0064394C
|
||||
call get_code_size5
|
||||
.deltaof patch_code5, patch_code_end5
|
||||
get_code_size5:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end5
|
||||
patch_code5:
|
||||
fld st0, dword [0x00689B65]
|
||||
fld st0, dword [esp + 0x28]
|
||||
fmulp st1, st0
|
||||
fchs st0
|
||||
ret
|
||||
patch_code_end5:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
|
||||
# TODO: And this one?
|
||||
patch_func_6:
|
||||
pop ecx
|
||||
push 6
|
||||
push 0x0065B985
|
||||
call get_code_size6
|
||||
.deltaof patch_code6, patch_code_end6
|
||||
get_code_size6:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end6
|
||||
patch_code6:
|
||||
mov ebp, ecx
|
||||
fld st0, dword [0x00689B65]
|
||||
fld st0, dword [esp + 0x30]
|
||||
fmulp st1, st0
|
||||
ret
|
||||
patch_code_end6:
|
||||
push ecx
|
||||
jmp write_call_func
|
||||
@@ -1,258 +0,0 @@
|
||||
.meta name="DMC"
|
||||
.meta description="Mitigates effects\nof enemy health\ndesync"
|
||||
.meta client_flag="0x0000001000000000"
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
write_call_to_code_multi:
|
||||
.include WriteCallToCodeMulti-59NJ
|
||||
write_address_of_code:
|
||||
.include WriteAddressOfCode-59NJ
|
||||
|
||||
start:
|
||||
|
||||
# Replace 6x09 with 6xE4 in subcommand handler table
|
||||
mov dword [0x00A0DC30], 0x000600E4 # subcommand=0xE4, flags=6
|
||||
push 0x00A0DC34
|
||||
call +4
|
||||
.deltaof handle_6xE4_start, handle_6xE4_end
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call handle_6xE4_end
|
||||
|
||||
handle_6xE4_start: # (G_6xE4* cmd @ [esp + 4]) -> void
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
test byte [0x00AA8DFC], 0x80
|
||||
jz handle_6xE4_return
|
||||
mov ebx, [esp + 0x10] # cmd
|
||||
movzx eax, word [ebx + 2]
|
||||
cmp eax, 0x1000
|
||||
jl handle_6xE4_return
|
||||
cmp eax, 0x1B50
|
||||
jge handle_6xE4_return
|
||||
|
||||
movzx eax, word [ebx + 2]
|
||||
.include GetEnemyEntity-59NJ # auto* ene = get_enemy_entity(cmd->header.entity_id);
|
||||
push eax
|
||||
|
||||
movzx eax, word [ebx + 2]
|
||||
and eax, 0x0FFF
|
||||
imul eax, eax, 0x0C
|
||||
add eax, [0x00AADE38] # eax = state_for_enemy(cmd->header.entity_id)
|
||||
|
||||
cmp dword [ebx + 0x0C], 0
|
||||
jl handle_6xE4_not_proportional
|
||||
mov cx, [ebx + 0x0A] # cmd->max_hp
|
||||
sub cx, [eax + 0x06] # st.total_damage
|
||||
movzx ecx, cx
|
||||
xor edx, edx
|
||||
cmp ecx, edx
|
||||
cmovl ecx, edx
|
||||
push ecx
|
||||
fild st0, dword [esp] # current_hp = static_cast<float>(max<int32_t>(cmd->max_hp - st.total_damage, 0))
|
||||
fld st0, dword [ebx + 0x0C]
|
||||
fmulp st1, st0
|
||||
fistp dword [esp], st0
|
||||
mov ecx, dword [esp] # adjusted_hit_amount = static_cast<int16_t>(current_hp * cmd->factor)
|
||||
add esp, 4
|
||||
xor edx, edx
|
||||
inc edx
|
||||
cmp ecx, edx
|
||||
cmovl ecx, edx
|
||||
mov [ebx + 0x04], cx # cmd->hit_amount = min<int32_t>(1, adjusted_hit_amount)
|
||||
handle_6xE4_not_proportional:
|
||||
|
||||
movzx edx, word [eax + 0x06] # st.total_damage
|
||||
movsx esi, word [ebx + 0x04] # cmd->hit_amount
|
||||
movzx edi, word [ebx + 0x0A] # cmd->max_hp
|
||||
add edx, esi # st.total_damage + cmd->hit_amount
|
||||
cmp edx, edi
|
||||
jl handle_6xE4_damage_less_than_max_hp
|
||||
mov [eax + 0x06], di # st.total_damage = cmd->max_hp;
|
||||
mov edx, [eax]
|
||||
test edx, 0x800
|
||||
jnz handle_6xE4_return_pop_ene
|
||||
or edx, 0x800
|
||||
mov [eax], edx
|
||||
cmp dword [esp], 0
|
||||
je handle_6xE4_return_pop_ene
|
||||
push edx # out_cmd.flags
|
||||
sub esp, 8
|
||||
mov word [esp], 0x030A # out_cmd.header.{subcommand,size}
|
||||
mov si, [ebx + 2]
|
||||
mov [esp + 2], si # out_cmd.header.entity_id
|
||||
and si, 0x0FFF
|
||||
mov [esp + 4], si # out_cmd.entity_index
|
||||
mov [esp + 6], di # out_cmd.total_damage
|
||||
mov ecx, esp
|
||||
mov edx, 0x00801150
|
||||
call edx # send_and_handle_60(&out_cmd);
|
||||
add esp, 0x10
|
||||
jmp handle_6xE4_return
|
||||
|
||||
handle_6xE4_damage_less_than_max_hp:
|
||||
xor edi, edi
|
||||
cmp edx, edx
|
||||
cmovl edx, edi
|
||||
mov [eax + 0x06], dx # st.total_damage = std::max<int16_t>(st.total_damage + cmd->hit_amount, 0);
|
||||
|
||||
mov edx, eax # edx = ene_st
|
||||
mov eax, [esp] # eax = ene
|
||||
test eax, eax
|
||||
jz handle_6xE4_return_pop_ene
|
||||
mov ecx, eax
|
||||
push edx
|
||||
mov edx, [ecx]
|
||||
call [edx + 0x148] # ene->vtable[0x52](ene, &st);
|
||||
|
||||
handle_6xE4_return_pop_ene:
|
||||
add esp, 4
|
||||
handle_6xE4_return:
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
handle_6xE4_end:
|
||||
call write_address_of_code
|
||||
|
||||
|
||||
|
||||
# Write TObjectV00b421c0::incr_hp_with_sync
|
||||
push 5
|
||||
push 0x00775224 # TObjectV00b421c0::v18_accept_hit (presumably Resta) - this is add_hp, not subtract_hp!
|
||||
push 5
|
||||
push 0x00778063 # TObjectV00b421c0::subtract_hp_if_not_in_state_2
|
||||
push 5
|
||||
push 0x00777AB2 # TObjectV00b421c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00777B2B # TObjectV00b421c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00777BFC # TObjectV00b421c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00777C75 # TObjectV00b421c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00776D2D # TObjectV00b421c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x007769C2 # TObjectV00b421c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x0077683C # TObjectV00b421c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00776502 # TObjectV00b421c0::v19_handle_hit_special_effects (Devil's/Demon's)
|
||||
push 5
|
||||
push 0x00775B57 # TObjectV00b421c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00775A23 # TObjectV00b421c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x007757F0 # TObjectV00b421c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00775606 # TObjectV00b421c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x007754BC # TObjectV00b421c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00774E3D # TObjectV00b421c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00774CD6 # TObjectV00b421c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00774713 # TObjectV00b421c0::v17
|
||||
push 18
|
||||
call +4
|
||||
.deltaof on_add_or_subtract_hp_start, on_add_or_subtract_hp_end
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call on_add_or_subtract_hp_end
|
||||
|
||||
on_add_or_subtract_hp_start: # (TObjectV00b421c0* this @ ecx, int16_t amount @ [esp + 4]) -> bool @ eax
|
||||
test byte [0x00AA8DFC], 0x80
|
||||
jz on_add_or_subtract_hp_skip_send
|
||||
movzx eax, word [ecx + 0x1C] # ene->entity_id
|
||||
cmp eax, 0x1000
|
||||
jl on_add_or_subtract_hp_skip_send
|
||||
cmp eax, 0x1B50
|
||||
jge on_add_or_subtract_hp_skip_send
|
||||
|
||||
and eax, 0x0FFF
|
||||
imul eax, eax, 0x0C
|
||||
add eax, [0x00AADE38] # eax = state_for_enemy(cmd->header.entity_id)
|
||||
|
||||
sub esp, 0x10
|
||||
mov word [esp], 0x04E4
|
||||
mov dx, [ecx + 0x1C]
|
||||
mov [esp + 0x02], dx # cmd.entity_id
|
||||
mov dx, [esp + 0x14]
|
||||
cmp dword [esp + 0x10], 0x00775229 # Check if callsite is add_hp
|
||||
jne on_add_or_subtract_hp_skip_negate_amount
|
||||
neg dx
|
||||
on_add_or_subtract_hp_skip_negate_amount:
|
||||
mov [esp + 0x04], dx # cmd.hit_amount
|
||||
mov dx, [eax + 6]
|
||||
mov [esp + 0x06], dx # cmd.total_damage_before_hit
|
||||
mov dx, [ecx + 0x0334]
|
||||
mov [esp + 0x08], dx # cmd.current_hp
|
||||
mov dx, [ecx + 0x02BC]
|
||||
mov [esp + 0x0A], dx # cmd.max_hp
|
||||
mov dword [esp + 0x0C], 0xBF800000 # cmd.factor
|
||||
|
||||
cmp dword [esp + 0x10], 0x00776507 # Check if callsite is Devil's/Demon's
|
||||
jne on_add_or_subtract_hp_not_proportional
|
||||
# esp is 0x18 down from where it is in caller's context
|
||||
mov edx, 100
|
||||
sub edx, [esp + 0x24] # edx = (100 - special_amount)
|
||||
push edx
|
||||
fild st0, dword [esp] # current_hp_factor = static_cast<float>(100 - special_amount)
|
||||
fmul st0, dword [esp + 0x54] # *= weapon_reduction_factor
|
||||
mov dword [esp], 0x42C80000 # 100.0f
|
||||
fdiv st0, dword [esp]
|
||||
add esp, 4
|
||||
fstp dword [esp + 0x0C], st0 # cmd.factor = ((100 - special_amount) * weapon_reduction_factor) / 100
|
||||
on_add_or_subtract_hp_not_proportional:
|
||||
|
||||
mov edx, esp
|
||||
push ecx
|
||||
push 0x10
|
||||
push edx
|
||||
mov ecx, [0x00AA8E04]
|
||||
mov edx, 0x007D4CBC
|
||||
call edx # send_60(root_protocol, &cmd, sizeof(cmd));
|
||||
pop ecx
|
||||
add esp, 0x10
|
||||
|
||||
on_add_or_subtract_hp_skip_send:
|
||||
mov eax, 0x007781F0 # subtract_hp
|
||||
mov edx, 0x007781B0 # add_hp
|
||||
cmp dword [esp], 0x00775229 # Check if callsite is add_hp
|
||||
cmove eax, edx
|
||||
jmp eax
|
||||
|
||||
on_add_or_subtract_hp_end:
|
||||
call write_call_to_code_multi
|
||||
|
||||
|
||||
|
||||
push 5
|
||||
push 0x0078864B
|
||||
push 1
|
||||
call +4
|
||||
.deltaof on_6x0A_patch_start, on_6x0A_patch_end
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call on_6x0A_patch_end
|
||||
|
||||
on_6x0A_patch_start: # (TObjectV00b421c0* this @ ecx, int16_t amount @ [esp + 4]) -> bool @ eax
|
||||
test byte [0x00AA8DFC], 0x80
|
||||
jz on_6x0A_patch_skip_write
|
||||
mov [esp + 0x0A], cx
|
||||
on_6x0A_patch_skip_write:
|
||||
ret
|
||||
|
||||
on_6x0A_patch_end:
|
||||
call write_call_to_code_multi
|
||||
|
||||
|
||||
|
||||
ret
|
||||
+42
-37
@@ -1,21 +1,25 @@
|
||||
.meta visibility="all"
|
||||
.meta key="EnemyDamageSync"
|
||||
.meta name="DMC"
|
||||
.meta description="Mitigates effects\nof enemy health\ndesync"
|
||||
.meta client_flag="0x0000001000000000"
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
write_call_to_code_multi:
|
||||
.include WriteCallToCodeMulti-59NL
|
||||
.include WriteCallToCodeMulti
|
||||
write_address_of_code:
|
||||
.include WriteAddressOfCode-59NL
|
||||
.include WriteAddressOfCode
|
||||
|
||||
start:
|
||||
|
||||
# Replace 6x09 with 6xE4 in subcommand handler table
|
||||
mov dword [0x00A0FC30], 0x000600E4 # subcommand=0xE4, flags=6
|
||||
push 0x00A0FC34
|
||||
mov dword [<VERS 0x00A0DC30 0x00A0FC30>], 0x000600E4 # subcommand=0xE4, flags=6
|
||||
push <VERS 0x00A0DC34 0x00A0FC34>
|
||||
call +4
|
||||
.deltaof handle_6xE4_start, handle_6xE4_end
|
||||
pop eax
|
||||
@@ -27,7 +31,7 @@ handle_6xE4_start: # (G_6xE4* cmd @ [esp + 4]) -> void
|
||||
push esi
|
||||
push edi
|
||||
|
||||
test byte [0x00AAB27C], 0x80
|
||||
test byte [<VERS 0x00AA8DFC 0x00AAB27C>], 0x80
|
||||
jz handle_6xE4_return
|
||||
mov ebx, [esp + 0x10] # cmd
|
||||
movzx eax, word [ebx + 2]
|
||||
@@ -37,13 +41,13 @@ handle_6xE4_start: # (G_6xE4* cmd @ [esp + 4]) -> void
|
||||
jge handle_6xE4_return
|
||||
|
||||
movzx eax, word [ebx + 2]
|
||||
.include GetEnemyEntity-59NL # auto* ene = get_enemy_entity(cmd->header.entity_id);
|
||||
.include GetEnemyEntity # auto* ene = get_enemy_entity(cmd->header.entity_id);
|
||||
push eax
|
||||
|
||||
movzx eax, word [ebx + 2]
|
||||
and eax, 0x0FFF
|
||||
imul eax, eax, 0x0C
|
||||
add eax, [0x00AB02B8] # eax = state_for_enemy(cmd->header.entity_id)
|
||||
add eax, [<VERS 0x00AADE38 0x00AB02B8>] # eax = state_for_enemy(cmd->header.entity_id)
|
||||
|
||||
cmp dword [ebx + 0x0C], 0
|
||||
jl handle_6xE4_not_proportional
|
||||
@@ -90,7 +94,7 @@ handle_6xE4_not_proportional:
|
||||
mov [esp + 4], si # out_cmd.entity_index
|
||||
mov [esp + 6], di # out_cmd.total_damage
|
||||
mov ecx, esp
|
||||
mov edx, 0x008003E0
|
||||
mov edx, <VERS 0x00801150 0x008003E0>
|
||||
call edx # send_and_handle_60(&out_cmd);
|
||||
add esp, 0x10
|
||||
jmp handle_6xE4_return
|
||||
@@ -123,43 +127,44 @@ handle_6xE4_end:
|
||||
|
||||
|
||||
|
||||
# Note: in 59NJ this object is TObjectV00b421c0 (it's the same as 3OE1's TObjectV8047c128)
|
||||
# Write TObjectV00b441c0::incr_hp_with_sync
|
||||
push 5
|
||||
push 0x00774448 # TObjectV00b441c0::v18_accept_hit (presumably Resta) - this is add_hp, not subtract_hp!
|
||||
push <VERS 0x00775224 0x00774448> # TObjectV00b441c0::v18_accept_hit (presumably Resta) - this is add_hp, not subtract_hp!
|
||||
push 5
|
||||
push 0x00777287 # TObjectV00b441c0::subtract_hp_if_not_in_state_2
|
||||
push <VERS 0x00778063 0x00777287> # TObjectV00b441c0::subtract_hp_if_not_in_state_2
|
||||
push 5
|
||||
push 0x00776CD6 # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push <VERS 0x00777AB2 0x00776CD6> # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00776D4F # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push <VERS 0x00777B2B 0x00776D4F> # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00776E20 # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push <VERS 0x00777BFC 0x00776E20> # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00776E99 # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push <VERS 0x00777C75 0x00776E99> # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00775F51 # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push <VERS 0x00776D2D 0x00775F51> # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00775BE6 # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push <VERS 0x007769C2 0x00775BE6> # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00775A60 # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push <VERS 0x0077683C 0x00775A60> # TObjectV00b441c0::v19_handle_hit_special_effects
|
||||
push 5
|
||||
push 0x00775726 # TObjectV00b441c0::v19_handle_hit_special_effects (Devil's/Demon's)
|
||||
push <VERS 0x00776502 0x00775726> # TObjectV00b441c0::v19_handle_hit_special_effects (Devil's/Demon's)
|
||||
push 5
|
||||
push 0x00774D7B # TObjectV00b441c0::v18_accept_hit
|
||||
push <VERS 0x00775B57 0x00774D7B> # TObjectV00b441c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00774C47 # TObjectV00b441c0::v18_accept_hit
|
||||
push <VERS 0x00775A23 0x00774C47> # TObjectV00b441c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00774A14 # TObjectV00b441c0::v18_accept_hit
|
||||
push <VERS 0x007757F0 0x00774A14> # TObjectV00b441c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x0077482A # TObjectV00b441c0::v18_accept_hit
|
||||
push <VERS 0x00775606 0x0077482A> # TObjectV00b441c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x007746E0 # TObjectV00b441c0::v18_accept_hit
|
||||
push <VERS 0x007754BC 0x007746E0> # TObjectV00b441c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00774061 # TObjectV00b441c0::v18_accept_hit
|
||||
push <VERS 0x00774E3D 0x00774061> # TObjectV00b441c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00773EFA # TObjectV00b441c0::v18_accept_hit
|
||||
push <VERS 0x00774CD6 0x00773EFA> # TObjectV00b441c0::v18_accept_hit
|
||||
push 5
|
||||
push 0x00773937 # TObjectV00b441c0::v17
|
||||
push <VERS 0x00774713 0x00773937> # TObjectV00b441c0::v17
|
||||
push 18
|
||||
call +4
|
||||
.deltaof on_add_or_subtract_hp_start, on_add_or_subtract_hp_end
|
||||
@@ -168,7 +173,7 @@ handle_6xE4_end:
|
||||
call on_add_or_subtract_hp_end
|
||||
|
||||
on_add_or_subtract_hp_start: # (TObjectV00b441c0* this @ ecx, int16_t amount @ [esp + 4]) -> bool @ eax
|
||||
test byte [0x00AAB27C], 0x80
|
||||
test byte [<VERS 0x00AA8DFC 0x00AAB27C>], 0x80
|
||||
jz on_add_or_subtract_hp_skip_send
|
||||
movzx eax, word [ecx + 0x1C] # ene->entity_id
|
||||
cmp eax, 0x1000
|
||||
@@ -178,14 +183,14 @@ on_add_or_subtract_hp_start: # (TObjectV00b441c0* this @ ecx, int16_t amount @
|
||||
|
||||
and eax, 0x0FFF
|
||||
imul eax, eax, 0x0C
|
||||
add eax, [0x00AB02B8] # eax = state_for_enemy(cmd->header.entity_id)
|
||||
add eax, [<VERS 0x00AADE38 0x00AB02B8>] # eax = state_for_enemy(cmd->header.entity_id)
|
||||
|
||||
sub esp, 0x10
|
||||
mov word [esp], 0x04E4
|
||||
mov dx, [ecx + 0x1C]
|
||||
mov [esp + 0x02], dx # cmd.entity_id
|
||||
mov dx, [esp + 0x14]
|
||||
cmp dword [esp + 0x10], 0x0077444D # Check if callsite is add_hp
|
||||
cmp dword [esp + 0x10], <VERS 0x00775229 0x0077444D> # Check if callsite is add_hp
|
||||
jne on_add_or_subtract_hp_skip_negate_amount
|
||||
neg dx
|
||||
on_add_or_subtract_hp_skip_negate_amount:
|
||||
@@ -198,7 +203,7 @@ on_add_or_subtract_hp_skip_negate_amount:
|
||||
mov [esp + 0x0A], dx # cmd.max_hp
|
||||
mov dword [esp + 0x0C], 0xBF800000 # cmd.factor
|
||||
|
||||
cmp dword [esp + 0x10], 0x0077572B # Check if callsite is Devil's/Demon's
|
||||
cmp dword [esp + 0x10], <VERS 0x00776507 0x0077572B> # Check if callsite is Devil's/Demon's
|
||||
jne on_add_or_subtract_hp_not_proportional
|
||||
# esp is 0x18 down from where it is in caller's context
|
||||
mov edx, 100
|
||||
@@ -216,16 +221,16 @@ on_add_or_subtract_hp_not_proportional:
|
||||
push ecx
|
||||
push 0x10
|
||||
push edx
|
||||
mov ecx, [0x00AAB284]
|
||||
mov edx, 0x007D3F38
|
||||
mov ecx, [<VERS 0x00AA8E04 0x00AAB284>]
|
||||
mov edx, <VERS 0x007D4CBC 0x007D3F38>
|
||||
call edx # send_60(root_protocol, &cmd, sizeof(cmd));
|
||||
pop ecx
|
||||
add esp, 0x10
|
||||
|
||||
on_add_or_subtract_hp_skip_send:
|
||||
mov eax, 0x00777414 # subtract_hp
|
||||
mov edx, 0x007773D4 # add_hp
|
||||
cmp dword [esp], 0x0077444D # Check if callsite is add_hp
|
||||
mov eax, <VERS 0x007781F0 0x00777414> # subtract_hp
|
||||
mov edx, <VERS 0x007781B0 0x007773D4> # add_hp
|
||||
cmp dword [esp], <VERS 0x00775229 0x0077444D> # Check if callsite is add_hp
|
||||
cmove eax, edx
|
||||
jmp eax
|
||||
|
||||
@@ -235,7 +240,7 @@ on_add_or_subtract_hp_end:
|
||||
|
||||
|
||||
push 5
|
||||
push 0x0078781F
|
||||
push <VERS 0x0078864B 0x0078781F>
|
||||
push 1
|
||||
call +4
|
||||
.deltaof on_6x0A_patch_start, on_6x0A_patch_end
|
||||
@@ -244,7 +249,7 @@ on_add_or_subtract_hp_end:
|
||||
call on_6x0A_patch_end
|
||||
|
||||
on_6x0A_patch_start: # (TObjectV00b441c0* this @ ecx, int16_t amount @ [esp + 4]) -> bool @ eax
|
||||
test byte [0x00AAB27C], 0x80
|
||||
test byte [<VERS 0x00AA8DFC 0x00AAB27C>], 0x80
|
||||
jz on_6x0A_patch_skip_write
|
||||
mov [esp + 0x0A], cx
|
||||
on_6x0A_patch_skip_write:
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
.meta visibility="all"
|
||||
.meta key="EnemyDamageSync"
|
||||
.meta name="DMC"
|
||||
.meta description="Mitigates effects\nof enemy health\ndesync"
|
||||
.meta client_flag="0x0000001000000000"
|
||||
@@ -8,7 +10,7 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.label TObjectV8047c128_add_hp, <VERS 0x8001143C 0x8001145C 0x800116EC 0x8001140C 0x80011454 0x80011454 0x8001140C 0x80011484>
|
||||
.label TObjectV8047c128_subtract_hp, <VERS 0x8001147C 0x8001149C 0x8001172C 0x8001144C 0x80011494 0x80011494 0x8001144C 0x800114C4>
|
||||
+7
-6
@@ -1,3 +1,5 @@
|
||||
.meta visibility="all"
|
||||
.meta key="EnemyDamageSync"
|
||||
.meta name="DMC"
|
||||
.meta description="Mitigates effects\nof enemy health\ndesync"
|
||||
.meta client_flag="0x0000001000000000"
|
||||
@@ -9,7 +11,7 @@ reloc0:
|
||||
.offsetof start
|
||||
|
||||
write_call_to_code_multi:
|
||||
.include WriteCallToCodeMultiXB
|
||||
.include WriteCallToCodeMulti
|
||||
|
||||
|
||||
|
||||
@@ -284,7 +286,7 @@ on_add_or_subtract_hp_end:
|
||||
|
||||
|
||||
write_static_patches:
|
||||
.include WriteCodeBlocksXB
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
@@ -326,10 +328,9 @@ on_subtract_hp_if_not_in_state_2_end:
|
||||
.deltaof v17_subtract_hp_inlined_callsite_start, v17_subtract_hp_inlined_callsite_end
|
||||
.address <VERS 0x002A60CA 0x002A6BAA 0x002A807A 0x002A7B0A 0x002A7CEA 0x002A7B2A 0x002A7DAA>
|
||||
v17_subtract_hp_inlined_callsite_start:
|
||||
# This must assemble to exactly 0x1A bytes. There is a vfn call shortly after
|
||||
# this, and fortunately it appears eax, ecx, and edx are not used before
|
||||
# then, so we don't have to save any registers here; we just have to move the
|
||||
# args into the right places.
|
||||
# This must assemble to exactly 0x1A bytes. There is a vfn call shortly after this, and fortunately it appears eax,
|
||||
# ecx, and edx are not used before then, so we don't have to save any registers here; we just have to move the args
|
||||
# into the right places.
|
||||
mov cx, ax
|
||||
mov eax, edi
|
||||
call -1 # Overwritten by write_call_to_code_multi later
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
.meta visibility="all"
|
||||
.meta key="EnemyHPBars"
|
||||
.meta name="Enemy HP bars"
|
||||
.meta description="Shows HP bars in\nenemy info windows"
|
||||
|
||||
@@ -7,7 +9,7 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksBB
|
||||
.include WriteCodeBlocks
|
||||
.data <VERS 0x0073197D 0x007318DD>
|
||||
.data 6
|
||||
.binary 81E2FDFFFFFF
|
||||
+6
-3
@@ -1,16 +1,19 @@
|
||||
.meta name="Enemy HP bars"
|
||||
.meta description="Shows HP bars in\nenemy info windows"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.meta visibility="all"
|
||||
.meta key="EnemyHPBars"
|
||||
.meta name="Enemy HP bars"
|
||||
.meta description="Shows HP bars in\nenemy info windows"
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.label hook_addr, 0x8000B650
|
||||
.label sprintf, <VERS 0x80395EFC 0x80398904 0x8039A7A4 0x8039A554 0x803971CC 0x80397224 0x8039A924 0x80399414>
|
||||
+8
-5
@@ -1,17 +1,20 @@
|
||||
.meta name="Enemy HP bars"
|
||||
.meta description="Shows HP bars in\nenemy info windows"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# Xbox port by fuzziqersoftware
|
||||
|
||||
.meta visibility="all"
|
||||
.meta key="EnemyHPBars"
|
||||
.meta name="Enemy HP bars"
|
||||
.meta description="Shows HP bars in\nenemy info windows"
|
||||
|
||||
.versions 4OED 4OEU 4OJB 4OJD 4OJU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
.include WriteCodeBlocks
|
||||
.data <VERS 0x0026B063 0x0026B193 0x0026ABA3 0x0026AF13 0x0026B2F3 0x0026B083 0x0026B193>
|
||||
.data 0x00000001
|
||||
.binary C0
|
||||
@@ -51,8 +54,8 @@ str_data_start:
|
||||
.data 0x00000000
|
||||
str_data_end:
|
||||
|
||||
# WARNING: FlickeringStatusIcons patch starts immediately after this segment;
|
||||
# if the size of this is changed, that patch will have to be changed too
|
||||
# WARNING: FlickeringStatusIcons patch starts immediately after this segment; if the size of this is changed, that
|
||||
# patch will have to be changed too
|
||||
.data <VERS 0x002DB050 0x002DB550 0x002D90E0 0x002D9CB0 0x002DB580 0x002DB080 0x002DB5D0>
|
||||
.deltaof new_code_start, new_code_end
|
||||
new_code_start:
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
# This patch gives you the maximum number of each card. It only works if used
|
||||
# in-game, which means it must be used by running `$patch AllCards`.
|
||||
# This patch gives you the maximum number of each card. It only works if used in-game, which means it must be used by
|
||||
# running `$patch AllCards`.
|
||||
|
||||
.meta hide_from_patches_menu
|
||||
.meta visibility="cheat"
|
||||
.meta name="All cards"
|
||||
.meta description="Gives you the\nmaximum number of\neach card."
|
||||
|
||||
+54
-75
@@ -1,18 +1,16 @@
|
||||
# This patch enables the debug menus in PSO Episode 3 USA. Specifically, it
|
||||
# causes them all to load, but only activates one (selected by uncommenting a
|
||||
# line below). See the comments for more information. Most of these editors are
|
||||
# present in PSO PC and PSO Xbox as well, but not in GC Episodes 1 & 2. There
|
||||
# are notes in the below comments that may help get these editors working on
|
||||
# PSO PC.
|
||||
# This patch enables the debug menus in PSO Episode 3 USA. Specifically, it causes them all to load, but only activates
|
||||
# one (selected by uncommenting a line below). See the comments for more information. Most of these editors are present
|
||||
# in PSO PC and PSO Xbox as well, but not in GC Episodes 1 & 2. There are notes in the below comments that may help get
|
||||
# these editors working on PSO PC.
|
||||
|
||||
# This patch must not be run from the Patches menu - it should only be run with
|
||||
# the $patch command, since the client will likely crash if the player is not
|
||||
# in a game or lobby when the patch runs.
|
||||
# This patch must not be run from the Patches menu - it should only be run with the $patch command, since the client
|
||||
# will likely crash if the player is not in a game or lobby when the patch runs.
|
||||
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="Editors"
|
||||
.meta description="Enables the various\ndebug menus"
|
||||
|
||||
.versions 3SE0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
@@ -25,8 +23,7 @@ start:
|
||||
stw [r1 + 0x0C], r30
|
||||
stw [r1 + 0x08], r29
|
||||
|
||||
# Write a short hook that updates our editors table when TEditor_destroy() is
|
||||
# called
|
||||
# Write a short hook that updates our editors table when TEditor_destroy() is called
|
||||
bl get_TEditor_destroy_hook_addr
|
||||
mr r4, r3
|
||||
bl get_TEditor_destroy_hook_end
|
||||
@@ -48,10 +45,9 @@ start:
|
||||
ori r29, r29, 0x17C4
|
||||
|
||||
construct_editors:
|
||||
# Call the constructors for all the editors and save the object pointers. If
|
||||
# an editor already exists, set its disable flags. (This behavior allows this
|
||||
# patch to run again to switch to a different editor without changing rooms.)
|
||||
# Note: In PSO PC (the version I have, at least) this table is at 00691FA8.
|
||||
# Call the constructors for all the editors and save the object pointers. If an editor already exists, set its
|
||||
# disable flags. (This behavior allows this patch to run again to switch to a different editor without changing
|
||||
# rooms.) In PSO PC (2OJW) this table is at 00691FA8.
|
||||
lis r30, 0x8043
|
||||
ori r30, r30, 0x3760
|
||||
addi r31, r30, 0xB4 # 15 entries * 12 bytes per entry
|
||||
@@ -76,13 +72,11 @@ editor_construction_failed:
|
||||
blt again
|
||||
|
||||
activate_chosen_editor:
|
||||
# All of the editors have flags set at construction time that effectively
|
||||
# disable them (by disabling both the update and render functions). At the
|
||||
# time this code is executed, the flags are already set (and we set them again
|
||||
# in the above loop anyway), so we can unset the flags for whichever editor we
|
||||
# want to run by uncommenting the appropriate lwz opcode below.
|
||||
# Most of these tools expect input from the controller in port 3; the comments
|
||||
# below all refer to inputs from that port.
|
||||
# All of the editors have flags set at construction time that effectively disable them (by disabling both the update
|
||||
# and render functions). At the time this code is executed, the flags are already set (and we set them again in the
|
||||
# above loop anyway), so we can unset the flags for whichever editor we want to run by uncommenting the appropriate
|
||||
# lwz opcode below. Most of these tools expect input from the controller in port 3; the comments below all refer to
|
||||
# inputs from that port.
|
||||
|
||||
li r4, 0
|
||||
lis r29, 0x8000
|
||||
@@ -92,91 +86,76 @@ activate_chosen_editor:
|
||||
# This editor is very similar to TGroupEnemySetEditor (see below).
|
||||
|
||||
# lwz r4, [r29 + 0x04] # TGroupEnemySetEditor
|
||||
# This editor only works in a game; it crashes if loaded in the lobby.
|
||||
# Use the D-pad to choose a value; hold X and use the D-pad to modify the
|
||||
# selected value. Hold R to use the menu on the right.
|
||||
# This editor only works in a game; it crashes if loaded in the lobby. Use the D-pad to choose a value; hold X and
|
||||
# use the D-pad to modify the selected value. Hold R to use the menu on the right.
|
||||
|
||||
# lwz r4, [r29 + 0x08] # TCameraEditor
|
||||
# This editor displays a floating-point value at the bottom of the screen,
|
||||
# which you can modify with C-left and C-right. It's not apparent what this
|
||||
# value represents, though.
|
||||
# This editor displays a floating-point value at the bottom of the screen, which you can modify with C-left and
|
||||
# C-right. It's not apparent what this value represents, though.
|
||||
|
||||
# lwz r4, [r29 + 0x0C] # TParticleEditor
|
||||
# This editor has two modes. Hold A and press X to switch modes. In "MAIN
|
||||
# MODE", use D-left/D-right to pick an effect. Hold L to make the effect
|
||||
# picker manageable (instead of insanely fast). In "ELEMENT MODE", it seems
|
||||
# that any of the displayed values can be modified, but the selector is very
|
||||
# hard to see (the selected section is rendered in FFFFFF, while the others
|
||||
# are rendered in F0F0F0 - very similar colors!). Hold A, Y, or X and use
|
||||
# the D-pad to change a value in the selected section (each of A/Y/X
|
||||
# corresponds to a specific field in the current section).
|
||||
# This editor has two modes. Hold A and press X to switch modes. In "MAIN MODE", use D-left/D-right to pick an
|
||||
# effect. Hold L to make the effect picker manageable (instead of insanely fast). In "ELEMENT MODE", it seems that
|
||||
# any of the displayed values can be modified, but the selector is very hard to see (the selected section is
|
||||
# rendered in FFFFFF, while the others are rendered in F0F0F0 - very similar colors!). Hold A, Y, or X and use the
|
||||
# D-pad to change a value in the selected section (each of A/Y/X corresponds to a specific field in the current
|
||||
# section).
|
||||
|
||||
# lwz r4, [r29 + 0x10] # TFreeCamera
|
||||
# This editor does nothing. Probably it was never implemented or the code
|
||||
# was intentionally deleted (though if it was, it's not clear why only this
|
||||
# editor's code was deleted).
|
||||
# This editor does nothing. Probably it was never implemented or the code was intentionally deleted (though if it
|
||||
# was, it's not clear why only this editor's code was deleted).
|
||||
|
||||
# lwz r4, [r29 + 0x14] # TFogEditor
|
||||
# Use L/R to pick a line, and the D-pad to modify the values. NO specifies
|
||||
# which fog entry you're editing (0-127).
|
||||
# Use L/R to pick a line, and the D-pad to modify the values. NO specifies which fog entry you're editing (0-127).
|
||||
|
||||
# lwz r4, [r29 + 0x18] # TLightEditor
|
||||
# Used for testing character lighting. Use L to select a section and the
|
||||
# D-pad to choose and modify values within that section. COLOR and DIR
|
||||
# specify the properties of the highlight; AMBIENT specifies the color of
|
||||
# the non-highlight lighting. It's not clear what the last section does.
|
||||
# Used for testing character lighting. Use L to select a section and the D-pad to choose and modify values within
|
||||
# that section. COLOR and DIR specify the properties of the highlight; AMBIENT specifies the color of the non-
|
||||
# highlight lighting. It's not clear what the last section does.
|
||||
|
||||
# lwz r4, [r29 + 0x1C] # nothing (type table entry is blank)
|
||||
|
||||
# lwz r4, [r29 + 0x20] # TSeqVarsEdit
|
||||
# Use L/R to change pages, use the D-pad to pick a flag, and use A to toggle
|
||||
# it. There are 8192 flags in total (0x400 bytes).
|
||||
# Use L/R to change pages, use the D-pad to pick a flag, and use A to toggle it. There are 8192 flags in total
|
||||
# (0x400 bytes).
|
||||
|
||||
# lwz r4, [r29 + 0x24] # TSetEvtScriptTest
|
||||
# Use D-left/D-right to change the label value and D-up/D-down to move the
|
||||
# menu selection. Two of the menu items appear to do nothing, and the last
|
||||
# crashes. Maybe it works better on Episodes 1&2.
|
||||
# Use D-left/D-right to change the label value and D-up/D-down to move the menu selection. Two of the menu items
|
||||
# appear to do nothing, and the last crashes. Maybe it works better on Episodes 1&2.
|
||||
|
||||
# lwz r4, [r29 + 0x28] # nothing (type table entry is blank)
|
||||
|
||||
# lwz r4, [r29 + 0x2C] # TQuestScriptChecker (quest debugger)
|
||||
# Use L to change functions, and the D-pad to navigate within each function.
|
||||
# If you set EVENT NO to a very high value, the editor can appear messed up;
|
||||
# what actually happens is the value is shifted one decimal place to the
|
||||
# right, but the cursor remains in the same position with incorrect
|
||||
# highlighting. The value appears to be a signed 32-bit integer. On the
|
||||
# registers page, use D-left/D-right to see more registers; hold X and use
|
||||
# the D-pad to modify a register's value. Similarly, hold X and use the
|
||||
# D-pad on the breakpoints page to change values.
|
||||
# Use L to change functions, and the D-pad to navigate within each function. If you set EVENT NO to a very high
|
||||
# value, the editor can appear messed up; what actually happens is the value is shifted one decimal place to the
|
||||
# right, but the cursor remains in the same position with incorrect highlighting. The value appears to be a signed
|
||||
# 32-bit integer. On the registers page, use D-left/D-right to see more registers; hold X and use the D-pad to
|
||||
# modify a register's value. Similarly, hold X and use the D-pad on the breakpoints page to change values.
|
||||
|
||||
# lwz r4, [r29 + 0x30] # TPlyPKEditor (battle mode options)
|
||||
# Use the D-pad to move the cursor and set options. In Episode 3, it appears
|
||||
# this debugger doesn't do anything. It's likely more functional in Episodes
|
||||
# 1 & 2.
|
||||
# Use the D-pad to move the cursor and set options. In Episode 3, it appears this debugger doesn't do anything.
|
||||
# It's likely more functional in Episodes 1 & 2.
|
||||
|
||||
# lwz r4, [r29 + 0x34] # TEffIndirectEditor
|
||||
# li r0, 1
|
||||
# stw [r4 + 0x38], r0
|
||||
# This editor is missing in PSO PC, but is present in PSOX. It appears to be
|
||||
# used for testing texture overlay effects, but it doesn't work properly in
|
||||
# Episode 3 - none of the effects appear to do anything. All three lines
|
||||
# This editor is missing in PSO PC, but is present in PSOX. It appears to be used for testing texture overlay
|
||||
# effects, but it doesn't work properly in Episode 3 - none of the effects appear to do anything. All three lines
|
||||
# above must be uncommented for it to load.
|
||||
|
||||
# lwz r4, [r29 + 0x38] # TCCScenarioDebug (movie/cutscene tests)
|
||||
# This editor exists only in Episode 3 - it is neither in PSOPC nor PSOX.
|
||||
# Nothing appears immediately after activating this debugger because the
|
||||
# default page is blank. Use C-left and C-right to change major pages; use
|
||||
# L/R to change minor pages (sets of 50 flags within each major page). Use
|
||||
# the D-pad to pick a flag and A to toggle it. On the "STAFFROLL" page, use
|
||||
# the D-pad to pick a movie, and R+A to play it. If you watch the movie to
|
||||
# the end, you'll return to your game and things will work as normal, but
|
||||
# the textures will likely have been overwritten with garbage data.
|
||||
# This editor exists only in Episode 3 - it is neither in PSOPC nor PSOX. Nothing appears immediately after
|
||||
# activating this debugger because the default page is blank. Use C-left and C-right to change major pages; use L/R
|
||||
# to change minor pages (sets of 50 flags within each major page). Use the D-pad to pick a flag and A to toggle it.
|
||||
# On the "STAFFROLL" page, use the D-pad to pick a movie, and R+A to play it. If you watch the movie to the end,
|
||||
# you'll return to your game and things will work as normal, but the textures will likely have been overwritten
|
||||
# with garbage data.
|
||||
|
||||
li r3, 0
|
||||
mr. r0, r4
|
||||
beq skip_enable_editor
|
||||
# Note: The PSO PC TObject structure is a bit different; the flags field is at
|
||||
# +8 instead of +4 (but it is still a 16-bit integer).
|
||||
# Note: The PSO PC TObject structure is a bit different; the flags field is at +8 instead of +4 (but it is still a
|
||||
# 16-bit integer).
|
||||
sth [r4 + 4], r3
|
||||
skip_enable_editor:
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
# Original patch by Gigobooma
|
||||
# https://docs.google.com/document/d/1zG73l9joEqp_zB-xNgK9g8pXL0RSpmXfxPFQcdAvess/edit
|
||||
|
||||
.meta visibility="all"
|
||||
.meta name="Episode 3 Plus"
|
||||
.meta description="Enables Episode 3\nPlus features.\nDoes not include\ntext fixes.\n\nOriginally created\nby Gigobooma"
|
||||
|
||||
@@ -11,7 +12,7 @@ reloc0:
|
||||
.offsetof start
|
||||
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
# Disable curse word filter
|
||||
.data <VERS 0x8012FAD0 0x8012FA4C 0x8012FED8>
|
||||
+4
-3
@@ -1,11 +1,12 @@
|
||||
# This patch replaces the prices and contents of Pinz's Shop.
|
||||
# Each entry is structured as follows:
|
||||
# This patch replaces the prices and contents of Pinz's Shop. Each entry is structured as follows:
|
||||
# uint16_t card_id;
|
||||
# int16_t min_clv; // -1 = limit doesn't apply
|
||||
# int16_t max_clv; // -1 = limit doesn't apply
|
||||
# uint16_t relative_chance;
|
||||
# The values in the patch data below are the defaults.
|
||||
# Uncomment the .meta visibility line to make this appear in the Patches menu.
|
||||
|
||||
# .meta visibility="all"
|
||||
.meta name="New Pinz cards"
|
||||
.meta description="Replaces the cards\navailable in Pinz's\nShop"
|
||||
|
||||
@@ -16,7 +17,7 @@ reloc0:
|
||||
.offsetof start
|
||||
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
# Meseta prices
|
||||
.data <VERS 0x80487140 0x80487E80 0x8048A260>
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
.meta visibility="cheat"
|
||||
.meta name="VIP card"
|
||||
.meta description="Gives you a VIP card"
|
||||
.meta hide_from_patches_menu
|
||||
|
||||
.versions 3SJT 3SJ0 3SE0 3SP0
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# This function implements $exit in a game when no quest is loaded.
|
||||
|
||||
.meta name="Exit anywhere"
|
||||
.meta description=""
|
||||
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
|
||||
|
||||
.versions 2OJ5 2OJF 2OEF 2OPF
|
||||
start:
|
||||
mov r2, 0
|
||||
mova r0, [addrs]
|
||||
mov.l r1, [r0]
|
||||
mov.l [r1], r2
|
||||
mov.l r1, [r0 + 4]
|
||||
mov.l [r1], r2
|
||||
mov r2, 1
|
||||
mov.l r1, [r0 + 8]
|
||||
rets
|
||||
mov.w [r1], r2
|
||||
.align 4
|
||||
addrs:
|
||||
.data <VERS 0x8C4ED300 0x8C4E6DA0 0x8C4ED300 0x8C4DC800>
|
||||
.data <VERS 0x8C4ED344 0x8C4E6DE4 0x8C4ED344 0x8C4DC844>
|
||||
.data <VERS 0x8C4E8D88 0x8C4E2828 0x8C4E8D88 0x8C4D8288>
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
start:
|
||||
li r0, 0
|
||||
stw [r13 - <VERS 0x4760 0x4758 0x4738 0x4738 0x4748 0x4748 0x4728 0x46E8>], r0
|
||||
stw [r13 - <VERS 0x475C 0x4754 0x4734 0x4734 0x4744 0x4744 0x4724 0x46E4>], r0
|
||||
li r0, 1
|
||||
sth [r13 - <VERS 0x4950 0x4948 0x4928 0x4928 0x4938 0x4938 0x4918 0x48D8>], r0
|
||||
blr
|
||||
|
||||
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
start:
|
||||
xor eax, eax
|
||||
mov [<VERS 0x0062D374 0x0062D914 0x0063544C 0x00632934 0x006321CC 0x00632934 0x00632CCC>], eax # is_in_quest = false
|
||||
mov [<VERS 0x0062D370 0x0062D910 0x00635448 0x00632930 0x006321C8 0x00632930 0x00632CC8>], eax # dat_source_type = NONE
|
||||
inc eax
|
||||
mov [<VERS 0x0071E8E8 0x0071EF48 0x00726A88 0x00723F88 0x00723808 0x00723F88 0x00724308>], ax # should_leave_game = true
|
||||
ret
|
||||
|
||||
|
||||
|
||||
.versions 59NJ 59NL
|
||||
start:
|
||||
xor eax, eax
|
||||
mov [<VERS 0x00A931A4 0x00A95624>], eax # is_in_quest = false
|
||||
mov [<VERS 0x00A93160 0x00A955E0>], eax # dat_source_type = NONE
|
||||
inc eax
|
||||
mov [<VERS 0x00AAC254 0x00AAE6D4>], ax # should_leave_game = true
|
||||
ret
|
||||
@@ -1,28 +0,0 @@
|
||||
# This function implements $exit in a game when no quest is loaded.
|
||||
|
||||
.meta name="Exit anywhere"
|
||||
.meta description=""
|
||||
.meta hide_from_patches_menu
|
||||
|
||||
.versions 2OJ5 2OJF 2OEF 2OPF
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
start:
|
||||
mov r2, 0
|
||||
mova r0, [addrs]
|
||||
mov.l r1, [r0]
|
||||
mov.l [r1], r2
|
||||
mov.l r1, [r0 + 4]
|
||||
mov.l [r1], r2
|
||||
mov r2, 1
|
||||
mov.l r1, [r0 + 8]
|
||||
rets
|
||||
mov.w [r1], r2
|
||||
.align 4
|
||||
addrs:
|
||||
.data <VERS 0x8C4ED300 0x8C4E6DA0 0x8C4ED300 0x8C4DC800>
|
||||
.data <VERS 0x8C4ED344 0x8C4E6DE4 0x8C4ED344 0x8C4DC844>
|
||||
.data <VERS 0x8C4E8D88 0x8C4E2828 0x8C4E8D88 0x8C4D8288>
|
||||
@@ -1,19 +0,0 @@
|
||||
# This function implements $exit in a game when no quest is loaded.
|
||||
|
||||
.meta name="Exit anywhere"
|
||||
.meta description=""
|
||||
.meta hide_from_patches_menu
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
start:
|
||||
li r0, 0
|
||||
stw [r13 - <VERS 0x4760 0x4758 0x4738 0x4738 0x4748 0x4748 0x4728 0x46E8>], r0
|
||||
stw [r13 - <VERS 0x475C 0x4754 0x4734 0x4734 0x4744 0x4744 0x4724 0x46E4>], r0
|
||||
li r0, 1
|
||||
sth [r13 - <VERS 0x4950 0x4948 0x4928 0x4928 0x4938 0x4938 0x4918 0x48D8>], r0
|
||||
blr
|
||||
@@ -1,19 +0,0 @@
|
||||
# This function implements $exit in a game when no quest is loaded.
|
||||
|
||||
.meta name="Exit anywhere"
|
||||
.meta description=""
|
||||
.meta hide_from_patches_menu
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
start:
|
||||
xor eax, eax
|
||||
mov [<VERS 0x0062D374 0x0062D914 0x0063544C 0x00632934 0x006321CC 0x00632934 0x00632CCC>], eax # is_in_quest = false
|
||||
mov [<VERS 0x0062D370 0x0062D910 0x00635448 0x00632930 0x006321C8 0x00632930 0x00632CC8>], eax # dat_source_type = NONE
|
||||
inc eax
|
||||
mov [<VERS 0x0071E8E8 0x0071EF48 0x00726A88 0x00723F88 0x00723808 0x00723F88 0x00724308>], ax # should_leave_game = true
|
||||
ret
|
||||
@@ -1,19 +0,0 @@
|
||||
# This function implements $exit in a game when no quest is loaded.
|
||||
|
||||
.meta name="Exit anywhere"
|
||||
.meta description=""
|
||||
.meta hide_from_patches_menu
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
start:
|
||||
xor eax, eax
|
||||
mov [<VERS 0x00A931A4 0x00A95624>], eax # is_in_quest = false
|
||||
mov [<VERS 0x00A93160 0x00A955E0>], eax # dat_source_type = NONE
|
||||
inc eax
|
||||
mov [<VERS 0x00AAC254 0x00AAE6D4>], ax # should_leave_game = true
|
||||
ret
|
||||
+4
-5
@@ -1,3 +1,4 @@
|
||||
.meta visibility="all"
|
||||
.meta name="Ext item info"
|
||||
.meta description="Shows more info\nbefore picking up\nan item"
|
||||
|
||||
@@ -7,7 +8,7 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.data <VERS 0x804CA3D8 0x804CDB28 0x804D0078 0x804CFE18 0x804CABA8 0x804CB088 0x804CF6F0 0x804CFAE0>
|
||||
.data 0x00000004
|
||||
@@ -132,8 +133,7 @@ set_window_state: # (TItem* item: r3) -> void
|
||||
cmplwi r3, 0
|
||||
beq window_should_not_exist
|
||||
|
||||
# Only show the window for weapons, armors, shields, and mags (not for
|
||||
# units, tools, or meseta)
|
||||
# Only show the window for weapons, armors, shields, and mags (not for units, tools, or meseta)
|
||||
lhz r4, [r3 + 0xEC] # data[0] and data[1]
|
||||
cmplwi r4, 0x0103
|
||||
beq window_should_not_exist
|
||||
@@ -145,8 +145,7 @@ set_window_state: # (TItem* item: r3) -> void
|
||||
cmplwi r3, 0
|
||||
bne window_should_not_exist
|
||||
|
||||
# If the TWindowMainMenu1P exists and is visible, the TWindowHelpItem should
|
||||
# not be visible
|
||||
# If the TWindowMainMenu1P exists and is visible, the TWindowHelpItem should not be visible
|
||||
lis r3, 0x8000
|
||||
lwz r3, [r3 + 0x4004]
|
||||
cmplwi r3, 0
|
||||
@@ -0,0 +1,96 @@
|
||||
.meta visibility="all"
|
||||
.meta name="Fast tekker"
|
||||
.meta description="Skips wind-up sound\nat tekker window"
|
||||
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
.versions 1OJ1 1OJ2 1OJ3 1OJ4 1OJF 1OEF 1OPF 2OJ4 2OJ5 2OJF 2OEF 2OPF
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C15B0CA 0x8C162302 0x8C175E66 0x8C1780AE 0x8C17600E 0x8C17863E 0x8C1783FA 0x8C19BD4A 0x8C19BD4A 0x8C19ADB6 0x8C19BD4A 0x8C19B7E2>
|
||||
.data 0x00000002
|
||||
mov r1, 1
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C15B0E6 0x8C16231E 0x8C175E82 0x8C1780CA 0x8C17602A 0x8C17865A 0x8C178416 0x8C19BD66 0x8C19BD66 0x8C19ADD2 0x8C19BD66 0x8C19B7FE>
|
||||
.data 0x00000002
|
||||
nop
|
||||
|
||||
.align 4
|
||||
|
||||
|
||||
|
||||
.versions 3OJT 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x8026FAE8 0x8021F8CC 0x80220250 0x80221154 0x80220EF0 0x80220170 0x80220170 0x80221224 0x80220ABC>
|
||||
.data 4
|
||||
li r0, 1
|
||||
|
||||
.data <VERS 0x8026FB10 0x8021F8F4 0x80220278 0x8022117C 0x80220F18 0x80220198 0x80220198 0x8022124C 0x80220AE4>
|
||||
.data 4
|
||||
nop
|
||||
|
||||
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x0023EC5C 0x0023EEAC 0x0023F21C 0x0023EF3C 0x0023F0BC 0x0023EF5C 0x0023F14C>
|
||||
.deltaof patch1_start, patch1_end
|
||||
patch1_start:
|
||||
mov dword [ebp + 0x14C], 1
|
||||
patch1_end:
|
||||
|
||||
.data <VERS 0x0023EC77 0x0023EEC7 0x0023F237 0x0023EF57 0x0023F0D7 0x0023EF77 0x0023F167>
|
||||
.deltaof patch2_start, patch2_end
|
||||
patch2_start:
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
patch2_end:
|
||||
|
||||
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
.data <VERS 0x006DA14B 0x006DA113>
|
||||
.deltaof patch1_start, patch1_end
|
||||
patch1_start:
|
||||
mov dword [edi + 0x14C], 1
|
||||
patch1_end:
|
||||
|
||||
.data <VERS 0x006DA168 0x006DA130>
|
||||
.deltaof patch2_start, patch2_end
|
||||
patch2_start:
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
patch2_end:
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,24 +0,0 @@
|
||||
.meta name="Fast tekker"
|
||||
.meta description="Skips wind-up sound\nat tekker window"
|
||||
|
||||
.versions 1OJ1 1OJ2 1OJ3 1OJ4 1OJF 1OEF 1OPF 2OJ4 2OJ5 2OJF 2OEF 2OPF
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksDC
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C15B0CA 0x8C162302 0x8C175E66 0x8C1780AE 0x8C17600E 0x8C17863E 0x8C1783FA 0x8C19BD4A 0x8C19BD4A 0x8C19ADB6 0x8C19BD4A 0x8C19B7E2>
|
||||
.data 0x00000002
|
||||
mov r1, 1
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C15B0E6 0x8C16231E 0x8C175E82 0x8C1780CA 0x8C17602A 0x8C17865A 0x8C178416 0x8C19BD66 0x8C19BD66 0x8C19ADD2 0x8C19BD66 0x8C19B7FE>
|
||||
.data 0x00000002
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,21 +0,0 @@
|
||||
.meta name="Fast tekker"
|
||||
.meta description="Skips wind-up sound\nat tekker window"
|
||||
|
||||
.versions 3OJT 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
|
||||
.data <VERS 0x8026FAE8 0x8021F8CC 0x80220250 0x80221154 0x80220EF0 0x80220170 0x80220170 0x80221224 0x80220ABC>
|
||||
.data 4
|
||||
li r0, 1
|
||||
|
||||
.data <VERS 0x8026FB10 0x8021F8F4 0x80220278 0x8022117C 0x80220F18 0x80220198 0x80220198 0x8022124C 0x80220AE4>
|
||||
.data 4
|
||||
nop
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,34 +0,0 @@
|
||||
.meta name="Fast tekker"
|
||||
.meta description="Skips wind-up sound\nat tekker window"
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
|
||||
.data <VERS 0x0023EC5C 0x0023EEAC 0x0023F21C 0x0023EF3C 0x0023F0BC 0x0023EF5C 0x0023F14C>
|
||||
.deltaof patch1_start, patch1_end
|
||||
patch1_start:
|
||||
mov dword [ebp + 0x14C], 1
|
||||
patch1_end:
|
||||
|
||||
.data <VERS 0x0023EC77 0x0023EEC7 0x0023F237 0x0023EF57 0x0023F0D7 0x0023EF77 0x0023F167>
|
||||
.deltaof patch2_start, patch2_end
|
||||
patch2_start:
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
patch2_end:
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,35 +0,0 @@
|
||||
.meta name="Fast tekker"
|
||||
.meta description="Skips wind-up sound\nat tekker window"
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksBB
|
||||
|
||||
.data <VERS 0x006DA14B 0x006DA113>
|
||||
.deltaof patch1_start, patch1_end
|
||||
patch1_start:
|
||||
mov dword [edi + 0x14C], 1
|
||||
patch1_end:
|
||||
|
||||
.data <VERS 0x006DA168 0x006DA130>
|
||||
.deltaof patch2_start, patch2_end
|
||||
patch2_start:
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
patch2_end:
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
+51
-5
@@ -1,17 +1,59 @@
|
||||
.meta name="Blinking SD"
|
||||
.meta description="Makes the Shifta\nand Deband status\nicons flicker when\nthey are about\nto run out"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# Xbox port by fuzziqersoftware
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
.meta visibility="all"
|
||||
.meta name="Blinking SD"
|
||||
.meta description="Makes the Shifta\nand Deband status\nicons flicker when\nthey are about\nto run out"
|
||||
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data 0x8000B86C
|
||||
.data 0x00000054
|
||||
.address 0x8000B86C
|
||||
code_start:
|
||||
mr r3, r0
|
||||
andi. r0, r31, 2
|
||||
beqlr
|
||||
lwz r4, [r3 + 0x0028]
|
||||
cmplwi r4, 0
|
||||
beqlr
|
||||
lwz r4, [r4]
|
||||
cmplwi r4, 0
|
||||
beqlr
|
||||
mulli r0, r31, 12
|
||||
add r5, r29, r0
|
||||
lwz r6, [r5 + 0x025C]
|
||||
cmplwi r6, 450
|
||||
bge full_intensity
|
||||
lbz r6, [r4 + 0x002C]
|
||||
subi r6, r6, 0x0008
|
||||
cmpwi r6, 0
|
||||
bge not_full_intensity
|
||||
full_intensity:
|
||||
li r6, 0x00FF
|
||||
not_full_intensity:
|
||||
stb [r4 + 0x002C], r6
|
||||
blr
|
||||
code_end:
|
||||
|
||||
.data <VERS 0x8026DF94 0x8026EC58 0x8026FCB4 0x8026FA68 0x8026E7F4 0x8026E7F4 0x8026FC1C 0x8026F464>
|
||||
.data 4
|
||||
.address <VERS 0x8026DF94 0x8026EC58 0x8026FCB4 0x8026FA68 0x8026E7F4 0x8026E7F4 0x8026FC1C 0x8026F464>
|
||||
bl code_start
|
||||
|
||||
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x0027782A 0x00277ADA 0x00277EEA 0x00277C0A 0x00277D2A 0x00277C2A 0x00277DFA>
|
||||
.data 5
|
||||
@@ -58,5 +100,9 @@ skip:
|
||||
jmp edx
|
||||
code_end:
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
|
||||
.data 0
|
||||
.data 0
|
||||
@@ -1,50 +0,0 @@
|
||||
.meta name="Blinking SD"
|
||||
.meta description="Makes the Shifta\nand Deband status\nicons flicker when\nthey are about\nto run out"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
|
||||
.data 0x8000B86C
|
||||
.data 0x00000054
|
||||
.address 0x8000B86C
|
||||
code_start:
|
||||
mr r3, r0
|
||||
andi. r0, r31, 2
|
||||
beqlr
|
||||
lwz r4, [r3 + 0x0028]
|
||||
cmplwi r4, 0
|
||||
beqlr
|
||||
lwz r4, [r4]
|
||||
cmplwi r4, 0
|
||||
beqlr
|
||||
mulli r0, r31, 12
|
||||
add r5, r29, r0
|
||||
lwz r6, [r5 + 0x025C]
|
||||
cmplwi r6, 450
|
||||
bge full_intensity
|
||||
lbz r6, [r4 + 0x002C]
|
||||
subi r6, r6, 0x0008
|
||||
cmpwi r6, 0
|
||||
bge not_full_intensity
|
||||
full_intensity:
|
||||
li r6, 0x00FF
|
||||
not_full_intensity:
|
||||
stb [r4 + 0x002C], r6
|
||||
blr
|
||||
code_end:
|
||||
|
||||
.data <VERS 0x8026DF94 0x8026EC58 0x8026FCB4 0x8026FA68 0x8026E7F4 0x8026E7F4 0x8026FC1C 0x8026F464>
|
||||
.data 4
|
||||
.address <VERS 0x8026DF94 0x8026EC58 0x8026FCB4 0x8026FA68 0x8026E7F4 0x8026E7F4 0x8026FC1C 0x8026F464>
|
||||
bl code_start
|
||||
|
||||
.data 0
|
||||
.data 0
|
||||
+5
-3
@@ -1,16 +1,18 @@
|
||||
.meta name="GC targets"
|
||||
.meta description="Changes the target\nreticle colors to\nthose used on the\nGameCube"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.meta visibility="all"
|
||||
.meta name="GC targets"
|
||||
.meta description="Changes the target\nreticle colors to\nthose used on the\nGameCube"
|
||||
|
||||
.versions 4OED 4OEU 4OJB 4OJD 4OJU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.data <VERS 0x0025BD09 0x0025BE29 0x0025B889 0x0025BC39 0x0025BFB9 0x0025BD29 0x0025BE59>
|
||||
.data 0x00000004
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="GetExtendedPlayerInfo"
|
||||
.meta key="GetExtendedPlayerInfo"
|
||||
.meta name="Get extended player info"
|
||||
.meta description=""
|
||||
|
||||
.versions 2OJ5 2OJF 2OEF 2OPF
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="GetExtendedPlayerInfo"
|
||||
.meta key="GetExtendedPlayerInfo"
|
||||
.meta name="Get extended player info"
|
||||
.meta description=""
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0 3SJT 3SJ0 3SE0 3SP0
|
||||
+4
-2
@@ -1,7 +1,9 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="GetExtendedPlayerInfo"
|
||||
.meta key="GetExtendedPlayerInfo"
|
||||
.meta name="Get extended player info"
|
||||
.meta description=""
|
||||
|
||||
.versions 3OJT
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="GetExtendedPlayerInfo"
|
||||
.meta key="GetExtendedPlayerInfo"
|
||||
.meta name="Get extended player info"
|
||||
.meta description=""
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
+75
-4
@@ -1,17 +1,55 @@
|
||||
.meta name="MAG alert"
|
||||
.meta description="Plays a sound when\nyour MAG is hungry"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# Xbox port by fuzziqersoftware
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
.meta visibility="all"
|
||||
.meta name="Mag alert"
|
||||
.meta description="Plays a sound when\nyour Mag is hungry"
|
||||
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.label play_sound, <VERS 0x800336AC 0x800336DC 0x800336F8 0x8003368C 0x800338CC 0x800338CC 0x80033894 0x8003390C>
|
||||
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.data 0x8000BF30
|
||||
.deltaof code_start, code_end
|
||||
.address 0x8000BF30
|
||||
code_start: # [std] (TItemMag* this @ r3) -> void
|
||||
lwz r4, [r3 + 0xF0]
|
||||
lhz r4, [r4 + 0x1C] # r4 = this->owner_player->entity_id
|
||||
lwz r5, [r13 - <VERS 0x5298 0x5290 0x5270 0x5270 0x5280 0x5280 0x5260 0x5220>] # local_client_id
|
||||
cmpl r4, r5
|
||||
bnelr
|
||||
lis r3, 0x0002
|
||||
ori r3, r3, 0x2825
|
||||
li r4, 0
|
||||
b play_sound
|
||||
code_end:
|
||||
|
||||
.data <VERS 0x80110D94 0x80110F94 0x80111080 0x80110F20 0x80111038 0x80111038 0x80110F30 0x80111114>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x80110D94 0x80110F94 0x80111080 0x80110F20 0x80111038 0x80111038 0x80110F30 0x80111114>
|
||||
b code_start
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
start:
|
||||
.include WriteCodeBlocks
|
||||
|
||||
.data <VERS 0x00180EF5 0x00181075 0x00181125 0x00181065 0x00181095 0x00181085 0x00181055>
|
||||
.data 0x0A
|
||||
@@ -81,3 +119,36 @@ hook6_end:
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
|
||||
|
||||
.versions 59NJ 59NL
|
||||
|
||||
start:
|
||||
pop ecx
|
||||
push 6
|
||||
push <VERS 0x005D91BE 0x005D91E2>
|
||||
call get_code_size
|
||||
.deltaof patch_code, patch_code_end
|
||||
get_code_size:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end
|
||||
patch_code: # [eax] (TItemMag* this @ ecx) -> void
|
||||
mov dword [ecx + 0x01B8], eax
|
||||
mov eax, [ecx + 0x00F8]
|
||||
movzx eax, word [eax + 0x001C] # eax = this->owner_player->entity_id
|
||||
cmp [<VERS 0x00A9A074 0x00A9C4F4>], eax
|
||||
jne patch_code_skip_sound
|
||||
push 0
|
||||
push 0
|
||||
push 0
|
||||
push 0xAC
|
||||
mov eax, <VERS 0x00815020 0x00814298>
|
||||
call eax
|
||||
add esp, 0x10
|
||||
patch_code_skip_sound:
|
||||
ret
|
||||
patch_code_end:
|
||||
push ecx
|
||||
.include WriteCallToCode
|
||||
@@ -1,38 +0,0 @@
|
||||
.meta name="Mag alert"
|
||||
.meta description="Plays a sound when\nyour Mag is hungry"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
|
||||
.label play_sound, <VERS 0x800336AC 0x800336DC 0x800336F8 0x8003368C 0x800338CC 0x800338CC 0x80033894 0x8003390C>
|
||||
|
||||
.data 0x8000BF30
|
||||
.deltaof code_start, code_end
|
||||
.address 0x8000BF30
|
||||
code_start: # [std] (TItemMag* this @ r3) -> void
|
||||
lwz r4, [r3 + 0xF0]
|
||||
lhz r4, [r4 + 0x1C] # r4 = this->owner_player->entity_id
|
||||
lwz r5, [r13 - <VERS 0x5298 0x5290 0x5270 0x5270 0x5280 0x5280 0x5260 0x5220>] # local_client_id
|
||||
cmpl r4, r5
|
||||
bnelr
|
||||
lis r3, 0x0002
|
||||
ori r3, r3, 0x2825
|
||||
li r4, 0
|
||||
b play_sound
|
||||
code_end:
|
||||
|
||||
.data <VERS 0x80110D94 0x80110F94 0x80111080 0x80110F20 0x80111038 0x80111038 0x80110F30 0x80111114>
|
||||
.data 0x00000004
|
||||
.address <VERS 0x80110D94 0x80110F94 0x80111080 0x80110F20 0x80111038 0x80111038 0x80110F30 0x80111114>
|
||||
b code_start
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,34 +0,0 @@
|
||||
.meta name="MAG alert"
|
||||
.meta description="Plays a sound when\nyour MAG is hungry"
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
pop ecx
|
||||
push 6
|
||||
push 0x005D91BE
|
||||
call get_code_size
|
||||
.deltaof patch_code, patch_code_end
|
||||
get_code_size:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end
|
||||
patch_code: # [eax] (TItemMag* this @ ecx) -> void
|
||||
mov dword [ecx + 0x01B8], eax
|
||||
mov eax, [ecx + 0x00F8]
|
||||
movzx eax, word [eax + 0x001C] # eax = this->owner_player->entity_id
|
||||
cmp [0x00A9A074], eax
|
||||
jne patch_code_skip_sound
|
||||
push 0
|
||||
push 0
|
||||
push 0
|
||||
push 0xAC
|
||||
mov eax, 0x00815020
|
||||
call eax
|
||||
add esp, 0x10
|
||||
patch_code_skip_sound:
|
||||
ret
|
||||
patch_code_end:
|
||||
push ecx
|
||||
.include WriteCallToCode-59NJ
|
||||
@@ -1,34 +0,0 @@
|
||||
.meta name="MAG alert"
|
||||
.meta description="Plays a sound when\nyour MAG is hungry"
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
pop ecx
|
||||
push 6
|
||||
push 0x005D91E2
|
||||
call get_code_size
|
||||
.deltaof patch_code, patch_code_end
|
||||
get_code_size:
|
||||
pop eax
|
||||
push dword [eax]
|
||||
call patch_code_end
|
||||
patch_code: # [eax] (TItemMag* this @ ecx) -> void
|
||||
mov dword [ecx + 0x01B8], eax
|
||||
mov eax, [ecx + 0x00F8]
|
||||
movzx eax, word [eax + 0x001C] # eax = this->owner_player->entity_id
|
||||
cmp [0x00A9C4F4], eax
|
||||
jne patch_code_skip_sound
|
||||
push 0
|
||||
push 0
|
||||
push 0
|
||||
push 0xAC
|
||||
mov eax, 0x00814298
|
||||
call eax
|
||||
add esp, 0x10
|
||||
patch_code_skip_sound:
|
||||
ret
|
||||
patch_code_end:
|
||||
push ecx
|
||||
.include WriteCallToCode-59NL
|
||||
@@ -0,0 +1,45 @@
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# DC and Xbox ports by fuzziqersoftware
|
||||
|
||||
.meta visibility="all"
|
||||
.meta name="Invisible MAG"
|
||||
.meta description="Makes MAGs invisible"
|
||||
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
.versions 1OJ2 1OJ3 1OJ4 1OJF 1OEF 1OPF 2OJ4 2OJ5 2OJF 2OEF 2OPF
|
||||
.align 4
|
||||
.data <VERS 0x8C1AADD8 0x8C1C7408 0x8C1C9E9C 0x8C1C75B4 0x8C1CA49C 0x8C1CA240 0x8C1F27E8 0x8C1F27E8 0x8C1F17F0 0x8C1F27E8 0x8C1F2354>
|
||||
.data 0x00000004
|
||||
rets
|
||||
nop
|
||||
.align 4
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
.data <VERS 0x80114F04 0x80115118 0x8011521C 0x801150B0 0x801151A8 0x801151A8 0x801150C0 0x80115298>
|
||||
.data 0x00000004
|
||||
.data 0x480000D4
|
||||
|
||||
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
.data <VERS 0x001837C1 0x00183951 0x00183A01 0x00183941 0x00183971 0x00183961 0x00183931>
|
||||
.data 0x00000002
|
||||
.binary 90E9
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,24 +0,0 @@
|
||||
.meta name="Invisible MAG"
|
||||
.meta description="Makes MAGs invisible"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# DC port by fuzziqersoftware
|
||||
|
||||
.versions 1OJ2 1OJ3 1OJ4 1OJF 1OEF 1OPF 2OJ4 2OJ5 2OJF 2OEF 2OPF
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksDC
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C1AADD8 0x8C1C7408 0x8C1C9E9C 0x8C1C75B4 0x8C1CA49C 0x8C1CA240 0x8C1F27E8 0x8C1F27E8 0x8C1F17F0 0x8C1F27E8 0x8C1F2354>
|
||||
.data 0x00000004
|
||||
rets
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,20 +0,0 @@
|
||||
.meta name="Invisible MAG"
|
||||
.meta description="Makes MAGs invisible"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksGC
|
||||
|
||||
.data <VERS 0x80114F04 0x80115118 0x8011521C 0x801150B0 0x801151A8 0x801151A8 0x801150C0 0x80115298>
|
||||
.data 0x00000004
|
||||
.data 0x480000D4
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,19 +0,0 @@
|
||||
.meta name="Invisible MAG"
|
||||
.meta description="Makes MAGs invisible"
|
||||
# Original code by Ralf @ GC-Forever and Aleron Ives
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2050
|
||||
# https://www.gc-forever.com/forums/viewtopic.php?t=2049
|
||||
# Xbox port by fuzziqersoftware
|
||||
|
||||
.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksXB
|
||||
.data <VERS 0x001837C1 0x00183951 0x00183A01 0x00183941 0x00183971 0x00183961 0x00183931>
|
||||
.data 0x00000002
|
||||
.binary 90E9
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -0,0 +1,240 @@
|
||||
.meta visibility="all"
|
||||
.meta name="No item loss"
|
||||
.meta description="Disables logic that\ndeletes items if\nyou don't log off\nnormally"
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocks
|
||||
|
||||
|
||||
|
||||
.versions 1OJ4 1OEF 1OPF
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C0254B2 0x8C0254BE 0x8C0254D2>
|
||||
.data 4
|
||||
bs +0x38
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C150B2C 0x8C150F9C 0x8C150D58>
|
||||
.data 2
|
||||
sett
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C15F346 0x8C15F856 0x8C15F612>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C16053A 0x8C160A4A 0x8C160806>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C1617DA 0x8C161D6A 0x8C161B26>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C15F3BA 0x8C15F8CA 0x8C15F686>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C1605A6 0x8C160AB6 0x8C160872>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C161808 0x8C161D98 0x8C161B54>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
|
||||
|
||||
|
||||
.versions 1OJ2
|
||||
|
||||
.align 4
|
||||
.data 0x8C14C71A
|
||||
.data 2
|
||||
nop
|
||||
.align 4
|
||||
|
||||
|
||||
|
||||
.versions 2OJ4 2OJ5 2OJF 2OEF 2OPF
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C0280AA 0x8C0280AA 0x8C028276 0x8C0280AA 0x8C0280AA>
|
||||
.data 6
|
||||
nop
|
||||
bs +0x2C
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C16BDFE 0x8C16BDFE 0x8C16B50A 0x8C16BDFE 0x8C16BA22>
|
||||
.data 2
|
||||
sett
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C17F1DC 0x8C17F1DC 0x8C17E738 0x8C17F1DC 0x8C17EC74>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C17F2BA 0x8C17F2BA 0x8C17E816 0x8C17F2BA 0x8C17ED52>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C180D0A 0x8C180D0A 0x8C18005A 0x8C180D0A 0x8C1807A2>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C180DB0 0x8C180DB0 0x8C180100 0x8C180DB0 0x8C180848>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C181BC4 0x8C181BC4 0x8C180EC8 0x8C181BC4 0x8C18165C>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C181C92 0x8C181C92 0x8C180F96 0x8C181C92 0x8C18172A>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C182BC6 0x8C182BC6 0x8C181DBE 0x8C182BC6 0x8C18265E>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C182BF4 0x8C182BF4 0x8C181DEC 0x8C182BF4 0x8C18268C>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C1834D0 0x8C1834D0 0x8C1825F0 0x8C1834D0 0x8C182F68>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
|
||||
|
||||
|
||||
.versions 3OJ2 3OJ3 3OJ4 3OJ5 3OE0 3OE1 3OE2 3OP0
|
||||
|
||||
.data <VERS 0x801D33E4 0x801D38EC 0x801D3CC4 0x801D39B8 0x801D381C 0x801D381C 0x801D3A1C 0x801D3ED8>
|
||||
.data 0x00000004
|
||||
b +0x4C
|
||||
|
||||
.data <VERS 0x801FE900 0x801FF174 0x8020010C 0x801FF710 0x801FF0FC 0x801FF0FC 0x801FFA44 0x801FF9E0>
|
||||
.data 0x00000004
|
||||
nop
|
||||
|
||||
.data <VERS 0x801FFE5C 0x802006D0 0x802016CC 0x80200C9C 0x80200658 0x80200658 0x80200FD0 0x80200F3C>
|
||||
.data 0x00000004
|
||||
nop
|
||||
|
||||
.data <VERS 0x802019C8 0x8020223C 0x801FD944 0x80202860 0x802021C4 0x802021C4 0x80202B94 0x80202AA8>
|
||||
.data 0x00000004
|
||||
li r0, 0
|
||||
|
||||
.data <VERS 0x802C2060 0x802C2F98 0x802C42E4 0x802C3E78 0x802C2A40 0x802C2A84 0x802C402C 0x802C37C0>
|
||||
.data 0x00000004
|
||||
b +0x4C
|
||||
|
||||
.data <VERS 0x802D0AA0 0x802D1A58 0x802D2C10 0x802D2938 0x802D1480 0x802D14C4 0x802D2AEC 0x802D2280>
|
||||
.data 0x00000004
|
||||
b +0x20
|
||||
|
||||
|
||||
|
||||
.versions 4OED 4OEU 4OJB 4OJD 4OJU 4OPD 4OPU
|
||||
|
||||
.data <VERS 0x000D1B85 0x000D1BD5 0x000D1A35 0x000D1B05 0x000D1AF5 0x000D1BA5 0x000D1BD5>
|
||||
.data 0x00000001
|
||||
.binary 00
|
||||
|
||||
.data <VERS 0x000D1BFC 0x000D1C4C 0x000D1AAC 0x000D1B7C 0x000D1B6C 0x000D1C1C 0x000D1C4C>
|
||||
.data 0x00000002
|
||||
.binary EB08
|
||||
|
||||
.data <VERS 0x0020E805 0x0020E805 0x0020E5D5 0x0020E755 0x0020E9D5 0x0020E825 0x0020E895>
|
||||
.data 0x00000001
|
||||
.binary EB
|
||||
|
||||
.data <VERS 0x002119CA 0x00211A2A 0x0021170A 0x0021197A 0x00211BFA 0x002119EA 0x00211ABA>
|
||||
.data 0x00000002
|
||||
.binary EB74
|
||||
|
||||
.data <VERS 0x002291B5 0x00229255 0x00228F15 0x00229125 0x00229415 0x002291D5 0x002292E5>
|
||||
.data 0x00000002
|
||||
.binary 9090
|
||||
|
||||
.data <VERS 0x00229237 0x002292D7 0x00228F97 0x002291A7 0x00229497 0x00229257 0x00229367>
|
||||
.data 0x00000002
|
||||
.binary EB08
|
||||
|
||||
.data <VERS 0x0022A222 0x0022A2C2 0x00229F82 0x0022A192 0x0022A482 0x0022A242 0x0022A352>
|
||||
.data 0x00000002
|
||||
.binary 9090
|
||||
|
||||
.data <VERS 0x0022A29B 0x0022A33B 0x00229FFB 0x0022A20B 0x0022A4FB 0x0022A2BB 0x0022A3CB>
|
||||
.data 0x00000002
|
||||
.binary EB08
|
||||
|
||||
.data <VERS 0x0022BF35 0x0022BFD5 0x0022BC95 0x0022BEA5 0x0022C195 0x0022BF55 0x0022C065>
|
||||
.data 0x00000001
|
||||
.binary 00
|
||||
|
||||
.data <VERS 0x0022BF6E 0x0022C00E 0x0022BCCE 0x0022BEDE 0x0022C1CE 0x0022BF8E 0x0022C09E>
|
||||
.data 0x00000002
|
||||
.binary EB08
|
||||
|
||||
.data <VERS 0x0022C2E6 0x0022C386 0x0022C046 0x0022C256 0x0022C546 0x0022C306 0x0022C416>
|
||||
.data 0x00000001
|
||||
.binary 00
|
||||
|
||||
.data <VERS 0x002418E8 0x00241A78 0x00241608 0x00241858 0x00241BD8 0x00241908 0x00241B08>
|
||||
.data 0x00000001
|
||||
.binary 00
|
||||
|
||||
.data <VERS 0x0024195C 0x00241AEC 0x0024167C 0x002418CC 0x00241C4C 0x0024197C 0x00241B7C>
|
||||
.data 0x00000002
|
||||
.binary EB08
|
||||
|
||||
.data <VERS 0x002A2904 0x002A2B34 0x002A0FA4 0x002A19F4 0x002A2EC4 0x002A2924 0x002A2BF4>
|
||||
.data 0x00000001
|
||||
.binary 00
|
||||
|
||||
.data <VERS 0x002A297C 0x002A2BAC 0x002A101C 0x002A1A6C 0x002A2F3C 0x002A299C 0x002A2C6C>
|
||||
.data 0x00000002
|
||||
.binary EB08
|
||||
|
||||
.data <VERS 0x002D677A 0x002D6C8A 0x002D481A 0x002D53DA 0x002D6CBA 0x002D67AA 0x002D6D0A>
|
||||
.data 0x00000001
|
||||
.binary 00
|
||||
|
||||
.data <VERS 0x002D67ED 0x002D6CFD 0x002D488D 0x002D544D 0x002D6D2D 0x002D681D 0x002D6D7D>
|
||||
.data 0x00000002
|
||||
.binary EB08
|
||||
|
||||
.data <VERS 0x002F0E1E 0x002F0FCE 0x002EEEBE 0x002EF9CE 0x002F0FCE 0x002F0E4E 0x002F103E>
|
||||
.data 0x00000001
|
||||
.binary EB
|
||||
|
||||
|
||||
|
||||
.all_versions
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,17 +0,0 @@
|
||||
.meta name="No item loss"
|
||||
.meta description="Disables logic that\ndeletes items if\nyou don't log off\nnormally"
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksDC
|
||||
|
||||
.align 4
|
||||
.data 0x8C14C71A
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
@@ -1,55 +0,0 @@
|
||||
.meta name="No item loss"
|
||||
.meta description="Disables logic that\ndeletes items if\nyou don't log off\nnormally"
|
||||
|
||||
.versions 1OJ4 1OEF 1OPF
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include WriteCodeBlocksDC
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C0254B2 0x8C0254BE 0x8C0254D2>
|
||||
.data 4
|
||||
bs +0x38
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C150B2C 0x8C150F9C 0x8C150D58>
|
||||
.data 2
|
||||
sett
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C15F346 0x8C15F856 0x8C15F612>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C16053A 0x8C160A4A 0x8C160806>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C1617DA 0x8C161D6A 0x8C161B26>
|
||||
.data 2
|
||||
and r0, 0xFE
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C15F3BA 0x8C15F8CA 0x8C15F686>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C1605A6 0x8C160AB6 0x8C160872>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data <VERS 0x8C161808 0x8C161D98 0x8C161B54>
|
||||
.data 2
|
||||
nop
|
||||
|
||||
.align 4
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user