From de8badc9a6e74ca29cbc04ab5438d6eed2eb8984 Mon Sep 17 00:00:00 2001 From: Cerapter Date: Tue, 23 Oct 2018 16:15:15 +0200 Subject: [PATCH] Support for case alerts serverside. - Users can use an ingame button to alert people of cases. --- Attorney_Online_remake.pro | 6 ++- aoapplication.cpp | 9 +++++ aoapplication.h | 1 + aocaseannouncerdialog.cpp | 77 ++++++++++++++++++++++++++++++++++++++ aocaseannouncerdialog.h | 44 ++++++++++++++++++++++ courtroom.cpp | 33 +++++++++++++++- courtroom.h | 7 +++- server/aoprotocol.py | 2 +- server/client_manager.py | 15 ++++++++ server/commands.py | 48 ++++++++++++++++++++++++ 10 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 aocaseannouncerdialog.cpp create mode 100644 aocaseannouncerdialog.h diff --git a/Attorney_Online_remake.pro b/Attorney_Online_remake.pro index 9e31fa0..756a25b 100644 --- a/Attorney_Online_remake.pro +++ b/Attorney_Online_remake.pro @@ -50,7 +50,8 @@ SOURCES += main.cpp\ aoevidencedisplay.cpp \ discord_rich_presence.cpp \ aooptionsdialog.cpp \ - chatlogpiece.cpp + chatlogpiece.cpp \ + aocaseannouncerdialog.cpp HEADERS += lobby.h \ aoimage.h \ @@ -84,7 +85,8 @@ HEADERS += lobby.h \ discord-rpc.h \ aooptionsdialog.h \ text_file_functions.h \ - chatlogpiece.h + chatlogpiece.h \ + aocaseannouncerdialog.h # 1. You need to get BASS and put the x86 bass DLL/headers in the project root folder # AND the compilation output folder. If you want a static link, you'll probably diff --git a/aoapplication.cpp b/aoapplication.cpp index 03679a7..67807ff 100644 --- a/aoapplication.cpp +++ b/aoapplication.cpp @@ -6,6 +6,7 @@ #include "debug_functions.h" #include "aooptionsdialog.h" +#include "aocaseannouncerdialog.h" AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv) { @@ -184,3 +185,11 @@ void AOApplication::call_settings_menu() settings->exec(); delete settings; } + + +void AOApplication::call_announce_menu(Courtroom *court) +{ + AOCaseAnnouncerDialog* announcer = new AOCaseAnnouncerDialog(nullptr, this, court); + announcer->exec(); + delete announcer; +} diff --git a/aoapplication.h b/aoapplication.h index e106bcc..eafb2b7 100644 --- a/aoapplication.h +++ b/aoapplication.h @@ -56,6 +56,7 @@ public: void send_server_packet(AOPacket *p_packet, bool encoded = true); void call_settings_menu(); + void call_announce_menu(Courtroom *court); /////////////////server metadata////////////////// diff --git a/aocaseannouncerdialog.cpp b/aocaseannouncerdialog.cpp new file mode 100644 index 0000000..aa37353 --- /dev/null +++ b/aocaseannouncerdialog.cpp @@ -0,0 +1,77 @@ +#include "aocaseannouncerdialog.h" + +AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, AOApplication *p_ao_app, Courtroom *p_court) +{ + ao_app = p_ao_app; + court = p_court; + + setWindowTitle("Case Announcer"); + resize(405, 235); + + AnnouncerButtons = new QDialogButtonBox(this); + + QSizePolicy sizepolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + sizepolicy.setHorizontalStretch(0); + sizepolicy.setVerticalStretch(0); + sizepolicy.setHeightForWidth(AnnouncerButtons->sizePolicy().hasHeightForWidth()); + AnnouncerButtons->setSizePolicy(sizepolicy); + AnnouncerButtons->setOrientation(Qt::Horizontal); + AnnouncerButtons->setStandardButtons(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); + + QObject::connect(AnnouncerButtons, SIGNAL(accepted()), this, SLOT(ok_pressed())); + QObject::connect(AnnouncerButtons, SIGNAL(rejected()), this, SLOT(cancel_pressed())); + + setUpdatesEnabled(false); + + VBoxLayout = new QVBoxLayout(this); + + FormLayout = new QFormLayout(this); + FormLayout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); + FormLayout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); + FormLayout->setContentsMargins(6, 6, 6, 6); + + VBoxLayout->addItem(FormLayout); + VBoxLayout->addWidget(AnnouncerButtons); + + CaseTitleLabel = new QLabel(this); + CaseTitleLabel->setText("Case title:"); + + FormLayout->setWidget(0, QFormLayout::LabelRole, CaseTitleLabel); + + CaseTitleLineEdit = new QLineEdit(this); + CaseTitleLineEdit->setMaxLength(50); + + FormLayout->setWidget(0, QFormLayout::FieldRole, CaseTitleLineEdit); + + DefenceNeeded = new QCheckBox(this); + DefenceNeeded->setText("Defence needed"); + ProsecutorNeeded = new QCheckBox(this); + ProsecutorNeeded->setText("Prosecution needed"); + JudgeNeeded = new QCheckBox(this); + JudgeNeeded->setText("Judge needed"); + JurorNeeded = new QCheckBox(this); + JurorNeeded->setText("Jurors needed"); + + FormLayout->setWidget(1, QFormLayout::FieldRole, DefenceNeeded); + FormLayout->setWidget(2, QFormLayout::FieldRole, ProsecutorNeeded); + FormLayout->setWidget(3, QFormLayout::FieldRole, JudgeNeeded); + FormLayout->setWidget(4, QFormLayout::FieldRole, JurorNeeded); + + setUpdatesEnabled(true); +} + +void AOCaseAnnouncerDialog::ok_pressed() +{ + court->announce_case(CaseTitleLineEdit->text(), + DefenceNeeded->isChecked(), + ProsecutorNeeded->isChecked(), + JudgeNeeded->isChecked(), + JurorNeeded->isChecked()); + + done(0); +} + +void AOCaseAnnouncerDialog::cancel_pressed() +{ + done(0); +} diff --git a/aocaseannouncerdialog.h b/aocaseannouncerdialog.h new file mode 100644 index 0000000..b98f4d7 --- /dev/null +++ b/aocaseannouncerdialog.h @@ -0,0 +1,44 @@ +#ifndef AOCASEANNOUNCERDIALOG_H +#define AOCASEANNOUNCERDIALOG_H + +#include "aoapplication.h" +#include "courtroom.h" + +#include +#include +#include +#include +#include +#include +#include + +class AOCaseAnnouncerDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr, Courtroom *p_court = nullptr); + +private: + AOApplication *ao_app; + Courtroom *court; + + QDialogButtonBox *AnnouncerButtons; + + QVBoxLayout *VBoxLayout; + QFormLayout *FormLayout; + + QLabel *CaseTitleLabel; + QLineEdit *CaseTitleLineEdit; + + QCheckBox *DefenceNeeded; + QCheckBox *ProsecutorNeeded; + QCheckBox *JudgeNeeded; + QCheckBox *JurorNeeded; + +public slots: + void ok_pressed(); + void cancel_pressed(); +}; + +#endif // AOCASEANNOUNCERDIALOG_H diff --git a/courtroom.cpp b/courtroom.cpp index 4426caa..9cf074a 100644 --- a/courtroom.cpp +++ b/courtroom.cpp @@ -191,6 +191,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_reload_theme = new AOButton(this, ao_app); ui_call_mod = new AOButton(this, ao_app); ui_settings = new AOButton(this, ao_app); + ui_announce_casing = new AOButton(this, ao_app); ui_switch_area_music = new AOButton(this, ao_app); ui_pre = new QCheckBox(this); @@ -202,7 +203,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_guard->setText("Guard"); ui_guard->hide(); ui_casing = new QCheckBox(this); - ui_showname_enable->setChecked(ao_app->get_casing_enabled()); + ui_casing->setChecked(ao_app->get_casing_enabled()); ui_casing->setText("Casing"); ui_casing->hide(); @@ -322,6 +323,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_reload_theme, SIGNAL(clicked()), this, SLOT(on_reload_theme_clicked())); connect(ui_call_mod, SIGNAL(clicked()), this, SLOT(on_call_mod_clicked())); connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); + connect(ui_announce_casing, SIGNAL(clicked()), this, SLOT(on_announce_casing_clicked())); connect(ui_switch_area_music, SIGNAL(clicked()), this, SLOT(on_switch_area_music_clicked())); connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); @@ -431,6 +433,15 @@ void Courtroom::set_widgets() ui_ic_chat_name->setEnabled(false); } + if (ao_app->casing_alerts_enabled) + { + ui_announce_casing->show(); + } + else + { + ui_announce_casing->hide(); + } + // We also show the non-server-dependent client additions. // Once again, if the theme can't display it, set_move_and_pos will catch them. ui_settings->show(); @@ -597,6 +608,9 @@ void Courtroom::set_widgets() set_size_and_pos(ui_settings, "settings"); ui_settings->setText("Settings"); + set_size_and_pos(ui_announce_casing, "casing_button"); + ui_announce_casing->setText("Casing"); + set_size_and_pos(ui_switch_area_music, "switch_area_music"); ui_switch_area_music->setText("A/M"); @@ -3461,6 +3475,11 @@ void Courtroom::on_settings_clicked() ao_app->call_settings_menu(); } +void Courtroom::on_announce_casing_clicked() +{ + ao_app->call_announce_menu(this); +} + void Courtroom::on_pre_clicked() { ui_ic_chat_message->setFocus(); @@ -3551,6 +3570,18 @@ void Courtroom::on_casing_clicked() } } +void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, bool jur) +{ + if (ao_app->casing_alerts_enabled) + ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/anncase \"" + + title + "\" " + + QString::number(def) + " " + + QString::number(pro) + " " + + QString::number(jud) + " " + + QString::number(jur) + + "#%")); +} + Courtroom::~Courtroom() { delete music_player; diff --git a/courtroom.h b/courtroom.h index 2b60db5..0dc7ba4 100644 --- a/courtroom.h +++ b/courtroom.h @@ -198,6 +198,8 @@ public: //state is an number between 0 and 10 inclusive void set_hp_bar(int p_bar, int p_state); + void announce_case(QString title, bool def, bool pro, bool jud, bool jur); + void check_connection_received(); ~Courtroom(); @@ -218,6 +220,7 @@ private: int maximumMessages = 0; // This is for inline message-colouring. + enum INLINE_COLOURS { INLINE_BLUE, INLINE_GREEN, @@ -455,6 +458,7 @@ private: AOButton *ui_reload_theme; AOButton *ui_call_mod; AOButton *ui_settings; + AOButton *ui_announce_casing; AOButton *ui_switch_area_music; QCheckBox *ui_pre; @@ -536,8 +540,6 @@ private: void construct_evidence(); void set_evidence_page(); - - public slots: void objection_done(); void preanim_done(); @@ -625,6 +627,7 @@ private slots: void on_reload_theme_clicked(); void on_call_mod_clicked(); void on_settings_clicked(); + void on_announce_casing_clicked(); void on_pre_clicked(); void on_flip_clicked(); diff --git a/server/aoprotocol.py b/server/aoprotocol.py index 1bf9001..0af8f67 100644 --- a/server/aoprotocol.py +++ b/server/aoprotocol.py @@ -213,7 +213,7 @@ class AOProtocol(asyncio.Protocol): self.client.is_ao2 = True - self.client.send_command('FL', 'yellowtext', 'customobjections', 'flipping', 'fastloading', 'noencryption', 'deskmod', 'evidence', 'modcall_reason', 'cccc_ic_support', 'arup') + self.client.send_command('FL', 'yellowtext', 'customobjections', 'flipping', 'fastloading', 'noencryption', 'deskmod', 'evidence', 'modcall_reason', 'cccc_ic_support', 'arup', 'casing_alerts') def net_cmd_ch(self, _): """ Periodically checks the connection. diff --git a/server/client_manager.py b/server/client_manager.py index f5ef4ef..4a5c1ef 100644 --- a/server/client_manager.py +++ b/server/client_manager.py @@ -65,6 +65,15 @@ class ClientManager: self.flip = 0 self.claimed_folder = '' + # Casing stuff + self.casing_cm = False + self.casing_cases = "" + self.casing_def = False + self.casing_pro = False + self.casing_jud = False + self.casing_jur = False + self.case_call_time = 0 + #flood-guard stuff self.mus_counter = 0 self.mus_mute_time = 0 @@ -359,6 +368,12 @@ class ClientManager: def can_call_mod(self): return (time.time() * 1000.0 - self.mod_call_time) > 0 + def set_case_call_delay(self): + self.case_call_time = round(time.time() * 1000.0 + 60000) + + def can_call_case(self): + return (time.time() * 1000.0 - self.case_call_time) > 0 + def disemvowel_message(self, message): message = re.sub("[aeiou]", "", message, flags=re.IGNORECASE) return re.sub(r"\s+", " ", message) diff --git a/server/commands.py b/server/commands.py index aae12de..49fd979 100644 --- a/server/commands.py +++ b/server/commands.py @@ -16,6 +16,7 @@ # along with this program. If not, see . #possible keys: ip, OOC, id, cname, ipid, hdid import random +import re import hashlib import string from server.constants import TargetType @@ -767,6 +768,53 @@ def ooc_cmd_uncm(client, arg): client.send_host_message('{} does not look like a valid ID.'.format(id)) else: raise ClientError('You must be authorized to do that.') + +def ooc_cmd_setcase(client, arg): + args = re.findall(r'(?:[^\s,"]|"(?:\\.|[^"])*")+', arg) + if len(args) == 0: + raise ArgumentError('Please do not call this command manually!') + else: + client.casing_cases = args[0] + client.casing_cm = args[1] == "1" + client.casing_def = args[2] == "1" + client.casing_pro = args[3] == "1" + client.casing_jud = args[4] == "1" + client.casing_jur = args[5] == "1" + +def ooc_cmd_anncase(client, arg): + if client in client.area.owners: + if not client.can_call_case(): + raise ClientError('Please wait 60 seconds between case announcements!') + args = re.findall(r'(?:[^\s,"]|"(?:\\.|[^"])*")+', arg) + if len(args) == 0: + raise ArgumentError('Please do not call this command manually!') + elif len(args) == 1: + raise ArgumentError('You should probably announce the case to at least one person.') + else: + if not args[1] == "1" and not args[2] == "1" and not args[3] == "1" and not args[4] == "1": + raise ArgumentError('You should probably announce the case to at least one person.') + msg = '=== Case Announcement ===\r\n{} [{}] is hosting {}, looking for '.format(client.get_char_name(), client.id, args[0]) + + lookingfor = [] + + if args[1] == "1": + lookingfor.append("defence") + if args[2] == "1": + lookingfor.append("prosecutor") + if args[3] == "1": + lookingfor.append("judge") + if args[4] == "1": + lookingfor.append("juror") + + msg = msg + ', '.join(lookingfor) + '.\r\n==================' + + client.server.send_all_cmd_pred('CASEA', msg, args[1], args[2], args[3], args[4], '1') + + client.set_case_call_delay() + + logger.log_server('[{}][{}][CASE_ANNOUNCEMENT]{}, DEF: {}, PRO: {}, JUD: {}, JUR: {}.'.format(client.area.abbreviation, client.get_char_name(), args[0], args[1], args[2], args[3], args[4]), client) + else: + raise ClientError('You cannot announce a case in an area where you are not a CM!') def ooc_cmd_unmod(client, arg): client.is_mod = False