From da0ffea7e0f37788ad73e6a40c0b0138a3912c8b Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Mon, 4 Dec 2023 21:42:07 -0800 Subject: [PATCH] prevent player from joining game if a quest they don't have access to is in progress --- src/ChatCommands.cc | 6 ++++++ src/Client.cc | 19 ++++++++++++++++++- src/Client.hh | 5 ++++- src/Lobby.cc | 22 +++------------------- src/ReceiveCommands.cc | 4 ++++ 5 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 8adf594f..865b3c21 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -282,6 +282,12 @@ static void server_command_qset_qclear(shared_ptr c, const std::string& uint16_t flag_num = stoul(args, nullptr, 0); + if (should_set) { + c->game_data.character()->quest_flags.set(l->difficulty, flag_num); + } else { + c->game_data.character()->quest_flags.clear(l->difficulty, flag_num); + } + if (is_v1_or_v2(c->version())) { G_SetQuestFlag_DC_PC_6x75 cmd = {{0x75, 0x02, 0x0000}, flag_num, should_set ? 0 : 1}; send_command_t(l, 0x60, 0x00, cmd); diff --git a/src/Client.cc b/src/Client.cc index 66abe1f7..cc53ef77 100644 --- a/src/Client.cc +++ b/src/Client.cc @@ -246,7 +246,7 @@ shared_ptr Client::require_lobby() const { return l; } -shared_ptr Client::team() { +shared_ptr Client::team() const { if (!this->license) { throw logic_error("Client::team called on client with no license"); } @@ -287,6 +287,23 @@ shared_ptr Client::team() { return team; } +bool Client::can_access_quest(shared_ptr q, uint8_t difficulty) const { + if (this->license && (this->license->flags & License::Flag::DISABLE_QUEST_REQUIREMENTS)) { + return true; + } + if ((q->require_flag >= 0) && + !this->game_data.character()->quest_flags.get(difficulty, q->require_flag)) { + return false; + } + if (!q->require_team_reward_key.empty()) { + auto team = this->team(); + if (!team || !team->has_reward(q->require_team_reward_key)) { + return false; + } + } + return true; +} + void Client::dispatch_save_game_data(evutil_socket_t, short, void* ctx) { reinterpret_cast(ctx)->save_game_data(); } diff --git a/src/Client.hh b/src/Client.hh index f6e61e32..595cd2f0 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -16,6 +16,7 @@ #include "PSOProtocol.hh" #include "PatchFileIndex.hh" #include "Player.hh" +#include "Quest.hh" #include "QuestScript.hh" #include "TeamIndex.hh" #include "Text.hh" @@ -232,7 +233,9 @@ struct Client : public std::enable_shared_from_this { std::shared_ptr require_server_state() const; std::shared_ptr require_lobby() const; - std::shared_ptr team(); + std::shared_ptr team() const; + + bool can_access_quest(std::shared_ptr q, uint8_t difficulty) const; static void dispatch_save_game_data(evutil_socket_t, short, void* ctx); void save_game_data(); diff --git a/src/Lobby.cc b/src/Lobby.cc index 3a064de5..373aa57d 100644 --- a/src/Lobby.cc +++ b/src/Lobby.cc @@ -404,25 +404,9 @@ unordered_map> Lobby::clients_by_serial_number() co QuestIndex::IncludeCondition Lobby::quest_include_condition() const { return [this](shared_ptr q) -> bool { - if (q->require_flag >= 0) { - for (const auto& lc : this->clients) { - if (lc && !lc->game_data.character()->quest_flags.get(this->difficulty, q->require_flag)) { - return false; - } - } - } - if (!q->require_team_reward_key.empty()) { - // TODO: Technically we should check that all clients are on the SAME - // team, but I'm lazy (for now), so we allow clients on different teams - // to access the quest as long as all their teams have the quest reward. - for (const auto& lc : this->clients) { - if (!lc) { - continue; - } - auto team = lc->team(); - if (!team || !team->has_reward(q->require_team_reward_key)) { - return false; - } + for (const auto& lc : this->clients) { + if (lc && !lc->can_access_quest(q, this->difficulty)) { + return false; } } return true; diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index a22de898..b7725fc8 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -2287,6 +2287,10 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, string& data) { send_lobby_message_box(c, "$C6Your level is too\nhigh to join this\ngame."); break; } + if (game->quest && !c->can_access_quest(game->quest, game->difficulty)) { + send_lobby_message_box(c, "$C6You don't have access\nto the quest in progress\nin this game."); + break; + } } if (!s->change_client_lobby(c, game)) {