diff --git a/include/aoclient.h b/include/aoclient.h index 2b325d8..71ddf6f 100644 --- a/include/aoclient.h +++ b/include/aoclient.h @@ -262,11 +262,21 @@ class AOClient : public QObject { */ bool advert_enabled = true; + /** + * @brief If true, the client is restricted to only changing into certain characters. + */ + bool is_charcursed = false; + /** * @brief Timer for tracking user interaction. Automatically restarted whenever a user interacts (i.e. sends any packet besides CH) */ QTimer* afk_timer; + /** + * @brief The list of char IDs a charcursed player is allowed to switch to. + */ + QList charcurse_list; + /** * @brief Temporary client permission if client is allowed to save a testimony to server storage. */ @@ -1456,6 +1466,8 @@ class AOClient : public QObject { * @brief Toggles whether a client will recieve @ref cmdPM private messages or not. * * @details No arguments. + * + * @iscommand */ void cmdMutePM(int argc, QStringList argv); @@ -1463,6 +1475,8 @@ class AOClient : public QObject { * @brief Toggles whether a client will recieve @ref cmdNeed "advertisement" messages. * * @details No arguments. + * + * @iscommand */ void cmdToggleAdverts(int argc, QStringList argv); @@ -1475,6 +1489,25 @@ class AOClient : public QObject { */ void cmdAfk(int argc, QStringList argv); + /** + * @brief Restricts a target client to a set of characters that they can switch from, blocking them from other characters. + * + * @details The first argument is the **target's ID** whom the client wants to charcurse. + * + * The second argument is one or more character names the client wants to restrict to, comma separated. + * + * @iscommand + */ + void cmdCharCurse(int argc, QStringList argv); + + /** + * @brief Removes the charcurse status from a client. + * + * @details The only argument is the **target's ID** whom the client wants to uncharcurse. + * + * @iscommand + */ + void cmdUnCharCurse(int argc, QStringList argv); void cmdCharSelect(int argc, QStringList argv); /** @@ -1945,10 +1978,12 @@ class AOClient : public QObject { {"block_dj", {ACLFlags.value("MUTE"), 1, &AOClient::cmdBlockDj}}, {"unblockdj", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnBlockDj}}, {"unblock_dj", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnBlockDj}}, + {"charcurse", {ACLFlags.value("MUTE"), 1, &AOClient::cmdCharCurse}}, + {"uncharcurse", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnCharCurse}}, {"charselect", {ACLFlags.value("NONE"), 0, &AOClient::cmdCharSelect}}, {"togglemusic", {ACLFlags.value("CM"), 0, &AOClient::cmdToggleMusic}}, {"a", {ACLFlags.value("NONE"), 2, &AOClient::cmdA}}, - {"s", {ACLFlags.value("NONE"), 0, &AOClient::cmdS}}, + {"s", {ACLFlags.value("NONE"), 0, &AOClient::cmdS}} }; /** diff --git a/include/server.h b/include/server.h index 1eece71..0d44b0e 100644 --- a/include/server.h +++ b/include/server.h @@ -259,6 +259,8 @@ class Server : public QObject { */ QStringList loadConfigFile(QString filename); + QStringList getCursedCharsTaken(AOClient* client, QStringList chars_taken); + /** * @brief List holding the contents of 8ball.txt, used by /8ball. */ diff --git a/src/aoclient.cpp b/src/aoclient.cpp index c4332ea..5ccfdf6 100644 --- a/src/aoclient.cpp +++ b/src/aoclient.cpp @@ -148,6 +148,10 @@ bool AOClient::changeCharacter(int char_id) if(char_id >= server->characters.length()) return false; + if (is_charcursed && !charcurse_list.contains(char_id)) { + return false; + } + if (current_char != "") { area->characters_taken.removeAll(server->getCharID(current_char)); } diff --git a/src/commands/messaging.cpp b/src/commands/messaging.cpp index 839844f..044169d 100644 --- a/src/commands/messaging.cpp +++ b/src/commands/messaging.cpp @@ -318,6 +318,78 @@ void AOClient::cmdAfk(int argc, QStringList argv) sendServerMessage("You are now AFK."); } +void AOClient::cmdCharCurse(int argc, QStringList argv) +{ + bool conv_ok = false; + int uid = argv[0].toInt(&conv_ok); + if (!conv_ok) { + sendServerMessage("Invalid user ID."); + return; + } + + AOClient* target = server->getClientByID(uid); + + if (target->is_charcursed) { + sendServerMessage("That player is already charcursed!"); + return; + } + + if (argc == 1) { + target->charcurse_list.append(server->getCharID(target->current_char)); + } + else { + argv.removeFirst(); + QStringList char_names = argv.join(" ").split(","); + + target->charcurse_list.clear(); + for (QString char_name : char_names) { + int char_id = server->getCharID(char_name); + if (char_id == -1) { + sendServerMessage("Could not find character: " + char_name); + return; + } + target->charcurse_list.append(char_id); + } + } + + target->is_charcursed = true; + + //Kick back to char select screen + if (!target->charcurse_list.contains(server->getCharID(target->current_char))) { + target->changeCharacter(-1); + server->updateCharsTaken(server->areas.value(current_area)); + target->sendPacket("DONE"); + } + else { + server->updateCharsTaken(server->areas.value(current_area)); + } + + target->sendServerMessage("You have been charcursed!"); + sendServerMessage("Charcursed player."); +} + +void AOClient::cmdUnCharCurse(int argc, QStringList argv) +{ + bool conv_ok = false; + int uid = argv[0].toInt(&conv_ok); + if (!conv_ok) { + sendServerMessage("Invalid user ID."); + return; + } + + AOClient* target = server->getClientByID(uid); + + if (!target->is_charcursed) { + sendServerMessage("That player is not charcursed!"); + return; + } + target->is_charcursed = false; + target->charcurse_list.clear(); + server->updateCharsTaken(server->areas.value(current_area)); + sendServerMessage("Uncharcursed player."); + target->sendServerMessage("You were uncharcursed."); +} + void AOClient::cmdCharSelect(int argc, QStringList argv) { if (argc == 0) { diff --git a/src/server.cpp b/src/server.cpp index 382e5a2..e0c5825 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -151,7 +151,30 @@ void Server::updateCharsTaken(AreaData* area) } AOPacket response_cc("CharsCheck", chars_taken); - broadcast(response_cc, area->index); + + for (AOClient* client : clients) { + if (client->current_area == area->index){ + if (!client->is_charcursed) + client->sendPacket(response_cc); + else { + QStringList chars_taken_cursed = getCursedCharsTaken(client, chars_taken); + AOPacket response_cc_cursed("CharsCheck", chars_taken_cursed); + client->sendPacket(response_cc_cursed); + } + } + } +} + +QStringList Server::getCursedCharsTaken(AOClient* client, QStringList chars_taken) +{ + QStringList chars_taken_cursed; + for (int i = 0; i < chars_taken.length(); i++) { + if (!client->charcurse_list.contains(i)) + chars_taken_cursed.append("-1"); + else + chars_taken_cursed.append(chars_taken.value(i)); + } + return chars_taken_cursed; } void Server::broadcast(AOPacket packet, int area_index)