src/news_gui.cpp
branchnoai
changeset 10294 7798ae816af8
parent 10249 58810805030e
child 10355 ee4b5f7a5bf2
equal deleted inserted replaced
10292:7856e972f8aa 10294:7798ae816af8
    51 
    51 
    52 typedef byte NewsID;
    52 typedef byte NewsID;
    53 #define INVALID_NEWS 255
    53 #define INVALID_NEWS 255
    54 
    54 
    55 NewsItem _statusbar_news_item;
    55 NewsItem _statusbar_news_item;
    56 uint32 _news_display_opt;
       
    57 bool _news_ticker_sound;
    56 bool _news_ticker_sound;
    58 static NewsItem _news_items[MAX_NEWS];      ///< The news FIFO queue
    57 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
    58 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
    59 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
    60 static NewsID _latest_news = INVALID_NEWS;  ///< points to last item in fifo queue
   333 	w->vscroll.count = _total_news;
   332 	w->vscroll.count = _total_news;
   334 }
   333 }
   335 
   334 
   336 
   335 
   337 /**
   336 /**
   338  * Maximum age of news items.
   337  * Per-NewsType data
   339  * Don't show item if it's older than x days, corresponds with NewsType in news_type.h
       
   340  * @see NewsType
       
   341  */
   338  */
   342 static const byte _news_items_age[NT_END] = {
   339 NewsTypeData _news_type_data[NT_END] = {
   343 	60,  ///< NT_ARRIVAL_PLAYER
   340 	/* name,              age, sound,           display */
   344 	60,  ///< NT_ARRIVAL_OTHER
   341 	{ "arrival_player",    60, SND_1D_APPLAUSE, ND_FULL },  ///< NT_ARRIVAL_PLAYER
   345 	90,  ///< NT_ACCIDENT
   342 	{ "arrival_other",     60, SND_1D_APPLAUSE, ND_FULL },  ///< NT_ARRIVAL_OTHER
   346 	60,  ///< NT_COMPANY_INFO
   343 	{ "accident",          90, SND_BEGIN,       ND_FULL },  ///< NT_ACCIDENT
   347 	90,  ///< NT_OPENCLOSE
   344 	{ "company_info",      60, SND_BEGIN,       ND_FULL },  ///< NT_COMPANY_INFO
   348 	30,  ///< NT_ECONOMY
   345 	{ "openclose",         90, SND_BEGIN,       ND_FULL },  ///< NT_OPENCLOSE
   349 	30,  ///< NT_INDUSTRY_PLAYER
   346 	{ "economy",           30, SND_BEGIN,       ND_FULL },  ///< NT_ECONOMY
   350 	30,  ///< NT_INDUSTRY_OTHER
   347 	{ "production_player", 30, SND_BEGIN,       ND_FULL },  ///< NT_INDUSTRY_PLAYER
   351 	30,  ///< NT_INDUSTRY_NOBODY
   348 	{ "production_other",  30, SND_BEGIN,       ND_FULL },  ///< NT_INDUSTRY_OTHER
   352 	150, ///< NT_ADVICE
   349 	{ "production_nobody", 30, SND_BEGIN,       ND_FULL },  ///< NT_INDUSTRY_NOBODY
   353 	30,  ///< NT_NEW_VEHICLES
   350 	{ "advice",           150, SND_BEGIN,       ND_FULL },  ///< NT_ADVICE
   354 	90,  ///< NT_ACCEPTANCE
   351 	{ "new_vehicles",      30, SND_1E_OOOOH,    ND_FULL },  ///< NT_NEW_VEHICLES
   355 	180, ///< NT_SUBSIDIES
   352 	{ "acceptance",        90, SND_BEGIN,       ND_FULL },  ///< NT_ACCEPTANCE
   356 	60   ///< NT_GENERAL
   353 	{ "subsidies",        180, SND_BEGIN,       ND_FULL },  ///< NT_SUBSIDIES
       
   354 	{ "general",           60, SND_BEGIN,       ND_FULL },  ///< NT_GENERAL
   357 };
   355 };
   358 
   356 
   359 
   357 
   360 static const Widget _news_type13_widgets[] = {
   358 static const Widget _news_type13_widgets[] = {
   361 {      WWT_PANEL,   RESIZE_NONE,    15,     0,   429,     0,   169, 0x0, STR_NULL},
   359 {      WWT_PANEL,   RESIZE_NONE,    15,     0,   429,     0,   169, 0x0, STR_NULL},
   399 	WDF_DEF_WIDGET,
   397 	WDF_DEF_WIDGET,
   400 	_news_type0_widgets,
   398 	_news_type0_widgets,
   401 	NewsWindowProc
   399 	NewsWindowProc
   402 };
   400 };
   403 
   401 
   404 static const SoundFx _news_sounds[NT_END] = {
       
   405 	SND_1D_APPLAUSE, ///< NT_ARRIVAL_PLAYER
       
   406 	SND_1D_APPLAUSE, ///< NT_ARRIVAL_OTHER
       
   407 	SND_BEGIN,       ///< NT_ACCIDENT
       
   408 	SND_BEGIN,       ///< NT_COMPANY_INFO
       
   409 	SND_BEGIN,       ///< NT_OPENCLOSE
       
   410 	SND_BEGIN,       ///< NT_ECONOMY
       
   411 	SND_BEGIN,       ///< NT_INDUSTRY_PLAYER
       
   412 	SND_BEGIN,       ///< NT_INDUSTRY_OTHER
       
   413 	SND_BEGIN,       ///< NT_INDUSTRY_NOBODY
       
   414 	SND_BEGIN,       ///< NT_ADVICE
       
   415 	SND_1E_OOOOH,    ///< NT_NEW_VEHICLES
       
   416 	SND_BEGIN,       ///< NT_ACCEPTANCE
       
   417 	SND_BEGIN,       ///< NT_SUBSIDIES
       
   418 	SND_BEGIN,       ///< NT_GENERAL
       
   419 };
       
   420 
       
   421 const char *_news_display_name[NT_END] = {
       
   422 	"arrival_player",
       
   423 	"arrival_other",
       
   424 	"accident",
       
   425 	"company_info",
       
   426 	"openclose",
       
   427 	"economy",
       
   428 	"production_player",
       
   429 	"production_other",
       
   430 	"production_nobody",
       
   431 	"advice",
       
   432 	"new_vehicles",
       
   433 	"acceptance",
       
   434 	"subsidies",
       
   435 	"general",
       
   436 };
       
   437 
       
   438 /**
       
   439  * Get the value of an item of the news-display settings. This is
       
   440  * a little tricky since on/off/summary must use 2 bits to store the value
       
   441  * @param item the item whose value is requested
       
   442  * @return return the found value which is between 0-2
       
   443  */
       
   444 static inline byte GetNewsDisplayValue(byte item)
       
   445 {
       
   446 	assert(item < NT_END && GB(_news_display_opt, item * 2, 2) <= 2);
       
   447 	return GB(_news_display_opt, item * 2, 2);
       
   448 }
       
   449 
       
   450 /**
       
   451  * Set the value of an item in the news-display settings. This is
       
   452  * a little tricky since on/off/summary must use 2 bits to store the value
       
   453  * @param item the item whose value is being set
       
   454  * @param val new value
       
   455  */
       
   456 static inline void SetNewsDisplayValue(byte item, byte val)
       
   457 {
       
   458 	assert(item < NT_END && val <= 2);
       
   459 	SB(_news_display_opt, item * 2, 2, val);
       
   460 }
       
   461 
   402 
   462 /** Open up an own newspaper window for the news item */
   403 /** Open up an own newspaper window for the news item */
   463 static void ShowNewspaper(NewsItem *ni)
   404 static void ShowNewspaper(NewsItem *ni)
   464 {
   405 {
   465 	ni->flags &= ~NF_FORCE_BIG;
   406 	ni->flags &= ~NF_FORCE_BIG;
   466 	ni->duration = 555;
   407 	ni->duration = 555;
   467 
   408 
   468 	SoundFx sound = _news_sounds[ni->type];
   409 	SoundFx sound = _news_type_data[ni->type].sound;
   469 	if (sound != 0) SndPlayFx(sound);
   410 	if (sound != 0) SndPlayFx(sound);
   470 
   411 
   471 	int top = _screen.height;
   412 	int top = _screen.height;
   472 	Window *w;
   413 	Window *w;
   473 	switch (ni->display_mode) {
   414 	switch (ni->display_mode) {
   474 		case NM_NORMAL:
   415 		case NM_NORMAL:
   475 		case NM_CALLBACK:
   416 		case NM_CALLBACK:
   476 			_news_type13_desc.top = top;
   417 			_news_type13_desc.top = top;
   477 			w = AllocateWindowDesc(&_news_type13_desc);
   418 			w = AllocateWindowDesc(&_news_type13_desc);
   478 			if (ni->flags & NF_VIEWPORT) {
   419 			if (ni->flags & NF_VIEWPORT) {
   479 				AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E,
   420 				InitializeWindowViewport(w, 2, 58, 426, 110,
   480 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
   421 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
   481 			}
   422 			}
   482 			break;
   423 			break;
   483 
   424 
   484 		case NM_THIN:
   425 		case NM_THIN:
   485 			_news_type2_desc.top = top;
   426 			_news_type2_desc.top = top;
   486 			w = AllocateWindowDesc(&_news_type2_desc);
   427 			w = AllocateWindowDesc(&_news_type2_desc);
   487 			if (ni->flags & NF_VIEWPORT) {
   428 			if (ni->flags & NF_VIEWPORT) {
   488 				AssignWindowViewport(w, 2, 58, 0x1AA, 0x46,
   429 				InitializeWindowViewport(w, 2, 58, 426, 70,
   489 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
   430 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
   490 			}
   431 			}
   491 			break;
   432 			break;
   492 
   433 
   493 		default:
   434 		default:
   494 			_news_type0_desc.top = top;
   435 			_news_type0_desc.top = top;
   495 			w = AllocateWindowDesc(&_news_type0_desc);
   436 			w = AllocateWindowDesc(&_news_type0_desc);
   496 			if (ni->flags & NF_VIEWPORT) {
   437 			if (ni->flags & NF_VIEWPORT) {
   497 				AssignWindowViewport(w, 3, 17, 0x112, 0x2F,
   438 				InitializeWindowViewport(w, 3, 17, 274, 47,
   498 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
   439 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
   499 			}
   440 			}
   500 			break;
   441 			break;
   501 	}
   442 	}
   502 
   443 
   551 	if (_current_news != _latest_news) {
   492 	if (_current_news != _latest_news) {
   552 		_current_news = (_current_news == INVALID_NEWS) ? _oldest_news : IncreaseIndex(_current_news);
   493 		_current_news = (_current_news == INVALID_NEWS) ? _oldest_news : IncreaseIndex(_current_news);
   553 		NewsItem *ni = &_news_items[_current_news];
   494 		NewsItem *ni = &_news_items[_current_news];
   554 
   495 
   555 		/* check the date, don't show too old items */
   496 		/* check the date, don't show too old items */
   556 		if (_date - _news_items_age[ni->type] > ni->date) return;
   497 		if (_date - _news_type_data[ni->type].age > ni->date) return;
   557 
   498 
   558 		switch (GetNewsDisplayValue(ni->type)) {
   499 		switch (_news_type_data[ni->type].display) {
   559 			default: NOT_REACHED();
   500 			default: NOT_REACHED();
   560 			case 0: { // Off - show nothing only a small reminder in the status bar
   501 			case ND_OFF: { // Off - show nothing only a small reminder in the status bar
   561 				Window *w = FindWindowById(WC_STATUS_BAR, 0);
   502 				Window *w = FindWindowById(WC_STATUS_BAR, 0);
   562 
   503 
   563 				if (w != NULL) {
   504 				if (w != NULL) {
   564 					WP(w, def_d).data_2 = 91;
   505 					WP(w, def_d).data_2 = 91;
   565 					SetWindowDirty(w);
   506 					SetWindowDirty(w);
   566 				}
   507 				}
   567 				break;
   508 				break;
   568 			}
   509 			}
   569 
   510 
   570 			case 1: // Summary - show ticker, but if forced big, cascade to full
   511 			case ND_SUMMARY: // Summary - show ticker, but if forced big, cascade to full
   571 				if (!(ni->flags & NF_FORCE_BIG)) {
   512 				if (!(ni->flags & NF_FORCE_BIG)) {
   572 					ShowTicker(ni);
   513 					ShowTicker(ni);
   573 					break;
   514 					break;
   574 				}
   515 				}
   575 				/* Fallthrough */
   516 				/* Fallthrough */
   576 
   517 
   577 			case 2: // Full - show newspaper
   518 			case ND_FULL: // Full - show newspaper
   578 				ShowNewspaper(ni);
   519 				ShowNewspaper(ni);
   579 				break;
   520 				break;
   580 		}
   521 		}
   581 	}
   522 	}
   582 }
   523 }
   801 	static const StringID message_opt[] = {STR_OFF, STR_SUMMARY, STR_FULL, INVALID_STRING_ID};
   742 	static const StringID message_opt[] = {STR_OFF, STR_SUMMARY, STR_FULL, INVALID_STRING_ID};
   802 
   743 
   803 	/* WP(w, def_d).data_1 stores state of the ALL on/off/summary button */
   744 	/* WP(w, def_d).data_1 stores state of the ALL on/off/summary button */
   804 	switch (e->event) {
   745 	switch (e->event) {
   805 		case WE_CREATE: {
   746 		case WE_CREATE: {
   806 			uint32 val = _news_display_opt;
   747 			NewsDisplay all_val;
   807 			uint32 all_val;
       
   808 
   748 
   809 			/* Set up the initial disabled buttons in the case of 'off' or 'full' */
   749 			/* Set up the initial disabled buttons in the case of 'off' or 'full' */
   810 			all_val = val & 0x3;
   750 			all_val = _news_type_data[0].display;
   811 			for (int i = 0; i < NT_END; i++, val >>= 2) {
   751 			for (int i = 0; i < NT_END; i++) {
   812 				SetMessageButtonStates(w, val & 0x3, i);
   752 				SetMessageButtonStates(w, _news_type_data[i].display, i);
   813 				/* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */
   753 				/* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */
   814 				if ((val & 0x3) != all_val) all_val = 0;
   754 				if (_news_type_data[i].display != all_val) all_val = ND_OFF;
   815 			}
   755 			}
   816 			/* If all values are the same value, the ALL-button will take over this value */
   756 			/* If all values are the same value, the ALL-button will take over this value */
   817 			WP(w, def_d).data_1 = all_val;
   757 			WP(w, def_d).data_1 = all_val;
   818 		} break;
   758 		} break;
   819 
   759 
   820 		case WE_PAINT: {
   760 		case WE_PAINT: {
   821 			uint32 val = _news_display_opt;
       
   822 
       
   823 			if (_news_ticker_sound) w->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER);
   761 			if (_news_ticker_sound) w->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER);
   824 
   762 
   825 			w->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = message_opt[WP(w, def_d).data_1];
   763 			w->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = message_opt[WP(w, def_d).data_1];
   826 			DrawWindowWidgets(w);
   764 			DrawWindowWidgets(w);
   827 
   765 
   828 			/* Draw the string of each setting on each button. */
   766 			/* Draw the string of each setting on each button. */
   829 			for (int i = 0, y = 26; i < NT_END; i++, y += 12, val >>= 2) {
   767 			for (int i = 0, y = 26; i < NT_END; i++, y += 12) {
   830 				/* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division,
   768 				/* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division,
   831 				 * which will give centered position */
   769 				 * which will give centered position */
   832 				DrawStringCentered(51, y + 1, message_opt[val & 0x3], TC_BLACK);
   770 				DrawStringCentered(51, y + 1, message_opt[_news_type_data[i].display], TC_BLACK);
   833 			}
   771 			}
   834 		} break;
   772 		} break;
   835 
   773 
   836 		case WE_CLICK:
   774 		case WE_CLICK:
   837 			switch (e->we.click.widget) {
   775 			switch (e->we.click.widget) {
   847 
   785 
   848 				default: { // Clicked on the [<] .. [>] widgets
   786 				default: { // Clicked on the [<] .. [>] widgets
   849 					int wid = e->we.click.widget - WIDGET_NEWSOPT_START_OPTION;
   787 					int wid = e->we.click.widget - WIDGET_NEWSOPT_START_OPTION;
   850 					if (wid >= 0 && wid < (NB_WIDG_PER_SETTING * NT_END)) {
   788 					if (wid >= 0 && wid < (NB_WIDG_PER_SETTING * NT_END)) {
   851 						int element = wid / NB_WIDG_PER_SETTING;
   789 						int element = wid / NB_WIDG_PER_SETTING;
   852 						byte val = (GetNewsDisplayValue(element) + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3;
   790 						byte val = (_news_type_data[element].display + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3;
   853 
   791 
   854 						SetMessageButtonStates(w, val, element);
   792 						SetMessageButtonStates(w, val, element);
   855 						SetNewsDisplayValue(element, val);
   793 						_news_type_data[element].display = (NewsDisplay)val;
   856 						SetWindowDirty(w);
   794 						SetWindowDirty(w);
   857 					}
   795 					}
   858 				} break;
   796 				} break;
   859 			}
   797 			}
   860 			break;
   798 			break;
   862 		case WE_DROPDOWN_SELECT: // Select all settings for newsmessages
   800 		case WE_DROPDOWN_SELECT: // Select all settings for newsmessages
   863 			WP(w, def_d).data_1 = e->we.dropdown.index;
   801 			WP(w, def_d).data_1 = e->we.dropdown.index;
   864 
   802 
   865 			for (int i = 0; i < NT_END; i++) {
   803 			for (int i = 0; i < NT_END; i++) {
   866 				SetMessageButtonStates(w, e->we.dropdown.index, i);
   804 				SetMessageButtonStates(w, e->we.dropdown.index, i);
   867 				SetNewsDisplayValue(i, e->we.dropdown.index);
   805 				_news_type_data[i].display = (NewsDisplay)e->we.dropdown.index;
   868 			}
   806 			}
   869 			SetWindowDirty(w);
   807 			SetWindowDirty(w);
   870 			break;
   808 			break;
   871 	}
   809 	}
   872 }
   810 }