From 93cd2ad3747ff609e0aa2175a2622afe9ef6b56d Mon Sep 17 00:00:00 2001 From: Cerapter Date: Wed, 5 Sep 2018 17:21:27 +0200 Subject: [PATCH] Non-interrupting pres. --- courtroom.cpp | 132 +++++++++++++++++++++++++++++++++++++---- courtroom.h | 6 +- datatypes.h | 3 +- server/aoprotocol.py | 26 +++++++- server/area_manager.py | 7 ++- 5 files changed, 156 insertions(+), 18 deletions(-) diff --git a/courtroom.cpp b/courtroom.cpp index 435dcd3..dd6c160 100644 --- a/courtroom.cpp +++ b/courtroom.cpp @@ -178,6 +178,9 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_showname_enable->setChecked(ao_app->get_showname_enabled_by_default()); ui_showname_enable->setText("Custom shownames"); + ui_pre_non_interrupt = new QCheckBox(this); + ui_pre_non_interrupt->setText("No Intrpt"); + ui_custom_objection = new AOButton(this, ao_app); ui_realization = new AOButton(this, ao_app); ui_mute = new AOButton(this, ao_app); @@ -551,6 +554,9 @@ void Courtroom::set_widgets() set_size_and_pos(ui_pre, "pre"); ui_pre->setText("Pre"); + set_size_and_pos(ui_pre_non_interrupt, "pre_no_interrupt"); + ui_pre_non_interrupt->setText("No Intrpt"); + set_size_and_pos(ui_flip, "flip"); set_size_and_pos(ui_guard, "guard"); @@ -1012,7 +1018,8 @@ void Courtroom::on_chat_return_pressed() //showname# //other_charid# - //self_offset#% + //self_offset# + //noninterrupting_preanim#% QStringList packet_contents; @@ -1051,7 +1058,7 @@ void Courtroom::on_chat_return_pressed() 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; @@ -1134,6 +1141,22 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(QString::number(offset_with_pair)); } + if (ui_pre_non_interrupt->isChecked() and ui_pre->isChecked()) + { + if (ui_ic_chat_name->text().isEmpty()) + { + packet_contents.append(""); + } + + if (!(other_charid > -1 && other_charid != m_cid)) + { + packet_contents.append("-1"); + packet_contents.append("0"); + } + + packet_contents.append("1"); + } + ao_app->send_server_packet(new AOPacket("MS", packet_contents)); } @@ -1468,7 +1491,10 @@ void Courtroom::handle_chatmessage_2() qDebug() << "W: invalid emote mod: " << QString::number(emote_mod); //intentional fallthru case 0: case 5: - handle_chatmessage_3(); + if (m_chatmessage[NONINTERRUPTING_PRE].isEmpty()) + handle_chatmessage_3(); + else + play_noninterrupting_preanim(); } } @@ -1915,8 +1941,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); + + if (!file_exists(ao_app->get_character_path(f_char) + f_preanim.toLower() + ".gif") || + preanim_duration < 0) + { + anim_state = 4; + preanim_done(); + qDebug() << "could not find " + ao_app->get_character_path(f_char) + f_preanim.toLower() + ".gif"; + 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(); } @@ -1927,13 +1990,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 @@ -1992,8 +2056,11 @@ void Courtroom::chat_tick() if (tick_pos >= f_message.size()) { text_state = 2; - 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 @@ -2083,7 +2150,7 @@ void Courtroom::chat_tick() // Here, we check if the entire message is blue. // If it isn't, we stop talking. - if (!entire_message_is_blue) + if (!entire_message_is_blue and anim_state != 4) { QString f_char = m_chatmessage[CHAR_NAME]; QString f_emote = m_chatmessage[EMOTE]; @@ -2107,7 +2174,7 @@ void Courtroom::chat_tick() // If it isn't, we start talking if we have completely climbed out of inline blues. if (!entire_message_is_blue) { - if (inline_blue_depth == 0) + if (inline_blue_depth == 0 and anim_state != 4) { QString f_char = m_chatmessage[CHAR_NAME]; QString f_emote = m_chatmessage[EMOTE]; @@ -2566,18 +2633,23 @@ 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."); + } else if (ooc_message.startsWith("/rainbow") && ao_app->yellow_text_enabled && !rainbow_appended) { //ui_text_color->addItem("Rainbow"); ui_ooc_chat_message->clear(); //rainbow_appended = true; + append_server_chatmessage("CLIENT", "This does nohing, but there you go."); 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."); return; } else if (ooc_message.startsWith("/pair")) @@ -2590,7 +2662,21 @@ void Courtroom::on_ooc_return_pressed() 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); + } + else + { + append_server_chatmessage("CLIENT", "You are no longer paired with anyone."); + } + } + else + { + append_server_chatmessage("CLIENT", "Are you sure you typed that well? The char ID could not be recognised."); } return; } @@ -2604,18 +2690,34 @@ void Courtroom::on_ooc_return_pressed() 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); + } + else + { + append_server_chatmessage("CLIENT", "Your offset must be between -100% and 100%!"); + } + } + else + { + append_server_chatmessage("CLIENT", "That offset does not look like one."); } return; } else if (ooc_message.startsWith("/switch_am")) { + append_server_chatmessage("CLIENT", "You switched your music and area list."); 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."); ao_app->shownames_enabled = true; ao_app->charpairs_enabled = true; ao_app->arup_enabled = true; @@ -2624,6 +2726,16 @@ void Courtroom::on_ooc_return_pressed() 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."); + else + append_server_chatmessage("CLIENT", "Your pre-animations will not interrupt text."); + ui_pre_non_interrupt->setChecked(!ui_pre_non_interrupt->isChecked()); + ui_ooc_chat_message->clear(); + return; + } QStringList packet_contents; packet_contents.append(ui_ooc_chat_name->text()); diff --git a/courtroom.h b/courtroom.h index 19a19ea..d15dde0 100644 --- a/courtroom.h +++ b/courtroom.h @@ -184,6 +184,7 @@ public: 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, int variant); @@ -298,7 +299,7 @@ private: //every time point in char.inis times this equals the final time const int time_mod = 40; - static const int chatmessage_size = 22; + static const int chatmessage_size = 23; QString m_chatmessage[chatmessage_size]; bool chatmessage_is_empty = false; @@ -319,7 +320,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 @@ -451,6 +452,7 @@ private: QCheckBox *ui_flip; QCheckBox *ui_guard; + QCheckBox *ui_pre_non_interrupt; QCheckBox *ui_showname_enable; AOButton *ui_custom_objection; diff --git a/datatypes.h b/datatypes.h index 63ad836..aaa5de5 100644 --- a/datatypes.h +++ b/datatypes.h @@ -99,7 +99,8 @@ enum CHAT_MESSAGE OTHER_EMOTE, SELF_OFFSET, OTHER_OFFSET, - OTHER_FLIP + OTHER_FLIP, + NONINTERRUPTING_PRE }; enum COLOR diff --git a/server/aoprotocol.py b/server/aoprotocol.py index d7a2c6c..d8d91d2 100644 --- a/server/aoprotocol.py +++ b/server/aoprotocol.py @@ -346,6 +346,7 @@ class AOProtocol(asyncio.Protocol): showname = "" charid_pair = -1 offset_pair = 0 + nonint_pre = '' elif self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.INT, @@ -355,6 +356,7 @@ class AOProtocol(asyncio.Protocol): msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname = args charid_pair = -1 offset_pair = 0 + nonint_pre = '' if len(showname) > 0 and not self.client.area.showname_changes_allowed: self.client.send_host_message("Showname changes are forbidden in this area!") return @@ -363,8 +365,19 @@ class AOProtocol(asyncio.Protocol): self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.INT, self.ArgType.INT): - # 1.4.0 validation monstrosity. + # 1.3.5 validation monstrosity. msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair = args + nonint_pre = '' + if len(showname) > 0 and not self.client.area.showname_changes_allowed: + self.client.send_host_message("Showname changes are forbidden in this area!") + return + elif self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, self.ArgType.STR, + self.ArgType.STR, + self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.INT, + self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, + self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT): + # 1.4.0 validation monstrosity. + msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair, nonint_pre = args if len(showname) > 0 and not self.client.area.showname_changes_allowed: self.client.send_host_message("Showname changes are forbidden in this area!") return @@ -383,7 +396,7 @@ class AOProtocol(asyncio.Protocol): if text.isspace(): self.client.send_host_message("Blankposting is forbidden in this area, and putting more spaces in does not make it not blankposting.") return - if len(text.replace(' ', '')) < 3 and text != '<' and text != '>': + if len(re.sub(r'[{}\\`|]','', text).replace(' ', '')) < 3 and text != '<' and text != '>': self.client.send_host_message("While that is not a blankpost, it is still pretty spammy. Try forming sentences.") return if msg_type not in ('chat', '0', '1'): @@ -405,6 +418,13 @@ class AOProtocol(asyncio.Protocol): if len(showname) > 15: self.client.send_host_message("Your IC showname is way too long!") return + if self.client.area.non_int_pres_only: + if anim_type == 1 or anim_type == 2: + anim_type = 0 + nonint_pre = 1 + elif anim_type == 6: + anim_type = 5 + nonint_pre = 1 if not self.client.area.shouts_allowed: # Old clients communicate the objecting in anim_type. if anim_type == 2: @@ -471,7 +491,7 @@ class AOProtocol(asyncio.Protocol): self.client.area.send_command('MS', msg_type, pre, folder, anim, msg, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, - charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip) + charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre) self.client.area.set_next_msg_delay(len(msg)) logger.log_server('[IC][{}][{}]{}'.format(self.client.area.abbreviation, self.client.get_char_name(), msg), self.client) diff --git a/server/area_manager.py b/server/area_manager.py index 6e024f6..23c4339 100644 --- a/server/area_manager.py +++ b/server/area_manager.py @@ -26,7 +26,7 @@ from server.evidence import EvidenceList class AreaManager: class Area: - def __init__(self, area_id, server, name, background, bg_lock, evidence_mod = 'FFA', locking_allowed = False, iniswap_allowed = True, showname_changes_allowed = False, shouts_allowed = True, jukebox = False, abbreviation = ''): + def __init__(self, area_id, server, name, background, bg_lock, evidence_mod = 'FFA', locking_allowed = False, iniswap_allowed = True, showname_changes_allowed = False, shouts_allowed = True, jukebox = False, abbreviation = '', non_int_pres_only = False): self.iniswap_allowed = iniswap_allowed self.clients = set() self.invite_list = {} @@ -65,6 +65,7 @@ class AreaManager: self.is_locked = False self.blankposting_allowed = True + self.non_int_pres_only = non_int_pres_only self.jukebox = jukebox self.jukebox_votes = [] self.jukebox_prev_char_id = -1 @@ -305,10 +306,12 @@ class AreaManager: item['shouts_allowed'] = True if 'jukebox' not in item: item['jukebox'] = False + if 'noninterrupting_pres' not in item: + item['noninterrupting_pres'] = False if 'abbreviation' not in item: item['abbreviation'] = self.get_generated_abbreviation(item['area']) self.areas.append( - self.Area(self.cur_id, self.server, item['area'], item['background'], item['bglock'], item['evidence_mod'], item['locking_allowed'], item['iniswap_allowed'], item['showname_changes_allowed'], item['shouts_allowed'], item['jukebox'], item['abbreviation'])) + self.Area(self.cur_id, self.server, item['area'], item['background'], item['bglock'], item['evidence_mod'], item['locking_allowed'], item['iniswap_allowed'], item['showname_changes_allowed'], item['shouts_allowed'], item['jukebox'], item['abbreviation'], item['noninterrupting_pres'])) self.cur_id += 1 def default_area(self):