Index: src/functions.h =================================================================== --- src/functions.h (revision 9263) +++ src/functions.h (working copy) @@ -114,7 +114,7 @@ void InitTextMessage(); void DrawTextMessage(); -void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...); +void CDECL AddTextMessage(uint16 color, const char *message, ...); void UndrawTextMessage(); bool AddAnimatedTile(TileIndex tile); Index: src/lang/english.txt =================================================================== --- src/lang/english.txt (revision 9263) +++ src/lang/english.txt (working copy) @@ -1090,6 +1090,12 @@ STR_CONFIG_PATCHES_LIVERIES_OWN :Own company STR_CONFIG_PATCHES_LIVERIES_ALL :All companies STR_CONFIG_PATCHES_PREFER_TEAMCHAT :{LTBLUE}Prefer team chat with : {ORANGE}{STRING1} +STR_CONFIG_PATCHES_CHAT_TEXT_VISIBLE :{LTBLUE}Chat text stays visible at least {ORANGE}{STRING1}{LTBLUE} seconds +STR_CONFIG_PATCHES_CHAT_TEXT_SHADOW :{LTBLUE}Chat text shadowing: {ORANGE}{STRING1}{LTBLUE} +STR_CONFIG_PATCHES_CHAT_TEXT_SHADOW_NONE :none +STR_CONFIG_PATCHES_CHAT_TEXT_SHADOW_LINE :individual lines +STR_CONFIG_PATCHES_CHAT_TEXT_SHADOW_WINDOW :full window (default) + STR_CONFIG_PATCHES_SCROLLWHEEL_SCROLLING :{LTBLUE}Function of scrollwheel: {ORANGE}{STRING1} STR_CONFIG_PATCHES_SCROLLWHEEL_ZOOM :Zoom map STR_CONFIG_PATCHES_SCROLLWHEEL_SCROLL :Scroll map Index: src/network/network.cpp =================================================================== --- src/network/network.cpp (revision 9263) +++ src/network/network.cpp (working copy) @@ -136,7 +136,6 @@ { char buf[1024]; va_list va; - const int duration = 10; // Game days the messages stay visible char message[1024]; char temp[1024]; @@ -196,7 +195,7 @@ } IConsolePrintF(color, "%s", message); - AddTextMessage(color, duration, "%s", message); + AddTextMessage(color, "%s", message); } // Calculate the frame-lag of a client Index: src/settings.cpp =================================================================== --- src/settings.cpp (revision 9263) +++ src/settings.cpp (working copy) @@ -1283,6 +1283,8 @@ SDT_BOOL(Patches, link_terraform_toolbar, S, 0, false, STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR,NULL), SDT_VAR(Patches, liveries, SLE_UINT8, S,MS, 2, 0, 2, 0, STR_CONFIG_PATCHES_LIVERIES, RedrawScreen), SDT_BOOL(Patches, prefer_teamchat, S, 0, false, STR_CONFIG_PATCHES_PREFER_TEAMCHAT, NULL), + SDT_VAR(Patches, chat_text_visible, SLE_UINT16,S,NC, 60,10,900,10, STR_CONFIG_PATCHES_CHAT_TEXT_VISIBLE, NULL), + SDT_VAR(Patches, chat_text_shadow, SLE_UINT8, S,MS, 2, 0, 2, 1, STR_CONFIG_PATCHES_CHAT_TEXT_SHADOW, NULL), SDT_VAR(Patches, scrollwheel_scrolling,SLE_UINT8,S,MS, 0, 0, 2, 0, STR_CONFIG_PATCHES_SCROLLWHEEL_SCROLLING, NULL), SDT_VAR(Patches,scrollwheel_multiplier,SLE_UINT8,S, 0, 5, 1, 15, 1, STR_CONFIG_PATCHES_SCROLLWHEEL_MULTIPLIER,NULL), Index: src/settings_gui.cpp =================================================================== --- src/settings_gui.cpp (revision 9263) +++ src/settings_gui.cpp (working copy) @@ -576,6 +576,8 @@ "link_terraform_toolbar", "liveries", "prefer_teamchat", + "chat_text_visible", + "chat_text_shadow", /* While the horizontal scrollwheel scrolling is written as general code, only * the cocoa (OSX) driver generates input for it. * Since it's also able to completely disable the scrollwheel will we display it on all platforms anyway */ Index: src/texteff.cpp =================================================================== --- src/texteff.cpp (revision 9263) +++ src/texteff.cpp (working copy) @@ -15,11 +15,13 @@ #include "table/sprites.h" #include /* va_list */ #include "date.h" +#include enum { - MAX_TEXTMESSAGE_LENGTH = 200, - MAX_TEXT_MESSAGES = 30, - MAX_CHAT_MESSAGES = 10, + MAX_TEXTMESSAGE_LENGTH = 256, ///< maximum text message length in bytes + MAX_TEXT_MESSAGES = 24, ///< adjusted _text and _chat values to keep more messages on the screen, and to keep + MAX_CHAT_MESSAGES = 24, ///< text within the limits of _textmsg_box below. _chat doesn't need to be less than _text + MAX_CHATMESSAGE_HEIGHT = 13, ///< height between lines of text for the chat message display, including padding MAX_ANIMATED_TILES = 256, }; @@ -34,11 +36,11 @@ uint32 params_2; }; - +/* Storage for the on-screen text display */ struct TextMessage { - char message[MAX_TEXTMESSAGE_LENGTH]; - uint16 color; - Date end_date; + char message[MAX_TEXTMESSAGE_LENGTH]; ///< message to be displayed + uint16 color; ///< text color + time_t time_stamp; ///< timestamp of when message was created, in real-seconds since 1/1/1970 }; static TextEffect _text_effect_list[MAX_TEXT_MESSAGES]; @@ -49,9 +51,10 @@ static bool _textmessage_visible = false; /* The chatbox grows from the bottom so the coordinates are pixels from - * the left and pixels from the bottom. The height is the maximum height */ -static const Oblong _textmsg_box = {10, 30, 500, 150}; -static Pixel _textmessage_backup[150 * 500]; // (height * width) + * the left and pixels from the bottom. The height is the maximum height + */ +static const Oblong _textmsg_box = {10, 30, 512, (MAX_CHAT_MESSAGES * MAX_CHATMESSAGE_HEIGHT)}; // height adjusted to allow for 24 lines of allowed text in MAX_TEXT_MESSAGES +static Pixel _textmessage_backup[(MAX_CHAT_MESSAGES * MAX_CHATMESSAGE_HEIGHT) * 512]; // (height * width) extern void memcpy_pitch(void *dst, void *src, int w, int h, int srcpitch, int dstpitch); @@ -68,9 +71,9 @@ /* Add a text message to the 'chat window' to be shown * @param color The colour this message is to be shown in - * @param duration The duration of the chat message in game-days - * @param message message itself in printf() style */ -void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...) + * @param message message itself in printf() style + */ +void CDECL AddTextMessage(uint16 color, const char *message, ...) { char buf[MAX_TEXTMESSAGE_LENGTH]; const char *bufp; @@ -82,7 +85,6 @@ vsnprintf(buf, lengthof(buf), message, va); va_end(va); - Utf8TrimString(buf, MAX_TEXTMESSAGE_LENGTH); /* Force linebreaks for strings that are too long */ @@ -104,8 +106,7 @@ /* The default colour for a message is player colour. Replace this with * white for any additional lines */ tmsg->color = (bufp == buf && color & IS_PALETTE_COLOR) ? color : (0x1D - 15) | IS_PALETTE_COLOR; - tmsg->end_date = _date + duration; - + time(&tmsg->time_stamp); // Current real time in seconds. Daily loop compares this against current time minus _patch.text_stays_visible bufp += strlen(bufp) + 1; // jump to 'next line' in the formatted string } @@ -159,46 +160,44 @@ } } -/* Check if a message is expired every day */ +/* Check if a chat message is expired every day */ void TextMessageDailyLoop() { - uint i; + time_t tstamp; + time(&tstamp); + tstamp = tstamp - _patches.chat_text_visible; // adjust tstamp for comparing against tmsg->time_stamp - for (i = 0; i < MAX_CHAT_MESSAGES; i++) { - TextMessage *tmsg = &_textmsg_list[i]; - if (tmsg->message[0] == '\0') continue; + TextMessage *tmsg = &_textmsg_list[0]; + while (tmsg->message[0] != '\0' && tmsg->time_stamp < tstamp) { // if message exists, and it is older than tstamp, expire it - /* Message has expired, remove from the list */ - if (tmsg->end_date < _date) { - /* Move the remaining messages over the current message */ - if (i != MAX_CHAT_MESSAGES - 1) memmove(tmsg, tmsg + 1, sizeof(*tmsg) * (MAX_CHAT_MESSAGES - i - 1)); + /* Move the remaining messages over the current message */ + memmove(tmsg, tmsg + 1, sizeof(*tmsg) * (MAX_CHAT_MESSAGES - 1)); - /* Mark the last item as empty */ - _textmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0'; - _textmessage_dirty = true; - - /* Go one item back, because we moved the array 1 to the left */ - i--; - } + /* Mark the last item as empty */ + _textmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0'; + _textmessage_dirty = true; } } -/* Draw the textmessage-box */ +/* Draw the (chat)textmessage-box */ void DrawTextMessage() { - uint y, count; - if (!_textmessage_dirty) return; /* First undraw if needed */ UndrawTextMessage(); - if (_iconsole_mode == ICONSOLE_FULL) return; /* Check if we have anything to draw at all */ - count = GetTextMessageCount(); + uint count = GetTextMessageCount(); if (count == 0) return; + enum { ///< text shadowing + CS_NONE, ///< 0 = none + CS_LINE, ///< 1 = individual lines + CS_WINDOW, ///< 2 = whole window (default setting) + }; + /* Make a copy of the screen as it is before painting (for undraw) */ memcpy_pitch( _textmessage_backup, @@ -207,18 +206,35 @@ _cur_dpi = &_screen; // switch to _screen painting - /* Paint a half-transparent box behind the text messages */ - GfxFillRect( - _textmsg_box.x, - _screen.height - _textmsg_box.y - count * 13 - 2, - _textmsg_box.x + _textmsg_box.width - 1, - _screen.height - _textmsg_box.y - 2, - PALETTE_TO_TRANSPARENT | (1 << USE_COLORTABLE) // black, but with some alpha for background + /* Paint the messages from bottom to top. + * Lowest numbered 'count' is the oldest, and prints at the top. + * Highest numbered 'count' is the most recent, and prints at the bottom. + * Since 'count' is not consistent enough between cycles to use for line position, we print the lines + * based on line position, reducing 'count' for each line until 'count' is 0 + * We could make it cleaner here, but that would mean making it messier for the other functions that + * manipulate the strings. + */ + for (uint y = 1; count-- != 0; y++) { + + int16 length = GetStringBoundingBox(_textmsg_list[count].message).width; ///< length is the pixel-length of the current line of text being dealt with + + /* Paint a half-transparent box behind the individual text messages */ + if (_patches.chat_text_shadow != CS_NONE) { // if shadow is set to none, no need to run this function + GfxFillRect( + _textmsg_box.x, + _screen.height - _textmsg_box.y - (y * MAX_CHATMESSAGE_HEIGHT), + _textmsg_box.x + (_patches.chat_text_shadow != CS_LINE ? _textmsg_box.width - 1 : length + 5), // if shadow is not set to line, then default behavior + _screen.height - _textmsg_box.y - (y * MAX_CHATMESSAGE_HEIGHT) + (MAX_CHATMESSAGE_HEIGHT - 1), + PALETTE_TO_TRANSPARENT | (1 << USE_COLORTABLE) // black, but with some alpha for background + ); + } + /* Output the line of text to the chat window area */ + DoDrawString( + _textmsg_list[count].message, + _textmsg_box.x + 3, // 3 is enough offset to center the text in the shaded box + _screen.height - _textmsg_box.y - (y * MAX_CHATMESSAGE_HEIGHT) + 2, // 2 is enough offset to center the text in the shaded box + _textmsg_list[count].color ); - - /* Paint the messages starting with the lowest at the bottom */ - for (y = 13; count-- != 0; y += 13) { - DoDrawString(_textmsg_list[count].message, _textmsg_box.x + 3, _screen.height - _textmsg_box.y - y + 1, _textmsg_list[count].color); } /* Make sure the data is updated next flush */ Index: src/variables.h =================================================================== --- src/variables.h (revision 9263) +++ src/variables.h (working copy) @@ -129,6 +129,8 @@ bool measure_tooltip; // Show a permanent tooltip when dragging tools byte liveries; // Options for displaying company liveries, 0=none, 1=self, 2=all bool prefer_teamchat; // Choose the chat message target with , true=all players, false=your team + uint16 chat_text_visible; // Chat text stays visible minimum (real-time seconds) + uint8 chat_text_shadow; // Chat text shadowing style (0=none, 1=line, 2=window) uint8 toolbar_pos; // position of toolbars, 0=left, 1=center, 2=right uint8 window_snap_radius; // Windows snap at each other if closer than this