Merge pull request #246 from AttorneyOnline/2.8

Merges 2.8.5, which is a patch release for 2.8 with no substantially new features.

This commit is release-ready.
This commit is contained in:
oldmud0 2020-08-21 12:42:45 -05:00 committed by GitHub
commit 2c6a690d47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1701 additions and 1629 deletions

1
.gitignore vendored
View File

@ -22,6 +22,7 @@ base/characters
base/sounds
base/callwords.ini
base/config.ini
base/serverlist.txt
.qmake.stash

View File

@ -5,8 +5,6 @@ stages:
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- lib/
variables:
DEBIAN_FRONTEND: noninteractive
@ -15,7 +13,7 @@ before_script:
- echo Current working directory is $(pwd)
build linux x86_64:
image: ubuntu
image: ubuntu:18.04
stage: build
tags:
- docker
@ -34,15 +32,15 @@ build linux x86_64:
- clang --version
# Extract BASS
#- mkdir bass
#- cd bass
#- curl http://www.un4seen.com/files/bass24-linux.zip -o bass.zip
#- unzip bass.zip
#- cp x64/libbass.so ../lib
#- curl http://www.un4seen.com/files/bassopus24-linux.zip -o bassopus.zip
#- unzip bassopus.zip
#- cp x64/libbassopus.so ../lib
#- cd ..
- mkdir bass
- cd bass
- curl http://www.un4seen.com/files/bass24-linux.zip -o bass.zip
- unzip bass.zip
- cp x64/libbass.so ../lib
- curl http://www.un4seen.com/files/bassopus24-linux.zip -o bassopus.zip
- unzip bassopus.zip
- cp x64/libbassopus.so ../lib
- cd ..
# Extract Discord RPC
- mkdir discord-rpc
@ -53,21 +51,32 @@ build linux x86_64:
- cd ..
# Extract QtApng
- mkdir qtapng
- cd qtapng
- curl -L https://github.com/Skycoder42/QtApng/releases/download/1.1.0-5/build_gcc_64_5.12.0.tar.xz -o apng.tar.xz
- tar -xvf apng.tar.xz
- cp gcc_64/plugins/imageformats/libqapng.so ../lib
#- mkdir qtapng
#- cd qtapng
#- curl -L https://github.com/Skycoder42/QtApng/releases/download/1.1.0-5/build_gcc_64_5.12.0.tar.xz -o apng.tar.xz
#- tar -xvf apng.tar.xz
#- cp gcc_64/plugins/imageformats/libqapng.so ../lib
#- cd ..
# Build QtApng
- git clone https://github.com/Skycoder42/QtApng
- cd QtApng
- qmake -spec linux-clang
# Don't make examples - they're not compatible with Qt 5.9
- make -j4 sub-src
#- make sub-src-install_subtargets
- cp plugins/imageformats/libqapng.so ../lib
- cd ..
# Build
- qmake -spec linux-clang "DEFINES += DISCORD QTAUDIO"
- qmake -spec linux-clang "DEFINES += DISCORD"
- make -j4
# Post-processing
- upx --lzma -9 --force bin/Attorney_Online
artifacts:
paths:
- lib/
- bin/
build windows i686:
@ -109,19 +118,21 @@ build windows i686:
- ls lib
# Build
- /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake "DEFINES += DISCORD BASSAUDIO"
- /opt/mxe/usr/${TARGET_SPEC}/qt5/bin/qmake "DEFINES += DISCORD"
- make -j4
# Post-processing
- upx --lzma -9 --force bin/Attorney_Online.exe
artifacts:
paths:
- lib/
- bin/
# Base folder
.deploy_base: &deploy_base |
mkdir base
cp -a ../base/ base/
rm -rf base/themes/_Unadapted/
rm base/themes/.gitattributes base/themes/.git
# Miscellaneous files
.deploy_misc: &deploy_misc |

View File

@ -3,7 +3,7 @@ QT += core gui widgets network
TARGET = Attorney_Online
TEMPLATE = app
VERSION = 2.8.4.0
VERSION = 2.8.5.0
INCLUDEPATH += $$PWD/include
DESTDIR = $$PWD/bin
@ -22,35 +22,15 @@ contains(DEFINES, DISCORD) {
LIBS += -ldiscord-rpc
}
# Uncomment to enable the BASS audio engine
# (Recommended for Windows)
# DEFINES += BASSAUDIO
contains(DEFINES, BASSAUDIO) {
LIBS += -lbass
LIBS += -lbassopus
}
# Uncomment to enable the Qt audio engine
# (Recommended for non-Windows platforms)
# DEFINES += QTAUDIO
contains(DEFINES, QTAUDIO) {
QT += multimedia
}
AUDIO_DEFINES = $$find(DEFINES, BASSAUDIO) $$find(DEFINES, QTAUDIO)
count(AUDIO_DEFINES, 0) {
warning("No audio system selected. Your build will not have audio.")
}
count(AUDIO_DEFINES, 2) {
error("More than one audio system selected.")
}
# As of 2.8.5, BASS and BASSOPUS are required for all platforms. Qt Multimedia
# is no longer an option due to outdated code and lack of versatility.
# Download at un4seen.com and place the DLLs in the "lib" and "bin" folders.
DEFINES += BASSAUDIO
LIBS += -lbass
LIBS += -lbassopus
macx:LIBS += -framework CoreFoundation -framework Foundation -framework CoreServices
CONFIG += c++14
RESOURCES += resources.qrc

@ -1 +1 @@
Subproject commit 8de30fc0fa0e1492a29dad0e839764ca44168cb3
Subproject commit 15b0cc4aa1241a9b740fb1ce8a61c7f699a80de5

View File

@ -5,6 +5,9 @@
#include "datatypes.h"
#include "discord_rich_presence.h"
#include "bass.h"
#include "bassopus.h"
#include <QApplication>
#include <QFile>
#include <QSettings>
@ -23,9 +26,6 @@
#include <QScreen>
#include <QStringList>
#include <QTextStream>
#ifdef QTAUDIO
#include <QAudioDeviceInfo>
#endif
class NetworkManager;
class Lobby;
@ -202,7 +202,8 @@ public:
// Returns the value of whether custom chatboxes should be a thing.
// from the config.ini.
// I am increasingly maddened by the lack of dynamic auto-generation system for settings.
// I am increasingly maddened by the lack of dynamic auto-generation system
// for settings.
bool is_customchat_enabled();
// Returns the value of the maximum amount of lines the IC chatlog
@ -213,14 +214,20 @@ public:
// or downwards (vanilla behaviour).
bool get_log_goes_downwards();
// Returns whether the log should separate name from text via newline or :
bool get_log_newline();
// Get spacing between IC log entries.
int get_log_margin();
// Returns whether the log should have a timestamp.
bool get_log_timestamp();
// 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();
#ifdef QTAUDIO
QAudioDeviceInfo QtAudioDevice;
#endif
// Returns whether the user would like to have custom shownames on by default.
bool get_showname_enabled_by_default();
@ -433,10 +440,16 @@ public:
// The file name of the log file in base/logs.
QString log_filename;
void initBASS();
static void load_bass_opus_plugin();
static void CALLBACK BASSreset(HSTREAM handle, DWORD channel, DWORD data,
void *user);
static void doBASSreset();
private:
const int RELEASE = 2;
const int MAJOR_VERSION = 8;
const int MINOR_VERSION = 4;
const int MINOR_VERSION = 5;
QString current_theme = "default";

View File

