From 760d46b206164d507d4c1126f3fe835982f18de1 Mon Sep 17 00:00:00 2001
From: MangosArentLiterature
 <58055358+MangosArentLiterature@users.noreply.github.com>
Date: Sun, 18 Apr 2021 14:45:53 -0500
Subject: [PATCH] add /charcurse and /uncharcurse

this code makes me want to die. please end my suffering.
---
 include/aoclient.h         | 33 +++++++++++++++++++
 src/aoclient.cpp           |  4 +++
 src/commands/messaging.cpp | 67 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+)

diff --git a/include/aoclient.h b/include/aoclient.h
index 7c05caf..80b3c09 100644
--- a/include/aoclient.h
+++ b/include/aoclient.h
@@ -260,11 +260,18 @@ 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;
 
+    QStringList charcurse_list;
+
 
   public slots:
     /**
@@ -1453,6 +1460,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);
 
@@ -1460,6 +1469,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);
 
@@ -1472,6 +1483,26 @@ 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);
+
     ///@}
 
     /**
@@ -1888,6 +1919,8 @@ 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}},
     };
 
     /**
diff --git a/src/aoclient.cpp b/src/aoclient.cpp
index 6e8dfbd..d6394e7 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(QString::number(char_id))) {
+        return false;
+    }
+
     if (char_id >= 0) {
         QString char_selected = server->characters[char_id];
         bool taken = area->characters_taken.contains(char_id);
diff --git a/src/commands/messaging.cpp b/src/commands/messaging.cpp
index 0be4203..e2cafa1 100644
--- a/src/commands/messaging.cpp
+++ b/src/commands/messaging.cpp
@@ -302,3 +302,70 @@ void AOClient::cmdAfk(int argc, QStringList argv)
     is_afk = true;
     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(QString::number(server->getCharID(current_char)));
+    }
+
+    else {
+        argv.removeFirst(); //remove the UID
+        QString names = argv.join(" ");
+        argv = names.split(", ");
+        QString char_name;
+        foreach (char_name, argv) {
+            QString converted_char_id = QString::number(server->getCharID(char_name));
+            argv.replaceInStrings(char_name, converted_char_id);
+        }
+        if (argv.contains("-1")) {
+            sendServerMessage("One of these characters was not found.");
+            return;
+        }
+        target->charcurse_list = argv;
+    }
+
+    //Kick back to char select screen
+    if (!target->charcurse_list.contains(QString::number(server->getCharID(current_char)))) {
+        target->current_char = "";
+        target->sendPacket("DONE");
+    }
+    target->is_charcursed = true;
+    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();
+    sendServerMessage("Uncharcursed plater.");
+    target->sendServerMessage("You were uncharcursed.");
+}