diff --git a/include/aoapplication.h b/include/aoapplication.h index 776a5f1..8bd0781 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -1,8 +1,11 @@ #ifndef AOAPPLICATION_H #define AOAPPLICATION_H +#define UNUSED(x) (void)(x) + #include "aopacket.h" #include "datatypes.h" +#include "demoserver.h" #include "discord_rich_presence.h" #include "bass.h" @@ -28,6 +31,8 @@ #include #include +#include + class NetworkManager; class Lobby; class Courtroom; @@ -129,6 +134,7 @@ public: QString get_default_theme_path(QString p_file); QString get_custom_theme_path(QString p_theme, QString p_file); QString get_character_path(QString p_char, QString p_file); + QString get_misc_path(QString p_misc, QString p_file); QString get_sounds_path(QString p_file); QString get_music_path(QString p_song); QString get_background_path(QString p_file); @@ -223,6 +229,9 @@ public: // Current wait time between messages for the queue system int stay_time(); + // Returns Minimum amount of time (in miliseconds) that must pass before the next Enter key press will send your IC message. (new behaviour) + int get_chat_ratelimit(); + // Returns whether the log should go upwards (new behaviour) // or downwards (vanilla behaviour). bool get_log_goes_downwards(); @@ -265,6 +274,9 @@ public: // directory if it doesn't exist. bool append_to_file(QString p_text, QString p_file, bool make_dir = false); + // Append to the currently open demo file if there is one + void append_to_demofile(QString packet_string); + // Appends the argument string to serverlist.txt void write_to_serverlist_txt(QString p_line); @@ -294,14 +306,14 @@ public: // Returns the color with p_identifier from p_file QColor get_color(QString p_identifier, QString p_file); - // Returns the markdown symbol used for specified p_identifier such as colors - QString get_chat_markdown(QString p_identifier, QString p_file); + // Returns the markup symbol used for specified p_identifier such as colors + QString get_chat_markup(QString p_identifier, QString p_file); // Returns the color from the misc folder. QColor get_chat_color(QString p_identifier, QString p_chat); // Returns the sfx with p_identifier from sounds.ini in the current theme path - QString get_sfx(QString p_identifier); + QString get_sfx(QString p_identifier, QString p_misc="default"); // Figure out if we can opus this or if we should fall back to wav QString get_sfx_suffix(QString sound_to_check); @@ -337,6 +349,9 @@ public: // Returns the showname from the ini of p_char QString get_showname(QString p_char); + // Returns the category of this character + QString get_category(QString p_char); + // Returns the value of chat image from the specific p_char's ini file QString get_chat(QString p_char); @@ -370,9 +385,9 @@ public: // t QString get_effect(QString effect, QString p_char, QString p_folder); - // Return the effect sound associated with the fx_name in the - // misc/effects//sounds.ini, or theme/effects/sounds.ini. - QString get_effect_sound(QString fx_name, QString p_char); + // Return p_property of fx_name. If p_property is "sound", return + // the value associated with fx_name, otherwise use fx_name + '_' + p_property. + QString get_effect_property(QString fx_name, QString p_char, QString p_property); // Returns the custom realisation used by the character. QString get_custom_realization(QString p_char); @@ -422,6 +437,15 @@ public: // Returns p_char's blips (previously called their "gender") QString get_blips(QString p_char); + // Get a property of a given emote, or get it from "options" if emote doesn't have it + QString get_emote_property(QString p_char, QString p_emote, QString p_property); + + // Return a transformation mode from a string ("smooth" for smooth, anything else for fast) + Qt::TransformationMode get_scaling(QString p_scaling); + + // Returns the scaling type for p_miscname + Qt::TransformationMode get_misc_scaling(QString p_miscname); + // ====== // These are all casing-related settings. // ====== @@ -462,6 +486,9 @@ public: void *user); static void doBASSreset(); + QElapsedTimer demo_timer; + DemoServer* demo_server = nullptr; + private: const int RELEASE = 2; const int MAJOR_VERSION = 8; diff --git a/include/aocharmovie.h b/include/aocharmovie.h deleted file mode 100644 index 2dda0ec..0000000 --- a/include/aocharmovie.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef AOCHARMOVIE_H -#define AOCHARMOVIE_H - -#include -#include -#include -#include -#include - -class AOApplication; - -class AOCharMovie : public QLabel { - Q_OBJECT - -public: - AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app); - - // Play a hat.gif - style preanimation - void play_pre(QString p_char, QString p_emote, int duration); - - // Play a (b)normal.gif - style animation (talking) - void play_talking(QString p_char, QString p_emote); - - // Play an (a)normal.gif - style animation (not talking) - void play_idle(QString p_char, QString p_emote); - - // Stop the movie, clearing the image - void stop(); - - // Set the m_flipped variable to true/false - void set_flipped(bool p_flipped) { m_flipped = p_flipped; } - - // Set the movie's playback speed (between 10% and 1000%) - void set_speed(int modifier) { speed = qMax(10, qMin(modifier, 1000)); } - - // Move the label itself around - void move(int ax, int ay); - - // This is somewhat pointless now as there's no "QMovie" object to resize, aka - // no "combo" to speak of - void combo_resize(int w, int h); - - // Return the frame delay adjusted for speed - int get_frame_delay(int delay); - - QStringList network_strings; - - QString m_char; - QString m_emote; - -private: - AOApplication *ao_app; - - QVector movie_frames; - QVector movie_delays; - - // Effects such as sfx, screenshakes and realization flashes are stored in - // here. QString entry format: "sfx^[sfx_name]", "shake", "flash". The program - // uses the QVector index as reference. - QVector> movie_effects; - - QTimer *preanim_timer; - QTimer *ticker; - QString last_path; - QImageReader *m_reader = new QImageReader(); - - QElapsedTimer actual_time; - - // Usually used to turn seconds into milliseconds such as for [Time] tag in - // char.ini - const int time_mod = 60; - - // These are the X and Y values before they are fixed based on the sprite's - // width. - int x = 0; - int y = 0; - // These are the width and height values before they are fixed based on the - // sprite's width. - int f_w = 0; - int f_h = 0; - - int frame = 0; - int max_frames = 0; - - int speed = 100; - - bool m_flipped = false; - bool play_once = true; - - // Set the movie's image to provided paths, preparing for playback. - void load_image(QString p_char, QString p_emote, QString emote_prefix); - - // Start playback of the movie (if animated). - void play(); - - // Play a frame-specific effect, if there's any defined for that specific - // frame. - void play_frame_effect(int frame); - - // Retreive a pixmap adjused for mirroring/aspect ratio shenanigans from a - // provided QImage - QPixmap get_pixmap(QImage image); - - // Set the movie's frame to provided pixmap - void set_frame(QPixmap f_pixmap); - - // Initialize the frame-specific effects from the char.ini - void load_effects(); - - // Initialize the frame-specific effects from the provided network_strings, - // this is only initialized if network_strings has size more than 0. - void load_network_effects(); - -signals: - void done(); - void shake(); - void flash(); - void play_sfx(QString sfx); - -private slots: - void preanim_done(); - void movie_ticker(); -}; - -#endif // AOCHARMOVIE_H diff --git a/include/aoevidencedisplay.h b/include/aoevidencedisplay.h index 979a754..ff448c9 100644 --- a/include/aoevidencedisplay.h +++ b/include/aoevidencedisplay.h @@ -2,7 +2,7 @@ #define AOEVIDENCEDISPLAY_H #include "aoapplication.h" -#include "aomovie.h" +#include "aolayer.h" #include "aosfxplayer.h" #include @@ -21,7 +21,7 @@ public: private: AOApplication *ao_app; - AOMovie *evidence_movie; + InterfaceLayer *evidence_movie; QLabel *evidence_icon; AOSfxPlayer *sfx_player; diff --git a/include/aolayer.h b/include/aolayer.h new file mode 100644 index 0000000..6265cec --- /dev/null +++ b/include/aolayer.h @@ -0,0 +1,221 @@ +#ifndef AOLAYER_H +#define AOLAYER_H + +#include +#include +#include +#include +#include +#include + +class AOApplication; + +class AOLayer : public QLabel { + Q_OBJECT + +public: + AOLayer(QWidget *p_parent, AOApplication *p_ao_app); + + QString filename; // file name without extension, i.e. "witnesstestimony" + int static_duration; // time in ms for static images to be displayed, if + // applicable. set to 0 for infinite + int max_duration; // maximum duration in ms, image will be culled if it is + // exceeded. set this to 0 for infinite duration + bool play_once = false; // Whether to loop this animation or not + bool cull_image = true; // if we're done playing this animation, should we + // hide it? also controls durational culling + Qt::TransformationMode transform_mode = Qt::FastTransformation; // transformation mode to use for this image + bool stretch = false; // Should we stretch/squash this image to fill the screen? + + // Set the movie's image to provided paths, preparing for playback. + void start_playback(QString p_image); + + void set_play_once(bool p_play_once); + void set_cull_image(bool p_cull_image); + void set_static_duration(int p_static_duration); + void set_max_duration(int p_max_duration); + + // Stop the movie, clearing the image + void stop(); + + // Set the m_flipped variable to true/false + void set_flipped(bool p_flipped) { m_flipped = p_flipped; } + + // Set the movie's playback speed (between 10% and 1000%) + void set_speed(int modifier) { speed = qMax(10, qMin(modifier, 1000)); } + + // Move the label itself around + void move(int ax, int ay); + + // This is somewhat pointless now as there's no "QMovie" object to resize, aka + // no "combo" to speak of + void combo_resize(int w, int h); + + // Return the frame delay adjusted for speed + int get_frame_delay(int delay); + + // iterate through a list of paths and return the first entry that exists. if + // none exist, return NULL (safe because we check again for existence later) + QString find_image(QList p_list); + +protected: + AOApplication *ao_app; + QVector movie_frames; + QVector movie_delays; + + QTimer *preanim_timer; + QTimer *shfx_timer; + QTimer *ticker; + QString last_path; + QImageReader m_reader; + + QElapsedTimer actual_time; + + // Usually used to turn seconds into milliseconds such as for [Time] tag in + // char.ini + const int tick_ms = 60; + + // These are the X and Y values before they are fixed based on the sprite's + // width. + int x = 0; + int y = 0; + // These are the width and height values before they are fixed based on the + // sprite's width. + int f_w = 0; + int f_h = 0; + + int frame = 0; + int max_frames = 0; + int last_max_frames = 0; + + int speed = 100; + + bool m_flipped = false; + // Are we loading this from the same frame we left off on? TODO: actually make + // this work + bool continuous = false; + // Whether or not to forcibly bypass the simple check done by start_playback + // and use the existent value of continuous instead + bool force_continuous = false; + + int duration = 0; + + // Start playback of the movie (if animated). + void play(); + + // Freeze the movie at the current frame. + void freeze(); + + // Retreive a pixmap adjused for mirroring/aspect ratio shenanigans from a + // provided QImage + QPixmap get_pixmap(QImage image); + + // Set the movie's frame to provided pixmap + void set_frame(QPixmap f_pixmap); + +signals: + void done(); + +protected slots: + virtual void preanim_done(); + void shfx_timer_done(); + virtual void movie_ticker(); +}; + +class BackgroundLayer : public AOLayer { + Q_OBJECT +public: + BackgroundLayer(QWidget *p_parent, AOApplication *p_ao_app); + void load_image(QString p_filename); +}; + +class ForegroundLayer : public AOLayer { + Q_OBJECT +public: + ForegroundLayer(QWidget *p_parent, AOApplication *p_ao_app); + QString miscname; //'misc' folder to search. we fetch this based on p_charname below + void load_image(QString p_filename, QString p_charname); +}; + +class CharLayer : public AOLayer { + Q_OBJECT +public: + CharLayer(QWidget *p_parent, AOApplication *p_ao_app); + QString current_emote = ""; // name of the emote we're using + bool is_preanim; // equivalent to the old play_once, if true we don't want + // to loop this + QString prefix = ""; // prefix, left blank if it's a preanim + + void load_image(QString p_filename, QString p_charname, int p_duration, bool p_is_preanim); + void play(); // overloaded so we can play effects + + // networked frame fx string + QStringList network_strings; + +private: + QString last_char; // name of the last character we used + QString last_emote; // name of the last animation we used + QString last_prefix; // prefix of the last animation we played + bool was_preanim = false; // whether is_preanim was true last time + + // Effects such as sfx, screenshakes and realization flashes are stored in + // here. QString entry format: "sfx^[sfx_name]", "shake", "flash". The program + // uses the QVector index as reference. + QVector> movie_effects; + + // used for effect loading + QString m_char = ""; + QString m_emote = ""; + + // overloaded for effects reasons + void start_playback(QString p_image); + + // Initialize the frame-specific effects from the char.ini + void load_effects(); + + // Initialize the frame-specific effects from the provided network_strings, + // this is only initialized if network_strings has size more than 0. + void load_network_effects(); + + // Play a frame-specific effect, if there's any defined for that specific + // frame. + void play_frame_effect(int p_frame); + +private slots: + void preanim_done() override; // overridden so we don't accidentally cull characters + void movie_ticker() override; // overridden so we can play effects + +signals: + void shake(); + void flash(); + void play_sfx(QString sfx); +}; + +class InterjectionLayer : public AOLayer { + Q_OBJECT +public: + InterjectionLayer(QWidget *p_parent, AOApplication *p_ao_app); + void load_image(QString p_filename, QString p_charname, QString p_miscname); +}; + +class EffectLayer : public AOLayer { + Q_OBJECT +public: + EffectLayer(QWidget *p_parent, AOApplication *p_ao_app); + void load_image(QString p_filename, bool p_looping); +}; + +class InterfaceLayer : public AOLayer { + Q_OBJECT +public: + InterfaceLayer(QWidget *p_parent, AOApplication *p_ao_app); + void load_image(QString p_filename, QString p_miscname); +}; + +class StickerLayer : public AOLayer { + Q_OBJECT +public: + StickerLayer(QWidget *p_parent, AOApplication *p_ao_app); + void load_image(QString p_charname); +}; +#endif // AOLAYER_H diff --git a/include/aomovie.h b/include/aomovie.h deleted file mode 100644 index eb7f7a5..0000000 --- a/include/aomovie.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef AOMOVIE_H -#define AOMOVIE_H - -#include -#include - -class Courtroom; -class AOApplication; - -class AOMovie : public QLabel { - Q_OBJECT - -public: - AOMovie(QWidget *p_parent, AOApplication *p_ao_app); - - void set_play_once(bool p_play_once); - void play(QString p_image, QString p_char = "", QString p_custom_theme = "", - int default_duration = 0); - void combo_resize(int w, int h); - void stop(); - -private: - QMovie *m_movie; - AOApplication *ao_app; - QTimer *timer; - bool play_once = true; - -signals: - void done(); - -private slots: - void frame_change(int n_frame); - void timer_done(); -}; - -#endif // AOMOVIE_H diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 93b6677..74fc9af 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -58,6 +58,8 @@ private: QCheckBox *ui_desync_logs_cb; QLabel *ui_instant_objection_lbl; QCheckBox *ui_instant_objection_cb; + QLabel *ui_chat_ratelimit_lbl; + QSpinBox *ui_chat_ratelimit_spinbox; QLabel *ui_log_ic_actions_lbl; QCheckBox *ui_log_ic_actions_cb; QFrame *ui_log_names_divider; diff --git a/include/aopacket.h b/include/aopacket.h index 6d1deba..794025c 100644 --- a/include/aopacket.h +++ b/include/aopacket.h @@ -12,7 +12,7 @@ public: QString get_header() { return m_header; } QStringList &get_contents() { return m_contents; } - QString to_string(); + QString to_string(bool encoded = false); void net_encode(); void net_decode(); diff --git a/include/aoscene.h b/include/aoscene.h deleted file mode 100644 index 726e264..0000000 --- a/include/aoscene.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef AOSCENE_H -#define AOSCENE_H - -#include -#include -#include - -class Courtroom; -class AOApplication; - -class AOScene : public QLabel { - Q_OBJECT -public: - explicit AOScene(QWidget *parent, AOApplication *p_ao_app); - - void set_image(QString p_image); - void set_legacy_desk(QString p_image); - - // Move the label itself around - void move(int ax, int ay); - - // This is somewhat pointless now as there's no "QMovie" object to resize, aka - // no "combo" to speak of - void combo_resize(int w, int h); - -private: - QWidget *m_parent; - QMovie *m_movie; - AOApplication *ao_app; - QString last_image; - - // These are the X and Y values before they are fixed based on the sprite's - // width. - int x = 0; - int y = 0; - // These are the width and height values before they are fixed based on the - // sprite's width. - int f_w = 0; - int f_h = 0; -}; - -#endif // AOSCENE_H diff --git a/include/courtroom.h b/include/courtroom.h index d996715..0dcc53d 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -5,18 +5,16 @@ #include "aoblipplayer.h" #include "aobutton.h" #include "aocharbutton.h" -#include "aocharmovie.h" #include "aoclocklabel.h" #include "aoemotebutton.h" #include "aoevidencebutton.h" #include "aoevidencedisplay.h" #include "aoimage.h" +#include "aolayer.h" #include "aolineedit.h" -#include "aomovie.h" #include "aomusicplayer.h" #include "aooptionsdialog.h" #include "aopacket.h" -#include "aoscene.h" #include "aosfxplayer.h" #include "aotextarea.h" #include "aotextedit.h" @@ -152,6 +150,9 @@ public: // reads theme inis and sets size and pos based on the identifier void set_size_and_pos(QWidget *p_widget, QString p_identifier); + // reads theme and char inis and sets size and pos based on the identifier + void set_size_and_pos(QWidget *p_widget, QString p_identifier, QString p_char); + // reads theme inis and returns the size and pos as defined by it QPoint get_theme_pos(QString p_identifier); @@ -225,11 +226,13 @@ public: // Parse the chat message packet and unpack it into the m_chatmessage[ITEM] format void unpack_chatmessage(QStringList p_contents); - // Log the message contents and information such as evidence presenting etc. into the log file - void log_chatmessage(QString f_message, int f_char_id, QString f_showname = "", int f_color = 0); - - // Display the message contents and information such as evidence presenting etc. in the IC logs - void display_log_chatmessage(QString f_message, int f_char_id, QString f_showname = "", int f_color = 0); + enum LogMode { + IO_ONLY, + DISPLAY_ONLY, + DISPLAY_AND_IO + }; + // Log the message contents and information such as evidence presenting etc. into the log file, the IC log, or both. + void log_chatmessage(QString f_message, int f_char_id, QString f_showname = "", int f_color = 0, LogMode f_log_mode=IO_ONLY); // Log the message contents and information such as evidence presenting etc. into the IC logs void handle_callwords(); @@ -265,7 +268,8 @@ 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); + 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 @@ -357,6 +361,7 @@ private: QVector arup_locks; QVector ic_chatlog_history; + QString last_ic_message = ""; QQueue chatmessage_queue; @@ -392,7 +397,8 @@ private: // True, if log should display colors. bool log_colors = true; - // True, if the log should display the message like name
text instead of name: text + // True, if the log should display the message like name
text instead of + // name: text bool log_newline = false; // True, if the log should include RP actions like interjections, showing evidence, etc. @@ -420,16 +426,21 @@ private: const int time_mod = 40; // the amount of time non-animated objection/hold it/takethat images stay - // onscreen for in ms - const int shout_stay_time = 724; + // onscreen for in ms, and the maximum amount of time any interjections are + // allowed to play + const int shout_static_time = 724; + const int shout_max_time = 1500; // the amount of time non-animated guilty/not guilty images stay onscreen for - // in ms - const int verdict_stay_time = 3000; + // in ms, and the maximum amount of time g/ng images are allowed to play + const int verdict_static_time = 3000; + const int verdict_max_time = 4000; // the amount of time non-animated witness testimony/cross-examination images - // stay onscreen for in ms - const int wtce_stay_time = 1500; + // stay onscreen for in ms, and the maximum time any wt/ce image is allowed to + // play + const int wtce_static_time = 1500; + const int wtce_max_time = 4000; // characters we consider punctuation const QString punctuation_chars = ".,?!:;"; @@ -453,7 +464,7 @@ private: bool is_muted = false; // state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = - // noniterrupting preanim + // noniterrupting preanim, 5 = (c) animation int anim_state = 3; // whether or not current color is a talking one @@ -516,8 +527,15 @@ private: // List of all currently available pos QStringList pos_dropdown_list; + // Current list file sorted line by line + QStringList sound_list; + + // Current SFX the user put in for the sfx dropdown list + QString custom_sfx = ""; + // is the message we're about to send supposed to present evidence? bool is_presenting_evidence = false; + bool c_played = false; // whether we've played a (c)-style postanimation yet // have we already presented evidence for this message? bool evidence_presented = false; @@ -585,21 +603,20 @@ private: AOImage *ui_background; QWidget *ui_viewport; - AOScene *ui_vp_background; - AOMovie *ui_vp_speedlines; - AOCharMovie *ui_vp_player_char; - AOCharMovie *ui_vp_sideplayer_char; - AOScene *ui_vp_desk; - AOScene *ui_vp_legacy_desk; + BackgroundLayer *ui_vp_background; + ForegroundLayer *ui_vp_speedlines; + CharLayer *ui_vp_player_char; + CharLayer *ui_vp_sideplayer_char; + BackgroundLayer *ui_vp_desk; AOEvidenceDisplay *ui_vp_evidence_display; AOImage *ui_vp_chatbox; QLabel *ui_vp_showname; - AOMovie *ui_vp_chat_arrow; + InterfaceLayer *ui_vp_chat_arrow; QTextEdit *ui_vp_message; - AOMovie *ui_vp_effect; - AOMovie *ui_vp_testimony; - AOMovie *ui_vp_wtce; - AOMovie *ui_vp_objection; + EffectLayer *ui_vp_effect; + InterfaceLayer *ui_vp_testimony; + InterjectionLayer *ui_vp_wtce; + InterjectionLayer *ui_vp_objection; QTextEdit *ui_ic_chatlog; @@ -611,7 +628,9 @@ private: QTreeWidget *ui_music_list; ScrollText *ui_music_name; - AOMovie *ui_music_display; + InterfaceLayer *ui_music_display; + + StickerLayer *ui_vp_sticker; static const int max_clocks = 5; AOClockLabel *ui_clock[max_clocks]; @@ -724,6 +743,9 @@ private: AOImage *ui_char_select_background; + // pretty list of characters + QTreeWidget *ui_char_list; + // abstract widget to hold char buttons QWidget *ui_char_buttons; @@ -765,6 +787,7 @@ private: void regenerate_ic_chatlog(); public slots: void objection_done(); + void effect_done(); void preanim_done(); void do_screenshake(); void do_flash(); @@ -820,6 +843,7 @@ private slots: void on_iniswap_remove_clicked(); void on_sfx_dropdown_changed(int p_index); + void on_sfx_dropdown_custom(QString p_sfx); void set_sfx_dropdown(); void on_sfx_context_menu_requested(const QPoint &pos); void on_sfx_edit_requested(); @@ -916,6 +940,7 @@ private slots: void on_back_to_lobby_clicked(); + void on_char_list_double_clicked(QTreeWidgetItem *p_item, int column); void on_char_select_left_clicked(); void on_char_select_right_clicked(); void on_char_search_changed(); diff --git a/include/demoserver.h b/include/demoserver.h new file mode 100644 index 0000000..b21811b --- /dev/null +++ b/include/demoserver.h @@ -0,0 +1,55 @@ +#ifndef DEMOSERVER_H +#define DEMOSERVER_H + +#include "aopacket.h" + +#include +#include +#include +#include +#include +#include +#include + +class DemoServer : public QObject +{ + Q_OBJECT +public: + explicit DemoServer(QObject *parent = nullptr); + + bool server_started = false; + int port = 27088; + int max_wait = -1; + int min_wait = -1; + +private: + void handle_packet(AOPacket packet); + void load_demo(QString filename); + + QTcpServer* tcp_server; + QTcpSocket* client_sock = nullptr; + bool client_connected = false; + bool partial_packet = false; + QString temp_packet = ""; + QQueue demo_data; + QString sc_packet; + int num_chars = 0; + QString p_path; + QTimer *timer; + int elapsed_time = 0; + +private slots: + void accept_connection(); + void destroy_connection(); + void recv_data(); + void client_disconnect(); + void playback(); + +public slots: + void start_server(); + +signals: + +}; + +#endif // DEMOSERVER_H diff --git a/resource/translations/ao_de.qm b/resource/translations/ao_de.qm index 6fd250d..0025260 100644 Binary files a/resource/translations/ao_de.qm and b/resource/translations/ao_de.qm differ diff --git a/resource/translations/ao_de.ts b/resource/translations/ao_de.ts index c4e96b9..f29d855 100644 --- a/resource/translations/ao_de.ts +++ b/resource/translations/ao_de.ts @@ -27,7 +27,7 @@ Wir verwenden mehrere Master Server um Ausfälle zu verhindern, jedoch hat der C Bitte prüfe deine Internetverbindung und Firewall, und versuche es erneut. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. Version zu alt! Deine Version: %1 @@ -40,54 +40,51 @@ Have a nice day. Schönen Urlaub. - + Attorney Online 2 Attorney Online 2 - + Loading Laden - Loading evidence: %1/%2 - Lade Beweisstücke: + Lade Beweisstücke: %1/%2 - - + Loading music: %1/%2 Lade Musik: %1/%2 - - + Loading chars: %1/%2 Lade Charaktere: %1/%2 - + You have been kicked from the server. Reason: %1 Du wurdest von diesem Server geschmissen. Grund: %1 - + You have been banned from the server. Reason: %1 Du wurdest von diesem Server verbannt. Grund: %1 - + You are banned on this server. Reason: %1 Du bist von diesem Server verbannt. @@ -239,42 +236,112 @@ Grund: Die Menge an Nachrichten die aufgehoben werden bevor alte gelöscht werden. 0 bedeutet unendlich. - + + Log newline: + Absätze protokollieren: + + + + 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'. + Wenn Nachrichten mehrere Zeilen enthalten wird dies mitprotokolliert. + + + + Log margin: + Protokollabstand: + + + + The distance in pixels between each entry in the IC log. Default: 0. + Setzt den Abstand zwischen den Zeilen im Protokoll. Standard: 0. + + + + Log timestamp: + Zeitstempel: + + + + If ticked, log will contain a timestamp in UTC before the name. + Das Protokoll enthält vor dem Namen einen Zeitstempel in UTC. + + + + Log IC actions: + Aktionen protokollieren: + + + + If ticked, log will show IC actions such as shouting and presenting evidence. + Protokolliert Charakteraktionen wie Zwischenrufe und Beweisstücke. + + + + Text Stay Time: + Standzeit: + + + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behaivor. + Minimale Zeit (in Milisekunden) die eine Nachricht auf dem Bildschirm bleibt bevor die nächste gezeigt wird. 0 deaktiviert dies. + + + + Desynchronize IC Logs: + Protokoll desynchronisieren: + + + + If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). + Wenn angehakt werden die Nachrichten sofort im Protokoll angezeigt, ansonsten wartet es auf den Chat. + + + + Instant Objection: + Zwischenrufe sofort: + + + + If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up. + Wenn die Standzeit länger als 0 ist überspringen Zwischenrufe die Warteschleife. + + + Default username: Standard Benutzername: - + Your OOC name will be automatically set to this value when you join a server. Dein OOC Name wird automatisch auf dies gesetzt. - + Custom shownames: Eigener Anzeigename: - + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. Standardwert für die Anzeigename Box, welche den In-Charakter Namen bestimmt. - + Backup MS: Rückfall MS: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Wenn dereingebaute Master Server fehlschlägt, wird das Spiel diesen hier verwenden. - + Discord: Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Erlaubt anderen auf Discord zu sehen auf welchem Server du spielst, welchen Charakter du spielst und wie lange. @@ -287,12 +354,12 @@ Grund: Erlaubt schütteln des Bildschirms und weiße Blitze. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. - + Language: Sprache: - + Sets the language if you don't want to use your system language. Setzte die Sprache falls du nicht die Systemsprache verwenden möchtest. @@ -313,271 +380,291 @@ Grund: Aktivieren damit die Blips bei Satzzeichen langsamer werden. - + - Keep current setting - aktuelle Einstellung behalten - + Allow Screenshake: Schütteln erlauben: - + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. Erlaubt schütteln des Bildschirms. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. - + Allow Effects: Effekte erlauben: - + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. Erlaubt Bildeffekte. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. - + Network Frame Effects: Netzwerk Frame-Effekte: - + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. Sendet schüttel, Blitze und Geräusche aus der char.ini Datei über das Netzwerk. Funkioniert nur wenn der Server dies unterstützt. - + Colors in IC Log: Farben im IC Log: - + Use the markup colors in the server IC chatlog. Verwendet Farbe im IC Log so wie im Bild. - + Sticky Sounds: Klebende Geräuschauswahl: - + Turn this on to prevent the sound dropdown from clearing the sound after playing it. Aktiviere dies damit die Geräuschauswahl nicht zurückspringt nachdem es abgespielt wurde. - + Sticky Effects: Klebende Effekt: - + Turn this on to prevent the effects dropdown from clearing the effect after playing it. Aktiviere dies damit die Effektauswahl nicht zurückspringt nachdem er abgespielt wurde. - + Sticky Preanims: Klebende Voranimation: - + Turn this on to prevent preanimation checkbox from clearing after playing the emote. Aktiviere dies damit das Kontrollkästchen für die Voranimation nicht zurückspringt nachdem sie abgespielt wurde. - + + Custom Chatboxes: + Eigene Chatboxen: + + + + Turn this on to allow characters to define their own custom chat box designs. + Charaktere können ihre eigenen Chatboxen verwenden. + + + Callwords Alarmwörter - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Gib so viele Alarmwörter ein wie du möchtest. Groß/Kleinschreibung ist egal. Für jede Wort nur eine Zeile!<br>Bitte keine leere Zeile am Ende -- du bekommst sonst bei jeder Nachricht einen Alarm.</body></html> - + Audio Audio - + Audio device: Audiogerät: - + Sets the audio device for all sounds. Setzt das Audiogerät für all Geräusche. - + Music: Musik: - + Sets the music's default volume. Setzt die Musiklautstärke. - + SFX: SFX: - + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. Setzt die Lautstärke der Soundeffekte wie Einsprüche und die Geräusche der Charaktere. - + Blips: Blips: - + Sets the volume of the blips, the talking sound effects. Setzt die Lautstärke der Blips, das ist das Geräusch das die Charaktere beim Reden machen. - + Blip rate: Bliprate: - + Sets the delay between playing the blip sounds. Setzt die Pause zwischen einzelnen Blips. - + Play a blip sound "once per every X symbols", where X is the blip rate. Spiele ein blip einmal für all X Buchstaben. - + Blank blips: Leere Blips: - + If true, the game will play a blip sound even when a space is 'being said'. Wenn angehakt wird das Spiel auch bei einem Leerzeichen einen Blip machen. - + Enable Looping SFX: Wiederholende Soundeffekte: - + If true, the game will allow looping sound effects to play on preanimations. Wenn aktiviert, werden wiederholende Soundeffekte bei den Voranimationen erlaubt. - + Kill Music On Objection: Stoppe Musik bei Einspruch: - + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. Hält die Musik an wenn jemand "Einspruch" ruft, wie im echten Spiel. + + + Automatic Logging: + Autmatisches Protokollieren: + + + + If checked, all logs will be automatically written in the /logs folder. + Schreibt die Protokolle automatisch in den /logs Ordner. + If true, the game will stop music when someone objects, like in the actual games. Hält die Musik an wenn jemand "Einspruch" ruft, wie im echten Spiel. - + Casing Fälle - + This server supports case alerts. Dieser Server unterstützt Fallalarme. - + This server does not support case alerts. Dieser Server unterstützt Fallalarme nicht. - + Pretty self-explanatory. Eigentlich selbsterklärend. - + Casing: Fälle: - + If checked, you will get alerts about case announcements. Wenn angehakt wirst du benachrichtigt wenn ein Fall angekündigt wird. - + Defense: Verteidigung: - + If checked, you will get alerts about case announcements if a defense spot is open. Wenn angehakt wirst du benachrichtigt wenn ein Verteidiger benötigt wird. - + Prosecution: Kläger: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Wenn angehakt wirst du benachrichtigt wenn ein Kläger benötigt wird. - + Judge: Richter: - + If checked, you will get alerts about case announcements if the judge spot is open. Wenn angehakt wirst du benachrichtigt wenn ein Richter benötigt wird. - + Juror: Jury: - + If checked, you will get alerts about case announcements if a juror spot is open. Wenn angehakt wirst du benachrichtigt wenn eine Jury benötigt wird. - + Stenographer: Stenograph: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Wenn angehakt wirst du benachrichtigt wenn ein Stenograph benötigt wird. - + CM: CM: - + If checked, you will appear amongst the potential CMs on the server. Wenn angehakt wirst du als potentielle CM angezeigt. @@ -590,12 +677,12 @@ Grund: Wenn angehakt wirst du als potentielle Zeuge angezeigt. - + Hosting cases: Fallleitung: - + If you're a CM, enter what cases you are willing to host. Wenn du CM bist, gib ein welche Fälle du spielen möchtest. @@ -603,33 +690,33 @@ Grund: Courtroom - + Password Passwort - + Spectator Zuschauer - - + + Search Suche - + Passworded Gesperrt - + Taken Benutzt - + Generating chars: %1/%2 Generiere Charaktere: @@ -646,12 +733,12 @@ Grund: Konnte %1 nicht finden - + Showname Anzeigename - + Message Nachricht @@ -660,22 +747,22 @@ Grund: OOC Nachricht - + Name Name - + Pre Vor - + Flip Spiegeln - + Guard Wache @@ -684,18 +771,18 @@ Grund: Deaktiviere Moderatorenrufe - - + + Casing Fall - + Shownames Anzeigenamen - + Immediate Keine Unterbrechung @@ -724,17 +811,17 @@ Grund: Gelb - + Music Musik - + Sfx Sfx - + Blips Blips @@ -743,53 +830,53 @@ Grund: Verlaufsgrenze - - + + Server Server - + Change character Charakter ändern - + Reload theme Aussehen neu laden - + Call mod Moderator rufen - + Settings Einstellungen - + A/M A/M - + Preanim Voranimation - + Back to Lobby Zurück zur Lobby - + You were granted the Disable Modcalls button. Du hast nun den "Modcall deaktivieren" Knopf. - + You have been banned. Du wurdest verbannt. @@ -814,9 +901,8 @@ Grund: Cyan - % offset - % Abstand + % Abstand You were granted the Guard button. @@ -831,7 +917,7 @@ Grund: Dies bewirkt nichts, aber egal. - + You opened the settings menu. Du hast die Einstellungen geöffnet. @@ -844,350 +930,461 @@ Grund: gepaart, wenn der andere dies auch tut. - + + + + None Keine - + Additive Hinzufügend - + + % x offset + % Horizontaler Abstand + + + + % y offset + % Vertikaler Abstand + + + To front Vorne - + To behind Hinten - + Select a character you wish to pair with. Wähle einen Charakter mit dem du gepaart sein möchtest. - Change the percentage offset of your character's position from the center of the screen. - Ändere den Abstand des Charakters zur Mitte. + Ändere den Abstand des Charakters zur Mitte. - + Change the order of appearance for your character. Ändere die Reihenfolge in der die Charaktere erscheinen. - + Display the list of characters to pair with. Zeigt die Liste der paarbaren Charaktere. - + Oops, you're muted! Ohje, du bist stumm! - + Set your character's emote to play on your next message. Setzt den Ausdruck für die nächste Nachricht. - + Set your character's supplementary background. Setzt die Position des Charakters. - Set an 'iniswap', or an alternative character folder to refer to from your current character. Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - + Setz einen 'iniswap', oder einen anderen Charakterordner von deinem aktuellen Charakter. +Bearbeiten durch tippen und Enter drücken, [X] zum entfernen. Das wird in base/characters/<charname>/iniswaps.ini gespeichert. - - + + Change the horizontal percentage offset of your character's position from the center of the screen. + Ändert den Hoizontalen Abstand relativ zur Mitte. + + + + Change the vertical percentage offset of your character's position from the center of the screen. + Ändert den vertikalen Abstand relativ zur Mitte. + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/iniswaps.ini + Setz einen 'iniswap', oder einen anderen Charakterordner von deinem aktuellen Charakter. +Bearbeiten durch tippen und Enter drücken, [X] zum entfernen. Das wird in base/iniswaps.ini gespeichert. + + + Remove the currently selected iniswap from the list and return to the original character folder. - + Entfernt den aktuellen iniswap von der Liste und stellt den originalen Ordner wieder her. - + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini - + Wähle einen Soundeffekt der bei der nächsten 'Preanim' gespielt wird. Lasse dies auf Standard um den emote-Sound zu verwenden. +Bearbeiten durch tippen und Enter drücken, [X] zum entfernen. Das wird in base/characters/<charname>/soundlist.ini gespeichert. - + + Remove the currently selected sound effect. + Entfernt den aktuell ausgewählten Soundeffekt. + + + Choose an effect to play on your next spoken message. The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. - + Wähle einen Effekt für die nächste Nachricht. +Die Effekte sind definiert in theme/effects/effects.ini. Dein Charakter kann eigene Effekte in der +char.ini [Options] Kategorie, effects = 'miscname' haben welcher dann misc/<miscname>/effects.ini liest. - + Hold It! Moment mal! - - - + + + When this is turned on, your next in-character message will be a shout! Wenn dies an ist, wird die Nächste Nachricht ein Zuruf! - + Objection! Einspruch! - + Take That! Nimm das! - + Toggle between server chat and global AO2 chat. Wechselt zwischen Serverchat und AO2 Chat. - - - - + + + + This will display the animation in the viewport as soon as it is pressed. - + Dies zeigt die Animation im Spielfeld sobald es angeklickt wird. - + Guilty! Schuldig! - - - Bring up the Character Select Screen and change your character. - - - - - Refresh the theme and update all of the ui elements to match. - - - - - Request the attention of the current server's moderator. - - - - - Allows you to change various aspects of the client. - - - - - An interface to help you announce a case (you have to be a CM first to be able to announce cases) - - - Switch between Areas and Music lists - + Bring up the Character Select Screen and change your character. + Zeige die Charakterauswahl und ändere deinen Charakter. - - Play a single-shot animation as defined by the emote when checked. - + + Refresh the theme and update all of the ui elements to match. + Aktualisiert das Design und alle UI Elemente. - - If preanim is checked, display the input text immediately as the animation plays concurrently. - + + Request the attention of the current server's moderator. + Fordere einen Moderator an. - - Mirror your character's emotes when checked. - + + Allows you to change various aspects of the client. + Lässt dich verschiedene Dinge des Clients anpassen. - - Add text to your last spoken message when checked. - - - - - Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. - - - - - Lets you receive case alerts when enabled. -(You can set your preferences in the Settings!) - + + An interface to help you announce a case (you have to be a CM first to be able to announce cases) + Ein Menü um einen Fall anzukündigen (du musst dafür erst CM sein) - Display customized shownames for all users when checked. - + Switch between Areas and Music lists + Wechsel zwischen Areal- und Musikliste - - Custom Shout! - + + Play a single-shot animation as defined by the emote when checked. + Zeigt eine Animation vor dem Sprechen. - - This will display the custom character-defined animation in the viewport as soon as it is pressed. -To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect - - - - - Play realization sound and animation in the viewport on the next spoken message when checked. - - - - - Shake the screen on next spoken message when checked. - + + If preanim is checked, display the input text immediately as the animation plays concurrently. + Starte sofort zu sprechen, ohne auf das Ende der Voranimation zu warten. - Display the list of character folders you wish to mute. - + Mirror your character's emotes when checked. + Spiegelt die Emotes deines Charakters. - - Increase the health bar. - + Add text to your last spoken message when checked. + Füge Text zu deiner letzten Nachricht hinzu. - - Decrease the health bar. - + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. + Ignoriere Modcalls und spiel keinen Ton ab. + + + + Lets you receive case alerts when enabled. +(You can set your preferences in the Settings!) + Lässt dich Fallalarme erhalten. +(Du kannst dies in den Einstellungen anpassen!) + + + + Display customized shownames for all users when checked. + Zeigt selbst einstellbare Namen für alle. - Change the text color of the spoken message. -You can also select a part of your currently typed message and use the dropdown to change its color! - + Custom Shout! + Eigener Zwischenruf! - - Return back to the server list. - + + This will display the custom character-defined animation in the viewport as soon as it is pressed. +To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect + Dies zeigt des Charakters eigenen Zwischenruf. +Um einen zu haben muss im Charakterordner eine custom.[webp/apng/gif/png] und ein custom.[wav/ogg/opus] Soundeffekt sein + + + + Play realization sound and animation in the viewport on the next spoken message when checked. + Spiele den Realisierung Sound und Animation mit der nächsten Nachricht. + + + + Shake the screen on next spoken message when checked. + Schüttelt den Bildschirm bei der nächsten Nachricht. + + + + Display the list of character folders you wish to mute. + Zeigt die Charakterliste um einen stumm zu schalten. - Become a spectator. You won't be able to interact with the in-character screen. - + + Increase the health bar. + Erhöhe die Gesundheit. - - + + + Decrease the health bar. + Verringere die Gesundheit. + + + + Change the text color of the spoken message. +You can also select a part of your currently typed message and use the dropdown to change its color! + Ändert die Textfarbe. +Du kannst auch nur einen Teil der Nachricht auswählen und dessen Farbe ändern! + + + + Return back to the server list. + Zurück zur Serverliste. + + + + Become a spectator. You won't be able to interact with the in-character screen. + Werde ein Zuschauer. Es ist dir nicht möglich mit dem Spielfeld zu interagieren. + + + + CLIENT CLIENT - - - + + + + HOLD IT! + MOMENT MAL! + + + + + + OBJECTION! + EINSPRUCH! + + + + + + TAKE THAT! + NIMM DAS! + + + + + + CUSTOM OBJECTION! + SPEZIALRUF! + + + + + + shouts + Zwischenrufe + + + + + has presented evidence + hat Beweis präsentiert + + + + + + has stopped the music + hat die Musik angehalten + + + + + [MISSING] %1 + [FEHLEND] %1 + + + + has played a song spielte ein Lied - + You will now pair up with %1 if they also choose your character in return. - + Du paarst dich nun mit %1 wenn diese deinen Charakter auch gewählt haben. - + You are no longer paired with anyone. Du bist nicht mehr gepaart. - + Are you sure you typed that well? The char ID could not be recognised. Hast du dich vertippt? Die ID konnte nicht erkannt werden. - - You have set your offset to - Dein Abstand ist auf + + You have set your offset to %1%%. + Dein Abstand ist auf %1%% gesetzt. - + You have set your offset to + Dein Abstand ist auf + + + Your offset must be between -100% and 100%! Der Abstand muss zwischen -100% und 100% liegen! - + That offset does not look like one. Das sieht nicht wie ein Abstand aus. - + + You have set your vertical offset to %1%%. + Du hast deinen vertikalen Abstand auf %1%% gesetzt. + + + + Your vertical offset must be between -100% and 100%! + Dein vertikaler Abstand muss zwischen -100% und 100% sein! + + + + That vertical offset does not look like one. + Das sieht nicht wie ein Abstand aus. + + + You switched your music and area list. Du hast zwischen Musik- und Gebitsliste umgeschaltet. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Du hast Funktionen erzwungen die der Server eventuell nicht unterstützt. Möglicherweise wirst du nicht mehr sprechen können. - + Your pre-animations interrupt again. Deine Voranimation unterbrechen nun Text. - + Your pre-animations will not interrupt text. Deine Voranimation unterbrechen Text nicht. - + Couldn't open chatlog.txt to write into. Konnte chatlog.txt nicht öffnen. - + The IC chatlog has been saved. Der IC Verlauf wurde gespeichert. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 Du musst einen Dateinamen angeben (ohne .ini). Stelle sicher das er im 'base/cases' Ordner ist und das er korrekt formatiert ist. Verfügbare Fälle: %1 - + Case made by %1. Fall von %1. - + Navigate to %1 for the CM doc. Gehe zu %1 für das CM Dokument. - - - - + + + + UNKNOWN UNBEKANNT - + Your case "%1" was loaded! Dein Fall "%1" wurde geladen! @@ -1198,7 +1395,7 @@ Cases you can load: Verfügbare Fälle: - + Too many arguments to load a case! You only need one filename, without extension. Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung. @@ -1223,83 +1420,93 @@ Verfügbare Fälle: " wurde geladen! - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. - + You need to give a filename to save (extension not needed) and the courtroom status! Du musst einen Dateinamen (ohne Erweiterung) angebenn, sowie den Gebietsstatus! - + Too many arguments to save a case! You only need a filename without extension and the courtroom status! Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung sowie den Gebietsstatus! - + Succesfully saved, edit doc and cmdoc link on the ini! Erfolgreich gespeichert! - + Master Master - + + Stop Current Song + Lied stoppen + + + + Play Random Song + Zufälliges Lied + + + Expand All Categories Alle Kategorien erweitern - + Collapse All Categories Alle Kategorien verstecken - + Fade Out Previous - + Vorheriges ausblenden - + Fade In - + Einblenden - + Synchronize - + Synchronisieren - + Default Standard - + Reason: Grund: - + Call Moderator Moderator rufen - - + + Error Fehler - + You must provide a reason. Du musst einen Grund angeben. - + The message is too long. Die Nachricht ist zu lang. @@ -1315,139 +1522,143 @@ Verfügbare Fälle: Present this piece of evidence to everyone on your next spoken message - + Präsentiere dieses Beweisstück allen in der nächsten Nachricht Save evidence to an .ini file. - + Speichere Beweise in einer .ini Datei. Load evidence from an .ini file. - + Lade Beweise aus einer .ini Datei. Destroy this piece of evidence - + Zerstöre dieses Beweisstück Close the evidence display/editing overlay. You will be prompted if there's any unsaved changes. - + Schließe das Beweisfenster. +Du wirst gefragt wenn es ungespeicherte Änderungen gibt. Save any changes made to this piece of evidence and send them to server. - + Speichert alle Änderungen an diesem Beweisstück und schickt sie zum Server. Double-click to edit. Press [X] to update your changes. - + Doppelklick zum bearbeiten. Klicke [X] um die Änderungen zu übernehmen. Bring up the Evidence screen. - + Zeigt die Beweisliste. Switch evidence to private inventory. - + Wechselt zum eigenen Inventar. Switch evidence to global inventory. - + Wechselt zum globalen Inventar. - + Transfer evidence to private inventory. - + Übertrage Beweisstück zum eigenen Inventar. - + Transfer evidence to global inventory. - - - - - The piece of evidence you've been editing has changed. - + Übertrage Beweisstück zum globalen Inventar. - Do you wish to keep your changes? - + The piece of evidence you've been editing has changed. + Das Beweisstück das du bearbeitet hast hat sich verändert. + Do you wish to keep your changes? + Möchtest du deine Änderungen behalten? + + + Name: %1 Image: %2 Description: %3 - + Name: %1 +Bild: %2 +Beschreibung: +%3 - + Images (*.png) Bilder (*.png) - - - + + + Double-click to edit... - + Doppelklick zum bearbeiten... - + Add new evidence... Neues Beweisstück... - + Evidence has been modified. - + Beweise wurden verändert. - + Do you want to save your changes? - + Möchtest du deine Änderungen speichen? - + Current evidence is global. Click to switch to private. - + Beweise sind global. Klicken um zu eigenen zu wechseln. - + Current evidence is private. Click to switch to global. - + Beweise sind die eigenen. Klicken um zu global zu wechseln. - + "%1" has been transferred. - + "%1" wurde übertragen. - + Save Inventory - + Inventar speichen - - + + Ini Files (*.ini) Ini Dateien (*.ini) - + Open Inventory Inventar öffnen @@ -1482,59 +1693,73 @@ Description: Lobby - + Attorney Online 2 Attorney Online 2 - + Search Suche - + Name Name - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? Dein Client ist nicht korrekt eingerichtet. Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen 'base' Ordner? - + Version: %1 Version: %1 - + Settings Einstellungen - + Allows you to change various aspects of the client. Erlaubt es verschiedene Aspekte des Clients zu ändern. - + Loading Laden - + Cancel Abbrechen - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! - <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Version 2.8 Entwicklung:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Qualitätskontrolle:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, die AO2 Community, Serverbetreiber, Gamemaster, Fallersteller, Inhaltersteller und Spieler! + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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 BASS audio engine.<br>APNG plugin loaded: %3<p>Built on %4 + <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Cliententwicklung:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Qualitätssicherung:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Danksagungen:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, und FanatSors (AO1); Serverbetreiber, Gamemaster, Fallersteller, Inhaltsersteller und die ganze AO2 Community!<p>Das Attorney Online networked visual novel Projekt ist copyright (c) 2016-2020 Attorney Online Entwickler. Unter Open-Source Lizenz. Alle anderen Inhalte sind Eigentum ihrer Besitzer.<p>Läuft auf Qt version %2 mit der BASS Audio Engine.<br>APNG plugin geladen: %3<p>Built on %4 - + + Yes + Ja + + + + No + Nein + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! + <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Version 2.8 Entwicklung:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Qualitätskontrolle:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, die AO2 Community, Serverbetreiber, Gamemaster, Fallersteller, Inhaltersteller und Spieler! + + + About Über @@ -1547,7 +1772,7 @@ Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen & <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 Online: %1/%2 @@ -1592,8 +1817,8 @@ Noevain Cronnicossy - - + + Offline Offline @@ -1608,25 +1833,24 @@ Cronnicossy UNBEKANNT - has played a song: - hat ein Lied gespielt: + hat ein Lied gespielt: debug_functions - + Error: %1 Fehler: %1 - + Error Fehler - + Notice Hinweis diff --git a/resource/translations/ao_en.qm b/resource/translations/ao_en.qm index 9dad8df..937ea3e 100644 Binary files a/resource/translations/ao_en.qm and b/resource/translations/ao_en.qm differ diff --git a/resource/translations/ao_en.ts b/resource/translations/ao_en.ts index 8d21c99..718f66e 100644 --- a/resource/translations/ao_en.ts +++ b/resource/translations/ao_en.ts @@ -4,72 +4,64 @@ AOApplication - + Disconnected from server. - + Error connecting to master server. Will try again in %1 seconds. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. - + Attorney Online 2 - + Loading - - Loading evidence: -%1/%2 - - - - - + Loading music: %1/%2 - - + Loading chars: %1/%2 - + You have been kicked from the server. Reason: %1 - + You have been banned from the server. Reason: %1 - + You are banned on this server. Reason: %1 @@ -156,917 +148,1102 @@ Reason: %1 - + Default username: - + Your OOC name will be automatically set to this value when you join a server. - + Custom shownames: - + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - + Backup MS: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - + Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - + Language: - + Sets the language if you don't want to use your system language. - + Callwords - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - + Audio - + Audio device: - + Sets the audio device for all sounds. - + Music: - + SFX: - + Blips: - + Sets the volume of the blips, the talking sound effects. - + Blip rate: - + Sets the delay between playing the blip sounds. - + Blank blips: - + If true, the game will play a blip sound even when a space is 'being said'. - + Enable Looping SFX: - + If true, the game will allow looping sound effects to play on preanimations. - + Kill Music On Objection: - + - Keep current setting - + + Log newline: + + + + + 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'. + + + + + Log margin: + + + + + The distance in pixels between each entry in the IC log. Default: 0. + + + + + Log timestamp: + + + + + If ticked, log will contain a timestamp in UTC before the name. + + + + + Log IC actions: + + + + + If ticked, log will show IC actions such as shouting and presenting evidence. + + + + + Text Stay Time: + + + + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior. + + + + + Desynchronize IC Logs: + + + + + If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). + + + + + Instant Objection: + + + + + If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up. + + + + Allow Screenshake: - + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Allow Effects: - + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Network Frame Effects: - + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. - + Colors in IC Log: - + Use the markup colors in the server IC chatlog. - + Sticky Sounds: - + Turn this on to prevent the sound dropdown from clearing the sound after playing it. - + Sticky Effects: - + Turn this on to prevent the effects dropdown from clearing the effect after playing it. - + Sticky Preanims: - + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + Custom Chatboxes: + + + Turn this on to allow characters to define their own custom chat box designs. + + + + Sets the music's default volume. - + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - + Play a blip sound "once per every X symbols", where X is the blip rate. - + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - + Casing - + This server supports case alerts. - + This server does not support case alerts. - + Pretty self-explanatory. - + Casing: - + If checked, you will get alerts about case announcements. - + Defense: - + If checked, you will get alerts about case announcements if a defense spot is open. - + Prosecution: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. - + Judge: - + If checked, you will get alerts about case announcements if the judge spot is open. - + Juror: - + If checked, you will get alerts about case announcements if a juror spot is open. - + Stenographer: - + If checked, you will get alerts about case announcements if a stenographer spot is open. - + CM: - + If checked, you will appear amongst the potential CMs on the server. - + Hosting cases: - + If you're a CM, enter what cases you are willing to host. + + + Automatic Logging: + + + + + If checked, all logs will be automatically written in the /logs folder. + + Courtroom - + Password - + Spectator - - + + Search - + Passworded - + Taken - + Generating chars: %1/%2 - + Showname - + Message - + Name - + Pre - + Flip - - + + Casing - + Shownames - + Immediate - + + % x offset + + + + + % y offset + + + + + Change the horizontal percentage offset of your character's position from the center of the screen. + + + + + Change the vertical percentage offset of your character's position from the center of the screen. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/iniswaps.ini + + + + You were granted the Disable Modcalls button. - + + You have set your offset to %1%%. + + + + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 - + Case made by %1. - + Navigate to %1 for the CM doc. - + Your case "%1" was loaded! - - + + Server - + Back to Lobby - - % offset - - - - + Music - + Sfx - + Blips - + Change character - + Reload theme - + Call mod - + Settings - + A/M - + Preanim - + You have been banned. - + You opened the settings menu. - + + + + None - + Guard - + Additive - + To front - + To behind - + Select a character you wish to pair with. - - Change the percentage offset of your character's position from the center of the screen. - - - - + Change the order of appearance for your character. - + Display the list of characters to pair with. - + Oops, you're muted! - + Set your character's emote to play on your next message. - + Set your character's supplementary background. - - Set an 'iniswap', or an alternative character folder to refer to from your current character. -Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - - - - - + Remove the currently selected iniswap from the list and return to the original character folder. - + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini - + + Remove the currently selected sound effect. + + + + Choose an effect to play on your next spoken message. The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. - + Hold It! - - - + + + When this is turned on, your next in-character message will be a shout! - + Objection! - + Take That! - + Toggle between server chat and global AO2 chat. - - - - + + + + This will display the animation in the viewport as soon as it is pressed. - + Guilty! - + Bring up the Character Select Screen and change your character. - + Refresh the theme and update all of the ui elements to match. - + Request the attention of the current server's moderator. - + Allows you to change various aspects of the client. - + An interface to help you announce a case (you have to be a CM first to be able to announce cases) - + Switch between Areas and Music lists - + Play a single-shot animation as defined by the emote when checked. - + If preanim is checked, display the input text immediately as the animation plays concurrently. - + Mirror your character's emotes when checked. - + Add text to your last spoken message when checked. - + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. - + Lets you receive case alerts when enabled. (You can set your preferences in the Settings!) - + Display customized shownames for all users when checked. - + Custom Shout! - + This will display the custom character-defined animation in the viewport as soon as it is pressed. To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect - + Play realization sound and animation in the viewport on the next spoken message when checked. - + Shake the screen on next spoken message when checked. - + Display the list of character folders you wish to mute. - - + + Increase the health bar. - - + + Decrease the health bar. - + Change the text color of the spoken message. You can also select a part of your currently typed message and use the dropdown to change its color! - + Return back to the server list. - + Become a spectator. You won't be able to interact with the in-character screen. - - + + CLIENT - - - + + + + HOLD IT! + + + + + + + OBJECTION! + + + + + + + TAKE THAT! + + + + + + + CUSTOM OBJECTION! + + + + + + + shouts + + + + + + has presented evidence + + + + + + + has stopped the music + + + + + + [MISSING] %1 + + + + + has played a song - + You will now pair up with %1 if they also choose your character in return. - + You are no longer paired with anyone. - + Are you sure you typed that well? The char ID could not be recognised. - - You have set your offset to - - - - + Your offset must be between -100% and 100%! - + That offset does not look like one. - + + You have set your vertical offset to %1%%. + + + + + Your vertical offset must be between -100% and 100%! + + + + + That vertical offset does not look like one. + + + + You switched your music and area list. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - + Your pre-animations interrupt again. - + Your pre-animations will not interrupt text. - + Couldn't open chatlog.txt to write into. - + The IC chatlog has been saved. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - + Too many arguments to load a case! You only need one filename, without extension. - - - - + + + + UNKNOWN - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - + You need to give a filename to save (extension not needed) and the courtroom status! - + Too many arguments to save a case! You only need a filename without extension and the courtroom status! - + Succesfully saved, edit doc and cmdoc link on the ini! - + Master - + + Stop Current Song + + + + + Play Random Song + + + + Expand All Categories - + Collapse All Categories - + Fade Out Previous - + Fade In - + Synchronize - + Default - + Reason: - + Call Moderator - - + + Error - + You must provide a reason. - + The message is too long. @@ -1128,28 +1305,28 @@ You will be prompted if there's any unsaved changes. - + Transfer evidence to private inventory. - + Transfer evidence to global inventory. - + The piece of evidence you've been editing has changed. - + Do you wish to keep your changes? - + Name: %1 Image: %2 Description: @@ -1157,130 +1334,155 @@ Description: - + Images (*.png) - - - + + + Double-click to edit... - + Add new evidence... - + Evidence has been modified. - + Do you want to save your changes? - + Current evidence is global. Click to switch to private. - + Current evidence is private. Click to switch to global. - + "%1" has been transferred. - + Save Inventory - - + + Ini Files (*.ini) - + Open Inventory + + DemoServer + + + + Load Demo + + + + + + Demo Files (*.demo) + + + Lobby - + Attorney Online 2 - + Search - + Name - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - + Version: %1 - + Settings - + Allows you to change various aspects of the client. - + Loading - + Cancel - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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 BASS audio engine.<br>APNG plugin loaded: %3<p>Built on %4 - + + Yes + + + + + No + + + + About - + Online: %1/%2 - - + + Offline @@ -1294,26 +1496,21 @@ Did you download all resources correctly from tiny.cc/getao, including the large UNKNOWN - - - has played a song: - - debug_functions - + Error: %1 - + Error - + Notice diff --git a/resource/translations/ao_es.qm b/resource/translations/ao_es.qm index 7b5e6f2..6963455 100644 Binary files a/resource/translations/ao_es.qm and b/resource/translations/ao_es.qm differ diff --git a/resource/translations/ao_es.ts b/resource/translations/ao_es.ts index 36cc653..10b8e43 100644 --- a/resource/translations/ao_es.ts +++ b/resource/translations/ao_es.ts @@ -1,20 +1,20 @@ - + AOApplication - + Disconnected from server. Desconectado del servidor. - + Error connecting to master server. Will try again in %1 seconds. Error al conectarse a la lista de servidores. Se intentará nuevamente en %1 segundos. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. @@ -22,7 +22,7 @@ Please check your Internet connection and firewall, and please try again.Hubo un error al obtener la lista de servidores. Verifique su conexión a Internet y firewall, y vuelva a intentarlo. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. ¡Versión desactualizada! Su versión: %1 @@ -35,54 +35,51 @@ Have a nice day. Que tengas un buen día. - + Attorney Online 2 - + Loading Cargando - Loading evidence: %1/%2 - Cargando evidencia: + Cargando evidencia: %1/%2 - - + Loading music: %1/%2 Cargando música: %1/%2 - - + Loading chars: %1/%2 Cargando personajes: %1/%2 - + You have been kicked from the server. Reason: %1 Has sido expulsado del servidor. Razón: %1 - + You have been banned from the server. Reason: %1 Has sido bloqueado de este servidor. Razón: %1 - + You are banned on this server. Reason: %1 Has sido bloqueado en este servidor. @@ -216,42 +213,82 @@ Razón: Si está marcado, el registro contendrá una marca de tiempo en UTC antes del nombre. - + + Log IC actions: + + + + + If ticked, log will show IC actions such as shouting and presenting evidence. + + + + + Text Stay Time: + + + + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior. + + + + + Desynchronize IC Logs: + + + + + If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). + + + + + Instant Objection: + + + + + If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up. + + + + Default username: Usuario predeterminado: - + Your OOC name will be automatically set to this value when you join a server. Su nombre OOC se establecerá automáticamente a este cuando se una a un servidor. - + Custom shownames: Mostrar nombres: - + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. Activa la casilla 'Mostrar nombres' de forma predeterminada en el juego, que a su vez determina si el cliente debe mostrar nombres personalizados en los personajes. - + Backup MS: Master SV de respaldo: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Si la lista de servidores predeterminada falla, el juego probará la dirección proporcionada aquí. - + Discord: Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Permite a otros en Discord ver en qué servidor estás, qué personaje juegas y cuánto tiempo has estado jugando. @@ -264,12 +301,12 @@ Razón: Permite el movimiento de la pantalla y el parpadeo. Desactive esto si tiene inquietudes o problemas con la fotosensibilidad y/o convulsiones. - + Language: Idioma: - + Sets the language if you don't want to use your system language. Establece el idioma si no desea utilizar el idioma de su sistema. @@ -278,47 +315,47 @@ Razón: Habilítelo para agregar una pequeña pausa en los signos de puntuación. - + Callwords Palabras clave - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Ingrese tantas palabras de llamada como desee.<br>Esto no distingue entre mayúsculas y minúsculas. ¡Asegúrese de dejar cada palabra en su propia línea!<br>No deje una línea con un espacio al final; recibirá una alerta cada vez que alguien use un espacio en sus mensajes.</body></html> - + Audio Audio - + Audio device: Dispositivo: - + Sets the audio device for all sounds. Establece el dispositivo de audio. - + Music: Música: - + Sets the music's default volume. Establece el volumen predeterminado de la música. - + SFX: SFX: - + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. Establece el volumen predeterminado de SFX. Las interjecciones y los efectos de sonido reales cuentan como 'SFX'. @@ -347,47 +384,47 @@ Razón: Establece el volumen predeterminado para sonidos SFX, como las interjecciones y otros efectos de sonido de personajes. - + Blips: Blips: - + Sets the volume of the blips, the talking sound effects. Establece el volumen de los blips, el sonido al hablar. - + Blip rate: Tasa de blips: - + Sets the delay between playing the blip sounds. Establece el retraso entre la reproducción de los sonidos blip. - + Blank blips: Blips en blanco: - + If true, the game will play a blip sound even when a space is 'being said'. Si está marcada, el juego reproducirá un sonido blip incluso cuando se 'dice' un espacio. - + Enable Looping SFX: Habilitar repetición de SFX: - + If true, the game will allow looping sound effects to play on preanimations. Si está habilitado, el juego permitirá que se reproduzcan efectos de sonido en bucle en preanimaciones. - + Kill Music On Objection: Parar la música al objetar: @@ -396,197 +433,197 @@ Razón: Si está habilitado, el juego detendrá la música cuando alguien haga una objeción, como en los juegos. - + - Keep current setting - Mantener la configuración actual - + Allow Screenshake: Permitir screenshake: - + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. Permite el movimiento de la pantalla (ADVERTENCIA: esto podría inducir convulsiones debido a imágenes parpadeantes). - + Allow Effects: Permitir efectos: - + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. Permite efectos de pantalla (ADVERTENCIA: esto podría inducir convulsiones debido a imágenes parpadeantes). - + Network Frame Effects: Enviar efectos al servidor: - + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. Envíe temblores de pantalla, destellos y sonidos como se define en char.ini a través de la red. Solo funciona para servidores que admiten esta funcionalidad. - + Colors in IC Log: Colores en el registro IC: - + Use the markup colors in the server IC chatlog. Permite colores en el chat IC del servidor. - + Sticky Sounds: Mantener sonidos: - + Turn this on to prevent the sound dropdown from clearing the sound after playing it. Actívelo para evitar que el menú desplegable de sonido borre el sonido después de reproducirlo. - + Sticky Effects: Mantener efectos: - + Turn this on to prevent the effects dropdown from clearing the effect after playing it. Actívelo para evitar que el menú desplegable de efectos elimine el efecto después de reproducirlo. - + Sticky Preanims: Mantener preanims: - + Turn this on to prevent preanimation checkbox from clearing after playing the emote. Actívelo para evitar que la casilla preanimation se desactive después de reproducir el emote. - + Custom Chatboxes: Chatboxes personalizados: - + Turn this on to allow characters to define their own custom chat box designs. Actívelo para permitir que los personajes definan sus propios diseños de cuadros de chat personalizados. - + Play a blip sound "once per every X symbols", where X is the blip rate. Reproduce un sonido de blip "una vez por cada X símbolos", donde X es la tasa de blip. - + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. Si es activado, AO2 detendrá la música por ti cuando tú u otra persona hagan un '¡Protesto!'. - + Casing Caso - + This server supports case alerts. Este servidor admite alertas de casos. - + This server does not support case alerts. Este servidor no admite alertas de casos. - + Pretty self-explanatory. Bastante autoexplicativo. - + Casing: Caso: - + If checked, you will get alerts about case announcements. Si está marcado, recibirá anuncios de casos. - + Defense: Abogado: - + If checked, you will get alerts about case announcements if a defense spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de abogado libre. - + Prosecution: Fiscal: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Si está marcada, recibirá alertas sobre anuncios de casos si hay un puesto de fiscal libre. - + Judge: Juez: - + If checked, you will get alerts about case announcements if the judge spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si el puesto de juez está libre. - + Juror: Jurado: - + If checked, you will get alerts about case announcements if a juror spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si hay un puesto de jurado libre. - + Stenographer: Taquígrafo: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Si está marcado, recibirá alertas sobre anuncios de casos si hay un lugar de taquígrafo libre. - + CM: CM: - + If checked, you will appear amongst the potential CMs on the server. Si está marcado, aparecerá entre los posibles CM en el servidor. - + Automatic Logging: Registro automático: - + If checked, all logs will be automatically written in the /logs folder. Si está marcado, todos los registros se guardarán automáticamente en la carpeta logs. @@ -599,12 +636,12 @@ Razón: Si está marcado, aparecerá entre los posibles testigos en el servidor. - + Hosting cases: Casos: - + If you're a CM, enter what cases you are willing to host. Si eres un CM, ingresa qué casos estás dispuesto a organizar. @@ -648,29 +685,29 @@ Razón: Courtroom - + Password Contraseña - + Spectator Espectador - - + + Search Buscar - + Passworded A translation wouldn't fit because of the shitty theme system. - + Taken En uso @@ -679,7 +716,7 @@ Razón: No se pudo encontrar %1 - + Generating chars: %1/%2 Generando personajes: @@ -692,53 +729,53 @@ Razón: - + Showname A translation wouldn't fit because of the shitty theme system. - + Message Mensaje - + Name Nombre - + Pre A translation wouldn't fit because of the shitty theme system. - + Flip A translation wouldn't fit because of the shitty theme system. - + Guard Guardia - - + + Casing This could be translated as 'caso' and it wouldn't get cut, but there are so many other buttons that can't be translated on the courtroom window that might as well leave this also untranslated so it's at least consistent. - + Shownames A translation wouldn't fit because of the shitty theme system. - + Immediate A translation wouldn't fit because of the shitty theme system. @@ -780,68 +817,67 @@ Razón: Cian - % offset - % desplazamiento + % desplazamiento - + Music - + Sfx - + Blips - + Change character - + Reload theme - + Call mod - + Settings - + A/M - + Preanim - + Back to Lobby 'Volver al lobby' got cut, changed to just Lobby Lobby - + You were granted the Disable Modcalls button. Se le concedió el botón para deshabilitar llamadas a moderadores. - + You have been banned. Has sido vetado. @@ -854,7 +890,7 @@ Razón: Esto no hace nada, pero ahí lo tienes. - + You opened the settings menu. Abriste el menú de configuración. @@ -867,82 +903,113 @@ Razón: si ellos también eligen a tu personaje a cambio. - + + + + None Nada - + Additive Aditivo - + + % x offset + + + + + % y offset + + + + To front Al frente - + To behind Al fondo - + Select a character you wish to pair with. Seleccione un personaje con el que desee emparejarse. - Change the percentage offset of your character's position from the center of the screen. - Cambia el desplazamiento porcentual de la posición de tu personaje desde el centro de la pantalla. + Cambia el desplazamiento porcentual de la posición de tu personaje desde el centro de la pantalla. - + Change the order of appearance for your character. Cambia el orden de aparición de tu personaje. - + Display the list of characters to pair with. Muestra la lista de personajes para emparejar. - + Oops, you're muted! ¡Ups, estas silenciado! - + Set your character's emote to play on your next message. Configura el emote de tu personaje para usar en tu próximo mensaje. - + Set your character's supplementary background. Establece el fondo suplementario de tu personaje. - Set an 'iniswap', or an alternative character folder to refer to from your current character. Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - Establece un 'iniswap', o una carpeta de caracteres alternativa para consultar desde su personaje actual. + Establece un 'iniswap', o una carpeta de caracteres alternativa para consultar desde su personaje actual. Edite escribiendo y presionando Enter, [X] para eliminar. Esto es guardado en base/characters/<charname>/iniswaps.ini - - + + Change the horizontal percentage offset of your character's position from the center of the screen. + + + + + Change the vertical percentage offset of your character's position from the center of the screen. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/iniswaps.ini + + + + Remove the currently selected iniswap from the list and return to the original character folder. Elimina el iniswap seleccionado actualmente de la lista y regresa a la carpeta de caracteres original. - + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini Establece un efecto de sonido para jugar en su próximo 'Preanim'. Dejarlo en Predeterminado usará el sonido definido por emoticones (si hay). Edite escribiendo y presionando Enter, [X] para eliminar. Esto es guardado en base/characters/<charname>/iniswaps.ini - + + Remove the currently selected sound effect. + + + + Choose an effect to play on your next spoken message. The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. @@ -951,314 +1018,386 @@ Los efectos se definen en theme/effects/effects.ini. Tu personaje puede definir char.ini [Opciones] categoría, effects = 'miscname' donde se refiere a misc/<miscname>/effects.ini para leer los efectos. - + Hold It! ¡Un Momento! - - - + + + When this is turned on, your next in-character message will be a shout! Why the exclamation? Cuando esto es activado, tu próximo mensaje del personaje será un grito. - + Objection! ¡Protesto! - + Take That! ¡Toma Eso! - + Toggle between server chat and global AO2 chat. Alternar entre el chat del servidor y el chat global. - - - - + + + + This will display the animation in the viewport as soon as it is pressed. Esto mostrará la animación en el viewport tan pronto como se presione. - + Guilty! ¡Culpable! - + Bring up the Character Select Screen and change your character. Abre la pantalla de selección de personaje y cambia tu personaje. - + Refresh the theme and update all of the ui elements to match. Actualiza el tema y todos los elementos de la interfaz de usuario para que coincidan. - + Request the attention of the current server's moderator. Solicite la atención del moderador actual del servidor. - + Allows you to change various aspects of the client. Le permite cambiar varios aspectos del cliente. - + An interface to help you announce a case (you have to be a CM first to be able to announce cases) Una interfaz para ayudarlo a anunciar un caso (debe ser un CM para poder anunciar casos) - + Switch between Areas and Music lists Cambiar entre áreas y listas de música - + Play a single-shot animation as defined by the emote when checked. Reproduzca una animación de un solo disparo según lo definido por el emote cuando esté marcado. - + If preanim is checked, display the input text immediately as the animation plays concurrently. Si se marca preanim, muestre el texto de entrada inmediatamente mientras la animación se reproduce simultáneamente. - + Mirror your character's emotes when checked. Refleja los gestos de tu personaje cuando esté marcado. - + Add text to your last spoken message when checked. Agregar texto a su último mensaje hablado cuando esté marcado. - + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. No escucha llamadas de moderación cuando esté marcado, evitando que reproduzcan sonidos o centrando la atención en la ventana. - + Lets you receive case alerts when enabled. (You can set your preferences in the Settings!) Le permite recibir alertas de casos cuando está habilitado. (¡Puedes configurar tus preferencias en la Configuración!) - + Display customized shownames for all users when checked. Mostrar nombres personalizados para todos los usuarios cuando esté marcado. - + Custom Shout! ¡Grito personalizado! - + This will display the custom character-defined animation in the viewport as soon as it is pressed. To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect Esto mostrará la animación de personaje personalizada definida en el viewport tan pronto como se presione. Para hacer una, la carpeta de tu personaje debe contener efectos personalizados [webp/apng/gif/png]. Y efectos personalizados de sonido [wav/ogg/opus] - + Play realization sound and animation in the viewport on the next spoken message when checked. Reproduzca sonido y animación de realización en la ventana gráfica en el siguiente mensaje hablado cuando esté marcado. - + Shake the screen on next spoken message when checked. Agite la pantalla en el siguiente mensaje hablado cuando esté marcado. - + Display the list of character folders you wish to mute. Muestra la lista de carpetas de caracteres que desea silenciar. - - + + Increase the health bar. Aumenta la barra de salud. - - + + Decrease the health bar. Disminuye la barra de salud. - + Change the text color of the spoken message. You can also select a part of your currently typed message and use the dropdown to change its color! Cambia el color del texto en el chat IC. ¡También puede seleccionar una parte de su mensaje escrito actualmente y usar el menú desplegable para cambiar su color! - + Return back to the server list. Regresar a la lista de servidores. - + Become a spectator. You won't be able to interact with the in-character screen. Conviértete en espectador. No podrás interactuar como personaje. - - + + CLIENT - - + + + + HOLD IT! + + + + + + + OBJECTION! + + + + + + + TAKE THAT! + + + + + + + CUSTOM OBJECTION! + + + + + + + shouts + + + + + has presented evidence ha presentado evidencia - - + + + + has stopped the music + + + + + + [MISSING] %1 + + + + + has played a song ha reproducido la canción - + You will now pair up with %1 if they also choose your character in return. Ahora se emparejará con %1 si también eligen a su personaje. - + You are no longer paired with anyone. Ya no estás emparejado con nadie. - + Are you sure you typed that well? The char ID could not be recognised. ¿Estás seguro de que lo escribiste bien? El ID de personaje no pudo ser reconocido. - - You have set your offset to - Ha configurado su desplazamiento en + + You have set your offset to %1%%. + - + You have set your offset to + Ha configurado su desplazamiento en + + + Your offset must be between -100% and 100%! ¡Su desplazamiento debe estar entre -100% y 100%! - + That offset does not look like one. Ese desplazamiento no se parece a uno. - + + You have set your vertical offset to %1%%. + + + + + Your vertical offset must be between -100% and 100%! + + + + + That vertical offset does not look like one. + + + + You switched your music and area list. Cambiaste tu lista de música y área. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Ha habilitado forzosamente funciones que el servidor puede no admitir. Es posible que no pueda hablar IC, o peor, debido a esto. - + Your pre-animations interrupt again. Sus pre-animaciones interrumpen de nuevo. - + Your pre-animations will not interrupt text. Sus pre-animaciones no interrumpirán el texto. - + Couldn't open chatlog.txt to write into. No se pudo abrir chatlog.txt para escribir. - + The IC chatlog has been saved. El chat IC se ha guardado. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. ¡No tienes una carpeta `base/cases /`! Ha sido creada para ti. Pero debido a que no existia la carpeta, tampoco habían casos guardados ahí. - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 ¡Debe dar un nombre de archivo para cargar (no se necesita extensión)! Asegúrese de que esté en la carpeta `base/cases/` y de que tenga el formato correcto. Casos que puede cargar: %1 - + Case made by %1. Caso hecho por %1. - + Navigate to %1 for the CM doc. Navegue a %1 para el documento del CM. - - - - + + + + UNKNOWN - + Your case "%1" was loaded! Su caso "%1" fue cargado! - + + Stop Current Song + + + + Play Random Song Reproducir canción aleatoria - + Expand All Categories Expandir todas las categorías - + Collapse All Categories Contraer todas las categorías - + Fade Out Previous Desvanecer Anterior - + Fade In Fundirse - + Synchronize Sincronizar - + Default Predeterminado @@ -1269,7 +1408,7 @@ Cases you can load: Casos que puede cargar: - + Too many arguments to load a case! You only need one filename, without extension. ¡Demasiados argumentos para cargar un caso! Solo necesita un nombre de archivo, sin extensión. @@ -1294,34 +1433,34 @@ Casos que puede cargar: " fue cargado! - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. ¡No tienes una carpeta `base/cases /`! Fue creada para ti. - + You need to give a filename to save (extension not needed) and the courtroom status! ¡Debe dar un nombre de archivo para guardar (no se necesita la extensión) y el estado de la sala del tribunal! - + Too many arguments to save a case! You only need a filename without extension and the courtroom status! why two exclamations, seems excesive. ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. - + Succesfully saved, edit doc and cmdoc link on the ini! ¡Guardado con éxito, puede editar el doc y doc link en el archivo ini! - + Master - - + + Server @@ -1334,28 +1473,28 @@ Casos que puede cargar: ¡Demasiados argumentos para salvar un caso! Solo necesita un nombre de archivo sin extensión y el estado de la sala del tribunal. - + Reason: Razón: - + Call Moderator Llamar Moderador - - + + Error Error - + You must provide a reason. Debes proporcionar una razón. - + The message is too long. El mensaje es muy largo. @@ -1422,28 +1561,28 @@ Se le preguntará si hay cambios no guardados. - + Transfer evidence to private inventory. Transferir evidencia al inventario privado. - + Transfer evidence to global inventory. Transferir evidencia al inventario global. - + The piece of evidence you've been editing has changed. La evidencia que has estado editando ha cambiado. - + Do you wish to keep your changes? ¿Desea conservar sus cambios? - + Name: %1 Image: %2 Description: @@ -1454,125 +1593,140 @@ Descripción: %3 - + Images (*.png) Imágenes (* .png) - - - + + + Double-click to edit... Doble click para editar... - + Add new evidence... Añadir nueva evidencia... - + Evidence has been modified. La evidencia ha sido modificada. - + Do you want to save your changes? ¿Quieres guardar tus cambios? - + Current evidence is global. Click to switch to private. La evidencia actual es global. Haga clic para cambiar a privado. - + Current evidence is private. Click to switch to global. La evidencia actual es privada. Haga clic para cambiar a global. - + "%1" has been transferred. "%1" ha sido transferido. - + Save Inventory Guardar inventario - - + + Ini Files (*.ini) Archivos Ini (*.ini) - + Open Inventory Abrir el inventario + + DemoServer + + + + Load Demo + + + + + + Demo Files (*.demo) + + + Lobby - + Attorney Online 2 - + Search Buscar - + Name Nombre - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? No parece que su cliente esté configurado correctamente. ¿Descargó todos los recursos correctamente desde tiny.cc/getao, incluida la gran carpeta 'base'? - + Version: %1 Versión: %1 - + Settings Ajustes - + Allows you to change various aspects of the client. Le permite cambiar varios aspectos del cliente. - + Loading Cargando - + Cancel Cancelar - + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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 BASS audio engine.<br>APNG plugin loaded: %3<p>Built on %4 <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Desarrollo del cliente:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Prueba de control de calidad:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Agradecimiento especial:</b><br>CrazyJC y MaximumVolty (versión 2.8); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, y FanatSors (AO1); server hosts, game masters, case makers, creadores de contenido y toda la comunidad AO2.<p>El proyecto Attorney Online novela visual en red tiene copyright (c) 2016-2020 Attorney Online developers. Se aplican licencias de código abierto. Todos los demás activos son propiedad de sus respectivos dueños.<p>Usando Qt versión %2 con el motor de audio BASS.<br>Plugin APNG cargado: %3<p>Compilado el %4 - + Yes - + No @@ -1585,7 +1739,7 @@ Did you download all resources correctly from tiny.cc/getao, including the large <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Desarrollo del cliente:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Prueba de control de calidad:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Agradecimiento especial:</b><br>CrazyJC y MaximumVolty (versión 2.8); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, y FanatSors (AO1); server hosts, game masters, case makers, creadores de contenido y toda la comunidad AO2.<p>El proyecto Attorney Online novela visual en red tiene copyright (c) 2016-2020 Attorney Online developers. Se aplican licencias de código abierto. Todos los demás activos son propiedad de sus respectivos dueños.<p>Usando Qt versión %2 con el motor de audio %3.<p>Compilado el %4 - + About Acerca de @@ -1598,13 +1752,13 @@ Did you download all resources correctly from tiny.cc/getao, including the large <h2>Attorney Online %1</h2>El simulador de drama legal<p><b>Código fuente:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https: //github.com/AttorneyOnline/AO2-Client</a><p><b>Desarrollo mayor:</b> <br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Agradecimiento especial:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (diseño de interfaz de usuario), Draxirch (diseño de interfaz de usuario), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 En línea: %1/%2 - - + + Offline Fuera de línea @@ -1626,17 +1780,17 @@ Did you download all resources correctly from tiny.cc/getao, including the large debug_functions - + Error: %1 - + Error - + Notice In spanish it would be "Aviso", but I believe it's going to be more useful for bug reports to not translate any debug strings. diff --git a/resource/translations/ao_jp.qm b/resource/translations/ao_jp.qm index e4fb562..5989c9b 100644 Binary files a/resource/translations/ao_jp.qm and b/resource/translations/ao_jp.qm differ diff --git a/resource/translations/ao_jp.ts b/resource/translations/ao_jp.ts index c2fea9a..2298bcf 100644 --- a/resource/translations/ao_jp.ts +++ b/resource/translations/ao_jp.ts @@ -4,72 +4,69 @@ AOApplication - + Disconnected from server. - + サーバーがつながらなくなりました - + Error connecting to master server. Will try again in %1 seconds. - + マスターサーバーにつながりません。%1秒の後でもう一回 - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. - + Attorney Online 2 - + 逆転裁判オンライン2 - + Loading ロード中 - Loading evidence: %1/%2 - 証拠がロード中: %1/%2 + 証拠がロード中: %1/%2 - - + Loading music: %1/%2 音楽がロード中: %1/%2 - - + Loading chars: %1/%2 キャラがロード中: %1/%2 - + You have been kicked from the server. Reason: %1 - + You have been banned from the server. Reason: %1 - + You are banned on this server. Reason: %1 @@ -118,7 +115,7 @@ Reason: %1 Settings - + 設定 @@ -156,413 +153,503 @@ Reason: %1 - + Default username: - + Your OOC name will be automatically set to this value when you join a server. - + Custom shownames: - + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - + Backup MS: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - + Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - + Language: - + Sets the language if you don't want to use your system language. - + Callwords - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - + Audio - + Audio device: - + Sets the audio device for all sounds. - + Music: 音楽: - + SFX: 効果音: - + Blips: ブリップ: - + Sets the volume of the blips, the talking sound effects. - + Blip rate: - + Sets the delay between playing the blip sounds. - + Blank blips: - + If true, the game will play a blip sound even when a space is 'being said'. - + Enable Looping SFX: - + If true, the game will allow looping sound effects to play on preanimations. - + Kill Music On Objection: - + - Keep current setting - + + Log newline: + + + + + 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'. + + + + + Log margin: + + + + + The distance in pixels between each entry in the IC log. Default: 0. + + + + + Log timestamp: + + + + + If ticked, log will contain a timestamp in UTC before the name. + + + + + Log IC actions: + + + + + If ticked, log will show IC actions such as shouting and presenting evidence. + + + + + Text Stay Time: + + + + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior. + + + + + Desynchronize IC Logs: + + + + + If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). + + + + + Instant Objection: + + + + + If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up. + + + + Allow Screenshake: - + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Allow Effects: - + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. - + Network Frame Effects: - + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. - + Colors in IC Log: - + Use the markup colors in the server IC chatlog. - + Sticky Sounds: - + Turn this on to prevent the sound dropdown from clearing the sound after playing it. - + Sticky Effects: - + Turn this on to prevent the effects dropdown from clearing the effect after playing it. - + Sticky Preanims: - + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + Custom Chatboxes: + + + Turn this on to allow characters to define their own custom chat box designs. + + + + Sets the music's default volume. - + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - + Play a blip sound "once per every X symbols", where X is the blip rate. - + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - + Casing - + This server supports case alerts. - + This server does not support case alerts. - + Pretty self-explanatory. - + Casing: - + If checked, you will get alerts about case announcements. - + Defense: - + 弁護士 - + If checked, you will get alerts about case announcements if a defense spot is open. - + Prosecution: - + 検事 - + If checked, you will get alerts about case announcements if a prosecutor spot is open. - + Judge: - + 裁判官 - + If checked, you will get alerts about case announcements if the judge spot is open. - + Juror: - + 陪審員 - + If checked, you will get alerts about case announcements if a juror spot is open. - + Stenographer: - + 記録官 - + If checked, you will get alerts about case announcements if a stenographer spot is open. - + CM: - + If checked, you will appear amongst the potential CMs on the server. - + Hosting cases: - + If you're a CM, enter what cases you are willing to host. + + + Automatic Logging: + + + + + If checked, all logs will be automatically written in the /logs folder. + + Courtroom - + Password - + パースワード - + Spectator 観客 - - + + Search - + 検索 - + Passworded - + Taken - + Generating chars: %1/%2 - + Showname - + Message - + Name 名前 - + Pre - + Flip フリップ - + Guard ガード - + Additive - - + + Casing - + Shownames - + Immediate @@ -591,204 +678,296 @@ Reason: %1 黄色 - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 - + Case made by %1. - + Navigate to %1 for the CM doc. - + Your case "%1" was loaded! - - + + Server - + サーバー - + + + + None + + + + + % x offset - - Hold It! + + % y offset - - - - When this is turned on, your next in-character message will be a shout! + + Change the horizontal percentage offset of your character's position from the center of the screen. - - Objection! - 意義あり! - - - - Take That! + + Change the vertical percentage offset of your character's position from the center of the screen. - - Toggle between server chat and global AO2 chat. + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/iniswaps.ini - - - - - This will display the animation in the viewport as soon as it is pressed. + + Remove the currently selected sound effect. - Guilty! + Hold It! + 待った! + + + + + + When this is turned on, your next in-character message will be a shout! - + + Objection! + 意義あり! + + + + Take That! + くらえ! + + + + Toggle between server chat and global AO2 chat. + + + + + + + + This will display the animation in the viewport as soon as it is pressed. + + + + + Guilty! + 有罪! + + + Bring up the Character Select Screen and change your character. - + Refresh the theme and update all of the ui elements to match. - + Request the attention of the current server's moderator. - + Allows you to change various aspects of the client. - + クライアントで変更できます - + An interface to help you announce a case (you have to be a CM first to be able to announce cases) - + Switch between Areas and Music lists - + Play a single-shot animation as defined by the emote when checked. - + If preanim is checked, display the input text immediately as the animation plays concurrently. - + Mirror your character's emotes when checked. - + Add text to your last spoken message when checked. - + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. - + Lets you receive case alerts when enabled. (You can set your preferences in the Settings!) - + Display customized shownames for all users when checked. - + Custom Shout! - + This will display the custom character-defined animation in the viewport as soon as it is pressed. To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect - + Play realization sound and animation in the viewport on the next spoken message when checked. - + Shake the screen on next spoken message when checked. - + Display the list of character folders you wish to mute. - - + + Increase the health bar. - - + + Decrease the health bar. - + Change the text color of the spoken message. You can also select a part of your currently typed message and use the dropdown to change its color! - + Back to Lobby ロビーに戻る - - - + + + + HOLD IT! + + + + + + + OBJECTION! + + + + + + + TAKE THAT! + + + + + + + CUSTOM OBJECTION! + + + + + + + shouts + + + + + + has presented evidence + + + + + + + has stopped the music + + + + + + [MISSING] %1 + + + + + has played a song - + You will now pair up with %1 if they also choose your character in return. + + + You have set your offset to %1%%. + + Rainbow @@ -802,307 +981,310 @@ You can also select a part of your currently typed message and use the dropdown シアン - - % offset - - - - + To front - + To behind - + Select a character you wish to pair with. - - Change the percentage offset of your character's position from the center of the screen. - - - - + Change the order of appearance for your character. - + Display the list of characters to pair with. - + Oops, you're muted! - + Set your character's emote to play on your next message. - + Set your character's supplementary background. - - Set an 'iniswap', or an alternative character folder to refer to from your current character. -Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - - - - - + Remove the currently selected iniswap from the list and return to the original character folder. - + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini - + Choose an effect to play on your next spoken message. The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. - + Music 音楽 - + Sfx 効果音 - + Blips ブリップ - + Change character - + キャラを変更します - + Reload theme - + Call mod - + Settings - + 設定 - + A/M - + Preanim - + Return back to the server list. - + サーバーリストに戻る - + Become a spectator. You won't be able to interact with the in-character screen. - + You were granted the Disable Modcalls button. - - + + CLIENT - + クライアント - + You have been banned. - + You opened the settings menu. - + You are no longer paired with anyone. - + Are you sure you typed that well? The char ID could not be recognised. - - You have set your offset to - - - - + Your offset must be between -100% and 100%! - + That offset does not look like one. - + + You have set your vertical offset to %1%%. + + + + + Your vertical offset must be between -100% and 100%! + + + + + That vertical offset does not look like one. + + + + You switched your music and area list. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - + Your pre-animations interrupt again. - + Your pre-animations will not interrupt text. - + Couldn't open chatlog.txt to write into. - + The IC chatlog has been saved. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. - + Too many arguments to load a case! You only need one filename, without extension. - - - - + + + + UNKNOWN - + 未知 - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. - + You need to give a filename to save (extension not needed) and the courtroom status! - + Too many arguments to save a case! You only need a filename without extension and the courtroom status! - + Succesfully saved, edit doc and cmdoc link on the ini! - + Master マスター - + + Stop Current Song + + + + + Play Random Song + + + + Expand All Categories - + Collapse All Categories - + Fade Out Previous - + Fade In - + Synchronize - + Default - + Reason: - + Call Moderator モデレーターを呼ぶ - - + + Error エラー - + You must provide a reason. - + The message is too long. @@ -1168,28 +1350,28 @@ You will be prompted if there's any unsaved changes. - + Transfer evidence to private inventory. - + Transfer evidence to global inventory. - + The piece of evidence you've been editing has changed. - + Do you wish to keep your changes? - + Name: %1 Image: %2 Description: @@ -1197,64 +1379,79 @@ Description: - + Images (*.png) イメージ (*.png) - - - + + + Double-click to edit... - + Add new evidence... 新しい証拠を付け加える... - + Evidence has been modified. - + Do you want to save your changes? - + Current evidence is global. Click to switch to private. - + Current evidence is private. Click to switch to global. - + "%1" has been transferred. - + Save Inventory - - + + Ini Files (*.ini) - + Open Inventory + + DemoServer + + + + Load Demo + + + + + + Demo Files (*.demo) + + + Discord @@ -1281,69 +1478,79 @@ Description: Lobby - + Attorney Online 2 - + 逆転裁判オンライン2 - + Search - + 検索 - + Name 名前 - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - + クライアントの設定が正しくないかもしれません。「tiny.cc/getao」からのファイルをダウンロードしましたか? - + Version: %1 - + バージョン: %1 - + Settings - + 設定 - + Allows you to change various aspects of the client. - + クライアントで変更できます - + Loading ロード中 - + Cancel キャンセル - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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 BASS audio engine.<br>APNG plugin loaded: %3<p>Built on %4 - + + Yes + + + + + No + + + + About - + について - + Online: %1/%2 - + オンライン: %1/%2 - - + + Offline オフライン @@ -1355,28 +1562,27 @@ Did you download all resources correctly from tiny.cc/getao, including the large UNKNOWN - + 未知 - has played a song: - + は音楽をかける debug_functions - + Error: %1 エラー: %1 - + Error エラー - + Notice 通知 diff --git a/resource/translations/ao_pl.qm b/resource/translations/ao_pl.qm index 04ec834..5bb086d 100644 Binary files a/resource/translations/ao_pl.qm and b/resource/translations/ao_pl.qm differ diff --git a/resource/translations/ao_pl.ts b/resource/translations/ao_pl.ts index 6383833..e3a9974 100644 --- a/resource/translations/ao_pl.ts +++ b/resource/translations/ao_pl.ts @@ -4,26 +4,26 @@ AOApplication - + Disconnected from server. Odłączono od serwera. - + Error connecting to master server. Will try again in %1 seconds. Błąd podczas łączenia się z głównym serwerem. Spróbuj ponownie za %1 sekundy. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. Odkryto błąd podczas łączenia się z głównym serwerem. -Używamy wielu master serwerów, aby zminimalizować każdą możliwą przerwę, ale klient wyczerpał jakąkolwiek możliwość znalezienia i połączenia się z jednym. +Używamy wielu master serwerów, aby zminimalizować każdą możliwą przerwę, ale klient wyczerpał wszystkie możliwe metody znalezienia i połączenia się z jednym. Sprawdź swoje połączenie internetowe oraz zaporę ogniową i spróbuj ponownie. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. Nieaktualna wersja! Twoja wersja: %1 @@ -36,58 +36,55 @@ Have a nice day. Życzymy miłego dnia. - + Attorney Online 2 Prawnik w Internecie 2 - + Loading Ładowanie - Loading evidence: %1/%2 - Ładowanie dowodów: + Ładowanie dowodów: %1/%2 - - + Loading music: %1/%2 Ładowanie muzyki: %1/%2 - - + Loading chars: %1/%2 Ładowanie postaci: %1/%2 - + You have been kicked from the server. Reason: %1 - Zostałeś wyrzucony z tego serwera. + Zostałeś/aś wyrzucony/a z tego serwera. Powód: %1 - + You have been banned from the server. Reason: %1 - Zostałeś zbanowany z tego serwera. + Zostałeś/aś zbanowany/a z tego serwera. Powód: %1 - + You are banned on this server. Reason: %1 - Jesteś zbanowany na tym serwerze. + Jesteś zbanowany/a na tym serwerze. Powód: %1 @@ -143,7 +140,7 @@ Powód: %1 Gameplay - Rozgrywka + Gra @@ -153,7 +150,7 @@ Powód: %1 Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - Ustawia motyw używany w grze. Jeżeli nowy motyw zmienia wygląd poczekalni, będziesz musiał ją również odświeżyć, aby zmiany zaczęły działać, np. poprzez dołączenie do serwera i wyjście z niego. + Ustawia motyw używany w grze. Jeżeli nowy motyw zmienia wygląd poczekalni, będziesz musiał(a) ją również odświeżyć, aby zmiany zaczęły działać, np. poprzez dołączenie do serwera i wyjście z niego. @@ -163,7 +160,7 @@ Powód: %1 If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - Jeżeli zaznaczone, nowe wiadomości zaczną się pojawiać na dole (tak jak na czacie OOC). Tradycyjne (AO1) zachowanie jest równoważne do tego bycia nie zaznaczonym. + Jeżeli zaznaczone, nowe wiadomości zaczną się pojawiać na dole (tak jak na czacie OOC). Tradycyjne (AO1) zachowanie jest równoważne do tego bycia odznaczonym. @@ -173,45 +170,114 @@ Powód: %1 The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - Ilość wiadomości, jakie dziennik IC będzie pokazywał zanim usunie starsze wiadomości. Wartość 0 albo niżej, liczy się jako 'nieskończone'. + Ilość wiadomości, jakie dziennik IC będzie pokazywał zanim usunie starsze wiadomości. Wartość 0 lub niżej, liczy się jako 'nieskończone'. - + + Log newline: + Oddzielenia w dzienniku: + + + + 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'. + Jeśli zaznaczone, nowe wiadomości będą pojawiać się oddzielone, z wiadomością w kolejnym wierszu po nicku. Jeżeli odznaczone, będzie się pokazywać w formacie 'nick: wiadomość". + + + + Log margin: + Margines dziennika: + + + + The distance in pixels between each entry in the IC log. Default: 0. + Dystans w pikselach pomiędzy każdym wpisem w dzienniku IC. Domyślnie: 0. + + + + Log timestamp: + Daty w dzienniku: + + + + If ticked, log will contain a timestamp in UTC before the name. + Jeżeli zaznaczone, dziennik będzie pokazywać datę w UTC przed nickiem. + + + + Log IC actions: + Zapisuj akcje IC: + + + + If ticked, log will show IC actions such as shouting and presenting evidence. + Jeśli zaznaczone, dziennik będzie pokazywać akcje IC takie jak krzyki i prezentowanie dowodów. + + + + Text Stay Time: + Czas Pozostania Tekstu: + + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behaivor. + Minimalna ilość czasu (w milisekundach), w której wiadomość IC musi pozostać na ekranie, zanim kolejna zostanie wyświetlona, działa niczym 'kolejka'. Ustaw na 0, aby wyłączyć tą funkcję. + + + + Desynchronize IC Logs: + Desynchronizacja Dziennika IC: + + + + If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). + Jeżeli zaznaczone, dziennik pokaże wiadomości jako odebrane, podczas gdy okno będzie analizować kolejkę (Czas Pozostania Tekstu). + + + + Instant Objection: + Natychmiastowy Sprzeciw: + + + + If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up. + Jeśli wartość Czasu Pozostania Tekstu jest większa, niż 0, natychmiastowe sprzeciwy pominą kolejkowane wiadomości, zamiast czekania na nadrobienie zaległości. + + + Default username: Domyślna nazwa użytkownika: - + Your OOC name will be automatically set to this value when you join a server. - Twoja nazwa OOC będzie ustawiana automatycznie do tej wartości, kiedy dołączysz na serwer. + Twoja nazwa OOC będzie automatycznie ustawiana do tej wartości, gdy dołączysz na serwer. - + Custom shownames: Niestandardowe ksywki: - + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. Daje domyślną wartość przyciskowi 'Niestandardowe ksywki', który określa, czy klient powinien pokazywać niestandardowe nazwy IC. - + Backup MS: Kopia zapasowa master serwera: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Jeśli wbudowane szukanie serwerów zawiedzie, gra spróbuje użyć adresu podanego tutaj i użyje go jako adresu zapasowego master serwera. - + Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Pozwala innym na Discordzie zobaczyć na jakim serwerze się znajdujesz, jaką postać używasz i jak długo grałeś. @@ -224,292 +290,307 @@ Powód: %1 Pozwala na wstrząśnięcia ekranu i błyśnięcia. Wyłącz to, jeśli przejmujesz się lub masz problemy z światłoczułością oraz/lub napady padaczkowe. - + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior. + + + + Language: Język: - + Sets the language if you don't want to use your system language. Ustawia język, jeśli nie chcesz używać języka systemowego. - + - Keep current setting - Zostaw obecne ustawienia - + Allow Screenshake: Zezwalaj Wstrząśnięcia: - + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. Zezwala na wstrząśnięcia ekranu. Wyłącz to, jeśli przejmujesz się lub masz problemy z światłoczułością oraz/lub z napadami padaczkowymi. - + Allow Effects: Zezwalaj Efekty: - + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. Zezwala na efekty ekranowe. Wyłącz to, jeśli przejmujesz się lub masz problemy z światłoczułością oraz/lub z napadami padaczkowymi. - + Network Frame Effects: Efekty Network Frame: - + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. Wysyła wstrząśnięcia ekranu, błyśnięcia i dźwięki, jak zdefiniowano w pliku char.ini, przez sieć. Działa tylko w przypadku serwerów, które obsługują tę funkcję. - + Colors in IC Log: - Kolory w dzienniku IC: + Kolory w Dzienniku IC: - + Use the markup colors in the server IC chatlog. Użyj znaczników kolorów w serwerowym dzienniku IC. - + Sticky Sounds: Lepkie Dźwięki: - + Turn this on to prevent the sound dropdown from clearing the sound after playing it. Włącz to, aby zapobiec listę dźwięków przed odznaczeniem zaznaczonego dźwięku po jego odtworzeniu. - + Sticky Effects: Lepkie Efekty: - + Turn this on to prevent the effects dropdown from clearing the effect after playing it. Włącz to, aby zapobiec listę efektów przed odznaczeniem zaznaczonego efektu po jego odtworzeniu. - + Sticky Preanims: Lepkie Przed-animacje: - + Turn this on to prevent preanimation checkbox from clearing after playing the emote. Włącz to, aby zapobiec przycisku wyboru przed-animacji od odznaczenia się po odegraniu emotki. - + Custom Chatboxes: Niestandardowe Okna Czatu: - + Turn this on to allow characters to define their own custom chat box designs. Włącz to, aby pozwolić postaciom definiować swoje własne designy okienek czatu. - + Callwords Zawołania - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - <html><head/><body>Wpisz tyle zawołań, ile dusza zapragnie. Wielkość liter nie ma znaczenia. Miej na uwadze, aby każde zawołanie było w swojej lini!<br>Nie zostawiaj spacji na końcu -- zostaniesz zaalarmowany za każdym razem, kiedy ktoś użyje spacji w swojej wiadomości.</body></html> + <html><head/><body>Wpisz tyle zawołań, ile dusza zapragnie. Wielkość liter nie ma znaczenia. Miej na uwadze, aby każde zawołanie było w swoim wierszu!<br>Nie zostawiaj spacji na końcu -- zostaniesz zaalarmowany za każdym razem, kiedy ktoś użyje spacji w swojej wiadomości.</body></html> - + Audio Dźwięk - + Audio device: Urządzenie dźwiękowe: - + Sets the audio device for all sounds. Ustawia urządzenie dźwiękowe dla wszystkich dźwięków. - + Music: Muzyka: - + Sets the music's default volume. Ustawia domyślną głośność muzyki. - + SFX: Efekty dźwiękowe (SFX): - + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Ustawia domyślną głośność efektów dźwiękowych (SFX). Sprzeciwy i same efekty specjalne są zaliczane jako 'SFX'. + Ustawia domyślną głośność efektów dźwiękowych (SFX). Sprzeciwy, jak i same efekty specjalne są zaliczane jako 'SFX'. - + Blips: Blipy: - + Sets the volume of the blips, the talking sound effects. Ustawia głośność blipów, efektów dźwiękowych mówienia. - + Blip rate: Szybkość blipów: - + Sets the delay between playing the blip sounds. Ustawia opóźnienie pomiędzy graniem blipów. - + Play a blip sound "once per every X symbols", where X is the blip rate. Zagraj dźwięk blipa "raz na X symboli", gdzie X to tempo blipów. - + Blank blips: The 'blip' isn't an accurate polish representation of this english word. Puste blipy: - + If true, the game will play a blip sound even when a space is 'being said'. Jeżeli zaznaczone, gra zagra dźwięk blip za każdym razem spacja 'jest mówiona'. - + Enable Looping SFX: Włącz pętlące się efekty dźwiękowe (SFX): - + If true, the game will allow looping sound effects to play on preanimations. Jeśli zaznaczone, gra zezwoli na pętlące się efekty dźwiękowe (SFX) na odtwarzanie podczas animacji. - + Kill Music On Objection: Przerwij muzykę na czas sprzeciwu: - + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - Jeśli zaznaczone, gra przerwie muzykę, kiedy ktoś się sprzeciwi (Objection!). + Jeśli zaznaczone, gra przerwie muzykę, kiedy ktoś się sprzeciwi. + + + + Automatic Logging: + Auto Logowanie: + + + + If checked, all logs will be automatically written in the /logs folder. + Jeśli zaznaczone, dziennik będzie automatycznie zapisywany w twoim folderze /logs. If true, the game will stop music when someone objects, like in the actual games. Jeśli zaznaczone, gra przerwie muzykę, kiedy ktoś sprzeciwi się, tak jak w oryginalnych grach. - + Casing Rozprawy - + This server supports case alerts. Ten serwer wspiera komunikaty rozpraw. - + This server does not support case alerts. Ten serwer nie wspiera komunikatów rozpraw. - + Pretty self-explanatory. Dosyć oczywiste. - + Casing: Rozprawy: - + If checked, you will get alerts about case announcements. Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw. - + Defense: Obrona: - + If checked, you will get alerts about case announcements if a defense spot is open. Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce obrony jest otwarte. - + Prosecution: Prokuratura: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce prokuratora jest otwarte. - + Judge: Sędzia: - + If checked, you will get alerts about case announcements if the judge spot is open. Jeśli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce sędzi jest otwarte. - + Juror: Ławnik: - + If checked, you will get alerts about case announcements if a juror spot is open. Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce ławnika jest otwarte. - + Stenographer: Stenograf: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Jeżeli zaznaczone, dostaniesz komunikaty o ogłoszeniach rozpraw, jeśli miejsce stenografa jest otwarte. - + CM: Zarządca rozpraw (CM): - + If checked, you will appear amongst the potential CMs on the server. Jeśli zaznaczone, pojawisz się wśród potencjalnych zarządców rozpraw (CM) na serwerze. @@ -522,12 +603,12 @@ Powód: %1 Jeżeli zaznaczone, pojawisz się wśród potencjalnych świadków na serwerze. - + Hosting cases: Hostowane rozprawy: - + If you're a CM, enter what cases you are willing to host. Jeżeli jesteś zarządcą rozpraw (CM), wpisz jakie rozprawy jesteś chętny hostowania. @@ -535,28 +616,28 @@ Powód: %1 Courtroom - + Password Hasło - + Spectator Spektator - - + + Search Wyszukaj - + Passworded Zahasłowany - + Taken Zajęty @@ -565,63 +646,63 @@ Powód: %1 Nie znaleziono %1 - + Generating chars: %1/%2 Generowanie postaci: -%1.%2 +%1/%2 - + Showname Ksywka - + Message Wiadomość - + Name Nazwa - + Pre przed- - + Flip Odwróć - + Guard Na Służbie (mod) - + Additive - I'm not sure about this one. - Dodatek + I'm not sure about this one either.The previous form was "Dodatek". + Kontynuacja - - + + Casing Rozprawa - + Shownames Ksywki - + Immediate - Bez ociągania się + Natychmiastowe White @@ -652,208 +733,301 @@ Powód: %1 To nic nie robi, ale proszę bardzo. - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 - Musisz podać nazwę pliku, którego chcesz załadować (rozszerzenie nie potrzebne!) Upewnij się, że jest w folderze `base/cases/` i że jest to poprawnie sformatowane ini. + Musisz podać nazwę pliku, którego chcesz załadować (rozszerzenie nie jest potrzebne!) Upewnij się, że jest w folderze `base/cases/` i że jest to poprawnie sformatowane ini. Rozprawy które możesz załadować: %1 - + Case made by %1. - Rozprawa zrobiona przez %1. + Rozprawa stworzona przez %1. - + Navigate to %1 for the CM doc. Przejdź do %1, aby dojść do dokumentu CM. - + Your case "%1" was loaded! Twoja rozprawa "%1" została wczytana! - - + + Server Serwer - + + + + None Nic - + + % x offset + % wyrówanie x + + + + % y offset + % wyrówanie y + + + + Change the horizontal percentage offset of your character's position from the center of the screen. + Zmień procent poziomego wyrównania pozycji twojej postaci licząc od środka ekranu. + + + + Change the vertical percentage offset of your character's position from the center of the screen. + Zmień procent pionowego wyrównania pozycji twojej postaci licząc od środka ekranu. + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/iniswaps.ini + Ustaw 'iniswap' albo alternatywny folder postaci, aby odnosił się do twojej obecnej postaci. +Edytuj poprzez wciśnięcie Enter po wpisaniu tekstu, [X] aby usunąć. Zapisuje się to w base/characters/iniswaps.ini + + + + Remove the currently selected sound effect. + Wycofaj obecny zaznaczony efekt dźwiękowy. + + + Hold It! - (Hold It)! Zaczekaj! + Zaczekaj! - - - + + + When this is turned on, your next in-character message will be a shout! - Kiedy to jest włączone, twoja następna wiadomość IC będzie krzykiem! + Kiedy jest to włączone, twoja następna wiadomość IC będzie krzykiem! - + Objection! - (Objection!) Sprzeciw! + Sprzeciw! - + Take That! - (Take That!) Weź To! + Trzymaj To! - + Toggle between server chat and global AO2 chat. Przełączaj pomiędzy czatem serwerowym i globalnym czatem AO2. - - - - + + + + This will display the animation in the viewport as soon as it is pressed. To będzie wyświetlać animację w oknie, jak tylko zostanie to wciśnięte. - + Guilty! Winny! - + Bring up the Character Select Screen and change your character. Wyświetl ekran zmiany postaci i zmień swoją postać. - + Refresh the theme and update all of the ui elements to match. Odśwież motyw i uaktualnij wszystkie elementy UI, aby dopasować. - + Request the attention of the current server's moderator. - Poproś o uwagę moderatora obecnego serwera. + Zażądaj uwagę moderatora obecnego serwera. - + Allows you to change various aspects of the client. Umożliwia zmianę różnych aspektów klienta. - + An interface to help you announce a case (you have to be a CM first to be able to announce cases) Interfejs, który pomoże ci ogłosić rozprawę (musisz być zarządcą rozpraw (CM), aby móc ogłaszać rozprawy) - + Switch between Areas and Music lists Przełącz pomiędzy listami Obszarów i Muzyki - + Play a single-shot animation as defined by the emote when checked. Odegraj pojedyńczą animację, jak zdefiniowano przez emotkę, gdy zaznaczone. - + If preanim is checked, display the input text immediately as the animation plays concurrently. Jeśli przed-animacja jest zaznaczona, wyświetl wpisany tekst natychmiastowo, jednocześnie podczas odgrywania animacji. - + Mirror your character's emotes when checked. Odzwierciedlij emotki twojej postaci, gdy zaznaczone. - + Add text to your last spoken message when checked. Dodaj tekst do twojej ostatniej wiadomości, gdy zaznaczone. - + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. Nie słuchaj wezwań moda, gdy zaznaczone, zapobiegając grania dźwięków oraz skupiania uwagi na okienko. - + Lets you receive case alerts when enabled. (You can set your preferences in the Settings!) Pozwala ci otrzymywać komunikaty rozpraw, gdy włączone. (Możesz ustawić swoje preferencje w Ustawieniach!) - + Display customized shownames for all users when checked. Wyświetl niestandardowe ksywki dla wszystkich użytkowników, gdy zaznaczone. - + Custom Shout! - Niestandardowy Krzyk (sprzeciw)! + Niestandardowy Krzyk! - + This will display the custom character-defined animation in the viewport as soon as it is pressed. To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect - To będzie wyświetlać zdefiniowanej animacji niestandardowej postaci w oknie, jak tylko zostanie to wciśnięte. -Aby zrobić coś takiego, folder twojej postaci musi zawierać niestandardowe [webp/apng/gif/png] i niestandardowe [wav/ogg/opus] efekty dźwiękowe + Będzie to wyświatlać animację zdefiniowaną przez niestandardową postaći w oknie, jak tylko zostanie to wciśnięte. +Aby stworzyć coś takiego, folder twojej postaci musi zawierać niestandardowe [webp/apng/gif/png] i niestandardowe [wav/ogg/opus] efekty dźwiękowe - + Play realization sound and animation in the viewport on the next spoken message when checked. Zagraj dźwięk realizacji i animację w oknie podczas następnej wiadomości, gdy zaznaczone. - + Shake the screen on next spoken message when checked. Wstrząśnij ekranem podczas następnej wiadomości, gdy zaznaczone. - + Display the list of character folders you wish to mute. Wyświetl listę folderów postaci, których chcesz zmutować. - - + + Increase the health bar. Zwiększ pasek życia. - - + + Decrease the health bar. Obniż pasek życia. - + Change the text color of the spoken message. You can also select a part of your currently typed message and use the dropdown to change its color! - Zmień kolor tekstu dla twojej wiadomości. + Zmień kolor tekstu twojej wiadomości. Możesz również zaznaczyć część twojej obecnie pisanej wiadomości i użyć listy aby zmienić jej kolor! - + Back to Lobby Powrót do poczekalni - - - - has played a song - włączył piosenkę + + + + HOLD IT! + ZACZEKAJ! - + + + + OBJECTION! + SPRZECIW! + + + + + + TAKE THAT! + TRZYMAJ TO! + + + + + + CUSTOM OBJECTION! + NIESTANDARDOWY SPRZECIW! + + + + + + shouts + krzyki + + + + + has presented evidence + zaprezentował(a) dowód + + + + + + has stopped the music + zatrzymał(a) muzykę + + + + + [MISSING] %1 + [BRAKUJĄCY] %1 + + + + + has played a song + włączył(a) piosenkę + + + You will now pair up with %1 if they also choose your character in return. Będziesz teraz w parze z %1, jeśli oni również wybiorą twoją postać. + + + You have set your offset to %1%%. + Ustawiłeś/aś swoje wyrównanie do %1%%. + Rainbow Tęczowy @@ -871,96 +1045,92 @@ Możesz również zaznaczyć część twojej obecnie pisanej wiadomości i uży Turkusowy - % offset - % wyrówanie + % wyrówanie - + To front Do przodu - + To behind Do tyłu - + Select a character you wish to pair with. Zaznacz postać, z którą chcesz się sparować. - Change the percentage offset of your character's position from the center of the screen. - Zmień procentową odległość dla pozycji twojej postaci licząc od środka ekranu. + Zmień procentową odległość dla pozycji twojej postaci licząc od środka ekranu. - + Change the order of appearance for your character. Zmień kolejność występowania dla twojej postaci. - + Display the list of characters to pair with. Wyświetl listę postaci do sparowania się z. - + Oops, you're muted! Ups, jesteś zmutowany! - + Set your character's emote to play on your next message. Ustaw emotkę twojej postaci do odegrania podczas następnej wiadomości. - + Set your character's supplementary background. Ustaw uzupełniające tło twojej postaci. - Set an 'iniswap', or an alternative character folder to refer to from your current character. Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - Ustaw 'iniswap' albo alternatywny folder postaci, aby odnosił się do twojej obecnej postaci. + Ustaw 'iniswap' albo alternatywny folder postaci, aby odnosił się do twojej obecnej postaci. Edytuj poprzez pisanie i naciśnięcie enter, [X] aby usunąć. To się zapisuje do base/characters/<charname>/iniswaps.ini - - + Remove the currently selected iniswap from the list and return to the original character folder. Usuń obecne zaznaczony iniswap z listy i powróć do pierwotnego foldera postaci. - + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini - Ustaw efekt dźwiękowy do zagrania dla twojej następnej 'Animacji' Zostawienie to jako domyślne, użyje dźwięku zdefiniowanego przez emotkę (jeśli istnieje). -Edytuj poprzez pisanie i naciśnięcie enter, [X] aby usunąć. To się zapisuje do base/characters/<charname>/soundlist.ini + Ustaw efekt dźwiękowy do zagrania dla twojej następnej 'Animacji'. Zostawienie tego jako domyślne, użyje dźwięku zdefiniowanego przez emotkę (jeśli istnieje). +Edytuj poprzez wciśnięcie Enter po wpisaniu tekstu, [X] aby usunąć. Zapisuje się to w base/characters/<charname>/soundlist.ini - + Choose an effect to play on your next spoken message. The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. Wybierz efekt dla twojej następnej wiadomości. -Efekty są zdefiniowane w twoim pliku theme/effect/effects.ini. Twoja postać może zdefiniować niestandardowe efekty przez +Efekty są zdefiniowane w pliku theme/effect/effects.ini. Twoja postać może zdefiniować niestandardowe efekty przez kategorię char.ini [Options], effects = 'miscname' gdzie się odnosi do misc/<miscname>/effects.ini, aby przejrzeć efekty. - + Music Muzyka - + Sfx Sfx - + Blips Blipy @@ -969,69 +1139,69 @@ kategorię char.ini [Options], effects = 'miscname' gdzie się odnosi Limit dziennika - + Change character Zmiana postaci - + Reload theme Odśwież motyw - + Call mod Wezwij moda - + Settings Ustawienia - + A/M O meaning 'Obszar' and M meaning 'Muzyka'. O/M - + Preanim Whatever, I'll just call it an animation. Animacja - + Return back to the server list. Wróć z powrotem do listy serwerów. - + Become a spectator. You won't be able to interact with the in-character screen. - Zostań spektatorem. Nie będziesz mógł wchodzić w interakcję z oknem IC. + Funkcja spektatora. Nie będziesz mógł wchodzić w interakcję z oknem IC. - + You were granted the Disable Modcalls button. Zostałeś obdarzonym przyciskiem Wyłącz Wezwania Moda. - - + + CLIENT KLIENT - + You have been banned. - Zostałeś zbanowany. + Zostałeś/aś zbanowany. You were granted the Guard button. Zostałeś obdarzonym przyciskiem Na Służbie. - + You opened the settings menu. Otworzyłeś ustawienia. @@ -1044,156 +1214,180 @@ kategorię char.ini [Options], effects = 'miscname' gdzie się odnosi jeżeli oni również wybiorą ciebie spowrotem. - + You are no longer paired with anyone. Nie jesteś już w parze z nikim. - + Are you sure you typed that well? The char ID could not be recognised. Czy jesteś pewien, że dobrze to napisałeś? ID postaci nie zostało rozpoznane. - You have set your offset to - Musisz ustawić swoje wyrównanie do + Musisz ustawić swoje wyrównanie do - + Your offset must be between -100% and 100%! Twoje wyrównanie musi być między -100%, a 100%! - + That offset does not look like one. - To wyrównanie nie wygląda na poprawne. + To wyrównanie nie jest poprawne. - + + You have set your vertical offset to %1%%. + Ustawiłeś/aś swoje pionowe wyrównanie do %1%%. + + + + Your vertical offset must be between -100% and 100%! + Twoje pionowe wyrównanie musi być pomiędzy -100%, a 100%! + + + + That vertical offset does not look like one. + To pionowe wyrównanie nie jest poprawne. + + + You switched your music and area list. Przełączyłeś swoją listę obszarów i muzyki. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - Włączyłeś funkcje, które ten serwer może nie wspierać. Możliwe że, nie możesz rozmawiać na czacie IC lub gorzej z tego powodu. + Włączyłeś funkcje, które ten serwer może nie wspierać. Możliwe, że nie będziesz mógł rozmawiać na czacie IC lub gorzej przez to. - + Your pre-animations interrupt again. - Twoje animacje przerywają tekst spowrotem. + Twoje animacje będą przerywać tekst znowu. - + Your pre-animations will not interrupt text. Twoje animacje nie będą przerywać tekstu. - + Couldn't open chatlog.txt to write into. Nie można było otworzyć chatlog.txt, aby pisać w nim. - + The IC chatlog has been saved. Dziennik czatu IC został zapisany. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. Nie masz folderu `base/cases/`! Został zrobiony tylko dla ciebie, ale widząc, że ZOSTAŁ zrobiony tylko dla ciebie, prawdopodobnie plik rozpraw, którego szukasz nie został znaleziony tutaj. - + Too many arguments to load a case! You only need one filename, without extension. Zbyt dużo parametrów, aby załadować rozprawę! Potrzebujesz tylko jedną nazwę pliku, bez rozszerzenia nazwy pliku. - - - - + + + + UNKNOWN NIEZNANE - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. Nie masz folderu `base/cases/`! Został zrobiony tylko dla ciebie, ale widząc, że ZOSTAŁ zrobiony tylko dla ciebie, prawdopodobnie jakoś usunąłeś go. - + You need to give a filename to save (extension not needed) and the courtroom status! - Musisz podać nazwę pliku, aby go zapisać (rozszerzenie nie potrzebne) i status sali sądowej! + Musisz podać nazwę pliku, aby go zapisać (rozszerzenie nie jest potrzebne) i status sali sądowej! - + Too many arguments to save a case! You only need a filename without extension and the courtroom status! Zbyt dużo parametrów, aby zapisać rozprawę! Potrzebujesz tylko jedną nazwę pliku, bez rozszerzenia nazwy pliku i statusu sali sądowej! - + Succesfully saved, edit doc and cmdoc link on the ini! Zapisano pomyślnie, edytuj dokument i link cmdoc w .ini! - + Master - + + Stop Current Song + Zatrzymaj Obecną Piosenkę + + + + Play Random Song + Włącz Losową Piosenkę + + + Expand All Categories Rozwiń Wszystkie Kategorie - + Collapse All Categories Zwiń Wszystkie Kategorie - + Fade Out Previous Zanikaj poprzednie - + Fade In Rozjaśnij - + Synchronize Zsynchronizuj - + Default Domyślne - + Reason: Powód: - + Call Moderator Wezwij Moderatora - - + + Error Błąd - + You must provide a reason. Musisz podać przyczynę. - + The message is too long. Ta wiadomość jest zbyt długa. @@ -1204,7 +1398,7 @@ kategorię char.ini [Options], effects = 'miscname' gdzie się odnosi Present this piece of evidence to everyone on your next spoken message - Zaprezentuj ten dowód dla każdego podczas twojej następnej wiadomości + Zaprezentujesz ten dowód dla każdego podczas twojej następnej wiadomości @@ -1231,7 +1425,7 @@ kategorię char.ini [Options], effects = 'miscname' gdzie się odnosi Close the evidence display/editing overlay. You will be prompted if there's any unsaved changes. Zamknij wyświetlanie/edytowanie okienka dowodów. -Zostaniesz poproszony, jeśli są jakieś niezapisane zmiany. +Zostaniesz zawiadomiony, jeśli są jakieś niezapisane zmiany. @@ -1260,28 +1454,28 @@ Zostaniesz poproszony, jeśli są jakieś niezapisane zmiany. - + Transfer evidence to private inventory. Przenieś dowody do prywatnego ekwipunku. - + Transfer evidence to global inventory. Przenieś dowody do globalnego ekwipunku. - + The piece of evidence you've been editing has changed. - Ten dowód, który edytujesz, zmienił się. + Dowód, który edytujesz, właśnie się zmienił. - + Do you wish to keep your changes? Czy chcesz zatrzymać zmiany? - + Name: %1 Image: %2 Description: @@ -1292,124 +1486,153 @@ Opis: %3 - + Images (*.png) Obrazy (*.png) - - - + + + Double-click to edit... Kliknij dwa razy, aby edytować... - + Add new evidence... Dodaj nowe dowody... - + Evidence has been modified. Dowody zostały zmodyfikowane. - + Do you want to save your changes? Czy chcesz zapisać zmiany? - + Current evidence is global. Click to switch to private. - Obecne dowody są globalne. Kliknij, aby przełączyć na prywatne. + Obecne dowody są globalne. Kliknij, aby przełączyć się na prywatne. - + Current evidence is private. Click to switch to global. - Obecne dowody są prywatne. Kliknij, aby przełączyć na globalne. + Obecne dowody są prywatne. Kliknij, aby przełączyć się na globalne. - + "%1" has been transferred. "%1" został przeniesiony. - + Save Inventory Zapisz ekwipunek - - + + Ini Files (*.ini) Pliki ini (*.ini) - + Open Inventory Otwórz ekwipunek + + DemoServer + + + + Load Demo + + + + + + Demo Files (*.demo) + + + Lobby - + Attorney Online 2 - + Search Szukaj - + Name Nazwa - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? Wygłąda na to, że twój klient nie jest ustawiony poprawnie. Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży folder 'base'? - + Version: %1 Wersja: %1 - + Settings Ustawienia - + Allows you to change various aspects of the client. Umożliwia zmianę różnych aspektów klienta. - + Loading Ładowanie - + Cancel Anuluj - + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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 BASS audio engine.<br>APNG plugin loaded: %3<p>Built on %4 + <h2>Attorney Online %1</h2>Symulator dramy sądowej<p><b>Kod źródłowy:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Główny rozwój:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Rozwój Klienta:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Testowanie QA:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (inaczej Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Szczególne podziękowania:</b><br>CrazyJC (dyrektor wydania 2.8) i MaximumVolty (promocja wydania 2.8); Remy, Hibiki, court-records.net (sprite'y); Qubrick (webAO); Rue (strona internetowa); Draxirch (design UI); Lewdton i Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy oraz FanatSors (AO1); hostom serwerów, mistrzom gier, twórcom rozpraw, twórcom kontentu, i dla całej społeczności AO2!<p>Attorney Online sieciowy projekt wizualnej powieści ma prawa autorskie (c) 2016-2020 Attorney Online developerzy. Dotyczy licencji open-source. Wszystkie inne własności należą do ich odpowiednich właścicieli.<p>Działa na wersji Qt %2 z silnikiem audio BASS.<br>Plugin APNG załadowany: %3<p>Zbudowany na %4 + + + + Yes + Tak + + + + No + Nie + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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>Built on %4 - <h2>Attorney Online %1</h2>Symulator dramy sądowej<p><b>Kod źródłowy:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Główny rozwój:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Rozwój Klienta:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Testowanie QA:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Szczególne podziękowania:</b><br>CrazyJC (dyrektor wydania 2.8) and MaximumVolty (promocja wydania 2.8); Remy, Hibiki, court-records.net (sprite'y); Qubrick (webAO); Rue (strona internetowa); Draxirch (design UI); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); hostom serwerów, mistrzom gier, twórcom rozpraw, twórcom kontentu, i dla całej społeczności AO2!<p>Attorney Online sieciowy projekt wizualnej powieści ma prawa autorskie (c) 2016-2020 Attorney Online developerzy. Dotyczy licencji open-source. Wszystkie inne własności należą do ich odpiowiednich właścicieli.<p>Działa na wersji QT %2 z %3 silnikiem audio.<p>Zbudowany na %4 + <h2>Attorney Online %1</h2>Symulator dramy sądowej<p><b>Kod źródłowy:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Główny rozwój:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Rozwój Klienta:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Testowanie QA:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Szczególne podziękowania:</b><br>CrazyJC (dyrektor wydania 2.8) and MaximumVolty (promocja wydania 2.8); Remy, Hibiki, court-records.net (sprite'y); Qubrick (webAO); Rue (strona internetowa); Draxirch (design UI); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); hostom serwerów, mistrzom gier, twórcom rozpraw, twórcom kontentu, i dla całej społeczności AO2!<p>Attorney Online sieciowy projekt wizualnej powieści ma prawa autorskie (c) 2016-2020 Attorney Online developerzy. Dotyczy licencji open-source. Wszystkie inne własności należą do ich odpiowiednich właścicieli.<p>Działa na wersji QT %2 z %3 silnikiem audio.<p>Zbudowany na %4 <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! <h2>Attorney Online %1</h2>Symulator dramy sądowej<p><b>Kod źródłowy:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Główny rozwój:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Główny rozwój nad wydaniem 2.8:</b><br>Crystalwarrior, Iamgoofball<p><b>Zapewnienie jakości 2.8:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Szczególne podziękowania:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, społeczności AO2, hostów serwerów, mistrzów gier, twórców rozpraw, twórców kontentu i dla graczy! - + About Opis @@ -1418,13 +1641,13 @@ Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży fo <h2>Attorney Online: %1</h2>Symulator dramy sądowej<p><b>Kod żródłowy:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Główny rozwój:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Szczególne podziękowania:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 - - + + Offline @@ -1439,25 +1662,24 @@ Czy pobrałeś wszystkie zasoby poprawnie z tiny.cc/getao, włączając duży fo NIEZNANE - has played a song: - włączył piosenkę: + włączył piosenkę: debug_functions - + Error: %1 Błąd: %1 - + Error Błąd - + Notice Ogłoszenie diff --git a/resource/translations/ao_pt.qm b/resource/translations/ao_pt.qm index 1ff0239..a02e566 100644 Binary files a/resource/translations/ao_pt.qm and b/resource/translations/ao_pt.qm differ diff --git a/resource/translations/ao_pt.ts b/resource/translations/ao_pt.ts index e867729..4c6dceb 100644 --- a/resource/translations/ao_pt.ts +++ b/resource/translations/ao_pt.ts @@ -1,27 +1,27 @@ - + AOApplication - + Disconnected from server. Desconectado do servidor. - + Error connecting to master server. Will try again in %1 seconds. Erro ao conectar ao servidor principal. Testando novamente em %1 segundos. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. Ocorreu um erro ao obter a lista de servidores. Verifique sua conexão à Internet e firewall e tente novamente. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. Versão desatualizada! Sua versão: %1 @@ -34,54 +34,51 @@ Have a nice day. Tenha um bom dia. - + Attorney Online 2 - + Loading Carregando - - + Loading chars: %1/%2 Carregando personagens: %1/%2 - Loading evidence: %1/%2 - Carregando evidências: + Carregando evidências: %1/%2 - - + Loading music: %1/%2 Carregando músicas: %1/%2 - + You have been kicked from the server. Reason: %1 Você foi expulso do servidor. Motivo: %1 - + You have been banned from the server. Reason: %1 Você foi banido do servidor. Motivo: %1 - + You are banned on this server. Reason: %1 Você foi banido neste servidor. @@ -204,43 +201,83 @@ Motivo: %1 Se marcado, o registro conterá um carimbo de tempo em UTC antes do nome. - + + Log IC actions: + + + + + If ticked, log will show IC actions such as shouting and presenting evidence. + + + + + Text Stay Time: + + + + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior. + + + + + Desynchronize IC Logs: + + + + + If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). + + + + + Instant Objection: + + + + + If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up. + + + + Default username: Nome de usuário padrão: - + Your OOC name will be automatically set to this value when you join a server. Seu nome OOC será automaticamente definido com esse valor quando você ingressar em um servidor. - + Custom shownames: Nomes personalizados: - + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. 'Custom shownames' changed to 'Shownames' because that's the actual name Fornece o valor padrão para a caixa de seleção 'Shownames' no jogo, que determina se o cliente deve exibir nomes personalizados nos personagens. - + Backup MS: MS de backup: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Se as pesquisas internas do servidor falharem, o jogo tentará o endereço fornecido aqui e o usará como um endereço de servidor principal de backup. - + Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Permite que outras pessoas no Discord vejam em que servidor você está, qual personagem está jogando e há quanto tempo está jogando. @@ -253,12 +290,12 @@ Motivo: %1 Permite agitar e piscar. Desative isso se você tiver preocupações ou problemas com fotosensibilidade e/ou convulsões. - + Language: Língua: - + Sets the language if you don't want to use your system language. Define o idioma se você não quiser usar o idioma do sistema. @@ -267,47 +304,47 @@ Motivo: %1 Habilite para adicionar uma pequena pausa nos sinais de pontuação. - + Callwords Palavras-chave - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Digite quantas palavras-chave você desejar. Estes não diferenciam maiúsculas de minúsculas. Certifique-se de deixar cada palavra chave em sua própria linha!<br>Não deixe uma linha com um espaço no final - você será alertado toda vez que alguém usar um espaço em suas mensagens.</body></html> - + Audio Áudio - + Audio device: Dispositivo de áudio: - + Sets the audio device for all sounds. Define o dispositivo de áudio para todos os sons. - + Music: Música: - + Sets the music's default volume. Define o volume padrão da música. - + SFX: SFX: - + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. Define o volume padrão do SFX. Interjeições e efeitos sonoros reais contam como 'SFX'. @@ -336,47 +373,47 @@ Motivo: %1 Define o volume padrão para sons SFX, como interjeições ou outros efeitos sonoros de personagens. - + Blips: - + Sets the volume of the blips, the talking sound effects. Define o volume dos blips, os efeitos sonoros de fala. - + Blip rate: Taxa de blip: - + Sets the delay between playing the blip sounds. Define o atraso entre a reprodução dos sons de blip. - + Blank blips: Blips em branco: - + If true, the game will play a blip sound even when a space is 'being said'. Se ativado, o jogo emitirá um sinal sonoro, mesmo quando um espaço estiver sendo "dito". - + Enable Looping SFX: Ative o SFX em loop: - + If true, the game will allow looping sound effects to play on preanimations. Se ativado, o jogo permitirá que efeitos sonoros em loop sejam reproduzidos em pré-animações. - + Kill Music On Objection: Parar a música no protesto: @@ -385,197 +422,197 @@ Motivo: %1 Se ativado, o jogo interrompe a música quando alguém protestar , como nos jogos reais. - + - Keep current setting - Mantenha as configurações atuais - + Allow Screenshake: Permitir screenshake: - + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. Permite o tremor de tela (AVISO: Pode causar convulsões devido à imagens tremidas). - + Allow Effects: Permitir efeitos: - + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. Permite efeitos de tela (AVISO: Pode causar convulsões devido à imagens tremidas).. - + Network Frame Effects: Envie efeitos para o servidor: - + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. Envie vibrações, flashes e sons na tela, conforme definido no char.ini pela rede. Funciona apenas para servidores que suportam essa funcionalidade. - + Colors in IC Log: Cores no Log IC: - + Use the markup colors in the server IC chatlog. Permitir cores no chat do IC no servidor. - + Sticky Sounds: Manter sons: - + Turn this on to prevent the sound dropdown from clearing the sound after playing it. Marque para evitar que o som do menu suspenso apague o som após a reprodução. - + Sticky Effects: Manter efeitos: - + Turn this on to prevent the effects dropdown from clearing the effect after playing it. Ative-o para impedir que o menu suspenso de efeito exclua o efeito após reproduzi-lo. - + Sticky Preanims: Manter preanims: - + Turn this on to prevent preanimation checkbox from clearing after playing the emote. Ative-o para impedir que a caixa de seleção de pré-animação seja desmarcada após a execução do emote. - + Custom Chatboxes: Caixas de bate-papo personalizadas: - + Turn this on to allow characters to define their own custom chat box designs. Ative isso para permitir que os personagens tenham as suas próprias caixas de bate-papo personalizadas. - + Play a blip sound "once per every X symbols", where X is the blip rate. Reproduz um som de blip "uma vez para cada símbolo X", em que X é a taxa de blip. - + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. Se ativado, o AO2 interromperá a música quando você ou outra pessoa fizer uma 'Protesto!'. - + Casing Caso - + This server supports case alerts. Este servidor suporta anúncios de casos. - + This server does not support case alerts. Este servidor não suporta alertas de caso. - + Pretty self-explanatory. Bastante auto-explicativo. - + Casing: Caso: - + If checked, you will get alerts about case announcements. Se marcado, você será alertado quando houverem anúncios de casos. - + Defense: Defesa: - + If checked, you will get alerts about case announcements if a defense spot is open. Se marcado, você receberá alertas sobre os anúncios de casos, se um ponto de defesa estiver aberto. - + Prosecution: Promotor: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Se marcado, você receberá alertas sobre os anúncios de casos, se uma posição de promotor estiver disponível. - + Judge: Juíz: - + If checked, you will get alerts about case announcements if the judge spot is open. Se marcado, você receberá alertas sobre os anúncios de casos, se o local do juíz: estiver aberto. - + Juror: Jurado: - + If checked, you will get alerts about case announcements if a juror spot is open. Se marcado, você receberá alertas sobre os anúncios de casos, se um local do jurado estiver aberto. - + Stenographer: Estenógrafo: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Se marcado, você receberá alertas sobre anúncios de casos, se um local de estenógrafo estiver aberto. - + CM: CM: - + If checked, you will appear amongst the potential CMs on the server. Se marcado, você aparecerá entre os CMs possíveis no servidor. - + Automatic Logging: Registro automático: - + If checked, all logs will be automatically written in the /logs folder. Se marcado, todos os registros serão automaticamente salvos na pasta logs. @@ -588,12 +625,12 @@ Motivo: %1 Se marcado, você aparecerá entre as testemunhas em potencial no servidor. - + Hosting cases: Casos: - + If you're a CM, enter what cases you are willing to host. Se você é um CM, insira os casos que deseja hospedar. @@ -625,34 +662,34 @@ Motivo: %1 Courtroom - + Password Senha - + Spectator Espectador - - + + Search Pesquisar - + Passworded A translation wouldn't fit because of the shitty theme system. - + Taken Em uso - + Generating chars: %1/%2 Gerando personagens: @@ -663,13 +700,13 @@ Motivo: %1 Não foi possível encontrar %1 - + Showname A translation wouldn't fit because of the shitty theme system. - + Message Mensagem @@ -678,37 +715,37 @@ Motivo: %1 Mensagem OOC - + Name Nome - + Pre A translation wouldn't fit because of the shitty theme system. - + Flip A translation wouldn't fit because of the shitty theme system. - - + + Casing A translation wouldn't fit because of the shitty theme system. - + Shownames A translation wouldn't fit because of the shitty theme system. - + Immediate A translation wouldn't fit because of the shitty theme system. @@ -750,74 +787,73 @@ Motivo: %1 Ciano - % offset - % deslocamento + % deslocamento - + Music - + Sfx - + Blips - - + + Server - + Change character - + Reload theme - + Call mod - + Settings - + A/M - + Preanim - + Back to Lobby A translation wouldn't fit because of the shitty theme system. Lobby - + You were granted the Disable Modcalls button. Você recebeu o botão Desativar Modcalls. - + You have been banned. Você foi banido. @@ -826,7 +862,7 @@ Motivo: %1 Isso não faz nada, mas lá vai você. - + You opened the settings menu. Você abriu o menu de configurações. @@ -839,87 +875,118 @@ Motivo: %1 se eles também escolherem seu personagem em troca. - + + + + None Nada - + Guard Guarda - + Additive Aditivo - + + % x offset + + + + + % y offset + + + + To front Para frente - + To behind Ao fundo - + Select a character you wish to pair with. Selecione um personagem com o qual deseja parear. - Change the percentage offset of your character's position from the center of the screen. - Altere o deslocamento percentual da posição do seu personagem no centro da tela. + Altere o deslocamento percentual da posição do seu personagem no centro da tela. - + Change the order of appearance for your character. Mude a ordem de aparência do seu personagem. - + Display the list of characters to pair with. Exibe a lista de caracteres para corresponder. - + Oops, you're muted! Opa, você está mudo! - + Set your character's emote to play on your next message. Defina o emote do seu personagem para usar na próxima mensagem. - + Set your character's supplementary background. Defina o plano de fundo suplementar para o seu personagem. - Set an 'iniswap', or an alternative character folder to refer to from your current character. Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - Defina um 'iniswap' ou uma pasta de caracteres alternativa para consultar seu personagem atual. + Defina um 'iniswap' ou uma pasta de caracteres alternativa para consultar seu personagem atual. Edite digitando e pressionando Enter, [X] para excluir. Isso é salvo em base/characters/<charname>/iniswaps.ini - - + + Change the horizontal percentage offset of your character's position from the center of the screen. + + + + + Change the vertical percentage offset of your character's position from the center of the screen. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/iniswaps.ini + + + + Remove the currently selected iniswap from the list and return to the original character folder. Remova o iniswap atualmente selecionado da lista e retorne à pasta de caracteres original. - + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini Configure um efeito sonoro para tocar no seu próximo 'Preanim'. Deixá-lo no padrão usará o som definido pelos emoticons (caso existam). Edite digitando e pressionando Enter, [X] para excluir. Isso é salvo em base/characters/<charname>/soundlist.ini - + + Remove the currently selected sound effect. + + + + Choose an effect to play on your next spoken message. The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. @@ -928,293 +995,360 @@ Os efeitos são definidos em theme / effects / effects.ini. Seu personagem pode categoria char.ini [Opções], effects = 'miscname', onde se refere a misc/<miscname>/effects.ini to read the effects. - + Hold It! Um momento! - - - + + + When this is turned on, your next in-character message will be a shout! Quando isso estiver ativado, sua próxima mensagem do personagem será um grito. - + Objection! Protesto! - + Take That! Tome isso! - + Toggle between server chat and global AO2 chat. Alterne entre o bate-papo do servidor e o global. - - - - + + + + This will display the animation in the viewport as soon as it is pressed. Isso exibirá a animação na janela de visualização assim que for pressionada. - + Guilty! Culpado! - + Bring up the Character Select Screen and change your character. Abra a tela de seleção de personagem e mude seu personagem. - + Refresh the theme and update all of the ui elements to match. Atualize o tema e todos os elementos da interface do usuário para corresponder. - + Request the attention of the current server's moderator. Solicite a atenção do moderador do servidor atual. - + Allows you to change various aspects of the client. Permite alterar vários aspectos do cliente. - + An interface to help you announce a case (you have to be a CM first to be able to announce cases) Uma interface para ajudá-lo a anunciar um caso (deve ser um CM para poder anunciar casos) - + Switch between Areas and Music lists Alterne entre áreas e listas de músicas - + Play a single-shot animation as defined by the emote when checked. Reproduza uma animação de tiro único, conforme definido pelo emote, quando marcada. - + If preanim is checked, display the input text immediately as the animation plays concurrently. Se pré-impressão estiver marcada, exiba o texto de entrada imediatamente enquanto a animação estiver sendo reproduzida simultaneamente. - + Mirror your character's emotes when checked. Reflita os gestos do seu personagem quando marcado. - + Add text to your last spoken message when checked. Adicione texto à sua última mensagem falada quando marcado. - + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. Você não ouve chamadas de moderação quando marcado, impedindo-os de tocar sons ou concentrando a atenção na janela. - + Lets you receive case alerts when enabled. (You can set your preferences in the Settings!) Permite que você receba alertas de caso quando ativado. (Você pode configurar suas preferências em Configurações!) - + Display customized shownames for all users when checked. Mostrar nomes personalizados para todos os usuários quando marcado. - + Custom Shout! Grito personalizado! - + This will display the custom character-defined animation in the viewport as soon as it is pressed. To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect Isso exibirá a animação de caracteres personalizados definida na viewport assim que for pressionada. Para criar uma, a pasta do seu personagem deve conter efeitos personalizados [webp/apng/gif/png]. E efeitos sonoros personalizados [wav/ogg/opus] - + Play realization sound and animation in the viewport on the next spoken message when checked. Tocar animação de som e performance na janela de desenho na seguinte mensagem falada quando marcada. - + Shake the screen on next spoken message when checked. Agite a tela na próxima mensagem falada quando marcada. - + Display the list of character folders you wish to mute. Exibe a lista de pastas de caracteres que você deseja silenciar. - - + + Increase the health bar. Aumente a barra de saúde. - - + + Decrease the health bar. Abaixe a barra de saúde. - + Change the text color of the spoken message. You can also select a part of your currently typed message and use the dropdown to change its color! Mude a cor do texto no chat IC. Você também pode selecionar uma parte da sua mensagem escrita no momento e usar o menu suspenso para alterar sua cor! - + Return back to the server list. Retorne à lista de servidores. - + Become a spectator. You won't be able to interact with the in-character screen. Torne-se um espectador. Você não será capaz de interagir como personagem. - - + + CLIENT - - + + + + HOLD IT! + + + + + + + OBJECTION! + + + + + + + TAKE THAT! + + + + + + + CUSTOM OBJECTION! + + + + + + + shouts + + + + + has presented evidence apresentou evidência - - + + + + has stopped the music + + + + + + [MISSING] %1 + + + + + has played a song tocou a música - + You will now pair up with %1 if they also choose your character in return. Agora você será emparelhado com %1 se também escolher seu personagem. - + You are no longer paired with anyone. Você não está mais fazendo par com ninguém. - + Are you sure you typed that well? The char ID could not be recognised. Você tem certeza que você escreveu isso certo? O ID do personagem não pôde ser encontrado. - - You have set your offset to - Você definiu seu deslocamento como + + You have set your offset to %1%%. + - + You have set your offset to + Você definiu seu deslocamento como + + + Your offset must be between -100% and 100%! Seu deslocamento deve estar entre -100% e 100%! - + That offset does not look like one. Esse deslocamento não se parece com um. - + + You have set your vertical offset to %1%%. + + + + + Your vertical offset must be between -100% and 100%! + + + + + That vertical offset does not look like one. + + + + You switched your music and area list. Você mudou sua lista de músicas e áreas. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Você forçou recursos que o servidor pode não suportar. Você pode não conseguir falar de IC, ou pior, por causa disso. - + Your pre-animations interrupt again. Suas pré-animações interrompem novamente. - + Your pre-animations will not interrupt text. Suas pré-animações não interromperão o texto. - + Couldn't open chatlog.txt to write into. Não foi possível abrir o chatlog.txt para gravar. - + The IC chatlog has been saved. O chat do IC foi salvo. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. Você não possui uma pasta `base/cases/`! Foi feito para você, mas, como foi feito para você, provavelmente o arquivo do caso que você está procurando não pode ser encontrado lá. - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 Você precisa fornecer um nome de arquivo para carregar (extensão não necessária)! Verifique se está na pasta `base/cases/` e se é um ini formatado corretamente. Casos que você pode carregar: %1 - + Too many arguments to load a case! You only need one filename, without extension. Muitos argumentos para carregar um caso! Você só precisa de um nome de arquivo, sem extensão. - + Case made by %1. Caso feito por %1. - + Navigate to %1 for the CM doc. Navegue para %1 para o documento do CM. - - - - + + + + UNKNOWN - + Your case "%1" was loaded! Seu caso "%1" foi carregado! - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. Você não possui uma pasta `base/cases/`! Foi feito para você, mas, como foi feito para você, é provável que você o tenha excluído. - + You need to give a filename to save (extension not needed) and the courtroom status! Você deve fornecer um nome de arquivo para salvar (sem extensão necessária) e o estado do tribunal! @@ -1223,78 +1357,83 @@ Casos que você pode carregar: %1 Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. - + Too many arguments to save a case! You only need a filename without extension and the courtroom status! Muitos argumentos para salvar um caso! Você só precisa de um nome de arquivo sem extensão e o estado do tribunal. - + Succesfully saved, edit doc and cmdoc link on the ini! Salvo com sucesso, você pode editar o documento e o link do documento no arquivo ini! - + Master - + + Stop Current Song + + + + Play Random Song Tocar música aleatória - + Expand All Categories Expandir todas as categorias - + Collapse All Categories Recolher todas as categorias - + Fade Out Previous Desvanecer Anterior - + Fade In Aparecimento gradual - + Synchronize Sincronizar - + Default Predeterminado - + Reason: Razão: - + Call Moderator Chamar um Moderador - - + + Error Erro - + You must provide a reason. Você deve fornecer um motivo. - + The message is too long. A mensagem é muito longa. @@ -1361,28 +1500,28 @@ Você será perguntado se existem alterações não salvas. - + Transfer evidence to private inventory. Transfira evidências para o inventário privado. - + Transfer evidence to global inventory. Transfira evidências para o inventário global. - + The piece of evidence you've been editing has changed. A evidência que você está editando mudou. - + Do you wish to keep your changes? Deseja manter suas alterações? - + Name: %1 Image: %2 Description: @@ -1393,131 +1532,146 @@ Descrição: %3 - + Images (*.png) Imagens (* .png) - - - + + + Double-click to edit... Clique duas vezes para editar... - + Add new evidence... Adicionar nova evidência... - + Evidence has been modified. A evidência foi modificada. - + Do you want to save your changes? Você quer salvar suas mudanças? - + Current evidence is global. Click to switch to private. A evidência atual é global. Clique para mudar para privado. - + Current evidence is private. Click to switch to global. A evidência atual é privada. Clique para mudar para global. - + "%1" has been transferred. "%1" foi transferido. - + Save Inventory Salvar inventário - - + + Ini Files (*.ini) Arquivos INI (* .ini) - + Open Inventory Abrir inventário + + DemoServer + + + + Load Demo + + + + + + Demo Files (*.demo) + + + Lobby - + Attorney Online 2 - + Search Pesquisar - + Name Nome - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? Seu cliente não parece estar configurado corretamente. Você baixou todos os recursos corretamente do tiny.cc/getao, incluindo a grande pasta 'base'? - + Version: %1 Versão: %1 - + Settings Configurações - + Allows you to change various aspects of the client. Permite alterar vários aspectos do cliente. - - + + Offline Offline - + Loading Carregando - + Cancel Cancelar - + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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 BASS audio engine.<br>APNG plugin loaded: %3<p>Built on %4 <h2>Attorney Online %1</h2>O simulador de drama jurídico<p><b>Código fonte:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desenvolvimento principal:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Desenvolvimento de cliente:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Teste de controle de qualidade:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Agradecimentos especiais:</b><br>CrazyJC y MaximumVolty (versão 2.8); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, y FanatSors (AO1); server hosts, game masters, case makers, criadores de conteúdo e toda a comunidade AO2.<p>O projeto Attorney Online possui direitos autorais (c) 2016-2020 Attorney Online developers. Aplicam-se licenças de código aberto. Todos os outros ativos são de propriedade de seus respectivos proprietários.<p>Usando a versão Qt %2 com o mecanismo de áudio BASS..<br>Plugin APNG carregado: %3<p>Compilado em %4 - + Yes Sim - + No Não @@ -1530,7 +1684,7 @@ Você baixou todos os recursos corretamente do tiny.cc/getao, incluindo a grande <h2>Attorney Online %1</h2>O simulador de drama jurídico<p><b>Código fonte:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desenvolvimento principal:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Desenvolvimento de cliente:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Teste de controle de qualidade:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Agradecimentos especiais:</b><br>CrazyJC y MaximumVolty (versão 2.8); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, y FanatSors (AO1); server hosts, game masters, case makers, criadores de conteúdo e toda a comunidade AO2.<p>O projeto Attorney Online possui direitos autorais (c) 2016-2020 Attorney Online developers. Aplicam-se licenças de código aberto. Todos os outros ativos são de propriedade de seus respectivos proprietários.<p>Usando a versão Qt %2 com o mecanismo de áudio %3.<p>Compilado em %4 - + About Sobre @@ -1543,7 +1697,7 @@ Você baixou todos os recursos corretamente do tiny.cc/getao, incluindo a grande <h2>Attorney Online %1</h2>O simulador de drama jurídico<p><b>Código fonte:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Desenvolvimento principal:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Agradecimentos especiais:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 Online: %1/%2 @@ -1565,17 +1719,17 @@ Você baixou todos os recursos corretamente do tiny.cc/getao, incluindo a grande debug_functions - + Error: %1 - + Error - + Notice diff --git a/resource/translations/ao_ru.qm b/resource/translations/ao_ru.qm index 19bf0a9..6847fc9 100644 Binary files a/resource/translations/ao_ru.qm and b/resource/translations/ao_ru.qm differ diff --git a/resource/translations/ao_ru.ts b/resource/translations/ao_ru.ts index e2e04b9..eedbb17 100644 --- a/resource/translations/ao_ru.ts +++ b/resource/translations/ao_ru.ts @@ -4,17 +4,17 @@ AOApplication - + Disconnected from server. Соединение с сервером разорвано. - + Error connecting to master server. Will try again in %1 seconds. Ошибка соединения с главным сервером. Повторная попытка соединения через %1 с. - + There was an error connecting to the master server. We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. Please check your Internet connection and firewall, and please try again. @@ -23,7 +23,7 @@ Please check your Internet connection and firewall, and please try again. - + Outdated version! Your version: %1 Please go to aceattorneyonline.com to update. Устаревшая версия! У вас установлена версия %1 @@ -36,54 +36,51 @@ Have a nice day. Всего хорошего. - + Attorney Online 2 Attorney Online 2 - + Loading Загрузка - Loading evidence: %1/%2 - Загрузка улик: + Загрузка улик: %1/%2 - - + Loading music: %1/%2 Загрузка музыки: %1/%2 - - + Loading chars: %1/%2 Загрузка персонажей: %1/%2 - + You have been kicked from the server. Reason: %1 Вас выпнули с сервера. Причина: %1 - + You have been banned from the server. Reason: %1 Вы были забанены на сервере. Причина: %1 - + You are banned on this server. Reason: %1 Вы забанены на этом сервере. @@ -185,349 +182,419 @@ Reason: Поставьте 0 или отрицательное значение, чтобы снять ограничение. - + + Log newline: + + + + + 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'. + + + + + Log margin: + + + + + The distance in pixels between each entry in the IC log. Default: 0. + + + + + Log timestamp: + + + + + If ticked, log will contain a timestamp in UTC before the name. + + + + + Log IC actions: + + + + + If ticked, log will show IC actions such as shouting and presenting evidence. + + + + + Text Stay Time: + + + + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior. + + + + + Desynchronize IC Logs: + + + + + If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). + + + + + Instant Objection: + + + + + If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up. + + + + Default username: Никнейм по умолчанию: - + Your OOC name will be automatically set to this value when you join a server. Псевдоним по умолчанию для ООС-чата. - + Custom shownames: Пользовательские имена: - + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. Задать значение по умолчанию для настройки отображения пользовательских имён, которая определяет возможность показа в игровом чате имён персонажей, установленных самими игроками. - + Backup MS: Запасной ГС: - + If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. Если клиент не сможет соединиться с встроенным главным сервером (ГС), он проверит адреса из этого списка. - + Discord: Discord: - + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. Показывать в Discord сервер, на котором вы играете, вашего персонажа и продолжительность игры. - + Language: Язык: - + Sets the language if you don't want to use your system language. Изменяет язык интерфейса программы, если вы не хотите использовать язык системы. - + - Keep current setting - сохранить текущие настройки - + Allow Screenshake: Встряска экрана: - + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. Разрешить показ встрясок экрана. Отключите, если вы страдаете от светочувствительности и/или припадков. - + Allow Effects: Визуальные эффекты: - + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. Разрешить показ визуальных эффектов. Отключите, если вы страдаете от светочувствительности и/или припадков. - + Network Frame Effects: Эффекты по сети: - + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. Разрешить отправку звуков, эффектов вспышек и встряски экрана по сети в соответствии с char.ini. Работает только на серверах, поддерживающих данную функцию. - + Colors in IC Log: Цвета в истории чата: - + Use the markup colors in the server IC chatlog. Отображать цвета в истории игрового чата. - + Sticky Sounds: Закрепить звуки: - + Turn this on to prevent the sound dropdown from clearing the sound after playing it. Не сбрасывать выбранные настройки звука после его воспроизведения. - + Sticky Effects: Закрепить эффекты: - + Turn this on to prevent the effects dropdown from clearing the effect after playing it. Не сбрасывать выбранные настройки эффекта после его воспроизведения. - + Sticky Preanims: Закрепить пред. анимации: - + Turn this on to prevent preanimation checkbox from clearing after playing the emote. Не сбрасывать настройки пред. анимации после её воспроизведения. - + Custom Chatboxes: Пользовательские подложки: - + Turn this on to allow characters to define their own custom chat box designs. Отображать дизайны подложек, заданные персонажами. - + Callwords Позывные - + <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> <html><head/><body>Введите на отдельных строках свои позывные. Если кто-то в чате напишет их, вы услышите звуковой сигнал. Регистр символов не учитывается.<br>Не оставляйте в конце строк пробелы, иначе вы будете получать оповещения о каждом пробеле в чате.</body></html> - + Audio Аудио - + Audio device: Устройство воспроизведения: - + Sets the audio device for all sounds. Укажите устройство вывода всего аудио игры. - + Music: Музыка: - + Sets the music's default volume. Громкость музыки по умолчанию. - + SFX: Звук. эффекты: - + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. Громкость звуковых эффектов по умолчанию. В категорию эффектов также входят возгласы. - + Blips: Сигналы: - + Sets the volume of the blips, the talking sound effects. Громкость сигналов, заменяющих голос, по умолчанию. - + Blip rate: Частота сигналов: - + Sets the delay between playing the blip sounds. Задержка по умолчанию между сигналами, заменяющими голос. - + Play a blip sound "once per every X symbols", where X is the blip rate. Проигрывать сигнал "каждые Х символов", где Х - частота. - + Blank blips: Пустые сигналы: - + If true, the game will play a blip sound even when a space is 'being said'. Проигрывать сигналы даже для пробелов. - + Enable Looping SFX: Повтор звук. эффектов: - + If true, the game will allow looping sound effects to play on preanimations. Разрешить воспроизведение зацикленных звуковых эффектов во время предварительной анимации. - + Kill Music On Objection: Тишина при протесте: - + If true, AO2 will stop the music for you when you or someone else does 'Objection!'. Останавливать музыку, когда кто-нибудь кричит "Objection!". - + Casing Заседания - + This server supports case alerts. Этот сервер поддерживает объявления заседаний. - + This server does not support case alerts. Этот сервер не поддерживает объявления заседаний. - + Pretty self-explanatory. Дополнительные пояснения не требуются. - + Casing: Заседания: - + If checked, you will get alerts about case announcements. Вы получите уведомление, когда будет объявлено заседание. - + Defense: Защита: - + If checked, you will get alerts about case announcements if a defense spot is open. Вы получите уведомление при объявлении дела, в котором нужна сторона защиты. - + Prosecution: Обвинение: - + If checked, you will get alerts about case announcements if a prosecutor spot is open. Вы получите уведомление при объявлении дела, в котором нужна сторона обвинения. - + Judge: Судья: - + If checked, you will get alerts about case announcements if the judge spot is open. Вы получите уведомление при объявлении дела, в котором нужен судья. - + Juror: Присяжные: - + If checked, you will get alerts about case announcements if a juror spot is open. Вы получите уведомление при объявлении дела, в котором нужны присяжные заседатели. - + Stenographer: Стенографист: - + If checked, you will get alerts about case announcements if a stenographer spot is open. Вы получите уведомление при объявлении дела, в котором нужна стенография. - + CM: ПД: - + If checked, you will appear amongst the potential CMs on the server. Отметьте, если хотите состоять в числе возможных производителей дел (ПД). - + Hosting cases: Проведение дел: - + If you're a CM, enter what cases you are willing to host. Если вы производитель дел (ПД), укажите, какими делами вы хотите заниматься. - + Automatic Logging: Авт. сохранение истории: - + If checked, all logs will be automatically written in the /logs folder. Автоматически сохранять всю историю чатов в папке /logs. @@ -535,33 +602,33 @@ Reason: Courtroom - + Password Пароль - + Spectator Зритель - - + + Search Поиск - + Passworded Защищён паролем - + Taken Занят - + Generating chars: %1/%2 Генерация персонажей: @@ -574,53 +641,53 @@ Reason: - + Showname Имя - + Message Сообщение - + Name Никнейм - + Pre - + Flip - + Guard - + Additive - - + + Casing - + Заседания - + Shownames - + Immediate @@ -653,153 +720,187 @@ Reason: В общем-то, это ни на что не влияет... - + You need to give a filename to load (extension not needed)! Make sure that it is in the `base/cases/` folder, and that it is a correctly formatted ini. Cases you can load: %1 Укажите имя файла с делом (без расширения) для загрузки. Убедитесь, что он расположен в папке `base/cases`, и что это правильно отформатированный файл .ini. Вы можете загрузить следующие дела: %1 - + Case made by %1. Автор дела: %1. - + Navigate to %1 for the CM doc. Откройте %1 для получения материалов дела. - + Your case "%1" was loaded! Ваше дело "%1" было загружено! - - + + Server Сервер - + + + + None - + + % x offset + + + + + % y offset + + + + + Change the horizontal percentage offset of your character's position from the center of the screen. + + + + + Change the vertical percentage offset of your character's position from the center of the screen. + + + + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/iniswaps.ini + + + + + Remove the currently selected sound effect. + + + + Hold It! - - - + + + When this is turned on, your next in-character message will be a shout! Когда эта опция включена, ваше следующее сообщение в игровом чате будет с возгласом! - + Objection! - + Take That! - + Toggle between server chat and global AO2 chat. Переключатель между чатом сервера и общим чатом AO2. - - - - + + + + This will display the animation in the viewport as soon as it is pressed. Показать анимацию в игровом чате сразу после нажатия. - + Guilty! Виновен! - + Bring up the Character Select Screen and change your character. Перейти на экран выбора и сменить персонажа. - + Refresh the theme and update all of the ui elements to match. Перезагрузить тему и обновить все элементы интерфейса. - + Request the attention of the current server's moderator. Привлечь внимание модератора сервера. - + Allows you to change various aspects of the client. Изменить параметры работы программы. - + An interface to help you announce a case (you have to be a CM first to be able to announce cases) Открыть окно, которое позволит вам объявить о деле (для этого нужно быть производителем дел (ПД)) - + Switch between Areas and Music lists Переключатель между списками музыки и локаций - + Play a single-shot animation as defined by the emote when checked. Показать разовую анимацию, соответствующую выбранной эмоции. - + If preanim is checked, display the input text immediately as the animation plays concurrently. Если включена предварительная анимация: вывести текст, не дожидаясь окончания предварительной анимации. - + Mirror your character's emotes when checked. Отразить анимации персонажа по горизонтали. - + Add text to your last spoken message when checked. Добавлять текст к своему последнему сообщению. - + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. Заглушить вызовы модератора: вы не будете получать звуковые оповещения, а игра не будет привлекать к себе внимание. - + Lets you receive case alerts when enabled. (You can set your preferences in the Settings!) Получать уведомления о заседаниях. (См. подробнее в меню опций) - + Display customized shownames for all users when checked. Показывать пользовательские имена для всех. - + Custom Shout! Пользовательский возглас! - + This will display the custom character-defined animation in the viewport as soon as it is pressed. To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect Показать в игровом чате анимацию, уникальную для персонажа, сразу после нажатия. @@ -807,56 +908,114 @@ To make one, your character's folder must contain custom.[webp/apng/gif/png в формате webp/apng/gif/png и звук в формате wav/ogg/opus - + Play realization sound and animation in the viewport on the next spoken message when checked. Показать вспышку и воспроизвести звук озарения во время вывода следующей реплики. - + Shake the screen on next spoken message when checked. Потрясти экран во время вывода следующей реплики. - + Display the list of character folders you wish to mute. Выбрать персонажей, которых нужно игнорировать. - - + + Increase the health bar. Поощрить. - - + + Decrease the health bar. Оштрафовать. - + Change the text color of the spoken message. You can also select a part of your currently typed message and use the dropdown to change its color! Изменить цвет текста сообщения. Вы также можете выделить часть текста и изменить только её цвет в выпадающем меню. - + Back to Lobby Назад в лобби - - - + + + + HOLD IT! + + + + + + + OBJECTION! + + + + + + + TAKE THAT! + + + + + + + CUSTOM OBJECTION! + + + + + + + shouts + + + + + + has presented evidence + + + + + + + has stopped the music + + + + + + [MISSING] %1 + + + + + has played a song включил(а) композицию - + You will now pair up with %1 if they also choose your character in return. Вы встанете рядом с %1, если он(а) выберет вашего персонажа. + + + You have set your offset to %1%%. + + Rainbow Радужный @@ -870,71 +1029,67 @@ You can also select a part of your currently typed message and use the dropdown Голубой - % offset - % сдвига + % сдвига - + To front Вперёд - + To behind Назад - + Select a character you wish to pair with. Выберите персонажа, с которым хотите встать рядом. - Change the percentage offset of your character's position from the center of the screen. - Изменить процент сдвига вашего персонажа относительно центра экрана. + Изменить процент сдвига вашего персонажа относительно центра экрана. - + Change the order of appearance for your character. Переместить вашего персонажа вперёд или назад относительно партнёра. - + Display the list of characters to pair with. Показать список персонажей, с которыми можно встать рядом. - + Oops, you're muted! О нет, вас заглушили! - + Set your character's emote to play on your next message. Выберите эмоцию для отображения при выводе вашего следующего сообщения. - + Set your character's supplementary background. Установить фон для вашего персонажа. - Set an 'iniswap', or an alternative character folder to refer to from your current character. Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - Включить т.н. подмену ini – альтернативную папку персонажа, к которой будет обращаться текущий персонаж. + Включить т.н. подмену ini – альтернативную папку персонажа, к которой будет обращаться текущий персонаж. Введите имя персонажа и нажмите Enter; нажмите [X], чтобы удалить. Изменения сохраняются по следующему пути: base/characters/<имя_персонажа>/iniswaps.ini - - + Remove the currently selected iniswap from the list and return to the original character folder. Удалить выбранного для подмены ini персонажа и вернуться к папке изначально выбранного персонажа. - + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini Выберите звук, который нужно воспроизвести со следующей пред. анимацией. @@ -943,7 +1098,7 @@ Edit by typing and pressing Enter, [X] to remove. This saves to your base/charac Изменения сохраняются по следующему пути: base/characters/<имя_персонажа>/soundlist.ini - + Choose an effect to play on your next spoken message. The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. @@ -952,73 +1107,73 @@ char.ini [Options] category, effects = 'miscname' where it referes to в категории [Options] файла char.ini, effects = 'название', что отсылает к файлу misc/<название>/effects.ini. - + Music - + Sfx - + Blips - + Change character - + Reload theme - + Call mod - + Settings - + A/M Л/М - + Preanim - + Return back to the server list. Вернуться к списку серверов. - + Become a spectator. You won't be able to interact with the in-character screen. Зайти в качестве зрителя. Вы не сможете взаимодействовать с игровым чатом. - + You were granted the Disable Modcalls button. Вам дали кнопку выключения вызова модератора. - - + + CLIENT КЛИЕНТ - + You have been banned. Вас забанили. @@ -1027,7 +1182,7 @@ char.ini [Options] category, effects = 'miscname' where it referes to Теперь у вас есть кнопка "Охрана". - + You opened the settings menu. Вы открыли меню опций. @@ -1040,161 +1195,180 @@ char.ini [Options] category, effects = 'miscname' where it referes to (если он выберет вас в ответ). - + You are no longer paired with anyone. Вы больше не стоите рядом ни с кем. - + Are you sure you typed that well? The char ID could not be recognised. Убедитесь в правильности введённой информации: персонаж с таким ID не найден. - You have set your offset to - Вы установили сдвиг персонажа на + Вы установили сдвиг персонажа на - + Your offset must be between -100% and 100%! Сдвиг персонажа должен быть между -100% и 100%! - + That offset does not look like one. Неверный сдвиг персонажа. - + + You have set your vertical offset to %1%%. + + + + + Your vertical offset must be between -100% and 100%! + + + + + That vertical offset does not look like one. + + + + You switched your music and area list. Вы переключили списки локаций и музыки. - + You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. Из-за того, что вы включили не поддерживаемые сервером возможности, он может не принять ваши сообщения. - + Your pre-animations interrupt again. Персонаж будет говорить только после предварительной анимации. - + Your pre-animations will not interrupt text. Предварительные анимации не будут прерывать вывод текста. - + Couldn't open chatlog.txt to write into. Невозможно открыть `chatlog.txt` для записи. - + The IC chatlog has been saved. История игрового чата сохранена. - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely the case file you're looking for can't be found in there. Файл с делом не найден. Если найдёте, положите его в папку `base/cases/`, которую мы для вас создали. - + Too many arguments to load a case! You only need one filename, without extension. Введите имя файла без расширения. - - - - + + + + UNKNOWN н/д - + You don't have a `base/cases/` folder! It was just made for you, but seeing as it WAS just made for you, it's likely that you somehow deleted it. Папка `base/cases/` отсутствует. - + You need to give a filename to save (extension not needed) and the courtroom status! Введите имя файла (без расширения) и укажите статус зала суда. - + Too many arguments to save a case! You only need a filename without extension and the courtroom status! Убедитесь, что имя файла указано без расширения. - + Succesfully saved, edit doc and cmdoc link on the ini! Сохранение прошло успешно. Ссылки на документы можно редактировать в ini. - + Master Мастер - + + Stop Current Song + + + + Play Random Song Включить случайную композицию - + Expand All Categories Развернуть все категории - + Collapse All Categories Свернуть все категории - + Fade Out Previous Постепенное затухание предыдущей композиции - + Fade In Постепенное нарастание - + Synchronize Синхронизировать - + Default по умолчанию - + Reason: Причина: - + Call Moderator Вызов модератора - - + + Error Ошибка - + You must provide a reason. Укажите причину. - + The message is too long. Слишком длинное сообщение. @@ -1261,28 +1435,28 @@ You will be prompted if there's any unsaved changes. - + Transfer evidence to private inventory. Перенести улику в свой список. - + Transfer evidence to global inventory. Перенести улику в общий список. - + The piece of evidence you've been editing has changed. В улику, которую вы редактировали, были внесены изменения. - + Do you wish to keep your changes? Хотите сохранить внесённые изменения? - + Name: %1 Image: %2 Description: @@ -1293,120 +1467,149 @@ Description: %3 - + Images (*.png) Изображения (*.png) - - - + + + Double-click to edit... Редактирование по двойному клику... - + Add new evidence... Добавить новую улику... - + Evidence has been modified. Улика была изменена. - + Do you want to save your changes? Хотите сохранить внесённые изменения? - + Current evidence is global. Click to switch to private. Вы видите общий список улик. Нажмите здесь для просмотра своих улик. - + Current evidence is private. Click to switch to global. Вы видите свой список улик. Нажмите здесь для просмотра общих улик. - + "%1" has been transferred. Улика "%1" была перенесена. - + Save Inventory Сохранить список улик - - + + Ini Files (*.ini) Файлы ini (*.ini) - + Open Inventory Загрузить список улик + + DemoServer + + + + Load Demo + + + + + + Demo Files (*.demo) + + + Lobby - + Attorney Online 2 Attorney Online 2 - + Search Поиск - + Name Никнейм - + It doesn't look like your client is set up correctly. Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? Кажется, ваш клиент неправильно настроен. Вы точно скачали все ресурсы отсюда tiny.cc/getao, включая огромную папку `base`? - + Version: %1 Версия: %1 - + Settings Опции - + Allows you to change various aspects of the client. Изменить параметры работы программы. - + Loading Загрузка - + Cancel Отмена - - <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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>Built on %4 - <h2>Attorney Online %1</h2>Симулятор драмы в зале суда<p><b>Исходный код:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Основная разработка:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Разработка клиента:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Тестирование:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Благодарности:</b><br>CrazyJC (директор по выпуску версии 2.8) и MaximumVolty (продвижение версии 2.8); Remy, Hibiki, court-records.net (спрайты); Qubrick (webAO); Rue (вебсайт); Draxirch (дизайн интерфейса); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, и FanatSors (AO1); держатели серверов, ГМ, ПД, создатели контента, и всё сообщество AO2!<p>Проект сетевой визуальной новеллы Attorney Online (c) 2016-2020 разработчики Attorney Online. Применяется лицензия на открытое ПО. Все прочие файлы являются собственностью их владельцев.<p>Работает на Qt версии %2 с аудио-движком %3.<p>Сборка от %4 + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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 BASS audio engine.<br>APNG plugin loaded: %3<p>Built on %4 + + Yes + + + + + No + + + + <h2>Attorney Online %1</h2>The courtroom drama simulator<p><b>Source code:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Major development:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>QA testing:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Special thanks:</b><br>CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); Rue (website); Draxirch (UI design); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); server hosts, game masters, case makers, content creators, and the whole AO2 community!<p>The Attorney Online networked visual novel project 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>Built on %4 + <h2>Attorney Online %1</h2>Симулятор драмы в зале суда<p><b>Исходный код:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Основная разработка:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Разработка клиента:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Тестирование:</b><br>CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, Veritas, Wiso<p><b>Благодарности:</b><br>CrazyJC (директор по выпуску версии 2.8) и MaximumVolty (продвижение версии 2.8); Remy, Hibiki, court-records.net (спрайты); Qubrick (webAO); Rue (вебсайт); Draxirch (дизайн интерфейса); Lewdton and Argoneus (tsuserver); Fiercy, Noevain, Cronnicossy, и FanatSors (AO1); держатели серверов, ГМ, ПД, создатели контента, и всё сообщество AO2!<p>Проект сетевой визуальной новеллы Attorney Online (c) 2016-2020 разработчики Attorney Online. Применяется лицензия на открытое ПО. Все прочие файлы являются собственностью их владельцев.<p>Работает на Qt версии %2 с аудио-движком %3.<p>Сборка от %4 + + + About О программе @@ -1415,13 +1618,13 @@ Did you download all resources correctly from tiny.cc/getao, including the large <h2>Attorney Online %1</h2>Симулятор судебной драмы<p><b>Исходный код:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Основной разработкой занимались:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Особенная благодарность:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (дизайн интерфейса), Draxirch (дизайн интерфейса), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - + Online: %1/%2 Онлайн: %1/%2 - - + + Offline Не в сети @@ -1436,25 +1639,24 @@ Did you download all resources correctly from tiny.cc/getao, including the large н/д - has played a song: - включил(а) композицию: + включил(а) композицию: debug_functions - + Error: %1 Ошибка: %1 - + Error Ошибка - + Notice Уведомление diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index fa58ab8..34afb28 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -45,6 +45,10 @@ void AOApplication::construct_lobby() if (is_discord_enabled()) discord->state_lobby(); + if (demo_server) + demo_server->deleteLater(); + demo_server = new DemoServer(); + w_lobby->show(); } @@ -182,6 +186,10 @@ void AOApplication::call_announce_menu(Courtroom *court) void CALLBACK AOApplication::BASSreset(HSTREAM handle, DWORD channel, DWORD data, void *user) { + UNUSED(handle); + UNUSED(channel); + UNUSED(data); + UNUSED(user); doBASSreset(); } diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp deleted file mode 100644 index 09a4b88..0000000 --- a/src/aocharmovie.cpp +++ /dev/null @@ -1,332 +0,0 @@ -#include "aocharmovie.h" - -#include "aoapplication.h" -#include "file_functions.h" -#include "misc_functions.h" - -AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) - : QLabel(p_parent) -{ - ao_app = p_ao_app; - preanim_timer = new QTimer(this); - preanim_timer->setSingleShot(true); - - ticker = new QTimer(this); - ticker->setTimerType(Qt::PreciseTimer); - ticker->setSingleShot(false); - connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); - - // connect(m_movie, SIGNAL(frameChanged(int)), this, - // SLOT(frame_change(int))); - connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); -} - -void AOCharMovie::load_image(QString p_char, QString p_emote, - QString emote_prefix) -{ -#ifdef DEBUG_CHARMOVIE - actual_time.restart(); -#endif - QString emote_path; - QList pathlist; - pathlist = { - ao_app->get_image_suffix(ao_app->get_character_path( - p_char, emote_prefix + p_emote)), // Default path - ao_app->get_image_suffix(ao_app->get_character_path( - p_char, emote_prefix + "/" + - p_emote)), // Path check if it's categorized into a folder - ao_app->get_image_suffix(ao_app->get_character_path( - p_char, p_emote)), // Just use the non-prefixed image, animated or not - ao_app->get_image_suffix( - ao_app->get_theme_path("placeholder")), // Theme placeholder path - ao_app->get_image_suffix(ao_app->get_default_theme_path( - "placeholder")), // Default theme placeholder path - }; - - for (QString path : pathlist) { - if (file_exists(path)) { - emote_path = path; - break; - } - } - - this->clear(); - ticker->stop(); - preanim_timer->stop(); - movie_frames.clear(); - movie_delays.clear(); - movie_effects.clear(); - - if (!file_exists(emote_path)) - return; - - m_reader->setFileName(emote_path); - - // set format to apng if png supports animation - if (emote_path.endsWith("png")) { - m_reader->setFormat("apng"); - if (!m_reader->supportsAnimation()) { - m_reader->setFormat("png"); - } - } - - QPixmap f_pixmap = this->get_pixmap(m_reader->read()); - int f_delay = m_reader->nextImageDelay(); - - frame = 0; - max_frames = m_reader->imageCount(); - - this->set_frame(f_pixmap); - this->show(); - if (max_frames > 1) { - movie_frames.append(f_pixmap); - movie_delays.append(f_delay); - } - - m_char = p_char; - m_emote = emote_prefix + p_emote; - - if (network_strings.size() > 0) // our FX overwritten by networked ones - this->load_network_effects(); - else // Use default ini FX - this->load_effects(); -#ifdef DEBUG_CHARMOVIE - qDebug() << max_frames << "Setting image to " << emote_path - << "Time taken to process image:" << actual_time.elapsed(); - - actual_time.restart(); -#endif -} - -void AOCharMovie::load_effects() -{ - movie_effects.clear(); - movie_effects.resize(max_frames); - for (int e_frame = 0; e_frame < max_frames; ++e_frame) { - QString effect = ao_app->get_screenshake_frame(m_char, m_emote, e_frame); - if (effect != "") { - movie_effects[e_frame].append("shake"); - } - - effect = ao_app->get_flash_frame(m_char, m_emote, e_frame); - if (effect != "") { - movie_effects[e_frame].append("flash"); - } - - effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame); - if (effect != "") { - movie_effects[e_frame].append("sfx^" + effect); - } - } -} - -void AOCharMovie::load_network_effects() -{ - movie_effects.clear(); - movie_effects.resize(max_frames); - // Order is important!!! - QStringList effects_list = {"shake", "flash", "sfx^"}; - - // Determines which list is smaller - effects_list or network_strings - and - // uses it as basis for the loop. This way, incomplete network_strings would - // still be parsed, and excess/unaccounted for networked information is - // omitted. - int effects_size = qMin(effects_list.size(), network_strings.size()); - - for (int i = 0; i < effects_size; ++i) { - QString netstring = network_strings.at(i); - QStringList emote_splits = netstring.split("^"); - foreach (QString emote, emote_splits) { - QStringList parsed = emote.split("|"); - if (parsed.size() <= 0 || parsed.at(0) != m_emote) - continue; - foreach (QString frame_data, parsed) { - QStringList frame_split = frame_data.split("="); - if (frame_split.size() <= - 1) // We might still be hanging at the emote itself (entry 0). - continue; - int f_frame = frame_split.at(0).toInt(); - if (f_frame >= max_frames) { - qDebug() << "Warning: out of bounds" << effects_list[i] << "frame" - << f_frame << "out of" << max_frames << "for" << m_char - << m_emote; - continue; - } - QString f_data = frame_split.at(1); - if (f_data != "") { - QString effect = effects_list[i]; - if (effect == "sfx^") // Currently the only frame result that feeds us - // data, let's yank it in. - effect += f_data; - qDebug() << effect << f_data << "frame" << f_frame << "for" << m_char - << m_emote; - movie_effects[f_frame].append(effect); - } - } - } - } -} - -void AOCharMovie::play() -{ - play_frame_effect(frame); - if (max_frames <= 1) { - if (play_once) - ticker->start(60); - } - else - ticker->start(this->get_frame_delay(movie_delays[frame])); -} - -void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) -{ - load_image(p_char, p_emote, ""); - // As much as I'd like to screw around with [Time] durations modifying the - // animation speed, I don't think I can reliably do that, not without looping - // through all frames in the image at least - which causes lag. So for now it - // simply ends the preanimation early instead. - play_once = true; - if (duration > - 0) // It's -1 if there's no definition in [Time] for it. In which case, it - // will let the animation run out in full. Duration 0 does the same. - preanim_timer->start(duration * - time_mod); // This timer will not fire if the animation - // finishes earlier than that - play(); -} - -void AOCharMovie::play_talking(QString p_char, QString p_emote) -{ - play_once = false; - load_image(p_char, p_emote, "(b)"); - play(); -} - -void AOCharMovie::play_idle(QString p_char, QString p_emote) -{ - play_once = false; - load_image(p_char, p_emote, "(a)"); - play(); -} - -void AOCharMovie::play_frame_effect(int frame) -{ - if (frame < max_frames) { - foreach (QString effect, movie_effects[frame]) { - if (effect == "shake") { - shake(); -#ifdef DEBUG_CHARMOVIE - qDebug() << "Attempting to play shake on frame" << frame; -#endif - } - - if (effect == "flash") { - flash(); -#ifdef DEBUG_CHARMOVIE - qDebug() << "Attempting to play flash on frame" << frame; -#endif - } - - if (effect.startsWith("sfx^")) { - QString sfx = effect.section("^", 1); - play_sfx(sfx); -#ifdef DEBUG_CHARMOVIE - qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame; -#endif - } - } - } -} - -void AOCharMovie::stop() -{ - // for all intents and purposes, stopping is the same as hiding. at no point - // do we want a frozen gif to display - ticker->stop(); - preanim_timer->stop(); - this->hide(); -} - -QPixmap AOCharMovie::get_pixmap(QImage image) -{ - QPixmap f_pixmap; - if (m_flipped) - f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); - else - f_pixmap = QPixmap::fromImage(image); - // auto aspect_ratio = Qt::KeepAspectRatio; - auto transform_mode = Qt::FastTransformation; - if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing. - transform_mode = Qt::SmoothTransformation; - - f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); - this->resize(f_pixmap.size()); - - return f_pixmap; -} - -void AOCharMovie::set_frame(QPixmap f_pixmap) -{ - this->setPixmap(f_pixmap); - QLabel::move( - x + (f_w - f_pixmap.width()) / 2, - y + (f_h - f_pixmap.height())); // Always center horizontally, always put - // at the bottom vertically -} - -void AOCharMovie::combo_resize(int w, int h) -{ - QSize f_size(w, h); - f_w = w; - f_h = h; - this->resize(f_size); -} - -int AOCharMovie::get_frame_delay(int delay) -{ - return static_cast(double(delay) * double(speed / 100)); -} - -void AOCharMovie::move(int ax, int ay) -{ - x = ax; - y = ay; - QLabel::move(x, y); -} - -void AOCharMovie::movie_ticker() -{ - ++frame; - if (frame >= max_frames) { - if (play_once) { - preanim_done(); - return; - } - else - frame = 0; - } - // qint64 difference = elapsed - movie_delays[frame]; - if (frame >= movie_frames.size()) { - m_reader->jumpToImage(frame); - movie_frames.resize(frame + 1); - movie_frames[frame] = this->get_pixmap(m_reader->read()); - movie_delays.resize(frame + 1); - movie_delays[frame] = m_reader->nextImageDelay(); - } - -#ifdef DEBUG_CHARMOVIE - qDebug() << frame << movie_delays[frame] - << "actual time taken from last frame:" << actual_time.restart(); -#endif - - this->set_frame(movie_frames[frame]); - play_frame_effect(frame); - ticker->setInterval(this->get_frame_delay(movie_delays[frame])); -} - -void AOCharMovie::preanim_done() -{ - ticker->stop(); - preanim_timer->stop(); - done(); -} diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index 2ffea2c..f6dffd8 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -11,7 +11,7 @@ AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) evidence_icon = new QLabel(this); sfx_player = new AOSfxPlayer(this, ao_app); - evidence_movie = new AOMovie(this, ao_app); + evidence_movie = new InterfaceLayer(this, ao_app); connect(evidence_movie, SIGNAL(done()), this, SLOT(show_done())); } @@ -46,9 +46,11 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, evidence_icon->setPixmap(f_pixmap); evidence_icon->resize(f_pixmap.size()); evidence_icon->move(icon_dimensions.x, icon_dimensions.y); - - evidence_movie->play(gif_name); - sfx_player->play(ao_app->get_sfx("evidence_present")); + evidence_movie->static_duration = 320; + evidence_movie->max_duration = 1000; + evidence_movie->set_play_once(true); + evidence_movie->load_image(gif_name, ""); + sfx_player->play(ao_app->get_sfx("evidence_present", "default")); } void AOEvidenceDisplay::reset() diff --git a/src/aolayer.cpp b/src/aolayer.cpp new file mode 100644 index 0000000..f95773b --- /dev/null +++ b/src/aolayer.cpp @@ -0,0 +1,601 @@ +#include "aolayer.h" + +#include "aoapplication.h" +#include "file_functions.h" +#include "misc_functions.h" + +AOLayer::AOLayer(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) +{ + ao_app = p_ao_app; + + // used for culling images when their max_duration is exceeded + shfx_timer = new QTimer(this); + shfx_timer->setTimerType(Qt::PreciseTimer); + shfx_timer->setSingleShot(true); + connect(shfx_timer, SIGNAL(timeout()), this, SLOT(shfx_timer_done())); + + ticker = new QTimer(this); + ticker->setTimerType(Qt::PreciseTimer); + ticker->setSingleShot(false); + connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); + + preanim_timer = new QTimer(this); + preanim_timer->setSingleShot(true); + connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); +} + +BackgroundLayer::BackgroundLayer(QWidget *p_parent, AOApplication *p_ao_app) + : AOLayer(p_parent, p_ao_app) +{ +} +ForegroundLayer::ForegroundLayer(QWidget *p_parent, AOApplication *p_ao_app) + : AOLayer(p_parent, p_ao_app) +{ +} +CharLayer::CharLayer(QWidget *p_parent, AOApplication *p_ao_app) + : AOLayer(p_parent, p_ao_app) +{ +} +EffectLayer::EffectLayer(QWidget *p_parent, AOApplication *p_ao_app) + : AOLayer(p_parent, p_ao_app) +{ +} +InterjectionLayer::InterjectionLayer(QWidget *p_parent, AOApplication *p_ao_app) + : AOLayer(p_parent, p_ao_app) +{ +} +InterfaceLayer::InterfaceLayer(QWidget *p_parent, AOApplication *p_ao_app) + : AOLayer(p_parent, p_ao_app) +{ +} + +StickerLayer::StickerLayer(QWidget *p_parent, AOApplication *p_ao_app) + : AOLayer(p_parent, p_ao_app) +{ +} + +QString AOLayer::find_image(QList p_list) +{ + QString image_path; + for (QString path : p_list) { +#ifdef DEBUG_MOVIE + qDebug() << "checking path " << path; +#endif + if (file_exists(path)) { + image_path = path; +#ifdef DEBUG_MOVIE + qDebug() << "found path " << path; +#endif + break; + } + } + return image_path; +} + +QPixmap AOLayer::get_pixmap(QImage image) +{ + QPixmap f_pixmap; + if (m_flipped) + f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); + else + f_pixmap = QPixmap::fromImage(image); + // auto aspect_ratio = Qt::KeepAspectRatio; + if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing. + transform_mode = Qt::SmoothTransformation; + if (stretch) + f_pixmap = f_pixmap.scaled(f_w, f_h); + else + f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); + this->resize(f_pixmap.size()); + + return f_pixmap; +} + +void AOLayer::set_frame(QPixmap f_pixmap) +{ + this->setPixmap(f_pixmap); + QLabel::move( + x + (f_w - f_pixmap.width()) / 2, + y + (f_h - f_pixmap.height())); // Always center horizontally, always put + // at the bottom vertically + this->setMask( + QRegion((f_pixmap.width() - f_w) / 2, (f_pixmap.height() - f_h) / 2, f_w, + f_h)); // make sure we don't escape the area we've been given +} + +void AOLayer::combo_resize(int w, int h) +{ + QSize f_size(w, h); + f_w = w; + f_h = h; + this->resize(f_size); +} + +int AOLayer::get_frame_delay(int delay) +{ + return static_cast(double(delay) * double(speed / 100)); +} + +void AOLayer::move(int ax, int ay) +{ + x = ax; + y = ay; + QLabel::move(x, y); +} + +void BackgroundLayer::load_image(QString p_filename) +{ + play_once = false; + cull_image = false; + QString design_path = ao_app->get_background_path("design.ini"); + transform_mode = + ao_app->get_scaling(ao_app->read_design_ini("scaling", design_path)); + stretch = ao_app->read_design_ini("stretch", design_path).startsWith("true"); + qDebug() << "[BackgroundLayer] BG loaded: " << p_filename; + start_playback(ao_app->get_image_suffix(ao_app->get_background_path(p_filename))); +} + +void ForegroundLayer::load_image(QString p_filename, QString p_charname) +{ + play_once = false; + cull_image = false; + miscname = ao_app->get_char_shouts(p_charname); + qDebug() << "[ForegroundLayer] FG loaded: " << p_filename; + QList pathlist = { + ao_app->get_image_suffix(ao_app->get_character_path( + p_charname, p_filename)), // first check the character folder + ao_app->get_image_suffix(ao_app->get_theme_path( + "misc/" + miscname + "/" + + p_filename)), // then check our theme's misc directory + ao_app->get_image_suffix(ao_app->get_misc_path( + miscname, p_filename)), // then check our global misc folder + ao_app->get_image_suffix( + ao_app->get_theme_path(p_filename)), // then check the user's theme + ao_app->get_image_suffix(ao_app->get_default_theme_path( + p_filename))}; // and finally check the default theme + start_playback(find_image(pathlist)); +} + +void CharLayer::load_image(QString p_filename, QString p_charname, + int p_duration, bool p_is_preanim) +{ + duration = p_duration; + cull_image = false; + force_continuous = false; + transform_mode = ao_app->get_scaling( + ao_app->get_emote_property(p_charname, p_filename, "scaling")); + stretch = ao_app->get_emote_property(p_charname, p_filename, "stretch") + .startsWith(true); + if ((p_charname == last_char) && + ((p_filename == last_emote) || + (p_filename.mid(3, -1) == last_emote.mid(3, -1))) && + (!is_preanim) && (!was_preanim)) { + continuous = true; + force_continuous = true; + } + else { + continuous = false; + force_continuous = true; + } + prefix = ""; + current_emote = p_filename; + was_preanim = is_preanim; + m_char = p_charname; + m_emote = current_emote; + last_char = p_charname; + last_emote = current_emote; + last_prefix = prefix; + is_preanim = p_is_preanim; + if ((p_filename.left(3) == "(a)") || (p_filename.left(3) == "(b)")) { + prefix = p_filename.left(3); + current_emote = p_filename.mid(3, -1); + } + else if ((duration > 0) || (p_filename.left(3) == "(c)")) { + if (p_filename.left(3) == "(c)") { + prefix = "(c)"; + current_emote = p_filename.mid(3, -1); + } + is_preanim = true; + play_once = true; + preanim_timer->start(duration * tick_ms); + } + qDebug() << "[CharLayer] anim loaded: prefix " << prefix << " filename " + << current_emote << " from character: " << p_charname + << " continuous: " << continuous; + QList pathlist = { + ao_app->get_image_suffix(ao_app->get_character_path( + p_charname, prefix + current_emote)), // Default path + ao_app->get_image_suffix(ao_app->get_character_path( + p_charname, + prefix + "/" + current_emote)), // Path check if it's categorized + // into a folder + ao_app->get_image_suffix(ao_app->get_character_path( + p_charname, + current_emote)), // Just use the non-prefixed image, animated or not + ao_app->get_image_suffix( + ao_app->get_theme_path("placeholder")), // Theme placeholder path + ao_app->get_image_suffix(ao_app->get_default_theme_path( + "placeholder"))}; // Default theme placeholder path + this->start_playback(find_image(pathlist)); +} + +void InterjectionLayer::load_image(QString p_filename, QString p_charname, + QString p_miscname) +{ + continuous = false; + force_continuous = true; + play_once = true; + transform_mode = ao_app->get_misc_scaling(p_miscname); + QList pathlist = { + ao_app->get_image_suffix(ao_app->get_character_path( + p_charname, p_filename)), // Character folder + ao_app->get_image_suffix(ao_app->get_theme_path( + "misc/" + p_miscname + "/" + p_filename)), // Theme misc path + ao_app->get_image_suffix( + ao_app->get_misc_path(p_miscname, p_filename)), // Misc path + ao_app->get_image_suffix( + ao_app->get_theme_path(p_filename)), // Theme path + ao_app->get_image_suffix( + ao_app->get_default_theme_path(p_filename)), // Default theme path + ao_app->get_image_suffix( + ao_app->get_theme_path("placeholder")), // Placeholder path + ao_app->get_image_suffix(ao_app->get_default_theme_path( + "placeholder")), // Default placeholder path + }; + QString final_image = find_image(pathlist); + if (final_image == ao_app->get_theme_path("custom.png") || + final_image == ao_app->get_default_theme_path("custom.png") || + final_image == ao_app->get_theme_path("witnesstestimony.png") || + final_image == ao_app->get_default_theme_path("witnesstestimony.png") || + final_image == ao_app->get_theme_path("crossexamination.png") || + final_image == ao_app->get_default_theme_path("crossexamination.png")) + // stupid exceptions because themes are stupid + final_image = find_image( + {ao_app->get_image_suffix(ao_app->get_theme_path("placeholder")), + ao_app->get_image_suffix(ao_app->get_default_theme_path("placeholder"))}); + start_playback(final_image); +} + +void EffectLayer::load_image(QString p_filename, bool p_looping) +{ + if (p_looping) + play_once = false; + else + play_once = true; + continuous = false; + force_continuous = true; + start_playback(p_filename); // handled in its own file before we see it +} + +void InterfaceLayer::load_image(QString p_filename, QString p_miscname) +{ + transform_mode = ao_app->get_misc_scaling(p_miscname); + QList pathlist = { + ao_app->get_image_suffix(ao_app->get_theme_path( + "misc/" + p_miscname + "/" + + p_filename)), // first check our theme's misc directory + ao_app->get_image_suffix(ao_app->get_misc_path( + p_miscname, p_filename)), // then check our global misc folder + ao_app->get_image_suffix(ao_app->get_theme_path( + p_filename)), // then check the user's theme for a default image + ao_app->get_image_suffix(ao_app->get_default_theme_path( + p_filename))}; // and finally check the default theme + start_playback(find_image(pathlist)); +} + +void StickerLayer::load_image(QString p_charname) +{ + QString miscname = ao_app->get_char_shouts(p_charname); + transform_mode = ao_app->get_misc_scaling(miscname); + QList pathlist = { + ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + + miscname + "/sticker/" + p_charname), // Misc path + ao_app->get_image_suffix(ao_app->get_custom_theme_path(miscname, "sticker/" + p_charname)), // Custom theme path + ao_app->get_image_suffix(ao_app->get_theme_path("sticker/" + p_charname)), // Theme path + ao_app->get_image_suffix( + ao_app->get_default_theme_path("sticker/" + p_charname)), // Default theme path + ao_app->get_image_suffix( + ao_app->get_character_path(p_charname, "sticker")), // Character folder + ao_app->get_image_suffix( + ao_app->get_character_path(p_charname, "showname")), // Scuffed DRO way + }; + start_playback(find_image(pathlist)); +} + +void CharLayer::start_playback(QString p_image) +{ + movie_effects.clear(); + AOLayer::start_playback(p_image); + if (network_strings.size() > 0) // our FX overwritten by networked ones + load_network_effects(); + else // Use default ini FX + load_effects(); +} + +void AOLayer::start_playback(QString p_image) +{ +#ifdef DEBUG_MOVIE + actual_time.restart(); +#endif + this->clear(); + freeze(); + movie_frames.clear(); + movie_delays.clear(); + + if (!file_exists(p_image)) + return; + + QString scaling_override = + ao_app->read_design_ini("scaling", p_image + ".ini"); + if (scaling_override != "") + transform_mode = ao_app->get_scaling(scaling_override); + QString stretch_override = + ao_app->read_design_ini("stretch", p_image + ".ini"); + if (stretch_override != "") + stretch = stretch_override.startsWith("true"); + + qDebug() << "stretch:" << stretch << "filename:" << p_image; + m_reader.setFileName(p_image); + if (m_reader.loopCount() == 0) + play_once = true; + if ((last_path == p_image) && (!force_continuous)) + continuous = true; + else if ((last_path != p_image) && !force_continuous) + continuous = false; + if (!continuous) + frame = 0; + force_continuous = false; + last_max_frames = max_frames; + max_frames = m_reader.imageCount(); + if (((continuous) && (max_frames != last_max_frames)) || max_frames == 0) { + frame = 0; + continuous = false; + } + // CANTFIX: this causes a slight hitch + // The correct way of doing this would be to use QImageReader::jumpToImage() + // and populate missing data in the movie ticker when it's needed. This is + // unforunately completely impossible, because QImageReader::jumpToImage() is + // not implemented in any image format AO2 is equipped to use. Instead, the + // default behavior is used - that is, absolutely nothing. + if (continuous) { + for (int i = frame; i--;) { + if (i <= -1) + break; + QPixmap l_pixmap = this->get_pixmap(m_reader.read()); + int l_delay = m_reader.nextImageDelay(); + movie_frames.append(l_pixmap); + movie_delays.append(l_delay); + // qDebug() << "appending delay of " << l_delay; + } + } + // qDebug() << "CONT: " << continuous << " MAX: " << max_frames + // << " LAST MAX: " << last_max_frames << " FRAME: " << frame; + QPixmap f_pixmap = this->get_pixmap(m_reader.read()); + int f_delay = m_reader.nextImageDelay(); + + this->set_frame(f_pixmap); + this->show(); + if (max_frames > 1) { + movie_frames.append(f_pixmap); + movie_delays.append(f_delay); + } + else if (max_frames <= 1) { + duration = static_duration; + play_once = false; +#ifdef DEBUG_MOVIE + qDebug() << "max_frames is <= 1, using static duration"; +#endif + } + if (duration > 0 && cull_image == true) + shfx_timer->start(duration); + play(); +#ifdef DEBUG_MOVIE + qDebug() << max_frames << "Setting image to " << image_path + << "Time taken to process image:" << actual_time.elapsed(); + + actual_time.restart(); +#endif +} + +void CharLayer::play() +{ + play_frame_effect(frame); + AOLayer::play(); +} + +void AOLayer::play() +{ + if (max_frames <= 1) { + if (play_once) + ticker->start(tick_ms); + else + this->freeze(); + } + else + ticker->start(this->get_frame_delay(movie_delays[frame])); +} + +void AOLayer::set_play_once(bool p_play_once) { play_once = p_play_once; } +void AOLayer::set_cull_image(bool p_cull_image) { cull_image = p_cull_image; } +void AOLayer::set_static_duration(int p_static_duration) +{ + static_duration = p_static_duration; +} +void AOLayer::set_max_duration(int p_max_duration) +{ + max_duration = p_max_duration; +} + +void CharLayer::load_effects() +{ + movie_effects.clear(); + movie_effects.resize(max_frames); + for (int e_frame = 0; e_frame < max_frames; ++e_frame) { + QString effect = ao_app->get_screenshake_frame(m_char, m_emote, e_frame); + if (effect != "") { + movie_effects[e_frame].append("shake"); + } + + effect = ao_app->get_flash_frame(m_char, m_emote, e_frame); + if (effect != "") { + movie_effects[e_frame].append("flash"); + } + + effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame); + if (effect != "") { + movie_effects[e_frame].append("sfx^" + effect); + } + } +} + +void CharLayer::load_network_effects() +{ + movie_effects.clear(); + movie_effects.resize(max_frames); + // Order is important!!! + QStringList effects_list = {"shake", "flash", "sfx^"}; + + // Determines which list is smaller - effects_list or network_strings - and + // uses it as basis for the loop. This way, incomplete network_strings would + // still be parsed, and excess/unaccounted for networked information is + // omitted. + int effects_size = qMin(effects_list.size(), network_strings.size()); + + for (int i = 0; i < effects_size; ++i) { + QString netstring = network_strings.at(i); + QStringList emote_splits = netstring.split("^"); + for (const QString &emote : emote_splits) { + QStringList parsed = emote.split("|"); + if (parsed.size() <= 0 || parsed.at(0) != m_emote) + continue; + foreach (QString frame_data, parsed) { + QStringList frame_split = frame_data.split("="); + if (frame_split.size() <= + 1) // We might still be hanging at the emote itself (entry 0). + continue; + int f_frame = frame_split.at(0).toInt(); + if (f_frame >= max_frames || f_frame < 0) { + qDebug() << "Warning: out of bounds" << effects_list[i] << "frame" + << f_frame << "out of" << max_frames << "for" << m_emote; + continue; + } + QString f_data = frame_split.at(1); + if (f_data != "") { + QString effect = effects_list[i]; + if (effect == "sfx^") // Currently the only frame result that feeds us + // data, let's yank it in. + effect += f_data; + qDebug() << effect << f_data << "frame" << f_frame << "for" + << m_emote; + movie_effects[f_frame].append(effect); + } + } + } + } +} + +void CharLayer::play_frame_effect(int p_frame) +{ + if (p_frame < max_frames) { + foreach (QString effect, movie_effects[p_frame]) { + if (effect == "shake") { + shake(); +#ifdef DEBUG_MOVIE + qDebug() << "Attempting to play shake on frame" << frame; +#endif + } + + if (effect == "flash") { + flash(); +#ifdef DEBUG_MOVIE + qDebug() << "Attempting to play flash on frame" << frame; +#endif + } + + if (effect.startsWith("sfx^")) { + QString sfx = effect.section("^", 1); + play_sfx(sfx); +#ifdef DEBUG_MOVIE + qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame; +#endif + } + } + } +} + +void AOLayer::stop() +{ + // for all intents and purposes, stopping is the same as hiding. at no point + // do we want a frozen gif to display + this->freeze(); + this->hide(); +} + +void AOLayer::freeze() +{ + // aT nO pOiNt Do We WaNt A fRoZeN gIf To DiSpLaY + ticker->stop(); + preanim_timer->stop(); + shfx_timer->stop(); +} + +void CharLayer::movie_ticker() +{ + AOLayer::movie_ticker(); + play_frame_effect(frame); +} + +void AOLayer::movie_ticker() +{ + ++frame; + if ((frame >= max_frames) && (max_frames > 1)) { + if (play_once) { + if (cull_image) + this->stop(); + else + this->freeze(); + preanim_done(); + return; + } + else + frame = 0; + } + // qint64 difference = elapsed - movie_delays[frame]; + if (frame >= movie_frames.size()) { + movie_frames.append(this->get_pixmap(m_reader.read())); + movie_delays.append(m_reader.nextImageDelay()); + } + +#ifdef DEBUG_MOVIE + qDebug() << frame << movie_delays[frame] + << "actual time taken from last frame:" << actual_time.restart(); +#endif + + this->set_frame(movie_frames[frame]); + ticker->setInterval(this->get_frame_delay(movie_delays[frame])); +} + +void CharLayer::preanim_done() +{ + if (is_preanim) + AOLayer::preanim_done(); + else + return; +} + +void AOLayer::preanim_done() +{ + ticker->stop(); + preanim_timer->stop(); + done(); +} + +void AOLayer::shfx_timer_done() +{ + this->stop(); +#ifdef DEBUG_MOVIE + qDebug() << "shfx timer signaled done"; +#endif + // signal connected to courtroom object, let it figure out what to do + done(); +} diff --git a/src/aomovie.cpp b/src/aomovie.cpp deleted file mode 100644 index 196c1d3..0000000 --- a/src/aomovie.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "aomovie.h" - -#include "courtroom.h" -#include "file_functions.h" -#include "misc_functions.h" - -AOMovie::AOMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) -{ - ao_app = p_ao_app; - - m_movie = new QMovie(); - m_movie->setCacheMode(QMovie::CacheAll); - - this->setMovie(m_movie); - - timer = new QTimer(this); - timer->setTimerType(Qt::PreciseTimer); - timer->setSingleShot(true); - - connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); - connect(timer, SIGNAL(timeout()), this, SLOT(timer_done())); -} - -void AOMovie::set_play_once(bool p_play_once) { play_once = p_play_once; } - -void AOMovie::play(QString p_image, QString p_char, QString p_custom_theme, - int duration) -{ - m_movie->stop(); - - QString shout_path = p_image; - if (!file_exists(p_image)) { - QList pathlist; - - pathlist = { - ao_app->get_image_suffix( - ao_app->get_character_path(p_char, p_image)), // Character folder - ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + - p_custom_theme + "/" + p_image), // Misc path - ao_app->get_image_suffix(ao_app->get_custom_theme_path( - p_custom_theme, p_image)), // Custom theme path - ao_app->get_image_suffix(ao_app->get_theme_path(p_image)), // Theme path - ao_app->get_image_suffix( - ao_app->get_default_theme_path(p_image)), // Default theme path - ao_app->get_image_suffix( - ao_app->get_theme_path("placeholder")), // Placeholder path - ao_app->get_image_suffix(ao_app->get_default_theme_path( - "placeholder")), // Default placeholder path - }; - - for (QString path : pathlist) { - if (file_exists(path)) { - shout_path = path; - break; - } - } - } - - m_movie->setFileName(shout_path); - - if (m_movie->loopCount() == 0) - play_once = true; - - this->show(); - m_movie->start(); - if (m_movie->frameCount() == 0 && duration > 0) - timer->start(duration); -} - -void AOMovie::stop() -{ - m_movie->stop(); - this->hide(); -} - -void AOMovie::frame_change(int n_frame) -{ - // If it's a "static movie" (only one frame - png image), we can't change - // frames - ignore this function (use timer instead). If the frame didn't reach - // the last frame or the movie is continuous, don't stop the movie. - if (m_movie->frameCount() == 0 || n_frame < (m_movie->frameCount() - 1) || - !play_once) - return; - // we need this or else the last frame wont show - timer->start(m_movie->nextFrameDelay()); -} - -void AOMovie::timer_done() -{ - this->stop(); - // signal connected to courtroom object, let it figure out what to do - done(); -} - -void AOMovie::combo_resize(int w, int h) -{ - QSize f_size(w, h); - this->resize(f_size); - m_movie->setScaledSize(f_size); -} diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 6219edf..b36de48 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -96,7 +96,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop, BASS_ChannelLock(oldstream, false); } - if (effect_flags & FADE_OUT) { + if (effect_flags & FADE_OUT & (m_volume[channel] != 0)) { // Fade out the other sample and stop it (due to -1) BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1, 4000); @@ -116,6 +116,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop, BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume[channel] / 100.0f), 1000); + } else this->set_volume(m_volume[channel], channel); @@ -149,12 +150,15 @@ void AOMusicPlayer::set_volume(int p_value, int channel) void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) { + UNUSED(handle); + UNUSED(data); QWORD loop_start = *(static_cast(user)); BASS_ChannelLock(channel, true); BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE); BASS_ChannelLock(channel, false); } + void AOMusicPlayer::set_looping(bool toggle, int channel) { m_looping = toggle; diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 7b42520..0fbee47 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -182,7 +182,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_stay_time_lbl->setText(tr("Text Stay Time:")); ui_stay_time_lbl->setToolTip(tr( "Minimum amount of time (in miliseconds) an IC message must stay on screen before " - "the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behaivor.")); + "the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior.")); ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stay_time_lbl); @@ -218,6 +218,19 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_instant_objection_cb); + row += 1; + ui_chat_ratelimit_lbl = new QLabel(ui_form_layout_widget); + ui_chat_ratelimit_lbl->setText(tr("Chat Rate Limit:")); + ui_chat_ratelimit_lbl->setToolTip(tr( + "Minimum amount of time (in miliseconds) that must pass before the next Enter key press will send your IC message.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_chat_ratelimit_lbl); + + ui_chat_ratelimit_spinbox = new QSpinBox(ui_form_layout_widget); + ui_chat_ratelimit_spinbox->setMaximum(5000); + ui_chat_ratelimit_spinbox->setValue(p_ao_app->get_chat_ratelimit()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_chat_ratelimit_spinbox); row += 1; ui_log_names_divider = new QFrame(ui_form_layout_widget); ui_log_names_divider->setFrameShape(QFrame::HLine); @@ -824,6 +837,7 @@ void AOOptionsDialog::save_pressed() configini->setValue("desync_logs", ui_desync_logs_cb->isChecked()); configini->setValue("stay_time", ui_stay_time_spinbox->value()); configini->setValue("instant_objection", ui_instant_objection_cb->isChecked()); + configini->setValue("chat_ratelimit", ui_chat_ratelimit_spinbox->value()); configini->setValue("default_username", ui_username_textbox->text()); configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); configini->setValue("master", ui_ms_textbox->text()); diff --git a/src/aopacket.cpp b/src/aopacket.cpp index bb6ac73..a40d2ef 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -8,9 +8,15 @@ AOPacket::AOPacket(QString p_packet_string) m_contents = packet_contents.mid(1, packet_contents.size()-2); // trims % } -QString AOPacket::to_string() +QString AOPacket::to_string(bool encoded) { - return m_header + "#" + m_contents.join("#") + "#%"; + QStringList contents = m_contents; + if (encoded) + contents.replaceInStrings("#", "") + .replaceInStrings("%", "") + .replaceInStrings("$", "") + .replaceInStrings("&", ""); + return m_header + "#" + contents.join("#") + "#%"; } void AOPacket::net_encode() diff --git a/src/aoscene.cpp b/src/aoscene.cpp deleted file mode 100644 index 78d69ac..0000000 --- a/src/aoscene.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "aoscene.h" -#include "courtroom.h" -#include "file_functions.h" - -AOScene::AOScene(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) -{ - m_parent = parent; - ao_app = p_ao_app; - m_movie = new QMovie(this); - m_movie->setCacheMode(QMovie::CacheAll); - last_image = ""; -} - -void AOScene::set_image(QString p_image) -{ - QString background_path = - ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(background_path)) // If image is missing, clear current image - { - this->clear(); - this->setMovie(nullptr); - - m_movie->stop(); - last_image = ""; - return; - } - - if (!file_exists(background_path) || background_path != last_image) - { - this->clear(); - this->setMovie(nullptr); - - m_movie->stop(); - m_movie->setFileName(background_path); - } - - if (m_movie->isValid() && m_movie->frameCount() > 1) { - m_movie->jumpToNextFrame(); - float scale_factor = static_cast(f_h) / - static_cast(m_movie->frameRect().height()); - // preserve aspect ratio - int n_w = static_cast(m_movie->frameRect().width() * scale_factor); - int n_h = static_cast(m_movie->frameRect().height() * scale_factor); - - m_movie->setScaledSize(QSize(n_w, n_h)); - this->resize(m_movie->scaledSize()); - if (!file_exists(background_path) || background_path != last_image) - { - this->setMovie(m_movie); - m_movie->start(); - } - QLabel::move(x + (f_w - n_w) / 2, y + (f_h - n_h) / 2); // Center - } - else { - QPixmap background(background_path); - auto transform_mode = Qt::FastTransformation; - if (background.height() > f_h) // We are downscaling, use anti-aliasing. - transform_mode = Qt::SmoothTransformation; - - background = background.scaledToHeight(f_h, transform_mode); - this->resize(background.size()); - this->setPixmap(background); - QLabel::move( - x + (f_w - background.width()) / 2, - y + (f_h - background.height()) / - 2); // Always center horizontally, always center vertically - } - last_image = background_path; -} - -void AOScene::set_legacy_desk(QString p_image) -{ - - QString desk_path = - ao_app->get_image_suffix(ao_app->get_background_path(p_image)); - if (!file_exists(desk_path)) // If image is missing, clear current image - { - this->clear(); - this->setMovie(nullptr); - - m_movie->stop(); - last_image = ""; - return; - } - - if (file_exists(desk_path) && desk_path == last_image) - return; - - QPixmap f_desk(desk_path); - - // vanilla desks vary in both width and height. in order to make that work - // with viewport rescaling, some INTENSE math is needed. - int vp_width = m_parent->width(); - int vp_height = m_parent->height(); - - double h_modifier = vp_height / 192; - - int final_h = static_cast(h_modifier * f_desk.height()); - - this->clear(); - this->setMovie(nullptr); - - m_movie->stop(); - m_movie->setFileName(desk_path); - - m_movie->setScaledSize(QSize(vp_width, final_h)); - - if (m_movie->isValid() && m_movie->frameCount() > 1) { - this->setMovie(m_movie); - m_movie->start(); - } - else { - this->resize(vp_width, final_h); - this->setPixmap(f_desk.scaled(vp_width, final_h)); - } - last_image = desk_path; -} - -void AOScene::combo_resize(int w, int h) -{ - QSize f_size(w, h); - f_w = w; - f_h = h; - this->resize(f_size); -} - -void AOScene::move(int ax, int ay) -{ - x = ax; - y = ay; - QLabel::move(x, y); -} diff --git a/src/charselect.cpp b/src/charselect.cpp index 33cc517..abed095 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -11,6 +11,16 @@ void Courtroom::construct_char_select() ui_char_select_background = new AOImage(this, ao_app); + ui_char_list = new QTreeWidget(ui_char_select_background); + ui_char_list->setColumnCount(2); + ui_char_list->setHeaderLabels({"Name", "ID"}); + ui_char_list->setHeaderHidden(true); + ui_char_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui_char_list->hideColumn(1); + ui_char_list->setDropIndicatorShown(true); + set_size_and_pos(ui_char_list, "char_list"); + + ui_char_buttons = new QWidget(ui_char_select_background); ui_selector = new AOImage(ui_char_select_background, ao_app); @@ -46,6 +56,9 @@ void Courtroom::construct_char_select() set_size_and_pos(ui_char_buttons, "char_buttons"); + connect(ui_char_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), + this, SLOT(on_char_list_double_clicked(QTreeWidgetItem *, int))); + connect(ui_back_to_lobby, SIGNAL(clicked()), this, SLOT(on_back_to_lobby_clicked())); @@ -126,6 +139,21 @@ void Courtroom::set_char_select_page() put_button_in_place(current_char_page * max_chars_on_page, chars_on_page); } +void Courtroom::on_char_list_double_clicked(QTreeWidgetItem *p_item, int column) +{ + UNUSED(column); + int cid = p_item->text(1).toInt(); + if (cid == -1 && !p_item->isExpanded()) { + p_item->setExpanded(true); + return; + } + else if (cid == -1) { + p_item->setExpanded(false); + return; + } + char_clicked(cid); +} + void Courtroom::char_clicked(int n_char) { if (n_char != -1) @@ -218,7 +246,32 @@ void Courtroom::character_loading_finished() char_button->set_image(char_list.at(n).name); char_button->setToolTip(char_list.at(n).name); ui_char_button_list.append(char_button); - + QString char_category = ao_app->get_category(char_list.at(n).name); + QList matching_list = ui_char_list->findItems(char_category, Qt::MatchFixedString, 0); + // create the character tree item + QTreeWidgetItem *treeItem = new QTreeWidgetItem(); + treeItem->setText(0, char_list.at(n).name); + treeItem->setIcon(0, QIcon(ao_app->get_static_image_suffix( + ao_app->get_character_path(char_list.at(n).name, "char_icon")))); + treeItem->setText(1, QString::number(n)); + // category logic + QTreeWidgetItem *category; + if (char_category == "") // no category + ui_char_list->addTopLevelItem(treeItem); + else if (!matching_list.isEmpty()) { // our category already exists + category = matching_list[0]; + category->addChild(treeItem); + } + else { // we need to make a new category + category = new QTreeWidgetItem(); + category->setText(0, char_category); + category->setText(1, "-1"); + category->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); + ui_char_list->insertTopLevelItem(0, category); + category->addChild(treeItem); + } + + connect(char_button, &AOCharButton::clicked, [this, n]() { this->char_clicked(n); }); @@ -241,7 +294,7 @@ void Courtroom::character_loading_finished() .arg(QString::number(ao_app->char_list_size))); } } - + ui_char_list->expandAll(); filter_character_list(); } @@ -250,24 +303,37 @@ void Courtroom::filter_character_list() ui_char_button_list_filtered.clear(); for (int i = 0; i < char_list.size(); i++) { AOCharButton *current_char = ui_char_button_list.at(i); + QTreeWidgetItem* current_char_list_item = ui_char_list->findItems(QString::number(i), Qt::MatchExactly | Qt::MatchRecursive, 1)[0]; + + // It seems passwording characters is unimplemented yet? // Until then, this will stay here, I suppose. // if (ui_char_passworded->isChecked() && character_is_passworded??) // continue; - if (!ui_char_taken->isChecked() && char_list.at(i).taken) + if (!ui_char_taken->isChecked() && char_list.at(i).taken) { + current_char_list_item->setHidden(true); continue; + } if (!char_list.at(i).name.contains(ui_char_search->text(), - Qt::CaseInsensitive)) + Qt::CaseInsensitive)) { + current_char_list_item->setHidden(true); continue; + } // We only really need to update the fact that a character is taken // for the buttons that actually appear. // You'd also update the passwordedness and etc. here later. current_char->reset(); + current_char_list_item->setHidden(false); current_char->set_taken(char_list.at(i).taken); + current_char_list_item->setText(0, char_list.at(i).name); + // reset disabled + current_char_list_item->setDisabled(false); + if (char_list.at(i).taken) // woops, we are taken + current_char_list_item->setDisabled(true); ui_char_button_list_filtered.append(current_char); } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 0c36215..4b37e6f 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -43,21 +43,22 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_background = new AOImage(this, ao_app); ui_viewport = new QWidget(this); - ui_vp_background = new AOScene(ui_viewport, ao_app); - ui_vp_speedlines = new AOMovie(ui_viewport, ao_app); - ui_vp_speedlines->set_play_once(false); - ui_vp_player_char = new AOCharMovie(ui_viewport, ao_app); - ui_vp_sideplayer_char = new AOCharMovie(ui_viewport, ao_app); + ui_vp_background = new BackgroundLayer(ui_viewport, ao_app); + ui_vp_speedlines = new ForegroundLayer(ui_viewport, ao_app); + ui_vp_player_char = new CharLayer(ui_viewport, ao_app); + ui_vp_sideplayer_char = new CharLayer(ui_viewport, ao_app); ui_vp_sideplayer_char->hide(); - ui_vp_desk = new AOScene(ui_viewport, ao_app); - ui_vp_legacy_desk = new AOScene(ui_viewport, ao_app); + ui_vp_desk = new BackgroundLayer(ui_viewport, ao_app); + + ui_vp_effect = new EffectLayer(this, ao_app); + ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents); ui_vp_evidence_display = new AOEvidenceDisplay(ui_viewport, ao_app); ui_vp_chatbox = new AOImage(this, ao_app); ui_vp_showname = new QLabel(ui_vp_chatbox); ui_vp_showname->setAlignment(Qt::AlignLeft); - ui_vp_chat_arrow = new AOMovie(ui_vp_chatbox, ao_app); + ui_vp_chat_arrow = new InterfaceLayer(this, ao_app); ui_vp_chat_arrow->set_play_once(false); ui_vp_message = new QTextEdit(this); @@ -66,14 +67,13 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui_vp_message->setReadOnly(true); - ui_vp_testimony = new AOMovie(this, ao_app); + ui_vp_testimony = new InterfaceLayer(this, ao_app); ui_vp_testimony->set_play_once(false); ui_vp_testimony->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_vp_effect = new AOMovie(this, ao_app); - ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_vp_wtce = new AOMovie(this, ao_app); + ui_vp_wtce = new InterjectionLayer(this, ao_app); + ui_vp_wtce->set_play_once(true); ui_vp_wtce->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_vp_objection = new AOMovie(this, ao_app); + ui_vp_objection = new InterjectionLayer(this, ao_app); ui_vp_objection->setAttribute(Qt::WA_TransparentForMouseEvents); ui_ic_chatlog = new QTextEdit(this); @@ -110,8 +110,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_music_list->header()->setStretchLastSection(false); ui_music_list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); ui_music_list->setContextMenuPolicy(Qt::CustomContextMenu); + ui_music_list->setUniformRowHeights(true); + - ui_music_display = new AOMovie(this, ao_app); + ui_music_display = new InterfaceLayer(this, ao_app); ui_music_display->set_play_once(false); ui_music_display->setAttribute(Qt::WA_TransparentForMouseEvents); @@ -138,6 +140,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() // todo: filter out \n from showing up as that commonly breaks the chatlog and // can be spammed to hell + ui_vp_sticker = new StickerLayer(ui_viewport, ao_app); + ui_vp_sticker->set_play_once(false); + ui_vp_sticker->setAttribute(Qt::WA_TransparentForMouseEvents); + ui_muted = new AOImage(ui_ic_chat_message, ao_app); ui_muted->hide(); @@ -275,6 +281,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(keepalive_timer, SIGNAL(timeout()), this, SLOT(ping_server())); connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); + connect(ui_vp_effect, SIGNAL(done()), this, SLOT(effect_done())); + connect(ui_vp_wtce, SIGNAL(done()), this, SLOT(effect_done())); connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); connect(ui_vp_player_char, SIGNAL(shake()), this, SLOT(do_screenshake())); connect(ui_vp_player_char, SIGNAL(flash()), this, SLOT(do_flash())); @@ -303,6 +311,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_sfx_dropdown, SIGNAL(currentIndexChanged(int)), this, SLOT(on_sfx_dropdown_changed(int))); + connect(ui_sfx_dropdown, SIGNAL(editTextChanged(QString)), this, + SLOT(on_sfx_dropdown_custom(QString))); connect(ui_sfx_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_sfx_context_menu_requested(QPoint))); connect(ui_sfx_remove, SIGNAL(clicked()), this, @@ -534,14 +544,6 @@ void Courtroom::set_widgets() ui_vp_desk->move(0, 0); ui_vp_desk->combo_resize(ui_viewport->width(), ui_viewport->height()); - // the size of the ui_vp_legacy_desk element relies on various factors and is - // set in set_scene() - - double y_modifier = 147.0 / 192.0; - int final_y = static_cast(y_modifier * ui_viewport->height()); - ui_vp_legacy_desk->move(0, final_y); - ui_vp_legacy_desk->hide(); - ui_vp_evidence_display->move(0, 0); ui_vp_evidence_display->combo_resize(ui_viewport->width(), ui_viewport->height()); @@ -555,11 +557,14 @@ void Courtroom::set_widgets() ui_vp_chat_arrow->hide(); } else { - ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); - ui_vp_chat_arrow->combo_resize(design_ini_result.width, - design_ini_result.height); + ui_vp_chat_arrow->move(design_ini_result.x + ui_vp_chatbox->x(), design_ini_result.y + ui_vp_chatbox->y()); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); } + // layering shenanigans with ui_vp_chatbox prevent us from doing the sensible + // thing, which is to parent these to ui_viewport. instead, AOLayer handles + // masking so we don't overlap parts of the UI, and they become free floating + // widgets. ui_vp_testimony->move(ui_viewport->x(), ui_viewport->y()); ui_vp_testimony->combo_resize(ui_viewport->width(), ui_viewport->height()); @@ -634,6 +639,17 @@ void Courtroom::set_widgets() set_size_and_pos(ui_music_list, "music_list"); ui_music_list->header()->setMinimumSectionSize(ui_music_list->width()); + QString music_list_indentation = ao_app->get_font_name("music_list_indent", "courtroom_design.ini"); + if (music_list_indentation == "") + ui_music_list->resetIndentation(); + else + ui_music_list->setIndentation(music_list_indentation.toInt()); + + QString music_list_animated = ao_app->get_font_name("music_list_animated", "courtroom_design.ini"); + if (music_list_animated == "1") + ui_music_list->setAnimated(true); + else + ui_music_list->setAnimated(false); set_size_and_pos(ui_music_name, "music_name"); @@ -642,7 +658,7 @@ void Courtroom::set_widgets() ao_app->get_element_dimensions("music_display", "courtroom_design.ini"); if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qDebug() << "W: could not find \"music_name\" in courtroom_design.ini"; + qDebug() << "W: could not find \"music_display\" in courtroom_design.ini"; ui_music_display->hide(); } else { @@ -650,9 +666,8 @@ void Courtroom::set_widgets() ui_music_display->combo_resize(design_ini_result.width, design_ini_result.height); } + ui_music_display->load_image("music_display", ""); - ui_music_display->play("music_display"); - ui_music_display->set_play_once(false); for (int i = 0; i < max_clocks; i++) { set_size_and_pos(ui_clock[i], "clock_" + QString::number(i)); @@ -660,12 +675,12 @@ void Courtroom::set_widgets() if (is_ao2_bg) { set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); - set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); + // set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); set_size_and_pos(ui_ic_chat_name, "ao2_ic_chat_name"); } else { set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); - set_size_and_pos(ui_vp_chatbox, "chatbox"); + // set_size_and_pos(ui_vp_chatbox, "chatbox"); set_size_and_pos(ui_ic_chat_name, "ic_chat_name"); } @@ -688,6 +703,10 @@ void Courtroom::set_widgets() ui_vp_message->y() + ui_vp_chatbox->y()); ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); + ui_vp_sticker->move(0, 0); + ui_vp_sticker->combo_resize(ui_viewport->width(), + ui_viewport->height()); + ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); ui_muted->set_image("muted"); ui_muted->setToolTip(tr("Oops, you're muted!")); @@ -729,7 +748,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); ui_sfx_dropdown->setEditable(true); - ui_sfx_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); + ui_sfx_dropdown->setInsertPolicy(QComboBox::NoInsert); ui_sfx_dropdown->setToolTip( tr("Set a sound effect to play on your next 'Preanim'. Leaving it on " "Default will use the emote-defined sound (if any).\n" @@ -1118,6 +1137,24 @@ void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier) } } +void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier, + QString p_char) +{ + QString filename = "courtroom_design.ini"; + + pos_size_type design_ini_result = + ao_app->get_element_dimensions(p_identifier, filename, p_char); + + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find \"" << p_identifier << "\" in " << filename; + p_widget->hide(); + } + else { + p_widget->move(design_ini_result.x, design_ini_result.y); + p_widget->resize(design_ini_result.width, design_ini_result.height); + } +} + void Courtroom::set_taken(int n_char, bool p_taken) { if (n_char >= char_list.size()) { @@ -1160,13 +1197,20 @@ void Courtroom::done_received() objection_player->set_volume(0); blip_player->set_volume(0); - set_char_select_page(); + if (char_list.size() > 0) + { + set_char_select_page(); + set_char_select(); + } + else + { + update_character(m_cid); + enter_courtroom(); + } set_mute_list(); set_pair_list(); - set_char_select(); - show(); ui_spectator->show(); @@ -1210,11 +1254,11 @@ void Courtroom::set_background(QString p_background, bool display) is_ao2_bg = true; if (is_ao2_bg) { - set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); + // set_size_and_pos(ui_vp_chatbox, "ao2_chatbox"); set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); } else { - set_size_and_pos(ui_vp_chatbox, "chatbox"); + // set_size_and_pos(ui_vp_chatbox, "chatbox"); set_size_and_pos(ui_ic_chat_message, "ic_chat_message"); } @@ -1280,8 +1324,6 @@ void Courtroom::set_pos_dropdown(QStringList pos_dropdowns) ui_pos_dropdown->addItems(pos_dropdown_list); // Unblock the signals so the element can be used for setting pos again ui_pos_dropdown->blockSignals(false); - - qDebug() << pos_dropdown_list; } void Courtroom::update_character(int p_cid) @@ -1324,7 +1366,6 @@ void Courtroom::update_character(int p_cid) set_sfx_dropdown(); set_effects_dropdown(); - qDebug() << "update_character called"; if (newchar) // Avoid infinite loop of death and suffering set_iniswap_dropdown(); @@ -1397,6 +1438,12 @@ void Courtroom::update_character(int p_cid) } } } + if (is_ao2_bg) { + set_size_and_pos(ui_vp_chatbox, "ao2_chatbox", f_char); + } + else { + set_size_and_pos(ui_vp_chatbox, "chatbox", f_char); + } if (m_cid != -1) // there is no name at char_list -1, and we crash if we try // to find one @@ -1622,7 +1669,7 @@ void Courtroom::on_chat_return_pressed() return; ui_ic_chat_message->blockSignals(true); - QTimer::singleShot(200, this, + QTimer::singleShot(ao_app->get_chat_ratelimit(), this, [=] { ui_ic_chat_message->blockSignals(false); }); // MS# // deskmod# @@ -1681,12 +1728,6 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(current_side); packet_contents.append(get_char_sfx()); - if (ui_pre->isChecked() && !ao_app->is_stickysounds_enabled() && ui_sfx_dropdown->currentIndex() > 1) { - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->setCurrentIndex(0); - ui_sfx_dropdown->blockSignals(false); - ui_sfx_remove->hide(); - } int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); @@ -1838,7 +1879,8 @@ void Courtroom::on_chat_return_pressed() packet_contents.append(ui_additive->isChecked() ? "1" : "0"); } if (ao_app->effects_enabled) { - QString fx_sound = ao_app->get_effect_sound(effect, current_char); + QString fx_sound = + ao_app->get_effect_property(effect, current_char, "sound"); QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); packet_contents.append(effect + "|" + p_effect + "|" + fx_sound); @@ -1862,8 +1904,6 @@ void Courtroom::reset_ui() realization_state = 0; screenshake_state = 0; is_presenting_evidence = false; - if (!ao_app->is_stickypres_enabled()) - ui_pre->setChecked(false); ui_hold_it->set_image("holdit"); ui_objection->set_image("objection"); ui_take_that->set_image("takethat"); @@ -1871,6 +1911,14 @@ void Courtroom::reset_ui() ui_realization->set_image("realization"); ui_screenshake->set_image("screenshake"); ui_evidence_present->set_image("present"); + + if (ui_pre->isChecked() && !ao_app->is_stickysounds_enabled()) { + ui_sfx_dropdown->setCurrentIndex(0); + ui_sfx_remove->hide(); + custom_sfx = ""; + } + if (!ao_app->is_stickypres_enabled()) + ui_pre->setChecked(false); } void Courtroom::chatmessage_enqueue(QStringList p_contents) @@ -1913,12 +1961,9 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents) } // Record the log I/O, log files should be accurate. - log_chatmessage(p_contents[MESSAGE], f_char_id, p_contents[SHOWNAME], p_contents[TEXT_COLOR].toInt()); - if (ao_app->is_desyncrhonized_logs_enabled()) { - // Display the logs immediately. - display_log_chatmessage(p_contents[MESSAGE], f_char_id, p_contents[SHOWNAME], p_contents[TEXT_COLOR].toInt()); - } - + // If desynced logs are on, display the log IC immediately. + LogMode log_mode = ao_app->is_desyncrhonized_logs_enabled() ? DISPLAY_AND_IO : IO_ONLY; + log_chatmessage(p_contents[MESSAGE], f_char_id, p_contents[SHOWNAME], p_contents[TEXT_COLOR].toInt(), log_mode); // Send this boi into the queue chatmessage_queue.enqueue(p_contents); @@ -1933,11 +1978,12 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents) void Courtroom::chatmessage_dequeue() { // Chat stopped being processed, indicate that the user can post their message now. - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); - ui_vp_chat_arrow->play( - "chat_arrow", f_char, - f_custom_theme); + QString f_custom_theme; + if (ao_app->is_customchat_enabled()) { + QString f_char = m_chatmessage[CHAR_NAME]; + f_custom_theme = ao_app->get_chat(f_char); + } + ui_vp_chat_arrow->load_image("chat_arrow", f_custom_theme); // Nothing to parse in the queue if (chatmessage_queue.isEmpty()) @@ -1969,7 +2015,7 @@ void Courtroom::unpack_chatmessage(QStringList p_contents) if (!ao_app->is_desyncrhonized_logs_enabled()) { // We have logs displaying as soon as we reach the message in our queue, which is a less confusing but also less accurate experience for the user. - display_log_chatmessage(m_chatmessage[MESSAGE], m_chatmessage[CHAR_ID].toInt(), m_chatmessage[SHOWNAME], m_chatmessage[TEXT_COLOR].toInt()); + log_chatmessage(m_chatmessage[MESSAGE], m_chatmessage[CHAR_ID].toInt(), m_chatmessage[SHOWNAME], m_chatmessage[TEXT_COLOR].toInt(), DISPLAY_ONLY); } // Process the callwords for this message @@ -1988,7 +2034,7 @@ void Courtroom::unpack_chatmessage(QStringList p_contents) handle_ic_message(); } -void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_showname, int f_color) +void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_showname, int f_color, LogMode f_log_mode) { // Display name will use the showname QString f_displayname = f_showname; @@ -2052,95 +2098,17 @@ void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_show } break; } - log_ic_text(f_char, f_displayname, shout_message, tr("shouts")); - } - - // Obtain evidence ID we're trying to work with - int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); - // If the evidence ID is in the valid range - if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { - // Obtain the evidence name - QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name; - // Add the message to the logs file - log_ic_text(f_showname, f_displayname, f_evi_name, - tr("has presented evidence")); - } - } - - // If the chat message isn't a blankpost, or the chatlog history is empty, or its last message isn't a blankpost - if (!f_message.isEmpty() || - ic_chatlog_history.isEmpty() || ic_chatlog_history.last().get_message() != "") { - // Add the message to the logs file - log_ic_text(f_showname, f_displayname, f_message, "", - f_color); - } -} - -void Courtroom::display_log_chatmessage(QString f_message, int f_char_id, QString f_showname, int f_color) -{ - // Display name will use the showname - QString f_displayname = f_showname; - if (f_char_id != -1) { - // Grab the char.ini showname - f_showname = ao_app->get_showname(char_list.at(f_char_id).name); - // If custom serversided shownames are not enabled - if (!ui_showname_enable->isChecked()) { - // Set the display name to the char.ini showname - f_displayname = f_showname; - } - } - // If display name is just whitespace, use the char.ini showname. - if (f_displayname.trimmed().isEmpty()) - f_displayname = f_showname; - - if (log_ic_actions) { - // 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(); - } - - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); - if (objection_mod <= 4 && objection_mod >= 1) { - QString shout_message; - switch (objection_mod) { - case 1: - shout_message = ao_app->read_char_ini(f_char, "holdit_message", "Shouts"); - if (shout_message == "") - shout_message = tr("HOLD IT!"); - break; - case 2: - shout_message = ao_app->read_char_ini(f_char, "objection_message", "Shouts"); - if (shout_message == "") - shout_message = tr("OBJECTION!"); - break; - case 3: - shout_message = ao_app->read_char_ini(f_char, "takethat_message", "Shouts"); - if (shout_message == "") - shout_message = tr("TAKE THAT!"); - break; - // case 4 is AO2 only - case 4: - if (custom_objection != "") { - shout_message = ao_app->read_char_ini(f_char, custom_objection.split('.')[0] + "_message", "Shouts"); - if (shout_message == "") - shout_message = custom_objection.split('.')[0]; - } - else { - shout_message = ao_app->read_char_ini(f_char, "custom_message", "Shouts"); - if (shout_message == "") - shout_message = tr("CUSTOM OBJECTION!"); - } - break; + switch (f_log_mode) { + case IO_ONLY: + log_ic_text(f_char, f_displayname, shout_message, tr("shouts")); + break; + case DISPLAY_AND_IO: + log_ic_text(f_char, f_displayname, shout_message, tr("shouts")); + [[fallthrough]]; + case DISPLAY_ONLY: + append_ic_text(shout_message, f_displayname, tr("shouts")); + break; } - append_ic_text(shout_message, f_displayname, tr("shouts")); } // Obtain evidence ID we're trying to work with @@ -2149,17 +2117,34 @@ void Courtroom::display_log_chatmessage(QString f_message, int f_char_id, QStrin if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { // Obtain the evidence name QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name; - // Append the message to the IC chatlogs in client - append_ic_text(f_evi_name, f_displayname, tr("has presented evidence")); + switch (f_log_mode) { + case IO_ONLY: + log_ic_text(f_showname, f_displayname, f_evi_name, tr("has presented evidence")); + break; + case DISPLAY_AND_IO: + log_ic_text(f_showname, f_displayname, f_evi_name, tr("has presented evidence")); + [[fallthrough]]; + case DISPLAY_ONLY: + append_ic_text(f_evi_name, f_displayname, tr("has presented evidence")); + break; + } } } // If the chat message isn't a blankpost, or the chatlog history is empty, or its last message isn't a blankpost if (!f_message.isEmpty() || ic_chatlog_history.isEmpty() || ic_chatlog_history.last().get_message() != "") { - // Append the message to the IC chatlogs in client - append_ic_text(f_message, f_displayname, "", - f_color); + switch (f_log_mode) { + case IO_ONLY: + log_ic_text(f_showname, f_displayname, f_message, "",f_color); + break; + case DISPLAY_AND_IO: + log_ic_text(f_showname, f_displayname, f_message, "",f_color); + [[fallthrough]]; + case DISPLAY_ONLY: + append_ic_text(f_message, f_displayname, "",f_color); + break; + } } } @@ -2177,64 +2162,75 @@ bool Courtroom::handle_objection() objection_mod = m_chatmessage[OBJECTION_MOD].toInt(); } - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); + if (is_ao2_bg) { + set_size_and_pos(ui_vp_chatbox, "ao2_chatbox", m_chatmessage[CHAR_NAME]); + } + else { + set_size_and_pos(ui_vp_chatbox, "chatbox", m_chatmessage[CHAR_NAME]); + } + set_size_and_pos(ui_vp_showname, "showname", m_chatmessage[CHAR_NAME]); + set_size_and_pos(ui_vp_message, "message", m_chatmessage[CHAR_NAME]); + ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), + ui_vp_message->y() + ui_vp_chatbox->y()); + ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); // if an objection is used if (objection_mod <= 4 && objection_mod >= 1) { - QString shout_message; + ui_vp_objection->set_static_duration(shout_static_time); + ui_vp_objection->set_max_duration(shout_max_time); + QString filename; switch (objection_mod) { case 1: - ui_vp_objection->play("holdit_bubble", f_char, f_custom_theme, 724); - objection_player->play("holdit", f_char, f_custom_theme); - shout_message = ao_app->read_char_ini(f_char, "holdit_message", "Shouts"); - if (shout_message == "") - shout_message = tr("HOLD IT!"); + filename = "holdit_bubble"; + objection_player->play("holdit", m_chatmessage[CHAR_NAME], + ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); break; case 2: - ui_vp_objection->play("objection_bubble", f_char, f_custom_theme, 724); - objection_player->play("objection", f_char, f_custom_theme); - shout_message = ao_app->read_char_ini(f_char, "objection_message", "Shouts"); - if (shout_message == "") - shout_message = tr("OBJECTION!"); + filename = "objection_bubble"; + objection_player->play("objection", m_chatmessage[CHAR_NAME], + ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); if (ao_app->objection_stop_music()) music_player->stop(); break; case 3: - ui_vp_objection->play("takethat_bubble", f_char, f_custom_theme, 724); - objection_player->play("takethat", f_char, f_custom_theme); - shout_message = ao_app->read_char_ini(f_char, "takethat_message", "Shouts"); - if (shout_message == "") - shout_message = tr("TAKE THAT!"); + filename = "takethat_bubble"; + objection_player->play("takethat", m_chatmessage[CHAR_NAME], + ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); break; // case 4 is AO2 only case 4: if (custom_objection != "") { - ui_vp_objection->play("custom_objections/" + custom_objection, f_char, - f_custom_theme, shout_stay_time); - objection_player->play("custom_objections/" + - custom_objection.split('.')[0], - f_char, f_custom_theme); - shout_message = ao_app->read_char_ini(f_char, custom_objection.split('.')[0] + "_message", "Shouts"); - if (shout_message == "") - shout_message = custom_objection.split('.')[0]; + filename = "custom_objections/" + custom_objection; + objection_player->play( + "custom_objections/" + custom_objection.split('.')[0], + m_chatmessage[CHAR_NAME], + ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); } else { - ui_vp_objection->play("custom", f_char, f_custom_theme, - shout_stay_time); - objection_player->play("custom", f_char, f_custom_theme); - shout_message = ao_app->read_char_ini(f_char, "custom_message", "Shouts"); - if (shout_message == "") - shout_message = tr("CUSTOM OBJECTION!"); + filename = "custom"; + objection_player->play( + "custom", m_chatmessage[CHAR_NAME], + ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); } - break; + break; + m_chatmessage[EMOTE_MOD] = 1; } + ui_vp_objection->load_image( + filename, m_chatmessage[CHAR_NAME], + ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); sfx_player->clear(); // Objection played! Cut all sfx. return true; } + display_character(); return false; } +void Courtroom::effect_done() +{ + ui_vp_effect->stop(); + ui_vp_wtce->stop(); +} + void Courtroom::display_character() { // Stop all previously playing animations, effects etc. @@ -2246,6 +2242,8 @@ void Courtroom::display_character() // Hide the message and chatbox and handle the emotes ui_vp_message->hide(); ui_vp_chatbox->hide(); + // Hide the face sticker + ui_vp_sticker->stop(); // Initialize the correct pos (called SIDE here for some reason) with DESK_MOD to determine if we should hide the desk or not. switch(m_chatmessage[DESK_MOD].toInt()) { case 4: @@ -2326,26 +2324,6 @@ void Courtroom::display_pair_character(QString other_charid, QString other_offse ui_vp_sideplayer_char->move(ui_viewport->width() * offset_x / 100, ui_viewport->height() * offset_y / 100); - // Split the charid according to the ^ to determine if we have "ordering" info - QStringList args = other_charid.split("^"); - if (args.size() > - 1) // This ugly workaround is so we don't make an extra packet just - // for this purpose. Rewrite pairing when? - { - // Change the order of appearance based on the pair order variable - int order = args.at(1).toInt(); - switch (order) { - case 0: // Our character is in front - ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); - break; - case 1: // Our character is behind - ui_vp_player_char->stackUnder(ui_vp_sideplayer_char); - break; - default: - break; - } - } - // Flip the pair character if (ao_app->flipping_enabled && m_chatmessage[OTHER_FLIP].toInt() == 1) ui_vp_sideplayer_char->set_flipped(true); @@ -2353,10 +2331,11 @@ void Courtroom::display_pair_character(QString other_charid, QString other_offse ui_vp_sideplayer_char->set_flipped(false); // Play the other pair character's idle animation - ui_vp_sideplayer_char->play_idle(m_chatmessage[OTHER_NAME], - m_chatmessage[OTHER_EMOTE]); + QString filename = "(a)" + m_chatmessage[OTHER_EMOTE]; + ui_vp_sideplayer_char->load_image(filename, m_chatmessage[OTHER_NAME], + 0, false); + } } - } } void Courtroom::handle_emote_mod(int emote_mod, bool p_immediate) @@ -2487,7 +2466,11 @@ void Courtroom::do_flash() QString f_char = m_chatmessage[CHAR_NAME]; QString f_custom_theme = ao_app->get_char_shouts(f_char); - ui_vp_effect->play("realizationflash", f_char, f_custom_theme, 60); + ui_vp_effect->stretch = true; + ui_vp_effect->set_static_duration(60); + ui_vp_effect->set_max_duration(60); + 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, @@ -2504,12 +2487,17 @@ void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char, // Only check if effects are disabled after playing the sound if it exists if (!ao_app->is_effects_enabled()) return; - + ui_vp_effect->transform_mode = ao_app->get_scaling( + ao_app->get_effect_property(fx_name, p_char, "scaling")); + ui_vp_effect->stretch = + ao_app->get_effect_property(fx_name, p_char, "stretch") + .startsWith("true"); ui_vp_effect->set_play_once( false); // The effects themselves dictate whether or not they're looping. // Static effects will linger. - ui_vp_effect->play(effect); // It will set_play_once to true if the filepath - // provided is not designed to loop more than once + ui_vp_effect->set_static_duration(0); + ui_vp_effect->set_max_duration(0); + ui_vp_effect->load_image(effect, false); } void Courtroom::play_char_sfx(QString sfx_name) @@ -2520,10 +2508,10 @@ void Courtroom::play_char_sfx(QString sfx_name) void Courtroom::initialize_chatbox() { int f_charid = m_chatmessage[CHAR_ID].toInt(); - if (f_charid >= 0 && + if (f_charid >= 0 && f_charid < char_list.size() && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { QString real_name = char_list.at(f_charid).name; - + ui_vp_player_char->set_static_duration(0); QString f_showname = ao_app->get_showname(real_name); ui_vp_showname->setText(f_showname); @@ -2555,23 +2543,28 @@ void Courtroom::initialize_chatbox() QString chatbox = ao_app->get_chat(customchar); if (chatbox != "" && ao_app->is_customchat_enabled()) { - chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat"; - if (!ui_vp_chatbox->set_chatbox(chatbox_path)) - ui_vp_chatbox->set_chatbox(chatbox_path + "box"); + chatbox_path = ao_app->get_theme_path("misc/" + chatbox + "/chat"); + if (!ui_vp_chatbox->set_chatbox(chatbox_path)) { + chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat"; + if (!ui_vp_chatbox->set_chatbox(chatbox_path)) + ui_vp_chatbox->set_chatbox(chatbox_path + "box"); + } } // This should probably be called only if any change from the last chat // arrow was actually detected. - pos_size_type design_ini_result = ao_app->get_element_dimensions( - "chat_arrow", "courtroom_design.ini", customchar); - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qDebug() << "W: could not find \"chat_arrow\" in courtroom_design.ini"; - ui_vp_chat_arrow->hide(); - } - else { - ui_vp_chat_arrow->move(design_ini_result.x, design_ini_result.y); - ui_vp_chat_arrow->combo_resize(design_ini_result.width, - design_ini_result.height); + if (current_misc != last_misc) { + pos_size_type design_ini_result = ao_app->get_element_dimensions( + "chat_arrow", "courtroom_design.ini", customchar); + if (design_ini_result.width < 0 || design_ini_result.height < 0) { + qDebug() << "W: could not find \"chat_arrow\" in courtroom_design.ini"; + ui_vp_chat_arrow->hide(); + } + else { + ui_vp_chat_arrow->move(design_ini_result.x + ui_vp_chatbox->x(), design_ini_result.y + ui_vp_chatbox->y()); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, + design_ini_result.height); + } } pos_size_type default_width = ao_app->get_element_dimensions( @@ -2679,39 +2672,41 @@ void Courtroom::handle_ic_speaking() if (emote_mod == 5 || emote_mod == 6) { // Hide the desks ui_vp_desk->hide(); - ui_vp_legacy_desk->hide(); // Obtain character information for our character - QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); + QString filename; // I still hate this hardcoding. If we're on pos pro, hlp and wit, use prosecution_speedlines. Otherwise, defense_speedlines. if (side == "pro" || side == "hlp" || side == "wit") - ui_vp_speedlines->play("prosecution_speedlines", f_char, f_custom_theme); + filename = "prosecution_speedlines"; else - ui_vp_speedlines->play("defense_speedlines", f_char, f_custom_theme); + filename = "defense_speedlines"; + ui_vp_speedlines->load_image(filename, m_chatmessage[CHAR_NAME]); } // Check if this is a talking color (white text, etc.) color_is_talking = color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); - + QString filename; // If color is talking, and our state isn't already talking if (color_is_talking && text_state == 1 && anim_state < 2) { // Stop the previous animation and play the talking animation ui_vp_player_char->stop(); - ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], - m_chatmessage[EMOTE]); + ui_vp_player_char->set_play_once(false); + filename = "(b)" + m_chatmessage[EMOTE]; + ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, false); // Set the anim state accordingly anim_state = 2; } - else if (anim_state < 3) + else if (anim_state < 3 && + anim_state != 3) // Set it to idle as we're not on that already { // Stop the previous animation and play the idle animation ui_vp_player_char->stop(); - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], - m_chatmessage[EMOTE]); + ui_vp_player_char->set_play_once(false); + filename = "(a)" + m_chatmessage[EMOTE]; + ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, false); // Set the anim state accordingly anim_state = 3; } @@ -2968,7 +2963,7 @@ void Courtroom::log_ic_text(QString p_name, QString p_showname, { 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()) + if (ao_app->get_auto_logging_enabled() && !ao_app->log_filename.isEmpty()) ao_app->append_to_file(log_entry.get_full(), ao_app->log_filename, true); while (ic_chatlog_history.size() > log_maximum_blocks && @@ -3110,7 +3105,6 @@ void Courtroom::play_preanim(bool immediate) { 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); @@ -3133,11 +3127,12 @@ void Courtroom::play_preanim(bool immediate) else anim_state = 1; preanim_done(); - qDebug() << "could not find " + anim_to_find; + qDebug() << "W: could not find " + anim_to_find; return; } - - ui_vp_player_char->play_pre(f_char, f_preanim, preanim_duration); + ui_vp_player_char->set_static_duration(preanim_duration); + ui_vp_player_char->set_play_once(true); + ui_vp_player_char->load_image(f_preanim, f_char, preanim_duration, true); if (immediate) anim_state = 4; @@ -3154,6 +3149,7 @@ void Courtroom::play_preanim(bool immediate) void Courtroom::preanim_done() { anim_state = 1; + qDebug() << "preanim over, anim_state set to 1"; handle_ic_speaking(); } @@ -3202,6 +3198,8 @@ void Courtroom::start_chat_ticking() ui_vp_chatbox->show(); ui_vp_message->show(); + ui_vp_sticker->load_image(m_chatmessage[CHAR_NAME]); + if (m_chatmessage[ADDITIVE] != "1") { ui_vp_message->clear(); real_tick_pos = 0; @@ -3225,6 +3223,8 @@ void Courtroom::start_chat_ticking() // means text is currently ticking text_state = 1; + + c_played = false; } void Courtroom::chat_tick() @@ -3236,13 +3236,30 @@ void Courtroom::chat_tick() // Due to our new text speed system, we always need to stop the timer now. chat_tick_timer->stop(); + ui_vp_player_char->set_static_duration(0); + QString filename; if (tick_pos >= f_message.size()) { text_state = 2; if (anim_state < 3) { - anim_state = 3; - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], - m_chatmessage[EMOTE]); + QStringList c_paths = { + ao_app->get_image_suffix(ao_app->get_character_path(m_chatmessage[CHAR_NAME], "(c)" + m_chatmessage[EMOTE])), + ao_app->get_image_suffix(ao_app->get_character_path(m_chatmessage[CHAR_NAME], "(c)/" + m_chatmessage[EMOTE])) + }; + // if there is a (c) animation for this emote and we haven't played it already + if (file_exists(ui_vp_player_char->find_image(c_paths)) &&(!c_played)) { + anim_state = 5; + ui_vp_player_char->set_play_once(true); + filename = "(c)" + m_chatmessage[EMOTE]; + c_played = true; + } + else { + anim_state = 3; + ui_vp_player_char->set_play_once(false); + filename = "(a)" + m_chatmessage[EMOTE]; + } + ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, + false); } QString f_char; QString f_custom_theme; @@ -3250,7 +3267,11 @@ void Courtroom::chat_tick() f_char = m_chatmessage[CHAR_NAME]; f_custom_theme = ao_app->get_chat(f_char); } - QString f_message_filtered = filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); + ui_vp_chat_arrow->load_image("chat_arrow",f_custom_theme); // Chat stopped being processed, indicate that. + additive_previous = + additive_previous + + filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); + QString f_message_filtered = filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); for (int c = 0; c < max_colors; ++c) { f_message_filtered = f_message_filtered.replace("$c" + QString::number(c), char_color_rgb_list.at(c).name(QColor::HexRgb)); } @@ -3446,16 +3467,20 @@ void Courtroom::chat_tick() // to avoid interrupting a non-interrupted preanim) { ui_vp_player_char->stop(); - ui_vp_player_char->play_talking(m_chatmessage[CHAR_NAME], - m_chatmessage[EMOTE]); + ui_vp_player_char->set_play_once(false); + filename = "(b)" + m_chatmessage[EMOTE]; + ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, + false); anim_state = 2; } else if (!color_is_talking && anim_state < 3 && anim_state != 3) // Set it to idle as we're not on that already { ui_vp_player_char->stop(); - ui_vp_player_char->play_idle(m_chatmessage[CHAR_NAME], - m_chatmessage[EMOTE]); + ui_vp_player_char->set_play_once(false); + filename = "(a)" + m_chatmessage[EMOTE]; + ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, + false); anim_state = 3; } // Continue ticking @@ -3540,19 +3565,15 @@ void Courtroom::set_scene(QString f_desk_mod, QString f_side) f_background = f_side; f_desk_image = f_side + "_overlay"; } - - ui_vp_background->set_image(f_background); - ui_vp_desk->set_image(f_desk_image); - ui_vp_legacy_desk->set_legacy_desk(f_desk_image); + ui_vp_background->load_image(f_background); + ui_vp_desk->load_image(f_desk_image); if (f_desk_mod == "0" || (f_desk_mod != "1" && (f_side == "jud" || f_side == "hld" || f_side == "hlp"))) { ui_vp_desk->hide(); - ui_vp_legacy_desk->hide(); } else { - ui_vp_legacy_desk->hide(); ui_vp_desk->show(); } } @@ -3700,31 +3721,40 @@ void Courtroom::handle_song(QStringList *p_contents) void Courtroom::handle_wtce(QString p_wtce, int variant) { QString sfx_file = "courtroom_sounds.ini"; - + QString sfx_name; + QString filename; + ui_vp_wtce->set_static_duration(wtce_static_time); + ui_vp_wtce->set_max_duration(wtce_max_time); // witness testimony if (p_wtce == "testimony1") { - sfx_player->play(ao_app->get_sfx("witness_testimony")); - ui_vp_wtce->play("witnesstestimony", "", "", 1500); - ui_vp_testimony->play("testimony"); + sfx_name = "witness_testimony"; + filename = "witnesstestimony"; + ui_vp_testimony->load_image("testimony", ""); } // cross examination else if (p_wtce == "testimony2") { - sfx_player->play(ao_app->get_sfx("cross_examination")); - ui_vp_wtce->play("crossexamination", "", "", 1500); + sfx_name = "cross_examination"; + filename = "crossexamination"; ui_vp_testimony->stop(); } else if (p_wtce == "judgeruling") { + ui_vp_wtce->set_static_duration(verdict_static_time); + ui_vp_wtce->set_max_duration(verdict_max_time); if (variant == 0) { - sfx_player->play(ao_app->get_sfx("not_guilty")); - ui_vp_wtce->play("notguilty", "", "", 3000); + sfx_name = "not_guilty"; + filename = "notguilty"; ui_vp_testimony->stop(); } else if (variant == 1) { - sfx_player->play(ao_app->get_sfx("guilty")); - ui_vp_wtce->play("guilty", "", "", 3000); + sfx_name = "guilty"; + filename = "guilty"; ui_vp_testimony->stop(); } } + QString bg_misc = ao_app->read_design_ini("misc", ao_app->get_background_path("design.ini")); + sfx_player->play(ao_app->get_sfx(sfx_name, bg_misc)); + ui_vp_wtce->load_image(filename, "", bg_misc); + ui_vp_wtce->set_play_once(true); } void Courtroom::set_hp_bar(int p_bar, int p_state) @@ -3795,9 +3825,6 @@ void Courtroom::on_ooc_return_pressed() { QString ooc_message = ui_ooc_chat_message->text(); - if (ooc_message == "" || ui_ooc_chat_name->text() == "") - return; - if (ooc_message.startsWith("/pos")) { if (ooc_message == "/pos jud") { toggle_judge_buttons(true); @@ -4322,28 +4349,28 @@ void Courtroom::set_sfx_dropdown() ui_sfx_remove->hide(); return; } - QStringList soundlist = ao_app->get_list_file( + // Initialzie character sound list first. Will be empty if not found. + sound_list = ao_app->get_list_file( ao_app->get_character_path(current_char, "soundlist.ini")); - if (soundlist.size() <= 0) { - soundlist = ao_app->get_list_file( - ao_app->get_theme_path("character_soundlist.ini")); - if (soundlist.size() <= 0) { - soundlist = ao_app->get_list_file( - ao_app->get_default_theme_path("character_soundlist.ini")); - } - } + // Append default sound list after the character sound list. + sound_list += ao_app->get_list_file( + ao_app->get_base_path() + "soundlist.ini"); - if (soundlist.size() <= 0) { - ui_sfx_dropdown->hide(); - ui_sfx_remove->hide(); - return; + QStringList display_sounds; + for (QString sound : sound_list) { + QStringList unpacked = sound.split("="); + QString display = unpacked[0].trimmed(); + if (unpacked.size() > 1) + display = unpacked[1].trimmed(); + + display_sounds.append(display); } - soundlist.prepend("Nothing"); - soundlist.prepend("Default"); + display_sounds.prepend("Nothing"); + display_sounds.prepend("Default"); ui_sfx_dropdown->show(); - ui_sfx_dropdown->addItems(soundlist); + ui_sfx_dropdown->addItems(display_sounds); ui_sfx_dropdown->setCurrentIndex(0); ui_sfx_remove->hide(); ui_sfx_dropdown->blockSignals(false); @@ -4351,37 +4378,16 @@ void Courtroom::set_sfx_dropdown() void Courtroom::on_sfx_dropdown_changed(int p_index) { + UNUSED(p_index); ui_ic_chat_message->setFocus(); + ui_sfx_remove->hide(); + custom_sfx = ""; +} - QStringList soundlist; - for (int i = 2; i < ui_sfx_dropdown->count(); ++i) { - QString entry = ui_sfx_dropdown->itemText(i); - if (!soundlist.contains(entry)) - soundlist.append(entry); - } - - QStringList defaultlist = - ao_app->get_list_file(ao_app->get_theme_path("character_soundlist.ini")); - if (defaultlist.size() <= 0) { - defaultlist = ao_app->get_list_file( - ao_app->get_default_theme_path("character_soundlist.ini")); - } - - if (defaultlist.size() > 0 && - defaultlist.toSet().subtract(soundlist.toSet()).size() > - 0) // There's a difference from the default configuration - ao_app->write_to_file( - soundlist.join("\n"), - ao_app->get_character_path(current_char, - "soundlist.ini")); // Create a new sound list - - ui_sfx_dropdown->blockSignals(true); - ui_sfx_dropdown->setCurrentIndex(p_index); - ui_sfx_dropdown->blockSignals(false); - if (p_index > 1) - ui_sfx_remove->show(); - else - ui_sfx_remove->hide(); +void Courtroom::on_sfx_dropdown_custom(QString p_sfx) +{ + ui_sfx_remove->show(); + custom_sfx = p_sfx; } void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) @@ -4394,40 +4400,27 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) menu->addAction(QString("Edit " + current_char + "/soundlist.ini"), this, SLOT(on_sfx_edit_requested())); else - menu->addAction(QString("Edit theme's character_soundlist.ini"), this, + menu->addAction(QString("Edit global soundlist.ini"), this, SLOT(on_sfx_edit_requested())); - if (ui_sfx_dropdown->currentIndex() > 1) - menu->addAction(QString("Remove " + ui_sfx_dropdown->itemText( - ui_sfx_dropdown->currentIndex())), - this, SLOT(on_sfx_remove_clicked())); + if (!custom_sfx.isEmpty()) + menu->addAction(QString("Clear Edit Text"), this, SLOT(on_sfx_remove_clicked())); menu->popup(ui_sfx_dropdown->mapToGlobal(pos)); } + void Courtroom::on_sfx_edit_requested() { QString p_path = ao_app->get_character_path(current_char, "soundlist.ini"); if (!file_exists(p_path)) { - p_path = ao_app->get_theme_path("character_soundlist.ini"); - if (!file_exists(p_path)) { - p_path = ao_app->get_default_theme_path("character_soundlist.ini"); - if (!file_exists(p_path)) { - return; - } + p_path = ao_app->get_base_path() + "soundlist.ini"; } - } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } void Courtroom::on_sfx_remove_clicked() { - if (ui_sfx_dropdown->count() <= 0) { - ui_sfx_remove->hide(); // We're not supposed to see it. Do this or the - // client will crash - return; - } - if (ui_sfx_dropdown->currentIndex() > 1) { - ui_sfx_dropdown->removeItem(ui_sfx_dropdown->currentIndex()); - on_sfx_dropdown_changed(0); // Reset back to original - } + ui_sfx_remove->hide(); + ui_sfx_dropdown->setCurrentIndex(0); + custom_sfx = ""; } void Courtroom::set_effects_dropdown() @@ -4530,19 +4523,21 @@ bool Courtroom::effects_dropdown_find_and_set(QString effect) QString Courtroom::get_char_sfx() { - QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); - if (sfx == "Nothing") - return "1"; - if (sfx != "" && sfx != "Default") - return sfx; - return ao_app->get_sfx_name(current_char, current_emote); + if (!custom_sfx.isEmpty()) + return custom_sfx; + int index = ui_sfx_dropdown->currentIndex(); + if (index == 0) // Default + return ao_app->get_sfx_name(current_char, current_emote); + if (index == 1) // Nothing + return "1"; + QString sfx = sound_list[index-2].split("=")[0].trimmed(); + if (sfx == "") + return "1"; + return sfx; } int Courtroom::get_char_sfx_delay() { - // QString sfx = ui_sfx_dropdown->itemText(ui_sfx_dropdown->currentIndex()); - // if (sfx != "" && sfx != "Default") - // return 0; //todo: a way to define this return ao_app->get_sfx_delay(current_char, current_emote); } @@ -4745,12 +4740,12 @@ void Courtroom::music_stop() void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) { column = 0; // The metadata + UNUSED(column); // so gcc shuts up QString p_area = p_item->text(0); QStringList packet_contents; packet_contents.append(p_area); packet_contents.append(QString::number(m_cid)); - qDebug() << packet_contents; ao_app->send_server_packet(new AOPacket("MC", packet_contents), false); } @@ -4982,18 +4977,18 @@ void Courtroom::set_text_color_dropdown() 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( + color_markdown_start_list.append(ao_app->get_chat_markup( "c" + QString::number(c) + "_start", current_char)); - color_markdown_end_list.append(ao_app->get_chat_markdown( + color_markdown_end_list.append(ao_app->get_chat_markup( "c" + QString::number(c) + "_end", current_char)); color_markdown_remove_list.append( - ao_app->get_chat_markdown("c" + QString::number(c) + "_remove", - current_char) == "1"); + ao_app->get_chat_markup("c" + QString::number(c) + "_remove", + current_char) == "1"); color_markdown_talking_list.append( - ao_app->get_chat_markdown("c" + QString::number(c) + "_talking", - current_char) != "0"); + ao_app->get_chat_markup("c" + QString::number(c) + "_talking", + current_char) != "0"); - QString color_name = ao_app->get_chat_markdown( + QString color_name = ao_app->get_chat_markup( "c" + QString::number(c) + "_name", current_char); if (color_name.isEmpty()) // Not defined { @@ -5244,12 +5239,16 @@ void Courtroom::on_showname_enable_clicked() void Courtroom::regenerate_ic_chatlog() { ui_ic_chatlog->clear(); + last_ic_message = ""; foreach (chatlogpiece item, ic_chatlog_history) { - append_ic_text(item.get_message(), - ui_showname_enable->isChecked() ? item.get_showname() - : item.get_name(), + QString message = item.get_message(); + QString name = ui_showname_enable->isChecked() ? item.get_showname() + : item.get_name(); + append_ic_text(message, + name, item.get_action(), item.get_chat_color(), item.get_datetime().toLocalTime()); + last_ic_message = name + ":" + message; } } diff --git a/src/demoserver.cpp b/src/demoserver.cpp new file mode 100644 index 0000000..fcb5003 --- /dev/null +++ b/src/demoserver.cpp @@ -0,0 +1,304 @@ +#include "demoserver.h" +#include "lobby.h" + +DemoServer::DemoServer(QObject *parent) : QObject(parent) +{ + timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setSingleShot(true); + + tcp_server = new QTcpServer(this); + connect(tcp_server, &QTcpServer::newConnection, this, &DemoServer::accept_connection); + connect(timer, &QTimer::timeout, this, &DemoServer::playback); +} + +void DemoServer::start_server() +{ + if (server_started) return; + if (!tcp_server->listen(QHostAddress::LocalHost, 0)) { + qCritical() << "Could not start demo playback server..."; + qDebug() << tcp_server->errorString(); + return; + } + this->port = tcp_server->serverPort(); + qDebug() << "Server started"; + server_started = true; +} + +void DemoServer::destroy_connection() +{ + QTcpSocket* temp_socket = tcp_server->nextPendingConnection(); + connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); + temp_socket->disconnectFromHost(); + return; +} + +void DemoServer::accept_connection() +{ + QString path = QFileDialog::getOpenFileName(nullptr, tr("Load Demo"), "logs/", tr("Demo Files (*.demo)")); + if (path.isEmpty()) + { + destroy_connection(); + return; + } + load_demo(path); + + if (demo_data.isEmpty()) + { + destroy_connection(); + return; + } + + if (demo_data.head().startsWith("SC#")) + { + sc_packet = demo_data.dequeue(); + AOPacket sc(sc_packet); + num_chars = sc.get_contents().length(); + } + else + { + sc_packet = "SC#%"; + num_chars = 0; + } + + if (client_sock) { + // Client is already connected... + qDebug() << "Multiple connections to demo server disallowed."; + QTcpSocket* temp_socket = tcp_server->nextPendingConnection(); + connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); + temp_socket->disconnectFromHost(); + return; + } + client_sock = tcp_server->nextPendingConnection(); + connect(client_sock, &QAbstractSocket::disconnected, this, &DemoServer::client_disconnect); + connect(client_sock, &QAbstractSocket::readyRead, this, &DemoServer::recv_data); + client_sock->write("decryptor#NOENCRYPT#%"); +} + +void DemoServer::recv_data() +{ + QString in_data = QString::fromUtf8(client_sock->readAll()); + + // Copypasted from NetworkManager + if (!in_data.endsWith("%")) { + partial_packet = true; + temp_packet += in_data; + return; + } + + else { + if (partial_packet) { + in_data = temp_packet + in_data; + temp_packet = ""; + partial_packet = false; + } + } + + QStringList packet_list = + in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + + for (QString packet : packet_list) { + AOPacket ao_packet(packet); + handle_packet(ao_packet); + } +} + +void DemoServer::handle_packet(AOPacket packet) +{ + packet.net_decode(); + + // This code is literally a barebones AO server + // It is wise to do it this way, because I can + // avoid touching any of this disgusting shit + // related to hardcoding this stuff in. + + // Also, at some point, I will make akashit + // into a shared library. + + QString header = packet.get_header(); + QStringList contents = packet.get_contents(); + + if (header == "HI") { + client_sock->write("ID#0#DEMOINTERNAL#0#%"); + } + else if (header == "ID") { + QStringList feature_list = { + "noencryption", "yellowtext", "prezoom", + "flipping", "customobjections", "fastloading", + "deskmod", "evidence", "cccc_ic_support", + "arup", "casing_alerts", "modcall_reason", + "looping_sfx", "additive", "effects", + "y_offset", "expanded_desk_mods"}; + client_sock->write("PN#0#1#%"); + client_sock->write("FL#"); + client_sock->write(feature_list.join('#').toUtf8()); + client_sock->write("#%"); + } + else if (header == "askchaa") { + client_sock->write("SI#"); + client_sock->write(QString::number(num_chars).toUtf8()); + client_sock->write("#0#1#%"); + } + else if (header == "RC") { + client_sock->write(sc_packet.toUtf8()); + } + else if (header == "RM") { + client_sock->write("SM#%"); + } + else if (header == "RD") { + client_sock->write("DONE#%"); + } + else if (header == "CC") { + client_sock->write("PV#0#CID#-1#%"); + client_sock->write("CT#DEMO#Demo file loaded. Send /play or > in OOC to begin playback.#1#%"); + } + else if (header == "CT") { + if (contents[1].startsWith("/load")) + { + QString path = QFileDialog::getOpenFileName(nullptr, tr("Load Demo"), "logs/", tr("Demo Files (*.demo)")); + if (path.isEmpty()) + return; + load_demo(path); + client_sock->write("CT#DEMO#Demo file loaded. Send /play or > in OOC to begin playback.#1#%"); + } + else if (contents[1].startsWith("/play") || contents[1] == ">") + { + if (timer->interval() != 0 && !timer->isActive()) + { + timer->start(); + client_sock->write("CT#DEMO#Resuming playback.#1#%"); + } + else + { + if (demo_data.isEmpty() && p_path != "") + load_demo(p_path); + playback(); + } + } + else if (contents[1].startsWith("/pause") || contents[1] == "|") + { + int timeleft = timer->remainingTime(); + timer->stop(); + timer->setInterval(timeleft); + client_sock->write("CT#DEMO#Pausing playback.#1#%"); + } + else if (contents[1].startsWith("/max_wait")) + { + QStringList args = contents[1].split(" "); + if (args.size() > 1) + { + bool ok; + int p_max_wait = args.at(1).toInt(&ok); + if (ok) + { + if (p_max_wait < 0) + p_max_wait = -1; + max_wait = p_max_wait; + client_sock->write("CT#DEMO#Setting max_wait to "); + client_sock->write(QString::number(max_wait).toUtf8()); + client_sock->write(" milliseconds.#1#%"); + } + else + { + client_sock->write("CT#DEMO#Not a valid integer!#1#%"); + } + } + else + { + client_sock->write("CT#DEMO#Current max_wait is "); + client_sock->write(QString::number(max_wait).toUtf8()); + client_sock->write(" milliseconds.#1#%"); + } + } + else if (contents[1].startsWith("/min_wait")) + { + QStringList args = contents[1].split(" "); + if (args.size() > 1) + { + bool ok; + int p_min_wait = args.at(1).toInt(&ok); + if (ok) + { + if (p_min_wait < 0) + p_min_wait = -1; + min_wait = p_min_wait; + client_sock->write("CT#DEMO#Setting min_wait to "); + client_sock->write(QString::number(min_wait).toUtf8()); + client_sock->write(" milliseconds.#1#%"); + } + else + { + client_sock->write("CT#DEMO#Not a valid integer!#1#%"); + } + } + else + { + client_sock->write("CT#DEMO#Current min_wait is "); + client_sock->write(QString::number(min_wait).toUtf8()); + client_sock->write(" milliseconds.#1#%"); + } + } + else if (contents[1].startsWith("/help")) + { + client_sock->write("CT#DEMO#Available commands:\nload, play, pause, max_wait, min_wait, help#1#%"); + } + } +} + +void DemoServer::load_demo(QString filename) +{ + QFile demo_file(filename); + demo_file.open(QIODevice::ReadOnly); + if (!demo_file.isOpen()) + return; + demo_data.clear(); + p_path = filename; + QTextStream demo_stream(&demo_file); + QString line = demo_stream.readLine(); + while (!line.isNull()) { + if (!line.endsWith("%")) { + line += "\n"; + } + demo_data.enqueue(line); + line = demo_stream.readLine(); + } +} + +void DemoServer::playback() +{ + if (demo_data.isEmpty()) + return; + + QString current_packet = demo_data.dequeue(); + // We reset the elapsed time with this packet + if (current_packet.startsWith("MS#")) + elapsed_time = 0; + + while (!current_packet.startsWith("wait") && !demo_data.isEmpty()) { + client_sock->write(current_packet.toUtf8()); + current_packet = demo_data.dequeue(); + } + if (!demo_data.isEmpty()) { + AOPacket wait_packet = AOPacket(current_packet); + + int duration = wait_packet.get_contents().at(0).toInt(); + if (max_wait != -1 && duration + elapsed_time > max_wait) + duration = qMax(0, max_wait - elapsed_time); + // We use elapsed_time to make sure that the packet we're using min_wait on is "priority" (e.g. IC) + if (elapsed_time == 0 && min_wait != -1 && duration < min_wait) + duration = min_wait; + elapsed_time += duration; + timer->start(duration); + } + else + { + client_sock->write("CT#DEMO#Reached the end of the demo file. Send /play or > in OOC to restart, or /load to open a new file.#1#%"); + timer->setInterval(0); + } +} + +void DemoServer::client_disconnect() +{ + client_sock->deleteLater(); + client_sock = nullptr; +} diff --git a/src/lobby.cpp b/src/lobby.cpp index 954c30a..4528dc7 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -3,6 +3,7 @@ #include "aoapplication.h" #include "aosfxplayer.h" #include "debug_functions.h" +#include "demoserver.h" #include "networkmanager.h" #include @@ -28,6 +29,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() ui_server_list = new QTreeWidget(this); ui_server_list->setHeaderLabels({"#", "Name"}); //, "Players"}); ui_server_list->hideColumn(0); + ui_server_list->setHeaderHidden(true); ui_server_search = new QLineEdit(this); ui_server_search->setFrame(false); @@ -438,7 +440,15 @@ void Lobby::on_server_list_clicked(QTreeWidgetItem *p_item, int column) ui_connect->setEnabled(false); - ao_app->net_manager->connect_to_server(f_server); + if (f_server.port == 99999 && f_server.ip == "127.0.0.1") { + // Demo playback server selected + ao_app->demo_server->start_server(); + server_type demo_server; + demo_server.ip = "127.0.0.1"; + demo_server.port = ao_app->demo_server->port; + ao_app->net_manager->connect_to_server(demo_server); + } + else ao_app->net_manager->connect_to_server(f_server); } } diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index cf89d0a..5e29e21 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -131,7 +131,7 @@ void NetworkManager::on_srv_lookup() qDebug() << "Connecting to " << record.target() << ":" << record.port(); #endif ms_socket->connectToHost(record.target(), record.port()); - QTime timer; + QElapsedTimer timer; timer.start(); do { ao_app->processEvents(); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 6865987..2da6981 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -102,6 +102,19 @@ end: delete p_packet; } +void AOApplication::append_to_demofile(QString packet_string) +{ + if (get_auto_logging_enabled() && !log_filename.isEmpty()) + { + QString path = log_filename.left(log_filename.size()).replace(".log", ".demo"); + append_to_file(packet_string, path, true); + if (!demo_timer.isValid()) + demo_timer.start(); + else + append_to_file("wait#"+ QString::number(demo_timer.restart()) + "#%", path, true); + } +} + void AOApplication::server_packet_received(AOPacket *p_packet) { p_packet->net_decode(); @@ -164,6 +177,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) else w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); + + append_to_demofile(p_packet->to_string(true)); } } else if (header == "FL") { @@ -232,7 +247,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) evidence_list_size = f_contents.at(1).toInt(); music_list_size = f_contents.at(2).toInt(); - if (char_list_size < 1 || evidence_list_size < 0 || music_list_size < 0) + if (char_list_size < 0 || evidence_list_size < 0 || music_list_size < 0) goto end; loaded_chars = 0; @@ -255,7 +270,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) server_name = info.name; server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); - qDebug() << server_address; window_title += ": " + server_name; } } @@ -265,7 +279,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) server_name = info.name; server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); - qDebug() << server_address; window_title += ": " + server_name; } } @@ -283,7 +296,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() && server_name != "Demo playback") { this->log_filename = QDateTime::currentDateTime().toUTC().toString( "'logs/" + server_name.remove(QRegExp("[\\\\/:*?\"<>|\']")) + "/'yyyy-MM-dd hh-mm-ss t'.log'"); @@ -292,6 +305,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) QDateTime::currentDateTime().toUTC().toString(), log_filename, true); } + else + this->log_filename = ""; QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); hash.addData(server_address.toUtf8()); @@ -312,7 +327,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } else if (header == "SC") { - if (!courtroom_constructed) + if (!courtroom_constructed || courtroom_loaded) goto end; for (int n_element = 0; n_element < f_contents.size(); ++n_element) { @@ -344,9 +359,10 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } send_server_packet(new AOPacket("RM#%")); + append_to_demofile(p_packet->to_string(true)); } else if (header == "SM") { - if (!courtroom_constructed) + if (!courtroom_constructed || courtroom_loaded) goto end; bool musics_time = false; @@ -445,6 +461,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) 2) // We have a pos included in the background packet! w_courtroom->set_side(f_contents.at(1)); w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2); + append_to_demofile(p_packet->to_string(true)); } } else if (header == "SP") { @@ -454,6 +471,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (courtroom_constructed) // We were sent a "set position" packet { w_courtroom->set_side(f_contents.at(0)); + append_to_demofile(p_packet->to_string(true)); } } else if (header == "SD") // Send pos dropdown @@ -475,27 +493,37 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } else if (header == "MS") { if (courtroom_constructed && courtroom_loaded) + { w_courtroom->chatmessage_enqueue(p_packet->get_contents()); + append_to_demofile(p_packet->to_string(true)); + } } else if (header == "MC") { if (courtroom_constructed && courtroom_loaded) + { w_courtroom->handle_song(&p_packet->get_contents()); + append_to_demofile(p_packet->to_string(true)); + } } else if (header == "RT") { if (f_contents.size() < 1) goto end; if (courtroom_constructed) { - if (f_contents.size() == 1) - w_courtroom->handle_wtce(f_contents.at(0), 0); - else if (f_contents.size() == 2) { - w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + if (f_contents.size() == 1) + w_courtroom->handle_wtce(f_contents.at(0), 0); + else if (f_contents.size() == 2) { + w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + append_to_demofile(p_packet->to_string(true)); } } } else if (header == "HP") { if (courtroom_constructed && f_contents.size() > 1) + { w_courtroom->set_hp_bar(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + append_to_demofile(p_packet->to_string(true)); + } } else if (header == "LE") { if (courtroom_constructed) { diff --git a/src/path_functions.cpp b/src/path_functions.cpp index c6c73a8..728f5a4 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -65,6 +65,16 @@ QString AOApplication::get_character_path(QString p_char, QString p_file) return get_case_sensitive_path(path); } +QString AOApplication::get_misc_path(QString p_misc, QString p_file) +{ + QString path = get_base_path() + "misc/" + p_misc + "/" + p_file; +#ifndef CASE_SENSITIVE_FILESYSTEM + return path; +#else + return get_case_sensitive_path(path); +#endif +} + QString AOApplication::get_sounds_path(QString p_file) { QString path = get_base_path() + "sounds/general/" + p_file; diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 1ea27bf..0128f56 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -52,6 +52,12 @@ int AOApplication::stay_time() return result; } +int AOApplication::get_chat_ratelimit() +{ + int result = configini->value("chat_ratelimit", 300).toInt(); + return result; +} + bool AOApplication::get_log_goes_downwards() { QString result = @@ -61,8 +67,7 @@ bool AOApplication::get_log_goes_downwards() bool AOApplication::get_log_newline() { - QString result = - configini->value("log_newline", "false").value(); + QString result = configini->value("log_newline", "false").value(); return result.startsWith("true"); } @@ -74,8 +79,7 @@ int AOApplication::get_log_margin() bool AOApplication::get_log_timestamp() { - QString result = - configini->value("log_timestamp", "false").value(); + QString result = configini->value("log_timestamp", "false").value(); return result.startsWith("true"); } @@ -178,6 +182,10 @@ bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir) bool AOApplication::append_to_file(QString p_text, QString p_file, bool make_dir) { + if(!file_exists(p_file)) //Don't create a newline if file didn't exist before now + { + return write_to_file(p_text, p_file, make_dir); + } QString path = QFileInfo(p_file).path(); // Create the dir if it doesn't exist yet if (make_dir) { @@ -249,6 +257,13 @@ QVector AOApplication::read_serverlist_txt() f_server_list.append(f_server); } + server_type demo_server; + demo_server.ip = "127.0.0.1"; + demo_server.port = 99999; + demo_server.name = "Demo playback"; + demo_server.desc = "Play back demos you have previously recorded"; + f_server_list.append(demo_server); + return f_server_list; } @@ -265,6 +280,13 @@ QString AOApplication::read_design_ini(QString p_identifier, } } +Qt::TransformationMode AOApplication::get_scaling(QString p_scaling) +{ + if (p_scaling == "smooth") + return Qt::SmoothTransformation; + return Qt::FastTransformation; +} + QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file) { QString design_ini_path = get_theme_path(p_file); @@ -298,28 +320,12 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QString p_file, QString p_char) { - QString char_ini_path = - get_base_path() + "misc/" + get_chat(p_char) + "/" + p_file; - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, char_ini_path); - pos_size_type return_value; - return_value.x = 0; return_value.y = 0; return_value.width = -1; return_value.height = -1; - - if (f_result == "") { - f_result = read_design_ini(p_identifier, design_ini_path); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return return_value; - } - } + QString f_result = get_design_element(p_identifier, p_file, p_char); QStringList sub_line_elements = f_result.split(","); @@ -336,17 +342,16 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QString AOApplication::get_design_element(QString p_identifier, QString p_file, QString p_char) { - QString char_ini_path = - get_base_path() + "misc/" + get_chat(p_char) + "/" + p_file; - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, char_ini_path); - if (f_result == "") { - f_result = read_design_ini(p_identifier, design_ini_path); - if (f_result == "") - f_result = read_design_ini(p_identifier, default_path); + QStringList paths{get_theme_path("misc/" + get_chat(p_char) + "/" + + p_file), // user theme overrides base/misc + get_base_path() + "misc/" + get_chat(p_char) + "/" + p_file, + get_theme_path(p_file), get_default_theme_path(p_file)}; + for (const QString &path : paths) { + QString value = read_design_ini(p_identifier, path); + if (!value.isEmpty()) + return value; } - return f_result; + return ""; } QString AOApplication::get_font_name(QString p_identifier, QString p_file) { @@ -466,34 +471,30 @@ QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) return f_text; } -QString AOApplication::get_chat_markdown(QString p_identifier, QString p_chat) +QString AOApplication::get_chat_markup(QString p_identifier, QString p_chat) { - 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); + QStringList paths{get_theme_path("misc/" + get_chat(p_chat) + "/config.ini"), + get_base_path() + "misc/" + get_chat(p_chat) + + "/config.ini", + get_base_path() + "misc/default/config.ini", + get_theme_path("misc/default/config.ini")}; - if (f_result == "") - f_result = read_design_ini(p_identifier, default_path); + for (const QString &path : paths) { + QString value = read_design_ini(p_identifier, path); + if (!value.isEmpty()) { + return value.toLatin1(); + } + } - return f_result.toLatin1(); + return ""; } 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/" + 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); - - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return return_color; - } + QString f_result = get_chat_markup(p_identifier, p_chat); + if (f_result == "") + return return_color; QStringList color_list = f_result.split(","); @@ -507,23 +508,21 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) return return_color; } -QString AOApplication::get_sfx(QString p_identifier) +QString AOApplication::get_sfx(QString p_identifier, QString p_misc) { - QString design_ini_path = get_theme_path("courtroom_sounds.ini"); - QString default_path = get_default_theme_path("courtroom_sounds.ini"); - QString f_result = read_design_ini(p_identifier, design_ini_path); + QStringList paths{get_theme_path("misc/" + p_misc + "/courtroom_sounds.ini"), + get_misc_path(p_misc, "courtroom_sounds.ini"), + get_theme_path("courtroom_sounds.ini"), + get_default_theme_path("courtroom_sounds.ini")}; QString return_sfx = ""; - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return return_sfx; + for (const QString &path : paths) { + QString value = read_design_ini(p_identifier, path); + if (!value.isEmpty()) { + return value.toLatin1(); + } } - - return_sfx = f_result; - return return_sfx; } @@ -650,6 +649,37 @@ QString AOApplication::get_blips(QString p_char) return f_result; } +QString AOApplication::get_emote_property(QString p_char, QString p_emote, + QString p_property) +{ + QString f_result = + read_char_ini(p_char, p_emote, p_property); // per-emote override + if (f_result == "") + f_result = read_char_ini(p_char, p_property, + "Options"); // global for this character + return f_result; +} + +Qt::TransformationMode AOApplication::get_misc_scaling(QString p_miscname) +{ + if (p_miscname != "") { + QString misc_transform_mode = read_design_ini( + "scaling", get_theme_path("misc/" + p_miscname + "/config.ini")); + if (misc_transform_mode == "") + misc_transform_mode = + read_design_ini("scaling", get_misc_path(p_miscname, "config.ini")); + if (misc_transform_mode == "smooth") + return Qt::SmoothTransformation; + } + return Qt::FastTransformation; +} + +QString AOApplication::get_category(QString p_char) +{ + QString f_result = read_char_ini(p_char, "category", "Options"); + return f_result; +} + QString AOApplication::get_chat(QString p_char) { if (p_char == "default") @@ -881,7 +911,7 @@ QStringList AOApplication::get_theme_effects() QStringList lines = read_file(p_path).split("\n"); foreach (QString effect, lines) { - effect = effect.split("=")[0].trimmed(); + effect = effect.split("=")[0].trimmed().split("_")[0]; if (!effect.isEmpty() && !effects.contains(effect)) effects.append(effect); } @@ -899,7 +929,7 @@ QStringList AOApplication::get_effects(QString p_char) QStringList lines = read_file(p_path).split("\n"); foreach (QString effect, lines) { - effect = effect.split("=")[0].trimmed(); + effect = effect.split("=")[0].trimmed().split("_")[0]; if (!effect.isEmpty() && !effects.contains(effect)) effects.append(effect); } @@ -934,25 +964,33 @@ QString AOApplication::get_effect(QString effect, QString p_char, return p_path; } -QString AOApplication::get_effect_sound(QString fx_name, QString p_char) +QString AOApplication::get_effect_property(QString fx_name, QString p_char, + QString p_property) { + QString f_property; + if (p_property == "sound") + f_property = fx_name; + else + f_property = fx_name + "_" + p_property; QString p_effect = read_char_ini(p_char, "effects", "Options"); QString p_path = get_base_path() + "misc/" + p_effect + "/effects.ini"; QString design_ini_path = get_theme_path("effects/effects.ini"); QString default_path = get_default_theme_path("effects/effects.ini"); - QString f_result = read_design_ini(fx_name, p_path); + QString f_result = read_design_ini(f_property, p_path); if (f_result == "") { - f_result = read_design_ini(fx_name, design_ini_path); + f_result = read_design_ini(f_property, design_ini_path); if (f_result == "") { - f_result = read_design_ini(fx_name, default_path); + f_result = read_design_ini(f_property, default_path); } } - if (fx_name == "realization") { + if (fx_name == "realization" && p_property == "sound") { f_result = get_custom_realization(p_char); } + qDebug() << "got" << f_property << "of" << fx_name << "==" << f_result; + return f_result; }