@ -1,12 +1,8 @@
#ifndef AOBLIPPLAYER_H
#define AOBLIPPLAYER_H
#if defined(BASSAUDIO)
#include "bass.h"
#include "bassopus.h"
#elif defined(QTAUDIO)
#include <QSoundEffect>
#endif
#include "aoapplication.h"
@ -35,11 +31,7 @@ private:
void set_volume_internal(qreal p_volume);
#if defined(BASSAUDIO)
HSTREAM m_stream_list[5];
#elif defined(QTAUDIO)
QSoundEffect m_blips;
#endif
};
#endif // AOBLIPPLAYER_H

View File

@ -2,12 +2,8 @@
#define AOMUSICPLAYER_H
#include "file_functions.h"
#if defined(BASSAUDIO)
#include "bass.h"
#include "bassopus.h"
#elif defined(QTAUDIO)
#include <QMediaPlayer>
#endif
#include "aoapplication.h"
@ -44,12 +40,8 @@ private:
// Channel 1 = ambience
// Channel 2 = extra
// Channel 3 = extra
#if defined(BASSAUDIO)
HSTREAM m_stream_list[4];
HSYNC loop_sync[4];
#elif defined(QTAUDIO)
QMediaPlayer m_stream_list[4];
#endif
};
#endif // AOMUSICPLAYER_H

View File

@ -46,6 +46,12 @@ private:
QCheckBox *ui_downwards_cb;
QLabel *ui_length_lbl;
QSpinBox *ui_length_spinbox;
QLabel *ui_log_newline_lbl;
QCheckBox *ui_log_newline_cb;
QLabel *ui_log_margin_lbl;
QSpinBox *ui_log_margin_spinbox;
QLabel *ui_log_timestamp_lbl;
QCheckBox *ui_log_timestamp_cb;
QFrame *ui_log_names_divider;
QLineEdit *ui_username_textbox;
QLabel *ui_username_lbl;

View File

@ -1,12 +1,8 @@
#ifndef AOSFXPLAYER_H
#define AOSFXPLAYER_H
#if defined(BASSAUDIO)
#include "bass.h"
#include "bassopus.h"
#elif defined(QTAUDIO)
#include <QSoundEffect>
#endif
#include "aoapplication.h"
@ -37,11 +33,7 @@ private:
const int m_channelmax = 5;
#if defined(BASSAUDIO)
HSTREAM m_stream_list[5];
#elif defined(QTAUDIO)
QSoundEffect m_stream_list[5];
#endif
};
#endif // AOSFXPLAYER_H

View File

@ -10,14 +10,14 @@ class chatlogpiece {
public:
chatlogpiece();
chatlogpiece(QString p_name, QString p_showname, QString p_message,
bool p_song,int color);
QString p_action,int color);
chatlogpiece(QString p_name, QString p_showname, QString p_message,
bool p_song, int color, QDateTime p_datetime);
QString p_action, int color, QDateTime p_datetime);
QString get_name();
QString get_showname();
QString get_message();
bool is_song();
QString get_action();
QDateTime get_datetime();
QString get_datetime_as_string();
int get_chat_color();
@ -27,9 +27,9 @@ private:
QString name;
QString showname;
QString message;
QString action;
QDateTime datetime;
int color;
bool p_is_song;
};
#endif // CHATLOGPIECE_H

View File

@ -109,7 +109,6 @@ public:
if (arup_locks.size() > place)
arup_locks[place] = value;
}
list_areas();
}
void character_loading_finished();
@ -118,7 +117,9 @@ public:
void set_widgets();
// sets font size based on theme ini files
void set_font(QWidget *widget, QString class_name, QString p_identifier, QString p_char="", QString font_name="", int f_pointsize=0);
void set_font(QWidget *widget, QString class_name, QString p_identifier,
QString p_char = "", QString font_name = "",
int f_pointsize = 0);
// Get the properly constructed font
QFont get_qfont(QString font_name, int f_pointsize, bool antialias = true);
@ -128,7 +129,7 @@ public:
QColor f_color = Qt::black, bool bold = false);
// helper function that calls above function on the relevant widgets
void set_fonts(QString p_char="");
void set_fonts(QString p_char = "");
// sets dropdown menu stylesheet
void set_dropdown(QWidget *widget);
@ -217,11 +218,14 @@ public:
QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1,
int default_color = 0);
void log_ic_text(QString p_name, QString p_showname, QString p_message, QString p_action="", int p_color=0);
// adds text to the IC chatlog. p_name first as bold then p_text then a newlin
// this function keeps the chatlog scrolled to the top unless there's text
// selected
// or the user isn't already scrolled to the top
void append_ic_text(QString p_text, QString p_name = "", QString action = "", int color = 0);
void append_ic_text(QString p_text, QString p_name = "", QString action = "",
int color = 0);
// 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
@ -260,7 +264,6 @@ private:
int m_viewport_width = 256;
int m_viewport_height = 192;
bool first_message_sent = false;
int maximumMessages = 0;
QParallelAnimationGroup *screenshake_animation_group =
@ -313,14 +316,23 @@ private:
bool rainbow_appended = false;
bool blank_blip = false;
// Whether or not is this message additive to the previous one
bool is_additive = 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;
bool log_goes_downwards = true;
// True, if log should display colors.
bool log_colors = true;
// True, if the log should display the message like name<br>text instead of name: text
bool log_newline = false;
// Margin in pixels between log entries for the IC log.
int log_margin = 0;
// True, if the log should have a timestamp.
bool log_timestamp = false;
// delay before chat messages starts ticking
QTimer *text_delay_timer;
@ -349,9 +361,10 @@ private:
// amount by which we multiply the delay when we parse punctuation chars
const int punctuation_modifier = 3;
static const int chatmessage_size = 30;
QString m_chatmessage[chatmessage_size];
bool chatmessage_is_empty = false;
// Minumum and maximum number of parameters in the MS packet
static const int MS_MINIMUM = 15;
static const int MS_MAXIMUM = 30;
QString m_chatmessage[MS_MAXIMUM];
QString previous_ic_message = "";
QString additive_previous = "";
@ -458,6 +471,14 @@ private:
QString current_background = "default";
QString current_side = "";
QBrush free_brush;
QBrush lfp_brush;
QBrush casing_brush;
QBrush recess_brush;
QBrush rp_brush;
QBrush gaming_brush;
QBrush locked_brush;
AOMusicPlayer *music_player;
AOSfxPlayer *sfx_player;
AOSfxPlayer *objection_player;
@ -639,6 +660,10 @@ private:
void refresh_evidence();
void set_evidence_page();
void reset_ic();
void reset_ui();
void regenerate_ic_chatlog();
public slots:
void objection_done();
void preanim_done();
@ -803,8 +828,6 @@ private slots:
void on_casing_clicked();
void ping_server();
void load_bass_opus_plugin();
};
#endif // COURTROOM_H

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -101,9 +101,7 @@ const specialActions = changesFile ?
// higher-level directories will succeed.
.concat(Array.from(dirsDeleted.values())
.sort((a, b) => b.split("/").length - a.split("/").length)
.map(dir => {
return { action: "deleteDir", target: dir };
}))
.map(dir => ({ action: "deleteDir", target: dir })))
: [];
const urlBase = "https://s3.wasabisys.com/ao-downloads/";

View File

@ -3,6 +3,11 @@ FROM oldmud0/mxe-qt:5.13.0-win32-static-posix
ENV TARGET_SPEC i686-w64-mingw32.static.posix
# Build libarchive statically
WORKDIR /opt/mxe
RUN make -j4 MXE_TARGETS=${TARGET_SPEC} libarchive bzip2 xz lz4 zstd nettle expat libxml2
WORKDIR /
# Build Discord RPC statically
RUN git clone https://github.com/discordapp/discord-rpc
WORKDIR discord-rpc/build

View File

