aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore19
-rw-r--r--Attorney_Online_remake.pro31
-rw-r--r--README.md129
-rw-r--r--android/AndroidManifest.xml79
-rw-r--r--android/project.properties1
-rw-r--r--aoapplication.cpp25
-rw-r--r--aoapplication.h96
-rw-r--r--aoblipplayer.cpp38
-rw-r--r--aoblipplayer.h5
-rw-r--r--aocaseannouncerdialog.cpp82
-rw-r--r--aocaseannouncerdialog.h45
-rw-r--r--aocharbutton.cpp11
-rw-r--r--aocharbutton.h5
-rw-r--r--aocharmovie.cpp26
-rw-r--r--aocharmovie.h6
-rw-r--r--aomovie.cpp9
-rw-r--r--aomusicplayer.cpp19
-rw-r--r--aomusicplayer.h4
-rw-r--r--aooptionsdialog.cpp517
-rw-r--r--aooptionsdialog.h115
-rw-r--r--aoscene.cpp20
-rw-r--r--aoscene.h2
-rw-r--r--aosfxplayer.cpp38
-rw-r--r--aosfxplayer.h7
-rw-r--r--aotextarea.cpp4
-rw-r--r--aotextarea.h2
-rw-r--r--base/serverlist.txt5
-rw-r--r--charselect.cpp208
-rw-r--r--chatlogpiece.cpp76
-rw-r--r--chatlogpiece.h31
-rw-r--r--courtroom.cpp1775
-rw-r--r--courtroom.h193
-rw-r--r--datatypes.h14
-rw-r--r--discord_rich_presence.h5
-rw-r--r--emotes.cpp2
-rw-r--r--encryption_functions.cpp6
-rw-r--r--encryption_functions.h6
-rw-r--r--evidence.cpp3
-rw-r--r--file_functions.cpp3
-rw-r--r--file_functions.h2
-rw-r--r--hex_functions.cpp2
-rw-r--r--include/discord_register.h26
-rw-r--r--include/discord_rpc.h87
-rw-r--r--lobby.cpp14
-rw-r--r--lobby.h4
-rw-r--r--main.cpp6
-rw-r--r--misc_functions.cpp3
-rw-r--r--misc_functions.h3
-rw-r--r--networkmanager.cpp7
-rw-r--r--networkmanager.h1
-rw-r--r--packet_distribution.cpp160
-rw-r--r--path_functions.cpp2
-rw-r--r--text_file_functions.cpp355
-rw-r--r--text_file_functions.h13
54 files changed, 3747 insertions, 600 deletions
diff --git a/.gitignore b/.gitignore
index 9a949cb9..9d5dcdb9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,22 @@ base_override.h
base-full/
bass.lib
+
+bins/
+release/
+debug/
+
+.qmake.stash
+
+Makefile*
+object_script*
+/Attorney_Online_remake_resource.rc
+/attorney_online_remake_plugin_import.cpp
+
+server/__pycache__
+discord/
+
+*.o
+moc*
+/Attorney_Online_CC_resource.rc
+/attorney_online_cc_plugin_import.cpp
diff --git a/Attorney_Online_remake.pro b/Attorney_Online_remake.pro
index 86a86073..62a7dc98 100644
--- a/Attorney_Online_remake.pro
+++ b/Attorney_Online_remake.pro
@@ -5,15 +5,14 @@
#-------------------------------------------------
QT += core gui multimedia network
-
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
RC_ICONS = logo.ico
-TARGET = Attorney_Online_remake
+TARGET = Attorney_Online
TEMPLATE = app
-VERSION = 2.4.10.0
+VERSION = 2.6.0.0
SOURCES += main.cpp\
lobby.cpp \
@@ -48,7 +47,10 @@ SOURCES += main.cpp\
aolineedit.cpp \
aotextedit.cpp \
aoevidencedisplay.cpp \
- discord_rich_presence.cpp
+ discord_rich_presence.cpp \
+ aooptionsdialog.cpp \
+ chatlogpiece.cpp \
+ aocaseannouncerdialog.cpp
HEADERS += lobby.h \
aoimage.h \
@@ -78,18 +80,23 @@ HEADERS += lobby.h \
aotextedit.h \
aoevidencedisplay.h \
discord_rich_presence.h \
- discord-rpc.h
-
-# You need to compile the Discord Rich Presence SDK separately and add the lib/headers.
-# Discord RPC uses CMake, which does not play nicely with QMake, so this step must be manual.
+ discord-rpc.h \
+ aooptionsdialog.h \
+ text_file_functions.h \
+ chatlogpiece.h \
+ aocaseannouncerdialog.h
-unix:LIBS += -L$$PWD -ldiscord-rpc
-win32:LIBS += -L$$PWD -ldiscord-rpc #"$$PWD/discord-rpc.dll"
+# 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
+# need the .lib file too. MinGW-GCC is really finicky finding BASS, it seems.
+# 2. You need to compile the Discord Rich Presence SDK separately and add the lib/headers
+# in the same way as BASS. Discord RPC uses CMake, which does not play nicely with
+# QMake, so this step must be manual.
+unix:LIBS += -L$$PWD -lbass -ldiscord-rpc
+win32:LIBS += -L$$PWD "$$PWD/bass.dll" -ldiscord-rpc
CONFIG += c++11
-ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
-
RESOURCES += \
resources.qrc
diff --git a/README.md b/README.md
index 569b6b20..0df61ae7 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,132 @@
+# Attorney Online 2: Case Café Custom Client (AO2:CCCC)
+
+This project is a custom client made specifically for the Case Café server of Attorney Online 2. Nevertheless, the client itself has a bunch of features that are server independent, and if you so wish to run a server with the additional features, get yourself a copy of `tsuserver3`, and replace its `server/` folder with the one supplied here.
+
+Building the project is... complicated. I'm not even sure what I'm doing myself, most of the time. Still, get yourself Qt Creator, and compile the project using that, that's the easiest method of doing things.
+
+Alternatively, you may wait till I make some stuff, and release a compiled executable. You may find said executables in the 'Tags' submenu to the left.
+
+## Features
+
+- **Inline colouring:** allows you to change the text's colour midway through the text.
+ - `()` (parentheses) will make the text inbetween them blue.
+ - \` (backwards apostrophes) will make the text green.
+ - `|` (straight lines) will make the text orange.
+ - `[]` (square brackets) will make the text grey.
+ - No need for server support: the clients themselves will interpret these.
+- **Additional text features:**
+ - Type `{` to slow down the text a bit. This takes effect after the character has been typed, so the text may take up different speeds at different points.
+ - Type `}` to do the opposite! Similar rules apply.
+ - Both of these can be stacked up to three times, and even against eachother.
+ - As an example, here is a text:
+ ```
+ Hello there! This text goes at normal speed.} Now, it's a bit faster!{ Now, it's back to normal.}}} Now it goes at maximum speed! {{Now it's only a little bit faster than normal.
+ ```
+ - If you begin a message with `~~` (two tildes), those two tildes will be removed, and your message will be centered.
+- **Use the in-game settings button:**
+ - If the theme supports it, you may have a Settings button on the client now, but you can also just type `/settings` in the OOC.
+ - Modify the contents of your `config.ini` and `callwords.ini` from inside the game!
+ - Some options may need a restart to take effect.
+- **Custom Discord RPC icon and name!**
+- **Enhanced character selection screen:**
+ - The game preloads the characters' icons available on the server, avoiding lag on page switch this way.
+ - As a side-effect of this, characters can now easily be filtered down to name, whether they are passworded, and if they're taken.
+- **Server-supported features:** These will require the modifications in the `server/` folder applied to the server.
+ - Call mod reason: allows you to input a reason for your modcall.
+ - Modcalls can be cancelled, if needed.
+ - Shouts can be disabled serverside (in the sense that they can still interrupt text, but will not make a sound or make the bubble appear).
+ - The characters' shownames can be changed.
+ - This needs the server to specifically approve it in areas.
+ - The client can also turn off the showing of changed shownames if someone is maliciously impersonating someone.
+ - Any character in the 'jud' position can make a Guilty / Not Guilty text appear with the new button additions.
+ - These work like the WT / CE popups.
+ - Capitalisation ignored for server commands. `/getarea` is exactly the same as `/GEtAreA`!
+ - Various quality-of-life changes for mods, like `/m`, a server-wide mods-only chat.
+ - Disallow blankposting using `/allow_blankposting`.
+ - Avoid cucking by setting a jukebox using `/jukebox_toggle`.
+ - Check the contents of the jukbox with `/jukebox`.
+ - If you're a mod or the CM, skip the current jukebox song using `/jukebox_skip`.
+ - Pair up with someone else!
+ - If two people select eachother's character's character ID using the in-game pair button, or with `/pair [id]`, they will appear on the same screen (assuming they're both in the same position).
+ - When you appear alongside someone else, you can offset your character to either side using the in-game spinbox, or with `/offset [percentage]`. The percentage can go from -100% (one whole screen's worth to the left) to 100% (one whole screen's worth to the right).
+ - Areas can have multiple CMs, and these CMs can be anywhere on the server!
+ - CMs away from the areas they CM in can still see IC and OOC messages coming from there.
+ - They can also remotely send messages with the `/a [area_id]` command (works both IC and OOC!) or the `/s` command, if they want to message all areas.
+ - A CM can add other CMs using `/cm [id]`.
+ - Tired of waiting for pres to finish? Try non-interrupting pres!
+ - Tired of waiting for OTHERS' pres to finish? `/force_nonint_pres` that thing!
+ - Also tired of filling evidence up one-by-one? Try `/load_case`!
+ - Additional juror and seance positions for your RPing / casing needs.
+ - Areas can be set to locked and spectatable.
+ - Spectatable areas (using `/area_spectate`) allow people to join, but not talk if they're not on the invite list.
+ - Locked areas (using `/area_lock`) forbid people not on the invite list from even entering.
+ - Can't find people to case with? Try the case alert system!
+ -
+- **Area list:**
+ - The client automatically filters out areas from music if applicable, and these appear in their own list.
+ - Use the in-game A/M button, or the `/switch_am` command to switch between them.
+ - If the server supports it, you can even get constant updates about changes in the areas, like players leaving, CMs appearing, statuses changing, etc.
+- **Features not mentioned in here?**
+ - Check the link given by the `/help` function.
+ - Alternatively, assuming you're reading this on the Github page, browse the wiki!
+
+## Modifications that need to be done
+
+Since this custom client, and the server files supplied with it, add a few features not present in Vanilla, some modifications need to be done to ensure that you can use the full extent of them all. These are as follows:
+
+- **In `areas.yaml`:** (assuming you are the server owner)
+ - You may add `shouts_allowed` to any of the areas to enable / disable shouts (and judge buttons, and realisation). By default, it's `shouts_allowed: true`.
+ - You may add `jukebox` to any of the areas to enable the jukebox in there, but you can also use `/jukebox_toggle` in game as a mod to do the same thing. By default, it's `jukebox: false`.
+ - You may add `showname_changes_allowed` to any of the areas to allow custom shownames used in there. If it's forbidden, players can't send messages or change music as long as they have a custom name set. By default, it's `showname_changes_allowed: false`.
+ - You may add `abbreviation` to override the server-generated abbreviation of the area. Instead of area numbers, this server-pack uses area abbreviations in server messages for easier understanding (but still uses area IDs in commands, of course). No default here, but here is an example: `abbreviation: SIN` gives the area the abbreviation of 'SIN'.
+ - You may add `noninterrupting_pres` to force users to use non-interrupting pres only. CCCC users will see the pres play as the text goes, Vanilla users will not see pres at all. The default is `noninterrupting_pres: false`.
+- **In your themes:**
+ - You'll need the following, additional images:
+ - `notguilty.gif`, which is a gif of the Not Guilty verdict being given.
+ - `guilty.gif`, which is a gif of the Guilty verdict being given.
+ - `notguilty.png`, which is a static image for the button for the Not Guilty verdict.
+ - `guilty.png`, which is a static image for the button for the Guilty verdict.
+ - `pair_button.png`, which is a static image for the Pair button, when it isn't pressed.
+ - `pair_button_pressed.png`, which is the same, but for when the button is pressed.
+ - In your `lobby_design.ini`:
+ - Extend the width of the `version` label to a bigger size. Said label now shows both the underlying AO's version, and the custom client's version.
+ - In your `courtroom_sounds.ini`:
+ - Add a sound effect for `not_guilty`, for example: `not_guilty = sfx-notguilty.wav`.
+ - Add a sound effect for `guilty`, for example: `guilty = sfx-guilty.wav`.
+ - Add a sound effect for the case alerts. They work similarly to modcall alerts, or callword alerts. For example: `case_call = sfx-triplegavel-soj.wav`.
+ - In your `courtroom_design.ini`, place the following new UI elements as and if you wish:
+ - `log_limit_label`, which is a simple text that exmplains what the spinbox with the numbers is. Needs an X, Y, width, height number.
+ - `log_limit_spinbox`, which is the spinbox for the log limit, allowing you to set the size of the log limit in-game. Needs the same stuff as above.
+ - `ic_chat_name`, which is an input field for your custom showname. Needs the same stuff.
+ - `ao2_ic_chat_name`, which is the same as above, but comes into play when the background has a desk.
+ - Further comments on this: all `ao2_` UI elements come into play when the background has a desk. However, in AO2 nowadays, it's customary for every background to have a desk, even if it's just an empty gif. So you most likely have never seen the `ao2_`-less UI elements ever come into play, unless someone mis-named a desk or something.
+ - `showname_enable` is a tickbox that toggles whether you should see shownames or not. This does not influence whether you can USE custom shownames or not, so you can have it off, while still showing a custom showname to everyone else. Needs X, Y, width, height as usual.
+ - `settings` is a plain button that takes up the OS's looks, like the 'Call mod' button. Takes the same arguments as above.
+ - You can also just type `/settings` in OOC.
+ - `char_search` is a text input box on the character selection screen, which allows you to filter characters down to name. Needs the same arguments.
+ - `char_passworded` is a tickbox, that when ticked, shows all passworded characters on the character selection screen. Needs the same as above.
+ - `char_taken` is another tickbox, that does the same, but for characters that are taken.
+ - `not_guilty` is a button similar to the CE / WT buttons, that if pressed, plays the Not Guilty verdict animation. Needs the same arguments.
+ - `guilty` is similar to `not_guilty`, but for the Guilty verdict.
+ - `pair_button` is a toggleable button, that shows and hides the pairing list and the offset spinbox. Works similarly to the mute button.
+ - `pair_list` is a list of all characters in alphabetical order, shown when the user presses the Pair button. If a character is clicked on it, it is selected as the character the user wants to pair up with.
+ - `pair_offset_spinbox` is a spinbox that allows the user to choose between offsets of -100% to 100%.
+ - `switch_area_music` is a button with the text 'A/M', that toggles between the music list and the areas list. Though the two are different, they are programmed to take the same space.
+ - `pre_no_interrupt` is a tickbox with the text 'No Intrpt', that toggles whether preanimations should delay the text or not.
+ - `area_free_color` is a combination of red, green, and blue values ranging from 0 to 255. This determines the colour of the area in the Area list if it's free, and has a status of IDLE.
+ - `area_lfp_color` determines the colour of the area if its status is LOOKING-FOR-PLAYERS.
+ - `area_casing_color` determines the colour of the area if its status is CASING.
+ - `area_recess_color` determines the colour of the area if its status is RECESS.
+ - `area_rp_color` determines the colour of the area if its status is RP.
+ - `area_gaming_color` determines the colour of the area if its status is GAMING.
+ - `area_locked_color` determines the colour of the area if it is locked, REGARDLESS of status.
+ - `ooc_default_color` determines the colour of the username in the OOC chat if the message doesn't come from the server.
+ - `ooc_server_color` determines the colour of the username if the message arrived from the server.
+ - `casing_button` is a button with the text 'Casing' that when clicked, brings up the Case Announcements dialog. You can give the case a name, and tick whom do you want to alert. You need to be a CM for it to go through. Only people who have at least one of the roles ticked will get the alert.
+ - `casing` is a tickbox with the text 'Casing'. If ticked, you will get the case announcements alerts you should get, in accordance to the above. In the settings, you can change your defaults on the 'Casing' tab. (That's a buncha things titled 'Casing'!)
+
+---
+
# Attorney-Online-Client-Remake
This is a open-source remake of Attorney Online written by OmniTroid. The original Attorney Online client was written by FanatSors in Delphi.
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
deleted file mode 100644
index f458c6a7..00000000
--- a/android/AndroidManifest.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0"?>
-<manifest package="com.aceattorneyonline.ao2" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.3.5.0" android:versionCode="2" android:installLocation="auto">
- <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="Attorney Online 2" android:icon="@drawable/icon">
- <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="Attorney Online 2 Lobby" android:screenOrientation="unspecified" android:launchMode="singleTop">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
-
- <!-- Application arguments -->
- <!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
- <!-- Application arguments -->
-
- <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
- <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
- <meta-data android:name="android.app.repository" android:value="default"/>
- <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
- <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
- <!-- Deploy Qt libs as part of package -->
- <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
- <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
- <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
- <!-- Run with local libs -->
- <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
- <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
- <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
- <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
- <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
- <!-- Messages maps -->
- <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
- <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
- <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
- <!-- Messages maps -->
-
- <!-- Splash screen -->
- <!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
- <!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
- <!-- Splash screen -->
-
- <!-- Background running -->
- <!-- Warning: changing this value to true may cause unexpected crashes if the
- application still try to draw after
- "applicationStateChanged(Qt::ApplicationSuspended)"
- signal is sent! -->
- <meta-data android:name="android.app.background_running" android:value="false"/>
- <!-- Background running -->
-
- <!-- auto screen scale factor -->
- <meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
- <!-- auto screen scale factor -->
-
- <!-- extract android style -->
- <!-- available android:values :
- * full - useful QWidget & Quick Controls 1 apps
- * minimal - useful for Quick Controls 2 apps, it is much faster than "full"
- * none - useful for apps that don't use any of the above Qt modules
- -->
- <meta-data android:name="android.app.extract_android_style" android:value="full"/>
- <!-- extract android style -->
- </activity>
-
- <!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
-
- </application>
-
- <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23"/>
- <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
-
- <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
- Remove the comment if you do not require these default permissions. -->
-
-
- <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
- Remove the comment if you do not require these default features. -->
- <!-- %%INSERT_FEATURES -->
-
-<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.INTERNET"/>
-</manifest>
diff --git a/android/project.properties b/android/project.properties
deleted file mode 100644
index a08f37ed..00000000
--- a/android/project.properties
+++ /dev/null
@@ -1 +0,0 @@
-target=android-21 \ No newline at end of file
diff --git a/aoapplication.cpp b/aoapplication.cpp
index 62a4a39c..cb98aef7 100644
--- a/aoapplication.cpp
+++ b/aoapplication.cpp
@@ -5,8 +5,14 @@
#include "networkmanager.h"
#include "debug_functions.h"
+#include "aooptionsdialog.h"
+#include "aocaseannouncerdialog.h"
+
AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv)
{
+ // Create the QSettings class that points to the config.ini.
+ configini = new QSettings(get_base_path() + "config.ini", QSettings::IniFormat);
+
net_manager = new NetworkManager(this);
discord = new AttorneyOnline::Discord();
QObject::connect(net_manager, SIGNAL(ms_connect_finished(bool, bool)),
@@ -36,7 +42,7 @@ void AOApplication::construct_lobby()
int y = (screenGeometry.height()-w_lobby->height()) / 2;
w_lobby->move(x, y);
- if(is_discord_enabled())
+ if (is_discord_enabled())
discord->state_lobby();
w_lobby->show();
@@ -151,8 +157,9 @@ void AOApplication::ms_connect_finished(bool connected, bool will_retry)
{
if (will_retry)
{
- w_lobby->append_error("Error connecting to master server. Will try again in "
- + QString::number(net_manager->ms_reconnect_delay_ms / 1000.f) + " seconds.");
+ if (w_lobby != nullptr)
+ w_lobby->append_error("Error connecting to master server. Will try again in "
+ + QString::number(net_manager->ms_reconnect_delay_ms / 1000.f) + " seconds.");
}
else
{
@@ -164,3 +171,15 @@ void AOApplication::ms_connect_finished(bool connected, bool will_retry)
}
}
}
+
+void AOApplication::call_settings_menu()
+{
+ AOOptionsDialog settings(nullptr, this);
+ settings.exec();
+}
+
+void AOApplication::call_announce_menu(Courtroom *court)
+{
+ AOCaseAnnouncerDialog announcer(nullptr, this, court);
+ announcer.exec();
+}
diff --git a/aoapplication.h b/aoapplication.h
index 6f970150..a237b8f4 100644
--- a/aoapplication.h
+++ b/aoapplication.h
@@ -8,10 +8,21 @@
#include <QApplication>
#include <QVector>
#include <QFile>
+#include <QSettings>
+
#include <QDebug>
#include <QRect>
#include <QDesktopWidget>
+#include <QCryptographicHash>
+
+#include <QDir>
+#include <QStandardPaths>
+
+#include <QTextStream>
+#include <QStringList>
+#include <QColor>
+
class NetworkManager;
class Lobby;
class Courtroom;
@@ -44,6 +55,9 @@ public:
void send_ms_packet(AOPacket *p_packet);
void send_server_packet(AOPacket *p_packet, bool encoded = true);
+ void call_settings_menu();
+ void call_announce_menu(Courtroom *court);
+
/////////////////server metadata//////////////////
unsigned int s_decryptor = 5;
@@ -56,6 +70,10 @@ public:
bool improved_loading_enabled = false;
bool desk_mod_enabled = false;
bool evidence_enabled = false;
+ bool cccc_ic_support_enabled = false;
+ bool arup_enabled = false;
+ bool casing_alerts_enabled = false;
+ bool modcall_reason_enabled = false;
///////////////loading info///////////////////
@@ -66,6 +84,7 @@ public:
int char_list_size = 0;
int loaded_chars = 0;
+ int generated_chars = 0;
int evidence_list_size = 0;
int loaded_evidence = 0;
int music_list_size = 0;
@@ -75,9 +94,9 @@ public:
//////////////////versioning///////////////
- int get_release() {return RELEASE;}
- int get_major_version() {return MAJOR_VERSION;}
- int get_minor_version() {return MINOR_VERSION;}
+ constexpr int get_release() const { return RELEASE; }
+ constexpr int get_major_version() const { return MAJOR_VERSION; }
+ constexpr int get_minor_version() const { return MINOR_VERSION; }
QString get_version_string();
///////////////////////////////////////////
@@ -111,8 +130,8 @@ public:
////// Functions for reading and writing files //////
// Implementations file_functions.cpp
- //Returns the config value for the passed searchline from a properly formatted config ini file
- QString read_config(QString searchline);
+ // Instead of reinventing the wheel, we'll use a QSettings class.
+ QSettings *configini;
//Reads the theme from config.ini and loads it into the current_theme variable
QString read_theme();
@@ -135,11 +154,26 @@ public:
//Returns the value of default_blip in config.ini
int get_default_blip();
- //Returns true if discord is enabled in config.ini and false otherwise
+ // Returns the value of whether Discord should be enabled on startup
+ // from the config.ini.
bool is_discord_enabled();
- //Returns true if reverse IC is enabled in config.ini and false otherwise
- bool ic_scroll_down_enabled();
+ // Returns the value of the maximum amount of lines the IC chatlog
+ // may contain, from config.ini.
+ int get_max_log_size();
+
+ // Returns whether the log should go upwards (new behaviour)
+ // or downwards (vanilla behaviour).
+ bool get_log_goes_downwards();
+
+ // Returns the username the user may have set in config.ini.
+ QString get_default_username();
+
+ // Returns the audio device used for the client.
+ QString get_audio_output_device();
+
+ // Returns whether the user would like to have custom shownames on by default.
+ bool get_showname_enabled_by_default();
//Returns the list of words in callwords.ini
QStringList get_call_words();
@@ -165,11 +199,20 @@ public:
//Returns the color with p_identifier from p_file
QColor get_color(QString p_identifier, QString p_file);
+ // Returns the colour from the misc folder.
+ QColor get_chat_color(QString p_identifier, QString p_chat);
+
//Returns the sfx with p_identifier from sounds.ini in the current theme path
QString get_sfx(QString p_identifier);
+ //Figure out if we can opus this or if we should fall back to wav
+ QString get_sfx_suffix(QString sound_to_check);
+
+ // Can we use APNG for this? If not, fall back to a gif.
+ QString get_image_suffix(QString path_to_check);
+
//Returns the value of p_search_line within target_tag and terminator_tag
- QString read_char_ini(QString p_char, QString p_search_line, QString target_tag, QString terminator_tag);
+ QString read_char_ini(QString p_char, QString p_search_line, QString target_tag);
//Returns the side of the p_char character from that characters ini file
QString get_char_side(QString p_char);
@@ -192,6 +235,9 @@ public:
//Not in use
int get_text_delay(QString p_char, QString p_emote);
+ // Returns the custom realisation used by the character.
+ QString get_custom_realization(QString p_char);
+
//Returns the name of p_char
QString get_char_name(QString p_char);
@@ -222,10 +268,38 @@ public:
//Returns p_char's gender
QString get_gender(QString p_char);
+ // ======
+ // These are all casing-related settings.
+ // ======
+
+ // Returns if the user has casing alerts enabled.
+ bool get_casing_enabled();
+
+ // Returns if the user wants to get alerts for the defence role.
+ bool get_casing_defence_enabled();
+
+ // Same for prosecution.
+ bool get_casing_prosecution_enabled();
+
+ // Same for judge.
+ bool get_casing_judge_enabled();
+
+ // Same for juror.
+ bool get_casing_juror_enabled();
+
+ // Same for steno.
+ bool get_casing_steno_enabled();
+
+ // Same for CM.
+ bool get_casing_cm_enabled();
+
+ // Get the message for the CM for casing alerts.
+ QString get_casing_can_host_cases();
+
private:
const int RELEASE = 2;
- const int MAJOR_VERSION = 4;
- const int MINOR_VERSION = 10;
+ const int MAJOR_VERSION = 6;
+ const int MINOR_VERSION = 0;
QString current_theme = "default";
diff --git a/aoblipplayer.cpp b/aoblipplayer.cpp
index 1e33236d..0ea08978 100644
--- a/aoblipplayer.cpp
+++ b/aoblipplayer.cpp
@@ -2,32 +2,46 @@
AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app)
{
- m_sfxplayer = new QSoundEffect;
m_parent = parent;
ao_app = p_ao_app;
}
-AOBlipPlayer::~AOBlipPlayer()
-{
- m_sfxplayer->stop();
- m_sfxplayer->deleteLater();
-}
-
void AOBlipPlayer::set_blips(QString p_sfx)
{
- m_sfxplayer->stop();
- QString f_path = ao_app->get_sounds_path(p_sfx);
- m_sfxplayer->setSource(QUrl::fromLocalFile(f_path));
+ QString f_path = ao_app->get_sounds_path() + p_sfx.toLower();
+
+ for (int n_stream = 0 ; n_stream < 5 ; ++n_stream)
+ {
+ BASS_StreamFree(m_stream_list[n_stream]);
+
+ m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE);
+ }
+
set_volume(m_volume);
}
void AOBlipPlayer::blip_tick()
{
- m_sfxplayer->play();
+ int f_cycle = m_cycle++;
+
+ if (m_cycle == 5)
+ m_cycle = 0;
+
+ HSTREAM f_stream = m_stream_list[f_cycle];
+
+ if (ao_app->get_audio_output_device() != "Default")
+ BASS_ChannelSetDevice(f_stream, BASS_GetDevice());
+ BASS_ChannelPlay(f_stream, false);
}
void AOBlipPlayer::set_volume(int p_value)
{
m_volume = p_value;
- m_sfxplayer->setVolume(p_value / 100.0);
+
+ float volume = p_value / 100.0f;
+
+ for (int n_stream = 0 ; n_stream < 5 ; ++n_stream)
+ {
+ BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume);
+ }
}
diff --git a/aoblipplayer.h b/aoblipplayer.h
index c8a8cb6d..aebba77d 100644
--- a/aoblipplayer.h
+++ b/aoblipplayer.h
@@ -1,18 +1,17 @@
#ifndef AOBLIPPLAYER_H
#define AOBLIPPLAYER_H
+#include "bass.h"
#include "aoapplication.h"
#include <QWidget>
#include <string.h>
#include <QDebug>
-#include <QSoundEffect>
class AOBlipPlayer
{
public:
AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app);
- ~AOBlipPlayer();
void set_blips(QString p_sfx);
void blip_tick();
@@ -23,9 +22,9 @@ public:
private:
QWidget *m_parent;
AOApplication *ao_app;
- QSoundEffect *m_sfxplayer;
int m_volume;
+ HSTREAM m_stream_list[5];
};
#endif // AOBLIPPLAYER_H
diff --git a/aocaseannouncerdialog.cpp b/aocaseannouncerdialog.cpp
new file mode 100644
index 00000000..a925034d
--- /dev/null
+++ b/aocaseannouncerdialog.cpp
@@ -0,0 +1,82 @@
+#include "aocaseannouncerdialog.h"
+
+AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, AOApplication *p_ao_app, Courtroom *p_court)
+ : QDialog(parent)
+{
+ ao_app = p_ao_app;
+ court = p_court;
+
+ setWindowTitle(tr("Case Announcer"));
+ resize(405, 235);
+
+ ui_announcer_buttons = new QDialogButtonBox(this);
+
+ QSizePolicy sizepolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ sizepolicy.setHorizontalStretch(0);
+ sizepolicy.setVerticalStretch(0);
+ sizepolicy.setHeightForWidth(ui_announcer_buttons->sizePolicy().hasHeightForWidth());
+ ui_announcer_buttons->setSizePolicy(sizepolicy);
+ ui_announcer_buttons->setOrientation(Qt::Horizontal);
+ ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+
+ QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, SLOT(on_ok_pressed()));
+ QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, SLOT(cancel_pressed()));
+
+ setUpdatesEnabled(false);
+
+ ui_vbox_layout = new QVBoxLayout(this);
+
+ ui_form_layout = new QFormLayout(this);
+ ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter);
+ ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
+ ui_form_layout->setContentsMargins(6, 6, 6, 6);
+
+ ui_vbox_layout->addItem(ui_form_layout);
+ ui_vbox_layout->addWidget(ui_announcer_buttons);
+
+ ui_case_title_label = new QLabel(this);
+ ui_case_title_label->setText(tr("Case title:"));
+
+ ui_form_layout->setWidget(0, QFormLayout::LabelRole, ui_case_title_label);
+
+ ui_case_title_textbox = new QLineEdit(this);
+ ui_case_title_textbox->setMaxLength(50);
+
+ ui_form_layout->setWidget(0, QFormLayout::FieldRole, ui_case_title_textbox);
+
+ ui_defense_needed = new QCheckBox(this);
+ ui_defense_needed->setText(tr("Defense needed"));
+ ui_prosecutor_needed = new QCheckBox(this);
+ ui_prosecutor_needed->setText(tr("Prosecution needed"));
+ ui_judge_needed = new QCheckBox(this);
+ ui_judge_needed->setText(tr("Judge needed"));
+ ui_juror_needed = new QCheckBox(this);
+ ui_juror_needed->setText(tr("Jurors needed"));
+ ui_steno_needed = new QCheckBox(this);
+ ui_steno_needed->setText(tr("Stenographer needed"));
+
+ ui_form_layout->setWidget(1, QFormLayout::FieldRole, ui_defense_needed);
+ ui_form_layout->setWidget(2, QFormLayout::FieldRole, ui_prosecutor_needed);
+ ui_form_layout->setWidget(3, QFormLayout::FieldRole, ui_judge_needed);
+ ui_form_layout->setWidget(4, QFormLayout::FieldRole, ui_juror_needed);
+ ui_form_layout->setWidget(5, QFormLayout::FieldRole, ui_steno_needed);
+
+ setUpdatesEnabled(true);
+}
+
+void AOCaseAnnouncerDialog::ok_pressed()
+{
+ court->announce_case(ui_case_title_textbox->text(),
+ ui_defense_needed->isChecked(),
+ ui_prosecutor_needed->isChecked(),
+ ui_judge_needed->isChecked(),
+ ui_juror_needed->isChecked(),
+ ui_steno_needed->isChecked());
+
+ done(0);
+}
+
+void AOCaseAnnouncerDialog::cancel_pressed()
+{
+ done(0);
+}
diff --git a/aocaseannouncerdialog.h b/aocaseannouncerdialog.h
new file mode 100644
index 00000000..a238c3f2
--- /dev/null
+++ b/aocaseannouncerdialog.h
@@ -0,0 +1,45 @@
+#ifndef AOCASEANNOUNCERDIALOG_H
+#define AOCASEANNOUNCERDIALOG_H
+
+#include "aoapplication.h"
+#include "courtroom.h"
+
+#include <QtWidgets/QDialog>
+#include <QDialogButtonBox>
+#include <QtWidgets/QVBoxLayout>
+#include <QtWidgets/QFormLayout>
+#include <QtWidgets/QCheckBox>
+#include <QtWidgets/QLabel>
+#include <QtWidgets/QLineEdit>
+
+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 *ui_announcer_buttons;
+
+ QVBoxLayout *ui_vbox_layout;
+ QFormLayout *ui_form_layout;
+
+ QLabel *ui_case_title_label;
+ QLineEdit *ui_case_title_textbox;
+
+ QCheckBox *ui_defense_needed;
+ QCheckBox *ui_prosecutor_needed;
+ QCheckBox *ui_judge_needed;
+ QCheckBox *ui_juror_needed;
+ QCheckBox *ui_steno_needed;
+
+public slots:
+ void ok_pressed();
+ void cancel_pressed();
+};
+
+#endif // AOCASEANNOUNCERDIALOG_H
diff --git a/aocharbutton.cpp b/aocharbutton.cpp
index f7e77024..23fd0c68 100644
--- a/aocharbutton.cpp
+++ b/aocharbutton.cpp
@@ -2,12 +2,14 @@
#include "file_functions.h"
-AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos) : QPushButton(parent)
+AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken) : QPushButton(parent)
{
m_parent = parent;
ao_app = p_ao_app;
+ taken = is_taken;
+
this->resize(60, 60);
this->move(x_pos, y_pos);
@@ -40,7 +42,11 @@ void AOCharButton::reset()
void AOCharButton::set_taken()
{
- ui_taken->show();
+ if (taken)
+ {
+ ui_taken->move(0,0);
+ ui_taken->show();
+ }
}
void AOCharButton::set_passworded()
@@ -65,6 +71,7 @@ void AOCharButton::set_image(QString p_character)
void AOCharButton::enterEvent(QEvent * e)
{
+ ui_selector->move(this->x() - 1, this->y() - 1);
ui_selector->raise();
ui_selector->show();
diff --git a/aocharbutton.h b/aocharbutton.h
index 6b80460c..6e5e50e1 100644
--- a/aocharbutton.h
+++ b/aocharbutton.h
@@ -14,10 +14,11 @@ class AOCharButton : public QPushButton
Q_OBJECT
public:
- AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos);
+ AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken);
AOApplication *ao_app;
+ void refresh();
void reset();
void set_taken();
void set_passworded();
@@ -25,6 +26,8 @@ public:
void set_image(QString p_character);
private:
+ bool taken;
+
QWidget *m_parent;
AOImage *ui_taken;
diff --git a/aocharmovie.cpp b/aocharmovie.cpp
index c3490ce6..57487233 100644
--- a/aocharmovie.cpp
+++ b/aocharmovie.cpp
@@ -21,11 +21,14 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix)
{
QString original_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".gif");
QString alt_path = ao_app->get_character_path(p_char, p_emote + ".png");
+ QString apng_path = ao_app->get_character_path(p_char, emote_prefix + p_emote + ".apng");
QString placeholder_path = ao_app->get_theme_path("placeholder.gif");
QString placeholder_default_path = ao_app->get_default_theme_path("placeholder.gif");
QString gif_path;
- if (file_exists(original_path))
+ if (file_exists(apng_path))
+ gif_path = apng_path;
+ else if (file_exists(original_path))
gif_path = original_path;
else if (file_exists(alt_path))
gif_path = alt_path;
@@ -152,14 +155,31 @@ void AOCharMovie::combo_resize(int w, int h)
m_movie->setScaledSize(f_size);
}
+void AOCharMovie::move(int ax, int ay)
+{
+ x = ax;
+ y = ay;
+ QLabel::move(x, y);
+}
+
void AOCharMovie::frame_change(int n_frame)
{
+
if (movie_frames.size() > n_frame)
{
QPixmap f_pixmap = QPixmap::fromImage(movie_frames.at(n_frame));
+ auto aspect_ratio = Qt::KeepAspectRatio;
- this->setPixmap(f_pixmap.scaled(this->width(), this->height()));
- }
+ if (f_pixmap.size().width() > f_pixmap.size().height())
+ aspect_ratio = Qt::KeepAspectRatioByExpanding;
+
+ if (f_pixmap.size().width() > this->size().width() || f_pixmap.size().height() > this->size().height())
+ this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::SmoothTransformation));
+ else
+ this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation));
+
+ QLabel::move(x + (this->width() - this->pixmap()->width())/2, y);
+ }
if (m_movie->frameCount() - 1 == n_frame && play_once)
{
diff --git a/aocharmovie.h b/aocharmovie.h
index b26bada5..7ef7da3f 100644
--- a/aocharmovie.h
+++ b/aocharmovie.h
@@ -25,6 +25,8 @@ public:
void stop();
+ void move(int ax, int ay);
+
void combo_resize(int w, int h);
private:
@@ -36,6 +38,10 @@ private:
const int time_mod = 62;
+ // These are the X and Y values before they are fixed based on the sprite's width.
+ int x = 0;
+ int y = 0;
+
bool m_flipped = false;
bool play_once = true;
diff --git a/aomovie.cpp b/aomovie.cpp
index 53181de3..6839eab1 100644
--- a/aomovie.cpp
+++ b/aomovie.cpp
@@ -28,17 +28,20 @@ void AOMovie::play(QString p_gif, QString p_char, QString p_custom_theme)
QString custom_path;
if (p_gif == "custom")
- custom_path = ao_app->get_character_path(p_char, p_gif + ".gif");
+ custom_path = ao_app->get_image_suffix(get_character_path(p_char, p_gif));
else
- custom_path = ao_app->get_character_path(p_char, p_gif + "_bubble.gif");
+ custom_path = ao_app->get_image_suffix(get_character_path(p_char, p_gif + "_bubble"));
+ QString misc_path = ao_app->get_base_path() + "misc/" + p_custom_theme + "/" + p_gif + "_bubble.gif";
QString custom_theme_path = ao_app->get_base_path() + "themes/" + p_custom_theme + "/" + p_gif + ".gif";
QString theme_path = ao_app->get_theme_path(p_gif + ".gif");
QString default_theme_path = ao_app->get_default_theme_path(p_gif + ".gif");
QString placeholder_path = ao_app->get_theme_path("placeholder.gif");
QString default_placeholder_path = ao_app->get_default_theme_path("placeholder.gif");
- if (file_exists(custom_path))
+ if (file_exists(misc_path))
+ gif_path = misc_path;
+ else if (file_exists(custom_path))
gif_path = custom_path;
else if (file_exists(custom_theme_path))
gif_path = custom_theme_path;
diff --git a/aomusicplayer.cpp b/aomusicplayer.cpp
index ca37ac71..bd363933 100644
--- a/aomusicplayer.cpp
+++ b/aomusicplayer.cpp
@@ -4,24 +4,31 @@ AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app)
{
m_parent = parent;
ao_app = p_ao_app;
- m_player = new QMediaPlayer;
}
AOMusicPlayer::~AOMusicPlayer()
{
- m_player->stop();
- m_player->deleteLater();
+ BASS_ChannelStop(m_stream);
}
void AOMusicPlayer::play(QString p_song)
{
- m_player->setMedia(QUrl::fromLocalFile(ao_app->get_music_path(p_song)));
+ BASS_ChannelStop(m_stream);
+
+ QString f_path = ao_app->get_music_path(p_song);
+
+ m_stream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE);
+
this->set_volume(m_volume);
- m_player->play();
+
+ if (ao_app->get_audio_output_device() != "Default")
+ BASS_ChannelSetDevice(m_stream, BASS_GetDevice());
+ BASS_ChannelPlay(m_stream, false);
}
void AOMusicPlayer::set_volume(int p_value)
{
m_volume = p_value;
- m_player->setVolume(p_value);
+ float volume = m_volume / 100.0f;
+ BASS_ChannelSetAttribute(m_stream, BASS_ATTRIB_VOL, volume);
}
diff --git a/aomusicplayer.h b/aomusicplayer.h
index f7b2d0d3..560a7f90 100644
--- a/aomusicplayer.h
+++ b/aomusicplayer.h
@@ -1,12 +1,12 @@
#ifndef AOMUSICPLAYER_H
#define AOMUSICPLAYER_H
+#include "bass.h"
#include "aoapplication.h"
#include <QWidget>
#include <string.h>
#include <QDebug>
-#include <QMediaPlayer>
class AOMusicPlayer
{
@@ -21,8 +21,8 @@ private:
QWidget *m_parent;
AOApplication *ao_app;
- QMediaPlayer *m_player;
int m_volume = 0;
+ HSTREAM m_stream;
};
#endif // AOMUSICPLAYER_H
diff --git a/aooptionsdialog.cpp b/aooptionsdialog.cpp
new file mode 100644
index 00000000..7182e7a0
--- /dev/null
+++ b/aooptionsdialog.cpp
@@ -0,0 +1,517 @@
+#include "aooptionsdialog.h"
+#include "aoapplication.h"
+#include "bass.h"
+
+AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDialog(parent)
+{
+ ao_app = p_ao_app;
+
+ // Setting up the basics.
+ // setAttribute(Qt::WA_DeleteOnClose);
+ setWindowTitle(tr("Settings"));
+ resize(398, 320);
+
+ ui_settings_buttons = new QDialogButtonBox(this);
+
+ QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ sizePolicy1.setHorizontalStretch(0);
+ sizePolicy1.setVerticalStretch(0);
+ sizePolicy1.setHeightForWidth(ui_settings_buttons->sizePolicy().hasHeightForWidth());
+ ui_settings_buttons->setSizePolicy(sizePolicy1);
+ ui_settings_buttons->setOrientation(Qt::Horizontal);
+ ui_settings_buttons->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Save);
+
+ QObject::connect(ui_settings_buttons, SIGNAL(accepted()), this, SLOT(save_pressed()));
+ QObject::connect(ui_settings_buttons, SIGNAL(rejected()), this, SLOT(discard_pressed()));
+
+ // We'll stop updates so that the window won't flicker while it's being made.
+ setUpdatesEnabled(false);
+
+ // First of all, we want a tabbed dialog, so let's add some layout.
+ ui_vertical_layout = new QVBoxLayout(this);
+ ui_settings_tabs = new QTabWidget(this);
+
+ ui_vertical_layout->addWidget(ui_settings_tabs);
+ ui_vertical_layout->addWidget(ui_settings_buttons);
+
+ // Let's add the tabs one by one.
+ // First, we'll start with 'Gameplay'.
+ ui_gameplay_tab = new QWidget();
+ ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay"));
+
+ ui_form_layout_widget = new QWidget(ui_gameplay_tab);
+ ui_form_layout_widget->setGeometry(QRect(10, 10, 361, 211));
+
+ ui_gameplay_form = new QFormLayout(ui_form_layout_widget);
+ ui_gameplay_form->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
+ ui_gameplay_form->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop);
+ ui_gameplay_form->setContentsMargins(0, 0, 0, 0);
+
+ ui_theme_label = new QLabel(ui_form_layout_widget);
+ ui_theme_label->setText(tr("Theme:"));
+ ui_theme_label->setToolTip(tr("Sets the theme used in-game. If the new theme changes "
+ "the lobby's look as well, you'll need to reload the "
+ "lobby for the changes to take effect, such as by joining "
+ "a server and leaving it."));
+ ui_gameplay_form->setWidget(0, QFormLayout::LabelRole, ui_theme_label);
+
+ ui_theme_combobox = new QComboBox(ui_form_layout_widget);
+
+ // Fill the combobox with the names of the themes.
+ QDirIterator it(p_ao_app->get_base_path() + "themes", QDir::Dirs, QDirIterator::NoIteratorFlags);
+ while (it.hasNext())
+ {
+ QString actualname = QDir(it.next()).dirName();
+ if (actualname != "." && actualname != "..")
+ ui_theme_combobox->addItem(actualname);
+ if (actualname == p_ao_app->read_theme())
+ ui_theme_combobox->setCurrentIndex(ui_theme_combobox->count()-1);
+ }
+
+ ui_gameplay_form->setWidget(0, QFormLayout::FieldRole, ui_theme_combobox);
+
+ ui_theme_log_divider = new QFrame(ui_form_layout_widget);
+ ui_theme_log_divider->setMidLineWidth(0);
+ ui_theme_log_divider->setFrameShape(QFrame::HLine);
+ ui_theme_log_divider->setFrameShadow(QFrame::Sunken);
+
+ ui_gameplay_form->setWidget(1, QFormLayout::FieldRole, ui_theme_log_divider);
+
+ ui_downwards_lbl = new QLabel(ui_form_layout_widget);
+ ui_downwards_lbl->setText(tr("Log goes downwards:"));
+ ui_downwards_lbl->setToolTip(tr("If ticked, new messages will appear at "
+ "the bottom (like the OOC chatlog). The traditional "
+ "(AO1) behaviour is equivalent to this being unticked."));
+
+ ui_gameplay_form->setWidget(2, QFormLayout::LabelRole, ui_downwards_lbl);
+
+ ui_downwards_cb = new QCheckBox(ui_form_layout_widget);
+ ui_downwards_cb->setChecked(p_ao_app->get_log_goes_downwards());
+
+ ui_gameplay_form->setWidget(2, QFormLayout::FieldRole, ui_downwards_cb);
+
+ ui_length_lbl = new QLabel(ui_form_layout_widget);
+ ui_length_lbl->setText(tr("Log length:"));
+ ui_length_lbl->setToolTip(tr("The amount of messages the IC chatlog will keep before "
+ "deleting older messages. A value of 0 or below counts as 'infinite'."));
+
+ ui_gameplay_form->setWidget(3, QFormLayout::LabelRole, ui_length_lbl);
+
+ ui_length_spinbox = new QSpinBox(ui_form_layout_widget);
+ ui_length_spinbox->setMaximum(10000);
+ ui_length_spinbox->setValue(p_ao_app->get_max_log_size());
+
+ ui_gameplay_form->setWidget(3, QFormLayout::FieldRole, ui_length_spinbox);
+
+ ui_log_names_divider = new QFrame(ui_form_layout_widget);
+ ui_log_names_divider->setFrameShape(QFrame::HLine);
+ ui_log_names_divider->setFrameShadow(QFrame::Sunken);
+
+ ui_gameplay_form->setWidget(4, QFormLayout::FieldRole, ui_log_names_divider);
+
+ ui_username_lbl = new QLabel(ui_form_layout_widget);
+ ui_username_lbl->setText(tr("Default username:"));
+ ui_username_lbl->setToolTip(tr("Your OOC name will be automatically set to this value "
+ "when you join a server."));
+
+ ui_gameplay_form->setWidget(5, QFormLayout::LabelRole, ui_username_lbl);
+
+ ui_username_textbox = new QLineEdit(ui_form_layout_widget);
+ ui_username_textbox->setMaxLength(30);
+ ui_username_textbox->setText(p_ao_app->get_default_username());
+
+ ui_gameplay_form->setWidget(5, QFormLayout::FieldRole, ui_username_textbox);
+
+ ui_showname_lbl = new QLabel(ui_form_layout_widget);
+ ui_showname_lbl->setText(tr("Custom shownames:"));
+ ui_showname_lbl->setToolTip(tr("Gives the default value for the in-game 'Custom shownames' "
+ "tickbox, which in turn determines whether the client should "
+ "display custom in-character names."));
+
+ ui_gameplay_form->setWidget(6, QFormLayout::LabelRole, ui_showname_lbl);
+
+ ui_showname_cb = new QCheckBox(ui_form_layout_widget);
+ ui_showname_cb->setChecked(p_ao_app->get_showname_enabled_by_default());
+
+ ui_gameplay_form->setWidget(6, QFormLayout::FieldRole, ui_showname_cb);
+
+ ui_net_divider = new QFrame(ui_form_layout_widget);
+ ui_net_divider->setFrameShape(QFrame::HLine);
+ ui_net_divider->setFrameShadow(QFrame::Sunken);
+
+ ui_gameplay_form->setWidget(7, QFormLayout::FieldRole, ui_net_divider);
+
+ ui_ms_lbl = new QLabel(ui_form_layout_widget);
+ ui_ms_lbl->setText(tr("Backup MS:"));
+ ui_ms_lbl->setToolTip(tr("If the built-in server lookups fail, the game will try the "
+ "address given here and use it as a backup master server address."));
+
+ ui_gameplay_form->setWidget(8, QFormLayout::LabelRole, ui_ms_lbl);
+
+ QSettings* configini = ao_app->configini;
+ ui_ms_textbox = new QLineEdit(ui_form_layout_widget);
+ ui_ms_textbox->setText(configini->value("master", "").value<QString>());
+
+ ui_gameplay_form->setWidget(8, QFormLayout::FieldRole, ui_ms_textbox);
+
+ ui_discord_lbl = new QLabel(ui_form_layout_widget);
+ ui_discord_lbl->setText(tr("Discord:"));
+ ui_discord_lbl->setToolTip(tr("Allows others on Discord to see what server you are in, "
+ "what character are you playing, and how long you have "
+ "been playing for."));
+
+ ui_gameplay_form->setWidget(9, QFormLayout::LabelRole, ui_discord_lbl);
+
+ ui_discord_cb = new QCheckBox(ui_form_layout_widget);
+ ui_discord_cb->setChecked(ao_app->is_discord_enabled());
+
+ ui_gameplay_form->setWidget(9, QFormLayout::FieldRole, ui_discord_cb);
+
+ // Here we start the callwords tab.
+ ui_callwords_tab = new QWidget();
+ ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords"));
+
+ ui_callwords_widget = new QWidget(ui_callwords_tab);
+ ui_callwords_widget->setGeometry(QRect(10, 10, 361, 211));
+
+ ui_callwords_layout = new QVBoxLayout(ui_callwords_widget);
+ ui_callwords_layout->setContentsMargins(0,0,0,0);
+
+ ui_callwords_textbox = new QPlainTextEdit(ui_callwords_widget);
+ QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(ui_callwords_textbox->sizePolicy().hasHeightForWidth());
+ ui_callwords_textbox->setSizePolicy(sizePolicy);
+
+ // Let's fill the callwords text edit with the already present callwords.
+ ui_callwords_textbox->document()->clear();
+ foreach (QString callword, p_ao_app->get_call_words()) {
+ ui_callwords_textbox->appendPlainText(callword);
+ }
+
+ ui_callwords_layout->addWidget(ui_callwords_textbox);
+
+ ui_callwords_explain_lbl = new QLabel(ui_callwords_widget);
+ ui_callwords_explain_lbl->setWordWrap(true);
+ ui_callwords_explain_lbl->setText(tr("<html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html>"));
+
+ ui_callwords_layout->addWidget(ui_callwords_explain_lbl);
+
+ // The audio tab.
+ ui_audio_tab = new QWidget();
+ ui_settings_tabs->addTab(ui_audio_tab, tr("Audio"));
+
+ ui_audio_widget = new QWidget(ui_audio_tab);
+ ui_audio_widget->setGeometry(QRect(10, 10, 361, 211));
+
+ ui_audio_layout = new QFormLayout(ui_audio_widget);
+ ui_audio_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
+ ui_audio_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop);
+ ui_audio_layout->setContentsMargins(0, 0, 0, 0);
+
+ ui_audio_device_lbl = new QLabel(ui_audio_widget);
+ ui_audio_device_lbl->setText(tr("Audio device:"));
+ ui_audio_device_lbl->setToolTip(tr("Sets the audio device for all sounds."));
+
+ ui_audio_layout->setWidget(0, QFormLayout::LabelRole, ui_audio_device_lbl);
+
+ ui_audio_device_combobox = new QComboBox(ui_audio_widget);
+
+ // Let's fill out the combobox with the available audio devices.
+ int a = 0;
+ BASS_DEVICEINFO info;
+
+ if (needs_default_audiodev())
+ {
+ ui_audio_device_combobox->addItem("Default");
+ }
+
+ for (a = 0; BASS_GetDeviceInfo(a, &info); a++)
+ {
+ ui_audio_device_combobox->addItem(info.name);
+ if (p_ao_app->get_audio_output_device() == info.name)
+ ui_audio_device_combobox->setCurrentIndex(ui_audio_device_combobox->count()-1);
+ }
+
+ ui_audio_layout->setWidget(0, QFormLayout::FieldRole, ui_audio_device_combobox);
+
+ ui_audio_volume_divider = new QFrame(ui_audio_widget);
+ ui_audio_volume_divider->setFrameShape(QFrame::HLine);
+ ui_audio_volume_divider->setFrameShadow(QFrame::Sunken);
+
+ ui_audio_layout->setWidget(1, QFormLayout::FieldRole, ui_audio_volume_divider);
+
+ ui_music_volume_lbl = new QLabel(ui_audio_widget);
+ ui_music_volume_lbl->setText(tr("Music:"));
+ ui_music_volume_lbl->setToolTip(tr("Sets the music's default volume."));
+
+ ui_audio_layout->setWidget(2, QFormLayout::LabelRole, ui_music_volume_lbl);
+
+ ui_music_volume_spinbox = new QSpinBox(ui_audio_widget);
+ ui_music_volume_spinbox->setValue(p_ao_app->get_default_music());
+ ui_music_volume_spinbox->setMaximum(100);
+ ui_music_volume_spinbox->setSuffix("%");
+
+ ui_audio_layout->setWidget(2, QFormLayout::FieldRole, ui_music_volume_spinbox);
+
+ ui_sfx_volume_lbl = new QLabel(ui_audio_widget);
+ ui_sfx_volume_lbl->setText(tr("SFX:"));
+ ui_sfx_volume_lbl->setToolTip(tr("Sets the SFX's default volume. "
+ "Interjections and actual sound effects count as 'SFX'."));
+
+ ui_audio_layout->setWidget(3, QFormLayout::LabelRole, ui_sfx_volume_lbl);
+
+ ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget);
+ ui_sfx_volume_spinbox->setValue(p_ao_app->get_default_sfx());
+ ui_sfx_volume_spinbox->setMaximum(100);
+ ui_sfx_volume_spinbox->setSuffix("%");
+
+ ui_audio_layout->setWidget(3, QFormLayout::FieldRole, ui_sfx_volume_spinbox);
+
+ ui_blips_volume_lbl = new QLabel(ui_audio_widget);
+ ui_blips_volume_lbl->setText(tr("Blips:"));
+ ui_blips_volume_lbl->setToolTip(tr("Sets the volume of the blips, the talking sound effects."));
+
+ ui_audio_layout->setWidget(4, QFormLayout::LabelRole, ui_blips_volume_lbl);
+
+ ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget);
+ ui_blips_volume_spinbox->setValue(p_ao_app->get_default_blip());
+ ui_blips_volume_spinbox->setMaximum(100);
+ ui_blips_volume_spinbox->setSuffix("%");
+
+ ui_audio_layout->setWidget(4, QFormLayout::FieldRole, ui_blips_volume_spinbox);
+
+ ui_volume_blip_divider = new QFrame(ui_audio_widget);
+ ui_volume_blip_divider->setFrameShape(QFrame::HLine);
+ ui_volume_blip_divider->setFrameShadow(QFrame::Sunken);
+
+ ui_audio_layout->setWidget(5, QFormLayout::FieldRole, ui_volume_blip_divider);
+
+ ui_bliprate_lbl = new QLabel(ui_audio_widget);
+ ui_bliprate_lbl->setText(tr("Blip rate:"));
+ ui_bliprate_lbl->setToolTip(tr("Sets the delay between playing the blip sounds."));
+
+ ui_audio_layout->setWidget(6, QFormLayout::LabelRole, ui_bliprate_lbl);
+
+ ui_bliprate_spinbox = new QSpinBox(ui_audio_widget);
+ ui_bliprate_spinbox->setValue(p_ao_app->read_blip_rate());
+ ui_bliprate_spinbox->setMinimum(1);
+
+ ui_audio_layout->setWidget(6, QFormLayout::FieldRole, ui_bliprate_spinbox);
+
+ ui_blank_blips_lbl = new QLabel(ui_audio_widget);
+ ui_blank_blips_lbl->setText(tr("Blank blips:"));
+ ui_blank_blips_lbl->setToolTip(tr("If true, the game will play a blip sound even "
+ "when a space is 'being said'."));
+
+ ui_audio_layout->setWidget(7, QFormLayout::LabelRole, ui_blank_blips_lbl);
+
+ ui_blank_blips_cb = new QCheckBox(ui_audio_widget);
+ ui_blank_blips_cb->setChecked(p_ao_app->get_blank_blip());
+
+ ui_audio_layout->setWidget(7, QFormLayout::FieldRole, ui_blank_blips_cb);
+
+ // The casing tab!
+ ui_casing_tab = new QWidget();
+ ui_settings_tabs->addTab(ui_casing_tab, tr("Casing"));
+
+ ui_casing_widget = new QWidget(ui_casing_tab);
+ ui_casing_widget->setGeometry(QRect(10,10, 361, 211));
+
+ ui_casing_layout = new QFormLayout(ui_casing_widget);
+ ui_casing_layout->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
+ ui_casing_layout->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop);
+ ui_casing_layout->setContentsMargins(0, 0, 0, 0);
+
+ // -- SERVER SUPPORTS CASING
+
+ ui_casing_supported_lbl = new QLabel(ui_casing_widget);
+ if (ao_app->casing_alerts_enabled)
+ ui_casing_supported_lbl->setText(tr("This server supports case alerts."));
+ else
+ ui_casing_supported_lbl->setText(tr("This server does not support case alerts."));
+ ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory."));
+
+ ui_casing_layout->setWidget(0, QFormLayout::FieldRole, ui_casing_supported_lbl);
+
+ // -- CASE ANNOUNCEMENTS
+
+ ui_casing_enabled_lbl = new QLabel(ui_casing_widget);
+ ui_casing_enabled_lbl->setText(tr("Casing:"));
+ ui_casing_enabled_lbl->setToolTip(tr("If checked, you will get alerts about case "
+ "announcements."));
+
+ ui_casing_layout->setWidget(1, QFormLayout::LabelRole, ui_casing_enabled_lbl);
+
+ ui_casing_enabled_cb = new QCheckBox(ui_casing_widget);
+ ui_casing_enabled_cb->setChecked(ao_app->get_casing_enabled());
+
+ ui_casing_layout->setWidget(1, QFormLayout::FieldRole, ui_casing_enabled_cb);
+
+ // -- DEFENSE ANNOUNCEMENTS
+
+ ui_casing_def_lbl = new QLabel(ui_casing_widget);
+ ui_casing_def_lbl->setText(tr("Defense:"));
+ ui_casing_def_lbl->setToolTip(tr("If checked, you will get alerts about case "
+ "announcements if a defense spot is open."));
+
+ ui_casing_layout->setWidget(2, QFormLayout::LabelRole, ui_casing_def_lbl);
+
+ ui_casing_def_cb = new QCheckBox(ui_casing_widget);
+ ui_casing_def_cb->setChecked(ao_app->get_casing_defence_enabled());
+
+ ui_casing_layout->setWidget(2, QFormLayout::FieldRole, ui_casing_def_cb);
+
+ // -- PROSECUTOR ANNOUNCEMENTS
+
+ ui_casing_pro_lbl = new QLabel(ui_casing_widget);
+ ui_casing_pro_lbl->setText(tr("Prosecution:"));
+ ui_casing_pro_lbl->setToolTip(tr("If checked, you will get alerts about case "
+ "announcements if a prosecutor spot is open."));
+
+ ui_casing_layout->setWidget(3, QFormLayout::LabelRole, ui_casing_pro_lbl);
+
+ ui_casing_pro_cb = new QCheckBox(ui_casing_widget);
+ ui_casing_pro_cb->setChecked(ao_app->get_casing_prosecution_enabled());
+
+ ui_casing_layout->setWidget(3, QFormLayout::FieldRole, ui_casing_pro_cb);
+
+ // -- JUDGE ANNOUNCEMENTS
+
+ ui_casing_jud_lbl = new QLabel(ui_casing_widget);
+ ui_casing_jud_lbl->setText(tr("Judge:"));
+ ui_casing_jud_lbl->setToolTip(tr("If checked, you will get alerts about case "
+ "announcements if the judge spot is open."));
+
+ ui_casing_layout->setWidget(4, QFormLayout::LabelRole, ui_casing_jud_lbl);
+
+ ui_casing_jud_cb = new QCheckBox(ui_casing_widget);
+ ui_casing_jud_cb->setChecked(ao_app->get_casing_judge_enabled());
+
+ ui_casing_layout->setWidget(4, QFormLayout::FieldRole, ui_casing_jud_cb);
+
+ // -- JUROR ANNOUNCEMENTS
+
+ ui_casing_jur_lbl = new QLabel(ui_casing_widget);
+ ui_casing_jur_lbl->setText(tr("Juror:"));
+ ui_casing_jur_lbl->setToolTip(tr("If checked, you will get alerts about case "
+ "announcements if a juror spot is open."));
+
+ ui_casing_layout->setWidget(5, QFormLayout::LabelRole, ui_casing_jur_lbl);
+
+ ui_casing_jur_cb = new QCheckBox(ui_casing_widget);
+ ui_casing_jur_cb->setChecked(ao_app->get_casing_juror_enabled());
+
+ ui_casing_layout->setWidget(5, QFormLayout::FieldRole, ui_casing_jur_cb);
+
+ // -- STENO ANNOUNCEMENTS
+
+ ui_casing_steno_lbl = new QLabel(ui_casing_widget);
+ ui_casing_steno_lbl->setText(tr("Stenographer:"));
+ ui_casing_steno_lbl->setToolTip(tr("If checked, you will get alerts about case "
+ "announcements if a stenographer spot is open."));
+
+ ui_casing_layout->setWidget(6, QFormLayout::LabelRole, ui_casing_steno_lbl);
+
+ ui_casing_steno_cb = new QCheckBox(ui_casing_widget);
+ ui_casing_steno_cb->setChecked(ao_app->get_casing_steno_enabled());
+
+ ui_casing_layout->setWidget(6, QFormLayout::FieldRole, ui_casing_steno_cb);
+
+ // -- CM ANNOUNCEMENTS
+
+ ui_casing_cm_lbl = new QLabel(ui_casing_widget);
+ ui_casing_cm_lbl->setText(tr("CM:"));
+ ui_casing_cm_lbl->setToolTip(tr("If checked, you will appear amongst the potential "
+ "CMs on the server."));
+
+ ui_casing_layout->setWidget(7, QFormLayout::LabelRole, ui_casing_cm_lbl);
+
+ ui_casing_cm_cb = new QCheckBox(ui_casing_widget);
+ ui_casing_cm_cb->setChecked(ao_app->get_casing_cm_enabled());
+
+ ui_casing_layout->setWidget(7, QFormLayout::FieldRole, ui_casing_cm_cb);
+
+ // -- CM CASES ANNOUNCEMENTS
+
+ ui_casing_cm_cases_lbl = new QLabel(ui_casing_widget);
+ ui_casing_cm_cases_lbl->setText(tr("Hosting cases:"));
+ ui_casing_cm_cases_lbl->setToolTip(tr("If you're a CM, enter what cases you are "
+ "willing to host."));
+
+ ui_casing_layout->setWidget(8, QFormLayout::LabelRole, ui_casing_cm_cases_lbl);
+
+ ui_casing_cm_cases_textbox = new QLineEdit(ui_casing_widget);
+ ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases());
+
+ ui_casing_layout->setWidget(8, QFormLayout::FieldRole, ui_casing_cm_cases_textbox);
+
+ // When we're done, we should continue the updates!
+ setUpdatesEnabled(true);
+}
+
+void AOOptionsDialog::save_pressed()
+{
+ // Save everything into the config.ini.
+ QSettings* configini = ao_app->configini;
+
+ configini->setValue("theme", ui_theme_combobox->currentText());
+ configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked());
+ configini->setValue("log_maximum", ui_length_spinbox->value());
+ configini->setValue("default_username", ui_username_textbox->text());
+ configini->setValue("show_custom_shownames", ui_showname_cb->isChecked());
+ configini->setValue("master", ui_ms_textbox->text());
+ configini->setValue("discord", ui_discord_cb->isChecked());
+
+ QFile* callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini");
+
+ if (!callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
+ {
+ // Nevermind!
+ }
+ else
+ {
+ QTextStream out(callwordsini);
+ out << ui_callwords_textbox->toPlainText();
+ callwordsini->close();
+ }
+
+ configini->setValue("default_audio_device", ui_audio_device_combobox->currentText());
+ configini->setValue("default_music", ui_music_volume_spinbox->value());
+ configini->setValue("default_sfx", ui_sfx_volume_spinbox->value());
+ configini->setValue("default_blip", ui_blips_volume_spinbox->value());
+ configini->setValue("blip_rate", ui_bliprate_spinbox->value());
+ configini->setValue("blank_blip", ui_blank_blips_cb->isChecked());
+
+ configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked());
+ configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked());
+ configini->setValue("casing_prosecution_enabled", ui_casing_pro_cb->isChecked());
+ configini->setValue("casing_judge_enabled", ui_casing_jud_cb->isChecked());
+ configini->setValue("casing_juror_enabled", ui_casing_jur_cb->isChecked());
+ configini->setValue("casing_steno_enabled", ui_casing_steno_cb->isChecked());
+ configini->setValue("casing_cm_enabled", ui_casing_cm_cb->isChecked());
+ configini->setValue("casing_can_host_cases", ui_casing_cm_cases_textbox->text());
+
+ callwordsini->close();
+ done(0);
+}
+
+void AOOptionsDialog::discard_pressed()
+{
+ done(0);
+}
+
+#if (defined (_WIN32) || defined (_WIN64))
+bool AOOptionsDialog::needs_default_audiodev()
+{
+ return true;
+}
+#elif (defined (LINUX) || defined (__linux__))
+bool AOOptionsDialog::needs_default_audiodev()
+{
+ return false;
+}
+#else
+#error This operating system is not supported.
+#endif
diff --git a/aooptionsdialog.h b/aooptionsdialog.h
new file mode 100644
index 00000000..a65e3f59
--- /dev/null
+++ b/aooptionsdialog.h
@@ -0,0 +1,115 @@
+#ifndef AOOPTIONSDIALOG_H
+#define AOOPTIONSDIALOG_H
+
+#include "aoapplication.h"
+#include "bass.h"
+
+#include <QtCore/QVariant>
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QCheckBox>
+#include <QtWidgets/QComboBox>
+#include <QtWidgets/QDialog>
+#include <QtWidgets/QDialogButtonBox>
+#include <QtWidgets/QFormLayout>
+#include <QtWidgets/QFrame>
+#include <QtWidgets/QLabel>
+#include <QtWidgets/QLineEdit>
+#include <QtWidgets/QPlainTextEdit>
+#include <QtWidgets/QSpinBox>
+#include <QtWidgets/QTabWidget>
+#include <QtWidgets/QVBoxLayout>
+#include <QtWidgets/QWidget>
+
+#include <QDirIterator>
+#include <QTextStream>
+
+class AOOptionsDialog: public QDialog
+{
+ Q_OBJECT
+public:
+ explicit AOOptionsDialog(QWidget *parent = nullptr, AOApplication *p_ao_app = nullptr);
+
+private:
+ AOApplication *ao_app;
+
+ QVBoxLayout *ui_vertical_layout;
+ QTabWidget *ui_settings_tabs;
+
+ QWidget *ui_gameplay_tab;
+ QWidget *ui_form_layout_widget;
+ QFormLayout *ui_gameplay_form;
+ QLabel *ui_theme_label;
+ QComboBox *ui_theme_combobox;
+ QFrame *ui_theme_log_divider;
+ QLabel *ui_downwards_lbl;
+ QCheckBox *ui_downwards_cb;
+ QLabel *ui_length_lbl;
+ QSpinBox *ui_length_spinbox;
+ QFrame *ui_log_names_divider;
+ QLineEdit *ui_username_textbox;
+ QLabel *ui_username_lbl;
+ QLabel *ui_showname_lbl;
+ QCheckBox *ui_showname_cb;
+ QFrame *ui_net_divider;
+ QLabel *ui_ms_lbl;
+ QLineEdit *ui_ms_textbox;
+ QLabel *ui_discord_lbl;
+ QCheckBox *ui_discord_cb;
+
+ QWidget *ui_callwords_tab;
+ QWidget *ui_callwords_widget;
+ QVBoxLayout *ui_callwords_layout;
+ QPlainTextEdit *ui_callwords_textbox;
+ QLabel *ui_callwords_explain_lbl;
+ QCheckBox *ui_callwords_char_textbox;
+
+ QWidget *ui_audio_tab;
+ QWidget *ui_audio_widget;
+ QFormLayout *ui_audio_layout;
+ QLabel *ui_audio_device_lbl;
+ QComboBox *ui_audio_device_combobox;
+ QFrame *ui_audio_volume_divider;
+ QSpinBox *ui_music_volume_spinbox;
+ QLabel *ui_music_volume_lbl;
+ QSpinBox *ui_sfx_volume_spinbox;
+ QSpinBox *ui_blips_volume_spinbox;
+ QLabel *ui_sfx_volume_lbl;
+ QLabel *ui_blips_volume_lbl;
+ QFrame *ui_volume_blip_divider;
+ QSpinBox *ui_bliprate_spinbox;
+ QLabel *ui_bliprate_lbl;
+ QCheckBox *ui_blank_blips_cb;
+ QLabel *ui_blank_blips_lbl;
+ QDialogButtonBox *ui_settings_buttons;
+
+ QWidget *ui_casing_tab;
+ QWidget *ui_casing_widget;
+ QFormLayout *ui_casing_layout;
+ QLabel *ui_casing_supported_lbl;
+ QLabel *ui_casing_enabled_lbl;
+ QCheckBox *ui_casing_enabled_cb;
+ QLabel *ui_casing_def_lbl;
+ QCheckBox *ui_casing_def_cb;
+ QLabel *ui_casing_pro_lbl;
+ QCheckBox *ui_casing_pro_cb;
+ QLabel *ui_casing_jud_lbl;
+ QCheckBox *ui_casing_jud_cb;
+ QLabel *ui_casing_jur_lbl;
+ QCheckBox *ui_casing_jur_cb;
+ QLabel *ui_casing_steno_lbl;
+ QCheckBox *ui_casing_steno_cb;
+ QLabel *ui_casing_cm_lbl;
+ QCheckBox *ui_casing_cm_cb;
+ QLabel *ui_casing_cm_cases_lbl;
+ QLineEdit *ui_casing_cm_cases_textbox;
+
+ bool needs_default_audiodev();
+
+signals:
+
+public slots:
+ void save_pressed();
+ void discard_pressed();
+};
+
+#endif // AOOPTIONSDIALOG_H
diff --git a/aoscene.cpp b/aoscene.cpp
index 7056bfc0..344522b6 100644
--- a/aoscene.cpp
+++ b/aoscene.cpp
@@ -6,6 +6,7 @@ AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent)
{
m_parent = parent;
ao_app = p_ao_app;
+ m_movie = new QMovie(this);
}
void AOScene::set_image(QString p_image)
@@ -15,18 +16,31 @@ void AOScene::set_image(QString p_image)
QString default_path = ao_app->get_default_background_path(p_image + ".png");
QPixmap background(background_path);
- QPixmap animated_background(animated_background_path);
QPixmap default_bg(default_path);
int w = this->width();
int h = this->height();
- if (file_exists(animated_background_path))
- this->setPixmap(animated_background.scaled(w, h));
+ this->clear();
+ this->setMovie(nullptr);
+
+ m_movie->stop();
+ m_movie->setFileName(animated_background_path);
+ m_movie->setScaledSize(QSize(w, h));
+
+ if (m_movie->isValid())
+ {
+ this->setMovie(m_movie);
+ m_movie->start();
+ }
else if (file_exists(background_path))
+ {
this->setPixmap(background.scaled(w, h));
+ }
else
+ {
this->setPixmap(default_bg.scaled(w, h));
+ }
}
void AOScene::set_legacy_desk(QString p_image)
diff --git a/aoscene.h b/aoscene.h
index 08c286e1..b58c0fd0 100644
--- a/aoscene.h
+++ b/aoscene.h
@@ -3,6 +3,7 @@
#include <QLabel>
#include <QDebug>
+#include <QMovie>
class Courtroom;
class AOApplication;
@@ -18,6 +19,7 @@ public:
private:
QWidget *m_parent;
+ QMovie *m_movie;
AOApplication *ao_app;
};
diff --git a/aosfxplayer.cpp b/aosfxplayer.cpp
index 575e91f9..d5b5a9e0 100644
--- a/aosfxplayer.cpp
+++ b/aosfxplayer.cpp
@@ -1,41 +1,47 @@
#include "aosfxplayer.h"
+#include "file_functions.h"
AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app)
{
- m_sfxplayer = new QSoundEffect;
m_parent = parent;
ao_app = p_ao_app;
}
-AOSfxPlayer::~AOSfxPlayer()
+void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout)
{
- m_sfxplayer->stop();
- m_sfxplayer->deleteLater();
-}
+ QString misc_path = "";
+ QString char_path = "";
+ QString sound_path = ao_app->get_sounds_path(p_sfx);
-void AOSfxPlayer::play(QString p_sfx, QString p_char)
-{
- m_sfxplayer->stop();
- p_sfx = p_sfx;
- QString f_path;
+ if (shout != "")
+ misc_path = ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx;
if (p_char != "")
- f_path = ao_app->get_character_path(p_char, p_sfx);
+ char_path = ao_app->get_character_path(p_char, p_sfx);
+
+ QString f_path;
+
+ if (file_exists(char_path))
+ f_path = char_path;
+ else if (file_exists(misc_path))
+ f_path = misc_path;
else
- f_path = ao_app->get_sounds_path(p_sfx);
+ f_path = sound_path;
- m_sfxplayer->setSource(QUrl::fromLocalFile(f_path));
set_volume(m_volume);
- m_sfxplayer->play();
+ if (ao_app->get_audio_output_device() != "Default")
+ BASS_ChannelSetDevice(m_stream, BASS_GetDevice());
+ BASS_ChannelPlay(m_stream, false);
}
void AOSfxPlayer::stop()
{
- m_sfxplayer->stop();
+ BASS_ChannelStop(m_stream);
}
void AOSfxPlayer::set_volume(int p_value)
{
m_volume = p_value;
- m_sfxplayer->setVolume(p_value / 100.0);
+ float volume = p_value / 100.0f;
+ BASS_ChannelSetAttribute(m_stream, BASS_ATTRIB_VOL, volume);
}
diff --git a/aosfxplayer.h b/aosfxplayer.h
index 1b73e490..30cbe9d3 100644
--- a/aosfxplayer.h
+++ b/aosfxplayer.h
@@ -1,29 +1,28 @@
#ifndef AOSFXPLAYER_H
#define AOSFXPLAYER_H
+#include "bass.h"
#include "aoapplication.h"
#include <QWidget>
#include <string.h>
#include <QDebug>
-#include <QSoundEffect>
class AOSfxPlayer
{
public:
AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app);
- ~AOSfxPlayer();
- void play(QString p_sfx, QString p_char = "");
+ void play(QString p_sfx, QString p_char = "", QString shout = "");
void stop();
void set_volume(int p_volume);
private:
QWidget *m_parent;
AOApplication *ao_app;
- QSoundEffect *m_sfxplayer;
int m_volume = 0;
+ HSTREAM m_stream;
};
#endif // AOSFXPLAYER_H
diff --git a/aotextarea.cpp b/aotextarea.cpp
index 16add101..5e146326 100644
--- a/aotextarea.cpp
+++ b/aotextarea.cpp
@@ -5,7 +5,7 @@ AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent)
}
-void AOTextArea::append_chatmessage(QString p_name, QString p_message)
+void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p_colour)
{
const QTextCursor old_cursor = this->textCursor();
const int old_scrollbar_value = this->verticalScrollBar()->value();
@@ -14,7 +14,7 @@ void AOTextArea::append_chatmessage(QString p_name, QString p_message)
this->moveCursor(QTextCursor::End);
this->append("");
- this->insertHtml("<b>" + p_name.toHtmlEscaped() + "</b>:&nbsp;");
+ this->insertHtml("<b><font color=" + p_colour + ">" + p_name.toHtmlEscaped() + "</font></b>:&nbsp;");
//cheap workarounds ahoy
p_message += " ";
diff --git a/aotextarea.h b/aotextarea.h
index 9f01f15e..d44596b2 100644
--- a/aotextarea.h
+++ b/aotextarea.h
@@ -12,7 +12,7 @@ class AOTextArea : public QTextBrowser
public:
AOTextArea(QWidget *p_parent = nullptr);
- void append_chatmessage(QString p_name, QString p_message);
+ void append_chatmessage(QString p_name, QString p_message, QString p_colour);
void append_error(QString p_message);
private:
diff --git a/base/serverlist.txt b/base/serverlist.txt
index fef701da..f700836c 100644
--- a/base/serverlist.txt
+++ b/base/serverlist.txt
@@ -1,4 +1 @@
-10.0.0.1:27071:the shit server
-88.203.168.170:27777:Demon Server For Demons! Vanilla! 1.8+
-24.193.75.13:27053:The Flaming Phoenix
-51.255.160.217:50000:Attorney Online Vidya(Dedicated)
+127.0.0.1:27016:Default local server
diff --git a/charselect.cpp b/charselect.cpp
index 5686dd87..ce37f85d 100644
--- a/charselect.cpp
+++ b/charselect.cpp
@@ -1,11 +1,10 @@
#include "courtroom.h"
+#include "lobby.h"
#include "file_functions.h"
#include "debug_functions.h"
#include "hardware_functions.h"
-#include <QDebug>
-
void Courtroom::construct_char_select()
{
ui_char_select_background = new AOImage(this, ao_app);
@@ -19,6 +18,7 @@ void Courtroom::construct_char_select()
ui_back_to_lobby = new AOButton(ui_char_select_background, ao_app);
ui_char_password = new QLineEdit(ui_char_select_background);
+ ui_char_password->setPlaceholderText("Password");
ui_char_select_left = new AOButton(ui_char_select_background, ao_app);
ui_char_select_right = new AOButton(ui_char_select_background, ao_app);
@@ -26,41 +26,23 @@ void Courtroom::construct_char_select()
ui_spectator = new AOButton(ui_char_select_background, ao_app);
ui_spectator->setText("Spectator");
- QPoint f_spacing = ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini");
-
- const int button_width = 60;
- int x_spacing = f_spacing.x();
- int x_mod_count = 0;
-
- const int button_height = 60;
- int y_spacing = f_spacing.y();
- int y_mod_count = 0;
-
- set_size_and_pos(ui_char_buttons, "char_buttons");
-
- char_columns = ((ui_char_buttons->width() - button_width) / (x_spacing + button_width)) + 1;
- char_rows = ((ui_char_buttons->height() - button_height) / (y_spacing + button_height)) + 1;
-
- max_chars_on_page = char_columns * char_rows;
-
- for (int n = 0 ; n < max_chars_on_page ; ++n)
- {
- int x_pos = (button_width + x_spacing) * x_mod_count;
- int y_pos = (button_height + y_spacing) * y_mod_count;
+ ui_char_search = new QLineEdit(ui_char_select_background);
+ ui_char_search->setPlaceholderText("Search");
+ ui_char_search->setFocus();
+ set_size_and_pos(ui_char_search, "char_search");
- ui_char_button_list.append(new AOCharButton(ui_char_buttons, ao_app, x_pos, y_pos));
+ ui_char_passworded = new QCheckBox(ui_char_select_background);
+ ui_char_passworded->setText("Passworded");
+ set_size_and_pos(ui_char_passworded, "char_passworded");
- connect(ui_char_button_list.at(n), SIGNAL(clicked()), char_button_mapper, SLOT(map())) ;
- char_button_mapper->setMapping (ui_char_button_list.at(n), n) ;
+ ui_char_taken = new QCheckBox(ui_char_select_background);
+ ui_char_taken->setText("Taken");
+ set_size_and_pos(ui_char_taken, "char_taken");
- ++x_mod_count;
+ ui_char_taken->setChecked(true);
+ ui_char_passworded->setChecked(true);
- if (x_mod_count == char_columns)
- {
- ++y_mod_count;
- x_mod_count = 0;
- }
- }
+ set_size_and_pos(ui_char_buttons, "char_buttons");
connect (char_button_mapper, SIGNAL(mapped(int)), this, SLOT(char_clicked(int)));
connect(ui_back_to_lobby, SIGNAL(clicked()), this, SLOT(on_back_to_lobby_clicked()));
@@ -69,6 +51,10 @@ void Courtroom::construct_char_select()
connect(ui_char_select_right, SIGNAL(clicked()), this, SLOT(on_char_select_right_clicked()));
connect(ui_spectator, SIGNAL(clicked()), this, SLOT(on_spectator_clicked()));
+
+ connect(ui_char_search, SIGNAL(textEdited(const QString&)), this, SLOT(on_char_search_changed(const QString&)));
+ connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, SLOT(on_char_passworded_clicked(int)));
+ connect(ui_char_taken, SIGNAL(stateChanged(int)), this, SLOT(on_char_taken_clicked(int)));
}
void Courtroom::set_char_select()
@@ -87,6 +73,10 @@ void Courtroom::set_char_select()
ui_char_select_background->resize(f_charselect.width, f_charselect.height);
ui_char_select_background->set_image("charselect_background.png");
+
+ filter_character_list();
+
+ ui_char_search->setFocus();
}
void Courtroom::set_char_select_page()
@@ -97,19 +87,23 @@ void Courtroom::set_char_select_page()
ui_char_select_right->hide();
for (AOCharButton *i_button : ui_char_button_list)
+ {
+ i_button->reset();
i_button->hide();
+ i_button->move(0,0);
+ }
- int total_pages = char_list.size() / max_chars_on_page;
+ int total_pages = ui_char_button_list_filtered.size() / max_chars_on_page;
int chars_on_page = 0;
- if (char_list.size() % max_chars_on_page != 0)
+ if (ui_char_button_list_filtered.size() % max_chars_on_page != 0)
{
++total_pages;
//i. e. not on the last page
if (total_pages > current_char_page + 1)
chars_on_page = max_chars_on_page;
else
- chars_on_page = char_list.size() % max_chars_on_page;
+ chars_on_page = ui_char_button_list_filtered.size() % max_chars_on_page;
}
else
@@ -121,26 +115,13 @@ void Courtroom::set_char_select_page()
if (current_char_page > 0)
ui_char_select_left->show();
- for (int n_button = 0 ; n_button < chars_on_page ; ++n_button)
- {
- int n_real_char = n_button + current_char_page * max_chars_on_page;
- AOCharButton *f_button = ui_char_button_list.at(n_button);
-
- f_button->reset();
- f_button->set_image(char_list.at(n_real_char).name);
- f_button->show();
-
- if (char_list.at(n_real_char).taken)
- f_button->set_taken();
- }
-
+ put_button_in_place(current_char_page * max_chars_on_page, chars_on_page);
}
void Courtroom::char_clicked(int n_char)
{
- int n_real_char = n_char + current_char_page * max_chars_on_page;
+ QString char_ini_path = ao_app->get_character_path(char_list.at(n_char).name, "char.ini");
- QString char_ini_path = ao_app->get_character_path(char_list.at(n_real_char).name, "char.ini");
qDebug() << "char_ini_path" << char_ini_path;
if (!file_exists(char_ini_path))
@@ -149,13 +130,134 @@ void Courtroom::char_clicked(int n_char)
return;
}
- if (n_real_char == m_cid)
+ if (n_char == m_cid)
{
enter_courtroom(m_cid);
}
else
{
- ao_app->send_server_packet(new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + QString::number(n_real_char) + "#" + get_hdid() + "#%"));
+ ao_app->send_server_packet(new AOPacket("CC#" + QString::number(ao_app->s_pv) + "#" + QString::number(n_char) + "#" + get_hdid() + "#%"));
}
+
+ ui_ic_chat_name->setPlaceholderText(char_list.at(n_char).name);
+}
+
+void Courtroom::put_button_in_place(int starting, int chars_on_this_page)
+{
+ if (ui_char_button_list_filtered.size() == 0)
+ return;
+
+ QPoint f_spacing = ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini");
+
+ int x_spacing = f_spacing.x();
+ int x_mod_count = 0;
+
+ int y_spacing = f_spacing.y();
+ int y_mod_count = 0;
+
+ char_columns = ((ui_char_buttons->width() - button_width) / (x_spacing + button_width)) + 1;
+ char_rows = ((ui_char_buttons->height() - button_height) / (y_spacing + button_height)) + 1;
+
+ max_chars_on_page = char_columns * char_rows;
+
+ int startout = starting;
+ for (int n = starting ; n < startout+chars_on_this_page ; ++n)
+ {
+ int x_pos = (button_width + x_spacing) * x_mod_count;
+ int y_pos = (button_height + y_spacing) * y_mod_count;
+
+ ui_char_button_list_filtered.at(n)->move(x_pos, y_pos);
+ ui_char_button_list_filtered.at(n)->show();
+
+ ui_char_button_list_filtered.at(n)->set_taken();
+
+ ++x_mod_count;
+
+ if (x_mod_count == char_columns)
+ {
+ ++y_mod_count;
+ x_mod_count = 0;
+ }
+ }
}
+void Courtroom::character_loading_finished()
+{
+ // Zeroeth, we'll clear any leftover characters from previous server visits.
+ ao_app->generated_chars = 0;
+ if (ui_char_button_list.size() > 0)
+ {
+ foreach (AOCharButton* item, ui_char_button_list) {
+ delete item;
+ }
+ ui_char_button_list.clear();
+ }
+
+ // First, we'll make all the character buttons in the very beginning.
+ // We also hide them all, so they can't be accidentally clicked.
+ // Later on, we'll be revealing buttons as we need them.
+ for (int n = 0; n < char_list.size(); n++)
+ {
+ AOCharButton* character = new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken);
+ character->reset();
+ character->hide();
+ character->set_image(char_list.at(n).name);
+ ui_char_button_list.append(character);
+
+ connect(character, SIGNAL(clicked()), char_button_mapper, SLOT(map()));
+ char_button_mapper->setMapping(character, ui_char_button_list.size() - 1);
+
+ // This part here serves as a way of showing to the player that the game is still running, it is
+ // just loading the pictures of the characters.
+ if (ao_app->lobby_constructed)
+ {
+ ao_app->generated_chars++;
+ int total_loading_size = ao_app->char_list_size * 2 + ao_app->evidence_list_size + ao_app->music_list_size;
+ int loading_value = int(((ao_app->loaded_chars + ao_app->generated_chars + ao_app->loaded_music + ao_app->loaded_evidence) / static_cast<double>(total_loading_size)) * 100);
+ ao_app->w_lobby->set_loading_value(loading_value);
+ ao_app->w_lobby->set_loading_text("Generating chars:\n" + QString::number(ao_app->generated_chars) + "/" + QString::number(ao_app->char_list_size));
+ }
+ }
+
+ filter_character_list();
+}
+
+void Courtroom::filter_character_list()
+{
+ ui_char_button_list_filtered.clear();
+ for (int i = 0; i < char_list.size(); i++)
+ {
+ AOCharButton* current_char = ui_char_button_list.at(i);
+
+ // 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_taken->isChecked() && char_list.at(i).taken)
+ continue;
+
+ if (!char_list.at(i).name.contains(ui_char_search->text(), Qt::CaseInsensitive))
+ continue;
+
+ ui_char_button_list_filtered.append(current_char);
+ }
+
+ current_char_page = 0;
+ set_char_select_page();
+}
+
+void Courtroom::on_char_search_changed(const QString& newtext)
+{
+ filter_character_list();
+}
+
+void Courtroom::on_char_passworded_clicked(int newstate)
+{
+ filter_character_list();
+}
+
+void Courtroom::on_char_taken_clicked(int newstate)
+{
+ filter_character_list();
+}
diff --git a/chatlogpiece.cpp b/chatlogpiece.cpp
new file mode 100644
index 00000000..6c861f01
--- /dev/null
+++ b/chatlogpiece.cpp
@@ -0,0 +1,76 @@
+#include "chatlogpiece.h"
+
+chatlogpiece::chatlogpiece()
+{
+ name = "UNKNOWN";
+ showname = "UNKNOWN";
+ message = "UNKNOWN";
+ is_song = false;
+ datetime = QDateTime::currentDateTime().toUTC();
+}
+
+chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song)
+{
+ name = p_name;
+ showname = p_showname;
+ message = p_message;
+ is_song = p_song;
+ datetime = QDateTime::currentDateTime().toUTC();
+}
+
+chatlogpiece::chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime)
+{
+ name = p_name;
+ showname = p_showname;
+ message = p_message;
+ is_song = p_song;
+ datetime = p_datetime.toUTC();
+}
+
+QString chatlogpiece::get_name()
+{
+ return name;
+}
+
+QString chatlogpiece::get_showname()
+{
+ return showname;
+}
+
+QString chatlogpiece::get_message()
+{
+ return message;
+}
+
+QDateTime chatlogpiece::get_datetime()
+{
+ return datetime;
+}
+
+bool chatlogpiece::get_is_song()
+{
+ return is_song;
+}
+
+QString chatlogpiece::get_datetime_as_string()
+{
+ return datetime.toString();
+}
+
+
+QString chatlogpiece::get_full()
+{
+ QString full = "[";
+
+ full.append(get_datetime_as_string());
+ full.append(" UTC] ");
+ full.append(get_showname());
+ full.append(" (");
+ full.append(get_name());
+ full.append(")");
+ if (is_song)
+ full.append(" has played a song: ");
+ full.append(get_message());
+
+ return full;
+}
diff --git a/chatlogpiece.h b/chatlogpiece.h
new file mode 100644
index 00000000..34c5926b
--- /dev/null
+++ b/chatlogpiece.h
@@ -0,0 +1,31 @@
+#ifndef CHATLOGPIECE_H
+#define CHATLOGPIECE_H
+
+#include <QString>
+#include <QDateTime>
+
+class chatlogpiece
+{
+public:
+ chatlogpiece();
+ chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song);
+ chatlogpiece(QString p_name, QString p_showname, QString p_message, bool p_song, QDateTime p_datetime);
+
+ QString get_name();
+ QString get_showname();
+ QString get_message();
+ bool get_is_song();
+ QDateTime get_datetime();
+ QString get_datetime_as_string();
+
+ QString get_full();
+
+private:
+ QString name;
+ QString showname;
+ QString message;
+ QDateTime datetime;
+ bool is_song;
+};
+
+#endif // CHATLOGPIECE_H
diff --git a/courtroom.cpp b/courtroom.cpp
index e180817f..88139e18 100644
--- a/courtroom.cpp
+++ b/courtroom.cpp
@@ -4,6 +4,31 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
{
ao_app = p_ao_app;
+ // Change the default audio output device to be the one the user has given
+ // in his config.ini file for now.
+ int a = 0;
+ BASS_DEVICEINFO info;
+
+ if (ao_app->get_audio_output_device() == "Default")
+ {
+ BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, 0, NULL);
+ load_bass_opus_plugin();
+ }
+ else
+ {
+ for (a = 0; BASS_GetDeviceInfo(a, &info); a++)
+ {
+ if (ao_app->get_audio_output_device() == info.name)
+ {
+ BASS_SetDevice(a);
+ BASS_Init(a, 48000, BASS_DEVICE_LATENCY, 0, NULL);
+ load_bass_opus_plugin();
+ qDebug() << info.name << "was set as the default audio output device.";
+ break;
+ }
+ }
+ }
+
keepalive_timer = new QTimer(this);
keepalive_timer->start(60000);
@@ -45,6 +70,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_vp_speedlines = new AOMovie(ui_viewport, ao_app);
ui_vp_speedlines->set_play_once(false);
ui_vp_player_char = new AOCharMovie(ui_viewport, ao_app);
+ ui_vp_sideplayer_char = new AOCharMovie(ui_viewport, ao_app);
+ ui_vp_sideplayer_char->hide();
ui_vp_desk = new AOScene(ui_viewport, ao_app);
ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app);
@@ -66,6 +93,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_ic_chatlog = new QTextEdit(this);
ui_ic_chatlog->setReadOnly(true);
+ log_maximum_blocks = ao_app->get_max_log_size();
+ log_goes_downwards = ao_app->get_log_goes_downwards();
+
ui_ms_chatlog = new AOTextArea(this);
ui_ms_chatlog->setReadOnly(true);
ui_ms_chatlog->setOpenExternalLinks(true);
@@ -76,11 +106,23 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_server_chatlog->setOpenExternalLinks(true);
ui_mute_list = new QListWidget(this);
- //ui_area_list = new QListWidget(this);
+ ui_area_list = new QListWidget(this);
+ ui_area_list->hide();
ui_music_list = new QListWidget(this);
+ ui_pair_list = new QListWidget(this);
+ ui_pair_offset_spinbox = new QSpinBox(this);
+ ui_pair_offset_spinbox->setRange(-100,100);
+ ui_pair_offset_spinbox->setSuffix("% offset");
+ ui_pair_button = new AOButton(this, ao_app);
+
+ ui_ic_chat_name = new QLineEdit(this);
+ ui_ic_chat_name->setFrame(false);
+ ui_ic_chat_name->setPlaceholderText(tr("Showname"));
+
ui_ic_chat_message = new QLineEdit(this);
ui_ic_chat_message->setFrame(false);
+ ui_ic_chat_message->setPlaceholderText(tr("Message"));
ui_muted = new AOImage(ui_ic_chat_message, ao_app);
ui_muted->hide();
@@ -91,7 +133,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_ooc_chat_name = new QLineEdit(this);
ui_ooc_chat_name->setFrame(false);
ui_ooc_chat_name->setPlaceholderText("Name");
- ui_ooc_chat_name->setText(ao_app->get_ooc_name());
+ ui_ooc_chat_name->setMaxLength(30);
+ ui_ooc_chat_name->setText(p_ao_app->get_default_username());
//ui_area_password = new QLineEdit(this);
//ui_area_password->setFrame(false);
@@ -111,6 +154,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_pos_dropdown->addItem("jud");
ui_pos_dropdown->addItem("hld");
ui_pos_dropdown->addItem("hlp");
+ ui_pos_dropdown->addItem("jur");
+ ui_pos_dropdown->addItem("sea");
ui_defense_bar = new AOImage(this, ao_app);
ui_prosecution_bar = new AOImage(this, ao_app);
@@ -119,6 +164,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_sfx_label = new QLabel(this);
ui_blip_label = new QLabel(this);
+ ui_log_limit_label = new QLabel(this);
+
ui_hold_it = new AOButton(this, ao_app);
ui_objection = new AOButton(this, ao_app);
ui_take_that = new AOButton(this, ao_app);
@@ -126,10 +173,15 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_ooc_toggle = new AOButton(this, ao_app);
ui_witness_testimony = new AOButton(this, ao_app);
ui_cross_examination = new AOButton(this, ao_app);
+ ui_guilty = new AOButton(this, ao_app);
+ ui_not_guilty = new AOButton(this, ao_app);
ui_change_character = new AOButton(this, ao_app);
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);
ui_pre->setText("Pre");
@@ -139,6 +191,18 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_guard = new QCheckBox(this);
ui_guard->setText("Guard");
ui_guard->hide();
+ ui_casing = new QCheckBox(this);
+ ui_casing->setChecked(ao_app->get_casing_enabled());
+ ui_casing->setText(tr("Casing"));
+ ui_casing->hide();
+
+ ui_showname_enable = new QCheckBox(this);
+ ui_showname_enable->setChecked(ao_app->get_showname_enabled_by_default());
+ ui_showname_enable->setText(tr("Shownames"));
+
+ ui_pre_non_interrupt = new QCheckBox(this);
+ ui_pre_non_interrupt->setText(tr("No Intrpt"));
+ ui_pre_non_interrupt->hide();
ui_custom_objection = new AOButton(this, ao_app);
ui_realization = new AOButton(this, ao_app);
@@ -156,8 +220,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_text_color->addItem("Red");
ui_text_color->addItem("Orange");
ui_text_color->addItem("Blue");
- if (ao_app->yellow_text_enabled)
- ui_text_color->addItem("Yellow");
+ ui_text_color->addItem("Yellow");
+ ui_text_color->addItem("Rainbow");
+ ui_text_color->addItem("Pink");
+ ui_text_color->addItem("Cyan");
ui_music_slider = new QSlider(Qt::Horizontal, this);
ui_music_slider->setRange(0, 100);
@@ -171,6 +237,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
ui_blip_slider->setRange(0, 100);
ui_blip_slider->setValue(ao_app->get_default_blip());
+ ui_log_limit_spinbox = new QSpinBox(this);
+ ui_log_limit_spinbox->setRange(0, 10000);
+ ui_log_limit_spinbox->setValue(ao_app->get_max_log_size());
+
ui_evidence_button = new AOButton(this, ao_app);
construct_evidence();
@@ -196,7 +266,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
connect(ui_emote_right, SIGNAL(clicked()), this, SLOT(on_emote_right_clicked()));
connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int)));
- connect(ui_pos_dropdown, SIGNAL(activated(int)), this, SLOT(on_pos_dropdown_changed(int)));
+ connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_pos_dropdown_changed(int)));
connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_mute_list_clicked(QModelIndex)));
@@ -205,6 +275,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, SLOT(on_ooc_return_pressed()));
connect(ui_music_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_music_list_double_clicked(QModelIndex)));
+ connect(ui_area_list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_area_list_double_clicked(QModelIndex)));
connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked()));
connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked()));
@@ -226,20 +297,34 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, SLOT(on_sfx_slider_moved(int)));
connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, SLOT(on_blip_slider_moved(int)));
+ connect(ui_log_limit_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_log_limit_changed(int)));
+
connect(ui_ooc_toggle, SIGNAL(clicked()), this, SLOT(on_ooc_toggle_clicked()));
connect(ui_music_search, SIGNAL(textChanged(QString)), this, SLOT(on_music_search_edited(QString)));
connect(ui_witness_testimony, SIGNAL(clicked()), this, SLOT(on_witness_testimony_clicked()));
connect(ui_cross_examination, SIGNAL(clicked()), this, SLOT(on_cross_examination_clicked()));
+ connect(ui_guilty, SIGNAL(clicked()), this, SLOT(on_guilty_clicked()));
+ connect(ui_not_guilty, SIGNAL(clicked()), this, SLOT(on_not_guilty_clicked()));
connect(ui_change_character, SIGNAL(clicked()), this, SLOT(on_change_character_clicked()));
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()));
connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked()));
connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked()));
+ connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked()));
+
+ connect(ui_showname_enable, SIGNAL(clicked()), this, SLOT(on_showname_enable_clicked()));
+
+ connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked()));
+ connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, SLOT(on_pair_list_clicked(QModelIndex)));
+ connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, SLOT(on_pair_offset_changed(int)));
connect(ui_evidence_button, SIGNAL(clicked()), this, SLOT(on_evidence_button_clicked()));
@@ -272,6 +357,21 @@ void Courtroom::set_mute_list()
}
}
+void Courtroom::set_pair_list()
+{
+ QStringList sorted_pair_list;
+
+ for (char_type i_char : char_list)
+ sorted_pair_list.append(i_char.name);
+
+ sorted_pair_list.sort();
+
+ for (QString i_name : sorted_pair_list)
+ {
+ ui_pair_list->addItem(i_name);
+ }
+}
+
void Courtroom::set_widgets()
{
blip_rate = ao_app->read_blip_rate();
@@ -303,6 +403,40 @@ void Courtroom::set_widgets()
set_size_and_pos(ui_viewport, "viewport");
+ // If there is a point to it, show all CCCC features.
+ // We also do this this soon so that set_size_and_pos can hide them all later, if needed.
+ if (ao_app->cccc_ic_support_enabled)
+ {
+ ui_pair_button->show();
+ ui_pre_non_interrupt->show();
+ ui_showname_enable->show();
+ ui_ic_chat_name->show();
+ ui_ic_chat_name->setEnabled(true);
+ }
+ else
+ {
+ ui_pair_button->hide();
+ ui_pre_non_interrupt->hide();
+ ui_showname_enable->hide();
+ ui_ic_chat_name->hide();
+ 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();
+ ui_log_limit_label->show();
+ ui_log_limit_spinbox->show();
+
ui_vp_background->move(0, 0);
ui_vp_background->resize(ui_viewport->width(), ui_viewport->height());
@@ -312,6 +446,9 @@ void Courtroom::set_widgets()
ui_vp_player_char->move(0, 0);
ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height());
+ ui_vp_sideplayer_char->move(0, 0);
+ ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), ui_viewport->height());
+
//the AO2 desk element
ui_vp_desk->move(0, 0);
ui_vp_desk->resize(ui_viewport->width(), ui_viewport->height());
@@ -358,8 +495,15 @@ void Courtroom::set_widgets()
set_size_and_pos(ui_mute_list, "mute_list");
ui_mute_list->hide();
- //set_size_and_pos(ui_area_list, "area_list");
- //ui_area_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);");
+ set_size_and_pos(ui_pair_list, "pair_list");
+ ui_pair_list->hide();
+ set_size_and_pos(ui_pair_offset_spinbox, "pair_offset_spinbox");
+ ui_pair_offset_spinbox->hide();
+ set_size_and_pos(ui_pair_button, "pair_button");
+ ui_pair_button->set_image("pair_button.png");
+
+ set_size_and_pos(ui_area_list, "music_list");
+ ui_area_list->setStyleSheet("background-color: rgba(0, 0, 0, 0);");
set_size_and_pos(ui_music_list, "music_list");
@@ -367,14 +511,17 @@ void Courtroom::set_widgets()
{
set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message");
set_size_and_pos(ui_vp_chatbox, "ao2_chatbox");
+ set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name");
}
else
{
set_size_and_pos(ui_ic_chat_message, "ic_chat_message");
set_size_and_pos(ui_vp_chatbox, "chatbox");
+ set_size_and_pos(ui_ic_chat_name, "ic_chat_name");
}
ui_ic_chat_message->setStyleSheet("QLineEdit{background-color: rgba(100, 100, 100, 255);}");
+ ui_ic_chat_name->setStyleSheet("QLineEdit{background-color: rgba(180, 180, 180, 255);}");
ui_vp_chatbox->set_image("chatmed.png");
ui_vp_chatbox->hide();
@@ -415,6 +562,9 @@ void Courtroom::set_widgets()
set_size_and_pos(ui_blip_label, "blip_label");
ui_blip_label->setText("Blips");
+ set_size_and_pos(ui_log_limit_label, "log_limit_label");
+ ui_log_limit_label->setText("Log limit");
+
set_size_and_pos(ui_hold_it, "hold_it");
ui_hold_it->set_image("holdit.png");
set_size_and_pos(ui_objection, "objection");
@@ -430,6 +580,11 @@ void Courtroom::set_widgets()
set_size_and_pos(ui_cross_examination, "cross_examination");
ui_cross_examination->set_image("crossexamination.png");
+ set_size_and_pos(ui_guilty, "guilty");
+ ui_guilty->set_image("guilty.png");
+ set_size_and_pos(ui_not_guilty, "not_guilty");
+ ui_not_guilty->set_image("notguilty.png");
+
set_size_and_pos(ui_change_character, "change_character");
ui_change_character->setText("Change character");
@@ -439,13 +594,27 @@ void Courtroom::set_widgets()
set_size_and_pos(ui_call_mod, "call_mod");
ui_call_mod->setText("Call mod");
+ 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");
+
set_size_and_pos(ui_pre, "pre");
ui_pre->setText("Pre");
+ set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt");
set_size_and_pos(ui_flip, "flip");
set_size_and_pos(ui_guard, "guard");
+ set_size_and_pos(ui_casing, "casing");
+
+ set_size_and_pos(ui_showname_enable, "showname_enable");
+
set_size_and_pos(ui_custom_objection, "custom_objection");
ui_custom_objection->set_image("custom.png");
@@ -473,6 +642,8 @@ void Courtroom::set_widgets()
set_size_and_pos(ui_sfx_slider, "sfx_slider");
set_size_and_pos(ui_blip_slider, "blip_slider");
+ set_size_and_pos(ui_log_limit_spinbox, "log_limit_spinbox");
+
set_size_and_pos(ui_evidence_button, "evidence_button");
ui_evidence_button->set_image("evidencebutton.png");
@@ -534,6 +705,7 @@ void Courtroom::set_fonts()
set_font(ui_ms_chatlog, "ms_chatlog");
set_font(ui_server_chatlog, "server_chatlog");
set_font(ui_music_list, "music_list");
+ set_font(ui_area_list, "music_list");
}
void Courtroom::set_font(QWidget *widget, QString p_identifier)
@@ -607,6 +779,7 @@ void Courtroom::done_received()
set_char_select_page();
set_mute_list();
+ set_pair_list();
set_char_select();
@@ -645,14 +818,15 @@ void Courtroom::enter_courtroom(int p_cid)
if (m_cid == -1)
{
- if(ao_app->is_discord_enabled())
+ if (ao_app->is_discord_enabled())
ao_app->discord->state_spectate();
f_char = "";
}
else
{
f_char = ao_app->get_char_name(char_list.at(m_cid).name);
- if(ao_app->is_discord_enabled())
+
+ if (ao_app->is_discord_enabled())
ao_app->discord->state_character(f_char.toStdString());
}
@@ -680,6 +854,8 @@ void Courtroom::enter_courtroom(int p_cid)
{
ui_witness_testimony->show();
ui_cross_examination->show();
+ ui_not_guilty->show();
+ ui_guilty->show();
ui_defense_minus->show();
ui_defense_plus->show();
ui_prosecution_minus->show();
@@ -689,6 +865,8 @@ void Courtroom::enter_courtroom(int p_cid)
{
ui_witness_testimony->hide();
ui_cross_examination->hide();
+ ui_guilty->hide();
+ ui_not_guilty->hide();
ui_defense_minus->hide();
ui_defense_plus->hide();
ui_prosecution_minus->hide();
@@ -696,8 +874,9 @@ void Courtroom::enter_courtroom(int p_cid)
}
if (ao_app->custom_objection_enabled &&
- file_exists(ao_app->get_character_path(current_char, "custom.gif")) &&
- file_exists(ao_app->get_character_path(current_char, "custom.wav")))
+ (file_exists(ao_app->get_character_path(char_path, "custom.gif")) ||
+ file_exists(ao_app->get_character_path(char_path, "custom.apng"))) &&
+ file_exists(ao_app->get_character_path(char_path, "custom.wav")))
ui_custom_objection->show();
else
ui_custom_objection->hide();
@@ -707,7 +886,13 @@ void Courtroom::enter_courtroom(int p_cid)
else
ui_flip->hide();
+ if (ao_app->casing_alerts_enabled)
+ ui_casing->show();
+ else
+ ui_casing->hide();
+
list_music();
+ list_areas();
music_player->set_volume(ui_music_slider->value());
sfx_player->set_volume(ui_sfx_slider->value());
@@ -729,6 +914,7 @@ void Courtroom::enter_courtroom(int p_cid)
void Courtroom::list_music()
{
ui_music_list->clear();
+ music_row_to_number.clear();
QString f_file = "courtroom_design.ini";
@@ -740,10 +926,13 @@ void Courtroom::list_music()
for (int n_song = 0 ; n_song < music_list.size() ; ++n_song)
{
QString i_song = music_list.at(n_song);
+ QString i_song_listname = i_song;
+ i_song_listname = i_song_listname.left(i_song_listname.lastIndexOf("."));
if (i_song.toLower().contains(ui_music_search->text().toLower()))
{
- ui_music_list->addItem(i_song);
+ ui_music_list->addItem(i_song_listname);
+ music_row_to_number.append(n_song);
QString song_path = ao_app->get_music_path(i_song);
@@ -757,14 +946,100 @@ void Courtroom::list_music()
}
}
+void Courtroom::list_areas()
+{
+ ui_area_list->clear();
+ area_row_to_number.clear();
+
+ QString f_file = "courtroom_design.ini";
+
+ QBrush free_brush(ao_app->get_color("area_free_color", f_file));
+ QBrush lfp_brush(ao_app->get_color("area_lfp_color", f_file));
+ QBrush casing_brush(ao_app->get_color("area_casing_color", f_file));
+ QBrush recess_brush(ao_app->get_color("area_recess_color", f_file));
+ QBrush rp_brush(ao_app->get_color("area_rp_color", f_file));
+ QBrush gaming_brush(ao_app->get_color("area_gaming_color", f_file));
+ QBrush locked_brush(ao_app->get_color("area_locked_color", f_file));
+
+ int n_listed_areas = 0;
+
+ for (int n_area = 0 ; n_area < area_list.size() ; ++n_area)
+ {
+ QString i_area = "";
+ i_area.append("[");
+ i_area.append(QString::number(n_area));
+ i_area.append("] ");
+
+ i_area.append(area_list.at(n_area));
+
+ if (ao_app->arup_enabled)
+ {
+ i_area.append("\n ");
+
+ i_area.append(arup_statuses.at(n_area));
+ i_area.append(" | CM: ");
+ i_area.append(arup_cms.at(n_area));
+
+ i_area.append("\n ");
+
+ i_area.append(QString::number(arup_players.at(n_area)));
+ i_area.append(" users | ");
+
+ i_area.append(arup_locks.at(n_area));
+ }
+
+ if (i_area.toLower().contains(ui_music_search->text().toLower()))
+ {
+ ui_area_list->addItem(i_area);
+ area_row_to_number.append(n_area);
+
+ if (ao_app->arup_enabled)
+ {
+ // Colouring logic here.
+ ui_area_list->item(n_listed_areas)->setBackground(free_brush);
+ if (arup_locks.at(n_area) == "LOCKED")
+ {
+ ui_area_list->item(n_listed_areas)->setBackground(locked_brush);
+ }
+ else
+ {
+ if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS")
+ ui_area_list->item(n_listed_areas)->setBackground(lfp_brush);
+ else if (arup_statuses.at(n_area) == "CASING")
+ ui_area_list->item(n_listed_areas)->setBackground(casing_brush);
+ else if (arup_statuses.at(n_area) == "RECESS")
+ ui_area_list->item(n_listed_areas)->setBackground(recess_brush);
+ else if (arup_statuses.at(n_area) == "RP")
+ ui_area_list->item(n_listed_areas)->setBackground(rp_brush);
+ else if (arup_statuses.at(n_area) == "GAMING")
+ ui_area_list->item(n_listed_areas)->setBackground(gaming_brush);
+ }
+ }
+ else
+ {
+ ui_area_list->item(n_listed_areas)->setBackground(free_brush);
+ }
+
+ ++n_listed_areas;
+ }
+ }
+}
+
void Courtroom::append_ms_chatmessage(QString f_name, QString f_message)
{
- ui_ms_chatlog->append_chatmessage(f_name, f_message);
+ ui_ms_chatlog->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name());
}
-void Courtroom::append_server_chatmessage(QString p_name, QString p_message)
+void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_colour)
{
- ui_server_chatlog->append_chatmessage(p_name, p_message);
+ QString colour = "#000000";
+
+ if (p_colour == "0")
+ colour = ao_app->get_color("ooc_default_color", "courtroom_design.ini").name();
+ if (p_colour == "1")
+ colour = ao_app->get_color("ooc_server_color", "courtroom_design.ini").name();
+
+ ui_server_chatlog->append_chatmessage(p_name, p_message, colour);
}
void Courtroom::on_chat_return_pressed()
@@ -793,6 +1068,13 @@ void Courtroom::on_chat_return_pressed()
//realization#
//text_color#%
+ // Additionally, in our case:
+
+ //showname#
+ //other_charid#
+ //self_offset#
+ //noninterrupting_preanim#%
+
QStringList packet_contents;
QString f_side = ao_app->get_char_side(current_char);
@@ -825,12 +1107,15 @@ void Courtroom::on_chat_return_pressed()
//needed or else legacy won't understand what we're saying
if (objection_state > 0)
{
- if (f_emote_mod == 5)
- f_emote_mod = 6;
- else
- f_emote_mod = 2;
+ if (ui_pre->isChecked())
+ {
+ if (f_emote_mod == 5)
+ f_emote_mod = 6;
+ else
+ f_emote_mod = 2;
+ }
}
- else if (ui_pre->isChecked())
+ else if (ui_pre->isChecked() and !ui_pre_non_interrupt->isChecked())
{
if (f_emote_mod == 0)
f_emote_mod = 1;
@@ -887,24 +1172,78 @@ void Courtroom::on_chat_return_pressed()
if (text_color < 0)
f_text_color = "0";
- else if (text_color > 4 && !ao_app->yellow_text_enabled)
+ else if (text_color > 8)
f_text_color = "0";
else
f_text_color = QString::number(text_color);
packet_contents.append(f_text_color);
+ // If the server we're on supports CCCC stuff, we should use it!
+ if (ao_app->cccc_ic_support_enabled)
+ {
+ // If there is a showname entered, use that -- else, just send an empty packet-part.
+ if (!ui_ic_chat_name->text().isEmpty())
+ {
+ packet_contents.append(ui_ic_chat_name->text());
+ }
+ else
+ {
+ packet_contents.append("");
+ }
+
+ // Similarly, we send over whom we're paired with, unless we have chosen ourselves.
+ // Or a charid of -1 or lower, through some means.
+ if (other_charid > -1 && other_charid != m_cid)
+ {
+ packet_contents.append(QString::number(other_charid));
+ packet_contents.append(QString::number(offset_with_pair));
+ }
+ else
+ {
+ packet_contents.append("-1");
+ packet_contents.append("0");
+ }
+
+ // Finally, we send over if we want our pres to not interrupt.
+ if (ui_pre_non_interrupt->isChecked() && ui_pre->isChecked())
+ {
+ packet_contents.append("1");
+ }
+ else
+ {
+ packet_contents.append("0");
+ }
+ }
+
ao_app->send_server_packet(new AOPacket("MS", packet_contents));
}
void Courtroom::handle_chatmessage(QStringList *p_contents)
{
- if (p_contents->size() < chatmessage_size)
+ // Instead of checking for whether a message has at least chatmessage_size
+ // amount of packages, we'll check if it has at least 15.
+ // That was the original chatmessage_size.
+ if (p_contents->size() < 15)
return;
for (int n_string = 0 ; n_string < chatmessage_size ; ++n_string)
{
- m_chatmessage[n_string] = p_contents->at(n_string);
+ //m_chatmessage[n_string] = p_contents->at(n_string);
+
+ // Note that we have added stuff that vanilla clients and servers simply won't send.
+ // So now, we have to check if the thing we want even exists amongst the packet's content.
+ // We also have to check if the server even supports CCCC's IC features, or if it's just japing us.
+ // Also, don't forget! A size 15 message will have indices from 0 to 14.
+ if (n_string < p_contents->size() &&
+ (n_string < 15 || ao_app->cccc_ic_support_enabled))
+ {
+ m_chatmessage[n_string] = p_contents->at(n_string);
+ }
+ else
+ {
+ m_chatmessage[n_string] = "";
+ }
}
int f_char_id = m_chatmessage[CHAR_ID].toInt();
@@ -915,7 +1254,16 @@ void Courtroom::handle_chatmessage(QStringList *p_contents)
if (mute_map.value(m_chatmessage[CHAR_ID].toInt()))
return;
- QString f_showname = ao_app->get_showname(char_list.at(f_char_id).name);
+ QString f_showname;
+ if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())
+ {
+ f_showname = ao_app->get_showname(char_list.at(f_char_id).name);
+ }
+ else
+ {
+ f_showname = m_chatmessage[SHOWNAME];
+ }
+
QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n';
@@ -946,6 +1294,14 @@ void Courtroom::handle_chatmessage(QStringList *p_contents)
ui_evidence_present->set_image("present_disabled.png");
}
+ chatlogpiece* temp = new chatlogpiece(ao_app->get_showname(char_list.at(f_char_id).name), f_showname, ": " + m_chatmessage[MESSAGE], false);
+ ic_chatlog_history.append(*temp);
+
+ while(ic_chatlog_history.size() > log_maximum_blocks)
+ {
+ ic_chatlog_history.removeFirst();
+ }
+
append_ic_text(": " + m_chatmessage[MESSAGE], f_showname);
previous_ic_message = f_message;
@@ -961,20 +1317,20 @@ void Courtroom::handle_chatmessage(QStringList *p_contents)
{
case 1:
ui_vp_objection->play("holdit", f_char, f_custom_theme);
- objection_player->play("holdit.wav", f_char);
+ objection_player->play("holdit.wav", f_char, f_custom_theme);
break;
case 2:
ui_vp_objection->play("objection", f_char, f_custom_theme);
- objection_player->play("objection.wav", f_char);
+ objection_player->play("objection.wav", f_char, f_custom_theme);
break;
case 3:
ui_vp_objection->play("takethat", f_char, f_custom_theme);
- objection_player->play("takethat.wav", f_char);
+ objection_player->play("takethat.wav", f_char, f_custom_theme);
break;
//case 4 is AO2 only
case 4:
ui_vp_objection->play("custom", f_char, f_custom_theme);
- objection_player->play("custom.wav", f_char);
+ objection_player->play("custom.wav", f_char, f_custom_theme);
break;
default:
qDebug() << "W: Logic error in objection switch statement!";
@@ -999,11 +1355,18 @@ void Courtroom::handle_chatmessage_2()
ui_vp_speedlines->stop();
ui_vp_player_char->stop();
- QString real_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name;
+ if (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())
+ {
+ QString real_name = char_list.at(m_chatmessage[CHAR_ID].toInt()).name;
- QString f_showname = ao_app->get_showname(real_name);
+ QString f_showname = ao_app->get_showname(real_name);
- ui_vp_showname->setText(f_showname);
+ ui_vp_showname->setText(f_showname);
+ }
+ else
+ {
+ ui_vp_showname->setText(m_chatmessage[SHOWNAME]);
+ }
ui_vp_message->clear();
ui_vp_chatbox->hide();
@@ -1014,13 +1377,34 @@ void Courtroom::handle_chatmessage_2()
ui_vp_chatbox->set_image("chatmed.png");
else
{
- QString chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + ".png";
+ QString chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chatbox.png";
ui_vp_chatbox->set_image_from_path(chatbox_path);
}
+ ui_vp_showname->setStyleSheet("QLabel { color : " + get_text_color("_showname").name() + "; }");
+
set_scene();
set_text_color();
+ // Check if the message needs to be centered.
+ QString f_message = m_chatmessage[MESSAGE];
+ if (f_message.size() >= 2)
+ {
+ if (f_message.startsWith("~~"))
+ {
+ message_is_centered = true;
+ }
+ else
+ {
+ message_is_centered = false;
+ }
+ }
+ else
+ {
+ ui_vp_message->setAlignment(Qt::AlignLeft);
+ }
+
+
int emote_mod = m_chatmessage[EMOTE_MOD].toInt();
if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1)
@@ -1028,6 +1412,143 @@ void Courtroom::handle_chatmessage_2()
else
ui_vp_player_char->set_flipped(false);
+ QString side = m_chatmessage[SIDE];
+
+ // Making the second character appear.
+ if (m_chatmessage[OTHER_CHARID].isEmpty())
+ {
+ // If there is no second character, hide 'em, and center the first.
+ ui_vp_sideplayer_char->hide();
+ ui_vp_sideplayer_char->move(0,0);
+
+ ui_vp_player_char->move(0,0);
+ }
+ else
+ {
+ bool ok;
+ int got_other_charid = m_chatmessage[OTHER_CHARID].toInt(&ok);
+ if (ok)
+ {
+ if (got_other_charid > -1)
+ {
+ // If there is, show them!
+ ui_vp_sideplayer_char->show();
+
+ // Depending on where we are, we offset the characters, and reorder their stacking.
+ if (side == "def")
+ {
+ // We also move the character down depending on how far the are to the right.
+ int hor_offset = m_chatmessage[SELF_OFFSET].toInt();
+ int vert_offset = 0;
+ if (hor_offset > 0)
+ {
+ vert_offset = hor_offset / 10;
+ }
+ ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, ui_viewport->height() * vert_offset / 100);
+
+ // We do the same with the second character.
+ int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt();
+ int vert2_offset = 0;
+ if (hor2_offset > 0)
+ {
+ vert2_offset = hor2_offset / 10;
+ }
+ ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, ui_viewport->height() * vert2_offset / 100);
+
+ // Finally, we reorder them based on who is more to the left.
+ // The person more to the left is more in the front.
+ if (hor2_offset >= hor_offset)
+ {
+ ui_vp_sideplayer_char->raise();
+ ui_vp_player_char->raise();
+ }
+ else
+ {
+ ui_vp_player_char->raise();
+ ui_vp_sideplayer_char->raise();
+ }
+ ui_vp_desk->raise();
+ ui_vp_legacy_desk->raise();
+ }
+ else if (side == "pro")
+ {
+ // Almost the same thing happens here, but in reverse.
+ int hor_offset = m_chatmessage[SELF_OFFSET].toInt();
+ int vert_offset = 0;
+ if (hor_offset < 0)
+ {
+ // We don't want to RAISE the char off the floor.
+ vert_offset = -1 * hor_offset / 10;
+ }
+ ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, ui_viewport->height() * vert_offset / 100);
+
+ // We do the same with the second character.
+ int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt();
+ int vert2_offset = 0;
+ if (hor2_offset < 0)
+ {
+ vert2_offset = -1 * hor2_offset / 10;
+ }
+ ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, ui_viewport->height() * vert2_offset / 100);
+
+ // Finally, we reorder them based on who is more to the right.
+ if (hor2_offset <= hor_offset)
+ {
+ ui_vp_sideplayer_char->raise();
+ ui_vp_player_char->raise();
+ }
+ else
+ {
+ ui_vp_player_char->raise();
+ ui_vp_sideplayer_char->raise();
+ }
+ ui_vp_desk->raise();
+ ui_vp_legacy_desk->raise();
+ }
+ else
+ {
+ // In every other case, the person more to the left is on top.
+ // These cases also don't move the characters down.
+ int hor_offset = m_chatmessage[SELF_OFFSET].toInt();
+ ui_vp_player_char->move(ui_viewport->width() * hor_offset / 100, 0);
+
+ // We do the same with the second character.
+ int hor2_offset = m_chatmessage[OTHER_OFFSET].toInt();
+ ui_vp_sideplayer_char->move(ui_viewport->width() * hor2_offset / 100, 0);
+
+ // Finally, we reorder them based on who is more to the left.
+ // The person more to the left is more in the front.
+ if (hor2_offset >= hor_offset)
+ {
+ ui_vp_sideplayer_char->raise();
+ ui_vp_player_char->raise();
+ }
+ else
+ {
+ ui_vp_player_char->raise();
+ ui_vp_sideplayer_char->raise();
+ }
+ ui_vp_desk->raise();
+ ui_vp_legacy_desk->raise();
+ }
+ // We should probably also play the other character's idle emote.
+ if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1)
+ ui_vp_sideplayer_char->set_flipped(true);
+ else
+ ui_vp_sideplayer_char->set_flipped(false);
+ ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], m_chatmessage[OTHER_EMOTE]);
+ }
+ else
+ {
+ // If the server understands other characters, but there
+ // really is no second character, hide 'em, and center the first.
+ ui_vp_sideplayer_char->hide();
+ ui_vp_sideplayer_char->move(0,0);
+
+ ui_vp_player_char->move(0,0);
+ }
+ }
+ }
switch (emote_mod)
{
@@ -1035,7 +1556,10 @@ void Courtroom::handle_chatmessage_2()
play_preanim();
break;
case 0: case 5:
- handle_chatmessage_3();
+ if (m_chatmessage[NONINTERRUPTING_PRE].toInt() == 0)
+ handle_chatmessage_3();
+ else
+ play_noninterrupting_preanim();
break;
default:
qDebug() << "W: invalid emote mod: " << QString::number(emote_mod);
@@ -1046,6 +1570,13 @@ void Courtroom::handle_chatmessage_3()
{
start_chat_ticking();
+ if (m_chatmessage[REALIZATION] == "1")
+ {
+ realization_timer->start(60);
+ ui_vp_realization->show();
+ sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME]));
+ }
+
int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt();
QString f_side = m_chatmessage[SIDE];
@@ -1054,19 +1585,24 @@ void Courtroom::handle_chatmessage_3()
//shifted by 1 because 0 is no evidence per legacy standards
QString f_image = local_evidence_list.at(f_evi_id - 1).image;
//def jud and hlp should display the evidence icon on the RIGHT side
- bool is_left_side = !(f_side == "def" || f_side == "hlp" || f_side == "jud");
+ bool is_left_side = !(f_side == "def" || f_side == "hlp" || f_side == "jud" || f_side == "jur");
ui_vp_evidence_display->show_evidence(f_image, is_left_side, ui_sfx_slider->value());
}
int emote_mod = m_chatmessage[EMOTE_MOD].toInt();
+ QString side = m_chatmessage[SIDE];
+
if (emote_mod == 5 ||
emote_mod == 6)
{
- QString side = m_chatmessage[SIDE];
ui_vp_desk->hide();
ui_vp_legacy_desk->hide();
+ // Since we're zooming, hide the second character, and centre the first.
+ ui_vp_sideplayer_char->hide();
+ ui_vp_player_char->move(0,0);
+
if (side == "pro" ||
side == "hlp" ||
side == "wit")
@@ -1081,11 +1617,17 @@ void Courtroom::handle_chatmessage_3()
bool text_is_blue = m_chatmessage[TEXT_COLOR].toInt() == BLUE;
if (!text_is_blue && text_state == 1)
+ {
//talking
f_anim_state = 2;
+ entire_message_is_blue = false;
+ }
else
+ {
//idle
f_anim_state = 3;
+ entire_message_is_blue = true;
+ }
if (f_anim_state <= anim_state)
return;
@@ -1098,18 +1640,12 @@ void Courtroom::handle_chatmessage_3()
ui_vp_player_char->play_talking(f_char, f_emote);
anim_state = 2;
}
- else {
+ else
+ {
ui_vp_player_char->play_idle(f_char, f_emote);
anim_state = 3;
}
- if (m_chatmessage[REALIZATION] == "1")
- {
- realization_timer->start(60);
- ui_vp_realization->show();
- sfx_player->play(ao_app->get_sfx("realization"));
- }
-
QString f_message = m_chatmessage[MESSAGE];
QStringList call_words = ao_app->get_call_words();
@@ -1128,45 +1664,311 @@ void Courtroom::handle_chatmessage_3()
void Courtroom::append_ic_text(QString p_text, QString p_name)
{
+ // a bit of a silly hack, should use QListWidget for IC in the first place though
+ static bool isEmpty = true;
+
QTextCharFormat bold;
QTextCharFormat normal;
bold.setFontWeight(QFont::Bold);
normal.setFontWeight(QFont::Normal);
const QTextCursor old_cursor = ui_ic_chatlog->textCursor();
const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value();
-
- int scrollbar_limit;
-
- if(ao_app->ic_scroll_down_enabled()) {
- scrollbar_limit = ui_ic_chatlog->verticalScrollBar()->maximum();
+
+ // Get rid of centering.
+ if(p_text.startsWith(": ~~"))
+ {
+ // Don't forget, the p_text part actually everything after the name!
+ // Hence why we check for ': ~~'.
+
+ // Let's remove those two tildes, then.
+ // : _ ~ ~
+ // 0 1 2 3
+ p_text.remove(2,2);
+ }
+
+ // Get rid of the inline-colouring.
+ // I know, I know, excessive code duplication.
+ // Nobody looks in here, I'm fine.
+ int trick_check_pos = 0;
+ bool ic_next_is_not_special = false;
+ QString f_character = p_text.at(trick_check_pos);
+ std::stack<INLINE_COLOURS> ic_colour_stack;
+ while (trick_check_pos < p_text.size())
+ {
+ f_character = p_text.at(trick_check_pos);
+
+ // Escape character.
+ if (f_character == "\\" and !ic_next_is_not_special)
+ {
+ ic_next_is_not_special = true;
+ p_text.remove(trick_check_pos,1);
+ }
+
+ // Text speed modifier.
+ else if (f_character == "{" and !ic_next_is_not_special)
+ {
+ p_text.remove(trick_check_pos,1);
+ }
+ else if (f_character == "}" and !ic_next_is_not_special)
+ {
+ p_text.remove(trick_check_pos,1);
+ }
+
+ // Orange inline colourisation.
+ else if (f_character == "|" and !ic_next_is_not_special)
+ {
+ if (!ic_colour_stack.empty())
+ {
+ if (ic_colour_stack.top() == INLINE_ORANGE)
+ {
+ ic_colour_stack.pop();
+ p_text.remove(trick_check_pos,1);
+ }
+ else
+ {
+ ic_colour_stack.push(INLINE_ORANGE);
+ p_text.remove(trick_check_pos,1);
+ }
+ }
+ else
+ {
+ ic_colour_stack.push(INLINE_ORANGE);
+ p_text.remove(trick_check_pos,1);
+ }
+ }
+
+ // Blue inline colourisation.
+ else if (f_character == "(" and !ic_next_is_not_special)
+ {
+ ic_colour_stack.push(INLINE_BLUE);
+ trick_check_pos++;
+ }
+ else if (f_character == ")" and !ic_next_is_not_special
+ and !ic_colour_stack.empty())
+ {
+ if (ic_colour_stack.top() == INLINE_BLUE)
+ {
+ ic_colour_stack.pop();
+ trick_check_pos++;
+ }
+ else
+ {
+ ic_next_is_not_special = true;
+ }
+ }
+
+ // Grey inline colourisation.
+ else if (f_character == "[" and !ic_next_is_not_special)
+ {
+ ic_colour_stack.push(INLINE_GREY);
+ trick_check_pos++;
+ }
+ else if (f_character == "]" and !ic_next_is_not_special
+ and !ic_colour_stack.empty())
+ {
+ if (ic_colour_stack.top() == INLINE_GREY)
+ {
+ ic_colour_stack.pop();
+ trick_check_pos++;
+ }
+ else
+ {
+ ic_next_is_not_special = true;
+ }
+ }
+
+ // Green inline colourisation.
+ else if (f_character == "`" and !ic_next_is_not_special)
+ {
+ if (!ic_colour_stack.empty())
+ {
+ if (ic_colour_stack.top() == INLINE_GREEN)
+ {
+ ic_colour_stack.pop();
+ p_text.remove(trick_check_pos,1);
+ }
+ else
+ {
+ ic_colour_stack.push(INLINE_GREEN);
+ p_text.remove(trick_check_pos,1);
+ }
+ }
+ else
+ {
+ ic_colour_stack.push(INLINE_GREEN);
+ p_text.remove(trick_check_pos,1);
+ }
+ }
+ else
+ {
+ trick_check_pos++;
+ ic_next_is_not_special = false;
+ }
+ }
+
+ // After all of that, let's jot down the message into the IC chatlog.
+
+ if (log_goes_downwards)
+ {
+ const bool is_scrolled_down = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum();
+
ui_ic_chatlog->moveCursor(QTextCursor::End);
+
+ if (!first_message_sent)
+ {
+ ui_ic_chatlog->textCursor().insertText(p_name, bold);
+ first_message_sent = true;
+ }
+ else
+ {
+ ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold);
+ }
+
+ ui_ic_chatlog->textCursor().insertText(p_text, normal);
+
+ // If we got too many blocks in the current log, delete some from the top.
+ while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0)
+ {
+ ui_ic_chatlog->moveCursor(QTextCursor::Start);
+ ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor);
+ ui_ic_chatlog->textCursor().removeSelectedText();
+ ui_ic_chatlog->textCursor().deleteChar();
+ //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks;
+ }
+
+ if (old_cursor.hasSelection() || !is_scrolled_down)
+ {
+ // The user has selected text or scrolled away from the bottom: maintain position.
+ ui_ic_chatlog->setTextCursor(old_cursor);
+ ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value);
+ }
+ else
+ {
+ // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom.
+ ui_ic_chatlog->moveCursor(QTextCursor::End);
+ ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->maximum());
+ }
}
- else {
- scrollbar_limit = ui_ic_chatlog->verticalScrollBar()->minimum();
+ else
+ {
+ const bool is_scrolled_up = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum();
+
ui_ic_chatlog->moveCursor(QTextCursor::Start);
+
+ ui_ic_chatlog->textCursor().insertText(p_name, bold);
+ ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal);
+
+ // If we got too many blocks in the current log, delete some from the bottom.
+ while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0)
+ {
+ ui_ic_chatlog->moveCursor(QTextCursor::End);
+ ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor);
+ ui_ic_chatlog->textCursor().removeSelectedText();
+ ui_ic_chatlog->textCursor().deletePreviousChar();
+ //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks;
+ }
+
+ if (old_cursor.hasSelection() || !is_scrolled_up)
+ {
+ // The user has selected text or scrolled away from the top: maintain position.
+ ui_ic_chatlog->setTextCursor(old_cursor);
+ ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value);
+ }
+ else
+ {
+ // The user hasn't selected any text and the scrollbar is at the top: scroll to the top.
+ ui_ic_chatlog->moveCursor(QTextCursor::Start);
+ ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->minimum());
+ }
}
-
- const bool is_fully_scrolled = old_scrollbar_value == scrollbar_limit;
+}
- ui_ic_chatlog->textCursor().insertText(p_name, bold);
- ui_ic_chatlog->textCursor().insertText(p_text + '\n', normal);
-
- if (old_cursor.hasSelection() || !is_fully_scrolled)
+// Call it ugly, call it a hack, but I wanted to do something special with the songname changes.
+void Courtroom::append_ic_songchange(QString p_songname, QString p_name)
+{
+ QTextCharFormat bold;
+ QTextCharFormat normal;
+ QTextCharFormat italics;
+ bold.setFontWeight(QFont::Bold);
+ normal.setFontWeight(QFont::Normal);
+ italics.setFontItalic(true);
+ const QTextCursor old_cursor = ui_ic_chatlog->textCursor();
+ const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value();
+
+ if (log_goes_downwards)
{
- // The user has selected text or scrolled away from the top: maintain position.
- ui_ic_chatlog->setTextCursor(old_cursor);
- ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value);
+ const bool is_scrolled_down = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum();
+
+ ui_ic_chatlog->moveCursor(QTextCursor::End);
+
+ if (!first_message_sent)
+ {
+ ui_ic_chatlog->textCursor().insertText(p_name, bold);
+ first_message_sent = true;
+ }
+ else
+ {
+ ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold);
+ }
+
+ ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal);
+ ui_ic_chatlog->textCursor().insertText(p_songname + ".", italics);
+
+ // If we got too many blocks in the current log, delete some from the top.
+ while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0)
+ {
+ ui_ic_chatlog->moveCursor(QTextCursor::Start);
+ ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor);
+ ui_ic_chatlog->textCursor().removeSelectedText();
+ ui_ic_chatlog->textCursor().deleteChar();
+ //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks;
+ }
+
+ if (old_cursor.hasSelection() || !is_scrolled_down)
+ {
+ // The user has selected text or scrolled away from the bottom: maintain position.
+ ui_ic_chatlog->setTextCursor(old_cursor);
+ ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value);
+ }
+ else
+ {
+ // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom.
+ ui_ic_chatlog->moveCursor(QTextCursor::End);
+ ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->maximum());
+ }
}
else
{
- // The user hasn't selected any text and the scrollbar is at the top: scroll to the top.
- if(ao_app->ic_scroll_down_enabled()) {
- ui_ic_chatlog->moveCursor(QTextCursor::End);
- ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->maximum());
+ const bool is_scrolled_up = old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum();
+
+ ui_ic_chatlog->moveCursor(QTextCursor::Start);
+
+ ui_ic_chatlog->textCursor().insertText(p_name, bold);
+
+ ui_ic_chatlog->textCursor().insertText(" has played a song: ", normal);
+ ui_ic_chatlog->textCursor().insertText(p_songname + "." + '\n', italics);
+
+ // If we got too many blocks in the current log, delete some from the bottom.
+ while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0)
+ {
+ ui_ic_chatlog->moveCursor(QTextCursor::End);
+ ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor);
+ ui_ic_chatlog->textCursor().removeSelectedText();
+ ui_ic_chatlog->textCursor().deletePreviousChar();
+ //qDebug() << ui_ic_chatlog->document()->blockCount() << " < " << log_maximum_blocks;
+ }
+
+ if (old_cursor.hasSelection() || !is_scrolled_up)
+ {
+ // The user has selected text or scrolled away from the top: maintain position.
+ ui_ic_chatlog->setTextCursor(old_cursor);
+ ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value);
}
- else {
- ui_ic_chatlog->moveCursor(QTextCursor::Start);
- ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->minimum());
+ else
+ {
+ // The user hasn't selected any text and the scrollbar is at the top: scroll to the top.
+ ui_ic_chatlog->moveCursor(QTextCursor::Start);
+ ui_ic_chatlog->verticalScrollBar()->setValue(ui_ic_chatlog->verticalScrollBar()->minimum());
}
}
}
@@ -1189,12 +1991,13 @@ void Courtroom::play_preanim()
preanim_duration = ao2_duration;
sfx_delay_timer->start(sfx_delay);
-
- if (!file_exists(ao_app->get_character_path(f_char, f_preanim + ".gif")) ||
+ QString anim_to_find = ao_app->get_image_suffix(ao_app->get_character_path(f_char) + f_preanim.toLower());
+ if (!file_exists(anim_to_find) ||
preanim_duration < 0)
{
anim_state = 1;
preanim_done();
+ qDebug() << "could not find " + anim_to_find;
return;
}
@@ -1205,8 +2008,45 @@ void Courtroom::play_preanim()
}
+void Courtroom::play_noninterrupting_preanim()
+{
+ QString f_char = m_chatmessage[CHAR_NAME];
+ QString f_preanim = m_chatmessage[PRE_EMOTE];
+
+ //all time values in char.inis are multiplied by a constant(time_mod) to get the actual time
+ int ao2_duration = ao_app->get_ao2_preanim_duration(f_char, f_preanim);
+ int text_delay = ao_app->get_text_delay(f_char, f_preanim) * time_mod;
+ int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * 60;
+
+ int preanim_duration;
+
+ if (ao2_duration < 0)
+ preanim_duration = ao_app->get_preanim_duration(f_char, f_preanim);
+ else
+ preanim_duration = ao2_duration;
+
+ sfx_delay_timer->start(sfx_delay);
+ QString anim_to_find = ao_app->get_image_suffix(ao_app->get_character_path(f_char) + f_preanim.toLower());
+ if (!file_exists(anim_to_find) ||
+ preanim_duration < 0)
+ {
+ anim_state = 4;
+ preanim_done();
+ qDebug() << "could not find " + anim_to_find;
+ return;
+ }
+
+ ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration);
+ anim_state = 4;
+ if (text_delay >= 0)
+ text_delay_timer->start(text_delay);
+
+ handle_chatmessage_3();
+}
+
void Courtroom::preanim_done()
{
+ anim_state = 1;
handle_chatmessage_3();
}
@@ -1217,13 +2057,14 @@ void Courtroom::realization_done()
void Courtroom::start_chat_ticking()
{
- ui_vp_message->clear();
- set_text_color();
- rainbow_counter = 0;
//we need to ensure that the text isn't already ticking because this function can be called by two logic paths
if (text_state != 0)
return;
+ ui_vp_message->clear();
+ set_text_color();
+ rainbow_counter = 0;
+
if (chatmessage_is_empty)
{
//since the message is empty, it's technically done ticking
@@ -1231,11 +2072,25 @@ void Courtroom::start_chat_ticking()
return;
}
+ // At this point, we'd do well to clear the inline colour stack.
+ // This stops it from flowing into next messages.
+ while (!inline_colour_stack.empty())
+ {
+ inline_colour_stack.pop();
+ }
+
ui_vp_chatbox->show();
tick_pos = 0;
blip_pos = 0;
- chat_tick_timer->start(chat_tick_interval);
+
+ // Just in case we somehow got inline blue text left over from a previous message,
+ // let's set it to false.
+ inline_blue_depth = 0;
+
+ // At the start of every new message, we set the text speed to the default.
+ current_display_speed = 3;
+ chat_tick_timer->start(message_display_speed[current_display_speed]);
QString f_gender = ao_app->get_gender(m_chatmessage[CHAR_NAME]);
@@ -1252,12 +2107,27 @@ void Courtroom::chat_tick()
QString f_message = m_chatmessage[MESSAGE];
+ // Due to our new text speed system, we always need to stop the timer now.
+ chat_tick_timer->stop();
+
+ // Stops blips from playing when we have a formatting option.
+ bool formatting_char = false;
+
+ // If previously, we have detected that the message is centered, now
+ // is the time to remove those two tildes at the start.
+ if (message_is_centered)
+ {
+ f_message.remove(0,2);
+ }
+
if (tick_pos >= f_message.size())
{
text_state = 2;
- chat_tick_timer->stop();
- anim_state = 3;
- ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]);
+ if (anim_state != 4)
+ {
+ anim_state = 3;
+ ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], m_chatmessage[EMOTE]);
+ }
}
else
@@ -1274,19 +2144,19 @@ void Courtroom::chat_tick()
switch (rainbow_counter)
{
case 0:
- html_color = "#FF0000";
+ html_color = get_text_color(QString::number(RED)).name();
break;
case 1:
- html_color = "#FF7F00";
+ html_color = get_text_color(QString::number(ORANGE)).name();
break;
case 2:
- html_color = "#FFFF00";
+ html_color = get_text_color(QString::number(YELLOW)).name();
break;
case 3:
- html_color = "#00FF00";
+ html_color = get_text_color(QString::number(GREEN)).name();
break;
default:
- html_color = "#2d96ff";
+ html_color = get_text_color(QString::number(BLUE)).name();
rainbow_counter = -1;
}
@@ -1294,8 +2164,181 @@ void Courtroom::chat_tick()
ui_vp_message->insertHtml("<font color=\"" + html_color + "\">" + f_character + "</font>");
}
+
+ // Escape character.
+ else if (f_character == "\\" and !next_character_is_not_special)
+ {
+ next_character_is_not_special = true;
+ formatting_char = true;
+ }
+
+ // Text speed modifier.
+ else if (f_character == "{" and !next_character_is_not_special)
+ {
+ // ++, because it INCREASES delay!
+ current_display_speed++;
+ formatting_char = true;
+ }
+ else if (f_character == "}" and !next_character_is_not_special)
+ {
+ current_display_speed--;
+ formatting_char = true;
+ }
+
+ // Orange inline colourisation.
+ else if (f_character == "|" and !next_character_is_not_special)
+ {
+ if (!inline_colour_stack.empty())
+ {
+ if (inline_colour_stack.top() == INLINE_ORANGE)
+ {
+ inline_colour_stack.pop();
+ }
+ else
+ {
+ inline_colour_stack.push(INLINE_ORANGE);
+ }
+ }
+ else
+ {
+ inline_colour_stack.push(INLINE_ORANGE);
+ }
+ formatting_char = true;
+ }
+
+ // Blue inline colourisation.
+ else if (f_character == "(" and !next_character_is_not_special)
+ {
+ inline_colour_stack.push(INLINE_BLUE);
+ ui_vp_message->insertHtml("<font color=\""+ get_text_color(QString::number(BLUE)).name() +"\">" + f_character + "</font>");
+
+ // Increase how deep we are in inline blues.
+ inline_blue_depth++;
+
+ // Here, we check if the entire message is blue.
+ // If it isn't, we stop talking.
+ if (!entire_message_is_blue and anim_state != 4)
+ {
+ QString f_char = m_chatmessage[CHAR_NAME];
+ QString f_emote = m_chatmessage[EMOTE];
+ ui_vp_player_char->play_idle(f_char, f_emote);
+ }
+ }
+ else if (f_character == ")" and !next_character_is_not_special
+ and !inline_colour_stack.empty())
+ {
+ if (inline_colour_stack.top() == INLINE_BLUE)
+ {
+ inline_colour_stack.pop();
+ ui_vp_message->insertHtml("<font color=\""+ get_text_color(QString::number(BLUE)).name() +"\">" + f_character + "</font>");
+
+ // Decrease how deep we are in inline blues.
+ // Just in case, we do a check if we're above zero, but we should be.
+ if (inline_blue_depth > 0)
+ {
+ inline_blue_depth--;
+ // Here, we check if the entire message is blue.
+ // If it isn't, we start talking if we have completely climbed out of inline blues.
+ if (!entire_message_is_blue)
+ {
+ // We should only go back to talking if we're out of inline blues, not during a non. int. pre, and not on the last character.
+ if (inline_blue_depth == 0 and anim_state != 4 and !(tick_pos+1 >= f_message.size()))
+ {
+ QString f_char = m_chatmessage[CHAR_NAME];
+ QString f_emote = m_chatmessage[EMOTE];
+ ui_vp_player_char->play_talking(f_char, f_emote);
+ }
+ }
+ }
+ }
+ else
+ {
+ next_character_is_not_special = true;
+ tick_pos--;
+ }
+ }
+
+ // Grey inline colourisation.
+ else if (f_character == "[" and !next_character_is_not_special)
+ {
+ inline_colour_stack.push(INLINE_GREY);
+ ui_vp_message->insertHtml("<font color=\""+ get_text_color("_inline_grey").name() +"\">" + f_character + "</font>");
+ }
+ else if (f_character == "]" and !next_character_is_not_special
+ and !inline_colour_stack.empty())
+ {
+ if (inline_colour_stack.top() == INLINE_GREY)
+ {
+ inline_colour_stack.pop();
+ ui_vp_message->insertHtml("<font color=\""+ get_text_color("_inline_grey").name() +"\">" + f_character + "</font>");
+ }
+ else
+ {
+ next_character_is_not_special = true;
+ tick_pos--;
+ }
+ }
+
+ // Green inline colourisation.
+ else if (f_character == "`" and !next_character_is_not_special)
+ {
+ if (!inline_colour_stack.empty())
+ {
+ if (inline_colour_stack.top() == INLINE_GREEN)
+ {
+ inline_colour_stack.pop();
+ formatting_char = true;
+ }
+ else
+ {
+ inline_colour_stack.push(INLINE_GREEN);
+ formatting_char = true;
+ }
+ }
+ else
+ {
+ inline_colour_stack.push(INLINE_GREEN);
+ formatting_char = true;
+ }
+ }
else
- ui_vp_message->insertHtml(f_character);
+ {
+ next_character_is_not_special = false;
+ if (!inline_colour_stack.empty())
+ {
+ switch (inline_colour_stack.top()) {
+ case INLINE_ORANGE:
+ ui_vp_message->insertHtml("<font color=\""+ get_text_color(QString::number(ORANGE)).name() +"\">" + f_character + "</font>");
+ break;
+ case INLINE_BLUE:
+ ui_vp_message->insertHtml("<font color=\""+ get_text_color(QString::number(BLUE)).name() +"\">" + f_character + "</font>");
+ break;
+ case INLINE_GREEN:
+ ui_vp_message->insertHtml("<font color=\""+ get_text_color(QString::number(GREEN)).name() +"\">" + f_character + "</font>");
+ break;
+ case INLINE_GREY:
+ ui_vp_message->insertHtml("<font color=\""+ get_text_color("_inline_grey").name() +"\">" + f_character + "</font>");
+ break;
+ default:
+ ui_vp_message->insertHtml(f_character);
+ break;
+ }
+
+ }
+ else
+ {
+ ui_vp_message->insertHtml(f_character);
+ }
+
+ if (message_is_centered)
+ {
+ ui_vp_message->setAlignment(Qt::AlignCenter);
+ }
+ else
+ {
+ ui_vp_message->setAlignment(Qt::AlignLeft);
+ }
+ }
QScrollBar *scroll = ui_vp_message->verticalScrollBar();
scroll->setValue(scroll->maximum());
@@ -1306,7 +2349,7 @@ void Courtroom::chat_tick()
if (f_message.at(tick_pos) != ' ' || blank_blip)
{
- if (blip_pos % blip_rate == 0)
+ if (blip_pos % blip_rate == 0 && !formatting_char)
{
blip_pos = 0;
blip_player->blip_tick();
@@ -1316,6 +2359,29 @@ void Courtroom::chat_tick()
}
++tick_pos;
+
+ // Restart the timer, but according to the newly set speeds, if there were any.
+ // Keep the speed at bay.
+ if (current_display_speed < 0)
+ {
+ current_display_speed = 0;
+ }
+
+ if (current_display_speed > 6)
+ {
+ current_display_speed = 6;
+ }
+
+ // If we had a formatting char, we shouldn't wait so long again, as it won't appear!
+ if (formatting_char)
+ {
+ chat_tick_timer->start(1);
+ }
+ else
+ {
+ chat_tick_timer->start(message_display_speed[current_display_speed]);
+ }
+
}
}
@@ -1346,7 +2412,7 @@ void Courtroom::play_sfx()
if (sfx_name == "1")
return;
- sfx_player->play(sfx_name + ".wav");
+ sfx_player->play(ao_app->get_sfx_suffix(sfx_name));
}
void Courtroom::set_scene()
@@ -1391,6 +2457,16 @@ void Courtroom::set_scene()
f_background = "prohelperstand";
f_desk_image = "prohelperdesk";
}
+ else if (f_side == "jur")
+ {
+ f_background = "jurystand";
+ f_desk_image = "jurydesk";
+ }
+ else if (f_side == "sea")
+ {
+ f_background = "seancestand";
+ f_desk_image = "seancedesk";
+ }
else
{
if (is_ao2_bg)
@@ -1435,37 +2511,26 @@ void Courtroom::set_scene()
void Courtroom::set_text_color()
{
- switch (m_chatmessage[TEXT_COLOR].toInt())
- {
- case GREEN:
- ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"
- "color: rgb(0, 255, 0)");
- break;
- case RED:
- ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"
- "color: red");
- break;
- case ORANGE:
- ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"
- "color: orange");
- break;
- case BLUE:
- ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"
- "color: rgb(45, 150, 255)");
- break;
- case YELLOW:
- ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"
- "color: yellow");
- break;
- case WHITE:
- ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"
- "color: white");
- break;
- default:
- ui_vp_message->setStyleSheet("background-color: rgba(0, 0, 0, 0);"
- "color: white");
- qDebug() << "W: undefined text color: " << m_chatmessage[TEXT_COLOR];
- }
+ QColor textcolor = ao_app->get_chat_color(m_chatmessage[TEXT_COLOR], ao_app->get_chat(m_chatmessage[CHAR_NAME]));
+
+ ui_vp_message->setTextBackgroundColor(QColor(0,0,0,0));
+ ui_vp_message->setTextColor(textcolor);
+
+ QString style = "background-color: rgba(0, 0, 0, 0);";
+ style.append("color: rgb(");
+ style.append(QString::number(textcolor.red()));
+ style.append(", ");
+ style.append(QString::number(textcolor.green()));
+ style.append(", ");
+ style.append(QString::number(textcolor.blue()));
+ style.append(")");
+
+ ui_vp_message->setStyleSheet(style);
+}
+
+QColor Courtroom::get_text_color(QString color)
+{
+ return ao_app->get_chat_color(color, ao_app->get_chat(m_chatmessage[CHAR_NAME]));
}
void Courtroom::set_ip_list(QString p_list)
@@ -1514,6 +2579,8 @@ void Courtroom::handle_song(QStringList *p_contents)
return;
QString f_song = f_contents.at(0);
+ QString f_song_clear = f_song;
+ f_song_clear = f_song_clear.left(f_song_clear.lastIndexOf("."));
int n_char = f_contents.at(1).toInt();
if (n_char < 0 || n_char >= char_list.size())
@@ -1523,16 +2590,30 @@ void Courtroom::handle_song(QStringList *p_contents)
else
{
QString str_char = char_list.at(n_char).name;
+ QString str_show = char_list.at(n_char).name;
+
+ if (p_contents->length() > 2)
+ {
+ str_show = p_contents->at(2);
+ }
if (!mute_map.value(n_char))
{
- append_ic_text(" has played a song: " + f_song, str_char);
+ chatlogpiece* temp = new chatlogpiece(str_char, str_show, f_song, true);
+ ic_chatlog_history.append(*temp);
+
+ while(ic_chatlog_history.size() > log_maximum_blocks)
+ {
+ ic_chatlog_history.removeFirst();
+ }
+
+ append_ic_songchange(f_song_clear, str_show);
music_player->play(f_song);
}
}
}
-void Courtroom::handle_wtce(QString p_wtce)
+void Courtroom::handle_wtce(QString p_wtce, int variant)
{
QString sfx_file = "courtroom_sounds.ini";
@@ -1551,6 +2632,20 @@ void Courtroom::handle_wtce(QString p_wtce)
ui_vp_wtce->play("crossexamination");
testimony_in_progress = false;
}
+ else if (p_wtce == "judgeruling")
+ {
+ if (variant == 0)
+ {
+ sfx_player->play(ao_app->get_sfx("not_guilty"));
+ ui_vp_wtce->play("notguilty");
+ testimony_in_progress = false;
+ }
+ else if (variant == 1) {
+ sfx_player->play(ao_app->get_sfx("guilty"));
+ ui_vp_wtce->play("guilty");
+ testimony_in_progress = false;
+ }
+ }
}
void Courtroom::set_hp_bar(int p_bar, int p_state)
@@ -1580,6 +2675,23 @@ void Courtroom::mod_called(QString p_ip)
}
}
+void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno)
+{
+ if (ui_casing->isChecked())
+ {
+ ui_server_chatlog->append(msg);
+ if ((ao_app->get_casing_defence_enabled() && def) ||
+ (ao_app->get_casing_prosecution_enabled() && pro) ||
+ (ao_app->get_casing_judge_enabled() && jud) ||
+ (ao_app->get_casing_juror_enabled() && jur) ||
+ (ao_app->get_casing_steno_enabled() && steno))
+ {
+ modcall_player->play(ao_app->get_sfx("case_call"));
+ ao_app->alert(this);
+ }
+ }
+}
+
void Courtroom::on_ooc_return_pressed()
{
QString ooc_message = ui_ooc_chat_message->text();
@@ -1593,6 +2705,8 @@ void Courtroom::on_ooc_return_pressed()
{
ui_witness_testimony->show();
ui_cross_examination->show();
+ ui_guilty->show();
+ ui_not_guilty->show();
ui_defense_minus->show();
ui_defense_plus->show();
ui_prosecution_minus->show();
@@ -1602,6 +2716,8 @@ void Courtroom::on_ooc_return_pressed()
{
ui_witness_testimony->hide();
ui_cross_examination->hide();
+ ui_guilty->hide();
+ ui_not_guilty->hide();
ui_defense_minus->hide();
ui_defense_plus->hide();
ui_prosecution_minus->hide();
@@ -1609,12 +2725,198 @@ void Courtroom::on_ooc_return_pressed()
}
}
else if (ooc_message.startsWith("/login"))
+ {
ui_guard->show();
+ append_server_chatmessage("CLIENT", "You were granted the Guard button.", "1");
+ }
else if (ooc_message.startsWith("/rainbow") && ao_app->yellow_text_enabled && !rainbow_appended)
{
- ui_text_color->addItem("Rainbow");
+ //ui_text_color->addItem("Rainbow");
+ ui_ooc_chat_message->clear();
+ //rainbow_appended = true;
+ append_server_chatmessage("CLIENT", "This does nohing, but there you go.", "1");
+ return;
+ }
+ else if (ooc_message.startsWith("/settings"))
+ {
+ ui_ooc_chat_message->clear();
+ ao_app->call_settings_menu();
+ append_server_chatmessage("CLIENT", "You opened the settings menu.", "1");
+ return;
+ }
+ else if (ooc_message.startsWith("/pair"))
+ {
+ ui_ooc_chat_message->clear();
+ ooc_message.remove(0,6);
+
+ bool ok;
+ int whom = ooc_message.toInt(&ok);
+ if (ok)
+ {
+ if (whom > -1)
+ {
+ other_charid = whom;
+ QString msg = "You will now pair up with ";
+ msg.append(char_list.at(whom).name);
+ msg.append(" if they also choose your character in return.");
+ append_server_chatmessage("CLIENT", msg, "1");
+ }
+ else
+ {
+ append_server_chatmessage("CLIENT", "You are no longer paired with anyone.", "1");
+ }
+ }
+ else
+ {
+ append_server_chatmessage("CLIENT", "Are you sure you typed that well? The char ID could not be recognised.", "1");
+ }
+ return;
+ }
+ else if (ooc_message.startsWith("/offset"))
+ {
+ ui_ooc_chat_message->clear();
+ ooc_message.remove(0,8);
+
+ bool ok;
+ int off = ooc_message.toInt(&ok);
+ if (ok)
+ {
+ if (off >= -100 && off <= 100)
+ {
+ offset_with_pair = off;
+ QString msg = "You have set your offset to ";
+ msg.append(QString::number(off));
+ msg.append("%.");
+ append_server_chatmessage("CLIENT", msg, "1");
+ }
+ else
+ {
+ append_server_chatmessage("CLIENT", "Your offset must be between -100% and 100%!", "1");
+ }
+ }
+ else
+ {
+ append_server_chatmessage("CLIENT", "That offset does not look like one.", "1");
+ }
+ return;
+ }
+ else if (ooc_message.startsWith("/switch_am"))
+ {
+ append_server_chatmessage("CLIENT", "You switched your music and area list.", "1");
+ on_switch_area_music_clicked();
+ ui_ooc_chat_message->clear();
+ return;
+ }
+ else if (ooc_message.startsWith("/enable_blocks"))
+ {
+ append_server_chatmessage("CLIENT", "You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this.", "1");
+ ao_app->cccc_ic_support_enabled = true;
+ ao_app->arup_enabled = true;
+ ao_app->modcall_reason_enabled = true;
+ on_reload_theme_clicked();
+ ui_ooc_chat_message->clear();
+ return;
+ }
+ else if (ooc_message.startsWith("/non_int_pre"))
+ {
+ if (ui_pre_non_interrupt->isChecked())
+ append_server_chatmessage("CLIENT", "Your pre-animations interrupt again.", "1");
+ else
+ append_server_chatmessage("CLIENT", "Your pre-animations will not interrupt text.", "1");
+ ui_pre_non_interrupt->setChecked(!ui_pre_non_interrupt->isChecked());
+ ui_ooc_chat_message->clear();
+ return;
+ }
+ else if (ooc_message.startsWith("/save_chatlog"))
+ {
+ QFile file("chatlog.txt");
+
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
+ {
+ append_server_chatmessage("CLIENT", "Couldn't open chatlog.txt to write into.", "1");
+ ui_ooc_chat_message->clear();
+ return;
+ }
+
+ QTextStream out(&file);
+
+ foreach (chatlogpiece item, ic_chatlog_history) {
+ out << item.get_full() << '\n';
+ }
+
+ file.close();
+
+ append_server_chatmessage("CLIENT", "The IC chatlog has been saved.", "1");
+ ui_ooc_chat_message->clear();
+ return;
+ }
+ else if (ooc_message.startsWith("/load_case"))
+ {
+ QStringList command = ooc_message.split(" ", QString::SkipEmptyParts);
+
+ QDir casefolder("base/cases");
+ if (!casefolder.exists())
+ {
+ QDir::current().mkdir("base/" + casefolder.dirName());
+ append_server_chatmessage("CLIENT", "You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there.", "1");
+ ui_ooc_chat_message->clear();
+ return;
+ }
+ QStringList caseslist = casefolder.entryList();
+ caseslist.removeOne(".");
+ caseslist.removeOne("..");
+ caseslist.replaceInStrings(".ini","");
+
+ if (command.size() < 2)
+ {
+ append_server_chatmessage("CLIENT", "You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini.\nCases you can load: " + caseslist.join(", "), "1");
+ ui_ooc_chat_message->clear();
+ return;
+ }
+
+
+ if (command.size() > 2)
+ {
+ append_server_chatmessage("CLIENT", "Too many arguments to load a case! You only need one filename, without extension.", "1");
+ ui_ooc_chat_message->clear();
+ return;
+ }
+
+ QSettings casefile("base/cases/" + command[1] + ".ini", QSettings::IniFormat);
+
+ QString caseauth = casefile.value("author", "").value<QString>();
+ QString casedoc = casefile.value("doc", "").value<QString>();
+ QString cmdoc = casefile.value("cmdoc", "").value<QString>();
+ QString casestatus = casefile.value("status", "").value<QString>();
+
+ if (!caseauth.isEmpty())
+ append_server_chatmessage("CLIENT", "Case made by " + caseauth + ".", "1");
+ if (!casedoc.isEmpty())
+ ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/doc " + casedoc + "#%"));
+ if (!casestatus.isEmpty())
+ ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/status " + casestatus + "#%"));
+ if (!cmdoc.isEmpty())
+ append_server_chatmessage("CLIENT", "Navigate to " + cmdoc + " for the CM doc.", "1");
+
+ for (int i = local_evidence_list.size() - 1; i >= 0; i--) {
+ ao_app->send_server_packet(new AOPacket("DE#" + QString::number(i) + "#%"));
+ }
+
+ foreach (QString evi, casefile.childGroups()) {
+ if (evi == "General")
+ continue;
+
+ QStringList f_contents;
+
+ f_contents.append(casefile.value(evi + "/name", "UNKNOWN").value<QString>());
+ f_contents.append(casefile.value(evi + "/description", "UNKNOWN").value<QString>());
+ f_contents.append(casefile.value(evi + "/image", "UNKNOWN.png").value<QString>());
+
+ ao_app->send_server_packet(new AOPacket("PE", f_contents));
+ }
+
+ append_server_chatmessage("CLIENT", "Your case \"" + command[1] + "\" was loaded!", "1");
ui_ooc_chat_message->clear();
- rainbow_appended = true;
return;
}
@@ -1659,6 +2961,7 @@ void Courtroom::on_music_search_edited(QString p_text)
//preventing compiler warnings
p_text += "a";
list_music();
+ list_areas();
}
void Courtroom::on_pos_dropdown_changed(int p_index)
@@ -1735,25 +3038,51 @@ void Courtroom::on_mute_list_clicked(QModelIndex p_index)
mute_map.insert(f_cid, true);
f_item->setText(real_char + " [x]");
}
+}
+void Courtroom::on_pair_list_clicked(QModelIndex p_index)
+{
+ QListWidgetItem *f_item = ui_pair_list->item(p_index.row());
+ QString f_char = f_item->text();
+ QString real_char;
-
- /*
if (f_char.endsWith(" [x]"))
{
real_char = f_char.left(f_char.size() - 4);
- mute_map.remove(real_char);
- mute_map.insert(real_char, false);
f_item->setText(real_char);
}
else
- {
real_char = f_char;
- mute_map.remove(real_char);
- mute_map.insert(real_char, true);
- f_item->setText(real_char + " [x]");
+
+ int f_cid = -1;
+
+ for (int n_char = 0 ; n_char < char_list.size() ; n_char++)
+ {
+ if (char_list.at(n_char).name == real_char)
+ f_cid = n_char;
}
- */
+
+ if (f_cid < 0 || f_cid >= char_list.size())
+ {
+ qDebug() << "W: " << real_char << " not present in char_list";
+ return;
+ }
+
+ other_charid = f_cid;
+
+ // Redo the character list.
+ QStringList sorted_pair_list;
+
+ for (char_type i_char : char_list)
+ sorted_pair_list.append(i_char.name);
+
+ sorted_pair_list.sort();
+
+ for (int i = 0; i < ui_pair_list->count(); i++) {
+ ui_pair_list->item(i)->setText(sorted_pair_list.at(i));
+ }
+
+ f_item->setText(real_char + " [x]");
}
void Courtroom::on_music_list_double_clicked(QModelIndex p_model)
@@ -1761,9 +3090,22 @@ void Courtroom::on_music_list_double_clicked(QModelIndex p_model)
if (is_muted)
return;
- QString p_song = ui_music_list->item(p_model.row())->text();
+ QString p_song = music_list.at(music_row_to_number.at(p_model.row()));
+
+ if (!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_support_enabled)
+ {
+ ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#" + ui_ic_chat_name->text() + "#%"), false);
+ }
+ else
+ {
+ ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#%"), false);
+ }
+}
- ao_app->send_server_packet(new AOPacket("MC#" + p_song + "#" + QString::number(m_cid) + "#%"), false);
+void Courtroom::on_area_list_double_clicked(QModelIndex p_model)
+{
+ QString p_area = area_list.at(area_row_to_number.at(p_model.row()));
+ ao_app->send_server_packet(new AOPacket("MC#" + p_area + "#" + QString::number(m_cid) + "#%"), false);
}
void Courtroom::on_hold_it_clicked()
@@ -1867,6 +3209,9 @@ void Courtroom::on_mute_clicked()
if (ui_mute_list->isHidden())
{
ui_mute_list->show();
+ ui_pair_list->hide();
+ ui_pair_offset_spinbox->hide();
+ ui_pair_button->set_image("pair_button.png");
ui_mute->set_image("mute_pressed.png");
}
else
@@ -1876,6 +3221,24 @@ void Courtroom::on_mute_clicked()
}
}
+void Courtroom::on_pair_clicked()
+{
+ if (ui_pair_list->isHidden())
+ {
+ ui_pair_list->show();
+ ui_pair_offset_spinbox->show();
+ ui_mute_list->hide();
+ ui_mute->set_image("mute.png");
+ ui_pair_button->set_image("pair_button_pressed.png");
+ }
+ else
+ {
+ ui_pair_list->hide();
+ ui_pair_offset_spinbox->hide();
+ ui_pair_button->set_image("pair_button.png");
+ }
+}
+
void Courtroom::on_defense_minus_clicked()
{
int f_state = defense_bar_state - 1;
@@ -1933,6 +3296,16 @@ void Courtroom::on_blip_slider_moved(int p_value)
ui_ic_chat_message->setFocus();
}
+void Courtroom::on_log_limit_changed(int value)
+{
+ log_maximum_blocks = value;
+}
+
+void Courtroom::on_pair_offset_changed(int value)
+{
+ offset_with_pair = value;
+}
+
void Courtroom::on_witness_testimony_clicked()
{
if (is_muted)
@@ -1953,6 +3326,26 @@ void Courtroom::on_cross_examination_clicked()
ui_ic_chat_message->setFocus();
}
+void Courtroom::on_not_guilty_clicked()
+{
+ if (is_muted)
+ return;
+
+ ao_app->send_server_packet(new AOPacket("RT#judgeruling#0#%"));
+
+ ui_ic_chat_message->setFocus();
+}
+
+void Courtroom::on_guilty_clicked()
+{
+ if (is_muted)
+ return;
+
+ ao_app->send_server_packet(new AOPacket("RT#judgeruling#1#%"));
+
+ ui_ic_chat_message->setFocus();
+}
+
void Courtroom::on_change_character_clicked()
{
music_player->set_volume(0);
@@ -2008,11 +3401,48 @@ void Courtroom::on_spectator_clicked()
void Courtroom::on_call_mod_clicked()
{
- ao_app->send_server_packet(new AOPacket("ZZ#%"));
+ if (ao_app->modcall_reason_enabled) {
+ QMessageBox errorBox;
+ QInputDialog input;
+
+ input.setWindowFlags(Qt::WindowSystemMenuHint);
+ input.setLabelText("Reason:");
+ input.setWindowTitle("Call Moderator");
+ auto code = input.exec();
+
+ if (code != QDialog::Accepted)
+ return;
+
+ QString text = input.textValue();
+ if (text.isEmpty()) {
+ errorBox.critical(nullptr, "Error", "You must provide a reason.");
+ return;
+ } else if (text.length() > 256) {
+ errorBox.critical(nullptr, "Error", "The message is too long.");
+ return;
+ }
+
+ QStringList mod_reason;
+ mod_reason.append(text);
+
+ ao_app->send_server_packet(new AOPacket("ZZ", mod_reason));
+ } else {
+ ao_app->send_server_packet(new AOPacket("ZZ#%"));
+ }
ui_ic_chat_message->setFocus();
}
+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();
@@ -2028,6 +3458,31 @@ void Courtroom::on_guard_clicked()
ui_ic_chat_message->setFocus();
}
+void Courtroom::on_showname_enable_clicked()
+{
+ ui_ic_chatlog->clear();
+ first_message_sent = false;
+
+ foreach (chatlogpiece item, ic_chatlog_history) {
+ if (ui_showname_enable->isChecked())
+ {
+ if (item.get_is_song())
+ append_ic_songchange(item.get_message(), item.get_showname());
+ else
+ append_ic_text(item.get_message(), item.get_showname());
+ }
+ else
+ {
+ if (item.get_is_song())
+ append_ic_songchange(item.get_message(), item.get_name());
+ else
+ append_ic_text(item.get_message(), item.get_name());
+ }
+ }
+
+ ui_ic_chat_message->setFocus();
+}
+
void Courtroom::on_evidence_button_clicked()
{
if (ui_evidence->isHidden())
@@ -2041,11 +3496,57 @@ void Courtroom::on_evidence_button_clicked()
}
}
+void Courtroom::on_switch_area_music_clicked()
+{
+ if (ui_area_list->isHidden())
+ {
+ ui_area_list->show();
+ ui_music_list->hide();
+ }
+ else
+ {
+ ui_area_list->hide();
+ ui_music_list->show();
+ }
+}
+
void Courtroom::ping_server()
{
ao_app->send_server_packet(new AOPacket("CH#" + QString::number(m_cid) + "#%"));
}
+void Courtroom::on_casing_clicked()
+{
+ if (ao_app->casing_alerts_enabled)
+ {
+ if (ui_casing->isChecked())
+ ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/setcase"
+ + " \"" + ao_app->get_casing_can_host_cases() + "\""
+ + " " + QString::number(ao_app->get_casing_cm_enabled())
+ + " " + QString::number(ao_app->get_casing_defence_enabled())
+ + " " + QString::number(ao_app->get_casing_prosecution_enabled())
+ + " " + QString::number(ao_app->get_casing_judge_enabled())
+ + " " + QString::number(ao_app->get_casing_juror_enabled())
+ + " " + QString::number(ao_app->get_casing_steno_enabled())
+ + "#%"));
+ else
+ ao_app->send_server_packet(new AOPacket("CT#" + ui_ooc_chat_name->text() + "#/setcase \"\" 0 0 0 0 0 0#%"));
+ }
+}
+
+void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, bool jur, bool steno)
+{
+ 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) + " "
+ + QString::number(steno)
+ + "#%"));
+}
+
Courtroom::~Courtroom()
{
delete music_player;
@@ -2053,3 +3554,17 @@ Courtroom::~Courtroom()
delete objection_player;
delete blip_player;
}
+
+#if (defined (_WIN32) || defined (_WIN64))
+void Courtroom::load_bass_opus_plugin()
+{
+ BASS_PluginLoad("bassopus.dll", 0);
+}
+#elif (defined (LINUX) || defined (__linux__))
+void Courtroom::load_bass_opus_plugin()
+{
+ BASS_PluginLoad("libbassopus.so", 0);
+}
+#else
+#error This operating system is unsupported for bass plugins.
+#endif
diff --git a/courtroom.h b/courtroom.h
index 286ae7ef..85c454a7 100644
--- a/courtroom.h
+++ b/courtroom.h
@@ -24,13 +24,8 @@
#include "file_functions.h"
#include "datatypes.h"
#include "debug_functions.h"
+#include "chatlogpiece.h"
-#include <QDebug>
-#include <QScrollBar>
-#include <QRegExp>
-#include <QBrush>
-#include <QTextCharFormat>
-#include <QFont>
#include <QMainWindow>
#include <QLineEdit>
#include <QPlainTextEdit>
@@ -43,6 +38,18 @@
#include <QSignalMapper>
#include <QMap>
#include <QTextBrowser>
+#include <QSpinBox>
+
+#include <QDebug>
+#include <QScrollBar>
+#include <QRegExp>
+#include <QBrush>
+#include <QTextCharFormat>
+#include <QFont>
+#include <QInputDialog>
+#include <QFileDialog>
+
+#include <stack>
class AOApplication;
@@ -55,6 +62,49 @@ public:
void append_char(char_type p_char){char_list.append(p_char);}
void append_evidence(evi_type p_evi){evidence_list.append(p_evi);}
void append_music(QString f_music){music_list.append(f_music);}
+ void append_area(QString f_area){area_list.append(f_area);}
+
+ void fix_last_area()
+ {
+ QString malplaced = area_list.last();
+ area_list.removeLast();
+ append_music(malplaced);
+ }
+
+ void arup_append(int players, QString status, QString cm, QString locked)
+ {
+ arup_players.append(players);
+ arup_statuses.append(status);
+ arup_cms.append(cm);
+ arup_locks.append(locked);
+ }
+
+ void arup_modify(int type, int place, QString value)
+ {
+ if (type == 0)
+ {
+ if (arup_players.size() > place)
+ arup_players[place] = value.toInt();
+ }
+ else if (type == 1)
+ {
+ if (arup_statuses.size() > place)
+ arup_statuses[place] = value;
+ }
+ else if (type == 2)
+ {
+ if (arup_cms.size() > place)
+ arup_cms[place] = value;
+ }
+ else if (type == 3)
+ {
+ if (arup_locks.size() > place)
+ arup_locks[place] = value;
+ }
+ list_areas();
+ }
+
+ void character_loading_finished();
//sets position of widgets based on theme ini files
void set_widgets();
@@ -83,12 +133,18 @@ public:
//sets the local mute list based on characters available on the server
void set_mute_list();
+ // Sets the local pair list based on the characters available on the server.
+ void set_pair_list();
+
//sets desk and bg based on pos in chatmessage
void set_scene();
//sets text color based on text color in chatmessage
void set_text_color();
+ // And gets the colour, too!
+ QColor get_text_color(QString color);
+
//takes in serverD-formatted IP list as prints a converted version to server OOC
//admittedly poorly named
void set_ip_list(QString p_list);
@@ -110,10 +166,11 @@ public:
//helper function that populates ui_music_list with the contents of music_list
void list_music();
+ void list_areas();
//these are for OOC chat
void append_ms_chatmessage(QString f_name, QString f_message);
- void append_server_chatmessage(QString p_name, QString p_message);
+ void append_server_chatmessage(QString p_name, QString p_message, QString p_colour);
//these functions handle chatmessages sequentially.
//The process itself is very convoluted and merits separate documentation
@@ -127,19 +184,25 @@ public:
// or the user isn't already scrolled to the top
void append_ic_text(QString p_text, QString p_name = "");
+ // This is essentially the same as the above, but specifically for song changes.
+ void append_ic_songchange(QString p_songname, QString p_name = "");
+
//prints who played the song to IC chat and plays said song(if found on local filesystem)
//takes in a list where the first element is the song name and the second is the char id of who played it
void handle_song(QStringList *p_contents);
void play_preanim();
+ void play_noninterrupting_preanim();
//plays the witness testimony or cross examination animation based on argument
- void handle_wtce(QString p_wtce);
+ void handle_wtce(QString p_wtce, int variant);
//sets the hp bar of defense(p_bar 1) or pro(p_bar 2)
//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, bool steno);
+
void check_connection_received();
~Courtroom();
@@ -156,18 +219,67 @@ private:
int m_viewport_width = 256;
int m_viewport_height = 192;
+ bool first_message_sent = false;
+ int maximumMessages = 0;
+
+ // This is for inline message-colouring.
+
+ enum INLINE_COLOURS {
+ INLINE_BLUE,
+ INLINE_GREEN,
+ INLINE_ORANGE,
+ INLINE_GREY
+ };
+
+ // A stack of inline colours.
+ std::stack<INLINE_COLOURS> inline_colour_stack;
+
+ bool next_character_is_not_special = false; // If true, write the
+ // next character as it is.
+
+ bool message_is_centered = false;
+
+ int current_display_speed = 3;
+ int message_display_speed[7] = {30, 40, 50, 60, 75, 100, 120};
+
+ // This is for checking if the character should start talking again
+ // when an inline blue text ends.
+ bool entire_message_is_blue = false;
+
+ // And this is the inline 'talking checker'. Counts how 'deep' we are
+ // in inline blues.
+ int inline_blue_depth = 0;
+
+ // The character ID of the character this user wants to appear alongside with.
+ int other_charid = -1;
+
+ // The offset this user has given if they want to appear alongside someone.
+ int offset_with_pair = 0;
+
QVector<char_type> char_list;
QVector<evi_type> evidence_list;
QVector<QString> music_list;
+ QVector<QString> area_list;
+
+ QVector<int> arup_players;
+ QVector<QString> arup_statuses;
+ QVector<QString> arup_cms;
+ QVector<QString> arup_locks;
QSignalMapper *char_button_mapper;
+ QVector<chatlogpiece> ic_chatlog_history;
+
+ // These map music row items and area row items to their actual IDs.
+ QVector<int> music_row_to_number;
+ QVector<int> area_row_to_number;
+
//triggers ping_server() every 60 seconds
QTimer *keepalive_timer;
//determines how fast messages tick onto screen
QTimer *chat_tick_timer;
- int chat_tick_interval = 60;
+ //int chat_tick_interval = 60;
//which tick position(character in chat message) we are at
int tick_pos = 0;
//used to determine how often blips sound
@@ -177,6 +289,12 @@ private:
bool rainbow_appended = false;
bool blank_blip = false;
+ // Used for getting the current maximum blocks allowed in the IC chatlog.
+ int log_maximum_blocks = 0;
+
+ // True, if the log should go downwards.
+ bool log_goes_downwards = false;
+
//delay before chat messages starts ticking
QTimer *text_delay_timer;
@@ -194,7 +312,7 @@ private:
//every time point in char.inis times this equals the final time
const int time_mod = 40;
- static const int chatmessage_size = 15;
+ static const int chatmessage_size = 23;
QString m_chatmessage[chatmessage_size];
bool chatmessage_is_empty = false;
@@ -215,7 +333,7 @@ private:
bool is_muted = false;
- //state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle
+ //state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = noniterrupting preanim
int anim_state = 3;
//state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = ticking done
@@ -239,6 +357,9 @@ private:
int char_rows = 9;
int max_chars_on_page = 90;
+ const int button_width = 60;
+ const int button_height = 60;
+
int current_emote_page = 0;
int current_emote = 0;
int emote_columns = 5;
@@ -274,6 +395,7 @@ private:
AOScene *ui_vp_background;
AOMovie *ui_vp_speedlines;
AOCharMovie *ui_vp_player_char;
+ AOCharMovie *ui_vp_sideplayer_char;
AOScene *ui_vp_desk;
AOScene *ui_vp_legacy_desk;
AOEvidenceDisplay *ui_vp_evidence_display;
@@ -294,7 +416,12 @@ private:
QListWidget *ui_area_list;
QListWidget *ui_music_list;
+ AOButton *ui_pair_button;
+ QListWidget *ui_pair_list;
+ QSpinBox *ui_pair_offset_spinbox;
+
QLineEdit *ui_ic_chat_message;
+ QLineEdit *ui_ic_chat_name;
QLineEdit *ui_ooc_chat_message;
QLineEdit *ui_ooc_chat_name;
@@ -325,14 +452,23 @@ private:
AOButton *ui_witness_testimony;
AOButton *ui_cross_examination;
+ AOButton *ui_guilty;
+ AOButton *ui_not_guilty;
AOButton *ui_change_character;
AOButton *ui_reload_theme;
AOButton *ui_call_mod;
+ AOButton *ui_settings;
+ AOButton *ui_announce_casing;
+ AOButton *ui_switch_area_music;
QCheckBox *ui_pre;
QCheckBox *ui_flip;
QCheckBox *ui_guard;
+ QCheckBox *ui_casing;
+
+ QCheckBox *ui_pre_non_interrupt;
+ QCheckBox *ui_showname_enable;
AOButton *ui_custom_objection;
AOButton *ui_realization;
@@ -352,6 +488,9 @@ private:
AOImage *ui_muted;
+ QSpinBox *ui_log_limit_spinbox;
+ QLabel *ui_log_limit_label;
+
AOButton *ui_evidence_button;
AOImage *ui_evidence;
AOLineEdit *ui_evidence_name;
@@ -373,6 +512,7 @@ private:
QWidget *ui_char_buttons;
QVector<AOCharButton*> ui_char_button_list;
+ QVector<AOCharButton*> ui_char_button_list_filtered;
AOImage *ui_selector;
AOButton *ui_back_to_lobby;
@@ -384,9 +524,15 @@ private:
AOButton *ui_spectator;
+ QLineEdit *ui_char_search;
+ QCheckBox *ui_char_passworded;
+ QCheckBox *ui_char_taken;
+
void construct_char_select();
void set_char_select();
void set_char_select_page();
+ void put_button_in_place(int starting, int chars_on_this_page);
+ void filter_character_list();
void construct_emotes();
void set_emote_page();
@@ -395,8 +541,6 @@ private:
void construct_evidence();
void set_evidence_page();
-
-
public slots:
void objection_done();
void preanim_done();
@@ -408,6 +552,8 @@ public slots:
void mod_called(QString p_ip);
+ void case_called(QString msg, bool def, bool pro, bool jud, bool jur, bool steno);
+
private slots:
void start_chat_ticking();
void play_sfx();
@@ -415,6 +561,7 @@ private slots:
void chat_tick();
void on_mute_list_clicked(QModelIndex p_index);
+ void on_pair_list_clicked(QModelIndex p_index);
void on_chat_return_pressed();
@@ -422,6 +569,7 @@ private slots:
void on_music_search_edited(QString p_text);
void on_music_list_double_clicked(QModelIndex p_model);
+ void on_area_list_double_clicked(QModelIndex p_model);
void select_emote(int p_id);
@@ -453,6 +601,7 @@ private slots:
void on_realization_clicked();
void on_mute_clicked();
+ void on_pair_clicked();
void on_defense_minus_clicked();
void on_defense_plus_clicked();
@@ -465,19 +614,28 @@ private slots:
void on_sfx_slider_moved(int p_value);
void on_blip_slider_moved(int p_value);
+ void on_log_limit_changed(int value);
+ void on_pair_offset_changed(int value);
+
void on_ooc_toggle_clicked();
void on_witness_testimony_clicked();
void on_cross_examination_clicked();
+ void on_not_guilty_clicked();
+ void on_guilty_clicked();
void on_change_character_clicked();
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();
void on_guard_clicked();
+ void on_showname_enable_clicked();
+
void on_evidence_button_clicked();
void on_evidence_delete_clicked();
@@ -487,12 +645,21 @@ private slots:
void on_char_select_left_clicked();
void on_char_select_right_clicked();
+ void on_char_search_changed(const QString& newtext);
+ void on_char_taken_clicked(int newstate);
+ void on_char_passworded_clicked(int newstate);
void on_spectator_clicked();
void char_clicked(int n_char);
+ void on_switch_area_music_clicked();
+
+ void on_casing_clicked();
+
void ping_server();
+
+ void load_bass_opus_plugin();
};
#endif // COURTROOM_H
diff --git a/datatypes.h b/datatypes.h
index 37d3e99a..aaa5de52 100644
--- a/datatypes.h
+++ b/datatypes.h
@@ -92,7 +92,15 @@ enum CHAT_MESSAGE
EVIDENCE_ID,
FLIP,
REALIZATION,
- TEXT_COLOR
+ TEXT_COLOR,
+ SHOWNAME,
+ OTHER_CHARID,
+ OTHER_NAME,
+ OTHER_EMOTE,
+ SELF_OFFSET,
+ OTHER_OFFSET,
+ OTHER_FLIP,
+ NONINTERRUPTING_PRE
};
enum COLOR
@@ -103,7 +111,9 @@ enum COLOR
ORANGE,
BLUE,
YELLOW,
- RAINBOW
+ RAINBOW,
+ PINK,
+ CYAN
};
#endif // DATATYPES_H
diff --git a/discord_rich_presence.h b/discord_rich_presence.h
index 348d36fa..e7ecc6ef 100644
--- a/discord_rich_presence.h
+++ b/discord_rich_presence.h
@@ -7,6 +7,11 @@
#include <string>
#include <discord-rpc.h>
+#include <cstring>
+#include <ctime>
+
+#include <QDebug>
+
namespace AttorneyOnline {
class Discord
diff --git a/emotes.cpp b/emotes.cpp
index 27a1a4fd..b6a217e6 100644
--- a/emotes.cpp
+++ b/emotes.cpp
@@ -2,8 +2,6 @@
#include "aoemotebutton.h"
-#include <QDebug>
-
void Courtroom::construct_emotes()
{
ui_emotes = new QWidget(this);
diff --git a/encryption_functions.cpp b/encryption_functions.cpp
index 56b6e34c..ffbe0cdb 100644
--- a/encryption_functions.cpp
+++ b/encryption_functions.cpp
@@ -2,12 +2,6 @@
#include "hex_functions.h"
-#include <cstddef>
-#include <stdlib.h>
-#include <sstream>
-#include <iomanip>
-#include <QVector>
-
QString fanta_encrypt(QString temp_input, unsigned int p_key)
{
//using standard stdlib types is actually easier here because of implicit char<->int conversion
diff --git a/encryption_functions.h b/encryption_functions.h
index b6ea1d70..dc67d122 100644
--- a/encryption_functions.h
+++ b/encryption_functions.h
@@ -3,6 +3,12 @@
#include <QString>
+#include <cstddef>
+#include <stdlib.h>
+#include <sstream>
+#include <iomanip>
+#include <QVector>
+
QString fanta_encrypt(QString p_input, unsigned int key);
QString fanta_decrypt(QString p_input, unsigned int key);
diff --git a/evidence.cpp b/evidence.cpp
index 45621366..4e796642 100644
--- a/evidence.cpp
+++ b/evidence.cpp
@@ -1,8 +1,5 @@
#include "courtroom.h"
-#include <QDebug>
-#include <QFileDialog>
-
void Courtroom::construct_evidence()
{
ui_evidence = new AOImage(this, ao_app);
diff --git a/file_functions.cpp b/file_functions.cpp
index fa53ab6c..f93ee15d 100644
--- a/file_functions.cpp
+++ b/file_functions.cpp
@@ -1,6 +1,3 @@
-#include <QFileInfo>
-#include <QDir>
-
#include "file_functions.h"
bool file_exists(QString file_path)
diff --git a/file_functions.h b/file_functions.h
index 223804bf..6937ed8a 100644
--- a/file_functions.h
+++ b/file_functions.h
@@ -1,6 +1,8 @@
#ifndef FILE_FUNCTIONS_H
#define FILE_FUNCTIONS_H
+#include <QFileInfo>
+#include <QDir>
#include <QString>
bool file_exists(QString file_path);
diff --git a/hex_functions.cpp b/hex_functions.cpp
index 3bb535b1..4a58d2b4 100644
--- a/hex_functions.cpp
+++ b/hex_functions.cpp
@@ -9,7 +9,7 @@ namespace omni
std::stringstream stream;
stream << std::setfill('0') << std::setw(sizeof(char)*2)
- << std::hex << input;
+ << std::hex << input;
std::string result(stream.str());
std::transform(result.begin(), result.end(), result.begin(), ::toupper);
diff --git a/include/discord_register.h b/include/discord_register.h
new file mode 100644
index 00000000..4c16b68a
--- /dev/null
+++ b/include/discord_register.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#if defined(DISCORD_DYNAMIC_LIB)
+# if defined(_WIN32)
+# if defined(DISCORD_BUILDING_SDK)
+# define DISCORD_EXPORT __declspec(dllexport)
+# else
+# define DISCORD_EXPORT __declspec(dllimport)
+# endif
+# else
+# define DISCORD_EXPORT __attribute__((visibility("default")))
+# endif
+#else
+# define DISCORD_EXPORT
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command);
+DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/include/discord_rpc.h b/include/discord_rpc.h
new file mode 100644
index 00000000..3e1441e0
--- /dev/null
+++ b/include/discord_rpc.h
@@ -0,0 +1,87 @@
+#pragma once
+#include <stdint.h>
+
+// clang-format off
+
+#if defined(DISCORD_DYNAMIC_LIB)
+# if defined(_WIN32)
+# if defined(DISCORD_BUILDING_SDK)
+# define DISCORD_EXPORT __declspec(dllexport)
+# else
+# define DISCORD_EXPORT __declspec(dllimport)
+# endif
+# else
+# define DISCORD_EXPORT __attribute__((visibility("default")))
+# endif
+#else
+# define DISCORD_EXPORT
+#endif
+
+// clang-format on
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DiscordRichPresence {
+ const char* state; /* max 128 bytes */
+ const char* details; /* max 128 bytes */
+ int64_t startTimestamp;
+ int64_t endTimestamp;
+ const char* largeImageKey; /* max 32 bytes */
+ const char* largeImageText; /* max 128 bytes */
+ const char* smallImageKey; /* max 32 bytes */
+ const char* smallImageText; /* max 128 bytes */
+ const char* partyId; /* max 128 bytes */
+ int partySize;
+ int partyMax;
+ const char* matchSecret; /* max 128 bytes */
+ const char* joinSecret; /* max 128 bytes */
+ const char* spectateSecret; /* max 128 bytes */
+ int8_t instance;
+} DiscordRichPresence;
+
+typedef struct DiscordUser {
+ const char* userId;
+ const char* username;
+ const char* discriminator;
+ const char* avatar;
+} DiscordUser;
+
+typedef struct DiscordEventHandlers {
+ void (*ready)(const DiscordUser* request);
+ void (*disconnected)(int errorCode, const char* message);
+ void (*errored)(int errorCode, const char* message);
+ void (*joinGame)(const char* joinSecret);
+ void (*spectateGame)(const char* spectateSecret);
+ void (*joinRequest)(const DiscordUser* request);
+} DiscordEventHandlers;
+
+#define DISCORD_REPLY_NO 0
+#define DISCORD_REPLY_YES 1
+#define DISCORD_REPLY_IGNORE 2
+
+DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
+ DiscordEventHandlers* handlers,
+ int autoRegister,
+ const char* optionalSteamId);
+DISCORD_EXPORT void Discord_Shutdown(void);
+
+/* checks for incoming messages, dispatches callbacks */
+DISCORD_EXPORT void Discord_RunCallbacks(void);
+
+/* If you disable the lib starting its own io thread, you'll need to call this from your own */
+#ifdef DISCORD_DISABLE_IO_THREAD
+DISCORD_EXPORT void Discord_UpdateConnection(void);
+#endif
+
+DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence);
+DISCORD_EXPORT void Discord_ClearPresence(void);
+
+DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply);
+
+DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/lobby.cpp b/lobby.cpp
index c0dbf0c3..aa1f43f2 100644
--- a/lobby.cpp
+++ b/lobby.cpp
@@ -5,9 +5,6 @@
#include "networkmanager.h"
#include "aosfxplayer.h"
-#include <QDebug>
-#include <QScrollBar>
-
Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow()
{
ao_app = p_ao_app;
@@ -52,6 +49,8 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow()
connect(ui_chatmessage, SIGNAL(returnPressed()), this, SLOT(on_chatfield_return_pressed()));
connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled()));
+ ui_connect->setEnabled(false);
+
set_widgets();
}
@@ -315,6 +314,8 @@ void Lobby::on_server_list_clicked(QModelIndex p_model)
ui_player_count->setText("Offline");
+ ui_connect->setEnabled(false);
+
ao_app->net_manager->connect_to_server(f_server);
}
@@ -361,7 +362,7 @@ void Lobby::list_favorites()
void Lobby::append_chatmessage(QString f_name, QString f_message)
{
- ui_chatbox->append_chatmessage(f_name, f_message);
+ ui_chatbox->append_chatmessage(f_name, f_message, ao_app->get_color("ooc_default_color", "courtroom_design.ini").name());
}
void Lobby::append_error(QString f_message)
@@ -375,6 +376,11 @@ void Lobby::set_player_count(int players_online, int max_players)
ui_player_count->setText(f_string);
}
+void Lobby::enable_connect_button()
+{
+ ui_connect->setEnabled(true);
+}
+
Lobby::~Lobby()
{
diff --git a/lobby.h b/lobby.h
index 2d3aee5f..19276a7d 100644
--- a/lobby.h
+++ b/lobby.h
@@ -14,6 +14,9 @@
#include <QProgressBar>
#include <QTextBrowser>
+#include <QDebug>
+#include <QScrollBar>
+
class AOApplication;
class Lobby : public QMainWindow
@@ -34,6 +37,7 @@ public:
void hide_loading_overlay(){ui_loading_background->hide();}
QString get_chatlog();
int get_selected_server();
+ void enable_connect_button();
void set_loading_value(int p_value);
diff --git a/main.cpp b/main.cpp
index 5696e2e0..cf51b0af 100644
--- a/main.cpp
+++ b/main.cpp
@@ -5,9 +5,9 @@
#include "networkmanager.h"
#include "lobby.h"
#include "courtroom.h"
-
+#include <QPluginLoader>
#include <QDebug>
-
+Q_IMPORT_PLUGIN(ApngImagePlugin);
int main(int argc, char *argv[])
{
#if QT_VERSION > QT_VERSION_CHECK(5, 6, 0)
@@ -16,10 +16,10 @@ int main(int argc, char *argv[])
// packages up to Qt 5.6, so this is conditional.
AOApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
+
AOApplication main_app(argc, argv);
main_app.construct_lobby();
main_app.net_manager->connect_to_master();
main_app.w_lobby->show();
-
return main_app.exec();
}
diff --git a/misc_functions.cpp b/misc_functions.cpp
index e767b2ef..23520551 100644
--- a/misc_functions.cpp
+++ b/misc_functions.cpp
@@ -1,8 +1,5 @@
#include "misc_functions.h"
-#include <QTime>
-#include <QCoreApplication>
-
void delay(int p_milliseconds)
{
QTime dieTime = QTime::currentTime().addMSecs(p_milliseconds);
diff --git a/misc_functions.h b/misc_functions.h
index 0de2d8ad..026c6353 100644
--- a/misc_functions.h
+++ b/misc_functions.h
@@ -1,6 +1,9 @@
#ifndef MISC_FUNCTIONS_H
#define MISC_FUNCTIONS_H
+#include <QTime>
+#include <QCoreApplication>
+
void delay(int p_milliseconds);
#endif // MISC_FUNCTIONS_H
diff --git a/networkmanager.cpp b/networkmanager.cpp
index e7246fe3..288a9007 100644
--- a/networkmanager.cpp
+++ b/networkmanager.cpp
@@ -4,8 +4,6 @@
#include "debug_functions.h"
#include "lobby.h"
-#include <cstring>
-
NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent)
{
ao_app = parent;
@@ -21,10 +19,9 @@ NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent)
QObject::connect(server_socket, SIGNAL(readyRead()), this, SLOT(handle_server_packet()));
QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, SLOT(server_disconnected()));
- QString master_config = ao_app->read_config("master");
- if (master_config != "") {
+ QString master_config = ao_app->configini->value("master", "").value<QString>();
+ if (master_config != "")
ms_nosrv_hostname = master_config;
- }
}
NetworkManager::~NetworkManager()
diff --git a/networkmanager.h b/networkmanager.h
index 99987f3b..e28abfda 100644
--- a/networkmanager.h
+++ b/networkmanager.h
@@ -21,6 +21,7 @@
#include <QDnsLookup>
#include <QTime>
#include <QTimer>
+#include <cstring>
class NetworkManager : public QObject
{
diff --git a/packet_distribution.cpp b/packet_distribution.cpp
index 83faccf1..0254064e 100644
--- a/packet_distribution.cpp
+++ b/packet_distribution.cpp
@@ -7,9 +7,6 @@
#include "hardware_functions.h"
#include "debug_functions.h"
-#include <QDebug>
-#include <QCryptographicHash>
-
void AOApplication::ms_packet_received(AOPacket *p_packet)
{
p_packet->net_decode();
@@ -150,6 +147,10 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
improved_loading_enabled = false;
desk_mod_enabled = false;
evidence_enabled = false;
+ cccc_ic_support_enabled = false;
+ arup_enabled = false;
+ casing_alerts_enabled = false;
+ modcall_reason_enabled = false;
//workaround for tsuserver4
if (f_contents.at(0) == "NOENCRYPT")
@@ -177,7 +178,12 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
goto end;
if (courtroom_constructed)
- w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1));
+ {
+ if (f_contents.size() == 3)
+ w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), f_contents.at(2));
+ else
+ w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0");
+ }
}
else if (header == "FL")
{
@@ -195,6 +201,16 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
desk_mod_enabled = true;
if (f_packet.contains("evidence",Qt::CaseInsensitive))
evidence_enabled = true;
+ if (f_packet.contains("cccc_ic_support",Qt::CaseInsensitive))
+ cccc_ic_support_enabled = true;
+ if (f_packet.contains("arup",Qt::CaseInsensitive))
+ arup_enabled = true;
+ if (f_packet.contains("casing_alerts",Qt::CaseInsensitive))
+ casing_alerts_enabled = true;
+ if (f_packet.contains("modcall_reason",Qt::CaseInsensitive))
+ modcall_reason_enabled = true;
+
+ w_lobby->enable_connect_button();
}
else if (header == "PN")
{
@@ -218,6 +234,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
loaded_chars = 0;
loaded_evidence = 0;
loaded_music = 0;
+ generated_chars = 0;
destruct_courtroom();
construct_courtroom();
@@ -233,7 +250,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
if (selected_server >= 0 && selected_server < server_list.size()) {
auto info = server_list.at(selected_server);
server_name = info.name;
- server_address = info.ip + info.port;
+ server_address = QString("%1:%2").arg(info.ip, info.port);
window_title += ": " + server_name;
}
}
@@ -264,7 +281,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256);
hash.addData(server_address.toUtf8());
- if(is_discord_enabled())
+ if (is_discord_enabled())
discord->state_server(server_name.toStdString(), hash.result().toBase64().toStdString());
}
else if (header == "CI")
@@ -272,8 +289,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
if (!courtroom_constructed)
goto end;
- int total_loading_size = char_list_size + evidence_list_size + music_list_size;
-
for (int n_element = 0 ; n_element < f_contents.size() ; n_element += 2)
{
if (f_contents.at(n_element).toInt() != loaded_chars)
@@ -300,7 +315,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
w_courtroom->append_char(f_char);
- int loading_value = (loaded_chars / static_cast<double>(total_loading_size)) * 100;
+ int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size;
+ int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast<double>(total_loading_size)) * 100);
w_lobby->set_loading_value(loading_value);
}
@@ -343,8 +359,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
w_courtroom->append_evidence(f_evi);
- int total_loading_size = char_list_size + evidence_list_size + music_list_size;
- int loading_value = ((loaded_chars + loaded_evidence) / static_cast<double>(total_loading_size)) * 100;
+ int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size;
+ int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast<double>(total_loading_size)) * 100);
w_lobby->set_loading_value(loading_value);
QString next_packet_number = QString::number(loaded_evidence);
@@ -356,7 +372,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
if (!courtroom_constructed)
goto end;
- int total_loading_size = char_list_size + evidence_list_size + music_list_size;
+ bool musics_time = false;
+ int areas = 0;
for (int n_element = 0 ; n_element < f_contents.size() ; n_element += 2)
{
@@ -372,12 +389,40 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
w_lobby->set_loading_text("Loading music:\n" + QString::number(loaded_music) + "/" + QString::number(music_list_size));
- w_courtroom->append_music(f_music);
+ if (musics_time)
+ {
+ w_courtroom->append_music(f_music);
+ }
+ else
+ {
+ if (f_music.endsWith(".wav") ||
+ f_music.endsWith(".mp3") ||
+ f_music.endsWith(".mp4") ||
+ f_music.endsWith(".ogg") ||
+ f_music.endsWith(".opus"))
+ {
+ musics_time = true;
+ areas--;
+ w_courtroom->fix_last_area();
+ w_courtroom->append_music(f_music);
+ }
+ else
+ {
+ w_courtroom->append_area(f_music);
+ areas++;
+ }
+ }
+
+ for (int area_n = 0; area_n < areas; area_n++)
+ {
+ w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown");
+ }
- int loading_value = ((loaded_chars + loaded_evidence + loaded_music) / static_cast<double>(total_loading_size)) * 100;
+ int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size;
+ int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast<double>(total_loading_size)) * 100);
w_lobby->set_loading_value(loading_value);
-
}
+
QString next_packet_number = QString::number(((loaded_music - 1) / 10) + 1);
send_server_packet(new AOPacket("AM#" + next_packet_number + "#%"));
}
@@ -400,8 +445,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
if (!courtroom_constructed)
goto end;
- int total_loading_size = char_list_size + evidence_list_size + music_list_size;
-
for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element)
{
QStringList sub_elements = f_contents.at(n_element).split("&");
@@ -420,7 +463,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
w_courtroom->append_char(f_char);
- int loading_value = ((loaded_chars + loaded_evidence + loaded_music) / static_cast<double>(total_loading_size)) * 100;
+ int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size;
+ int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast<double>(total_loading_size)) * 100);
w_lobby->set_loading_value(loading_value);
}
@@ -431,7 +475,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
if (!courtroom_constructed)
goto end;
- int total_loading_size = char_list_size + evidence_list_size + music_list_size;
+ bool musics_time = false;
+ int areas = 0;
for (int n_element = 0 ; n_element < f_contents.size() ; ++n_element)
{
@@ -441,7 +486,37 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
w_courtroom->append_music(f_contents.at(n_element));
- int loading_value = ((loaded_chars + loaded_evidence + loaded_music) / static_cast<double>(total_loading_size)) * 100;
+ if (musics_time)
+ {
+ w_courtroom->append_music(f_contents.at(n_element));
+ }
+ else
+ {
+ if (f_contents.at(n_element).endsWith(".wav") ||
+ f_contents.at(n_element).endsWith(".mp3") ||
+ f_contents.at(n_element).endsWith(".mp4") ||
+ f_contents.at(n_element).endsWith(".ogg") ||
+ f_contents.at(n_element).endsWith(".opus"))
+ {
+ musics_time = true;
+ w_courtroom->fix_last_area();
+ w_courtroom->append_music(f_contents.at(n_element));
+ areas--;
+ }
+ else
+ {
+ w_courtroom->append_area(f_contents.at(n_element));
+ areas++;
+ }
+ }
+
+ for (int area_n = 0; area_n < areas; area_n++)
+ {
+ w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown");
+ }
+
+ int total_loading_size = char_list_size * 2 + evidence_list_size + music_list_size;
+ int loading_value = int(((loaded_chars + generated_chars + loaded_music + loaded_evidence) / static_cast<double>(total_loading_size)) * 100);
w_lobby->set_loading_value(loading_value);
}
@@ -455,6 +530,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
if (lobby_constructed)
w_courtroom->append_ms_chatmessage("", w_lobby->get_chatlog());
+ w_courtroom->character_loading_finished();
w_courtroom->done_received();
courtroom_loaded = true;
@@ -493,7 +569,13 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
if (f_contents.size() < 1)
goto end;
if (courtroom_constructed)
- w_courtroom->handle_wtce(f_contents.at(0));
+ {
+ if (f_contents.size() == 1)
+ w_courtroom->handle_wtce(f_contents.at(0), 0);
+ else if (f_contents.size() == 2) {
+ w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt());
+ }
+ }
}
else if (header == "HP")
{
@@ -524,6 +606,17 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
w_courtroom->set_evidence_list(f_evi_list);
}
}
+ else if (header == "ARUP")
+ {
+ if (courtroom_constructed)
+ {
+ int arup_type = f_contents.at(0).toInt();
+ for (int n_element = 1 ; n_element < f_contents.size() ; n_element++)
+ {
+ w_courtroom->arup_modify(arup_type, n_element - 1, f_contents.at(n_element));
+ }
+ }
+ }
else if (header == "IL")
{
if (courtroom_constructed && f_contents.size() > 0)
@@ -541,24 +634,22 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
}
else if (header == "KK")
{
- if (courtroom_constructed && f_contents.size() > 0)
+ if (courtroom_constructed && f_contents.size() >= 1)
{
- int f_cid = w_courtroom->get_cid();
- int remote_cid = f_contents.at(0).toInt();
-
- if (f_cid != remote_cid && remote_cid != -1)
- goto end;
-
- call_notice("You have been kicked.");
+ call_notice("You have been kicked from the server.\nReason: " + f_contents.at(0));
construct_lobby();
destruct_courtroom();
}
-
}
else if (header == "KB")
{
- if (courtroom_constructed && f_contents.size() > 0)
- w_courtroom->set_ban(f_contents.at(0).toInt());
+ if (courtroom_constructed && f_contents.size() >= 1)
+ {
+ call_notice("You have been banned from the server.\nReason: " + f_contents.at(0));
+ construct_lobby();
+ destruct_courtroom();
+ }
+
}
else if (header == "BD")
{
@@ -569,6 +660,11 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
if (courtroom_constructed && f_contents.size() > 0)
w_courtroom->mod_called(f_contents.at(0));
}
+ else if (header == "CASEA")
+ {
+ if (courtroom_constructed && f_contents.size() > 6)
+ w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", f_contents.at(2) == "1", f_contents.at(3) == "1", f_contents.at(4) == "1", f_contents.at(5) == "1");
+ }
end:
diff --git a/path_functions.cpp b/path_functions.cpp
index afa1e11e..24041e2d 100644
--- a/path_functions.cpp
+++ b/path_functions.cpp
@@ -1,8 +1,8 @@
#include "aoapplication.h"
#include "courtroom.h"
#include "file_functions.h"
+
#include <QDir>
-#include <QDebug>
#include <QStandardPaths>
#include <QRegExp>
diff --git a/text_file_functions.cpp b/text_file_functions.cpp
index f63e720c..69c5fab7 100644
--- a/text_file_functions.cpp
+++ b/text_file_functions.cpp
@@ -1,98 +1,72 @@
-#include "aoapplication.h"
+#include "text_file_functions.h"
-#include "file_functions.h"
-
-#include <QTextStream>
-#include <QStringList>
-#include <QVector>
-#include <QDebug>
-#include <QColor>
-
-QString AOApplication::read_config(QString searchline)
+QString AOApplication::read_theme()
{
- QString return_value = "";
-
- QFile config_file(get_base_path() + "config.ini");
- if (!config_file.open(QIODevice::ReadOnly))
- return return_value;
-
- QTextStream in(&config_file);
-
- while(!in.atEnd())
- {
- QString f_line = in.readLine().trimmed();
-
- if (!f_line.startsWith(searchline))
- continue;
-
- QStringList line_elements = f_line.split("=");
-
- if (line_elements.at(0).trimmed() != searchline)
- continue;
-
- if (line_elements.size() < 2)
- continue;
-
- return_value = line_elements.at(1).trimmed();
- break;
- }
-
- config_file.close();
-
- return return_value;
+ QString result = configini->value("theme", "default").value<QString>();
+ return result;
}
-QString AOApplication::read_theme()
+int AOApplication::read_blip_rate()
{
- QString result = read_config("theme");
-
- if (result == "")
- return "default";
- else
- return result;
+ int result = configini->value("blip_rate", 1).toInt();
+ return result;
}
QString AOApplication::get_ooc_name()
{
- return read_config("ooc_name");
+ QString result = configini->value("ooc_name").value<QString>();
+ return result;
}
-int AOApplication::read_blip_rate()
+int AOApplication::get_default_music()
{
- QString result = read_config("blip_rate");
+ int result = configini->value("default_music", 50).toInt();
+ return result;
+}
- //note: the empty string converted to int will return 0
- if (result.toInt() <= 0)
- return 1;
- else
- return result.toInt();
+int AOApplication::get_default_sfx()
+{
+ int result = configini->value("default_sfx", 50).toInt();
+ return result;
}
-int AOApplication::get_default_music()
+int AOApplication::get_default_blip()
{
- QString f_result = read_config("default_music");
+ int result = configini->value("default_blip", 50).toInt();
+ return result;
+}
- if (f_result == "")
- return 50;
- else return f_result.toInt();
+int AOApplication::get_max_log_size()
+{
+ int result = configini->value("log_maximum", 200).toInt();
+ return result;
}
-int AOApplication::get_default_sfx()
+bool AOApplication::get_log_goes_downwards()
{
- QString f_result = read_config("default_sfx");
+ QString result = configini->value("log_goes_downwards", "false").value<QString>();
+ return result.startsWith("true");
+}
- if (f_result == "")
- return 50;
- else return f_result.toInt();
+bool AOApplication::get_showname_enabled_by_default()
+{
+ QString result = configini->value("show_custom_shownames", "false").value<QString>();
+ return result.startsWith("true");
}
-int AOApplication::get_default_blip()
+QString AOApplication::get_default_username()
{
- QString f_result = read_config("default_blip");
+ QString result = configini->value("default_username", "").value<QString>();
+ if (result.isEmpty())
+ return get_ooc_name();
+ else
+ return result;
+}
- if (f_result == "")
- return 50;
- else return f_result.toInt();
+QString AOApplication::get_audio_output_device()
+{
+ QString result = configini->value("default_audio_device", "default").value<QString>();
+ return result;
}
QStringList AOApplication::get_call_words()
@@ -174,40 +148,13 @@ QVector<server_type> AOApplication::read_serverlist_txt()
QString AOApplication::read_design_ini(QString p_identifier, QString p_design_path)
{
- QFile design_ini;
-
- design_ini.setFileName(p_design_path);
-
- if (!design_ini.open(QIODevice::ReadOnly))
- {
- return "";
+ QSettings settings(p_design_path, QSettings::IniFormat);
+ QVariant value = settings.value(p_identifier);
+ if (value.type() == QVariant::StringList) {
+ return value.toStringList().join(",");
+ } else {
+ return value.toString();
}
- QTextStream in(&design_ini);
-
- QString result = "";
-
- while (!in.atEnd())
- {
- QString f_line = in.readLine().trimmed();
-
- if (!f_line.startsWith(p_identifier))
- continue;
-
- QStringList line_elements = f_line.split("=");
-
- if (line_elements.at(0).trimmed() != p_identifier)
- continue;
-
- if (line_elements.size() < 2)
- continue;
-
- result = line_elements.at(1).trimmed();
- break;
- }
-
- design_ini.close();
-
- return result;
}
QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file)
@@ -319,6 +266,34 @@ QColor AOApplication::get_color(QString p_identifier, QString p_file)
return return_color;
}
+QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat)
+{
+ p_identifier = p_identifier.prepend("c");
+ QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini";
+ QString default_path = get_base_path() + "misc/default/config.ini";
+ QString f_result = read_design_ini(p_identifier, design_ini_path);
+
+ QColor return_color(255, 255, 255);
+ if (f_result == "")
+ {
+ f_result = read_design_ini(p_identifier, default_path);
+
+ if (f_result == "")
+ return return_color;
+ }
+
+ QStringList color_list = f_result.split(",");
+
+ if (color_list.size() < 3)
+ return return_color;
+
+ return_color.setRed(color_list.at(0).toInt());
+ return_color.setGreen(color_list.at(1).toInt());
+ return_color.setBlue(color_list.at(2).toInt());
+
+ return return_color;
+}
+
QString AOApplication::get_sfx(QString p_identifier)
{
QString design_ini_path = get_theme_path("courtroom_sounds.ini");
@@ -340,61 +315,46 @@ QString AOApplication::get_sfx(QString p_identifier)
return return_sfx;
}
-//returns whatever is to the right of "search_line =" within target_tag and terminator_tag, trimmed
-//returns the empty string if the search line couldnt be found
-QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QString target_tag, QString terminator_tag)
+QString AOApplication::get_sfx_suffix(QString sound_to_check)
{
- QString char_ini_path = get_character_path(p_char, "char.ini");
-
- QFile char_ini;
-
- char_ini.setFileName(char_ini_path);
-
- if (!char_ini.open(QIODevice::ReadOnly))
- return "";
-
- QTextStream in(&char_ini);
-
- bool tag_found = false;
-
- while(!in.atEnd())
- {
- QString line = in.readLine();
-
- if (QString::compare(line, terminator_tag, Qt::CaseInsensitive) == 0)
- break;
-
- if (line.startsWith(target_tag, Qt::CaseInsensitive))
+ QString mp3_check = get_sounds_path(sound_to_check + ".mp3");
+ QString opus_check = get_sounds_path(sound_to_check + ".opus");
+ if (file_exists(opus_check))
{
- tag_found = true;
- continue;
+ return sound_to_check + ".opus";
}
+ else if (file_exists(mp3_check))
+ {
+ return sound_to_check + ".mp3";
+ }
+ return sound_to_check + ".wav";
+}
- if (!line.startsWith(p_search_line, Qt::CaseInsensitive))
- continue;
-
- QStringList line_elements = line.split("=");
-
- if (QString::compare(line_elements.at(0).trimmed(), p_search_line, Qt::CaseInsensitive) != 0)
- continue;
-
- if (line_elements.size() < 2)
- continue;
-
- if (tag_found)
+QString AOApplication::get_image_suffix(QString path_to_check)
+{
+ QString apng_check = get_sounds_path(path_to_check + ".apng");
+ if (file_exists(apng_check))
{
- char_ini.close();
- return line_elements.at(1).trimmed();
+ return path_to_check + ".apng";
}
- }
+ return path_to_check + ".gif";
+}
+
- char_ini.close();
- return "";
+//returns whatever is to the right of "search_line =" within target_tag and terminator_tag, trimmed
+//returns the empty string if the search line couldnt be found
+QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QString target_tag)
+{
+ QSettings settings(get_character_path(p_char) + "char.ini", QSettings::IniFormat);
+ settings.beginGroup(target_tag);
+ QString value = settings.value(p_search_line).toString();
+ settings.endGroup();
+ return value;
}
QString AOApplication::get_char_name(QString p_char)
{
- QString f_result = read_char_ini(p_char, "name", "[Options]", "[Time]");
+ QString f_result = read_char_ini(p_char, "name", "Options");
if (f_result == "")
return p_char;
@@ -403,8 +363,11 @@ QString AOApplication::get_char_name(QString p_char)
QString AOApplication::get_showname(QString p_char)
{
- QString f_result = read_char_ini(p_char, "showname", "[Options]", "[Time]");
+ QString f_result = read_char_ini(p_char, "showname", "Options");
+ QString f_needed = read_char_ini(p_char, "needs_showname", "Options");
+ if (f_needed.startsWith("false"))
+ return "";
if (f_result == "")
return p_char;
else return f_result;
@@ -412,7 +375,7 @@ QString AOApplication::get_showname(QString p_char)
QString AOApplication::get_char_side(QString p_char)
{
- QString f_result = read_char_ini(p_char, "side", "[Options]", "[Time]");
+ QString f_result = read_char_ini(p_char, "side", "Options");
if (f_result == "")
return "wit";
@@ -421,7 +384,7 @@ QString AOApplication::get_char_side(QString p_char)
QString AOApplication::get_gender(QString p_char)
{
- QString f_result = read_char_ini(p_char, "gender", "[Options]", "[Time]");
+ QString f_result = read_char_ini(p_char, "gender", "Options");
if (f_result == "")
return "male";
@@ -430,7 +393,7 @@ QString AOApplication::get_gender(QString p_char)
QString AOApplication::get_chat(QString p_char)
{
- QString f_result = read_char_ini(p_char, "chat", "[Options]", "[Time]");
+ QString f_result = read_char_ini(p_char, "chat", "Options");
//handling the correct order of chat is a bit complicated, we let the caller do it
return f_result;
@@ -438,14 +401,14 @@ QString AOApplication::get_chat(QString p_char)
QString AOApplication::get_char_shouts(QString p_char)
{
- QString f_result = read_char_ini(p_char, "shouts", "[Options]", "[Time]");
+ QString f_result = read_char_ini(p_char, "shouts", "Options");
return f_result;
}
int AOApplication::get_preanim_duration(QString p_char, QString p_emote)
{
- QString f_result = read_char_ini(p_char, p_emote, "[Time]", "[Emotions]");
+ QString f_result = read_char_ini(p_char, p_emote, "Time");
if (f_result == "")
return -1;
@@ -454,7 +417,7 @@ int AOApplication::get_preanim_duration(QString p_char, QString p_emote)
int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote)
{
- QString f_result = read_char_ini(p_char, "%" + p_emote, "[Time]", "[Emotions]");
+ QString f_result = read_char_ini(p_char, "%" + p_emote, "Time");
if (f_result == "")
return -1;
@@ -463,7 +426,7 @@ int AOApplication::get_ao2_preanim_duration(QString p_char, QString p_emote)
int AOApplication::get_emote_number(QString p_char)
{
- QString f_result = read_char_ini(p_char, "number", "[Emotions]", "[SoundN]");
+ QString f_result = read_char_ini(p_char, "number", "Emotions");
if (f_result == "")
return 0;
@@ -472,7 +435,7 @@ int AOApplication::get_emote_number(QString p_char)
QString AOApplication::get_emote_comment(QString p_char, int p_emote)
{
- QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "[Emotions]", "[SoundN]");
+ QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions");
QStringList result_contents = f_result.split("#");
@@ -486,7 +449,7 @@ QString AOApplication::get_emote_comment(QString p_char, int p_emote)
QString AOApplication::get_pre_emote(QString p_char, int p_emote)
{
- QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "[Emotions]", "[SoundN]");
+ QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions");
QStringList result_contents = f_result.split("#");
@@ -500,7 +463,7 @@ QString AOApplication::get_pre_emote(QString p_char, int p_emote)
QString AOApplication::get_emote(QString p_char, int p_emote)
{
- QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "[Emotions]", "[SoundN]");
+ QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions");
QStringList result_contents = f_result.split("#");
@@ -514,7 +477,7 @@ QString AOApplication::get_emote(QString p_char, int p_emote)
int AOApplication::get_emote_mod(QString p_char, int p_emote)
{
- QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "[Emotions]", "[SoundN]");
+ QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions");
QStringList result_contents = f_result.split("#");
@@ -528,7 +491,7 @@ int AOApplication::get_emote_mod(QString p_char, int p_emote)
int AOApplication::get_desk_mod(QString p_char, int p_emote)
{
- QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "[Emotions]", "[SoundN]");
+ QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions");
QStringList result_contents = f_result.split("#");
@@ -544,7 +507,7 @@ int AOApplication::get_desk_mod(QString p_char, int p_emote)
QString AOApplication::get_sfx_name(QString p_char, int p_emote)
{
- QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "[SoundN]", "[SoundT]");
+ QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundN");
if (f_result == "")
return "1";
@@ -553,7 +516,7 @@ QString AOApplication::get_sfx_name(QString p_char, int p_emote)
int AOApplication::get_sfx_delay(QString p_char, int p_emote)
{
- QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "[SoundT]", "[TextDelay]");
+ QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundT");
if (f_result == "")
return 1;
@@ -562,28 +525,78 @@ int AOApplication::get_sfx_delay(QString p_char, int p_emote)
int AOApplication::get_text_delay(QString p_char, QString p_emote)
{
- QString f_result = read_char_ini(p_char, p_emote, "[TextDelay]", "END_OF_FILE");
+ QString f_result = read_char_ini(p_char, p_emote, "TextDelay");
if (f_result == "")
return -1;
else return f_result.toInt();
}
-bool AOApplication::get_blank_blip()
+QString AOApplication::get_custom_realization(QString p_char)
{
- QString f_result = read_config("blank_blip");
+ QString f_result = read_char_ini(p_char, "realization", "Options");
- return f_result.startsWith("true");
+ if (f_result == "")
+ return get_sfx("realization");
+ else return f_result;
+}
+
+bool AOApplication::get_blank_blip()
+{
+ QString result = configini->value("blank_blip", "false").value<QString>();
+ return result.startsWith("true");
}
bool AOApplication::is_discord_enabled()
{
- QString f_result = read_config("discord");
- return !f_result.startsWith("false");
+ QString result = configini->value("discord", "true").value<QString>();
+ return result.startsWith("true");
+}
+
+bool AOApplication::get_casing_enabled()
+{
+ QString result = configini->value("casing_enabled", "false").value<QString>();
+ return result.startsWith("true");
}
-bool AOApplication::ic_scroll_down_enabled()
+bool AOApplication::get_casing_defence_enabled()
{
- QString f_result = read_config("ic_scroll_down");
- return f_result.startsWith("true");
+ QString result = configini->value("casing_defence_enabled", "false").value<QString>();
+ return result.startsWith("true");
+}
+
+bool AOApplication::get_casing_prosecution_enabled()
+{
+ QString result = configini->value("casing_prosecution_enabled", "false").value<QString>();
+ return result.startsWith("true");
+}
+
+bool AOApplication::get_casing_judge_enabled()
+{
+ QString result = configini->value("casing_judge_enabled", "false").value<QString>();
+ return result.startsWith("true");
+}
+
+bool AOApplication::get_casing_juror_enabled()
+{
+ QString result = configini->value("casing_juror_enabled", "false").value<QString>();
+ return result.startsWith("true");
+}
+
+bool AOApplication::get_casing_steno_enabled()
+{
+ QString result = configini->value("casing_steno_enabled", "false").value<QString>();
+ return result.startsWith("true");
+}
+
+bool AOApplication::get_casing_cm_enabled()
+{
+ QString result = configini->value("casing_cm_enabled", "false").value<QString>();
+ return result.startsWith("true");
+}
+
+QString AOApplication::get_casing_can_host_cases()
+{
+ QString result = configini->value("casing_can_host_cases", "Turnabout Check Your Settings").value<QString>();
+ return result;
}
diff --git a/text_file_functions.h b/text_file_functions.h
new file mode 100644
index 00000000..119f38e2
--- /dev/null
+++ b/text_file_functions.h
@@ -0,0 +1,13 @@
+#ifndef TEXT_FILE_FUNCTIONS_H
+#define TEXT_FILE_FUNCTIONS_H
+
+#include "aoapplication.h"
+#include "file_functions.h"
+#include <QTextStream>
+#include <QStringList>
+#include <QVector>
+#include <QDebug>
+#include <QColor>
+#include <QSettings>
+
+#endif // TEXT_FILE_FUNCTIONS_H