news_gui.c
changeset 427 d87c7d677d2f
parent 337 66647f97e7c0
child 497 2d6d31173813
equal deleted inserted replaced
426:bd6f3c2cad9f 427:d87c7d677d2f
    21 [O------------F-------------C---------L           ]
    21 [O------------F-------------C---------L           ]
    22               |
    22               |
    23            forced
    23            forced
    24 */
    24 */
    25 
    25 
    26 # define MAX_NEWS 30
    26 #define MAX_NEWS 30
       
    27 
       
    28 #define INVALID_NEWS 255
    27 
    29 
    28 static NewsItem _news_items[MAX_NEWS];
    30 static NewsItem _news_items[MAX_NEWS];
    29 static byte _current_news = 255; // points to news item that should be shown next
    31 static byte _current_news = INVALID_NEWS; // points to news item that should be shown next
    30 static byte _oldest_news = 0;    // points to first item in fifo queue
    32 static byte _oldest_news = 0;    // points to first item in fifo queue
    31 static byte _latest_news = 255;  // points to last item in fifo queue
    33 static byte _latest_news = INVALID_NEWS;  // points to last item in fifo queue
    32 static byte _forced_news = 255;  // if the message being shown was forced by the user, its index is stored in _forced_news.
    34 /* if the message being shown was forced by the user, its index is stored in
    33 																 //forced_news is 255 otherwise. (Users can force messages through history or "last message")
    35  * _forced_news. forced_news is INVALID_NEWS otherwise.
       
    36  * (Users can force messages through history or "last message") */
       
    37 static byte _forced_news = INVALID_NEWS;
    34 
    38 
    35 static byte _total_news = 0; // total news count
    39 static byte _total_news = 0; // total news count
    36 
    40 
    37 void DrawNewsNewTrainAvail(Window *w);
    41 void DrawNewsNewTrainAvail(Window *w);
    38 void DrawNewsNewRoadVehAvail(Window *w);
    42 void DrawNewsNewRoadVehAvail(Window *w);
    39 void DrawNewsNewShipAvail(Window *w);
    43 void DrawNewsNewShipAvail(Window *w);
    40 void DrawNewsNewAircraftAvail(Window *w);
    44 void DrawNewsNewAircraftAvail(Window *w);
    41 void DrawNewsBankrupcy(Window *w);
    45 void DrawNewsBankrupcy(Window *w);
    42 static void MoveToNexItem();
    46 static void MoveToNexItem(void);
    43 
    47 
    44 StringID GetNewsStringNewTrainAvail(NewsItem *ni);
    48 StringID GetNewsStringNewTrainAvail(NewsItem *ni);
    45 StringID GetNewsStringNewRoadVehAvail(NewsItem *ni);
    49 StringID GetNewsStringNewRoadVehAvail(NewsItem *ni);
    46 StringID GetNewsStringNewShipAvail(NewsItem *ni);
    50 StringID GetNewsStringNewShipAvail(NewsItem *ni);
    47 StringID GetNewsStringNewAircraftAvail(NewsItem *ni);
    51 StringID GetNewsStringNewAircraftAvail(NewsItem *ni);
    48 StringID GetNewsStringBankrupcy(NewsItem *ni);
    52 StringID GetNewsStringBankrupcy(NewsItem *ni);
    49 
    53 
    50 static DrawNewsCallbackProc * const _draw_news_callback[] = {
    54 static DrawNewsCallbackProc * const _draw_news_callback[] = {
    51 	DrawNewsNewTrainAvail, /* DNC_TRAINAVAIL */
    55 	DrawNewsNewTrainAvail,    /* DNC_TRAINAVAIL */
    52 	DrawNewsNewRoadVehAvail, /* DNC_ROADAVAIL */
    56 	DrawNewsNewRoadVehAvail,  /* DNC_ROADAVAIL */
    53 	DrawNewsNewShipAvail, /* DNC_SHIPAVAIL */
    57 	DrawNewsNewShipAvail,     /* DNC_SHIPAVAIL */
    54 	DrawNewsNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
    58 	DrawNewsNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
    55 	DrawNewsBankrupcy, /* DNC_BANKRUPCY */
    59 	DrawNewsBankrupcy,        /* DNC_BANKRUPCY */
    56 };
    60 };
    57 
    61 
    58 GetNewsStringCallbackProc * const _get_news_string_callback[] = {
    62 GetNewsStringCallbackProc * const _get_news_string_callback[] = {
    59 	GetNewsStringNewTrainAvail, /* DNC_TRAINAVAIL */
    63 	GetNewsStringNewTrainAvail,    /* DNC_TRAINAVAIL */
    60 	GetNewsStringNewRoadVehAvail, /* DNC_ROADAVAIL */
    64 	GetNewsStringNewRoadVehAvail,  /* DNC_ROADAVAIL */
    61 	GetNewsStringNewShipAvail, /* DNC_SHIPAVAIL */
    65 	GetNewsStringNewShipAvail,     /* DNC_SHIPAVAIL */
    62 	GetNewsStringNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
    66 	GetNewsStringNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
    63 	GetNewsStringBankrupcy, /* DNC_BANKRUPCY */
    67 	GetNewsStringBankrupcy,        /* DNC_BANKRUPCY */
    64 };
    68 };
    65 
    69 
    66 void InitNewsItemStructs()
    70 void InitNewsItemStructs(void)
    67 {
    71 {
    68 	memset(_news_items, 0, sizeof(NewsItem)*MAX_NEWS);
    72 	memset(_news_items, 0, sizeof(_news_items));
    69 	_current_news = 255;
    73 	_current_news = INVALID_NEWS;
    70 	_oldest_news = 0;
    74 	_oldest_news = 0;
    71 	_latest_news = 255;
    75 	_latest_news = INVALID_NEWS;
    72 	_forced_news = 255;
    76 	_forced_news = INVALID_NEWS;
    73 	_total_news = 0;
    77 	_total_news = 0;
    74 }
    78 }
    75 
    79 
    76 void DrawNewsBorder(Window *w)
    80 void DrawNewsBorder(const Window *w)
    77 {
    81 {
    78 	int left = 0;
    82 	int left = 0;
    79 	int right = w->width - 1;
    83 	int right = w->width - 1;
    80 	int top = 0;
    84 	int top = 0;
    81 	int bottom = w->height - 1;
    85 	int bottom = w->height - 1;
    90 	DrawString(left + 2, top + 1, STR_00C6, 0);
    94 	DrawString(left + 2, top + 1, STR_00C6, 0);
    91 }
    95 }
    92 
    96 
    93 static void NewsWindowProc(Window *w, WindowEvent *e)
    97 static void NewsWindowProc(Window *w, WindowEvent *e)
    94 {
    98 {
    95 	switch(e->event) {
    99 	switch (e->event) {
    96 	case WE_PAINT: {
   100 	case WE_PAINT: {
    97 		NewsItem *ni = WP(w,news_d).ni;
   101 		const NewsItem *ni = WP(w, news_d).ni;
    98 		ViewPort *vp;
   102 		ViewPort *vp;
    99 
   103 
   100 		if (ni->display_mode == NM_NORMAL || ni->display_mode == NM_THIN) {
   104 		switch (ni->display_mode) {
   101 			DrawNewsBorder(w);
   105 			case NM_NORMAL:
   102 
   106 			case NM_THIN: {
   103 			DrawString(2, 1, STR_00C6, 0);
   107 				DrawNewsBorder(w);
   104 
   108 
   105 			SET_DPARAM16(0, ni->date);
   109 				DrawString(2, 1, STR_00C6, 0);
   106 			DrawStringRightAligned(428, 1, STR_01FF, 0);
   110 
   107 
   111 				SET_DPARAM16(0, ni->date);
   108 			if (!(ni->flags & NF_VIEWPORT)) {
   112 				DrawStringRightAligned(428, 1, STR_01FF, 0);
   109 				COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
   113 
   110 				DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56, ni->string_id, 426);
   114 				if (!(ni->flags & NF_VIEWPORT)) {
   111 			} else {
   115 					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
   112 				byte bk = _display_opt;
   116 					DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56,
   113 				_display_opt |= DO_TRANS_BUILDINGS;
   117 						ni->string_id, 426);
   114 				DrawWindowViewport(w);
   118 				} else {
   115 				_display_opt = bk;
   119 					byte bk = _display_opt;
   116 
   120 					_display_opt |= DO_TRANS_BUILDINGS;
   117 				/* Shade the viewport into gray, or color*/
   121 					DrawWindowViewport(w);
   118 				vp = w->viewport;
   122 					_display_opt = bk;
   119 				GfxFillRect(vp->left - w->left, vp->top - w->top, vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1,
   123 
   120 					ni->flags & NF_INCOLOR ? 0x4322:0x4323
   124 					/* Shade the viewport into gray, or color*/
   121 				);
   125 					vp = w->viewport;
   122 
   126 					GfxFillRect(vp->left - w->left, vp->top - w->top,
   123 				COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
   127 						vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1,
   124 				DrawStringMultiCenter((w->width>>1), 20, ni->string_id, 428);
   128 						ni->flags & NF_INCOLOR ? 0x4322 : 0x4323
       
   129 					);
       
   130 
       
   131 					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
       
   132 					DrawStringMultiCenter(w->width / 2, 20, ni->string_id, 428);
       
   133 				}
       
   134 				break;
   125 			}
   135 			}
   126 		} else if (ni->display_mode == NM_CALLBACK) {
   136 
   127 			_draw_news_callback[ni->callback](w);
   137 			case NM_CALLBACK: {
   128 		} else {
   138 				_draw_news_callback[ni->callback](w);
   129 			DrawWindowWidgets(w);
   139 				break;
   130 			if (!(ni->flags & NF_VIEWPORT)) {
       
   131 				COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
       
   132 				DrawStringMultiCenter(140,38, ni->string_id, 276);
       
   133 			} else {
       
   134 				DrawWindowViewport(w);
       
   135 				COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
       
   136 				DrawStringMultiCenter((w->width>>1), w->height - 16, ni->string_id, 276);
       
   137 			}
   140 			}
       
   141 
       
   142 			default: {
       
   143 				DrawWindowWidgets(w);
       
   144 				if (!(ni->flags & NF_VIEWPORT)) {
       
   145 					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
       
   146 					DrawStringMultiCenter(140, 38, ni->string_id, 276);
       
   147 				} else {
       
   148 					DrawWindowViewport(w);
       
   149 					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
       
   150 					DrawStringMultiCenter(w->width / 2, w->height - 16, ni->string_id, 276);
       
   151 				}
       
   152 				break;
       
   153 			}
   138 		}
   154 		}
   139 	} break;
   155 	} break;
   140 
   156 
   141 	case WE_CLICK: {
   157 	case WE_CLICK: {
   142 		switch(e->click.widget) {
   158 		switch (e->click.widget) {
   143 		case 1: {
   159 		case 1: {
   144 			NewsItem *ni = WP(w,news_d).ni;
   160 			NewsItem *ni = WP(w, news_d).ni;
   145 			DeleteWindow(w);
   161 			DeleteWindow(w);
   146 			ni->duration = 0;
   162 			ni->duration = 0;
   147 			if(_forced_news!=255) _forced_news = 255;
   163 			_forced_news = INVALID_NEWS;
   148 		} break;
   164 		} break;
   149 		case 0: {
   165 		case 0: {
   150 			NewsItem *ni = WP(w,news_d).ni;
   166 			NewsItem *ni = WP(w, news_d).ni;
   151 			if (ni->flags & NF_VEHICLE) {
   167 			if (ni->flags & NF_VEHICLE) {
   152 				Vehicle *v = &_vehicles[ni->data_a];
   168 				Vehicle *v = &_vehicles[ni->data_a];
   153 				ScrollMainWindowTo(v->x_pos, v->y_pos);
   169 				ScrollMainWindowTo(v->x_pos, v->y_pos);
   154 			} else if (ni->flags & NF_TILE) {
   170 			} else if (ni->flags & NF_TILE) {
   155 				if (!ScrollMainWindowToTile(ni->data_a) && ni->data_b != 0)
   171 				if (!ScrollMainWindowToTile(ni->data_a) && ni->data_b != 0)
   184 
   200 
   185 // returns the correct index in the array
   201 // returns the correct index in the array
   186 // (to deal with overflows)
   202 // (to deal with overflows)
   187 byte increaseIndex(byte i)
   203 byte increaseIndex(byte i)
   188 {
   204 {
   189 	if(i==255)
   205 	if (i == INVALID_NEWS)
   190 		return 0;
   206 		return 0;
   191 	i++;
   207 	i++;
   192 	if(i >= MAX_NEWS)
   208 	if (i >= MAX_NEWS)
   193 		i = i % MAX_NEWS;
   209 		i = i % MAX_NEWS;
   194 	return i;
   210 	return i;
   195 }
   211 }
   196 
   212 
   197 
   213 
   202 
   218 
   203 	if (_game_mode == GM_MENU)
   219 	if (_game_mode == GM_MENU)
   204 		return;
   220 		return;
   205 
   221 
   206 	// check the rare case that the oldest (to be overwritten) news item is open
   222 	// check the rare case that the oldest (to be overwritten) news item is open
   207 	if(_oldest_news == _current_news || _oldest_news == _forced_news)
   223 	if (_oldest_news == _current_news || _oldest_news == _forced_news)
   208 		MoveToNexItem();
   224 		MoveToNexItem();
   209 
   225 
   210 	_forced_news = 255;
   226 	_forced_news = INVALID_NEWS;
   211 	if(_total_news < MAX_NEWS) _total_news++;
   227 	if (_total_news < MAX_NEWS) _total_news++;
   212 
   228 
   213 	// make sure our pointer isn't overflowing
   229 	// make sure our pointer isn't overflowing
   214 	_latest_news = increaseIndex(_latest_news);
   230 	_latest_news = increaseIndex(_latest_news);
   215 
   231 
   216 	// overwrite oldest news entry
   232 	// overwrite oldest news entry
   217 	if( _oldest_news == _latest_news && _news_items[_oldest_news].string_id != 0)
   233 	if (_oldest_news == _latest_news && _news_items[_oldest_news].string_id != 0)
   218 		_oldest_news = increaseIndex(_oldest_news); // but make sure we're not overflowing here
   234 		_oldest_news = increaseIndex(_oldest_news); // but make sure we're not overflowing here
   219 
   235 
   220 	// add news to _latest_news
   236 	// add news to _latest_news
   221 	ni = &_news_items[_latest_news];
   237 	ni = &_news_items[_latest_news];
   222 
   238 
   234 	ni->data_b = data_b;
   250 	ni->data_b = data_b;
   235 	ni->date = _date;
   251 	ni->date = _date;
   236 	COPY_OUT_DPARAM(ni->params, 0, lengthof(ni->params));
   252 	COPY_OUT_DPARAM(ni->params, 0, lengthof(ni->params));
   237 
   253 
   238 	w = FindWindowById(WC_MESSAGE_HISTORY, 0);
   254 	w = FindWindowById(WC_MESSAGE_HISTORY, 0);
   239 	if(w==NULL) return;
   255 	if (w == NULL) return;
   240 	SetWindowDirty(w);
   256 	SetWindowDirty(w);
   241 	w->vscroll.count = _total_news;
   257 	w->vscroll.count = _total_news;
   242 }
   258 }
   243 
   259 
   244 // don't show item if it's older than x days
   260 // don't show item if it's older than x days
   245 static const byte _news_items_age[] = {60, 60, 90, 60, 90, 30, 150, 30, 90, 180};
   261 static const byte _news_items_age[] = {60, 60, 90, 60, 90, 30, 150, 30, 90, 180};
   246 
   262 
   247 static const Widget _news_type13_widgets[] = {
   263 static const Widget _news_type13_widgets[] = {
   248 {      WWT_PANEL,    15,     0,   429,     0,   169, 0x0,	STR_NULL},
   264 {      WWT_PANEL,    15,     0,   429,     0,   169, 0x0, STR_NULL},
   249 {      WWT_PANEL,    15,     0,    10,     0,    11, 0x0,	STR_NULL},
   265 {      WWT_PANEL,    15,     0,    10,     0,    11, 0x0, STR_NULL},
   250 {   WIDGETS_END},
   266 {   WIDGETS_END},
   251 };
   267 };
   252 
   268 
   253 static WindowDesc _news_type13_desc = {
   269 static WindowDesc _news_type13_desc = {
   254 	WDP_CENTER, 476, 430, 170,
   270 	WDP_CENTER, 476, 430, 170,
   255 	WC_NEWS_WINDOW,0,
   271 	WC_NEWS_WINDOW, 0,
   256 	WDF_DEF_WIDGET,
   272 	WDF_DEF_WIDGET,
   257 	_news_type13_widgets,
   273 	_news_type13_widgets,
   258 	NewsWindowProc
   274 	NewsWindowProc
   259 };
   275 };
   260 
   276 
   261 static const Widget _news_type2_widgets[] = {
   277 static const Widget _news_type2_widgets[] = {
   262 {      WWT_PANEL,    15,     0,   429,     0,   129, 0x0,	STR_NULL},
   278 {      WWT_PANEL,    15,     0,   429,     0,   129, 0x0, STR_NULL},
   263 {      WWT_PANEL,    15,     0,    10,     0,    11, 0x0,	STR_NULL},
   279 {      WWT_PANEL,    15,     0,    10,     0,    11, 0x0, STR_NULL},
   264 {   WIDGETS_END},
   280 {   WIDGETS_END},
   265 };
   281 };
   266 
   282 
   267 static WindowDesc _news_type2_desc = {
   283 static WindowDesc _news_type2_desc = {
   268 	WDP_CENTER, 476, 430, 130,
   284 	WDP_CENTER, 476, 430, 130,
   269 	WC_NEWS_WINDOW,0,
   285 	WC_NEWS_WINDOW, 0,
   270 	WDF_DEF_WIDGET,
   286 	WDF_DEF_WIDGET,
   271 	_news_type2_widgets,
   287 	_news_type2_widgets,
   272 	NewsWindowProc
   288 	NewsWindowProc
   273 };
   289 };
   274 
   290 
   280 {   WIDGETS_END},
   296 {   WIDGETS_END},
   281 };
   297 };
   282 
   298 
   283 static WindowDesc _news_type0_desc = {
   299 static WindowDesc _news_type0_desc = {
   284 	WDP_CENTER, 476, 280, 87,
   300 	WDP_CENTER, 476, 280, 87,
   285 	WC_NEWS_WINDOW,0,
   301 	WC_NEWS_WINDOW, 0,
   286 	WDF_DEF_WIDGET,
   302 	WDF_DEF_WIDGET,
   287 	_news_type0_widgets,
   303 	_news_type0_widgets,
   288 	NewsWindowProc
   304 	NewsWindowProc
   289 };
   305 };
   290 
   306 
   291 static byte _news_sounds[] = { 27, 27, 0, 0, 0, 0, 28, 0, 0, 0 };
   307 static const SoundFx _news_sounds[] = {
       
   308 	SND_1D_APPLAUSE,
       
   309 	SND_1D_APPLAUSE,
       
   310 	0,
       
   311 	0,
       
   312 	0,
       
   313 	0,
       
   314 	SND_1E_OOOOH,
       
   315 	0,
       
   316 	0,
       
   317 	0
       
   318 };
   292 
   319 
   293 // open up an own newspaper window for the news item
   320 // open up an own newspaper window for the news item
   294 static void ShowNewspaper(NewsItem *ni)
   321 static void ShowNewspaper(NewsItem *ni)
   295 {
   322 {
   296 	Window *w;
   323 	Window *w;
   297 	int sound;
   324 	int sound;
   298 	int top;
   325 	int top;
   299 	ni->flags &= ~(NF_NOEXPIRE|NF_FORCE_BIG);
   326 	ni->flags &= ~(NF_NOEXPIRE | NF_FORCE_BIG);
   300 	ni->duration = 555;
   327 	ni->duration = 555;
   301 
   328 
   302 	sound = _news_sounds[ni->type];
   329 	sound = _news_sounds[ni->type];
   303 	if (sound != 0)
   330 	if (sound != 0)
   304 		SndPlayFx(sound);
   331 		SndPlayFx(sound);
   305 
   332 
   306 	top = _screen.height - 4;
   333 	top = _screen.height - 4;
   307 	if (ni->display_mode == NM_NORMAL || ni->display_mode == NM_CALLBACK) {
   334 	switch (ni->display_mode) {
   308 		_news_type13_desc.top = top;
   335 		case NM_NORMAL:
   309 		w = AllocateWindowDesc(&_news_type13_desc);
   336 		case NM_CALLBACK: {
   310 		if (ni->flags & NF_VIEWPORT) {
   337 			_news_type13_desc.top = top;
   311 			AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E, ni->data_a | ((ni->flags&NF_VEHICLE) ? 0x80000000 : 0), 0);
   338 			w = AllocateWindowDesc(&_news_type13_desc);
   312 		}
   339 			if (ni->flags & NF_VIEWPORT)
   313 	} else if (ni->display_mode == NM_THIN) {
   340 				AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E,
   314 		_news_type2_desc.top = top;
   341 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), 0);
   315 		w = AllocateWindowDesc(&_news_type2_desc);
   342 			break;
   316 		if (ni->flags & NF_VIEWPORT) {
   343 		}
   317 			AssignWindowViewport(w, 2, 58, 0x1AA, 0x46, ni->data_a | ((ni->flags&NF_VEHICLE) ? 0x80000000 : 0), 0);
   344 
   318 		}
   345 		case NM_THIN: {
   319 	} else {
   346 			_news_type2_desc.top = top;
   320 		_news_type0_desc.top = top;
   347 			w = AllocateWindowDesc(&_news_type2_desc);
   321 		w = AllocateWindowDesc(&_news_type0_desc);
   348 			if (ni->flags & NF_VIEWPORT)
   322 		if (ni->flags & NF_VIEWPORT) {
   349 				AssignWindowViewport(w, 2, 58, 0x1AA, 0x46,
   323 			AssignWindowViewport(w, 3, 17, 0x112, 0x2F, ni->data_a | ((ni->flags&NF_VEHICLE) ? 0x80000000 : 0), 0);
   350 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), 0);
   324 		}
   351 			break;
   325 	}
   352 		}
   326 	WP(w,news_d).ni = &_news_items[(_forced_news==255)?_current_news:_forced_news];
   353 
       
   354 		default: {
       
   355 			_news_type0_desc.top = top;
       
   356 			w = AllocateWindowDesc(&_news_type0_desc);
       
   357 			if (ni->flags & NF_VIEWPORT)
       
   358 				AssignWindowViewport(w, 3, 17, 0x112, 0x2F,
       
   359 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), 0);
       
   360 			break;
       
   361 		}
       
   362 	}
       
   363 	WP(w, news_d).ni = &_news_items[_forced_news == INVALID_NEWS ? _current_news : _forced_news];
   327 	w->flags4 |= WF_DISABLE_VP_SCROLL;
   364 	w->flags4 |= WF_DISABLE_VP_SCROLL;
   328 }
   365 }
   329 
   366 
   330 // show news item in the ticker
   367 // show news item in the ticker
   331 static void ShowTicker(NewsItem *ni)
   368 static void ShowTicker(const NewsItem *ni)
   332 {
   369 {
   333 	Window *w;
   370 	Window *w;
   334 
   371 
   335 	SndPlayFx(20);
   372 	SndPlayFx(20);
   336 	_statusbar_news_item = *ni;
   373 	_statusbar_news_item = *ni;
   337 	w = FindWindowById(WC_STATUS_BAR, 0);
   374 	w = FindWindowById(WC_STATUS_BAR, 0);
   338 	if (w != 0)
   375 	if (w != NULL)
   339 		WP(w,def_d).data_1 = 360;
   376 		WP(w, def_d).data_1 = 360;
   340 }
   377 }
   341 
   378 
   342 
   379 
   343 // Are we ready to show another news item?
   380 // Are we ready to show another news item?
   344 // Only if nothing is in the newsticker and no newspaper is displayed
   381 // Only if nothing is in the newsticker and no newspaper is displayed
   345 static bool ReadyForNextItem()
   382 static bool ReadyForNextItem(void)
   346 {
   383 {
   347 	Window *w;
   384 	const Window *w;
   348 	byte item = (_forced_news==255)?_current_news:_forced_news;
   385 	byte item = _forced_news == INVALID_NEWS ? _current_news : _forced_news;
   349 	NewsItem *ni;
   386 	NewsItem *ni;
   350 
   387 
   351 	if(item>=MAX_NEWS) return true;
   388 	if (item >= MAX_NEWS) return true;
   352 	ni = &_news_items[item];
   389 	ni = &_news_items[item];
   353 
   390 
   354 	// Ticker message
   391 	// Ticker message
   355 	// Check if the status bar message is still being displayed?
   392 	// Check if the status bar message is still being displayed?
   356 	w = FindWindowById(WC_STATUS_BAR, 0);
   393 	w = FindWindowById(WC_STATUS_BAR, 0);
   357 	if (w != NULL && WP(w,def_d).data_1 > -1280)
   394 	if (w != NULL && WP(w, def_d).data_1 > -1280)
   358 	{
       
   359 		return false;
   395 		return false;
   360 	}
       
   361 
   396 
   362 	// Newspaper message
   397 	// Newspaper message
   363 	// Wait until duration reaches 0
   398 	// Wait until duration reaches 0
   364 	if (ni->duration != 0) {
   399 	if (ni->duration != 0) {
   365 		ni->duration--;
   400 		ni->duration--;
   368 
   403 
   369 	// neither newsticker nor newspaper are running
   404 	// neither newsticker nor newspaper are running
   370 	return true;
   405 	return true;
   371 }
   406 }
   372 
   407 
   373 static void MoveToNexItem()
   408 static void MoveToNexItem(void)
   374 {
   409 {
   375 	DeleteWindowById(WC_NEWS_WINDOW, 0);
   410 	DeleteWindowById(WC_NEWS_WINDOW, 0);
   376 	_forced_news = 255;
   411 	_forced_news = INVALID_NEWS;
   377 
   412 
   378 	// if we're not at the last item, than move on
   413 	// if we're not at the last item, than move on
   379 	if(_current_news != _latest_news)
   414 	if (_current_news != _latest_news) {
   380 	{
       
   381 		NewsItem *ni;
   415 		NewsItem *ni;
   382 
   416 
   383 		_current_news = increaseIndex(_current_news);
   417 		_current_news = increaseIndex(_current_news);
   384 		ni = &_news_items[_current_news];
   418 		ni = &_news_items[_current_news];
   385 
   419 
   386 		// check the date, don't show too old items
   420 		// check the date, don't show too old items
   387 		if(_date - _news_items_age[ni->type] > ni->date)
   421 		if (_date - _news_items_age[ni->type] > ni->date)
   388 			return;
   422 			return;
   389 
   423 
   390 		// show newspaper or send to ticker?
   424 		// show newspaper or send to ticker?
   391 		if(!HASBIT(_news_display_opt, ni->type) && !(ni->flags&NF_FORCE_BIG))
   425 		if (!HASBIT(_news_display_opt, ni->type) && !(ni->flags & NF_FORCE_BIG))
   392 			ShowTicker(ni);
   426 			ShowTicker(ni);
   393 		else
   427 		else
   394 			ShowNewspaper(ni);
   428 			ShowNewspaper(ni);
   395 	}
   429 	}
   396 }
   430 }
   397 
   431 
   398 void NewsLoop()
   432 void NewsLoop(void)
   399 {
   433 {
   400 	// no news item yet
   434 	// no news item yet
   401 	if(_total_news==0) return;
   435 	if (_total_news == 0) return;
   402 
   436 
   403 	if( ReadyForNextItem() )
   437 	if (ReadyForNextItem())
   404 		MoveToNexItem();
   438 		MoveToNexItem();
   405 }
   439 }
   406 
   440 
   407 /* Do a forced show of a specific message */
   441 /* Do a forced show of a specific message */
   408 void ShowNewsMessage(byte i)
   442 void ShowNewsMessage(byte i)
   409 {
   443 {
   410 	if(_total_news==0) return;
   444 	if (_total_news == 0) return;
   411 
   445 
   412 	// Delete the news window
   446 	// Delete the news window
   413 	DeleteWindowById(WC_NEWS_WINDOW, 0);
   447 	DeleteWindowById(WC_NEWS_WINDOW, 0);
   414 
   448 
   415 	// setup forced news item
   449 	// setup forced news item
   416 	_forced_news = i;
   450 	_forced_news = i;
   417 
   451 
   418 	if(_forced_news!=255)
   452 	if (_forced_news != INVALID_NEWS) {
   419 	{
       
   420 		NewsItem *ni = &_news_items[_forced_news];
   453 		NewsItem *ni = &_news_items[_forced_news];
   421 		ni->duration = 555;
   454 		ni->duration = 555;
   422 		ni->flags |= NF_NOEXPIRE | NF_FORCE_BIG;
   455 		ni->flags |= NF_NOEXPIRE | NF_FORCE_BIG;
   423 		DeleteWindowById(WC_NEWS_WINDOW, 0);
   456 		DeleteWindowById(WC_NEWS_WINDOW, 0);
   424 		ShowNewspaper(ni);
   457 		ShowNewspaper(ni);
   425 	}
   458 	}
   426 }
   459 }
   427 
   460 
   428 void ShowLastNewsMessage()
   461 void ShowLastNewsMessage(void)
   429 {
   462 {
   430 	if(_forced_news==255)
   463 	if (_forced_news == INVALID_NEWS)
   431 		ShowNewsMessage(_current_news);
   464 		ShowNewsMessage(_current_news);
   432 	else if(_forced_news!=0)
   465 	else if (_forced_news != 0)
   433 		ShowNewsMessage(_forced_news-1);
   466 		ShowNewsMessage(_forced_news - 1);
   434 	else {
   467 	else {
   435 		if(_total_news != MAX_NEWS)
   468 		if (_total_news != MAX_NEWS)
   436 			ShowNewsMessage(_latest_news);
   469 			ShowNewsMessage(_latest_news);
   437 		else
   470 		else
   438 			ShowNewsMessage(MAX_NEWS-1);
   471 			ShowNewsMessage(MAX_NEWS - 1);
   439 	}
   472 	}
   440 }
   473 }
   441 
   474 
   442 
   475 
   443 /* return news by number, with 0 being the most
   476 /* return news by number, with 0 being the most
   444 recent news. Returns 255 if end of queue reached. */
   477 recent news. Returns INVALID_NEWS if end of queue reached. */
   445 static byte getNews(byte i)
   478 static byte getNews(byte i)
   446 {
   479 {
   447 	if(i>=_total_news)
   480 	if (i >= _total_news)
   448 		return 255;
   481 		return INVALID_NEWS;
   449 
   482 
   450 	if(_latest_news < i)
   483 	if (_latest_news < i)
   451 		i = _latest_news + MAX_NEWS - i;
   484 		i = _latest_news + MAX_NEWS - i;
   452 	else
   485 	else
   453 		i = _latest_news - i;
   486 		i = _latest_news - i;
   454 
   487 
   455 	i = i % MAX_NEWS;
   488 	i %= MAX_NEWS;
   456 	return i;
   489 	return i;
   457 }
   490 }
   458 
   491 
   459 static void GetNewsString(NewsItem *ni, byte *buffer)
   492 static void GetNewsString(NewsItem *ni, byte *buffer)
   460 {
   493 {
   472 	assert(strlen(str_buffr) < sizeof(str_buffr) - 1);
   505 	assert(strlen(str_buffr) < sizeof(str_buffr) - 1);
   473 
   506 
   474 	s = str_buffr;
   507 	s = str_buffr;
   475 	d = buffer;
   508 	d = buffer;
   476 
   509 
   477 	for(;;s++) {
   510 	for (;; s++) {
   478 		// cut strings that are too long
   511 		// cut strings that are too long
   479 		if(s >= str_buffr + 55) {
   512 		if (s >= str_buffr + 55) {
   480 			d[0] = d[1] = d[2] = '.';
   513 			d[0] = d[1] = d[2] = '.';
   481 			d+=3;
   514 			d += 3;
   482 			*d = 0;
   515 			*d = '\0';
   483 			break;
   516 			break;
   484 		}
   517 		}
   485 
   518 
   486 		if (*s == 0) {
   519 		if (*s == '\0') {
   487 			*d = 0;
   520 			*d = '\0';
   488 			break;
   521 			break;
   489 		} else if (*s == 13) {
   522 		} else if (*s == '\r') {
   490 			d[0] = d[1] = d[2] = d[3] = ' ';
   523 			d[0] = d[1] = d[2] = d[3] = ' ';
   491 			d+=4;
   524 			d += 4;
   492 		} else if (*s >= ' ' && (*s < 0x88 || *s >= 0x99)) {
   525 		} else if (*s >= ' ' && (*s < 0x88 || *s >= 0x99)) {
   493 			*d++ = *s;
   526 			*d++ = *s;
   494 		}
   527 		}
   495 	}
   528 	}
   496 }
   529 }
   497 
   530 
   498 
   531 
   499 static void MessageHistoryWndProc(Window *w, WindowEvent *e)
   532 static void MessageHistoryWndProc(Window *w, WindowEvent *e)
   500 {
   533 {
   501 	switch(e->event) {
   534 	switch (e->event) {
   502 	case WE_PAINT: {
   535 	case WE_PAINT: {
   503 		byte buffer[256];
   536 		byte buffer[256];
   504 		int y=19;
   537 		int y = 19;
   505 		byte p, show;
   538 		byte p, show;
   506 		NewsItem *ni;
   539 		NewsItem *ni;
   507 
   540 
   508 		DrawWindowWidgets(w);
   541 		DrawWindowWidgets(w);
   509 
   542 
   510 		if(_total_news==0) break;
   543 		if (_total_news == 0) break;
   511 		show = min(_total_news, 10);
   544 		show = min(_total_news, 10);
   512 
   545 
   513 		for(p=w->vscroll.pos; p<w->vscroll.pos+show; p++)
   546 		for (p = w->vscroll.pos; p < w->vscroll.pos + show; p++) {
   514 		{
       
   515 			// get news in correct order
   547 			// get news in correct order
   516 			ni = &_news_items[ getNews(p) ];
   548 			ni = &_news_items[getNews(p)];
   517 
   549 
   518 			SET_DPARAM16(0, ni->date);
   550 			SET_DPARAM16(0, ni->date);
   519 			DrawString(4, y, STR_00AF, 16);
   551 			DrawString(4, y, STR_00AF, 16);
   520 
   552 
   521 			GetNewsString(ni, buffer);
   553 			GetNewsString(ni, buffer);
   525 
   557 
   526 		break;
   558 		break;
   527 	}
   559 	}
   528 
   560 
   529 	case WE_CLICK:
   561 	case WE_CLICK:
   530 		switch(e->click.widget) {
   562 		switch (e->click.widget) {
   531 		case 2: {
   563 		case 2: {
   532 			int y = (e->click.pt.y - 19) / 12;
   564 			int y = (e->click.pt.y - 19) / 12;
   533 			byte p, q;
   565 			byte p, q;
   534 
   566 
   535 			/* // === DEBUG code only
   567 			#if 0 // === DEBUG code only
   536 			for(p=0; p<_total_news; p++)
   568 			for (p = 0; p < _total_news; p++)
   537 			{
   569 			{
   538 				NewsItem *ni;
   570 				NewsItem *ni;
   539 				byte buffer[256];
   571 				byte buffer[256];
   540 				ni=&_news_items[p];
   572 				ni = &_news_items[p];
   541 				GetNewsString(ni, buffer);
   573 				GetNewsString(ni, buffer);
   542 				printf("%i\t%i\t%s\n", p, ni->date, buffer);
   574 				printf("%i\t%i\t%s\n", p, ni->date, buffer);
   543 			}
   575 			}
   544 			printf("=========================\n");
   576 			printf("=========================\n");
   545 			// === END OF DEBUG CODE */
   577 			#endif
   546 
   578 
   547 			p = y + w->vscroll.pos;
   579 			p = y + w->vscroll.pos;
   548 			if( p > _total_news-1 ) break;
   580 			if (p > _total_news - 1) break;
   549 
   581 
   550 			if(_latest_news >= p) q=_latest_news - p;
   582 			if (_latest_news >= p)
   551 			else q=_latest_news + MAX_NEWS - p;
   583 				q = _latest_news - p;
       
   584 			else
       
   585 				q = _latest_news + MAX_NEWS - p;
   552 			ShowNewsMessage(q);
   586 			ShowNewsMessage(q);
   553 
   587 
   554 			break;
   588 			break;
   555 		}
   589 		}
   556 		}
   590 		}
   566 {   WIDGETS_END},
   600 {   WIDGETS_END},
   567 };
   601 };
   568 
   602 
   569 static const WindowDesc _message_history_desc = {
   603 static const WindowDesc _message_history_desc = {
   570 	240, 22, 400, 140,
   604 	240, 22, 400, 140,
   571 	WC_MESSAGE_HISTORY,0,
   605 	WC_MESSAGE_HISTORY, 0,
   572 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
   606 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
   573 	_message_history_widgets,
   607 	_message_history_widgets,
   574 	MessageHistoryWndProc
   608 	MessageHistoryWndProc
   575 };
   609 };
   576 
   610 
   577 void ShowMessageHistory()
   611 void ShowMessageHistory(void)
   578 {
   612 {
   579 	Window *w;
   613 	Window *w;
   580 
   614 
   581 	DeleteWindowById(WC_MESSAGE_HISTORY, 0);
   615 	DeleteWindowById(WC_MESSAGE_HISTORY, 0);
   582 	w = AllocateWindowDesc(&_message_history_desc);
   616 	w = AllocateWindowDesc(&_message_history_desc);
   583 
   617 
   584 	if (w) {
   618 	if (w != NULL) {
   585 		w->vscroll.cap = 10;
   619 		w->vscroll.cap = 10;
   586 		w->vscroll.count = _total_news;
   620 		w->vscroll.count = _total_news;
   587 		SetWindowDirty(w);
   621 		SetWindowDirty(w);
   588 	}
   622 	}
   589 }
   623 }
   590 
   624 
   591 
   625 
   592 static void MessageOptionsWndProc(Window *w, WindowEvent *e)
   626 static void MessageOptionsWndProc(Window *w, WindowEvent *e)
   593 {
   627 {
   594 	switch(e->event) {
   628 	switch (e->event) {
   595 	case WE_PAINT: {
   629 	case WE_PAINT: {
   596 		uint16 x = _news_display_opt;
   630 		uint16 x = _news_display_opt;
   597 		uint32 cs = 0;
   631 		uint32 cs = 0;
   598 		int i, y;
   632 		int i, y;
   599 
   633 
   600 		for(i=3; i!=23; i+=2) {
   634 		for (i = 3; i != 23; i += 2) {
   601 			cs |= 1 << (i + (x&1));
   635 			cs |= 1 << (i + (x & 1));
   602 			x >>= 1;
   636 			x >>= 1;
   603 		}
   637 		}
   604 		cs |= (w->click_state >> 23) << 23;
   638 		cs |= (w->click_state >> 23) << 23;
   605 
   639 
   606 		w->click_state = cs;
   640 		w->click_state = cs;
   607 		DrawWindowWidgets(w);
   641 		DrawWindowWidgets(w);
   608 
   642 
   609 		DrawStringCentered(185, 15, STR_0205_MESSAGE_TYPES, 0);
   643 		DrawStringCentered(185, 15, STR_0205_MESSAGE_TYPES, 0);
   610 
   644 
   611 		y = 27;
   645 		y = 27;
   612 		for(i=STR_0206_ARRIVAL_OF_FIRST_VEHICLE; i <= STR_020F_GENERAL_INFORMATION; i++) {
   646 		for (i = STR_0206_ARRIVAL_OF_FIRST_VEHICLE; i <= STR_020F_GENERAL_INFORMATION; i++) {
   613 			DrawString(124, y, i, 0);
   647 			DrawString(124, y, i, 0);
   614 			y += 12;
   648 			y += 12;
   615 		}
   649 		}
   616 
   650 
   617 		break;
   651 		break;
   618 		}
   652 	}
   619 
   653 
   620 	case WE_CLICK: {
   654 	case WE_CLICK: {
   621 		int wid;
   655 		int wid;
   622 		if ( (uint)(wid=e->click.widget - 3) < 20) {
   656 		if ((uint)(wid = e->click.widget - 3) < 20) {
   623 			if (!(wid & 1)) {
   657 			if (!(wid & 1))
   624 				_news_display_opt &= ~(1 << (wid>>1));
   658 				_news_display_opt &= ~(1 << (wid / 2));
   625 			} else {
   659 			else
   626 				_news_display_opt |= (1 << (wid>>1));
   660 				_news_display_opt |= (1 << (wid / 2));
   627 			}
       
   628 			SetWindowDirty(w);
   661 			SetWindowDirty(w);
   629 			// XXX: write settings
   662 			// XXX: write settings
   630 		}
   663 		}
   631 		if( e->click.widget == 23) {
   664 		if (e->click.widget == 23) {
   632 			_news_display_opt = 0;
   665 			_news_display_opt = 0;
   633 			HandleButtonClick(w, 23);
   666 			HandleButtonClick(w, 23);
   634 			SetWindowDirty(w);
   667 			SetWindowDirty(w);
   635 		}
   668 		}
   636 		if( e->click.widget == 24) {
   669 		if (e->click.widget == 24) {
   637 			_news_display_opt = ~0;
   670 			_news_display_opt = ~0;
   638 			HandleButtonClick(w, 24);
   671 			HandleButtonClick(w, 24);
   639 			SetWindowDirty(w);
   672 			SetWindowDirty(w);
   640 		}
   673 		}
   641 	} break;
   674 	} break;
   673 {   WIDGETS_END},
   706 {   WIDGETS_END},
   674 };
   707 };
   675 
   708 
   676 static const WindowDesc _message_options_desc = {
   709 static const WindowDesc _message_options_desc = {
   677 	270, 22, 370, 173,
   710 	270, 22, 370, 173,
   678 	WC_GAME_OPTIONS,0,
   711 	WC_GAME_OPTIONS, 0,
   679 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
   712 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
   680 	_message_options_widgets,
   713 	_message_options_widgets,
   681 	MessageOptionsWndProc
   714 	MessageOptionsWndProc
   682 };
   715 };
   683 
   716 
   684 void ShowMessageOptions()
   717 void ShowMessageOptions(void)
   685 {
   718 {
   686 	DeleteWindowById(WC_GAME_OPTIONS, 0);
   719 	DeleteWindowById(WC_GAME_OPTIONS, 0);
   687 	AllocateWindowDesc(&_message_options_desc);
   720 	AllocateWindowDesc(&_message_options_desc);
   688 }
   721 }