From 3b8bc386d316b6e177c814920f21f5ab5d798ee6 Mon Sep 17 00:00:00 2001 From: Osmium Sorcerer Date: Sun, 22 Mar 2026 17:30:03 +0000 Subject: Support passworded characters in character list This obscure feature has been present for years, from sending passwords to the server to showing `char_passworded` image over character icons. Servers could already exploit clients sending `PW` with a password every time they select a character to implement passworded characters. The clients had no way of knowing which ones were passworded, however, and couldn't filter them despite "Passworded" checkbox being here all along. The approach used by this commit is a hack. During loading, server sends SC which is a list of characters, each one having name, description, and evidence. In practice, only names were used. Descriptions were stored in memory but unused, and evidence was ignored altogether. By adding a magic value "P" in this "character evidence" field, server can mark passworded characters without breaking Vanilla compatibility. --- src/aocharbutton.cpp | 19 +++++++++++++++++++ src/aocharbutton.h | 4 ++++ src/charselect.cpp | 15 +++++++++------ src/courtroom.cpp | 1 + src/datatypes.h | 1 + src/packet_distribution.cpp | 5 +++++ 6 files changed, 39 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index d446cca3..fe87041f 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -11,6 +11,12 @@ AOCharButton::AOCharButton(AOApplication *ao_app, QWidget *parent) resize(size, size); + ui_passworded = new AOImage(ao_app, this); + ui_passworded->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_passworded->resize(size, size); + ui_passworded->setImage("char_passworded"); + ui_passworded->hide(); + ui_taken = new AOImage(ao_app, this); ui_taken->setAttribute(Qt::WA_TransparentForMouseEvents); ui_taken->resize(size, size); @@ -24,6 +30,19 @@ AOCharButton::AOCharButton(AOApplication *ao_app, QWidget *parent) ui_selector->hide(); } +void AOCharButton::setPassworded(bool enabled) +{ + if (enabled) + { + ui_passworded->move(0, 0); + ui_passworded->show(); + } + else + { + ui_passworded->hide(); + } +} + void AOCharButton::setTaken(bool enabled) { if (enabled) diff --git a/src/aocharbutton.h b/src/aocharbutton.h index ba618976..64bea50a 100644 --- a/src/aocharbutton.h +++ b/src/aocharbutton.h @@ -18,6 +18,8 @@ public: void setCharacter(QString character); + void setPassworded(bool enabled); + void setTaken(bool enabled); protected: @@ -30,7 +32,9 @@ protected: private: AOApplication *ao_app; + bool m_passworded = false; bool m_taken = false; + AOImage *ui_passworded; AOImage *ui_taken; AOImage *ui_selector; }; diff --git a/src/charselect.cpp b/src/charselect.cpp index 040bfd0e..2443393f 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -62,8 +62,8 @@ void Courtroom::construct_char_select() connect(ui_spectator, &AOButton::clicked, this, &Courtroom::on_spectator_clicked); connect(ui_char_search, &QLineEdit::textEdited, this, &Courtroom::on_char_search_changed); - connect(ui_char_passworded, &QCheckBox::stateChanged, this, &Courtroom::on_char_passworded_clicked); - connect(ui_char_taken, &QCheckBox::stateChanged, this, &Courtroom::on_char_taken_clicked); + connect(ui_char_passworded, &QCheckBox::checkStateChanged, this, &Courtroom::on_char_passworded_clicked); + connect(ui_char_taken, &QCheckBox::checkStateChanged, this, &Courtroom::on_char_taken_clicked); } void Courtroom::set_char_select() @@ -300,6 +300,7 @@ void Courtroom::character_loading_finished() char_button->setContextMenuPolicy(Qt::CustomContextMenu); char_button->hide(); char_button->setCharacter(character.name); + char_button->setPassworded(character.passworded); char_button->setTaken(character.taken); char_button->setToolTip(character.name); ui_char_button_list.append(char_button); @@ -354,10 +355,11 @@ void Courtroom::filter_character_list() AOCharButton *current_char = ui_char_button_list.at(i); QTreeWidgetItem *current_char_list_item = ui_char_list->findItems(QString::number(i), Qt::MatchExactly | Qt::MatchRecursive, 1).at(0); - // It seems passwording characters is unimplemented yet? - // Until then, this will stay here, I suppose. - // if (ui_char_passworded->isChecked() && character_is_passworded??) - // continue; + if (!ui_char_passworded->isChecked() && char_list.at(i).passworded) + { + current_char_list_item->setHidden(true); + continue; + } if (!ui_char_taken->isChecked() && char_list.at(i).taken) { @@ -375,6 +377,7 @@ void Courtroom::filter_character_list() // for the buttons that actually appear. // You'd also update the passwordedness and etc. here later. current_char_list_item->setHidden(false); + current_char->setPassworded(char_list.at(i).passworded); current_char->setTaken(char_list.at(i).taken); current_char_list_item->setText(0, char_list.at(i).name); // reset disabled diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 0edef949..82caddd2 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1357,6 +1357,7 @@ void Courtroom::set_taken(int n_char, bool p_taken) CharacterSlot f_char; f_char.name = char_list.at(n_char).name; f_char.description = char_list.at(n_char).description; + f_char.passworded = char_list.at(n_char).passworded; f_char.taken = p_taken; f_char.evidence_string = char_list.at(n_char).evidence_string; diff --git a/src/datatypes.h b/src/datatypes.h index 0bc6b20f..a6231c45 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -10,6 +10,7 @@ struct CharacterSlot QString name; QString description; QString evidence_string; + bool passworded; bool taken; }; diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 6aa50368..066fc6be 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -223,10 +223,15 @@ void AOApplication::server_packet_received(AOPacket packet) CharacterSlot f_char; f_char.name = sub_elements.at(0); + f_char.passworded = false; if (sub_elements.size() >= 2) { f_char.description = sub_elements.at(1); } + if (sub_elements.size() >= 3) + { + f_char.passworded = sub_elements.at(2) == "P"; + } // temporary. the CharsCheck packet sets this properly f_char.taken = false; -- cgit