Add effect layering under the character, flippable effects and more (#701)

* Fix effect offsets only applying after the effect already plays
Add "_layer" property which can be "behind", "character" or default "chat". This deprecates the "under_chatbox" property

* Add a "sticky" effect property which is the same as "stickyeffects" setting being enabled but just for that 1 effect

* Clang is tidy, clang is caring

* make character layer actually stack over the character but under the desk
add new "over" layer which is over everything in the viewport but under the chat box

* Switch "ignore_offset" to "respect_offset" so effects only respect character offsets if explicitly told to

* Appease clang tidy... mostly. I don't understand the last thing it's talking about.

* Appease clang tidy further

* Remove "effect_done" due to it overwriting the AOLayers behavior
Add "loop" effect property so you set up in the ini if the effect should loop rather than it using the file's loop settings
Add "max_duration" effect property
Add "cull" effect property which decides whether to clear the effect or not when it's done (if loop is false)

* Fix effects not allowed to have underscores (_) in them without breaking

* Change the way effects.ini looks and is parsed to be more sane and doable.
However, since order may or may not matter, you can optionally include index:name and it orders it properly.

* Appeal to clang

* Fix a dumb way I created QSettings in get_effects

* Fix effect properties being broken due to optional index

* Fix get_effect_property not getting the current theme properties if a misc theme exists

* If sound list has a sound effect selected, if pre is not checked, don't play effect sound and prefer the sfx we chose instead.

* Fix \f not using the theme's realization effect

* Add missing curly bracket

* Yolo

Co-authored-by: Salanto <62221668+Salanto@users.noreply.github.com>
Co-authored-by: stonedDiscord <Tukz@gmx.de>
This commit is contained in:
Crystalwarrior 2022-07-18 15:45:47 +03:00 committed by GitHub
parent 9849ce2610
commit c8914c9302
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 143 additions and 81 deletions

View File

@ -188,8 +188,7 @@ public:
void set_scene(QString f_desk_mod, QString f_side); void set_scene(QString f_desk_mod, QString f_side);
// sets ui_vp_player_char according to SELF_OFFSET, only a function bc it's used with desk_mod 4 and 5 // sets ui_vp_player_char according to SELF_OFFSET, only a function bc it's used with desk_mod 4 and 5
// sets ui_effects_layer according to the SELF_OFFSET, unless it is overwritten by effects.ini void set_self_offset(const QString& p_list);
void set_self_offset(QString p_list, QString p_effect);
// takes in serverD-formatted IP list as prints a converted version to server // takes in serverD-formatted IP list as prints a converted version to server
// OOC admittedly poorly named // OOC admittedly poorly named
@ -821,7 +820,6 @@ private:
void regenerate_ic_chatlog(); void regenerate_ic_chatlog();
public slots: public slots:
void objection_done(); void objection_done();
void effect_done();
void preanim_done(); void preanim_done();
void do_screenshake(); void do_screenshake();
void do_flash(); void do_flash();

View File

@ -411,8 +411,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow()
connect(keepalive_timer, &QTimer::timeout, this, &Courtroom::ping_server); connect(keepalive_timer, &QTimer::timeout, this, &Courtroom::ping_server);
connect(ui_vp_objection, &SplashLayer::done, this, &Courtroom::objection_done); connect(ui_vp_objection, &SplashLayer::done, this, &Courtroom::objection_done);
connect(ui_vp_effect, &EffectLayer::done, this, &Courtroom::effect_done);
connect(ui_vp_wtce, &SplashLayer::done, this, &Courtroom::effect_done);
connect(ui_vp_player_char, &CharLayer::done, this, &Courtroom::preanim_done); connect(ui_vp_player_char, &CharLayer::done, this, &Courtroom::preanim_done);
connect(ui_vp_player_char, &CharLayer::shake, this, &Courtroom::do_screenshake); connect(ui_vp_player_char, &CharLayer::shake, this, &Courtroom::do_screenshake);
connect(ui_vp_player_char, &CharLayer::flash, this, &Courtroom::do_flash); connect(ui_vp_player_char, &CharLayer::flash, this, &Courtroom::do_flash);
@ -2056,8 +2054,14 @@ void Courtroom::on_chat_return_pressed()
ao_app->get_effect_property(effect, current_char, "sound"); ao_app->get_effect_property(effect, current_char, "sound");
QString p_effect = QString p_effect =
ao_app->read_char_ini(current_char, "effects", "Options"); ao_app->read_char_ini(current_char, "effects", "Options");
// Don't overlap the two sfx
if (!ui_pre->isChecked() && (!custom_sfx.isEmpty() || ui_sfx_dropdown->currentIndex() == 1)) {
fx_sound = "0";
}
packet_contents.append(effect + "|" + p_effect + "|" + fx_sound); packet_contents.append(effect + "|" + p_effect + "|" + fx_sound);
if (!ao_app->is_stickyeffects_enabled()) { if (!ao_app->is_stickyeffects_enabled() && !ao_app->get_effect_property(effect, current_char, "sticky").startsWith("true")) {
ui_effects_dropdown->blockSignals(true); ui_effects_dropdown->blockSignals(true);
ui_effects_dropdown->setCurrentIndex(0); ui_effects_dropdown->setCurrentIndex(0);
ui_effects_dropdown->blockSignals(false); ui_effects_dropdown->blockSignals(false);
@ -2396,12 +2400,6 @@ bool Courtroom::handle_objection()
return false; return false;
} }
void Courtroom::effect_done()
{
ui_vp_effect->stop();
ui_vp_wtce->stop();
}
void Courtroom::display_character() void Courtroom::display_character()
{ {
// Stop all previously playing animations, effects etc. // Stop all previously playing animations, effects etc.
@ -2436,13 +2434,10 @@ void Courtroom::display_character()
else else
ui_vp_player_char->network_strings.clear(); ui_vp_player_char->network_strings.clear();
// Determine if we should flip the character or not (what servers don't support flipping at this point?) // Determine if we should flip the character or not
if (ao_app->flipping_enabled && m_chatmessage[FLIP].toInt() == 1) ui_vp_player_char->set_flipped(m_chatmessage[FLIP].toInt() == 1);
ui_vp_player_char->set_flipped(true);
else
ui_vp_player_char->set_flipped(false);
// Move the character on the viewport according to the offsets // Move the character on the viewport according to the offsets
set_self_offset(m_chatmessage[SELF_OFFSET], m_chatmessage[EFFECTS]); set_self_offset(m_chatmessage[SELF_OFFSET]);
} }
void Courtroom::display_pair_character(QString other_charid, QString other_offset) void Courtroom::display_pair_character(QString other_charid, QString other_offset)
@ -2652,45 +2647,100 @@ void Courtroom::do_flash()
QString f_char = m_chatmessage[CHAR_NAME]; QString f_char = m_chatmessage[CHAR_NAME];
QString f_custom_theme = ao_app->get_chat(f_char); QString f_custom_theme = ao_app->get_chat(f_char);
ui_vp_effect->stretch = true; do_effect("realization", "", f_char, f_custom_theme);
ui_vp_effect->set_static_duration(60);
ui_vp_effect->set_max_duration(60);
ui_vp_player_char->stackUnder(ui_vp_objection); // go above the chatbox
ui_vp_effect->load_image(
ao_app->get_effect("realization", f_char, f_custom_theme), false);
} }
void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char, void Courtroom::do_effect(QString fx_path, QString fx_sound, QString p_char,
QString p_folder) QString p_folder)
{ {
if (fx_name == "") if (fx_path == "") {
return; return;
QString effect = ao_app->get_effect(fx_name, p_char, p_folder); }
if (effect == "") QString effect = ao_app->get_effect(fx_path, p_char, p_folder);
if (effect == "") {
return; return;
}
if (fx_sound != "") if (fx_sound != "") {
sfx_player->play(fx_sound); sfx_player->play(fx_sound);
}
// Only check if effects are disabled after playing the sound if it exists // Only check if effects are disabled after playing the sound if it exists
if (!ao_app->is_effects_enabled()) if (!ao_app->is_effects_enabled()) {
return; return;
}
ui_vp_effect->transform_mode = ao_app->get_scaling( ui_vp_effect->transform_mode = ao_app->get_scaling(
ao_app->get_effect_property(fx_name, p_char, "scaling")); ao_app->get_effect_property(fx_path, p_char, "scaling"));
ui_vp_effect->stretch = ui_vp_effect->stretch =
ao_app->get_effect_property(fx_name, p_char, "stretch") ao_app->get_effect_property(fx_path, p_char, "stretch")
.startsWith("true"); .startsWith("true");
bool under_chatbox = ao_app->get_effect_property(fx_name, p_char, "under_chatbox").startsWith("true"); ui_vp_effect->set_flipped(ao_app->get_effect_property(fx_path, p_char, "respect_flip").startsWith("true") && m_chatmessage[FLIP].toInt() == 1);
if (under_chatbox)
ui_vp_effect->stackUnder(ui_vp_chatbox);
else
ui_vp_effect->stackUnder(ui_vp_objection);
ui_vp_effect->set_play_once( ui_vp_effect->set_play_once(
false); // The effects themselves dictate whether or not they're looping. false); // The effects themselves dictate whether or not they're looping.
// Static effects will linger. // Static effects will linger.
ui_vp_effect->set_static_duration(0);
ui_vp_effect->set_max_duration(0); bool looping =
ui_vp_effect->load_image(effect, true); ao_app->get_effect_property(fx_path, p_char, "loop")
.startsWith("true");
int max_duration =
ao_app->get_effect_property(fx_path, p_char, "max_duration")
.toInt();
bool cull =
ao_app->get_effect_property(fx_path, p_char, "cull")
.startsWith("true");
// Possible values: "chat", "character", "behind"
QString layer = ao_app->get_effect_property(fx_path, p_char, "layer").toLower();
if (layer == "behind"){
ui_vp_effect->setParent(ui_viewport);
ui_vp_effect->stackUnder(ui_vp_player_char);
}
else if (layer == "character") {
ui_vp_effect->setParent(ui_viewport);
ui_vp_effect->stackUnder(ui_vp_desk);
}
else if (layer == "over") {
ui_vp_effect->setParent(ui_viewport);
ui_vp_effect->raise();
}
else { // if (layer == "chat") {
ui_vp_effect->setParent(this);
ui_vp_effect->stackUnder(ui_vp_objection);
}
int effect_x = 0;
int effect_y = 0;
// The effect is not parented to viewport, meaning we're overlaying ui elements
if (ui_vp_effect->parentWidget() != ui_viewport) {
//We need to add the viewport as an offset as effects are not bound to it.
effect_x = ui_viewport->x();
effect_y = ui_viewport->y();
}
// This effect respects the character offset settings
if (ao_app->get_effect_property(fx_path, p_char, "respect_offset") == "true") {
QStringList self_offsets = m_chatmessage[SELF_OFFSET].split("&");
int self_offset = self_offsets[0].toInt();
int self_offset_v;
if (self_offsets.length() <= 1) {
self_offset_v = 0;
}
else {
self_offset_v = self_offsets[1].toInt();
}
// Move the effects layer to match the position of our character
const int percent = 100;
effect_x += ui_viewport->width() * self_offset / percent;
effect_y += ui_viewport->height() * self_offset_v / percent;
}
ui_vp_effect->move(effect_x, effect_y);
ui_vp_effect->set_static_duration(max_duration);
ui_vp_effect->set_max_duration(max_duration);
ui_vp_effect->load_image(effect, looping);
ui_vp_effect->set_cull_image(cull);
} }
void Courtroom::play_char_sfx(QString sfx_name) void Courtroom::play_char_sfx(QString sfx_name)
@ -3385,7 +3435,7 @@ void Courtroom::start_chat_ticking()
// handle expanded desk mods // handle expanded desk mods
switch(m_chatmessage[DESK_MOD].toInt()) { switch(m_chatmessage[DESK_MOD].toInt()) {
case 4: case 4:
set_self_offset(m_chatmessage[SELF_OFFSET], QString("||")); set_self_offset(m_chatmessage[SELF_OFFSET]);
[[fallthrough]]; [[fallthrough]];
case 2: case 2:
set_scene("1", m_chatmessage[SIDE]); set_scene("1", m_chatmessage[SIDE]);
@ -3785,28 +3835,19 @@ void Courtroom::set_scene(const QString f_desk_mod, const QString f_side)
} }
} }
void Courtroom::set_self_offset(QString p_list, QString p_effect) { void Courtroom::set_self_offset(const QString& p_list) {
QStringList self_offsets = p_list.split("&"); QStringList self_offsets = p_list.split("&");
QStringList play_effect = p_effect.split("|");
int self_offset = self_offsets[0].toInt(); int self_offset = self_offsets[0].toInt();
int self_offset_v; int self_offset_v;
if (self_offsets.length() <= 1) if (self_offsets.length() <= 1) {
self_offset_v = 0; self_offset_v = 0;
else
self_offset_v = self_offsets[1].toInt();
ui_vp_player_char->move_and_center(ui_viewport->width() * self_offset / 100, ui_viewport->height() * self_offset_v / 100);
//If an effect is ignoring the users offset, we force it to the default position of the viewport.
if (ao_app->get_effect_property(play_effect[0], current_char, "ignore_offset") == "true") {
ui_vp_effect->move(ui_viewport->x(), ui_viewport->y());
return;
} }
else {
//Offset is not disabled, we move the effects layer to match the position of our character self_offset_v = self_offsets[1].toInt();
//We need to add the viewport as an offset as effects are not bound to it. ui_vp_player_char->move_and_center(ui_viewport->width() * self_offset / 100, ui_viewport->height() * self_offset_v / 100);
int effect_x = (ui_viewport->width() * self_offset / 100) + ui_viewport->x(); const int percent = 100;
int effect_y = (ui_viewport->height() * self_offset_v / 100) + ui_viewport->y(); ui_vp_player_char->move(ui_viewport->width() * self_offset / percent, ui_viewport->height() * self_offset_v / percent);
ui_vp_effect->move(effect_x, effect_y); }
} }
void Courtroom::set_ip_list(QString p_list) void Courtroom::set_ip_list(QString p_list)
@ -4607,9 +4648,17 @@ void Courtroom::set_effects_dropdown()
ui_effects_dropdown->hide(); ui_effects_dropdown->hide();
return; return;
} }
QStringList effectslist = ao_app->get_effects(current_char); QStringList effectslist;
QStringList char_effects = ao_app->get_effects(current_char);
for (int i = 0; i < char_effects.size(); ++i) {
QString effect = char_effects[i];
if (effect.contains(":")) {
effect = effect.section(':', 1);
}
effectslist.append(effect);
}
if (effectslist.size() <= 0) { if (effectslist.empty()) {
ui_effects_dropdown->hide(); ui_effects_dropdown->hide();
return; return;
} }

