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/wares.c $
21 * $Revision: 1.109 $
22 * $Author: dc $
23 * $Date: 1994/11/22 15:59:26 $
24 *
25 */
26
27 #include <string.h>
28
29 #include "wares.h"
30 #include "hud.h"
31 #include "player.h"
32 #include "gamesys.h"
33 #include "sideicon.h"
34 #include "newmfd.h"
35 #include "cybstrng.h"
36 #include "gamestrn.h"
37 #include "textmaps.h"
38 #include "render.h"
39 #include "frparams.h"
40 #include "FrUtils.h"
41 #include "objsim.h"
42 #include "otrip.h"
43 #include "mainloop.h"
44 #include "gameloop.h"
45 #include "musicai.h"
46 #include "sfxlist.h"
47 #include "objbit.h"
48 #include "objprop.h"
49 #include "tools.h"
50 #include "faketime.h"
51 #include "weapons.h"
52 #include "fullscrn.h"
53 #include "mainloop.h"
54 #include "map.h"
55 #include "physics.h"
56 #include "softdef.h"
57 #include "cyber.h"
58 #include "damage.h"
59
60 //----------------
61 // Internal Prototypes
62 //----------------
63 uchar is_passive_hardware(int n);
64 bool is_oneshot_misc_software(int n);
65 int energy_cost(int warenum);
66 void hardware_closedown(uchar visible);
67 void hardware_startup(uchar visible);
68 void hardware_power_outage(void);
69 bool check_game(void);
70
71 // ------
72 // Globals
73 // -------
74
75 // forward decls for arrays at end of file
76 extern WARE HardWare[NUM_HARDWAREZ];
77 extern WARE Combat_SoftWare[NUM_COMBAT_SOFTS];
78 extern WARE Defense_SoftWare[NUM_DEFENSE_SOFTS];
79 extern WARE Misc_SoftWare[NUM_MISC_SOFTS];
80
81 #define MAX_VERSIONS 5
82 extern short energy_cost_vec[NUM_HARDWAREZ][MAX_VERSIONS];
83
84 long ware_base_triples[NUM_WARE_TYPES] = {
85 MAKETRIP(CLASS_HARDWARE, 0, 0),
86 MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_OFFENSE, 0),
87 MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_DEFENSE, 0),
88 MAKETRIP(CLASS_SOFTWARE, SOFTWARE_SUBCLASS_ONESHOT, 0),
89 };
90
91 // The existence of this array is a crime. I should be shot.
92 ubyte waretype2invtype[] = {
93 MFD_INV_HARDWARE,
94 MFD_INV_SOFT_COMBAT,
95 MFD_INV_SOFT_DEFENSE,
96 MFD_INV_SOFT_MISC,
97 };
98
99 #define IDX_OF_TYPE(type, trip) (OPTRIP(trip) - OPTRIP(ware_base_triples[type]))
100
101 #define PASSIVE_WARE_FLAG 1
102
103 // EXTERNALS
104 // =========
105 // -------------------------------------------------------
106 // get_ware_triple() converts our stupid representation for
107 // a ware triple into the standard one.
108
get_ware_triple(int waretype,int num)109 int get_ware_triple(int waretype, int num) { return nth_after_triple(ware_base_triples[waretype], num); }
110
111 // ---------------------------------------------------------------------------
112 // get_ware_name()
113 //
114 // Returns the name of a ware to the inventory system.
115
get_ware_name(int waretype,int num,char * buf,int sz)116 char *get_ware_name(int waretype, int num, char *buf, int sz) {
117 get_object_short_name(nth_after_triple(ware_base_triples[waretype], num), buf, sz);
118 return buf;
119 }
120
is_passive_hardware(int n)121 uchar is_passive_hardware(int n) {
122 ushort cflags = (ObjProps[OPTRIP(MAKETRIP(CLASS_HARDWARE, 0, 0)) + n].flags & CLASS_FLAGS) >> CLASS_FLAGS_SHF;
123 return (cflags & PASSIVE_WARE_FLAG);
124 }
125
is_oneshot_misc_software(int n)126 bool is_oneshot_misc_software(int n) { return ((n < NUM_ONESHOT_SOFTWARE)); }
127
128 // INTERNALS
129 // =========
130
energy_cost(int warenum)131 int energy_cost(int warenum) {
132 uchar version = player_struct.hardwarez[warenum];
133 if (version == 0)
134 return 0;
135 if (warenum == CPTRIP(LANTERN_HARD_TRIPLE))
136 version = LAMP_SETTING(player_struct.hardwarez_status[warenum]) + 1;
137 if (warenum == CPTRIP(SHIELD_HARD_TRIPLE))
138 version = LAMP_SETTING(player_struct.hardwarez_status[warenum]) + 1;
139 if (warenum == CPTRIP(MOTION_HARD_TRIPLE) && motionware_mode == MOTION_SKATES)
140 version = MOTION_SKATES;
141 if (warenum == CPTRIP(JET_HARD_TRIPLE))
142 return 0;
143 return energy_cost_vec[warenum][version - 1];
144 }
145
146 // ---------------------------------------------------------------------------
147 // use_ware()
148 //
149 // Called from the UI/Inventory, this routine figures out what is being used
150 // and what function to call. Turns things on or off as appropriate.
151
use_ware(int waretype,int num)152 void use_ware(int waretype, int num) {
153 ubyte *player_wares, *player_status;
154 WARE *wares;
155 int n, ecost;
156 int ware_sfx = SFX_NONE, hnd;
157 // int i;
158 // ubyte invtype;
159 if ((!global_fullmap->cyber != (waretype == 0)) // boolean equality, yum.
160 && !(waretype == WARE_SOFT_MISC && num == 4) // special games ware hack
161 && !(waretype == WARE_HARD && num == HARDWARE_FULLSCREEN))
162 return;
163 get_ware_pointers(waretype, &player_wares, &player_status, &wares, &n);
164 if ((player_wares[num] == 0) && (!(WareActive(player_status[num])))) {
165 return; // don't turn on a ware we don't have, only turn off one we're discarding
166 }
167
168 // Hey, can we even use this kind of ware right now?
169 if (wares[num].check != NULL)
170 if (!wares[num].check())
171 return;
172
173 // check to see if we have enough power
174 if (waretype == WARE_HARD && !WareActive(player_status[num]) && player_struct.energy < (energy_cost(num) + 4) / 5) {
175 string_message_info(REF_STR_WareNoPower);
176 return;
177 }
178 player_status[num] ^= WARE_ON;
179
180 if (wares[num].sideicon != SI_NONE)
181 side_icon_expose(wares[num].sideicon);
182
183 if (!WareActive(player_status[num])) { // we're turning a ware off
184
185 // note that the energy_cost function may use state which is
186 // dependent on the ware being on to figure out the correct
187 // cost (e.g., motionware).
188 if (waretype == WARE_HARD)
189 ecost = energy_cost(num);
190
191 if (wares[num].turnoff)
192 wares[num].turnoff(TRUE, TRUE);
193 switch (num) {
194 case HARDWARE_360:
195 case HARDWARE_SHIELD:
196 case HARDWARE_EMAIL:
197 break;
198 case HARDWARE_GOGGLE_INFRARED:
199 ware_sfx = SFX_VIDEO_DOWN;
200 break;
201 default:
202 ware_sfx = SFX_HUDFROB;
203 break;
204 }
205 } else { // we're turning a ware on
206
207 // Turn on the durned thing
208 if (wares[num].turnon)
209 wares[num].turnon(TRUE, TRUE);
210
211 // note that the energy_cost function may use state which is
212 // dependent on the ware being on to figure out the correct
213 // cost (e.g., motionware).
214 if (waretype == WARE_HARD)
215 ecost = energy_cost(num);
216
217 if ((waretype == WARE_HARD) && (num >= FIRST_GOGGLE_WARE) && (num <= LAST_GOGGLE_WARE)) {
218 // Play the goggle sound effect
219 ware_sfx = SFX_GOGGLE;
220 } else {
221 if (num != HARDWARE_SHIELD) {
222 ware_sfx = SFX_HUDFROB;
223 }
224 }
225
226 // // keep the invtype around in case we want to let mfd know about it
227 // if (waretype == WARE_HARD) invtype = MFD_INV_HARDWARE;
228 // else if (waretype == WARE_SOFT_COMBAT) invtype = MFD_INV_SOFT_COMBAT;
229 // else if (waretype == WARE_SOFT_DEFENSE) invtype = MFD_INV_SOFT_DEFENSE;
230 // else invtype = MFD_INV_SOFT_MISC;
231 }
232 if (ware_sfx != SFX_NONE) {
233 extern char secret_global_pan;
234 int ci_idx = wares[num].sideicon;
235 // secret_global_pan=(ci_idx==SI_NONE)?SND_DEF_PAN:(ci_idx<5)?5:122;
236 hnd = play_digi_fx(ware_sfx, 1);
237 // secret_global_pan=SND_DEF_PAN;
238 }
239 if (waretype == WARE_HARD) {
240 short newe = player_struct.energy_spend;
241 if (WareActive(player_status[num]))
242 newe = lg_min(newe + ecost, MAX_ENERGY);
243 else
244 newe = lg_max(newe - ecost, 0);
245 set_player_energy_spend((ubyte)newe);
246 }
247 if (_current_loop <= FULLSCREEN_LOOP)
248 chg_set_flg(INVENTORY_UPDATE);
249 mfd_notify_func(NOTIFY_ANY_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
250 }
251
252 // Hey, we're closing down a game. return to normalcy.
hardware_closedown(uchar visible)253 void hardware_closedown(uchar visible) {
254 for (uint16_t i = 0; i < NUM_HARDWAREZ; i++) {
255 // if (i != HARDWARE_FULLSCREEN)
256 if (WareActive(player_struct.hardwarez_status[i]))
257 if (HardWare[i].turnoff != NULL)
258 HardWare[i].turnoff(visible, FALSE);
259 }
260 }
261
hardware_startup(uchar visible)262 void hardware_startup(uchar visible) {
263 for (uint16_t i = 0; i < NUM_HARDWAREZ; i++) {
264 // if (i != HARDWARE_FULLSCREEN)
265 if (WareActive(player_struct.hardwarez_status[i]))
266 if (HardWare[i].turnon != NULL)
267 HardWare[i].turnon(visible, FALSE);
268 }
269 }
270
hardware_power_outage(void)271 void hardware_power_outage(void) {
272 for (uint16_t i = 0; i < NUM_HARDWAREZ; i++) {
273 if (energy_cost(i) > 0 && WareActive(player_struct.hardwarez_status[i]))
274 use_ware(WARE_HARD, i);
275 }
276 if (WareActive(player_struct.hardwarez_status[CPTRIP(JET_HARD_TRIPLE)]))
277 use_ware(WARE_HARD, CPTRIP(JET_HARD_TRIPLE));
278 }
279
280 // ---------------------------------------------------------------------------
281 // get_ware_pointers()
282 //
283 // Sets a number of pointers to point at the appropriate ware structures
284 // for a given type.
285
get_ware_pointers(int type,ubyte ** player_wares,ubyte ** player_status,WARE ** wares,int * n)286 void get_ware_pointers(int type, ubyte **player_wares, ubyte **player_status, WARE **wares, int *n) {
287 if (type == WARE_HARD) {
288 *n = NUM_HARDWAREZ;
289 *player_wares = player_struct.hardwarez;
290 *player_status = player_struct.hardwarez_status;
291 *wares = HardWare;
292 }
293
294 else if (type == WARE_SOFT_COMBAT) {
295 *n = NUM_COMBAT_SOFTS;
296 *player_wares = player_struct.softs.combat;
297 *player_status = player_struct.softs_status.combat;
298 *wares = Combat_SoftWare;
299 } else if (type == WARE_SOFT_DEFENSE) {
300 *n = NUM_DEFENSE_SOFTS;
301 *player_wares = player_struct.softs.defense;
302 *player_status = player_struct.softs_status.defense;
303 *wares = Defense_SoftWare;
304 } else {
305 *n = NUM_MISC_SOFTS;
306 *player_wares = player_struct.softs.misc;
307 *player_status = player_struct.softs_status.misc;
308 *wares = Misc_SoftWare;
309 }
310
311 }
312
313 // --------------------------------------------------
314 //
315 // get_player_ware_version returns the version number
316 // of a ware in the player's inventory. zero means
317 // the player doesn't have it.
318
get_player_ware_version(int type,int n)319 int get_player_ware_version(int type, int n) {
320 WARE *Pwares;
321 ubyte *pver;
322 ubyte *pstat;
323 int num;
324 get_ware_pointers(type, &pver, &pstat, &Pwares, &num);
325 return pver[n];
326 }
327
328 // ---------------------------------------------------------------------------
329 // wares_update()
330 //
331 // Called from the main loop, this routine cycles through all active wares
332 // and sees if any need attention.
333
wares_update()334 void wares_update() {
335 ubyte *player_status, *player_wares;
336 WARE *wares;
337 int i, j, n;
338
339 if ((player_struct.game_time - player_struct.last_ware_update) >= WARE_UPDATE_FREQ) {
340
341 player_struct.last_ware_update = player_struct.game_time;
342
343 // Iterate through all types of wares...
344
345 // NOTE: At some point, we may want to differentiate here between
346 // wares that get updated in the cyberloop as opposed to the
347 // real world. For now, we leave it all mashed together.
348
349 for (i = 0; i < NUM_WARE_TYPES; i++) {
350
351 get_ware_pointers(i, &player_wares, &player_status, &wares, &n);
352
353 // Now we know what type of ware we're looking at.
354 // Look at all wares of this type.
355
356 for (j = 0; j < n; j++) {
357
358 // Is it active? If so...
359 if (WareActive(player_status[j])) {
360
361 // Does it have a continually active effect?
362 if (wares[j].effect)
363 wares[j].effect();
364 }
365 }
366
367 // We're ready to look at the next type of ware.
368 }
369 }
370 for (j = 0; j < NUM_HARDWAREZ; j++)
371 if (player_struct.hardwarez_status[j] & WARE_FLASH) {
372 side_icon_expose(HardWare[j].sideicon);
373 }
374
375 }
376
377 // ---------------------------------------------------------------------------
378 // wares_init()
379 //
380 // Sets the static values for all wares.
381
wares_init()382 void wares_init() { }
383
384 // CALLBACKS
385 // =========
386
387 // ---------------------------------------------------------------------------
388 // wares_dummy_func()
389 //
390 // Temporary dummy function for all wares callbacks.
391
392 // void wares_dummy_func()
393 //{
394 // return;
395 //}
396
397 // ----------
398 // * BIO WARE
399 // ----------
400 void bioware_turnon(uchar visible, uchar real_start);
401 void bioware_turnoff(uchar visible, uchar real_stop);
402 void bioware_effect(void);
403
404 // ---------------------------------------------------------------------------
405 // bioware_turnon()
406 //
407 // Let the MFD system know that the bioware is active, and take over
408 // the appropriate info MFD
409
bioware_turnon(uchar visible,uchar real_s)410 void bioware_turnon(uchar visible, uchar real_s) {
411 if (visible) {
412 mfd_notify_func(MFD_BIOWARE_FUNC, MFD_INFO_SLOT, TRUE, MFD_FLASH, TRUE);
413 int32_t i = mfd_grab_func(MFD_BIOWARE_FUNC, MFD_INFO_SLOT);
414 mfd_change_slot(i, MFD_INFO_SLOT);
415 }
416
417 }
418
419 // ---------------------------------------------------------------------------
420 // bioware_turnoff()
421 //
422 // Let the MFD system know that the bioware is deactivated, and toss it off
423 // the info slot, replacing it with a blank.
424
bioware_turnoff(uchar visible,uchar real_stop)425 void bioware_turnoff(uchar visible, uchar real_stop) {
426 if (real_stop && player_struct.mfd_all_slots[MFD_INFO_SLOT] == MFD_BIOWARE_FUNC)
427 mfd_notify_func(MFD_EMPTY_FUNC, MFD_INFO_SLOT, TRUE, MFD_EMPTY, TRUE);
428 }
429
430 // ---------------------------------------------------
431 // bioware_effect()
432 //
433 // updates the mfd.
434
bioware_effect(void)435 void bioware_effect(void) { mfd_notify_func(MFD_BIOWARE_FUNC, MFD_INFO_SLOT, FALSE, MFD_ACTIVE, FALSE); }
436
437 // ---------------
438 // * INFRARED WARE
439 // ---------------
440 void infrared_turnon(uchar visible, uchar real_start);
441 void infrared_turnoff(uchar visible, uchar real_start);
442
443 extern char curr_clut_table;
444 // ---------------------------------------------------------------------------
445 // infrared_turnon()
446 //
447 // Turns on the infrared ware
infrared_turnon(uchar visible,uchar real_s)448 void infrared_turnon(uchar visible, uchar real_s) {
449 if (visible) {
450 gr_set_light_tab(bw_shading_table);
451 curr_clut_table = 1;
452 chg_set_flg(_current_3d_flag);
453 hud_set(HUD_INFRARED);
454 }
455 }
456
457 // ---------------------------------------------------------------------------
458 // infrared_turnoff()
459 //
460 // Turns off the infrared ware
461
infrared_turnoff(uchar visible,uchar real_s)462 void infrared_turnoff(uchar visible, uchar real_s) {
463 if (visible) {
464 gr_set_light_tab(shading_table);
465 chg_set_flg(_current_3d_flag);
466 curr_clut_table = 0;
467
468 hud_unset(HUD_INFRARED);
469 }
470 }
471
472 // --------------------
473 // * TARGETING WARE
474 // --------------------
475 void targeting_turnon(uchar visible, uchar real_start);
476 void targeting_turnoff(uchar visible, uchar real_start);
477
478 // ---------------------------------------------------------------------------
479 // targeting_turnon()
480 //
481 // Turn on the targeting ware
482
targeting_turnon(uchar visible,uchar real_start)483 void targeting_turnon(uchar visible, uchar real_start) {
484 extern void select_closest_target();
485
486 player_struct.hardwarez_status[CPTRIP(TARG_GOG_TRIPLE)] &= ~WARE_ON;
487 if (visible && real_start) {
488 if (player_struct.curr_target == OBJ_NULL)
489 select_closest_target();
490 mfd_change_slot(mfd_grab_func(MFD_TARGET_FUNC, MFD_TARGET_SLOT), MFD_TARGET_SLOT);
491 }
492 }
493
494 // ---------------------------------------------------------------------------
495 // targeting_turnoff()
496 //
497 // Turn off the targeting ware
498
targeting_turnoff(uchar visible,uchar real_s)499 void targeting_turnoff(uchar visible, uchar real_s) { }
500
501 // -------------------------------------------------------
502 // LANTERN WARE
503 // ---------------
504 void lamp_set_vals(void);
505 void lamp_set_vals_with_offset(byte offset);
506 void lamp_turnon(uchar visible, uchar real_start);
507 void lamp_change_setting(byte offset);
508 void lamp_turnoff(uchar visible, uchar real_stop);
509 uchar lantern_change_setting_hkey(ushort keycode, uint32_t context, intptr_t data);
510
511 struct _lampspec {
512 int rad1;
513 int base1;
514 int rad2;
515 int base2;
516 fix slope;
517 fix yint;
518 } lamp_specs[] = {
519 {0, 10, 5, 0, -2 * FIX_UNIT, 12 * FIX_UNIT},
520 {1, 20, 6, 0, -4 * FIX_UNIT, 24 * FIX_UNIT},
521 {1, 18, 7, 0, -3 * FIX_UNIT, 21 * FIX_UNIT},
522 {1, 14, 8, 0, -2 * FIX_UNIT, 16 * FIX_UNIT}
523 };
524
525 // other oldest lowest value
526 // { 0,15,5,0,-3*FIX_UNIT,18*FIX_UNIT},
527 // old lowest value (old 0)
528 // { 0,8,4,0,-2*FIX_UNIT,8*FIX_UNIT},
529 // is level 3 above ever used?
530
531 extern uchar muzzle_fire_light;
532
lamp_set_vals(void)533 void lamp_set_vals(void) { lamp_set_vals_with_offset(0); }
534
535 #define OFF_SHF 3
lamp_set_vals_with_offset(byte offset)536 void lamp_set_vals_with_offset(byte offset) {
537 int n = IDX_OF_TYPE(WARE_HARD, LANTERN_HARD_TRIPLE), s;
538 struct _lampspec *lspec;
539
540 s = (muzzle_fire_light) ? LAMP_SETTING(player_struct.light_value) : LAMP_SETTING(player_struct.hardwarez_status[n]);
541 lspec = &lamp_specs[s];
542
543 _frp.lighting.yint = lspec->yint + (offset << (16 - OFF_SHF));
544 _frp.lighting.slope = lspec->slope;
545 _frp.lighting.rad[0] = (uchar)lspec->rad1;
546 _frp.lighting.base[0] =
547 (uchar)((lspec->base1 + (offset >> OFF_SHF) > 0) ? (lspec->base1 + (offset >> OFF_SHF)) : 0);
548 if (offset != 0) {
549 fix slope_based_mod;
550 slope_based_mod = fix_div((offset << (16 - OFF_SHF)), -lspec->slope);
551 _frp.lighting.rad[1] = (uchar)(lspec->rad2 + (slope_based_mod >> 16));
552 // slope_based_mod=fix_mul((offset<<(16-OFF_SHF)),-lspec->slope);
553 _frp.lighting.yint += -lspec->slope;
554 _frp.lighting.rad[0]++;
555 } else
556 _frp.lighting.rad[1] = (uchar)lspec->rad2;
557 _frp.lighting.base[1] = (uchar)lspec->base2;
558
559 chg_set_flg(_current_3d_flag);
560 // Warning(("New parms %x %x, %x %x, line %x %x from %x %x\n",
561 // _frp.lighting.rad[0], _frp.lighting.base[0],
562 // _frp.lighting.rad[1], _frp.lighting.base[1],
563 // _frp.lighting.yint, _frp.lighting.slope,offset,s));
564 }
565
lamp_turnon(uchar visible,uchar real_s)566 void lamp_turnon(uchar visible, uchar real_s) {
567 lamp_set_vals();
568 if (visible) {
569 _frp_light_bits_set(LIGHT_BITS_CAM);
570 mfd_notify_func(MFD_LANTERN_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
571 }
572 }
573
lamp_change_setting(byte offset)574 void lamp_change_setting(byte offset) {
575 lamp_set_vals_with_offset(offset);
576 _frp_light_bits_set(LIGHT_BITS_CAM);
577 }
578
lamp_turnoff(uchar visible,uchar real_stop)579 void lamp_turnoff(uchar visible, uchar real_stop) {
580 if (visible) {
581 _frp_light_bits_clear(LIGHT_BITS_CAM);
582 chg_set_flg(_current_3d_flag);
583 if (real_stop)
584 mfd_notify_func(MFD_LANTERN_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
585 }
586 }
587
lantern_change_setting_hkey(ushort key,uint32_t context,intptr_t data)588 uchar lantern_change_setting_hkey(ushort key, uint32_t context, intptr_t data) {
589 int n = CPTRIP(LANTERN_HARD_TRIPLE);
590 int v = player_struct.hardwarez[n];
591 uint32_t s = player_struct.hardwarez_status[n];
592 uchar on = s & WARE_ON;
593 void mfd_lantern_setting(int setting);
594
595 s = LAMP_SETTING(s);
596 if (s == 0 && on) {
597 use_ware(WARE_HARD, n);
598 mfd_notify_func(MFD_LANTERN_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
599 return TRUE;
600 }
601
602 s = (s + v - 1) % v; // decrement current setting
603 mfd_lantern_setting(s);
604
605 if (!on)
606 use_ware(WARE_HARD, n);
607 mfd_notify_func(MFD_LANTERN_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
608
609 return TRUE;
610 }
611
612 //--------------------------
613 // SHIELD WARE
614 //--------------------------
615 void shield_set_absorb(void);
616 void shield_toggle(uchar visible, uchar real);
617 uchar shield_change_setting_hkey(ushort keycode, uint32_t context, intptr_t data);
618
619 #define SHIELD_IDX (CPTRIP(SHIELD_HARD_TRIPLE))
620
621 ubyte shield_absorb_rates[] = {20, 40, 75, 75};
622 ubyte shield_thresholds[] = {0, 10, 15, 30};
623
624 extern void set_shield_raisage(uchar going_up);
625
shield_set_absorb(void)626 void shield_set_absorb(void) {
627 ubyte s = player_struct.hardwarez_status[SHIELD_IDX];
628 if (s & WARE_ON) {
629 player_struct.shield_absorb_rate = shield_absorb_rates[LAMP_SETTING(s)];
630 player_struct.shield_threshold = shield_thresholds[LAMP_SETTING(s)];
631 } else {
632 player_struct.shield_absorb_rate = 0;
633 player_struct.shield_threshold = 0;
634 }
635 }
636
shield_toggle(uchar visible,uchar real)637 void shield_toggle(uchar visible, uchar real) {
638 ubyte s = player_struct.hardwarez_status[SHIELD_IDX];
639 if (real) {
640 if (s & WARE_ON) {
641 set_shield_raisage(TRUE);
642 play_digi_fx(SFX_SHIELD_UP, 1);
643 } else {
644 set_shield_raisage(FALSE);
645 play_digi_fx(SFX_SHIELD_DOWN, 1);
646 }
647 mfd_notify_func(MFD_SHIELD_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
648 }
649 shield_set_absorb();
650 }
651
shield_change_setting_hkey(ushort key,uint32_t context,intptr_t data)652 uchar shield_change_setting_hkey(ushort key, uint32_t context, intptr_t data) {
653 int n = CPTRIP(SHIELD_HARD_TRIPLE);
654 int v = player_struct.hardwarez[n];
655 uint32_t s = player_struct.hardwarez_status[n];
656 uchar on = s & WARE_ON;
657 void mfd_shield_setting(int setting);
658
659 // version 4 has only one setting.
660 if (v == 4)
661 v = 1;
662
663 s = LAMP_SETTING(s);
664 if (s == 0 && on) {
665 use_ware(WARE_HARD, n);
666 mfd_notify_func(MFD_SHIELD_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
667 return TRUE;
668 }
669
670 s = (s + v - 1) % v; // decrement current setting
671 mfd_shield_setting(s);
672
673 if (!on)
674 use_ware(WARE_HARD, n);
675 mfd_notify_func(MFD_SHIELD_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
676
677 return TRUE;
678 }
679
680 //----------------
681 // NAV WARE
682 //----------------
683 void nav_turnon(uchar visible, uchar real_start);
684 void nav_turnoff(uchar visible, uchar real_start);
685
nav_turnon(uchar visible,uchar real_s)686 void nav_turnon(uchar visible, uchar real_s) {
687 if (visible)
688 hud_set(HUD_COMPASS);
689 }
690
nav_turnoff(uchar visible,uchar real_s)691 void nav_turnoff(uchar visible, uchar real_s) {
692 if (visible) {
693 hud_unset(HUD_COMPASS);
694 }
695 }
696
697 //----------------------
698 // MOTION WARE
699 //----------------------
700 void motionware_update(uchar visible, uchar real, uchar on);
701 void motionware_turnon(uchar visible, uchar real);
702 void motionware_turnoff(uchar visible, uchar real);
703
704 ubyte motionware_mode = MOTION_INACTIVE;
705
706 #define MOTION_SETTING LAMP_SETTING
707
motionware_update(uchar visible,uchar real,uchar on)708 void motionware_update(uchar visible, uchar real, uchar on) {
709 ubyte s = player_struct.hardwarez_status[CPTRIP(MOTION_HARD_TRIPLE)];
710 if (on)
711 motionware_mode = MOTION_SETTING(s) + 1;
712 else
713 motionware_mode = MOTION_INACTIVE;
714 if (visible) {
715 Pelvis elvis;
716 mfd_notify_func(MFD_MOTION_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, TRUE);
717 EDMS_get_pelvis_parameters(PLAYER_PHYSICS, &elvis);
718 if (motionware_mode == MOTION_SKATES) {
719 if (!global_fullmap->cyber) {
720 elvis.cyber_space = PELVIS_MODE_SKATES;
721 }
722 } else {
723 if (!global_fullmap->cyber) {
724 elvis.cyber_space = PELVIS_MODE_NORMAL;
725 }
726 }
727 EDMS_set_pelvis_parameters(PLAYER_PHYSICS, &elvis);
728 }
729 }
730
motionware_turnon(uchar visible,uchar real)731 void motionware_turnon(uchar visible, uchar real) { motionware_update(visible, real, TRUE); }
732
motionware_turnoff(uchar visible,uchar real)733 void motionware_turnoff(uchar visible, uchar real) { motionware_update(visible, real, FALSE); }
734
735 // ---------------------
736 // JUMP JET WARE
737 // ---------------------
738 void activate_jumpjets(fix *xcntl, fix *ycntl, fix *zcntl);
739
740 static short jumpjet_controls[] = {-25, -50, -75};
741 static fix jumpjet_thrust_scales[] = {FIX_UNIT / 64, FIX_UNIT / 32, FIX_UNIT / 16};
742
743 uchar jumpjets_active = FALSE;
744
745 // modifies z control based on jumpject ware.
activate_jumpjets(fix * xcntl,fix * ycntl,fix * zcntl)746 void activate_jumpjets(fix *xcntl, fix *ycntl, fix *zcntl) {
747 int ecost;
748 short edrain;
749
750 ubyte n = CPTRIP(JET_HARD_TRIPLE);
751 ubyte v = player_struct.hardwarez[n];
752 ubyte s = player_struct.hardwarez_status[n];
753
754 jumpjets_active = FALSE;
755 if ((s & WARE_ON) == 0 || player_struct.energy == 0)
756 return;
757 ecost = energy_cost_vec[n][v - 1] * player_struct.deltat + player_struct.jumpjet_energy_fraction;
758 player_struct.jumpjet_energy_fraction = ecost % APPROX_CIT_CYCLE_HZ;
759 ecost /= APPROX_CIT_CYCLE_HZ;
760 edrain = drain_energy(ecost);
761 *zcntl = fix_make(jumpjet_controls[v - 1], 0);
762 if (edrain < ecost)
763 *zcntl = (*zcntl) * edrain / ecost;
764 *ycntl = fix_mul(*ycntl, jumpjet_thrust_scales[v - 1]);
765 *xcntl = 0;
766 jumpjets_active = TRUE;
767 }
768
769 //-----------------------
770 // FULLSCREEN WARE
771 //-----------------------
772 void fullscreen_turnon(uchar visible, uchar real_start);
773 void fullscreen_turnoff(uchar visible, uchar real_start);
774 extern bool DoubleSize;
775
fullscreen_turnon(uchar visible,uchar real_s)776 void fullscreen_turnon(uchar visible, uchar real_s) {
777 if (visible) {
778 _new_mode = FULLSCREEN_LOOP;
779 chg_set_flg(GL_CHG_LOOP);
780 }
781 }
782
fullscreen_turnoff(uchar visible,uchar real_s)783 void fullscreen_turnoff(uchar visible, uchar real_s) {
784 if (visible) {
785 _new_mode = GAME_LOOP;
786 chg_set_flg(GL_CHG_LOOP);
787 }
788 }
789
790 //-----------------------
791 // CYBERSPACE ONESHOTS
792 //-----------------------
793 void do_turbo_stuff(uchar from_drug);
794 void turbo_turnon(uchar visible, uchar real_start);
795 void turbo_turnoff(uchar visible, uchar real_start);
796 void fakeid_turnon(uchar visible, uchar real_start);
797 void decoy_turnon(uchar visible, uchar real_start);
798 void decoy_turnoff(uchar visible, uchar real_stop);
799 void recall_turnon(uchar visible, uchar real_start);
800
do_turbo_stuff(uchar from_drug)801 void do_turbo_stuff(uchar from_drug) {
802 if (cspace_effect_times[CS_TURBO_EFF] == 0) {
803 if (from_drug) {
804 hud_set(HUD_TURBO);
805 chg_set_flg(INVENTORY_UPDATE);
806 }
807 }
808 }
809
turbo_turnon(uchar visible,uchar real_start)810 void turbo_turnon(uchar visible, uchar real_start) {
811 ulong hammer_time = cspace_effect_durations[CS_TURBO_EFF];
812 do_turbo_stuff(visible);
813 if (real_start) {
814 play_digi_fx(SFX_TURBO, 1);
815 player_struct.softs.misc[SOFTWARE_TURBO]--;
816 cspace_effect_times[CS_TURBO_EFF] = player_struct.game_time + hammer_time;
817 }
818 }
819
turbo_turnoff(uchar visible,uchar real_s)820 void turbo_turnoff(uchar visible, uchar real_s) {
821 if (visible) {
822 hud_unset(HUD_TURBO);
823 }
824 cspace_effect_times[CS_TURBO_EFF] = 0;
825 }
826
fakeid_turnon(uchar visible,uchar real_start)827 void fakeid_turnon(uchar visible, uchar real_start) {
828 if (!(player_struct.hud_modes & HUD_FAKEID) && visible) {
829 if (real_start) {
830 player_struct.softs.misc[SOFTWARE_FAKEID]--;
831 play_digi_fx(SFX_FAKEID, 1);
832 }
833 hud_set(HUD_FAKEID);
834 chg_set_flg(INVENTORY_UPDATE);
835 }
836 }
837
decoy_turnon(uchar visible,uchar real_start)838 void decoy_turnon(uchar visible, uchar real_start) {
839 if (real_start) {
840 if (cspace_decoy_obj != OBJ_NULL)
841 decoy_turnoff(TRUE, TRUE);
842 cspace_decoy_obj = obj_create_base(TARGET_TRIPLE);
843 if (cspace_decoy_obj != OBJ_NULL) {
844 obj_move_to(cspace_decoy_obj, &objs[PLAYER_OBJ].loc, FALSE);
845 cspace_effect_times[CS_DECOY_EFF] = player_struct.game_time + cspace_effect_durations[CS_DECOY_EFF];
846 player_struct.softs.misc[SOFTWARE_DECOY]--;
847 play_digi_fx(SFX_DECOY, 1);
848 hud_set(HUD_DECOY);
849 chg_set_flg(INVENTORY_UPDATE);
850 }
851 }
852 }
853
decoy_turnoff(uchar visible,uchar real_stop)854 void decoy_turnoff(uchar visible, uchar real_stop) {
855 if (visible) {
856 hud_unset(HUD_DECOY);
857 }
858 cspace_effect_times[CS_DECOY_EFF] = 0;
859 if (real_stop) {
860 if (cspace_decoy_obj != OBJ_NULL)
861 ADD_DESTROYED_OBJECT(cspace_decoy_obj);
862 }
863 cspace_decoy_obj = OBJ_NULL;
864 }
865
recall_turnon(uchar visible,uchar real_start)866 void recall_turnon(uchar visible, uchar real_start) {
867 if (visible && real_start) {
868 player_struct.softs.misc[SOFTWARE_RECALL]--;
869 obj_move_to(PLAYER_OBJ, &recall_objloc, TRUE);
870 chg_set_flg(INVENTORY_UPDATE);
871 play_digi_fx(SFX_RECALL, 1);
872 }
873 }
874
875 // =================
876 // THE STATIC ARRAYS
877
878 extern void view360_turnon(uchar visible, uchar real_start), view360_turnoff(uchar visible, uchar real_start);
879 extern bool view360_check();
880 extern void email_turnon(uchar visible, uchar real_start);
881 extern void email_turnoff(uchar visible, uchar real_start);
882 extern void plotware_turnon(uchar visible, uchar real_start);
883
884 WARE HardWare[NUM_HARDWAREZ] = {
885 //"infrared"
886 {WARE_FLAGS_NONE, SI_SIXTH, infrared_turnon, NULL, infrared_turnoff, NULL},
887 //"target info"
888 {WARE_FLAGS_NONE, SI_NONE, targeting_turnon, NULL, targeting_turnoff, NULL},
889 //"360 view"
890 {WARE_FLAGS_NONE, SI_THIRD, view360_turnon, NULL, view360_turnoff, view360_check},
891 //"aim"
892 {WARE_FLAGS_NONE, SI_NONE, NULL, NULL, NULL, NULL},
893 //"HUD"
894 {WARE_FLAGS_NONE, SI_NONE, NULL, NULL, NULL, NULL},
895 //"bioscan"
896 {WARE_FLAGS_NONE, SI_FIRST, bioware_turnon, bioware_effect, bioware_turnoff, NULL},
897 //"nav unit"
898 {WARE_FLAGS_NONE, SI_SEVENTH, nav_turnon, NULL, nav_turnoff, NULL},
899 //"shield"
900 {WARE_FLAGS_NONE, SI_FIFTH, shield_toggle, NULL, shield_toggle, NULL},
901 //"data reader"
902 {WARE_FLAGS_NONE, SI_EIGHTH, email_turnon, NULL, email_turnoff, NULL},
903 //"lantern"
904 {WARE_FLAGS_NONE, SI_FOURTH, lamp_turnon, NULL, lamp_turnoff, NULL},
905 //"fullscreen"
906 {WARE_FLAGS_NONE, SI_SECOND, fullscreen_turnon, NULL, fullscreen_turnoff, NULL},
907 //"enviro-suit"
908 {WARE_FLAGS_NONE, SI_NONE, NULL, NULL, NULL, NULL},
909 //"motion"
910 {WARE_FLAGS_NONE, SI_NINTH, motionware_turnon, NULL, motionware_turnoff, NULL},
911 //"skates"
912 {WARE_FLAGS_NONE, SI_TENTH, NULL, NULL, NULL, NULL},
913 //"status"
914 {WARE_FLAGS_NONE, SI_NONE, plotware_turnon, NULL, NULL, NULL},
915 };
916
917 // Except for jumpjets, these costs are in points per
918 // minute of use.
919
920 short energy_cost_vec[NUM_HARDWAREZ][MAX_VERSIONS] = {
921 //"infrared"
922 {50, 50, 50},
923 //"target info"
924 {0},
925 //"360 view"
926 {9, 9, 9},
927 //"aim"
928 {0},
929 //"HUD"
930 {0},
931 //"bioscan"
932 {1},
933 //"nav unit"
934 {0},
935 //"shield"
936 {24, 60, 105, 30},
937 //"data reader"
938 {0},
939 //"lantern"
940 // { 15, 25, 30, },
941 {10, 25, 30},
942 //"robo comm"
943 {0},
944 //"enviro-suit"
945 {0},
946 //"motion"
947 {0, 40},
948 //"jumpjets"
949 // these are in points per second of thrust
950 {25, 30, 35},
951 //"status"
952 {0},
953 };
954
check_game(void)955 bool check_game(void) { return (!global_fullmap->cyber); }
956 extern void mfd_games_turnon(uchar, uchar real_s), mfd_games_turnoff(uchar, uchar real_s);
957
958 WARE Combat_SoftWare[NUM_COMBAT_SOFTS];
959 WARE Defense_SoftWare[NUM_DEFENSE_SOFTS];
960 WARE Misc_SoftWare[NUM_MISC_SOFTS] = {
961 {WARE_FLAGS_NONE, SI_NONE, turbo_turnon, NULL, NULL, NULL},
962 {WARE_FLAGS_NONE, SI_NONE, fakeid_turnon, NULL, NULL, NULL},
963 {WARE_FLAGS_NONE, SI_NONE, decoy_turnon, NULL, decoy_turnoff, NULL},
964 {WARE_FLAGS_NONE, SI_NONE, recall_turnon, NULL, NULL, NULL},
965 {WARE_FLAGS_NONE, SI_NONE, mfd_games_turnon, NULL, mfd_games_turnoff, check_game},
966 };
967