diff --git a/src/Lobby.cc b/src/Lobby.cc index 88465372..e1afba77 100644 --- a/src/Lobby.cc +++ b/src/Lobby.cc @@ -21,6 +21,7 @@ Lobby::Lobby(uint32_t id) episode(Episode::NONE), mode(GameMode::NORMAL), difficulty(0), + exp_multiplier(1), random_seed(random_object()), event(0), block(0), diff --git a/src/Lobby.hh b/src/Lobby.hh index 911533c1..b25437c0 100644 --- a/src/Lobby.hh +++ b/src/Lobby.hh @@ -69,6 +69,7 @@ struct Lobby : public std::enable_shared_from_this { Episode episode; GameMode mode; uint8_t difficulty; // 0-3 + uint16_t exp_multiplier; std::u16string password; std::u16string name; // This seed is also sent to the client for rare enemy generation diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 72ef7f40..ddcae4be 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -3417,6 +3417,9 @@ static void on_6F(shared_ptr s, shared_ptr c, c->flags &= (~Client::Flag::LOADING); send_resume_game(l, c); + if (l->version == GameVersion::BB) { + send_set_exp_multiplier(l); + } send_server_time(c); // Only get player info again on BB, since on other versions the returned info // only includes items that would be saved if the client disconnects diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index d82b62c0..cf650352 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -1447,7 +1447,7 @@ static void on_enemy_killed_bb(shared_ptr s, uint32_t experience = 0xFFFFFFFF; try { - experience = s->battle_params->get(l->mode == GameMode::SOLO, l->episode, l->difficulty, e.type).experience; + experience = s->battle_params->get(l->mode == GameMode::SOLO, l->episode, l->difficulty, e.type).experience * l->exp_multiplier; } catch (const exception& e) { if (c->options.debug) { send_text_message_printf(c, "$C5E-%hX __MISSING__\n%s", cmd.enemy_id.load(), e.what()); @@ -1472,9 +1472,8 @@ static void on_enemy_killed_bb(shared_ptr s, if (experience != 0xFFFFFFFF) { // Killer gets full experience, others get 77% - uint32_t player_exp = (e.last_hit_by_client_id == other_c->lobby_client_id) - ? experience - : ((experience * 77) / 100); + bool is_killer = (e.last_hit_by_client_id == other_c->lobby_client_id); + uint32_t player_exp = is_killer ? experience : ((experience * 77) / 100); other_c->game_data.player()->disp.experience += player_exp; send_give_experience(l, other_c, player_exp); @@ -1498,6 +1497,8 @@ static void on_enemy_killed_bb(shared_ptr s, if (leveled_up) { send_level_up(l, other_c); } + + // TODO: Update kill counts on unsealable items } } } diff --git a/src/SendCommands.cc b/src/SendCommands.cc index aea82e1e..6d05d47f 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2082,13 +2082,23 @@ void send_give_experience(shared_ptr l, shared_ptr c, if (c->version() != GameVersion::BB) { throw logic_error("6xBF can only be sent to BB clients"); } - uint16_t client_id = c->lobby_client_id; G_GiveExperience_BB_6xBF cmd = { {0xBF, sizeof(G_GiveExperience_BB_6xBF) / 4, client_id}, amount}; send_command_t(l, 0x60, 0x00, cmd); } +void send_set_exp_multiplier(std::shared_ptr l) { + if (l->version != GameVersion::BB) { + throw logic_error("6xDD can only be sent to BB clients"); + } + if (!l->is_game()) { + throw logic_error("6xDD can only be sent in games (not in lobbies)"); + } + G_SetEXPMultiplier_BB_6xDD cmd = {{0xBF, sizeof(G_SetEXPMultiplier_BB_6xDD) / 4, l->exp_multiplier}}; + send_command_t(l, 0x60, 0x00, cmd); +} + void send_rare_enemy_index_list(shared_ptr c, const vector& indexes) { S_RareMonsterList_BB_DE cmd; if (indexes.size() > cmd.enemy_ids.size()) { diff --git a/src/SendCommands.hh b/src/SendCommands.hh index e07c92f3..59c6d012 100644 --- a/src/SendCommands.hh +++ b/src/SendCommands.hh @@ -322,6 +322,7 @@ void send_shop(std::shared_ptr c, uint8_t shop_type); void send_level_up(std::shared_ptr l, std::shared_ptr c); void send_give_experience(std::shared_ptr l, std::shared_ptr c, uint32_t amount); +void send_set_exp_multiplier(std::shared_ptr l); void send_rare_enemy_index_list(std::shared_ptr c, const std::vector& indexes); void send_ep3_card_list_update( std::shared_ptr s, std::shared_ptr c);