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