branch | NewGRF_ports |
changeset 10184 | fcf5fb2548eb |
parent 6872 | 1c4a4a609f85 |
child 10210 | a2131f7a315d |
10179:eec5a7dcbf61 | 10184:fcf5fb2548eb |
---|---|
4 #include "stdafx.h" |
4 #include "stdafx.h" |
5 #include "openttd.h" |
5 #include "openttd.h" |
6 #include "gui.h" |
6 #include "gui.h" |
7 #include "window_gui.h" |
7 #include "window_gui.h" |
8 #include "viewport_func.h" |
8 #include "viewport_func.h" |
9 #include "news.h" |
9 #include "news_func.h" |
10 #include "settings_type.h" |
10 #include "settings_type.h" |
11 #include "transparency.h" |
11 #include "transparency.h" |
12 #include "strings_func.h" |
12 #include "strings_func.h" |
13 #include "window_func.h" |
13 #include "window_func.h" |
14 #include "date_func.h" |
14 #include "date_func.h" |
58 static NewsItem _news_items[MAX_NEWS]; ///< The news FIFO queue |
58 static NewsItem _news_items[MAX_NEWS]; ///< The news FIFO queue |
59 static NewsID _current_news = INVALID_NEWS; ///< points to news item that should be shown next |
59 static NewsID _current_news = INVALID_NEWS; ///< points to news item that should be shown next |
60 static NewsID _oldest_news = 0; ///< points to first item in fifo queue |
60 static NewsID _oldest_news = 0; ///< points to first item in fifo queue |
61 static NewsID _latest_news = INVALID_NEWS; ///< points to last item in fifo queue |
61 static NewsID _latest_news = INVALID_NEWS; ///< points to last item in fifo queue |
62 |
62 |
63 struct news_d { |
|
64 uint16 follow_vehicle; |
|
65 int32 scrollpos_x; |
|
66 int32 scrollpos_y; |
|
67 int32 dest_scrollpos_x; |
|
68 int32 dest_scrollpos_y; |
|
69 NewsItem *ni; |
|
70 }; |
|
71 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(news_d)); |
|
72 |
|
63 /** Forced news item. |
73 /** Forced news item. |
64 * Users can force an item by accessing the history or "last message". |
74 * Users can force an item by accessing the history or "last message". |
65 * If the message being shown was forced by the user, its index is stored in |
75 * If the message being shown was forced by the user, its index is stored in |
66 * _forced_news. Otherwise, \a _forced_news variable is INVALID_NEWS. */ |
76 * _forced_news. Otherwise, \a _forced_news variable is INVALID_NEWS. */ |
67 static NewsID _forced_news = INVALID_NEWS; |
77 static NewsID _forced_news = INVALID_NEWS; |
68 |
78 |
69 static byte _total_news = 0; ///< Number of news items in FIFO queue @see _news_items |
79 static byte _total_news = 0; ///< Number of news items in FIFO queue @see _news_items |
70 |
80 |
71 void DrawNewsNewVehicleAvail(Window *w); |
81 void DrawNewsNewVehicleAvail(Window *w, const NewsItem *ni); |
72 void DrawNewsBankrupcy(Window *w); |
82 void DrawNewsBankrupcy(Window *w, const NewsItem *ni); |
73 static void MoveToNextItem(); |
83 static void MoveToNextItem(); |
74 |
84 |
75 StringID GetNewsStringNewVehicleAvail(const NewsItem *ni); |
85 StringID GetNewsStringNewVehicleAvail(const NewsItem *ni); |
76 StringID GetNewsStringBankrupcy(const NewsItem *ni); |
86 StringID GetNewsStringBankrupcy(const NewsItem *ni); |
77 |
87 |
115 } |
125 } |
116 |
126 |
117 static void NewsWindowProc(Window *w, WindowEvent *e) |
127 static void NewsWindowProc(Window *w, WindowEvent *e) |
118 { |
128 { |
119 switch (e->event) { |
129 switch (e->event) { |
120 case WE_CREATE: { // If chatbar is open at creation time, we need to go above it |
130 case WE_CREATE: { // If chatbar is open at creation time, we need to go above it |
121 const Window *w1 = FindWindowById(WC_SEND_NETWORK_MSG, 0); |
131 const Window *w1 = FindWindowById(WC_SEND_NETWORK_MSG, 0); |
122 w->message.msg = (w1 != NULL) ? w1->height : 0; |
132 w->message.msg = (w1 != NULL) ? w1->height : 0; |
123 } break; |
133 } break; |
124 |
134 |
125 case WE_PAINT: { |
135 case WE_PAINT: { |
126 const NewsItem *ni = WP(w, news_d).ni; |
136 const NewsItem *ni = WP(w, news_d).ni; |
127 ViewPort *vp; |
137 |
128 |
138 switch (ni->display_mode) { |
129 switch (ni->display_mode) { |
139 case NM_NORMAL: |
130 case NM_NORMAL: |
140 case NM_THIN: { |
131 case NM_THIN: { |
141 DrawNewsBorder(w); |
132 DrawNewsBorder(w); |
142 |
133 |
143 DrawString(2, 1, STR_00C6, TC_FROMSTRING); |
134 DrawString(2, 1, STR_00C6, TC_FROMSTRING); |
144 |
135 |
145 SetDParam(0, ni->date); |
136 SetDParam(0, ni->date); |
146 DrawStringRightAligned(428, 1, STR_01FF, TC_FROMSTRING); |
137 DrawStringRightAligned(428, 1, STR_01FF, TC_FROMSTRING); |
147 |
138 |
148 if (!(ni->flags & NF_VIEWPORT)) { |
139 if (!(ni->flags & NF_VIEWPORT)) { |
149 CopyInDParam(0, ni->params, lengthof(ni->params)); |
140 CopyInDParam(0, ni->params, lengthof(ni->params)); |
150 DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56, |
141 DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56, |
151 ni->string_id, w->width - 4); |
142 ni->string_id, w->width - 4); |
152 } else { |
143 } else { |
153 /* Back up transparency options to draw news view */ |
144 /* Back up transparency options to draw news view */ |
154 TransparencyOptionBits to_backup = _transparency_opt; |
145 TransparencyOptionBits to_backup = _transparency_opt; |
155 _transparency_opt = 0; |
146 _transparency_opt = 0; |
156 DrawWindowViewport(w); |
147 DrawWindowViewport(w); |
157 _transparency_opt = to_backup; |
148 _transparency_opt = to_backup; |
158 |
149 |
159 /* Shade the viewport into gray, or color*/ |
150 /* Shade the viewport into gray, or color*/ |
160 ViewPort *vp = w->viewport; |
151 vp = w->viewport; |
161 GfxFillRect(vp->left - w->left, vp->top - w->top, |
152 GfxFillRect(vp->left - w->left, vp->top - w->top, |
162 vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1, |
153 vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1, |
163 (ni->flags & NF_INCOLOR ? PALETTE_TO_TRANSPARENT : PALETTE_TO_STRUCT_GREY) | (1 << USE_COLORTABLE) |
154 (ni->flags & NF_INCOLOR ? PALETTE_TO_TRANSPARENT : PALETTE_TO_STRUCT_GREY) | (1 << USE_COLORTABLE) |
164 ); |
155 ); |
165 |
156 |
166 CopyInDParam(0, ni->params, lengthof(ni->params)); |
157 CopyInDParam(0, ni->params, lengthof(ni->params)); |
167 DrawStringMultiCenter(w->width / 2, 20, ni->string_id, w->width - 4); |
158 DrawStringMultiCenter(w->width / 2, 20, ni->string_id, w->width - 4); |
168 } |
169 break; |
|
159 } |
170 } |
160 break; |
171 |
161 } |
172 case NM_CALLBACK: |
162 |
173 _draw_news_callback[ni->callback](w, ni); |
163 case NM_CALLBACK: { |
174 break; |
164 _draw_news_callback[ni->callback](w); |
175 |
165 break; |
176 default: |
166 } |
177 DrawWindowWidgets(w); |
167 |
178 if (!(ni->flags & NF_VIEWPORT)) { |
168 default: { |
179 CopyInDParam(0, ni->params, lengthof(ni->params)); |
169 DrawWindowWidgets(w); |
180 DrawStringMultiCenter(140, 38, ni->string_id, 276); |
170 if (!(ni->flags & NF_VIEWPORT)) { |
181 } else { |
171 CopyInDParam(0, ni->params, lengthof(ni->params)); |
182 DrawWindowViewport(w); |
172 DrawStringMultiCenter(140, 38, ni->string_id, 276); |
183 CopyInDParam(0, ni->params, lengthof(ni->params)); |
173 } else { |
184 DrawStringMultiCenter(w->width / 2, w->height - 16, ni->string_id, w->width - 4); |
174 DrawWindowViewport(w); |
185 } |
175 CopyInDParam(0, ni->params, lengthof(ni->params)); |
186 break; |
176 DrawStringMultiCenter(w->width / 2, w->height - 16, ni->string_id, w->width - 4); |
187 } |
188 } break; |
|
189 |
|
190 case WE_CLICK: { |
|
191 switch (e->we.click.widget) { |
|
192 case 1: { |
|
193 NewsItem *ni = WP(w, news_d).ni; |
|
194 DeleteWindow(w); |
|
195 ni->duration = 0; |
|
196 _forced_news = INVALID_NEWS; |
|
197 } break; |
|
198 case 0: { |
|
199 NewsItem *ni = WP(w, news_d).ni; |
|
200 if (ni->flags & NF_VEHICLE) { |
|
201 Vehicle *v = GetVehicle(ni->data_a); |
|
202 ScrollMainWindowTo(v->x_pos, v->y_pos); |
|
203 } else if (ni->flags & NF_TILE) { |
|
204 if (!ScrollMainWindowToTile(ni->data_a) && ni->data_b != 0) |
|
205 ScrollMainWindowToTile(ni->data_b); |
|
177 } |
206 } |
178 break; |
207 } break; |
179 } |
208 } |
180 } |
|
181 } break; |
|
182 |
|
183 case WE_CLICK: { |
|
184 switch (e->we.click.widget) { |
|
185 case 1: { |
|
186 NewsItem *ni = WP(w, news_d).ni; |
|
187 DeleteWindow(w); |
|
188 ni->duration = 0; |
|
189 _forced_news = INVALID_NEWS; |
|
190 } break; |
209 } break; |
191 case 0: { |
210 |
192 NewsItem *ni = WP(w, news_d).ni; |
211 case WE_KEYPRESS: |
193 if (ni->flags & NF_VEHICLE) { |
212 if (e->we.keypress.keycode == WKC_SPACE) { |
194 Vehicle *v = GetVehicle(ni->data_a); |
213 /* Don't continue. */ |
195 ScrollMainWindowTo(v->x_pos, v->y_pos); |
214 e->we.keypress.cont = false; |
196 } else if (ni->flags & NF_TILE) { |
215 DeleteWindow(w); |
197 if (!ScrollMainWindowToTile(ni->data_a) && ni->data_b != 0) |
216 } |
198 ScrollMainWindowToTile(ni->data_b); |
217 break; |
199 } |
218 |
219 case WE_MESSAGE: // The chatbar has notified us that is was either created or closed |
|
220 switch (e->we.message.msg) { |
|
221 case WE_CREATE: w->message.msg = e->we.message.wparam; break; |
|
222 case WE_DESTROY: w->message.msg = 0; break; |
|
223 } |
|
224 break; |
|
225 |
|
226 case WE_TICK: { // Scroll up newsmessages from the bottom in steps of 4 pixels |
|
227 int diff; |
|
228 int y = max(w->top - 4, _screen.height - w->height - 12 - w->message.msg); |
|
229 if (y == w->top) return; |
|
230 |
|
231 if (w->viewport != NULL) |
|
232 w->viewport->top += y - w->top; |
|
233 |
|
234 diff = Delta(w->top, y); |
|
235 w->top = y; |
|
236 |
|
237 SetDirtyBlocks(w->left, w->top - diff, w->left + w->width, w->top + w->height); |
|
200 } break; |
238 } break; |
201 } |
|
202 } break; |
|
203 |
|
204 case WE_KEYPRESS: |
|
205 if (e->we.keypress.keycode == WKC_SPACE) { |
|
206 /* Don't continue. */ |
|
207 e->we.keypress.cont = false; |
|
208 DeleteWindow(w); |
|
209 } |
|
210 break; |
|
211 |
|
212 case WE_MESSAGE: // The chatbar has notified us that is was either created or closed |
|
213 switch (e->we.message.msg) { |
|
214 case WE_CREATE: w->message.msg = e->we.message.wparam; break; |
|
215 case WE_DESTROY: w->message.msg = 0; break; |
|
216 } |
|
217 break; |
|
218 |
|
219 case WE_TICK: { // Scroll up newsmessages from the bottom in steps of 4 pixels |
|
220 int diff; |
|
221 int y = max(w->top - 4, _screen.height - w->height - 12 - w->message.msg); |
|
222 if (y == w->top) return; |
|
223 |
|
224 if (w->viewport != NULL) |
|
225 w->viewport->top += y - w->top; |
|
226 |
|
227 diff = Delta(w->top, y); |
|
228 w->top = y; |
|
229 |
|
230 SetDirtyBlocks(w->left, w->top - diff, w->left + w->width, w->top + w->height); |
|
231 } break; |
|
232 } |
239 } |
233 } |
240 } |
234 |
241 |
235 /** |
242 /** |
236 * Return the correct index in the pseudo-fifo |
243 * Return the correct index in the pseudo-fifo |
237 * queue and deals with overflows when increasing the index |
244 * queue and deals with overflows when increasing the index |
238 */ |
245 */ |
239 static inline NewsID increaseIndex(NewsID i) |
246 static inline NewsID IncreaseIndex(NewsID i) |
240 { |
247 { |
241 assert(i != INVALID_NEWS); |
248 assert(i != INVALID_NEWS); |
242 return (i + 1) % MAX_NEWS; |
249 return (i + 1) % MAX_NEWS; |
243 } |
250 } |
244 |
251 |
245 /** |
252 /** |
246 * Return the correct index in the pseudo-fifo |
253 * Return the correct index in the pseudo-fifo |
247 * queue and deals with overflows when decreasing the index |
254 * queue and deals with overflows when decreasing the index |
248 */ |
255 */ |
249 static inline NewsID decreaseIndex(NewsID i) |
256 static inline NewsID DecreaseIndex(NewsID i) |
250 { |
257 { |
251 assert(i != INVALID_NEWS); |
258 assert(i != INVALID_NEWS); |
252 return (i + MAX_NEWS - 1) % MAX_NEWS; |
259 return (i + MAX_NEWS - 1) % MAX_NEWS; |
253 } |
260 } |
254 |
261 |
255 /** |
262 /** |
256 * Add a new newsitem to be shown. |
263 * Add a new newsitem to be shown. |
257 * @param string String to display, can have special values based on parameter \a flags |
264 * @param string String to display, can have special values based on parameter \a display_mode |
258 * @param flags various control bits that will show various news-types. See macro NEWS_FLAGS() |
265 * @param display_mode, any of the NewsMode enums (NM_) |
266 * @param flags any of the NewsFlag enums (NF_) |
|
267 * @param type news category, any of the NewsType enums (NT_) |
|
268 * @param callback news callback function, any of the NewsCallback enums (DNC_) |
|
259 * @param data_a news-specific value based on news type |
269 * @param data_a news-specific value based on news type |
260 * @param data_b news-specific value based on news type |
270 * @param data_b news-specific value based on news type |
261 * @note flags exists of 4 byte-sized extra parameters. |
|
262 * -# Bits 0 - 7 display_mode, any of the NewsMode enums (NM_) |
|
263 * -# Bits 8 - 15 news flags, any of the NewsFlags enums (NF_) |
|
264 * -# Bits 16 - 23 news category, any of the NewsType enums (NT_) |
|
265 * -# Bits 24 - 31 news callback function, any of the NewsCallback enums (DNC_) |
|
266 * |
271 * |
267 * If the display mode is NM_CALLBACK, special news is shown and parameter |
272 * @note If the display mode is NM_CALLBACK, special news is shown and parameter |
268 * \a string has a special meaning. |
273 * \a string has a special meaning. |
269 * - For DNC_TRAINAVAIL, DNC_ROADAVAIL, DNC_SHIPAVAIL, DNC_AIRCRAFTAVAIL messages: StringID is |
274 * - For DNC_TRAINAVAIL, DNC_ROADAVAIL, DNC_SHIPAVAIL, DNC_AIRCRAFTAVAIL messages: StringID is |
270 * the index of the engine that is shown |
275 * the index of the engine that is shown |
271 * |
276 * |
272 * - For DNC_BANKRUPCY: bytes 0-3 of StringID contains the player that is in trouble, |
277 * - For DNC_BANKRUPCY: bytes 0-3 of StringID contains the player that is in trouble, |
273 * and 4-7 contains what kind of bankrupcy message is shown. |
278 * and 4-7 contains what kind of bankrupcy message is shown. |
274 * @see NewsBankrupcy |
279 * @see NewsBankrupcy |
275 * |
280 * |
276 * @see NewsMode |
281 * @see NewsMode |
277 * @see NewsFlags |
282 * @see NewsFlag |
278 * @see NewsType |
283 * @see NewsType |
279 * @see NewsCallback |
284 * @see NewsCallback |
280 */ |
285 */ |
281 void AddNewsItem(StringID string, uint32 flags, uint data_a, uint data_b) |
286 void AddNewsItem(StringID string, NewsMode display_mode, NewsFlag flags, NewsType type, NewsCallback callback, uint data_a, uint data_b) |
282 { |
287 { |
283 NewsID l_news; |
|
284 |
|
285 if (_game_mode == GM_MENU) return; |
288 if (_game_mode == GM_MENU) return; |
286 |
289 |
287 /* check the rare case that the oldest (to be overwritten) news item is open */ |
290 /* check the rare case that the oldest (to be overwritten) news item is open */ |
288 if (_total_news == MAX_NEWS && (_oldest_news == _current_news || _oldest_news == _forced_news)) |
291 if (_total_news == MAX_NEWS && (_oldest_news == _current_news || _oldest_news == _forced_news)) { |
289 MoveToNextItem(); |
292 MoveToNextItem(); |
293 } |
|
290 |
294 |
291 if (_total_news < MAX_NEWS) _total_news++; |
295 if (_total_news < MAX_NEWS) _total_news++; |
292 |
296 |
293 /* Increase _latest_news. If we have no news yet, use _oldest news as an |
297 /* Increase _latest_news. If we have no news yet, use _oldest news as an |
294 * index. We cannot use 0 as _oldest_news can jump around due to |
298 * index. We cannot use 0 as _oldest_news can jump around due to |
295 * DeleteVehicleNews */ |
299 * DeleteVehicleNews */ |
296 l_news = _latest_news; |
300 NewsID l_news = _latest_news; |
297 _latest_news = (_latest_news == INVALID_NEWS) ? _oldest_news : increaseIndex(_latest_news); |
301 _latest_news = (_latest_news == INVALID_NEWS) ? _oldest_news : IncreaseIndex(_latest_news); |
298 |
302 |
299 /* If the fifo-buffer is full, overwrite the oldest entry */ |
303 /* If the fifo-buffer is full, overwrite the oldest entry */ |
300 if (l_news != INVALID_NEWS && _latest_news == _oldest_news) { |
304 if (l_news != INVALID_NEWS && _latest_news == _oldest_news) { |
301 assert(_total_news == MAX_NEWS); |
305 assert(_total_news == MAX_NEWS); |
302 _oldest_news = increaseIndex(_oldest_news); |
306 _oldest_news = IncreaseIndex(_oldest_news); |
303 } |
307 } |
304 |
308 |
305 /*DEBUG(misc, 0, "+cur %3d, old %2d, lat %3d, for %3d, tot %2d", |
309 /*DEBUG(misc, 0, "+cur %3d, old %2d, lat %3d, for %3d, tot %2d", |
306 _current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/ |
310 _current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/ |
307 |
311 |
308 /* Add news to _latest_news */ |
312 /* Add news to _latest_news */ |
309 { |
313 NewsItem *ni = &_news_items[_latest_news]; |
310 Window *w; |
314 memset(ni, 0, sizeof(*ni)); |
311 NewsItem *ni = &_news_items[_latest_news]; |
315 |
312 memset(ni, 0, sizeof(*ni)); |
316 ni->string_id = string; |
313 |
317 ni->display_mode = display_mode; |
314 ni->string_id = string; |
318 ni->flags = flags; |
315 ni->display_mode = (byte)flags; |
319 |
316 ni->flags = (byte)(flags >> 8); |
320 /* show this news message in color? */ |
317 |
321 if (_cur_year >= _patches.colored_news_year) ni->flags |= NF_INCOLOR; |
318 /* show this news message in color? */ |
322 |
319 if (_cur_year >= _patches.colored_news_year) ni->flags |= NF_INCOLOR; |
323 ni->type = type; |
320 |
324 ni->callback = callback; |
321 ni->type = (byte)(flags >> 16); |
325 ni->data_a = data_a; |
322 ni->callback = (byte)(flags >> 24); |
326 ni->data_b = data_b; |
323 ni->data_a = data_a; |
327 ni->date = _date; |
324 ni->data_b = data_b; |
328 CopyOutDParam(ni->params, 0, lengthof(ni->params)); |
325 ni->date = _date; |
329 |
326 CopyOutDParam(ni->params, 0, lengthof(ni->params)); |
330 Window *w = FindWindowById(WC_MESSAGE_HISTORY, 0); |
327 |
331 if (w == NULL) return; |
328 w = FindWindowById(WC_MESSAGE_HISTORY, 0); |
332 SetWindowDirty(w); |
329 if (w == NULL) return; |
333 w->vscroll.count = _total_news; |
330 SetWindowDirty(w); |
|
331 w->vscroll.count = _total_news; |
|
332 } |
|
333 } |
334 } |
334 |
335 |
335 |
336 |
336 /** |
337 /** |
337 * Maximum age of news items. |
338 * Maximum age of news items. |
338 * Don't show item if it's older than x days, corresponds with NewsType in news.h |
339 * Don't show item if it's older than x days, corresponds with NewsType in news_type.h |
339 * @see NewsType |
340 * @see NewsType |
340 */ |
341 */ |
341 static const byte _news_items_age[NT_END] = { |
342 static const byte _news_items_age[NT_END] = { |
342 60, ///< NT_ARRIVAL_PLAYER |
343 60, ///< NT_ARRIVAL_PLAYER |
343 60, ///< NT_ARRIVAL_OTHER |
344 60, ///< NT_ARRIVAL_OTHER |
459 } |
460 } |
460 |
461 |
461 /** Open up an own newspaper window for the news item */ |
462 /** Open up an own newspaper window for the news item */ |
462 static void ShowNewspaper(NewsItem *ni) |
463 static void ShowNewspaper(NewsItem *ni) |
463 { |
464 { |
464 Window *w; |
|
465 SoundFx sound; |
|
466 int top; |
|
467 ni->flags &= ~NF_FORCE_BIG; |
465 ni->flags &= ~NF_FORCE_BIG; |
468 ni->duration = 555; |
466 ni->duration = 555; |
469 |
467 |
470 sound = _news_sounds[ni->type]; |
468 SoundFx sound = _news_sounds[ni->type]; |
471 if (sound != 0) SndPlayFx(sound); |
469 if (sound != 0) SndPlayFx(sound); |
472 |
470 |
473 top = _screen.height; |
471 int top = _screen.height; |
472 Window *w; |
|
474 switch (ni->display_mode) { |
473 switch (ni->display_mode) { |
475 case NM_NORMAL: |
474 case NM_NORMAL: |
476 case NM_CALLBACK: { |
475 case NM_CALLBACK: |
477 _news_type13_desc.top = top; |
476 _news_type13_desc.top = top; |
478 w = AllocateWindowDesc(&_news_type13_desc); |
477 w = AllocateWindowDesc(&_news_type13_desc); |
479 if (ni->flags & NF_VIEWPORT) |
478 if (ni->flags & NF_VIEWPORT) { |
480 AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E, |
479 AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E, |
481 ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS); |
480 ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS); |
481 } |
|
482 break; |
482 break; |
483 } |
483 |
484 |
484 case NM_THIN: |
485 case NM_THIN: { |
|
486 _news_type2_desc.top = top; |
485 _news_type2_desc.top = top; |
487 w = AllocateWindowDesc(&_news_type2_desc); |
486 w = AllocateWindowDesc(&_news_type2_desc); |
488 if (ni->flags & NF_VIEWPORT) |
487 if (ni->flags & NF_VIEWPORT) { |
489 AssignWindowViewport(w, 2, 58, 0x1AA, 0x46, |
488 AssignWindowViewport(w, 2, 58, 0x1AA, 0x46, |
490 ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS); |
489 ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS); |
490 } |
|
491 break; |
491 break; |
492 } |
492 |
493 |
493 default: |
494 default: { |
|
495 _news_type0_desc.top = top; |
494 _news_type0_desc.top = top; |
496 w = AllocateWindowDesc(&_news_type0_desc); |
495 w = AllocateWindowDesc(&_news_type0_desc); |
497 if (ni->flags & NF_VIEWPORT) |
496 if (ni->flags & NF_VIEWPORT) { |
498 AssignWindowViewport(w, 3, 17, 0x112, 0x2F, |
497 AssignWindowViewport(w, 3, 17, 0x112, 0x2F, |
499 ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS); |
498 ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS); |
499 } |
|
500 break; |
500 break; |
501 } |
|
502 } |
501 } |
503 |
502 |
504 /*DEBUG(misc, 0, " cur %3d, old %2d, lat %3d, for %3d, tot %2d", |
503 /*DEBUG(misc, 0, " cur %3d, old %2d, lat %3d, for %3d, tot %2d", |
505 _current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/ |
504 _current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/ |
506 |
505 |
509 } |
508 } |
510 |
509 |
511 /** Show news item in the ticker */ |
510 /** Show news item in the ticker */ |
512 static void ShowTicker(const NewsItem *ni) |
511 static void ShowTicker(const NewsItem *ni) |
513 { |
512 { |
514 Window *w; |
|
515 |
|
516 if (_news_ticker_sound) SndPlayFx(SND_16_MORSE); |
513 if (_news_ticker_sound) SndPlayFx(SND_16_MORSE); |
517 |
514 |
518 _statusbar_news_item = *ni; |
515 _statusbar_news_item = *ni; |
519 w = FindWindowById(WC_STATUS_BAR, 0); |
516 Window *w = FindWindowById(WC_STATUS_BAR, 0); |
520 if (w != NULL) WP(w, def_d).data_1 = 360; |
517 if (w != NULL) WP(w, def_d).data_1 = 360; |
521 } |
518 } |
522 |
519 |
523 |
520 |
524 /** |
521 /** |
525 * Are we ready to show another news item? |
522 * Are we ready to show another news item? |
526 * Only if nothing is in the newsticker and no newspaper is displayed |
523 * Only if nothing is in the newsticker and no newspaper is displayed |
527 */ |
524 */ |
528 static bool ReadyForNextItem() |
525 static bool ReadyForNextItem() |
529 { |
526 { |
530 const Window *w; |
|
531 NewsID item = (_forced_news == INVALID_NEWS) ? _current_news : _forced_news; |
527 NewsID item = (_forced_news == INVALID_NEWS) ? _current_news : _forced_news; |
532 NewsItem *ni; |
|
533 |
528 |
534 if (item >= MAX_NEWS) return true; |
529 if (item >= MAX_NEWS) return true; |
535 ni = &_news_items[item]; |
530 NewsItem *ni = &_news_items[item]; |
536 |
531 |
537 /* Ticker message |
532 /* Ticker message |
538 * Check if the status bar message is still being displayed? */ |
533 * Check if the status bar message is still being displayed? */ |
539 w = FindWindowById(WC_STATUS_BAR, 0); |
534 const Window *w = FindWindowById(WC_STATUS_BAR, 0); |
540 if (w != NULL && WP(w, const def_d).data_1 > -1280) return false; |
535 if (w != NULL && WP(w, const def_d).data_1 > -1280) return false; |
541 |
536 |
542 /* Newspaper message, decrement duration counter */ |
537 /* Newspaper message, decrement duration counter */ |
543 if (ni->duration != 0) ni->duration--; |
538 if (ni->duration != 0) ni->duration--; |
544 |
539 |
552 DeleteWindowById(WC_NEWS_WINDOW, 0); |
547 DeleteWindowById(WC_NEWS_WINDOW, 0); |
553 _forced_news = INVALID_NEWS; |
548 _forced_news = INVALID_NEWS; |
554 |
549 |
555 /* if we're not at the last item, then move on */ |
550 /* if we're not at the last item, then move on */ |
556 if (_current_news != _latest_news) { |
551 if (_current_news != _latest_news) { |
557 NewsItem *ni; |
552 _current_news = (_current_news == INVALID_NEWS) ? _oldest_news : IncreaseIndex(_current_news); |
558 |
553 NewsItem *ni = &_news_items[_current_news]; |
559 _current_news = (_current_news == INVALID_NEWS) ? _oldest_news : increaseIndex(_current_news); |
|
560 ni = &_news_items[_current_news]; |
|
561 |
554 |
562 /* check the date, don't show too old items */ |
555 /* check the date, don't show too old items */ |
563 if (_date - _news_items_age[ni->type] > ni->date) return; |
556 if (_date - _news_items_age[ni->type] > ni->date) return; |
564 |
557 |
565 switch (GetNewsDisplayValue(ni->type)) { |
558 switch (GetNewsDisplayValue(ni->type)) { |
621 { |
614 { |
622 if (_forced_news == INVALID_NEWS) { |
615 if (_forced_news == INVALID_NEWS) { |
623 /* Not forced any news yet, show the current one, unless a news window is |
616 /* Not forced any news yet, show the current one, unless a news window is |
624 * open (which can only be the current one), then show the previous item */ |
617 * open (which can only be the current one), then show the previous item */ |
625 const Window *w = FindWindowById(WC_NEWS_WINDOW, 0); |
618 const Window *w = FindWindowById(WC_NEWS_WINDOW, 0); |
626 ShowNewsMessage((w == NULL || (_current_news == _oldest_news)) ? _current_news : decreaseIndex(_current_news)); |
619 ShowNewsMessage((w == NULL || (_current_news == _oldest_news)) ? _current_news : DecreaseIndex(_current_news)); |
627 } else if (_forced_news == _oldest_news) { |
620 } else if (_forced_news == _oldest_news) { |
628 /* We have reached the oldest news, start anew with the latest */ |
621 /* We have reached the oldest news, start anew with the latest */ |
629 ShowNewsMessage(_latest_news); |
622 ShowNewsMessage(_latest_news); |
630 } else { |
623 } else { |
631 /* 'Scrolling' through news history show each one in turn */ |
624 /* 'Scrolling' through news history show each one in turn */ |
632 ShowNewsMessage(decreaseIndex(_forced_news)); |
625 ShowNewsMessage(DecreaseIndex(_forced_news)); |
633 } |
626 } |
634 } |
627 } |
635 |
628 |
636 |
629 |
637 /* return news by number, with 0 being the most |
630 /* return news by number, with 0 being the most |
659 * @param maxw maximum width of string in pixels |
652 * @param maxw maximum width of string in pixels |
660 */ |
653 */ |
661 static void DrawNewsString(int x, int y, uint16 color, const NewsItem *ni, uint maxw) |
654 static void DrawNewsString(int x, int y, uint16 color, const NewsItem *ni, uint maxw) |
662 { |
655 { |
663 char buffer[512], buffer2[512]; |
656 char buffer[512], buffer2[512]; |
664 const char *ptr; |
|
665 char *dest; |
|
666 StringID str; |
657 StringID str; |
667 |
658 |
668 if (ni->display_mode == NM_CALLBACK) { |
659 if (ni->display_mode == NM_CALLBACK) { |
669 str = _get_news_string_callback[ni->callback](ni); |
660 str = _get_news_string_callback[ni->callback](ni); |
670 } else { |
661 } else { |
673 } |
664 } |
674 |
665 |
675 GetString(buffer, str, lastof(buffer)); |
666 GetString(buffer, str, lastof(buffer)); |
676 /* Copy the just gotten string to another buffer to remove any formatting |
667 /* Copy the just gotten string to another buffer to remove any formatting |
677 * from it such as big fonts, etc. */ |
668 * from it such as big fonts, etc. */ |
678 ptr = buffer; |
669 const char *ptr = buffer; |
679 dest = buffer2; |
670 char *dest = buffer2; |
680 WChar c_last = '\0'; |
671 WChar c_last = '\0'; |
681 for (;;) { |
672 for (;;) { |
682 WChar c = Utf8Consume(&ptr); |
673 WChar c = Utf8Consume(&ptr); |
683 if (c == 0) break; |
674 if (c == 0) break; |
684 /* Make a space from a newline, but ignore multiple newlines */ |
675 /* Make a space from a newline, but ignore multiple newlines */ |
701 |
692 |
702 |
693 |
703 static void MessageHistoryWndProc(Window *w, WindowEvent *e) |
694 static void MessageHistoryWndProc(Window *w, WindowEvent *e) |
704 { |
695 { |
705 switch (e->event) { |
696 switch (e->event) { |
706 case WE_PAINT: { |
697 case WE_PAINT: { |
707 int y = 19; |
698 int y = 19; |
708 NewsID p, show; |
699 |
709 |
700 SetVScrollCount(w, _total_news); |
710 SetVScrollCount(w, _total_news); |
701 DrawWindowWidgets(w); |
711 DrawWindowWidgets(w); |
702 |
712 |
703 if (_total_news == 0) break; |
713 if (_total_news == 0) break; |
704 NewsID show = min(_total_news, w->vscroll.cap); |
714 show = min(_total_news, w->vscroll.cap); |
705 |
715 |
706 for (NewsID p = w->vscroll.pos; p < w->vscroll.pos + show; p++) { |
716 for (p = w->vscroll.pos; p < w->vscroll.pos + show; p++) { |
707 /* get news in correct order */ |
717 /* get news in correct order */ |
708 const NewsItem *ni = &_news_items[getNews(p)]; |
718 const NewsItem *ni = &_news_items[getNews(p)]; |
709 |
719 |
710 SetDParam(0, ni->date); |
720 SetDParam(0, ni->date); |
711 DrawString(4, y, STR_SHORT_DATE, TC_WHITE); |
721 DrawString(4, y, STR_SHORT_DATE, TC_WHITE); |
712 |
722 |
713 DrawNewsString(82, y, TC_WHITE, ni, w->width - 95); |
723 DrawNewsString(82, y, TC_WHITE, ni, w->width - 95); |
714 y += 12; |
724 y += 12; |
715 } |
725 } |
|
726 break; |
|
727 } |
|
728 |
|
729 case WE_CLICK: |
|
730 switch (e->we.click.widget) { |
|
731 case 3: { |
|
732 int y = (e->we.click.pt.y - 19) / 12; |
|
733 NewsID p = getNews(y + w->vscroll.pos); |
|
734 |
|
735 if (p == INVALID_NEWS) break; |
|
736 |
|
737 ShowNewsMessage(p); |
|
738 break; |
716 break; |
739 } |
717 } |
740 } |
718 |
741 break; |
719 case WE_CLICK: |
742 |
720 if (e->we.click.widget == 3) { |
743 case WE_RESIZE: |
721 int y = (e->we.click.pt.y - 19) / 12; |
744 w->vscroll.cap += e->we.sizing.diff.y / 12; |
722 NewsID p = getNews(y + w->vscroll.pos); |
745 break; |
723 |
724 if (p != INVALID_NEWS) ShowNewsMessage(p); |
|
725 } |
|
726 break; |
|
727 |
|
728 case WE_RESIZE: |
|
729 w->vscroll.cap += e->we.sizing.diff.y / 12; |
|
730 break; |
|
746 } |
731 } |
747 } |
732 } |
748 |
733 |
749 static const Widget _message_history_widgets[] = { |
734 static const Widget _message_history_widgets[] = { |
750 { WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
735 { WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
765 }; |
750 }; |
766 |
751 |
767 /** Display window with news messages history */ |
752 /** Display window with news messages history */ |
768 void ShowMessageHistory() |
753 void ShowMessageHistory() |
769 { |
754 { |
770 Window *w; |
|
771 |
|
772 DeleteWindowById(WC_MESSAGE_HISTORY, 0); |
755 DeleteWindowById(WC_MESSAGE_HISTORY, 0); |
773 w = AllocateWindowDesc(&_message_history_desc); |
756 Window *w = AllocateWindowDesc(&_message_history_desc); |
774 |
757 |
775 if (w != NULL) { |
758 if (w != NULL) { |
776 w->vscroll.cap = 10; |
759 w->vscroll.cap = 10; |
777 w->vscroll.count = _total_news; |
760 w->vscroll.count = _total_news; |
778 w->resize.step_height = 12; |
761 w->resize.step_height = 12; |
820 /* WP(w, def_d).data_1 stores state of the ALL on/off/summary button */ |
803 /* WP(w, def_d).data_1 stores state of the ALL on/off/summary button */ |
821 switch (e->event) { |
804 switch (e->event) { |
822 case WE_CREATE: { |
805 case WE_CREATE: { |
823 uint32 val = _news_display_opt; |
806 uint32 val = _news_display_opt; |
824 uint32 all_val; |
807 uint32 all_val; |
825 int i; |
|
826 |
808 |
827 /* Set up the initial disabled buttons in the case of 'off' or 'full' */ |
809 /* Set up the initial disabled buttons in the case of 'off' or 'full' */ |
828 all_val = val & 0x3; |
810 all_val = val & 0x3; |
829 for (i = 0; i < NT_END; i++, val >>= 2) { |
811 for (int i = 0; i < NT_END; i++, val >>= 2) { |
830 SetMessageButtonStates(w, val & 0x3, i); |
812 SetMessageButtonStates(w, val & 0x3, i); |
831 /* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */ |
813 /* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */ |
832 if ((val & 0x3) != all_val) all_val = 0; |
814 if ((val & 0x3) != all_val) all_val = 0; |
833 } |
815 } |
834 /* If all values are the same value, the ALL-button will take over this value */ |
816 /* If all values are the same value, the ALL-button will take over this value */ |
835 WP(w, def_d).data_1 = all_val; |
817 WP(w, def_d).data_1 = all_val; |
836 } break; |
818 } break; |
837 |
819 |
838 case WE_PAINT: { |
820 case WE_PAINT: { |
839 uint32 val = _news_display_opt; |
821 uint32 val = _news_display_opt; |
840 int i, y; |
|
841 |
822 |
842 if (_news_ticker_sound) w->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER); |
823 if (_news_ticker_sound) w->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER); |
843 |
824 |
844 w->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = message_opt[WP(w, def_d).data_1]; |
825 w->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = message_opt[WP(w, def_d).data_1]; |
845 DrawWindowWidgets(w); |
826 DrawWindowWidgets(w); |
846 |
827 |
847 /* Draw the string of each setting on each button. */ |
828 /* Draw the string of each setting on each button. */ |
848 for (i = 0, y = 26; i < NT_END; i++, y += 12, val >>= 2) { |
829 for (int i = 0, y = 26; i < NT_END; i++, y += 12, val >>= 2) { |
849 /* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division, |
830 /* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division, |
850 * which will give centered position */ |
831 * which will give centered position */ |
851 DrawStringCentered(51, y + 1, message_opt[val & 0x3], TC_BLACK); |
832 DrawStringCentered(51, y + 1, message_opt[val & 0x3], TC_BLACK); |
852 } |
833 } |
853 } break; |
834 } break; |
873 SetMessageButtonStates(w, val, element); |
854 SetMessageButtonStates(w, val, element); |
874 SetNewsDisplayValue(element, val); |
855 SetNewsDisplayValue(element, val); |
875 SetWindowDirty(w); |
856 SetWindowDirty(w); |
876 } |
857 } |
877 } break; |
858 } break; |
878 } break; |
859 } |
879 |
860 break; |
880 case WE_DROPDOWN_SELECT: { // Select all settings for newsmessages |
861 |
881 int i; |
862 case WE_DROPDOWN_SELECT: // Select all settings for newsmessages |
882 |
|
883 WP(w, def_d).data_1 = e->we.dropdown.index; |
863 WP(w, def_d).data_1 = e->we.dropdown.index; |
884 |
864 |
885 for (i = 0; i < NT_END; i++) { |
865 for (int i = 0; i < NT_END; i++) { |
886 SetMessageButtonStates(w, e->we.dropdown.index, i); |
866 SetMessageButtonStates(w, e->we.dropdown.index, i); |
887 SetNewsDisplayValue(i, e->we.dropdown.index); |
867 SetNewsDisplayValue(i, e->we.dropdown.index); |
888 } |
868 } |
889 SetWindowDirty(w); |
869 SetWindowDirty(w); |
890 } break; |
870 break; |
891 } |
871 } |
892 } |
872 } |
893 |
873 |
894 |
874 |
895 /* |
875 /* |
1000 } |
980 } |
1001 |
981 |
1002 |
982 |
1003 void DeleteVehicleNews(VehicleID vid, StringID news) |
983 void DeleteVehicleNews(VehicleID vid, StringID news) |
1004 { |
984 { |
1005 NewsID n; |
985 for (NewsID n = _oldest_news; _latest_news != INVALID_NEWS; n = IncreaseIndex(n)) { |
1006 |
|
1007 for (n = _oldest_news; _latest_news != INVALID_NEWS; n = increaseIndex(n)) { |
|
1008 const NewsItem *ni = &_news_items[n]; |
986 const NewsItem *ni = &_news_items[n]; |
1009 |
987 |
1010 if (ni->flags & NF_VEHICLE && |
988 if (ni->flags & NF_VEHICLE && |
1011 ni->data_a == vid && |
989 ni->data_a == vid && |
1012 (news == INVALID_STRING_ID || ni->string_id == news)) { |
990 (news == INVALID_STRING_ID || ni->string_id == news)) { |
1013 Window *w; |
|
1014 |
|
1015 /* If we delete a forced news and it is just before the current news |
991 /* If we delete a forced news and it is just before the current news |
1016 * then we need to advance to the next news (if any) */ |
992 * then we need to advance to the next news (if any) */ |
1017 if (_forced_news == n) MoveToNextItem(); |
993 if (_forced_news == n) MoveToNextItem(); |
1018 if (_forced_news == INVALID_NEWS && _current_news == n) MoveToNextItem(); |
994 if (_forced_news == INVALID_NEWS && _current_news == n) MoveToNextItem(); |
1019 _total_news--; |
995 _total_news--; |
1032 * will become (change dramatized to make clear) |
1008 * will become (change dramatized to make clear) |
1033 * [---------O-----------L--] |
1009 * [---------O-----------L--] |
1034 * We also need an update of the current, forced and visible (open window) |
1010 * We also need an update of the current, forced and visible (open window) |
1035 * news's as this shifting could change the items they were pointing to */ |
1011 * news's as this shifting could change the items they were pointing to */ |
1036 if (_total_news != 0) { |
1012 if (_total_news != 0) { |
1037 w = FindWindowById(WC_NEWS_WINDOW, 0); |
1013 Window *w = FindWindowById(WC_NEWS_WINDOW, 0); |
1038 NewsID visible_news = (w != NULL) ? (NewsID)(WP(w, news_d).ni - _news_items) : INVALID_NEWS; |
1014 NewsID visible_news = (w != NULL) ? (NewsID)(WP(w, news_d).ni - _news_items) : INVALID_NEWS; |
1039 |
1015 |
1040 for (NewsID i = n;; i = decreaseIndex(i)) { |
1016 for (NewsID i = n;; i = DecreaseIndex(i)) { |
1041 _news_items[i] = _news_items[decreaseIndex(i)]; |
1017 _news_items[i] = _news_items[DecreaseIndex(i)]; |
1042 |
1018 |
1043 if (i != _latest_news) { |
1019 if (i != _latest_news) { |
1044 if (i == _current_news) _current_news = increaseIndex(_current_news); |
1020 if (i == _current_news) _current_news = IncreaseIndex(_current_news); |
1045 if (i == _forced_news) _forced_news = increaseIndex(_forced_news); |
1021 if (i == _forced_news) _forced_news = IncreaseIndex(_forced_news); |
1046 if (i == visible_news) WP(w, news_d).ni = &_news_items[increaseIndex(visible_news)]; |
1022 if (i == visible_news) WP(w, news_d).ni = &_news_items[IncreaseIndex(visible_news)]; |
1047 } |
1023 } |
1048 |
1024 |
1049 if (i == _oldest_news) break; |
1025 if (i == _oldest_news) break; |
1050 } |
1026 } |
1051 _oldest_news = increaseIndex(_oldest_news); |
1027 _oldest_news = IncreaseIndex(_oldest_news); |
1052 } |
1028 } |
1053 |
1029 |
1054 /*DEBUG(misc, 0, "-cur %3d, old %2d, lat %3d, for %3d, tot %2d", |
1030 /*DEBUG(misc, 0, "-cur %3d, old %2d, lat %3d, for %3d, tot %2d", |
1055 _current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/ |
1031 _current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/ |
1056 |
1032 |
1057 w = FindWindowById(WC_MESSAGE_HISTORY, 0); |
1033 Window *w = FindWindowById(WC_MESSAGE_HISTORY, 0); |
1058 if (w != NULL) { |
1034 if (w != NULL) { |
1059 SetWindowDirty(w); |
1035 SetWindowDirty(w); |
1060 w->vscroll.count = _total_news; |
1036 w->vscroll.count = _total_news; |
1061 } |
1037 } |
1062 } |
1038 } |