14 #include "variables.h" |
14 #include "variables.h" |
15 #include "table/sprites.h" |
15 #include "table/sprites.h" |
16 #include <stdarg.h> /* va_list */ |
16 #include <stdarg.h> /* va_list */ |
17 #include "date.h" |
17 #include "date.h" |
18 |
18 |
|
19 enum { |
|
20 MAX_TEXTMESSAGE_LENGTH = 150, |
|
21 MAX_TEXT_MESSAGES = 30, |
|
22 MAX_CHAT_MESSAGES = 10, |
|
23 MAX_ANIMATED_TILES = 256, |
|
24 }; |
|
25 |
19 typedef struct TextEffect { |
26 typedef struct TextEffect { |
20 StringID string_id; |
27 StringID string_id; |
21 int32 x; |
28 int32 x; |
22 int32 y; |
29 int32 y; |
23 int32 right; |
30 int32 right; |
25 uint16 duration; |
32 uint16 duration; |
26 uint32 params_1; |
33 uint32 params_1; |
27 uint32 params_2; |
34 uint32 params_2; |
28 } TextEffect; |
35 } TextEffect; |
29 |
36 |
30 #define MAX_TEXTMESSAGE_LENGTH 150 |
|
31 |
37 |
32 typedef struct TextMessage { |
38 typedef struct TextMessage { |
33 char message[MAX_TEXTMESSAGE_LENGTH]; |
39 char message[MAX_TEXTMESSAGE_LENGTH]; |
34 uint16 color; |
40 uint16 color; |
35 Date end_date; |
41 Date end_date; |
36 } TextMessage; |
42 } TextMessage; |
37 |
43 |
38 #define MAX_CHAT_MESSAGES 10 |
44 static TextEffect _text_effect_list[MAX_TEXT_MESSAGES]; |
39 static TextEffect _text_effect_list[30]; |
|
40 static TextMessage _textmsg_list[MAX_CHAT_MESSAGES]; |
45 static TextMessage _textmsg_list[MAX_CHAT_MESSAGES]; |
41 TileIndex _animated_tile_list[256]; |
46 TileIndex _animated_tile_list[MAX_ANIMATED_TILES]; |
42 |
47 |
43 static bool _textmessage_dirty = false; |
48 static bool _textmessage_dirty = false; |
44 static bool _textmessage_visible = false; |
49 static bool _textmessage_visible = false; |
45 |
50 |
46 /* The chatbox grows from the bottom so the coordinates are pixels from |
51 /* The chatbox grows from the bottom so the coordinates are pixels from |
111 for (i = 0; i < MAX_CHAT_MESSAGES; i++) { |
116 for (i = 0; i < MAX_CHAT_MESSAGES; i++) { |
112 _textmsg_list[i].message[0] = '\0'; |
117 _textmsg_list[i].message[0] = '\0'; |
113 } |
118 } |
114 } |
119 } |
115 |
120 |
116 // Hide the textbox |
121 /* Hide the textbox */ |
117 void UndrawTextMessage(void) |
122 void UndrawTextMessage(void) |
118 { |
123 { |
119 if (_textmessage_visible) { |
124 if (_textmessage_visible) { |
120 // Sometimes we also need to hide the cursor |
125 /* Sometimes we also need to hide the cursor |
121 // This is because both textmessage and the cursor take a shot of the |
126 * This is because both textmessage and the cursor take a shot of the |
122 // screen before drawing. |
127 * screen before drawing. |
123 // Now the textmessage takes his shot and paints his data before the cursor |
128 * Now the textmessage takes his shot and paints his data before the cursor |
124 // does, so in the shot of the cursor is the screen-data of the textmessage |
129 * does, so in the shot of the cursor is the screen-data of the textmessage |
125 // included when the cursor hangs somewhere over the textmessage. To |
130 * included when the cursor hangs somewhere over the textmessage. To |
126 // avoid wrong repaints, we undraw the cursor in that case, and everything |
131 * avoid wrong repaints, we undraw the cursor in that case, and everything |
127 // looks nicely ;) |
132 * looks nicely ;) |
128 // (and now hope this story above makes sense to you ;)) |
133 * (and now hope this story above makes sense to you ;)) |
|
134 */ |
129 |
135 |
130 if (_cursor.visible) { |
136 if (_cursor.visible) { |
131 if (_cursor.draw_pos.x + _cursor.draw_size.x >= _textmsg_box.x && |
137 if (_cursor.draw_pos.x + _cursor.draw_size.x >= _textmsg_box.x && |
132 _cursor.draw_pos.x <= _textmsg_box.x + _textmsg_box.width && |
138 _cursor.draw_pos.x <= _textmsg_box.x + _textmsg_box.width && |
133 _cursor.draw_pos.y + _cursor.draw_size.y >= _screen.height - _textmsg_box.y - _textmsg_box.height && |
139 _cursor.draw_pos.y + _cursor.draw_size.y >= _screen.height - _textmsg_box.y - _textmsg_box.height && |
135 UndrawMouseCursor(); |
141 UndrawMouseCursor(); |
136 } |
142 } |
137 } |
143 } |
138 |
144 |
139 _textmessage_visible = false; |
145 _textmessage_visible = false; |
140 // Put our 'shot' back to the screen |
146 /* Put our 'shot' back to the screen */ |
141 memcpy_pitch( |
147 memcpy_pitch( |
142 _screen.dst_ptr + _textmsg_box.x + (_screen.height - _textmsg_box.y - _textmsg_box.height) * _screen.pitch, |
148 _screen.dst_ptr + _textmsg_box.x + (_screen.height - _textmsg_box.y - _textmsg_box.height) * _screen.pitch, |
143 _textmessage_backup, |
149 _textmessage_backup, |
144 _textmsg_box.width, _textmsg_box.height, _textmsg_box.width, _screen.pitch); |
150 _textmsg_box.width, _textmsg_box.height, _textmsg_box.width, _screen.pitch); |
145 |
151 |
146 // And make sure it is updated next time |
152 /* And make sure it is updated next time */ |
147 _video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height); |
153 _video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height); |
148 |
154 |
149 _textmessage_dirty = true; |
155 _textmessage_dirty = true; |
150 } |
156 } |
151 } |
157 } |
152 |
158 |
153 // Check if a message is expired every day |
159 /* Check if a message is expired every day */ |
154 void TextMessageDailyLoop(void) |
160 void TextMessageDailyLoop(void) |
155 { |
161 { |
156 uint i; |
162 uint i; |
157 |
163 |
158 for (i = 0; i < MAX_CHAT_MESSAGES; i++) { |
164 for (i = 0; i < MAX_CHAT_MESSAGES; i++) { |
172 i--; |
178 i--; |
173 } |
179 } |
174 } |
180 } |
175 } |
181 } |
176 |
182 |
177 // Draw the textmessage-box |
183 /* Draw the textmessage-box */ |
178 void DrawTextMessage(void) |
184 void DrawTextMessage(void) |
179 { |
185 { |
180 uint y, count; |
186 uint y, count; |
181 |
187 |
182 if (!_textmessage_dirty) return; |
188 if (!_textmessage_dirty) return; |
183 |
189 |
184 // First undraw if needed |
190 /* First undraw if needed */ |
185 UndrawTextMessage(); |
191 UndrawTextMessage(); |
186 |
192 |
187 if (_iconsole_mode == ICONSOLE_FULL) return; |
193 if (_iconsole_mode == ICONSOLE_FULL) return; |
188 |
194 |
189 /* Check if we have anything to draw at all */ |
195 /* Check if we have anything to draw at all */ |
190 count = GetTextMessageCount(); |
196 count = GetTextMessageCount(); |
191 if (count == 0) return; |
197 if (count == 0) return; |
192 |
198 |
193 // Make a copy of the screen as it is before painting (for undraw) |
199 /* Make a copy of the screen as it is before painting (for undraw) */ |
194 memcpy_pitch( |
200 memcpy_pitch( |
195 _textmessage_backup, |
201 _textmessage_backup, |
196 _screen.dst_ptr + _textmsg_box.x + (_screen.height - _textmsg_box.y - _textmsg_box.height) * _screen.pitch, |
202 _screen.dst_ptr + _textmsg_box.x + (_screen.height - _textmsg_box.y - _textmsg_box.height) * _screen.pitch, |
197 _textmsg_box.width, _textmsg_box.height, _screen.pitch, _textmsg_box.width); |
203 _textmsg_box.width, _textmsg_box.height, _screen.pitch, _textmsg_box.width); |
198 |
204 |
210 /* Paint the messages starting with the lowest at the bottom */ |
216 /* Paint the messages starting with the lowest at the bottom */ |
211 for (y = 13; count-- != 0; y += 13) { |
217 for (y = 13; count-- != 0; y += 13) { |
212 DoDrawString(_textmsg_list[count].message, _textmsg_box.x + 3, _screen.height - _textmsg_box.y - y + 1, _textmsg_list[count].color); |
218 DoDrawString(_textmsg_list[count].message, _textmsg_box.x + 3, _screen.height - _textmsg_box.y - y + 1, _textmsg_list[count].color); |
213 } |
219 } |
214 |
220 |
215 // Make sure the data is updated next flush |
221 /* Make sure the data is updated next flush */ |
216 _video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height); |
222 _video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height); |
217 |
223 |
218 _textmessage_visible = true; |
224 _textmessage_visible = true; |
219 _textmessage_dirty = false; |
225 _textmessage_dirty = false; |
220 } |
226 } |
317 } |
323 } |
318 } |
324 } |
319 |
325 |
320 void DeleteAnimatedTile(TileIndex tile) |
326 void DeleteAnimatedTile(TileIndex tile) |
321 { |
327 { |
322 TileIndex* ti; |
328 TileIndex *ti; |
323 |
329 |
324 for (ti = _animated_tile_list; ti != endof(_animated_tile_list); ti++) { |
330 for (ti = _animated_tile_list; ti != endof(_animated_tile_list); ti++) { |
325 if (tile == *ti) { |
331 if (tile == *ti) { |
326 /* remove the hole */ |
332 /* remove the hole */ |
327 memmove(ti, ti + 1, endof(_animated_tile_list) - 1 - ti); |
333 memmove(ti, ti + 1, (lastof(_animated_tile_list) - ti) * sizeof(*ti)); |
328 /* and clear last item */ |
334 /* and clear last item */ |
329 endof(_animated_tile_list)[-1] = 0; |
335 *lastof(_animated_tile_list) = 0; |
330 MarkTileDirtyByTile(tile); |
336 MarkTileDirtyByTile(tile); |
331 return; |
337 return; |
332 } |
338 } |
333 } |
339 } |
334 } |
340 } |
335 |
341 |
336 bool AddAnimatedTile(TileIndex tile) |
342 bool AddAnimatedTile(TileIndex tile) |
337 { |
343 { |
338 TileIndex* ti; |
344 TileIndex *ti; |
339 |
345 |
340 for (ti = _animated_tile_list; ti != endof(_animated_tile_list); ti++) { |
346 for (ti = _animated_tile_list; ti != endof(_animated_tile_list); ti++) { |
341 if (tile == *ti || *ti == 0) { |
347 if (tile == *ti || *ti == 0) { |
342 *ti = tile; |
348 *ti = tile; |
343 MarkTileDirtyByTile(tile); |
349 MarkTileDirtyByTile(tile); |
362 memset(_animated_tile_list, 0, sizeof(_animated_tile_list)); |
368 memset(_animated_tile_list, 0, sizeof(_animated_tile_list)); |
363 } |
369 } |
364 |
370 |
365 static void SaveLoad_ANIT(void) |
371 static void SaveLoad_ANIT(void) |
366 { |
372 { |
367 // In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) |
373 /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ |
368 if (CheckSavegameVersion(6)) { |
374 if (CheckSavegameVersion(6)) { |
369 SlArray(_animated_tile_list, lengthof(_animated_tile_list), SLE_FILE_U16 | SLE_VAR_U32); |
375 SlArray(_animated_tile_list, lengthof(_animated_tile_list), SLE_FILE_U16 | SLE_VAR_U32); |
370 } else { |
376 } else { |
371 SlArray(_animated_tile_list, lengthof(_animated_tile_list), SLE_UINT32); |
377 SlArray(_animated_tile_list, lengthof(_animated_tile_list), SLE_UINT32); |
372 } |
378 } |