a5ec8db5f7
build / build (push) Failing after 5s
dependency (SDL2, SDL2_mixer, fluidsynth-lite, a MIDI soundfont) prebuilt, so compiling the engine needs no network access - just the image and the engine source. Add res/assets/extract_assets.sh to pull the game's data files out of a purchased GOG installer, and a Makefile that assembles a runnable dist/ from the two. Also add `make package`, which builds a redistributable tarball that omits the proprietary game assets (shipping res/GET_ASSETS.txt instead) plus license information for both the MIT tooling and the GPLv3 engine, and a Gitea Actions workflow that builds and publishes it to dl.ladkau.de on every push.
3423 lines
108 KiB
C
3423 lines
108 KiB
C
/*
|
|
|
|
Copyright (C) 2015-2018 Night Dive Studios, LLC.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
/*
|
|
* $Source: r:/prj/cit/src/RCS/invent.c $
|
|
* $Revision: 1.240 $
|
|
* $Author: dc $
|
|
* $Date: 1994/11/22 15:58:48 $
|
|
*
|
|
*/
|
|
|
|
// Source code for inventory manipulation / display
|
|
|
|
#include <string.h>
|
|
|
|
#include "email.h"
|
|
#include "invent.h"
|
|
#include "leanmetr.h"
|
|
#include "objprop.h"
|
|
#include "objwpn.h"
|
|
#include "objwarez.h"
|
|
#include "objsim.h"
|
|
#include "objuse.h"
|
|
#include "status.h"
|
|
#include "tools.h"
|
|
#include "colors.h"
|
|
#include "player.h"
|
|
#include "weapons.h"
|
|
#include "drugs.h"
|
|
#include "grenades.h"
|
|
#include "wares.h"
|
|
#include "cybstrng.h"
|
|
#include "gamestrn.h"
|
|
#include "sideicon.h"
|
|
#include "gameloop.h"
|
|
#include "loops.h"
|
|
#include "input.h"
|
|
#include "mfdext.h"
|
|
#include "objbit.h"
|
|
#include "fullscrn.h"
|
|
#include "cit2d.h"
|
|
#include "gr2ss.h"
|
|
#include "criterr.h"
|
|
#include "view360.h"
|
|
#include "objload.h"
|
|
#include "invpages.h"
|
|
#include "sfxlist.h"
|
|
#include "musicai.h"
|
|
#include "emailbit.h"
|
|
#include "popups.h"
|
|
|
|
#include "otrip.h"
|
|
#include "gamescr.h"
|
|
#include "amap.h"
|
|
|
|
#include "game_screen.h" // was screen.h?
|
|
|
|
//#include <inp6d.h>
|
|
//#include <i6dvideo.h>
|
|
|
|
/***************************************/
|
|
/* INVENTORY DISPLAY MODULE */
|
|
/*-------------------------------------*/
|
|
/*---------------------------------------------
|
|
The inventory display is arranged into a number of
|
|
/pages/, each of which can contain one or more
|
|
/lists/. In general, a list shows "what types of
|
|
a particular thing you have," and "how many of
|
|
each do you have." There is a list for weapons,
|
|
one for grenades, one for drugs, etc.
|
|
|
|
The contents of each list is, more or less, defined
|
|
by two arrays, and "exists" array and a "quantity"
|
|
array. For a particular list, say, the grenades
|
|
list, exists[N] is non-zero if you have any
|
|
grenades of type N, and quant[N] is the number of
|
|
grenades of that type you have.You astutely
|
|
observe: "Why are these lists different, when the
|
|
quantity of something is always zero if you have
|
|
none of it, and thus the quantity array and the
|
|
exists array could be the same?" The answer is:
|
|
because it's goofy.
|
|
|
|
For each list, the inventory display maintains a
|
|
state array describing what stuff was actually
|
|
DRAWN, so it can redraw incrementally. The
|
|
elements of the array are structures of type
|
|
/quantity_state/, defined below.
|
|
|
|
A list can be divided onto different pages of the
|
|
inventory, and each section of a list that
|
|
appears on its own page is called a /display/.
|
|
The inventory panel figures out what to display
|
|
by looking through a huge list of all the
|
|
displays in the game. Adding a new display is as
|
|
simple as adding a new element to this array. Of
|
|
course, that element is a huge wonking structure
|
|
describing when and where and how to draw, use,
|
|
and select items on the display.
|
|
|
|
And now, the code...
|
|
----------------------------------------------*/
|
|
|
|
#define KEY_CODE_ESC 0x1b
|
|
|
|
// -------------
|
|
// DISPLAY STUFF
|
|
// -------------
|
|
// -------
|
|
// DEFINES
|
|
// -------
|
|
#define INVENT_CHANGED \
|
|
if (_current_loop <= FULLSCREEN_LOOP) \
|
|
chg_set_flg(INVENTORY_UPDATE);
|
|
|
|
// colors & fonts
|
|
#define TITLE_COLOR (RED_BASE + 5)
|
|
#define ITEM_COLOR (0x5A)
|
|
#define SELECTED_ITEM_COLOR (0x4C)
|
|
#define BRIGHT_ITEM_COLOR (0xE7)
|
|
#define DULL_ITEM_COLOR (0x5F)
|
|
// let us no longer pretend we have differenet fonts for everything
|
|
#define ITEM_FONT RES_tinyTechFont
|
|
#define WEAPONS_FONT ITEM_FONT
|
|
|
|
// Screen margins/locations/proportions
|
|
#define TOP_MARGIN 2 // was 15
|
|
#define LEFT_MARGIN 4
|
|
#define RIGHT_MARGIN 3
|
|
#define Y_STEP 6
|
|
#define WEAPON_X LEFT_MARGIN
|
|
#define AMMO_X 70
|
|
#define GRENADE_LEFT_X (AMMO_X + 4)
|
|
#define GRENADE_RIGHT_X (GRENADE_LEFT_X + 30)
|
|
#define DRUG_RIGHT_X (INVENTORY_PANEL_WIDTH - RIGHT_MARGIN)
|
|
#define DRUG_LEFT_X (DRUG_RIGHT_X - 35)
|
|
#define AMMO_LEFT_1 WEAPON_X
|
|
#define AMMO_RIGHT_1 (AMMO_LEFT_1 + 40)
|
|
#define AMMO_LEFT_2 (AMMO_RIGHT_1 + 4)
|
|
#define AMMO_RIGHT_2 (AMMO_LEFT_2 + 40)
|
|
#define AMMO_LEFT_3 (AMMO_RIGHT_2 + 4)
|
|
#define AMMO_RIGHT_3 (AMMO_LEFT_3 + 40)
|
|
#define CENTER_X (INVENTORY_PANEL_WIDTH / 2)
|
|
#define RIGHT_X INVENTORY_PANEL_WIDTH
|
|
#define ONETHIRD_X (INVENTORY_PANEL_WIDTH / 3)
|
|
#define TWOTHIRDS_X (2 * INVENTORY_PANEL_WIDTH / 3)
|
|
|
|
// Page button defines
|
|
#define FIRST_BTTN_X (3)
|
|
#define INVENT_BTTN_Y (2)
|
|
#define INVENT_BTTN_HT 3
|
|
#define INVENT_BTTN_WD 18
|
|
#define BUTTON_X_STEP 24
|
|
|
|
// Hey, these colors are stolen from mfd
|
|
#define INVENT_BTTN_EMPTY 0xcb
|
|
#define INVENT_BTTN_FLASH_ON 0x35
|
|
#define INVENT_BTTN_FLASH_OFF 0xcb
|
|
#define INVENT_BTTN_SELECT 0x77
|
|
|
|
typedef enum {
|
|
BttnOff = 0,
|
|
BttnDummy = 1,
|
|
BttnActive = 2,
|
|
BttnFlashOff = 3,
|
|
BttnFlashOn = 16,
|
|
NUM_BUTTON_STATES = BttnFlashOn + 1
|
|
} invent_bttn_state;
|
|
|
|
#define FlashOn(state) (((state)&0x1) == 0)
|
|
#define Flashing(state) ((state) >= BttnFlashOff && (state) <= BttnFlashOn)
|
|
|
|
// mapping from button states to colors
|
|
ubyte _bttn_state2color[] = {
|
|
INVENT_BTTN_EMPTY, INVENT_BTTN_EMPTY, INVENT_BTTN_SELECT, INVENT_BTTN_FLASH_OFF, INVENT_BTTN_FLASH_ON,
|
|
};
|
|
|
|
#define bttn_state2color(state) _bttn_state2color[Flashing(state) ? BttnFlashOff + !(state & 1) : state]
|
|
|
|
#define INVENT_BTTN_FLASH_TIME 128
|
|
|
|
#define NUM_PAGE_BUTTONS 6
|
|
|
|
// Page stuff
|
|
#define WEAPON_PAGES 1
|
|
#define WEAPONS_PER_PAGE 7
|
|
#define DRUG_PAGES 1
|
|
#define DRUGS_PER_PAGE 7
|
|
#define GRENADE_PAGES 1
|
|
#define GRENADES_PER_PAGE 7
|
|
#define AMMO_PAGES 3
|
|
#define AMMO_PER_PAGE 3
|
|
#define ITEMS_PER_PAGE 7
|
|
|
|
// Misc
|
|
#define BUFSZ 50
|
|
#define NULL_ACTIVE -1 // the null active
|
|
|
|
// Object adding return codes
|
|
|
|
typedef enum { ADD_FAIL, ADD_POP, ADD_SWAP, ADD_REJECT, ADD_NOROOM, ADD_NOEFFECT } AddResult;
|
|
|
|
#define IS_POP_RESULT(r) ((r) == ADD_POP || (r) == ADD_NOEFFECT)
|
|
|
|
typedef struct _quantity_state {
|
|
ushort num; // item number
|
|
ubyte exist; // do we have it;
|
|
ubyte quant; // quantity
|
|
byte pad;
|
|
} quantity_state;
|
|
|
|
// Get the correct color for an item, given its rank in the list.
|
|
typedef uchar (*color_func)(void *dp, int num);
|
|
|
|
// Get the string name of an item, given its rank in the
|
|
// list.
|
|
typedef char *(*name_func)(void *dp, int num, char *buf);
|
|
|
|
struct _inventory_display_list;
|
|
|
|
// Get the string quantity of an item, given its rank in the
|
|
// list,and its actual quantity.
|
|
typedef char *(*quant_string_func)(struct _inventory_display_list *dp, int num, int quant, char *buf);
|
|
|
|
// Draw a display
|
|
typedef void (*draw_func)(struct _inventory_display_list *dp);
|
|
|
|
// Select an item given its rank in the list
|
|
typedef uchar (*select_func)(struct _inventory_display_list *dp, int itemnum);
|
|
|
|
// Use an item given its rank in the list.
|
|
typedef uchar (*use_func)(struct _inventory_display_list *dp, int itemnum);
|
|
|
|
// Add an object to a list
|
|
typedef ubyte (*add_func)(struct _inventory_display_list *dp, int itemnum, ObjID *obj, uchar select);
|
|
|
|
// Remove and object from a list
|
|
typedef void (*drop_func)(struct _inventory_display_list *dp, int itemnum);
|
|
|
|
typedef struct _inventory_display_list {
|
|
ushort pgnum; // Page number this display is on
|
|
short relnum; // Relative page number for this list.
|
|
short left, right; // Left and right pixel edge
|
|
short top; // Top pixel margin
|
|
ubyte titlecolor; // Title color. Duh.
|
|
ubyte listcolor; // color for list items. if greater than 239,
|
|
// it's a color func.
|
|
ushort first; // first list item to start at.
|
|
ushort pgsize; // Number of items in each list page
|
|
ushort listlen; // Number of total list items
|
|
int titlenum; // String number of title.
|
|
int activenum; // index into player_struct.actives
|
|
int offset; // offset of quantities into player struct
|
|
int mfdtype; // inventory time for set_inventory_mfd
|
|
name_func name; // given a type number, give us the name
|
|
quant_string_func quant; // Given an item number, give us the quantity string
|
|
draw_func draw; // draw this inv_display
|
|
select_func select; // select a row
|
|
use_func use; // use a row
|
|
int add_classes; // Classes of objects that this list represents
|
|
add_func add; // function to add an object to this list.
|
|
drop_func drop; // remove an object from a row.
|
|
int basetrip; // triple of item number zero.
|
|
int (*toidx)(int); // convert from a triple to an index (NOT USED)
|
|
// state data
|
|
uchar dummy; // used to be known_active
|
|
quantity_state *lines; // lines of state data
|
|
} inv_display;
|
|
|
|
int known_actives[NUM_ACTIVES];
|
|
|
|
#define NULL_PAGE 0xFFFF
|
|
extern inv_display inv_display_list[];
|
|
|
|
color_func color_func_list[] = {email_color_func};
|
|
#define EMAIL_COLOR_FUNC 240
|
|
|
|
// -------
|
|
// GLOBALS
|
|
// -------
|
|
|
|
// The current inventory "page"
|
|
|
|
short inventory_page = 0;
|
|
uchar show_all_actives = FALSE;
|
|
|
|
// The last page we drew
|
|
short inv_last_page = INV_BLANK_PAGE;
|
|
|
|
LGRegion *inventory_region;
|
|
extern LGRegion *inventory_region_game, *inventory_region_full;
|
|
LGRegion **all_inventory_regions[] = {&inventory_region_game, &inventory_region_full};
|
|
|
|
#define NUM_INVENT_REGIONS (sizeof(all_inventory_regions) / sizeof(LGRegion **))
|
|
|
|
static struct _weapon_list_state {
|
|
ubyte active;
|
|
weapon_slot slots[WEAPON_PAGES * WEAPONS_PER_PAGE];
|
|
ubyte ammo_available[WEAPON_PAGES * WEAPONS_PER_PAGE];
|
|
} weapon_list;
|
|
|
|
quantity_state generic_lines[48];
|
|
|
|
// page button state
|
|
invent_bttn_state page_button_state[NUM_PAGE_BUTTONS] = {
|
|
BttnOff, BttnOff, BttnOff, BttnDummy, BttnDummy, BttnOff,
|
|
};
|
|
// Last button state that was actually drawn.
|
|
invent_bttn_state old_button_state[NUM_PAGE_BUTTONS] = {BttnDummy, BttnDummy, BttnDummy,
|
|
BttnDummy, BttnDummy, BttnDummy};
|
|
|
|
LGRegion *pagebutton_region;
|
|
|
|
// DRAWING STUFF
|
|
grs_bitmap inv_backgnd;
|
|
grs_canvas inv_norm_canvas;
|
|
grs_canvas inv_fullscrn_canvas;
|
|
grs_canvas inv_view360_canvas;
|
|
grs_canvas *pinv_canvas = &inv_norm_canvas;
|
|
|
|
grs_canvas inv_gamepage_canvas;
|
|
grs_canvas inv_fullpage_canvas;
|
|
grs_canvas *ppage_canvas = &inv_gamepage_canvas;
|
|
|
|
#define inv_canvas (*pinv_canvas)
|
|
|
|
#define NUM_PAGE_BTTNS NUM_PAGE_BUTTONS
|
|
|
|
#ifdef OLD_BUTTON_CURSORS
|
|
LGCursor invent_bttn_cursors[NUM_PAGE_BTTNS];
|
|
grs_bitmap invent_bttn_bitmaps[NUM_PAGE_BTTNS];
|
|
Ref invent_bttn_curs_ids[NUM_PAGE_BTTNS] = {
|
|
REF_IMG_bmInventWeapon, REF_IMG_bmInventHardware, REF_IMG_bmInventGeneral,
|
|
REF_IMG_bmTargetCursor, REF_IMG_bmInventCombatSoft, REF_IMG_bmInventMiscSoft,
|
|
};
|
|
#else
|
|
LGCursor invent_bttn_cursor;
|
|
grs_bitmap invent_bttn_bitmap;
|
|
#endif
|
|
|
|
static char *cursor_strings[NUM_PAGE_BUTTONS];
|
|
static char cursor_string_buf[128];
|
|
|
|
#define BUTTON_PANEL_Y (INVENTORY_PANEL_Y + INVENTORY_PANEL_HEIGHT)
|
|
|
|
#define INVENT_BUTTON_PANEL_X (-1)
|
|
#define INVENT_BUTTON_PANEL_Y (196 - BUTTON_PANEL_Y)
|
|
|
|
// ---------------------
|
|
// Internal Prototypes
|
|
// ---------------------
|
|
ubyte add_to_some_page(ObjID obj, uchar select);
|
|
void draw_inventory_string(char *s, int x, int y, uchar clear);
|
|
void clear_inventory_region(short x1, short y1, short x2, short y2);
|
|
void draw_quant_line(char *name, char *quant, long color, uchar active, short left, short right, short y);
|
|
void draw_quant_list(inv_display *dp, uchar newpage);
|
|
int get_item_at_pixrow(inv_display *dp, int row);
|
|
char *weapon_name_func(void *, int num, char *buf);
|
|
char *weapon_quant_func(int num, char *buf);
|
|
void draw_weapons_list(inv_display *dp);
|
|
uchar inventory_select_weapon(inv_display *dp, int w);
|
|
uchar weapon_use_func(inv_display *dp, int w);
|
|
ubyte weapons_add_func(inv_display *dp, int row, ObjID *objP, uchar select);
|
|
void weapon_drop_func(inv_display *dp, int itemnum);
|
|
ubyte generic_add_func(inv_display *dp, int row, ObjID *idP, uchar select);
|
|
void generic_drop_func(inv_display *dp, int row);
|
|
char *null_name_func(inv_display *dp, int n, char *buf);
|
|
static char *grenade_name_func(void *vdp, int n, char *buf);
|
|
uchar grenade_use_func(inv_display *dp, int row);
|
|
ubyte grenade_add_func(inv_display *dp, int row, ObjID *idP, uchar select);
|
|
char *drug_name_func(inv_display *dp, int n, char *buf);
|
|
uchar drug_use_func(inv_display *dp, int row);
|
|
char *ammo_name_func(void *, int n, char *buf);
|
|
void hardware_add_specials(int n, int ver);
|
|
ubyte ware_add_func(inv_display *dp, int, ObjID *idP, uchar select);
|
|
void ware_drop_func(inv_display *dp, int row);
|
|
char *null_quant_func(inv_display *, int, int, char *buf);
|
|
void draw_general_list(inv_display *dp);
|
|
uchar general_use_func(inv_display *dp, int row);
|
|
ubyte inv_empty_trash(void);
|
|
ubyte add_access_card(inv_display *dp, ObjID *idP, uchar select);
|
|
ubyte general_add_func(inv_display *dp, int row, ObjID *idP, uchar select);
|
|
void general_drop_func(inv_display *, int row);
|
|
uchar inv_select_general(inv_display *dp, int w);
|
|
void email_more_draw(inv_display *dp);
|
|
uchar email_more_use(inv_display *dp, int);
|
|
uchar email_use_func(inv_display *dp, int row);
|
|
void email_select_func(inv_display *dp, int row);
|
|
ubyte email_add_func(inv_display *, int, ObjID *idP, uchar select);
|
|
void email_drop_func(inv_display *, int);
|
|
char *log_name_func(void *, int num, char *buf);
|
|
uchar log_use_func(inv_display *dp, int row);
|
|
void inventory_draw_page(int pgnum);
|
|
void draw_page_button_panel();
|
|
uchar do_selection(inv_display *dp, int row);
|
|
void add_object_on_cursor(inv_display *dp, int row);
|
|
uchar inventory_handle_leftbutton(uiEvent *ev, inv_display *dp, int row);
|
|
uchar inventory_handle_rightbutton(uiEvent *ev, LGRegion *reg, inv_display *dp, int row);
|
|
uchar inventory_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t);
|
|
uchar pagebutton_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t);
|
|
uchar invent_hotkey_func(ushort, uint32_t, intptr_t data);
|
|
void init_invent_hotkeys(void);
|
|
void gen_log_displays(int pgnum);
|
|
void absorb_object_on_cursor(ushort keycode, uint32_t context, intptr_t data);
|
|
uchar gen_inv_page(int pgnum, int *i, inv_display **dp);
|
|
uchar gen_inv_displays(int *i, inv_display **dp);
|
|
|
|
// ---------------------
|
|
// DISPLAY LIST ROUTINES
|
|
// ---------------------
|
|
|
|
// --------
|
|
// ROUTINES
|
|
// --------
|
|
|
|
void push_inventory_cursors(LGCursor *newcurs) {
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_INVENT_REGIONS; i++) {
|
|
uiPushRegionCursor(*(all_inventory_regions[i]), newcurs);
|
|
}
|
|
}
|
|
|
|
void pop_inventory_cursors(void) {
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_INVENT_REGIONS; i++) {
|
|
uiPopRegionCursor(*(all_inventory_regions[i]));
|
|
}
|
|
}
|
|
|
|
// draw a string in relative coordinates
|
|
void draw_inventory_string(char *s, int x, int y, uchar clear) {
|
|
short w, h;
|
|
short a, b, c, d;
|
|
|
|
gr_string_size(s, &w, &h);
|
|
if (w <= 0 || h <= 0 || strlen(s) == 0)
|
|
return;
|
|
STORE_CLIP(a, b, c, d);
|
|
// Warning(("draw_string clip %d %d %d %d\n",x-1,y-1,x+w,y+h));
|
|
ss_safe_set_cliprect(x - 1, y - 1, x + w, y + h);
|
|
if (!full_game_3d) {
|
|
|
|
LGRect r;
|
|
r.ul.x = x - 1;
|
|
r.ul.y = y - 1;
|
|
r.lr.x = x + w;
|
|
r.lr.y = y + h;
|
|
RECT_MOVE(&r, MakePoint(INVENTORY_PANEL_X, INVENTORY_PANEL_Y));
|
|
uiHideMouse(&r);
|
|
if (clear)
|
|
ss_bitmap(&inv_backgnd, 0, 0);
|
|
// gr_bitmap(&inv_backgnd, 0, 0);
|
|
draw_shadowed_string(s, x, y, FALSE);
|
|
uiShowMouse(&r);
|
|
} else {
|
|
long oldcolor = gr_get_fcolor();
|
|
if (clear) {
|
|
gr_set_fcolor(0);
|
|
ss_rect(x, y, x + w, y + h - 1);
|
|
}
|
|
gr_set_fcolor(oldcolor);
|
|
draw_shadowed_string(s, x, y, TRUE);
|
|
}
|
|
RESTORE_CLIP(a, b, c, d);
|
|
}
|
|
|
|
void clear_inventory_region(short x1, short y1, short x2, short y2) {
|
|
LGRect r;
|
|
short a, b, c, d;
|
|
|
|
if (!full_game_3d) {
|
|
r.ul.x = x1;
|
|
r.ul.y = y1;
|
|
r.lr.x = x2;
|
|
r.lr.y = y2;
|
|
STORE_CLIP(a, b, c, d);
|
|
ss_safe_set_cliprect(x1, y1, x2, y2);
|
|
RECT_MOVE(&r, MakePoint(INVENTORY_PANEL_X, INVENTORY_PANEL_Y));
|
|
uiHideMouse(&r);
|
|
ss_bitmap(&inv_backgnd, 0, 0);
|
|
// gr_bitmap(&inv_backgnd, 0, 0);
|
|
uiShowMouse(&r);
|
|
RESTORE_CLIP(a, b, c, d);
|
|
} else {
|
|
gr_set_fcolor(0);
|
|
ss_rect(x1 - 1, y1, x2 + 1, y2);
|
|
}
|
|
}
|
|
|
|
// Draw a single line of the weapons list
|
|
void draw_quant_line(char *name, char *quant, long color, uchar active, short left, short right, short y) {
|
|
short ht, wd;
|
|
|
|
gr_string_size(name, &wd, &ht);
|
|
wd = gr_string_width(quant);
|
|
clear_inventory_region(left, y, right, y + ht);
|
|
if (active)
|
|
gr_set_fcolor(SELECTED_ITEM_COLOR);
|
|
else if (color < 256)
|
|
gr_set_fcolor(color);
|
|
draw_inventory_string(name, left, y, FALSE);
|
|
draw_inventory_string(quant, right - wd, y, FALSE);
|
|
}
|
|
|
|
void draw_quant_list(inv_display *dp, uchar newpage) {
|
|
int wtype;
|
|
int cnt;
|
|
int y, i;
|
|
char buf[BUFSZ];
|
|
ubyte *quant = (ubyte *)&player_struct + dp->offset;
|
|
ubyte *exist = quant;
|
|
int active = (dp->activenum == NULL_ACTIVE) ? -1 : player_struct.actives[dp->activenum];
|
|
int known_active = (dp->activenum == NULL_ACTIVE) ? -1 : known_actives[dp->activenum];
|
|
quantity_state *line = dp->lines + dp->relnum * dp->pgsize;
|
|
|
|
// Hey, what if we don't have our active item anymore...
|
|
if (active >= 0 && active < dp->listlen && quant[active] == 0) {
|
|
player_struct.actives[dp->activenum] = active = MFD_INV_NOTYPE;
|
|
set_inventory_mfd(dp->mfdtype, MFD_INV_NOTYPE, TRUE);
|
|
}
|
|
if (newpage && dp->titlenum != REF_STR_Null) {
|
|
gr_set_fcolor(dp->titlecolor);
|
|
get_string(dp->titlenum, buf, BUFSZ);
|
|
draw_inventory_string(buf, dp->left, dp->top, TRUE);
|
|
}
|
|
if (dp->first != 0)
|
|
wtype = dp->first;
|
|
else
|
|
for (wtype = 0, cnt = 0; wtype < dp->listlen && cnt < dp->pgsize * dp->relnum; wtype++) {
|
|
if (exist[wtype] > 0)
|
|
cnt++;
|
|
}
|
|
for (y = dp->top + Y_STEP, i = 0, cnt = 0; cnt < dp->pgsize; i++, wtype++) {
|
|
if (wtype >= dp->listlen) {
|
|
if (line->num < dp->listlen) {
|
|
clear_inventory_region(dp->left, y, dp->right, y + Y_STEP);
|
|
}
|
|
y += Y_STEP;
|
|
line->num = wtype;
|
|
line++;
|
|
cnt++;
|
|
continue;
|
|
}
|
|
if (exist[wtype] != 0) {
|
|
uchar newactive = active != known_active;
|
|
// note the hack for combat softwares
|
|
uchar curractive =
|
|
((show_all_actives && dp->pgnum == INV_MAIN_PAGE) || player_struct.current_active == dp->activenum) ||
|
|
dp->activenum == ACTIVE_COMBAT_SOFT;
|
|
uchar changed = newpage || newactive || (line->num != wtype) || (line->quant != quant[wtype]) ||
|
|
(line->exist != exist[wtype]);
|
|
line->num = wtype;
|
|
line->quant = quant[wtype];
|
|
line->exist = exist[wtype];
|
|
if (changed) {
|
|
char buf[BUFSZ] = "";
|
|
char buf2[BUFSZ] = "";
|
|
uchar is_active = wtype == active && curractive;
|
|
uchar col;
|
|
|
|
if (dp->name != NULL)
|
|
dp->name(dp, wtype, buf);
|
|
if (dp->quant != NULL)
|
|
dp->quant(dp, wtype, quant[wtype], buf2);
|
|
col = dp->listcolor;
|
|
if (col > 239)
|
|
col = (color_func_list[col - 240])(dp, wtype);
|
|
draw_quant_line(buf, buf2, col, is_active, dp->left, dp->right, y);
|
|
}
|
|
cnt++;
|
|
line++;
|
|
y += Y_STEP;
|
|
}
|
|
}
|
|
}
|
|
|
|
void set_current_active(int activenum) {
|
|
int old = player_struct.current_active;
|
|
known_actives[old] = -1;
|
|
player_struct.current_active = activenum;
|
|
known_actives[activenum] = -1;
|
|
}
|
|
|
|
// Get the item at a particular pixel y
|
|
int get_item_at_pixrow(inv_display *dp, int row) {
|
|
int linenum = dp->relnum * dp->pgsize;
|
|
int ipanel_y;
|
|
int y_step;
|
|
int r1, r2;
|
|
|
|
#ifdef STEREO_SUPPORT
|
|
if (convert_use_mode == 5) {
|
|
switch (i6d_device) {
|
|
case I6D_CTM:
|
|
ipanel_y = 1;
|
|
y_step = Y_STEP << 2;
|
|
break;
|
|
case I6D_VFX1:
|
|
ipanel_y = INVENTORY_PANEL_Y >> 1;
|
|
// ipanel_y = (200 - inv_fullscrn_canvas.bm.h);
|
|
// y_step = Y_STEP << 1;
|
|
y_step = 10;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
ipanel_y = INVENTORY_PANEL_Y;
|
|
y_step = Y_STEP;
|
|
}
|
|
r1 = row;
|
|
row -= ipanel_y + dp->top + y_step;
|
|
if (row < 0)
|
|
return -1;
|
|
r2 = row;
|
|
row /= y_step;
|
|
if (row >= dp->pgsize)
|
|
return -1;
|
|
// Warning(("row = %d = (%d - %d + %d + %d) = %d / %d\n",row,r1,ipanel_y,dp->top,y_step,r2,y_step));
|
|
|
|
return linenum + row;
|
|
}
|
|
|
|
// --------------------
|
|
// WEAPON DISPLAY FUNCS
|
|
// --------------------
|
|
|
|
#define WEAP_CLASSES (1 << CLASS_GUN)
|
|
#define WEAP_TRIP MAKETRIP(CLASS_GUN, 0, 0)
|
|
|
|
char *weapon_name_func(void *v, int num, char *buf) {
|
|
weapon_slot *ws = &player_struct.weapons[num];
|
|
get_weapon_name(ws->type, ws->subtype, buf);
|
|
return buf;
|
|
}
|
|
|
|
char *weapon_quant_func(int num, char *buf) {
|
|
int triple, num_ammo_types, ammo_subclass;
|
|
ubyte ammo_types[3];
|
|
int i = 0;
|
|
weapon_slot *ws = &player_struct.weapons[num];
|
|
uchar energy = is_energy_weapon(ws->type);
|
|
|
|
if (is_handtohand_weapon(ws->type)) {
|
|
buf[0] = '\0';
|
|
return buf;
|
|
}
|
|
|
|
if ((!energy) && (ws->type != GUN_SUBCLASS_BEAMPROJ)) {
|
|
int ammo = ws->ammo;
|
|
if (ws->ammo_type == EMPTY_WEAPON_SLOT) {
|
|
ammo = 0;
|
|
}
|
|
|
|
get_available_ammo_type(ws->type, ws->subtype, &num_ammo_types, ammo_types, &ammo_subclass);
|
|
|
|
triple = MAKETRIP(CLASS_AMMO, ammo_subclass, ws->ammo_type);
|
|
if (ammo > 0) {
|
|
buf[i++] = AMMO_TYPE_LETTER((CPTRIP(triple)));
|
|
buf[i++] = ' ';
|
|
}
|
|
if (ammo == 0 && num_ammo_types > 0)
|
|
get_string(REF_STR_AmmoLoad, buf, BUFSZ);
|
|
else
|
|
sprintf(buf + i, "%d", ammo);
|
|
// itoa(ammo,buf+i,10);
|
|
} else {
|
|
if (ws->heat > OVERHEAT_THRESHOLD)
|
|
get_string(REF_STR_GunHot, buf, BUFSZ);
|
|
else if (OVERLOAD_VALUE(ws->setting))
|
|
get_string(REF_STR_AmmoOver, buf, BUFSZ);
|
|
else if (ws->heat > WARM_THRESHOLD)
|
|
get_string(REF_STR_GunWarm, buf, BUFSZ);
|
|
else
|
|
get_string(REF_STR_GunOK, buf, BUFSZ);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
void draw_weapons_list(inv_display *dp) {
|
|
uchar newpage = inv_last_page != inventory_page;
|
|
char buf[BUFSZ];
|
|
int i, s;
|
|
short y;
|
|
gr_set_font(ResLock(WEAPONS_FONT));
|
|
|
|
if (newpage) {
|
|
gr_set_fcolor(dp->titlecolor);
|
|
get_string(REF_STR_WeaponTitle, buf, BUFSZ);
|
|
draw_inventory_string(buf, WEAPON_X, TOP_MARGIN, TRUE);
|
|
get_string(REF_STR_AmmoTitle, buf, BUFSZ);
|
|
draw_inventory_string(buf, AMMO_X - gr_string_width(buf), TOP_MARGIN, TRUE);
|
|
}
|
|
s = dp->relnum * WEAPONS_PER_PAGE;
|
|
y = TOP_MARGIN + Y_STEP;
|
|
for (i = 0; i < WEAPONS_PER_PAGE && s < NUM_WEAPON_SLOTS; i++, s++, y += Y_STEP) {
|
|
int num_ammo_types, dummy1;
|
|
ubyte dummy2[3];
|
|
uchar avail;
|
|
uchar newactive = weapon_list.active != player_struct.actives[ACTIVE_WEAPON];
|
|
uchar changed;
|
|
|
|
get_available_ammo_type(weapon_list.slots[s].type, weapon_list.slots[s].subtype, &num_ammo_types, dummy2,
|
|
&dummy1);
|
|
avail = (num_ammo_types > 0);
|
|
changed = newpage || (avail != weapon_list.ammo_available[s]) ||
|
|
memcmp(&weapon_list.slots[s], &player_struct.weapons[s], sizeof(weapon_slot)) != 0 ||
|
|
(newactive && s == weapon_list.active) || (newactive && s == player_struct.actives[ACTIVE_WEAPON]);
|
|
weapon_list.slots[s] = player_struct.weapons[s];
|
|
weapon_list.ammo_available[s] = avail;
|
|
if (!changed)
|
|
continue;
|
|
if (weapon_list.slots[s].type != EMPTY_WEAPON_SLOT) {
|
|
char name[BUFSZ];
|
|
char quant[BUFSZ];
|
|
weapon_name_func(dp, s, name);
|
|
weapon_quant_func(s, quant);
|
|
draw_quant_line(name, quant, dp->listcolor, s == player_struct.actives[ACTIVE_WEAPON], WEAPON_X, AMMO_X, y);
|
|
} else
|
|
clear_inventory_region(WEAPON_X, y, AMMO_X, y + Y_STEP);
|
|
}
|
|
weapon_list.active = player_struct.actives[ACTIVE_WEAPON];
|
|
ResUnlock(WEAPONS_FONT);
|
|
}
|
|
|
|
uchar inventory_select_weapon(inv_display *dp, int w) {
|
|
uchar retval = FALSE;
|
|
int aw = player_struct.actives[ACTIVE_WEAPON];
|
|
#ifndef NO_DUMMIES
|
|
inv_display *newdisp;
|
|
newdisp = dp;
|
|
#endif // NO_DUMMIES
|
|
if (player_struct.weapons[w].type == EMPTY_WEAPON_SLOT)
|
|
goto out;
|
|
if (aw != w) {
|
|
weapon_slot *ws = &player_struct.weapons[w];
|
|
play_digi_fx(SFX_INVENT_SELECT, 1);
|
|
change_selected_weapon(w);
|
|
player_struct.last_fire = 0;
|
|
player_struct.fire_rate = weapon_fire_rate(ws->type, ws->subtype);
|
|
}
|
|
player_struct.actives[ACTIVE_WEAPON] = w;
|
|
set_inventory_mfd(MFD_INV_WEAPON, w, TRUE);
|
|
set_inventory_mfd(MFD_INV_AMMO, 0, TRUE);
|
|
mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
|
|
INVENT_CHANGED;
|
|
retval = TRUE;
|
|
out:
|
|
return retval;
|
|
}
|
|
|
|
uchar weapon_use_func(inv_display *dp, int w) {
|
|
if (player_struct.weapons[w].type == EMPTY_WEAPON_SLOT)
|
|
return FALSE;
|
|
inventory_select_weapon(dp, w);
|
|
mfd_change_slot(mfd_grab_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT), MFD_WEAPON_SLOT);
|
|
return TRUE;
|
|
}
|
|
|
|
ubyte weapons_add_func(inv_display *dp, int row, ObjID *objP, uchar select) {
|
|
ubyte retval = ADD_REJECT;
|
|
ObjID obj = *objP;
|
|
weapon_slot *ws;
|
|
weapon_slot tmp;
|
|
ObjSpecID spec;
|
|
play_digi_fx(SFX_INVENT_ADD, 1);
|
|
row += dp->pgsize * dp->relnum;
|
|
if (player_struct.weapons[NUM_WEAPON_SLOTS - 1].type == EMPTY_WEAPON_SLOT)
|
|
row = NUM_WEAPON_SLOTS - 1;
|
|
if (row < 0 || row >= NUM_WEAPON_SLOTS || player_struct.weapons[row].type == EMPTY_WEAPON_SLOT) {
|
|
for (row = 0; row < NUM_WEAPON_SLOTS; row++)
|
|
if (player_struct.weapons[row].type == EMPTY_WEAPON_SLOT)
|
|
break;
|
|
if (row >= NUM_WEAPON_SLOTS) {
|
|
string_message_info(REF_STR_InvNoRoom);
|
|
return ADD_FAIL;
|
|
}
|
|
}
|
|
ws = &player_struct.weapons[row];
|
|
tmp = *ws;
|
|
spec = objs[obj].specID;
|
|
|
|
ws->type = objs[obj].subclass;
|
|
ws->subtype = objs[obj].info.type;
|
|
ws->ammo = objGuns[spec].ammo_count;
|
|
ws->ammo_type = objGuns[spec].ammo_type;
|
|
if (player_struct.actives[ACTIVE_WEAPON] == row)
|
|
set_inventory_mfd(MFD_INV_WEAPON, row, TRUE);
|
|
if (tmp.type != EMPTY_WEAPON_SLOT) {
|
|
objs[obj].subclass = tmp.type;
|
|
objs[obj].info.type = tmp.subtype;
|
|
objGuns[spec].ammo_type = tmp.ammo_type;
|
|
objGuns[spec].ammo_count = tmp.ammo;
|
|
retval = ADD_SWAP;
|
|
} else {
|
|
obj_destroy(obj);
|
|
retval = ADD_POP;
|
|
}
|
|
if (select)
|
|
inventory_select_weapon(dp, row);
|
|
|
|
if (player_struct.actives[ACTIVE_WEAPON] == row) {
|
|
set_inventory_mfd(MFD_INV_WEAPON, row, TRUE);
|
|
mfd_notify_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT, TRUE, MFD_ACTIVE, TRUE);
|
|
}
|
|
// in case ammo mfd
|
|
mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
|
|
|
|
void SetMotionCursorsColorForActiveWeapon(void);
|
|
SetMotionCursorsColorForActiveWeapon();
|
|
|
|
return retval;
|
|
}
|
|
|
|
void weapon_drop_func(inv_display *dp, int itemnum) {
|
|
weapon_slot *ws;
|
|
ObjID obj;
|
|
ObjSpecID spec;
|
|
int it;
|
|
|
|
if (itemnum < 0 || itemnum >= dp->listlen)
|
|
return;
|
|
ws = &player_struct.weapons[itemnum];
|
|
if (ws->type == EMPTY_WEAPON_SLOT)
|
|
return;
|
|
obj = obj_create_base(MAKETRIP(CLASS_GUN, ws->type, ws->subtype));
|
|
if (obj == OBJ_NULL) {
|
|
return;
|
|
}
|
|
spec = objs[obj].specID;
|
|
objGuns[spec].ammo_type = ws->ammo_type;
|
|
objGuns[spec].ammo_count = ws->ammo;
|
|
push_cursor_object(obj);
|
|
// preserve selected weapon.
|
|
if (itemnum < player_struct.actives[ACTIVE_WEAPON])
|
|
player_struct.actives[ACTIVE_WEAPON]--;
|
|
for (it = itemnum + 1; it < NUM_WEAPON_SLOTS; it++) {
|
|
player_struct.weapons[it - 1] = player_struct.weapons[it];
|
|
}
|
|
player_struct.weapons[NUM_WEAPON_SLOTS - 1].type = EMPTY_WEAPON_SLOT;
|
|
if (itemnum > 0 && player_struct.weapons[player_struct.actives[ACTIVE_WEAPON]].type == EMPTY_WEAPON_SLOT)
|
|
player_struct.actives[ACTIVE_WEAPON]--;
|
|
|
|
// in case ammo mfd
|
|
mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
|
|
// In case the weapons MFD was looking at that weapon, nix it
|
|
if (player_struct.weapons[player_struct.actives[ACTIVE_WEAPON]].type == EMPTY_WEAPON_SLOT)
|
|
mfd_notify_func(MFD_EMPTY_FUNC, MFD_WEAPON_SLOT, TRUE, MFD_EMPTY, TRUE);
|
|
else
|
|
set_inventory_mfd(MFD_INV_WEAPON, player_struct.actives[ACTIVE_WEAPON], TRUE);
|
|
INVENT_CHANGED;
|
|
|
|
void SetMotionCursorsColorForActiveWeapon(void);
|
|
SetMotionCursorsColorForActiveWeapon();
|
|
}
|
|
|
|
// -------------
|
|
// GENERIC FUNCS
|
|
// -------------
|
|
|
|
static char *generic_name_func(void *vdp, int num, char *buf) {
|
|
int trip = nth_after_triple(((inv_display *)vdp)->basetrip, num);
|
|
get_object_short_name(trip, buf, BUFSZ);
|
|
return buf;
|
|
}
|
|
|
|
static void generic_draw_list(inv_display *dp) {
|
|
uchar newpage = inv_last_page != inventory_page;
|
|
gr_set_font(ResLock(ITEM_FONT));
|
|
|
|
draw_quant_list(dp, newpage);
|
|
ResUnlock(ITEM_FONT);
|
|
}
|
|
|
|
ubyte generic_add_func(inv_display *dp, int row, ObjID *idP, uchar select) {
|
|
ObjID id = *idP;
|
|
int trip = ID2TRIP(id);
|
|
int n = OPTRIP(trip) - OPTRIP(dp->basetrip);
|
|
int obclass = objs[id].obclass;
|
|
#ifndef NO_DUMMIES
|
|
int guf;
|
|
guf = row;
|
|
#endif // NO_DUMMIES
|
|
play_digi_fx(SFX_INVENT_ADD, 1);
|
|
if (n >= 0 && n < dp->listlen) {
|
|
ubyte *quants = (ubyte *)&player_struct + dp->offset;
|
|
quants[n]++;
|
|
if (dp->activenum != NULL_ACTIVE) {
|
|
if (select) {
|
|
player_struct.actives[dp->activenum] = n;
|
|
play_digi_fx(SFX_INVENT_SELECT, 1);
|
|
}
|
|
if (select || n == player_struct.actives[dp->activenum])
|
|
set_inventory_mfd(dp->mfdtype, n, TRUE);
|
|
}
|
|
obj_destroy(id);
|
|
// This is a special-case hack for cartridges.
|
|
if (obclass == CLASS_AMMO) {
|
|
mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
|
|
mfd_notify_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT, FALSE, MFD_ACTIVE, TRUE);
|
|
INVENT_CHANGED;
|
|
}
|
|
return ADD_POP;
|
|
}
|
|
return ADD_REJECT;
|
|
}
|
|
|
|
void generic_drop_func(inv_display *dp, int row) {
|
|
int itemnum = dp->lines[row].num;
|
|
ObjID obj;
|
|
int triple;
|
|
ubyte *quant;
|
|
if (itemnum < 0 || itemnum >= dp->listlen)
|
|
return;
|
|
quant = (ubyte *)&player_struct + dp->offset;
|
|
if (quant[itemnum] == 0)
|
|
return;
|
|
quant[itemnum]--;
|
|
triple = nth_after_triple(dp->basetrip, itemnum);
|
|
obj = obj_create_base(triple);
|
|
if (obj == OBJ_NULL) {
|
|
return;
|
|
}
|
|
push_cursor_object(obj);
|
|
if (dp->activenum != NULL_ACTIVE && player_struct.actives[dp->activenum] == itemnum && quant[itemnum] == 0) {
|
|
player_struct.actives[dp->activenum] = 0xFF;
|
|
set_inventory_mfd(dp->mfdtype, MFD_INV_NOTYPE, FALSE);
|
|
}
|
|
INVENT_CHANGED;
|
|
}
|
|
|
|
static char *generic_quant_func(inv_display *dp, int n, int q, char *buf) {
|
|
#ifndef NO_DUMMIES
|
|
char *dummy;
|
|
dummy = n + (char*)dp;
|
|
#endif // NO_DUMMIES
|
|
// itoa(q,buf,10);
|
|
sprintf(buf, "%d", q);
|
|
return buf;
|
|
}
|
|
|
|
char *null_name_func(inv_display *dp, int n, char *buf) {
|
|
#ifndef NO_DUMMIES
|
|
char *goof;
|
|
goof = (char*)dp + n;
|
|
#endif // NO_DUMMIES
|
|
*buf = '\0';
|
|
return buf;
|
|
}
|
|
|
|
// -------------
|
|
// GRENADE FUNCS
|
|
// -------------
|
|
|
|
#define GREN_CLASSES (1 << CLASS_GRENADE)
|
|
#define GREN_TRIP MAKETRIP(CLASS_GRENADE, 0, 0)
|
|
|
|
static char *grenade_name_func(void *dp, int n, char *buf) { return get_grenade_name(n, buf); }
|
|
|
|
extern uiSlab fullscreen_slab;
|
|
extern uiSlab main_slab;
|
|
|
|
grs_bitmap grenade_bmap;
|
|
#ifdef SVGA_SUPPORT
|
|
char grenade_bmap_buffer[8700];
|
|
#else
|
|
char grenade_bmap_buffer[700];
|
|
#endif
|
|
|
|
void push_live_grenade_cursor(ObjID obj) {
|
|
short w, h;
|
|
extern LGCursor object_cursor;
|
|
char live_string[22];
|
|
#ifdef CURSOR_BACKUPS
|
|
extern grs_bitmap backup_object_cursor;
|
|
extern uchar *backup[NUM_BACKUP_BITS];
|
|
#endif
|
|
#ifdef SVGA_SUPPORT
|
|
uchar old_over = gr2ss_override;
|
|
short temp;
|
|
#endif
|
|
grs_canvas cursor_canvas;
|
|
LGPoint hotspot;
|
|
grs_bitmap *bmap = bitmaps_2d[OPNUM(obj)];
|
|
void *bits = grenade_bmap_buffer;
|
|
|
|
grenade_bmap = *bmap;
|
|
gr_set_font(ResLock(ITEM_FONT));
|
|
get_string(REF_STR_WordLiveGrenade, live_string, sizeof(live_string));
|
|
gr_string_size(live_string, &w, &h);
|
|
w++;
|
|
h++; // compensate for shadowing
|
|
#ifdef SVGA_SUPPORT
|
|
gr2ss_override = OVERRIDE_ALL;
|
|
ss_set_hack_mode(2, &temp);
|
|
if (convert_use_mode != 0) {
|
|
grenade_bmap.w = lg_max(bmap->w, w);
|
|
grenade_bmap.h = bmap->h + h;
|
|
grenade_bmap.w = SCONV_X(grenade_bmap.w);
|
|
grenade_bmap.h = SCONV_Y(grenade_bmap.h);
|
|
} else {
|
|
#endif
|
|
grenade_bmap.w = lg_max(bmap->w, w);
|
|
grenade_bmap.h = bmap->h + h;
|
|
#ifdef SVGA_SUPPORT
|
|
}
|
|
#endif
|
|
// mprintf("bsize = %d, w * h = %d\n",sizeof(grenade_bmap_buffer), grenade_bmap.w * grenade_bmap.h);
|
|
if (sizeof(grenade_bmap_buffer) < grenade_bmap.w * grenade_bmap.h)
|
|
critical_error(0x3006);
|
|
|
|
gr_init_bitmap(&grenade_bmap, (uchar *)bits, grenade_bmap.type, grenade_bmap.flags, grenade_bmap.w, grenade_bmap.h);
|
|
gr_init_canvas(&cursor_canvas, (uchar *)bits, BMT_FLAT8, grenade_bmap.w, grenade_bmap.h);
|
|
gr_push_canvas(&cursor_canvas);
|
|
gr_set_font(ResGet(ITEM_FONT));
|
|
gr_clear(0);
|
|
#ifdef SVGA_SUPPORT
|
|
if (convert_use_mode > 0) {
|
|
ss_bitmap(bmap, (INV_SCONV_X(grenade_bmap.w) - bmap->w) / 2, 0);
|
|
gr_set_fcolor(0x4c);
|
|
draw_shadowed_string(live_string, (INV_SCONV_X(grenade_bmap.w) - w) / 2, INV_SCONV_Y(grenade_bmap.h) - h, TRUE);
|
|
} else {
|
|
#endif
|
|
ss_bitmap(bmap, (grenade_bmap.w - bmap->w) / 2, 0);
|
|
gr_set_fcolor(0x4c);
|
|
draw_shadowed_string(live_string, (grenade_bmap.w - w) / 2 + 1, grenade_bmap.h - h, TRUE);
|
|
#ifdef SVGA_SUPPORT
|
|
}
|
|
#endif
|
|
ResUnlock(ITEM_FONT);
|
|
gr_pop_canvas();
|
|
#ifdef SVGA_SUPPORT
|
|
ss_set_hack_mode(0, &temp);
|
|
gr2ss_override = old_over;
|
|
if (convert_use_mode != 0) {
|
|
hotspot.x = grenade_bmap.w / 2;
|
|
hotspot.y = grenade_bmap.h / 2;
|
|
} else {
|
|
#endif
|
|
hotspot.x = grenade_bmap.w / 2;
|
|
hotspot.y = grenade_bmap.h / 2;
|
|
#ifdef SVGA_SUPPORT
|
|
}
|
|
#endif
|
|
uiHideMouse(NULL);
|
|
uiMakeBitmapCursor(&object_cursor, &grenade_bmap, hotspot);
|
|
uiPushSlabCursor(&fullscreen_slab, &object_cursor);
|
|
uiPushSlabCursor(&main_slab, &object_cursor);
|
|
uiShowMouse(NULL);
|
|
object_on_cursor = obj;
|
|
input_cursor_mode = INPUT_OBJECT_CURSOR;
|
|
}
|
|
|
|
uchar grenade_use_func(inv_display *dp, int row) {
|
|
int itemnum = dp->lines[row].num;
|
|
ObjID obj;
|
|
int triple;
|
|
ubyte *quant;
|
|
ObjSpecID spec;
|
|
if (itemnum < 0 || itemnum >= dp->listlen)
|
|
return (FALSE);
|
|
quant = (ubyte *)&player_struct + dp->offset;
|
|
if (quant[itemnum] == 0)
|
|
return (FALSE);
|
|
quant[itemnum]--;
|
|
triple = nth_after_triple(dp->basetrip, itemnum);
|
|
obj = obj_create_base(triple);
|
|
if (obj == OBJ_NULL) {
|
|
return (FALSE);
|
|
}
|
|
if (dp->activenum != NULL_ACTIVE && player_struct.actives[dp->activenum] == itemnum && quant[itemnum] == 0) {
|
|
player_struct.actives[dp->activenum] = 0xFF;
|
|
set_inventory_mfd(dp->mfdtype, MFD_INV_NOTYPE, FALSE);
|
|
}
|
|
INVENT_CHANGED;
|
|
push_live_grenade_cursor(obj);
|
|
spec = objs[obj].specID;
|
|
activate_grenade(spec);
|
|
return (TRUE);
|
|
}
|
|
|
|
ubyte grenade_add_func(inv_display *dp, int row, ObjID *idP, uchar select) {
|
|
ObjSpecID sid = objs[*idP].specID;
|
|
play_digi_fx(SFX_INVENT_ADD, 1);
|
|
if (objGrenades[sid].flags & GREN_ACTIVE_FLAG) {
|
|
string_message_info(REF_STR_InvLiveGrenade);
|
|
return ADD_FAIL;
|
|
}
|
|
return generic_add_func(dp, row, idP, select);
|
|
}
|
|
|
|
// ----------
|
|
// DRUG FUNCS
|
|
// ----------
|
|
#define DRUG_CLASSES (1 << CLASS_DRUG)
|
|
#define DRUG_TRIP MAKETRIP(CLASS_DRUG, 0, 0)
|
|
|
|
char *drug_name_func(inv_display *dp, int n, char *buf) {
|
|
#ifndef NO_DUMMIES
|
|
inv_display *dummy;
|
|
dummy = dp;
|
|
#endif // NO_DUMMIES
|
|
return get_drug_name(n, buf);
|
|
}
|
|
|
|
uchar drug_use_func(inv_display *dp, int row) {
|
|
uchar retval = FALSE;
|
|
int n = dp->lines[row].num;
|
|
if (n < dp->listlen) {
|
|
drug_use(n);
|
|
set_inventory_mfd(dp->mfdtype, n, TRUE);
|
|
retval = TRUE;
|
|
INVENT_CHANGED;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
// ----------
|
|
// AMMO FUNCS
|
|
// ----------
|
|
#define AMMO_CLASSES (1 << CLASS_AMMO)
|
|
#define AMMO_TRIP MAKETRIP(CLASS_AMMO, 0, 0)
|
|
|
|
char *ammo_name_func(void *dp, int n, char *buf) {
|
|
int triple;
|
|
|
|
buf[0] = AMMO_TYPE_LETTER(n);
|
|
buf[1] = ' ';
|
|
triple = get_triple_from_class_nth_item(CLASS_AMMO, n);
|
|
get_object_short_name(triple, buf + 2, 31);
|
|
return buf;
|
|
}
|
|
|
|
// ---------
|
|
// HARDWARES
|
|
// ---------
|
|
#define HARD_CLASSES (1 << CLASS_HARDWARE)
|
|
#define HARD_TRIP MAKETRIP(CLASS_HARDWARE, 0, 0)
|
|
#define HARDWARE_PAGES 2
|
|
|
|
static char *ware_name_func(void *vdp, int n, char *buf) {
|
|
int type;
|
|
switch (((inv_display *)vdp)->activenum) {
|
|
case ACTIVE_HARDWARE:
|
|
type = WARE_HARD;
|
|
break;
|
|
case ACTIVE_COMBAT_SOFT:
|
|
type = WARE_SOFT_COMBAT;
|
|
break;
|
|
case ACTIVE_DEFENSE_SOFT:
|
|
type = WARE_SOFT_DEFENSE;
|
|
break;
|
|
case ACTIVE_MISC_SOFT:
|
|
type = WARE_SOFT_MISC;
|
|
break;
|
|
}
|
|
get_ware_name(type, n, buf, BUFSZ);
|
|
return NULL;
|
|
}
|
|
|
|
static uchar ware_use_func(inv_display *dp, int row) {
|
|
int waretype;
|
|
int t = dp->lines[row].num;
|
|
if (t >= dp->listlen)
|
|
return FALSE;
|
|
switch (dp->activenum) {
|
|
case ACTIVE_HARDWARE:
|
|
waretype = WARE_HARD;
|
|
break;
|
|
case ACTIVE_COMBAT_SOFT:
|
|
waretype = WARE_SOFT_COMBAT;
|
|
break;
|
|
case ACTIVE_DEFENSE_SOFT:
|
|
waretype = WARE_SOFT_DEFENSE;
|
|
break;
|
|
case ACTIVE_MISC_SOFT:
|
|
waretype = WARE_SOFT_MISC;
|
|
break;
|
|
}
|
|
use_ware(waretype, t);
|
|
return TRUE;
|
|
}
|
|
|
|
void hardware_add_specials(int n, int ver) {
|
|
extern WARE HardWare[NUM_HARDWAREZ];
|
|
switch (n) {
|
|
case HARDWARE_AUTOMAP:
|
|
mfd_notify_func(MFD_MAP_FUNC, MFD_MAP_SLOT, TRUE, MFD_ACTIVE, TRUE);
|
|
{
|
|
int i;
|
|
for (i = 0; i < NUM_O_AMAP; i++)
|
|
amap_version_set(i, player_struct.hardwarez[HARDWARE_AUTOMAP]);
|
|
}
|
|
break;
|
|
case HARDWARE_TARGET:
|
|
mfd_notify_func(MFD_TARGET_FUNC, MFD_TARGET_SLOT, TRUE, MFD_ACTIVE, TRUE);
|
|
break;
|
|
case HARDWARE_SHIELD: {
|
|
int ener = 0;
|
|
if (WareActive(player_struct.hardwarez_status[CPTRIP(SHIELD_HARD_TRIPLE)]))
|
|
ener = energy_cost(CPTRIP(SHIELD_HARD_TRIPLE));
|
|
SHIELD_SETTING_SET(player_struct.hardwarez_status[n], ver - 1);
|
|
if (ener) {
|
|
shield_set_absorb();
|
|
ener = energy_cost(CPTRIP(SHIELD_HARD_TRIPLE)) - ener;
|
|
set_player_energy_spend(lg_min(MAX_ENERGY, player_struct.energy_spend + ener));
|
|
}
|
|
mfd_notify_func(MFD_SHIELD_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
|
|
} break;
|
|
case HARDWARE_ENVIROSUIT: {
|
|
if (_current_loop == GAME_LOOP)
|
|
gamescr_bio_func();
|
|
zoom_to_lean_meter();
|
|
} break;
|
|
// Flash the email sideicon the first time you pick up the data reader to tell the player he has a log.
|
|
// After that, it is never flashed again if a new log is picked up.
|
|
case HARDWARE_EMAIL:
|
|
player_struct.hardwarez_status[HARDWARE_EMAIL] |= WARE_FLASH;
|
|
QUESTBIT_ON(0x12c);
|
|
break;
|
|
}
|
|
if (HardWare[n].sideicon != SI_NONE) {
|
|
LGPoint from;
|
|
ui_mouse_get_xy(&from.x, &from.y);
|
|
zoom_to_side_icon(from, HardWare[n].sideicon);
|
|
}
|
|
}
|
|
|
|
ubyte ware_add_func(inv_display *dp, int nn, ObjID *idP, uchar select) {
|
|
ObjID id = *idP;
|
|
int trip = ID2TRIP(id);
|
|
uchar oneshot;
|
|
uchar bigstuff_fake = FALSE;
|
|
int n;
|
|
extern uchar shameful_obselete_flag;
|
|
|
|
if (global_fullmap->cyber && (objs[id].obclass == CLASS_BIGSTUFF)) {
|
|
bigstuff_fake = TRUE;
|
|
trip = MAKETRIP(CLASS_SOFTWARE, objBigstuffs[objs[id].specID].data1, objBigstuffs[objs[id].specID].data2);
|
|
}
|
|
n = OPTRIP(trip) - OPTRIP(dp->basetrip);
|
|
oneshot = TRIP2CL(trip) == CLASS_SOFTWARE && TRIP2SC(trip) == SOFTWARE_SUBCLASS_ONESHOT;
|
|
if (TRIP2CL(trip) == CLASS_SOFTWARE && TRIP2SC(trip) == SOFTWARE_SUBCLASS_DATA)
|
|
return ADD_REJECT;
|
|
if (n >= 0 && n < dp->listlen) {
|
|
ubyte ver;
|
|
ubyte *quants = (ubyte *)&player_struct + dp->offset;
|
|
if (bigstuff_fake)
|
|
ver = objBigstuffs[objs[id].specID].cosmetic_value;
|
|
else
|
|
ver = (TRIP2CL(trip) == CLASS_HARDWARE) ? objHardwares[objs[id].specID].version
|
|
: objSoftwares[objs[id].specID].version;
|
|
|
|
if (trip == GAMES_TRIPLE)
|
|
quants[n] |= ver;
|
|
else if (oneshot)
|
|
quants[n]++;
|
|
else if (quants[n] >= ver) {
|
|
string_message_info(REF_STR_AlreadyHaveOne);
|
|
shameful_obselete_flag = TRUE;
|
|
return ADD_NOEFFECT;
|
|
} else
|
|
quants[n] = ver;
|
|
|
|
play_digi_fx(SFX_INVENT_WARE, 1);
|
|
if (select) {
|
|
player_struct.actives[dp->activenum] = n;
|
|
}
|
|
if (select || n == player_struct.actives[dp->activenum])
|
|
set_inventory_mfd(dp->mfdtype, n, TRUE);
|
|
obj_destroy(id);
|
|
|
|
// Tell the side icons that things may no longer be what they were
|
|
// side_icon_expose_all();
|
|
|
|
// If we picked up an automapper unit, let mfd slot know
|
|
if (TRIP2CL(trip) == CLASS_HARDWARE) {
|
|
hardware_add_specials(n, ver);
|
|
}
|
|
return ADD_POP;
|
|
}
|
|
return ADD_REJECT;
|
|
}
|
|
|
|
void ware_drop_func(inv_display *dp, int n) {
|
|
#ifndef GAMEONLY
|
|
int itemnum = dp->lines[row].num;
|
|
ObjID obj;
|
|
int triple;
|
|
uchar oneshot;
|
|
ubyte *quant;
|
|
extern int nth_after_triple(int, uchar);
|
|
if (itemnum < 0 || itemnum >= dp->listlen)
|
|
return;
|
|
quant = (ubyte *)&player_struct + dp->offset;
|
|
if (quant[itemnum] == 0)
|
|
return;
|
|
triple = nth_after_triple(dp->basetrip, itemnum);
|
|
oneshot = TRIP2CL(triple) == CLASS_SOFTWARE && TRIP2SC(triple) == SOFTWARE_SUBCLASS_ONESHOT;
|
|
obj = obj_create_base(triple);
|
|
if (obj == OBJ_NULL) {
|
|
return;
|
|
}
|
|
if (dp->mfdtype == MFD_INV_HARDWARE)
|
|
objHardwares[objs[obj].specID].version = quant[itemnum];
|
|
else
|
|
objSoftwares[objs[obj].specID].version = quant[itemnum];
|
|
// If the ware was on, turn it off
|
|
if ((dp->mfdtype == MFD_INV_HARDWARE) && (player_struct.hardwarez_status[itemnum] & WARE_ON))
|
|
use_ware(WARE_HARD, itemnum); // actually toggles, not uses
|
|
if (oneshot)
|
|
quant[itemnum]--;
|
|
else
|
|
quant[itemnum] = 0;
|
|
push_cursor_object(obj);
|
|
if (player_struct.actives[dp->activenum] == itemnum) {
|
|
player_struct.actives[dp->activenum] = 0xFF;
|
|
// Tell the item mfd that what it was looking at may no longer be there
|
|
set_inventory_mfd(dp->mfdtype, MFD_INV_NOTYPE, FALSE);
|
|
}
|
|
INVENT_CHANGED;
|
|
|
|
// Tell the side icons that things are no longer what they were
|
|
side_icon_expose_all();
|
|
|
|
mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
|
|
|
|
// If we no longer have an automapper, let the mfd know
|
|
if (player_struct.hardwarez[HARDWARE_AUTOMAP] == 0)
|
|
mfd_notify_func(MFD_EMPTY_FUNC, MFD_MAP_SLOT, TRUE, MFD_EMPTY, TRUE);
|
|
#endif // !GAME_ONLY
|
|
}
|
|
|
|
char *null_quant_func(inv_display *dp, int n, int q, char *buf) {
|
|
*buf = '\0';
|
|
return buf;
|
|
}
|
|
|
|
// -----
|
|
// SOFTS
|
|
// -----
|
|
|
|
#define SOFT_PAGES 2
|
|
#define SOFT_CLASSES (1 << CLASS_SOFTWARE)
|
|
#define COMSOFT_TRIP MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_OFFENSE, 0)
|
|
#define DEFSOFT_TRIP MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_DEFENSE, 0)
|
|
#define MISCSOFT_TRIP MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_ONESHOT, 0)
|
|
|
|
#define VERSION_PREFIX (get_temp_string(REF_STR_VersionPrefix)[0])
|
|
|
|
// QUANTS *******************************
|
|
static char *soft_quant_func(inv_display *dp, int n, int q, char *buf) {
|
|
int l = 1;
|
|
buf[0] = VERSION_PREFIX;
|
|
if (q < 10)
|
|
buf[l++] = q + '0';
|
|
buf[l] = '\0';
|
|
return buf;
|
|
}
|
|
|
|
// COMPUTRON SUPPORT
|
|
|
|
#define CTRON_WD 10
|
|
|
|
#ifdef COMPUTRONS
|
|
char *computron_quant_func(inv_display *dp, int n, int q, char *buf) {
|
|
#ifdef REALLY_DO_COMPUTRONS
|
|
ubyte exists, ctrons;
|
|
|
|
switch (dp->mfdtype) {
|
|
case MFD_INV_SOFT_COMBAT:
|
|
exists = player_struct.softs.combat[n];
|
|
ctrons = player_struct.softs_ctrons.combat[n];
|
|
break;
|
|
case MFD_INV_SOFT_DEFENSE:
|
|
exists = player_struct.softs.defense[n];
|
|
ctrons = player_struct.softs_ctrons.defense[n];
|
|
break;
|
|
case MFD_INV_SOFT_MISC:
|
|
exists = player_struct.softs.misc[n];
|
|
ctrons = player_struct.softs_ctrons.misc[n];
|
|
break;
|
|
}
|
|
if (exists == 0 || ctrons == 0)
|
|
*buf = '\0';
|
|
else
|
|
itoa(ctrons, buf, 10);
|
|
#endif
|
|
*buf = '\0';
|
|
return buf;
|
|
}
|
|
#endif // COMPUTRONS
|
|
|
|
// ------------------------------
|
|
// GENERAL INVENTORY -- FUN! FUN!
|
|
// ------------------------------
|
|
|
|
#define GENERAL_CLASSES 0xFFFFFF80
|
|
static ObjID general_lines[NUM_GENERAL_SLOTS];
|
|
|
|
#define GARBAGE_COLOR TITLE_COLOR
|
|
|
|
void draw_general_list(inv_display *dp) {
|
|
uchar newpage = inv_last_page != inventory_page;
|
|
char buf[BUFSZ];
|
|
int i, s;
|
|
short y;
|
|
ubyte active = player_struct.actives[dp->activenum];
|
|
ubyte known_active = known_actives[dp->activenum];
|
|
uchar newactive = known_active != active;
|
|
|
|
gr_set_font(ResLock(ITEM_FONT));
|
|
|
|
if (newpage) {
|
|
gr_set_fcolor(dp->titlecolor);
|
|
get_string(dp->titlenum, buf, BUFSZ);
|
|
draw_inventory_string(buf, dp->left, dp->top, TRUE);
|
|
}
|
|
s = dp->relnum * dp->pgsize;
|
|
y = dp->top + Y_STEP;
|
|
for (i = 0; i < dp->pgsize && s < dp->listlen; i++, s++, y += Y_STEP) {
|
|
uchar curractive = player_struct.current_active == dp->activenum;
|
|
uchar changed = newpage || general_lines[s] != player_struct.inventory[s] || newactive;
|
|
general_lines[s] = player_struct.inventory[s];
|
|
if (!changed)
|
|
continue;
|
|
if (general_lines[s] != OBJ_NULL) {
|
|
ulong color = dp->listcolor;
|
|
char name[BUFSZ];
|
|
get_object_short_name(ID2TRIP(general_lines[s]), name, BUFSZ);
|
|
if (!(ObjProps[OPNUM(general_lines[s])].flags & INVENTORY_GENERAL))
|
|
color = GARBAGE_COLOR;
|
|
draw_quant_line(name, "", color, s == active && curractive, dp->left, dp->right, y);
|
|
} else
|
|
clear_inventory_region(dp->left, y, dp->right, y + Y_STEP);
|
|
}
|
|
ResUnlock(ITEM_FONT);
|
|
}
|
|
|
|
uchar general_use_func(inv_display *dp, int row) {
|
|
ObjID id = player_struct.inventory[row];
|
|
if (id == OBJ_NULL)
|
|
return FALSE;
|
|
if (ObjProps[OPNUM(id)].flags & OBJECT_USE_NOCURSOR) {
|
|
object_use(id, TRUE, object_on_cursor);
|
|
// only change mfd if using object did not destroy it.
|
|
if (player_struct.current_active == dp->activenum && row <= player_struct.actives[dp->activenum])
|
|
set_inventory_mfd(dp->mfdtype, row, TRUE);
|
|
if (player_struct.inventory[row] == id) {
|
|
set_inventory_mfd(dp->mfdtype, row, TRUE);
|
|
mfd_change_slot(mfd_grab_func(MFD_ITEM_FUNC, MFD_ITEM_SLOT), MFD_ITEM_SLOT);
|
|
}
|
|
} else if (dp->drop != NULL)
|
|
dp->drop(dp, row);
|
|
return TRUE;
|
|
}
|
|
|
|
ubyte inv_empty_trash(void) {
|
|
uchar found = FALSE;
|
|
ubyte non_trash = 0;
|
|
ubyte trash;
|
|
ubyte last_trash = NUM_GENERAL_SLOTS;
|
|
// find the first trash object
|
|
for (trash = 0; trash < NUM_GENERAL_SLOTS; trash++) {
|
|
ObjID id = player_struct.inventory[trash];
|
|
if (id != OBJ_NULL && !(ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL)) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
return last_trash;
|
|
// find the next non-trash object
|
|
for (non_trash = trash; non_trash < NUM_GENERAL_SLOTS; non_trash++) {
|
|
ObjID id = player_struct.inventory[non_trash];
|
|
if (id != OBJ_NULL && (ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL))
|
|
break;
|
|
}
|
|
// iterate through, destroying trash.
|
|
for (; trash < NUM_GENERAL_SLOTS; trash++) {
|
|
ObjID id = player_struct.inventory[trash];
|
|
uchar is_trash = !(ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL);
|
|
if (is_trash)
|
|
obj_destroy(id);
|
|
if (is_trash || id == OBJ_NULL) {
|
|
if (non_trash < NUM_GENERAL_SLOTS) {
|
|
player_struct.inventory[trash] = player_struct.inventory[non_trash];
|
|
player_struct.inventory[non_trash] = OBJ_NULL;
|
|
for (; non_trash < NUM_GENERAL_SLOTS; non_trash++) {
|
|
ObjID id = player_struct.inventory[non_trash];
|
|
if (id != OBJ_NULL && (ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL))
|
|
break;
|
|
}
|
|
} else {
|
|
player_struct.inventory[trash] = OBJ_NULL;
|
|
last_trash = lg_min(last_trash, trash);
|
|
}
|
|
}
|
|
}
|
|
return last_trash;
|
|
}
|
|
|
|
ubyte add_access_card(inv_display *dp, ObjID *idP, uchar select) {
|
|
ubyte retval = ADD_NOEFFECT;
|
|
int i, d1, old_d1, gain;
|
|
ObjID cards;
|
|
for (i = 0; i < dp->listlen; i++) {
|
|
if (ID2TRIP(player_struct.inventory[i]) == GENCARDS_TRIPLE || player_struct.inventory[i] == OBJ_NULL)
|
|
break;
|
|
}
|
|
if (i >= dp->listlen)
|
|
i = inv_empty_trash();
|
|
if (i >= dp->listlen)
|
|
return ADD_FAIL;
|
|
|
|
// Extract the data out of the old card, so that we can copy it
|
|
// correctly into the new set of cards. Destroy the old one first
|
|
// so that if we are right on the border of number of cards available
|
|
// in the universe, we don't die.
|
|
d1 = objSmallstuffs[objs[*idP].specID].data1;
|
|
obj_destroy(*idP);
|
|
|
|
if (player_struct.inventory[i] == OBJ_NULL) {
|
|
cards = obj_create_base(GENCARDS_TRIPLE);
|
|
if (cards == OBJ_NULL)
|
|
return ADD_FAIL;
|
|
player_struct.inventory[i] = cards;
|
|
retval = ADD_POP;
|
|
} else
|
|
cards = player_struct.inventory[i];
|
|
old_d1 = objSmallstuffs[objs[cards].specID].data1;
|
|
objSmallstuffs[objs[cards].specID].data1 |= d1;
|
|
if (select && dp->select != NULL)
|
|
dp->select(dp, i);
|
|
gain = d1 & (~old_d1);
|
|
if (gain == 0)
|
|
string_message_info(REF_STR_AccessCardNoGain);
|
|
else {
|
|
char gainbuf[80], bitname[16];
|
|
int l, bitgot;
|
|
|
|
get_string(REF_STR_AccessCardNewGain, gainbuf, 80);
|
|
l = strlen(gainbuf);
|
|
|
|
bitgot = 0;
|
|
while (gain != 0) {
|
|
if (gain & 1) {
|
|
get_string(MKREF(RES_accessCards, bitgot << 1), bitname, sizeof(bitname));
|
|
if (l + strlen(bitname) + 1 < 80) {
|
|
strcat(gainbuf, bitname);
|
|
strcat(gainbuf, " ");
|
|
l += strlen(bitname) + 1;
|
|
}
|
|
}
|
|
gain = gain >> 1;
|
|
bitgot = bitgot + 1;
|
|
}
|
|
gainbuf[l] = '\0';
|
|
|
|
message_info(gainbuf);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
ubyte general_add_func(inv_display *dp, int row, ObjID *idP, uchar select) {
|
|
play_digi_fx(SFX_INVENT_ADD, 1);
|
|
if ((objs[*idP].obclass == CLASS_SMALLSTUFF) &&
|
|
((objs[*idP].subclass == SMALLSTUFF_SUBCLASS_CARDS) || (ID2TRIP(*idP) == CYBERCARD_TRIPLE)))
|
|
return add_access_card(dp, idP, select);
|
|
if (player_struct.inventory[NUM_GENERAL_SLOTS - 1] == OBJ_NULL)
|
|
row = NUM_GENERAL_SLOTS - 1;
|
|
if (row < 0 || row >= dp->listlen || player_struct.inventory[row] == OBJ_NULL)
|
|
for (row = 0; row < dp->listlen; row++)
|
|
if (player_struct.inventory[row] == OBJ_NULL)
|
|
break;
|
|
if (row >= dp->listlen)
|
|
row = inv_empty_trash();
|
|
if (row >= dp->listlen)
|
|
return ADD_NOROOM;
|
|
else {
|
|
ObjID tmp = player_struct.inventory[row];
|
|
// if we're trying to swap with the "access cards" object,
|
|
// use the next object instead. Since there's only one "access cards"
|
|
// object, this works.
|
|
if (ID2TRIP(tmp) == GENCARDS_TRIPLE) {
|
|
row = (row + 1) % dp->listlen;
|
|
tmp = player_struct.inventory[row];
|
|
}
|
|
player_struct.inventory[row] = *idP;
|
|
if (select && dp->select != NULL)
|
|
dp->select(dp, row);
|
|
if (tmp != OBJ_NULL && ID2TRIP(tmp) != GENCARDS_TRIPLE) {
|
|
*idP = tmp;
|
|
return ADD_SWAP;
|
|
}
|
|
return ADD_POP;
|
|
}
|
|
}
|
|
|
|
void remove_general_item(ObjID obj) {
|
|
int row;
|
|
int i;
|
|
|
|
for (row = 0; row < NUM_GENERAL_SLOTS; row++)
|
|
if (player_struct.inventory[row] == obj)
|
|
break;
|
|
if (row >= NUM_GENERAL_SLOTS)
|
|
return;
|
|
for (i = row + 1; i < NUM_GENERAL_SLOTS; i++)
|
|
player_struct.inventory[i - 1] = player_struct.inventory[i];
|
|
player_struct.inventory[NUM_GENERAL_SLOTS - 1] = OBJ_NULL;
|
|
|
|
// Turn off any active gear when it leaves our inventory.
|
|
switch (ID2TRIP(obj)) {
|
|
case TRACBEAM_TRIPLE:
|
|
if (objs[obj].info.inst_flags & CLASS_INST_FLAG)
|
|
obj_tractor_beam_func(obj, FALSE);
|
|
break;
|
|
}
|
|
if (player_struct.current_active == ACTIVE_GENERAL)
|
|
set_inventory_mfd(MFD_INV_GENINV, player_struct.actives[ACTIVE_GENERAL], TRUE);
|
|
mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
|
|
// Redraw the panel, or setup thereof
|
|
INVENT_CHANGED;
|
|
}
|
|
|
|
void general_drop_func(inv_display *dp, int row) {
|
|
ObjID obj = player_struct.inventory[row];
|
|
if (obj != OBJ_NULL && ID2TRIP(obj) != GENCARDS_TRIPLE) // don't let us drop access cards.
|
|
{
|
|
// Put on cursor...
|
|
push_cursor_object(obj);
|
|
remove_general_item(obj);
|
|
}
|
|
}
|
|
|
|
uchar inv_select_general(inv_display *dp, int w) {
|
|
uchar retval = FALSE;
|
|
if (player_struct.inventory[w] == OBJ_NULL)
|
|
goto out;
|
|
player_struct.actives[dp->activenum] = w;
|
|
set_inventory_mfd(dp->mfdtype, w, TRUE);
|
|
INVENT_CHANGED;
|
|
retval = TRUE;
|
|
out:
|
|
return retval;
|
|
}
|
|
|
|
// -----
|
|
// EMAIL
|
|
// -----
|
|
|
|
#define EMAIL_TRIP 0 // MAKETRIP(CLASS_SOFTWARE,SOFTWARE_SUBCLASS_EMAIL,0)
|
|
|
|
#define FIRST_DATA (NUM_EMAIL - NUM_DATA)
|
|
#define MORE_COLOR SELECTED_ITEM_COLOR
|
|
|
|
static uchar email_morebuttons[2];
|
|
|
|
void email_more_draw(inv_display *dp) {
|
|
gr_set_font(ResLock(ITEM_FONT));
|
|
|
|
if (dp->relnum % 2 == 1) {
|
|
int i;
|
|
int count = 0;
|
|
for (i = 0; i < NUM_EMAIL_PROPER; i++)
|
|
if (player_struct.email[i])
|
|
count++;
|
|
if (count > (dp->relnum + 1) * dp->pgsize) {
|
|
short y = dp->top + Y_STEP;
|
|
char buf[50];
|
|
get_string(REF_STR_EmailMoreRight, buf, sizeof(buf));
|
|
draw_quant_line("", buf, MORE_COLOR, FALSE, dp->left, dp->right, y);
|
|
email_morebuttons[1] = TRUE;
|
|
} else
|
|
email_morebuttons[1] = FALSE;
|
|
} else if (dp->relnum != 0) {
|
|
short y = dp->top + Y_STEP;
|
|
char buf[50];
|
|
get_string(REF_STR_EmailMoreLeft, buf, sizeof(buf));
|
|
draw_quant_line(buf, "", MORE_COLOR, FALSE, dp->left, dp->right, y);
|
|
email_morebuttons[0] = TRUE;
|
|
} else
|
|
email_morebuttons[0] = FALSE;
|
|
ResUnlock(ITEM_FONT);
|
|
}
|
|
|
|
uchar email_more_use(inv_display *dp, int w) {
|
|
uchar retval = FALSE;
|
|
if (dp->relnum != 0 && email_morebuttons[dp->relnum % 2]) {
|
|
int newpage = (dp->relnum % 2 == 0) ? inventory_page - 1 : inventory_page + 1;
|
|
inventory_page = newpage;
|
|
INVENT_CHANGED;
|
|
retval = TRUE;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
#define EMAIL_BASE_ID RES_email0
|
|
#define TITLE_IDX 1
|
|
|
|
uchar email_use_func(inv_display *dp, int row) {
|
|
uchar retval = FALSE;
|
|
int n = dp->lines[row].num;
|
|
|
|
if (n < dp->listlen) {
|
|
read_email(EMAIL_BASE_ID, n);
|
|
retval = TRUE;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void email_select_func(inv_display *dp, int row) {
|
|
int n = dp->lines[row].num;
|
|
if (n < dp->listlen) {
|
|
play_digi_fx(SFX_INVENT_SELECT, 1);
|
|
select_email(n, TRUE);
|
|
}
|
|
}
|
|
|
|
void add_email_datamunge(short mung, uchar select) {
|
|
int n;
|
|
uchar flash_email = TRUE;
|
|
ubyte ver;
|
|
extern short last_email_taken;
|
|
|
|
n = mung & 0xFF;
|
|
ver = mung >> 8;
|
|
switch (ver) {
|
|
case EMAIL_VER:
|
|
set_email_flags(n);
|
|
break;
|
|
case LOG_VER: {
|
|
int lev;
|
|
lev = n / LOGS_PER_LEVEL;
|
|
n = NUM_EMAIL_PROPER + n;
|
|
if (player_struct.email[n] == 0)
|
|
player_struct.logs[lev]++;
|
|
flash_email = FALSE;
|
|
} break;
|
|
case DATA_VER:
|
|
flash_email = FALSE;
|
|
n = n + NUM_EMAIL - NUM_DATA;
|
|
break;
|
|
}
|
|
if (player_struct.email[n] & EMAIL_GOT)
|
|
return;
|
|
last_email_taken = ver;
|
|
string_message_info(REF_STR_ReceiveEmail + ver);
|
|
player_struct.email[n] |= EMAIL_GOT;
|
|
if (flash_email) {
|
|
player_struct.hardwarez_status[CPTRIP(VIDTEX_HARD_TRIPLE)] |= WARE_FLASH;
|
|
QUESTBIT_ON(0x12c);
|
|
}
|
|
INVENT_CHANGED;
|
|
select_email(n, select);
|
|
}
|
|
|
|
ubyte email_add_func(inv_display *dp, int w, ObjID *idP, uchar select) {
|
|
play_digi_fx(SFX_INVENT_ADD, 1);
|
|
if (ID2TRIP(*idP) != EMAIL1_TRIPLE && ID2TRIP(*idP) != TEXT1_TRIPLE)
|
|
return ADD_REJECT;
|
|
add_email_datamunge(SOFTWARE_CONTENTS(objs[*idP].specID), select);
|
|
return ADD_POP;
|
|
}
|
|
|
|
void email_drop_func(inv_display *dp, int n) {
|
|
// For now, do nothing.
|
|
}
|
|
|
|
// ----
|
|
// LOGS
|
|
// ----
|
|
|
|
// I'm on your side; we are on the both side.
|
|
|
|
#define FIRST_LOG_PAGE 20
|
|
|
|
char *log_name_func(void *v, int num, char *buf) { return get_string(REF_STR_LogName0 + num, buf, BUFSZ); }
|
|
|
|
uchar log_use_func(inv_display *dp, int row) {
|
|
uchar retval = FALSE;
|
|
int n = dp->lines[row].num;
|
|
if (n < dp->listlen) {
|
|
inventory_draw_new_page(FIRST_LOG_PAGE + n);
|
|
retval = TRUE;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
// ---------
|
|
// INTERNALS
|
|
// ---------
|
|
|
|
void inventory_draw_page(int pgnum) {
|
|
int i;
|
|
inv_display *dpy;
|
|
|
|
for (i = 0; gen_inv_page(pgnum, &i, &dpy); i++) {
|
|
if (dpy->draw != NULL)
|
|
dpy->draw(dpy);
|
|
}
|
|
for (i = 0; i < NUM_ACTIVES; i++)
|
|
known_actives[i] = player_struct.actives[i];
|
|
}
|
|
|
|
ubyte add_to_some_page(ObjID obj, uchar select) {
|
|
inv_display *dpy;
|
|
int i;
|
|
for (i = 0; gen_inv_displays(&i, &dpy); i++) {
|
|
ubyte pop;
|
|
if (global_fullmap->cyber && (objs[obj].obclass == CLASS_BIGSTUFF)) {
|
|
if (!(dpy->add_classes & (1 << CLASS_SOFTWARE)))
|
|
continue;
|
|
} else {
|
|
if (!(dpy->add_classes & (1 << objs[obj].obclass)))
|
|
continue;
|
|
}
|
|
if (dpy->add != NULL)
|
|
pop = dpy->add(dpy, -1, &obj, select);
|
|
if (pop == ADD_FAIL)
|
|
return pop;
|
|
if (pop == ADD_NOROOM) {
|
|
string_message_info(REF_STR_InvNoRoom);
|
|
return pop;
|
|
}
|
|
if (pop != ADD_REJECT) {
|
|
if (pop != ADD_NOEFFECT) {
|
|
if (dpy->pgnum != inventory_page && dpy->pgnum < NUM_PAGE_BUTTONS) {
|
|
page_button_state[dpy->pgnum] = BttnFlashOn;
|
|
}
|
|
INVENT_CHANGED;
|
|
}
|
|
return pop;
|
|
}
|
|
}
|
|
string_message_info(REF_STR_InvReject);
|
|
return ADD_REJECT;
|
|
}
|
|
|
|
/*KLC - no longer used
|
|
void draw_page_button_panel()
|
|
{
|
|
draw_page_buttons(TRUE);
|
|
}
|
|
*/
|
|
|
|
void draw_page_buttons(uchar full) {
|
|
LGRect r, hider;
|
|
int i;
|
|
short x;
|
|
uchar old_over = gr2ss_override;
|
|
|
|
gr_push_canvas(ppage_canvas);
|
|
|
|
if (full_game_3d)
|
|
gr2ss_override = OVERRIDE_NONE;
|
|
else
|
|
gr2ss_override = OVERRIDE_ALL;
|
|
|
|
if (full) {
|
|
draw_res_bm(REF_IMG_bmInventoryButtonBackground, INVENT_BUTTON_PANEL_X, INVENT_BUTTON_PANEL_Y);
|
|
// draw_hires_resource_bm(REF_IMG_bmInventoryButtonBackground, 0, 0);
|
|
}
|
|
|
|
r.ul.y = INVENT_BTTN_Y;
|
|
r.lr.y = r.ul.y + INVENT_BTTN_HT;
|
|
|
|
for (x = FIRST_BTTN_X, i = 0; i < NUM_PAGE_BUTTONS; i++, x += BUTTON_X_STEP) {
|
|
invent_bttn_state newstate = page_button_state[i];
|
|
ulong clr;
|
|
uchar active = i == inventory_page;
|
|
|
|
if (newstate == BttnDummy)
|
|
continue;
|
|
// Figure out what the button state really is.
|
|
if (active)
|
|
newstate = BttnActive;
|
|
else if (Flashing(newstate)) {
|
|
uchar flashon = (player_struct.game_time / INVENT_BTTN_FLASH_TIME) % 2;
|
|
if (flashon != FlashOn(newstate)) {
|
|
newstate = (invent_bttn_state)((char)newstate - 1);
|
|
if (newstate == BttnFlashOff)
|
|
newstate = BttnOff;
|
|
}
|
|
// if (time_passes) // We want to remember that we need to change when time starts again..
|
|
INVENT_CHANGED;
|
|
} else
|
|
newstate = BttnOff;
|
|
|
|
if (!full && newstate == old_button_state[i])
|
|
continue;
|
|
|
|
clr = bttn_state2color(newstate);
|
|
gr_set_fcolor(clr);
|
|
r.ul.x = x;
|
|
r.lr.x = x + INVENT_BTTN_WD;
|
|
RECT_OFFSETTED_RECT(&r, MakePoint(INVENTORY_PANEL_X, BUTTON_PANEL_Y), &hider);
|
|
uiHideMouse(&hider);
|
|
ss_rect(r.ul.x, r.ul.y, r.lr.x, r.lr.y);
|
|
// gr_rect(SCONV_X(r.ul.x)+2, 2, SCONV_X(r.lr.x)+2, 10);
|
|
uiShowMouse(&hider);
|
|
page_button_state[i] = old_button_state[i] = newstate;
|
|
}
|
|
gr_pop_canvas();
|
|
gr2ss_override = old_over;
|
|
}
|
|
|
|
// ---------
|
|
// EXTERNALS
|
|
// ---------
|
|
|
|
uchar dirty_inv_canvas = FALSE;
|
|
|
|
errtype inventory_clear(void) {
|
|
gr_push_canvas(&inv_canvas);
|
|
if (full_game_3d)
|
|
gr_clear(0);
|
|
else {
|
|
LGRect r;
|
|
r.ul.x = INVENTORY_PANEL_X;
|
|
r.ul.y = INVENTORY_PANEL_Y;
|
|
r.lr.x = INVENTORY_PANEL_X + INVENTORY_PANEL_WIDTH;
|
|
r.lr.y = INVENTORY_PANEL_Y + INVENTORY_PANEL_HEIGHT;
|
|
if (dirty_inv_canvas) {
|
|
FrameDesc *f = RefGet(REF_IMG_bmBlankInventoryPanel);
|
|
LG_memcpy(inv_backgnd.bits, f + 1, f->bm.w * f->bm.h);
|
|
dirty_inv_canvas = FALSE;
|
|
}
|
|
uiHideMouse(&r);
|
|
ss_safe_set_cliprect(0, 0, INVENTORY_PANEL_WIDTH, INVENTORY_PANEL_HEIGHT);
|
|
ss_bitmap(&inv_backgnd, 0, 0);
|
|
// gr_bitmap(&inv_backgnd, 0, 0);
|
|
uiShowMouse(&r);
|
|
}
|
|
gr_pop_canvas();
|
|
/* Now, you might ask "Why not just set inv_last_page = INV_BLANK_PAGE all the time?"
|
|
And the answer is, well, the wrapper panel saves the inventory page in inv_last_page,
|
|
so that things like load game know how to blow the saved page away */
|
|
if (inventory_page == inv_last_page)
|
|
inv_last_page = INV_BLANK_PAGE;
|
|
return (OK);
|
|
}
|
|
|
|
errtype inventory_full_redraw() {
|
|
int i;
|
|
inv_last_page = -1;
|
|
for (i = 0; i < NUM_PAGE_BUTTONS; i++)
|
|
old_button_state[i] = BttnDummy;
|
|
return (inventory_draw());
|
|
}
|
|
|
|
errtype inventory_draw(void) {
|
|
uchar full = inventory_page != inv_last_page;
|
|
#ifdef SVGA_SUPPORT
|
|
uchar old_over;
|
|
short temp;
|
|
#endif
|
|
if (inventory_page < 0)
|
|
return OK;
|
|
gr_push_canvas(&inv_canvas);
|
|
#ifdef SVGA_SUPPORT
|
|
old_over = gr2ss_override;
|
|
// if (full_game_3d)
|
|
// gr2ss_override = OVERRIDE_FONT|OVERRIDE_CLIP;
|
|
// else
|
|
gr2ss_override = OVERRIDE_ALL;
|
|
#endif
|
|
if (global_fullmap->cyber)
|
|
inventory_page = INV_SOFTWARE_PAGE;
|
|
if (full)
|
|
inventory_clear();
|
|
draw_page_buttons(full_game_3d || full);
|
|
#ifdef SVGA_SUPPORT
|
|
ss_set_hack_mode(2, &temp);
|
|
#endif
|
|
inventory_draw_page(inventory_page);
|
|
#ifdef SVGA_SUPPORT
|
|
ss_set_hack_mode(0, &temp);
|
|
gr2ss_override = old_over;
|
|
#endif
|
|
gr_pop_canvas();
|
|
inv_last_page = inventory_page;
|
|
return (OK);
|
|
}
|
|
|
|
errtype inventory_draw_new_page(int pgnum) {
|
|
inv_last_page = -1;
|
|
inventory_page = pgnum;
|
|
if (full_game_3d) {
|
|
#ifdef STEREO_SUPPORT
|
|
if (convert_use_mode == 5)
|
|
full_visible = FULL_INVENT_MASK;
|
|
else
|
|
#endif
|
|
full_visible |= FULL_INVENT_MASK;
|
|
full_raise_region(inventory_region_full);
|
|
chg_set_sta(FULLSCREEN_UPDATE);
|
|
}
|
|
return inventory_draw();
|
|
}
|
|
|
|
uchar inventory_add_object(ObjID obj, uchar select) {
|
|
ubyte result = add_to_some_page(obj, select);
|
|
return (result != ADD_FAIL) && (result != ADD_REJECT) && (result != ADD_NOROOM);
|
|
}
|
|
|
|
// ------------
|
|
// EVENTHANDLER
|
|
// ------------
|
|
|
|
uchar do_selection(inv_display *dp, int row) {
|
|
uchar retval = FALSE;
|
|
int w = dp->lines[row].num;
|
|
if (w >= dp->listlen)
|
|
goto out;
|
|
if (dp->activenum == NULL_ACTIVE)
|
|
goto out;
|
|
player_struct.actives[dp->activenum] = w;
|
|
set_inventory_mfd(dp->mfdtype, w, TRUE);
|
|
INVENT_CHANGED;
|
|
retval = TRUE;
|
|
out:
|
|
return retval;
|
|
}
|
|
|
|
void add_object_on_cursor(inv_display *dp, int row) {
|
|
ObjID obj = object_on_cursor;
|
|
ubyte pop = ADD_REJECT;
|
|
if (dp != NULL)
|
|
pop = (dp->add_classes & (1 << TRIP2CL(ID2TRIP(object_on_cursor)))) ? ADD_POP : ADD_REJECT;
|
|
if (pop != ADD_REJECT && dp->add != NULL)
|
|
pop = dp->add(dp, row, &obj, FALSE);
|
|
if (pop == ADD_NOROOM) {
|
|
string_message_info(REF_STR_InvNoRoom);
|
|
return;
|
|
}
|
|
if (pop == ADD_REJECT)
|
|
pop = add_to_some_page(obj, FALSE);
|
|
if (pop != ADD_REJECT && pop != ADD_FAIL) {
|
|
INVENT_CHANGED;
|
|
if (IS_POP_RESULT(pop) || pop == ADD_SWAP)
|
|
pop_cursor_object();
|
|
if (pop == ADD_SWAP)
|
|
push_cursor_object(obj);
|
|
uiShowMouse(NULL); // KLC - added to make sure the pointer changes.
|
|
}
|
|
if (pop == ADD_REJECT)
|
|
string_message_info(REF_STR_InvReject);
|
|
}
|
|
|
|
uchar inventory_handle_leftbutton(uiEvent *ev, inv_display *dp, int row) {
|
|
uchar retval = FALSE;
|
|
#ifndef NO_DUMMIES
|
|
void *dummy;
|
|
dummy = ev;
|
|
#endif // NO_DUMMIES
|
|
switch (input_cursor_mode) {
|
|
case INPUT_NORMAL_CURSOR:
|
|
if (dp != NULL && row >= 0) {
|
|
if (dp->select != NULL)
|
|
retval = dp->select(dp, row);
|
|
else
|
|
retval = do_selection(dp, row);
|
|
}
|
|
break;
|
|
case INPUT_OBJECT_CURSOR:
|
|
add_object_on_cursor(dp, row);
|
|
retval = TRUE;
|
|
break;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
static uchar invpanel_focus = FALSE;
|
|
|
|
uchar inventory_handle_rightbutton(uiEvent *ev, LGRegion *reg, inv_display *dp, int row) {
|
|
static int lastrow = 0;
|
|
static inv_display *lastdp = NULL;
|
|
|
|
uchar retval = FALSE;
|
|
LGRect r;
|
|
uchar grab = FALSE;
|
|
|
|
if (input_cursor_mode != INPUT_NORMAL_CURSOR)
|
|
return FALSE;
|
|
if (ev->subtype & MOUSE_RDOWN && row >= 0 && dp != NULL && !invpanel_focus) {
|
|
// let us know if we leave the region
|
|
invpanel_focus = TRUE;
|
|
uiGrabFocus(reg, UI_EVENT_MOUSE_MOVE);
|
|
lastrow = row;
|
|
lastdp = dp;
|
|
retval = TRUE;
|
|
}
|
|
// Check to see if we've left the region and release focus.
|
|
region_abs_rect(reg, reg->r, &r);
|
|
if (!RECT_TEST_PT(&r, ev->pos)) {
|
|
grab = TRUE;
|
|
row = lastrow;
|
|
dp = lastdp;
|
|
retval = TRUE;
|
|
}
|
|
if (ev->subtype & MOUSE_RUP) {
|
|
if (row == lastrow && dp == lastdp)
|
|
grab = TRUE;
|
|
} else if (ev->subtype & MOUSE_MOTION && (row != lastrow || dp != lastdp)) {
|
|
row = lastrow;
|
|
dp = lastdp;
|
|
grab = TRUE;
|
|
}
|
|
if (grab && dp != NULL && row >= 0) {
|
|
uchar cyber = TRIP2CL(dp->basetrip) == CLASS_SOFTWARE;
|
|
if (cyber != global_fullmap->cyber) {
|
|
int str = cyber ? REF_STR_InvCybFailSoft : REF_STR_InvCybFailHard;
|
|
string_message_info(str);
|
|
} else if (dp->drop != NULL) {
|
|
dp->drop(dp, row);
|
|
}
|
|
lastrow = -1;
|
|
lastdp = NULL;
|
|
retval = TRUE;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
#define SEARCH_MARGIN 2
|
|
|
|
uchar inventory_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t data) {
|
|
uchar retval = FALSE;
|
|
int relx;
|
|
inv_display *dp = NULL;
|
|
int i;
|
|
int row = -1;
|
|
extern uchar game_paused;
|
|
#ifdef SVGA_SUPPORT
|
|
short temp;
|
|
#endif
|
|
if (game_paused)
|
|
return (TRUE);
|
|
|
|
#ifdef STEREO_SUPPORT
|
|
if (convert_use_mode == 5) {
|
|
if (i6d_device == I6D_CTM)
|
|
relx = ev->pos.x - 1;
|
|
else {
|
|
relx = (ev->pos.x - ((320 - inv_fullscrn_canvas.bm.w) / 2)) >> 1;
|
|
// Warning(("relx: %d = %d - %d = %d >> 1\n",relx,ev->pos.x,((320-inv_fullscrn_canvas.bm.w)/2),
|
|
// (ev->pos.x - ((320-inv_fullscrn_canvas.bm.w)/2))));
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
relx = ev->pos.x - INVENTORY_PANEL_X;
|
|
}
|
|
if (invpanel_focus && !(ev->mouse_data.buttons & (1 << MOUSE_RBUTTON))) {
|
|
uiReleaseFocus(r, UI_EVENT_MOUSE_MOVE);
|
|
invpanel_focus = FALSE;
|
|
}
|
|
if (full_game_3d && !(full_visible & FULL_INVENT_MASK))
|
|
return FALSE;
|
|
if (full_game_3d && !(ev->mouse_data.buttons & (1 << MOUSE_RBUTTON))) {
|
|
if (!(ev->mouse_data.action & ~MOUSE_MOTION))
|
|
return FALSE;
|
|
if (input_cursor_mode != INPUT_OBJECT_CURSOR) {
|
|
uchar found = FALSE;
|
|
short rel_y;
|
|
short x, y;
|
|
short smx, smy;
|
|
#ifdef STEREO_SUPPORT
|
|
if (convert_use_mode == 5) {
|
|
switch (i6d_device) {
|
|
case I6D_CTM:
|
|
rel_y = ev->pos.y - 1;
|
|
break;
|
|
case I6D_VFX1:
|
|
rel_y = ev->pos.y - (INVENTORY_PANEL_Y >> 1);
|
|
// rel_y = ev->pos.y - (200 - inv_fullscrn_canvas.bm.h);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
#endif
|
|
rel_y = ev->pos.y - INVENTORY_PANEL_Y;
|
|
gr_push_canvas(&inv_fullscrn_canvas);
|
|
smx = SEARCH_MARGIN;
|
|
smy = SEARCH_MARGIN;
|
|
#ifdef SVGA_SUPPORT
|
|
ss_set_hack_mode(2, &temp);
|
|
ss_point_convert(&smx, &smy, FALSE);
|
|
#endif
|
|
for (x = relx - smx; !found && x <= relx + smx; x++)
|
|
for (y = rel_y - smy; !found && y <= rel_y + smy; y++) {
|
|
short usex, usey;
|
|
usex = x;
|
|
usey = y;
|
|
#ifdef SVGA_SUPPORT
|
|
ss_point_convert(&usex, &usey, FALSE);
|
|
#endif
|
|
if (gr_get_pixel(usex, usey) != 0) // found non-transparent pixel
|
|
found = TRUE;
|
|
}
|
|
#ifdef SVGA_SUPPORT
|
|
ss_set_hack_mode(0, &temp);
|
|
#endif
|
|
gr_pop_canvas();
|
|
if (!found) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; gen_inv_page(inventory_page, &i, &dp); i++) {
|
|
if (relx < dp->left || relx > dp->right)
|
|
continue;
|
|
row = get_item_at_pixrow(dp, ev->pos.y);
|
|
if (row >= 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (input_cursor_mode == INPUT_OBJECT_CURSOR && (ev->mouse_data.action & (MOUSE_LDOWN | MOUSE_RUP | UI_MOUSE_LDOUBLE))) {
|
|
add_object_on_cursor(dp, row);
|
|
return TRUE;
|
|
}
|
|
if ((ev->mouse_data.buttons & (1 << MOUSE_RBUTTON)) || (ev->subtype & (MOUSE_RUP | MOUSE_RDOWN)))
|
|
if (inventory_handle_rightbutton(ev, r, dp, row))
|
|
retval = TRUE;
|
|
// Handle left button
|
|
if (ev->subtype & MOUSE_LDOWN) {
|
|
if (inventory_handle_leftbutton(ev, dp, row))
|
|
retval = TRUE;
|
|
}
|
|
// Handle left doubleclick
|
|
if (ev->subtype & UI_MOUSE_LDOUBLE)
|
|
if (dp != NULL && (row >= 0) && (dp->use != NULL)) {
|
|
retval = dp->use(dp, row);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
int last_invent_cnum = -1; // last cursor num set for region
|
|
uchar pagebutton_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t data) {
|
|
LGPoint pos = ev->pos;
|
|
int cnum;
|
|
|
|
if (full_game_3d && (ev->mouse_data.buttons & (1 << MOUSE_LBUTTON)) != 0 &&
|
|
(ev->mouse_data.action & MOUSE_LDOWN) == 0 &&
|
|
uiLastMouseRegion[MOUSE_LBUTTON] != NULL && uiLastMouseRegion[MOUSE_LBUTTON] != r) {
|
|
uiSetRegionDefaultCursor(r, NULL);
|
|
return FALSE;
|
|
}
|
|
|
|
pos.x -= INVENTORY_PANEL_X;
|
|
pos.y -= INVENTORY_PANEL_Y;
|
|
|
|
cnum = (pos.x - FIRST_BTTN_X) / BUTTON_X_STEP;
|
|
if (full_game_3d && global_fullmap->cyber && cnum != INV_SOFTWARE_PAGE) {
|
|
last_invent_cnum = cnum;
|
|
uiSetRegionDefaultCursor(r, NULL);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((cnum != last_invent_cnum) && (cnum < NUM_PAGE_BTTNS)) {
|
|
LGCursor *c = &invent_bttn_cursor;
|
|
LGPoint offset = {0, -1};
|
|
|
|
if ((page_button_state[cnum] == BttnDummy) || !popup_cursors)
|
|
c = NULL;
|
|
last_invent_cnum = cnum;
|
|
#ifdef SVGA_SUPPORT
|
|
free(invent_bttn_bitmap.bits);
|
|
make_popup_cursor(c, &invent_bttn_bitmap, cursor_strings[cnum], POPUP_DOWN, TRUE, offset);
|
|
#else
|
|
make_popup_cursor(c, &invent_bttn_bitmap, cursor_strings[cnum], POPUP_DOWN, FALSE, offset);
|
|
#endif
|
|
uiSetRegionDefaultCursor(r, c);
|
|
}
|
|
|
|
if (input_cursor_mode == INPUT_OBJECT_CURSOR && (ev->mouse_data.action & (MOUSE_LDOWN | MOUSE_RDOWN | UI_MOUSE_LDOUBLE))) {
|
|
AddResult pop = (AddResult)add_to_some_page(object_on_cursor, FALSE);
|
|
if (IS_POP_RESULT(pop))
|
|
pop_cursor_object();
|
|
return TRUE;
|
|
}
|
|
|
|
if (page_button_state[cnum] == BttnDummy)
|
|
return FALSE;
|
|
|
|
if (ev->mouse_data.action & MOUSE_LDOWN) {
|
|
int i = cnum;
|
|
short x = FIRST_BTTN_X + i * BUTTON_X_STEP;
|
|
if (pos.x >= x && pos.x < x + INVENT_BTTN_WD && page_button_state[i] != BttnDummy) {
|
|
if (full_game_3d) {
|
|
if (i == inventory_page && full_visible & FULL_INVENT_MASK) {
|
|
full_visible &= ~FULL_INVENT_MASK;
|
|
} else {
|
|
gr_push_canvas(pinv_canvas);
|
|
gr_clear(0);
|
|
gr_pop_canvas();
|
|
#ifdef STEREO_SUPPORT
|
|
if (convert_use_mode == 5)
|
|
full_visible = FULL_INVENT_MASK;
|
|
else
|
|
#endif
|
|
full_visible |= FULL_INVENT_MASK;
|
|
inv_last_page = -1;
|
|
full_raise_region(inventory_region_full);
|
|
chg_set_sta(FULLSCREEN_UPDATE);
|
|
}
|
|
}
|
|
play_digi_fx(SFX_INVENT_BUTTON, 1);
|
|
inventory_page = i;
|
|
INVENT_CHANGED;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#define MAX_HOTKEY_PAGES 6
|
|
#define EMPTY_PAGE(i) (page_button_state[i] == BttnDummy)
|
|
|
|
uchar invent_hotkey_func(ushort keycode, uint32_t context, intptr_t data) {
|
|
if (inventory_page < 0)
|
|
inventory_page = MAX_HOTKEY_PAGES;
|
|
if (inventory_page >= MAX_HOTKEY_PAGES)
|
|
inventory_page = -1;
|
|
if (data == 0) {
|
|
inventory_page--;
|
|
if (inventory_page < 0)
|
|
inventory_page = MAX_HOTKEY_PAGES - 1;
|
|
while (EMPTY_PAGE(inventory_page))
|
|
inventory_page--;
|
|
} else {
|
|
inventory_page++;
|
|
if (inventory_page >= MAX_HOTKEY_PAGES)
|
|
inventory_page = 0;
|
|
while (EMPTY_PAGE(inventory_page))
|
|
inventory_page++;
|
|
}
|
|
play_digi_fx(SFX_INVENT_BUTTON, 1);
|
|
if (!(full_visible & FULL_INVENT_MASK)) {
|
|
gr_push_canvas(pinv_canvas);
|
|
gr_clear(0);
|
|
gr_pop_canvas();
|
|
#ifdef SVGA_SUPPORT
|
|
if (convert_use_mode == 5)
|
|
full_visible = FULL_INVENT_MASK;
|
|
else
|
|
#endif
|
|
full_visible |= FULL_INVENT_MASK;
|
|
}
|
|
INVENT_CHANGED;
|
|
return TRUE;
|
|
}
|
|
|
|
uchar cycle_weapons_func(ushort keycode, uint32_t context, intptr_t data) {
|
|
if (global_fullmap->cyber) {
|
|
int ac = player_struct.actives[ACTIVE_COMBAT_SOFT];
|
|
int bound1 = (data > 0) ? NUM_COMBAT_SOFTS : -1;
|
|
int bound2 = (data > 0) ? 0 : NUM_COMBAT_SOFTS - 1;
|
|
int i;
|
|
for (i = ac + data; i != bound1; i += data)
|
|
if (player_struct.softs.combat[i] != 0)
|
|
goto got_soft;
|
|
for (i = bound2; i != ac; i += data)
|
|
if (player_struct.softs.combat[i] != 0)
|
|
goto got_soft;
|
|
got_soft:
|
|
player_struct.actives[ACTIVE_COMBAT_SOFT] = i;
|
|
INVENT_CHANGED;
|
|
} else {
|
|
int aw = player_struct.actives[ACTIVE_WEAPON];
|
|
|
|
aw += data;
|
|
if (aw >= NUM_WEAPON_SLOTS || player_struct.weapons[aw].type == EMPTY_WEAPON_SLOT)
|
|
aw = 0;
|
|
else if (aw < 0) {
|
|
for (aw = NUM_WEAPON_SLOTS - 1; player_struct.weapons[aw].type == EMPTY_WEAPON_SLOT && aw > 0; aw--)
|
|
;
|
|
}
|
|
inventory_select_weapon(NULL, aw);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#define PAGEUP_KEY KEY_PAD_PGUP | KB_FLAG_DOWN
|
|
#define PAGEDN_KEY KEY_PAD_PGDN | KB_FLAG_DOWN
|
|
|
|
void init_invent_hotkeys(void) {
|
|
/* later
|
|
// hotkey_add(PAGEUP_KEY,DEMO_CONTEXT,invent_hotkey_func,0);
|
|
hotkey_add(PAGEUP_KEY|KB_FLAG_2ND,DEMO_CONTEXT,invent_hotkey_func,0);
|
|
hotkey_add(KB_FLAG_DOWN|KB_FLAG_ALT|'[',DEMO_CONTEXT,invent_hotkey_func,0);
|
|
// hotkey_add(PAGEDN_KEY,DEMO_CONTEXT,invent_hotkey_func,1);
|
|
hotkey_add(PAGEDN_KEY|KB_FLAG_2ND,DEMO_CONTEXT,invent_hotkey_func,1);
|
|
hotkey_add(KB_FLAG_DOWN|KB_FLAG_ALT|']',DEMO_CONTEXT,invent_hotkey_func,1);
|
|
*/
|
|
hotkey_add(KEY_TAB | KB_FLAG_DOWN, DEMO_CONTEXT, cycle_weapons_func, 1);
|
|
hotkey_add(KEY_TAB | KB_FLAG_DOWN | KB_FLAG_SHIFT, DEMO_CONTEXT, cycle_weapons_func, -1);
|
|
}
|
|
|
|
void invent_language_change(void) {
|
|
load_string_array(REF_STR_InvCursor, cursor_strings, cursor_string_buf, sizeof(cursor_string_buf),
|
|
NUM_PAGE_BUTTONS);
|
|
}
|
|
|
|
#define MAX_INV_FULL_WD(x) (fix_int(fix_mul_div(fix_make((x), 0), fix_make(1024, 0), fix_make(320, 0))))
|
|
#define MAX_INV_FULL_HT(y) (fix_int(fix_mul_div(fix_make((y), 0), fix_make(768, 0), fix_make(200, 0))))
|
|
|
|
LGRegion *create_invent_region(LGRegion *root, LGRegion **pbuttons, LGRegion **pinvent) {
|
|
static uchar done_init = FALSE;
|
|
int id;
|
|
LGRect invrect;
|
|
LGRegion *invreg = (LGRegion *)malloc(sizeof(LGRegion));
|
|
LGRegion *pagereg = (LGRegion *)malloc(sizeof(LGRegion));
|
|
FrameDesc *f;
|
|
#ifdef OLD_BUTTON_CURSORS
|
|
LGPoint pt;
|
|
int i;
|
|
#endif
|
|
#ifdef CURSOR_BACKUPS
|
|
extern uchar *backup[NUM_BACKUP_BITS];
|
|
extern grs_bitmap backup_invent_bttn_cursors[NUM_PAGE_BTTNS];
|
|
#endif
|
|
|
|
// Create the panel region
|
|
invrect.ul.x = INVENTORY_PANEL_X;
|
|
invrect.ul.y = INVENTORY_PANEL_Y;
|
|
invrect.lr.x = invrect.ul.x + INVENTORY_PANEL_WIDTH;
|
|
invrect.lr.y = invrect.ul.y + INVENTORY_PANEL_HEIGHT;
|
|
region_create(root, invreg, &invrect, 0, 0, REG_USER_CONTROLLED | AUTODESTROY_FLAG, NULL, NULL, NULL, NULL);
|
|
uiInstallRegionHandler(invreg, UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE, inventory_mouse_handler, 0, &id);
|
|
uiSetRegionDefaultCursor(invreg, NULL);
|
|
add_email_handler(invreg);
|
|
if (pinvent != NULL)
|
|
*pinvent = invreg;
|
|
|
|
// Create the pagebutton region
|
|
invrect.ul.y = invrect.lr.y;
|
|
invrect.lr.y = RectHeight(root->r);
|
|
region_create(root, pagereg, &invrect, 0, 0, REG_USER_CONTROLLED | AUTODESTROY_FLAG, NULL, NULL, NULL, NULL);
|
|
uiInstallRegionHandler(pagereg, (UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE), pagebutton_mouse_handler,
|
|
0, &id);
|
|
uiSetRegionDefaultCursor(pagereg, &globcursor);
|
|
|
|
if (pbuttons != NULL)
|
|
*pbuttons = pagereg;
|
|
|
|
if (!done_init) {
|
|
done_init = TRUE;
|
|
// Assign different cursors to different buttons in pagebutton region
|
|
{
|
|
grs_bitmap *bm = &invent_bttn_bitmap;
|
|
LGCursor *c = &invent_bttn_cursor;
|
|
LGPoint offset = {0, -1};
|
|
|
|
invent_language_change();
|
|
make_popup_cursor(c, bm, cursor_strings[0], POPUP_DOWN, TRUE, offset);
|
|
}
|
|
|
|
// Pull in the background bitmap
|
|
f = RefLock(REF_IMG_bmBlankInventoryPanel);
|
|
inv_backgnd = f->bm;
|
|
|
|
// This background is going to get used by the 360 ware
|
|
// in fullscreen mode, so we need extra bits
|
|
inv_backgnd.bits = (uchar *)malloc(MAX_INV_FULL_WD(INV_FULL_WD) * MAX_INV_FULL_HT(grd_cap->h - GAME_MESSAGE_Y));
|
|
LG_memcpy(inv_backgnd.bits, (f + 1), f->bm.w * f->bm.h);
|
|
RefUnlock(REF_IMG_bmBlankInventoryPanel);
|
|
|
|
// init the canvas
|
|
gr_init_sub_canvas(grd_scr_canv, &inv_norm_canvas, INVENTORY_PANEL_X, INVENTORY_PANEL_Y, INVENTORY_PANEL_WIDTH,
|
|
INVENTORY_PANEL_HEIGHT);
|
|
gr_init_canvas(&inv_fullscrn_canvas, inv_backgnd.bits, BMT_FLAT8, INVENTORY_PANEL_WIDTH,
|
|
INVENTORY_PANEL_HEIGHT);
|
|
gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, INV_FULL_WD, INV_FULL_HT);
|
|
gr_init_sub_canvas(grd_scr_canv, &inv_gamepage_canvas, INVENTORY_PANEL_X, BUTTON_PANEL_Y, INVENTORY_PANEL_WIDTH,
|
|
grd_cap->h - BUTTON_PANEL_Y);
|
|
|
|
uchar *p = (uchar *)malloc(292 * 10); // This canvas holds an off-screen image of the
|
|
gr_init_canvas(&inv_fullpage_canvas, p, BMT_FLAT8, 292, 10); // inventory buttons.
|
|
gr_push_canvas(&inv_fullpage_canvas);
|
|
gr_clear(0);
|
|
gr_pop_canvas();
|
|
}
|
|
|
|
inventory_update_screen_mode();
|
|
|
|
return invreg;
|
|
}
|
|
|
|
errtype inventory_update_screen_mode() {
|
|
if (convert_use_mode) {
|
|
gr_init_sub_canvas(grd_scr_canv, &inv_norm_canvas, SCONV_X(INVENTORY_PANEL_X), SCONV_Y(INVENTORY_PANEL_Y),
|
|
SCONV_X(INVENTORY_PANEL_WIDTH), SCONV_Y(INVENTORY_PANEL_HEIGHT));
|
|
if (full_game_3d) {
|
|
gr_init_canvas(&inv_fullscrn_canvas, inv_backgnd.bits, BMT_FLAT8, SCONV_X(INVENTORY_PANEL_WIDTH),
|
|
SCONV_Y(INVENTORY_PANEL_HEIGHT));
|
|
// gr_init_canvas(&inv_fullscrn_canvas, inv_backgnd.bits, BMT_FLAT8, 290, 120);
|
|
gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, SCONV_X(INV_FULL_WD),
|
|
SCONV_Y(INV_FULL_HT));
|
|
// gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, 290, SCONV_Y(INV_FULL_HT));
|
|
} else {
|
|
gr_init_sub_canvas(grd_scr_canv, &inv_gamepage_canvas, SCONV_X(INVENTORY_PANEL_X), SCONV_Y(BUTTON_PANEL_Y),
|
|
SCONV_X(INVENTORY_PANEL_WIDTH), SCONV_Y(10));
|
|
gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, SCONV_X(INV_FULL_WD),
|
|
SCONV_Y(INV_FULL_HT));
|
|
}
|
|
} else {
|
|
gr_init_sub_canvas(grd_scr_canv, &inv_norm_canvas, INVENTORY_PANEL_X, INVENTORY_PANEL_Y, INVENTORY_PANEL_WIDTH,
|
|
INVENTORY_PANEL_HEIGHT);
|
|
if (full_game_3d) {
|
|
gr_init_canvas(&inv_fullscrn_canvas, inv_backgnd.bits, BMT_FLAT8, INVENTORY_PANEL_WIDTH,
|
|
INVENTORY_PANEL_HEIGHT);
|
|
gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, INV_FULL_WD, INV_FULL_HT);
|
|
} else {
|
|
gr_init_sub_canvas(grd_scr_canv, &inv_gamepage_canvas, INVENTORY_PANEL_X, BUTTON_PANEL_Y,
|
|
INVENTORY_PANEL_WIDTH, grd_cap->h - BUTTON_PANEL_Y);
|
|
gr_init_canvas(&inv_view360_canvas, inv_backgnd.bits, BMT_FLAT8, INVENTORY_PANEL_WIDTH,
|
|
INVENTORY_PANEL_HEIGHT);
|
|
}
|
|
}
|
|
|
|
/*KLC - not used in Mac version
|
|
else
|
|
{
|
|
gr_init_sub_canvas(grd_scr_canv,&inv_norm_canvas,INVENTORY_PANEL_X,INVENTORY_PANEL_Y,
|
|
INVENTORY_PANEL_WIDTH,INVENTORY_PANEL_HEIGHT);
|
|
if (full_game_3d)
|
|
{
|
|
gr_init_canvas(&inv_fullscrn_canvas,inv_backgnd.bits, BMT_FLAT8,
|
|
INVENTORY_PANEL_WIDTH,INVENTORY_PANEL_HEIGHT); gr_init_canvas(&inv_view360_canvas,inv_backgnd.bits, BMT_FLAT8,
|
|
INV_FULL_WD, INV_FULL_HT);
|
|
}
|
|
else
|
|
{
|
|
gr_init_sub_canvas(grd_scr_canv,&inv_gamepage_canvas,INVENTORY_PANEL_X,BUTTON_PANEL_Y,
|
|
INVENTORY_PANEL_WIDTH,grd_cap->h - BUTTON_PANEL_Y);
|
|
}
|
|
}
|
|
*/
|
|
return (OK);
|
|
}
|
|
|
|
void inv_change_fullscreen(uchar on) {
|
|
if (on) {
|
|
pinv_canvas = &inv_fullscrn_canvas;
|
|
ppage_canvas = &inv_fullpage_canvas;
|
|
gr_push_canvas(pinv_canvas);
|
|
gr_clear(0);
|
|
gr_pop_canvas();
|
|
dirty_inv_canvas = TRUE;
|
|
|
|
gr_push_canvas(ppage_canvas);
|
|
gr_clear(0);
|
|
gr_pop_canvas();
|
|
} else {
|
|
int i;
|
|
pinv_canvas = &inv_norm_canvas;
|
|
ppage_canvas = &inv_gamepage_canvas;
|
|
for (i = 0; i < NUM_PAGE_BUTTONS; i++)
|
|
old_button_state[i] = BttnOff;
|
|
if (inventory_page == INV_EMAILTEXT_PAGE)
|
|
inventory_page = INV_MAIN_PAGE;
|
|
}
|
|
inv_last_page = INV_BLANK_PAGE;
|
|
INVENT_CHANGED;
|
|
}
|
|
|
|
void inv_update_fullscreen(uchar full) {
|
|
grs_bitmap *bm;
|
|
short a, b, c, d;
|
|
STORE_CLIP(a, b, c, d);
|
|
if (full) {
|
|
#ifdef SVGA_SUPPORT
|
|
|
|
if (inv_is_360_view()) {
|
|
ss_noscale_bitmap(&inv_view360_canvas.bm, GAME_MESSAGE_X, GAME_MESSAGE_Y);
|
|
} else {
|
|
inv_fullscrn_canvas.bm.flags |= BMF_TRANS;
|
|
// ss_bitmap(&(inv_fullscrn_canvas.bm),INVENTORY_PANEL_X,INVENTORY_PANEL_Y);
|
|
/* KLC -- Shouldn't this be ifdef'd out?
|
|
if (convert_use_mode == 5)
|
|
{
|
|
switch (i6d_device)
|
|
{
|
|
case I6D_CTM:
|
|
ss_noscale_bitmap(&(inv_fullscrn_canvas.bm),1,1);
|
|
break;
|
|
case I6D_VFX1:
|
|
// ss_noscale_bitmap(&(inv_fullscrn_canvas.bm),(320-inv_fullscrn_canvas.bm.w)/2,200 -
|
|
inv_fullscrn_canvas.bm.h);
|
|
ss_noscale_bitmap(&(inv_fullscrn_canvas.bm),(320-inv_fullscrn_canvas.bm.w)/2,INVENTORY_PANEL_Y
|
|
>> 1); break;
|
|
}
|
|
}
|
|
else
|
|
*/
|
|
ss_noscale_bitmap(&(inv_fullscrn_canvas.bm), INVENTORY_PANEL_X, INVENTORY_PANEL_Y);
|
|
inv_fullscrn_canvas.bm.flags &= ~BMF_TRANS;
|
|
}
|
|
#else
|
|
if (inv_is_360_view()) {
|
|
ss_noscale_bitmap(&inv_view360_canvas.bm, GAME_MESSAGE_X, GAME_MESSAGE_Y);
|
|
} else {
|
|
inv_fullscrn_canvas.bm.flags |= BMF_TRANS;
|
|
// ss_bitmap(&(inv_fullscrn_canvas.bm),INVENTORY_PANEL_X,INVENTORY_PANEL_Y);
|
|
ss_noscale_bitmap(&(inv_fullscrn_canvas.bm), INVENTORY_PANEL_X, INVENTORY_PANEL_Y);
|
|
inv_fullscrn_canvas.bm.flags &= ~BMF_TRANS;
|
|
}
|
|
#endif
|
|
}
|
|
region_set_invisible(inventory_region_full, !full);
|
|
bm = &inv_fullpage_canvas.bm;
|
|
bm->flags |= BMF_TRANS;
|
|
if (global_fullmap->cyber) {
|
|
ss_safe_set_cliprect(INVENTORY_PANEL_X + bm->w / 2, BUTTON_PANEL_Y, INVENTORY_PANEL_X + bm->w,
|
|
BUTTON_PANEL_Y + bm->h);
|
|
}
|
|
|
|
if (convert_use_mode == 3) {
|
|
// CC - something about this in 640x480 mode does not scale correctly
|
|
gr_bitmap(bm, 172, 470); // KLC - was ss_bitmap (with scaling)
|
|
} else {
|
|
ss_bitmap(bm, INVENTORY_PANEL_X, BUTTON_PANEL_Y);
|
|
}
|
|
|
|
bm->flags &= BMF_TRANS;
|
|
RESTORE_CLIP(a, b, c, d);
|
|
}
|
|
|
|
// ----------------------
|
|
// THE DISPLAY LIST ARRAY
|
|
// ----------------------
|
|
|
|
#define FIELD_OFFSET(fld) (offsetof(Player, fld))
|
|
|
|
inv_display inv_display_list[] = {
|
|
// Page 0, weapons, grenades, drugs
|
|
// weapons are there own thang, they have slots and stuff...
|
|
{0, 0,
|
|
WEAPON_X, AMMO_X, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, WEAPONS_PER_PAGE, NUM_WEAPON_SLOTS,
|
|
REF_STR_WeaponTitle,
|
|
ACTIVE_WEAPON,
|
|
0,
|
|
MFD_INV_WEAPON,
|
|
NULL,
|
|
NULL,
|
|
draw_weapons_list,
|
|
inventory_select_weapon,
|
|
weapon_use_func,
|
|
WEAP_CLASSES,
|
|
weapons_add_func,
|
|
weapon_drop_func,
|
|
WEAP_TRIP,
|
|
NULL,
|
|
0,
|
|
NULL},
|
|
// grenades
|
|
{0, 0,
|
|
GRENADE_LEFT_X, GRENADE_RIGHT_X, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, GRENADES_PER_PAGE, NUM_GRENADES,
|
|
REF_STR_GrenadeTitle,
|
|
ACTIVE_GRENADE,
|
|
FIELD_OFFSET(grenades),
|
|
MFD_INV_GRENADE,
|
|
grenade_name_func,
|
|
generic_quant_func,
|
|
generic_draw_list,
|
|
NULL,
|
|
grenade_use_func,
|
|
GREN_CLASSES,
|
|
grenade_add_func,
|
|
generic_drop_func,
|
|
GREN_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
// drug
|
|
{0, 0,
|
|
DRUG_LEFT_X, DRUG_RIGHT_X, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, DRUGS_PER_PAGE, NUM_DRUGS,
|
|
REF_STR_DrugTitle,
|
|
ACTIVE_DRUG,
|
|
FIELD_OFFSET(drugs),
|
|
MFD_INV_DRUG,
|
|
generic_name_func,
|
|
generic_quant_func,
|
|
generic_draw_list,
|
|
NULL,
|
|
drug_use_func,
|
|
DRUG_CLASSES,
|
|
generic_add_func,
|
|
generic_drop_func,
|
|
DRUG_TRIP,
|
|
triple2drug,
|
|
0,
|
|
generic_lines + NUM_GRENADES},
|
|
// Page 1, Hardwares.
|
|
{1, 0,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, ITEMS_PER_PAGE, NUM_HARDWAREZ,
|
|
REF_STR_HardwareTitle,
|
|
ACTIVE_HARDWARE,
|
|
FIELD_OFFSET(hardwarez),
|
|
MFD_INV_HARDWARE,
|
|
ware_name_func,
|
|
soft_quant_func,
|
|
generic_draw_list,
|
|
NULL,
|
|
ware_use_func,
|
|
HARD_CLASSES,
|
|
ware_add_func,
|
|
ware_drop_func,
|
|
HARD_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{1, 1,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, ITEMS_PER_PAGE, NUM_HARDWAREZ,
|
|
REF_STR_Null,
|
|
ACTIVE_HARDWARE,
|
|
FIELD_OFFSET(hardwarez),
|
|
MFD_INV_HARDWARE,
|
|
ware_name_func,
|
|
soft_quant_func,
|
|
generic_draw_list,
|
|
NULL,
|
|
ware_use_func,
|
|
HARD_CLASSES,
|
|
ware_add_func,
|
|
ware_drop_func,
|
|
HARD_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
// Page 2. General
|
|
{2, 0,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, ITEMS_PER_PAGE, NUM_GENERAL_SLOTS,
|
|
REF_STR_GeneralTitle,
|
|
ACTIVE_GENERAL,
|
|
0,
|
|
MFD_INV_GENINV,
|
|
NULL,
|
|
NULL,
|
|
draw_general_list,
|
|
inv_select_general,
|
|
general_use_func,
|
|
GENERAL_CLASSES,
|
|
general_add_func,
|
|
general_drop_func,
|
|
0,
|
|
NULL,
|
|
0,
|
|
(quantity_state *)general_lines},
|
|
{2, 1,
|
|
CENTER_X - RIGHT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, ITEMS_PER_PAGE, NUM_GENERAL_SLOTS,
|
|
REF_STR_Null,
|
|
ACTIVE_GENERAL,
|
|
0,
|
|
MFD_INV_GENINV,
|
|
NULL,
|
|
NULL,
|
|
draw_general_list,
|
|
inv_select_general,
|
|
general_use_func,
|
|
GENERAL_CLASSES,
|
|
general_add_func,
|
|
general_drop_func,
|
|
0,
|
|
NULL,
|
|
0,
|
|
(quantity_state *)general_lines},
|
|
// Page 2, Softwares.
|
|
{5, 0,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, NUM_COMBAT_SOFTS - 1, NUM_COMBAT_SOFTS - 1,
|
|
REF_STR_SoftTitle,
|
|
ACTIVE_COMBAT_SOFT,
|
|
FIELD_OFFSET(softs.combat),
|
|
MFD_INV_SOFT_COMBAT,
|
|
ware_name_func,
|
|
soft_quant_func,
|
|
generic_draw_list,
|
|
NULL,
|
|
ware_use_func,
|
|
SOFT_CLASSES,
|
|
ware_add_func,
|
|
ware_drop_func,
|
|
COMSOFT_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{5, 0,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN + 6 * Y_STEP,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, 1, 1,
|
|
REF_STR_Null,
|
|
ACTIVE_DEFENSE_SOFT,
|
|
FIELD_OFFSET(softs.defense),
|
|
MFD_INV_SOFT_DEFENSE,
|
|
ware_name_func,
|
|
soft_quant_func,
|
|
generic_draw_list,
|
|
NULL,
|
|
ware_use_func,
|
|
SOFT_CLASSES,
|
|
ware_add_func,
|
|
ware_drop_func,
|
|
DEFSOFT_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines + NUM_COMBAT_SOFTS},
|
|
{5, 0,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, NUM_ONESHOT_SOFTWARE, NUM_ONESHOT_SOFTWARE,
|
|
REF_STR_Null,
|
|
ACTIVE_MISC_SOFT,
|
|
FIELD_OFFSET(softs.misc),
|
|
MFD_INV_SOFT_MISC,
|
|
ware_name_func,
|
|
generic_quant_func,
|
|
generic_draw_list,
|
|
NULL,
|
|
ware_use_func,
|
|
SOFT_CLASSES,
|
|
ware_add_func,
|
|
ware_drop_func,
|
|
MISCSOFT_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines + NUM_COMBAT_SOFTS + NUM_DEFENSE_SOFTS},
|
|
{5, 0,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN + 6 * Y_STEP,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
NUM_ONESHOT_SOFTWARE, 1, NUM_MISC_SOFTWARE,
|
|
REF_STR_Null,
|
|
ACTIVE_MISC_SOFT,
|
|
FIELD_OFFSET(softs.misc),
|
|
MFD_INV_SOFT_MISC,
|
|
ware_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
NULL,
|
|
ware_use_func,
|
|
SOFT_CLASSES,
|
|
ware_add_func,
|
|
ware_drop_func,
|
|
MISCSOFT_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines + NUM_COMBAT_SOFTS + NUM_DEFENSE_SOFTS + NUM_ONESHOT_SOFTWARE},
|
|
// Page 7 main log page
|
|
{7, 0,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, ITEMS_PER_PAGE, NUM_LOG_LEVELS,
|
|
REF_STR_LogTitle,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(logs),
|
|
MFD_INV_NULL,
|
|
log_name_func,
|
|
generic_quant_func,
|
|
generic_draw_list,
|
|
log_use_func,
|
|
log_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{7, 1,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, ITEMS_PER_PAGE, NUM_LOG_LEVELS,
|
|
REF_STR_Null,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(logs),
|
|
MFD_INV_NULL,
|
|
log_name_func,
|
|
generic_quant_func,
|
|
generic_draw_list,
|
|
log_use_func,
|
|
log_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
#ifdef NEED_THIRD_LOGLVL_PAGE
|
|
{7, 2,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X, TOP_MARGIN - Y_STEP,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, ITEMS_PER_PAGE, NUM_LOG_LEVELS - 1,
|
|
REF_STR_Null,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(logs),
|
|
MFD_INV_NULL,
|
|
log_name_func,
|
|
generic_quant_func,
|
|
generic_draw_list,
|
|
log_use_func,
|
|
log_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
#endif
|
|
// Page 8, Data
|
|
{8, 0,
|
|
LEFT_MARGIN, ONETHIRD_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
FIRST_DATA, ITEMS_PER_PAGE, FIRST_DATA + ITEMS_PER_PAGE,
|
|
REF_STR_DataTitle,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
email_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
email_use_func,
|
|
email_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{8, 1,
|
|
ONETHIRD_X + LEFT_MARGIN, TWOTHIRDS_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
FIRST_DATA + ITEMS_PER_PAGE, ITEMS_PER_PAGE + 1, FIRST_DATA + 2 * ITEMS_PER_PAGE + 1,
|
|
REF_STR_Null,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
email_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
email_use_func,
|
|
email_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{8, 2,
|
|
TWOTHIRDS_X + LEFT_MARGIN, RIGHT_X, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
FIRST_DATA + 2 * ITEMS_PER_PAGE + 1, ITEMS_PER_PAGE + 1, NUM_EMAIL,
|
|
REF_STR_Null,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
email_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
email_use_func,
|
|
email_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
// Ammo page, off screen.
|
|
{9, 0,
|
|
AMMO_LEFT_1, AMMO_RIGHT_1, TOP_MARGIN,
|
|
TITLE_COLOR, ITEM_COLOR,
|
|
0, NUM_AMMO_TYPES, NUM_AMMO_TYPES,
|
|
REF_STR_PistolCartTitle,
|
|
ACTIVE_CART,
|
|
FIELD_OFFSET(cartridges),
|
|
MFD_INV_AMMO,
|
|
ammo_name_func,
|
|
generic_quant_func,
|
|
generic_draw_list,
|
|
NULL,
|
|
NULL,
|
|
AMMO_CLASSES,
|
|
generic_add_func,
|
|
generic_drop_func,
|
|
AMMO_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
// Pages 50-52 Email
|
|
{50, 0,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_EmailTitle,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
email_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
email_use_func,
|
|
email_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{50, 0,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_EmailTitle,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
NULL,
|
|
NULL,
|
|
email_more_draw,
|
|
email_more_use,
|
|
email_more_use,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{50, 1,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_Null,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
email_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
email_use_func,
|
|
email_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{50, 1,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_Null,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
NULL,
|
|
NULL,
|
|
email_more_draw,
|
|
email_more_use,
|
|
email_more_use,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{51, 2,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_EmailTitle,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
email_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
email_use_func,
|
|
email_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{51, 2,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_Null,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
NULL,
|
|
NULL,
|
|
email_more_draw,
|
|
email_more_use,
|
|
email_more_use,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{51, 3,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_Null,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
email_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
email_use_func,
|
|
email_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{51, 3,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_EmailTitle,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
NULL,
|
|
NULL,
|
|
email_more_draw,
|
|
email_more_use,
|
|
email_more_use,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{52, 4,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_EmailTitle,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
email_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
email_use_func,
|
|
email_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{52, 4,
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_EmailTitle,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
NULL,
|
|
NULL,
|
|
email_more_draw,
|
|
email_more_use,
|
|
email_more_use,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{52, 5,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_Null,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
email_name_func,
|
|
null_quant_func,
|
|
generic_draw_list,
|
|
email_use_func,
|
|
email_use_func,
|
|
SOFT_CLASSES,
|
|
email_add_func,
|
|
email_drop_func,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
{52, 5,
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN + (ITEMS_PER_PAGE - 1) * Y_STEP,
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC,
|
|
0, ITEMS_PER_PAGE - 1, NUM_EMAIL_PROPER,
|
|
REF_STR_EmailTitle,
|
|
NULL_ACTIVE,
|
|
FIELD_OFFSET(email),
|
|
MFD_INV_NULL,
|
|
NULL,
|
|
NULL,
|
|
email_more_draw,
|
|
email_more_use,
|
|
email_more_use,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
EMAIL_TRIP,
|
|
NULL,
|
|
0,
|
|
generic_lines},
|
|
// Page 20 logs
|
|
#define LOG_PAGE(i) \
|
|
{FIRST_LOG_PAGE + i, 0, \
|
|
LEFT_MARGIN, CENTER_X - RIGHT_MARGIN, TOP_MARGIN, \
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC, \
|
|
NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL, \
|
|
ITEMS_PER_PAGE, NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL + ITEMS_PER_PAGE, \
|
|
REF_STR_LogName0 + i, \
|
|
NULL_ACTIVE, \
|
|
FIELD_OFFSET(email), \
|
|
MFD_INV_NULL, \
|
|
email_name_func, \
|
|
null_quant_func, \
|
|
generic_draw_list, \
|
|
email_use_func, \
|
|
email_use_func, \
|
|
SOFT_CLASSES, \
|
|
email_add_func, \
|
|
email_drop_func, \
|
|
EMAIL_TRIP, \
|
|
NULL, \
|
|
0, \
|
|
generic_lines}, \
|
|
{FIRST_LOG_PAGE + i, 2, \
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN - Y_STEP, \
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC, \
|
|
NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL + 2 * ITEMS_PER_PAGE + 1, \
|
|
1, NUM_EMAIL_PROPER + ((i) + 1) * LOGS_PER_LEVEL , \
|
|
REF_STR_Null, \
|
|
NULL_ACTIVE, \
|
|
FIELD_OFFSET(email), \
|
|
MFD_INV_NULL, \
|
|
email_name_func, \
|
|
null_quant_func, \
|
|
generic_draw_list, \
|
|
email_use_func, \
|
|
email_use_func, \
|
|
SOFT_CLASSES, \
|
|
email_add_func, \
|
|
email_drop_func, \
|
|
EMAIL_TRIP, \
|
|
NULL, \
|
|
0, \
|
|
generic_lines + 2 * ITEMS_PER_PAGE}, \
|
|
{FIRST_LOG_PAGE + i, 1, \
|
|
CENTER_X + LEFT_MARGIN, RIGHT_X - RIGHT_MARGIN, TOP_MARGIN, \
|
|
TITLE_COLOR, EMAIL_COLOR_FUNC, \
|
|
NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL + ITEMS_PER_PAGE, ITEMS_PER_PAGE, \
|
|
NUM_EMAIL_PROPER + (i)*LOGS_PER_LEVEL + 2 * ITEMS_PER_PAGE + 1, \
|
|
REF_STR_Null, \
|
|
NULL_ACTIVE, \
|
|
FIELD_OFFSET(email), \
|
|
MFD_INV_NULL, \
|
|
email_name_func, \
|
|
null_quant_func, \
|
|
generic_draw_list, \
|
|
email_use_func, \
|
|
email_use_func, \
|
|
SOFT_CLASSES, \
|
|
email_add_func, \
|
|
email_drop_func, \
|
|
EMAIL_TRIP, \
|
|
NULL, \
|
|
0, \
|
|
generic_lines}
|
|
|
|
// Hey these pages MUST BE LAST.
|
|
LOG_PAGE(0),
|
|
#ifdef EXPLICIT_LOG_PAGES
|
|
LOG_PAGE(1),
|
|
LOG_PAGE(2),
|
|
LOG_PAGE(3),
|
|
LOG_PAGE(4),
|
|
LOG_PAGE(5),
|
|
LOG_PAGE(6),
|
|
LOG_PAGE(7),
|
|
LOG_PAGE(8),
|
|
LOG_PAGE(9),
|
|
LOG_PAGE(10),
|
|
LOG_PAGE(11),
|
|
LOG_PAGE(12),
|
|
LOG_PAGE(13),
|
|
LOG_PAGE(14),
|
|
#endif // EXPLICIT_LOG_PAGES
|
|
|
|
};
|
|
|
|
#define NUM_INV_DISPLAYS (sizeof(inv_display_list) / sizeof(inv_display))
|
|
|
|
#define DUMMY_LOG_INDEX (NUM_INV_DISPLAYS - 3)
|
|
|
|
void super_drop_func(int dispnum, int row) {
|
|
inv_display *dp = &(inv_display_list[dispnum]);
|
|
dp->drop(dp, row);
|
|
}
|
|
|
|
void super_use_func(int dispnum, int row) {
|
|
inv_display *dp = &(inv_display_list[dispnum]);
|
|
dp->use(dp, row);
|
|
}
|
|
|
|
void gen_log_displays(int pgnum) {
|
|
inv_display *dp = &inv_display_list[DUMMY_LOG_INDEX];
|
|
pgnum -= FIRST_LOG_PAGE;
|
|
if (pgnum >= 0 && pgnum < NUM_LOG_LEVELS) {
|
|
dp->pgnum = FIRST_LOG_PAGE + pgnum;
|
|
dp->first = NUM_EMAIL_PROPER + pgnum * LOGS_PER_LEVEL;
|
|
dp->listlen = NUM_EMAIL_PROPER + ITEMS_PER_PAGE + pgnum * LOGS_PER_LEVEL;
|
|
dp->titlenum = MKREF(RES_lognames, pgnum);
|
|
dp++;
|
|
dp->pgnum = FIRST_LOG_PAGE + pgnum;
|
|
dp->first = NUM_EMAIL_PROPER + pgnum * LOGS_PER_LEVEL + 2 * ITEMS_PER_PAGE + 1;
|
|
dp->listlen = NUM_EMAIL_PROPER + (pgnum + 1) * LOGS_PER_LEVEL;
|
|
dp++;
|
|
dp->pgnum = FIRST_LOG_PAGE + pgnum;
|
|
dp->first = NUM_EMAIL_PROPER + pgnum * LOGS_PER_LEVEL + ITEMS_PER_PAGE;
|
|
dp->listlen = NUM_EMAIL_PROPER + pgnum * LOGS_PER_LEVEL + 2 * ITEMS_PER_PAGE + 1;
|
|
}
|
|
}
|
|
|
|
uchar gen_inv_page(int pgnum, int *i, inv_display **dp) {
|
|
if (*i == 0)
|
|
gen_log_displays(pgnum);
|
|
for (; *i < NUM_INV_DISPLAYS; (*i)++) {
|
|
inv_display *idp = &inv_display_list[*i];
|
|
if (idp->pgnum == pgnum) {
|
|
*dp = idp;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#define LOG_PAGE_SHF 8
|
|
|
|
uchar gen_inv_displays(int *i, inv_display **dp) {
|
|
if (*i == 0)
|
|
gen_log_displays(inventory_page);
|
|
for (; *i < NUM_INV_DISPLAYS; (*i)++) {
|
|
inv_display *idp = &inv_display_list[*i];
|
|
*dp = idp;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void absorb_object_on_cursor(ushort keycode, uint32_t context, intptr_t data) {
|
|
if (object_on_cursor == 0)
|
|
return;
|
|
|
|
if (inventory_add_object(object_on_cursor, TRUE))
|
|
pop_cursor_object();
|
|
}
|