src/news_gui.cpp
branchnoai
changeset 9826 9707ad4c9b60
parent 9724 b39bc69bb2f2
child 9837 c9ec4f82e0d0
equal deleted inserted replaced
9825:cc77111ebd85 9826:9707ad4c9b60
     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 			ViewPort *vp;
   128 
   138 
   129 		switch (ni->display_mode) {
   139 			switch (ni->display_mode) {
   130 			case NM_NORMAL:
   140 				case NM_NORMAL:
   131 			case NM_THIN: {
   141 				case NM_THIN: {
   132 				DrawNewsBorder(w);
   142 					DrawNewsBorder(w);
   133 
   143 
   134 				DrawString(2, 1, STR_00C6, TC_FROMSTRING);
   144 					DrawString(2, 1, STR_00C6, TC_FROMSTRING);
   135 
   145 
   136 				SetDParam(0, ni->date);
   146 					SetDParam(0, ni->date);
   137 				DrawStringRightAligned(428, 1, STR_01FF, TC_FROMSTRING);
   147 					DrawStringRightAligned(428, 1, STR_01FF, TC_FROMSTRING);
   138 
   148 
   139 				if (!(ni->flags & NF_VIEWPORT)) {
   149 					if (!(ni->flags & NF_VIEWPORT)) {
   140 					CopyInDParam(0, ni->params, lengthof(ni->params));
   150 						CopyInDParam(0, ni->params, lengthof(ni->params));
   141 					DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56,
   151 						DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56,
   142 						ni->string_id, w->width - 4);
   152 							ni->string_id, w->width - 4);
   143 				} else {
   153 					} else {
   144 					/* Back up transparency options to draw news view */
   154 						/* Back up transparency options to draw news view */
   145 					TransparencyOptionBits to_backup = _transparency_opt;
   155 						TransparencyOptionBits to_backup = _transparency_opt;
   146 					_transparency_opt = 0;
   156 						_transparency_opt = 0;
   147 					DrawWindowViewport(w);
   157 						DrawWindowViewport(w);
   148 					_transparency_opt = to_backup;
   158 						_transparency_opt = to_backup;
   149 
   159 
   150 					/* Shade the viewport into gray, or color*/
   160 						/* Shade the viewport into gray, or color*/
   151 					vp = w->viewport;
   161 						vp = w->viewport;
   152 					GfxFillRect(vp->left - w->left, vp->top - w->top,
   162 						GfxFillRect(vp->left - w->left, vp->top - w->top,
   153 						vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1,
   163 							vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1,
   154 						(ni->flags & NF_INCOLOR ? PALETTE_TO_TRANSPARENT : PALETTE_TO_STRUCT_GREY) | (1 << USE_COLORTABLE)
   164 							(ni->flags & NF_INCOLOR ? PALETTE_TO_TRANSPARENT : PALETTE_TO_STRUCT_GREY) | (1 << USE_COLORTABLE)
   155 					);
   165 						);
   156 
   166 
   157 					CopyInDParam(0, ni->params, lengthof(ni->params));
   167 						CopyInDParam(0, ni->params, lengthof(ni->params));
   158 					DrawStringMultiCenter(w->width / 2, 20, ni->string_id, w->width - 4);
   168 						DrawStringMultiCenter(w->width / 2, 20, ni->string_id, w->width - 4);
       
   169 					}
       
   170 					break;
   159 				}
   171 				}
   160 				break;
   172 
   161 			}
   173 				case NM_CALLBACK: {
   162 
   174 					_draw_news_callback[ni->callback](w, ni);
   163 			case NM_CALLBACK: {
   175 					break;
   164 				_draw_news_callback[ni->callback](w);
       
   165 				break;
       
   166 			}
       
   167 
       
   168 			default: {
       
   169 				DrawWindowWidgets(w);
       
   170 				if (!(ni->flags & NF_VIEWPORT)) {
       
   171 					CopyInDParam(0, ni->params, lengthof(ni->params));
       
   172 					DrawStringMultiCenter(140, 38, ni->string_id, 276);
       
   173 				} else {
       
   174 					DrawWindowViewport(w);
       
   175 					CopyInDParam(0, ni->params, lengthof(ni->params));
       
   176 					DrawStringMultiCenter(w->width / 2, w->height - 16, ni->string_id, w->width - 4);
       
   177 				}
   176 				}
   178 				break;
   177 
   179 			}
   178 				default: {
   180 		}
   179 					DrawWindowWidgets(w);
   181 	} break;
   180 					if (!(ni->flags & NF_VIEWPORT)) {
   182 
   181 						CopyInDParam(0, ni->params, lengthof(ni->params));
   183 	case WE_CLICK: {
   182 						DrawStringMultiCenter(140, 38, ni->string_id, 276);
   184 		switch (e->we.click.widget) {
   183 					} else {
   185 		case 1: {
   184 						DrawWindowViewport(w);
   186 			NewsItem *ni = WP(w, news_d).ni;
   185 						CopyInDParam(0, ni->params, lengthof(ni->params));
   187 			DeleteWindow(w);
   186 						DrawStringMultiCenter(w->width / 2, w->height - 16, ni->string_id, w->width - 4);
   188 			ni->duration = 0;
   187 					}
   189 			_forced_news = INVALID_NEWS;
   188 					break;
   190 		} break;
   189 				}
   191 		case 0: {
       
   192 			NewsItem *ni = WP(w, news_d).ni;
       
   193 			if (ni->flags & NF_VEHICLE) {
       
   194 				Vehicle *v = GetVehicle(ni->data_a);
       
   195 				ScrollMainWindowTo(v->x_pos, v->y_pos);
       
   196 			} else if (ni->flags & NF_TILE) {
       
   197 				if (!ScrollMainWindowToTile(ni->data_a) && ni->data_b != 0)
       
   198 					ScrollMainWindowToTile(ni->data_b);
       
   199 			}
   190 			}
   200 		} break;
   191 		} break;
   201 		}
   192 
   202 	} break;
   193 		case WE_CLICK: {
   203 
   194 			switch (e->we.click.widget) {
   204 	case WE_KEYPRESS:
   195 			case 1: {
   205 		if (e->we.keypress.keycode == WKC_SPACE) {
   196 				NewsItem *ni = WP(w, news_d).ni;
   206 			/* Don't continue. */
   197 				DeleteWindow(w);
   207 			e->we.keypress.cont = false;
   198 				ni->duration = 0;
   208 			DeleteWindow(w);
   199 				_forced_news = INVALID_NEWS;
   209 		}
   200 			} break;
   210 		break;
   201 			case 0: {
   211 
   202 				NewsItem *ni = WP(w, news_d).ni;
   212 	case WE_MESSAGE: // The chatbar has notified us that is was either created or closed
   203 				if (ni->flags & NF_VEHICLE) {
   213 		switch (e->we.message.msg) {
   204 					Vehicle *v = GetVehicle(ni->data_a);
   214 			case WE_CREATE: w->message.msg = e->we.message.wparam; break;
   205 					ScrollMainWindowTo(v->x_pos, v->y_pos);
   215 			case WE_DESTROY: w->message.msg = 0; break;
   206 				} else if (ni->flags & NF_TILE) {
   216 		}
   207 					if (!ScrollMainWindowToTile(ni->data_a) && ni->data_b != 0)
   217 		break;
   208 						ScrollMainWindowToTile(ni->data_b);
   218 
   209 				}
   219 	case WE_TICK: { // Scroll up newsmessages from the bottom in steps of 4 pixels
   210 			} break;
   220 		int diff;
   211 			}
   221 		int y = max(w->top - 4, _screen.height - w->height - 12 - w->message.msg);
   212 		} break;
   222 		if (y == w->top) return;
   213 
   223 
   214 		case WE_KEYPRESS:
   224 		if (w->viewport != NULL)
   215 			if (e->we.keypress.keycode == WKC_SPACE) {
   225 			w->viewport->top += y - w->top;
   216 				/* Don't continue. */
   226 
   217 				e->we.keypress.cont = false;
   227 		diff = Delta(w->top, y);
   218 				DeleteWindow(w);
   228 		w->top = y;
   219 			}
   229 
   220 			break;
   230 		SetDirtyBlocks(w->left, w->top - diff, w->left + w->width, w->top + w->height);
   221 
   231 	} break;
   222 		case WE_MESSAGE: // The chatbar has notified us that is was either created or closed
       
   223 			switch (e->we.message.msg) {
       
   224 				case WE_CREATE: w->message.msg = e->we.message.wparam; break;
       
   225 				case WE_DESTROY: w->message.msg = 0; break;
       
   226 			}
       
   227 			break;
       
   228 
       
   229 		case WE_TICK: { // Scroll up newsmessages from the bottom in steps of 4 pixels
       
   230 			int diff;
       
   231 			int y = max(w->top - 4, _screen.height - w->height - 12 - w->message.msg);
       
   232 			if (y == w->top) return;
       
   233 
       
   234 			if (w->viewport != NULL)
       
   235 				w->viewport->top += y - w->top;
       
   236 
       
   237 			diff = Delta(w->top, y);
       
   238 			w->top = y;
       
   239 
       
   240 			SetDirtyBlocks(w->left, w->top - diff, w->left + w->width, w->top + w->height);
       
   241 		} break;
   232 	}
   242 	}
   233 }
   243 }
   234 
   244 
   235 /**
   245 /**
   236  * Return the correct index in the pseudo-fifo
   246  * Return the correct index in the pseudo-fifo
   252 	return (i + MAX_NEWS - 1) % MAX_NEWS;
   262 	return (i + MAX_NEWS - 1) % MAX_NEWS;
   253 }
   263 }
   254 
   264 
   255 /**
   265 /**
   256  * Add a new newsitem to be shown.
   266  * Add a new newsitem to be shown.
   257  * @param string String to display, can have special values based on parameter \a flags
   267  * @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()
   268  * @param display_mode, any of the NewsMode enums (NM_)
       
   269  * @param flags any of the NewsFlag enums (NF_)
       
   270  * @param type news category, any of the NewsType enums (NT_)
       
   271  * @param callback news callback function, any of the NewsCallback enums (DNC_)
   259  * @param data_a news-specific value based on news type
   272  * @param data_a news-specific value based on news type
   260  * @param data_b news-specific value based on news type
   273  * @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  *
   274  *
   267  * If the display mode is NM_CALLBACK, special news is shown and parameter
   275  * @note If the display mode is NM_CALLBACK, special news is shown and parameter
   268  * \a string has a special meaning.
   276  * \a string has a special meaning.
   269  *  - For DNC_TRAINAVAIL, DNC_ROADAVAIL, DNC_SHIPAVAIL, DNC_AIRCRAFTAVAIL messages: StringID is
   277  *  - For DNC_TRAINAVAIL, DNC_ROADAVAIL, DNC_SHIPAVAIL, DNC_AIRCRAFTAVAIL messages: StringID is
   270  *    the index of the engine that is shown
   278  *    the index of the engine that is shown
   271  *
   279  *
   272  *  - For DNC_BANKRUPCY: bytes 0-3 of StringID contains the player that is in trouble,
   280  *  - 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.
   281  *    and 4-7 contains what kind of bankrupcy message is shown.
   274  *    @see NewsBankrupcy
   282  *    @see NewsBankrupcy
   275  *
   283  *
   276  * @see NewsMode
   284  * @see NewsMode
   277  * @see NewsFlags
   285  * @see NewsFlag
   278  * @see NewsType
   286  * @see NewsType
   279  * @see NewsCallback
   287  * @see NewsCallback
   280  */
   288  */
   281 void AddNewsItem(StringID string, uint32 flags, uint data_a, uint data_b)
   289 void AddNewsItem(StringID string, NewsMode display_mode, NewsFlag flags, NewsType type, NewsCallback callback, uint data_a, uint data_b)
   282 {
   290 {
   283 	NewsID l_news;
   291 	NewsID l_news;
   284 
   292 
   285 	if (_game_mode == GM_MENU) return;
   293 	if (_game_mode == GM_MENU) return;
   286 
   294 
   304 
   312 
   305 	/*DEBUG(misc, 0, "+cur %3d, old %2d, lat %3d, for %3d, tot %2d",
   313 	/*DEBUG(misc, 0, "+cur %3d, old %2d, lat %3d, for %3d, tot %2d",
   306 	  _current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/
   314 	  _current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/
   307 
   315 
   308 	/* Add news to _latest_news */
   316 	/* Add news to _latest_news */
   309 	{
   317 	NewsItem *ni = &_news_items[_latest_news];
   310 		Window *w;
   318 	memset(ni, 0, sizeof(*ni));
   311 		NewsItem *ni = &_news_items[_latest_news];
   319 
   312 		memset(ni, 0, sizeof(*ni));
   320 	ni->string_id = string;
   313 
   321 	ni->display_mode = display_mode;
   314 		ni->string_id = string;
   322 	ni->flags = flags;
   315 		ni->display_mode = (byte)flags;
   323 
   316 		ni->flags = (byte)(flags >> 8);
   324 	/* show this news message in color? */
   317 
   325 	if (_cur_year >= _patches.colored_news_year) ni->flags |= NF_INCOLOR;
   318 		/* show this news message in color? */
   326 
   319 		if (_cur_year >= _patches.colored_news_year) ni->flags |= NF_INCOLOR;
   327 	ni->type = type;
   320 
   328 	ni->callback = callback;
   321 		ni->type = (byte)(flags >> 16);
   329 	ni->data_a = data_a;
   322 		ni->callback = (byte)(flags >> 24);
   330 	ni->data_b = data_b;
   323 		ni->data_a = data_a;
   331 	ni->date = _date;
   324 		ni->data_b = data_b;
   332 	CopyOutDParam(ni->params, 0, lengthof(ni->params));
   325 		ni->date = _date;
   333 
   326 		CopyOutDParam(ni->params, 0, lengthof(ni->params));
   334 	Window *w = FindWindowById(WC_MESSAGE_HISTORY, 0);
   327 
   335 	if (w == NULL) return;
   328 		w = FindWindowById(WC_MESSAGE_HISTORY, 0);
   336 	SetWindowDirty(w);
   329 		if (w == NULL) return;
   337 	w->vscroll.count = _total_news;
   330 		SetWindowDirty(w);
       
   331 		w->vscroll.count = _total_news;
       
   332 	}
       
   333 }
   338 }
   334 
   339 
   335 
   340 
   336 /**
   341 /**
   337  * Maximum age of news items.
   342  * Maximum age of news items.
   338  * Don't show item if it's older than x days, corresponds with NewsType in news.h
   343  * Don't show item if it's older than x days, corresponds with NewsType in news_type.h
   339  * @see NewsType
   344  * @see NewsType
   340  */
   345  */
   341 static const byte _news_items_age[NT_END] = {
   346 static const byte _news_items_age[NT_END] = {
   342 	60,  ///< NT_ARRIVAL_PLAYER
   347 	60,  ///< NT_ARRIVAL_PLAYER
   343 	60,  ///< NT_ARRIVAL_OTHER
   348 	60,  ///< NT_ARRIVAL_OTHER