fix game flag translation across v2/v3 boundary
This commit is contained in:
@@ -4982,9 +4982,7 @@ struct G_6x70_Base_DCNTE {
|
||||
/* 0002 */ le_uint16_t room_id = 0;
|
||||
/* 0004 */ le_uint32_t flags1 = 0;
|
||||
/* 0008 */ VectorXYZF pos;
|
||||
/* 0014 */ le_uint32_t angle_x = 0;
|
||||
/* 0018 */ le_uint32_t angle_y = 0;
|
||||
/* 001C */ le_uint32_t angle_z = 0;
|
||||
/* 0014 */ VectorXYZI angle;
|
||||
/* 0020 */ le_uint16_t unknown_a3a = 0;
|
||||
/* 0022 */ le_uint16_t current_hp = 0;
|
||||
} __packed_ws__(G_6x70_Base_DCNTE, 0x24);
|
||||
|
||||
@@ -28,6 +28,23 @@ static void set_log_level_from_json(
|
||||
}
|
||||
}
|
||||
|
||||
void set_all_log_levels(phosg::LogLevel level) {
|
||||
channel_exceptions_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;
|
||||
player_data_log.min_level = level;
|
||||
proxy_server_log.min_level = level;
|
||||
replay_log.min_level = level;
|
||||
server_log.min_level = level;
|
||||
static_game_data_log.min_level = 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_log, json, "Clients");
|
||||
|
||||
@@ -18,4 +18,5 @@ extern phosg::PrefixedLogger replay_log;
|
||||
extern phosg::PrefixedLogger server_log;
|
||||
extern phosg::PrefixedLogger static_game_data_log;
|
||||
|
||||
void set_all_log_levels(phosg::LogLevel level);
|
||||
void set_log_levels_from_json(const phosg::JSON& json);
|
||||
|
||||
@@ -3195,6 +3195,9 @@ Action a_run_server_replay_log(
|
||||
}
|
||||
|
||||
auto state = make_shared<ServerState>(get_config_filename(args));
|
||||
if (args.get<bool>("debug")) {
|
||||
state->is_debug = true;
|
||||
}
|
||||
state->load_all(true);
|
||||
|
||||
if (state->dns_server_port) {
|
||||
|
||||
+7
-62
@@ -5848,55 +5848,12 @@ uint32_t MapState::RareEnemyRates::for_enemy_type(EnemyType type) const {
|
||||
}
|
||||
}
|
||||
|
||||
const shared_ptr<const MapState::RareEnemyRates> MapState::NO_RARE_ENEMIES = make_shared<MapState::RareEnemyRates>(
|
||||
0, 0, 0);
|
||||
const shared_ptr<const MapState::RareEnemyRates> MapState::NO_RARE_ENEMIES = make_shared<MapState::RareEnemyRates>(0, 0, 0);
|
||||
const shared_ptr<const MapState::RareEnemyRates> MapState::DEFAULT_RARE_ENEMIES = make_shared<MapState::RareEnemyRates>(
|
||||
MapState::RareEnemyRates::DEFAULT_RARE_ENEMY_RATE_V3,
|
||||
MapState::RareEnemyRates::DEFAULT_MERICARAND_RATE_V3,
|
||||
MapState::RareEnemyRates::DEFAULT_RARE_BOSS_RATE_V4);
|
||||
|
||||
uint32_t MapState::EnemyState::convert_game_flags(uint32_t game_flags, bool to_v3) {
|
||||
// The format of game_flags was changed significantly between v2 and v3, and
|
||||
// not accounting for this results in odd effects like other characters not
|
||||
// appearing when joining a game. Unfortunately, some bits were deleted on v3
|
||||
// and other bits were added, so it doesn't suffice to simply store the most
|
||||
// complete format of this field - we have to be able to convert between the
|
||||
// two.
|
||||
|
||||
// Bits on v2: ?IHCBAzy xwvutsrq ponmlkji hgfedcba
|
||||
// Bits on v3: ?IHGFEDC BAzyxwvu srqponkj hgfedcba
|
||||
// The bits ilmt were removed in v3 and the bits to their left were shifted
|
||||
// right. The bits DEFG were added in v3 and do not exist on v2.
|
||||
// Known meanings for these bits:
|
||||
// o = is dead
|
||||
// n = should play hit animation
|
||||
// y = is near enemy
|
||||
// H = is enemy?
|
||||
// I = is object? (some entities have both H and I set though)
|
||||
|
||||
// TODO: The above might all be wrong.
|
||||
// GC 00100000 10010000 00001110 00000000
|
||||
// PC 00101001 00000000 01100100 00000000
|
||||
|
||||
// PC 00101001 10110000 00101110 00000000
|
||||
// GC 00100000 10011011 00000111 00000000
|
||||
|
||||
// PC 00101001 10010000 00101110 00000000
|
||||
// GC 00100000 10011001 00000111 00000000
|
||||
|
||||
if (to_v3) {
|
||||
return (game_flags & 0xE00000FF) |
|
||||
((game_flags & 0x00000600) >> 1) |
|
||||
((game_flags & 0x0007E000) >> 3) |
|
||||
((game_flags & 0x1FF00000) >> 4);
|
||||
} else {
|
||||
return (game_flags & 0xE00000FF) |
|
||||
((game_flags << 1) & 0x00000600) |
|
||||
((game_flags << 3) & 0x0007E000) |
|
||||
((game_flags << 4) & 0x1FF00000);
|
||||
}
|
||||
}
|
||||
|
||||
MapState::EntityIterator::EntityIterator(MapState* map_state, Version version, bool at_end)
|
||||
: map_state(map_state),
|
||||
version(version),
|
||||
@@ -6413,7 +6370,6 @@ void MapState::import_object_states_from_sync(
|
||||
void MapState::import_enemy_states_from_sync(Version from_version, const SyncEnemyStateEntry* entries, size_t entry_count) {
|
||||
this->log.info_f("Importing enemy state from sync command");
|
||||
size_t enemy_index = 0;
|
||||
bool is_v3 = !is_v1_or_v2(from_version);
|
||||
for (const auto& fc : this->floor_config_entries) {
|
||||
if (!fc.super_map) {
|
||||
continue;
|
||||
@@ -6434,15 +6390,10 @@ void MapState::import_enemy_states_from_sync(Version from_version, const SyncEne
|
||||
if (ene_st->super_ene != ene) {
|
||||
throw logic_error("super enemy link is incorrect");
|
||||
}
|
||||
if (ene_st->get_game_flags(is_v3) != entry.flags) {
|
||||
this->log.warning_f("({:04X} => E-{:03X}) Flags from client ({:08X}({})) do not match game flags from map ({:08X}({}))",
|
||||
enemy_index,
|
||||
ene_st->e_id,
|
||||
entry.flags,
|
||||
is_v3 ? "v3" : "v2",
|
||||
ene_st->game_flags,
|
||||
(ene_st->server_flags & MapState::EnemyState::Flag::GAME_FLAGS_IS_V3) ? "v3" : "v2");
|
||||
ene_st->set_game_flags(entry.flags, !is_v1_or_v2(from_version));
|
||||
if (ene_st->game_flags != entry.flags) {
|
||||
this->log.warning_f("({:04X} => E-{:03X}) Flags from client ({:08X}) do not match game flags from map ({:08X})",
|
||||
enemy_index, ene_st->e_id, entry.flags, ene_st->game_flags);
|
||||
ene_st->game_flags = entry.flags;
|
||||
}
|
||||
if (ene_st->total_damage != entry.total_damage) {
|
||||
this->log.warning_f("({:04X} => E-{:03X}) Total damage from client ({}) does not match total damage from map ({})",
|
||||
@@ -6771,14 +6722,8 @@ void MapState::print(FILE* stream) const {
|
||||
}
|
||||
}
|
||||
string ene_str = ene_st->super_ene->str();
|
||||
phosg::fwrite_fmt(stream, " {} total_damage={:04X} rare_flags={:04X} game_flags={:08X}({}) set_flags={:04X} server_flags={:04X}\n",
|
||||
ene_str,
|
||||
ene_st->total_damage,
|
||||
ene_st->rare_flags,
|
||||
ene_st->game_flags,
|
||||
(ene_st->server_flags & MapState::EnemyState::Flag::GAME_FLAGS_IS_V3) ? "v3" : "v2",
|
||||
ene_st->set_flags,
|
||||
ene_st->server_flags);
|
||||
phosg::fwrite_fmt(stream, " {} total_damage={:04X} rare_flags={:04X} game_flags={:08X} set_flags={:04X} server_flags={:04X}\n",
|
||||
ene_str, ene_st->total_damage, ene_st->rare_flags, ene_st->game_flags, ene_st->set_flags, ene_st->server_flags);
|
||||
}
|
||||
|
||||
if (this->bb_rare_enemy_indexes.empty()) {
|
||||
|
||||
-20
@@ -716,7 +716,6 @@ public:
|
||||
ITEM_DROPPED = 0x0008,
|
||||
ALL_HITS_MASK_FIRST = 0x0010,
|
||||
ALL_HITS_MASK = 0x00F0,
|
||||
GAME_FLAGS_IS_V3 = 0x0100,
|
||||
};
|
||||
size_t e_id = 0;
|
||||
size_t set_id = 0;
|
||||
@@ -727,8 +726,6 @@ public:
|
||||
uint16_t set_flags = 0; // Only used if super_ene->child_index == 0
|
||||
uint16_t server_flags = 0;
|
||||
|
||||
static uint32_t convert_game_flags(uint32_t game_flags, bool to_v3);
|
||||
|
||||
inline void reset() {
|
||||
this->total_damage = 0;
|
||||
this->rare_flags = 0;
|
||||
@@ -737,23 +734,6 @@ public:
|
||||
this->server_flags = 0;
|
||||
}
|
||||
|
||||
inline void set_game_flags(uint32_t game_flags, bool is_v3) {
|
||||
this->game_flags = game_flags;
|
||||
if (is_v3) {
|
||||
this->server_flags |= Flag::GAME_FLAGS_IS_V3;
|
||||
} else {
|
||||
this->server_flags &= ~Flag::GAME_FLAGS_IS_V3;
|
||||
}
|
||||
}
|
||||
inline uint32_t get_game_flags(bool is_v3) const {
|
||||
bool flags_is_v3 = (this->server_flags & Flag::GAME_FLAGS_IS_V3);
|
||||
if (flags_is_v3 == is_v3) {
|
||||
return this->game_flags;
|
||||
} else {
|
||||
return this->convert_game_flags(this->game_flags, is_v3);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_rare(Version version) const {
|
||||
return (((this->rare_flags >> static_cast<size_t>(version)) & 1) ||
|
||||
((version == Version::BB_V4) ? this->super_ene->is_default_rare_bb : this->super_ene->is_default_rare_v123));
|
||||
|
||||
+41
-21
@@ -1154,10 +1154,42 @@ G_6x70_Base_V1 Parsed6x70Data::base_v1(bool is_v3) const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t Parsed6x70Data::convert_game_flags(uint32_t game_flags, bool to_v3) {
|
||||
// The format of game_flags for players was changed significantly between v2
|
||||
// and v3, and not accounting for this results in odd effects like other
|
||||
// characters not appearing when joining a game. Unfortunately, some bits
|
||||
// were deleted on v3 and other bits were added, so it doesn't suffice to
|
||||
// simply store the most complete format of this field - we have to be able
|
||||
// to convert between the two.
|
||||
|
||||
// Bits on v2: ?IHCBAzy xwvutsrq ponmlkji hgfedcba
|
||||
// Bits on v3: ?IHGFEDC BAzyxwvu srqponkj hgfedcba
|
||||
// The bits ilmt were removed in v3 and the bits to their left were shifted
|
||||
// right. The bits DEFG were added in v3 and do not exist on v2.
|
||||
// Known meanings for these bits:
|
||||
// o = is dead
|
||||
// n = should play hit animation
|
||||
// y = is near enemy
|
||||
// H = is enemy?
|
||||
// I = is object? (some entities have both H and I set though)
|
||||
|
||||
if (to_v3) {
|
||||
return (game_flags & 0xE00000FF) |
|
||||
((game_flags & 0x00000600) >> 1) |
|
||||
((game_flags & 0x0007E000) >> 3) |
|
||||
((game_flags & 0x1FF00000) >> 4);
|
||||
} else {
|
||||
return (game_flags & 0xE00000FF) |
|
||||
((game_flags << 1) & 0x00000600) |
|
||||
((game_flags << 3) & 0x0007E000) |
|
||||
((game_flags << 4) & 0x1FF00000);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Parsed6x70Data::get_game_flags(bool is_v3) const {
|
||||
return (this->game_flags_is_v3 == is_v3)
|
||||
? this->game_flags
|
||||
: MapState::EnemyState::convert_game_flags(this->game_flags, is_v3);
|
||||
: Parsed6x70Data::convert_game_flags(this->game_flags, is_v3);
|
||||
}
|
||||
|
||||
static asio::awaitable<void> on_sync_joining_player_disp_and_inventory(
|
||||
@@ -3423,36 +3455,29 @@ static asio::awaitable<void> on_update_enemy_state(shared_ptr<Client> c, Subcomm
|
||||
if ((cmd.enemy_index & 0xF000) || (cmd.header.entity_id != (cmd.enemy_index | 0x1000))) {
|
||||
throw runtime_error("mismatched enemy id/index");
|
||||
}
|
||||
bool is_v3 = !is_v1_or_v2(c->version());
|
||||
auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.enemy_index);
|
||||
uint32_t src_flags = is_big_endian(c->version()) ? bswap32(cmd.game_flags) : cmd.game_flags.load();
|
||||
if (l->difficulty == 3) {
|
||||
src_flags = (src_flags & 0xFFFFFFC0) | (ene_st->get_game_flags(is_v3) & 0x0000003F);
|
||||
src_flags = (src_flags & 0xFFFFFFC0) | (ene_st->game_flags & 0x0000003F);
|
||||
}
|
||||
ene_st->set_game_flags(src_flags, is_v3);
|
||||
ene_st->game_flags = src_flags;
|
||||
ene_st->total_damage = cmd.total_damage;
|
||||
ene_st->set_last_hit_by_client_id(c->lobby_client_id);
|
||||
l->log.info_f("E-{:03X} updated to damage={} game_flags={:08X} ({})",
|
||||
ene_st->e_id,
|
||||
ene_st->total_damage,
|
||||
ene_st->game_flags,
|
||||
(ene_st->server_flags & MapState::EnemyState::Flag::GAME_FLAGS_IS_V3) ? "v3" : "v2");
|
||||
l->log.info_f("E-{:03X} updated to damage={} game_flags={:08X}", ene_st->e_id, ene_st->total_damage, ene_st->game_flags);
|
||||
|
||||
for (auto lc : l->clients) {
|
||||
if (lc && (lc != c)) {
|
||||
cmd.enemy_index = l->map_state->index_for_enemy_state(lc->version(), ene_st);
|
||||
if (cmd.enemy_index != 0xFFFF) {
|
||||
cmd.header.entity_id = 0x1000 | cmd.enemy_index;
|
||||
uint32_t game_flags = ene_st->get_game_flags(!is_v1_or_v2(lc->version()));
|
||||
cmd.game_flags = is_big_endian(lc->version()) ? phosg::bswap32(game_flags) : game_flags;
|
||||
cmd.game_flags = is_big_endian(lc->version()) ? phosg::bswap32(ene_st->game_flags) : ene_st->game_flags;
|
||||
send_command_t(lc, 0x60, 0x00, cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static asio::awaitable<void> on_set_enemy_low_game_flags_ultimate(
|
||||
shared_ptr<Client> c, SubcommandMessage& msg) {
|
||||
static asio::awaitable<void> on_set_enemy_low_game_flags_ultimate(shared_ptr<Client> c, SubcommandMessage& msg) {
|
||||
auto& cmd = msg.check_size_t<G_SetEnemyLowGameFlagsUltimate_6x9C>();
|
||||
|
||||
if (command_is_private(msg.command) ||
|
||||
@@ -3467,15 +3492,10 @@ static asio::awaitable<void> on_set_enemy_low_game_flags_ultimate(
|
||||
co_return;
|
||||
}
|
||||
|
||||
bool is_v3 = !is_v1_or_v2(c->version());
|
||||
auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.header.entity_id - 0x1000);
|
||||
uint32_t game_flags = ene_st->get_game_flags(is_v3);
|
||||
if (!(game_flags & cmd.low_game_flags)) {
|
||||
ene_st->set_game_flags(game_flags | cmd.low_game_flags, is_v3);
|
||||
l->log.info_f("E-{:03X} updated to game_flags={:08X} ({})",
|
||||
ene_st->e_id,
|
||||
ene_st->game_flags,
|
||||
(ene_st->server_flags & MapState::EnemyState::Flag::GAME_FLAGS_IS_V3) ? "v3" : "v2");
|
||||
if (!(ene_st->game_flags & cmd.low_game_flags)) {
|
||||
ene_st->game_flags |= cmd.low_game_flags;
|
||||
l->log.info_f("E-{:03X} updated to game_flags={:08X}", ene_st->e_id, ene_st->game_flags);
|
||||
}
|
||||
|
||||
co_await forward_subcommand_with_entity_id_transcode_t<G_SetEnemyLowGameFlagsUltimate_6x9C>(c, msg);
|
||||
|
||||
@@ -121,6 +121,7 @@ protected:
|
||||
Version from_version,
|
||||
bool from_client_customization);
|
||||
G_6x70_Base_V1 base_v1(bool is_v3) const;
|
||||
static uint32_t convert_game_flags(uint32_t game_flags, bool to_v3);
|
||||
uint32_t get_game_flags(bool is_v3) const;
|
||||
};
|
||||
|
||||
|
||||
+1
-2
@@ -2786,10 +2786,9 @@ void send_game_enemy_state(shared_ptr<Client> c) {
|
||||
auto s = c->require_server_state();
|
||||
|
||||
vector<SyncEnemyStateEntry> entries;
|
||||
bool is_v3 = !is_v1_or_v2(c->version());
|
||||
for (auto ene_st : l->map_state->iter_enemy_states(c->version())) {
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.flags = ene_st->get_game_flags(is_v3);
|
||||
entry.flags = ene_st->game_flags;
|
||||
entry.item_drop_id = (ene_st->server_flags & MapState::EnemyState::Flag::ITEM_DROPPED)
|
||||
? 0xFFFF
|
||||
: (0xCA0 + l->map_state->index_for_enemy_state(c->version(), ene_st));
|
||||
|
||||
+5
-1
@@ -1059,7 +1059,11 @@ void ServerState::load_config_early() {
|
||||
this->exp_share_multiplier = this->config_json->get_float("BBEXPShareMultiplier", 0.5);
|
||||
this->server_global_drop_rate_multiplier = this->config_json->get_float("ServerGlobalDropRateMultiplier", 1);
|
||||
|
||||
set_log_levels_from_json(this->config_json->get("LogLevels", phosg::JSON::dict()));
|
||||
if (this->is_debug) {
|
||||
set_all_log_levels(phosg::LogLevel::L_DEBUG);
|
||||
} else {
|
||||
set_log_levels_from_json(this->config_json->get("LogLevels", phosg::JSON::dict()));
|
||||
}
|
||||
|
||||
try {
|
||||
this->run_shell_behavior = this->config_json->at("RunInteractiveShell").as_bool()
|
||||
|
||||
@@ -109,6 +109,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
uint64_t client_ping_interval_usecs = 30000000;
|
||||
uint64_t client_idle_timeout_usecs = 60000000;
|
||||
uint64_t patch_client_idle_timeout_usecs = 300000000;
|
||||
bool is_debug = false;
|
||||
bool ip_stack_debug = false;
|
||||
bool allow_unregistered_users = false;
|
||||
bool allow_pc_nte = false;
|
||||
|
||||
@@ -119,7 +119,7 @@ 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 to the displayed four characters
|
||||
# not the index only within the displayed four characters
|
||||
push 6 # Call size
|
||||
push 0x00413CD8 # Call address
|
||||
call get_code_size_for_fix_scroll_patch2
|
||||
@@ -166,7 +166,7 @@ selection_index_fix2_end:
|
||||
|
||||
apply_preview_window_fix:
|
||||
# This patch fixes the preview display so it will show the correct section
|
||||
# ID, etc.
|
||||
# ID, level, etc.
|
||||
push 5 # Call size
|
||||
push 0x0040216C # Call address
|
||||
call get_code_size_for_preview_window_fix
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80134FE0
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80134FE0
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80135050
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80134D3C
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80134FA0
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80135108
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80135040
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x801352D0
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80092380
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x8009242C
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80092C78
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -9,7 +9,7 @@ start:
|
||||
|
||||
.data 0x80092588
|
||||
.data 0x00000004
|
||||
.data 0x38600000
|
||||
li r3, 0
|
||||
|
||||
.data 0x00000000
|
||||
.data 0x00000000
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# 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 PSOX 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.
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user