1 /*
2 
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 /*
20  * $Source: r:/prj/cit/src/RCS/invent.c $
21  * $Revision: 1.240 $
22  * $Author: dc $
23  * $Date: 1994/11/22 15:58:48 $
24  *
25  */
26 
27 // Source code for inventory manipulation / display
28 
29 #include <string.h>
30 
31 #include "invent.h"
32 #include "objprop.h"
33 #include "objwpn.h"
34 #include "objwarez.h"
35 #include "objsim.h"
36 #include "tools.h"
37 #include "colors.h"
38 #include "player.h"
39 #include "weapons.h"
40 #include "drugs.h"
41 #include "grenades.h"
42 #include "wares.h"
43 #include "cybstrng.h"
44 #include "gamestrn.h"
45 #include "sideicon.h"
46 #include "gameloop.h"
47 #include "loops.h"
48 #include "input.h"
49 #include "mfdext.h"
50 #include "objbit.h"
51 #include "fullscrn.h"
52 #include "cit2d.h"
53 #include "gr2ss.h"
54 #include "criterr.h"
55 
56 #include "hkeyfunc.h"
57 #include "objload.h"
58 #include "invpages.h"
59 #include "sfxlist.h"
60 #include "musicai.h"
61 #include "emailbit.h"
62 #include "popups.h"
63 
64 #include "otrip.h"
65 #include "gamescr.h"
66 #include "amap.h"
67 #include "citres.h"
68 
69 #include "game_screen.h" // was screen.h?
70 
71 //#include <inp6d.h>
72 //#include <i6dvideo.h>
73 
74 /***************************************/
75 /* INVENTORY DISPLAY MODULE            */
76 /*-------------------------------------*/
77 /*---------------------------------------------
78 The inventory display is arranged into a number of
79 /pages/, each of which can contain one or more
80 /lists/.  In general, a list shows "what types of
81 a particular thing you have," and "how many of
82 each do you have."  There is a list for weapons,
83 one for grenades, one for drugs, etc.
84 
85 The contents of each list is, more or less, defined
86 by two arrays, and "exists" array and a "quantity"
87 array.  For a particular list, say, the grenades
88 list, exists[N] is non-zero if you have any
89 grenades of type N, and quant[N] is the number of
90 grenades of that type you have.You astutely
91 observe: "Why are these lists different, when the
92 quantity of something is always zero if you have
93 none of it, and thus the quantity array and the
94 exists array could be the same?"  The answer is:
95 because it's goofy.
96 
97 For each list, the inventory display maintains a
98 state array describing what stuff was actually
99 DRAWN, so it can redraw incrementally.  The
100 elements of the array are structures of type
101 /quantity_state/, defined below.
102 
103 A list can be divided onto different pages of the
104 inventory, and each section of a list that
105 appears on its own page is called a /display/.
106 The inventory panel figures out what to display
107 by looking through a huge list of all the
108 displays in the game.  Adding a new display is as
109 simple as adding a new element to this array.  Of
110 course, that element is a huge wonking structure
111 describing when and where and how to draw, use,
112 and select items on the display.
113 
114 And now, the code...
115 ----------------------------------------------*/
116 
117 #define KEY_CODE_ESC 0x1b
118 
119 // -------------
120 // DISPLAY STUFF
121 // -------------
122 // -------
123 // DEFINES
124 // -------
125 #define INVENT_CHANGED                    \
126     if (_current_loop <= FULLSCREEN_LOOP) \
127         chg_set_flg(INVENTORY_UPDATE);
128 
129 // colors & fonts
130 #define TITLE_COLOR         (RED_BASE + 5)
131 #define ITEM_COLOR          (0x5A)
132 #define SELECTED_ITEM_COLOR (0x4C)
133 #define BRIGHT_ITEM_COLOR   (0xE7)
134 #define DULL_ITEM_COLOR     (0x5F)
135 // let us no longer pretend we have differenet fonts for everything
136 #define ITEM_FONT    RES_tinyTechFont
137 #define WEAPONS_FONT ITEM_FONT
138 
139 // Screen margins/locations/proportions
140 #define TOP_MARGIN      2 // was 15
141 #define LEFT_MARGIN     4
142 #define RIGHT_MARGIN    3
143 #define Y_STEP          6
144 #define WEAPON_X        LEFT_MARGIN
145 #define AMMO_X          70
146 #define GRENADE_LEFT_X  (AMMO_X + 4)
147 #define GRENADE_RIGHT_X (GRENADE_LEFT_X + 30)
148 #define DRUG_RIGHT_X    (INVENTORY_PANEL_WIDTH - RIGHT_MARGIN)
149 #define DRUG_LEFT_X     (DRUG_RIGHT_X - 35)
150 #define AMMO_LEFT_1     WEAPON_X
151 #define AMMO_RIGHT_1    (AMMO_LEFT_1 + 40)
152 #define AMMO_LEFT_2     (AMMO_RIGHT_1 + 4)
153 #define AMMO_RIGHT_2    (AMMO_LEFT_2 + 40)
154 #define AMMO_LEFT_3     (AMMO_RIGHT_2 + 4)
155 #define AMMO_RIGHT_3    (AMMO_LEFT_3 + 40)
156 #define CENTER_X        (INVENTORY_PANEL_WIDTH / 2)
157 #define RIGHT_X         INVENTORY_PANEL_WIDTH
158 #define ONETHIRD_X      (INVENTORY_PANEL_WIDTH / 3)
159 #define TWOTHIRDS_X     (2 * INVENTORY_PANEL_WIDTH / 3)
160 
161 // Page button defines
162 #define FIRST_BTTN_X   (3)
163 #define INVENT_BTTN_Y  (2)
164 #define INVENT_BTTN_HT 3
165 #define INVENT_BTTN_WD 18
166 #define BUTTON_X_STEP  24
167 
168 // Hey, these colors are stolen from mfd
169 #define INVENT_BTTN_EMPTY     0xcb
170 #define INVENT_BTTN_FLASH_ON  0x35
171 #define INVENT_BTTN_FLASH_OFF 0xcb
172 #define INVENT_BTTN_SELECT    0x77
173 
174 typedef enum {
175     BttnOff = 0,
176     BttnDummy = 1,
177     BttnActive = 2,
178     BttnFlashOff = 3,
179     BttnFlashOn = 16,
180     NUM_BUTTON_STATES = BttnFlashOn + 1
181 } invent_bttn_state;
182 
183 #define FlashOn(state) (((state)&0x1) == 0)
184 #define Flashing(state) ((state) >= BttnFlashOff && (state) <= BttnFlashOn)
185 
186 // mapping from button states to colors
187 ubyte _bttn_state2color[] = {
188     INVENT_BTTN_EMPTY, INVENT_BTTN_EMPTY, INVENT_BTTN_SELECT, INVENT_BTTN_FLASH_OFF, INVENT_BTTN_FLASH_ON,
189 };
190 
191 #define bttn_state2color(state) _bttn_state2color[Flashing(state) ? BttnFlashOff + !(state & 1) : state]
192 
193 #define INVENT_BTTN_FLASH_TIME 128
194 
195 #define NUM_PAGE_BUTTONS 6
196 
197 // Page stuff
198 #define WEAPON_PAGES      1
199 #define WEAPONS_PER_PAGE  7
200 #define DRUG_PAGES        1
201 #define DRUGS_PER_PAGE    7
202 #define GRENADE_PAGES     1
203 #define GRENADES_PER_PAGE 7
204 #define AMMO_PAGES        3
205 #define AMMO_PER_PAGE     3
206 #define ITEMS_PER_PAGE    7
207 
208 // Misc
209 #define BUFSZ 50
210 #define NULL_ACTIVE -1 // the null active
211 
212 // Object adding return codes
213 
214 typedef enum { ADD_FAIL, ADD_POP, ADD_SWAP, ADD_REJECT, ADD_NOROOM, ADD_NOEFFECT } AddResult;
215 
216 #define IS_POP_RESULT(r) ((r) == ADD_POP || (r) == ADD_NOEFFECT)
217 
218 typedef struct _quantity_state {
219     ushort num;  // item number
220     ubyte exist; // do we have it;
221     ubyte quant; // quantity
222     byte pad;
223 } quantity_state;
224 
225 // Get the correct color for an item, given its rank in the list.
226 typedef uchar (*color_func)(void *dp, int num);
227 
228 // Get the string name of an item, given its rank in the
229 // list.
230 typedef char *(*name_func)(void *dp, int num, char *buf);
231 
232 struct _inventory_display_list;
233 
234 // Get the string quantity of an item, given its rank in the
235 // list,and its actual quantity.
236 typedef char *(*quant_string_func)(struct _inventory_display_list *dp, int num, int quant, char *buf);
237 
238 // Draw a display
239 typedef void (*draw_func)(struct _inventory_display_list *dp);
240 
241 // Select an item given its rank in the list
242 typedef uchar (*select_func)(struct _inventory_display_list *dp, int itemnum);
243 
244 // Use an item given its rank in the list.
245 typedef uchar (*use_func)(struct _inventory_display_list *dp, int itemnum);
246 
247 // Add an object to a list
248 typedef ubyte (*add_func)(struct _inventory_display_list *dp, int itemnum, ObjID *obj, uchar select);
249 
250 // Remove and object from a list
251 typedef void (*drop_func)(struct _inventory_display_list *dp, int itemnum);
252 
253 typedef struct _inventory_display_list {
254     ushort pgnum;            // Page number this display is on
255     short relnum;            // Relative page number for this list.
256     short left, right;       // Left and right pixel edge
257     short top;               // Top pixel margin
258     ubyte titlecolor;        // Title color.  Duh.
259     ubyte listcolor;         // color for list items. if greater than 239,
260                              // it's a color func.
261     ushort first;            // first list item to start at.
262     ushort pgsize;           // Number of items in each list page
263     ushort listlen;          // Number of total list items
264     int titlenum;            // String number of title.
265     int activenum;           // index into player_struct.actives
266     int offset;              // offset of quantities into player struct
267     int mfdtype;             // inventory time for set_inventory_mfd
268     name_func name;          // given a type number, give us the name
269     quant_string_func quant; // Given an item number, give us the quantity string
270     draw_func draw;          // draw this inv_display
271     select_func select;      // select a row
272     use_func use;            // use a row
273     int add_classes;         // Classes of objects that this list represents
274     add_func add;            // function to add an object to this list.
275     drop_func drop;          // remove an object from a row.
276     int basetrip;            // triple of item number zero.
277     int (*toidx)(int);       // convert from a triple to an index  (NOT USED)
278     // state data
279     uchar dummy;           // used to be known_active
280     quantity_state *lines; // lines of state data
281 } inv_display;
282 
283 int known_actives[NUM_ACTIVES];
284 
285 #define NULL_PAGE 0xFFFF
286 extern inv_display inv_display_list[];
287 
288 extern uchar email_color_func(void *dp, int num);
289 
290 color_func color_func_list[] = {email_color_func};
291 #define EMAIL_COLOR_FUNC 240
292 
293 // -------
294 // GLOBALS
295 // -------
296 
297 // The current inventory "page"
298 
299 short inventory_page = 0;
300 uchar show_all_actives = FALSE;
301 
302 // The last page we drew
303 short inv_last_page = INV_BLANK_PAGE;
304 
305 LGRegion *inventory_region;
306 extern LGRegion *inventory_region_game, *inventory_region_full;
307 LGRegion **all_inventory_regions[] = {&inventory_region_game, &inventory_region_full};
308 
309 #define NUM_INVENT_REGIONS (sizeof(all_inventory_regions) / sizeof(LGRegion **))
310 
311 static struct _weapon_list_state {
312     ubyte active;
313     weapon_slot slots[WEAPON_PAGES * WEAPONS_PER_PAGE];
314     ubyte ammo_available[WEAPON_PAGES * WEAPONS_PER_PAGE];
315 } weapon_list;
316 
317 quantity_state generic_lines[48];
318 
319 // page button state
320 invent_bttn_state page_button_state[NUM_PAGE_BUTTONS] = {
321     BttnOff, BttnOff, BttnOff, BttnDummy, BttnDummy, BttnOff,
322 };
323 // Last button state that was actually drawn.
324 invent_bttn_state old_button_state[NUM_PAGE_BUTTONS] = {BttnDummy, BttnDummy, BttnDummy,
325                                                         BttnDummy, BttnDummy, BttnDummy};
326 
327 LGRegion *pagebutton_region;
328 
329 // DRAWING STUFF
330 grs_bitmap inv_backgnd;
331 grs_canvas inv_norm_canvas;
332 grs_canvas inv_fullscrn_canvas;
333 grs_canvas inv_view360_canvas;
334 grs_canvas *pinv_canvas = &inv_norm_canvas;
335 
336 grs_canvas inv_gamepage_canvas;
337 grs_canvas inv_fullpage_canvas;
338 grs_canvas *ppage_canvas = &inv_gamepage_canvas;
339 
340 #define inv_canvas (*pinv_canvas)
341 
342 #define NUM_PAGE_BTTNS NUM_PAGE_BUTTONS
343 
344 #ifdef OLD_BUTTON_CURSORS
345 LGCursor invent_bttn_cursors[NUM_PAGE_BTTNS];
346 grs_bitmap invent_bttn_bitmaps[NUM_PAGE_BTTNS];
347 Ref invent_bttn_curs_ids[NUM_PAGE_BTTNS] = {
348     REF_IMG_bmInventWeapon, REF_IMG_bmInventHardware,   REF_IMG_bmInventGeneral,
349     REF_IMG_bmTargetCursor, REF_IMG_bmInventCombatSoft, REF_IMG_bmInventMiscSoft,
350 };
351 #else
352 LGCursor invent_bttn_cursor;
353 grs_bitmap invent_bttn_bitmap;
354 #endif
355 
356 static char *cursor_strings[NUM_PAGE_BUTTONS];
357 static char cursor_string_buf[128];
358 
359 #define BUTTON_PANEL_Y (INVENTORY_PANEL_Y + INVENTORY_PANEL_HEIGHT)
360 
361 #define INVENT_BUTTON_PANEL_X (-1)
362 #define INVENT_BUTTON_PANEL_Y (196 - BUTTON_PANEL_Y)
363 
364 // ---------------------
365 //  Internal Prototypes
366 // ---------------------
367 void draw_page_buttons(uchar full);
368 ubyte add_to_some_page(ObjID obj, uchar select);
369 void push_inventory_cursors(LGCursor *newcurs);
370 void pop_inventory_cursors(void);
371 void draw_inventory_string(char *s, int x, int y, uchar clear);
372 void clear_inventory_region(short x1, short y1, short x2, short y2);
373 void draw_quant_line(char *name, char *quant, long color, uchar active, short left, short right, short y);
374 void draw_quant_list(inv_display *dp, uchar newpage);
375 void set_current_active(int activenum);
376 int get_item_at_pixrow(inv_display *dp, int row);
377 char *weapon_name_func(void *, int num, char *buf);
378 char *weapon_quant_func(int num, char *buf);
379 void draw_weapons_list(inv_display *dp);
380 uchar inventory_select_weapon(inv_display *dp, int w);
381 uchar weapon_use_func(inv_display *dp, int w);
382 ubyte weapons_add_func(inv_display *dp, int row, ObjID *objP, uchar select);
383 void weapon_drop_func(inv_display *dp, int itemnum);
384 ubyte generic_add_func(inv_display *dp, int row, ObjID *idP, uchar select);
385 void generic_drop_func(inv_display *dp, int row);
386 char *null_name_func(inv_display *dp, int n, char *buf);
387 static char *grenade_name_func(void *vdp, int n, char *buf);
388 void push_live_grenade_cursor(ObjID obj);
389 uchar grenade_use_func(inv_display *dp, int row);
390 ubyte grenade_add_func(inv_display *dp, int row, ObjID *idP, uchar select);
391 char *drug_name_func(inv_display *dp, int n, char *buf);
392 uchar drug_use_func(inv_display *dp, int row);
393 char *ammo_name_func(void *, int n, char *buf);
394 void hardware_add_specials(int n, int ver);
395 ubyte ware_add_func(inv_display *dp, int, ObjID *idP, uchar select);
396 void ware_drop_func(inv_display *dp, int row);
397 char *null_quant_func(inv_display *, int, int, char *buf);
398 void draw_general_list(inv_display *dp);
399 uchar general_use_func(inv_display *dp, int row);
400 ubyte inv_empty_trash(void);
401 ubyte add_access_card(inv_display *dp, ObjID *idP, uchar select);
402 ubyte general_add_func(inv_display *dp, int row, ObjID *idP, uchar select);
403 void remove_general_item(ObjID obj);
404 void general_drop_func(inv_display *, int row);
405 uchar inv_select_general(inv_display *dp, int w);
406 void email_more_draw(inv_display *dp);
407 uchar email_more_use(inv_display *dp, int);
408 uchar email_use_func(inv_display *dp, int row);
409 void email_select_func(inv_display *dp, int row);
410 void add_email_datamunge(short mung, uchar select);
411 ubyte email_add_func(inv_display *, int, ObjID *idP, uchar select);
412 void email_drop_func(inv_display *, int);
413 char *log_name_func(void *, int num, char *buf);
414 uchar log_use_func(inv_display *dp, int row);
415 void inventory_draw_page(int pgnum);
416 void draw_page_button_panel();
417 uchar do_selection(inv_display *dp, int row);
418 void add_object_on_cursor(inv_display *dp, int row);
419 uchar inventory_handle_leftbutton(uiEvent *ev, inv_display *dp, int row);
420 uchar inventory_handle_rightbutton(uiEvent *ev, LGRegion *reg, inv_display *dp, int row);
421 uchar inventory_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t);
422 uchar pagebutton_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t);
423 uchar invent_hotkey_func(ushort, uint32_t, intptr_t data);
424 uchar cycle_weapons_func(ushort, uint32_t, intptr_t data);
425 void init_invent_hotkeys(void);
426 void invent_language_change(void);
427 errtype inventory_update_screen_mode();
428 void inv_change_fullscreen(uchar on);
429 void inv_update_fullscreen(uchar full);
430 void super_drop_func(int dispnum, int row);
431 void super_use_func(int dispnum, int row);
432 void gen_log_displays(int pgnum);
433 void absorb_object_on_cursor(ushort, uint32_t, intptr_t);
434 uchar gen_inv_page(int pgnum, int *i, inv_display **dp);
435 uchar gen_inv_displays(int *i, inv_display **dp);
436 
437 // ---------------------
438 // DISPLAY LIST ROUTINES
439 // ---------------------
440 
441 // --------
442 // ROUTINES
443 // --------
444 
push_inventory_cursors(LGCursor * newcurs)445 void push_inventory_cursors(LGCursor *newcurs) {
446     int i;
447 
448     for (i = 0; i < NUM_INVENT_REGIONS; i++) {
449         uiPushRegionCursor(*(all_inventory_regions[i]), newcurs);
450     }
451 }
452 
pop_inventory_cursors(void)453 void pop_inventory_cursors(void) {
454     int i;
455 
456     for (i = 0; i < NUM_INVENT_REGIONS; i++) {
457         uiPopRegionCursor(*(all_inventory_regions[i]));
458     }
459 }
460 
461 // draw a string in relative coordinates
draw_inventory_string(char * s,int x,int y,uchar clear)462 void draw_inventory_string(char *s, int x, int y, uchar clear) {
463     short w, h;
464     short a, b, c, d;
465 
466     gr_string_size(s, &w, &h);
467     if (w <= 0 || h <= 0 || strlen(s) == 0)
468         return;
469     STORE_CLIP(a, b, c, d);
470     //   Warning(("draw_string clip %d %d %d %d\n",x-1,y-1,x+w,y+h));
471     ss_safe_set_cliprect(x - 1, y - 1, x + w, y + h);
472     if (!full_game_3d) {
473 
474         LGRect r;
475         r.ul.x = x - 1;
476         r.ul.y = y - 1;
477         r.lr.x = x + w;
478         r.lr.y = y + h;
479         RECT_MOVE(&r, MakePoint(INVENTORY_PANEL_X, INVENTORY_PANEL_Y));
480         uiHideMouse(&r);
481         if (clear)
482             ss_bitmap(&inv_backgnd, 0, 0);
483         // gr_bitmap(&inv_backgnd, 0, 0);
484         draw_shadowed_string(s, x, y, FALSE);
485         uiShowMouse(&r);
486     } else {
487         long oldcolor = gr_get_fcolor();
488         if (clear) {
489             gr_set_fcolor(0);
490             ss_rect(x, y, x + w, y + h - 1);
491         }
492         gr_set_fcolor(oldcolor);
493         draw_shadowed_string(s, x, y, TRUE);
494     }
495     RESTORE_CLIP(a, b, c, d);
496 }
497 
clear_inventory_region(short x1,short y1,short x2,short y2)498 void clear_inventory_region(short x1, short y1, short x2, short y2) {
499     LGRect r;
500     short a, b, c, d;
501 
502     if (!full_game_3d) {
503         r.ul.x = x1;
504         r.ul.y = y1;
505         r.lr.x = x2;
506         r.lr.y = y2;
507         STORE_CLIP(a, b, c, d);
508         ss_safe_set_cliprect(x1, y1, x2, y2);
509         RECT_MOVE(&r, MakePoint(INVENTORY_PANEL_X, INVENTORY_PANEL_Y));
510         uiHideMouse(&r);
511         ss_bitmap(&inv_backgnd, 0, 0);
512         // gr_bitmap(&inv_backgnd, 0, 0);
513         uiShowMouse(&r);
514         RESTORE_CLIP(a, b, c, d);
515     } else {
516         gr_set_fcolor(0);
517         ss_rect(x1 - 1, y1, x2 + 1, y2);
518     }
519 }
520 
521 // Draw a single line of the weapons list
draw_quant_line(char * name,char * quant,long color,uchar active,short left,short right,short y)522 void draw_quant_line(char *name, char *quant, long color, uchar active, short left, short right, short y) {
523     short ht, wd;
524 
525     gr_string_size(name, &wd, &ht);
526     wd = gr_string_width(quant);
527     clear_inventory_region(left, y, right, y + ht);
528     if (active)
529         gr_set_fcolor(SELECTED_ITEM_COLOR);
530     else if (color < 256)
531         gr_set_fcolor(color);
532     draw_inventory_string(name, left, y, FALSE);
533     draw_inventory_string(quant, right - wd, y, FALSE);
534 }
535 
draw_quant_list(inv_display * dp,uchar newpage)536 void draw_quant_list(inv_display *dp, uchar newpage) {
537     int wtype;
538     int cnt;
539     int y, i;
540     char buf[BUFSZ];
541     ubyte *quant = (ubyte *)&player_struct + dp->offset;
542     ubyte *exist = quant;
543     int active = (dp->activenum == NULL_ACTIVE) ? -1 : player_struct.actives[dp->activenum];
544     int known_active = (dp->activenum == NULL_ACTIVE) ? -1 : known_actives[dp->activenum];
545     quantity_state *line = dp->lines + dp->relnum * dp->pgsize;
546 
547     // Hey, what if we don't have our active item anymore...
548     if (active >= 0 && active < dp->listlen && quant[active] == 0) {
549         player_struct.actives[dp->activenum] = active = MFD_INV_NOTYPE;
550         set_inventory_mfd(dp->mfdtype, MFD_INV_NOTYPE, TRUE);
551     }
552     if (newpage && dp->titlenum != REF_STR_Null) {
553         gr_set_fcolor(dp->titlecolor);
554         get_string(dp->titlenum, buf, BUFSZ);
555         draw_inventory_string(buf, dp->left, dp->top, TRUE);
556     }
557     if (dp->first != 0)
558         wtype = dp->first;
559     else
560         for (wtype = 0, cnt = 0; wtype < dp->listlen && cnt < dp->pgsize * dp->relnum; wtype++) {
561             if (exist[wtype] > 0)
562                 cnt++;
563         }
564     for (y = dp->top + Y_STEP, i = 0, cnt = 0; cnt < dp->pgsize; i++, wtype++) {
565         if (wtype >= dp->listlen) {
566             if (line->num < dp->listlen) {
567                 clear_inventory_region(dp->left, y, dp->right, y + Y_STEP);
568             }
569             y += Y_STEP;
570             line->num = wtype;
571             line++;
572             cnt++;
573             continue;
574         }
575         if (exist[wtype] != 0) {
576             uchar newactive = active != known_active;
577             // note the hack for combat softwares
578             uchar curractive =
579                 ((show_all_actives && dp->pgnum == INV_MAIN_PAGE) || player_struct.current_active == dp->activenum) ||
580                 dp->activenum == ACTIVE_COMBAT_SOFT;
581             uchar changed = newpage || newactive || (line->num != wtype) || (line->quant != quant[wtype]) ||
582                             (line->exist != exist[wtype]);
583             line->num = wtype;
584             line->quant = quant[wtype];
585             line->exist = exist[wtype];
586             if (changed) {
587                 char buf[BUFSZ] = "";
588                 char buf2[BUFSZ] = "";
589                 uchar is_active = wtype == active && curractive;
590                 uchar col;
591 
592                 if (dp->name != NULL)
593                     dp->name(dp, wtype, buf);
594                 if (dp->quant != NULL)
595                     dp->quant(dp, wtype, quant[wtype], buf2);
596                 col = dp->listcolor;
597                 if (col > 239)
598                     col = (color_func_list[col - 240])(dp, wtype);
599                 draw_quant_line(buf, buf2, col, is_active, dp->left, dp->right, y);
600             }
601             cnt++;
602             line++;
603             y += Y_STEP;
604         }
605     }
606 }
607 
set_current_active(int activenum)608 void set_current_active(int activenum) {
609     int old = player_struct.current_active;
610     known_actives[old] = -1;
611     player_struct.current_active = activenum;
612     known_actives[activenum] = -1;
613 }
614 
615 // Get the item at a particular pixel y
get_item_at_pixrow(inv_display * dp,int row)616 int get_item_at_pixrow(inv_display *dp, int row) {
617     int linenum = dp->relnum * dp->pgsize;
618     int ipanel_y;
619     int y_step;
620     int r1, r2;
621 
622 #ifdef STEREO_SUPPORT
623     if (convert_use_mode == 5) {
624         switch (i6d_device) {
625         case I6D_CTM:
626             ipanel_y = 1;
627             y_step = Y_STEP << 2;
628             break;
629         case I6D_VFX1:
630             ipanel_y = INVENTORY_PANEL_Y >> 1;
631             //            ipanel_y = (200 - inv_fullscrn_canvas.bm.h);
632             //            y_step = Y_STEP << 1;
633             y_step = 10;
634             break;
635         default:
636             break;
637         }
638     } else
639 #endif
640     {
641         ipanel_y = INVENTORY_PANEL_Y;
642         y_step = Y_STEP;
643     }
644     r1 = row;
645     row -= ipanel_y + dp->top + y_step;
646     if (row < 0)
647         return -1;
648     r2 = row;
649     row /= y_step;
650     if (row >= dp->pgsize)
651         return -1;
652     //   Warning(("row = %d = (%d - %d + %d + %d) = %d / %d\n",row,r1,ipanel_y,dp->top,y_step,r2,y_step));
653 
654     return linenum + row;
655 }
656 
657     // --------------------
658     // WEAPON DISPLAY FUNCS
659     // --------------------
660 
661 #define WEAP_CLASSES (1 << CLASS_GUN)
662 #define WEAP_TRIP MAKETRIP(CLASS_GUN, 0, 0)
663 
weapon_name_func(void * v,int num,char * buf)664 char *weapon_name_func(void *v, int num, char *buf) {
665     weapon_slot *ws = &player_struct.weapons[num];
666     get_weapon_name(ws->type, ws->subtype, buf);
667     return buf;
668 }
669 
weapon_quant_func(int num,char * buf)670 char *weapon_quant_func(int num, char *buf) {
671     int triple, num_ammo_types, ammo_subclass;
672     ubyte ammo_types[3];
673     int i = 0;
674     weapon_slot *ws = &player_struct.weapons[num];
675     uchar energy = is_energy_weapon(ws->type);
676 
677     if (is_handtohand_weapon(ws->type)) {
678         buf[0] = '\0';
679         return buf;
680     }
681 
682     if ((!energy) && (ws->type != GUN_SUBCLASS_BEAMPROJ)) {
683         int ammo = ws->ammo;
684         if (ws->ammo_type == EMPTY_WEAPON_SLOT) {
685             ammo = 0;
686         }
687 
688         get_available_ammo_type(ws->type, ws->subtype, &num_ammo_types, ammo_types, &ammo_subclass);
689 
690         triple = MAKETRIP(CLASS_AMMO, ammo_subclass, ws->ammo_type);
691         if (ammo > 0) {
692             buf[i++] = AMMO_TYPE_LETTER((CPTRIP(triple)));
693             buf[i++] = ' ';
694         }
695         if (ammo == 0 && num_ammo_types > 0)
696             get_string(REF_STR_AmmoLoad, buf, BUFSZ);
697         else
698             sprintf(buf + i, "%d", ammo);
699         // itoa(ammo,buf+i,10);
700     } else {
701         if (ws->heat > OVERHEAT_THRESHOLD)
702             get_string(REF_STR_GunHot, buf, BUFSZ);
703         else if (OVERLOAD_VALUE(ws->setting))
704             get_string(REF_STR_AmmoOver, buf, BUFSZ);
705         else if (ws->heat > WARM_THRESHOLD)
706             get_string(REF_STR_GunWarm, buf, BUFSZ);
707         else
708             get_string(REF_STR_GunOK, buf, BUFSZ);
709     }
710     return buf;
711 }
712 
draw_weapons_list(inv_display * dp)713 void draw_weapons_list(inv_display *dp) {
714     uchar newpage = inv_last_page != inventory_page;
715     char buf[BUFSZ];
716     int i, s;
717     short y;
718     gr_set_font(ResLock(WEAPONS_FONT));
719 
720     if (newpage) {
721         gr_set_fcolor(dp->titlecolor);
722         get_string(REF_STR_WeaponTitle, buf, BUFSZ);
723         draw_inventory_string(buf, WEAPON_X, TOP_MARGIN, TRUE);
724         get_string(REF_STR_AmmoTitle, buf, BUFSZ);
725         draw_inventory_string(buf, AMMO_X - gr_string_width(buf), TOP_MARGIN, TRUE);
726     }
727     s = dp->relnum * WEAPONS_PER_PAGE;
728     y = TOP_MARGIN + Y_STEP;
729     for (i = 0; i < WEAPONS_PER_PAGE && s < NUM_WEAPON_SLOTS; i++, s++, y += Y_STEP) {
730         int num_ammo_types, dummy1;
731         ubyte dummy2[3];
732         uchar avail;
733         uchar newactive = weapon_list.active != player_struct.actives[ACTIVE_WEAPON];
734         uchar changed;
735 
736         get_available_ammo_type(weapon_list.slots[s].type, weapon_list.slots[s].subtype, &num_ammo_types, dummy2,
737                                 &dummy1);
738         avail = (num_ammo_types > 0);
739         changed = newpage || (avail != weapon_list.ammo_available[s]) ||
740                   memcmp(&weapon_list.slots[s], &player_struct.weapons[s], sizeof(weapon_slot)) != 0 ||
741                   (newactive && s == weapon_list.active) || (newactive && s == player_struct.actives[ACTIVE_WEAPON]);
742         weapon_list.slots[s] = player_struct.weapons[s];
743         weapon_list.ammo_available[s] = avail;
744         if (!changed)
745             continue;
746         if (weapon_list.slots[s].type != EMPTY_WEAPON_SLOT) {
747             char name[BUFSZ];
748             char quant[BUFSZ];
749             weapon_name_func(dp, s, name);
750             weapon_quant_func(s, quant);
751             draw_quant_line(name, quant, dp->listcolor, s == player_struct.actives[ACTIVE_WEAPON], WEAPON_X, AMMO_X, y);
752         } else
753             clear_inventory_region(WEAPON_X, y, AMMO_X, y + Y_STEP);
754     }
755     weapon_list.active = player_struct.actives[ACTIVE_WEAPON];
756     ResUnlock(WEAPONS_FONT);
757 }
758 
inventory_select_weapon(inv_display * dp,int w)759 uchar inventory_select_weapon(inv_display *dp, int w) {
760     uchar retval = FALSE;
761     int aw = player_struct.actives[ACTIVE_WEAPON];
762 #ifndef NO_DUMMIES
763     inv_display *newdisp;
764     newdisp = dp;
765 #endif // NO_DUMMIES
766     if (player_struct.weapons[w].type == EMPTY_WEAPON_SLOT)
767         goto out;
768     if (aw != w) {
769         weapon_slot *ws = &player_struct.weapons[w];
770         play_digi_fx(SFX_INVENT_SELECT, 1);
771         change_selected_weapon(w);
772         player_struct.last_fire = 0;
773         player_struct.fire_rate = weapon_fire_rate(ws->type, ws->subtype);
774     }
775     player_struct.actives[ACTIVE_WEAPON] = w;
776     set_inventory_mfd(MFD_INV_WEAPON, w, TRUE);
777     set_inventory_mfd(MFD_INV_AMMO, 0, TRUE);
778     mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
779     INVENT_CHANGED;
780     retval = TRUE;
781 out:
782     return retval;
783 }
784 
weapon_use_func(inv_display * dp,int w)785 uchar weapon_use_func(inv_display *dp, int w) {
786     if (player_struct.weapons[w].type == EMPTY_WEAPON_SLOT)
787         return FALSE;
788     inventory_select_weapon(dp, w);
789     mfd_change_slot(mfd_grab_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT), MFD_WEAPON_SLOT);
790     return TRUE;
791 }
792 
weapons_add_func(inv_display * dp,int row,ObjID * objP,uchar select)793 ubyte weapons_add_func(inv_display *dp, int row, ObjID *objP, uchar select) {
794     ubyte retval = ADD_REJECT;
795     ObjID obj = *objP;
796     weapon_slot *ws;
797     weapon_slot tmp;
798     ObjSpecID spec;
799     play_digi_fx(SFX_INVENT_ADD, 1);
800     row += dp->pgsize * dp->relnum;
801     if (player_struct.weapons[NUM_WEAPON_SLOTS - 1].type == EMPTY_WEAPON_SLOT)
802         row = NUM_WEAPON_SLOTS - 1;
803     if (row < 0 || row >= NUM_WEAPON_SLOTS || player_struct.weapons[row].type == EMPTY_WEAPON_SLOT) {
804         for (row = 0; row < NUM_WEAPON_SLOTS; row++)
805             if (player_struct.weapons[row].type == EMPTY_WEAPON_SLOT)
806                 break;
807         if (row >= NUM_WEAPON_SLOTS) {
808             string_message_info(REF_STR_InvNoRoom);
809             return ADD_FAIL;
810         }
811     }
812     ws = &player_struct.weapons[row];
813     tmp = *ws;
814     spec = objs[obj].specID;
815 
816     ws->type = objs[obj].subclass;
817     ws->subtype = objs[obj].info.type;
818     ws->ammo = objGuns[spec].ammo_count;
819     ws->ammo_type = objGuns[spec].ammo_type;
820     if (player_struct.actives[ACTIVE_WEAPON] == row)
821         set_inventory_mfd(MFD_INV_WEAPON, row, TRUE);
822     if (tmp.type != EMPTY_WEAPON_SLOT) {
823         objs[obj].subclass = tmp.type;
824         objs[obj].info.type = tmp.subtype;
825         objGuns[spec].ammo_type = tmp.ammo_type;
826         objGuns[spec].ammo_count = tmp.ammo;
827         retval = ADD_SWAP;
828     } else {
829         obj_destroy(obj);
830         retval = ADD_POP;
831     }
832     if (select)
833         inventory_select_weapon(dp, row);
834 
835     if (player_struct.actives[ACTIVE_WEAPON] == row) {
836         set_inventory_mfd(MFD_INV_WEAPON, row, TRUE);
837         mfd_notify_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT, TRUE, MFD_ACTIVE, TRUE);
838     }
839     // in case ammo mfd
840     mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
841 
842     void SetMotionCursorsColorForActiveWeapon(void);
843     SetMotionCursorsColorForActiveWeapon();
844 
845     return retval;
846 }
847 
weapon_drop_func(inv_display * dp,int itemnum)848 void weapon_drop_func(inv_display *dp, int itemnum) {
849     weapon_slot *ws;
850     ObjID obj;
851     ObjSpecID spec;
852     int it;
853 
854     if (itemnum < 0 || itemnum >= dp->listlen)
855         return;
856     ws = &player_struct.weapons[itemnum];
857     if (ws->type == EMPTY_WEAPON_SLOT)
858         return;
859     obj = obj_create_base(MAKETRIP(CLASS_GUN, ws->type, ws->subtype));
860     if (obj == OBJ_NULL) {
861         return;
862     }
863     spec = objs[obj].specID;
864     objGuns[spec].ammo_type = ws->ammo_type;
865     objGuns[spec].ammo_count = ws->ammo;
866     push_cursor_object(obj);
867     // preserve selected weapon.
868     if (itemnum < player_struct.actives[ACTIVE_WEAPON])
869         player_struct.actives[ACTIVE_WEAPON]--;
870     for (it = itemnum + 1; it < NUM_WEAPON_SLOTS; it++) {
871         player_struct.weapons[it - 1] = player_struct.weapons[it];
872     }
873     player_struct.weapons[NUM_WEAPON_SLOTS - 1].type = EMPTY_WEAPON_SLOT;
874     if (itemnum > 0 && player_struct.weapons[player_struct.actives[ACTIVE_WEAPON]].type == EMPTY_WEAPON_SLOT)
875         player_struct.actives[ACTIVE_WEAPON]--;
876 
877     // in case ammo mfd
878     mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
879     // In case the weapons MFD was looking at that weapon, nix it
880     if (player_struct.weapons[player_struct.actives[ACTIVE_WEAPON]].type == EMPTY_WEAPON_SLOT)
881         mfd_notify_func(MFD_EMPTY_FUNC, MFD_WEAPON_SLOT, TRUE, MFD_EMPTY, TRUE);
882     else
883         set_inventory_mfd(MFD_INV_WEAPON, player_struct.actives[ACTIVE_WEAPON], TRUE);
884     INVENT_CHANGED;
885 
886     void SetMotionCursorsColorForActiveWeapon(void);
887     SetMotionCursorsColorForActiveWeapon();
888 }
889 
890 // -------------
891 // GENERIC FUNCS
892 // -------------
893 extern int nth_after_triple(int, uchar);
894 
generic_name_func(void * vdp,int num,char * buf)895 static char *generic_name_func(void *vdp, int num, char *buf) {
896     int trip = nth_after_triple(((inv_display *)vdp)->basetrip, num);
897     get_object_short_name(trip, buf, BUFSZ);
898     return buf;
899 }
900 
generic_draw_list(inv_display * dp)901 static void generic_draw_list(inv_display *dp) {
902     uchar newpage = inv_last_page != inventory_page;
903     gr_set_font(ResLock(ITEM_FONT));
904 
905     draw_quant_list(dp, newpage);
906     ResUnlock(ITEM_FONT);
907 }
908 
generic_add_func(inv_display * dp,int row,ObjID * idP,uchar select)909 ubyte generic_add_func(inv_display *dp, int row, ObjID *idP, uchar select) {
910     ObjID id = *idP;
911     int trip = ID2TRIP(id);
912     int n = OPTRIP(trip) - OPTRIP(dp->basetrip);
913     int obclass = objs[id].obclass;
914 #ifndef NO_DUMMIES
915     int guf;
916     guf = row;
917 #endif // NO_DUMMIES
918     play_digi_fx(SFX_INVENT_ADD, 1);
919     if (n >= 0 && n < dp->listlen) {
920         ubyte *quants = (ubyte *)&player_struct + dp->offset;
921         quants[n]++;
922         if (dp->activenum != NULL_ACTIVE) {
923             if (select) {
924                 player_struct.actives[dp->activenum] = n;
925                 play_digi_fx(SFX_INVENT_SELECT, 1);
926             }
927             if (select || n == player_struct.actives[dp->activenum])
928                 set_inventory_mfd(dp->mfdtype, n, TRUE);
929         }
930         obj_destroy(id);
931         // This is a special-case hack for cartridges.
932         if (obclass == CLASS_AMMO) {
933             mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
934             mfd_notify_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT, FALSE, MFD_ACTIVE, TRUE);
935             INVENT_CHANGED;
936         }
937         return ADD_POP;
938     }
939     return ADD_REJECT;
940 }
941 
generic_drop_func(inv_display * dp,int row)942 void generic_drop_func(inv_display *dp, int row) {
943     int itemnum = dp->lines[row].num;
944     ObjID obj;
945     int triple;
946     ubyte *quant;
947     if (itemnum < 0 || itemnum >= dp->listlen)
948         return;
949     quant = (ubyte *)&player_struct + dp->offset;
950     if (quant[itemnum] == 0)
951         return;
952     quant[itemnum]--;
953     triple = nth_after_triple(dp->basetrip, itemnum);
954     obj = obj_create_base(triple);
955     if (obj == OBJ_NULL) {
956         return;
957     }
958     push_cursor_object(obj);
959     if (dp->activenum != NULL_ACTIVE && player_struct.actives[dp->activenum] == itemnum && quant[itemnum] == 0) {
960         player_struct.actives[dp->activenum] = 0xFF;
961         set_inventory_mfd(dp->mfdtype, MFD_INV_NOTYPE, FALSE);
962     }
963     INVENT_CHANGED;
964 }
965 
generic_quant_func(inv_display * dp,int n,int q,char * buf)966 static char *generic_quant_func(inv_display *dp, int n, int q, char *buf) {
967 #ifndef NO_DUMMIES
968     char *dummy;
969     dummy = n + (char*)dp;
970 #endif // NO_DUMMIES
971     //  itoa(q,buf,10);
972     sprintf(buf, "%d", q);
973     return buf;
974 }
975 
null_name_func(inv_display * dp,int n,char * buf)976 char *null_name_func(inv_display *dp, int n, char *buf) {
977 #ifndef NO_DUMMIES
978     char *goof;
979     goof = (char*)dp + n;
980 #endif // NO_DUMMIES
981     *buf = '\0';
982     return buf;
983 }
984 
985     // -------------
986     // GRENADE FUNCS
987     // -------------
988 
989 #define GREN_CLASSES (1 << CLASS_GRENADE)
990 #define GREN_TRIP MAKETRIP(CLASS_GRENADE, 0, 0)
991 
grenade_name_func(void * dp,int n,char * buf)992 static char *grenade_name_func(void *dp, int n, char *buf) { return get_grenade_name(n, buf); }
993 
994 extern uiSlab fullscreen_slab;
995 extern uiSlab main_slab;
996 
997 grs_bitmap grenade_bmap;
998 #ifdef SVGA_SUPPORT
999 char grenade_bmap_buffer[8700];
1000 #else
1001 char grenade_bmap_buffer[700];
1002 #endif
1003 
push_live_grenade_cursor(ObjID obj)1004 void push_live_grenade_cursor(ObjID obj) {
1005     short w, h;
1006     extern LGCursor object_cursor;
1007     char live_string[22];
1008 #ifdef CURSOR_BACKUPS
1009     extern grs_bitmap backup_object_cursor;
1010     extern uchar *backup[NUM_BACKUP_BITS];
1011 #endif
1012 #ifdef SVGA_SUPPORT
1013     uchar old_over = gr2ss_override;
1014     short temp;
1015 #endif
1016     grs_canvas cursor_canvas;
1017     LGPoint hotspot;
1018     grs_bitmap *bmap = bitmaps_2d[OPNUM(obj)];
1019     void *bits = grenade_bmap_buffer;
1020 
1021     grenade_bmap = *bmap;
1022     gr_set_font(ResLock(ITEM_FONT));
1023     get_string(REF_STR_WordLiveGrenade, live_string, sizeof(live_string));
1024     gr_string_size(live_string, &w, &h);
1025     w++;
1026     h++; // compensate for shadowing
1027 #ifdef SVGA_SUPPORT
1028     gr2ss_override = OVERRIDE_ALL;
1029     ss_set_hack_mode(2, &temp);
1030     if (convert_use_mode != 0) {
1031         grenade_bmap.w = lg_max(bmap->w, w);
1032         grenade_bmap.h = bmap->h + h;
1033         grenade_bmap.w = SCONV_X(grenade_bmap.w);
1034         grenade_bmap.h = SCONV_Y(grenade_bmap.h);
1035     } else {
1036 #endif
1037         grenade_bmap.w = lg_max(bmap->w, w);
1038         grenade_bmap.h = bmap->h + h;
1039 #ifdef SVGA_SUPPORT
1040     }
1041 #endif
1042     //   mprintf("bsize = %d, w * h = %d\n",sizeof(grenade_bmap_buffer), grenade_bmap.w * grenade_bmap.h);
1043     if (sizeof(grenade_bmap_buffer) < grenade_bmap.w * grenade_bmap.h)
1044         critical_error(0x3006);
1045 
1046     gr_init_bitmap(&grenade_bmap, (uchar *)bits, grenade_bmap.type, grenade_bmap.flags, grenade_bmap.w, grenade_bmap.h);
1047     gr_init_canvas(&cursor_canvas, (uchar *)bits, BMT_FLAT8, grenade_bmap.w, grenade_bmap.h);
1048     gr_push_canvas(&cursor_canvas);
1049     gr_set_font(ResGet(ITEM_FONT));
1050     gr_clear(0);
1051 #ifdef SVGA_SUPPORT
1052     if (convert_use_mode > 0) {
1053         ss_bitmap(bmap, (INV_SCONV_X(grenade_bmap.w) - bmap->w) / 2, 0);
1054         gr_set_fcolor(0x4c);
1055         draw_shadowed_string(live_string, (INV_SCONV_X(grenade_bmap.w) - w) / 2, INV_SCONV_Y(grenade_bmap.h) - h, TRUE);
1056     } else {
1057 #endif
1058         ss_bitmap(bmap, (grenade_bmap.w - bmap->w) / 2, 0);
1059         gr_set_fcolor(0x4c);
1060         draw_shadowed_string(live_string, (grenade_bmap.w - w) / 2 + 1, grenade_bmap.h - h, TRUE);
1061 #ifdef SVGA_SUPPORT
1062     }
1063 #endif
1064     ResUnlock(ITEM_FONT);
1065     gr_pop_canvas();
1066 #ifdef SVGA_SUPPORT
1067     ss_set_hack_mode(0, &temp);
1068     gr2ss_override = old_over;
1069     if (convert_use_mode != 0) {
1070         hotspot.x = grenade_bmap.w / 2;
1071         hotspot.y = grenade_bmap.h / 2;
1072     } else {
1073 #endif
1074         hotspot.x = grenade_bmap.w / 2;
1075         hotspot.y = grenade_bmap.h / 2;
1076 #ifdef SVGA_SUPPORT
1077     }
1078 #endif
1079     uiHideMouse(NULL);
1080     uiMakeBitmapCursor(&object_cursor, &grenade_bmap, hotspot);
1081     uiPushSlabCursor(&fullscreen_slab, &object_cursor);
1082     uiPushSlabCursor(&main_slab, &object_cursor);
1083     uiShowMouse(NULL);
1084     object_on_cursor = obj;
1085     input_cursor_mode = INPUT_OBJECT_CURSOR;
1086 }
1087 
grenade_use_func(inv_display * dp,int row)1088 uchar grenade_use_func(inv_display *dp, int row) {
1089     int itemnum = dp->lines[row].num;
1090     ObjID obj;
1091     int triple;
1092     ubyte *quant;
1093     ObjSpecID spec;
1094     if (itemnum < 0 || itemnum >= dp->listlen)
1095         return (FALSE);
1096     quant = (ubyte *)&player_struct + dp->offset;
1097     if (quant[itemnum] == 0)
1098         return (FALSE);
1099     quant[itemnum]--;
1100     triple = nth_after_triple(dp->basetrip, itemnum);
1101     obj = obj_create_base(triple);
1102     if (obj == OBJ_NULL) {
1103         return (FALSE);
1104     }
1105     if (dp->activenum != NULL_ACTIVE && player_struct.actives[dp->activenum] == itemnum && quant[itemnum] == 0) {
1106         player_struct.actives[dp->activenum] = 0xFF;
1107         set_inventory_mfd(dp->mfdtype, MFD_INV_NOTYPE, FALSE);
1108     }
1109     INVENT_CHANGED;
1110     push_live_grenade_cursor(obj);
1111     spec = objs[obj].specID;
1112     activate_grenade(spec);
1113     return (TRUE);
1114 }
1115 
grenade_add_func(inv_display * dp,int row,ObjID * idP,uchar select)1116 ubyte grenade_add_func(inv_display *dp, int row, ObjID *idP, uchar select) {
1117     extern errtype string_message_info(int strnum);
1118     ObjSpecID sid = objs[*idP].specID;
1119     play_digi_fx(SFX_INVENT_ADD, 1);
1120     if (objGrenades[sid].flags & GREN_ACTIVE_FLAG) {
1121         string_message_info(REF_STR_InvLiveGrenade);
1122         return ADD_FAIL;
1123     }
1124     return generic_add_func(dp, row, idP, select);
1125 }
1126 
1127 // ----------
1128 // DRUG FUNCS
1129 // ----------
1130 #define DRUG_CLASSES (1 << CLASS_DRUG)
1131 #define DRUG_TRIP MAKETRIP(CLASS_DRUG, 0, 0)
1132 
drug_name_func(inv_display * dp,int n,char * buf)1133 char *drug_name_func(inv_display *dp, int n, char *buf) {
1134 #ifndef NO_DUMMIES
1135     inv_display *dummy;
1136     dummy = dp;
1137 #endif // NO_DUMMIES
1138     return get_drug_name(n, buf);
1139 }
1140 
drug_use_func(inv_display * dp,int row)1141 uchar drug_use_func(inv_display *dp, int row) {
1142     uchar retval = FALSE;
1143     int n = dp->lines[row].num;
1144     if (n < dp->listlen) {
1145         drug_use(n);
1146         set_inventory_mfd(dp->mfdtype, n, TRUE);
1147         retval = TRUE;
1148         INVENT_CHANGED;
1149     }
1150     return retval;
1151 }
1152 
1153 // ----------
1154 // AMMO FUNCS
1155 // ----------
1156 #define AMMO_CLASSES (1 << CLASS_AMMO)
1157 #define AMMO_TRIP MAKETRIP(CLASS_AMMO, 0, 0)
1158 
ammo_name_func(void * dp,int n,char * buf)1159 char *ammo_name_func(void *dp, int n, char *buf) {
1160     int triple;
1161 
1162     buf[0] = AMMO_TYPE_LETTER(n);
1163     buf[1] = ' ';
1164     triple = get_triple_from_class_nth_item(CLASS_AMMO, n);
1165     get_object_short_name(triple, buf + 2, 31);
1166     return buf;
1167 }
1168 
1169 // ---------
1170 // HARDWARES
1171 // ---------
1172 #define HARD_CLASSES (1 << CLASS_HARDWARE)
1173 #define HARD_TRIP MAKETRIP(CLASS_HARDWARE, 0, 0)
1174 #define HARDWARE_PAGES 2
1175 
ware_name_func(void * vdp,int n,char * buf)1176 static char *ware_name_func(void *vdp, int n, char *buf) {
1177     int type;
1178     switch (((inv_display *)vdp)->activenum) {
1179     case ACTIVE_HARDWARE:
1180         type = WARE_HARD;
1181         break;
1182     case ACTIVE_COMBAT_SOFT:
1183         type = WARE_SOFT_COMBAT;
1184         break;
1185     case ACTIVE_DEFENSE_SOFT:
1186         type = WARE_SOFT_DEFENSE;
1187         break;
1188     case ACTIVE_MISC_SOFT:
1189         type = WARE_SOFT_MISC;
1190         break;
1191     }
1192     get_ware_name(type, n, buf, BUFSZ);
1193     return NULL;
1194 }
1195 
ware_use_func(inv_display * dp,int row)1196 static uchar ware_use_func(inv_display *dp, int row) {
1197     int waretype;
1198     int t = dp->lines[row].num;
1199     if (t >= dp->listlen)
1200         return FALSE;
1201     switch (dp->activenum) {
1202     case ACTIVE_HARDWARE:
1203         waretype = WARE_HARD;
1204         break;
1205     case ACTIVE_COMBAT_SOFT:
1206         waretype = WARE_SOFT_COMBAT;
1207         break;
1208     case ACTIVE_DEFENSE_SOFT:
1209         waretype = WARE_SOFT_DEFENSE;
1210         break;
1211     case ACTIVE_MISC_SOFT:
1212         waretype = WARE_SOFT_MISC;
1213         break;
1214     }
1215     use_ware(waretype, t);
1216     return TRUE;
1217 }
1218 
hardware_add_specials(int n,int ver)1219 void hardware_add_specials(int n, int ver) {
1220     extern WARE HardWare[NUM_HARDWAREZ];
1221     extern void gamescr_bio_func(void);
1222     switch (n) {
1223     case HARDWARE_AUTOMAP:
1224         mfd_notify_func(MFD_MAP_FUNC, MFD_MAP_SLOT, TRUE, MFD_ACTIVE, TRUE);
1225         {
1226             int i;
1227             for (i = 0; i < NUM_O_AMAP; i++)
1228                 amap_version_set(i, player_struct.hardwarez[HARDWARE_AUTOMAP]);
1229         }
1230         break;
1231     case HARDWARE_TARGET:
1232         mfd_notify_func(MFD_TARGET_FUNC, MFD_TARGET_SLOT, TRUE, MFD_ACTIVE, TRUE);
1233         break;
1234     case HARDWARE_SHIELD: {
1235         extern int energy_cost(int warenum);
1236         extern void shield_set_absorb(void);
1237         int ener = 0;
1238         if (WareActive(player_struct.hardwarez_status[CPTRIP(SHIELD_HARD_TRIPLE)]))
1239             ener = energy_cost(CPTRIP(SHIELD_HARD_TRIPLE));
1240         SHIELD_SETTING_SET(player_struct.hardwarez_status[n], ver - 1);
1241         if (ener) {
1242             shield_set_absorb();
1243             ener = energy_cost(CPTRIP(SHIELD_HARD_TRIPLE)) - ener;
1244             set_player_energy_spend(lg_min(MAX_ENERGY, player_struct.energy_spend + ener));
1245         }
1246         mfd_notify_func(MFD_SHIELD_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1247     } break;
1248     case HARDWARE_ENVIROSUIT: {
1249         extern void zoom_to_lean_meter(void);
1250         if (_current_loop == GAME_LOOP)
1251             gamescr_bio_func();
1252         zoom_to_lean_meter();
1253     } break;
1254     // Flash the email sideicon the first time you pick up the data reader to tell the player he has a log.
1255     // After that, it is never flashed again if a new log is picked up.
1256     case HARDWARE_EMAIL:
1257         player_struct.hardwarez_status[HARDWARE_EMAIL] |= WARE_FLASH;
1258         QUESTBIT_ON(0x12c);
1259         break;
1260     }
1261     if (HardWare[n].sideicon != SI_NONE) {
1262         extern void zoom_to_side_icon(LGPoint from, int icon);
1263         LGPoint from;
1264         ui_mouse_get_xy(&from.x, &from.y);
1265         zoom_to_side_icon(from, HardWare[n].sideicon);
1266     }
1267 }
1268 
ware_add_func(inv_display * dp,int nn,ObjID * idP,uchar select)1269 ubyte ware_add_func(inv_display *dp, int nn, ObjID *idP, uchar select) {
1270     ObjID id = *idP;
1271     int trip = ID2TRIP(id);
1272     uchar oneshot;
1273     uchar bigstuff_fake = FALSE;
1274     int n;
1275     extern uchar shameful_obselete_flag;
1276 
1277     if (global_fullmap->cyber && (objs[id].obclass == CLASS_BIGSTUFF)) {
1278         bigstuff_fake = TRUE;
1279         trip = MAKETRIP(CLASS_SOFTWARE, objBigstuffs[objs[id].specID].data1, objBigstuffs[objs[id].specID].data2);
1280     }
1281     n = OPTRIP(trip) - OPTRIP(dp->basetrip);
1282     oneshot = TRIP2CL(trip) == CLASS_SOFTWARE && TRIP2SC(trip) == SOFTWARE_SUBCLASS_ONESHOT;
1283     if (TRIP2CL(trip) == CLASS_SOFTWARE && TRIP2SC(trip) == SOFTWARE_SUBCLASS_DATA)
1284         return ADD_REJECT;
1285     if (n >= 0 && n < dp->listlen) {
1286         ubyte ver;
1287         ubyte *quants = (ubyte *)&player_struct + dp->offset;
1288         if (bigstuff_fake)
1289             ver = objBigstuffs[objs[id].specID].cosmetic_value;
1290         else
1291             ver = (TRIP2CL(trip) == CLASS_HARDWARE) ? objHardwares[objs[id].specID].version
1292                                                     : objSoftwares[objs[id].specID].version;
1293 
1294         if (trip == GAMES_TRIPLE)
1295             quants[n] |= ver;
1296         else if (oneshot)
1297             quants[n]++;
1298         else if (quants[n] >= ver) {
1299             string_message_info(REF_STR_AlreadyHaveOne);
1300             shameful_obselete_flag = TRUE;
1301             return ADD_NOEFFECT;
1302         } else
1303             quants[n] = ver;
1304 
1305         play_digi_fx(SFX_INVENT_WARE, 1);
1306         if (select) {
1307             player_struct.actives[dp->activenum] = n;
1308         }
1309         if (select || n == player_struct.actives[dp->activenum])
1310             set_inventory_mfd(dp->mfdtype, n, TRUE);
1311         obj_destroy(id);
1312 
1313         // Tell the side icons that things may no longer be what they were
1314         //      side_icon_expose_all();
1315 
1316         // If we picked up an automapper unit, let mfd slot know
1317         if (TRIP2CL(trip) == CLASS_HARDWARE) {
1318             hardware_add_specials(n, ver);
1319         }
1320         return ADD_POP;
1321     }
1322     return ADD_REJECT;
1323 }
1324 
ware_drop_func(inv_display * dp,int n)1325 void ware_drop_func(inv_display *dp, int n) {
1326 #ifndef GAMEONLY
1327     int itemnum = dp->lines[row].num;
1328     ObjID obj;
1329     int triple;
1330     uchar oneshot;
1331     ubyte *quant;
1332     extern int nth_after_triple(int, uchar);
1333     if (itemnum < 0 || itemnum >= dp->listlen)
1334         return;
1335     quant = (ubyte *)&player_struct + dp->offset;
1336     if (quant[itemnum] == 0)
1337         return;
1338     triple = nth_after_triple(dp->basetrip, itemnum);
1339     oneshot = TRIP2CL(triple) == CLASS_SOFTWARE && TRIP2SC(triple) == SOFTWARE_SUBCLASS_ONESHOT;
1340     obj = obj_create_base(triple);
1341     if (obj == OBJ_NULL) {
1342         return;
1343     }
1344     if (dp->mfdtype == MFD_INV_HARDWARE)
1345         objHardwares[objs[obj].specID].version = quant[itemnum];
1346     else
1347         objSoftwares[objs[obj].specID].version = quant[itemnum];
1348     // If the ware was on, turn it off
1349     if ((dp->mfdtype == MFD_INV_HARDWARE) && (player_struct.hardwarez_status[itemnum] & WARE_ON))
1350         use_ware(WARE_HARD, itemnum); // actually toggles, not uses
1351     if (oneshot)
1352         quant[itemnum]--;
1353     else
1354         quant[itemnum] = 0;
1355     push_cursor_object(obj);
1356     if (player_struct.actives[dp->activenum] == itemnum) {
1357         player_struct.actives[dp->activenum] = 0xFF;
1358         // Tell the item mfd that what it was looking at may no longer be there
1359         set_inventory_mfd(dp->mfdtype, MFD_INV_NOTYPE, FALSE);
1360     }
1361     INVENT_CHANGED;
1362 
1363     // Tell the side icons that things are no longer what they were
1364     side_icon_expose_all();
1365 
1366     mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1367 
1368     // If we no longer have an automapper, let the mfd know
1369     if (player_struct.hardwarez[HARDWARE_AUTOMAP] == 0)
1370         mfd_notify_func(MFD_EMPTY_FUNC, MFD_MAP_SLOT, TRUE, MFD_EMPTY, TRUE);
1371 #endif // !GAME_ONLY
1372 }
1373 
null_quant_func(inv_display * dp,int n,int q,char * buf)1374 char *null_quant_func(inv_display *dp, int n, int q, char *buf) {
1375     *buf = '\0';
1376     return buf;
1377 }
1378 
1379     // -----
1380     // SOFTS
1381     // -----
1382 
1383 #define SOFT_PAGES 2
1384 #define SOFT_CLASSES (1 << CLASS_SOFTWARE)
1385 #define COMSOFT_TRIP MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_OFFENSE, 0)
1386 #define DEFSOFT_TRIP MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_DEFENSE, 0)
1387 #define MISCSOFT_TRIP MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_ONESHOT, 0)
1388 
1389 #define VERSION_PREFIX (get_temp_string(REF_STR_VersionPrefix)[0])
1390 
1391 // QUANTS *******************************
soft_quant_func(inv_display * dp,int n,int q,char * buf)1392 static char *soft_quant_func(inv_display *dp, int n, int q, char *buf) {
1393     int l = 1;
1394     buf[0] = VERSION_PREFIX;
1395     if (q < 10)
1396         buf[l++] = q + '0';
1397     buf[l] = '\0';
1398     return buf;
1399 }
1400 
1401     // COMPUTRON SUPPORT
1402 
1403 #define CTRON_WD 10
1404 
1405 #ifdef COMPUTRONS
computron_quant_func(inv_display * dp,int n,int q,char * buf)1406 char *computron_quant_func(inv_display *dp, int n, int q, char *buf) {
1407 #ifdef REALLY_DO_COMPUTRONS
1408     ubyte exists, ctrons;
1409 
1410     switch (dp->mfdtype) {
1411     case MFD_INV_SOFT_COMBAT:
1412         exists = player_struct.softs.combat[n];
1413         ctrons = player_struct.softs_ctrons.combat[n];
1414         break;
1415     case MFD_INV_SOFT_DEFENSE:
1416         exists = player_struct.softs.defense[n];
1417         ctrons = player_struct.softs_ctrons.defense[n];
1418         break;
1419     case MFD_INV_SOFT_MISC:
1420         exists = player_struct.softs.misc[n];
1421         ctrons = player_struct.softs_ctrons.misc[n];
1422         break;
1423     }
1424     if (exists == 0 || ctrons == 0)
1425         *buf = '\0';
1426     else
1427         itoa(ctrons, buf, 10);
1428 #endif
1429     *buf = '\0';
1430     return buf;
1431 }
1432 #endif // COMPUTRONS
1433 
1434     // ------------------------------
1435     // GENERAL INVENTORY -- FUN! FUN!
1436     // ------------------------------
1437 
1438 #define GENERAL_CLASSES 0xFFFFFF80
1439 static ObjID general_lines[NUM_GENERAL_SLOTS];
1440 
1441 #define GARBAGE_COLOR TITLE_COLOR
1442 
draw_general_list(inv_display * dp)1443 void draw_general_list(inv_display *dp) {
1444     uchar newpage = inv_last_page != inventory_page;
1445     char buf[BUFSZ];
1446     int i, s;
1447     short y;
1448     ubyte active = player_struct.actives[dp->activenum];
1449     ubyte known_active = known_actives[dp->activenum];
1450     uchar newactive = known_active != active;
1451 
1452     gr_set_font(ResLock(ITEM_FONT));
1453 
1454     if (newpage) {
1455         gr_set_fcolor(dp->titlecolor);
1456         get_string(dp->titlenum, buf, BUFSZ);
1457         draw_inventory_string(buf, dp->left, dp->top, TRUE);
1458     }
1459     s = dp->relnum * dp->pgsize;
1460     y = dp->top + Y_STEP;
1461     for (i = 0; i < dp->pgsize && s < dp->listlen; i++, s++, y += Y_STEP) {
1462         uchar curractive = player_struct.current_active == dp->activenum;
1463         uchar changed = newpage || general_lines[s] != player_struct.inventory[s] || newactive;
1464         general_lines[s] = player_struct.inventory[s];
1465         if (!changed)
1466             continue;
1467         if (general_lines[s] != OBJ_NULL) {
1468             ulong color = dp->listcolor;
1469             char name[BUFSZ];
1470             get_object_short_name(ID2TRIP(general_lines[s]), name, BUFSZ);
1471             if (!(ObjProps[OPNUM(general_lines[s])].flags & INVENTORY_GENERAL))
1472                 color = GARBAGE_COLOR;
1473             draw_quant_line(name, "", color, s == active && curractive, dp->left, dp->right, y);
1474         } else
1475             clear_inventory_region(dp->left, y, dp->right, y + Y_STEP);
1476     }
1477     ResUnlock(ITEM_FONT);
1478 }
1479 
general_use_func(inv_display * dp,int row)1480 uchar general_use_func(inv_display *dp, int row) {
1481     ObjID id = player_struct.inventory[row];
1482     extern errtype object_use(ObjID id, uchar in_inv, ObjID cursor_obj);
1483     if (id == OBJ_NULL)
1484         return FALSE;
1485     if (ObjProps[OPNUM(id)].flags & OBJECT_USE_NOCURSOR) {
1486         object_use(id, TRUE, object_on_cursor);
1487         // only change mfd if using object did not destroy it.
1488         if (player_struct.current_active == dp->activenum && row <= player_struct.actives[dp->activenum])
1489             set_inventory_mfd(dp->mfdtype, row, TRUE);
1490         if (player_struct.inventory[row] == id) {
1491             set_inventory_mfd(dp->mfdtype, row, TRUE);
1492             mfd_change_slot(mfd_grab_func(MFD_ITEM_FUNC, MFD_ITEM_SLOT), MFD_ITEM_SLOT);
1493         }
1494     } else if (dp->drop != NULL)
1495         dp->drop(dp, row);
1496     return TRUE;
1497 }
1498 
inv_empty_trash(void)1499 ubyte inv_empty_trash(void) {
1500     uchar found = FALSE;
1501     ubyte non_trash = 0;
1502     ubyte trash;
1503     ubyte last_trash = NUM_GENERAL_SLOTS;
1504     // find the first trash object
1505     for (trash = 0; trash < NUM_GENERAL_SLOTS; trash++) {
1506         ObjID id = player_struct.inventory[trash];
1507         if (id != OBJ_NULL && !(ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL)) {
1508             found = TRUE;
1509             break;
1510         }
1511     }
1512     if (!found)
1513         return last_trash;
1514     // find the next non-trash object
1515     for (non_trash = trash; non_trash < NUM_GENERAL_SLOTS; non_trash++) {
1516         ObjID id = player_struct.inventory[non_trash];
1517         if (id != OBJ_NULL && (ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL))
1518             break;
1519     }
1520     // iterate through, destroying trash.
1521     for (; trash < NUM_GENERAL_SLOTS; trash++) {
1522         ObjID id = player_struct.inventory[trash];
1523         uchar is_trash = !(ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL);
1524         if (is_trash)
1525             obj_destroy(id);
1526         if (is_trash || id == OBJ_NULL) {
1527             if (non_trash < NUM_GENERAL_SLOTS) {
1528                 player_struct.inventory[trash] = player_struct.inventory[non_trash];
1529                 player_struct.inventory[non_trash] = OBJ_NULL;
1530                 for (; non_trash < NUM_GENERAL_SLOTS; non_trash++) {
1531                     ObjID id = player_struct.inventory[non_trash];
1532                     if (id != OBJ_NULL && (ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL))
1533                         break;
1534                 }
1535             } else {
1536                 player_struct.inventory[trash] = OBJ_NULL;
1537                 last_trash = lg_min(last_trash, trash);
1538             }
1539         }
1540     }
1541     return last_trash;
1542 }
1543 
add_access_card(inv_display * dp,ObjID * idP,uchar select)1544 ubyte add_access_card(inv_display *dp, ObjID *idP, uchar select) {
1545     ubyte retval = ADD_NOEFFECT;
1546     int i, d1, old_d1, gain;
1547     ObjID cards;
1548     for (i = 0; i < dp->listlen; i++) {
1549         if (ID2TRIP(player_struct.inventory[i]) == GENCARDS_TRIPLE || player_struct.inventory[i] == OBJ_NULL)
1550             break;
1551     }
1552     if (i >= dp->listlen)
1553         i = inv_empty_trash();
1554     if (i >= dp->listlen)
1555         return ADD_FAIL;
1556 
1557     // Extract the data out of the old card, so that we can copy it
1558     // correctly into the new set of cards.  Destroy the old one first
1559     // so that if we are right on the border of number of cards available
1560     // in the universe, we don't die.
1561     d1 = objSmallstuffs[objs[*idP].specID].data1;
1562     obj_destroy(*idP);
1563 
1564     if (player_struct.inventory[i] == OBJ_NULL) {
1565         cards = obj_create_base(GENCARDS_TRIPLE);
1566         if (cards == OBJ_NULL)
1567             return ADD_FAIL;
1568         player_struct.inventory[i] = cards;
1569         retval = ADD_POP;
1570     } else
1571         cards = player_struct.inventory[i];
1572     old_d1 = objSmallstuffs[objs[cards].specID].data1;
1573     objSmallstuffs[objs[cards].specID].data1 |= d1;
1574     if (select && dp->select != NULL)
1575         dp->select(dp, i);
1576     gain = d1 & (~old_d1);
1577     if (gain == 0)
1578         string_message_info(REF_STR_AccessCardNoGain);
1579     else {
1580         char gainbuf[80], bitname[16];
1581         int l, bitgot;
1582 
1583         get_string(REF_STR_AccessCardNewGain, gainbuf, 80);
1584         l = strlen(gainbuf);
1585 
1586         bitgot = 0;
1587         while (gain != 0) {
1588             if (gain & 1) {
1589                 get_string(MKREF(RES_accessCards, bitgot << 1), bitname, sizeof(bitname));
1590                 if (l + strlen(bitname) + 1 < 80) {
1591                     strcat(gainbuf, bitname);
1592                     strcat(gainbuf, " ");
1593                     l += strlen(bitname) + 1;
1594                 }
1595             }
1596             gain = gain >> 1;
1597             bitgot = bitgot + 1;
1598         }
1599         gainbuf[l] = '\0';
1600 
1601         message_info(gainbuf);
1602     }
1603     return retval;
1604 }
1605 
general_add_func(inv_display * dp,int row,ObjID * idP,uchar select)1606 ubyte general_add_func(inv_display *dp, int row, ObjID *idP, uchar select) {
1607     play_digi_fx(SFX_INVENT_ADD, 1);
1608     if ((objs[*idP].obclass == CLASS_SMALLSTUFF) &&
1609         ((objs[*idP].subclass == SMALLSTUFF_SUBCLASS_CARDS) || (ID2TRIP(*idP) == CYBERCARD_TRIPLE)))
1610         return add_access_card(dp, idP, select);
1611     if (player_struct.inventory[NUM_GENERAL_SLOTS - 1] == OBJ_NULL)
1612         row = NUM_GENERAL_SLOTS - 1;
1613     if (row < 0 || row >= dp->listlen || player_struct.inventory[row] == OBJ_NULL)
1614         for (row = 0; row < dp->listlen; row++)
1615             if (player_struct.inventory[row] == OBJ_NULL)
1616                 break;
1617     if (row >= dp->listlen)
1618         row = inv_empty_trash();
1619     if (row >= dp->listlen)
1620         return ADD_NOROOM;
1621     else {
1622         ObjID tmp = player_struct.inventory[row];
1623         // if we're trying to swap with the "access cards" object,
1624         // use the next object instead.  Since there's only one "access cards"
1625         // object, this works.
1626         if (ID2TRIP(tmp) == GENCARDS_TRIPLE) {
1627             row = (row + 1) % dp->listlen;
1628             tmp = player_struct.inventory[row];
1629         }
1630         player_struct.inventory[row] = *idP;
1631         if (select && dp->select != NULL)
1632             dp->select(dp, row);
1633         if (tmp != OBJ_NULL && ID2TRIP(tmp) != GENCARDS_TRIPLE) {
1634             *idP = tmp;
1635             return ADD_SWAP;
1636         }
1637         return ADD_POP;
1638     }
1639 }
1640 
remove_general_item(ObjID obj)1641 void remove_general_item(ObjID obj) {
1642     extern errtype obj_tractor_beam_func(ObjID id, uchar on);
1643     int row;
1644     int i;
1645 
1646     for (row = 0; row < NUM_GENERAL_SLOTS; row++)
1647         if (player_struct.inventory[row] == obj)
1648             break;
1649     if (row >= NUM_GENERAL_SLOTS)
1650         return;
1651     for (i = row + 1; i < NUM_GENERAL_SLOTS; i++)
1652         player_struct.inventory[i - 1] = player_struct.inventory[i];
1653     player_struct.inventory[NUM_GENERAL_SLOTS - 1] = OBJ_NULL;
1654 
1655     // Turn off any active gear when it leaves our inventory.
1656     switch (ID2TRIP(obj)) {
1657     case TRACBEAM_TRIPLE:
1658         if (objs[obj].info.inst_flags & CLASS_INST_FLAG)
1659             obj_tractor_beam_func(obj, FALSE);
1660         break;
1661     }
1662     if (player_struct.current_active == ACTIVE_GENERAL)
1663         set_inventory_mfd(MFD_INV_GENINV, player_struct.actives[ACTIVE_GENERAL], TRUE);
1664     mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1665     // Redraw the panel, or setup thereof
1666     INVENT_CHANGED;
1667 }
1668 
general_drop_func(inv_display * dp,int row)1669 void general_drop_func(inv_display *dp, int row) {
1670     ObjID obj = player_struct.inventory[row];
1671     if (obj != OBJ_NULL && ID2TRIP(obj) != GENCARDS_TRIPLE) // don't let us drop access cards.
1672     {
1673         // Put on cursor...
1674         push_cursor_object(obj);
1675         remove_general_item(obj);
1676     }
1677 }
1678 
inv_select_general(inv_display * dp,int w)1679 uchar inv_select_general(inv_display *dp, int w) {
1680     uchar retval = FALSE;
1681     if (player_struct.inventory[w] == OBJ_NULL)
1682         goto out;
1683     player_struct.actives[dp->activenum] = w;
1684     set_inventory_mfd(dp->mfdtype, w, TRUE);
1685     INVENT_CHANGED;
1686     retval = TRUE;
1687 out:
1688     return retval;
1689 }
1690 
1691 // -----
1692 // EMAIL
1693 // -----
1694 
1695 errtype inventory_draw_new_page(int pgnum);
1696 #define EMAIL_TRIP 0 // MAKETRIP(CLASS_SOFTWARE,SOFTWARE_SUBCLASS_EMAIL,0)
1697 
1698 #define FIRST_DATA (NUM_EMAIL - NUM_DATA)
1699 
1700 extern char *email_name_func(void *dp, int num, char *buf);
1701 
1702 #define MORE_COLOR SELECTED_ITEM_COLOR
1703 
1704 static uchar email_morebuttons[2];
1705 
email_more_draw(inv_display * dp)1706 void email_more_draw(inv_display *dp) {
1707     gr_set_font(ResLock(ITEM_FONT));
1708 
1709     if (dp->relnum % 2 == 1) {
1710         int i;
1711         int count = 0;
1712         for (i = 0; i < NUM_EMAIL_PROPER; i++)
1713             if (player_struct.email[i])
1714                 count++;
1715         if (count > (dp->relnum + 1) * dp->pgsize) {
1716             short y = dp->top + Y_STEP;
1717             char buf[50];
1718             get_string(REF_STR_EmailMoreRight, buf, sizeof(buf));
1719             draw_quant_line("", buf, MORE_COLOR, FALSE, dp->left, dp->right, y);
1720             email_morebuttons[1] = TRUE;
1721         } else
1722             email_morebuttons[1] = FALSE;
1723     } else if (dp->relnum != 0) {
1724         short y = dp->top + Y_STEP;
1725         char buf[50];
1726         get_string(REF_STR_EmailMoreLeft, buf, sizeof(buf));
1727         draw_quant_line(buf, "", MORE_COLOR, FALSE, dp->left, dp->right, y);
1728         email_morebuttons[0] = TRUE;
1729     } else
1730         email_morebuttons[0] = FALSE;
1731     ResUnlock(ITEM_FONT);
1732 }
1733 
email_more_use(inv_display * dp,int w)1734 uchar email_more_use(inv_display *dp, int w) {
1735     uchar retval = FALSE;
1736     if (dp->relnum != 0 && email_morebuttons[dp->relnum % 2]) {
1737         int newpage = (dp->relnum % 2 == 0) ? inventory_page - 1 : inventory_page + 1;
1738         inventory_page = newpage;
1739         INVENT_CHANGED;
1740         retval = TRUE;
1741     }
1742     return retval;
1743 }
1744 
1745 #define EMAIL_BASE_ID RES_email0
1746 #define TITLE_IDX 1
1747 
email_use_func(inv_display * dp,int row)1748 uchar email_use_func(inv_display *dp, int row) {
1749     extern void read_email(Id, int);
1750     uchar retval = FALSE;
1751     int n = dp->lines[row].num;
1752 
1753     if (n < dp->listlen) {
1754         read_email(EMAIL_BASE_ID, n);
1755         retval = TRUE;
1756     }
1757     return retval;
1758 }
1759 
1760 extern void select_email(int num, uchar scr_update);
1761 
email_select_func(inv_display * dp,int row)1762 void email_select_func(inv_display *dp, int row) {
1763     int n = dp->lines[row].num;
1764     if (n < dp->listlen) {
1765         play_digi_fx(SFX_INVENT_SELECT, 1);
1766         select_email(n, TRUE);
1767     }
1768 }
1769 
add_email_datamunge(short mung,uchar select)1770 void add_email_datamunge(short mung, uchar select) {
1771     extern void set_email_flags(int n);
1772 
1773     int n;
1774     uchar flash_email = TRUE;
1775     ubyte ver;
1776     extern short last_email_taken;
1777 
1778     n = mung & 0xFF;
1779     ver = mung >> 8;
1780     switch (ver) {
1781     case EMAIL_VER:
1782         set_email_flags(n);
1783         break;
1784     case LOG_VER: {
1785         int lev;
1786         lev = n / LOGS_PER_LEVEL;
1787         n = NUM_EMAIL_PROPER + n;
1788         if (player_struct.email[n] == 0)
1789             player_struct.logs[lev]++;
1790         flash_email = FALSE;
1791     } break;
1792     case DATA_VER:
1793         flash_email = FALSE;
1794         n = n + NUM_EMAIL - NUM_DATA;
1795         break;
1796     }
1797     if (player_struct.email[n] & EMAIL_GOT)
1798         return;
1799     last_email_taken = ver;
1800     string_message_info(REF_STR_ReceiveEmail + ver);
1801     player_struct.email[n] |= EMAIL_GOT;
1802     if (flash_email) {
1803         player_struct.hardwarez_status[CPTRIP(VIDTEX_HARD_TRIPLE)] |= WARE_FLASH;
1804         QUESTBIT_ON(0x12c);
1805     }
1806     INVENT_CHANGED;
1807     select_email(n, select);
1808 }
1809 
email_add_func(inv_display * dp,int w,ObjID * idP,uchar select)1810 ubyte email_add_func(inv_display *dp, int w, ObjID *idP, uchar select) {
1811     play_digi_fx(SFX_INVENT_ADD, 1);
1812     if (ID2TRIP(*idP) != EMAIL1_TRIPLE && ID2TRIP(*idP) != TEXT1_TRIPLE)
1813         return ADD_REJECT;
1814     add_email_datamunge(SOFTWARE_CONTENTS(objs[*idP].specID), select);
1815     return ADD_POP;
1816 }
1817 
email_drop_func(inv_display * dp,int n)1818 void email_drop_func(inv_display *dp, int n) {
1819     // For now, do nothing.
1820 }
1821 
1822     // ----
1823     // LOGS
1824     // ----
1825 
1826     // I'm on your side; we are on the both side.
1827 
1828 #define FIRST_LOG_PAGE 20
1829 
log_name_func(void * v,int num,char * buf)1830 char *log_name_func(void *v, int num, char *buf) { return get_string(REF_STR_LogName0 + num, buf, BUFSZ); }
1831 
log_use_func(inv_display * dp,int row)1832 uchar log_use_func(inv_display *dp, int row) {
1833     uchar retval = FALSE;
1834     int n = dp->lines[row].num;
1835     if (n < dp->listlen) {
1836         inventory_draw_new_page(FIRST_LOG_PAGE + n);
1837         retval = TRUE;
1838     }
1839     return retval;
1840 }
1841 
1842 // ---------
1843 // INTERNALS
1844 // ---------
1845 
inventory_draw_page(int pgnum)1846 void inventory_draw_page(int pgnum) {
1847     int i;
1848     inv_display *dpy;
1849 
1850     for (i = 0; gen_inv_page(pgnum, &i, &dpy); i++) {
1851         if (dpy->draw != NULL)
1852             dpy->draw(dpy);
1853     }
1854     for (i = 0; i < NUM_ACTIVES; i++)
1855         known_actives[i] = player_struct.actives[i];
1856 }
1857 
add_to_some_page(ObjID obj,uchar select)1858 ubyte add_to_some_page(ObjID obj, uchar select) {
1859     inv_display *dpy;
1860     int i;
1861     for (i = 0; gen_inv_displays(&i, &dpy); i++) {
1862         ubyte pop;
1863         if (global_fullmap->cyber && (objs[obj].obclass == CLASS_BIGSTUFF)) {
1864             if (!(dpy->add_classes & (1 << CLASS_SOFTWARE)))
1865                 continue;
1866         } else {
1867             if (!(dpy->add_classes & (1 << objs[obj].obclass)))
1868                 continue;
1869         }
1870         if (dpy->add != NULL)
1871             pop = dpy->add(dpy, -1, &obj, select);
1872         if (pop == ADD_FAIL)
1873             return pop;
1874         if (pop == ADD_NOROOM) {
1875             string_message_info(REF_STR_InvNoRoom);
1876             return pop;
1877         }
1878         if (pop != ADD_REJECT) {
1879             if (pop != ADD_NOEFFECT) {
1880                 if (dpy->pgnum != inventory_page && dpy->pgnum < NUM_PAGE_BUTTONS) {
1881                     page_button_state[dpy->pgnum] = BttnFlashOn;
1882                 }
1883                 INVENT_CHANGED;
1884             }
1885             return pop;
1886         }
1887     }
1888     string_message_info(REF_STR_InvReject);
1889     return ADD_REJECT;
1890 }
1891 
1892 /*KLC - no longer used
1893 void draw_page_button_panel()
1894 {
1895    draw_page_buttons(TRUE);
1896 }
1897 */
1898 
draw_page_buttons(uchar full)1899 void draw_page_buttons(uchar full) {
1900     LGRect r, hider;
1901     int i;
1902     short x;
1903     uchar old_over = gr2ss_override;
1904 
1905     gr_push_canvas(ppage_canvas);
1906 
1907     if (full_game_3d)
1908         gr2ss_override = OVERRIDE_NONE;
1909     else
1910         gr2ss_override = OVERRIDE_ALL;
1911 
1912     if (full) {
1913         draw_res_bm(REF_IMG_bmInventoryButtonBackground, INVENT_BUTTON_PANEL_X, INVENT_BUTTON_PANEL_Y);
1914         // draw_hires_resource_bm(REF_IMG_bmInventoryButtonBackground, 0, 0);
1915     }
1916 
1917     r.ul.y = INVENT_BTTN_Y;
1918     r.lr.y = r.ul.y + INVENT_BTTN_HT;
1919 
1920     for (x = FIRST_BTTN_X, i = 0; i < NUM_PAGE_BUTTONS; i++, x += BUTTON_X_STEP) {
1921         invent_bttn_state newstate = page_button_state[i];
1922         ulong clr;
1923         uchar active = i == inventory_page;
1924 
1925         if (newstate == BttnDummy)
1926             continue;
1927         // Figure out what the button state really is.
1928         if (active)
1929             newstate = BttnActive;
1930         else if (Flashing(newstate)) {
1931             uchar flashon = (player_struct.game_time / INVENT_BTTN_FLASH_TIME) % 2;
1932             if (flashon != FlashOn(newstate)) {
1933                 newstate = (invent_bttn_state)((char)newstate - 1);
1934                 if (newstate == BttnFlashOff)
1935                     newstate = BttnOff;
1936             }
1937             // if (time_passes)   // We want to remember that we need to change when time starts again..
1938             INVENT_CHANGED;
1939         } else
1940             newstate = BttnOff;
1941 
1942         if (!full && newstate == old_button_state[i])
1943             continue;
1944 
1945         clr = bttn_state2color(newstate);
1946         gr_set_fcolor(clr);
1947         r.ul.x = x;
1948         r.lr.x = x + INVENT_BTTN_WD;
1949         RECT_OFFSETTED_RECT(&r, MakePoint(INVENTORY_PANEL_X, BUTTON_PANEL_Y), &hider);
1950         uiHideMouse(&hider);
1951         ss_rect(r.ul.x, r.ul.y, r.lr.x, r.lr.y);
1952         // gr_rect(SCONV_X(r.ul.x)+2, 2, SCONV_X(r.lr.x)+2, 10);
1953         uiShowMouse(&hider);
1954         page_button_state[i] = old_button_state[i] = newstate;
1955     }
1956     gr_pop_canvas();
1957     gr2ss_override = old_over;
1958 }
1959 
1960 // ---------
1961 // EXTERNALS
1962 // ---------
1963 
1964 uchar dirty_inv_canvas = FALSE;
1965 
inventory_clear(void)1966 errtype inventory_clear(void) {
1967     gr_push_canvas(&inv_canvas);
1968     if (full_game_3d)
1969         gr_clear(0);
1970     else {
1971         LGRect r;
1972         r.ul.x = INVENTORY_PANEL_X;
1973         r.ul.y = INVENTORY_PANEL_Y;
1974         r.lr.x = INVENTORY_PANEL_X + INVENTORY_PANEL_WIDTH;
1975         r.lr.y = INVENTORY_PANEL_Y + INVENTORY_PANEL_HEIGHT;
1976         if (dirty_inv_canvas) {
1977             FrameDesc *f = RefGet(REF_IMG_bmBlankInventoryPanel);
1978             LG_memcpy(inv_backgnd.bits, f + 1, f->bm.w * f->bm.h);
1979             dirty_inv_canvas = FALSE;
1980         }
1981         uiHideMouse(&r);
1982         ss_safe_set_cliprect(0, 0, INVENTORY_PANEL_WIDTH, INVENTORY_PANEL_HEIGHT);
1983         ss_bitmap(&inv_backgnd, 0, 0);
1984         // gr_bitmap(&inv_backgnd, 0, 0);
1985         uiShowMouse(&r);
1986     }
1987     gr_pop_canvas();
1988     /* Now, you might ask "Why not just set inv_last_page = INV_BLANK_PAGE all the time?"
1989        And the answer is, well, the wrapper panel saves the inventory page in inv_last_page,
1990        so that things like load game know how to blow the saved page away */
1991     if (inventory_page == inv_last_page)
1992         inv_last_page = INV_BLANK_PAGE;
1993     return (OK);
1994 }
1995 
inventory_full_redraw()1996 errtype inventory_full_redraw() {
1997     int i;
1998     inv_last_page = -1;
1999     for (i = 0; i < NUM_PAGE_BUTTONS; i++)
2000         old_button_state[i] = BttnDummy;
2001     return (inventory_draw());
2002 }
2003 
inventory_draw(void)2004 errtype inventory_draw(void) {
2005     uchar full = inventory_page != inv_last_page;
2006 #ifdef SVGA_SUPPORT
2007     uchar old_over;
2008     short temp;
2009 #endif
2010     if (inventory_page < 0)
2011         return OK;
2012     gr_push_canvas(&inv_canvas);
2013 #ifdef SVGA_SUPPORT
2014     old_over = gr2ss_override;
2015     //   if (full_game_3d)
2016     //      gr2ss_override = OVERRIDE_FONT|OVERRIDE_CLIP;
2017     //   else
2018     gr2ss_override = OVERRIDE_ALL;
2019 #endif
2020     if (global_fullmap->cyber)
2021         inventory_page = INV_SOFTWARE_PAGE;
2022     if (full)
2023         inventory_clear();
2024     draw_page_buttons(full_game_3d || full);
2025 #ifdef SVGA_SUPPORT
2026     ss_set_hack_mode(2, &temp);
2027 #endif
2028     inventory_draw_page(inventory_page);
2029 #ifdef SVGA_SUPPORT
2030     ss_set_hack_mode(0, &temp);
2031     gr2ss_override = old_over;
2032 #endif
2033     gr_pop_canvas();
2034     inv_last_page = inventory_page;
2035     return (OK);
2036 }
2037 
inventory_draw_new_page(int pgnum)2038 errtype inventory_draw_new_page(int pgnum) {
2039     inv_last_page = -1;
2040     inventory_page = pgnum;
2041     if (full_game_3d) {
2042 #ifdef STEREO_SUPPORT
2043         if (convert_use_mode == 5)
2044             full_visible = FULL_INVENT_MASK;
2045         else
2046 #endif
2047             full_visible |= FULL_INVENT_MASK;
2048         full_raise_region(inventory_region_full);
2049         chg_set_sta(FULLSCREEN_UPDATE);
2050     }
2051     return inventory_draw();
2052 }
2053 
inventory_add_object(ObjID obj,uchar select)2054 uchar inventory_add_object(ObjID obj, uchar select) {
2055     ubyte result = add_to_some_page(obj, select);
2056     return (result != ADD_FAIL) && (result != ADD_REJECT) && (result != ADD_NOROOM);
2057 }
2058 
2059 // ------------
2060 // EVENTHANDLER
2061 // ------------
2062 
do_selection(inv_display * dp,int row)2063 uchar do_selection(inv_display *dp, int row) {
2064     uchar retval = FALSE;
2065     int w = dp->lines[row].num;
2066     if (w >= dp->listlen)
2067         goto out;
2068     if (dp->activenum == NULL_ACTIVE)
2069         goto out;
2070     player_struct.actives[dp->activenum] = w;
2071     set_inventory_mfd(dp->mfdtype, w, TRUE);
2072     INVENT_CHANGED;
2073     retval = TRUE;
2074 out:
2075     return retval;
2076 }
2077 
add_object_on_cursor(inv_display * dp,int row)2078 void add_object_on_cursor(inv_display *dp, int row) {
2079     ObjID obj = object_on_cursor;
2080     ubyte pop = ADD_REJECT;
2081     if (dp != NULL)
2082         pop = (dp->add_classes & (1 << TRIP2CL(ID2TRIP(object_on_cursor)))) ? ADD_POP : ADD_REJECT;
2083     if (pop != ADD_REJECT && dp->add != NULL)
2084         pop = dp->add(dp, row, &obj, FALSE);
2085     if (pop == ADD_NOROOM) {
2086         string_message_info(REF_STR_InvNoRoom);
2087         return;
2088     }
2089     if (pop == ADD_REJECT)
2090         pop = add_to_some_page(obj, FALSE);
2091     if (pop != ADD_REJECT && pop != ADD_FAIL) {
2092         INVENT_CHANGED;
2093         if (IS_POP_RESULT(pop) || pop == ADD_SWAP)
2094             pop_cursor_object();
2095         if (pop == ADD_SWAP)
2096             push_cursor_object(obj);
2097         uiShowMouse(NULL); // KLC - added to make sure the pointer changes.
2098     }
2099     if (pop == ADD_REJECT)
2100         string_message_info(REF_STR_InvReject);
2101 }
2102 
inventory_handle_leftbutton(uiEvent * ev,inv_display * dp,int row)2103 uchar inventory_handle_leftbutton(uiEvent *ev, inv_display *dp, int row) {
2104     uchar retval = FALSE;
2105 #ifndef NO_DUMMIES
2106     void *dummy;
2107     dummy = ev;
2108 #endif // NO_DUMMIES
2109     switch (input_cursor_mode) {
2110     case INPUT_NORMAL_CURSOR:
2111         if (dp != NULL && row >= 0) {
2112             if (dp->select != NULL)
2113                 retval = dp->select(dp, row);
2114             else
2115                 retval = do_selection(dp, row);
2116         }
2117         break;
2118     case INPUT_OBJECT_CURSOR:
2119         add_object_on_cursor(dp, row);
2120         retval = TRUE;
2121         break;
2122     }
2123     return retval;
2124 }
2125 
2126 static uchar invpanel_focus = FALSE;
2127 
inventory_handle_rightbutton(uiEvent * ev,LGRegion * reg,inv_display * dp,int row)2128 uchar inventory_handle_rightbutton(uiEvent *ev, LGRegion *reg, inv_display *dp, int row) {
2129     static int lastrow = 0;
2130     static inv_display *lastdp = NULL;
2131 
2132     uchar retval = FALSE;
2133     LGRect r;
2134     uchar grab = FALSE;
2135 
2136     if (input_cursor_mode != INPUT_NORMAL_CURSOR)
2137         return FALSE;
2138     if (ev->subtype & MOUSE_RDOWN && row >= 0 && dp != NULL && !invpanel_focus) {
2139         // let us know if we leave the region
2140         invpanel_focus = TRUE;
2141         uiGrabFocus(reg, UI_EVENT_MOUSE_MOVE);
2142         lastrow = row;
2143         lastdp = dp;
2144         retval = TRUE;
2145     }
2146     // Check to see if we've left the region and release focus.
2147     region_abs_rect(reg, reg->r, &r);
2148     if (!RECT_TEST_PT(&r, ev->pos)) {
2149         grab = TRUE;
2150         row = lastrow;
2151         dp = lastdp;
2152         retval = TRUE;
2153     }
2154     if (ev->subtype & MOUSE_RUP) {
2155         if (row == lastrow && dp == lastdp)
2156             grab = TRUE;
2157     } else if (ev->subtype & MOUSE_MOTION && (row != lastrow || dp != lastdp)) {
2158         row = lastrow;
2159         dp = lastdp;
2160         grab = TRUE;
2161     }
2162     if (grab && dp != NULL && row >= 0) {
2163         uchar cyber = TRIP2CL(dp->basetrip) == CLASS_SOFTWARE;
2164         if (cyber != global_fullmap->cyber) {
2165             extern errtype string_message_info(int);
2166             int str = cyber ? REF_STR_InvCybFailSoft : REF_STR_InvCybFailHard;
2167             string_message_info(str);
2168         } else if (dp->drop != NULL) {
2169             dp->drop(dp, row);
2170         }
2171         lastrow = -1;
2172         lastdp = NULL;
2173         retval = TRUE;
2174     }
2175     return retval;
2176 }
2177 
2178 #define SEARCH_MARGIN 2
2179 
inventory_mouse_handler(uiEvent * ev,LGRegion * r,intptr_t data)2180 uchar inventory_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t data) {
2181     uchar retval = FALSE;
2182     int relx;
2183     inv_display *dp = NULL;
2184     int i;
2185     int row = -1;
2186     extern uchar game_paused;
2187 #ifdef SVGA_SUPPORT
2188     short temp;
2189 #endif
2190     if (game_paused)
2191         return (TRUE);
2192 
2193 #ifdef STEREO_SUPPORT
2194     if (convert_use_mode == 5) {
2195         if (i6d_device == I6D_CTM)
2196             relx = ev->pos.x - 1;
2197         else {
2198             relx = (ev->pos.x - ((320 - inv_fullscrn_canvas.bm.w) / 2)) >> 1;
2199             //         Warning(("relx: %d = %d - %d = %d >> 1\n",relx,ev->pos.x,((320-inv_fullscrn_canvas.bm.w)/2),
2200             //             (ev->pos.x - ((320-inv_fullscrn_canvas.bm.w)/2))));
2201         }
2202     } else
2203 #endif
2204     {
2205         relx = ev->pos.x - INVENTORY_PANEL_X;
2206     }
2207     if (invpanel_focus && !(ev->mouse_data.buttons & (1 << MOUSE_RBUTTON))) {
2208         uiReleaseFocus(r, UI_EVENT_MOUSE_MOVE);
2209         invpanel_focus = FALSE;
2210     }
2211     if (full_game_3d && !(full_visible & FULL_INVENT_MASK))
2212         return FALSE;
2213     if (full_game_3d && !(ev->mouse_data.buttons & (1 << MOUSE_RBUTTON))) {
2214         if (!(ev->mouse_data.action & ~MOUSE_MOTION))
2215             return FALSE;
2216         if (input_cursor_mode != INPUT_OBJECT_CURSOR) {
2217             uchar found = FALSE;
2218             short rel_y;
2219             short x, y;
2220             short smx, smy;
2221 #ifdef STEREO_SUPPORT
2222             if (convert_use_mode == 5) {
2223                 switch (i6d_device) {
2224                 case I6D_CTM:
2225                     rel_y = ev->pos.y - 1;
2226                     break;
2227                 case I6D_VFX1:
2228                     rel_y = ev->pos.y - (INVENTORY_PANEL_Y >> 1);
2229                     //                     rel_y = ev->pos.y - (200 - inv_fullscrn_canvas.bm.h);
2230                     break;
2231                 default:
2232                     break;
2233                 }
2234             } else
2235 #endif
2236                 rel_y = ev->pos.y - INVENTORY_PANEL_Y;
2237             gr_push_canvas(&inv_fullscrn_canvas);
2238             smx = SEARCH_MARGIN;
2239             smy = SEARCH_MARGIN;
2240 #ifdef SVGA_SUPPORT
2241             ss_set_hack_mode(2, &temp);
2242             ss_point_convert(&smx, &smy, FALSE);
2243 #endif
2244             for (x = relx - smx; !found && x <= relx + smx; x++)
2245                 for (y = rel_y - smy; !found && y <= rel_y + smy; y++) {
2246                     short usex, usey;
2247                     usex = x;
2248                     usey = y;
2249 #ifdef SVGA_SUPPORT
2250                     ss_point_convert(&usex, &usey, FALSE);
2251 #endif
2252                     if (gr_get_pixel(usex, usey) != 0) // found non-transparent pixel
2253                         found = TRUE;
2254                 }
2255 #ifdef SVGA_SUPPORT
2256             ss_set_hack_mode(0, &temp);
2257 #endif
2258             gr_pop_canvas();
2259             if (!found) {
2260                 return FALSE;
2261             }
2262         }
2263     }
2264     for (i = 0; gen_inv_page(inventory_page, &i, &dp); i++) {
2265         if (relx < dp->left || relx > dp->right)
2266             continue;
2267         row = get_item_at_pixrow(dp, ev->pos.y);
2268         if (row >= 0) {
2269             break;
2270         }
2271     }
2272     if (input_cursor_mode == INPUT_OBJECT_CURSOR && (ev->mouse_data.action & (MOUSE_LDOWN | MOUSE_RUP | UI_MOUSE_LDOUBLE))) {
2273         add_object_on_cursor(dp, row);
2274         return TRUE;
2275     }
2276     if ((ev->mouse_data.buttons & (1 << MOUSE_RBUTTON)) || (ev->subtype & (MOUSE_RUP | MOUSE_RDOWN)))
2277         if (inventory_handle_rightbutton(ev, r, dp, row))
2278             retval = TRUE;
2279     // Handle left button
2280     if (ev->subtype & MOUSE_LDOWN) {
2281         if (inventory_handle_leftbutton(ev, dp, row))
2282             retval = TRUE;
2283     }
2284     // Handle left doubleclick
2285     if (ev->subtype & UI_MOUSE_LDOUBLE)
2286         if (dp != NULL && (row >= 0) && (dp->use != NULL)) {
2287             retval = dp->use(dp, row);
2288         }
2289     return retval;
2290 }
2291 
2292 int last_invent_cnum = -1; // last cursor num set for region
pagebutton_mouse_handler(uiEvent * ev,LGRegion * r,intptr_t data)2293 uchar pagebutton_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t data) {
2294     LGPoint pos = ev->pos;
2295     int cnum;
2296 
2297     if (full_game_3d && (ev->mouse_data.buttons & (1 << MOUSE_LBUTTON)) != 0 &&
2298 	(ev->mouse_data.action & MOUSE_LDOWN) == 0 &&
2299         uiLastMouseRegion[MOUSE_LBUTTON] != NULL && uiLastMouseRegion[MOUSE_LBUTTON] != r) {
2300         uiSetRegionDefaultCursor(r, NULL);
2301         return FALSE;
2302     }
2303 
2304     pos.x -= INVENTORY_PANEL_X;
2305     pos.y -= INVENTORY_PANEL_Y;
2306 
2307     cnum = (pos.x - FIRST_BTTN_X) / BUTTON_X_STEP;
2308     if (full_game_3d && global_fullmap->cyber && cnum != INV_SOFTWARE_PAGE) {
2309         last_invent_cnum = cnum;
2310         uiSetRegionDefaultCursor(r, NULL);
2311         return FALSE;
2312     }
2313 
2314     if ((cnum != last_invent_cnum) && (cnum < NUM_PAGE_BTTNS)) {
2315         LGCursor *c = &invent_bttn_cursor;
2316         LGPoint offset = {0, -1};
2317 
2318         if ((page_button_state[cnum] == BttnDummy) || !popup_cursors)
2319             c = NULL;
2320         last_invent_cnum = cnum;
2321 #ifdef SVGA_SUPPORT
2322         free(invent_bttn_bitmap.bits);
2323         make_popup_cursor(c, &invent_bttn_bitmap, cursor_strings[cnum], POPUP_DOWN, TRUE, offset);
2324 #else
2325         make_popup_cursor(c, &invent_bttn_bitmap, cursor_strings[cnum], POPUP_DOWN, FALSE, offset);
2326 #endif
2327         uiSetRegionDefaultCursor(r, c);
2328     }
2329 
2330     if (input_cursor_mode == INPUT_OBJECT_CURSOR && (ev->mouse_data.action & (MOUSE_LDOWN | MOUSE_RDOWN | UI_MOUSE_LDOUBLE))) {
2331         AddResult pop = (AddResult)add_to_some_page(object_on_cursor, FALSE);
2332         if (IS_POP_RESULT(pop))
2333             pop_cursor_object();
2334         return TRUE;
2335     }
2336 
2337     if (page_button_state[cnum] == BttnDummy)
2338         return FALSE;
2339 
2340     if (ev->mouse_data.action & MOUSE_LDOWN) {
2341         int i = cnum;
2342         short x = FIRST_BTTN_X + i * BUTTON_X_STEP;
2343         if (pos.x >= x && pos.x < x + INVENT_BTTN_WD && page_button_state[i] != BttnDummy) {
2344             if (full_game_3d) {
2345                 if (i == inventory_page && full_visible & FULL_INVENT_MASK) {
2346                     full_visible &= ~FULL_INVENT_MASK;
2347                 } else {
2348                     gr_push_canvas(pinv_canvas);
2349                     gr_clear(0);
2350                     gr_pop_canvas();
2351 #ifdef STEREO_SUPPORT
2352                     if (convert_use_mode == 5)
2353                         full_visible = FULL_INVENT_MASK;
2354                     else
2355 #endif
2356                         full_visible |= FULL_INVENT_MASK;
2357                     inv_last_page = -1;
2358                     full_raise_region(inventory_region_full);
2359                     chg_set_sta(FULLSCREEN_UPDATE);
2360                 }
2361             }
2362             play_digi_fx(SFX_INVENT_BUTTON, 1);
2363             inventory_page = i;
2364             INVENT_CHANGED;
2365         }
2366     }
2367     return TRUE;
2368 }
2369 
2370 #define MAX_HOTKEY_PAGES 6
2371 #define EMPTY_PAGE(i) (page_button_state[i] == BttnDummy)
2372 
invent_hotkey_func(ushort keycode,uint32_t context,intptr_t data)2373 uchar invent_hotkey_func(ushort keycode, uint32_t context, intptr_t data) {
2374     if (inventory_page < 0)
2375         inventory_page = MAX_HOTKEY_PAGES;
2376     if (inventory_page >= MAX_HOTKEY_PAGES)
2377         inventory_page = -1;
2378     if (data == 0) {
2379         inventory_page--;
2380         if (inventory_page < 0)
2381             inventory_page = MAX_HOTKEY_PAGES - 1;
2382         while (EMPTY_PAGE(inventory_page))
2383             inventory_page--;
2384     } else {
2385         inventory_page++;
2386         if (inventory_page >= MAX_HOTKEY_PAGES)
2387             inventory_page = 0;
2388         while (EMPTY_PAGE(inventory_page))
2389             inventory_page++;
2390     }
2391     play_digi_fx(SFX_INVENT_BUTTON, 1);
2392     if (!(full_visible & FULL_INVENT_MASK)) {
2393         gr_push_canvas(pinv_canvas);
2394         gr_clear(0);
2395         gr_pop_canvas();
2396 #ifdef SVGA_SUPPORT
2397         if (convert_use_mode == 5)
2398             full_visible = FULL_INVENT_MASK;
2399         else
2400 #endif
2401             full_visible |= FULL_INVENT_MASK;
2402     }
2403     INVENT_CHANGED;
2404     return TRUE;
2405 }
2406 
cycle_weapons_func(ushort keycode,uint32_t context,intptr_t data)2407 uchar cycle_weapons_func(ushort keycode, uint32_t context, intptr_t data) {
2408     if (global_fullmap->cyber) {
2409         int ac = player_struct.actives[ACTIVE_COMBAT_SOFT];
2410         int bound1 = (data > 0) ? NUM_COMBAT_SOFTS : -1;
2411         int bound2 = (data > 0) ? 0 : NUM_COMBAT_SOFTS - 1;
2412         int i;
2413         for (i = ac + data; i != bound1; i += data)
2414             if (player_struct.softs.combat[i] != 0)
2415                 goto got_soft;
2416         for (i = bound2; i != ac; i += data)
2417             if (player_struct.softs.combat[i] != 0)
2418                 goto got_soft;
2419     got_soft:
2420         player_struct.actives[ACTIVE_COMBAT_SOFT] = i;
2421         INVENT_CHANGED;
2422     } else {
2423         int aw = player_struct.actives[ACTIVE_WEAPON];
2424 
2425         aw += data;
2426         if (aw >= NUM_WEAPON_SLOTS || player_struct.weapons[aw].type == EMPTY_WEAPON_SLOT)
2427             aw = 0;
2428         else if (aw < 0) {
2429             for (aw = NUM_WEAPON_SLOTS - 1; player_struct.weapons[aw].type == EMPTY_WEAPON_SLOT && aw > 0; aw--)
2430                 ;
2431         }
2432         inventory_select_weapon(NULL, aw);
2433     }
2434     return TRUE;
2435 }
2436 
2437 #define PAGEUP_KEY KEY_PAD_PGUP | KB_FLAG_DOWN
2438 #define PAGEDN_KEY KEY_PAD_PGDN | KB_FLAG_DOWN
2439 
init_invent_hotkeys(void)2440 void init_invent_hotkeys(void) {
2441     /*  later
2442     //   hotkey_add(PAGEUP_KEY,DEMO_CONTEXT,invent_hotkey_func,0);
2443        hotkey_add(PAGEUP_KEY|KB_FLAG_2ND,DEMO_CONTEXT,invent_hotkey_func,0);
2444        hotkey_add(KB_FLAG_DOWN|KB_FLAG_ALT|'[',DEMO_CONTEXT,invent_hotkey_func,0);
2445     //   hotkey_add(PAGEDN_KEY,DEMO_CONTEXT,invent_hotkey_func,1);
2446        hotkey_add(PAGEDN_KEY|KB_FLAG_2ND,DEMO_CONTEXT,invent_hotkey_func,1);
2447        hotkey_add(KB_FLAG_DOWN|KB_FLAG_ALT|']',DEMO_CONTEXT,invent_hotkey_func,1);
2448     */
2449     hotkey_add(KEY_TAB | KB_FLAG_DOWN, DEMO_CONTEXT, cycle_weapons_func, 1);
2450     hotkey_add(KEY_TAB | KB_FLAG_DOWN | KB_FLAG_SHIFT, DEMO_CONTEXT, cycle_weapons_func, -1);
2451 }
2452 
invent_language_change(void)2453 void invent_language_change(void) {
2454     load_string_array(REF_STR_InvCursor, cursor_strings, cursor_string_buf, sizeof(cursor_string_buf),
2455                       NUM_PAGE_BUTTONS);
2456 }
2457 
2458 #define MAX_INV_FULL_WD(x) (fix_int(fix_mul_div(fix_make((x), 0), fix_make(1024, 0), fix_make(320, 0))))
2459 #define MAX_INV_FULL_HT(y) (fix_int(fix_mul_div(fix_make((y), 0), fix_make(768, 0), fix_make(200, 0))))
2460 
create_invent_region(LGRegion * root,LGRegion ** pbuttons,LGRegion ** pinvent)2461 LGRegion *create_invent_region(LGRegion *root, LGRegion **pbuttons, LGRegion **pinvent) {
2462     static uchar done_init = FALSE;
2463     extern void add_email_handler(LGRegion * r);
2464     int id;
2465     LGRect invrect;
2466     LGRegion *invreg = (LGRegion *)malloc(sizeof(LGRegion));
2467     LGRegion *pagereg = (LGRegion *)malloc(sizeof(LGRegion));
2468     FrameDesc *f;
2469 #ifdef OLD_BUTTON_CURSORS
2470     LGPoint pt;
2471     int i;
2472 #endif
2473 #ifdef CURSOR_BACKUPS
2474     extern uchar *backup[NUM_BACKUP_BITS];
2475     extern grs_bitmap backup_invent_bttn_cursors[NUM_PAGE_BTTNS];
2476 #endif
2477 
2478     // Create the panel region
2479     invrect.ul.x = INVENTORY_PANEL_X;
2480     invrect.ul.y = INVENTORY_PANEL_Y;
2481     invrect.lr.x = invrect.ul.x + INVENTORY_PANEL_WIDTH;
2482     invrect.lr.y = invrect.ul.y + INVENTORY_PANEL_HEIGHT;
2483     region_create(root, invreg, &invrect, 0, 0, REG_USER_CONTROLLED | AUTODESTROY_FLAG, NULL, NULL, NULL, NULL);
2484     uiInstallRegionHandler(invreg, UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE, inventory_mouse_handler, 0, &id);
2485     uiSetRegionDefaultCursor(invreg, NULL);
2486     add_email_handler(invreg);
2487     if (pinvent != NULL)
2488         *pinvent = invreg;
2489 
2490     // Create the pagebutton region
2491     invrect.ul.y = invrect.lr.y;
2492     invrect.lr.y = RectHeight(root->r);
2493     region_create(root, pagereg, &invrect, 0, 0, REG_USER_CONTROLLED | AUTODESTROY_FLAG, NULL, NULL, NULL, NULL);
2494     uiInstallRegionHandler(pagereg, (UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE), pagebutton_mouse_handler,
2495                            0, &id);
2496     uiSetRegionDefaultCursor(pagereg, &globcursor);
2497 
2498     if (pbuttons != NULL)
2499         *pbuttons = pagereg;
2500 
2501     if (!done_init) {
2502         done_init = TRUE;
2503         // Assign different cursors to different buttons in pagebutton region
2504         {
2505             grs_bitmap *bm = &invent_bttn_bitmap;
2506             LGCursor *c = &invent_bttn_cursor;
2507             LGPoint offset = {0, -1};
2508 
2509             invent_language_change();
2510             make_popup_cursor(c, bm, cursor_strings[0], POPUP_DOWN, TRUE, offset);
2511         }
2512 
2513         // Pull in the background bitmap
2514         f = RefLock(REF_IMG_bmBlankInventoryPanel);
2515         inv_backgnd = f->bm;
2516 
2517         // This background is going to get used by the 360 ware
2518         // in fullscreen mode, so we need extra bits
2519         inv_backgnd.bits = (uchar *)malloc(MAX_INV_FULL_WD(INV_FULL_WD) * MAX_INV_FULL_HT(grd_cap->h - GAME_MESSAGE_Y));
2520         LG_memcpy(inv_backgnd.bits, (f + 1), f->bm.w * f->bm.h);
2521 	RefUnlock(REF_IMG_bmBlankInventoryPanel);
2522 
2523         // init the canvas
2524         gr_init_sub_canvas(grd_scr_canv, &inv_norm_canvas, INVENTORY_PANEL_X, INVENTORY_PANEL_Y, INVENTORY_PANEL_WIDTH,
2525                            INVENTORY_PANEL_HEIGHT);
2526         gr_init_canvas(&inv_fullscrn_canvas, inv_backgnd.bits, BMT_FLAT8, INVENTORY_PANEL_WIDTH,
2527                        INVENTORY_PANEL_HEIGHT);
2528         gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, INV_FULL_WD, INV_FULL_HT);
2529         gr_init_sub_canvas(grd_scr_canv, &inv_gamepage_canvas, INVENTORY_PANEL_X, BUTTON_PANEL_Y, INVENTORY_PANEL_WIDTH,
2530                            grd_cap->h - BUTTON_PANEL_Y);
2531 
2532         uchar *p = (uchar *)malloc(292 * 10);                        // This canvas holds an off-screen image of the
2533         gr_init_canvas(&inv_fullpage_canvas, p, BMT_FLAT8, 292, 10); // inventory buttons.
2534         gr_push_canvas(&inv_fullpage_canvas);
2535         gr_clear(0);
2536         gr_pop_canvas();
2537     }
2538 
2539     inventory_update_screen_mode();
2540 
2541     return invreg;
2542 }
2543 
inventory_update_screen_mode()2544 errtype inventory_update_screen_mode() {
2545     if (convert_use_mode) {
2546         gr_init_sub_canvas(grd_scr_canv, &inv_norm_canvas, SCONV_X(INVENTORY_PANEL_X), SCONV_Y(INVENTORY_PANEL_Y),
2547                            SCONV_X(INVENTORY_PANEL_WIDTH), SCONV_Y(INVENTORY_PANEL_HEIGHT));
2548         if (full_game_3d) {
2549             gr_init_canvas(&inv_fullscrn_canvas, inv_backgnd.bits, BMT_FLAT8, SCONV_X(INVENTORY_PANEL_WIDTH),
2550                            SCONV_Y(INVENTORY_PANEL_HEIGHT));
2551             // gr_init_canvas(&inv_fullscrn_canvas, inv_backgnd.bits, BMT_FLAT8, 290, 120);
2552             gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, SCONV_X(INV_FULL_WD),
2553                            SCONV_Y(INV_FULL_HT));
2554             // gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, 290, SCONV_Y(INV_FULL_HT));
2555         } else {
2556             gr_init_sub_canvas(grd_scr_canv, &inv_gamepage_canvas, SCONV_X(INVENTORY_PANEL_X), SCONV_Y(BUTTON_PANEL_Y),
2557                                SCONV_X(INVENTORY_PANEL_WIDTH), SCONV_Y(10));
2558             gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, SCONV_X(INV_FULL_WD),
2559                            SCONV_Y(INV_FULL_HT));
2560         }
2561     } else {
2562         gr_init_sub_canvas(grd_scr_canv, &inv_norm_canvas, INVENTORY_PANEL_X, INVENTORY_PANEL_Y, INVENTORY_PANEL_WIDTH,
2563                            INVENTORY_PANEL_HEIGHT);
2564         if (full_game_3d) {
2565             gr_init_canvas(&inv_fullscrn_canvas, inv_backgnd.bits, BMT_FLAT8, INVENTORY_PANEL_WIDTH,
2566                            INVENTORY_PANEL_HEIGHT);
2567             gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, INV_FULL_WD, INV_FULL_HT);
2568         } else {
2569             gr_init_sub_canvas(grd_scr_canv, &inv_gamepage_canvas, INVENTORY_PANEL_X, BUTTON_PANEL_Y,
2570                                INVENTORY_PANEL_WIDTH, grd_cap->h - BUTTON_PANEL_Y);
2571             gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, INVENTORY_PANEL_WIDTH,
2572                            INVENTORY_PANEL_HEIGHT);
2573         }
2574     }
2575 
2576     /*KLC - not used in Mac version
2577        else
2578        {
2579           gr_init_sub_canvas(grd_scr_canv,&inv_norm_canvas,INVENTORY_PANEL_X,INVENTORY_PANEL_Y,
2580              INVENTORY_PANEL_WIDTH,INVENTORY_PANEL_HEIGHT);
2581           if (full_game_3d)
2582           {
2583              gr_init_canvas(&inv_fullscrn_canvas,inv_backgnd.bits, BMT_FLAT8,
2584        INVENTORY_PANEL_WIDTH,INVENTORY_PANEL_HEIGHT); gr_init_canvas(&inv_view360_canvas,inv_backgnd.bits, BMT_FLAT8,
2585        INV_FULL_WD, INV_FULL_HT);
2586           }
2587           else
2588           {
2589              gr_init_sub_canvas(grd_scr_canv,&inv_gamepage_canvas,INVENTORY_PANEL_X,BUTTON_PANEL_Y,
2590                 INVENTORY_PANEL_WIDTH,grd_cap->h - BUTTON_PANEL_Y);
2591           }
2592        }
2593     */
2594     return (OK);
2595 }
2596 
2597 extern uchar inv_is_360_view(void);
2598 
inv_change_fullscreen(uchar on)2599 void inv_change_fullscreen(uchar on) {
2600     if (on) {
2601         pinv_canvas = &inv_fullscrn_canvas;
2602         ppage_canvas = &inv_fullpage_canvas;
2603         gr_push_canvas(pinv_canvas);
2604         gr_clear(0);
2605         gr_pop_canvas();
2606         dirty_inv_canvas = TRUE;
2607 
2608         gr_push_canvas(ppage_canvas);
2609         gr_clear(0);
2610         gr_pop_canvas();
2611     } else {
2612         int i;
2613         pinv_canvas = &inv_norm_canvas;
2614         ppage_canvas = &inv_gamepage_canvas;
2615         for (i = 0; i < NUM_PAGE_BUTTONS; i++)
2616             old_button_state[i] = BttnOff;
2617         if (inventory_page == INV_EMAILTEXT_PAGE)
2618             inventory_page = INV_MAIN_PAGE;
2619     }
2620     inv_last_page = INV_BLANK_PAGE;
2621     INVENT_CHANGED;
2622 }
2623 
inv_update_fullscreen(uchar full)2624 void inv_update_fullscreen(uchar full) {
2625     grs_bitmap *bm;
2626     short a, b, c, d;
2627     STORE_CLIP(a, b, c, d);
2628     if (full) {
2629 #ifdef SVGA_SUPPORT
2630 
2631         if (inv_is_360_view()) {
2632             ss_noscale_bitmap(&inv_view360_canvas.bm, GAME_MESSAGE_X, GAME_MESSAGE_Y);
2633         } else {
2634             inv_fullscrn_canvas.bm.flags |= BMF_TRANS;
2635             //         ss_bitmap(&(inv_fullscrn_canvas.bm),INVENTORY_PANEL_X,INVENTORY_PANEL_Y);
2636             /* KLC -- Shouldn't this be ifdef'd out?
2637                      if (convert_use_mode == 5)
2638                      {
2639                         switch (i6d_device)
2640                         {
2641                            case I6D_CTM:
2642                               ss_noscale_bitmap(&(inv_fullscrn_canvas.bm),1,1);
2643                               break;
2644                            case I6D_VFX1:
2645             //                  ss_noscale_bitmap(&(inv_fullscrn_canvas.bm),(320-inv_fullscrn_canvas.bm.w)/2,200 -
2646             inv_fullscrn_canvas.bm.h);
2647                               ss_noscale_bitmap(&(inv_fullscrn_canvas.bm),(320-inv_fullscrn_canvas.bm.w)/2,INVENTORY_PANEL_Y
2648             >> 1); break;
2649                         }
2650                      }
2651                      else
2652              */
2653             ss_noscale_bitmap(&(inv_fullscrn_canvas.bm), INVENTORY_PANEL_X, INVENTORY_PANEL_Y);
2654             inv_fullscrn_canvas.bm.flags &= ~BMF_TRANS;
2655         }
2656 #else
2657         if (inv_is_360_view()) {
2658             ss_noscale_bitmap(&inv_view360_canvas.bm, GAME_MESSAGE_X, GAME_MESSAGE_Y);
2659         } else {
2660             inv_fullscrn_canvas.bm.flags |= BMF_TRANS;
2661             //         ss_bitmap(&(inv_fullscrn_canvas.bm),INVENTORY_PANEL_X,INVENTORY_PANEL_Y);
2662             ss_noscale_bitmap(&(inv_fullscrn_canvas.bm), INVENTORY_PANEL_X, INVENTORY_PANEL_Y);
2663             inv_fullscrn_canvas.bm.flags &= ~BMF_TRANS;
2664         }
2665 #endif
2666     }
2667     region_set_invisible(inventory_region_full, !full);
2668     bm = &inv_fullpage_canvas.bm;
2669     bm->flags |= BMF_TRANS;
2670     if (global_fullmap->cyber) {
2671         ss_safe_set_cliprect(INVENTORY_PANEL_X + bm->w / 2, BUTTON_PANEL_Y, INVENTORY_PANEL_X + bm->w,
2672                              BUTTON_PANEL_Y + bm->h);
2673     }
2674 
2675     if (convert_use_mode == 3) {
2676         // CC - something about this in 640x480 mode does not scale correctly
2677         gr_bitmap(bm, 172, 470); // KLC - was ss_bitmap (with scaling)
2678     } else {
2679         ss_bitmap(bm, INVENTORY_PANEL_X, BUTTON_PANEL_Y);
2680     }
2681 
2682     bm->flags &= BMF_TRANS;
2683     RESTORE_CLIP(a, b, c, d);
2684 }
2685 
2686     // ----------------------
2687     // THE DISPLAY LIST ARRAY
2688     // ----------------------
2689 
2690 #define FIELD_OFFSET(fld) (offsetof(Player, fld))
2691 
2692 inv_display inv_display_list[] = {
2693     // Page 0, weapons, grenades, drugs
2694     // weapons are there own thang, they have slots and stuff...
2695     {0, 0,
2696      WEAPON_X, AMMO_X, TOP_MARGIN,
2697      TITLE_COLOR, ITEM_COLOR,
2698      0, WEAPONS_PER_PAGE, NUM_WEAPON_SLOTS,
2699      REF_STR_WeaponTitle,
2700      ACTIVE_WEAPON,
2701      0,
2702      MFD_INV_WEAPON,
2703      NULL,
2704      NULL,
2705      draw_weapons_list,
2706      inventory_select_weapon,
2707      weapon_use_func,
2708      WEAP_CLASSES,
2709      weapons_add_func,
2710      weapon_drop_func,
2711      WEAP_TRIP,
2712      NULL,
2713      0,
2714      NULL},
2715     // grenades
2716     {0, 0,
2717      GRENADE_LEFT_X, GRENADE_RIGHT_X, TOP_MARGIN,
2718      TITLE_COLOR, ITEM_COLOR,
2719      0, GRENADES_PER_PAGE, NUM_GRENADES,
2720      REF_STR_GrenadeTitle,
2721      ACTIVE_GRENADE,
2722      FIELD_OFFSET(grenades),
2723      MFD_INV_GRENADE,
2724      grenade_name_func,
2725      generic_quant_func,
2726      generic_draw_list,
2727      NULL,
2728      grenade_use_func,
2729      GREN_CLASSES,
2730      grenade_add_func,
2731      generic_drop_func,
2732      GREN_TRIP,
2733      NULL,
2734      0,
2735      generic_lines},
2736     // drug
2737     {0, 0,
2738      DRUG_LEFT_X, DRUG_RIGHT_X, TOP_MARGIN,
2739      TITLE_COLOR, ITEM_COLOR,
2740      0, DRUGS_PER_PAGE, NUM_DRUGS,
2741      REF_STR_DrugTitle,
2742      ACTIVE_DRUG,
2743      FIELD_OFFSET(drugs),
2744      MFD_INV_DRUG,
2745      generic_name_func,
2746      generic_quant_func,
2747      generic_draw_list,
2748      NULL,
2749      drug_use_func,
2750      DRUG_CLASSES,
2751      generic_add_func,
2752      generic_drop_func,
2753      DRUG_TRIP,
2754      triple2drug,
2755      0,
2756      generic_lines + NUM_GRENADES},
2757     // Page 1, Hardwares.
2758     {1, 0,
2759      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
2760      TITLE_COLOR, ITEM_COLOR,
2761      0, ITEMS_PER_PAGE, NUM_HARDWAREZ,
2762      REF_STR_HardwareTitle,
2763      ACTIVE_HARDWARE,
2764      FIELD_OFFSET(hardwarez),
2765      MFD_INV_HARDWARE,
2766      ware_name_func,
2767      soft_quant_func,
2768      generic_draw_list,
2769      NULL,
2770      ware_use_func,
2771      HARD_CLASSES,
2772      ware_add_func,
2773      ware_drop_func,
2774      HARD_TRIP,
2775      NULL,
2776      0,
2777      generic_lines},
2778     {1, 1,
2779      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
2780      TITLE_COLOR, ITEM_COLOR,
2781      0, ITEMS_PER_PAGE, NUM_HARDWAREZ,
2782      REF_STR_Null,
2783      ACTIVE_HARDWARE,
2784      FIELD_OFFSET(hardwarez),
2785      MFD_INV_HARDWARE,
2786      ware_name_func,
2787      soft_quant_func,
2788      generic_draw_list,
2789      NULL,
2790      ware_use_func,
2791      HARD_CLASSES,
2792      ware_add_func,
2793      ware_drop_func,
2794      HARD_TRIP,
2795      NULL,
2796      0,
2797      generic_lines},
2798     // Page 2. General
2799     {2, 0,
2800      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
2801      TITLE_COLOR, ITEM_COLOR,
2802      0, ITEMS_PER_PAGE, NUM_GENERAL_SLOTS,
2803      REF_STR_GeneralTitle,
2804      ACTIVE_GENERAL,
2805      0,
2806      MFD_INV_GENINV,
2807      NULL,
2808      NULL,
2809      draw_general_list,
2810      inv_select_general,
2811      general_use_func,
2812      GENERAL_CLASSES,
2813      general_add_func,
2814      general_drop_func,
2815      0,
2816      NULL,
2817      0,
2818      (quantity_state *)general_lines},
2819     {2, 1,
2820      CENTER_X - RIGHT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
2821      TITLE_COLOR, ITEM_COLOR,
2822      0, ITEMS_PER_PAGE, NUM_GENERAL_SLOTS,
2823      REF_STR_Null,
2824      ACTIVE_GENERAL,
2825      0,
2826      MFD_INV_GENINV,
2827      NULL,
2828      NULL,
2829      draw_general_list,
2830      inv_select_general,
2831      general_use_func,
2832      GENERAL_CLASSES,
2833      general_add_func,
2834      general_drop_func,
2835      0,
2836      NULL,
2837      0,
2838      (quantity_state *)general_lines},
2839     // Page 2, Softwares.
2840     {5, 0,
2841      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
2842      TITLE_COLOR, ITEM_COLOR,
2843      0, NUM_COMBAT_SOFTS - 1, NUM_COMBAT_SOFTS - 1,
2844      REF_STR_SoftTitle,
2845      ACTIVE_COMBAT_SOFT,
2846      FIELD_OFFSET(softs.combat),
2847      MFD_INV_SOFT_COMBAT,
2848      ware_name_func,
2849      soft_quant_func,
2850      generic_draw_list,
2851      NULL,
2852      ware_use_func,
2853      SOFT_CLASSES,
2854      ware_add_func,
2855      ware_drop_func,
2856      COMSOFT_TRIP,
2857      NULL,
2858      0,
2859      generic_lines},
2860     {5, 0,
2861      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN + 6 * Y_STEP,
2862      TITLE_COLOR, ITEM_COLOR,
2863      0, 1, 1,
2864      REF_STR_Null,
2865      ACTIVE_DEFENSE_SOFT,
2866      FIELD_OFFSET(softs.defense),
2867      MFD_INV_SOFT_DEFENSE,
2868      ware_name_func,
2869      soft_quant_func,
2870      generic_draw_list,
2871      NULL,
2872      ware_use_func,
2873      SOFT_CLASSES,
2874      ware_add_func,
2875      ware_drop_func,
2876      DEFSOFT_TRIP,
2877      NULL,
2878      0,
2879      generic_lines + NUM_COMBAT_SOFTS},
2880     {5, 0,
2881      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
2882      TITLE_COLOR, ITEM_COLOR,
2883      0, NUM_ONESHOT_SOFTWARE, NUM_ONESHOT_SOFTWARE,
2884      REF_STR_Null,
2885      ACTIVE_MISC_SOFT,
2886      FIELD_OFFSET(softs.misc),
2887      MFD_INV_SOFT_MISC,
2888      ware_name_func,
2889      generic_quant_func,
2890      generic_draw_list,
2891      NULL,
2892      ware_use_func,
2893      SOFT_CLASSES,
2894      ware_add_func,
2895      ware_drop_func,
2896      MISCSOFT_TRIP,
2897      NULL,
2898      0,
2899      generic_lines + NUM_COMBAT_SOFTS + NUM_DEFENSE_SOFTS},
2900     {5, 0,
2901      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN + 6 * Y_STEP,
2902      TITLE_COLOR, ITEM_COLOR,
2903      NUM_ONESHOT_SOFTWARE, 1, NUM_MISC_SOFTWARE,
2904      REF_STR_Null,
2905      ACTIVE_MISC_SOFT,
2906      FIELD_OFFSET(softs.misc),
2907      MFD_INV_SOFT_MISC,
2908      ware_name_func,
2909      null_quant_func,
2910      generic_draw_list,
2911      NULL,
2912      ware_use_func,
2913      SOFT_CLASSES,
2914      ware_add_func,
2915      ware_drop_func,
2916      MISCSOFT_TRIP,
2917      NULL,
2918      0,
2919      generic_lines + NUM_COMBAT_SOFTS + NUM_DEFENSE_SOFTS + NUM_ONESHOT_SOFTWARE},
2920     // Page 7 main log page
2921     {7, 0,
2922      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
2923      TITLE_COLOR, ITEM_COLOR,
2924      0, ITEMS_PER_PAGE, NUM_LOG_LEVELS,
2925      REF_STR_LogTitle,
2926      NULL_ACTIVE,
2927      FIELD_OFFSET(logs),
2928      MFD_INV_NULL,
2929      log_name_func,
2930      generic_quant_func,
2931      generic_draw_list,
2932      log_use_func,
2933      log_use_func,
2934      SOFT_CLASSES,
2935      email_add_func,
2936      email_drop_func,
2937      EMAIL_TRIP,
2938      NULL,
2939      0,
2940      generic_lines},
2941     {7, 1,
2942      CENTER_X + LEFT_MARGIN, RIGHT_X, TOP_MARGIN,
2943      TITLE_COLOR, ITEM_COLOR,
2944      0, ITEMS_PER_PAGE, NUM_LOG_LEVELS,
2945      REF_STR_Null,
2946      NULL_ACTIVE,
2947      FIELD_OFFSET(logs),
2948      MFD_INV_NULL,
2949      log_name_func,
2950      generic_quant_func,
2951      generic_draw_list,
2952      log_use_func,
2953      log_use_func,
2954      SOFT_CLASSES,
2955      email_add_func,
2956      email_drop_func,
2957      EMAIL_TRIP,
2958      NULL,
2959      0,
2960      generic_lines},
2961 #ifdef NEED_THIRD_LOGLVL_PAGE
2962     {7, 2,
2963      CENTER_X + LEFT_MARGIN, RIGHT_X, TOP_MARGIN - Y_STEP,
2964      TITLE_COLOR, ITEM_COLOR,
2965      0, ITEMS_PER_PAGE, NUM_LOG_LEVELS - 1,
2966      REF_STR_Null,
2967      NULL_ACTIVE,
2968      FIELD_OFFSET(logs),
2969      MFD_INV_NULL,
2970      log_name_func,
2971      generic_quant_func,
2972      generic_draw_list,
2973      log_use_func,
2974      log_use_func,
2975      SOFT_CLASSES,
2976      email_add_func,
2977      email_drop_func,
2978      EMAIL_TRIP,
2979      NULL,
2980      0,
2981      generic_lines},
2982 #endif
2983     // Page 8, Data
2984     {8, 0,
2985      LEFT_MARGIN, ONETHIRD_X - RIGHT_MARGIN, TOP_MARGIN,
2986      TITLE_COLOR, ITEM_COLOR,
2987      FIRST_DATA, ITEMS_PER_PAGE, FIRST_DATA + ITEMS_PER_PAGE,
2988      REF_STR_DataTitle,
2989      NULL_ACTIVE,
2990      FIELD_OFFSET(email),
2991      MFD_INV_NULL,
2992      email_name_func,
2993      null_quant_func,
2994      generic_draw_list,
2995      email_use_func,
2996      email_use_func,
2997      SOFT_CLASSES,
2998      email_add_func,
2999      email_drop_func,
3000      EMAIL_TRIP,
3001      NULL,
3002      0,
3003      generic_lines},
3004     {8, 1,
3005      ONETHIRD_X + LEFT_MARGIN, TWOTHIRDS_X - RIGHT_MARGIN, TOP_MARGIN,
3006      TITLE_COLOR, ITEM_COLOR,
3007      FIRST_DATA + ITEMS_PER_PAGE, ITEMS_PER_PAGE + 1, FIRST_DATA + 2 * ITEMS_PER_PAGE + 1,
3008      REF_STR_Null,
3009      NULL_ACTIVE,
3010      FIELD_OFFSET(email),
3011      MFD_INV_NULL,
3012      email_name_func,
3013      null_quant_func,
3014      generic_draw_list,
3015      email_use_func,
3016      email_use_func,
3017      SOFT_CLASSES,
3018      email_add_func,
3019      email_drop_func,
3020      EMAIL_TRIP,
3021      NULL,
3022      0,
3023      generic_lines},
3024     {8, 2,
3025      TWOTHIRDS_X + LEFT_MARGIN, RIGHT_X, TOP_MARGIN,
3026      TITLE_COLOR, ITEM_COLOR,
3027      FIRST_DATA + 2 * ITEMS_PER_PAGE + 1, ITEMS_PER_PAGE + 1, NUM_EMAIL,
3028      REF_STR_Null,
3029      NULL_ACTIVE,
3030      FIELD_OFFSET(email),
3031      MFD_INV_NULL,
3032      email_name_func,
3033      null_quant_func,
3034      generic_draw_list,
3035      email_use_func,
3036      email_use_func,
3037      SOFT_CLASSES,
3038      email_add_func,
3039      email_drop_func,
3040      EMAIL_TRIP,
3041      NULL,
3042      0,
3043      generic_lines},
3044     // Ammo page, off screen.
3045     {9, 0,
3046      AMMO_LEFT_1, AMMO_RIGHT_1, TOP_MARGIN,
3047      TITLE_COLOR, ITEM_COLOR,
3048      0, NUM_AMMO_TYPES, NUM_AMMO_TYPES,
3049      REF_STR_PistolCartTitle,
3050      ACTIVE_CART,
3051      FIELD_OFFSET(cartridges),
3052      MFD_INV_AMMO,
3053      ammo_name_func,
3054      generic_quant_func,
3055      generic_draw_list,
3056      NULL,
3057      NULL,
3058      AMMO_CLASSES,
3059      generic_add_func,
3060      generic_drop_func,
3061      AMMO_TRIP,
3062      NULL,
3063      0,
3064      generic_lines},
3065     // Pages 50-52 Email
3066     {50, 0,
3067      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
3068      TITLE_COLOR, EMAIL_COLOR_FUNC,
3069      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3070      REF_STR_EmailTitle,
3071      NULL_ACTIVE,
3072      FIELD_OFFSET(email),
3073      MFD_INV_NULL,
3074      email_name_func,
3075      null_quant_func,
3076      generic_draw_list,
3077      email_use_func,
3078      email_use_func,
3079      SOFT_CLASSES,
3080      email_add_func,
3081      email_drop_func,
3082      EMAIL_TRIP,
3083      NULL,
3084      0,
3085      generic_lines},
3086     {50, 0,
3087      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
3088      TITLE_COLOR, EMAIL_COLOR_FUNC,
3089      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3090      REF_STR_EmailTitle,
3091      NULL_ACTIVE,
3092      FIELD_OFFSET(email),
3093      MFD_INV_NULL,
3094      NULL,
3095      NULL,
3096      email_more_draw,
3097      email_more_use,
3098      email_more_use,
3099      0,
3100      NULL,
3101      NULL,
3102      0,
3103      NULL,
3104      0,
3105      generic_lines},
3106     {50, 1,
3107      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
3108      TITLE_COLOR, EMAIL_COLOR_FUNC,
3109      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3110      REF_STR_Null,
3111      NULL_ACTIVE,
3112      FIELD_OFFSET(email),
3113      MFD_INV_NULL,
3114      email_name_func,
3115      null_quant_func,
3116      generic_draw_list,
3117      email_use_func,
3118      email_use_func,
3119      SOFT_CLASSES,
3120      email_add_func,
3121      email_drop_func,
3122      EMAIL_TRIP,
3123      NULL,
3124      0,
3125      generic_lines},
3126     {50, 1,
3127      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
3128      TITLE_COLOR, EMAIL_COLOR_FUNC,
3129      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3130      REF_STR_Null,
3131      NULL_ACTIVE,
3132      FIELD_OFFSET(email),
3133      MFD_INV_NULL,
3134      NULL,
3135      NULL,
3136      email_more_draw,
3137      email_more_use,
3138      email_more_use,
3139      0,
3140      NULL,
3141      NULL,
3142      EMAIL_TRIP,
3143      NULL,
3144      0,
3145      generic_lines},
3146     {51, 2,
3147      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
3148      TITLE_COLOR, EMAIL_COLOR_FUNC,
3149      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3150      REF_STR_EmailTitle,
3151      NULL_ACTIVE,
3152      FIELD_OFFSET(email),
3153      MFD_INV_NULL,
3154      email_name_func,
3155      null_quant_func,
3156      generic_draw_list,
3157      email_use_func,
3158      email_use_func,
3159      SOFT_CLASSES,
3160      email_add_func,
3161      email_drop_func,
3162      EMAIL_TRIP,
3163      NULL,
3164      0,
3165      generic_lines},
3166     {51, 2,
3167      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
3168      TITLE_COLOR, EMAIL_COLOR_FUNC,
3169      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3170      REF_STR_Null,
3171      NULL_ACTIVE,
3172      FIELD_OFFSET(email),
3173      MFD_INV_NULL,
3174      NULL,
3175      NULL,
3176      email_more_draw,
3177      email_more_use,
3178      email_more_use,
3179      0,
3180      NULL,
3181      NULL,
3182      0,
3183      NULL,
3184      0,
3185      generic_lines},
3186     {51, 3,
3187      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
3188      TITLE_COLOR, EMAIL_COLOR_FUNC,
3189      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3190      REF_STR_Null,
3191      NULL_ACTIVE,
3192      FIELD_OFFSET(email),
3193      MFD_INV_NULL,
3194      email_name_func,
3195      null_quant_func,
3196      generic_draw_list,
3197      email_use_func,
3198      email_use_func,
3199      SOFT_CLASSES,
3200      email_add_func,
3201      email_drop_func,
3202      EMAIL_TRIP,
3203      NULL,
3204      0,
3205      generic_lines},
3206     {51, 3,
3207      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
3208      TITLE_COLOR, EMAIL_COLOR_FUNC,
3209      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3210      REF_STR_EmailTitle,
3211      NULL_ACTIVE,
3212      FIELD_OFFSET(email),
3213      MFD_INV_NULL,
3214      NULL,
3215      NULL,
3216      email_more_draw,
3217      email_more_use,
3218      email_more_use,
3219      0,
3220      NULL,
3221      NULL,
3222      EMAIL_TRIP,
3223      NULL,
3224      0,
3225      generic_lines},
3226     {52, 4,
3227      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
3228      TITLE_COLOR, EMAIL_COLOR_FUNC,
3229      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3230      REF_STR_EmailTitle,
3231      NULL_ACTIVE,
3232      FIELD_OFFSET(email),
3233      MFD_INV_NULL,
3234      email_name_func,
3235      null_quant_func,
3236      generic_draw_list,
3237      email_use_func,
3238      email_use_func,
3239      SOFT_CLASSES,
3240      email_add_func,
3241      email_drop_func,
3242      EMAIL_TRIP,
3243      NULL,
3244      0,
3245      generic_lines},
3246     {52, 4,
3247      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
3248      TITLE_COLOR, EMAIL_COLOR_FUNC,
3249      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3250      REF_STR_EmailTitle,
3251      NULL_ACTIVE,
3252      FIELD_OFFSET(email),
3253      MFD_INV_NULL,
3254      NULL,
3255      NULL,
3256      email_more_draw,
3257      email_more_use,
3258      email_more_use,
3259      0,
3260      NULL,
3261      NULL,
3262      0,
3263      NULL,
3264      0,
3265      generic_lines},
3266     {52, 5,
3267      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
3268      TITLE_COLOR, EMAIL_COLOR_FUNC,
3269      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3270      REF_STR_Null,
3271      NULL_ACTIVE,
3272      FIELD_OFFSET(email),
3273      MFD_INV_NULL,
3274      email_name_func,
3275      null_quant_func,
3276      generic_draw_list,
3277      email_use_func,
3278      email_use_func,
3279      SOFT_CLASSES,
3280      email_add_func,
3281      email_drop_func,
3282      EMAIL_TRIP,
3283      NULL,
3284      0,
3285      generic_lines},
3286     {52, 5,
3287      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
3288      TITLE_COLOR, EMAIL_COLOR_FUNC,
3289      0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
3290      REF_STR_EmailTitle,
3291      NULL_ACTIVE,
3292      FIELD_OFFSET(email),
3293      MFD_INV_NULL,
3294      NULL,
3295      NULL,
3296      email_more_draw,
3297      email_more_use,
3298      email_more_use,
3299      0,
3300      NULL,
3301      NULL,
3302      EMAIL_TRIP,
3303      NULL,
3304      0,
3305      generic_lines},
3306 // Page 20 logs
3307 #define LOG_PAGE(i)                                                          \
3308     {FIRST_LOG_PAGE + i, 0,                                                  \
3309      LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,                       \
3310      TITLE_COLOR, EMAIL_COLOR_FUNC,                                          \
3311      NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL,                                  \
3312      ITEMS_PER_PAGE, NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL + ITEMS_PER_PAGE, \
3313      REF_STR_LogName0 + i,                                                   \
3314      NULL_ACTIVE,                                                            \
3315      FIELD_OFFSET(email),                                                    \
3316      MFD_INV_NULL,                                                           \
3317      email_name_func,                                                        \
3318      null_quant_func,                                                        \
3319      generic_draw_list,                                                      \
3320      email_use_func,                                                         \
3321      email_use_func,                                                         \
3322      SOFT_CLASSES,                                                           \
3323      email_add_func,                                                         \
3324      email_drop_func,                                                        \
3325      EMAIL_TRIP,                                                             \
3326      NULL,                                                                   \
3327      0,                                                                      \
3328      generic_lines},                                                         \
3329     {FIRST_LOG_PAGE + i, 2,                                                  \
3330      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN - Y_STEP,    \
3331      TITLE_COLOR, EMAIL_COLOR_FUNC,                                          \
3332      NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL + 2 * ITEMS_PER_PAGE + 1,         \
3333      1, NUM_EMAIL_PROPER + ((i) + 1) * LOGS_PER_LEVEL ,                      \
3334      REF_STR_Null,                                                           \
3335      NULL_ACTIVE,                                                            \
3336      FIELD_OFFSET(email),                                                    \
3337      MFD_INV_NULL,                                                           \
3338      email_name_func,                                                        \
3339      null_quant_func,                                                        \
3340      generic_draw_list,                                                      \
3341      email_use_func,                                                         \
3342      email_use_func,                                                         \
3343      SOFT_CLASSES,                                                           \
3344      email_add_func,                                                         \
3345      email_drop_func,                                                        \
3346      EMAIL_TRIP,                                                             \
3347      NULL,                                                                   \
3348      0,                                                                      \
3349      generic_lines + 2 * ITEMS_PER_PAGE},                                    \
3350     {FIRST_LOG_PAGE + i, 1,                                                  \
3351      CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,             \
3352      TITLE_COLOR, EMAIL_COLOR_FUNC,                                          \
3353      NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL + ITEMS_PER_PAGE, ITEMS_PER_PAGE, \
3354      NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL + 2 * ITEMS_PER_PAGE + 1,         \
3355      REF_STR_Null,                                                           \
3356      NULL_ACTIVE,                                                            \
3357      FIELD_OFFSET(email),                                                    \
3358      MFD_INV_NULL,                                                           \
3359      email_name_func,                                                        \
3360      null_quant_func,                                                        \
3361      generic_draw_list,                                                      \
3362      email_use_func,                                                         \
3363      email_use_func,                                                         \
3364      SOFT_CLASSES,                                                           \
3365      email_add_func,                                                         \
3366      email_drop_func,                                                        \
3367      EMAIL_TRIP,                                                             \
3368      NULL,                                                                   \
3369      0,                                                                      \
3370      generic_lines}
3371 
3372     // Hey these pages MUST BE LAST.
3373     LOG_PAGE(0),
3374 #ifdef EXPLICIT_LOG_PAGES
3375     LOG_PAGE(1),
3376     LOG_PAGE(2),
3377     LOG_PAGE(3),
3378     LOG_PAGE(4),
3379     LOG_PAGE(5),
3380     LOG_PAGE(6),
3381     LOG_PAGE(7),
3382     LOG_PAGE(8),
3383     LOG_PAGE(9),
3384     LOG_PAGE(10),
3385     LOG_PAGE(11),
3386     LOG_PAGE(12),
3387     LOG_PAGE(13),
3388     LOG_PAGE(14),
3389 #endif // EXPLICIT_LOG_PAGES
3390 
3391 };
3392 
3393 #define NUM_INV_DISPLAYS (sizeof(inv_display_list) / sizeof(inv_display))
3394 
3395 #define DUMMY_LOG_INDEX (NUM_INV_DISPLAYS - 3)
3396 
super_drop_func(int dispnum,int row)3397 void super_drop_func(int dispnum, int row) {
3398     inv_display *dp = &(inv_display_list[dispnum]);
3399     dp->drop(dp, row);
3400 }
3401 
super_use_func(int dispnum,int row)3402 void super_use_func(int dispnum, int row) {
3403     inv_display *dp = &(inv_display_list[dispnum]);
3404     dp->use(dp, row);
3405 }
3406 
gen_log_displays(int pgnum)3407 void gen_log_displays(int pgnum) {
3408     inv_display *dp = &inv_display_list[DUMMY_LOG_INDEX];
3409     pgnum -= FIRST_LOG_PAGE;
3410     if (pgnum >= 0 && pgnum < NUM_LOG_LEVELS) {
3411         dp->pgnum = FIRST_LOG_PAGE + pgnum;
3412         dp->first = NUM_EMAIL_PROPER + pgnum * LOGS_PER_LEVEL;
3413         dp->listlen = NUM_EMAIL_PROPER + ITEMS_PER_PAGE + pgnum * LOGS_PER_LEVEL;
3414         dp->titlenum = MKREF(RES_lognames, pgnum);
3415         dp++;
3416         dp->pgnum = FIRST_LOG_PAGE + pgnum;
3417         dp->first = NUM_EMAIL_PROPER + pgnum * LOGS_PER_LEVEL + 2 * ITEMS_PER_PAGE + 1;
3418         dp->listlen = NUM_EMAIL_PROPER + (pgnum + 1) * LOGS_PER_LEVEL;
3419         dp++;
3420         dp->pgnum = FIRST_LOG_PAGE + pgnum;
3421         dp->first = NUM_EMAIL_PROPER + pgnum * LOGS_PER_LEVEL + ITEMS_PER_PAGE;
3422         dp->listlen = NUM_EMAIL_PROPER + pgnum * LOGS_PER_LEVEL + 2 * ITEMS_PER_PAGE + 1;
3423     }
3424 }
3425 
gen_inv_page(int pgnum,int * i,inv_display ** dp)3426 uchar gen_inv_page(int pgnum, int *i, inv_display **dp) {
3427     if (*i == 0)
3428         gen_log_displays(pgnum);
3429     for (; *i < NUM_INV_DISPLAYS; (*i)++) {
3430         inv_display *idp = &inv_display_list[*i];
3431         if (idp->pgnum == pgnum) {
3432             *dp = idp;
3433             return TRUE;
3434         }
3435     }
3436     return FALSE;
3437 }
3438 
3439 #define LOG_PAGE_SHF 8
3440 
gen_inv_displays(int * i,inv_display ** dp)3441 uchar gen_inv_displays(int *i, inv_display **dp) {
3442     if (*i == 0)
3443         gen_log_displays(inventory_page);
3444     for (; *i < NUM_INV_DISPLAYS; (*i)++) {
3445         inv_display *idp = &inv_display_list[*i];
3446         *dp = idp;
3447         return TRUE;
3448     }
3449     return FALSE;
3450 }
3451 
absorb_object_on_cursor(ushort keycode,uint32_t context,intptr_t data)3452 void absorb_object_on_cursor(ushort keycode, uint32_t context, intptr_t data) {
3453     if (object_on_cursor == 0)
3454         return;
3455 
3456     if (inventory_add_object(object_on_cursor, TRUE))
3457         pop_cursor_object();
3458     return;
3459 }
3460