@ -177,3 +177,64 @@ void AOApplication::call_announce_menu(Courtroom *court)
AOCaseAnnouncerDialog announcer(nullptr, this, court);
announcer.exec();
}
// Callback for when BASS device is lost
void CALLBACK AOApplication::BASSreset(HSTREAM handle, DWORD channel,
DWORD data, void *user)
{
doBASSreset();
}
void AOApplication::doBASSreset()
{
BASS_Free();
BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr);
load_bass_opus_plugin();
}
void AOApplication::initBASS()
{
BASS_Free();
// Change the default audio output device to be the one the user has given
// in his config.ini file for now.
unsigned int a = 0;
BASS_DEVICEINFO info;
if (get_audio_output_device() == "default") {
BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr);
load_bass_opus_plugin();
}
else {
for (a = 0; BASS_GetDeviceInfo(a, &info); a++) {
if (get_audio_output_device() == info.name) {
BASS_SetDevice(a);
BASS_Init(static_cast<int>(a), 48000, BASS_DEVICE_LATENCY, nullptr,
nullptr);
load_bass_opus_plugin();
qDebug() << info.name << "was set as the default audio output device.";
return;
}
}
BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr);
load_bass_opus_plugin();
}
}
#if (defined(_WIN32) || defined(_WIN64))
void AOApplication::load_bass_opus_plugin()
{
BASS_PluginLoad("bassopus.dll", 0);
}
#elif (defined(LINUX) || defined(__linux__))
void AOApplication::load_bass_opus_plugin()
{
BASS_PluginLoad("libbassopus.so", 0);
}
#elif defined __APPLE__
void AOApplication::load_bass_opus_plugin()
{
BASS_PluginLoad("libbassopus.dylib", 0);
}
#else
#error This operating system is unsupported for BASS plugins.
#endif

View File

@ -1,6 +1,5 @@
#include "aoblipplayer.h"
#if defined(BASSAUDIO) // Using bass.dll for the blips
AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app)
{
m_parent = parent;
@ -37,8 +36,14 @@ void AOBlipPlayer::blip_tick()
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());
int f_bass_error = BASS_ErrorGetCode();
if (f_bass_error == BASS_ERROR_DEVICE) {
ao_app->doBASSreset();
BASS_ChannelSetDevice(f_stream, BASS_GetDevice());
}
BASS_ChannelPlay(f_stream, false);
}
@ -56,51 +61,3 @@ void AOBlipPlayer::set_volume_internal(qreal p_value)
BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume);
}
}
#elif defined(QTAUDIO) // Using Qt's QSoundEffect class
AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app)
{
m_parent = parent;
ao_app = p_ao_app;
}
void AOBlipPlayer::set_blips(QString p_sfx)
{
QString f_path = ao_app->get_sounds_path(p_sfx);
for (int n_stream = 0; n_stream < 5; ++n_stream) {
m_blips.setSource(QUrl::fromLocalFile(f_path));
}
set_volume(m_volume);
}
void AOBlipPlayer::blip_tick()
{
int f_cycle = m_cycle++;
if (m_cycle == 5)
m_cycle = 0;
m_blips.play();
}
void AOBlipPlayer::set_volume(int p_value)
{
m_volume = p_value;
m_blips.setVolume(m_volume);
}
#else // No audio
AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app)
{
m_parent = parent;
ao_app = p_ao_app;
}
void AOBlipPlayer::set_blips(QString p_sfx) {}
void AOBlipPlayer::blip_tick() {}
void AOBlipPlayer::set_volume(int p_value) {}
void AOBlipPlayer::set_volume_internal(qreal p_value) {}
#endif

View File

@ -1,14 +1,11 @@
#include "aomusicplayer.h"
AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app)
{
m_parent = parent;
ao_app = p_ao_app;
}
#ifdef BASSAUDIO
AOMusicPlayer::~AOMusicPlayer()
{
for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) {
@ -111,6 +108,9 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop,
else
this->set_volume(m_volume[channel], channel);
BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_DEV_FAIL, 0,
ao_app->BASSreset, 0);
this->set_looping(loop, channel); // Have to do this here due to any
// crossfading-related changes, etc.
}
@ -164,62 +164,13 @@ void AOMusicPlayer::set_looping(bool toggle, int channel)
}
if (loop_start[channel] > 0) {
if (loop_end[channel] == 0)
loop_end[channel] = BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE);
if (loop_end[channel] > 0) // Don't loop zero length songs even if we're asked to
loop_end[channel] =
BASS_ChannelGetLength(m_stream_list[channel], BASS_POS_BYTE);
if (loop_end[channel] >
0) // Don't loop zero length songs even if we're asked to
loop_sync[channel] = BASS_ChannelSetSync(
m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, loop_end[channel],
loopProc, &loop_start[channel]);
m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME,
loop_end[channel], loopProc, &loop_start[channel]);
}
}
}
#elif defined(QTAUDIO)
AOMusicPlayer::~AOMusicPlayer() {
for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) {
m_stream_list[n_stream].stop();
}
}
void AOMusicPlayer::play(QString p_song, int channel, bool loop,
int effect_flags)
{
channel = channel % m_channelmax;
if (channel < 0) // wtf?
return;
QString f_path = ao_app->get_music_path(p_song);
m_stream_list[channel].stop();
m_stream_list[channel].setMedia(QUrl::fromLocalFile(f_path));
this->set_volume(m_volume[channel], channel);
m_stream_list[channel].play();
}
void AOMusicPlayer::stop(int channel)
{
m_stream_list[channel].stop();
}
void AOMusicPlayer::set_volume(int p_value, int channel)
{
m_volume[channel] = p_value;
m_stream_list[channel].setVolume(m_volume[channel]);
}
#else
AOMusicPlayer::~AOMusicPlayer() {}
void AOMusicPlayer::play(QString p_song, int channel, bool loop,
int effect_flags) {}
void AOMusicPlayer::stop(int channel) {}
void AOMusicPlayer::set_volume(int p_value, int channel) {}
void loopProc(int handle, int channel, int data, int *user) {}
void AOMusicPlayer::set_looping(bool toggle, int channel) {}
#endif

View File

