diff --git a/README.md b/README.md index fb5bab4e..439e508b 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,7 @@ Some commands only work on the game server and not on the proxy server. The chat * `$si` (game server only): Shows basic information about the server. * `$ping`: Shows round-trip ping time from the server to you. On the proxy server, shows the ping time from you to the proxy and from the proxy to the server. * `$matcount` (game server only): Shows how many of each type of material you've used. + * `$rarenotifs` (game server only): Enables or disables rare drop notifications. When enabled, you'll see a message whenever a rare item drops. In private drop mode, you will only see a notification if the item is visible to you; you won't be notified of other players' rare drops. * `$what` (game server only): Shows the type, name, and stats of the nearest item on the ground. * `$where` (game server only): Shows your current floor number and coordinates. Mainly useful for debugging. diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index fa7cb618..94e8dc36 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -1478,6 +1478,12 @@ static void proxy_command_song(shared_ptr ses, const send_ep3_change_music(ses->client_channel, song); } +static void server_command_rare_notifs(shared_ptr c, const std::string&) { + c->config.toggle_flag(Client::Flag::RARE_DROP_NOTIFICATIONS_ENABLED); + bool enabled = c->config.check_flag(Client::Flag::RARE_DROP_NOTIFICATIONS_ENABLED); + send_text_message_printf(c, "$C6Rare notifications\n%s", enabled ? "enabled" : "disabled"); +} + static void server_command_infinite_hp(shared_ptr c, const std::string&) { auto s = c->require_server_state(); auto l = c->require_lobby(); @@ -1994,6 +2000,7 @@ static const unordered_map chat_commands({ {"$qsyncall", {server_command_qsyncall, proxy_command_qsyncall}}, {"$quest", {server_command_quest, nullptr}}, {"$rand", {server_command_rand, proxy_command_rand}}, + {"$rarenotifs", {server_command_rare_notifs, nullptr}}, {"$save", {server_command_save, nullptr}}, {"$savechar", {server_command_savechar, nullptr}}, {"$saverec", {server_command_saverec, nullptr}}, diff --git a/src/Client.hh b/src/Client.hh index d3819b82..8c3332ad 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -68,10 +68,11 @@ public: SHOULD_SEND_ENABLE_SAVE = 0x0004000000000000, SWITCH_ASSIST_ENABLED = 0x0000000100000000, - // Cheat mode flags + // Cheat mode and option flags INFINITE_HP_ENABLED = 0x0000000200000000, INFINITE_TP_ENABLED = 0x0000000400000000, DEBUG_ENABLED = 0x0000000800000000, + RARE_DROP_NOTIFICATIONS_ENABLED = 0x0010000000000000, // Proxy option flags PROXY_SAVE_FILES = 0x0000001000000000, diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index f424b4f2..e17cf23c 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -1539,6 +1539,16 @@ static void on_buy_shop_item(shared_ptr c, uint8_t command, uint8_t flag forward_subcommand_with_item_transcode_t(c, command, flag, cmd); } +static void send_rare_notification_if_needed(shared_ptr to_c, const ItemData& item) { + auto s = to_c->require_server_state(); + if (!to_c->config.check_flag(Client::Flag::RARE_DROP_NOTIFICATIONS_ENABLED) || + !s->item_parameter_table(to_c->version())->is_item_rare(item)) { + return; + } + string name = s->describe_item(to_c->version(), item, true); + send_text_message_printf(to_c, "$C6Rare item dropped:\n%s", name.c_str()); +} + template static void on_box_or_enemy_item_drop_t(shared_ptr c, uint8_t command, uint8_t flag, void* data, size_t size) { // I'm lazy and this should never happen for item commands (since all players @@ -1568,22 +1578,25 @@ static void on_box_or_enemy_item_drop_t(shared_ptr c, uint8_t command, u l->leader_id, item.id.load(), name.c_str(), cmd.item.floor, cmd.item.x.load(), cmd.item.z.load()); for (auto& lc : l->clients) { - if (!lc || lc == c) { + if (!lc) { continue; } - if (c->version() != lc->version()) { - CmdT out_cmd = cmd; - out_cmd.header.subcommand = translate_subcommand_number(lc->version(), c->version(), out_cmd.header.subcommand); - if (out_cmd.header.subcommand) { - out_cmd.item.item.decode_for_version(c->version()); - out_cmd.item.item.encode_for_version(lc->version(), s->item_parameter_table(lc->version())); - send_command_t(lc, command, flag, out_cmd); + if (lc != c) { + if (c->version() != lc->version()) { + CmdT out_cmd = cmd; + out_cmd.header.subcommand = translate_subcommand_number(lc->version(), c->version(), out_cmd.header.subcommand); + if (out_cmd.header.subcommand) { + out_cmd.item.item.decode_for_version(c->version()); + out_cmd.item.item.encode_for_version(lc->version(), s->item_parameter_table(lc->version())); + send_command_t(lc, command, flag, out_cmd); + } else { + lc->log.info("Subcommand cannot be translated to client\'s version"); + } } else { - lc->log.info("Subcommand cannot be translated to client\'s version"); + send_command_t(lc, command, flag, cmd); } - } else { - send_command_t(lc, command, flag, cmd); } + send_rare_notification_if_needed(lc, item); } } @@ -2144,6 +2157,7 @@ static void on_entity_drop_item_request(shared_ptr c, uint8_t command, u item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load(), lc->channel.name.c_str()); l->add_item(cmd.floor, item, cmd.x, cmd.z, (1 << lc->lobby_client_id)); send_drop_item_to_channel(s, lc->channel, item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id); + send_rare_notification_if_needed(lc, item); } } @@ -2153,6 +2167,11 @@ static void on_entity_drop_item_request(shared_ptr c, uint8_t command, u item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load()); l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F); send_drop_item_to_lobby(l, item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id); + for (auto lc : l->clients) { + if (lc) { + send_rare_notification_if_needed(lc, item); + } + } } } break; @@ -2171,6 +2190,7 @@ static void on_entity_drop_item_request(shared_ptr c, uint8_t command, u item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load(), lc->channel.name.c_str()); l->add_item(cmd.floor, item, cmd.x, cmd.z, (1 << lc->lobby_client_id)); send_drop_item_to_channel(s, lc->channel, item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id); + send_rare_notification_if_needed(lc, item); } } }