View File

@ -877,19 +877,18 @@ QStringList AOApplication::get_effects(QString p_char)
QString p_misc = read_char_ini(p_char, "effects", "Options"); QString p_misc = read_char_ini(p_char, "effects", "Options");
QString p_path = get_asset("effects/effects.ini", current_theme, get_subtheme(), default_theme, ""); QString p_path = get_asset("effects/effects.ini", current_theme, get_subtheme(), default_theme, "");
QString p_misc_path = get_asset("effects.ini", current_theme, get_subtheme(), default_theme, p_misc); QString p_misc_path = get_asset("effects.ini", current_theme, get_subtheme(), default_theme, p_misc);
QStringList effects; QSettings effects_config(p_path, QSettings::IniFormat);
effects_config.setIniCodec("UTF-8");
QStringList lines = read_file(p_path).split("\n"); QStringList effects = effects_config.childGroups();
// Misc path different from default path, stack the new miscs on top of the defaults std::sort(effects.begin(), effects.end(), [] (const QString &a, const QString &b) {return a.split(":")[0].toInt() < b.split(":")[0].toInt();});
if (p_misc_path != p_path) { if (p_path != p_misc_path) {
lines << read_file(p_misc_path).split("\n"); // If misc path is different from default path, stack the new miscs on top of the defaults
QSettings effects_config_misc(p_misc_path, QSettings::IniFormat);
effects_config_misc.setIniCodec("UTF-8");
QStringList misc_effects = effects_config_misc.childGroups();
std::sort(misc_effects.begin(), misc_effects.end(), [] (const QString &a, const QString &b) {return a.split(":")[0].toInt() < b.split(":")[0].toInt();});
effects += misc_effects;
} }
foreach (QString effect, lines) {
effect = effect.split("=")[0].trimmed().split("_")[0];
if (!effect.isEmpty() && !effects.contains(effect))
effects.append(effect);
}
return effects; return effects;
} }
@ -913,15 +912,31 @@ QString AOApplication::get_effect(QString effect, QString p_char,
QString AOApplication::get_effect_property(QString fx_name, QString p_char, QString AOApplication::get_effect_property(QString fx_name, QString p_char,
QString p_property) QString p_property)
{ {
QString f_property; const auto paths = get_asset_paths("effects/effects.ini", current_theme, get_subtheme(), default_theme, "");
if (p_property == "sound") const auto misc_paths = get_asset_paths("effects.ini", current_theme, get_subtheme(), default_theme, read_char_ini(p_char, "effects", "Options"));
f_property = fx_name; QString path;
else QString f_result;
f_property = fx_name + "_" + p_property; for (const VPath &p : paths + misc_paths) {
path = get_real_path(p);
QString f_result = get_config_value(f_property, "effects.ini", current_theme, get_subtheme(), default_theme, read_char_ini(p_char, "effects", "Options")); if (!path.isEmpty()) {
if (f_result == "") QSettings settings(path, QSettings::IniFormat);
f_result = get_config_value(f_property, "effects/effects.ini", current_theme, get_subtheme(), default_theme, ""); settings.setIniCodec("UTF-8");
QStringList char_effects = settings.childGroups();
for (int i = 0; i < char_effects.size(); ++i) {
QString effect = char_effects[i];
if (effect.contains(":")) {
effect = effect.section(':', 1);
}
if (effect.toLower() == fx_name.toLower()) {
f_result = settings.value(char_effects[i] + "/" + p_property).toString();
if (!f_result.isEmpty()) {
// Only break the loop if we get a non-empty result, continue the search otherwise
break;
}
}
}
}
}
if (fx_name == "realization" && p_property == "sound") { if (fx_name == "realization" && p_property == "sound") {
f_result = get_custom_realization(p_char); f_result = get_custom_realization(p_char);
} }