enable dcv1 native battle mode

This commit is contained in:
Martin Michelsen
2025-01-20 21:24:39 -08:00
parent 721b01a294
commit aa9e1e7305
21 changed files with 77 additions and 205 deletions
-17
View File
@@ -381,23 +381,6 @@ ChatCommandDefinition cc_bank(
},
unavailable_on_proxy_server);
ChatCommandDefinition cc_battle(
{"$battle"},
+[](const ServerArgs& a) {
a.check_is_game(false);
if (!is_v1(a.c->version())) {
throw precondition_failed("$C6This command can\nonly be used on\nDC v1 and earlier");
}
a.c->config.toggle_flag(Client::Flag::FORCE_BATTLE_MODE_GAME);
if (a.c->config.check_flag(Client::Flag::FORCE_BATTLE_MODE_GAME)) {
send_text_message(a.c, "$C6Battle mode enabled\nfor next game");
} else {
send_text_message(a.c, "$C6Battle mode disabled\nfor next game");
}
},
unavailable_on_proxy_server);
static void server_command_bbchar_savechar(const ServerArgs& a, bool is_bb_conversion) {
auto s = a.c->require_server_state();
auto l = a.c->require_lobby();
+1 -2
View File
@@ -35,7 +35,7 @@ public:
// TODO: It'd be nice to use a pattern here (e.g. all server-side flags are
// in the high bits) but that would require re-recording or manually
// rewriting all the tests
CLIENT_SIDE_MASK = 0xE73CFFFF7C0BFFFB,
CLIENT_SIDE_MASK = 0xEF3CFFFF7C0BFFFB,
// Version-related flags
CHECKED_FOR_DC_V1_PROTOTYPE = 0x0000000000000002,
@@ -81,7 +81,6 @@ public:
DEBUG_ENABLED = 0x0000000800000000,
ITEM_DROP_NOTIFICATIONS_1 = 0x0010000000000000,
ITEM_DROP_NOTIFICATIONS_2 = 0x0020000000000000,
FORCE_BATTLE_MODE_GAME = 0x0800000000000000, // Server-side only
// Proxy option flags
PROXY_SAVE_FILES = 0x0000001000000000,
+15 -11
View File
@@ -351,7 +351,7 @@ struct C_LegacyLogin_PC_V3_03 {
/* 08 */ le_uint32_t sub_version = 0;
/* 0C */ uint8_t is_extended = 0;
/* 0D */ uint8_t language = 0;
/* 0E */ le_uint16_t unknown_a2 = 0;
/* 0E */ le_uint16_t unused = 0;
// Note: These are suffixed with 2 since they come from the same source data
// as the corresponding fields in 9D/9E. (Even though serial_number and
// serial_number2 have the same contents in 9E, they do not come from the same
@@ -407,7 +407,7 @@ struct C_LegacyLogin_PC_V3_04 {
/* 08 */ le_uint32_t sub_version = 0;
/* 0C */ uint8_t is_extended = 0;
/* 0D */ uint8_t language = 0;
/* 0E */ le_uint16_t unknown_a2 = 0;
/* 0E */ le_uint16_t unused = 0;
/* 10 */ pstring<TextEncoding::ASCII, 0x10> serial_number;
/* 20 */ pstring<TextEncoding::ASCII, 0x10> access_key;
/* 30 */
@@ -682,7 +682,7 @@ struct C_MenuSelection_10_Flag00 {
template <TextEncoding Encoding>
struct C_MenuSelectionT_10_Flag01 {
C_MenuSelection_10_Flag00 basic_cmd;
pstring<Encoding, 0x10> unknown_a1;
pstring<Encoding, 0x10> name;
} __packed__;
using C_MenuSelection_DC_V3_10_Flag01 = C_MenuSelectionT_10_Flag01<TextEncoding::MARKED>;
using C_MenuSelection_PC_BB_10_Flag01 = C_MenuSelectionT_10_Flag01<TextEncoding::UTF16>;
@@ -702,7 +702,7 @@ check_struct_size(C_MenuSelection_PC_BB_10_Flag02, 0x28);
template <TextEncoding Encoding>
struct C_MenuSelectionT_10_Flag03 {
C_MenuSelection_10_Flag00 basic_cmd;
pstring<Encoding, 0x10> unknown_a1;
pstring<Encoding, 0x10> name;
pstring<Encoding, 0x10> password;
} __packed__;
using C_MenuSelection_DC_V3_10_Flag03 = C_MenuSelectionT_10_Flag03<TextEncoding::MARKED>;
@@ -861,8 +861,10 @@ struct S_ReconnectSplit_19 {
// 20: Invalid command
// 21: GameGuard control (old versions of BB)
// Format unknown
// 21: Invalid command
// My old notes call this command "GameGuard control (old versions of BB)", but
// it's not clear if this is accurate. At least, BB US v1.24.3 and later do not
// support this command.
// 0022: GameGuard check (BB)
@@ -891,8 +893,6 @@ struct SC_GameGuardCheck_BB_0022 {
// failure.
struct S_ExchangeSecretLotteryTicketResult_BB_24 {
// These fields map to unknown_a1 and unknown_a2 in the 6xDE command (but
// their order is swapped here).
le_uint16_t label = 0;
uint8_t start_index = 0;
uint8_t unused = 0;
@@ -1316,10 +1316,14 @@ struct LobbyFlags {
uint8_t disable_udp = 1;
uint8_t lobby_number = 0;
uint8_t block_number = 0;
uint8_t unknown_a1 = 0;
// When this flag is set in the lobby join commands (67/68), the client will
// show the Battle option in the game creation menu. This only has an effect
// on DCv1. On 11/2000, the option always appears but does nothing, and on
// DCv2 and later, the game mode option is always present.
uint8_t enable_battle_mode_v1 = 1;
uint8_t event = 0;
uint8_t unknown_a2 = 0;
le_uint32_t unused = 0;
uint8_t unused = 0;
le_uint32_t random_seed = 0; // Unused for lobbies
} __packed_ws__(LobbyFlags, 0x0C);
// Header flag = entry count (always 1 for 65 and 68; up to 0x0C for 67)
+7 -5
View File
@@ -1275,7 +1275,6 @@ static void on_96(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
check_size_t<C_CharSaveInfo_DCv2_PC_V3_BB_96>(data);
c->config.set_flag(Client::Flag::SHOULD_SEND_ENABLE_SAVE);
send_update_client_config(c, false);
send_server_time(c);
}
static void on_B1(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
@@ -2232,7 +2231,7 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
item_id = cmd.basic_cmd.item_id;
} else if (data.size() > sizeof(C_MenuSelection_DC_V3_10_Flag02)) {
const auto& cmd = check_size_t<C_MenuSelection_DC_V3_10_Flag03>(data);
team_name = cmd.unknown_a1.decode(c->language());
team_name = cmd.name.decode(c->language());
password = cmd.password.decode(c->language());
menu_id = cmd.basic_cmd.menu_id;
item_id = cmd.basic_cmd.item_id;
@@ -4327,10 +4326,14 @@ shared_ptr<Lobby> create_game_generic(
game->difficulty = difficulty;
game->allowed_versions = s->compatibility_groups.at(static_cast<size_t>(creator_c->version()));
static_assert(NUM_VERSIONS == 14, "Don't forget to update the group compatibility restrictions");
if (!allow_v1 || (difficulty > 2) || (mode != GameMode::NORMAL)) {
if (!allow_v1 || (difficulty > 2) || (mode == GameMode::CHALLENGE) || (mode == GameMode::SOLO)) {
game->forbid_version(Version::DC_NTE);
game->forbid_version(Version::DC_11_2000);
game->forbid_version(Version::DC_V1);
} else if (mode == GameMode::BATTLE) {
game->forbid_version(Version::DC_NTE);
game->forbid_version(Version::DC_11_2000);
// v1 supports battle mode but not battle quests
}
switch (game->episode) {
case Episode::NONE:
@@ -4597,9 +4600,8 @@ static void on_0C_C1_E7_EC(shared_ptr<Client> c, uint16_t command, uint32_t, str
GameMode mode = GameMode::NORMAL;
bool spectators_forbidden = false;
if (cmd.battle_mode || c->config.check_flag(Client::Flag::FORCE_BATTLE_MODE_GAME)) {
if (cmd.battle_mode) {
mode = GameMode::BATTLE;
c->config.clear_flag(Client::Flag::FORCE_BATTLE_MODE_GAME);
}
if (cmd.challenge_mode) {
if (client_is_ep3) {
+5 -9
View File
@@ -2118,13 +2118,9 @@ void send_join_lobby_t(shared_ptr<Client> c, shared_ptr<Lobby> l, shared_ptr<Cli
S_JoinLobbyT<LobbyFlags, LobbyDataT, DispDataT> cmd;
cmd.lobby_flags.client_id = c->lobby_client_id;
cmd.lobby_flags.leader_id = l->leader_id;
cmd.lobby_flags.disable_udp = 0x01;
cmd.lobby_flags.lobby_number = lobby_type;
cmd.lobby_flags.block_number = lobby_block;
cmd.lobby_flags.unknown_a1 = 0;
cmd.lobby_flags.event = l->event;
cmd.lobby_flags.unknown_a2 = 0;
cmd.lobby_flags.unused = 0;
vector<shared_ptr<Client>> lobby_clients;
if (joining_client) {
@@ -2194,13 +2190,9 @@ void send_join_lobby_xb(shared_ptr<Client> c, shared_ptr<Lobby> l, shared_ptr<Cl
S_JoinLobby_XB_65_67_68 cmd;
cmd.lobby_flags.client_id = c->lobby_client_id;
cmd.lobby_flags.leader_id = l->leader_id;
cmd.lobby_flags.disable_udp = 0x01;
cmd.lobby_flags.lobby_number = lobby_type;
cmd.lobby_flags.block_number = l->block;
cmd.lobby_flags.unknown_a1 = 0;
cmd.lobby_flags.event = l->event;
cmd.lobby_flags.unknown_a2 = 0;
cmd.lobby_flags.unused = 0;
vector<shared_ptr<Client>> lobby_clients;
if (joining_client) {
@@ -2247,7 +2239,6 @@ void send_join_lobby_dc_nte(shared_ptr<Client> c, shared_ptr<Lobby> l,
S_JoinLobby_DCNTE_65_67_68 cmd;
cmd.lobby_flags.client_id = c->lobby_client_id;
cmd.lobby_flags.leader_id = l->leader_id;
cmd.lobby_flags.disable_udp = 0x01;
vector<shared_ptr<Client>> lobby_clients;
if (joining_client) {
@@ -4068,6 +4059,11 @@ void send_ep3_disband_watcher_lobbies(shared_ptr<Lobby> primary_l) {
}
void send_server_time(shared_ptr<Client> c) {
// DC NTE and 11/2000 don't have this command
if (is_pre_v1(c->version())) {
return;
}
uint64_t t = phosg::now();
time_t t_secs = t / 1000000;