diff --git a/include/aoclient.h b/include/aoclient.h
index 690adbb..11ea067 100644
--- a/include/aoclient.h
+++ b/include/aoclient.h
@@ -46,10 +46,9 @@ class AOClient : public QObject {
     QString getIpid();
     void calculateIpid();
 
+    // user metadata
     int id;
-
     QHostAddress remote_ip;
-    QString password;
     bool joined;
     int current_area;
     QString current_char;
@@ -57,8 +56,9 @@ class AOClient : public QObject {
     QString moderator_name = "";
     QString ooc_name = "";
     QString showname = "";
-    bool global_enabled = true;
-    bool is_muted = false;
+
+    QString password; // for character passwords
+
     struct ClientVersion {
       QString string;
       int release = -1;
@@ -67,6 +67,21 @@ class AOClient : public QObject {
     };
     ClientVersion version;
 
+    // user preferences
+    bool global_enabled = true;
+    bool adverts_enabled = true;
+    bool pm_enabled = true;
+
+    // punitive conditions
+    bool is_muted = false;
+    bool is_ooc_muted = false;
+    bool is_dj_blocked = false;
+    bool is_wtce_blocked = false;
+    bool is_shaken = false;
+    bool is_disemvoweled = false;
+    bool is_gimped = false;
+    int char_curse = -1;
+
     QMap<QString, unsigned long long> ACLFlags {
         {"NONE", 0ULL},
         {"KICK", 1ULL << 0},
@@ -83,10 +98,6 @@ class AOClient : public QObject {
         {"SUPER", ~0ULL}
     };
 
-    bool is_shaken;
-    bool is_disemvoweled;
-    bool is_gimped;
-
   public slots:
     void clientDisconnected();
     void clientData();
@@ -118,9 +129,9 @@ class AOClient : public QObject {
     void changePosition(QString new_pos);
     void arup(ARUPType type, bool broadcast);
     void fullArup();
-    void sendServerMessage(QString message);
-    void sendServerMessageArea(QString message);
-    void sendServerBroadcast(QString message);
+    void sendServerMessage(QString message); // send a server OOC message to just this client
+    void sendServerMessageArea(QString message); // send a server OOC message to all clients in current area
+    void sendServerBroadcast(QString message); // send a server OOC message to all clients in the server
     bool checkAuth(unsigned long long acl_mask);
 
     // Packet headers
@@ -229,9 +240,15 @@ class AOClient : public QObject {
     void cmdAnnounce(int argc, QStringList argv);
     void cmdM(int argc, QStringList argv);
     void cmdGM(int argc, QStringList argv);
-    void cmdMute(int argc, QStringList argv);
-    void cmdUnmute(int argc, QStringList argv);
     void cmdBans(int argc, QStringList argv);
+    void cmdMute(int argc, QStringList argv);
+    void cmdUnMute(int argc, QStringList argv);
+    void cmdOocMute(int argc, QStringList argv);
+    void cmdOocUnMute(int argc, QStringList argv);
+    void cmdBlockDj(int argc, QStringList argv);
+    void cmdUnBlockDj(int argc, QStringList argv);
+    void cmdBlockWtce(int argc, QStringList argv);
+    void cmdUnBlockWtce(int argc, QStringList argv);
     // Casing/RP
     void cmdPlay(int argc, QStringList argv);
     void cmdNeed(int argc, QStringList argv);
@@ -258,6 +275,7 @@ class AOClient : public QObject {
     int genRand(int min, int max);
     void diceThrower(int argc, QStringList argv, RollType Type);
     long long parseTime(QString input);
+    QString getReprimand(bool positive = false);
 
     // Command function global variables
     bool change_auth_started = false;
@@ -324,12 +342,20 @@ class AOClient : public QObject {
         {"m", {ACLFlags.value("MODCHAT"), 1, &AOClient::cmdM}},
         {"gm", {ACLFlags.value("MODCHAT"), 1, &AOClient::cmdGM}},
         {"mute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdMute}},
-        {"unmute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnmute}},
+        {"unmute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnMute}},
         {"bans", {ACLFlags.value("BAN"), 0, &AOClient::cmdBans}},
         {"unban", {ACLFlags.value("BAN"), 1, &AOClient::cmdUnBan}},
         {"removeuser", {ACLFlags.value("MODIFY_USERS"), 1, &AOClient::cmdRemoveUser}},
         {"subtheme", {ACLFlags.value("CM"), 1, &AOClient::cmdSubTheme}},
-        {"about", {ACLFlags.value("NONE"), 0, &AOClient::cmdAbout}}
+        {"about", {ACLFlags.value("NONE"), 0, &AOClient::cmdAbout}},
+        {"oocmute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdOocMute}},
+        {"ooc_mute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdOocMute}},
+        {"oocunmute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdOocUnMute}},
+        {"ooc_unmute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdOocUnMute}},
+        {"blockdj", {ACLFlags.value("MUTE"), 1, &AOClient::cmdBlockDj}},
+        {"unblockdj", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnBlockDj}},
+        {"blockwtce", {ACLFlags.value("MUTE"), 1, &AOClient::cmdBlockWtce}},
+        {"unblockwtce", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnBlockWtce}},
     };
 
     QString partial_packet;
diff --git a/src/commands.cpp b/src/commands.cpp
index 2455016..3f3aa4e 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -953,38 +953,6 @@ void AOClient::cmdGM(int argc, QStringList argv)
     }
 }
 
-void AOClient::cmdMute(int argc, QStringList argv)
-{
-    bool conv_ok = false;
-    int uid = argv[0].toInt(&conv_ok);
-    if (!conv_ok) {
-        sendServerMessage("Invalid user ID.");
-        return;
-    }
-
-    if (server->getClientByID(uid)->is_muted)
-        sendServerMessage("That player is already muted!");
-    else
-        sendServerMessage("Muted player.");
-    server->getClientByID(uid)->is_muted = true;
-}
-
-void AOClient::cmdUnmute(int argc, QStringList argv)
-{
-    bool conv_ok = false;
-    int uid = argv[0].toInt(&conv_ok);
-    if (!conv_ok) {
-        sendServerMessage("Invalid user ID.");
-        return;
-    }
-
-    if (!server->getClientByID(uid)->is_muted)
-        sendServerMessage("That player is already unmuted!");
-    else
-        sendServerMessage("Unmuted player.");
-    server->getClientByID(uid)->is_muted = false;
-}
-
 void AOClient::cmdBans(int argc, QStringList argv)
 {
     QStringList recent_bans;
@@ -1035,6 +1003,167 @@ void AOClient::cmdAbout(int argc, QStringList argv)
     sendPacket("CT", {"The akashi dev team", "Thank you for using akashi! Made with love by scatterflower, with help from in1tiate and Salanto. akashi " + QCoreApplication::applicationVersion()});
 }
 
+
+void AOClient::cmdMute(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_muted)
+        sendServerMessage("That player is already muted!");
+    else {
+        sendServerMessage("Muted player.");
+        target->sendServerMessage("You were muted by a moderator. " + getReprimand());
+    }
+    target->is_muted = true;
+}
+
+void AOClient::cmdUnMute(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_muted)
+        sendServerMessage("That player is not muted!");
+    else {
+        sendServerMessage("Unmuted player.");
+        target->sendServerMessage("You were unmuted by a moderator. " + getReprimand(true));
+    }
+    target->is_muted = false;
+}
+
+void AOClient::cmdOocMute(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_ooc_muted)
+        sendServerMessage("That player is already OOC muted!");
+    else {
+        sendServerMessage("OOC muted player.");
+        target->sendServerMessage("You were OOC muted by a moderator. " + getReprimand());
+    }
+    target->is_ooc_muted = true;
+}
+
+void AOClient::cmdOocUnMute(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_ooc_muted)
+        sendServerMessage("That player is not OOC muted!");
+    else {
+        sendServerMessage("OOC unmuted player.");
+        target->sendServerMessage("You were OOC unmuted by a moderator. " + getReprimand(true));
+    }
+    target->is_ooc_muted = false;
+}
+
+void AOClient::cmdBlockDj(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_dj_blocked)
+        sendServerMessage("That player is already DJ blocked!");
+    else {
+        sendServerMessage("DJ blocked player.");
+        target->sendServerMessage("You were blocked from changing the music by a moderator. " + getReprimand());
+    }
+    target->is_dj_blocked = true;
+}
+
+void AOClient::cmdUnBlockDj(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_dj_blocked)
+        sendServerMessage("That player is not DJ blocked!");
+    else {
+        sendServerMessage("DJ permissions restored to player.");
+        target->sendServerMessage("A moderator restored your music permissions. " + getReprimand(true));
+    }
+    target->is_dj_blocked = false;
+}
+
+void AOClient::cmdBlockWtce(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_wtce_blocked)
+        sendServerMessage("That player is already judge blocked!");
+    else {
+        sendServerMessage("Revoked player's access to judge controls.");
+        target->sendServerMessage("A moderator revoked your judge controls access. " + getReprimand());
+    }
+    target->is_wtce_blocked = true;
+}
+
+void AOClient::cmdUnBlockWtce(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_wtce_blocked)
+        sendServerMessage("That player is not judge blocked!");
+    else {
+        sendServerMessage("Restored player's access to judge controls.");
+        target->sendServerMessage("A moderator restored your judge controls access. " + getReprimand(true));
+    }
+    target->is_wtce_blocked = false;
+}
+
 QStringList AOClient::buildAreaList(int area_idx)
 {
     QStringList entries;
@@ -1193,3 +1322,21 @@ long long AOClient::parseTime(QString input)
 
     return total;
 }
+
+QString AOClient::getReprimand(bool positive)
+{
+    QString filename = positive ? "praise" : "reprimands";
+    QFileInfo reprimands_info("config/text/" + filename + ".txt");
+    if (!(reprimands_info.exists() && reprimands_info.isFile())) {
+        qWarning() << filename + ".txt doesn't exist!";
+        return "";
+    }
+    QStringList reprimands;
+    QFile file("config/text/" + filename + ".txt");
+    file.open(QIODevice::ReadOnly | QIODevice::Text);
+    while (!file.atEnd()) {
+        reprimands.append(file.readLine().trimmed());
+    }
+    file.close();
+    return reprimands[genRand(0, reprimands.size() - 1)];
+}
diff --git a/src/packets.cpp b/src/packets.cpp
index 80e89ce..3ed0fd9 100644
--- a/src/packets.cpp
+++ b/src/packets.cpp
@@ -172,6 +172,11 @@ void AOClient::pktIcChat(AreaData* area, int argc, QStringList argv, AOPacket pa
 
 void AOClient::pktOocChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
 {
+    if (is_ooc_muted) {
+        sendServerMessage("You are OOC muted, and cannot speak.");
+        return;
+    }
+
     ooc_name = dezalgo(argv[0]).replace(QRegExp("\\[|\\]|\\{|\\}|\\#|\\$|\\%|\\&"), ""); // no fucky wucky shit here
     if (ooc_name.isEmpty() || ooc_name == server->getServerName()) // impersonation & empty name protection
         return;
@@ -203,6 +208,10 @@ void AOClient::pktPing(AreaData* area, int argc, QStringList argv, AOPacket pack
 
 void AOClient::pktChangeMusic(AreaData* area, int argc, QStringList argv, AOPacket packet)
 {
+    if (is_dj_blocked) {
+        sendServerMessage("You are blocked from changing the music.");
+        return;
+    }
     // Due to historical reasons, this
     // packet has two functions:
     // Change area, and set music.
@@ -243,6 +252,10 @@ void AOClient::pktChangeMusic(AreaData* area, int argc, QStringList argv, AOPack
 
 void AOClient::pktWtCe(AreaData* area, int argc, QStringList argv, AOPacket packet)
 {
+    if (is_wtce_blocked) {
+        sendServerMessage("You are blocked from using the judge controls.");
+        return;
+    }
     if (QDateTime::currentDateTime().toSecsSinceEpoch() - last_wtce_time <= 5)
         return;
     last_wtce_time = QDateTime::currentDateTime().toSecsSinceEpoch();
@@ -251,6 +264,10 @@ void AOClient::pktWtCe(AreaData* area, int argc, QStringList argv, AOPacket pack
 
 void AOClient::pktHpBar(AreaData* area, int argc, QStringList argv, AOPacket packet)
 {
+    if (is_wtce_blocked) {
+        sendServerMessage("You are blocked from using the judge controls.");
+        return;
+    }
     if (argv[0] == "1") {
         area->def_hp = std::min(std::max(0, argv[1].toInt()), 10);
     }