@ -120,6 +120,49 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_length_spinbox);
row += 1;
ui_log_newline_lbl = new QLabel(ui_form_layout_widget);
ui_log_newline_lbl->setText(tr("Log newline:"));
ui_log_newline_lbl->setToolTip(
tr("If ticked, new messages will appear separated, "
"with the message coming on the next line after the name. "
"When unticked, it displays it as 'name: message'."));
ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_log_newline_lbl);
ui_log_newline_cb = new QCheckBox(ui_form_layout_widget);
ui_log_newline_cb->setChecked(p_ao_app->get_log_newline());
ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_newline_cb);
row += 1;
ui_log_margin_lbl = new QLabel(ui_form_layout_widget);
ui_log_margin_lbl->setText(tr("Log margin:"));
ui_log_margin_lbl->setToolTip(tr(
"The distance in pixels between each entry in the IC log. "
"Default: 0."));
ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_log_margin_lbl);
ui_log_margin_spinbox = new QSpinBox(ui_form_layout_widget);
ui_log_margin_spinbox->setMaximum(1000);
ui_log_margin_spinbox->setValue(p_ao_app->get_log_margin());
ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_margin_spinbox);
row += 1;
ui_log_timestamp_lbl = new QLabel(ui_form_layout_widget);
ui_log_timestamp_lbl->setText(tr("Log timestamp:"));
ui_log_timestamp_lbl->setToolTip(
tr("If ticked, log will contain a timestamp in UTC before the name."));
ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_log_timestamp_lbl);
ui_log_timestamp_cb = new QCheckBox(ui_form_layout_widget);
ui_log_timestamp_cb->setChecked(p_ao_app->get_log_timestamp());
ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_timestamp_cb);
row += 1;
ui_log_names_divider = new QFrame(ui_form_layout_widget);
ui_log_names_divider->setFrameShape(QFrame::HLine);
@ -402,7 +445,6 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
ui_audio_device_combobox->addItem("default"); //TODO translate this without breaking the default audio device
}
#ifdef BASSAUDIO
BASS_DEVICEINFO info;
for (a = 0; BASS_GetDeviceInfo(a, &info); a++) {
ui_audio_device_combobox->addItem(info.name);
@ -410,15 +452,6 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
ui_audio_device_combobox->setCurrentIndex(
ui_audio_device_combobox->count() - 1);
}
#elif defined QTAUDIO
foreach (const QAudioDeviceInfo &deviceInfo,
QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) {
ui_audio_device_combobox->addItem(deviceInfo.deviceName());
if (p_ao_app->get_audio_output_device() == deviceInfo.deviceName())
ui_audio_device_combobox->setCurrentIndex(
ui_audio_device_combobox->count() - 1);
}
#endif
ui_audio_layout->setWidget(row, QFormLayout::FieldRole,
ui_audio_device_combobox);
@ -726,6 +759,9 @@ void AOOptionsDialog::save_pressed()
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("log_newline", ui_log_newline_cb->isChecked());
configini->setValue("log_margin", ui_log_margin_spinbox->value());
configini->setValue("log_timestamp", ui_log_timestamp_cb->isChecked());
configini->setValue("default_username", ui_username_textbox->text());
configini->setValue("show_custom_shownames", ui_showname_cb->isChecked());
configini->setValue("master", ui_ms_textbox->text());
@ -770,6 +806,7 @@ void AOOptionsDialog::save_pressed()
configini->setValue("casing_can_host_cases",
ui_casing_cm_cases_textbox->text());
ao_app->initBASS();
callwordsini->close();
done(0);
}

View File

@ -1,14 +1,12 @@
#include "aosfxplayer.h"
#include "file_functions.h"
AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app)
{
m_parent = parent;
ao_app = p_ao_app;
}
#if defined(BASSAUDIO) // Using bass.dll for sfx
void AOSfxPlayer::clear()
{
for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) {
@ -68,9 +66,16 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout,
set_volume_internal(m_volume);
if (ao_app->get_audio_output_device() != "default")
BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice());
int f_bass_error = BASS_ErrorGetCode();
if (f_bass_error == BASS_ERROR_DEVICE) {
ao_app->doBASSreset();
BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice());
}
BASS_ChannelPlay(m_stream_list[m_channel], false);
BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_DEV_FAIL, 0,
ao_app->BASSreset, 0);
}
void AOSfxPlayer::stop(int channel)
@ -112,100 +117,3 @@ void AOSfxPlayer::set_looping(bool toggle, int channel)
BASS_SAMPLE_LOOP); // set the LOOP flag
}
}
#elif defined(QTAUDIO) // Using Qt's QSoundEffect class
void AOSfxPlayer::clear()
{
for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) {
m_stream_list[n_stream].stop();
}
set_volume_internal(m_volume);
}
void AOSfxPlayer::loop_clear()
{
for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) {
m_stream_list[n_stream].stop();
}
set_volume_internal(m_volume);
}
void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout,
int channel)
{
m_stream_list[channel].stop();
QString misc_path = "";
QString char_path = "";
QString sound_path = ao_app->get_sounds_path(p_sfx);
if (shout != "")
misc_path = ao_app->get_base_path() + "misc/" + shout + "/" + p_sfx;
if (p_char != "")
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 = sound_path;
if (file_exists(f_path)) // if its missing, it will glitch out
{
m_stream_list[channel].setSource(QUrl::fromLocalFile(f_path));
set_volume_internal(m_volume);
m_stream_list[channel].play();
}
}
void AOSfxPlayer::stop(int channel)
{
if (channel == -1) {
channel = m_channel;
}
m_stream_list[channel].stop();
}
void AOSfxPlayer::set_volume(qreal p_value)
{
m_volume = p_value / 100;
set_volume_internal(m_volume);
}
void AOSfxPlayer::set_volume_internal(qreal p_value)
{
float volume = static_cast<float>(p_value);
for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) {
m_stream_list[n_stream].setVolume(volume);
}
}
void AOSfxPlayer::set_looping(bool toggle, int channel)
{
if (channel == -1) {
channel = m_channel;
}
m_looping = toggle;
// TODO
}
#else
void AOSfxPlayer::clear() {}
void AOSfxPlayer::loop_clear() {}
void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout,
int channel) {}
void AOSfxPlayer::stop(int channel) {}
void AOSfxPlayer::set_volume(qreal p_value) {}
void AOSfxPlayer::set_volume_internal(qreal p_value) {}
void AOSfxPlayer::set_looping(bool toggle, int channel) {}
#endif

View File

@ -6,29 +6,29 @@ chatlogpiece::chatlogpiece()
showname = tr("UNKNOWN");
message = tr("UNKNOWN");
color = 0;
p_is_song = false;
action = "";
datetime = QDateTime::currentDateTime().toUTC();
}
chatlogpiece::chatlogpiece(QString p_name, QString p_showname,
QString p_message, bool p_song, int p_color)
QString p_message, QString p_action, int p_color)
{
name = p_name;
showname = p_showname;
message = p_message;
p_is_song = p_song;
action = p_action;
color = p_color;
datetime = QDateTime::currentDateTime().toUTC();
}
chatlogpiece::chatlogpiece(QString p_name, QString p_showname,
QString p_message, bool p_song, int p_color,
QString p_message, QString p_action, int p_color,
QDateTime p_datetime)
{
name = p_name;
showname = p_showname;
message = p_message;
p_is_song = p_song;
action = p_action;
color = p_color;
datetime = p_datetime.toUTC();
}
@ -41,7 +41,7 @@ QString chatlogpiece::get_message() { return message; }
QDateTime chatlogpiece::get_datetime() { return datetime; }
bool chatlogpiece::is_song() { return p_is_song; }
QString chatlogpiece::get_action() { return action; }
QString chatlogpiece::get_datetime_as_string() { return datetime.toString(); }
@ -54,12 +54,14 @@ QString chatlogpiece::get_full()
full.append(get_datetime_as_string());
full.append("] ");
full.append(get_showname());
if (get_showname() != get_name())
{
full.append(" (");
full.append(get_name());
full.append(")");
if (p_is_song)
full.append(tr(" has played a song: "));
else
}
if (!get_action().isEmpty())
full.append(" " + get_action());
full.append(": ");
full.append(get_message());

View File

