add extension for fractional EXP multipliers on BB

This commit is contained in:
Martin Michelsen
2025-09-21 13:16:28 -07:00
parent 4236ff62b1
commit 65384435a3
8 changed files with 88 additions and 16 deletions
+10 -1
View File
@@ -6404,12 +6404,21 @@ struct G_Episode4BossActions_BB_6xDC {
// 6xDD: Set EXP multiplier (BB)
// header.param specifies the EXP multiplier. It is 1-based, so the value 2
// means all EXP is doubled, for example.
// means all EXP is doubled, for example. This only affects what the client
// shows when an enemy is killed; actual EXP gains are controlled by the server
// in response to the 6xC8 command.
// newserv supports an extension to this command that supports fractional
// multipliers. This is implemented in FractionalEXPMultiplier.59NL.patch.s.
struct G_SetEXPMultiplier_BB_6xDD {
G_ParameterHeader header;
} __packed_ws__(G_SetEXPMultiplier_BB_6xDD, 4);
struct G_SetFractionalEXPMultiplier_Extension_BB_6xDD {
G_ParameterHeader header;
le_float multiplier;
} __packed_ws__(G_SetEXPMultiplier_BB_6xDD, 4);
// 6xDE: Exchange Secret Lottery Ticket (BB; handled by server)
// The client sends this when it executes an F95C quest opcode.
// There appears to be a bug in the client here: it sets the subcommand size to
+2 -2
View File
@@ -154,8 +154,8 @@ Lobby::Lobby(shared_ptr<ServerState> s, uint32_t id, bool is_game)
episode(Episode::NONE),
mode(GameMode::NORMAL),
difficulty(0),
base_exp_multiplier(1),
exp_share_multiplier(0.5),
base_exp_multiplier(1.0f),
exp_share_multiplier(0.5f),
challenge_exp_multiplier(1.0f),
random_seed(phosg::random_object<uint32_t>()),
rand_crypt(make_shared<DisabledRandomGenerator>()),
+1 -1
View File
@@ -120,7 +120,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
Episode episode;
GameMode mode;
uint8_t difficulty; // 0-3
uint16_t base_exp_multiplier;
float base_exp_multiplier;
float exp_share_multiplier;
float challenge_exp_multiplier;
std::string password;
+1 -5
View File
@@ -4040,11 +4040,7 @@ static asio::awaitable<void> on_enemy_exp_request_bb(shared_ptr<Client> c, Subco
l->challenge_exp_multiplier *
(is_ep2 ? 1.3 : 1.0);
if (lc->check_flag(Client::Flag::DEBUG_ENABLED)) {
send_text_message_fmt(
lc, "$C5+{} E-{:03X} {}",
player_exp,
ene_st->e_id,
phosg::name_for_enum(type));
send_text_message_fmt(lc, "$C5+{} E-{:03X} {}", player_exp, ene_st->e_id, phosg::name_for_enum(type));
}
if (lc->character_file()->disp.stats.level < 199) {
add_player_exp(lc, player_exp);
+5 -1
View File
@@ -3261,7 +3261,11 @@ void send_set_exp_multiplier(shared_ptr<Lobby> l) {
if (!l->is_game()) {
throw logic_error("6xDD can only be sent in games (not in lobbies)");
}
G_SetEXPMultiplier_BB_6xDD cmd = {{0xDD, sizeof(G_SetEXPMultiplier_BB_6xDD) / 4, (l->mode == GameMode::CHALLENGE) ? 1 : l->base_exp_multiplier}};
G_SetFractionalEXPMultiplier_Extension_BB_6xDD cmd = {{0xDD, sizeof(G_SetEXPMultiplier_BB_6xDD) / 4, 1}, 1.0f};
if (l->mode != GameMode::CHALLENGE) {
cmd.header.param = l->base_exp_multiplier;
cmd.multiplier = l->base_exp_multiplier;
}
for (auto lc : l->clients) {
if (lc && (lc->version() == Version::BB_V4)) {
send_command_t(lc, 0x60, 0x00, cmd);
+3 -3
View File
@@ -1083,9 +1083,9 @@ void ServerState::load_config_early() {
}
}
this->bb_global_exp_multiplier = this->config_json->get_int("BBGlobalEXPMultiplier", 1);
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);
this->bb_global_exp_multiplier = this->config_json->get_float("BBGlobalEXPMultiplier", 1.0f);
this->exp_share_multiplier = this->config_json->get_float("BBEXPShareMultiplier", 0.5f);
this->server_global_drop_rate_multiplier = this->config_json->get_float("ServerGlobalDropRateMultiplier", 1.0f);
if (this->is_debug) {
set_all_log_levels(phosg::LogLevel::L_DEBUG);
+3 -3
View File
@@ -241,9 +241,9 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
std::vector<QuestF960Result> quest_F960_success_results;
QuestF960Result quest_F960_failure_results;
std::vector<ItemData> secret_lottery_results;
uint16_t bb_global_exp_multiplier = 1;
float exp_share_multiplier = 0.5;
double server_global_drop_rate_multiplier = 1.0;
float bb_global_exp_multiplier = 1.0f;
float exp_share_multiplier = 0.5f;
float server_global_drop_rate_multiplier = 1.0f;
std::shared_ptr<Episode3::TournamentIndex> ep3_tournament_index;
@@ -0,0 +1,63 @@
# This patch changes the 6xDD command to support fractional multipliers.
.meta name="Fractional EXP multiplier"
.meta description=""
.meta hide_from_patches_menu
entry_ptr:
reloc0:
.offsetof start
start:
call install_hook
call apply_static_patches
fild st0, dword [0x009F9EE0]
fstp dword [0x009F9EE0], st0
ret
install_hook:
pop ecx
push 7
push 0x0078747E
call get_code_size
.deltaof hook_start, hook_end
get_code_size:
pop eax
push dword [eax]
call hook_end
hook_start: # [eax, ebx]() -> void
push edx
fild st0, dword [esp]
fld st0, dword [0x009F9EE0]
fmulp st1, st0
fistp dword [esp], st0
pop edx
ret
hook_end:
push ecx
.include WriteCallToCode-59NL
apply_static_patches:
.include WriteCodeBlocksBB
.data 0x00787998
.deltaof handle_6xDD_start, handle_6xDD_end
handle_6xDD_start: # [std](G_6xDD* cmd @ [esp + 4]) -> void
mov eax, [esp + 4]
test eax, eax
je handle_6xDD_ret
cmp byte [eax + 1], 1
jg handle_6xDD_use_float
fild st0, word [eax + 2]
jmp handle_6xDD_write_float
handle_6xDD_use_float:
fld st0, dword [eax + 4]
handle_6xDD_write_float:
fstp dword [0x009F9EE0], st0
handle_6xDD_ret:
ret
handle_6xDD_end:
.data 0x00000000
.data 0x00000000