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/sideicon.c $
21 * $Revision: 1.53 $
22 * $Author: mahk $
23 * $Date: 1994/11/23 04:31:51 $
24 *
25 */
26
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "input.h"
31 #include "sideicon.h"
32 #include "sideart.h"
33 #include "popups.h"
34 #include "gamestrn.h"
35 #include "cybstrng.h"
36 #include "tools.h"
37 #include "mainloop.h"
38 #include "game_screen.h"
39 #include "fullscrn.h"
40 #include "wares.h"
41 #include "objsim.h"
42 #include "objclass.h"
43 #include "otrip.h"
44 #include "player.h"
45 #include "faketime.h"
46 #include "mfdext.h"
47 #include "gameloop.h"
48 #include "textmaps.h"
49 #include "criterr.h"
50 #include "objapp.h"
51 #include "objwarez.h"
52 #include "hkeyfunc.h"
53 #include "musicai.h"
54 #include "sfxlist.h"
55 #include "gr2ss.h"
56 #include "canvchek.h"
57
58 // ---------
59 // Constants
60 // ---------
61
62 #define NUM_SIDE_ICONS 10
63
64 #define SIDE_ICONS_TOP_Y 24
65 #define SIDE_ICONS_LEFT_X 4
66 #define SIDE_ICONS_RIGHT_X 300
67 #define SIDE_ICONS_HEIGHT 15
68 #define SIDE_ICONS_WIDTH 15
69 #define SIDE_ICONS_VSPACE 8
70
71 #define ICON_ART_ITEMS 2
72 #define ICON_ART_OFF 0
73 #define ICON_ART_ON 1
74 #define ICON_ART_BACKGROUND 255
75
76 #define FLASH_RATE 256
77 #define MAX_FLASH_COUNT 12
78
79 // ----------------
80 // Local Prototypes
81 // ----------------
82
83 void side_icon_language_change(void);
84 uchar side_icon_mouse_callback(uiEvent *e, LGRegion *r, intptr_t udata);
85 void zoom_side_icon_to_mfd(int icon, int waretype, int wnum);
86 void zoom_to_side_icon(LGPoint from, int icon);
87 uchar side_icon_hotkey_func(ushort keycode, uint32_t context, intptr_t i);
88 void side_icon_draw_bm(LGRect *r, ubyte icon, ubyte art);
89
90 // ----------
91 // Structures
92 // ----------
93
94 typedef struct _side_icon {
95 LGRect r;
96 uchar flashstate;
97 ubyte flashcount;
98 ubyte state;
99 } SIDE_ICON;
100
101 typedef struct _icon_data {
102 byte waretype;
103 long waretrip;
104 int flashfx;
105 } ICON_DATA;
106
107 // -------
108 // Globals
109 // -------
110
111 SIDE_ICON side_icons[NUM_SIDE_ICONS];
112 #ifdef PRELOAD_BITMAPS
113 grs_bitmap side_icon_bms[NUM_SIDE_ICONS][ICON_ART_ITEMS];
114 grs_bitmap side_icon_background;
115 #else
116 #define side_icon_bmid(icon, art) (MKREF(RES_SideIconArt, (ICON_ART_ITEMS * icon) + art + 1))
117 #define side_icon_backid (MKREF(RES_SideIconArt, 0))
118 #endif
119
120 #ifdef PROGRAM_SIDEICON
121 static char shiftnums[] = ")!@#$%^&*(";
122 static uchar programmed_sideicon = 0;
123 #endif
124
125 // this is in wares.c
126 extern long ware_base_triples[NUM_WARE_TYPES];
127
128 #define IDX_OF_TYPE(type, trip) (OPTRIP(trip) - OPTRIP(ware_base_triples[type]))
129
130 static ICON_DATA icon_data[NUM_SIDE_ICONS] = {
131
132 {WARE_HARD, BIOSCAN_HARD_TRIPLE}, {WARE_HARD, FULLSCR_HARD_TRIPLE}, {WARE_HARD, SENS_HARD_TRIPLE},
133 {WARE_HARD, LANTERN_HARD_TRIPLE}, {WARE_HARD, SHIELD_HARD_TRIPLE},
134
135 {WARE_HARD, INFRA_GOG_TRIPLE}, {WARE_HARD, NAV_HARD_TRIPLE}, {WARE_HARD, VIDTEX_HARD_TRIPLE, SFX_EMAIL},
136 {WARE_HARD, MOTION_HARD_TRIPLE}, {WARE_HARD, JET_HARD_TRIPLE},
137 };
138
139 grs_bitmap icon_cursor_bm[2];
140 LGCursor icon_cursor[2];
141 static char *cursor_strings[NUM_SIDE_ICONS];
142 static char cursor_strbuf[128];
143
144 // ============
145 // INITIALIZERS
146 // ============
147
148 // ---------------------------------------------------------------------------
149 // init_all_side_icons()
150 //
151 // Initialize all side icons to "unset" settings (should be called before
152 // wares_init()!). Also sets up their on-screen locations.
153 // And, as of 7/22, loads in all the bitmaps from memory.
154
side_icon_language_change(void)155 void side_icon_language_change(void) {
156 load_string_array(REF_STR_IconCursor, cursor_strings, cursor_strbuf, sizeof(cursor_strbuf), NUM_SIDE_ICONS);
157 }
158
init_all_side_icons()159 void init_all_side_icons() {
160 int i;
161
162 // Now, figure out on-screen locations
163
164 for (i = 0; i < (NUM_SIDE_ICONS / 2); i++) // left side first
165 {
166 side_icons[i].r.ul.x = SIDE_ICONS_LEFT_X;
167 side_icons[i].r.ul.y = SIDE_ICONS_TOP_Y + (i * (SIDE_ICONS_HEIGHT + SIDE_ICONS_VSPACE));
168
169 side_icons[i].r.lr.x = side_icons[i].r.ul.x + SIDE_ICONS_WIDTH;
170 side_icons[i].r.lr.y = side_icons[i].r.ul.y + SIDE_ICONS_HEIGHT;
171 }
172
173 for (i = (NUM_SIDE_ICONS / 2); i < NUM_SIDE_ICONS; i++) // now right side
174 {
175 side_icons[i].r.ul.x = SIDE_ICONS_RIGHT_X;
176 side_icons[i].r.ul.y = side_icons[i - (NUM_SIDE_ICONS / 2)].r.ul.y;
177
178 side_icons[i].r.lr.x = side_icons[i].r.ul.x + SIDE_ICONS_WIDTH;
179 side_icons[i].r.lr.y = side_icons[i].r.ul.y + SIDE_ICONS_HEIGHT;
180 }
181 }
182
init_side_icon_popups(void)183 void init_side_icon_popups(void) {
184 side_icon_language_change();
185 for (int i = 0; i < 2; i++) {
186 LGPoint offset = {0, -1};
187 LGCursor *c = &icon_cursor[i];
188 grs_bitmap *bm = &icon_cursor_bm[i];
189 make_popup_cursor(c, bm, cursor_strings[i * NUM_SIDE_ICONS / 2], i + POPUP_ICON_LEFT, TRUE, offset);
190 }
191 }
192
193 #ifdef DUMMY // not yet, bucko
194
init_side_icon_hotkeys(void)195 void init_side_icon_hotkeys(void) {
196 uchar side_icon_hotkey_func(ushort key, uint32_t context, intptr_t i);
197 uchar side_icon_progset_hotkey_func(ushort key, uint32_t context, intptr_t i);
198 uchar lantern_change_setting_hkey(ushort key, uint32_t context, intptr_t i);
199 uchar shield_change_setting_hkey(ushort key, uint32_t context, intptr_t i);
200 uchar side_icon_prog_hotkey_func(ushort key, uint32_t context, intptr_t notused);
201 int i;
202
203 hotkey_add(KB_FLAG_ALT | KB_FLAG_DOWN | '4', DEMO_CONTEXT, lantern_change_setting_hkey, 0);
204 hotkey_add(KB_FLAG_ALT | KB_FLAG_DOWN | '5', DEMO_CONTEXT, shield_change_setting_hkey, 0);
205
206 hotkey_add(KB_FLAG_DOWN | '0', DEMO_CONTEXT, side_icon_hotkey_func, NUM_SIDE_ICONS - 1);
207 #ifdef PROGRAM_SIDEICON
208 hotkey_add('`', DEMO_CONTEXT, ide_icon_prog_hotkey_func, 0);
209 hotkey_add(KB_FLAG_DOWN | shiftnums[0], DEMO_CONTEXT, side_icon_progset_hotkey_func,
210 NUM_SIDE_ICONS - 1);
211 #endif
212 for (i = 0; i < NUM_SIDE_ICONS - 1; i++) {
213 hotkey_add(KB_FLAG_DOWN | ('1' + i), DEMO_CONTEXT, side_icon_hotkey_func, i);
214 #ifdef PROGRAM_SIDEICON
215 hotkey_add(KB_FLAG_DOWN | shiftnums[1 + i], DEMO_CONTEXT, side_icon_progset_hotkey_func,
216 i);
217 #endif
218 }
219 }
220
221 #endif // DUMMY
222
223 // ---------------------------------------------------------------------------
224 // init_side_icon()
225 //
226
227 // ---------------------------------------------------------------------------
228 // screen_init_side_icons();
229 //
230 // Declare the appropriate regions for the side icons
231 // (called from screen_start() in screen.c)
232
screen_init_side_icons(LGRegion * root)233 void screen_init_side_icons(LGRegion *root) {
234 int id;
235 LGRegion *left_region, *right_region;
236 LGRect r;
237 left_region = (LGRegion *)malloc(sizeof(LGRegion));
238 right_region = (LGRegion *)malloc(sizeof(LGRegion));
239
240 // Wow, having a LGRegion for each of the side icons is totally uncool
241 // Let's just have two regions, and figure out from there.
242
243 r.ul = side_icons[0].r.ul;
244 r.lr = side_icons[(NUM_SIDE_ICONS - 1) / 2].r.lr;
245 macro_region_create_with_autodestroy(root, left_region, &r);
246 uiInstallRegionHandler(left_region, UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE, &side_icon_mouse_callback, 0,
247 &id);
248 uiSetRegionDefaultCursor(left_region, NULL);
249
250 r.ul = side_icons[(NUM_SIDE_ICONS + 1) / 2].r.ul;
251 r.lr = side_icons[(NUM_SIDE_ICONS - 1)].r.lr;
252 macro_region_create_with_autodestroy(root, right_region, &r);
253 uiInstallRegionHandler(right_region, UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE, &side_icon_mouse_callback,
254 ((NUM_SIDE_ICONS + 1) / 2), &id);
255 uiSetRegionDefaultCursor(right_region, NULL);
256
257 return;
258 }
259
260 // =========
261 // SELECTION
262 // =========
263
264 // ----------------------------------------------------------------
265 // select_side_icon() selects a given side icon.
266
zoom_side_icon_to_mfd(int icon,int waretype,int wnum)267 void zoom_side_icon_to_mfd(int icon, int waretype, int wnum) {
268 extern ubyte waretype2invtype[];
269 extern void mfd_zoom_rect(LGRect * start, int mfdnum);
270
271 int mfd;
272
273 mfd = mfd_grab_func(MFD_EMPTY_FUNC, MFD_ITEM_SLOT);
274 mfd_zoom_rect(&side_icons[icon].r, mfd);
275 set_inventory_mfd(waretype2invtype[waretype], wnum, TRUE);
276 mfd_change_slot(mfd, MFD_ITEM_SLOT);
277 }
278
279 // ---------------------------------------------------------------------------
280 // side_icon_mouse_callback()
281 //
282 // Callback function for mouse clicks inside the side icons.
283
284 extern LGCursor globcursor;
285
286 int last_side_icon = -1;
side_icon_mouse_callback(uiEvent * e,LGRegion * r,intptr_t udata)287 uchar side_icon_mouse_callback(uiEvent *e, LGRegion *r, intptr_t udata) {
288 extern uchar fullscrn_icons;
289 uchar retval = FALSE;
290 int i, type, num;
291
292 if (!global_fullmap->cyber && !(full_game_3d && !fullscrn_icons)) {
293 int ver;
294
295 i = (int)udata + (e->pos.y - SIDE_ICONS_TOP_Y) / (SIDE_ICONS_HEIGHT + SIDE_ICONS_VSPACE);
296 type = icon_data[i].waretype;
297 num = IDX_OF_TYPE(type, icon_data[i].waretrip);
298 ver = get_player_ware_version(type, num);
299
300 if (!RECT_TEST_PT(&side_icons[i].r, e->pos) || ver == 0) {
301 uiSetRegionDefaultCursor(r, &globcursor);
302 last_side_icon = -1;
303 return FALSE;
304 }
305 if (popup_cursors) {
306 if (last_side_icon != i) {
307 uchar side = i * 2 / NUM_SIDE_ICONS;
308 LGCursor *c = &icon_cursor[side];
309 grs_bitmap *bm = &icon_cursor_bm[side];
310 LGPoint offset = {0, -1};
311
312 free(bm->bits);
313 make_popup_cursor(c, bm, cursor_strings[i], side + POPUP_ICON_LEFT, TRUE, offset);
314 uiSetRegionDefaultCursor(r, c);
315 last_side_icon = i;
316 }
317 }
318 /*
319 if (m->action & MOUSE_RDOWN)
320 {
321 zoom_side_icon_to_mfd(i,type,num);
322 retval = TRUE;
323 }
324 */
325
326 if (!(e->mouse_data.action & MOUSE_LDOWN))
327 return retval; // ignore click releases
328 // mprintf(" Side Icon %d: CYBER(%d,%d) [%x] REAL(%d,%d) [%x]\n",
329 // i, side_icons[i].cyber_type, side_icons[i].cyber_num,
330 // side_icons[i].cyber_set, side_icons[i].real_type,
331 // side_icons[i].real_num, side_icons[i].real_set);
332
333 if (type >= 0)
334 use_ware(type, num);
335 retval = TRUE;
336 }
337 if (global_fullmap->cyber || (full_game_3d && !fullscrn_icons) || !popup_cursors) {
338 last_side_icon = -1;
339 uiSetRegionDefaultCursor(r, NULL);
340 }
341
342 return retval;
343 }
344
side_icon_hotkey_func(ushort keycode,uint32_t context,intptr_t i)345 uchar side_icon_hotkey_func(ushort keycode, uint32_t context, intptr_t i) {
346 int type = icon_data[i].waretype;
347 int num = IDX_OF_TYPE(type, icon_data[i].waretrip);
348 if ((!global_fullmap->cyber) || (i == 1)) {
349 if (type >= 0)
350 use_ware(type, num);
351 }
352 return TRUE;
353 }
354
355 #ifdef PROGRAM_SIDEICON
side_icon_progset_hotkey_func(ushort keycode,uint32_t context,intptr_t i)356 uchar side_icon_progset_hotkey_func(ushort keycode, uint32_t context, intptr_t i) {
357 char mess[80];
358 int l;
359 programmed_sideicon = i;
360 get_string(REF_STR_PresetSideicon, mess, 80);
361 l = strlen(mess);
362 get_object_short_name(icon_data[i].waretrip, mess + l, 80 - l);
363 message_info(mess);
364 return TRUE;
365 }
366
side_icon_prog_hotkey_func(ushort keycode,uint32_t context,intptr_t notused)367 uchar side_icon_prog_hotkey_func(ushort keycode, uint32_t context, intptr_t notused) {
368 return (side_icon_hotkey_func(keycode, context, programmed_sideicon));
369 }
370 #endif
371
372 // ========
373 // GRAPHICS
374 // ========
375
376 // ---------------------------------------------------------------------------
377 // side_icon_expose_all()
378 //
379 // Sort of an initial-draw-everything type of routine
380
side_icon_expose_all()381 void side_icon_expose_all() {
382 ubyte i;
383
384 for (i = 0; i < NUM_SIDE_ICONS; i++)
385 side_icon_expose(i);
386
387 return;
388 }
389
390 // ----------------------------------------------------
391 // zoom_to_side_icon(Point from, int icon)
392 // zooms a LGRect to a side icon and then exposes it.
393
zoom_to_side_icon(LGPoint from,int icon)394 void zoom_to_side_icon(LGPoint from, int icon) {
395 extern void zoom_rect(LGRect * s, LGRect * f);
396 LGRect start = {{-3, -3}, {3, 3}};
397 LGRect dest;
398 RECT_MOVE(&start, from);
399 dest = side_icons[icon].r;
400 zoom_rect(&start, &dest);
401 side_icon_expose(icon);
402 }
403
404 // ---------------------------------------------------------------------------
405 // side_icon_draw_bm()
406 //
407 // Draws a side icon of the specified ware, version, and status.
408
side_icon_draw_bm(LGRect * r,ubyte icon,ubyte art)409 void side_icon_draw_bm(LGRect *r, ubyte icon, ubyte art) {
410 #ifdef SVGA_SUPPORT
411 uchar old_over = gr2ss_override;
412 gr2ss_override = OVERRIDE_ALL;
413 #endif
414 if (is_onscreen())
415 uiHideMouse(r);
416 if (art == ICON_ART_BACKGROUND)
417 draw_raw_resource_bm(side_icon_backid, r->ul.x, r->ul.y);
418 // draw_hires_resource_bm(side_icon_backid, SCONV_X(r->ul.x), SCONV_Y(r->ul.y));
419 else
420 draw_raw_resource_bm(side_icon_bmid(icon, art), r->ul.x, r->ul.y);
421 // draw_hires_resource_bm(side_icon_bmid(icon,art), SCONV_X(r->ul.x), SCONV_Y(r->ul.y));
422 if (is_onscreen())
423 uiShowMouse(r);
424 #ifdef SVGA_SUPPORT
425 gr2ss_override = old_over;
426 #endif
427 return;
428 }
429
430 // ---------------------------------------------------------------------------
431 // side_icon_expose()
432 //
433 // Draw a side icon appropriately, depending on the ware it points at,
434 // and its state.
435
side_icon_expose(ubyte icon_num)436 void side_icon_expose(ubyte icon_num) {
437 ubyte *player_wares, *player_status;
438 WARE *wares;
439 int type, num, n;
440 LGRect *r;
441 extern uchar fullscrn_icons;
442
443 if (full_game_3d && (global_fullmap->cyber || !(fullscrn_icons)))
444 return;
445 r = &(side_icons[icon_num].r);
446
447 type = icon_data[icon_num].waretype;
448 num = IDX_OF_TYPE(type, icon_data[icon_num].waretrip);
449
450 if (type < 0)
451 return;
452 get_ware_pointers(type, &player_wares, &player_status, &wares, &n);
453
454 // Possible expose cases:
455 //
456 // 1) We don't have the appropriate ware for that side icon.
457 if (player_wares[num] == 0) {
458
459 // Expose screen background
460 // Spew(DSRC_TESTING_Test9,("icon number %d is empty\n",icon_num));
461 if (!full_game_3d)
462 side_icon_draw_bm(r, icon_num, ICON_ART_BACKGROUND);
463 }
464
465 // 3) We have the ware, and it's trying to get our attention.
466 //
467 else if (player_status[num] & WARE_FLASH) {
468 uchar fs = ((*tmd_ticks / FLASH_RATE) % 2);
469 if (fs == side_icons[icon_num].flashstate && !full_game_3d)
470 return;
471
472 if (fs) {
473 side_icon_draw_bm(r, icon_num, ICON_ART_ON);
474 if (fs != side_icons[icon_num].flashstate)
475 if (icon_data[icon_num].flashfx != 0)
476 if (QUESTBIT_GET(0x12c))
477 play_digi_fx(icon_data[icon_num].flashfx, 1);
478 } else
479 side_icon_draw_bm(r, icon_num, ICON_ART_OFF);
480 if (fs != side_icons[icon_num].flashstate) {
481 side_icons[icon_num].flashcount++;
482 if (side_icons[icon_num].flashcount >= MAX_FLASH_COUNT) {
483 side_icons[icon_num].flashcount = 0;
484 player_status[num] &= ~WARE_FLASH;
485 }
486 }
487 side_icons[icon_num].flashstate = fs;
488 }
489
490 // 2) We have the ware, but we're turning it off.
491 //
492 else if (!(player_status[num] & WARE_ON)) {
493
494 // Expose darkened bitmap of current version
495 // Spew(DSRC_TESTING_Test9,("icon number %d is off\n",icon_num));
496 side_icon_draw_bm(r, icon_num, ICON_ART_OFF);
497 } else {
498
499 // Expose normal (active) bitmap of current ware version
500 side_icon_draw_bm(r, icon_num, ICON_ART_ON);
501 }
502
503 return;
504 }
505
506 // ---------------------------------------------------------------------------
507 // side_icon_load_bitmaps()
508 //
509 // Load the bitmaps for all side icons and states from the resource system.
510
side_icon_load_bitmaps()511 errtype side_icon_load_bitmaps() {
512 #ifdef PRELOAD_BITMAPS
513 RefTable *side_icon_rft;
514 int i, j, index /*, file_handle */;
515
516 // file_handle = ResOpenFile("sideart.res");
517 // if (file_handle < 0) critical_error(CRITERR_RES|6);
518
519 side_icon_rft = ResLock(RES_SideIconArt);
520 load_bitmap_from_res(&side_icon_background, RES_SideIconArt, 0, side_icon_rft, FALSE, NULL, NULL);
521
522 for (i = 0; i < NUM_SIDE_ICONS; i++) {
523
524 for (j = 0; j < ICON_ART_ITEMS; j++) {
525
526 index = (ICON_ART_ITEMS * i) + j + 1;
527 load_bitmap_from_res(&(side_icon_bms[i][j]), RES_SideIconArt, index, side_icon_rft, FALSE, NULL, NULL);
528 }
529 }
530 ResUnlock(RES_SideIconArt);
531 // ResCloseFile(file_handle);
532 #endif
533
534 return (OK);
535 }
536
side_icon_free_bitmaps()537 errtype side_icon_free_bitmaps() {
538 #ifdef PRELOAD_BITMAPS
539 int i, j, index;
540 Free(side_icon_background.bits);
541 for (i = 0; i < NUM_SIDE_ICONS; i++) {
542
543 for (j = 0; j < ICON_ART_ITEMS; j++) {
544
545 index = (ICON_ART_ITEMS * i) + j;
546 Free(side_icon_bms[i][j].bits);
547 }
548 }
549 #endif
550 return (OK);
551 }
552