@ -3,42 +3,7 @@
Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
{
ao_app = p_ao_app;
#ifdef BASSAUDIO
// Change the default audio output device to be the one the user has given
// in his config.ini file for now.
unsigned int a = 0;
BASS_DEVICEINFO info;
if (ao_app->get_audio_output_device() == "default") {
BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr);
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(static_cast<int>(a), 48000, BASS_DEVICE_LATENCY, nullptr,
nullptr);
load_bass_opus_plugin();
qDebug() << info.name << "was set as the default audio output device.";
break;
}
}
}
#elif defined QTAUDIO
if (ao_app->get_audio_output_device() != "default") {
foreach (const QAudioDeviceInfo &deviceInfo,
QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) {
if (ao_app->get_audio_output_device() == deviceInfo.deviceName()) {
ao_app->QtAudioDevice = deviceInfo;
qDebug() << deviceInfo.deviceName()
<< "was set as the default audio output device.";
break;
}
}
}
#endif
ao_app->initBASS();
qsrand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch() / 1000));
@ -109,6 +74,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
log_maximum_blocks = ao_app->get_max_log_size();
log_goes_downwards = ao_app->get_log_goes_downwards();
log_colors = ao_app->is_colorlog_enabled();
log_newline = ao_app->get_log_newline();
log_margin = ao_app->get_log_margin();
log_timestamp = ao_app->get_log_timestamp();
ui_ms_chatlog = new AOTextArea(this);
ui_ms_chatlog->setReadOnly(true);
@ -581,8 +550,20 @@ void Courtroom::set_widgets()
ui_vp_objection->move(ui_viewport->x(), ui_viewport->y());
ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height());
log_maximum_blocks = ao_app->get_max_log_size();
bool regenerate = log_goes_downwards != ao_app->get_log_goes_downwards() || log_colors != ao_app->is_colorlog_enabled() || log_newline != ao_app->get_log_newline() || log_margin != ao_app->get_log_margin() || log_timestamp != ao_app->get_log_timestamp();
log_goes_downwards = ao_app->get_log_goes_downwards();
log_colors = ao_app->is_colorlog_enabled();
log_newline = ao_app->get_log_newline();
log_margin = ao_app->get_log_margin();
log_timestamp = ao_app->get_log_timestamp();
if (regenerate)
regenerate_ic_chatlog();
set_size_and_pos(ui_ic_chatlog, "ic_chatlog");
ui_ic_chatlog->setFrameShape(QFrame::NoFrame);
ui_ic_chatlog->setPlaceholderText(log_goes_downwards ? "▼ Log goes down ▼" : "▲ Log goes up ▲");
set_size_and_pos(ui_ms_chatlog, "ms_chatlog");
ui_ms_chatlog->setFrameShape(QFrame::NoFrame);
@ -636,6 +617,7 @@ void Courtroom::set_widgets()
}
ui_music_display->play("music_display");
ui_music_display->set_play_once(false);
if (is_ao2_bg) {
set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message");
@ -934,6 +916,20 @@ void Courtroom::set_widgets()
ui_spectator->setToolTip(tr("Become a spectator. You won't be able to "
"interact with the in-character screen."));
free_brush =
QBrush(ao_app->get_color("area_free_color", "courtroom_design.ini"));
lfp_brush =
QBrush(ao_app->get_color("area_lfp_color", "courtroom_design.ini"));
casing_brush =
QBrush(ao_app->get_color("area_casing_color", "courtroom_design.ini"));
recess_brush =
QBrush(ao_app->get_color("area_recess_color", "courtroom_design.ini"));
rp_brush = QBrush(ao_app->get_color("area_rp_color", "courtroom_design.ini"));
gaming_brush =
QBrush(ao_app->get_color("area_gaming_color", "courtroom_design.ini"));
locked_brush =
QBrush(ao_app->get_color("area_locked_color", "courtroom_design.ini"));
refresh_evidence();
}
@ -957,27 +953,28 @@ void Courtroom::set_font(QWidget *widget, QString class_name,
{
QString design_file = "courtroom_fonts.ini";
if (f_pointsize <= 0)
f_pointsize = ao_app->get_design_element(p_identifier, design_file, p_char).toInt();
f_pointsize =
ao_app->get_design_element(p_identifier, design_file, p_char).toInt();
if (font_name == "")
font_name =
ao_app->get_design_element(p_identifier + "_font", design_file, p_char);
QString f_color_result = ao_app->get_design_element(p_identifier + "_color", design_file, p_char);
QString f_color_result =
ao_app->get_design_element(p_identifier + "_color", design_file, p_char);
QColor f_color(0, 0, 0);
if (f_color_result != "")
{
if (f_color_result != "") {
QStringList color_list = f_color_result.split(",");
if (color_list.size() >= 3)
{
if (color_list.size() >= 3) {
f_color.setRed(color_list.at(0).toInt());
f_color.setGreen(color_list.at(1).toInt());
f_color.setBlue(color_list.at(2).toInt());
}
}
bool bold = ao_app->get_design_element(p_identifier + "_bold", design_file, p_char) ==
1; // is the font bold or not?
bool antialias =
ao_app->get_design_element(p_identifier + "_sharp", design_file, p_char) !=
bool bold =
ao_app->get_design_element(p_identifier + "_bold", design_file, p_char) ==
"1"; // is the font bold or not?
bool antialias = ao_app->get_design_element(p_identifier + "_sharp",
design_file, p_char) !=
"1"; // is the font anti-aliased or not?
this->set_qfont(widget, class_name,
@ -1129,8 +1126,8 @@ void Courtroom::set_background(QString p_background, bool display)
// Populate the dropdown list with all pos that exist on this bg
QStringList pos_list = {};
for (QString key : default_pos.keys()) {
if (file_exists(ao_app->get_image_suffix(
ao_app->get_background_path(key)))) {
if (file_exists(
ao_app->get_image_suffix(ao_app->get_background_path(key)))) {
pos_list.append(default_pos[key]);
}
}
@ -1237,6 +1234,8 @@ void Courtroom::update_character(int p_cid)
current_char = f_char;
current_side = ao_app->get_char_side(current_char);
set_text_color_dropdown();
current_emote_page = 0;
current_emote = 0;
@ -1282,8 +1281,7 @@ void Courtroom::update_character(int p_cid)
{
custom_obj_menu->clear();
if (file_exists(ao_app->get_image_suffix(
ao_app->get_character_path(current_char, "custom"))))
{
ao_app->get_character_path(current_char, "custom")))) {
ui_custom_objection->show();
QAction *action = custom_obj_menu->addAction("Default");
custom_obj_menu->setDefaultAction(action);
@ -1301,8 +1299,7 @@ void Courtroom::update_character(int p_cid)
QDir::Files);
for (const QString &filename : custom_obj) {
QAction *action = custom_obj_menu->addAction(filename);
if (custom_obj_menu->defaultAction() == nullptr)
{
if (custom_obj_menu->defaultAction() == nullptr) {
custom_obj_menu->setDefaultAction(action);
objection_custom = action->text();
}
@ -1433,16 +1430,6 @@ void Courtroom::list_areas()
ui_area_list->clear();
// ui_music_search->setText("");
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) {
@ -1532,7 +1519,7 @@ void Courtroom::append_server_chatmessage(QString p_name, QString p_message,
void Courtroom::on_chat_return_pressed()
{
if (ui_ic_chat_message->text() == "" || is_muted)
if (is_muted)
return;
if ((anim_state < 3 || text_state < 2) && objection_state == 0)
@ -1611,7 +1598,7 @@ void Courtroom::on_chat_return_pressed()
if (f_emote_mod == 0)
f_emote_mod = 1;
else if (f_emote_mod == 5 && ao_app->prezoom_enabled)
f_emote_mod = 4;
f_emote_mod = 6;
}
else {
if (f_emote_mod == 1)
@ -1760,88 +1747,18 @@ void Courtroom::on_chat_return_pressed()
ao_app->send_server_packet(new AOPacket("MS", packet_contents));
}
void Courtroom::handle_chatmessage(QStringList *p_contents)
void Courtroom::reset_ic()
{
// 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);
// 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();
if (f_char_id >= 0 && f_char_id >= char_list.size())
return;
if (mute_map.value(m_chatmessage[CHAR_ID].toInt()))
return;
QString f_showname;
if (f_char_id > -1 &&
(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];
}
if (f_showname.trimmed()
.isEmpty()) // Pure whitespace showname, get outta here.
f_showname = m_chatmessage[CHAR_NAME];
QString f_message = f_showname + ": " + m_chatmessage[MESSAGE] + '\n';
// Remove undesired newline chars
m_chatmessage[MESSAGE].remove("\n");
chatmessage_is_empty =
m_chatmessage[MESSAGE] == " " || m_chatmessage[MESSAGE] == "";
if (f_char_id >= 0 && !chatmessage_is_empty &&
f_message == previous_ic_message) // Not a system message
return;
if (f_char_id <= -1)
previous_ic_message =
""; // System messages don't care about repeating themselves
else
previous_ic_message = f_message;
bool ok;
int objection_mod = m_chatmessage[OBJECTION_MOD].toInt(
&ok, 10); // checks if its a custom obj.
QString custom_objection = "";
if (!ok && m_chatmessage[OBJECTION_MOD].contains("4&")) {
objection_mod = 4;
custom_objection = m_chatmessage[OBJECTION_MOD].split(
"4&")[1]; // takes the name of custom objection.
}
// Stop the chat arrow from animating
ui_vp_chat_arrow->stop();
text_state = 0;
anim_state = 0;
ui_vp_objection->stop();
chat_tick_timer->stop();
ui_vp_evidence_display->reset();
}
// Hey, our message showed up! Cool!
if (m_chatmessage[MESSAGE] == ui_ic_chat_message->text().remove("\n") &&
m_chatmessage[CHAR_ID].toInt() == m_cid) {
void Courtroom::reset_ui()
{
ui_ic_chat_message->clear();
if (ui_additive->isChecked())
ui_ic_chat_message->insert(" ");
@ -1858,27 +1775,91 @@ void Courtroom::handle_chatmessage(QStringList *p_contents)
ui_realization->set_image("realization");
ui_screenshake->set_image("screenshake");
ui_evidence_present->set_image("present");
}
void Courtroom::handle_chatmessage(QStringList *p_contents)
{
// 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() < MS_MINIMUM)
return;
for (int n_string = 0; n_string < MS_MAXIMUM; ++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 < MS_MINIMUM || ao_app->cccc_ic_support_enabled)) {
m_chatmessage[n_string] = p_contents->at(n_string);
}
else {
m_chatmessage[n_string] = "";
}
}
// Let the server handle actually checking if they're allowed to do this.
is_additive = m_chatmessage[ADDITIVE].toInt() == 1;
int f_char_id = m_chatmessage[CHAR_ID].toInt();
const bool is_spectator = (f_char_id == -1);
if (f_char_id < -1 || f_char_id >= char_list.size())
return;
if (mute_map.value(m_chatmessage[CHAR_ID].toInt()))
return;
QString f_displayname;
if (!is_spectator &&
(m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) {
// If the users is not a spectator and showname is disabled, use the
// character's name
f_displayname = ao_app->get_showname(char_list.at(f_char_id).name);
}
else {
// Otherwise, use the showname
f_displayname = m_chatmessage[SHOWNAME];
}
// If chatblank is enabled, use the character's name for logs
if (f_displayname.trimmed().isEmpty())
f_displayname = ao_app->get_showname(char_list.at(f_char_id).name);
// Check if a custom objection is in use
int objection_mod = 0;
QString custom_objection = "";
if (m_chatmessage[OBJECTION_MOD].contains("4&")) {
objection_mod = 4;
custom_objection = m_chatmessage[OBJECTION_MOD].split(
"4&")[1]; // takes the name of custom objection.
}
else {
objection_mod = m_chatmessage[OBJECTION_MOD].toInt();
}
// Reset IC display
reset_ic();
// Reset UI elements after client message gets sent
if (m_chatmessage[CHAR_ID].toInt() == m_cid) {
reset_ui();
}
QString f_charname = "";
if (f_char_id >= 0)
f_charname = ao_app->get_showname(char_list.at(f_char_id).name);
chatlogpiece *temp =
new chatlogpiece(f_charname, f_showname, m_chatmessage[MESSAGE], false, m_chatmessage[TEXT_COLOR].toInt());
ic_chatlog_history.append(*temp);
if (ao_app->get_auto_logging_enabled())
ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true);
while (ic_chatlog_history.size() > log_maximum_blocks &&
log_maximum_blocks > 0) {
ic_chatlog_history.removeFirst();
if (m_chatmessage[MESSAGE].trimmed().isEmpty()) // User-created blankpost
{
m_chatmessage[MESSAGE] = ""; // Turn it into true blankpost
}
append_ic_text(m_chatmessage[MESSAGE], f_showname, "", m_chatmessage[TEXT_COLOR].toInt());
if (!m_chatmessage[MESSAGE].isEmpty() || ic_chatlog_history.isEmpty() || ic_chatlog_history.last().get_message() != "")
{
log_ic_text(f_charname, f_displayname, m_chatmessage[MESSAGE], "",
m_chatmessage[TEXT_COLOR].toInt());
append_ic_text(m_chatmessage[MESSAGE], f_displayname, "",
m_chatmessage[TEXT_COLOR].toInt());
}
QString f_char = m_chatmessage[CHAR_NAME];
QString f_custom_theme = ao_app->get_char_shouts(f_char);
@ -1914,15 +1895,10 @@ void Courtroom::handle_chatmessage(QStringList *p_contents)
shout_stay_time);
objection_player->play("custom", f_char, f_custom_theme);
}
m_chatmessage[EMOTE_MOD] = 1;
break;
default:
qDebug() << "W: Logic error in objection switch statement!";
}
sfx_player->clear(); // Objection played! Cut all sfx.
int emote_mod = m_chatmessage[EMOTE_MOD].toInt();
if (emote_mod == 0)
m_chatmessage[EMOTE_MOD] = 1;
}
else
handle_chatmessage_2();
@ -2011,10 +1987,9 @@ void Courtroom::handle_chatmessage_2()
->get_design_element("showname_extra_width", "courtroom_design.ini",
customchar)
.toInt();
QString align =
ao_app
->get_design_element("showname_align", "courtroom_design.ini",
customchar)
QString align = ao_app
->get_design_element("showname_align",
"courtroom_design.ini", customchar)
.toLower();
if (align == "right")
ui_vp_showname->setAlignment(Qt::AlignRight);
@ -2047,8 +2022,7 @@ void Courtroom::handle_chatmessage_2()
set_font(ui_vp_showname, "", "showname", customchar);
}
else
{
else {
ui_vp_showname->resize(default_width.width, ui_vp_showname->height());
}
}
@ -2070,6 +2044,15 @@ void Courtroom::handle_chatmessage_2()
set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]);
int emote_mod = m_chatmessage[EMOTE_MOD].toInt();
// Deal with invalid emote modifiers
if (emote_mod != 0 && emote_mod != 1 && emote_mod != 2 && emote_mod != 5 &&
emote_mod != 6) {
if (emote_mod == 4)
emote_mod = 6; // Addresses issue with an old bug that sent the wrong
// emote modifier for zoompre
else
emote_mod = 0;
}
if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1)
ui_vp_player_char->set_flipped(true);
@ -2264,13 +2247,16 @@ void Courtroom::handle_chatmessage_3()
if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) {
// shifted by 1 because 0 is no evidence per legacy standards
QString f_image = local_evidence_list.at(f_evi_id - 1).image;
QString f_name = local_evidence_list.at(f_evi_id - 1).name;
QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name;
// 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" || f_side == "jur");
ui_vp_evidence_display->show_evidence(f_image, is_left_side,
ui_sfx_slider->value());
append_ic_text(f_name, f_showname, "has presented evidence");
log_ic_text(m_chatmessage[CHAR_NAME], m_chatmessage[SHOWNAME], f_evi_name, tr("has presented evidence"),
m_chatmessage[TEXT_COLOR].toInt());
append_ic_text(f_evi_name, f_showname, tr("has presented evidence"));
}
int emote_mod = m_chatmessage[EMOTE_MOD].toInt();
@ -2574,54 +2560,96 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos,
return p_text_escaped;
}
void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action, int color)
void Courtroom::log_ic_text(QString p_name, QString p_showname,
QString p_message, QString p_action, int p_color)
{
chatlogpiece log_entry(p_name, p_showname, p_message, p_action,
p_color);
ic_chatlog_history.append(log_entry);
if (ao_app->get_auto_logging_enabled())
ao_app->append_to_file(log_entry.get_full(), ao_app->log_filename, true);
while (ic_chatlog_history.size() > log_maximum_blocks &&
log_maximum_blocks > 0) {
ic_chatlog_history.removeFirst();
}
}
void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action,
int color)
{
QTextCharFormat bold;
QTextCharFormat normal;
QTextCharFormat italics;
QTextBlockFormat format;
bold.setFontWeight(QFont::Bold);
normal.setFontWeight(QFont::Normal);
italics.setFontItalic(true);
format.setTopMargin(log_margin);
const QTextCursor old_cursor = ui_ic_chatlog->textCursor();
const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value();
const bool need_newline = !ui_ic_chatlog->document()->isEmpty();
const int scrollbar_target_value = log_goes_downwards ? ui_ic_chatlog->verticalScrollBar()->maximum() : ui_ic_chatlog->verticalScrollBar()->minimum();
if (p_action == "")
p_text = filter_ic_text(p_text, ao_app->is_colorlog_enabled(), -1,
color);
ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::End : QTextCursor::Start);
if (log_goes_downwards) {
const bool is_scrolled_down =
old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum();
// Only prepend with newline if log goes downwards
if (log_goes_downwards && need_newline) {
ui_ic_chatlog->textCursor().insertBlock(format);
}
ui_ic_chatlog->moveCursor(QTextCursor::End);
// Timestamp if we're doing that meme
if (log_timestamp)
ui_ic_chatlog->textCursor().insertText("[" + QDateTime::currentDateTime().toString("h:mm:ss AP") + "] ", normal);
if (!first_message_sent) {
// Format the name of the actor
ui_ic_chatlog->textCursor().insertText(p_name, bold);
first_message_sent = true;
}
else {
ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold);
}
// If action not blank:
if (p_action != "") {
ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal);
// Format the action in normal
ui_ic_chatlog->textCursor().insertText(" " + p_action, normal);
if (log_newline)
// For some reason, we're forced to use <br> instead of the more sensible \n.
// Why? Because \n is treated as a new Block instead of a soft newline within a paragraph!
ui_ic_chatlog->textCursor().insertHtml("<br>");
else
ui_ic_chatlog->textCursor().insertText(": ", normal);
// Format the result in italics
ui_ic_chatlog->textCursor().insertText(p_text + ".", italics);
}
else {
if (log_newline)
// For some reason, we're forced to use <br> instead of the more sensible \n.
// Why? Because \n is treated as a new Block instead of a soft newline within a paragraph!
ui_ic_chatlog->textCursor().insertHtml("<br>");
else
ui_ic_chatlog->textCursor().insertText(": ", normal);
ui_ic_chatlog->textCursor().insertHtml(p_text);
// Format the result according to html
if (log_colors)
ui_ic_chatlog->textCursor().insertHtml(filter_ic_text(p_text, true, -1, color));
else
ui_ic_chatlog->textCursor().insertText(filter_ic_text(p_text, false), normal);
}
// If we got too many blocks in the current log, delete some from the top.
// Only append with newline if log goes upwards
if (!log_goes_downwards && need_newline) {
ui_ic_chatlog->textCursor().insertBlock(format);
}
// If we got too many blocks in the current log, delete some.
while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks &&
log_maximum_blocks > 0) {
ui_ic_chatlog->moveCursor(QTextCursor::Start);
ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::Start : QTextCursor::End);
ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor);
ui_ic_chatlog->textCursor().removeSelectedText();
if (log_goes_downwards)
ui_ic_chatlog->textCursor().deleteChar();
else
ui_ic_chatlog->textCursor().deletePreviousChar();
}
if (old_cursor.hasSelection() || !is_scrolled_down) {
// Finally, scroll the scrollbar to the correct position.
if (old_cursor.hasSelection() || old_scrollbar_value != scrollbar_target_value) {
// The user has selected text or scrolled away from the bottom: maintain
// position.
ui_ic_chatlog->setTextCursor(old_cursor);
@ -2630,52 +2658,10 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action,
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->moveCursor(log_goes_downwards ? QTextCursor::End : QTextCursor::Start);
ui_ic_chatlog->verticalScrollBar()->setValue(
ui_ic_chatlog->verticalScrollBar()->maximum());
}
}
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);
if (p_action != "") {
ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal);
ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics);
}
else {
ui_ic_chatlog->textCursor().insertText(": ", normal);
ui_ic_chatlog->textCursor().insertHtml(p_text + "<br>");
}
// 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();
}
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());
}
}
}
void Courtroom::play_preanim(bool noninterrupting)
@ -2756,16 +2742,25 @@ void Courtroom::start_chat_ticking()
this->do_flash();
sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME]));
}
if (chatmessage_is_empty) {
int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); // text meme bonanza
if ((emote_mod == 0 || emote_mod == 5) && m_chatmessage[SCREENSHAKE] == "1") {
this->do_screenshake();
}
if (m_chatmessage[MESSAGE].isEmpty()) {
// since the message is empty, it's technically done ticking
text_state = 2;
if (m_chatmessage[ADDITIVE] == "1") {
// Cool behavior
ui_vp_chatbox->show();
ui_vp_message->show();
}
return;
}
ui_vp_chatbox->show();
ui_vp_message->show();
if (!is_additive) {
if (m_chatmessage[ADDITIVE] != "1") {
ui_vp_message->clear();
real_tick_pos = 0;
additive_previous = "";
@ -2782,11 +2777,6 @@ void Courtroom::start_chat_ticking()
blip_player->set_blips(f_gender);
int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); // text meme bonanza
if ((emote_mod == 0 || emote_mod == 5) && m_chatmessage[SCREENSHAKE] == "1") {
this->do_screenshake();
}
// means text is currently ticking
text_state = 1;
}
@ -2810,8 +2800,7 @@ void Courtroom::chat_tick()
}
QString f_char;
QString f_custom_theme;
if (ao_app->is_customchat_enabled())
{
if (ao_app->is_customchat_enabled()) {
f_char = m_chatmessage[CHAR_NAME];
f_custom_theme = ao_app->get_chat(f_char);
}
@ -2914,6 +2903,12 @@ void Courtroom::chat_tick()
next_character_is_not_special = false;
}
// Keep the speed at bay.
if (current_display_speed < 0)
current_display_speed = 0;
else if (current_display_speed > 6)
current_display_speed = 6;
if ((message_display_speed[current_display_speed] <= 0 &&
tick_pos < f_message.size() - 1) ||
formatting_char) {
@ -2942,12 +2937,6 @@ void Courtroom::chat_tick()
ui_vp_message->ensureCursorVisible();
// Keep the speed at bay.
if (current_display_speed < 0)
current_display_speed = 0;
else if (current_display_speed > 6)
current_display_speed = 6;
// Blip player and real tick pos ticker
if (!formatting_char && (f_character != ' ' || blank_blip)) {
if (blip_ticker % blip_rate == 0) {
@ -3174,16 +3163,8 @@ void Courtroom::handle_song(QStringList *p_contents)
}
if (!mute_map.value(n_char)) {
chatlogpiece *temp = new chatlogpiece(str_char, str_show, f_song, true, m_chatmessage[TEXT_COLOR].toInt());
ic_chatlog_history.append(*temp);
if (ao_app->get_auto_logging_enabled())
ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true);
while (ic_chatlog_history.size() > log_maximum_blocks &&
log_maximum_blocks > 0) {
ic_chatlog_history.removeFirst();
}
log_ic_text(str_char, str_show, f_song, tr("has played a song"),
m_chatmessage[TEXT_COLOR].toInt());
append_ic_text(f_song_clear, str_show, tr("has played a song"));
music_player->play(f_song, channel, looping, effect_flags);
@ -4100,8 +4081,7 @@ void Courtroom::on_music_list_context_menu_requested(const QPoint &pos)
{
QMenu *menu = new QMenu();
menu->addAction(QString(tr("Play Random Song")), this,
SLOT(music_random()));
menu->addAction(QString(tr("Play Random Song")), this, SLOT(music_random()));
menu->addSeparator();
menu->addAction(QString(tr("Expand All Categories")), this,
SLOT(music_list_expand_all()));
@ -4157,7 +4137,9 @@ void Courtroom::music_synchronize(bool toggle)
void Courtroom::music_random()
{
QList<QTreeWidgetItem *> clist;
QTreeWidgetItemIterator it(ui_music_list, QTreeWidgetItemIterator::NotHidden | QTreeWidgetItemIterator::NoChildren);
QTreeWidgetItemIterator it(ui_music_list,
QTreeWidgetItemIterator::NotHidden |
QTreeWidgetItemIterator::NoChildren);
while (*it) {
clist += (*it);
++it;
@ -4402,7 +4384,8 @@ void Courtroom::set_text_color_dropdown()
// Update markdown colors. TODO: make a loading function that only loads the
// config file once instead of several times
for (int c = 0; c < max_colors; ++c) {
QColor color = ao_app->get_chat_color("c" + QString::number(c), current_char);
QColor color =
ao_app->get_chat_color("c" + QString::number(c), current_char);
color_rgb_list.append(color);
color_markdown_start_list.append(ao_app->get_chat_markdown(
"c" + QString::number(c) + "_start", current_char));
@ -4578,10 +4561,7 @@ void Courtroom::on_char_select_right_clicked()
set_char_select_page();
}
void Courtroom::on_spectator_clicked()
{
char_clicked(-1);
}
void Courtroom::on_spectator_clicked() { char_clicked(-1); }
void Courtroom::on_call_mod_clicked()
{
@ -4645,29 +4625,19 @@ 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.is_song())
append_ic_text(item.get_message(), item.get_showname(),
tr("has played a song"));
else
append_ic_text(item.get_message(), item.get_showname(), "", item.get_chat_color());
}
else {
if (item.is_song())
append_ic_text(item.get_message(), item.get_name(),
tr("has played a song"));
else
append_ic_text(item.get_message(), item.get_name(), "", item.get_chat_color());
}
}
regenerate_ic_chatlog();
ui_ic_chat_message->setFocus();
}
void Courtroom::regenerate_ic_chatlog()
{
ui_ic_chatlog->clear();
foreach (chatlogpiece item, ic_chatlog_history) {
append_ic_text(item.get_message(), ui_showname_enable->isChecked() ? item.get_showname() : item.get_name(),
item.get_action(), item.get_chat_color());
}
}
void Courtroom::on_evidence_button_clicked()
{
if (ui_evidence->isHidden()) {
@ -4745,28 +4715,3 @@ Courtroom::~Courtroom()
delete objection_player;
delete blip_player;
}
#if (defined(_WIN32) || defined(_WIN64))
void Courtroom::load_bass_opus_plugin()
{
#ifdef BASSAUDIO
BASS_PluginLoad("bassopus.dll", 0);
#endif
}
#elif (defined(LINUX) || defined(__linux__))
void Courtroom::load_bass_opus_plugin()
{
#ifdef BASSAUDIO
BASS_PluginLoad("libbassopus.so", 0);
#endif
}
#elif defined __APPLE__
void Courtroom::load_bass_opus_plugin()
{
#ifdef BASSAUDIO
BASS_PluginLoad("libbassopus.dylib", 0);
#endif
}
#else
#error This operating system is unsupported for bass plugins.
#endif

View File

@ -5,6 +5,8 @@
#include "debug_functions.h"
#include "networkmanager.h"
#include <QImageReader>
Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow()
{
ao_app = p_ao_app;
@ -353,13 +355,7 @@ void Lobby::on_connect_released()
void Lobby::on_about_clicked()
{
#ifdef BASSAUDIO
const QString audio = "BASS";
#elif defined(QTAUDIO)
const QString audio = "Qt Multimedia";
#else
const QString audio = "null";
#endif
const bool hasApng = QImageReader::supportedImageFormats().contains("APNG");
QString msg =
tr("<h2>Attorney Online %1</h2>"
@ -389,11 +385,12 @@ void Lobby::on_about_clicked()
"is copyright (c) 2016-2020 Attorney Online developers. Open-source "
"licenses apply. All other assets are the property of their "
"respective owners."
"<p>Running on Qt version %2 with the %3 audio engine."
"<p>Running on Qt version %2 with the BASS audio engine.<br>"
"APNG plugin loaded: %3"
"<p>Built on %4")
.arg(ao_app->get_version_string())
.arg(QLatin1String(QT_VERSION_STR))
.arg(audio)
.arg(hasApng ? tr("Yes") : tr("No"))
.arg(QLatin1String(__DATE__));
QMessageBox::about(this, tr("About"), msg);
}

View File

@ -176,7 +176,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
}
}
else if (header == "FL") {
// encryption_needed = true;
// encryption_needed = true;
yellow_text_enabled = false;
prezoom_enabled = false;
flipping_enabled = false;
@ -292,7 +292,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
// Remove any characters not accepted in folder names for the server_name
// here
if (AOApplication::get_auto_logging_enabled()){
if (AOApplication::get_auto_logging_enabled()) {
this->log_filename = QDateTime::currentDateTime().toUTC().toString(
"'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) +
"/'ddd MMMM yyyy hh.mm.ss t'.log'");
@ -676,6 +676,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet)
w_courtroom->arup_modify(arup_type, n_element - 1,
f_contents.at(n_element));
}
w_courtroom->list_areas();
}
}
else if (header == "IL") {

View File

@ -53,6 +53,26 @@ bool AOApplication::get_log_goes_downwards()
return result.startsWith("true");
}
bool AOApplication::get_log_newline()
{
QString result =
configini->value("log_newline", "false").value<QString>();
return result.startsWith("true");
}
int AOApplication::get_log_margin()
{
int result = configini->value("log_margin", 0).toInt();
return result;
}
bool AOApplication::get_log_timestamp()
{
QString result =
configini->value("log_timestamp", "false").value<QString>();
return result.startsWith("true");
}
bool AOApplication::get_showname_enabled_by_default()
{
QString result =
@ -435,7 +455,8 @@ QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file)
QString AOApplication::get_chat_markdown(QString p_identifier, QString p_chat)
{
QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini";
QString design_ini_path =
get_base_path() + "misc/" + get_chat(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);
@ -449,9 +470,10 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat)
{
QColor return_color(255, 255, 255);
QString design_ini_path = get_base_path() + "misc/" + p_chat + "/config.ini";
QString design_ini_path =
get_base_path() + "misc/" + get_chat(p_chat) + "/config.ini";
QString default_path = get_base_path() + "misc/default/config.ini";
QString f_result = read_design_ini("c" + p_identifier, design_ini_path);
QString f_result = read_design_ini(p_identifier, design_ini_path);
if (f_result == "") {
f_result = read_design_ini(p_identifier, default_path);
@ -908,6 +930,11 @@ QString AOApplication::get_effect_sound(QString fx_name, QString p_char)
f_result = read_design_ini(fx_name, default_path);
}
}
if (fx_name == "realization") {
f_result = get_custom_realization(p_char);
}
return f_result;
}