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); |