texteff.c
changeset 4957 8588d2e7f409
parent 4956 76db5a2689fc
child 4958 aaa8a92059bf
equal deleted inserted replaced
4956:76db5a2689fc 4957:8588d2e7f409
     1 /* $Id$ */
     1 /* $Id$ */
     2 
     2 
     3 #include "stdafx.h"
     3 #include "stdafx.h"
     4 #include "openttd.h"
     4 #include "openttd.h"
     5 #include "functions.h"
     5 #include "functions.h"
       
     6 #include "macros.h"
     6 #include "strings.h"
     7 #include "strings.h"
     7 #include "gfx.h"
     8 #include "gfx.h"
     8 #include "viewport.h"
     9 #include "viewport.h"
     9 #include "saveload.h"
    10 #include "saveload.h"
    10 #include "hal.h"
    11 #include "hal.h"
    24 	uint16 duration;
    25 	uint16 duration;
    25 	uint32 params_1;
    26 	uint32 params_1;
    26 	uint32 params_2;
    27 	uint32 params_2;
    27 } TextEffect;
    28 } TextEffect;
    28 
    29 
    29 #define MAX_TEXTMESSAGE_LENGTH 250
    30 #define MAX_TEXTMESSAGE_LENGTH 150
    30 
    31 
    31 typedef struct TextMessage {
    32 typedef struct TextMessage {
    32 	char message[MAX_TEXTMESSAGE_LENGTH];
    33 	char message[MAX_TEXTMESSAGE_LENGTH];
    33 	uint16 color;
    34 	uint16 color;
    34 	Date end_date;
    35 	Date end_date;
    42 static bool _textmessage_dirty = false;
    43 static bool _textmessage_dirty = false;
    43 static bool _textmessage_visible = false;
    44 static bool _textmessage_visible = false;
    44 
    45 
    45 /* The chatbox grows from the bottom so the coordinates are pixels from
    46 /* The chatbox grows from the bottom so the coordinates are pixels from
    46  * the left and pixels from the bottom. The height is the maximum height */
    47  * the left and pixels from the bottom. The height is the maximum height */
    47 static const Oblong _textmsg_box = {10, 30, 400, 150};
    48 static const Oblong _textmsg_box = {10, 30, 500, 150};
    48 static Pixel _textmessage_backup[150 * 400]; // (height * width)
    49 static Pixel _textmessage_backup[150 * 500]; // (height * width)
    49 
    50 
    50 extern void memcpy_pitch(void *d, void *s, int w, int h, int spitch, int dpitch);
    51 extern void memcpy_pitch(void *d, void *s, int w, int h, int spitch, int dpitch);
    51 
    52 
    52 // Duration is in game-days
    53 static inline uint GetTextMessageCount(void)
       
    54 {
       
    55 	uint i = 0;
       
    56 
       
    57 	for (i; i < MAX_CHAT_MESSAGES; i++) {
       
    58 		if (_textmsg_list[i].message[0] == '\0') break;
       
    59 	}
       
    60 
       
    61 	return i;
       
    62 }
       
    63 
       
    64 /* Add a text message to the 'chat window' to be shown
       
    65  * @param color The colour this message is to be shown in
       
    66  * @param duration The duration of the chat message in game-days
       
    67  * @param message message itself in printf() style */
    53 void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...)
    68 void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...)
    54 {
    69 {
    55 	char buf[MAX_TEXTMESSAGE_LENGTH];
    70 	char buf[MAX_TEXTMESSAGE_LENGTH];
       
    71 	const char *bufp;
    56 	va_list va;
    72 	va_list va;
    57 	size_t length;
    73 	uint msg_count;
    58 	uint i;
    74 	uint16 lines;
    59 
    75 
    60 	va_start(va, message);
    76 	va_start(va, message);
    61 	vsnprintf(buf, lengthof(buf), message, va);
    77 	vsnprintf(buf, lengthof(buf), message, va);
    62 	va_end(va);
    78 	va_end(va);
    63 
    79 
    64 	/* Special color magic */
    80 	/* Force linebreaks for strings that are too long */
    65 	if ((color & 0xFF) == 0xC9) color = 0x1CA;
    81 	lines = GB(FormatStringLinebreaks(buf, _textmsg_box.width - 8), 0, 16) + 1;
    66 
    82 	if (lines >= MAX_CHAT_MESSAGES) return;
    67 	/* Cut the message till it fits inside the chatbox */
    83 
    68 	length = strlen(buf);
    84 	msg_count = GetTextMessageCount();
    69 	while (GetStringBoundingBox(buf).width > _textmsg_box.width - 9) buf[--length] = '\0';
    85 	/* We want to add more chat messages than there is free space for, remove 'old' */
    70 
    86 	if (lines > MAX_CHAT_MESSAGES - msg_count) {
    71 	/* Find an empty spot and put the message there */
    87 		int i = lines - (MAX_CHAT_MESSAGES - msg_count);
    72 	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
    88 		memmove(&_textmsg_list[0], &_textmsg_list[i], sizeof(_textmsg_list[0]) * (msg_count - i));
    73 		if (_textmsg_list[i].message[0] == '\0') {
    89 		msg_count = MAX_CHAT_MESSAGES - lines;
    74 			// Empty spot
    90 	}
    75 			ttd_strlcpy(_textmsg_list[i].message, buf, sizeof(_textmsg_list[i].message));
    91 
    76 			_textmsg_list[i].color = color;
    92 	for (bufp = buf; lines != 0; lines--) {
    77 			_textmsg_list[i].end_date = _date + duration;
    93 		TextMessage *tmsg = &_textmsg_list[msg_count++];
    78 
    94 		ttd_strlcpy(tmsg->message, bufp, sizeof(tmsg->message));
    79 			_textmessage_dirty = true;
    95 
    80 			return;
    96 		/* The default colour for a message is player colour. Replace this with
    81 		}
    97 		 * white for any additional lines */
    82 	}
    98 		tmsg->color = (bufp == buf && color & IS_PALETTE_COLOR) ? color : (0x1D - 15) | IS_PALETTE_COLOR;
    83 
    99 		tmsg->end_date = _date + duration;
    84 	// We did not found a free spot, trash the first one, and add to the end
   100 
    85 	memmove(&_textmsg_list[0], &_textmsg_list[1], sizeof(_textmsg_list[0]) * (MAX_CHAT_MESSAGES - 1));
   101 		bufp += strlen(bufp) + 1; // jump to 'next line' in the formatted string
    86 	ttd_strlcpy(_textmsg_list[MAX_CHAT_MESSAGES - 1].message, buf, sizeof(_textmsg_list[MAX_CHAT_MESSAGES - 1].message));
   102 	}
    87 	_textmsg_list[MAX_CHAT_MESSAGES - 1].color = color;
       
    88 	_textmsg_list[MAX_CHAT_MESSAGES - 1].end_date = _date + duration;
       
    89 
   103 
    90 	_textmessage_dirty = true;
   104 	_textmessage_dirty = true;
    91 }
   105 }
    92 
   106 
    93 void InitTextMessage(void)
   107 void InitTextMessage(void)
   140 void TextMessageDailyLoop(void)
   154 void TextMessageDailyLoop(void)
   141 {
   155 {
   142 	uint i;
   156 	uint i;
   143 
   157 
   144 	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
   158 	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
   145 		if (_textmsg_list[i].message[0] == '\0') continue;
   159 		TextMessage *tmsg = &_textmsg_list[i];
   146 
   160 		if (tmsg->message[0] == '\0') continue;
   147 		if (_date > _textmsg_list[i].end_date) {
   161 
       
   162 		/* Message has expired, remove from the list */
       
   163 		if (tmsg->end_date < _date) {
   148 			/* Move the remaining messages over the current message */
   164 			/* Move the remaining messages over the current message */
   149 			if (i != MAX_CHAT_MESSAGES - 1)
   165 			if (i != MAX_CHAT_MESSAGES - 1) memmove(tmsg, tmsg + 1, sizeof(*tmsg) * (MAX_CHAT_MESSAGES - i - 1));
   150 				memmove(&_textmsg_list[i], &_textmsg_list[i + 1], sizeof(_textmsg_list[i]) * (MAX_CHAT_MESSAGES - i - 1));
       
   151 
   166 
   152 			/* Mark the last item as empty */
   167 			/* Mark the last item as empty */
   153 			_textmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0';
   168 			_textmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0';
   154 			_textmessage_dirty = true;
   169 			_textmessage_dirty = true;
   155 
   170 
   197 		if (_textmsg_list[i].message[0] == '\0') continue;
   212 		if (_textmsg_list[i].message[0] == '\0') continue;
   198 
   213 
   199 		j++;
   214 		j++;
   200 		GfxFillRect(_textmsg_box.x, _screen.height-_textmsg_box.y-j*13-2, _textmsg_box.x+_textmsg_box.width - 1, _screen.height-_textmsg_box.y-j*13+10, /* black, but with some alpha */ 0x322 | USE_COLORTABLE);
   215 		GfxFillRect(_textmsg_box.x, _screen.height-_textmsg_box.y-j*13-2, _textmsg_box.x+_textmsg_box.width - 1, _screen.height-_textmsg_box.y-j*13+10, /* black, but with some alpha */ 0x322 | USE_COLORTABLE);
   201 
   216 
   202 		DoDrawString(_textmsg_list[i].message, _textmsg_box.x + 2, _screen.height - _textmsg_box.y - j * 13 - 1, 0x10);
       
   203 		DoDrawString(_textmsg_list[i].message, _textmsg_box.x + 3, _screen.height - _textmsg_box.y - j * 13, _textmsg_list[i].color);
   217 		DoDrawString(_textmsg_list[i].message, _textmsg_box.x + 3, _screen.height - _textmsg_box.y - j * 13, _textmsg_list[i].color);
   204 	}
   218 	}
   205 
   219 
   206 	// Make sure the data is updated next flush
   220 	// Make sure the data is updated next flush
   207 	_video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height);
   221 	_video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height);