1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1999-2000 Revolution Software Ltd.
9  * This code is based on source code created by Revolution Software,
10  * used with permission.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "engines/icb/icon_menu.h"
29 #include "engines/icb/icon_menu_pc.h"
30 #include "engines/icb/global_objects.h"
31 #include "engines/icb/global_switches.h"
32 #include "engines/icb/res_man.h"
33 #include "engines/icb/mission.h"
34 #include "engines/icb/remora.h"
35 
36 namespace ICB {
37 
38 // Armed menu positioning  -- I've put these here as they are not need outside this file,
39 // and I don't like the rebuild over head when the are in the .h file
40 #define ICON_ARMED_MENU_PIXEL_X (ICON_MENU_PIXEL_X)
41 #define ICON_ARMED_MENU_PIXEL_Y (10)
42 
43 LRECT ICON_BITMAP_RECT = {0, 0, ICON_X_SIZE - 1, ICON_Y_SIZE - 1};
44 LRECT ICON_ADDING_RECT = {ICON_ADDING_X, ICON_ADDING_Y, ICON_ADDING_X + ICON_X_SIZE - 1, ICON_ADDING_Y + ICON_Y_SIZE - 1};
45 
Activate(const _icon_list * pIconList,const _icon_menu_duplicates & sDuplicates,bool8 bAllowEscape,uint32 nSelected)46 void _icon_menu::Activate(const _icon_list *pIconList, const _icon_menu_duplicates &sDuplicates, bool8 bAllowEscape, uint32 nSelected) {
47 	uint32 i;
48 	uint8 *pyIconBitmap;
49 	uint8 *pyHiLiteBitmap;
50 	uint32 nIconCount;
51 	char pcIconName[MAXLEN_ICON_NAME];
52 	char pcFullIconName[MAXLEN_URL];
53 	char pcIconPath[MAXLEN_URL];
54 	uint32 nFullIconNameHash;
55 	_pxBitmap *psIconBitmap;
56 
57 	Zdebug("Entered _icon_menu::Activate()");
58 
59 	PXTRY
60 
61 	// If we are not in the remora, then we want to scroll the icons onto the screen
62 	if (g_oRemora->IsActive())
63 		m_nMenuY = ICON_MENU_PIXEL_Y;
64 	else
65 		m_nMenuY = 490;
66 
67 	// This allows us to ignore extra key presses from instantly closing the menu again.
68 	m_nKeyLock = TRUE8;
69 
70 	// Tell the game that the menu is now active.
71 	m_eIconMenuGameState = ACTIVE;
72 
73 	// Set some parameters to do with the icons.
74 	m_nSelectedIcon = nSelected;
75 	m_bValidSelection = FALSE8;
76 	m_pIconList = pIconList;
77 	nIconCount = pIconList->GetIconCount();
78 	m_sDuplicates = sDuplicates;
79 	m_bAllowEscape = bAllowEscape;
80 	m_nLastIconIndex = (uint8)nSelected;
81 	m_nScrollCycles = 0;
82 	m_nScrollDirection = ICON_MENU_SCROLL_NONE;
83 
84 	// The maximum number of icons that can be displayed is reduced by one if there is currently an
85 	// email waiting because we need room to display the symbol for that.
86 	m_nMaxIconsDisplayed = (m_bEmailArrived) ? (uint8)(ICON_LIST_MAX_DISPLAYED - 1) : (uint8)ICON_LIST_MAX_DISPLAYED;
87 
88 	// Check if there are too many icons to display.
89 	if (nIconCount > m_nMaxIconsDisplayed) {
90 		// Set this flag so the drawing code knows about it.
91 		m_bWiderThanScreen = TRUE8;
92 
93 		// Prepare the off-screen arrows for drawing.
94 		SetUpOffScreenArrows();
95 	} else {
96 		// Icons fit on screen.
97 		m_bWiderThanScreen = FALSE8;
98 	}
99 
100 	// Loop for each icon to be drawn.
101 	for (i = 0; i < nIconCount; ++i) {
102 		// Get the full pathname for the icon.
103 		strcpy(pcIconName, m_pIconList->GetIcon(i));
104 		sprintf(pcIconPath, ICON_PATH);
105 		sprintf(pcFullIconName, "%s%s.%s", pcIconPath, pcIconName, PX_BITMAP_PC_EXT);
106 
107 		// Open the icon resource.
108 		nFullIconNameHash = NULL_HASH;
109 		psIconBitmap = (_pxBitmap *)rs_icons->Res_open(pcFullIconName, nFullIconNameHash, m_pcIconCluster, m_nIconClusterHash);
110 
111 		// Check the schema is correct.
112 		if (psIconBitmap->schema != PC_BITMAP_SCHEMA)
113 			Fatal_error("Incorrect versions loading [%s] (engine has %d, data has %d", pcFullIconName, PC_BITMAP_SCHEMA, psIconBitmap->schema);
114 
115 		// Create a surface for the icon
116 		m_pnIconSurfaceIDs[i] = surface_manager->Create_new_surface(pcIconName, ICON_X_SIZE, ICON_Y_SIZE, EITHER);
117 		surface_manager->Set_transparent_colour_key(m_pnIconSurfaceIDs[i], m_nTransparentKey);
118 		pyIconBitmap = surface_manager->Lock_surface(m_pnIconSurfaceIDs[i]);
119 		uint32 nPitch = surface_manager->Get_pitch(m_pnIconSurfaceIDs[i]);
120 		// Load the icon into the surface
121 		SpriteXYFrameDraw(pyIconBitmap, nPitch, ICON_X_SIZE, ICON_Y_SIZE, psIconBitmap, 0, 0, 0, FALSE8, NULL, 255);
122 		// convert it to b/w
123 		uint32 *icon_ad = (uint32 *)pyIconBitmap;
124 		for (uint32 y = 0; y < ICON_Y_SIZE; y++) {
125 			uint32 *rowAd = icon_ad;
126 			for (int32 x = 0; x < ICON_X_SIZE; x++) {
127 				uint32 col = *rowAd;
128 				if (col != m_nTransparentKey) {
129 					(*((uint8 *)rowAd + 0)) >>= 1;
130 					(*((uint8 *)rowAd + 1)) >>= 1;
131 					(*((uint8 *)rowAd + 2)) >>= 1;
132 					(*((uint8 *)rowAd + 3)) >>= 1;
133 				}
134 				rowAd++;
135 			}
136 			icon_ad += nPitch / 4;
137 		}
138 		// Unlock the surface
139 		surface_manager->Unlock_surface(m_pnIconSurfaceIDs[i]);
140 
141 		// Create a surface for the icons hilite
142 		sprintf(pcIconName + strlen(pcIconName), "H");
143 		m_pnHiLiteSurfaceIDs[i] = surface_manager->Create_new_surface(pcIconName, ICON_X_SIZE, ICON_Y_SIZE, EITHER);
144 		surface_manager->Set_transparent_colour_key(m_pnHiLiteSurfaceIDs[i], m_nTransparentKey);
145 		pyHiLiteBitmap = surface_manager->Lock_surface(m_pnHiLiteSurfaceIDs[i]);
146 		nPitch = surface_manager->Get_pitch(m_pnHiLiteSurfaceIDs[i]);
147 		// Load the icon hilight
148 		SpriteXYFrameDraw(pyHiLiteBitmap, nPitch, ICON_X_SIZE, ICON_Y_SIZE, psIconBitmap, 0, 0, 0, FALSE8, NULL, 255);
149 		// Unlock the surface
150 		surface_manager->Unlock_surface(m_pnHiLiteSurfaceIDs[i]);
151 	}
152 
153 	// Now we are set up so make an initial call to the code for actually drawing the menu on the game screen.
154 	DrawIconMenu();
155 
156 	PXCATCH
157 
158 	Tdebug(EXCEPTION_LOG, "Exception in _icon_menu::Activate()");
159 	Fatal_error("Exception in _icon_menu::Activate()");
160 
161 	PXENDCATCH
162 
163 	Zdebug("Leaving _icon_menu::Activate()");
164 }
165 
ReActivate()166 void _icon_menu::ReActivate() {
167 	int32 i;
168 
169 	// Free up all the previous icon surfaces
170 	for (i = m_pIconList->GetIconCount() - 1; i >= 0; --i) {
171 		surface_manager->Kill_surface(m_pnIconSurfaceIDs[i]);
172 		surface_manager->Kill_surface(m_pnHiLiteSurfaceIDs[i]);
173 	}
174 
175 	// Dump the off-screen arrows if we were using them.
176 	if (m_bWiderThanScreen) {
177 		surface_manager->Kill_surface(m_nLeftArrowID);
178 		surface_manager->Kill_surface(m_nRightArrowID);
179 		surface_manager->Kill_surface(m_nLeftArrowHiLiteID);
180 		surface_manager->Kill_surface(m_nRightArrowHiLiteID);
181 		SetUpOffScreenArrows();
182 	}
183 
184 	// Now recreate and reload all those surfi
185 	for (i = m_pIconList->GetIconCount() - 1; i >= 0; --i) {
186 		// Get the full pathname for the icon.
187 		char pcIconName[MAXLEN_ICON_NAME];
188 		char pcFullIconName[MAXLEN_URL];
189 		char pcIconPath[MAXLEN_URL];
190 
191 		strcpy(pcIconName, m_pIconList->GetIcon(i));
192 		sprintf(pcIconPath, ICON_PATH);
193 		sprintf(pcFullIconName, "%s%s.%s", pcIconPath, pcIconName, PX_BITMAP_PC_EXT);
194 
195 		// Open the icon resource.
196 		uint32 nFullIconNameHash = NULL_HASH;
197 		_pxBitmap *psIconBitmap = (_pxBitmap *)rs_icons->Res_open(pcFullIconName, nFullIconNameHash, m_pcIconCluster, m_nIconClusterHash);
198 
199 		// Check the schema is correct.
200 		if (psIconBitmap->schema != PC_BITMAP_SCHEMA)
201 			Fatal_error("Incorrect versions loading [%s] (engine has %d, data has %d", pcFullIconName, PC_BITMAP_SCHEMA, psIconBitmap->schema);
202 
203 		// Create a surface for the icon
204 		m_pnIconSurfaceIDs[i] = surface_manager->Create_new_surface("Icon", ICON_X_SIZE, ICON_Y_SIZE, EITHER);
205 		uint8 *pyIconBitmap = surface_manager->Lock_surface(m_pnIconSurfaceIDs[i]);
206 		uint32 nPitch = surface_manager->Get_pitch(m_pnIconSurfaceIDs[i]);
207 
208 		// Load the icon into the surface
209 		SpriteXYFrameDraw(pyIconBitmap, nPitch, ICON_X_SIZE, ICON_Y_SIZE, psIconBitmap, 0, 0, 0, FALSE8, NULL, 255);
210 		// convert it to b/w
211 		uint32 *icon_ad = (uint32 *)pyIconBitmap;
212 		for (uint32 y = 0; y < ICON_Y_SIZE; y++) {
213 			uint32 *rowAd = icon_ad;
214 			for (int32 x = 0; x < ICON_X_SIZE; x++) {
215 				uint32 col = *rowAd;
216 				if (col != m_nTransparentKey) {
217 					(*((uint8 *)rowAd + 0)) >>= 1;
218 					(*((uint8 *)rowAd + 1)) >>= 1;
219 					(*((uint8 *)rowAd + 2)) >>= 1;
220 					(*((uint8 *)rowAd + 3)) >>= 1;
221 				}
222 				rowAd++;
223 			}
224 			icon_ad += nPitch / 4;
225 		}
226 		// Unlock the surface
227 		surface_manager->Unlock_surface(m_pnIconSurfaceIDs[i]);
228 
229 		// Create a surface for the icons hilite
230 		sprintf(pcIconName + strlen(pcIconName), "H");
231 		m_pnHiLiteSurfaceIDs[i] = surface_manager->Create_new_surface(pcIconName, ICON_X_SIZE, ICON_Y_SIZE, EITHER);
232 		uint8 *pyHiLiteBitmap = surface_manager->Lock_surface(m_pnHiLiteSurfaceIDs[i]);
233 		nPitch = surface_manager->Get_pitch(m_pnHiLiteSurfaceIDs[i]);
234 		// Load the icon hilight
235 		SpriteXYFrameDraw(pyHiLiteBitmap, nPitch, ICON_X_SIZE, ICON_Y_SIZE, psIconBitmap, 0, 0, 0, FALSE8, NULL, 255);
236 		// Unlock the surface
237 		surface_manager->Unlock_surface(m_pnHiLiteSurfaceIDs[i]);
238 		// Set the transparency keys for the icon
239 		surface_manager->Set_transparent_colour_key(m_pnIconSurfaceIDs[i], m_nTransparentKey);
240 		surface_manager->Set_transparent_colour_key(m_pnHiLiteSurfaceIDs[i], m_nTransparentKey);
241 	}
242 }
243 
DrawIconMenu()244 void _icon_menu::DrawIconMenu() {
245 	uint32 i;
246 	uint32 nIconIndex;
247 	uint32 nItemCount;
248 	int32 nStartX;
249 	LRECT sToRectangle;
250 	LRECT sFromRectangle;
251 	uint32 nIconCount;
252 	uint32 nMaxDrawableIcons, nIconsToDraw;
253 	int32 scrolling = 0;
254 	char pcDigits[16];
255 	const char *pcIconLabel;
256 	char pcIconName[MAXLEN_ICON_NAME];
257 	uint32 nHashRef;
258 
259 	Zdebug("Entered _icon_menu::DrawIconMenu()");
260 
261 	// Check if we are scrolling the icon menu up
262 	if (m_nMenuY != ICON_MENU_PIXEL_Y)
263 		m_nMenuY -= 15;
264 	if (m_nMenuY < ICON_MENU_PIXEL_Y)
265 		m_nMenuY = ICON_MENU_PIXEL_Y;
266 
267 	// Get number of icons.
268 	nIconCount = m_pIconList->GetIconCount();
269 
270 	// Work out where we start drawing the icons from (based on which one is currently selected).
271 	nIconIndex = m_nSelectedIcon;
272 	nStartX = ICON_MENU_PIXEL_X;
273 
274 	int32 scrollyX = GetScrollingPosition(nStartX, nIconIndex);
275 
276 	if ((nStartX != scrollyX) || (nIconIndex != m_nSelectedIcon)) {
277 		scrolling = 1;
278 		nStartX = scrollyX;
279 	}
280 
281 	// Now modify the start drawing position and how many icons we can display based on whether or not
282 	// there are too many to fit on the screen.
283 	if (m_bWiderThanScreen) {
284 		// Allow space for the off-screen arrows, and start one position in.
285 		nMaxDrawableIcons = m_nMaxIconsDisplayed - 2;
286 		nStartX = nStartX + ICON_X_SIZE + ICON_SPACING;
287 
288 		// Draw the left off-screen arrows.
289 		sToRectangle.left = ICON_MENU_PIXEL_X;
290 		sToRectangle.right = sToRectangle.left + ICON_X_SIZE - 1;
291 		sToRectangle.top = m_nMenuY;
292 		sToRectangle.bottom = sToRectangle.top + ICON_Y_SIZE - 1;
293 
294 		sFromRectangle = ICON_BITMAP_RECT;
295 
296 		if (sToRectangle.left < 0) {
297 			sFromRectangle.left -= sToRectangle.left;
298 			sToRectangle.left = 0;
299 		}
300 
301 		if (sToRectangle.bottom > SCREEN_DEPTH) {
302 			sFromRectangle.bottom -= (sToRectangle.bottom - SCREEN_DEPTH);
303 			sToRectangle.bottom = SCREEN_DEPTH;
304 		}
305 
306 		// Draw the flashing highlight if it is visible.
307 		surface_manager->Blit_surface_to_surface(m_nLeftArrowHiLiteID, working_buffer_id, &sFromRectangle, &sToRectangle, DDBLT_KEYSRC);
308 
309 		// Draw the right off-screen arrows.
310 		sToRectangle.left = ICON_MENU_PIXEL_X + ((m_nMaxIconsDisplayed - 1) * (ICON_X_SIZE + ICON_SPACING));
311 		sToRectangle.right = sToRectangle.left + ICON_X_SIZE - 1;
312 		sToRectangle.top = ICON_MENU_PIXEL_Y;
313 		sToRectangle.bottom = ICON_MENU_PIXEL_Y + ICON_Y_SIZE - 1;
314 
315 		sFromRectangle = ICON_BITMAP_RECT;
316 
317 		if (sToRectangle.left < 0) {
318 			sFromRectangle.left -= sToRectangle.left;
319 			sToRectangle.left = 0;
320 		}
321 
322 		if (sToRectangle.bottom > SCREEN_DEPTH) {
323 			sFromRectangle.bottom -= (sToRectangle.bottom - SCREEN_DEPTH);
324 			sToRectangle.bottom = SCREEN_DEPTH;
325 		}
326 
327 		// Draw the flashing highlight if it is visible.
328 		surface_manager->Blit_surface_to_surface(m_nRightArrowHiLiteID, working_buffer_id, &sFromRectangle, &sToRectangle, DDBLT_KEYSRC);
329 	} else {
330 		nMaxDrawableIcons = m_nMaxIconsDisplayed;
331 	}
332 
333 	// The number of icons we draw is the lesser of the maximum we can draw and how many there actually are.
334 	nIconsToDraw = (nIconCount < nMaxDrawableIcons) ? nIconCount : nMaxDrawableIcons;
335 
336 	// Where to draw them
337 	int32 x = nStartX;
338 
339 	// Loop for each icon to be drawn.
340 	for (i = 0; i < nIconsToDraw; ++i) {
341 		// Work out blit-to rectangle.
342 		sToRectangle.left = x;
343 		sToRectangle.right = sToRectangle.left + ICON_X_SIZE - 1;
344 		sToRectangle.top = m_nMenuY;
345 		sToRectangle.bottom = sToRectangle.top + ICON_Y_SIZE - 1;
346 
347 		sFromRectangle = ICON_BITMAP_RECT;
348 
349 		if (sToRectangle.left < 0) {
350 			sFromRectangle.left -= sToRectangle.left;
351 			sToRectangle.left = 0;
352 		}
353 
354 		if (sToRectangle.bottom > SCREEN_DEPTH) {
355 			sFromRectangle.bottom -= (sToRectangle.bottom - SCREEN_DEPTH);
356 			sToRectangle.bottom = SCREEN_DEPTH;
357 		}
358 
359 		// Get the icon name and hash for it.
360 		strcpy(pcIconName, m_pIconList->GetIcon(nIconIndex));
361 		nHashRef = HashString(pcIconName);
362 
363 		// Now blit the icon itself.
364 		surface_manager->Blit_surface_to_surface(m_pnIconSurfaceIDs[nIconIndex], working_buffer_id, &sFromRectangle, &sToRectangle, DDBLT_KEYSRC);
365 
366 		// Are we drawing the highlighted icon?
367 		if ((nIconIndex == m_nSelectedIcon) && (scrolling == 0)) {
368 			surface_manager->Blit_surface_to_surface(m_pnHiLiteSurfaceIDs[nIconIndex], working_buffer_id, &sFromRectangle, &sToRectangle, DDBLT_KEYSRC);
369 
370 			// Look for the icon label in the global text file.
371 			pcIconLabel = (const char *)global_text->Try_fetch_item_by_hash(nHashRef);
372 
373 			// If we found it, display it.
374 			if (pcIconLabel && (g_px->display_mode == THREED)) {
375 				SetTextColour(255, 255, 255);
376 				MS->Create_remora_text(sToRectangle.left, sToRectangle.top - 17, pcIconLabel, 2, PIN_AT_TOP_LEFT, 3, 2, 600);
377 				MS->Render_speech(MS->text_bloc);
378 				MS->Kill_remora_text();
379 			}
380 		}
381 
382 		// Here, we deal with drawing the counts on the icons.
383 		nItemCount = m_sDuplicates.s_pnItemCounts[nIconIndex];
384 
385 		// Only write the number on in 3D mode.
386 		if (g_px->display_mode == THREED) {
387 			// Write the number if greater than 1 or it is the clips or medipacks count.
388 			if (((nItemCount > 1) || (nHashRef == HashString(ARMS_HEALTH_NAME)) || (nHashRef == HashString(ARMS_AMMO_NAME))) && x > 0) {
389 				snprintf(pcDigits, 16, "%d", m_sDuplicates.s_pnItemCounts[nIconIndex]);
390 				if ((nIconIndex != m_nSelectedIcon) || (scrolling != 0))
391 					SetTextColour(160, 160, 160);
392 				else
393 					SetTextColour(255, 255, 255);
394 				MS->Create_remora_text(x, sToRectangle.top, (const char *)(pcDigits), 2, PIN_AT_TOP_LEFT, 3, 2, ICON_X_SIZE);
395 				MS->Render_speech(MS->text_bloc);
396 				MS->Kill_remora_text();
397 			}
398 		}
399 
400 		// Work out index of next icon to be drawn.
401 		nIconIndex = (nIconIndex + 1) % nIconCount;
402 
403 		// And where to draw the next one
404 		x += (ICON_X_SIZE + ICON_SPACING);
405 	}
406 }
407 
CloseDownIconMenuDisplay()408 void _icon_menu::CloseDownIconMenuDisplay() {
409 	uint32 i;
410 	uint32 nIconCount;
411 
412 	Zdebug("Entered _icon_menu::CloseDownIconMenuDisplay()");
413 
414 	nIconCount = m_pIconList->GetIconCount();
415 
416 	// Dump the icon store graphic surfaces.
417 	for (i = 0; i < nIconCount; ++i) {
418 		surface_manager->Kill_surface(m_pnIconSurfaceIDs[i]);
419 		surface_manager->Kill_surface(m_pnHiLiteSurfaceIDs[i]);
420 	}
421 
422 	// Dump the off-screen arrows if we were using them.
423 	if (m_bWiderThanScreen) {
424 		surface_manager->Kill_surface(m_nLeftArrowID);
425 		surface_manager->Kill_surface(m_nRightArrowID);
426 		surface_manager->Kill_surface(m_nLeftArrowHiLiteID);
427 		surface_manager->Kill_surface(m_nRightArrowHiLiteID);
428 	}
429 
430 	Zdebug("Leaving _icon_menu::CloseDownIconMenuDisplay()");
431 }
432 
SetTransparencyColourKey()433 void _icon_menu::SetTransparencyColourKey() {
434 	uint32 nFullIconNameHash = NULL_HASH;
435 	_pxBitmap *psTransparentBitmap;
436 	uint8 *pnPalette;
437 	uint32 nIconClusterHash;
438 	char pcFullIconName[MAXLEN_URL];
439 	char pcIconCluster[MAXLEN_CLUSTER_URL];
440 
441 	strcpy(pcIconCluster, ICON_CLUSTER_PATH);
442 	nIconClusterHash = NULL_HASH;
443 
444 	// Here we open the bitmap containing the reference colour for transparency and set it.
445 	sprintf(pcFullIconName, ICON_PATH);
446 	strcat(pcFullIconName, BITMAP_TRANSPARENCY_REFERENCE);
447 	strcat(pcFullIconName, ".");
448 	strcat(pcFullIconName, PX_BITMAP_PC_EXT);
449 
450 	psTransparentBitmap = (_pxBitmap *)rs_icons->Res_open(pcFullIconName, nFullIconNameHash, pcIconCluster, nIconClusterHash);
451 
452 	if (psTransparentBitmap->schema != PC_BITMAP_SCHEMA)
453 		Fatal_error("Incorrect versions loading [%s] (engine has %d, data has %d", pcFullIconName, PC_BITMAP_SCHEMA, psTransparentBitmap->schema);
454 
455 	pnPalette = psTransparentBitmap->Fetch_palette_pointer();
456 	m_nTransparentKey = ((uint32 *)pnPalette)[0];
457 }
458 
SetupAdding(const char * pcIconName,uint32 & nSurfaceID)459 void _icon_menu::SetupAdding(const char *pcIconName, uint32 &nSurfaceID) {
460 	uint32 nPitch;
461 	char pcFullIconName[MAXLEN_URL];
462 	char pcIconPath[MAXLEN_URL];
463 	uint32 nFullIconNameHash;
464 	_pxBitmap *psIconBitmap;
465 	uint8 *p8Bitmap;
466 
467 	// Get the full pathname for the ammo clips icon.
468 	sprintf(pcIconPath, ICON_PATH);
469 	sprintf(pcFullIconName, "%s%s.%s", pcIconPath, pcIconName, PX_BITMAP_PC_EXT);
470 
471 	// Open the icon resource.
472 	nFullIconNameHash = NULL_HASH;
473 	psIconBitmap = (_pxBitmap *)rs_icons->Res_open(pcFullIconName, nFullIconNameHash, m_pcIconCluster, m_nIconClusterHash);
474 
475 	// Check the schema is correct.
476 	if (psIconBitmap->schema != PC_BITMAP_SCHEMA)
477 		Fatal_error("Incorrect versions loading [%s] (engine has %d, data has %d", pcFullIconName, PC_BITMAP_SCHEMA, psIconBitmap->schema);
478 
479 	// Create a surface for the clips icon.
480 	nSurfaceID = surface_manager->Create_new_surface(pcIconName, ICON_X_SIZE, ICON_Y_SIZE, EITHER);
481 	surface_manager->Set_transparent_colour_key(nSurfaceID, m_nTransparentKey);
482 	p8Bitmap = surface_manager->Lock_surface(nSurfaceID);
483 	nPitch = surface_manager->Get_pitch(nSurfaceID);
484 
485 	// Draw the icon into the surface.
486 	SpriteXYFrameDraw(p8Bitmap, nPitch, ICON_X_SIZE, ICON_Y_SIZE, psIconBitmap, 0, 0, 0, FALSE8, NULL, 255);
487 
488 	// Finished drawing the icon into the surfaces so we can unlock them.
489 	surface_manager->Unlock_surface(nSurfaceID);
490 }
491 
DrawAdding()492 void _icon_menu::DrawAdding() {
493 	// Check if a symbol currently needs to be drawn and if so which one.
494 	switch (m_nAddedSymbol) {
495 	case 1:
496 		// Draw the medipack flash.
497 		surface_manager->Blit_surface_to_surface(m_nAddedMedipacksSurface, working_buffer_id, &ICON_BITMAP_RECT, &ICON_ADDING_RECT, DDBLT_KEYSRC);
498 		break;
499 
500 	case 2:
501 		// Draw the ammo clips flash.
502 		surface_manager->Blit_surface_to_surface(m_nAddedClipsSurface, working_buffer_id, &ICON_BITMAP_RECT, &ICON_ADDING_RECT, DDBLT_KEYSRC);
503 		break;
504 
505 	case 3:
506 		// Draw the ammo clips flash.
507 		surface_manager->Blit_surface_to_surface(m_nEmailArrivedSurface, working_buffer_id, &ICON_BITMAP_RECT, &ICON_ADDING_RECT, DDBLT_KEYSRC);
508 		break;
509 
510 	default:
511 	    // Draw nothing.
512 	    ;
513 	}
514 }
515 
CloseDownAdding()516 void _icon_menu::CloseDownAdding() {
517 	Zdebug("Entered _icon_menu::CloseDownAdding()...");
518 
519 	surface_manager->Kill_surface(m_nAddedMedipacksSurface);
520 	surface_manager->Kill_surface(m_nAddedClipsSurface);
521 	surface_manager->Kill_surface(m_nEmailArrivedSurface);
522 
523 	Zdebug("Leaving _icon_menu::CloseDownAdding()...");
524 }
525 
SetAddingClipsCount(uint32 nNumClips)526 void _icon_menu::SetAddingClipsCount(uint32 nNumClips) {
527 	// Set the count.
528 	m_nAddedClips = (uint8)nNumClips;
529 
530 	// Set the counter that controls the flashing.  Starts at 1 just to tidy up the initial flash.
531 	m_nAddedFlashCount = 0;
532 
533 	// Prepare to draw the flashing icon (on PC only).
534 	SetupAdding(ARMS_AMMO_NAME, m_nAddedClipsSurface);
535 }
536 
SetAddingMedipacksCount(uint32 nNumMedipacks)537 void _icon_menu::SetAddingMedipacksCount(uint32 nNumMedipacks) {
538 	// Set the count.
539 	m_nAddedMedipacks = (uint8)nNumMedipacks;
540 
541 	// Set the counter that controls the flashing.
542 	m_nAddedFlashCount = 0;
543 
544 	// Prepare to draw the flashing icon (on PC only).
545 	SetupAdding(ARMS_HEALTH_NAME, m_nAddedMedipacksSurface);
546 }
547 
SetEmailArrived()548 void _icon_menu::SetEmailArrived() {
549 	// If the icon menu is active and taking up the whole screen then we need to disable it because
550 	// it needs to adjust its drawing size.
551 	if ((m_eIconMenuGameState == ACTIVE) && (m_pIconList->GetIconCount() >= ICON_LIST_MAX_DISPLAYED))
552 		CloseDownIconMenu();
553 
554 	// Set the email arrived flag.
555 	m_bEmailArrived = TRUE8;
556 
557 	// Set the counter that controls the flashing.
558 	m_nAddedFlashCount = 0;
559 
560 	// Prepare to draw the flashing icon (on PC only).
561 	SetupAdding(EMAIL_ARRIVED_NAME, m_nEmailArrivedSurface);
562 }
563 
DrawArmedMenu(const int32 nBullets,const int32 maxBullets,const int32 nClips,const int32 maxClips)564 void _icon_menu::DrawArmedMenu(const int32 nBullets, const int32 maxBullets, const int32 nClips, const int32 maxClips) {
565 	// Ok, let's see just how selfcontained, yet inefficient we can make one function :o)
566 	uint32 gunSurface = 0;
567 	uint32 clipSurface = 0;
568 
569 	// Load the 2 icons... We probably only deleted them last frame but whey !
570 	SetupAdding(ARMS_GUN_NAME, gunSurface);
571 	SetupAdding(ARMS_AMMO_NAME, clipSurface);
572 	// Icon positioning
573 	LRECT destRect;
574 	destRect.left = ICON_ARMED_MENU_PIXEL_X + 10;
575 	destRect.top = ICON_ARMED_MENU_PIXEL_Y;
576 	destRect.right = destRect.left + ICON_BITMAP_RECT.right - ICON_BITMAP_RECT.left;
577 	destRect.bottom = destRect.top + ICON_BITMAP_RECT.bottom - ICON_BITMAP_RECT.top;
578 
579 	// Blit the icon ...
580 	surface_manager->Blit_surface_to_surface(gunSurface, working_buffer_id, &ICON_BITMAP_RECT, &destRect, DDBLT_KEYSRC);
581 
582 	// ... and add the counter
583 	MS->Create_remora_text(destRect.left, destRect.top - 15, pxVString("%d/%d", nBullets, maxBullets), 2, PIN_AT_TOP_LEFT, 3, 2, 300);
584 	MS->Render_speech(MS->text_bloc);
585 	MS->Kill_remora_text();
586 
587 	// Update the screen pos
588 	destRect.left += (ICON_X_SIZE + ICON_SPACING);
589 	destRect.right += (ICON_X_SIZE + ICON_SPACING);
590 
591 	// Blit the icon
592 	surface_manager->Blit_surface_to_surface(clipSurface, working_buffer_id, &ICON_BITMAP_RECT, &destRect, DDBLT_KEYSRC);
593 	// and add the counter
594 	MS->Create_remora_text(destRect.left, destRect.top - 15, pxVString("%d/%d", nClips, maxClips), 2, PIN_AT_TOP_LEFT, 3, 2, 300);
595 	MS->Render_speech(MS->text_bloc);
596 	MS->Kill_remora_text();
597 
598 	// Now delete the surface, so we are ready to recreate them next game cycle.
599 	surface_manager->Kill_surface(gunSurface);
600 	surface_manager->Kill_surface(clipSurface);
601 }
602 
SetUpOffScreenArrows()603 void _icon_menu::SetUpOffScreenArrows() {
604 	uint8 *pyLeftBitmap;
605 	uint8 *pyLeftHiLiteBitmap;
606 	uint8 *pyRightBitmap;
607 	uint8 *pyRightHiLiteBitmap;
608 	uint32 nPitch;
609 	uint32 nFullIconNameHash;
610 	_pxBitmap *psIconBitmap;
611 	char pcArrowIconName[MAXLEN_URL];
612 	char pcIconPath[MAXLEN_URL];
613 
614 	// Create surfaces for the left arrow - both highlighted and normal.
615 	m_nLeftArrowID = surface_manager->Create_new_surface(ICON_MENU_OFF_SCREEN_LEFT, ICON_X_SIZE, ICON_Y_SIZE, EITHER);
616 	surface_manager->Set_transparent_colour_key(m_nLeftArrowID, m_nTransparentKey);
617 	pyLeftBitmap = surface_manager->Lock_surface(m_nLeftArrowID);
618 
619 	m_nLeftArrowHiLiteID = surface_manager->Create_new_surface(ICON_MENU_OFF_SCREEN_LEFT, ICON_X_SIZE, ICON_Y_SIZE, EITHER);
620 	surface_manager->Set_transparent_colour_key(m_nLeftArrowHiLiteID, m_nTransparentKey);
621 	pyLeftHiLiteBitmap = surface_manager->Lock_surface(m_nLeftArrowHiLiteID);
622 
623 	// Get the pitch (assume it's the same for both.
624 	nPitch = surface_manager->Get_pitch(m_nLeftArrowID);
625 
626 	// Open the icon (contains both the highlighted and normal frames).
627 	sprintf(pcIconPath, ICON_PATH);
628 	/*uint32 nBufferCount =*/ sprintf(pcArrowIconName, "%s%s.%s", pcIconPath, ICON_MENU_OFF_SCREEN_LEFT, PX_BITMAP_PC_EXT);
629 
630 	nFullIconNameHash = NULL_HASH;
631 
632 	psIconBitmap = (_pxBitmap *)rs_icons->Res_open(pcArrowIconName, nFullIconNameHash, m_pcIconCluster, m_nIconClusterHash);
633 
634 	if (psIconBitmap->schema != PC_BITMAP_SCHEMA)
635 		Fatal_error("Incorrect versions loading [%s] (engine has %d, data has %d", pcArrowIconName, PC_BITMAP_SCHEMA, psIconBitmap->schema);
636 
637 	// Draw the two frames onto their respective surfaces.
638 	SpriteXYFrameDraw(pyLeftBitmap, nPitch, ICON_X_SIZE, ICON_Y_SIZE, psIconBitmap, 0, 0, 0, FALSE8, NULL, 255);
639 	SpriteXYFrameDraw(pyLeftHiLiteBitmap, nPitch, ICON_X_SIZE, ICON_Y_SIZE, psIconBitmap, 0, 0, 1, FALSE8, NULL, 255);
640 
641 	// Finished drawing the icon into the surfaces so we can unlock them.
642 	surface_manager->Unlock_surface(m_nLeftArrowID);
643 	surface_manager->Unlock_surface(m_nLeftArrowHiLiteID);
644 
645 	// Now we repeat the whole thing for the right arrow.
646 	m_nRightArrowID = surface_manager->Create_new_surface(ICON_MENU_OFF_SCREEN_RIGHT, ICON_X_SIZE, ICON_Y_SIZE, EITHER);
647 	surface_manager->Set_transparent_colour_key(m_nRightArrowID, m_nTransparentKey);
648 	pyRightBitmap = surface_manager->Lock_surface(m_nRightArrowID);
649 
650 	m_nRightArrowHiLiteID = surface_manager->Create_new_surface(ICON_MENU_OFF_SCREEN_RIGHT, ICON_X_SIZE, ICON_Y_SIZE, EITHER);
651 	surface_manager->Set_transparent_colour_key(m_nRightArrowHiLiteID, m_nTransparentKey);
652 	pyRightHiLiteBitmap = surface_manager->Lock_surface(m_nRightArrowHiLiteID);
653 
654 	// Get the pitch (assume it's the same for both.
655 	nPitch = surface_manager->Get_pitch(m_nRightArrowID);
656 
657 	// Open the icon (contains both the highlighted and normal frames).
658 	/*uint32 nBufferCount =*/ sprintf(pcArrowIconName, "%s%s.%s", pcIconPath, ICON_MENU_OFF_SCREEN_RIGHT, PX_BITMAP_PC_EXT);
659 
660 	nFullIconNameHash = NULL_HASH;
661 
662 	psIconBitmap = (_pxBitmap *)rs_icons->Res_open(pcArrowIconName, nFullIconNameHash, m_pcIconCluster, m_nIconClusterHash);
663 
664 	if (psIconBitmap->schema != PC_BITMAP_SCHEMA)
665 		Fatal_error("Incorrect versions loading [%s] (engine has %d, data has %d", pcArrowIconName, PC_BITMAP_SCHEMA, psIconBitmap->schema);
666 
667 	// Draw the two frames onto their respective surfaces.
668 	SpriteXYFrameDraw(pyRightBitmap, nPitch, ICON_X_SIZE, ICON_Y_SIZE, psIconBitmap, 0, 0, 0, FALSE8, NULL, 255);
669 	SpriteXYFrameDraw(pyRightHiLiteBitmap, nPitch, ICON_X_SIZE, ICON_Y_SIZE, psIconBitmap, 0, 0, 1, FALSE8, NULL, 255);
670 
671 	// Finished drawing the icon into the surfaces so we can unlock them.
672 	surface_manager->Unlock_surface(m_nRightArrowID);
673 	surface_manager->Unlock_surface(m_nRightArrowHiLiteID);
674 }
675 
676 } // End of namespace ICB
677