1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19 /*
20 * $Source: r:/prj/cit/src/RCS/mfdfunc.c $
21 * $Revision: 1.237 $
22 * $Author: mahk $
23 * $Date: 1994/11/23 20:34:20 $
24 *
25 */
26 #define __MFDFUNC_SRC
27
28 // Source code for all MFD Expose/Handler function pairs
29 // This file is for callbacks only, actual infrastructure belongs
30 // in newmfd.c
31
32 #include <string.h>
33
34 #include "objprop.h" // temp
35 #include "tools.h"
36 #include "colors.h"
37 #include "mainloop.h"
38 #include "gameloop.h"
39 #include "mfdart.h"
40 #include "gamescr.h"
41 //¥¥#include "anim.h"
42 //¥¥#include "animreg.h"
43 #include "objwarez.h"
44 #include "objsim.h"
45 #include "gamestrn.h"
46 #include "cybstrng.h"
47 #include "mfdint.h"
48 #include "mfdext.h"
49 #include "mfddims.h"
50 #include "player.h"
51 #include "wares.h"
52 #include "drugs.h"
53 #include "weapons.h"
54 #include "automap.h"
55 #include "target.h"
56 #include "criterr.h"
57 #include "mfdgadg.h"
58 #include "objclass.h"
59 #include "otrip.h"
60 #include "citres.h"
61 #include "objuse.h"
62 #include "sfxlist.h"
63 #include "musicai.h"
64 #include "sideicon.h"
65 #include "hud.h"
66 #include "textmaps.h"
67 #include "fullscrn.h"
68 #include "objbit.h"
69 #include "limits.h"
70 #include "mapflags.h"
71 #include "input.h"
72 #include "cit2d.h"
73 #include "gr2ss.h"
74 #include "mfdgames.h"
75 #include "shodan.h"
76
77 #define MFD_SHIELD_FUNC 19
78
79 // ------------
80 // Useful Defines
81 // ------------
82
83 #define OVERLOAD_BUTTON_Y (MFD_VIEW_HGT - 24)
84 #define TEMPR_X 47
85 #define TEMPR_Y 27
86 #define TEMPR_WIDTH 13
87 #define TEMPR_HEIGHT 16
88 #define TEMPR_DIV 8
89 #define SETTING_TEXT 46
90 #define ENERGY_TEXT_LEN 40
91
92 static uchar in_or_out = FALSE;
93
94 extern void mouse_unconstrain(void);
95 extern void mfd_ammo_expose(ubyte control);
96 extern uchar mfd_ammo_handler(MFD *m, uiEvent *ev);
97
98 #define LNAME_BUFSIZE 128
99
100 #define GOOD_RED (RED_BASE + 5)
101 #define ITEM_COLOR (0x5A)
102 #define SELECTED_ITEM_COLOR (0x4C)
103 #define UNAVAILABLE_ITEM_COLOR (0x60)
104 #define X_MARGIN 1
105 #define Y_STEP 5
106
107 extern void check_panel_ref(uchar punt);
108
109 #define PUSH_CANVAS(x) gr_push_canvas(x)
110 #define POP_CANVAS() gr_pop_canvas()
111
112 #define MFD_REGION(m) ((full_game_3d) ? &(m)->reg2 : &(m)->reg)
113
114 // -------
115 // Globals
116 // -------
117
118 // Forward declaration of array at bottom of file
119
120 extern void lamp_set_vals(void);
121 extern uchar full_game_3d;
122
123 LGRegion *mfd_regions[NUM_MFDS];
124
125 // ----------------
126 // Local Prototypes
127 // ----------------
128
129 void mfd_clear_view(void);
130 int mfd_bmap_id(int triple);
131 void draw_blank_mfd(void);
132 void draw_mfd_item_spew(Ref id, int n);
133
134 errtype mfd_item_init(MFD_Func *mfd);
135 void mfd_expose_blank(MFD *m, ubyte control);
136 void mfd_item_expose(MFD *m, ubyte control);
137 uchar mfd_item_handler(MFD *m, uiEvent *e);
138 void mfd_item_micro_expose(uchar full, int triple);
139 void mfd_item_micro_hires_expose(uchar full, int triple);
140
141 void mfd_general_inv_expose(MFD *m, ubyte control, ObjID id, uchar full);
142 uchar mfd_general_inv_handler(MFD *m, uiEvent *ev, int row);
143
144 uchar mfd_lantern_button_handler(MFD *m, LGPoint bttn, uiEvent *ev, void *data);
145 void mfd_lantern_setting(int setting);
146 errtype mfd_lanternware_init(MFD_Func *f);
147 void mfd_lanternware_expose(MFD *mfd, ubyte control);
148
149 void draw_ammo_button(int triple, short x, short y);
150
151 errtype mfd_anim_init();
152 void mfd_anim_expose(MFD *m, ubyte control);
153
154 errtype mfd_weapon_init(MFD_Func *mfd);
155 void weapon_mfd_for_reload(void);
156 void mfd_weapon_expose(MFD *m, ubyte control);
157 uchar mfd_weapon_handler(MFD *m, uiEvent *e);
158 uchar mfd_weapon_beam_handler(MFD *m, uiEvent *e);
159 uchar mfd_weapon_projectile_handler(MFD *m, uiEvent *e, weapon_slot *ws);
160 uchar mfd_weapon_expose_projectile(MFD *m, weapon_slot *ws, ubyte control);
161 void mfd_weapon_expose_beam(weapon_slot *ws, ubyte id, uchar Redraw);
162 void mfd_weapon_draw_temp(ubyte temp);
163 void mfd_weapon_draw_ammo_buttons(int num_ammo_buttons, int ammo_subclass, ubyte *ammo_types, ubyte curr_ammo_type,
164 int ammo_count);
165 void mfd_weapon_draw_beam_status_bar(int charge, int setting, uchar does_overload);
166
167 void mfd_setup_keypad(char special);
168
169 uchar weapon_mfd_temp;
170
171 void mfd_bioware_expose(MFD *m, ubyte control);
172
173 // ------------
174 // USEFUL STUFF
175 // ------------
176
mfd_clear_view(void)177 void mfd_clear_view(void) {
178 if (full_game_3d)
179 return;
180 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
181 ss_bitmap(&mfd_background, 0, 0);
182 // gr_bitmap(&mfd_background, 0, 0);
183 mfd_add_rect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
184 }
185
mfd_bmap_id(int triple)186 int mfd_bmap_id(int triple) {
187 int obclass = TRIP2CL(triple);
188 int t = CPTRIP(triple);
189 return MKREF(RES_mfdClass_1 + obclass, t);
190 }
191
draw_blank_mfd(void)192 void draw_blank_mfd(void) {
193 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
194 draw_res_bm(REF_IMG_bmBlankMFD, 0, 0);
195 // draw_hires_resource_bm(REF_IMG_bmBlankMFD, 0, 0);
196 draw_res_bm(MKREF(RES_mfdArtOverlays, MFD_ART_TRIOP), 0, 0);
197 }
198
199 // --------------------
200 // FUNCTION INITIALIZER
201 // --------------------
202
203 // ---------------------------------------------------------------------------
204 // mfd_init_funcs()
205 //
206 // Here is where you set the global MFD_Func structures to point at
207 // expose/handler pairs, and also where you set their flags. This is also
208 // where MFD virtual slots are set to point at their functions.
209
mfd_init_funcs()210 void mfd_init_funcs() {
211 int i;
212 // Define a couple of MFD functions.
213 for (i = 0; i < MFD_NUM_FUNCS; i++)
214 if (mfd_funcs[i].init != NULL) {
215 errtype err = mfd_funcs[i].init(&mfd_funcs[i]);
216 if (err != OK)
217 critical_error(CRITERR_MISC | 1);
218 }
219
220 // Set slots to point at functions
221 set_slot_to_func(MFD_WEAPON_SLOT, MFD_WEAPON_FUNC, MFD_ACTIVE);
222 set_slot_to_func(MFD_ITEM_SLOT, MFD_ITEM_FUNC, MFD_ACTIVE);
223 set_slot_to_func(MFD_MAP_SLOT, MFD_MAP_FUNC, MFD_ACTIVE);
224 set_slot_to_func(MFD_INFO_SLOT, MFD_EMPTY_FUNC, MFD_ACTIVE);
225 set_slot_to_func(MFD_TARGET_SLOT, MFD_TARGET_FUNC, MFD_ACTIVE);
226
227 // set_slot_to_func(MFD_SPECIAL_SLOT, MFD_ANIM_FUNC, MFD_FLASH);
228 // set_slot_to_func(MFD_SPECIAL_SLOT, MFD_EMPTY_FUNC, MFD_EMPTY);
229
230 // debug_mfd_func_table();
231 // debug_mfd_slots_table();
232 return;
233 }
234
235 // ===========================================================================
236 //
237 // ===========================================================================
238
239 // --------------------
240 // ACTUAL MFD FUNCTIONS
241 // --------------------
242
243 // ===========================================================================
244 // * THE WEAPON MFD *
245 // ===========================================================================
246
247 // Hey, wow, floats and doubles are UNcool.
248
249 #define mfd_pixels_per_charge_unit (FIX_UNIT * 69 / 100) // How many hor. pixels equals a % of charge?
250 #define mfd_charge_units_per_pixel (FIX_UNIT * 100 / 69)
251
252 // note _LEFT is 0, _RIGHT is 1
253 #define MFDLeftOffs MFD_LEFT
254 #define MFDRightOffs MFD_RIGHT
255 #define MFDLastWeapon 0
256 #define MFDAmmo 2
257 #define MFDLastBeamHeat 4
258
259 #define MFD_Access(which, lorr) mfd_fdata[MFD_WEAPON_FUNC][(which) + (lorr)]
260
261 #define MFDGetLastLeftWeapon mfd_fdata[MFD_WEAPON_FUNC][0]
262 #define MFDGetLastRightWeapon mfd_fdata[MFD_WEAPON_FUNC][1]
263 #define MFDGetLeftAmmo mfd_fdata[MFD_WEAPON_FUNC][2]
264 #define MFDGetRightAmmo mfd_fdata[MFD_WEAPON_FUNC][3]
265 #define MFDGetLastLeftBeamHeat mfd_fdata[MFD_WEAPON_FUNC][4]
266 #define MFDGetLastRightBeamHeat mfd_fdata[MFD_WEAPON_FUNC][5]
267 #define MFDSetLastLeftWeapon(n) (mfd_fdata[MFD_WEAPON_FUNC][0] = (n))
268 #define MFDSetLastRightWeapon(n) (mfd_fdata[MFD_WEAPON_FUNC][1] = (n))
269 #define MFDSetLeftAmmo(n) (mfd_fdata[MFD_WEAPON_FUNC][2] = (n))
270 #define MFDSetRightAmmo(n) (mfd_fdata[MFD_WEAPON_FUNC][3] = (n))
271 #define MFDSetLastLeftBeamHeat(n) (mfd_fdata[MFD_WEAPON_FUNC][4] = (n))
272 #define MFDSetLastRightBeamHeat(n) (mfd_fdata[MFD_WEAPON_FUNC][5] = (n))
273
274 #define MFD_BEAMWPN_STAT_BORDER GREEN_YELLOW_BASE
275 #define MFD_BEAMWPN_STAT_CHARGE WHITE
276 #define MFD_BEAMWPN_STAT_MAXCHARGE PURPLE_BASE
277 #define MFD_BEAMWPN_STAT_DEADSPACE BLACK
278
279 #define WEAPON_ART_Y 7
280
281 #define AMMO_BUTTON_H 24
282 #define AMMO_BUTTON_W 23
283 #define AMMO_BUTTON_Y (MFD_VIEW_HGT - AMMO_BUTTON_H)
284 #define AMMO_STRING_Y (AMMO_BUTTON_Y - 4)
285 #define AMMO_NAME_Y (MFD_VIEW_HGT - 6)
286
287 #define AMMO_BUTTON_X1 29
288 #define AMMO_BUTTON_DX1 0
289 #define AMMO_BUTTON_X2 11
290 #define AMMO_BUTTON_DX2 31
291 #define AMMO_BUTTON_X3 1
292 #define AMMO_BUTTON_DX3 24
293
294 #define MFD_BEAM_RECT_X1 1
295 #define MFD_BEAM_RECT_X2 71
296 #define MFD_BEAM_RECT_Y1 52
297 #define MFD_BEAM_RECT_Y2 56
298
299 LGRect MfdAmmoRectZone = {{0, AMMO_BUTTON_Y}, {MFD_VIEW_WID, AMMO_BUTTON_Y + AMMO_BUTTON_H}};
300 LGRect MfdBeamStatusRect;
301
302 #define NO_CONSTRAIN NUM_MFDS
303 static ubyte beam_constrain = NO_CONSTRAIN;
304
305 LGCursor slider_cursor;
306 grs_bitmap slider_cursor_bmap;
307
308 // ---------- WEAPON MFD FUNC ---------------
309
310 // --------------------------------------------------------------------------
311 // mfd_weapon_init()
312 //
313 // Initializes the MFD weapons function.
314
mfd_weapon_init(MFD_Func * mfd)315 errtype mfd_weapon_init(MFD_Func *mfd) {
316 #ifndef NO_DUMMIES
317 void *yum;
318 yum = mfd;
319 #endif // NO_DUMMIES
320
321 MFDSetLastLeftWeapon(0);
322 MFDSetLastRightWeapon(0);
323 MFDSetLeftAmmo(0xFF);
324 MFDSetRightAmmo(0xFF);
325
326 MfdBeamStatusRect.ul.x = MFD_BEAM_RECT_X1;
327 MfdBeamStatusRect.ul.y = MFD_BEAM_RECT_Y1;
328 MfdBeamStatusRect.lr.x = MFD_BEAM_RECT_X2;
329 MfdBeamStatusRect.lr.y = MFD_BEAM_RECT_Y2;
330
331 return OK;
332 }
333
334 // --------------------------------------------------------------------------
335 // mfd_weapon_expose()
336 //
337 // Draws an overlay of a weapon in the current mfd slot.
338
mfd_weapon_expose(MFD * m,ubyte control)339 void mfd_weapon_expose(MFD *m, ubyte control) {
340 weapon_slot *ws;
341 char buf[50];
342 int triple;
343 uchar punt = player_struct.actives[ACTIVE_WEAPON] == EMPTY_WEAPON_SLOT;
344 uchar Redraw = FALSE;
345 uchar RedrawAmmoArea = TRUE;
346 extern uchar full_game_3d;
347
348 if (control == 0) {
349 uiCursorStack *cs;
350 weapon_mfd_temp = FALSE;
351
352 uiGetRegionCursorStack(MFD_REGION(m), &cs);
353 uiPopCursorEvery(cs, &slider_cursor);
354
355 if (beam_constrain == m->id) {
356 beam_constrain = NO_CONSTRAIN;
357 // KLC mouse_unconstrain();
358 }
359 return;
360 }
361
362 // Get the triple for the current weapon
363
364 if (!punt)
365 ws = &player_struct.weapons[player_struct.actives[ACTIVE_WEAPON]];
366 if (ws->type == EMPTY_WEAPON_SLOT)
367 punt = TRUE;
368 if (punt) {
369 mfd_expose_blank(m, control);
370 return;
371 }
372
373 triple = MAKETRIP(CLASS_GUN, ws->type, ws->subtype);
374
375 if (control & MFD_EXPOSE) {
376
377 PUSH_CANVAS(pmfd_canvas);
378 mfd_clear_rects();
379
380 if (control & MFD_EXPOSE_FULL)
381 Redraw = TRUE;
382 if (MFD_Access(m->id, MFDLastWeapon) != player_struct.actives[ACTIVE_WEAPON]) {
383 Redraw = TRUE;
384 MFD_Access(m->id, MFDLastWeapon) = player_struct.actives[ACTIVE_WEAPON];
385 MFD_Access(m->id, MFDAmmo) = 0xFF;
386 weapon_mfd_temp = FALSE;
387 }
388
389 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
390 if (!full_game_3d)
391 ss_bitmap(&mfd_background, 0, 0);
392 // gr_bitmap(&mfd_background, 0, 0);
393
394 // Draw the appropriate weapon art.
395 // We draw it here because it is effectively "background"
396 // Hopefully update-rects will take care of us..
397 {
398 int id = mfd_bmap_id(triple);
399 draw_res_bm(id, (MFD_VIEW_WID - res_bm_width(id)) / 2, WEAPON_ART_Y);
400 // draw_hires_resource_bm(id,
401 // (SCONV_X(MFD_VIEW_WID)-res_bm_width(id))/2, SCONV_Y(WEAPON_ART_Y)); // is this right?
402 }
403
404 // This is all stuff that should be drawn for a full expose of
405 // a new weapon
406 if (Redraw) {
407 short y = 2;
408 short w, h;
409
410 // Print name of gun in top line of mfd
411 get_weapon_long_name(ws->type, ws->subtype, buf);
412 mfd_draw_string(buf, X_MARGIN, y, GOOD_RED, TRUE);
413 gr_string_size(buf, &w, &h);
414 y += h;
415
416 mfd_add_rect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
417 }
418
419 // Here is where the dynamic info for a given weapon is drawn; ie; data that
420 // requires a redraw even when the current weapon has not changed
421
422 if ((ws->type == GUN_SUBCLASS_BEAM) || (ws->type == GUN_SUBCLASS_BEAMPROJ))
423 mfd_weapon_expose_beam(ws, m->id, Redraw);
424 else if (ws->type != GUN_SUBCLASS_HANDTOHAND)
425 RedrawAmmoArea = mfd_weapon_expose_projectile(m, ws, control);
426
427 // Redraw everything
428 POP_CANVAS();
429 mfd_update_rects(m);
430 }
431
432 return;
433 }
434
435 // --------------------------------------------------------------------------
436 // mfd_weapon_expose_projectile()
437 //
438 // Exposes relevant weapons mfd info for a projectile weapon.
439 // returns whether or not it drew the ammo buttons
440
mfd_weapon_expose_projectile(MFD * m,weapon_slot * ws,ubyte control)441 uchar mfd_weapon_expose_projectile(MFD *m, weapon_slot *ws, ubyte control) {
442 int num_ammo_buttons;
443 int ammo_subclass;
444 ubyte ammo_types[3];
445 uchar RedrawAmmoFlag = FALSE;
446
447 // Get the ammo data for the current weapon
448 get_available_ammo_type(ws->type, ws->subtype, &num_ammo_buttons, ammo_types, &ammo_subclass);
449
450 /*
451 * FIXME: shamaz 20.04.2020
452 *
453 * The following two lines were present in the code provided by
454 * Nightdive Studios, LLC along with the following comment:
455 * > ammo_type and setting have same memory location in
456 * > weapon_slot union. setting can have values greater than
457 * > num ammo buttons so check for and fix oob
458 * It's not clear how oob access can happen because .setting and
459 * .ammo_type fields are used independently (based on a type of
460 * the weapon, e.g. beam or other range weapon) and never .setting
461 * value is treated as .ammo_type and vice versa.
462 *
463 * On the other hand they cause a problem when you reload your
464 * weapon with the last clip (of any suitable type). At first, if
465 * you unload this clip, it get lost (disappears from your
466 * inventory forever) even if not depleted completely. At second,
467 * this final clip is replaced with a clip of other type
468 * (sometimes even inappropriate for this particular weapon).
469 *
470 * So I find it better to comment these lines out. Seems to be
471 * perfectly safe, but some more testing is required.
472 */
473 /* if (ws->ammo_type >= num_ammo_buttons) */
474 /* ws->ammo_type = (num_ammo_buttons ? ammo_types[0] : 0); */
475
476 if ((control & MFD_EXPOSE_FULL) || (ws->ammo == 0))
477 RedrawAmmoFlag = TRUE;
478 else if (MFD_Access(m->id, MFDAmmo) != ws->ammo) {
479 RedrawAmmoFlag = TRUE;
480 MFD_Access(m->id, MFDAmmo) = ws->ammo;
481 }
482
483 // Redraw ammo buttons if neccessary
484 if (RedrawAmmoFlag)
485 mfd_weapon_draw_ammo_buttons(num_ammo_buttons, ammo_subclass, ammo_types, ws->ammo_type, ws->ammo);
486
487 return RedrawAmmoFlag;
488 }
489
490 // ---------------------------------------------------------------------------
491 // mfd_weapon_draw_ammo_buttons()
492 //
493 // Draws the labelled buttons of ammo on a projectile gun's mfd
494
495 #define MAX_CART_COLORS 3
496 #define CARTRIDGE_BRACKET 8 // cartridges per color
497 static uchar cart_colors[MAX_CART_COLORS] = {GOOD_RED, 0x4b, GREEN_BASE + 2};
498
draw_ammo_button(int triple,short x,short y)499 void draw_ammo_button(int triple, short x, short y) {
500 short h;
501 int id;
502 int carts = player_struct.cartridges[CPTRIP(triple)];
503 ubyte cnum = lg_min(MAX_CART_COLORS - 1, (carts - 1) / CARTRIDGE_BRACKET);
504
505 // Draw the outline of an ammo box
506 draw_res_bm(REF_IMG_BullFrame + lg_min(2, lg_max(3 - carts, 0)), x, y);
507 id = mfd_bmap_id(triple);
508 h = res_bm_height(id);
509 draw_res_bm(id, x + 4, y + AMMO_BUTTON_H - 4 - h);
510 // draw_hires_resource_bm(id, SCONV_X(x+4), SCONV_Y(y+AMMO_BUTTON_H-3)-h);
511 if (carts > 0) {
512 int cnt = carts % CARTRIDGE_BRACKET;
513 if (cnt == 0)
514 cnt = CARTRIDGE_BRACKET;
515 gr_set_fcolor(cart_colors[cnum]);
516 while (cnt-- > 0) {
517 short cy = y + AMMO_BUTTON_H - 5 - 2 * cnt;
518 ss_hline(x + AMMO_BUTTON_W - 6, cy, x + AMMO_BUTTON_W - 5);
519 }
520 }
521 if (carts > 0 || player_struct.partial_clip[CPTRIP(triple)] > 0)
522 mfd_add_rect(x, y, x + AMMO_BUTTON_W, y + AMMO_BUTTON_H);
523 }
524
mfd_weapon_draw_ammo_buttons(int num_ammo_buttons,int ammo_subclass,ubyte * ammo_types,ubyte curr_ammo_type,int ammo_count)525 void mfd_weapon_draw_ammo_buttons(int num_ammo_buttons, int ammo_subclass, ubyte *ammo_types, ubyte curr_ammo_type,
526 int ammo_count) {
527 int i, triple;
528
529 // Draw ammo boxes
530 if (ammo_count == 0) {
531 for (i = 0; i < num_ammo_buttons; i++) {
532 short x = (ammo_types[i]) * AMMO_BUTTON_W;
533 triple = MAKETRIP(CLASS_AMMO, ammo_subclass, ammo_types[i]);
534 // Get useful ammo information for box label
535 draw_ammo_button(triple, x, AMMO_BUTTON_Y);
536 }
537 if (num_ammo_buttons > 0)
538 mfd_draw_string(get_temp_string(REF_STR_ClickToLoad), 1, AMMO_STRING_Y, GREEN_YELLOW_BASE, TRUE);
539 } else {
540 char buf[4], buf2[50];
541 triple = MAKETRIP(CLASS_AMMO, ammo_subclass, curr_ammo_type);
542
543 sprintf(buf, "%d", ammo_count);
544 gr_set_font(ResGet(RES_mediumLEDFont));
545 mfd_string_shadow = MFD_SHADOW_NEVER;
546 mfd_draw_font_string(buf, MFD_VIEW_WID - gr_string_width(buf) - 2, AMMO_BUTTON_Y + 2, GOOD_RED,
547 RES_mediumLEDFont, TRUE);
548 mfd_string_shadow = MFD_SHADOW_FULLSCREEN; // default
549
550 get_object_short_name(triple, buf2, 50);
551 gr_set_font(ResGet(MFD_FONT));
552 mfd_draw_string(buf2, MFD_VIEW_WID - gr_string_width(buf2) - 2, AMMO_NAME_Y, GREEN_YELLOW_BASE, TRUE);
553
554 draw_ammo_button(triple, 0, AMMO_BUTTON_Y);
555 draw_res_bm(REF_IMG_BullRightArrow, AMMO_BUTTON_W, AMMO_BUTTON_Y);
556 }
557
558 if ((num_ammo_buttons == 0) && (ammo_count == 0)) {
559 draw_res_bm(REF_IMG_NoAmmo, (MFD_VIEW_WID - res_bm_width(REF_IMG_NoAmmo)) / 2, AMMO_BUTTON_Y);
560 }
561 mfd_add_rect(0, AMMO_STRING_Y, MFD_VIEW_WID, MFD_VIEW_HGT);
562 return;
563 }
564
565 #define MFD_BEAM_WARM 0x40
566 #define MFD_BEAM_HOT 0x35
567 #define MFD_BEAM_READY 0x58
568
569 ubyte temp_levels[TEMPR_WIDTH] = {1, 2, 2, 3, 3, 4, 5, 6, 7, 9, 11, 13, 16};
570
571 // --------------------------------------------------------------------------
572 // mfd_weapon_draw_temp()
573 //
574
mfd_weapon_draw_temp(ubyte temp)575 void mfd_weapon_draw_temp(ubyte temp) {
576 int i;
577
578 gr_set_fcolor(MFD_BEAM_READY);
579
580 for (i = 0; i < TEMPR_WIDTH; i++) {
581 if (i == 5)
582 gr_set_fcolor(MFD_BEAM_WARM);
583 else if (i == 10)
584 gr_set_fcolor(MFD_BEAM_HOT);
585
586 if (temp >= i * TEMPR_DIV)
587 ss_vline(TEMPR_X + i * 2, TEMPR_Y + TEMPR_HEIGHT - temp_levels[i], TEMPR_Y + TEMPR_HEIGHT);
588 }
589 }
590
591 // --------------------------------------------------------------------------
592 // mfd_weapon_draw_beam_status_bar()
593 //
594 // Takes the current charge and the maximum charge, and draws the dynamic
595 // portion of the beam weapon status bar
596
mfd_weapon_draw_beam_status_bar(int amt,int setting,uchar does_overload)597 void mfd_weapon_draw_beam_status_bar(int amt, int setting, uchar does_overload) {
598 ubyte setting_x;
599
600 setting = (BEAM_SETTING_VAL(setting) < MIN_ENERGY_USE) ? 1 : (BEAM_SETTING_VAL(setting) - MIN_ENERGY_USE);
601 if (does_overload)
602 setting <<= 1;
603
604 setting++;
605
606 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
607
608 gr_set_fcolor(MFD_BEAMWPN_STAT_BORDER); // OUTLINE
609 ss_box(MfdBeamStatusRect.ul.x - 1, MfdBeamStatusRect.ul.y - 1, MfdBeamStatusRect.lr.x + 1,
610 MfdBeamStatusRect.lr.y + 1);
611
612 setting_x = (ubyte)fix_int(setting * mfd_pixels_per_charge_unit);
613 setting_x = lg_min(MfdBeamStatusRect.lr.x - MfdBeamStatusRect.ul.x, setting_x);
614
615 // draw the settings bar only if we're not in overload mode
616
617 if (!in_or_out)
618 draw_raw_resource_bm(REF_IMG_BeamSetting, MfdBeamStatusRect.ul.x + setting_x - 3, MfdBeamStatusRect.ul.y - 1);
619
620 mfd_add_rect(MfdBeamStatusRect.ul.x, MfdBeamStatusRect.ul.y, MfdBeamStatusRect.lr.x, MfdBeamStatusRect.lr.y);
621 return;
622 }
623
624 // --------------------------------------------------------------------------
625 // mfd_weapon_expose_beam()
626 //
627 // Exposes relevant weapons mfd info for a beam weapon.
628
mfd_weapon_expose_beam(weapon_slot * ws,ubyte id,uchar Redraw)629 void mfd_weapon_expose_beam(weapon_slot *ws, ubyte id, uchar Redraw) {
630 char buf[ENERGY_TEXT_LEN];
631 uchar does_overload = FALSE;
632 extern uchar does_weapon_overload(int type, int subtype);
633
634 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
635 if (id == MFD_LEFT) {
636 if (MFDGetLastLeftBeamHeat > ws->ammo)
637 Redraw = TRUE;
638 MFDSetLastLeftBeamHeat(ws->ammo);
639 }
640 if (id == MFD_RIGHT) {
641 if (MFDGetLastRightBeamHeat > ws->ammo)
642 Redraw = TRUE;
643 MFDSetLastRightBeamHeat(ws->ammo);
644 }
645
646 does_overload = does_weapon_overload(ws->type, ws->subtype);
647 if (does_overload) {
648 // if beam weapon is not set to overload then draw overload button, otherwise say "overload enabled"
649 if (Redraw && OVERLOAD_VALUE(ws->setting)) {
650 short w = res_bm_width(REF_IMG_BeamOverloadOn);
651
652 draw_raw_resource_bm(REF_IMG_BeamOverloadOn, 1, OVERLOAD_BUTTON_Y);
653 mfd_add_rect(1, OVERLOAD_BUTTON_Y, 1 + w, MFD_VIEW_HGT);
654
655 get_string(REF_STR_Overload, buf, ENERGY_TEXT_LEN);
656 mfd_draw_string(buf, 1, SETTING_TEXT, MFD_BEAM_HOT, TRUE);
657 } else {
658 short w = res_bm_width(REF_IMG_BeamOverload);
659
660 if (Redraw) {
661 (ws->ammo < MINIMUM_OVERLOAD) ? draw_raw_resource_bm(REF_IMG_BeamOverload, 1, OVERLOAD_BUTTON_Y)
662 : draw_raw_resource_bm(REF_IMG_BeamOverloadOff, 1, OVERLOAD_BUTTON_Y);
663 mfd_add_rect(1, OVERLOAD_BUTTON_Y, 1 + w, MFD_VIEW_HGT);
664 get_string(REF_STR_EnergySetting, buf, ENERGY_TEXT_LEN);
665 mfd_draw_string(buf, 1, SETTING_TEXT, MFD_BEAM_READY, TRUE);
666 }
667 }
668 }
669
670 get_string(REF_STR_LowSetting, buf, ENERGY_TEXT_LEN);
671 mfd_draw_string(buf, 2, MFD_BEAM_RECT_Y1 - 1, MFD_BEAM_READY, TRUE);
672 get_string(REF_STR_HighSetting, buf, ENERGY_TEXT_LEN);
673 mfd_draw_string(buf, 57, MFD_BEAM_RECT_Y1 - 1, MFD_BEAM_READY, TRUE);
674
675 draw_raw_resource_bm(REF_IMG_BeamTemperature, TEMPR_X, TEMPR_Y);
676
677 mfd_weapon_draw_temp(ws->ammo);
678
679 // Redraw the beam energy status bar
680 mfd_weapon_draw_beam_status_bar(ws->ammo, ws->setting, does_overload);
681
682 return;
683 }
684
685 // ---------------------------------------------------------------------------
686 // mfd_weapon_handler()
687 //
688 // Mostly responsible for figuring out which ammo boxes were clicked on
689 // to select new ammo, and for manipulating the charge on beam weapons
690
mfd_weapon_handler(MFD * m,uiEvent * e)691 uchar mfd_weapon_handler(MFD *m, uiEvent *e) {
692 weapon_slot *ws;
693 int triple;
694
695 // Get the triple for the current weapon
696 ws = &player_struct.weapons[player_struct.actives[ACTIVE_WEAPON]];
697 triple = MAKETRIP(CLASS_GUN, ws->type, ws->subtype);
698
699 switch (ws->type) {
700 case GUN_SUBCLASS_BEAM: // Is beam charge being set?
701 case GUN_SUBCLASS_BEAMPROJ: // Is beam charge being set?
702 // if (!(mouse->action & ~MOUSE_MOTION) && !(mouse->buttons & (1 << MOUSE_LBUTTON)))
703 // return FALSE;
704 return mfd_weapon_beam_handler(m, e);
705 break;
706 case GUN_SUBCLASS_PISTOL:
707 case GUN_SUBCLASS_AUTO:
708 case GUN_SUBCLASS_SPECIAL:
709 if (e->mouse_data.action == MOUSE_MOTION)
710 return FALSE;
711 return mfd_weapon_projectile_handler(m, e, ws);
712 break;
713 default:
714 break;
715 }
716 return FALSE;
717 }
718
719 ubyte old_energy_setting = 0xFF;
720
721 // ---------------------------------------------------------------------------
722 // mfd_weapon_beam_handler()
723 //
724 // This is the handler for beam type weapons in the weapons mfd.
725
726 extern uchar does_weapon_overload(int type, int subtype);
727
mfd_weapon_beam_handler(MFD * m,uiEvent * e)728 uchar mfd_weapon_beam_handler(MFD *m, uiEvent *e) {
729 uchar retval = TRUE;
730 LGRect r;
731 ubyte setting, setting_x;
732 weapon_slot *ws = &player_struct.weapons[player_struct.actives[ACTIVE_WEAPON]];
733 uchar overld = does_weapon_overload(ws->type, ws->subtype);
734
735 #ifdef CURSOR_BACKUPS
736 extern grs_bitmap backup_mfd_cursor;
737 extern uchar *backup[NUM_BACKUP_BITS];
738 #endif
739
740 // We're interested in this event iff its a mouse up,down,action event
741 // in the beam status bar.
742 if (!(e->mouse_data.action & (MOUSE_LUP | MOUSE_LDOWN | MOUSE_MOTION))) {
743 return FALSE;
744 }
745
746 if (overld) {
747 // okay - here's the overload button code
748 if (e->mouse_data.action & MOUSE_LDOWN) {
749
750 if (ws->ammo < MINIMUM_OVERLOAD) {
751 // set up the rect for the overload button
752 r.ul.x = (MFD_VIEW_WID - res_bm_width(REF_IMG_NoAmmo)) / 2;
753 r.ul.y = OVERLOAD_BUTTON_Y;
754 r.lr.x = r.ul.x + res_bm_width(REF_IMG_BeamOverload);
755 r.lr.y = OVERLOAD_BUTTON_Y + res_bm_height(REF_IMG_BeamOverload);
756 RECT_OFFSETTED_RECT(&r, m->rect.ul, &r);
757
758 // check if we clicked in the button
759 if (RECT_TEST_PT(&r, e->pos)) {
760 // toggle between the two values
761 chg_set_flg(INVENTORY_UPDATE);
762 OVERLOAD_VALUE(ws->setting) ? OVERLOAD_RESET(ws->setting) : OVERLOAD_SET(ws->setting);
763 mfd_force_update(); // make sure it redraws the mfd
764 return TRUE;
765 }
766 }
767 }
768 }
769
770 RECT_OFFSETTED_RECT(&MfdBeamStatusRect, m->rect.ul, &r);
771
772 if (!RECT_TEST_PT(&r, e->pos)) {
773 uiCursorStack *cs;
774
775 uiGetRegionCursorStack(MFD_REGION(m), &cs);
776 uiPopCursorEvery(cs, &slider_cursor);
777 mfd_notify_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT, FALSE, MFD_ACTIVE, FALSE);
778 if (!in_or_out)
779 return retval;
780 }
781 if (!in_or_out && (e->mouse_data.buttons == 0))
782 return retval;
783
784 // If the left button was pushed, we constrain the mouse to
785 // the beam status bar, and change the cursor appropriately
786 if (e->mouse_data.action & MOUSE_LDOWN) {
787
788 in_or_out = TRUE;
789
790 // Constrain the mouse to a 1-pixel y
791 slider_cursor.hotspot.x = slider_cursor_bmap.w / 2;
792 slider_cursor.hotspot.y = (slider_cursor_bmap.h / 2) + e->pos.y - (r.ul.y + r.lr.y) / 2;
793 ui_mouse_constrain_xy(r.ul.x + 1, e->pos.y, r.lr.x - 2, e->pos.y);
794 beam_constrain = m->id;
795 // Get our funky mfd-beam-phaser-setting cursor
796 uiPushRegionCursor(MFD_REGION(m), &slider_cursor);
797 #ifdef CURSOR_BACKUPS
798 backup[20] = (uchar *)malloc(f->bm.w * f->bm.h);
799 LG_memcpy(backup[20], f->bm.bits, f->bm.w * f->bm.h);
800 gr_init_bm(&backup_mfd_cursor, backup[14], BMT_FLAT8, 0, mfd_cursor.w, mfd_cursor.h);
801 #endif
802 retval = TRUE;
803 }
804
805 // If the left button was released, unconstrain the mouse and reset
806 // the cursor bitmap. There's no else here for the weird case that
807 // an up and down event might happen "simultaneously"
808 if (e->mouse_data.action & MOUSE_LUP) {
809
810 in_or_out = FALSE;
811
812 // Let the mouse run free
813 // note that we are NOT using the UI here since we're already looking at grd_cap
814 mouse_constrain_xy(0, 0, grd_cap->w - 1, grd_cap->h - 1);
815 beam_constrain = NO_CONSTRAIN;
816
817 uiPopRegionCursor(MFD_REGION(m));
818 mfd_notify_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT, FALSE, MFD_ACTIVE, TRUE);
819
820 retval = TRUE;
821 }
822
823 // Calculate the max charge setting based on mouse position (making goofy
824 // exceptions for the endpoints for aesthetics) and set the weapon
825 // accordingly.
826 setting_x = e->pos.x - r.ul.x;
827 if ((e->mouse_data.action & MOUSE_MOTION) && (setting_x == old_energy_setting))
828 return retval;
829 old_energy_setting = setting_x;
830
831 setting = (ubyte)fix_int(setting_x * mfd_charge_units_per_pixel);
832
833 if (overld)
834 setting >>= 1;
835
836 setting += MIN_ENERGY_USE;
837 uiSetCursor();
838
839 set_beam_weapon_max_charge(player_struct.actives[ACTIVE_WEAPON], setting);
840 // min(MAX_HEAT,setting));
841
842 return TRUE;
843 }
844
845 // ---------------------------------------------------------------------------
846 // mfd_weapon_projectile_handler()
847 //
848 // This is the handler for projectile weapons in the weapons mfd.
849
mfd_weapon_projectile_handler(MFD * m,uiEvent * e,weapon_slot * ws)850 uchar mfd_weapon_projectile_handler(MFD *m, uiEvent *e, weapon_slot *ws) {
851 int ammo_subclass, num_ammo_buttons;
852 ubyte ammo_types[3];
853 LGPoint pos = e->pos;
854
855 pos.x -= m->rect.ul.x;
856 pos.y -= m->rect.ul.y;
857
858 if (pos.y < AMMO_BUTTON_Y)
859 return FALSE;
860 // If we're already loaded, check for double click.
861 if (ws->ammo > 0) {
862 uchar retval = FALSE;
863 if (e->mouse_data.action & UI_MOUSE_LDOUBLE) {
864 extern void unload_current_weapon(void);
865
866 unload_current_weapon();
867 MFDSetLeftAmmo(0xFF);
868 MFDSetRightAmmo(0xFF);
869 mfd_notify_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT, FALSE, MFD_ACTIVE, FALSE);
870 mfd_notify_func(MFD_ITEM_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
871 retval = TRUE;
872 } else if (e->mouse_data.action & MOUSE_LDOWN) {
873 string_message_info(REF_STR_DClickToUnload);
874 retval = TRUE;
875 }
876 return retval;
877 }
878
879 // If it wasn't a left-mouse-button down event, throw it away.
880 if (!(e->mouse_data.action & (MOUSE_LDOWN | UI_MOUSE_LDOUBLE)))
881 return FALSE;
882
883 // Get the ammo data for the current weapon
884 get_available_ammo_type(ws->type, ws->subtype, &num_ammo_buttons, ammo_types, &ammo_subclass);
885 {
886 int b = pos.x / AMMO_BUTTON_W;
887 int atype;
888 for (atype = 0; atype < num_ammo_buttons; atype++) {
889 // If we have a hit, we let each mfd know independently that
890 // it needs to redraw its ammo buttons, to save redraw time
891 if (b == ammo_types[atype] && change_ammo_type(b)) {
892 if (weapon_mfd_temp) {
893 int mfd;
894 for (mfd = 0; mfd < NUM_MFDS; mfd++) {
895 if (player_struct.mfd_current_slots[mfd] == MFD_WEAPON_SLOT)
896 restore_mfd_slot(mfd);
897 }
898 weapon_mfd_temp = FALSE;
899 }
900 MFDSetLeftAmmo(0xFF);
901 MFDSetRightAmmo(0xFF);
902 mfd_notify_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT, FALSE, MFD_ACTIVE, FALSE);
903 mfd_notify_func(MFD_ITEM_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
904 break;
905 }
906 }
907 }
908
909 return TRUE;
910 }
911
weapon_mfd_for_reload(void)912 void weapon_mfd_for_reload(void) {
913 uchar target_pri;
914 uchar take_mfd;
915
916 extern int mfd_choose_func(int func, int slot);
917
918 // Do not take down target mfd in favor of weapon in this case!
919 target_pri = mfd_funcs[MFD_TARGET_FUNC].priority;
920 mfd_funcs[MFD_TARGET_FUNC].priority = 1;
921 take_mfd = mfd_choose_func(MFD_WEAPON_FUNC, MFD_WEAPON_SLOT);
922 if (player_struct.mfd_current_slots[take_mfd] != MFD_WEAPON_SLOT) {
923 save_mfd_slot(take_mfd);
924 weapon_mfd_temp = TRUE;
925 }
926 mfd_change_slot(take_mfd, MFD_WEAPON_SLOT);
927 mfd_funcs[MFD_TARGET_FUNC].priority = target_pri;
928 }
929
930 // ===========================================================================
931 // * THE ITEM MFD *
932 // ===========================================================================
933
934 // OK, the item MFD is pretty heinous, and, in fact, they all
935 // really want to be their own MFDfuncs, so, let's grant them their wish!
936
937 #define MFDGetLastItemClass(m) mfd_fdata[MFD_ITEM_FUNC][(m)]
938 #define MFDGetLastItemType(m) mfd_fdata[MFD_ITEM_FUNC][(m) + 2]
939 #define MFDGetCurrItemClass(m) mfd_fdata[MFD_ITEM_FUNC][(m) + 4]
940 #define MFDGetCurrItemType(m) mfd_fdata[MFD_ITEM_FUNC][(m) + 6]
941
942 #define MFDSetLastItemClass(m, n) mfd_fdata[MFD_ITEM_FUNC][(m)] = (n)
943 #define MFDSetLastItemType(m, n) mfd_fdata[MFD_ITEM_FUNC][(m) + 2] = (n)
944 #define MFDSetCurrItemClass(m, n) mfd_fdata[MFD_ITEM_FUNC][(m) + 4] = (n)
945 #define MFDSetCurrItemType(m, n) mfd_fdata[MFD_ITEM_FUNC][(m) + 6] = (n)
946
947 LGRect MfdGrenadeBox[2];
948
949 #define MFD_GRENADE_BOX_X1 27
950 #define MFD_GRENADE_BOX_X2 47
951 #define MFD_GRENADE_BOX_Y 5
952 #define MFD_GRENADE_BOX_W 5
953 #define MFD_GRENADE_BOX_H 5
954
955 #define HARDWARE_BUTTON_H 13
956 #define HARDWARE_BUTTON_W 44
957 #define HARDWARE_BUTTON_X ((MFD_VIEW_WID - HARDWARE_BUTTON_W) / 2)
958 #define HARDWARE_BUTTON_Y (MFD_VIEW_HGT - HARDWARE_BUTTON_H - 1)
959
960 #define DRUG_BUTTON_H 13
961 #define DRUG_BUTTON_W 32
962 #define DRUG_BUTTON_X ((MFD_VIEW_WID - DRUG_BUTTON_W) / 2)
963 #define DRUG_BUTTON_Y (MFD_VIEW_HGT - 1 - DRUG_BUTTON_H)
964
965 // --------------------------------------------------------------------------
966 // mfd_item_init()
967 //
968 // Sets some info.
969
mfd_item_init(MFD_Func * mfd)970 errtype mfd_item_init(MFD_Func *mfd) {
971 MFDSetCurrItemClass(0, MFD_INV_NULL);
972 MFDSetCurrItemClass(1, MFD_INV_NULL);
973 MFDSetLastItemClass(0, MFD_INV_NULL);
974 MFDSetLastItemClass(1, MFD_INV_NULL);
975
976 MfdGrenadeBox[0].ul.x = MFD_GRENADE_BOX_X1;
977 MfdGrenadeBox[0].ul.y = MFD_GRENADE_BOX_Y;
978 MfdGrenadeBox[0].lr.x = MFD_GRENADE_BOX_X1 + MFD_GRENADE_BOX_W;
979 MfdGrenadeBox[0].lr.y = MFD_GRENADE_BOX_Y + MFD_GRENADE_BOX_H;
980
981 MfdGrenadeBox[1].ul.x = MFD_GRENADE_BOX_X2;
982 MfdGrenadeBox[1].ul.y = MFD_GRENADE_BOX_Y;
983 MfdGrenadeBox[1].lr.x = MFD_GRENADE_BOX_X2 + MFD_GRENADE_BOX_W;
984 MfdGrenadeBox[1].lr.y = MFD_GRENADE_BOX_Y + MFD_GRENADE_BOX_H;
985
986 return OK;
987 }
988
989 //--------------------------------------------------------------
990 // Like mini-expose, but gets the name for you, and
991 // conforms to our rect-o-tronic update facility
992
mfd_item_micro_expose(uchar full,int triple)993 void mfd_item_micro_expose(uchar full, int triple) {
994 if (!full_game_3d) {
995 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
996 ss_bitmap(&mfd_background, 0, 0);
997 // gr_bitmap(&mfd_background, 0, 0);
998 }
999 if (full) {
1000 LGPoint siz;
1001 int id;
1002 short y = 2;
1003 char buf[LNAME_BUFSIZE];
1004 mfd_add_rect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1005 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1006
1007 get_object_long_name(triple, buf, LNAME_BUFSIZE);
1008 siz = mfd_draw_string(buf, X_MARGIN, y, GREEN_YELLOW_BASE, TRUE);
1009 y += siz.y + 2;
1010
1011 // Draw the appropriate weapon art
1012 id = mfd_bmap_id(triple);
1013 if (RefIndexValid((RefTable *)ResGet(REFID(id)), REFINDEX(id)))
1014 draw_raw_resource_bm(id, (MFD_VIEW_WID - res_bm_width(id)) / 2, y);
1015 else
1016 ResUnlock(REFID(id));
1017 }
1018 return;
1019 }
1020
1021 //--------------------------------------------------------------
1022 // Called by things that know they have hi-res art to display.
1023
mfd_item_micro_hires_expose(uchar full,int triple)1024 void mfd_item_micro_hires_expose(uchar full, int triple) {
1025 if (!full_game_3d) {
1026 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1027 gr_bitmap(&mfd_background, 0, 0);
1028 }
1029 if (full) {
1030 LGPoint siz;
1031 int id;
1032 short y = 2;
1033 char buf[LNAME_BUFSIZE];
1034
1035 mfd_add_rect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1036 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1037
1038 get_object_long_name(triple, buf, LNAME_BUFSIZE);
1039 siz = mfd_draw_string(buf, X_MARGIN, y, GREEN_YELLOW_BASE, TRUE);
1040 y += siz.y + 2;
1041
1042 id = mfd_bmap_id(triple);
1043 if (RefIndexValid((RefTable *)ResGet(REFID(id)), REFINDEX(id)))
1044 draw_hires_resource_bm(id, (SCONV_X(MFD_VIEW_WID) - res_bm_width(id)) / 2, SCONV_Y(y));
1045 else
1046 ResUnlock(REFID(id));
1047 }
1048 return;
1049 }
1050
1051 // --------------------------------------------------------------------------
1052 // mfd_item_draw_grenade_setting_boxes()
1053 //
1054 // Draws the little increment/decrement boxes on either side of the
1055 // "time left before grenade blows up" setting on the MFD.
1056
1057 #ifdef OLD_GRENADE_BUTTONS
mfd_item_draw_grenade_setting_boxes(MFD * m)1058 void mfd_item_draw_grenade_setting_boxes(MFD *m) {
1059 char buf[2];
1060 int i;
1061
1062 for (i = 0; i < 2; i++) {
1063 gr_set_fcolor(WHITE);
1064 ss_rect(MfdGrenadeBox[i].ul.x, MfdGrenadeBox[i].ul.y, MfdGrenadeBox[i].lr.x, MfdGrenadeBox[i].lr.y);
1065 gr_set_fcolor(MFD_BTTN_FLASH);
1066 ss_box(MfdGrenadeBox[i].ul.x, MfdGrenadeBox[i].ul.y, MfdGrenadeBox[i].lr.x, MfdGrenadeBox[i].lr.y);
1067 }
1068
1069 gr_set_fcolor(BLACK);
1070 sprintf(buf, "-");
1071 ss_string("-", MfdGrenadeBox[0].ul.x + 1, MfdGrenadeBox[0].ul.y + 1);
1072 sprintf(buf, "+");
1073 ss_string(buf, MfdGrenadeBox[1].ul.x + 1, MfdGrenadeBox[1].ul.y + 1);
1074
1075 return;
1076 }
1077 #endif // OLD_GRENADE_BUTTONS
1078
1079 // --------------------------------------------------------------------------
1080 // mfd_item_expose()
1081 //
1082 // Draws an overlay of a drug molecule or whatever in the current slot.
1083
1084 #define NULL_ACTIVE 0xFF
1085 static ubyte cat2active[MFD_INV_CATEGORIES] = {
1086 NULL_ACTIVE, ACTIVE_DRUG, ACTIVE_HARDWARE, ACTIVE_GRENADE, ACTIVE_CART,
1087 ACTIVE_WEAPON, ACTIVE_GENERAL, ACTIVE_COMBAT_SOFT, ACTIVE_DEFENSE_SOFT, ACTIVE_MISC_SOFT,
1088 };
1089
1090 #define TRASH_BUTTON REF_IMG_DiscardButton
1091
1092 #define NULL_REF MKREF(ID_NULL, 0)
1093
1094 Ref smallstuffSpews[] = {NULL_REF, NULL_REF, NULL_REF, REF_STR_gearSpew0,
1095 NULL_REF, NULL_REF, NULL_REF, REF_STR_plotSpew0};
1096
mfd_general_inv_expose(MFD * mfd,ubyte control,ObjID id,uchar full)1097 void mfd_general_inv_expose(MFD *mfd, ubyte control, ObjID id, uchar full) {
1098 int triple;
1099 Ref spew = NULL_REF;
1100
1101 if (id == OBJ_NULL) {
1102 draw_blank_mfd();
1103 return;
1104 }
1105 triple = ID2TRIP(id);
1106 mfd_item_micro_expose(full, triple);
1107 if (full && !(ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL)) {
1108 short x = (MFD_VIEW_WID - res_bm_width(TRASH_BUTTON)) / 2;
1109 short y = (MFD_VIEW_HGT - res_bm_height(TRASH_BUTTON)) / 2;
1110 draw_raw_resource_bm(TRASH_BUTTON, x, y);
1111 mfd_add_rect(x, y, x + res_bm_width(TRASH_BUTTON), y + res_bm_height(TRASH_BUTTON));
1112 }
1113 if (objs[id].obclass == CLASS_SMALLSTUFF)
1114 spew = smallstuffSpews[objs[id].subclass];
1115 if (spew != NULL_REF)
1116 draw_mfd_item_spew(spew + objs[id].info.type, 1);
1117 }
1118
mfd_general_inv_handler(MFD * m,uiEvent * ev,int row)1119 uchar mfd_general_inv_handler(MFD *m, uiEvent *ev, int row) {
1120 ObjID id = player_struct.inventory[row];
1121 if (ev->type != UI_EVENT_MOUSE || !(ev->subtype & MOUSE_LDOWN))
1122 return FALSE;
1123 if (!(ObjProps[OPNUM(id)].flags & INVENTORY_GENERAL)) {
1124 LGPoint pos = MakePoint(ev->pos.x - m->rect.ul.x, ev->pos.y - m->rect.ul.y);
1125 short x = (MFD_VIEW_WID - res_bm_width(TRASH_BUTTON)) / 2;
1126 short y = (MFD_VIEW_HGT - res_bm_height(TRASH_BUTTON)) / 2;
1127 LGRect r;
1128 r.ul = r.lr = MakePoint(x, y);
1129 r.lr.x += res_bm_width(TRASH_BUTTON);
1130 r.lr.y += res_bm_height(TRASH_BUTTON);
1131 if (RECT_TEST_PT(&r, pos)) {
1132 int i;
1133 obj_destroy(id);
1134 for (i = row + 1; i < NUM_GENERAL_SLOTS; i++)
1135 player_struct.inventory[i - 1] = player_struct.inventory[i];
1136 player_struct.inventory[NUM_GENERAL_SLOTS - 1] = OBJ_NULL;
1137 drain_energy(1);
1138 mfd_notify_func(MFD_EMPTY_FUNC, MFD_ITEM_SLOT, TRUE, MFD_EMPTY, FALSE);
1139 chg_set_flg(INVENTORY_UPDATE);
1140 }
1141 }
1142 return TRUE;
1143 }
1144
1145 #define STRINGS_PER_WARE (REF_STR_wareSpew1 - REF_STR_wareSpew0)
1146 //#define SPEW_VERT_MARGIN 10
1147 #define SPEW_VERT_MARGIN 2
1148
draw_mfd_item_spew(Ref id,int n)1149 void draw_mfd_item_spew(Ref id, int n) {
1150 uchar oldwrap = mfd_string_wrap;
1151 short w, h;
1152 short x, y;
1153 char buf[256];
1154 int i;
1155
1156 gr_set_font(ResLock(MFD_FONT));
1157 buf[0] = '\0';
1158 #ifdef CONCATENATE_ITEMSPEW
1159 for (i = 0; i < n; i++, id++)
1160 #else
1161 i = n - 1;
1162 id += i;
1163 #endif
1164 get_string(id, buf + strlen(buf), sizeof(buf) - strlen(buf));
1165 gr_string_wrap(buf, MFD_VIEW_WID - 2);
1166 gr_string_size(buf, &w, &h);
1167 x = (MFD_VIEW_WID - w) / 2;
1168 y = (MFD_VIEW_HGT - h - SPEW_VERT_MARGIN) / 2 + SPEW_VERT_MARGIN;
1169 mfd_string_wrap = FALSE;
1170 mfd_full_draw_string(buf, x, y, GREEN_YELLOW_BASE, MFD_FONT, TRUE, TRUE);
1171 mfd_string_wrap = oldwrap;
1172 ResUnlock(MFD_FONT);
1173 }
1174
mfd_item_expose(MFD * m,ubyte control)1175 void mfd_item_expose(MFD *m, ubyte control) {
1176 ubyte lastclass, currclass, lasttype, currtype = MFD_INV_NOTYPE;
1177 uchar FullRedraw = FALSE;
1178 int triple;
1179
1180 currclass = MFDGetCurrItemClass(m->id);
1181 lastclass = MFDGetLastItemClass(m->id);
1182
1183 if (cat2active[currclass] != NULL_ACTIVE)
1184 currtype = player_struct.actives[cat2active[currclass]];
1185 if (currtype == MFD_INV_NOTYPE)
1186 currclass = MFD_INV_NULL;
1187 lasttype = MFDGetLastItemType(m->id);
1188 MFDSetCurrItemType(m->id, currtype);
1189
1190 MFDSetLastItemClass(m->id, currclass);
1191 MFDSetLastItemType(m->id, MFDGetCurrItemType(m->id));
1192
1193 if (control & MFD_EXPOSE) {
1194
1195 if ((control & MFD_EXPOSE_FULL) || (currclass != lastclass) || (currtype != lasttype))
1196 FullRedraw = TRUE;
1197
1198 // If there is no currently selected member of the current class,
1199 // draw the blank screen thingie
1200 if (MFDGetCurrItemType(m->id) == EMPTY_WEAPON_SLOT) {
1201 mfd_expose_blank(m, control);
1202 return;
1203 }
1204
1205 PUSH_CANVAS(pmfd_canvas);
1206 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1207 mfd_clear_rects();
1208
1209 switch (currclass) {
1210
1211 case MFD_INV_NULL:
1212
1213 if (FullRedraw) {
1214 draw_blank_mfd();
1215 }
1216 break;
1217
1218 case MFD_INV_DRUG:
1219
1220 triple = get_triple_from_class_nth_item(CLASS_DRUG, currtype);
1221
1222 mfd_item_micro_expose(FullRedraw, triple);
1223 // mfd_item_micro_hires_expose(FullRedraw, triple);
1224 if (FullRedraw)
1225 draw_mfd_item_spew(REF_STR_drugSpew0 + currtype, 1);
1226 draw_res_bm(REF_IMG_Apply, DRUG_BUTTON_X, DRUG_BUTTON_Y);
1227 mfd_add_rect(DRUG_BUTTON_X, DRUG_BUTTON_Y, DRUG_BUTTON_X + DRUG_BUTTON_W, MFD_VIEW_HGT);
1228 break;
1229
1230 case MFD_INV_GRENADE:
1231
1232 triple = get_triple_from_class_nth_item(CLASS_GRENADE, currtype);
1233 mfd_item_micro_expose(FullRedraw, triple);
1234 // mfd_item_micro_hires_expose(FullRedraw, triple);
1235 break;
1236
1237 case MFD_INV_HARDWARE:
1238
1239 // if (currtype == HARDWARE_DATA_READER) {
1240 // ss_safe_set_cliprect(0,0,MFD_VIEW_WID,MFD_VIEW_HGT);
1241 // ss_bitmap(&mfd_background,0,0);
1242 // mfd_draw_string("Video reader",5,10,WHITE,TRUE);
1243 // mfd_draw_string("Text reader",5,15,WHITE,TRUE);
1244 // mfd_draw_string("Email reader",5,20,WHITE,TRUE);
1245 // }
1246 // else
1247 {
1248 extern uchar is_passive_hardware(int n);
1249 int id;
1250 short x = HARDWARE_BUTTON_X, y = HARDWARE_BUTTON_Y;
1251 triple = get_triple_from_class_nth_item(CLASS_HARDWARE, currtype);
1252
1253 mfd_item_micro_expose(FullRedraw, triple);
1254 // mfd_item_micro_hires_expose(FullRedraw, triple);
1255 if (!is_passive_hardware(currtype)) {
1256 id = (player_struct.hardwarez_status[currtype] & WARE_ON) ? REF_IMG_Active : REF_IMG_Inactive;
1257 draw_res_bm(id, x, y);
1258 mfd_add_rect(x, y, x + HARDWARE_BUTTON_W, MFD_VIEW_HGT);
1259 }
1260 if (FullRedraw) {
1261 uchar version = player_struct.hardwarez[currtype];
1262 draw_mfd_item_spew(REF_STR_wareSpew0 + STRINGS_PER_WARE * currtype, version);
1263 }
1264 }
1265
1266 break;
1267
1268 case MFD_INV_AMMO:
1269 mfd_ammo_expose(control);
1270 break;
1271
1272 case MFD_INV_SOFT_COMBAT:
1273 case MFD_INV_SOFT_DEFENSE:
1274 triple = get_ware_triple(currclass - MFD_INV_SOFT_COMBAT + WARE_SOFT_COMBAT, currtype);
1275 mfd_item_micro_expose(FullRedraw, triple);
1276 break;
1277 case MFD_INV_SOFT_MISC:
1278 // Monkey see, monkey do, monkey will destroy you.
1279 {
1280 extern uchar is_oneshot_misc_software(int n);
1281 short x = HARDWARE_BUTTON_X, y = HARDWARE_BUTTON_Y;
1282 triple = get_ware_triple(currclass - MFD_INV_SOFT_COMBAT + WARE_SOFT_COMBAT, currtype);
1283
1284 mfd_item_micro_expose(FullRedraw, triple);
1285 if (is_oneshot_misc_software(currtype)) {
1286 draw_res_bm(REF_IMG_Activate, x, y);
1287 mfd_add_rect(x, y, x + HARDWARE_BUTTON_W, MFD_VIEW_HGT);
1288 }
1289 }
1290 break;
1291 case MFD_INV_GENINV:
1292 mfd_general_inv_expose(m, control, player_struct.inventory[currtype], FullRedraw);
1293 break;
1294
1295 default:
1296 break;
1297 }
1298
1299 POP_CANVAS();
1300
1301 mfd_update_rects(m);
1302 }
1303
1304 return;
1305 }
1306
1307 // ---------------------------------------------------------------------------
1308 // mfd_item_handler()
1309 //
1310 // Handle clicks to, for now, the +- grenade set-time boxes.
1311
mfd_item_handler(MFD * m,uiEvent * e)1312 uchar mfd_item_handler(MFD *m, uiEvent *e) {
1313 uchar retval = FALSE;
1314
1315 if (!(e->mouse_data.action & MOUSE_LDOWN))
1316 return retval;
1317
1318 switch (MFDGetCurrItemClass(m->id)) {
1319
1320 case MFD_INV_GRENADE:
1321
1322 #ifdef OLD_GRENADE_BUTTONS
1323 {
1324 int i;
1325 LGRect r[2];
1326 int triple;
1327 ubyte min, max;
1328 triple = get_triple_from_class_nth_item(CLASS_GRENADE, MFDGetCurrItemType(m->id));
1329 if (!(TRIP2SC(triple) == GRENADE_SUBCLASS_TIMED))
1330 return retval;
1331
1332 min = TimedGrenadeProps[SCTRIP(triple)].min_time_set;
1333 max = TimedGrenadeProps[SCTRIP(triple)].max_time_set;
1334
1335 RECT_OFFSETTED_RECT(&MfdGrenadeBox[0], m->rect.ul, &(r[0]));
1336 RECT_OFFSETTED_RECT(&MfdGrenadeBox[1], m->rect.ul, &(r[1]));
1337
1338 for (i = 0; i < 2; i++) {
1339
1340 if (RECT_TEST_PT(&r[i], e->pos)) {
1341
1342 if (i == 0) {
1343 if (player_struct.grenades_time_setting[MFDGetCurrItemType(m->id)] > min)
1344 player_struct.grenades_time_setting[MFDGetCurrItemType(m->id)]--;
1345 } else if (i == 1) {
1346 if (player_struct.grenades_time_setting[MFDGetCurrItemType(m->id)] < max)
1347 player_struct.grenades_time_setting[MFDGetCurrItemType(m->id)]++;
1348 }
1349
1350 mfd_notify_func(MFD_ITEM_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1351 }
1352 }
1353 }
1354 #endif // OLD_GRENADE_BUTTONS
1355 break;
1356 case MFD_INV_HARDWARE: {
1357 LGRect r = {{HARDWARE_BUTTON_X, HARDWARE_BUTTON_Y},
1358 {HARDWARE_BUTTON_X + HARDWARE_BUTTON_W, HARDWARE_BUTTON_Y + HARDWARE_BUTTON_H}};
1359 RECT_OFFSETTED_RECT(&r, m->rect.ul, &r);
1360 if (RECT_TEST_PT(&r, e->pos)) {
1361 use_ware(WARE_HARD, player_struct.actives[ACTIVE_HARDWARE]);
1362 mfd_notify_func(MFD_ITEM_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1363 retval = TRUE;
1364 }
1365 } break;
1366 case MFD_INV_SOFT_MISC: {
1367 LGRect r = {{HARDWARE_BUTTON_X, HARDWARE_BUTTON_Y},
1368 {HARDWARE_BUTTON_X + HARDWARE_BUTTON_W, HARDWARE_BUTTON_Y + HARDWARE_BUTTON_H}};
1369 RECT_OFFSETTED_RECT(&r, m->rect.ul, &r);
1370 if (RECT_TEST_PT(&r, e->pos)) {
1371 use_ware(WARE_SOFT_MISC, player_struct.actives[ACTIVE_MISC_SOFT]);
1372 mfd_notify_func(MFD_ITEM_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1373 retval = TRUE;
1374 }
1375 } break;
1376 case MFD_INV_DRUG: {
1377 LGRect r = {{DRUG_BUTTON_X, DRUG_BUTTON_Y}, {DRUG_BUTTON_X + DRUG_BUTTON_W, DRUG_BUTTON_Y + DRUG_BUTTON_H}};
1378 RECT_OFFSETTED_RECT(&r, m->rect.ul, &r);
1379 // Why is it that for wares, it's use_drug whereas for drugs it's drug_use? Perhaps we'll never know.
1380 if (RECT_TEST_PT(&r, e->pos)) {
1381 drug_use(player_struct.actives[ACTIVE_DRUG]);
1382 mfd_notify_func(MFD_ITEM_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1383 retval = TRUE;
1384 }
1385 } break;
1386 case MFD_INV_GENINV:
1387 mfd_general_inv_handler(m, e, player_struct.actives[ACTIVE_GENERAL]);
1388 break;
1389
1390 case MFD_INV_AMMO:
1391 mfd_ammo_handler(m, e);
1392 break;
1393 }
1394
1395 return retval;
1396 }
1397
1398 // ----------------------
1399 // * ITEM MFD FOR LANTERN
1400 // ----------------------
1401
1402 #define LANTERN_BARRAY_X 2
1403 #define LANTERN_BARRAY_WD (MFD_VIEW_WID - 6)
1404 #define LANTERN_BARRAY_Y 45
1405
1406 #define LANTERN_LAST_SETTING(mfd) (player_struct.mfd_func_data[MFD_LANTERN_FUNC][mfd])
1407 #define LANTERN_LAST_VERSION(mfd) (player_struct.mfd_func_data[MFD_LANTERN_FUNC][NUM_MFDS + mfd])
1408 #define LANTERN_LAST_STATE(mfd) (player_struct.mfd_func_data[MFD_LANTERN_FUNC][2 * NUM_MFDS + mfd])
1409 #define LANTERN_BARRAY_IDX 0
1410
1411 extern uchar muzzle_fire_light;
1412
1413 int energy_cost(int warenum);
1414
mfd_lantern_button_handler(MFD * mfd,LGPoint bttn,uiEvent * ev,void * data)1415 uchar mfd_lantern_button_handler(MFD *mfd, LGPoint bttn, uiEvent *ev, void *data) {
1416 int n = CPTRIP(LANTERN_HARD_TRIPLE);
1417 int s = player_struct.hardwarez_status[n];
1418 void mfd_lantern_setting(int setting);
1419
1420 if (bttn.x >= player_struct.hardwarez[n] || !(ev->subtype & MOUSE_LDOWN))
1421 return FALSE; // Version too high
1422 if (bttn.x == LAMP_SETTING(s)) {
1423 use_ware(WARE_HARD, n);
1424 return TRUE;
1425 }
1426 mfd_lantern_setting(bttn.x);
1427 return TRUE;
1428 }
1429
mfd_lantern_setting(int setting)1430 void mfd_lantern_setting(int setting) {
1431 int n = CPTRIP(LANTERN_HARD_TRIPLE);
1432 int s = player_struct.hardwarez_status[n];
1433
1434 if (s & WARE_ON)
1435 set_player_energy_spend(player_struct.energy_spend - energy_cost(n));
1436 LAMP_SETTING_SET(s, setting);
1437 player_struct.hardwarez_status[n] = s;
1438 if (!muzzle_fire_light) {
1439 player_struct.light_value = s;
1440 lamp_set_vals();
1441 }
1442 if (player_struct.hardwarez_status[n] & WARE_ON)
1443 set_player_energy_spend(lg_min(MAX_ENERGY, (int)player_struct.energy_spend + energy_cost(n)));
1444 mfd_notify_func(MFD_LANTERN_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1445 }
1446
mfd_lanternware_init(MFD_Func * f)1447 errtype mfd_lanternware_init(MFD_Func *f) {
1448 int cnt = 0;
1449 LGPoint bsize;
1450 LGPoint bdims;
1451 LGRect r;
1452 errtype err;
1453 bsize.x = res_bm_width(REF_IMG_LitLamp0);
1454 bsize.y = res_bm_height(REF_IMG_LitLamp0);
1455 bdims.x = LAMP_VERSIONS;
1456 bdims.y = 1;
1457 r.ul.x = LANTERN_BARRAY_X;
1458 r.ul.y = LANTERN_BARRAY_Y;
1459 r.lr.x = r.ul.x + LANTERN_BARRAY_WD;
1460 r.lr.y = r.ul.y + bsize.y;
1461 err = MFDBttnArrayInit(&f->handlers[cnt++], &r, bdims, bsize, mfd_lantern_button_handler, NULL);
1462 if (err != OK)
1463 return err;
1464 f->handler_count = cnt;
1465 return OK;
1466 }
1467
mfd_lanternware_expose(MFD * mfd,ubyte control)1468 void mfd_lanternware_expose(MFD *mfd, ubyte control) {
1469 int n, s, v;
1470 uchar full = control & MFD_EXPOSE_FULL;
1471 if (control == 0)
1472 return;
1473 n = CPTRIP(LANTERN_HARD_TRIPLE);
1474 s = player_struct.hardwarez_status[n];
1475 v = player_struct.hardwarez[n];
1476 PUSH_CANVAS(pmfd_canvas);
1477 mfd_clear_rects();
1478 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1479 if (!full_game_3d)
1480 ss_bitmap(&mfd_background, 0, 0);
1481 // gr_bitmap(&mfd_background, 0, 0);
1482 mfd_item_micro_expose(full, LANTERN_HARD_TRIPLE);
1483 // mfd_item_micro_hires_expose(full,LANTERN_HARD_TRIPLE);
1484 if (full)
1485 draw_mfd_item_spew(REF_STR_wareSpew0 + STRINGS_PER_WARE * n, v);
1486 if (full || LAMP_SETTING(s) != LANTERN_LAST_SETTING(mfd->id) || LANTERN_LAST_VERSION(mfd->id) != v ||
1487 LANTERN_LAST_STATE(mfd->id) != (s & WARE_ON)) {
1488 int xjump = LANTERN_BARRAY_WD - res_bm_width(REF_IMG_LitLamp0);
1489 int i;
1490 for (i = 0; i < v; i++) {
1491 int lit = i == LAMP_SETTING(s) && (s & WARE_ON);
1492 int id = (lit) ? REF_IMG_LitLamp0 : REF_IMG_UnlitLamp0;
1493 short x = LANTERN_BARRAY_X + i * xjump / (LAMP_VERSIONS - 1);
1494 short y = LANTERN_BARRAY_Y;
1495 draw_raw_resource_bm(id + i, x, LANTERN_BARRAY_Y);
1496 if (i == LAMP_SETTING(s)) {
1497 gr_set_fcolor(GREEN_BASE + 2);
1498 ss_box(x - 1, y - 1, x + res_bm_width(id + i) + 1, y + res_bm_height(id + i) + 1);
1499 }
1500 }
1501 mfd_add_rect(LANTERN_BARRAY_X - 2, LANTERN_BARRAY_Y - 2, LANTERN_BARRAY_X + LANTERN_BARRAY_WD + 2,
1502 MFD_VIEW_HGT);
1503 LANTERN_LAST_SETTING(mfd->id) = LAMP_SETTING(s);
1504 LANTERN_LAST_VERSION(mfd->id) = v;
1505 LANTERN_LAST_STATE(mfd->id) = s & WARE_ON;
1506 }
1507 POP_CANVAS();
1508 mfd_update_rects(mfd);
1509 }
1510
1511 // ----------------------
1512 // * ITEM MFD FOR SHIELD
1513 // ----------------------
1514
1515 #define SHIELD_BARRAY_X 2
1516 #define SHIELD_BARRAY_WD (MFD_VIEW_WID - 4)
1517 #define SHIELD_BARRAY_Y 45
1518
1519 #define SHIELD_LAST_STATUS(mfd) (player_struct.mfd_func_data[MFD_SHIELD_FUNC][mfd])
1520 #define SHIELD_LAST_VERSION(mfd) (player_struct.mfd_func_data[MFD_SHIELD_FUNC][NUM_MFDS + mfd])
1521 #define SHIELD_BARRAY_IDX 0
1522
1523 #define SHIELD_SETTINGS 3
1524
1525 void mfd_shield_setting(int setting);
1526 uchar mfd_shield_handler(MFD *m, uiEvent *e);
1527 uchar mfd_shield_button_handler(MFD *m, LGPoint bttn, uiEvent *ev, void *data);
1528 errtype mfd_shield_init(MFD_Func *f);
1529 void mfd_shieldware_expose(MFD *mfd, ubyte control);
1530
mfd_shield_handler(MFD * m,uiEvent * e)1531 uchar mfd_shield_handler(MFD *m, uiEvent *e) {
1532 uchar retval = FALSE;
1533 LGPoint pos = e->pos;
1534 ubyte n = CPTRIP(SHIELD_HARD_TRIPLE);
1535 ubyte v = player_struct.hardwarez[n];
1536 if (v != SHIELD_VERSIONS) // are we at max version
1537 return FALSE;
1538 if (!(e->subtype & MOUSE_LDOWN))
1539 return FALSE;
1540 pos.x -= m->rect.ul.x - SHIELD_BARRAY_X;
1541 pos.y -= m->rect.ul.y - SHIELD_BARRAY_Y;
1542 if (pos.x > 0 && pos.x < SHIELD_BARRAY_WD && pos.y > 0) {
1543 use_ware(WARE_HARD, n);
1544 mfd_shield_setting(v - 1);
1545 retval = TRUE;
1546 }
1547 return retval;
1548 }
1549
mfd_shield_button_handler(MFD * mfd,LGPoint bttn,uiEvent * ev,void * data)1550 uchar mfd_shield_button_handler(MFD *mfd, LGPoint bttn, uiEvent *ev, void *data) {
1551 int n = CPTRIP(SHIELD_HARD_TRIPLE);
1552 int s = player_struct.hardwarez_status[n];
1553
1554 if (bttn.x >= player_struct.hardwarez[n] || !(ev->subtype & MOUSE_LDOWN))
1555 return FALSE; // Version too high
1556 if (SHIELD_SETTING(s) == bttn.x) {
1557 use_ware(WARE_HARD, n);
1558 return TRUE;
1559 }
1560 mfd_shield_setting(bttn.x);
1561 return TRUE;
1562 }
1563
mfd_shield_setting(int setting)1564 void mfd_shield_setting(int setting) {
1565 extern void shield_set_absorb(void);
1566 int n = CPTRIP(SHIELD_HARD_TRIPLE);
1567 int s = player_struct.hardwarez_status[n];
1568
1569 if (s & WARE_ON)
1570 set_player_energy_spend(player_struct.energy_spend - energy_cost(n));
1571 SHIELD_SETTING_SET(s, setting);
1572 player_struct.hardwarez_status[n] = s;
1573 if (s & WARE_ON) {
1574 shield_set_absorb();
1575 set_player_energy_spend(lg_min(MAX_ENERGY, (int)player_struct.energy_spend + energy_cost(n)));
1576 }
1577 mfd_notify_func(MFD_SHIELD_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1578 }
1579
mfd_shield_init(MFD_Func * f)1580 errtype mfd_shield_init(MFD_Func *f) {
1581 int cnt = 0;
1582 LGPoint bsize;
1583 LGPoint bdims;
1584 LGRect r;
1585 errtype err;
1586 bsize.x = res_bm_width(REF_IMG_LitShield0);
1587 bsize.y = res_bm_height(REF_IMG_LitShield0);
1588 bdims.x = SHIELD_SETTINGS;
1589 bdims.y = 1;
1590 r.ul.x = SHIELD_BARRAY_X;
1591 r.ul.y = SHIELD_BARRAY_Y;
1592 r.lr.x = r.ul.x + SHIELD_BARRAY_WD;
1593 r.lr.y = r.ul.y + bsize.y;
1594 err = MFDBttnArrayInit(&f->handlers[cnt++], &r, bdims, bsize, mfd_shield_button_handler, NULL);
1595 if (err != OK)
1596 return err;
1597 f->handler_count = cnt;
1598 return OK;
1599 }
1600
mfd_shieldware_expose(MFD * mfd,ubyte control)1601 void mfd_shieldware_expose(MFD *mfd, ubyte control) {
1602 int n, s, v;
1603 uchar full = control & MFD_EXPOSE_FULL;
1604 if (control == 0)
1605 return;
1606 n = CPTRIP(SHIELD_HARD_TRIPLE);
1607 s = player_struct.hardwarez_status[n];
1608 v = player_struct.hardwarez[n];
1609 PUSH_CANVAS(pmfd_canvas);
1610 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1611 mfd_clear_rects();
1612 if (!full_game_3d)
1613 ss_bitmap(&mfd_background, 0, 0);
1614 // gr_bitmap(&mfd_background, 0, 0);
1615 mfd_item_micro_expose(full, SHIELD_HARD_TRIPLE);
1616 // mfd_item_micro_hires_expose(full,SHIELD_HARD_TRIPLE);
1617 if (full)
1618 draw_mfd_item_spew(REF_STR_wareSpew0 + STRINGS_PER_WARE * n, v);
1619 if (full || s != SHIELD_LAST_STATUS(mfd->id) || SHIELD_LAST_VERSION(mfd->id) != v) {
1620 int xjump = SHIELD_BARRAY_WD / SHIELD_SETTINGS;
1621 int i;
1622 if (v >= SHIELD_VERSIONS) {
1623 int id = (s & WARE_ON) ? REF_IMG_LitShieldSuper : REF_IMG_UnlitShieldSuper;
1624 draw_raw_resource_bm(id, SHIELD_BARRAY_X + (SHIELD_BARRAY_WD - res_bm_width(id)) / 2, SHIELD_BARRAY_Y);
1625 mfd_add_rect(SHIELD_BARRAY_X, SHIELD_BARRAY_Y, SHIELD_BARRAY_X + SHIELD_BARRAY_WD, MFD_VIEW_WID);
1626 } else
1627 for (i = 0; i < v; i++) {
1628 int id = (i == SHIELD_SETTING(s) && (s & WARE_ON)) ? REF_IMG_LitShield0 : REF_IMG_UnlitShield0;
1629 grs_bitmap *bm = lock_bitmap_from_ref(id + i);
1630 short x = SHIELD_BARRAY_X + i * xjump;
1631 short y = SHIELD_BARRAY_Y;
1632 mfd_draw_bitmap(bm, x, y);
1633 if (i == SHIELD_SETTING(s)) {
1634 gr_set_fcolor(GREEN_BASE + 2);
1635 ss_box(x - 1, y - 1, x + bm->w + 1, y + bm->h + 1);
1636 }
1637 mfd_add_rect(x - 2, y - 2, x + bm->w + 2, y + bm->h + 2);
1638 RefUnlock(id + i);
1639 }
1640 SHIELD_LAST_STATUS(mfd->id) = s;
1641 SHIELD_LAST_VERSION(mfd->id) = v;
1642 }
1643 POP_CANVAS();
1644 mfd_update_rects(mfd);
1645 }
1646
1647 // ----------------------
1648 // * ITEM MFD FOR MOTION WARE
1649 // ----------------------
1650
1651 #define MOTION_BARRAY_WD (3 * MFD_VIEW_WID / 4)
1652 #define MOTION_BARRAY_X ((MFD_VIEW_WID - MOTION_BARRAY_WD) / 2)
1653 #define MOTION_BARRAY_Y 48
1654
1655 #define MOTION_LAST_STATUS(mfd) (player_struct.mfd_func_data[MFD_MOTION_FUNC][mfd])
1656 #define MOTION_LAST_VERSION(mfd) (player_struct.mfd_func_data[MFD_MOTION_FUNC][NUM_MFDS + mfd])
1657 #define MOTION_BARRAY_IDX 0
1658
1659 #define MOTION_SETTING LAMP_SETTING
1660 #define MOTION_SETTING_SET LAMP_SETTING_SET
1661
1662 #define MOTION_BUTTONS 2
1663
1664 uchar mfd_motion_button_handler(MFD *m, LGPoint bttn, uiEvent *ev, void *data);
1665 errtype mfd_motion_init(MFD_Func *f);
1666 void mfd_motionware_expose(MFD *mfd, ubyte control);
1667
mfd_motion_button_handler(MFD * mfd,LGPoint bttn,uiEvent * ev,void * data)1668 uchar mfd_motion_button_handler(MFD *mfd, LGPoint bttn, uiEvent *ev, void *data) {
1669 int n = CPTRIP(MOTION_HARD_TRIPLE);
1670 int s = player_struct.hardwarez_status[n];
1671 // if (bttn.x >= player_struct.hardwarez[n] ||
1672 if (!(ev->subtype & MOUSE_LDOWN))
1673 return FALSE;
1674 if (MOTION_SETTING(s) == bttn.x) {
1675 use_ware(WARE_HARD, n);
1676 return TRUE;
1677 }
1678 if (s & WARE_ON)
1679 set_player_energy_spend(player_struct.energy_spend - energy_cost(n));
1680 MOTION_SETTING_SET(s, bttn.x);
1681 player_struct.hardwarez_status[n] = s;
1682 if (!(s & WARE_ON)) {
1683 // use_ware(WARE_HARD,n);
1684 } else {
1685 motionware_mode = bttn.x + 1;
1686 set_player_energy_spend(lg_min(MAX_ENERGY, (int)player_struct.energy_spend + energy_cost(n)));
1687 }
1688 mfd_notify_func(MFD_MOTION_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1689 return TRUE;
1690 }
1691
mfd_motion_init(MFD_Func * f)1692 errtype mfd_motion_init(MFD_Func *f) {
1693 int cnt = 0;
1694 LGPoint bsize;
1695 LGPoint bdims;
1696 LGRect r;
1697 errtype err;
1698 bsize.x = res_bm_width(REF_IMG_LitMotion0);
1699 bsize.y = res_bm_height(REF_IMG_LitMotion0);
1700 bdims.x = MOTION_BUTTONS;
1701 bdims.y = 1;
1702 r.ul.x = MOTION_BARRAY_X;
1703 r.ul.y = MOTION_BARRAY_Y;
1704 r.lr.x = r.ul.x + MOTION_BARRAY_WD;
1705 r.lr.y = r.ul.y + bsize.y;
1706 err = MFDBttnArrayInit(&f->handlers[cnt++], &r, bdims, bsize, mfd_motion_button_handler, NULL);
1707 if (err != OK)
1708 return err;
1709 f->handler_count = cnt;
1710 return OK;
1711 }
1712
mfd_motionware_expose(MFD * mfd,ubyte control)1713 void mfd_motionware_expose(MFD *mfd, ubyte control) {
1714 int n, s, v;
1715 uchar full = control & MFD_EXPOSE_FULL;
1716 if (control == 0)
1717 return;
1718 n = CPTRIP(MOTION_HARD_TRIPLE);
1719 s = player_struct.hardwarez_status[n];
1720 v = player_struct.hardwarez[n];
1721 PUSH_CANVAS(pmfd_canvas);
1722 mfd_clear_rects();
1723 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1724 mfd_item_micro_expose(full, MOTION_HARD_TRIPLE);
1725 // mfd_item_micro_hires_expose(full,MOTION_HARD_TRIPLE);
1726 if (full)
1727 draw_mfd_item_spew(REF_STR_wareSpew0 + STRINGS_PER_WARE * n, v);
1728 if (full || s != MOTION_LAST_STATUS(mfd->id) || MOTION_LAST_VERSION(mfd->id) != v) {
1729 int xjump = MOTION_BARRAY_WD / MOTION_BUTTONS;
1730 int i;
1731 for (i = 0; i < lg_min(v, MOTION_BUTTONS); i++) {
1732 int id = ((i == MOTION_SETTING(s) && (s & WARE_ON))) ? REF_IMG_LitMotion0 : REF_IMG_UnlitMotion0;
1733 grs_bitmap *bm = lock_bitmap_from_ref(id + i);
1734 short x = MOTION_BARRAY_X + i * xjump;
1735 short y = MOTION_BARRAY_Y;
1736 mfd_draw_bitmap(bm, x, y);
1737 if (i == MOTION_SETTING(s)) {
1738 gr_set_fcolor(GREEN_BASE + 2);
1739 ss_box(x - 1, y - 1, x + bm->w + 1, y + bm->h + 1);
1740 }
1741 mfd_add_rect(x - 2, y - 2, x + bm->w + 2, y + bm->h + 2);
1742 RefUnlock(id + i);
1743 }
1744 MOTION_LAST_STATUS(mfd->id) = s;
1745 MOTION_LAST_VERSION(mfd->id) = v;
1746 }
1747 POP_CANVAS();
1748 mfd_update_rects(mfd);
1749 }
1750
1751 // -----------------
1752 // TIMED GRENADE MFD
1753 // -----------------
1754
1755 #define MFD_GRENADE_FUNC 10
1756
1757 #define GRENADE_TIME_UNIT 10 // fraction of second for each time second unit
1758
1759 #define GRENADE_SLIDER_X MFD_BEAM_RECT_X1
1760 #define GRENADE_SLIDER_Y 51
1761 #define GRENADE_SLIDER_W 70
1762 #define GRENADE_SLIDER_H 5
1763
1764 #define GRENADE_SLIDER_IDX 0
1765
1766 #define GRENADE_MOUSE_CONSTRAINED (player_struct.mfd_func_data[MFD_GRENADE_FUNC][7])
1767
1768 #define GRENADE_HIRES_CUTOFF 100
1769
1770 uchar mfd_grenade_slider_handler(MFD *m, short val, uiEvent *ev, void *data);
1771 uchar mfd_grenade_handler(MFD *m, uiEvent *ev);
1772 errtype mfd_grenade_init(MFD_Func *f);
1773 void mfd_grenade_expose(MFD *mfd, ubyte control);
1774
mfd_grenade_slider_handler(MFD * m,short val,uiEvent * ev,void * data)1775 uchar mfd_grenade_slider_handler(MFD *m, short val, uiEvent *ev, void *data) {
1776 int n = player_struct.actives[ACTIVE_GRENADE];
1777 int triple = nth_after_triple(MAKETRIP(CLASS_GRENADE, 0, 0), n);
1778 short min = TimedGrenadeProps[SCTRIP(triple)].min_time_set * GRENADE_TIME_UNIT;
1779 short max = TimedGrenadeProps[SCTRIP(triple)].max_time_set * GRENADE_TIME_UNIT;
1780 short width = GRENADE_SLIDER_W;
1781 short setting;
1782
1783 if (max > 2 * GRENADE_HIRES_CUTOFF) {
1784 width /= 2;
1785 if (val >= GRENADE_SLIDER_W / 2) {
1786 val -= GRENADE_SLIDER_W / 2;
1787 min = GRENADE_HIRES_CUTOFF;
1788 } else
1789 max = GRENADE_HIRES_CUTOFF;
1790 }
1791 setting = val * (max - min) / width + min;
1792 player_struct.grenades_time_setting[n] = setting;
1793 if (ev->subtype & MOUSE_LDOWN) {
1794 LGRect r = mfd_funcs[MFD_GRENADE_FUNC].handlers[GRENADE_SLIDER_IDX].r;
1795 int my = ev->pos.y;
1796 RECT_OFFSETTED_RECT(&r, m->rect.ul, &r);
1797 slider_cursor.hotspot.x = slider_cursor_bmap.w / 2;
1798 slider_cursor.hotspot.y = (slider_cursor_bmap.h / 2) + my - (r.ul.y + r.lr.y) / 2;
1799 ui_mouse_constrain_xy(r.ul.x, my, r.lr.x - 2, my);
1800
1801 GRENADE_MOUSE_CONSTRAINED = m->id + 1;
1802 // Get our funky mfd-beam-phaser-setting cursor
1803 #ifdef CURSOR_BACKUPS
1804 backup[20] = (uchar *)malloc(f->bm.w * f->bm.h);
1805 LG_memcpy(backup[20], f->bm.bits, f->bm.w * f->bm.h);
1806 gr_init_bm(&backup_mfd_cursor, backup[14], BMT_FLAT8, 0, mfd_cursor.w, mfd_cursor.h);
1807 #endif
1808 uiPushRegionCursor(MFD_REGION(m), &slider_cursor);
1809 }
1810 if ((ev->mouse_data.buttons & (1 << MOUSE_LBUTTON)) == 0) {
1811 uiCursorStack *cs;
1812 uiGetRegionCursorStack(MFD_REGION(m), &cs);
1813 uiPopCursorEvery(cs, &slider_cursor);
1814
1815 if (GRENADE_MOUSE_CONSTRAINED) {
1816 mouse_unconstrain();
1817 GRENADE_MOUSE_CONSTRAINED = 0;
1818 mfd_notify_func(MFD_GRENADE_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
1819 }
1820 }
1821 mfd_notify_func(MFD_GRENADE_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1822 return TRUE;
1823 }
1824
mfd_grenade_handler(MFD * m,uiEvent * ev)1825 uchar mfd_grenade_handler(MFD *m, uiEvent *ev) {
1826 LGRect r = mfd_funcs[MFD_GRENADE_FUNC].handlers[GRENADE_SLIDER_IDX].r;
1827 RECT_MOVE(&r, m->rect.ul);
1828 if (!RECT_TEST_PT(&r, ev->pos)) {
1829 uiCursorStack *cs;
1830 uiGetRegionCursorStack(MFD_REGION(m), &cs);
1831 uiPopCursorEvery(cs, &slider_cursor);
1832 mfd_notify_func(MFD_GRENADE_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
1833 }
1834 return FALSE;
1835 }
1836
mfd_grenade_init(MFD_Func * f)1837 errtype mfd_grenade_init(MFD_Func *f) {
1838 int cnt = 0;
1839 errtype err;
1840 LGRect r = {{GRENADE_SLIDER_X, GRENADE_SLIDER_Y},
1841 {GRENADE_SLIDER_X + GRENADE_SLIDER_W, GRENADE_SLIDER_Y + GRENADE_SLIDER_H}};
1842 err = MFDSliderInit(&f->handlers[cnt++], &r, mfd_grenade_slider_handler, NULL);
1843 if (err != OK)
1844 return err;
1845 f->handler_count = cnt;
1846 #ifdef CURSOR_BACKUPS
1847 backup[21] = (uchar *)Malloc(slider_bmap.w * slider_bmap.h);
1848 LG_memcpy(backup[21], slider_bmap.bits, slider_bmap.w * slider_bmap.h);
1849 gr_init_bm(&backup_slider_cursor, backup[21], BMT_FLAT8, 0, slider_bmap.w, slider_bmap.h);
1850 #endif
1851 return OK;
1852 }
1853
1854 #define LAST_GRENADE(mfd) (player_struct.mfd_func_data[MFD_GRENADE_FUNC][mfd])
1855 #define LAST_GRENADE_SETTING(mfd) (player_struct.mfd_func_data[MFD_GRENADE_FUNC][mfd + 2])
1856
1857 #define GRENADE_SLIDER_BORDER MFD_BEAMWPN_STAT_BORDER
1858 #define GRENADE_SLIDER_SETTING_COLOR MFD_BEAMWPN_STAT_CHARGE
1859
1860 #define TIME_TEXT_Y (GRENADE_SLIDER_Y - 8)
1861 #define TIME_TEXT_LEN 128
1862
mfd_grenade_expose(MFD * mfd,ubyte control)1863 void mfd_grenade_expose(MFD *mfd, ubyte control) {
1864 MFD_Func *f = &mfd_funcs[MFD_GRENADE_FUNC];
1865 int n = player_struct.actives[ACTIVE_GRENADE];
1866 int triple = nth_after_triple(MAKETRIP(CLASS_GRENADE, 0, 0), n);
1867 uchar full = (control & MFD_EXPOSE_FULL) || (n != LAST_GRENADE(mfd->id));
1868 short setting = player_struct.grenades_time_setting[n];
1869
1870 if (control == 0) {
1871
1872 uiCursorStack *cs;
1873 uiGetRegionCursorStack(MFD_REGION(mfd), &cs);
1874 uiPopCursorEvery(cs, &slider_cursor);
1875
1876 if (GRENADE_MOUSE_CONSTRAINED == mfd->id + 1) {
1877 mouse_unconstrain();
1878 GRENADE_MOUSE_CONSTRAINED = 0;
1879 }
1880 return;
1881 }
1882 mfd_clear_rects();
1883 PUSH_CANVAS(pmfd_canvas);
1884 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1885 if (!full_game_3d)
1886 ss_bitmap(&mfd_background, 0, 0);
1887 // gr_bitmap(&mfd_background, 0, 0);
1888 mfd_item_micro_expose(full, triple);
1889 // mfd_item_micro_hires_expose(full,triple);
1890 LAST_GRENADE(mfd->id) = n;
1891 if (full || LAST_GRENADE_SETTING(mfd->id) != setting) {
1892 char buf[TIME_TEXT_LEN];
1893 LGRect *r = &f->handlers[GRENADE_SLIDER_IDX].r;
1894 short min = TimedGrenadeProps[SCTRIP(triple)].min_time_set * GRENADE_TIME_UNIT;
1895 short max = TimedGrenadeProps[SCTRIP(triple)].max_time_set * GRENADE_TIME_UNIT;
1896 short width = GRENADE_SLIDER_W;
1897 short base = 0;
1898 short x;
1899 if (max > 2 * GRENADE_HIRES_CUTOFF) {
1900 width /= 2;
1901 if (setting < GRENADE_HIRES_CUTOFF)
1902 max = GRENADE_HIRES_CUTOFF;
1903 else {
1904 base = GRENADE_SLIDER_W / 2;
1905 min = GRENADE_HIRES_CUTOFF;
1906 }
1907 }
1908 x = (setting - min) * width / (max - min) + base;
1909 gr_set_fcolor(GRENADE_SLIDER_BORDER);
1910 ss_box(r->ul.x - 1, r->ul.y - 1, r->lr.x, r->lr.y);
1911 mfd_add_rect(r->ul.x - 1, r->ul.y - 1, r->lr.x, r->lr.y + 1);
1912 gr_set_fcolor(GRENADE_SLIDER_SETTING_COLOR);
1913 if (!GRENADE_MOUSE_CONSTRAINED)
1914 draw_raw_resource_bm(REF_IMG_BeamSetting, r->ul.x + x - 3, r->ul.y - 1);
1915
1916
1917 sprintf(buf, "%s %d.%d", get_string(REF_STR_TimeSetting, NULL, TIME_TEXT_LEN), setting / 10, setting % 10);
1918 //numtostring(setting / 10, buf + strlen(buf)); // itoa(setting/10,buf+strlen(buf),10);
1919 //strcat(buf, ".");
1920 //numtostring(setting % 10, buf + strlen(buf)); // itoa(setting%10,buf+strlen(buf),10);
1921 {
1922 LGRect r = {{GRENADE_SLIDER_X, TIME_TEXT_Y}, {MFD_VIEW_WID, GRENADE_SLIDER_Y - 1}};
1923 mfd_partial_clear(&r);
1924 }
1925 mfd_draw_string(buf, GRENADE_SLIDER_X, TIME_TEXT_Y, GRENADE_SLIDER_BORDER, TRUE);
1926 LAST_GRENADE_SETTING(mfd->id) = setting;
1927 }
1928 POP_CANVAS();
1929 mfd_update_rects(mfd);
1930 }
1931
1932 // ------------------
1933 // * THE BIO WARE MFD
1934 // ------------------
1935
1936 #define BIO_TEXT_X 29
1937
1938 // ---------------------------------------------------------------------------
1939 // mfd_bioware_expose()
1940 //
1941 // This is the bioware, activated in the info window. It displays stats.
1942 // As of now, it's pretty sketchy.
1943
1944 #define LAST_HP(mfd) (mfd_fdata[MFD_BIOWARE_FUNC][4 * mfd])
1945 #define LAST_FATIGUE(mfd) (mfd_fdata[MFD_BIOWARE_FUNC][1 + 4 * mfd])
1946 #define LAST_DRUGBITS(mfd) (*(ushort *)&mfd_fdata[MFD_BIOWARE_FUNC][2 + 4 * mfd])
1947
1948 // this is stolen from gamesys.c
1949 #define MAX_FATIGUE 10000
1950 #define MAX_HP UCHAR_MAX
1951
1952 #define BIO_DRUG_UP 1 // experincing normal effects
1953 #define BIO_DRUG_DOWN 2 // experiencing after effects.
1954 #define BIO_DRUG_CLEAN 0
1955
1956 #define BITS_PER_DRUG 2
1957
mfd_bioware_expose(MFD * m,ubyte control)1958 void mfd_bioware_expose(MFD *m, ubyte control) {
1959 uchar full = control & MFD_EXPOSE_FULL;
1960 int i, y = 2, triple;
1961 char buf2[12];
1962 LGRect r;
1963
1964 r.ul.x = BIO_TEXT_X;
1965 r.ul.y = 20;
1966 r.lr.x = MFD_VIEW_WID;
1967 r.lr.y = MFD_VIEW_HGT;
1968
1969 // turn off the bioware if there's no exposed mfd.
1970 {
1971 extern WARE HardWare[NUM_HARDWAREZ];
1972 int i;
1973 uchar on = full || control & MFD_EXPOSE;
1974 for (i = 0; i < NUM_MFDS; i++) {
1975 ubyte slot = player_struct.mfd_current_slots[i];
1976 ubyte func = mfd_get_func(i, slot);
1977 if (func == MFD_BIOWARE_FUNC && (control != 0 || m->id != i))
1978 on = TRUE;
1979 }
1980 if (on == !(player_struct.hardwarez_status[HARDWARE_BIOWARE] & WARE_ON)) {
1981 use_ware(WARE_HARD, HARDWARE_BIOWARE);
1982 }
1983 }
1984
1985 if (control & MFD_EXPOSE) {
1986 char *s;
1987 char pct[] = "%";
1988 short x;
1989 ubyte v = player_struct.hardwarez[HARDWARE_BIOWARE];
1990 int ref = MKREF(RES_mfdArtOverlays, MFD_ART_HUMAN);
1991 uchar stam = player_struct.drug_status[CPTRIP(STAMINA_DRUG_TRIPLE)] > 0;
1992
1993 PUSH_CANVAS(pmfd_canvas);
1994 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
1995 mfd_clear_rects();
1996 if (!full_game_3d)
1997 ss_bitmap(&mfd_background, 0, 0);
1998 // gr_bitmap(&mfd_background, 0, 0);
1999 gr_set_font(ResLock(MFD_FONT));
2000
2001 if (full) {
2002 draw_res_bm(ref, 0, 0);
2003 mfd_add_rect(0, 0, res_bm_width(ref), res_bm_height(ref));
2004 }
2005 #ifdef BIOWARE_TITLE
2006 // Title
2007 if (full) {
2008 s = get_temp_string(REF_STR_BiowareTitle);
2009 mfd_draw_string(s, BIO_TEXT_X, y, GREEN_YELLOW_BASE, TRUE);
2010 }
2011 y += Y_STEP;
2012 #endif
2013
2014 // Health
2015 if (full || (LAST_HP(m->id) != player_struct.hit_points)) {
2016 uint hp;
2017 LGRect rest;
2018 s = get_temp_string(REF_STR_BiowareHealth);
2019 x = BIO_TEXT_X + gr_string_width(s);
2020 if (full)
2021 mfd_draw_string(s, BIO_TEXT_X, y, GREEN_YELLOW_BASE, TRUE);
2022 hp = (100 * player_struct.hit_points + (MAX_HP / 2)) / MAX_HP;
2023 if (hp == 0 && player_struct.hit_points > 0)
2024 hp = 1;
2025 sprintf(buf2, "%d", hp);
2026
2027 // hack to save space in display. Use "I" for "1", knowing
2028 // that "I" is narrower.
2029 string_replace_char(buf2, '1', 'I');
2030
2031 mfd_draw_string(buf2, x, y, GREEN_YELLOW_BASE, TRUE);
2032 x += gr_string_width(buf2);
2033 mfd_draw_string(pct, x, y, GREEN_YELLOW_BASE, TRUE);
2034 x += gr_string_width(pct);
2035 rest.ul.x = x;
2036 rest.ul.y = y;
2037 rest.lr.x = MFD_VIEW_WID;
2038 rest.lr.y = y + Y_STEP;
2039 mfd_partial_clear(&rest);
2040 LAST_HP(m->id) = player_struct.hit_points;
2041 }
2042 y += Y_STEP;
2043
2044 // Fatigue
2045 if (full || stam || (LAST_FATIGUE(m->id) != 100 * (uint)player_struct.fatigue / MAX_FATIGUE)) {
2046 LGRect rest;
2047 ubyte f = 100 * (uint)player_struct.fatigue / MAX_FATIGUE;
2048 s = get_temp_string(REF_STR_BiowareFatigue);
2049 x = BIO_TEXT_X + gr_string_width(s);
2050 if (full)
2051 mfd_draw_string(s, BIO_TEXT_X, y, GREEN_YELLOW_BASE, TRUE);
2052 if (stam) {
2053 strcpy(buf2, "--");
2054 mfd_draw_string(buf2, x, y, GREEN_YELLOW_BASE, TRUE);
2055 x += gr_string_width(buf2);
2056 } else {
2057 sprintf(buf2, "%d", f); // itoa(f,buf2,10);
2058
2059 // hack to save space in display. Use "I" for "1", knowing
2060 // that "I" is narrower.
2061 string_replace_char(buf2, '1', 'I');
2062 mfd_draw_string(buf2, x, y, GREEN_YELLOW_BASE, TRUE);
2063 x += gr_string_width(buf2);
2064 mfd_draw_string(pct, x, y, GREEN_YELLOW_BASE, TRUE);
2065 x += gr_string_width(pct);
2066 }
2067
2068 rest.ul.x = x;
2069 rest.ul.y = y;
2070 rest.lr.x = MFD_VIEW_WID;
2071 rest.lr.y = y + Y_STEP;
2072 mfd_partial_clear(&rest);
2073 LAST_FATIGUE(m->id) = f;
2074 }
2075 y += Y_STEP;
2076
2077 if (v > 1) {
2078 ushort drugbits = 0;
2079 for (i = 0; i < NUM_DRUGS; i++) {
2080 if (player_struct.drug_status[i] > 0)
2081 drugbits |= (BIO_DRUG_UP << (i * BITS_PER_DRUG));
2082 if (player_struct.drug_status[i] < 0)
2083 drugbits |= (BIO_DRUG_DOWN << (i * BITS_PER_DRUG));
2084 }
2085
2086 if (full || drugbits != LAST_DRUGBITS(m->id)) {
2087 short savey = y;
2088 LAST_DRUGBITS(m->id) = drugbits;
2089 for (i = 0; i < NUM_DRUGS; i++, drugbits >>= BITS_PER_DRUG) {
2090 ushort drugged = drugbits & ((1 << BITS_PER_DRUG) - 1);
2091 if (drugged != BIO_DRUG_CLEAN) {
2092 ubyte color = (drugged == BIO_DRUG_UP) ? GREEN_BASE + 3 : GOOD_RED;
2093 triple = drug2triple(i);
2094 get_object_short_name(triple, buf2, sizeof(buf2));
2095 mfd_draw_string(buf2, BIO_TEXT_X, y, color, TRUE);
2096 y += Y_STEP;
2097 }
2098 }
2099 mfd_add_rect(BIO_TEXT_X, savey, MFD_VIEW_WID, savey + Y_STEP * NUM_DRUGS);
2100 }
2101 }
2102 if (full)
2103 mfd_add_rect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
2104
2105 ResUnlock(MFD_FONT);
2106
2107 POP_CANVAS();
2108 mfd_update_rects(m);
2109 }
2110
2111 return;
2112 }
2113
2114 // -------------------
2115 // * THE ANIMATION MFD
2116 // -------------------
2117
2118 // ---------------------------------------------------------------------------
2119 // mfd_anim_init()
2120 //
2121 // Open the space station resource file for animation
2122
mfd_anim_init()2123 errtype mfd_anim_init() {
2124 #ifdef USING_DORKY_BROKEN_ANIM
2125 if (ResOpenFile("space4.res") < 0)
2126 critical_error(CRITERR_RES | 5);
2127 #endif
2128
2129 return OK;
2130 }
2131
2132 // ---------------------------------------------------------------------------
2133 // mfd_anim_expose()
2134 //
2135 // Strictly temporary code. Starts or stops the space station animation.
2136
mfd_anim_expose(MFD * m,ubyte control)2137 void mfd_anim_expose(MFD *m, ubyte control) {
2138 #ifndef NO_DUMMIES
2139 MFD *dummy;
2140 ubyte dummy2;
2141 dummy = m;
2142 dummy2 = control;
2143 #endif
2144 #ifdef USING_DORKY_BROKEN_ANIM
2145 static uchar AnimOn[2];
2146 static ActAnim *anim[2];
2147
2148 if (control & MFD_EXPOSE) {
2149
2150 gr_set_fcolor((long)BLACK);
2151 ss_rect(m->rect.ul.x, m->rect.ul.y, m->rect.lr.x, m->rect.lr.y);
2152
2153 anim[m->id] = AnimPlayRegion(REF_ANIM_space4, &(m->reg), m->rect.ul, 0);
2154 chg_set_sta(ANIM_UPDATE);
2155 AnimOn[m->id] = TRUE;
2156 } else {
2157
2158 AnimKill((anim[m->id]));
2159 AnimOn[m->id] = FALSE;
2160 if ((AnimOn[0] == FALSE) && (AnimOn[1] == FALSE))
2161 chg_unset_sta(ANIM_UPDATE);
2162 }
2163 #endif
2164 return;
2165 }
2166
2167 // SHODAN!!
2168 // Note this expects all appropriate 2d preparation to already be done!!
2169
2170 errtype draw_shodan_influence(MFD *mfd, uchar amt);
2171
draw_shodan_influence(MFD * mfd,uchar amt)2172 errtype draw_shodan_influence(MFD *mfd, uchar amt) {
2173 char *s = get_temp_string(SHODAN_FAILURE_STRING);
2174
2175 amt = lg_min(NUM_SHODAN_MUGS - 1, amt >> SHODAN_INTERVAL_SHIFT);
2176 draw_raw_res_bm_temp(REF_IMG_EmailMugShotBase + FIRST_SHODAN_MUG + amt, 0, 0);
2177
2178 gr_set_font(ResLock(MFD_FONT));
2179 gr_string_wrap(s, MFD_VIEW_WID);
2180 mfd_draw_string(s, 2, 2, SHODAN_COLOR, TRUE);
2181 ResUnlock(MFD_FONT);
2182 gr_font_string_unwrap(s);
2183
2184 mfd_add_rect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
2185 return (OK);
2186 }
2187
2188 // ELEVATOR PANEL MFD
2189 // ------------------
2190
2191 // NOMENCLATURE: "level" refers to the internal, unique, game-system
2192 // number for a level. "floor" refers to the in-game floor number for
2193 // a floor.
2194
2195 #define NUM_ELEV_LVLS 15
2196 #define NUM_ELEVATOR_BUTTONS 12
2197 #define ELEV_BTTN_ROWS 4
2198 #define ELEV_BTTN_COLS ((NUM_ELEVATOR_BUTTONS + ELEV_BTTN_ROWS - 1) / ELEV_BTTN_ROWS)
2199 #define ELEV_BTTNS_X 11
2200 #define ELEV_BTTNS_WD (MFD_VIEW_WID - 20)
2201 #define ELEV_BTTNS_Y 21
2202 #define ELEV_BTTNS_HT (MFD_VIEW_HGT - ELEV_BTTNS_Y - 2)
2203 #define ELEV_BTTN_HT 8
2204 #define ELEV_BTTN_WD 11
2205 #define ELEV_STATUS_Y 3
2206 #define ELEV_STATUS_X 50
2207
2208 #define ELEV_STATUS_FONT RES_mediumLEDFont
2209 #define ELEV_STATUS_COLOR (GOOD_RED)
2210
2211 typedef struct _elev_data {
2212 ushort shownlvls; // level shown on the button panel (bitmask)
2213 ushort reachlvls; // level actually reachable (bitmask)
2214 struct _mfd_specific {
2215 ubyte currlev : 4; // current level shown
2216 ubyte selected : 4; // currently selected button
2217 } stat, mfd_last[NUM_MFDS];
2218 } elev_data_type;
2219
2220 uchar curr_elev_special = 0;
2221
2222 errtype mfd_elevator_setlev(MFD *mfd, short lev, elev_data_type *elev_data);
2223 uchar mfd_elevator_button_handler(MFD *mfd, LGPoint bttn, uiEvent *ev, void *data);
2224 errtype mfd_elevator_init(MFD_Func *f);
2225 void mfd_setup_elevator(ushort levmask, ushort reachmask, ushort curlevel, uchar special);
2226 char *level_to_floor(int lev_num, char *buf);
2227 void mfd_elevator_expose(MFD *mfd, ubyte control);
2228
mfd_elevator_setlev(MFD * mfd,short lev,elev_data_type * elev_data)2229 errtype mfd_elevator_setlev(MFD *mfd, short lev, elev_data_type *elev_data) {
2230 elev_data->stat.currlev = lev;
2231 mfd_notify_func(MFD_ELEV_FUNC, MFD_INFO_SLOT, FALSE, MFD_ACTIVE, TRUE);
2232 mfd_update_current_slot(mfd->id, MFD_CHANGEBIT_FULL, 0);
2233 return (OK);
2234 }
2235
mfd_elevator_button_handler(MFD * mfd,LGPoint bttn,uiEvent * ev,void * data)2236 uchar mfd_elevator_button_handler(MFD *mfd, LGPoint bttn, uiEvent *ev, void *data) {
2237 elev_data_type *elev_data = (elev_data_type *)&player_struct.mfd_func_data[MFD_ELEV_FUNC][0];
2238 int b = bttn.x * ELEV_BTTN_ROWS + bttn.y;
2239 int c;
2240 ubyte l;
2241 ubyte reachl;
2242 ushort bit;
2243
2244 if (!(ev->mouse_data.action & MOUSE_LDOWN))
2245 return FALSE;
2246
2247 // If SHODAN has defeated us, indicate this for our expose func
2248 if (curr_elev_special) {
2249 elev_data->mfd_last[mfd->id].currlev = 0xF;
2250 mfd_notify_func(MFD_ELEV_FUNC, MFD_INFO_SLOT, FALSE, MFD_ACTIVE, TRUE);
2251 mfd_update_current_slot(mfd->id, MFD_CHANGEBIT_FULL, 0);
2252 return (OK);
2253 }
2254
2255 for (c = 0, reachl = 0, l = 0, bit = 1; l < NUM_ELEV_LVLS; l++, bit = bit << 1) {
2256 if (elev_data->reachlvls & bit)
2257 reachl++;
2258 if (elev_data->shownlvls & bit) {
2259 c++;
2260 if (c > b)
2261 break;
2262 }
2263 }
2264 if (l >= NUM_ELEV_LVLS)
2265 return TRUE;
2266 elev_data->stat.selected = b;
2267 #ifdef PLAYTEST
2268 mprintf("Pushing button %d\n", b);
2269 #endif
2270 if (!(bit & elev_data->reachlvls)) {
2271 string_message_info(REF_STR_ElevatorNoMove);
2272 #ifdef PLAYTEST
2273 mprintf("Can't get to that level\n");
2274 #endif
2275 } else {
2276 if (me_bits_music(MAP_GET_XY(PLAYER_BIN_X, PLAYER_BIN_Y)) != ELEVATOR_ZONE)
2277 string_message_info(REF_STR_UseTooFar);
2278 else {
2279 int oldlev;
2280 oldlev = elev_data->stat.currlev;
2281 mfd_elevator_setlev(mfd, l, elev_data);
2282 if (!elevator_use(l, reachl - 1))
2283 mfd_elevator_setlev(mfd, oldlev, elev_data);
2284 }
2285 }
2286 return TRUE;
2287 }
2288
2289 #define TEST_ELEVPANEL
2290
mfd_elevator_init(MFD_Func * f)2291 errtype mfd_elevator_init(MFD_Func *f) {
2292 int cnt = 0;
2293 errtype err;
2294 LGPoint bsize = {ELEV_BTTN_WD, ELEV_BTTN_HT};
2295 LGPoint bdims = {ELEV_BTTN_COLS, ELEV_BTTN_ROWS};
2296 LGRect r = {{ELEV_BTTNS_X, ELEV_BTTNS_Y}, {ELEV_BTTNS_X + ELEV_BTTNS_WD, ELEV_BTTNS_Y + ELEV_BTTNS_HT}};
2297 err = MFDBttnArrayInit(&f->handlers[cnt++], &r, bdims, bsize, mfd_elevator_button_handler, NULL);
2298 if (err != OK)
2299 return err;
2300 f->handler_count = cnt;
2301 #ifdef TEST_ELEVPANEL
2302 {
2303 elev_data_type *elev_data = (elev_data_type *)&player_struct.mfd_func_data[MFD_ELEV_FUNC][0];
2304 elev_data->shownlvls = 0xFFF;
2305 elev_data->reachlvls = 0xF0F;
2306 }
2307 #endif
2308 return OK;
2309 }
2310
2311 // Does every thing but set the slot..
mfd_setup_elevator(ushort levmask,ushort reachmask,ushort curlevel,uchar special)2312 void mfd_setup_elevator(ushort levmask, ushort reachmask, ushort curlevel, uchar special) {
2313 elev_data_type *elev_data = (elev_data_type *)&player_struct.mfd_func_data[MFD_ELEV_FUNC][0];
2314 elev_data->shownlvls = levmask;
2315 elev_data->reachlvls = reachmask;
2316 elev_data->stat.currlev = curlevel;
2317 elev_data->stat.selected = 0xF;
2318 curr_elev_special = special;
2319 mfd_notify_func(MFD_ELEV_FUNC, MFD_INFO_SLOT, TRUE, MFD_ACTIVE, TRUE);
2320 }
2321
level_to_floor(int lev_num,char * buf)2322 char *level_to_floor(int lev_num, char *buf) {
2323 int bpos = 0;
2324 char grov_init = toupper(get_temp_string(REF_STR_GroveWord)[0]);
2325
2326 switch (lev_num) {
2327 case 0:
2328 buf[bpos++] = toupper(get_temp_string(REF_STR_ReactorWord)[0]);
2329 break;
2330 case 11:
2331 buf[bpos++] = grov_init;
2332 buf[bpos++] = '4';
2333 break;
2334 case 12:
2335 buf[bpos++] = grov_init;
2336 buf[bpos++] = '1';
2337 break;
2338 case 13:
2339 buf[bpos++] = grov_init;
2340 buf[bpos++] = '2';
2341 break;
2342 default:
2343 if (lev_num >= 10) {
2344 buf[bpos++] = '0' + ((lev_num / 10) % 10);
2345 buf[bpos++] = '0' + (lev_num % 10);
2346 } else
2347 buf[bpos++] = '0' + lev_num;
2348 break;
2349 }
2350 if (bpos != 0)
2351 buf[bpos] = '\0'; // add trailing stop
2352 return (buf);
2353 }
2354
2355 #define NUMBER_BUFSZ 4 // don't forget the terminator!
2356
2357 // if we null your panel_ref, return the value
2358 // before we nulled it. Otherwise, return NULL.
2359 //
panel_ref_unexpose(int mfdid,int func)2360 ObjID panel_ref_unexpose(int mfdid, int func) {
2361 uchar found = FALSE;
2362 int id = NUM_MFDS;
2363 ObjID pr = player_struct.panel_ref;
2364
2365 while (mfd_yield_func(func, &id))
2366 if (id != mfdid)
2367 return OBJ_NULL;
2368 else
2369 found = TRUE;
2370
2371 if (found)
2372 check_panel_ref(TRUE);
2373 else
2374 player_struct.panel_ref = OBJ_NULL;
2375 return pr;
2376 }
2377
mfd_elevator_expose(MFD * mfd,ubyte control)2378 void mfd_elevator_expose(MFD *mfd, ubyte control) {
2379 elev_data_type *elev_data = (elev_data_type *)&player_struct.mfd_func_data[MFD_ELEV_FUNC][0];
2380 char buf[NUMBER_BUFSZ];
2381 uchar full = control & MFD_EXPOSE_FULL;
2382 if (control == 0) {
2383 panel_ref_unexpose(mfd->id, MFD_ELEV_FUNC);
2384 return;
2385 }
2386 mfd_clear_rects();
2387 PUSH_CANVAS(pmfd_canvas);
2388 if (full)
2389 mfd_clear_view();
2390 if (curr_elev_special == 0)
2391 elev_data->mfd_last[mfd->id].currlev = 0;
2392 if (elev_data->mfd_last[mfd->id].currlev == 0xF)
2393 draw_shodan_influence(mfd, curr_elev_special);
2394 else {
2395 if (full || elev_data->mfd_last[mfd->id].currlev != elev_data->stat.currlev) {
2396 short w, h;
2397 int lev = elev_data->stat.currlev;
2398 gr_set_font(ResLock(ELEV_STATUS_FONT));
2399 level_to_floor(lev, buf);
2400 gr_string_size(buf, &w, &h);
2401 mfd_draw_font_string(buf, ELEV_STATUS_X - w, ELEV_STATUS_Y, ELEV_STATUS_COLOR, ELEV_STATUS_FONT, TRUE);
2402 elev_data->mfd_last[mfd->id].currlev = lev;
2403 ResUnlock(ELEV_STATUS_FONT);
2404 }
2405 if (full || elev_data->mfd_last[mfd->id].selected != elev_data->stat.selected) {
2406 int i;
2407 int l;
2408 short w, h;
2409 // LGPoint bstep = { ELEV_BTTNS_WD/ELEV_BTTN_COLS,
2410 // ELEV_BTTNS_HT/ELEV_BTTN_ROWS };
2411 gr_set_font(ResLock(MFD_FONT));
2412 for (i = 0, l = 0; i < NUM_ELEVATOR_BUTTONS; i++) {
2413 ubyte clr;
2414 LGPoint bttn;
2415
2416 bttn.x = ELEV_BTTNS_X + (i / ELEV_BTTN_ROWS) * (ELEV_BTTNS_WD - ELEV_BTTN_WD) / (ELEV_BTTN_COLS - 1);
2417 bttn.y = ELEV_BTTNS_Y + (i % ELEV_BTTN_ROWS) * (ELEV_BTTNS_HT - ELEV_BTTN_HT) / (ELEV_BTTN_ROWS - 1);
2418
2419 if (i > 0)
2420 l++;
2421 for (; l < NUM_ELEV_LVLS; l++)
2422 if ((1 << l) & elev_data->shownlvls)
2423 break;
2424 if (l >= NUM_ELEV_LVLS)
2425 break;
2426 if (!(elev_data->reachlvls & (1 << l)))
2427 clr = UNAVAILABLE_ITEM_COLOR;
2428 else if (i == elev_data->stat.selected)
2429 clr = SELECTED_ITEM_COLOR;
2430 else
2431 clr = ITEM_COLOR;
2432 gr_set_fcolor((long)clr);
2433 ss_box(bttn.x, bttn.y, bttn.x + ELEV_BTTN_WD, bttn.y + ELEV_BTTN_HT);
2434 gr_set_fcolor((long)ITEM_COLOR + 2);
2435 ss_box(bttn.x - 1, bttn.y - 1, bttn.x + ELEV_BTTN_WD + 1, bttn.y + ELEV_BTTN_HT + 1);
2436 level_to_floor(l, buf);
2437 gr_string_size(buf, &w, &h);
2438 mfd_draw_string(buf, bttn.x + (ELEV_BTTN_WD - w) / 2 + 1, bttn.y + 1, clr, TRUE);
2439 }
2440 elev_data->mfd_last[mfd->id].selected = elev_data->stat.selected;
2441 mfd_add_rect(ELEV_BTTNS_X, ELEV_BTTNS_Y, ELEV_BTTNS_X + ELEV_BTTNS_WD, ELEV_BTTNS_Y + ELEV_BTTNS_HT);
2442 ResUnlock(MFD_FONT);
2443 }
2444 }
2445 POP_CANVAS();
2446 mfd_update_rects(mfd);
2447 }
2448
2449 // ------------------
2450 // KEYPAD MFD
2451 // ------------------
2452
2453 #define NUM_KEYPAD_BUTTONS 12
2454 #define KEYPAD_BTTN_ROWS 4
2455 #define KEYPAD_BTTN_COLS 3
2456 #define KEYPAD_X_MARGIN 0
2457 #define KEYPAD_Y_MARGIN 2
2458 #define KEYPAD_BTTNS_X 19
2459 #define KEYPAD_BTTNS_WD (MFD_VIEW_WID - (2 * KEYPAD_BTTNS_X) - 1 - KEYPAD_X_MARGIN)
2460 //#define KEYPAD_BTTNS_WD (MFD_VIEW_WID - (3* KEYPAD_BTTNS_X))
2461 #define KEYPAD_BTTNS_Y 20
2462 #define KEYPAD_BTTNS_HT (MFD_VIEW_HGT - KEYPAD_BTTNS_Y - KEYPAD_Y_MARGIN - 1)
2463 #define KEYPAD_BTTN_HT 8
2464 #define KEYPAD_BTTN_WD 11
2465 #define KEYPAD_STATUS_Y 3
2466 #define KEYPAD_STATUS_X 60
2467
2468 #define MAX_KEYPAD_DIGITS 3
2469
2470 #define KEYPAD_STATUS_FONT RES_mediumLEDFont
2471 #define KEYPAD_STATUS_COLOR (GOOD_RED)
2472
2473 bool gKeypadOverride = false; // When this is true, don't move the player.
2474
2475 typedef struct _keypad_data {
2476 uchar curr_digit;
2477 uchar last_digit;
2478 uchar digits[MAX_KEYPAD_DIGITS];
2479 uchar special;
2480 } keypad_data_type;
2481
2482 uchar keypad_num(int b);
2483 char *keypad_name(int b, char *buf);
2484 char *mfd_keypad_assemble(keypad_data_type *keypad_data, char *buf);
2485 errtype mfd_keypad_input(MFD *m, char b_num);
2486 uchar keypad_hotkey_func(ushort keycode, uint32_t context, intptr_t data);
2487 void install_keypad_hotkeys(void);
2488 uchar mfd_keypad_handler(MFD *m, uiEvent *ev);
2489 uchar mfd_keypad_button_handler(MFD *mfd, LGPoint bttn, uiEvent *ev, void *data);
2490 errtype mfd_keypad_init(MFD_Func *f);
2491 void mfd_keypad_expose(MFD *mfd, ubyte control);
2492
keypad_num(int b)2493 uchar keypad_num(int b) {
2494 #ifdef KEYPAD_NUM_CASE
2495 uchar retval;
2496 // as Doug points out, this case statement is expressed algorithmically,
2497 // but hey, this is already done, easier to modify and maybe even easier
2498 // to understand.
2499 switch (b) {
2500 case 0:
2501 retval = 1;
2502 break;
2503 case 1:
2504 retval = 4;
2505 break;
2506 case 2:
2507 retval = 7;
2508 break;
2509 case 3:
2510 retval = 10;
2511 break;
2512 case 4:
2513 retval = 2;
2514 break;
2515 case 5:
2516 retval = 5;
2517 break;
2518 case 6:
2519 retval = 8;
2520 break;
2521 case 7:
2522 retval = 0;
2523 break;
2524 case 8:
2525 retval = 3;
2526 break;
2527 case 9:
2528 retval = 6;
2529 break;
2530 case 10:
2531 retval = 9;
2532 break;
2533 case 11:
2534 retval = 11;
2535 break;
2536 }
2537 return (retval);
2538 #endif
2539 static uchar retval[] = {1, 4, 7, 10, 2, 5, 8, 0, 3, 6, 9, 11};
2540 return (retval[b]);
2541 }
2542
2543 // note that the b in keypad_name is already converted from keypad_num
keypad_name(int b,char * buf)2544 char *keypad_name(int b, char *buf) {
2545 switch (b) {
2546 case 10:
2547 strcpy(buf, "-");
2548 break;
2549 case 11:
2550 strcpy(buf, "C");
2551 break;
2552 default:
2553 sprintf(buf, "%d", b);
2554 break;
2555 }
2556 return (buf);
2557 }
2558
mfd_keypad_assemble(keypad_data_type * keypad_data,char * buf)2559 char *mfd_keypad_assemble(keypad_data_type *keypad_data, char *buf) {
2560 char tmp[5];
2561 int i;
2562 strcpy(buf, "");
2563 for (i = 0; i < keypad_data->curr_digit; i++) {
2564 strcat(buf, keypad_name(keypad_data->digits[i], tmp));
2565 }
2566 return (buf);
2567 }
2568
mfd_keypad_input(MFD * mfd,char b_num)2569 errtype mfd_keypad_input(MFD *mfd, char b_num) {
2570 keypad_data_type *keypad_data = (keypad_data_type *)&player_struct.mfd_func_data[MFD_KEYPAD_FUNC][0];
2571 extern errtype keypad_trigger(ObjID id, uchar digits[MAX_KEYPAD_DIGITS]);
2572
2573 switch (b_num) {
2574 case 10:
2575 if (keypad_data->curr_digit != 0)
2576 keypad_data->curr_digit--;
2577 break;
2578 case 11:
2579 keypad_data->curr_digit = 0;
2580 break;
2581 default:
2582 if (keypad_data->curr_digit == MAX_KEYPAD_DIGITS)
2583 mfd_setup_keypad(keypad_data->special);
2584 keypad_data->digits[keypad_data->curr_digit] = b_num;
2585 keypad_data->curr_digit++;
2586 break;
2587 }
2588 play_digi_fx_obj(SFX_MFD_KEYPAD, 1, player_struct.panel_ref);
2589 if (keypad_data->special == 0 && keypad_data->curr_digit == MAX_KEYPAD_DIGITS) {
2590 keypad_trigger(player_struct.panel_ref, keypad_data->digits);
2591 }
2592 mfd_notify_func(MFD_KEYPAD_FUNC, MFD_INFO_SLOT, FALSE, MFD_ACTIVE, TRUE);
2593 return (OK);
2594 }
2595
keypad_hotkey_func(ushort keycode,uint32_t context,intptr_t data)2596 uchar keypad_hotkey_func(ushort keycode, uint32_t context, intptr_t data) {
2597 extern MFD mfd[];
2598 uchar digit = kb2ascii(keycode) - '0';
2599 int m = NUM_MFDS;
2600 while (mfd_yield_func(MFD_KEYPAD_FUNC, &m)) {
2601 mfd_keypad_input(&mfd[m], digit);
2602 return TRUE;
2603 }
2604 return FALSE;
2605 }
2606
install_keypad_hotkeys(void)2607 void install_keypad_hotkeys(void) {
2608 int i;
2609 for (i = 0; i < 10; i++)
2610 // KLC hotkey_add(('0'+i)|KB_FLAG_DOWN|KB_FLAG_2ND, DEMO_CONTEXT, keypad_hotkey_func, 0);
2611 hotkey_add(('0' + i) | KB_FLAG_DOWN, DEMO_CONTEXT, keypad_hotkey_func, 0);
2612 }
2613
mfd_keypad_handler(MFD * m,uiEvent * ev)2614 uchar mfd_keypad_handler(MFD *m, uiEvent *ev) {
2615 uchar retval = FALSE;
2616 char n;
2617
2618 if (ev->type != UI_EVENT_KBD_COOKED)
2619 return (FALSE);
2620 if (!(ev->cooked_key_data.code & KB_FLAG_DOWN))
2621 return (FALSE);
2622 n = (ev->cooked_key_data.code & 0xFF) - '0';
2623 if ((n < 0) || (n > 9))
2624 return (FALSE);
2625 mfd_keypad_input(m, n);
2626 return (FALSE);
2627 }
2628
mfd_keypad_button_handler(MFD * mfd,LGPoint bttn,uiEvent * ev,void * data)2629 uchar mfd_keypad_button_handler(MFD *mfd, LGPoint bttn, uiEvent *ev, void *data) {
2630 int b = bttn.x * KEYPAD_BTTN_ROWS + bttn.y;
2631
2632 // Filter out anything that isn't a left-click down at all
2633 if ((ev->subtype & (MOUSE_LDOWN | UI_MOUSE_LDOUBLE)) == 0)
2634 return (FALSE);
2635 mfd_keypad_input(mfd, keypad_num(b));
2636 return TRUE;
2637 }
2638
mfd_keypad_init(MFD_Func * f)2639 errtype mfd_keypad_init(MFD_Func *f) {
2640 int cnt = 0;
2641 errtype err;
2642 LGPoint bsize = {KEYPAD_BTTN_WD, KEYPAD_BTTN_HT};
2643 LGPoint bdims = {KEYPAD_BTTN_COLS, KEYPAD_BTTN_ROWS};
2644 LGRect r = {{KEYPAD_BTTNS_X, KEYPAD_BTTNS_Y}, {KEYPAD_BTTNS_X + KEYPAD_BTTNS_WD, KEYPAD_BTTNS_Y + KEYPAD_BTTNS_HT}};
2645 err = MFDBttnArrayInit(&f->handlers[cnt++], &r, bdims, bsize, mfd_keypad_button_handler, NULL);
2646 if (err != OK)
2647 return err;
2648 f->handler_count = cnt;
2649 return OK;
2650 }
2651
2652 // Does every thing but set the slot..
mfd_setup_keypad(char special)2653 void mfd_setup_keypad(char special) {
2654 int i;
2655 keypad_data_type *keypad_data = (keypad_data_type *)&player_struct.mfd_func_data[MFD_KEYPAD_FUNC][0];
2656 keypad_data->curr_digit = 0;
2657 for (i = 0; i < MAX_KEYPAD_DIGITS; i++)
2658 keypad_data->digits[i] = 0;
2659 keypad_data->special = special;
2660 mfd_notify_func(MFD_KEYPAD_FUNC, MFD_INFO_SLOT, TRUE, MFD_ACTIVE, TRUE);
2661 }
2662
mfd_keypad_expose(MFD * mfd,ubyte control)2663 void mfd_keypad_expose(MFD *mfd, ubyte control) {
2664 keypad_data_type *keypad_data = (keypad_data_type *)&player_struct.mfd_func_data[MFD_KEYPAD_FUNC][0];
2665 char buf[NUMBER_BUFSZ];
2666 uchar full = control & MFD_EXPOSE_FULL;
2667 if (control == 0) {
2668 ObjID pr;
2669 pr = panel_ref_unexpose(mfd->id, MFD_KEYPAD_FUNC);
2670 if (pr)
2671 objs[pr].info.current_frame = 0;
2672 gKeypadOverride = FALSE;
2673 return;
2674 }
2675 mfd_clear_rects();
2676 PUSH_CANVAS(pmfd_canvas);
2677 if (full)
2678 mfd_clear_view();
2679 if ((keypad_data->special > 0) && (keypad_data->curr_digit > 0))
2680 draw_shodan_influence(mfd, keypad_data->special);
2681 else {
2682 if (full || (keypad_data->last_digit != keypad_data->curr_digit)) {
2683 int i;
2684 short w, h;
2685 // LGPoint bstep = { KEYPAD_BTTNS_WD/KEYPAD_BTTN_COLS,
2686 // KEYPAD_BTTNS_HT/KEYPAD_BTTN_ROWS };
2687
2688 // Draw cool LED at top of MFD
2689 gr_set_font(ResLock(KEYPAD_STATUS_FONT));
2690 mfd_keypad_assemble(keypad_data, buf);
2691 gr_string_size(buf, &w, &h);
2692 mfd_draw_font_string(buf, KEYPAD_STATUS_X - w, KEYPAD_STATUS_Y, KEYPAD_STATUS_COLOR, KEYPAD_STATUS_FONT,
2693 TRUE);
2694 keypad_data->last_digit = keypad_data->curr_digit;
2695 ResUnlock(KEYPAD_STATUS_FONT);
2696
2697 // Draw buttons
2698 gr_set_font(ResLock(MFD_FONT));
2699 for (i = 0; i < NUM_KEYPAD_BUTTONS; i++) {
2700 ubyte clr;
2701 LGPoint bttn;
2702
2703 bttn.x = KEYPAD_BTTNS_X +
2704 (i / KEYPAD_BTTN_ROWS) * (KEYPAD_BTTNS_WD - KEYPAD_BTTN_WD) / (KEYPAD_BTTN_COLS - 1);
2705 bttn.y = KEYPAD_BTTNS_Y +
2706 (i % KEYPAD_BTTN_ROWS) * (KEYPAD_BTTNS_HT - KEYPAD_BTTN_HT) / (KEYPAD_BTTN_ROWS - 1);
2707
2708 if ((keypad_data->curr_digit > 0) &&
2709 (keypad_num(i) == keypad_data->digits[keypad_data->curr_digit - 1]))
2710 clr = SELECTED_ITEM_COLOR;
2711 else
2712 clr = ITEM_COLOR;
2713 gr_set_fcolor((long)clr);
2714 ss_box(bttn.x, bttn.y, bttn.x + KEYPAD_BTTN_WD, bttn.y + KEYPAD_BTTN_HT);
2715 gr_set_fcolor(ITEM_COLOR + 2);
2716 ss_box(bttn.x - 1, bttn.y - 1, bttn.x + KEYPAD_BTTN_WD + 1, bttn.y + KEYPAD_BTTN_HT + 1);
2717 keypad_name(keypad_num(i), buf);
2718 gr_string_size(buf, &w, &h);
2719 mfd_draw_string(buf, bttn.x + (KEYPAD_BTTN_WD - w) / 2 + 1, bttn.y + 1, clr, TRUE);
2720 }
2721 mfd_add_rect(KEYPAD_BTTNS_X, KEYPAD_BTTNS_Y, KEYPAD_BTTNS_X + KEYPAD_BTTNS_WD,
2722 KEYPAD_BTTNS_Y + KEYPAD_BTTNS_HT);
2723 ResUnlock(MFD_FONT);
2724 }
2725 }
2726 POP_CANVAS();
2727 mfd_update_rects(mfd);
2728 }
2729
2730 /*
2731 // --------------------
2732 // HUD WARE MFD
2733 // --------------------
2734
2735 #define MFD_HUD_FUNC 11
2736
2737 #define HUD_SETTING_MASK 0xF8
2738 #define HUD_SETTING_SHF 3
2739
2740 #define HUDWARE_STATUS (player_struct.hardwarez_status[CPTRIP(HUD_GOG_TRIPLE)])
2741 #define HUDWARE_VERSION (player_struct.hardwarez[CPTRIP(HUD_GOG_TRIPLE)])
2742
2743
2744 ushort hud_ware_bits[] = { HUD_COMPASS, HUD_DETECT_EXP, HUD_GRENADE };
2745
2746 #define NUM_HUDWARE_DISPLAYS (sizeof(hud_ware_bits)/sizeof(ushort))
2747
2748 #define HUDWARE_DISPLAY_AVAILABLE(dnum) (HUDWARE_VERSION & ( 1 << (dnum)))
2749
2750 // Note the use of negative logic here....
2751 #define HUDWARE_DISPLAY_ACTIVE(dnum) (!(HUDWARE_STATUS & (1 << ((dnum) + HUD_SETTING_SHF))))
2752 #define HUDWARE_DISPLAY_TOGGLE(dnum) (HUDWARE_STATUS ^= (1 << (dnum) + HUD_SETTING_SHF))
2753
2754 uchar mfd_hud_button_handler(MFD* m, LGPoint bttn, uiEvent* ev, void* data)
2755 {
2756
2757 // Check to see if we actually have the specified display.
2758 if (!HUDWARE_DISPLAY_AVAILABLE(bttn.y)) return FALSE;
2759 // Toggle the display
2760 if (ev->type == UI_EVENT_MOUSE && ev->subtype & (MOUSE_LDOWN|MOUSE_RDOWN))
2761 HUDWARE_DISPLAY_TOGGLE(bttn.y);
2762
2763 if (HUDWARE_STATUS & WARE_ON) // update the actual hud.
2764 {
2765 if (HUDWARE_DISPLAY_ACTIVE(bttn.y))
2766 hud_set(hud_ware_bits[bttn.y]);
2767 else
2768 hud_unset(hud_ware_bits[bttn.y]);
2769 }
2770 mfd_notify_func(MFD_HUD_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
2771 return TRUE;
2772 }
2773
2774
2775 #define HUDWARE_BUTTON_X 2
2776 #define HUDWARE_BUTTON_Y 16
2777 #define HUDWARE_LINE_SPACING 7
2778
2779 #define HUDWARE_LAST_STATUS(mfd) mfd_fdata[MFD_HUD_FUNC][mfd]
2780
2781 #define HUDWARE_BOX_COLOR ITEM_COLOR
2782 #define HUDWARE_BOX_SIZE HUDWARE_LINE_SPACING
2783
2784 #ifdef HUDWARE_MFD
2785
2786 errtype mfd_hud_init(MFD_Func* f)
2787 {
2788 errtype err;
2789 LGPoint bsize = { MFD_VIEW_WID, HUDWARE_LINE_SPACING};
2790 LGPoint bdims = { 1, NUM_HUDWARE_DISPLAYS };
2791 LGRect brect = { { 0, HUDWARE_BUTTON_Y },
2792 { MFD_VIEW_WID, HUDWARE_BUTTON_Y + NUM_HUDWARE_DISPLAYS*HUDWARE_LINE_SPACING}};
2793 int cnt = 0;
2794 err = MFDBttnArrayInit(&f->handlers[cnt++],&brect,bdims,bsize,mfd_hud_button_handler,NULL);
2795 if (err != OK) return err;
2796 f->handler_count = cnt;
2797 return OK;
2798 }
2799
2800 void mfd_hud_expose(MFD* mfd, ubyte control)
2801 {
2802 uchar full = control & MFD_EXPOSE_FULL;
2803 if (control == 0) return;
2804
2805 mfd_clear_rects();
2806 PUSH_CANVAS(pmfd_canvas);
2807 ss_safe_set_cliprect(0,0,MFD_VIEW_WID,MFD_VIEW_HGT);
2808
2809 // Lay down the "background"
2810 mfd_item_micro_expose(TRUE,HUD_GOG_TRIPLE);
2811 // clear rects so that we don't draw it if we don't have to
2812 if (!full) mfd_clear_rects();
2813
2814 if (full || HUDWARE_STATUS != HUDWARE_LAST_STATUS(mfd->id))
2815 {
2816 int i;
2817 for (i = 0; i < NUM_HUDWARE_DISPLAYS; i++)
2818 if (HUDWARE_DISPLAY_AVAILABLE(i))
2819 {
2820 short x = HUDWARE_BUTTON_X;
2821 short y = HUDWARE_BUTTON_Y + i * HUDWARE_LINE_SPACING;
2822 short textx;
2823 char* s;
2824 // draw an "x" if active
2825 if (HUDWARE_DISPLAY_ACTIVE(i))
2826 {
2827 gr_set_fcolor(GOOD_RED);
2828 ss_int_line(x,y,x+HUDWARE_BOX_SIZE-1,y+HUDWARE_BOX_SIZE-1);
2829 ss_int_line(x,y+HUDWARE_BOX_SIZE-1,x+HUDWARE_BOX_SIZE-1,y);
2830 }
2831 gr_set_fcolor(HUDWARE_BOX_COLOR);
2832 ss_box(x,y,x+HUDWARE_BOX_SIZE,y+HUDWARE_BOX_SIZE);
2833 gr_set_font(ResLock(MFD_FONT));
2834 s = get_temp_string(REF_STR_HudBase+i);
2835 textx = (MFD_VIEW_WID - HUDWARE_BOX_SIZE - gr_string_width(s))/2 + HUDWARE_BOX_SIZE;
2836 mfd_draw_string(s,textx,y+1,gr_get_fcolor(),TRUE);
2837 ResUnlock(MFD_FONT);
2838 mfd_add_rect(x,y,MFD_VIEW_WID,y+HUDWARE_LINE_SPACING);
2839 }
2840 HUDWARE_LAST_STATUS(mfd->id) = HUDWARE_STATUS;
2841 }
2842 POP_CANVAS();
2843 mfd_update_rects(mfd);
2844 }
2845
2846 void hudware_update_status(uchar on)
2847 {
2848 int i;
2849 for (i = 0; i < NUM_HUDWARE_DISPLAYS; i++)
2850 if (HUDWARE_DISPLAY_ACTIVE(i) && on)
2851 hud_set(hud_ware_bits[i]);
2852 else
2853 hud_unset(hud_ware_bits[i]);
2854 }
2855
2856 #endif // HUDWARE_MFD
2857 */
2858
2859 // ----------------------------------------------------------
2860 // THE GOOFY SEVERED HEAD MFD
2861 // ----------------------------------------------------------
2862
2863 void severed_head_expose(MFD *mfd, ubyte control);
2864
severed_head_expose(MFD * mfd,ubyte control)2865 void severed_head_expose(MFD *mfd, ubyte control) {
2866 uchar full = control & MFD_EXPOSE_FULL;
2867 if (full) {
2868 ubyte headnum = player_struct.actives[ACTIVE_GENERAL];
2869 ObjID head = player_struct.inventory[headnum];
2870 int mug;
2871 uint trip = ID2TRIP(head);
2872
2873 if (head == OBJ_NULL || !(trip == HEAD_TRIPLE || trip == HEAD2_TRIPLE))
2874 return;
2875 // clear update rects
2876 mfd_clear_rects();
2877 // set up canvas
2878 gr_push_canvas(pmfd_canvas);
2879 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
2880 // Clear the canvas by drawing the background bitmap
2881 if (!full_game_3d)
2882 ss_bitmap(&mfd_background, 0, 0);
2883 // gr_bitmap(&mfd_background, 0, 0);
2884
2885 mug = REF_IMG_EmailMugShotBase + objSmallstuffs[objs[head].specID].data1;
2886 FrameDesc *f = RefLock(mug);
2887 if (f != NULL) {
2888 ss_bitmap(&f->bm, (MFD_VIEW_WID - f->bm.w) / 2, (MFD_VIEW_HGT - f->bm.h) / 2);
2889 RefUnlock(mug);
2890 } else {
2891 WARN("severed_head_expose(): could not load head art ", mug);
2892 }
2893
2894 // draw the name
2895 mfd_draw_string(get_object_long_name(ID2TRIP(head), NULL, 0), X_MARGIN, 2, GREEN_YELLOW_BASE, TRUE);
2896 mfd_add_rect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
2897
2898 // Pop the canvas
2899 gr_pop_canvas();
2900 // Now that we've popped the canvas, we can send the
2901 // updated mfd to screen
2902 mfd_update_rects(mfd);
2903 }
2904 }
2905
2906 // -------------------
2907 // * GENERIC BLANK MFD
2908 // -------------------
2909
2910 // ---------------------------------------------------------------------------
2911 // mfd_expose_blank()
2912 //
2913 // Draw whatever we're supposed to draw if we're looking at an empty slot.
2914
mfd_expose_blank(MFD * m,ubyte control)2915 void mfd_expose_blank(MFD *m, ubyte control) {
2916 if (full_game_3d) {
2917 full_visible &= ~visible_mask(m->id);
2918 chg_set_sta(FULLSCREEN_UPDATE);
2919 return;
2920 }
2921 if ((control & MFD_EXPOSE) && !full_game_3d) {
2922
2923 PUSH_CANVAS(pmfd_canvas);
2924 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
2925
2926 draw_blank_mfd();
2927
2928 POP_CANVAS();
2929 mfd_update_display(m, 0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
2930 }
2931
2932 return;
2933 }
2934
2935 // ---------------------------------------------------------------------------
2936 // CALLS FROM OTHER MODULES TO THE MFD SYSTEM
2937 // ---------------------------------------------------------------------------
2938
2939 // ---------------------------------------------------------------------------
2940 // set_inventory_mfd()
2941 //
2942 // Called by the inventory whenever a new drug, ware, something is clicked
2943 // on in the inventory panel.
2944
2945 ulong catbasetrips[MFD_INV_CATEGORIES] = {
2946 0,
2947 MAKETRIP(CLASS_DRUG, 0, 0),
2948 MAKETRIP(CLASS_HARDWARE, 0, 0),
2949 MAKETRIP(CLASS_GRENADE, 0, 0),
2950 MAKETRIP(CLASS_AMMO, 0, 0),
2951 MAKETRIP(CLASS_GUN, 0, 0),
2952 0, // general inventory
2953 MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_OFFENSE, 0),
2954 MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_DEFENSE, 0),
2955 MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_ONESHOT, 0),
2956 };
2957
2958 // look, another array that should not exist.
2959 ubyte catactives[] = {
2960 0,
2961 ACTIVE_DRUG,
2962 ACTIVE_HARDWARE,
2963 ACTIVE_GRENADE,
2964 ACTIVE_CART,
2965 ACTIVE_WEAPON,
2966 ACTIVE_GENERAL,
2967 ACTIVE_COMBAT_SOFT,
2968 ACTIVE_DEFENSE_SOFT,
2969 ACTIVE_MISC_SOFT,
2970 };
2971
2972 ubyte activecats[] = {
2973 MFD_INV_WEAPON, MFD_INV_GRENADE, MFD_INV_DRUG, MFD_INV_AMMO, MFD_INV_HARDWARE,
2974 MFD_INV_SOFT_COMBAT, MFD_INV_SOFT_DEFENSE, MFD_INV_SOFT_MISC, MFD_INV_GENINV, 0,
2975 };
2976
2977 extern void set_current_active(int);
2978 void update_item_mfd(void);
2979 uchar mfd_distance_remove(ubyte slot_func);
2980 uchar mfd_target_qual(void);
2981 uchar mfd_automap_qual(void);
2982 uchar mfd_weapon_qual(void);
2983
set_inventory_mfd(ubyte obclass,ubyte type,uchar grab)2984 void set_inventory_mfd(ubyte obclass, ubyte type, uchar grab) {
2985 int i;
2986 ubyte func = MFD_EMPTY_FUNC;
2987 ubyte slot;
2988 MFD_Status stat;
2989 uchar classhit = FALSE;
2990
2991 switch (obclass) {
2992
2993 case MFD_INV_WEAPON:
2994
2995 // The "grab" arg is TRUE in case blanked out by an inventory drop
2996 func = MFD_WEAPON_FUNC;
2997 slot = MFD_WEAPON_SLOT;
2998 stat = MFD_ACTIVE;
2999 if (type == MFD_INV_NOTYPE) {
3000 stat = MFD_EMPTY;
3001 }
3002 break;
3003
3004 case MFD_INV_NULL:
3005
3006 if (type == MFD_INV_NOTYPE)
3007 break;
3008 for (i = 0; i < NUM_MFDS; i++) {
3009 MFDSetCurrItemClass(i, obclass);
3010 }
3011 func = MFD_ITEM_FUNC;
3012 slot = MFD_ITEM_SLOT;
3013 stat = MFD_EMPTY;
3014 break;
3015
3016 default:
3017 for (i = 0; i < NUM_MFDS; i++) {
3018 if (MFDGetCurrItemClass(i) == obclass)
3019 classhit = TRUE;
3020 if (type != MFD_INV_NOTYPE)
3021 MFDSetCurrItemClass(i, obclass);
3022 }
3023 slot = MFD_ITEM_SLOT;
3024 stat = MFD_ACTIVE;
3025 if (type == MFD_INV_NOTYPE) {
3026 if (classhit) {
3027 mfd_notify_func(MFD_EMPTY_FUNC, MFD_ITEM_SLOT, TRUE, MFD_EMPTY, TRUE);
3028 player_struct.actives[catactives[obclass]] = 0;
3029 }
3030 } else if (obclass == MFD_INV_GENINV && player_struct.inventory[type] == OBJ_NULL) {
3031 mfd_notify_func(MFD_EMPTY_FUNC, MFD_ITEM_SLOT, grab, MFD_EMPTY, TRUE);
3032 } else {
3033 ulong opnum = (obclass != MFD_INV_GENINV) ? OPTRIP(catbasetrips[obclass]) + type
3034 : OPNUM(player_struct.inventory[type]);
3035 func = ObjProps[opnum].mfd_id;
3036 if (func == MFD_EMPTY_FUNC)
3037 func = MFD_ITEM_FUNC;
3038 set_current_active(catactives[obclass]);
3039 }
3040 break;
3041 }
3042 if (func != MFD_EMPTY_FUNC) {
3043 mfd_notify_func(func, slot, grab, stat, TRUE);
3044 #ifdef RAISE_ON_SELECT
3045 if (full_game_3d) {
3046 int i;
3047 for (i = 0; i < NUM_MFDS; i++) {
3048 if (player_struct.mfd_current_slots[i] == MFD_ITEM_SLOT) {
3049 #ifdef STEREO_SUPPORT
3050 if (convert_use_mode == 5) {
3051 full_visible = FULL_MFD_MASK(i);
3052 } else
3053 #endif
3054 full_visible |= FULL_MFD_MASK(i);
3055 }
3056 }
3057 }
3058 #endif
3059 }
3060 // THEN we check to see if we need to take over the info mfd
3061
3062 switch (obclass) {
3063
3064 case MFD_INV_HARDWARE:
3065
3066 switch (type) {
3067
3068 case HARDWARE_BIOWARE:
3069
3070 if (WareActive(player_struct.hardwarez_status[HARDWARE_BIOWARE]))
3071 mfd_notify_func(MFD_BIOWARE_FUNC, MFD_INFO_SLOT, TRUE, MFD_ACTIVE, TRUE);
3072
3073 break;
3074 }
3075
3076 break;
3077 }
3078
3079 if (obclass != MFD_INV_NULL && type != MFD_INV_NOTYPE)
3080 player_struct.actives[catactives[obclass]] = type;
3081
3082 return;
3083 }
3084
update_item_mfd(void)3085 void update_item_mfd(void) {
3086 ubyte curr = player_struct.current_active;
3087 if (curr != NULL_ACTIVE) {
3088 ubyte obclass = activecats[curr];
3089 ubyte type = player_struct.actives[curr];
3090 ulong opnum =
3091 (obclass != MFD_INV_GENINV) ? OPTRIP(catbasetrips[obclass]) + type : OPNUM(player_struct.inventory[type]);
3092 int func = ObjProps[opnum].mfd_id;
3093 if (func != MFD_EMPTY_FUNC) {
3094 mfd_notify_func(func, MFD_ITEM_FUNC, TRUE, MFD_ACTIVE, TRUE);
3095 }
3096 }
3097 }
3098
mfd_distance_remove(ubyte slot_func)3099 uchar mfd_distance_remove(ubyte slot_func) {
3100 switch (slot_func) {
3101 case MFD_KEYPAD_FUNC:
3102 case MFD_FIXTURE_FUNC:
3103 case MFD_ELEV_FUNC:
3104 case MFD_BARK_FUNC:
3105 case MFD_ACCESSPANEL_FUNC:
3106 case MFD_GUMP_FUNC:
3107 case MFD_GRIDPANEL_FUNC:
3108 return TRUE;
3109 }
3110 return FALSE;
3111 }
3112
3113 // -------
3114 // DEFAULT MFD FUNC QUALIFYING FUNCTIONS
mfd_target_qual(void)3115 uchar mfd_target_qual(void) { return (player_struct.hardwarez[HARDWARE_TARGET] > 0); }
3116
mfd_automap_qual(void)3117 uchar mfd_automap_qual(void) { return (player_struct.hardwarez[HARDWARE_AUTOMAP] > 0); }
3118
mfd_weapon_qual(void)3119 uchar mfd_weapon_qual(void) {
3120 return (player_struct.weapons[player_struct.actives[ACTIVE_WEAPON]].type != EMPTY_WEAPON_SLOT);
3121 }
3122
3123 // --------------------------------------------------------
3124 // THE STATIC MFD_FUNCS ARRAY
3125
3126 extern void mfd_view360_expose(MFD *mfd, ubyte control);
3127 extern void mfd_dummy_expose(MFD *mfd, ubyte control);
3128 extern void mfd_fixture_expose(MFD *mfd, ubyte control);
3129 extern uchar mfd_fixture_handler(MFD *mfd, uiEvent *e);
3130 extern void mfd_emailmug_expose(MFD *mfd, ubyte control);
3131 extern uchar mfd_emailmug_handler(MFD *mfd, uiEvent *e);
3132 extern errtype mfd_emailware_init(MFD_Func *f);
3133 extern void mfd_emailware_expose(MFD *, ubyte);
3134 extern void mfd_plotware_expose(MFD *, ubyte);
3135 extern errtype mfd_plotware_init(MFD_Func *f);
3136 extern void mfd_bark_expose(MFD *, ubyte);
3137 extern errtype mfd_accesspanel_init(MFD_Func *f);
3138 extern uchar mfd_accesspanel_handler(MFD *mfd, uiEvent *ev);
3139 extern void mfd_accesspanel_expose(MFD *mfd, ubyte control);
3140 extern errtype mfd_gridpanel_init(MFD_Func *f);
3141 extern void mfd_gridpanel_expose(MFD *mfd, ubyte control);
3142 extern uchar mfd_gridpanel_handler(MFD *mfd, uiEvent *ev);
3143 extern void mfd_targetware_expose(MFD *mfd, ubyte control);
3144 extern uchar mfd_targetware_handler(MFD *mfd, uiEvent *ev);
3145 extern void mfd_gump_expose(MFD *mfd, ubyte control);
3146 extern uchar mfd_gump_handler(MFD *mfd, uiEvent *ev);
3147 extern void mfd_accesscard_expose(MFD *mfd, ubyte control);
3148 extern void mfd_biohelp_expose(MFD *mfd, ubyte control);
3149 extern errtype mfd_biohelp_init(MFD_Func *f);
3150 extern uchar mfd_biohelp_handler(MFD *mfd, uiEvent *ev);
3151 extern void mfd_cspace_expose(MFD *mfd, ubyte control);
3152 extern void mfd_viewhelp_expose(MFD *mfd, ubyte control);
3153 extern errtype mfd_viewhelp_init(MFD_Func *f);
3154 extern void mfd_gear_expose(MFD *mfd, ubyte control);
3155 extern uchar mfd_gear_handler(MFD *mfd, uiEvent *ev);
3156
3157 #define PANEL_PRIORITY 37
3158
3159 MFD_Func mfd_funcs[MFD_NUM_FUNCS] = {
3160 // MFD_EMPTY_FUNC 0
3161 {mfd_expose_blank, NULL, NULL, 255, MFD_NOSAVEREST},
3162 // MFD_ITEM_FUNC 1
3163 {mfd_item_expose, mfd_item_handler, mfd_item_init, 40},
3164 // MFD_MAP_FUNC 2
3165 {mfd_map_expose, mfd_map_handler, mfd_map_init, 20, MFD_INCREMENTAL},
3166 // MFD_TARGET_FUNC 3
3167 {mfd_target_expose, mfd_target_handler, NULL, 21},
3168 // MFD_ANIM_FUNC 4
3169 {mfd_expose_blank, NULL, NULL, 255},
3170 // MFD_WEAPON_FUNC 5
3171 {mfd_weapon_expose, mfd_weapon_handler, mfd_weapon_init, 25},
3172 // MFD_BIOWARE_FUNC 6
3173 {mfd_bioware_expose, NULL, NULL, 50, MFD_NOSAVEREST},
3174 // MFD_LANTERN_FUNC 7
3175 {mfd_lanternware_expose, NULL, mfd_lanternware_init, 38},
3176 // MFD_3DVIEW_FUNC 8
3177 {mfd_view360_expose, NULL, NULL, 25, MFD_NOSAVEREST},
3178 // MFD_ELEV_FUNC 9
3179 {mfd_elevator_expose, NULL, mfd_elevator_init, PANEL_PRIORITY, MFD_NOSAVEREST},
3180 // MFD_GRENADE_FUNC 10
3181 {mfd_grenade_expose, mfd_grenade_handler, mfd_grenade_init, 32},
3182 // MFD_HUD_FUNC 11
3183 {
3184 mfd_expose_blank,
3185 },
3186 // MFD_FIXTURE_FUNC 12
3187 {mfd_fixture_expose, mfd_fixture_handler, NULL, 32, MFD_NOSAVEREST},
3188 // MFD_KEYPAD_FUNC 13
3189 {mfd_keypad_expose, mfd_keypad_handler, mfd_keypad_init, PANEL_PRIORITY, MFD_NOSAVEREST},
3190 // MFD_EMAILMUG_FUNC 14
3191 {mfd_emailmug_expose, mfd_emailmug_handler, NULL, 60, MFD_NOSAVEREST},
3192 // MFD_EMAILWARE_FUNC 15
3193 {mfd_emailware_expose, NULL, mfd_emailware_init, 60},
3194 // MFD_PLOTWARE_FUNC 16
3195 {mfd_plotware_expose, NULL, mfd_plotware_init, 55},
3196 // MFD_BARK_FUNC 17
3197 {mfd_bark_expose, NULL, NULL, 255, MFD_NOSAVEREST},
3198 // MFD_ACCESSPANEL_FUNC 18
3199 {mfd_accesspanel_expose, mfd_accesspanel_handler, mfd_accesspanel_init, PANEL_PRIORITY,
3200 MFD_INCREMENTAL | MFD_NOSAVEREST},
3201 // MFD_SHIELD_FUNC 19
3202 {mfd_shieldware_expose, mfd_shield_handler, mfd_shield_init, 36},
3203 // MFD_MOTION_FUNC 20
3204 {mfd_motionware_expose, NULL, mfd_motion_init, 36},
3205 // MFD_SEVERED_HEAD_FUNC 21
3206 {severed_head_expose, NULL, NULL, 250},
3207 // MFD_TARGETWARE_FUNC 22
3208 {mfd_targetware_expose, mfd_targetware_handler, NULL, 40},
3209 // MFD_GUMP_FUNC 23
3210 {mfd_gump_expose, mfd_gump_handler, NULL, 40, MFD_NOSAVEREST},
3211 // MFD_CARD_FUNC 24
3212 {mfd_accesscard_expose, NULL, NULL, 40},
3213 // MFD_BIOHELP_FUNC 25
3214 {mfd_biohelp_expose, mfd_biohelp_handler, mfd_biohelp_init, 40},
3215 // MFD_GRIDPANEL_FUNC 26
3216 {mfd_gridpanel_expose, mfd_gridpanel_handler, mfd_gridpanel_init, PANEL_PRIORITY, MFD_NOSAVEREST},
3217 // MFD_GAMES_FUNC 27
3218 {mfd_games_expose, mfd_games_handler, mfd_games_init, PANEL_PRIORITY, MFD_INCREMENTAL | MFD_NOSAVEREST},
3219 // MFD_CYBERSPACE_FUNC 28
3220 {mfd_cspace_expose, NULL, NULL, 40},
3221 // MFD_VIEWHELP_FUNC 29
3222 {mfd_viewhelp_expose, NULL, mfd_viewhelp_init, 40},
3223 // MFD_GEAR_FUNC 30
3224 {mfd_gear_expose, mfd_gear_handler, NULL, 40}};
3225