add $qgread and $qgwrite commands
This commit is contained in:
@@ -376,12 +376,13 @@ Some commands only work on the game server and not on the proxy server. The chat
|
||||
* The rest of the commands in this section are enabled on the game server. (They are always enabled on the proxy server.)
|
||||
* `$quest <number>` (game server only): Load a quest by quest number. Can be used to load battle or challenge quests with only one player present.
|
||||
* `$qcall <function-id>`: Call a quest function on your client.
|
||||
* `$qcheck <flag-num>` (game server only): Show the value of a quest flag.
|
||||
* `$qset <flag-num>` or `$qclear <flag-num>`: Set or clear a global quest flag for everyone in the game.
|
||||
* `$qcheck <flag-num>` (game server only): Show the value of a quest flag. This command can be used without debug mode enabled.
|
||||
* `$qset <flag-num>` or `$qclear <flag-num>`: Set or clear a quest flag for everyone in the game.
|
||||
* `$qgread <flag-num>` (game server only): Get the value of a quest counter ("global flag"). This command can be used without debug mode enabled.
|
||||
* `$qgwrite <flag-num> <value>` (game server only): Set the value of a quest counter ("global flag") for yourself.
|
||||
* `$qsync <reg-num> <value>`: Set a quest register's value for yourself only. `<reg-num>` should be either rXX (e.g. r60) or fXX (e.g. f60); if the latter, `<value>` is parsed as a floating-point value instead of as an integer.
|
||||
* `$qsyncall <reg-num> <value>`: Set a quest register's value for everyone in the game. `<reg-num>` should be either rXX (e.g. r60) or fXX (e.g. f60); if the latter, `<value>` is parsed as a floating-point value instead of as an integer.
|
||||
* `$gc` (game server only): Send your own Guild Card to yourself.
|
||||
* `$persist` (game server only): Enable or disable persistence for the current game. When persistence is on, the game will not be deleted when the last player leaves. The state of enemies and objects on the map will be reset when the last player leaves.
|
||||
* `$sc <data>`: Send a command to yourself.
|
||||
* `$ss <data>` (proxy server only): Send a command to the remote server.
|
||||
* `$meseta <amount>` (game server only; Episode 3 only): Add the given amount to your Meseta total.
|
||||
@@ -402,6 +403,7 @@ Some commands only work on the game server and not on the proxy server. The chat
|
||||
* `$loadchar <slot>` (v1 and v2 only): Loads your character data from the specified slot. The changes will be undone if you join a game - to save your changes, disconnect from the lobby.
|
||||
* `$bbchar <username> <password> <slot>`: Use this command when playing on a non-BB version of PSO. If the username and password are correct, this command converts your current character to BB format and saves it on the server in the given slot (1-4). Any character already in that slot is overwritten. (This command is similar to `$savechar`, except it overwrites a BB character slot, and can transfer characters across accounts.) Note that the character's chat data, quick menu config, and bank contents are not copied, since there is no way for the server to request those types of data.
|
||||
* `$edit <stat> <value>`: Modifies your character data. If you are on V3 (GameCube/Xbox), this command does nothing. If you are on V1 or V2 (DC or PC, not BB), your changes will be undone if you join a game - to save your changes, disconnect from the lobby. If cheats are allowed on the server, `<stat>` can be any of `atp`, `mst`, `evp`, `hp`, `dfp`, `ata`, `lck`, `meseta`, `exp`, `level`, `namecolor`, `secid`, `name`, `npc`, or `tech`. If cheats are not allowed, only `namecolor`, `name`, and `npc` can be used.
|
||||
|
||||
* Blue Burst player commands (game server only)
|
||||
* `$bank [number]`: Switches your current bank, so you can access your other character's banks (if `number` is 1-4) or your shared account bank (if `number` is 0). If `number` is not given, switches back to your current character's bank.
|
||||
* `$save`: Saves your character, system, and Guild Card data immediately. (By default, your character is saved every 60 seconds while online, and your account and Guild Card data are saved whenever they change.)
|
||||
@@ -411,6 +413,7 @@ Some commands only work on the game server and not on the proxy server. The chat
|
||||
* `$minlevel <level>`: Sets the minimum level for players to join the current game.
|
||||
* `$password <password>`: Sets the game's join password. To unlock the game, run `$password` with nothing after it.
|
||||
* `$dropmode [mode]`: Changes the way item drops behave in the current game. `mode` can be `none`, `client`, `shared`, `private`, or `duplicate`. If `mode` is not given, tells you the current drop mode without changing it. See the "Item tables and drop modes" section for more information.
|
||||
* `$persist`: Enable or disable persistence for the current game. When persistence is on, the game will not be deleted when the last player leaves. The state of enemies and objects on the map will be reset when the last player leaves, but dropped items will not be deleted. If the game is empty for too long (15 minutes by default), it is then deleted.
|
||||
|
||||
* Episode 3 commands (game server only)
|
||||
* `$spec`: Toggles the allow spectators flag for Episode 3 games. If any players are spectating when this flag is disabled, they will be sent back to the lobby.
|
||||
|
||||
@@ -375,6 +375,51 @@ static void proxy_command_qclear(shared_ptr<ProxyServer::LinkedSession> ses, con
|
||||
return proxy_command_qset_qclear(ses, args, false);
|
||||
}
|
||||
|
||||
static void server_command_qgread(shared_ptr<Client> c, const std::string& args) {
|
||||
uint8_t flag_num = stoul(args, nullptr, 0);
|
||||
const auto& flags = c->character()->quest_counters;
|
||||
if (flag_num >= flags.size()) {
|
||||
send_text_message_printf(c, "$C7Flag number must be\nless than %zu", flags.size());
|
||||
} else {
|
||||
send_text_message_printf(c, "$C7Quest counter %hhu\nhas value %" PRIu32,
|
||||
flag_num, flags[flag_num].load());
|
||||
}
|
||||
}
|
||||
|
||||
static void server_command_qgwrite(shared_ptr<Client> c, const std::string& args) {
|
||||
if (c->version() != Version::BB_V4) {
|
||||
send_text_message(c, "$C6This command can\nonly be used on BB");
|
||||
return;
|
||||
}
|
||||
if (!c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
|
||||
send_text_message(c, "$C6This command can only\nbe run in debug mode\n(run %sdebug first)");
|
||||
return;
|
||||
}
|
||||
auto l = c->require_lobby();
|
||||
if (!l->is_game()) {
|
||||
send_text_message(c, "$C6This command cannot\nbe used in the lobby");
|
||||
return;
|
||||
}
|
||||
|
||||
auto tokens = split(args, ' ');
|
||||
if (tokens.size() != 2) {
|
||||
send_text_message(c, "$C6Incorrect number\nof arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t flag_num = stoul(tokens[0], nullptr, 0);
|
||||
uint32_t value = stoul(tokens[1], nullptr, 0);
|
||||
auto& flags = c->character()->quest_counters;
|
||||
if (flag_num >= flags.size()) {
|
||||
send_text_message_printf(c, "$C7Flag number must be\nless than %zu", flags.size());
|
||||
} else {
|
||||
c->character()->quest_counters[flag_num] = value;
|
||||
G_SetQuestCounter_BB_6xD2 cmd = {{0xD2, sizeof(G_SetQuestCounter_BB_6xD2) / 4, c->lobby_client_id}, flag_num, value};
|
||||
send_command_t(c, 0x60, 0x00, cmd);
|
||||
send_text_message_printf(c, "$C7Quest counter %hhu\nset to %" PRIu32, flag_num, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void server_command_qsync_qsyncall(shared_ptr<Client> c, const std::string& args, bool send_to_lobby) {
|
||||
if (!c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
|
||||
send_text_message(c, "$C6This command can only\nbe run in debug mode\n(run %sdebug first)");
|
||||
@@ -2021,6 +2066,8 @@ static const unordered_map<string, ChatCommandDefinition> chat_commands({
|
||||
{"$qcall", {server_command_qcall, proxy_command_qcall}},
|
||||
{"$qcheck", {server_command_qcheck, nullptr}},
|
||||
{"$qclear", {server_command_qclear, proxy_command_qclear}},
|
||||
{"$qgread", {server_command_qgread, nullptr}},
|
||||
{"$qgwrite", {server_command_qgwrite, nullptr}},
|
||||
{"$qset", {server_command_qset, proxy_command_qset}},
|
||||
{"$qsync", {server_command_qsync, proxy_command_qsync}},
|
||||
{"$qsyncall", {server_command_qsyncall, proxy_command_qsyncall}},
|
||||
|
||||
+1
-1
@@ -811,7 +811,7 @@ void Client::load_all_files() {
|
||||
this->character_data->battle_records = nsc_data.battle_records;
|
||||
this->character_data->challenge_records = nsc_data.challenge_records;
|
||||
this->character_data->tech_menu_config = nsc_data.tech_menu_config;
|
||||
this->character_data->quest_global_flags = nsc_data.quest_global_flags;
|
||||
this->character_data->quest_counters = nsc_data.quest_counters;
|
||||
if (nsa_data) {
|
||||
this->character_data->option_flags = nsa_data->option_flags;
|
||||
this->character_data->symbol_chats = nsa_data->symbol_chats;
|
||||
|
||||
@@ -5881,10 +5881,10 @@ struct G_ChallengeModeGraveRecoveryItemRequest_BB_6xD1 {
|
||||
le_uint32_t item_type = 0; // Should be < 6
|
||||
} __packed__;
|
||||
|
||||
// 6xD2: Set quest global flag (BB)
|
||||
// 6xD2: Set quest counter (BB)
|
||||
// Writes 4 bytes to the 32-bit field specified by index.
|
||||
|
||||
struct G_SetQuestGlobalFlag_BB_6xD2 {
|
||||
struct G_SetQuestCounter_BB_6xD2 {
|
||||
G_ClientIDHeader header;
|
||||
le_uint32_t index = 0; // There are 0x10 of them (0x00-0x0F)
|
||||
le_uint32_t value = 0;
|
||||
|
||||
@@ -827,7 +827,7 @@ struct PlayerConfig {
|
||||
/* 000C:---- */ parray<uint8_t, 0x1C> unknown_a1;
|
||||
/* 0028:---- */ parray<be_uint16_t, 20> tech_menu_shortcut_entries;
|
||||
/* 0050:---- */ parray<be_uint32_t, 10> choice_search_config;
|
||||
// This field maps to quest_global_flags on Episodes 1 & 2
|
||||
// This field maps to quest_counters on Episodes 1 & 2
|
||||
/* 0078:---- */ parray<be_uint32_t, 0x30> scenario_progress;
|
||||
// place_counts[0] and [1] from this field are added to the player's win and
|
||||
// loss count respectively when they're shown in the status menu. However,
|
||||
|
||||
+7
-7
@@ -279,11 +279,11 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
|
||||
{0x0010, "set", {REG}, F_V0_V4}, // Sets a register to 1
|
||||
{0x0011, "clear", {REG}, F_V0_V4}, // Sets a register to 0
|
||||
{0x0012, "rev", {REG}, F_V0_V4}, // Sets a register to 0 if it's nonzero and vice versa
|
||||
{0x0013, "gset", {INT16}, F_V0_V4}, // Sets a global flag
|
||||
{0x0014, "gclear", {INT16}, F_V0_V4}, // Clears a global flag
|
||||
{0x0015, "grev", {INT16}, F_V0_V4}, // Flips a global flag
|
||||
{0x0016, "glet", {INT16, REG}, F_V0_V4}, // Sets a global flag to a specific value
|
||||
{0x0017, "gget", {INT16, REG}, F_V0_V4}, // Gets a global flag
|
||||
{0x0013, "gset", {INT16}, F_V0_V4}, // Sets a quest flag
|
||||
{0x0014, "gclear", {INT16}, F_V0_V4}, // Clears a quest flag
|
||||
{0x0015, "grev", {INT16}, F_V0_V4}, // Flips a quest flag
|
||||
{0x0016, "glet", {INT16, REG}, F_V0_V4}, // Sets a quest flag to a specific value
|
||||
{0x0017, "gget", {INT16, REG}, F_V0_V4}, // Gets a quest flag
|
||||
{0x0018, "add", {REG, REG}, F_V0_V4}, // regA += regB
|
||||
{0x0019, "addi", {REG, INT32}, F_V0_V4}, // regA += imm
|
||||
{0x001A, "sub", {REG, REG}, F_V0_V4}, // regA -= regB
|
||||
@@ -779,8 +779,8 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
|
||||
{0xF922, "get_player_hp", {CLIENT_ID, {REG_SET_FIXED, 4}}, F_V3_V4 | F_ARGS},
|
||||
{0xF923, "get_floor_number", {CLIENT_ID, {REG_SET_FIXED, 2}}, F_V3_V4 | F_ARGS},
|
||||
{0xF924, "get_coord_player_detect", {{REG_SET_FIXED, 3}, {REG_SET_FIXED, 4}}, F_V3_V4},
|
||||
{0xF925, "read_global_flag", {INT32, REG}, F_V3_V4 | F_ARGS},
|
||||
{0xF926, "write_global_flag", {INT32, INT32}, F_V3_V4 | F_ARGS},
|
||||
{0xF925, "read_counter", {INT32, REG}, F_V3_V4 | F_ARGS},
|
||||
{0xF926, "write_counter", {INT32, INT32}, F_V3_V4 | F_ARGS},
|
||||
{0xF927, "item_detect_bank2", {{REG_SET_FIXED, 4}, REG}, F_V3_V4},
|
||||
{0xF928, "floor_player_detect", {{REG_SET_FIXED, 4}}, F_V3_V4},
|
||||
{0xF929, "prepare_gba_rom_from_disk", {CSTRING}, F_V3 | F_ARGS}, // Prepares to load a GBA ROM from a local GSL file
|
||||
|
||||
@@ -3567,9 +3567,9 @@ static void on_upgrade_weapon_attribute_bb(shared_ptr<Client> c, uint8_t, uint8_
|
||||
}
|
||||
}
|
||||
|
||||
static void on_write_quest_global_flag_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* data, size_t size) {
|
||||
const auto& cmd = check_size_t<G_SetQuestGlobalFlag_BB_6xD2>(data, size);
|
||||
c->character()->quest_global_flags[cmd.index] = cmd.value;
|
||||
static void on_write_quest_counter_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* data, size_t size) {
|
||||
const auto& cmd = check_size_t<G_SetQuestCounter_BB_6xD2>(data, size);
|
||||
c->character()->quest_counters[cmd.index] = cmd.value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -3785,7 +3785,7 @@ const SubcommandDefinition subcommand_definitions[0x100] = {
|
||||
/* 6xCF */ {0x00, 0x00, 0xCF, on_battle_restart_bb},
|
||||
/* 6xD0 */ {0x00, 0x00, 0xD0, on_battle_level_up_bb},
|
||||
/* 6xD1 */ {0x00, 0x00, 0xD1, on_request_challenge_grave_recovery_item_bb},
|
||||
/* 6xD2 */ {0x00, 0x00, 0xD2, on_write_quest_global_flag_bb},
|
||||
/* 6xD2 */ {0x00, 0x00, 0xD2, on_write_quest_counter_bb},
|
||||
/* 6xD3 */ {0x00, 0x00, 0xD3, on_invalid},
|
||||
/* 6xD4 */ {0x00, 0x00, 0xD4, on_forward_check_game},
|
||||
/* 6xD5 */ {0x00, 0x00, 0xD5, on_quest_exchange_item_bb},
|
||||
|
||||
@@ -210,7 +210,7 @@ struct PSOBBCharacterFile {
|
||||
/* 2DF8 */ parray<le_uint16_t, 0x0014> tech_menu_config;
|
||||
/* 2E20 */ ChoiceSearchConfig choice_search_config;
|
||||
/* 2E38 */ parray<uint8_t, 0x0010> unknown_a6;
|
||||
/* 2E48 */ parray<le_uint32_t, 0x0010> quest_global_flags;
|
||||
/* 2E48 */ parray<le_uint32_t, 0x0010> quest_counters;
|
||||
/* 2E88 */ parray<uint8_t, 0x1C> unknown_a7;
|
||||
/* 2EA4 */
|
||||
|
||||
@@ -360,7 +360,7 @@ struct PSOGCCharacterFile {
|
||||
/* 25E0:21C4 */ PlayerRecordsV3_Challenge<true> challenge_records;
|
||||
/* 26E0:22C4 */ parray<be_uint16_t, 20> tech_menu_shortcut_entries;
|
||||
/* 2708:22EC */ parray<uint8_t, 0x28> unknown_a6;
|
||||
/* 2730:2314 */ parray<be_uint32_t, 0x10> quest_global_flags;
|
||||
/* 2730:2314 */ parray<be_uint32_t, 0x10> quest_counters;
|
||||
/* 2770:2354 */ PlayerRecords_Battle<true> offline_battle_records;
|
||||
/* 2788:236C */ parray<uint8_t, 4> unknown_f5;
|
||||
/* 278C:2370 */ be_uint32_t unknown_f6;
|
||||
@@ -766,7 +766,7 @@ struct LegacySavedPlayerDataBB { // .nsc file format
|
||||
/* 1D00 */ parray<uint8_t, 4> unknown_a2;
|
||||
/* 1D04 */ QuestFlags quest_flags;
|
||||
/* 1F04 */ le_uint32_t death_count;
|
||||
/* 1F08 */ parray<le_uint32_t, 0x0016> quest_global_flags;
|
||||
/* 1F08 */ parray<le_uint32_t, 0x0016> quest_counters;
|
||||
/* 1F60 */ parray<le_uint16_t, 0x0014> tech_menu_config;
|
||||
/* 1F88 */
|
||||
} __attribute__((packed));
|
||||
|
||||
Reference in New Issue
Block a user