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