diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 46000938..1574a9dd 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -148,7 +148,6 @@ static void proxy_command_lobby_info(shared_ptr, msg += string_printf("%zX", z); } } - msg += "\n"; vector cheats_tokens; if (session.options.switch_assist) { @@ -1052,6 +1051,8 @@ static void proxy_command_item(shared_ptr, return; } + bool set_drop = (!args.empty() && (args[0] == u'!')); + string data = parse_data_string(encode_sjis(args)); if (data.size() < 2) { send_text_message(session.client_channel, u"$C6Item codes must be\n2 bytes or more"); @@ -1071,11 +1072,19 @@ static void proxy_command_item(shared_ptr, memcpy(&item.data.data2, data.data() + 12, data.size() - 12); } - send_drop_stacked_item(session.client_channel, item.data, session.area, session.x, session.z); - send_drop_stacked_item(session.server_channel, item.data, session.area, session.x, session.z); + if (set_drop) { + session.next_drop_item = item; - string name = name_for_item(item.data, true); - send_text_message(session.client_channel, u"$C7Item created:\n" + decode_sjis(name)); + string name = name_for_item(session.next_drop_item.data, true); + send_text_message(session.client_channel, u"$C7Next drop:\n" + decode_sjis(name)); + + } else { + send_drop_stacked_item(session.client_channel, item.data, session.area, session.x, session.z); + send_drop_stacked_item(session.server_channel, item.data, session.area, session.x, session.z); + + string name = name_for_item(item.data, true); + send_text_message(session.client_channel, u"$C7Item created:\n" + decode_sjis(name)); + } } diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index 89d02445..1759412e 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -939,6 +939,37 @@ static HandlerResult S_6x(shared_ptr, session.log.warning("Blocking subcommand 6x49 with invalid count"); return HandlerResult::Type::SUPPRESS; } + + } else if ((data[0] == 0x60) && + session.next_drop_item.data.data1d[0] && + (session.version != GameVersion::BB)) { + const auto& cmd = check_size_t(data, + sizeof(G_EnemyDropItemRequest_DC_6x60), + sizeof(G_EnemyDropItemRequest_PC_V3_BB_6x60)); + session.next_drop_item.data.id = session.next_item_id++; + send_drop_item(session.server_channel, session.next_drop_item.data, + true, cmd.area, cmd.x, cmd.z, cmd.request_id); + send_drop_item(session.client_channel, session.next_drop_item.data, + true, cmd.area, cmd.x, cmd.z, cmd.request_id); + session.next_drop_item.clear(); + return HandlerResult::Type::SUPPRESS; + + // Note: This static_cast is required to make compilers not complain that + // the comparison is always false (which even happens in some environments + // if we use -0x5E... apparently char is unsigned on some systems, or + // std::string's char_type isn't char??) + } else if ((static_cast(data[0]) == 0xA2) && + session.next_drop_item.data.data1d[0] && + (session.version != GameVersion::BB)) { + const auto& cmd = check_size_t(data); + session.next_drop_item.data.id = session.next_item_id++; + send_drop_item(session.server_channel, session.next_drop_item.data, + false, cmd.area, cmd.x, cmd.z, cmd.request_id); + send_drop_item(session.client_channel, session.next_drop_item.data, + false, cmd.area, cmd.x, cmd.z, cmd.request_id); + session.next_drop_item.clear(); + return HandlerResult::Type::SUPPRESS; + } else if ((static_cast(data[0]) == 0xB5) && (session.version == GameVersion::GC) && (data.size() > 4)) { diff --git a/src/ProxyServer.hh b/src/ProxyServer.hh index 7d143032..1375914e 100644 --- a/src/ProxyServer.hh +++ b/src/ProxyServer.hh @@ -65,6 +65,7 @@ public: ClientConfigBB newserv_client_config; std::deque should_forward_function_call_return_queue; G_SwitchStateChanged_6x05 last_switch_enabled_command; + PlayerInventoryItem next_drop_item; uint32_t next_item_id; struct LobbyPlayer { diff --git a/src/ServerShell.cc b/src/ServerShell.cc index 2d743e19..af95c9db 100644 --- a/src/ServerShell.cc +++ b/src/ServerShell.cc @@ -216,8 +216,10 @@ Proxy commands:\n\ responds as if the function was called (with the given return value), but\n\ does not send the code to the client. To stop blocking function calls, omit\n\ the return value.\n\ - set-next-item \n\ - Set the next item to be dropped as if the client had run the $item command.\n\ + create-item \n\ + Create an item as if the client had run the $item command.\n\ + set-next-item \n\ + Set the next item to be dropped.\n\ close-idle-sessions\n\ Closes all sessions that don\'t have a client and server connected.\n\ \n\ @@ -635,7 +637,7 @@ session with ID 17205AE4, run the command `on 17205AE4 sc 1D 00 04 00`.\n\ session->options.function_call_return_value = stoul(command_args); } - } else if (command_name == "set-next-item") { + } else if ((command_name == "create-item") || (command_name == "set-next-item")) { auto session = this->get_proxy_session(session_name); if (session->version == GameVersion::BB) { @@ -665,11 +667,19 @@ session with ID 17205AE4, run the command `on 17205AE4 sc 1D 00 04 00`.\n\ memcpy(&item.data.data2, data.data() + 12, data.size() - 12); } - send_drop_stacked_item(session->client_channel, item.data, session->area, session->x, session->z); - send_drop_stacked_item(session->server_channel, item.data, session->area, session->x, session->z); + if (command_name == "set-next-item") { + session->next_drop_item = item; - string name = name_for_item(item.data, true); - send_text_message(session->client_channel, u"$C7Item created:\n" + decode_sjis(name)); + string name = name_for_item(session->next_drop_item.data, true); + send_text_message(session->client_channel, u"$C7Next drop:\n" + decode_sjis(name)); + + } else { + send_drop_stacked_item(session->client_channel, item.data, session->area, session->x, session->z); + send_drop_stacked_item(session->server_channel, item.data, session->area, session->x, session->z); + + string name = name_for_item(item.data, true); + send_text_message(session->client_channel, u"$C7Item created:\n" + decode_sjis(name)); + } } else if (command_name == "close-idle-sessions") { size_t count = this->state->proxy_server->delete_disconnected_sessions();