1 /*
2 BStone: A Source port of
3 Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
4
5 Copyright (c) 1992-2013 Apogee Entertainment, LLC
6 Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the
20 Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24
25 #include <map>
26 #include "3d_def.h"
27 #include "jm_lzh.h"
28
29
30 void CA_CacheScreen(
31 int16_t chunk);
32
33 void VH_UpdateScreen();
34 void DrawHighScores();
35 void ClearMemory();
36
37 void DrawTopInfo(
38 sp_type type);
39
40 void PreloadUpdate(
41 uint16_t current,
42 uint16_t total);
43
44 void INL_GetJoyDelta(
45 uint16_t joy,
46 int* dx,
47 int* dy);
48
49 bool LoadTheGame(
50 const std::string& file_name);
51
52 bool IN_CheckAck();
53
54
55 //
56 // End game message
57 //
58
59 char EndGameStr[] = { " End current game?\n"
60 " Are you sure (Y or N)?" };
61
62
63 #define ENDGAMESTR (EndGameStr)
64
65 char QuitToDosStr[] = { " Quit to DOS?\n"
66 " Are you sure (Y or N)?" };
67
68 #define FREEFONT(fontnum) { if (fontnum != STARTFONT + 2 && grsegs[fontnum]) { UNCACHEGRCHUNK(fontnum); } }
69
70
71 static const char* const CURGAME =
72 " Continuing past this\n"
73 " point will end the game\n"
74 " you're currently playing.\n"
75 "\n"
76 " Start a NEW game? (Y/N)";
77
78 static const char* const GAMESVD =
79 "There's already a game\n"
80 "saved at this position.\n"
81 "\n"
82 " Overwrite? (Y/N)";
83
84
85 bool EscPressed = false;
86
87 int16_t lastmenumusic;
88
89 int16_t MENUSONG = 0;
90 int16_t ROSTER_MUS = 0;
91 int16_t TEXTSONG = 0;
92
93
94 // ===========================================================================
95 //
96 // PRIVATE PROTOTYPES
97 //
98 // ===========================================================================
99
100 void CP_ReadThis(
101 int16_t temp1);
102
103 void CP_OrderingInfo(
104 int16_t temp1);
105
106 void DrawEpisodePic(
107 int16_t w);
108
109 void DrawAllSoundLights(
110 int16_t which);
111
112 void ReadGameNames();
113 void FreeMusic();
114
115 void CP_GameOptions(
116 int16_t temp1);
117
118 void DrawGopMenu();
119 void CalibrateJoystick();
120 void ExitGame();
121
122 void CP_Switches(
123 int16_t temp1);
124
125 void DrawSwitchMenu();
126
127 void DrawAllSwitchLights(
128 int16_t which);
129
130 void DrawSwitchDescription(
131 int16_t which);
132
133 // BBi
134 void cp_sound_volume(
135 int16_t);
136
137 void cp_video(
138 int16_t);
139 // BBi
140
141
142 extern bool refresh_screen;
143
144
145 // ===========================================================================
146 //
147 // LOCAL DATA...
148 //
149 // ===========================================================================
150
151 CP_iteminfo MainItems = { MENU_X, MENU_Y, 12, MM_READ_THIS, 0, 9, { 77, 1, 154, 9, 1 } };
152 CP_iteminfo GopItems = { MENU_X, MENU_Y + 30, 5, 0, 0, 9, { 77, 1, 154, 9, 1 } };
153 CP_iteminfo SndItems = { SM_X, SM_Y, 6, 0, 0, 7, { 87, -1, 144, 7, 1 } };
154 CP_iteminfo LSItems = { LSM_X, LSM_Y, 10, 0, 0, 8, { 86, -1, 144, 8, 1 } };
155 CP_iteminfo CtlItems = { CTL_X, CTL_Y, 7, -1, 0, 9, { 87, 1, 174, 9, 1 } };
156 CP_iteminfo CusItems = { CST_X, CST_Y + 7, 6, -1, 0, 15, { 54, -1, 203, 7, 1 } };
157 CP_iteminfo NewEitems = { NE_X, NE_Y, 6, 0, 0, 16, { 43, -2, 119, 16, 1 } };
158 CP_iteminfo NewItems = { NM_X, NM_Y, 4, 1, 0, 16, { 60, -2, 105, 16, 1 } };
159 CP_iteminfo SwitchItems = { MENU_X, 0, 0, 0, 0, 9, { 87, -1, 132, 7, 1 } };
160
161 // BBi
162 CP_iteminfo video_items = { MENU_X, MENU_Y + 30, 1, 0, 0, 9, { 77, -1, 154, 7, 1 } };
163 // BBi
164
165
166 CP_itemtype MainMenu[] = {
167 { AT_ENABLED, "NEW MISSION", CP_NewGame, static_cast<uint8_t>(COAL_FONT) },
168 { AT_READIT, "ORDERING INFO", CP_OrderingInfo },
169 { AT_READIT, "INSTRUCTIONS", CP_ReadThis },
170 { AT_ENABLED, "STORY", CP_BlakeStoneSaga },
171 { AT_DISABLED, "", 0 },
172 { AT_ENABLED, "GAME OPTIONS", CP_GameOptions },
173 { AT_ENABLED, "HIGH SCORES", CP_ViewScores },
174 { AT_ENABLED, "LOAD MISSION", reinterpret_cast<void (*)(int16_t)>(CP_LoadGame) },
175 { AT_DISABLED, "SAVE MISSION", reinterpret_cast<void (*)(int16_t)>(CP_SaveGame) },
176 { AT_DISABLED, "", 0 },
177 { AT_ENABLED, "BACK TO DEMO", CP_ExitOptions },
178 { AT_ENABLED, "LOGOFF", 0 }
179 };
180
181 CP_itemtype GopMenu[] = {
182 // BBi
183 { AT_ENABLED, "VIDEO", cp_video },
184 // BBi
185
186 { AT_ENABLED, "SOUND", CP_Sound },
187
188 // BBi
189 { AT_ENABLED, "SOUND VOLUME", cp_sound_volume },
190 // BBi
191
192 { AT_ENABLED, "CONTROLS", CP_Control },
193 { AT_ENABLED, "SWITCHES", CP_Switches }
194 };
195
196 CP_itemtype SndMenu[] = {
197 { AT_ENABLED, "NONE", 0 },
198 { AT_ENABLED, "ADLIB/SOUND BLASTER", 0 },
199 { AT_DISABLED, "", 0 },
200 { AT_DISABLED, "", 0 },
201 { AT_ENABLED, "NONE", 0 },
202 { AT_ENABLED, "ADLIB/SOUND BLASTER", 0 }
203 };
204
205 CP_itemtype CtlMenu[] = {
206 { AT_DISABLED, "MOUSE ENABLED", 0 },
207 { AT_DISABLED, "JOYSTICK ENABLED", 0 },
208 { AT_DISABLED, "USE JOYSTICK PORT 2", 0 },
209 { AT_DISABLED, "GRAVIS GAMEPAD ENABLED", 0 },
210 { AT_DISABLED, "CALIBRATE JOYSTICK", 0 },
211 { AT_DISABLED, "MOUSE SENSITIVITY", MouseSensitivity },
212 { AT_ENABLED, "CUSTOMIZE CONTROLS", CustomControls }
213 };
214
215 CP_itemtype SwitchMenu[] = {
216 { AT_ENABLED, "LIGHTING", 0 },
217 { AT_ENABLED, "REBA ATTACK INFO", 0 },
218 { AT_ENABLED, "SHOW CEILINGS", 0 },
219 { AT_ENABLED, "SHOW FLOORS", 0 },
220
221 // BBi
222 { AT_ENABLED, "NO WALL HIT SOUND", 0 },
223 { AT_ENABLED, "MODERN CONTROLS", 0 },
224 { AT_ENABLED, "ALWAYS RUN", 0 },
225 { AT_ENABLED, "HEART BEAT SOUND", 0 },
226 { AT_ENABLED, "ROTATED AUTOMAP", 0 },
227 };
228
229
230 CP_itemtype NewEmenu[] = {
231 { AT_ENABLED, "MISSION 1:\n"
232 "STAR INSTITUTE", 0 },
233
234 { AT_NON_SELECTABLE, "MISSION 2:\n"
235 "FLOATING FORTRESS", 0 },
236
237 { AT_NON_SELECTABLE, "MISSION 3:\n"
238 "UNDERGROUND NETWORK", 0 },
239
240 { AT_NON_SELECTABLE, "MISSION 4:\n"
241 "STAR PORT", 0 },
242
243 { AT_NON_SELECTABLE, "MISSION 5:\n"
244 "HABITAT II", 0 },
245
246 { AT_NON_SELECTABLE, "MISSION 6:\n"
247 "SATELLITE DEFENSE", 0 },
248 };
249
250 CP_itemtype NewMenu[] = {
251 { AT_ENABLED, "LEVEL 1:\n"
252 "NOVICE AGENT", 0 },
253 { AT_ENABLED, "LEVEL 2:\n"
254 "SKILLED AGENT", 0 },
255 { AT_ENABLED, "LEVEL 3:\n"
256 "EXPERT AGENT", 0 },
257 { AT_ENABLED, "LEVEL 4:\n"
258 "VETERAN AGENT", 0 }
259 };
260
261 CP_itemtype LSMenu[] = {
262 { AT_ENABLED, "", 0 },
263 { AT_ENABLED, "", 0 },
264 { AT_ENABLED, "", 0 },
265 { AT_ENABLED, "", 0 },
266 { AT_ENABLED, "", 0 },
267 { AT_ENABLED, "", 0 },
268 { AT_ENABLED, "", 0 },
269 { AT_ENABLED, "", 0 },
270 { AT_ENABLED, "", 0 },
271 { AT_ENABLED, "", 0 }
272 };
273
274 CP_itemtype CusMenu[] = {
275 { AT_ENABLED, "", 0 },
276 { AT_DISABLED, "", 0 },
277 { AT_ENABLED, "", 0 },
278 { AT_DISABLED, "", 0 },
279 { AT_ENABLED, "", 0 },
280 { AT_ENABLED, "", 0 }
281 };
282
283 // BBi
284 CP_itemtype video_menu[] = {
285 { AT_ENABLED, "TOGGLE WIDESCREEN", nullptr },
286 };
287 // BBi
288
289
290 int16_t color_hlite[] = {
291 HIGHLIGHT_DISABLED_COLOR,
292 HIGHLIGHT_TEXT_COLOR,
293 READHCOLOR,
294 HIGHLIGHT_DEACTIAVED_COLOR,
295 };
296
297 int16_t color_norml[] = {
298 DISABLED_TEXT_COLOR,
299 ENABLED_TEXT_COLOR,
300 READCOLOR,
301 DEACTIAVED_TEXT_COLOR,
302 };
303
304 int16_t EpisodeSelect[6] = {
305 1,
306 0,
307 0,
308 0,
309 0,
310 0,
311 };
312
313 int16_t SaveGamesAvail[10];
314 int16_t StartGame;
315 int16_t SoundStatus = 1;
316 int16_t pickquick;
317 char SaveGameNames[10][GAME_DESCRIPTION_LEN + 1];
318
319 static uint8_t menu_background_color = 0x00;
320
321
get_saved_game_base_name()322 static const std::string& get_saved_game_base_name()
323 {
324 static auto base_name = std::string();
325 static auto is_initialized = false;
326
327 if (!is_initialized) {
328 is_initialized = true;
329
330 base_name = "bstone_";
331
332 if (::is_aog_sw()) {
333 base_name += "aog_sw";
334 } else if (::is_aog_full()) {
335 base_name += "aog_full";
336 } else if (::is_ps()) {
337 base_name += "ps";
338 } else {
339 throw std::runtime_error("Invalid game type.");
340 }
341
342 base_name += "_saved_game_";
343 }
344
345 return base_name;
346 }
347
348 ////////////////////////////////////////////////////////////////////
349 //
350 // INPUT MANAGER SCANCODE TABLES
351 //
352 ////////////////////////////////////////////////////////////////////
353
354 #ifndef CACHE_KEY_DATA
355
356 using ScanCodes = std::vector<ScanCode>;
357 using ScanNames = std::vector<std::string>;
358
359 // Scan code names with single chars
360 static ScanNames scan_names = {
361 "?", "?", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "?", "?",
362 "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "|", "?", "A", "S",
363 "D", "F", "G", "H", "J", "K", "L", ";", "\"", "?", "?", "?", "Z", "X", "C", "V",
364 "B", "N", "M", ",", ".", "/", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
365 "?", "?", "?", "?", "?", "?", "?", "?", "\xF", "?", "-", "\x15", "5", "\x11", "+", "?",
366 "\x13", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
367 "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
368 "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
369 }; // scan_names
370
371 // Scan codes with >1 char names
372 static ScanCodes ext_scan_codes = {
373 ScanCode::sc_escape,
374 ScanCode::sc_backspace,
375 ScanCode::sc_tab,
376 ScanCode::sc_control,
377 ScanCode::sc_left_shift,
378 ScanCode::sc_space,
379 ScanCode::sc_caps_lock,
380 ScanCode::sc_f1,
381 ScanCode::sc_f2,
382 ScanCode::sc_f3,
383 ScanCode::sc_f4,
384 ScanCode::sc_f5,
385 ScanCode::sc_f6,
386 ScanCode::sc_f7,
387 ScanCode::sc_f8,
388 ScanCode::sc_f9,
389 ScanCode::sc_f10,
390 ScanCode::sc_f11,
391 ScanCode::sc_f12,
392 ScanCode::sc_scroll_lock,
393 ScanCode::sc_return,
394 ScanCode::sc_right_shift,
395 ScanCode::sc_print_screen,
396 ScanCode::sc_alt,
397 ScanCode::sc_home,
398 ScanCode::sc_page_up,
399 ScanCode::sc_end,
400 ScanCode::sc_page_down,
401 ScanCode::sc_insert,
402 ScanCode::sc_delete,
403 ScanCode::sc_num_lock,
404 ScanCode::sc_up_arrow,
405 ScanCode::sc_down_arrow,
406 ScanCode::sc_left_arrow,
407 ScanCode::sc_right_arrow,
408 ScanCode::sc_none,
409 }; // ExtScanCodes
410
411 static ScanNames ext_scan_names = {
412 "ESC", "BKSP", "TAB", "CTRL", "LSHFT", "SPACE", "CAPSLK", "F1",
413 "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9",
414 "F10", "F11", "F12", "SCRLK", "ENTER", "RSHFT", "PRTSC", "ALT",
415 "HOME", "PGUP", "END", "PGDN", "INS", "DEL", "NUMLK", "UP",
416 "DOWN", "LEFT", "RIGHT", "",
417 }; // ext_scan_names
418
419 #else
420
421 uint8_t* ScanNames, * ExtScanNames;
422 ScanCode* ExtScanCodes;
423
424 #endif
425
426 using SpecialKeys = std::vector<ScanCode>;
427
428 static SpecialKeys special_keys = {
429 ScanCode::sc_back_quote,
430 ScanCode::sc_equals,
431 ScanCode::sc_minus,
432 ScanCode::sc_l,
433 ScanCode::sc_p,
434 ScanCode::sc_m,
435 ScanCode::sc_s,
436 ScanCode::sc_i,
437 ScanCode::sc_q,
438 ScanCode::sc_w,
439 ScanCode::sc_e,
440 ScanCode::sc_return,
441 ScanCode::sc_1,
442 ScanCode::sc_2,
443 ScanCode::sc_3,
444 ScanCode::sc_4,
445 ScanCode::sc_5,
446 ScanCode::sc_tab,
447 }; // special_keys
448
449
450 // BBi
451 namespace {
452
453
454 using BindsNames = std::map<ScanCode, const char*>;
455
456
457 enum BindsFindDirection {
458 e_bfd_forward,
459 e_bfd_backward
460 }; // BindsFindDirection
461
462 enum BindsFindFrom {
463 e_bff_current,
464 e_bff_not_current
465 }; // BindingFindFrom
466
467
468 class BindsItem {
469 public:
470 std::string name;
471 int name_width;
472 Binding* binding;
473
BindsItem(std::string new_name=std::string (),int new_name_width=0,Binding * new_binding=nullptr)474 BindsItem(
475 std::string new_name = std::string(),
476 int new_name_width = 0,
477 Binding* new_binding = nullptr) :
478 name(new_name),
479 name_width(new_name_width),
480 binding(new_binding)
481 {
482 }
483 }; // BindsItem
484
485 using BindsItems = std::vector<BindsItem>;
486
487 static BindsItems binds = {
488 { "MOVEMENT", 0, nullptr, },
489 { "FORWARD", 0, &in_bindings[e_bi_forward], },
490 { "BACKWARD", 0, &in_bindings[e_bi_backward], },
491 { "LEFT", 0, &in_bindings[e_bi_left], },
492 { "RIGHT", 0, &in_bindings[e_bi_right], },
493 { "STRAFE", 0, &in_bindings[e_bi_strafe], },
494 { "STRAFE LEFT", 0, &in_bindings[e_bi_strafe_left], },
495 { "STRAFE RIGHT", 0, &in_bindings[e_bi_strafe_right], },
496 { "QUICK LEFT", 0, &in_bindings[e_bi_quick_left], },
497 { "QUICK RIGHT", 0, &in_bindings[e_bi_quick_right], },
498 { "TURN AROUND", 0, &in_bindings[e_bi_turn_around], },
499 { "RUN", 0, &in_bindings[e_bi_run], },
500 { "", 0, nullptr, },
501
502 { "WEAPONS", 0, nullptr, },
503 { "ATTACK", 0, &in_bindings[e_bi_attack], },
504 { "AUTO CHARGE PISTOL", 0, &in_bindings[e_bi_weapon_1], },
505 { "SLOW FIRE PROTECTOR", 0, &in_bindings[e_bi_weapon_2], },
506 { "RAPID ASSAULT WEAPON", 0, &in_bindings[e_bi_weapon_3], },
507 { "DUAL NEUTRON DISRUPTOR", 0, &in_bindings[e_bi_weapon_4], },
508 { "PLASMA DISCHARGE UNIT", 0, &in_bindings[e_bi_weapon_5], },
509 { "ANTI-PLASMA CANNON (PS)", 0, &in_bindings[e_bi_weapon_6], },
510 { "FISSION DETONATOR (PS)", 0, &in_bindings[e_bi_weapon_7], },
511 { "", 0, nullptr, },
512
513 { "INTERACTION", 0, nullptr, },
514 { "USE", 0, &in_bindings[e_bi_use], },
515 { "", 0, nullptr, },
516
517 { "HUD", 0, nullptr, },
518 { "STATS", 0, &in_bindings[e_bi_stats], },
519 { "MAGNIFY RADAR (PS)", 0, &in_bindings[e_bi_radar_magnify], },
520 { "MINIFY RADAR (PS)", 0, &in_bindings[e_bi_radar_minify], },
521 { "", 0, nullptr, },
522
523 { "MENU", 0, nullptr, },
524 { "HELP", 0, &in_bindings[e_bi_help], },
525 { "SAVE", 0, &in_bindings[e_bi_save], },
526 { "LOAD", 0, &in_bindings[e_bi_load], },
527 { "SOUND OPTIONS", 0, &in_bindings[e_bi_sound], },
528 { "CONTROLS", 0, &in_bindings[e_bi_controls], },
529 { "END GAME", 0, &in_bindings[e_bi_end_game], },
530 { "QUICK SAVE", 0, &in_bindings[e_bi_quick_save], },
531 { "QUICK LOAD", 0, &in_bindings[e_bi_quick_load], },
532 { "QUICK EXIT", 0, &in_bindings[e_bi_quick_exit], },
533 { "", 0, nullptr, },
534
535 { "OPTIONS", 0, nullptr, },
536 { "ATTACK INFO", 0, &in_bindings[e_bi_attack_info], },
537 { "LIGHTNING", 0, &in_bindings[e_bi_lightning], },
538 { "SOUND", 0, &in_bindings[e_bi_sfx], },
539 { "MUSIC", 0, &in_bindings[e_bi_music], },
540 { "CEILING", 0, &in_bindings[e_bi_ceiling], },
541 { "FLOORING", 0, &in_bindings[e_bi_flooring], },
542 { "HEART BEAT (AOG)", 0, &in_bindings[e_bi_heart_beat], },
543 { "", 0, nullptr, },
544
545 { "MISC", 0, nullptr, },
546 { "PAUSE", 0, &in_bindings[e_bi_pause], },
547 { "(UN)GRAB MOUSE", 0, &in_bindings[e_bi_grab_mouse], },
548 }; // binds
549
550
551 const int k_binds_max_per_window = 14;
552 const int k_binds_text_keys_gap = 3;
553 const int k_binds_line_spacing = 1;
554 const int k_binds_top = 28;
555
556 const uint8_t k_binds_category_color = 0x4A;
557 const uint8_t k_binds_text_color = 0x56;
558 const uint8_t k_binds_key_text_color = 0x7F;
559 const uint8_t k_binds_key_bar_default_color = 0x03;
560 const uint8_t k_binds_key_bar_active_color = 0x31;
561 const uint8_t k_binds_key_bar_assign_color = 0x14;
562
563 int binds_count;
564 int binds_window;
565 int binds_window_offset;
566 int binds_key_index;
567 int binds_key_width;
568 int binds_max_text_width;
569 int binds_text_height;
570 int binds_text_x;
571 int binds_key_x[k_max_binding_keys];
572 bool binds_is_assigning = false;
573
574 BindsNames binds_names;
575
576
binds_initialize_menu()577 void binds_initialize_menu()
578 {
579 static bool is_initialized = false;
580
581 if (is_initialized) {
582 return;
583 }
584
585 binds_count = 0;
586 binds_window = 0;
587 binds_window_offset = 0;
588 binds_key_index = 0;
589 binds_key_width = 0;
590 binds_max_text_width = 0;
591 binds_text_height = 0;
592 binds_is_assigning = false;
593
594 bool has_bindings = false;
595
596 fontnumber = 2;
597
598 for (auto& bind : binds) {
599 ++binds_count;
600
601 if (!bind.name.empty()) {
602 int width = 0;
603 int height = 0;
604 VW_MeasurePropString(bind.name.c_str(), &width, &height);
605
606 bind.name_width = width;
607
608 if (width > binds_max_text_width) {
609 binds_max_text_width = width;
610 }
611
612 if (height > binds_text_height) {
613 binds_text_height = height;
614 }
615
616 has_bindings = true;
617 }
618 }
619
620
621 if (!has_bindings) {
622 ::Quit("No bindings.");
623 }
624
625 binds_names.clear();
626 binds_names[ScanCode::sc_return] = "ENTER";
627 binds_names[ScanCode::sc_space] = "SPACE";
628 binds_names[ScanCode::sc_minus] = "-";
629 binds_names[ScanCode::sc_equals] = "=";
630 binds_names[ScanCode::sc_backspace] = "BACKSPACE";
631 binds_names[ScanCode::sc_tab] = "TAB";
632 binds_names[ScanCode::sc_alt] = "ALT";
633 binds_names[ScanCode::sc_left_bracket] = "[";
634 binds_names[ScanCode::sc_right_bracket] = "]";
635 binds_names[ScanCode::sc_control] = "CTRL";
636 binds_names[ScanCode::sc_caps_lock] = "CAPS LOCK";
637 binds_names[ScanCode::sc_num_lock] = "NUM LOCK";
638 binds_names[ScanCode::sc_scroll_lock] = "SCROLL LOCK";
639 binds_names[ScanCode::sc_left_shift] = "L-SHIFT";
640 binds_names[ScanCode::sc_right_shift] = "R-SHIFT";
641 binds_names[ScanCode::sc_up_arrow] = "UP";
642 binds_names[ScanCode::sc_down_arrow] = "DOWN";
643 binds_names[ScanCode::sc_left_arrow] = "LEFT";
644 binds_names[ScanCode::sc_right_arrow] = "RIGHT";
645 binds_names[ScanCode::sc_insert] = "INS";
646 binds_names[ScanCode::sc_delete] = "DEL";
647 binds_names[ScanCode::sc_home] = "HOME";
648 binds_names[ScanCode::sc_end] = "END";
649 binds_names[ScanCode::sc_page_up] = "PGUP";
650 binds_names[ScanCode::sc_page_down] = "PGDN";
651 binds_names[ScanCode::sc_slash] = "/";
652 binds_names[ScanCode::sc_f1] = "F1";
653 binds_names[ScanCode::sc_f2] = "F2";
654 binds_names[ScanCode::sc_f3] = "F3";
655 binds_names[ScanCode::sc_f4] = "F4";
656 binds_names[ScanCode::sc_f5] = "F5";
657 binds_names[ScanCode::sc_f6] = "F6";
658 binds_names[ScanCode::sc_f7] = "F7";
659 binds_names[ScanCode::sc_f8] = "F8";
660 binds_names[ScanCode::sc_f9] = "F9";
661 binds_names[ScanCode::sc_f10] = "F10";
662 binds_names[ScanCode::sc_f11] = "F11";
663 binds_names[ScanCode::sc_f12] = "F12";
664 binds_names[ScanCode::sc_print_screen] = "PRT SCR";
665 binds_names[ScanCode::sc_pause] = "PAUSE";
666 binds_names[ScanCode::sc_back_quote] = "BACK QUOTE";
667 binds_names[ScanCode::sc_semicolon] = ";";
668 binds_names[ScanCode::sc_quote] = "'";
669 binds_names[ScanCode::sc_backslash] = "\\";
670 binds_names[ScanCode::sc_comma] = ",";
671 binds_names[ScanCode::sc_period] = ".";
672
673 binds_names[ScanCode::sc_1] = "1";
674 binds_names[ScanCode::sc_2] = "2";
675 binds_names[ScanCode::sc_3] = "3";
676 binds_names[ScanCode::sc_4] = "4";
677 binds_names[ScanCode::sc_5] = "5";
678 binds_names[ScanCode::sc_6] = "6";
679 binds_names[ScanCode::sc_7] = "7";
680 binds_names[ScanCode::sc_8] = "8";
681 binds_names[ScanCode::sc_9] = "9";
682 binds_names[ScanCode::sc_0] = "0";
683
684 binds_names[ScanCode::sc_a] = "A";
685 binds_names[ScanCode::sc_b] = "B";
686 binds_names[ScanCode::sc_c] = "C";
687 binds_names[ScanCode::sc_d] = "D";
688 binds_names[ScanCode::sc_e] = "E";
689 binds_names[ScanCode::sc_f] = "F";
690 binds_names[ScanCode::sc_g] = "G";
691 binds_names[ScanCode::sc_h] = "H";
692 binds_names[ScanCode::sc_i] = "I";
693 binds_names[ScanCode::sc_j] = "J";
694 binds_names[ScanCode::sc_k] = "K";
695 binds_names[ScanCode::sc_l] = "L";
696 binds_names[ScanCode::sc_m] = "M";
697 binds_names[ScanCode::sc_n] = "N";
698 binds_names[ScanCode::sc_o] = "O";
699 binds_names[ScanCode::sc_p] = "P";
700 binds_names[ScanCode::sc_q] = "Q";
701 binds_names[ScanCode::sc_r] = "R";
702 binds_names[ScanCode::sc_s] = "S";
703 binds_names[ScanCode::sc_t] = "T";
704 binds_names[ScanCode::sc_u] = "U";
705 binds_names[ScanCode::sc_v] = "V";
706 binds_names[ScanCode::sc_w] = "W";
707 binds_names[ScanCode::sc_x] = "X";
708 binds_names[ScanCode::sc_y] = "Y";
709 binds_names[ScanCode::sc_z] = "Z";
710
711 binds_names[ScanCode::sc_kp_minus] = "KP MINUS";
712 binds_names[ScanCode::sc_kp_plus] = "KP PLUS";
713
714 binds_names[ScanCode::sc_mouse_left] = "MOUSE 1";
715 binds_names[ScanCode::sc_mouse_middle] = "MOUSE 2";
716 binds_names[ScanCode::sc_mouse_right] = "MOUSE 3";
717 binds_names[ScanCode::sc_mouse_x1] = "MOUSE 4";
718 binds_names[ScanCode::sc_mouse_x2] = "MOUSE 5";
719
720 for (const auto& binds_name : binds_names) {
721 int width = 0;
722 int height = 0;
723 VW_MeasurePropString(binds_name.second, &width, &height);
724
725 if (width > binds_key_width) {
726 binds_key_width = width;
727 }
728 }
729
730 int max_keys_width = k_max_binding_keys * (binds_key_width + 1);
731 int max_text_width = 2 + binds_max_text_width;
732 int max_width = max_keys_width + k_binds_text_keys_gap + max_text_width;
733
734 int text_x = (SCREEN_W - max_width) / 2;
735
736 int base_key_x = text_x + max_text_width + k_binds_text_keys_gap;
737
738 binds_text_x = text_x;
739
740 for (int i = 0; i < k_max_binding_keys; ++i) {
741 binds_key_x[i] = base_key_x + (i * (binds_key_width + 1));
742 }
743
744 is_initialized = true;
745 }
746
binds_advance_to_item(BindsFindDirection direction)747 bool binds_advance_to_item(
748 BindsFindDirection direction)
749 {
750 switch (direction) {
751 case e_bfd_forward:
752 if ((binds_window + binds_window_offset + 1) < binds_count) {
753 ++binds_window_offset;
754
755 if (binds_window_offset == k_binds_max_per_window) {
756 ++binds_window;
757 --binds_window_offset;
758 }
759
760 return true;
761 } else {
762 return false;
763 }
764
765 case e_bfd_backward:
766 if ((binds_window + binds_window_offset) > 0) {
767 --binds_window_offset;
768
769 if (binds_window_offset < 0) {
770 --binds_window;
771 binds_window_offset = 0;
772 }
773
774 return true;
775 } else {
776 return false;
777 }
778
779 default:
780 return false;
781 }
782 }
783
binds_find_item(BindsFindDirection direction,BindsFindFrom from)784 bool binds_find_item(
785 BindsFindDirection direction,
786 BindsFindFrom from)
787 {
788 if (from == e_bff_not_current) {
789 if (!binds_advance_to_item(direction)) {
790 return false;
791 }
792 }
793
794 while (true) {
795 if (binds[binds_window + binds_window_offset].binding) {
796 return true;
797 }
798
799 if (!binds_advance_to_item(direction)) {
800 return false;
801 }
802 }
803
804 return false;
805 }
806
binds_assign_new_key(ScanCode key,Binding & binding)807 bool binds_assign_new_key(
808 ScanCode key,
809 Binding& binding)
810 {
811 auto it = binds_names.find(LastScan);
812
813 if (it == binds_names.end()) {
814 return false;
815 }
816
817 for (int b = 0; b < k_max_bindings; ++b) {
818 for (int k = 0; k < k_max_binding_keys; ++k) {
819 if (in_bindings[b][k] == key) {
820 in_bindings[b][k] = ScanCode::sc_none;
821 }
822 }
823 }
824
825 binding[binds_key_index] = key;
826
827 return true;
828 }
829
binds_remove_binding()830 void binds_remove_binding()
831 {
832 auto& item = binds[binds_window + binds_window_offset];
833 (*item.binding)[binds_key_index] = ScanCode::sc_none;
834 }
835
binds_draw_item_text(int item_index)836 void binds_draw_item_text(
837 int item_index)
838 {
839 auto& item = binds[binds_window + item_index];
840
841 if (item.name.empty()) {
842 return;
843 }
844
845 int x = SCREEN_X + binds_text_x;
846 int y = SCREEN_Y + k_binds_top +
847 (item_index * (binds_text_height + k_binds_line_spacing));
848
849 int text_left_offset = 0;
850 int text_width = 0;
851
852 if (item.binding) {
853 text_width = item.name_width;
854 text_left_offset = binds_max_text_width - item.name_width;
855
856 if (text_left_offset < 0) {
857 text_left_offset = 0;
858 text_width = binds_max_text_width;
859 }
860 } else {
861 text_width = SCREEN_W;
862 }
863
864 PrintX = static_cast<int16_t>(x + text_left_offset);
865 PrintY = static_cast<int16_t>(y);
866 WindowX = PrintX;
867 WindowY = PrintY;
868 WindowW = static_cast<int16_t>(text_width);
869 WindowH = static_cast<int16_t>(binds_text_height);
870
871 if (item.binding) {
872 fontcolor = k_binds_text_color;
873 US_Print(item.name.c_str());
874 } else {
875 fontcolor = k_binds_category_color;
876 US_PrintCentered(item.name.c_str());
877 }
878 }
879
binds_draw_keys(int item_index)880 void binds_draw_keys(
881 int item_index)
882 {
883 const auto& item = binds[binds_window + item_index];
884
885 if (!item.binding) {
886 return;
887 }
888
889 int y = SCREEN_Y + k_binds_top +
890 (item_index * (binds_text_height + k_binds_line_spacing));
891
892 bool is_current = (item_index == binds_window_offset);
893
894 for (int k = 0; k < k_max_binding_keys; ++k) {
895 uint8_t color;
896 ScanCode key;
897 const char* key_name;
898
899 bool is_active = is_current && (binds_key_index == k);
900
901 if (is_active) {
902 color =
903 binds_is_assigning ?
904 k_binds_key_bar_assign_color :
905 k_binds_key_bar_active_color;
906 } else {
907 color = k_binds_key_bar_default_color;
908 }
909
910 int x = SCREEN_X + binds_key_x[k];
911
912 VWB_Bar(
913 x,
914 y,
915 binds_key_width,
916 binds_text_height,
917 color);
918
919 PrintX = static_cast<int16_t>(x);
920 PrintY = static_cast<int16_t>(y);
921 WindowX = PrintX;
922 WindowY = PrintY;
923 WindowW = static_cast<int16_t>(binds_key_width);
924 WindowH = static_cast<int16_t>(binds_text_height);
925
926 if (!(is_active && binds_is_assigning)) {
927 key = (*item.binding)[k];
928
929 if (key != ScanCode::sc_none) {
930 key_name = "???";
931
932 auto name_it = binds_names.find(key);
933
934 if (name_it != binds_names.end()) {
935 key_name = name_it->second;
936 }
937
938 fontcolor = k_binds_key_text_color;
939 US_PrintCentered(key_name);
940 }
941 }
942 }
943 }
944
binds_draw()945 void binds_draw()
946 {
947 bool found_item = false;
948
949 found_item = binds_find_item(e_bfd_forward, e_bff_current);
950
951 if (!found_item) {
952 found_item = binds_find_item(e_bfd_backward, e_bff_current);
953 }
954
955 ClearMScreen();
956 DrawMenuTitle("CUSTOMIZE CONTROLS");
957
958 DrawInstructions(
959 binds_is_assigning ? IT_CONTROLS_ASSIGNING_KEY : IT_CONTROLS);
960
961 fontnumber = 2;
962
963 for (int i = 0; i < k_binds_max_per_window; ++i) {
964 int item_index = binds_window + i;
965
966 if (item_index == binds_count) {
967 break;
968 }
969
970 binds_draw_item_text(i);
971 binds_draw_keys(i);
972 }
973 }
974
binds_draw_menu()975 void binds_draw_menu()
976 {
977 bool is_up_pressed = false;
978 bool is_down_pressed = false;
979 bool is_left_pressed = false;
980 bool is_right_pressed = false;
981 bool is_pgdn_pressed = false;
982 bool is_pgup_pressed = false;
983 bool is_enter_pressed = false;
984 bool is_delete_pressed = false;
985 bool is_escape_pressed = false;
986
987 bool handle_up = false;
988 bool handle_down = false;
989 bool handle_left = false;
990 bool handle_right = false;
991 bool handle_pgdn = false;
992 bool handle_pgup = false;
993 bool handle_enter = false;
994 bool handle_delete = false;
995 bool handle_escape = false;
996
997 bool fade_in = true;
998
999 CA_CacheGrChunk(STARTFONT + 2);
1000 CA_CacheGrChunk(STARTFONT + 4);
1001 binds_initialize_menu();
1002
1003 binds_is_assigning = false;
1004
1005 while (true) {
1006 binds_draw();
1007 VW_UpdateScreen();
1008
1009 if (fade_in) {
1010 fade_in = false;
1011 MenuFadeIn();
1012 }
1013
1014 in_handle_events();
1015
1016 if (binds_is_assigning) {
1017 LastScan = ScanCode::sc_none;
1018 bool quit = false;
1019
1020 while (!quit) {
1021 LastScan = ScanCode::sc_none;
1022 in_handle_events();
1023
1024 if (Keyboard[ScanCode::sc_escape]) {
1025 quit = true;
1026 sd_play_player_sound(ESCPRESSEDSND, bstone::AC_ITEM);
1027 } else if (LastScan != ScanCode::sc_none) {
1028 auto& item = binds[binds_window + binds_window_offset];
1029
1030 if (binds_assign_new_key(LastScan, *item.binding)) {
1031 ShootSnd();
1032 quit = true;
1033 } else {
1034 sd_play_player_sound(NOWAYSND, bstone::AC_ITEM);
1035 }
1036 }
1037 }
1038
1039 is_escape_pressed = true;
1040 binds_is_assigning = false;
1041 } else {
1042 if (Keyboard[ScanCode::sc_up_arrow]) {
1043 if (!is_up_pressed) {
1044 handle_up = true;
1045 is_up_pressed = true;
1046 }
1047 } else {
1048 is_up_pressed = false;
1049 }
1050
1051 if (Keyboard[ScanCode::sc_down_arrow]) {
1052 if (!is_down_pressed) {
1053 handle_down = true;
1054 is_down_pressed = true;
1055 }
1056 } else {
1057 is_down_pressed = false;
1058 }
1059
1060 if (Keyboard[ScanCode::sc_left_arrow]) {
1061 if (!is_left_pressed) {
1062 handle_left = true;
1063 is_left_pressed = true;
1064 }
1065 } else {
1066 is_left_pressed = false;
1067 }
1068
1069 if (Keyboard[ScanCode::sc_right_arrow]) {
1070 if (!is_right_pressed) {
1071 handle_right = true;
1072 is_right_pressed = true;
1073 }
1074 } else {
1075 is_right_pressed = false;
1076 }
1077
1078 if (Keyboard[ScanCode::sc_page_down]) {
1079 if (!is_pgdn_pressed) {
1080 handle_pgdn = true;
1081 is_pgdn_pressed = true;
1082 }
1083 } else {
1084 is_pgdn_pressed = false;
1085 }
1086
1087 if (Keyboard[ScanCode::sc_page_up]) {
1088 if (!is_pgup_pressed) {
1089 handle_pgup = true;
1090 is_pgup_pressed = true;
1091 }
1092 } else {
1093 is_pgup_pressed = false;
1094 }
1095
1096 if (Keyboard[ScanCode::sc_return]) {
1097 if (!is_enter_pressed) {
1098 handle_enter = true;
1099 is_enter_pressed = true;
1100 }
1101 } else {
1102 is_enter_pressed = false;
1103 }
1104
1105 if (Keyboard[ScanCode::sc_delete]) {
1106 if (!is_delete_pressed) {
1107 handle_delete = true;
1108 is_delete_pressed = true;
1109 }
1110 } else {
1111 is_delete_pressed = false;
1112 }
1113
1114 if (Keyboard[ScanCode::sc_escape]) {
1115 if (!is_escape_pressed) {
1116 handle_escape = true;
1117 is_escape_pressed = true;
1118 }
1119 } else {
1120 is_escape_pressed = false;
1121 }
1122
1123 if (handle_up) {
1124 handle_up = false;
1125 binds_find_item(e_bfd_backward, e_bff_not_current);
1126 }
1127
1128 if (handle_down) {
1129 handle_down = false;
1130 binds_find_item(e_bfd_forward, e_bff_not_current);
1131 }
1132
1133 if (handle_left) {
1134 handle_left = false;
1135
1136 if (binds_key_index == 1) {
1137 binds_key_index = 0;
1138 }
1139 }
1140
1141 if (handle_right) {
1142 handle_right = false;
1143
1144 if (binds_key_index == 0) {
1145 binds_key_index = 1;
1146 }
1147 }
1148
1149 if (handle_pgdn) {
1150 handle_pgdn = false;
1151
1152 for (int i = 0; i < k_binds_max_per_window; ++i) {
1153 binds_find_item(e_bfd_forward, e_bff_not_current);
1154 }
1155 }
1156
1157 if (handle_pgup) {
1158 handle_pgup = false;
1159
1160 for (int i = 0; i < k_binds_max_per_window; ++i) {
1161 binds_find_item(e_bfd_backward, e_bff_not_current);
1162 }
1163 }
1164
1165 if (handle_enter) {
1166 handle_enter = false;
1167 binds_is_assigning = true;
1168 }
1169
1170 if (handle_delete) {
1171 handle_delete = false;
1172 binds_remove_binding();
1173 ShootSnd();
1174 }
1175
1176 if (handle_escape) {
1177 handle_escape = false;
1178 sd_play_player_sound(ESCPRESSEDSND, bstone::AC_ITEM);
1179 break;
1180 }
1181 }
1182 }
1183
1184 ::MenuFadeOut();
1185 }
1186
1187
1188 } // namespace
1189 // BBi
1190
HelpScreens()1191 void HelpScreens()
1192 {
1193 HelpPresenter(nullptr, false, HELPTEXT, true);
1194 }
1195
HelpPresenter(const char * fname,bool continue_keys,uint16_t id_cache,bool startmusic)1196 void HelpPresenter(
1197 const char* fname,
1198 bool continue_keys,
1199 uint16_t id_cache,
1200 bool startmusic)
1201 {
1202 const int FULL_VIEW_WIDTH = 19;
1203
1204 PresenterInfo pi;
1205 int oldwidth;
1206
1207 memset(&pi, 0, sizeof(pi));
1208
1209 pi.flags = TPF_SHOW_PAGES;
1210 if (continue_keys) {
1211 pi.flags |= TPF_CONTINUE;
1212 }
1213
1214 VW_FadeOut();
1215
1216 // Change view size to MAX! (scaler clips shapes on smaller views)
1217 //
1218 oldwidth = viewwidth / 16;
1219 if (oldwidth != FULL_VIEW_WIDTH) {
1220 NewViewSize();
1221 }
1222
1223 // Draw help border
1224 //
1225 CacheLump(H_TOPWINDOWPIC, H_BOTTOMINFOPIC);
1226 VWB_DrawPic(0, 0, H_TOPWINDOWPIC);
1227 VWB_DrawPic(0, 8, H_LEFTWINDOWPIC);
1228 VWB_DrawPic(312, 8, H_RIGHTWINDOWPIC);
1229 VWB_DrawPic(8, 176, H_BOTTOMINFOPIC);
1230 UnCacheLump(H_TOPWINDOWPIC, H_BOTTOMINFOPIC);
1231
1232 // Setup for text presenter
1233 //
1234 pi.xl = 8;
1235 pi.yl = 8;
1236 pi.xh = 311;
1237 pi.yh = 175;
1238 pi.ltcolor = 0x7b;
1239 pi.bgcolor = 0x7d;
1240 pi.dkcolor = 0x7f;
1241 pi.shcolor = 0x00;
1242 pi.fontnumber = 4;
1243
1244 if (continue_keys) {
1245 pi.infoline = (char*)" UP / DN - PAGES ENTER - CONTINUES ESC - EXITS";
1246 } else {
1247 pi.infoline = (char*)" UP / DN - PAGES ESC - EXITS";
1248 }
1249
1250 if (startmusic) {
1251 ::StartCPMusic(static_cast<int16_t>(TEXTSONG));
1252 }
1253
1254 // Load, present, and free help text.
1255 //
1256 TP_LoadScript(fname, &pi, id_cache);
1257 TP_Presenter(&pi);
1258 TP_FreeScript(&pi, id_cache);
1259
1260 ::MenuFadeOut();
1261
1262 // Reset view size
1263 //
1264 if (oldwidth != FULL_VIEW_WIDTH) {
1265 NewViewSize();
1266 }
1267
1268 if (startmusic && TPscan == ScanCode::sc_escape) {
1269 ::StartCPMusic(MENUSONG);
1270 }
1271
1272 IN_ClearKeysDown();
1273 }
1274
US_ControlPanel(ScanCode scancode)1275 void US_ControlPanel(
1276 ScanCode scancode)
1277 {
1278 // BBi
1279 menu_background_color = (
1280 (::is_aog_sw() | ::is_aog_full_v3_0()) ?
1281 0x04 :
1282 TERM_BACK_COLOR);
1283
1284
1285 int16_t which;
1286
1287 if (ingame) {
1288 if (CP_CheckQuick(scancode)) {
1289 return;
1290 }
1291 }
1292
1293 SetupControlPanel();
1294
1295 ::StartCPMusic(MENUSONG);
1296
1297 //
1298 // F-KEYS FROM WITHIN GAME
1299 //
1300 auto finish = false;
1301
1302 switch (scancode) {
1303 case ScanCode::sc_f1:
1304 ::CleanupControlPanel();
1305 ::HelpScreens();
1306 return;
1307
1308 case ScanCode::sc_f2:
1309 ::CP_SaveGame(0);
1310 finish = true;
1311 break;
1312
1313 case ScanCode::sc_f3:
1314 ::CP_LoadGame(0);
1315 finish = true;
1316 break;
1317
1318 case ScanCode::sc_f4:
1319 ::CP_Sound(0);
1320 finish = true;
1321 break;
1322
1323 case ScanCode::sc_f6:
1324 CP_Control(0);
1325 finish = true;
1326 break;
1327
1328 default:
1329 break;
1330 }
1331
1332 if (finish) {
1333 ::CleanupControlPanel();
1334 return;
1335 }
1336
1337 DrawMainMenu();
1338 MenuFadeIn();
1339 StartGame = 0;
1340
1341 //
1342 // MAIN MENU LOOP
1343 //
1344 do {
1345 which = HandleMenu(&MainItems, &MainMenu[0], nullptr);
1346
1347 switch (which) {
1348 case MM_VIEW_SCORES:
1349 if (!MainMenu[MM_VIEW_SCORES].routine) {
1350 if (CP_EndGame()) {
1351 StartGame = 1;
1352 }
1353 }
1354
1355 DrawMainMenu();
1356 MenuFadeIn();
1357 break;
1358
1359 case -1:
1360 case MM_LOGOFF:
1361 CP_Quit();
1362 break;
1363
1364 default:
1365 if (!StartGame) {
1366 DrawMainMenu();
1367 MenuFadeIn();
1368 }
1369 }
1370
1371 //
1372 // "EXIT OPTIONS" OR "NEW GAME" EXITS
1373 //
1374 } while (!StartGame);
1375
1376 //
1377 // DEALLOCATE EVERYTHING
1378 //
1379 CleanupControlPanel();
1380 if (!loadedgame) {
1381 StopMusic();
1382 }
1383
1384
1385 //
1386 // CHANGE MAINMENU ITEM
1387 //
1388 if (startgame || loadedgame) {
1389 MainMenu[MM_VIEW_SCORES].routine = nullptr;
1390 strcpy(MainMenu[MM_VIEW_SCORES].string, "END GAME");
1391 }
1392
1393 if (ingame && loadedgame) {
1394 refresh_screen = false;
1395 }
1396
1397
1398 #ifdef CACHE_KEY_DATA
1399 FREEFONT(SCANNAMES_DATA);
1400 FREEFONT(EXTSCANNAMES_DATA);
1401 FREEFONT(EXTSCANCODES_DATA);
1402 #endif
1403 }
1404
DrawMainMenu()1405 void DrawMainMenu()
1406 {
1407 ControlPanelFree();
1408 CA_CacheScreen(BACKGROUND_SCREENPIC);
1409 ControlPanelAlloc();
1410
1411 ClearMScreen();
1412 DrawMenuTitle("MAIN OPTIONS");
1413 DrawInstructions(IT_STANDARD);
1414
1415 //
1416 // CHANGE "MISSION" AND "DEMO"
1417 //
1418 if (ingame) {
1419 strcpy(&MainMenu[MM_BACK_TO_DEMO].string[8], "MISSION");
1420 MainMenu[MM_BACK_TO_DEMO].active = AT_READIT;
1421 } else {
1422 strcpy(&MainMenu[MM_BACK_TO_DEMO].string[8], "DEMO");
1423 MainMenu[MM_BACK_TO_DEMO].active = AT_ENABLED;
1424 }
1425
1426 fontnumber = 4; // COAL
1427
1428 DrawMenu(&MainItems, &MainMenu[0]);
1429
1430 VW_UpdateScreen();
1431 }
1432
CP_ReadThis(int16_t)1433 void CP_ReadThis(
1434 int16_t)
1435 {
1436 ControlPanelFree();
1437 HelpScreens();
1438 ControlPanelAlloc();
1439 }
1440
CP_OrderingInfo(int16_t)1441 void CP_OrderingInfo(
1442 int16_t)
1443 {
1444 ControlPanelFree();
1445 HelpPresenter("", false, ORDERTEXT, true);
1446 ControlPanelAlloc();
1447 }
1448
CP_BlakeStoneSaga(int16_t)1449 void CP_BlakeStoneSaga(
1450 int16_t)
1451 {
1452 ControlPanelFree();
1453 HelpPresenter("", false, SAGATEXT, true);
1454 ControlPanelAlloc();
1455 }
1456
1457 // --------------------------------------------------------------------------
1458 // CP_CheckQuick() - CHECK QUICK-KEYS & QUIT (WHILE IN A GAME)
1459 // --------------------------------------------------------------------------
CP_CheckQuick(ScanCode scancode)1460 bool CP_CheckQuick(
1461 ScanCode scancode)
1462 {
1463 switch (scancode) {
1464 // END GAME
1465 //
1466 case ScanCode::sc_f7:
1467 // BBi
1468 #if 0
1469 VW_ScreenToScreen(PAGE1START, ::bufferofs, 320, 160);
1470 #endif
1471
1472 CA_CacheGrChunk(STARTFONT + 1);
1473
1474 WindowH = 160;
1475 if (Confirm(ENDGAMESTR)) {
1476 playstate = ex_died;
1477 pickquick = gamestate.lives = 0;
1478 }
1479
1480 WindowH = 200;
1481 fontnumber = 4;
1482 return true;
1483
1484 // QUICKSAVE
1485 //
1486 case ScanCode::sc_f8:
1487 if (SaveGamesAvail[static_cast<int>(LSItems.curpos)] && pickquick) {
1488 char string[100] = "Quick Save will overwrite:\n\"";
1489
1490 CA_CacheGrChunk(STARTFONT + 1);
1491
1492 strcat(string, SaveGameNames[static_cast<int>(LSItems.curpos)]);
1493 strcat(string, "\"?");
1494
1495 // BBi
1496 #if 0
1497 VW_ScreenToScreen(PAGE1START, ::bufferofs, 320, 160);
1498 #endif
1499
1500 if (Confirm(string)) {
1501 CA_CacheGrChunk(STARTFONT + 1);
1502 CP_SaveGame(1);
1503 fontnumber = 4;
1504 } else {
1505 refresh_screen = false;
1506 }
1507 } else {
1508 CA_CacheGrChunk(STARTFONT + 1);
1509
1510 VW_FadeOut();
1511
1512 ::StartCPMusic(MENUSONG);
1513
1514 pickquick = CP_SaveGame(0);
1515
1516 lasttimecount = TimeCount;
1517 ::in_clear_mouse_deltas();
1518 }
1519
1520 return true;
1521
1522 // QUICKLOAD
1523 //
1524 case ScanCode::sc_f9:
1525 if (SaveGamesAvail[static_cast<int>(LSItems.curpos)] && pickquick) {
1526 char string[100] = "Quick Load:\n\"";
1527
1528 CA_CacheGrChunk(STARTFONT + 1);
1529
1530 strcat(string, SaveGameNames[static_cast<int>(LSItems.curpos)]);
1531 strcat(string, "\"?");
1532
1533 // BBi
1534 #if 0
1535 VW_ScreenToScreen(PAGE1START, ::bufferofs, 320, 160);
1536 #endif
1537
1538 if (Confirm(string)) {
1539 CP_LoadGame(1);
1540 } else {
1541 refresh_screen = false;
1542 return true;
1543 }
1544
1545 fontnumber = 4;
1546 } else {
1547 CA_CacheGrChunk(STARTFONT + 1);
1548
1549 VW_FadeOut();
1550
1551 ::StartCPMusic(MENUSONG);
1552
1553 pickquick = CP_LoadGame(0);
1554
1555 lasttimecount = TimeCount;
1556 ::in_clear_mouse_deltas();
1557 }
1558
1559 if (pickquick) {
1560 refresh_screen = false;
1561 }
1562 return true;
1563
1564 // QUIT
1565 //
1566 case ScanCode::sc_f10:
1567 CA_CacheGrChunk(STARTFONT + 1);
1568
1569 // BBi
1570 #if 0
1571 VW_ScreenToScreen(PAGE1START, ::bufferofs, 320, 160);
1572 #endif
1573
1574 WindowX = WindowY = 0;
1575 WindowW = 320;
1576 WindowH = 160;
1577 if (Confirm(QuitToDosStr)) {
1578 ExitGame();
1579 }
1580
1581 refresh_screen = false;
1582 WindowH = 200;
1583 fontnumber = 4;
1584
1585 return true;
1586
1587 default:
1588 return false;
1589 }
1590 }
1591
CP_EndGame()1592 int16_t CP_EndGame()
1593 {
1594 if (!Confirm(ENDGAMESTR)) {
1595 return 0;
1596 }
1597
1598 pickquick = gamestate.lives = 0;
1599 playstate = ex_died;
1600 InstantQuit = 1;
1601
1602 return 1;
1603 }
1604
CP_ViewScores(int16_t)1605 void CP_ViewScores(
1606 int16_t)
1607 {
1608 fontnumber = 4;
1609
1610 ::StartCPMusic(static_cast<int16_t>(ROSTER_MUS));
1611
1612 DrawHighScores();
1613 VW_UpdateScreen();
1614 MenuFadeIn();
1615 fontnumber = 1;
1616
1617 IN_Ack();
1618
1619 ::StartCPMusic(MENUSONG);
1620
1621 ::MenuFadeOut();
1622 }
1623
CP_NewGame(int16_t)1624 void CP_NewGame(
1625 int16_t)
1626 {
1627 int16_t which, episode = 0;
1628
1629 DrawMenuTitle("Difficulty Level");
1630 DrawInstructions(IT_STANDARD);
1631
1632
1633 firstpart:
1634
1635 if (!::is_ps()) {
1636 DrawNewEpisode();
1637 do {
1638 which = HandleMenu(&NewEitems, &NewEmenu[0], DrawEpisodePic);
1639 switch (which) {
1640 case -1:
1641 ::MenuFadeOut();
1642 return;
1643
1644 default:
1645 if (!EpisodeSelect[which]) {
1646 ::sd_play_player_sound(NOWAYSND, bstone::AC_ITEM);
1647 CacheMessage(READTHIS_TEXT);
1648 IN_ClearKeysDown();
1649 IN_Ack();
1650 VL_Bar(35, 69, 250, 62, ::menu_background_color);
1651 DrawNewEpisode();
1652 which = 0;
1653 } else {
1654 episode = which;
1655 which = 1;
1656 }
1657 break;
1658 }
1659
1660 } while (!which);
1661
1662 ShootSnd();
1663 } else {
1664 episode = 0;
1665 }
1666
1667 //
1668 // ALREADY IN A GAME?
1669 //
1670 if (!::is_ps() && ingame) {
1671 if (!Confirm(CURGAME)) {
1672 ::MenuFadeOut();
1673 return;
1674 }
1675 }
1676
1677 secondpart:
1678
1679 ::MenuFadeOut();
1680 if (ingame) {
1681 CA_CacheScreen(BACKGROUND_SCREENPIC);
1682 }
1683 DrawNewGame();
1684 which = HandleMenu(&NewItems, &NewMenu[0], DrawNewGameDiff);
1685
1686 if (which < 0) {
1687 ::MenuFadeOut();
1688
1689 if (!::is_ps()) {
1690 goto firstpart;
1691 } else {
1692 return;
1693 }
1694 }
1695
1696 ShootSnd();
1697 ::MenuFadeOut();
1698 ControlPanelFree();
1699
1700 if (Breifing(BT_INTRO, episode)) {
1701 CA_CacheScreen(BACKGROUND_SCREENPIC);
1702 ControlPanelAlloc();
1703 goto secondpart;
1704 }
1705
1706 StartGame = 1;
1707 NewGame(which, episode);
1708
1709 //
1710 // CHANGE "READ THIS!" TO NORMAL COLOR
1711 //
1712 MainMenu[MM_READ_THIS].active = AT_ENABLED;
1713 }
1714
DrawMenuTitle(const char * title)1715 void DrawMenuTitle(
1716 const char* title)
1717 {
1718
1719 fontnumber = 3;
1720 CA_CacheGrChunk(STARTFONT + 3);
1721
1722 PrintX = WindowX = 32;
1723 PrintY = WindowY = 32;
1724 WindowW = 244;
1725 WindowH = 20;
1726
1727 SETFONTCOLOR(TERM_SHADOW_COLOR, TERM_BACK_COLOR);
1728 US_PrintCentered(title);
1729
1730 WindowX = 32 - 1;
1731 WindowY = 32 - 1;
1732
1733 SETFONTCOLOR(ENABLED_TEXT_COLOR, TERM_BACK_COLOR);
1734 US_PrintCentered(title);
1735
1736 FREEFONT(STARTFONT + 3);
1737
1738 }
1739
1740 const int16_t INSTRUCTIONS_Y_POS = 154 + 10;
1741
1742 // ---------------------------------------------------------------------------
1743 // DrawInstructions() - Draws instructions centered at the bottom of
1744 // the view screen.
1745 //
1746 // NOTES: Orginal font number or font color is not maintained.
1747 // ---------------------------------------------------------------------------
DrawInstructions(inst_type Type)1748 void DrawInstructions(
1749 inst_type Type)
1750 {
1751 const char* instr[MAX_INSTRUCTIONS] = {
1752 "UP/DN SELECTS - ENTER CHOOSES - ESC EXITS",
1753 "PRESS ANY KEY TO CONTINUE",
1754 "ENTER YOUR NAME AND PRESS ENTER",
1755 "RT/LF ARROW SELECTS - ENTER CHOOSES",
1756
1757 // BBi
1758 "UP/DN SELECTS - LF/RT CHANGES - ESC EXITS",
1759 "ARROWS SELECTS - ENTER CHOOSES - DEL REMOVES",
1760 "ESC EXITS"
1761 };
1762
1763 fontnumber = 2;
1764
1765 WindowX = 48;
1766 WindowY = INSTRUCTIONS_Y_POS;
1767 WindowW = 236;
1768 WindowH = 8;
1769
1770 VWB_Bar(WindowX, WindowY - 1, WindowW, WindowH, ::menu_background_color);
1771
1772 SETFONTCOLOR(TERM_SHADOW_COLOR, TERM_BACK_COLOR);
1773 US_PrintCentered(instr[Type]);
1774
1775 WindowX--;
1776 WindowY--;
1777
1778 SETFONTCOLOR(INSTRUCTIONS_TEXT_COLOR, TERM_BACK_COLOR);
1779 US_PrintCentered(instr[Type]);
1780 }
1781
DrawNewEpisode()1782 void DrawNewEpisode()
1783 {
1784 ClearMScreen();
1785
1786 DrawMenuTitle("CHOOSE A MISSION");
1787 DrawInstructions(IT_STANDARD);
1788
1789 PrintY = 51;
1790 WindowX = 58;
1791
1792 fontnumber = 2; // six point font
1793 DrawMenu(&NewEitems, &NewEmenu[0]);
1794
1795 DrawEpisodePic(NewEitems.curpos);
1796
1797 VW_UpdateScreen();
1798 MenuFadeIn();
1799 WaitKeyUp();
1800
1801 }
1802
DrawNewGame()1803 void DrawNewGame()
1804 {
1805 ClearMScreen();
1806 DrawMenuTitle("DIFFICULTY LEVEL");
1807 DrawInstructions(IT_STANDARD);
1808
1809 fontnumber = 2; // six point font
1810 DrawMenu(&NewItems, &NewMenu[0]);
1811
1812 DrawNewGameDiff(NewItems.curpos);
1813
1814 px = 48;
1815 py = INSTRUCTIONS_Y_POS - 24;
1816 ShPrint(" HIGHER DIFFICULTY LEVELS CONTAIN", TERM_SHADOW_COLOR, false);
1817
1818 px = 48;
1819 py += 6;
1820 ShPrint(" MORE, STRONGER ENEMIES", TERM_SHADOW_COLOR, false);
1821
1822
1823 VW_UpdateScreen();
1824
1825 MenuFadeIn();
1826 WaitKeyUp();
1827 }
1828
DrawNewGameDiff(int16_t w)1829 void DrawNewGameDiff(
1830 int16_t w)
1831 {
1832 VWB_DrawPic(192, 77, w + C_BABYMODEPIC);
1833 }
1834
DrawEpisodePic(int16_t w)1835 void DrawEpisodePic(
1836 int16_t w)
1837 {
1838 VWB_DrawPic(176, 72, w + C_EPISODE1PIC);
1839 }
1840
CP_GameOptions(int16_t)1841 void CP_GameOptions(
1842 int16_t)
1843 {
1844 int16_t which;
1845
1846 CA_CacheScreen(BACKGROUND_SCREENPIC);
1847 DrawGopMenu();
1848 MenuFadeIn();
1849 WaitKeyUp();
1850
1851 do {
1852 which = HandleMenu(&GopItems, &GopMenu[0], nullptr);
1853
1854 if (which != -1) {
1855 DrawGopMenu();
1856 MenuFadeIn();
1857 }
1858
1859 } while (which >= 0);
1860
1861 ::MenuFadeOut();
1862 }
1863
DrawGopMenu()1864 void DrawGopMenu()
1865 {
1866 CA_CacheScreen(BACKGROUND_SCREENPIC);
1867
1868 ClearMScreen();
1869 DrawMenuTitle("GAME OPTIONS");
1870 DrawInstructions(IT_STANDARD);
1871
1872 fontnumber = 4; // COAL
1873
1874 DrawMenu(&GopItems, &GopMenu[0]);
1875
1876 VW_UpdateScreen();
1877 }
1878
ChangeSwaps()1879 void ChangeSwaps()
1880 {
1881 WindowX = WindowY = 0;
1882 WindowW = 320;
1883 WindowH = 200;
1884 Message(Computing);
1885
1886 PM_Shutdown();
1887 PM_Startup();
1888 ClearMemory();
1889 ControlPanelAlloc();
1890
1891 IN_UserInput(50);
1892 IN_ClearKeysDown();
1893
1894 }
1895
CP_Switches(int16_t)1896 void CP_Switches(
1897 int16_t)
1898 {
1899 int16_t which;
1900
1901 CA_CacheScreen(BACKGROUND_SCREENPIC);
1902 DrawSwitchMenu();
1903 MenuFadeIn();
1904 WaitKeyUp();
1905
1906 do {
1907 which = HandleMenu(&SwitchItems, &SwitchMenu[0], DrawAllSwitchLights);
1908
1909 switch (which) {
1910 case SW_LIGHTING:
1911 gamestate.flags ^= GS_LIGHTING;
1912 ShootSnd();
1913 DrawSwitchMenu();
1914 break;
1915
1916 case SW_REBA_ATTACK_INFO:
1917 gamestate.flags ^= GS_ATTACK_INFOAREA;
1918 ShootSnd();
1919 DrawSwitchMenu();
1920 break;
1921
1922 case SW_CEILING:
1923 gamestate.flags ^= GS_DRAW_CEILING;
1924 ShootSnd();
1925 DrawSwitchMenu();
1926 break;
1927
1928 case SW_FLOORS:
1929 gamestate.flags ^= GS_DRAW_FLOOR;
1930 ShootSnd();
1931 DrawSwitchMenu();
1932 break;
1933
1934 // BBi
1935 case SW_NO_WALL_HIT_SOUND:
1936 g_no_wall_hit_sound = !g_no_wall_hit_sound;
1937 ShootSnd();
1938 DrawSwitchMenu();
1939 break;
1940
1941 case SW_MODERN_CONTROLS:
1942 in_use_modern_bindings = !in_use_modern_bindings;
1943 ShootSnd();
1944 DrawSwitchMenu();
1945 break;
1946
1947 case SW_ALWAYS_RUN:
1948 g_always_run = !g_always_run;
1949 ShootSnd();
1950 DrawSwitchMenu();
1951 break;
1952
1953 case SW_HEART_BEAT_SOUND:
1954 g_heart_beat_sound = !g_heart_beat_sound;
1955 ShootSnd();
1956 DrawSwitchMenu();
1957 break;
1958
1959 case SW_ROTATED_AUTOMAP:
1960 g_rotated_automap = !g_rotated_automap;
1961 ShootSnd();
1962 DrawSwitchMenu();
1963 break;
1964 }
1965 } while (which >= 0);
1966
1967 ::MenuFadeOut();
1968 }
1969
DrawSwitchMenu()1970 void DrawSwitchMenu()
1971 {
1972 CA_CacheScreen(BACKGROUND_SCREENPIC);
1973
1974 ClearMScreen();
1975 DrawMenuTitle("GAME SWITCHES");
1976 DrawInstructions(IT_STANDARD);
1977
1978 fontnumber = 2;
1979
1980 DrawMenu(&SwitchItems, &SwitchMenu[0]);
1981 DrawAllSwitchLights(SwitchItems.curpos);
1982
1983 VW_UpdateScreen();
1984 }
1985
DrawAllSwitchLights(int16_t which)1986 void DrawAllSwitchLights(
1987 int16_t which)
1988 {
1989 int16_t i;
1990 uint16_t Shape;
1991
1992 for (i = 0; i < SwitchItems.amount; i++) {
1993 if (SwitchMenu[i].string[0]) {
1994 Shape = C_NOTSELECTEDPIC;
1995
1996 //
1997 // DRAW SELECTED/NOT SELECTED GRAPHIC BUTTONS
1998 //
1999
2000 if (SwitchItems.cursor.on) {
2001 if (i == which) { // Is the cursor sitting on this pic?
2002 Shape += 2;
2003 }
2004 }
2005
2006 switch (i) {
2007 case SW_LIGHTING:
2008 if (gamestate.flags & GS_LIGHTING) {
2009 Shape++;
2010 }
2011 break;
2012
2013 case SW_REBA_ATTACK_INFO:
2014 if (gamestate.flags & GS_ATTACK_INFOAREA) {
2015 Shape++;
2016 }
2017 break;
2018
2019 case SW_CEILING:
2020 if (gamestate.flags & GS_DRAW_CEILING) {
2021 Shape++;
2022 }
2023 break;
2024
2025 case SW_FLOORS:
2026 if (gamestate.flags & GS_DRAW_FLOOR) {
2027 Shape++;
2028 }
2029 break;
2030
2031 // BBi
2032 case SW_NO_WALL_HIT_SOUND:
2033 if (g_no_wall_hit_sound) {
2034 ++Shape;
2035 }
2036 break;
2037
2038 case SW_MODERN_CONTROLS:
2039 if (in_use_modern_bindings) {
2040 ++Shape;
2041 }
2042 break;
2043
2044 case SW_ALWAYS_RUN:
2045 if (g_always_run) {
2046 ++Shape;
2047 }
2048 break;
2049
2050 case SW_HEART_BEAT_SOUND:
2051 if (g_heart_beat_sound) {
2052 ++Shape;
2053 }
2054 break;
2055
2056 case SW_ROTATED_AUTOMAP:
2057 if (g_rotated_automap) {
2058 ++Shape;
2059 }
2060 break;
2061 }
2062
2063 VWB_DrawPic(SwitchItems.x - 16, SwitchItems.y + i * SwitchItems.y_spacing - 1, Shape);
2064 }
2065 }
2066
2067 DrawSwitchDescription(which);
2068
2069 }
2070
DrawSwitchDescription(int16_t which)2071 void DrawSwitchDescription(
2072 int16_t which)
2073 {
2074 const char* instr[] = {
2075 "TOGGLES LIGHT SOURCING IN HALLWAYS",
2076 "TOGGLES DETAILED ATTACKER INFO",
2077 "TOGGLES CEILING MAPPING",
2078 "TOGGLES FLOOR MAPPING",
2079
2080 // BBi
2081 "TOGGLES WALL HIT SOUND",
2082 "TOGGLES BETWEEN CLASSIC AND MODERN CONTROLS",
2083 "TOGGLES ALWAYS RUN MODE",
2084 "TOGGLES HEART BEAT SOUND WITH EKG",
2085 "TOGGLES <TAB>/<SHIFT+TAB> FUNCTIONS",
2086 };
2087
2088 fontnumber = 2;
2089
2090 WindowX = 48;
2091 WindowY = (::is_ps() ? 134 : 144);
2092 WindowW = 236;
2093 WindowH = 8;
2094
2095 VWB_Bar(WindowX, WindowY - 1, WindowW, WindowH, ::menu_background_color);
2096
2097 SETFONTCOLOR(TERM_SHADOW_COLOR, TERM_BACK_COLOR);
2098 US_PrintCentered(instr[which]);
2099
2100 WindowX--;
2101 WindowY--;
2102
2103 SETFONTCOLOR(INSTRUCTIONS_TEXT_COLOR, TERM_BACK_COLOR);
2104 US_PrintCentered(instr[which]);
2105 }
2106
CP_Sound(int16_t)2107 void CP_Sound(
2108 int16_t)
2109 {
2110 int16_t which;
2111
2112 CA_CacheScreen(BACKGROUND_SCREENPIC);
2113 DrawSoundMenu();
2114 MenuFadeIn();
2115 WaitKeyUp();
2116
2117 do {
2118 which = HandleMenu(&SndItems, &SndMenu[0], DrawAllSoundLights);
2119 //
2120 // HANDLE MENU CHOICES
2121 //
2122 switch (which) {
2123 //
2124 // SOUND EFFECTS / DIGITIZED SOUND
2125 //
2126 case 0:
2127 if (::sd_is_sound_enabled) {
2128 ::SD_WaitSoundDone();
2129 ::SD_EnableSound(false);
2130 ::DrawSoundMenu();
2131 }
2132 break;
2133
2134 case 1:
2135 if (!::sd_is_sound_enabled) {
2136 ::SD_WaitSoundDone();
2137 ::SD_EnableSound(true);
2138 ::CA_LoadAllSounds();
2139 ::DrawSoundMenu();
2140 ::ShootSnd();
2141 }
2142 break;
2143
2144 //
2145 // MUSIC
2146 //
2147 case 4:
2148 if (::sd_is_music_enabled) {
2149 ::SD_EnableMusic(false);
2150 ::DrawSoundMenu();
2151 ::ShootSnd();
2152 }
2153 break;
2154
2155 case 5:
2156 if (!::sd_is_music_enabled) {
2157 ::SD_EnableMusic(true);
2158 ::DrawSoundMenu();
2159 ::ShootSnd();
2160 ::StartCPMusic(MENUSONG);
2161 }
2162 break;
2163 }
2164 } while (which >= 0);
2165
2166 ::MenuFadeOut();
2167 }
2168
DrawSoundMenu()2169 void DrawSoundMenu()
2170 {
2171 //
2172 // DRAW SOUND MENU
2173 //
2174
2175 ClearMScreen();
2176 DrawMenuTitle("SOUND SETTINGS");
2177 DrawInstructions(IT_STANDARD);
2178
2179 //
2180 // IF NO ADLIB, NON-CHOOSENESS!
2181 //
2182
2183 if (!::sd_has_audio) {
2184 ::SndMenu[1].active = AT_DISABLED;
2185 ::SndMenu[5].active = AT_DISABLED;
2186 }
2187
2188 fontnumber = 4;
2189
2190 SETFONTCOLOR(DISABLED_TEXT_COLOR, TERM_BACK_COLOR);
2191 ShadowPrint("SOUND EFFECTS", 105, 72);
2192 ShadowPrint("BACKGROUND MUSIC", 105, 100);
2193
2194 fontnumber = 2;
2195 DrawMenu(&SndItems, &SndMenu[0]);
2196
2197
2198 DrawAllSoundLights(SndItems.curpos);
2199
2200 VW_UpdateScreen();
2201 }
2202
DrawAllSoundLights(int16_t which)2203 void DrawAllSoundLights(
2204 int16_t which)
2205 {
2206 int16_t i;
2207 uint16_t Shape;
2208
2209 for (i = 0; i < SndItems.amount; i++) {
2210 if (SndMenu[i].string[0]) {
2211 Shape = C_NOTSELECTEDPIC;
2212
2213 //
2214 // DRAW SELECTED/NOT SELECTED GRAPHIC BUTTONS
2215 //
2216
2217 if (SndItems.cursor.on) {
2218 if (i == which) { // Is the cursor sitting on this pic?
2219 Shape += 2;
2220 }
2221 }
2222
2223 switch (i) {
2224 //
2225 // SOUND EFFECTS / DIGITIZED SOUND
2226 //
2227 case 0:
2228 if (!::sd_is_sound_enabled) {
2229 ++Shape;
2230 }
2231 break;
2232
2233 case 1:
2234 if (::sd_is_sound_enabled) {
2235 ++Shape;
2236 }
2237 break;
2238
2239 //
2240 // MUSIC
2241 //
2242 case 4:
2243 if (!::sd_is_music_enabled) {
2244 ++Shape;
2245 }
2246 break;
2247
2248 case 5:
2249 if (::sd_is_music_enabled) {
2250 ++Shape;
2251 }
2252 break;
2253 }
2254
2255 VWB_DrawPic(SndItems.x - 16, SndItems.y + i * SndItems.y_spacing - 1, Shape);
2256 }
2257 }
2258 }
2259
2260 char LOADSAVE_GAME_MSG[2][25] = { "^ST1^CELoading Game\r^XX",
2261 "^ST1^CESaving Game\r^XX" };
2262
2263 extern int8_t LS_current, LS_total;
2264
2265 // --------------------------------------------------------------------------
2266 // DrawLSAction() - DRAW LOAD/SAVE IN PROGRESS
2267 // --------------------------------------------------------------------------
DrawLSAction(int16_t which)2268 void DrawLSAction(
2269 int16_t which)
2270 {
2271 int8_t total[] = { 19, 19 };
2272
2273 VW_FadeOut();
2274 screenfaded = true;
2275 DrawTopInfo(static_cast<sp_type>(sp_loading + which));
2276
2277 ::VL_Bar(
2278 0,
2279 ::ref_view_top,
2280 ::vga_ref_width,
2281 ::ref_view_height,
2282 BLACK);
2283
2284 DisplayPrepingMsg(LOADSAVE_GAME_MSG[which]);
2285
2286 if (which) {
2287 PreloadUpdate(1, 1); // GFX: bar is full when saving...
2288
2289 }
2290 LS_current = 1;
2291 LS_total = total[which];
2292 WindowY = 181;
2293 }
2294
CP_LoadGame(int16_t quick)2295 int16_t CP_LoadGame(
2296 int16_t quick)
2297 {
2298 int16_t which;
2299 int16_t exit = 0;
2300
2301 //
2302 // QUICKLOAD?
2303 //
2304 if (quick) {
2305 which = LSItems.curpos;
2306
2307 if (SaveGamesAvail[which]) {
2308 auto name = ::get_saved_game_base_name();
2309 name += static_cast<char>('0' + which);
2310
2311 DrawLSAction(0); // Testing...
2312
2313 auto name_path = ::get_profile_dir() + name;
2314
2315 loadedgame = ::LoadTheGame(name_path);
2316
2317 if (!loadedgame) {
2318 LS_current = -1; // clean up
2319 }
2320
2321 return loadedgame;
2322 }
2323 }
2324
2325 restart:
2326
2327 DrawLoadSaveScreen(0);
2328
2329 do {
2330 which = HandleMenu(&LSItems, &LSMenu[0], TrackWhichGame);
2331
2332 if (which >= 0 && SaveGamesAvail[which]) {
2333 ShootSnd();
2334
2335 auto name = ::get_saved_game_base_name();
2336 name += static_cast<char>('0' + which);
2337
2338 auto name_path = ::get_profile_dir() + name;
2339
2340 DrawLSAction(0);
2341
2342 if (!::LoadTheGame(name_path)) {
2343 exit = 0;
2344 StartGame = 0;
2345 loadedgame = 0;
2346 LS_current = -1; // Clean up
2347 ::playstate = ex_abort;
2348 goto restart;
2349 }
2350
2351 loadedgame = true;
2352 StartGame = true;
2353
2354 ::ShootSnd();
2355
2356 //
2357 // CHANGE "READ THIS!" TO NORMAL COLOR
2358 //
2359 MainMenu[MM_READ_THIS].active = AT_ENABLED;
2360 exit = 1;
2361 break;
2362 }
2363 } while (which >= 0);
2364
2365 if (which == -1) {
2366 ::MenuFadeOut();
2367 }
2368
2369 if (loadedgame) {
2370 refresh_screen = false;
2371 }
2372
2373 return exit;
2374 }
2375
2376
2377 ///////////////////////////////////
2378 //
2379 // HIGHLIGHT CURRENT SELECTED ENTRY
2380 //
TrackWhichGame(int16_t w)2381 void TrackWhichGame(
2382 int16_t w)
2383 {
2384 static int16_t lastgameon = 0;
2385
2386 PrintLSEntry(lastgameon, ENABLED_TEXT_COLOR);
2387 PrintLSEntry(w, HIGHLIGHT_TEXT_COLOR);
2388
2389 lastgameon = w;
2390 }
2391
DrawLoadSaveScreen(int16_t loadsave)2392 void DrawLoadSaveScreen(
2393 int16_t loadsave)
2394 {
2395 int16_t i;
2396
2397 CA_CacheScreen(BACKGROUND_SCREENPIC);
2398 ClearMScreen();
2399
2400 fontnumber = 1;
2401
2402 if (!loadsave) {
2403 DrawMenuTitle("Load Mission");
2404 } else {
2405 DrawMenuTitle("Save Mission");
2406 }
2407
2408 DrawInstructions(IT_STANDARD);
2409
2410 for (i = 0; i < 10; i++) {
2411 PrintLSEntry(i, ENABLED_TEXT_COLOR);
2412 }
2413
2414 fontnumber = 4;
2415 DrawMenu(&LSItems, &LSMenu[0]);
2416
2417 VW_UpdateScreen();
2418 MenuFadeIn();
2419 WaitKeyUp();
2420 }
2421
2422 // --------------------------------------------------------------------------
2423 // PRINT LOAD/SAVE GAME ENTRY W/BOX OUTLINE
2424 // --------------------------------------------------------------------------
PrintLSEntry(int16_t w,int16_t color)2425 void PrintLSEntry(
2426 int16_t w,
2427 int16_t color)
2428 {
2429 SETFONTCOLOR(color, BKGDCOLOR);
2430 DrawOutline(LSM_X + LSItems.indent, LSM_Y + w * LSItems.y_spacing - 2, LSM_W - LSItems.indent, 8, color, color);
2431
2432 fontnumber = 2;
2433
2434 PrintX = LSM_X + LSItems.indent + 2;
2435 PrintY = LSM_Y + w * LSItems.y_spacing;
2436
2437 if (SaveGamesAvail[w]) {
2438 US_Print(SaveGameNames[w]);
2439 } else {
2440 US_Print(" ----- EMPTY -----");
2441 }
2442
2443 fontnumber = 1;
2444 }
2445
CP_SaveGame(int16_t quick)2446 int16_t CP_SaveGame(
2447 int16_t quick)
2448 {
2449 int16_t which, exit = 0;
2450 char input[GAME_DESCRIPTION_LEN + 1];
2451 bool temp_caps = allcaps;
2452 US_CursorStruct TermCursor = { '@', 0, HIGHLIGHT_TEXT_COLOR, 2 };
2453
2454 allcaps = true;
2455 use_custom_cursor = true;
2456 US_CustomCursor = TermCursor;
2457
2458 //
2459 // QUICKSAVE?
2460 //
2461 if (quick) {
2462 which = LSItems.curpos;
2463
2464 if (SaveGamesAvail[which]) {
2465 DrawLSAction(1); // Testing...
2466 auto name = ::get_saved_game_base_name();
2467 name += static_cast<char>('0' + which);
2468
2469 auto name_path = ::get_profile_dir() + name;
2470
2471 ::SaveTheGame(name_path, &SaveGameNames[which][0]);
2472
2473 return 1;
2474 }
2475 }
2476
2477 DrawLoadSaveScreen(1);
2478
2479 do {
2480 which = HandleMenu(&LSItems, &LSMenu[0], TrackWhichGame);
2481 if (which >= 0) {
2482 //
2483 // OVERWRITE EXISTING SAVEGAME?
2484 //
2485 if (SaveGamesAvail[which]) {
2486 if (!Confirm(GAMESVD)) {
2487 DrawLoadSaveScreen(1);
2488 continue;
2489 } else {
2490 DrawLoadSaveScreen(1);
2491 PrintLSEntry(which, HIGHLIGHT_TEXT_COLOR);
2492 VW_UpdateScreen();
2493 }
2494 }
2495
2496 ShootSnd();
2497
2498 strcpy(input, &SaveGameNames[which][0]);
2499
2500 auto name = ::get_saved_game_base_name();
2501 name += static_cast<char>('0' + which);
2502
2503 fontnumber = 2;
2504 VWB_Bar(LSM_X + LSItems.indent + 1, LSM_Y + which * LSItems.y_spacing - 1, LSM_W - LSItems.indent - 1, 7, HIGHLIGHT_BOX_COLOR);
2505 SETFONTCOLOR(HIGHLIGHT_TEXT_COLOR, HIGHLIGHT_BOX_COLOR);
2506 VW_UpdateScreen();
2507
2508
2509 if (US_LineInput(LSM_X + LSItems.indent + 2, LSM_Y + which * LSItems.y_spacing, input, input, true, GAME_DESCRIPTION_LEN, LSM_W - LSItems.indent - 10)) {
2510 SaveGamesAvail[which] = 1;
2511 strcpy(&SaveGameNames[which][0], input);
2512
2513 DrawLSAction(1);
2514
2515 auto name_path = ::get_profile_dir() + name;
2516 ::SaveTheGame(name_path, input);
2517
2518 ShootSnd();
2519 exit = 1;
2520 } else {
2521 VWB_Bar(
2522 LSM_X + LSItems.indent + 1,
2523 LSM_Y + which * LSItems.y_spacing - 1,
2524 LSM_W - LSItems.indent - 1,
2525 7,
2526 ::menu_background_color);
2527
2528 PrintLSEntry(which, HIGHLIGHT_TEXT_COLOR);
2529 VW_UpdateScreen();
2530 ::sd_play_player_sound(ESCPRESSEDSND, bstone::AC_ITEM);
2531 continue;
2532 }
2533
2534 fontnumber = 1;
2535 break;
2536 }
2537
2538 } while (which >= 0);
2539
2540 ::MenuFadeOut();
2541 use_custom_cursor = false;
2542 allcaps = temp_caps;
2543 return exit;
2544 }
2545
CP_ExitOptions(int16_t)2546 void CP_ExitOptions(
2547 int16_t)
2548 {
2549 StartGame = 1;
2550 }
2551
CP_Control(int16_t)2552 void CP_Control(
2553 int16_t)
2554 {
2555 enum {MOUSEENABLE, JOYENABLE, USEPORT2, PADENABLE, CALIBRATEJOY, MOUSESENS, CUSTOMIZE};
2556
2557 int16_t which;
2558
2559 CA_CacheScreen(BACKGROUND_SCREENPIC);
2560
2561 DrawCtlScreen();
2562 MenuFadeIn();
2563 WaitKeyUp();
2564
2565 do {
2566 which = HandleMenu(&CtlItems, &CtlMenu[0], nullptr);
2567 switch (which) {
2568 case MOUSEENABLE:
2569 ::mouseenabled = !::mouseenabled;
2570
2571 DrawCtlScreen();
2572 CusItems.curpos = -1;
2573 ShootSnd();
2574 break;
2575
2576 case JOYENABLE:
2577 ::joystickenabled = !::joystickenabled;
2578 if (joystickenabled) {
2579 CalibrateJoystick();
2580 }
2581 DrawCtlScreen();
2582 CusItems.curpos = -1;
2583 ShootSnd();
2584 break;
2585
2586 case USEPORT2:
2587 joystickport ^= 1;
2588 DrawCtlScreen();
2589 ShootSnd();
2590 break;
2591
2592 case PADENABLE:
2593 ::joypadenabled = !::joypadenabled;
2594 DrawCtlScreen();
2595 ShootSnd();
2596 break;
2597
2598 case CALIBRATEJOY:
2599 CalibrateJoystick();
2600 DrawCtlScreen();
2601 break;
2602
2603
2604 case MOUSESENS:
2605 case CUSTOMIZE:
2606 DrawCtlScreen();
2607 MenuFadeIn();
2608 WaitKeyUp();
2609 break;
2610 }
2611 } while (which >= 0);
2612
2613 ::MenuFadeOut();
2614 }
2615
DrawMousePos()2616 void DrawMousePos()
2617 {
2618 const int thumb_width = 16;
2619 const int track_width = 160;
2620 const int slide_width = track_width - thumb_width;
2621 const int max_mouse_delta = ::max_mouse_sensitivity - ::min_mouse_sensitivity;
2622
2623 ::VWB_Bar(
2624 74,
2625 92,
2626 track_width,
2627 8,
2628 HIGHLIGHT_BOX_COLOR);
2629
2630 ::DrawOutline(
2631 73,
2632 91,
2633 track_width + 1,
2634 9,
2635 ENABLED_TEXT_COLOR,
2636 ENABLED_TEXT_COLOR);
2637
2638 ::VWB_Bar(
2639 74 + ((slide_width * ::mouseadjustment) / max_mouse_delta),
2640 92,
2641 thumb_width,
2642 8,
2643 HIGHLIGHT_TEXT_COLOR);
2644 }
2645
DrawMouseSens()2646 void DrawMouseSens()
2647 {
2648 ClearMScreen();
2649 DrawMenuTitle("MOUSE SENSITIVITY");
2650 DrawInstructions(IT_MOUSE_SEN);
2651
2652 fontnumber = 4;
2653
2654 SETFONTCOLOR(HIGHLIGHT_TEXT_COLOR, TERM_BACK_COLOR);
2655 PrintX = 36;
2656 PrintY = 91;
2657 US_Print("SLOW");
2658 PrintX = 242;
2659 US_Print("FAST");
2660
2661 DrawMousePos();
2662
2663 VW_UpdateScreen();
2664 MenuFadeIn();
2665 }
2666
CalibrateJoystick()2667 void CalibrateJoystick()
2668 {
2669 uint16_t minx, maxx, miny, maxy;
2670
2671 CacheMessage(CALJOY1_TEXT);
2672 VW_UpdateScreen();
2673
2674 while (IN_GetJoyButtonsDB(joystickport)) {
2675 }
2676 while ((LastScan != ScanCode::sc_escape) && !IN_GetJoyButtonsDB(joystickport)) {
2677 }
2678 if (LastScan == ScanCode::sc_escape) {
2679 return;
2680 }
2681
2682 IN_GetJoyAbs(joystickport, &minx, &miny);
2683 while (IN_GetJoyButtonsDB(joystickport)) {
2684 }
2685
2686 CacheMessage(CALJOY2_TEXT);
2687 VW_UpdateScreen();
2688
2689 while ((LastScan != ScanCode::sc_escape) && !IN_GetJoyButtonsDB(joystickport)) {
2690 }
2691 if (LastScan == ScanCode::sc_escape) {
2692 return;
2693 }
2694
2695 IN_GetJoyAbs(joystickport, &maxx, &maxy);
2696 if ((minx == maxx) || (miny == maxy)) {
2697 return;
2698 }
2699
2700 IN_SetupJoy(joystickport, minx, maxx, miny, maxy);
2701 while (IN_GetJoyButtonsDB(joystickport)) {
2702 }
2703
2704 IN_ClearKeysDown();
2705 JoystickCalibrated = true;
2706 }
2707
MouseSensitivity(int16_t)2708 void MouseSensitivity(
2709 int16_t)
2710 {
2711 ControlInfo ci;
2712 int16_t exit = 0;
2713
2714 const auto oldMA = ::mouseadjustment;
2715
2716 DrawMouseSens();
2717 do {
2718 ReadAnyControl(&ci);
2719 switch (ci.dir) {
2720 case dir_North:
2721 case dir_West:
2722 if (::mouseadjustment > 0) {
2723 ::mouseadjustment -= 1;
2724 DrawMousePos();
2725 VW_UpdateScreen();
2726 ::sd_play_player_sound(MOVEGUN1SND, bstone::AC_ITEM);
2727
2728 while (Keyboard[ScanCode::sc_left_arrow]) {
2729 ::in_handle_events();
2730 }
2731
2732 WaitKeyUp();
2733 }
2734 break;
2735
2736 case dir_South:
2737 case dir_East:
2738 if (::mouseadjustment < ::max_mouse_sensitivity)
2739 {
2740 ::mouseadjustment += 1;
2741 DrawMousePos();
2742 VW_UpdateScreen();
2743 ::sd_play_player_sound(MOVEGUN1SND, bstone::AC_ITEM);
2744
2745 while (Keyboard[ScanCode::sc_right_arrow]) {
2746 ::in_handle_events();
2747 }
2748
2749 WaitKeyUp();
2750 }
2751 break;
2752
2753 default:
2754 break;
2755 }
2756
2757 if (ci.button0 || Keyboard[ScanCode::sc_space] || Keyboard[ScanCode::sc_return]) {
2758 exit = 1;
2759 } else if (ci.button1 || Keyboard[ScanCode::sc_escape]) {
2760 exit = 2;
2761 }
2762
2763 } while (!exit);
2764
2765 if (exit == 2) {
2766 ::mouseadjustment = oldMA;
2767 ::sd_play_player_sound(ESCPRESSEDSND, bstone::AC_ITEM);
2768 } else {
2769 ::sd_play_player_sound(SHOOTSND, bstone::AC_ITEM);
2770 }
2771
2772 WaitKeyUp();
2773 ::MenuFadeOut();
2774 }
2775
2776 // --------------------------------------------------------------------------
2777 // DrawCtlScreen() - DRAW CONTROL MENU SCREEN
2778 // --------------------------------------------------------------------------
DrawCtlScreen()2779 void DrawCtlScreen()
2780 {
2781 const int16_t Y_CTL_PIC_OFS = 3;
2782
2783 int16_t i;
2784 int16_t x;
2785 int16_t y;
2786
2787 ClearMScreen();
2788 DrawMenuTitle("CONTROL");
2789 DrawInstructions(IT_STANDARD);
2790
2791 WindowX = 0;
2792 WindowW = 320;
2793 SETFONTCOLOR(TEXTCOLOR, BKGDCOLOR);
2794
2795 if (JoysPresent[0]) {
2796 CtlMenu[1].active = AT_ENABLED;
2797 CtlMenu[2].active = AT_ENABLED;
2798 CtlMenu[3].active = AT_ENABLED;
2799 CtlMenu[4].active = AT_ENABLED;
2800 }
2801
2802 CtlMenu[2].active = CtlMenu[3].active = CtlMenu[4].active = static_cast<activetypes>(joystickenabled);
2803
2804 if (MousePresent) {
2805 CtlMenu[0].active = AT_ENABLED;
2806 CtlMenu[5].active = AT_ENABLED;
2807 }
2808
2809 CtlMenu[5].active = static_cast<activetypes>(mouseenabled);
2810
2811 fontnumber = 4;
2812 DrawMenu(&CtlItems, &CtlMenu[0]);
2813
2814 x = CTL_X + CtlItems.indent - 24;
2815 y = CTL_Y + Y_CTL_PIC_OFS;
2816 if (mouseenabled) {
2817 VWB_DrawPic(x, y, C_SELECTEDPIC);
2818 } else {
2819 VWB_DrawPic(x, y, C_NOTSELECTEDPIC);
2820 }
2821
2822 y = CTL_Y + 9 + Y_CTL_PIC_OFS;
2823 if (joystickenabled) {
2824 VWB_DrawPic(x, y, C_SELECTEDPIC);
2825 } else {
2826 VWB_DrawPic(x, y, C_NOTSELECTEDPIC);
2827 }
2828
2829 y = CTL_Y + 9 * 2 + Y_CTL_PIC_OFS;
2830 if (joystickport) {
2831 VWB_DrawPic(x, y, C_SELECTEDPIC);
2832 } else {
2833 VWB_DrawPic(x, y, C_NOTSELECTEDPIC);
2834 }
2835
2836 y = CTL_Y + 9 * 3 + Y_CTL_PIC_OFS;
2837 if (joypadenabled) {
2838 VWB_DrawPic(x, y, C_SELECTEDPIC);
2839 } else {
2840 VWB_DrawPic(x, y, C_NOTSELECTEDPIC);
2841 }
2842
2843 //
2844 // PICK FIRST AVAILABLE SPOT
2845 //
2846
2847 if (CtlItems.curpos < 0 || !CtlMenu[static_cast<int>(CtlItems.curpos)].active) {
2848 for (i = 0; i < CtlItems.amount; ++i) {
2849 if (CtlMenu[i].active) {
2850 CtlItems.curpos = static_cast<int8_t>(i);
2851 break;
2852 }
2853 }
2854 }
2855
2856 DrawMenuGun(&CtlItems);
2857 VW_UpdateScreen();
2858 }
2859
2860 enum ControlButton1 {
2861 FIRE,
2862 STRAFE,
2863 RUN,
2864 OPEN
2865 }; // ControlButton1
2866
2867 char mbarray[4][3] = { "B0", "B1", "B2", "B3" };
2868 int order[4] = { RUN, OPEN, FIRE, STRAFE, };
2869
CustomControls(int16_t)2870 void CustomControls(
2871 int16_t)
2872 {
2873 if (in_use_modern_bindings) {
2874 binds_draw_menu();
2875 return;
2876 }
2877
2878 int16_t which;
2879
2880 DrawCustomScreen();
2881
2882 do {
2883 which = HandleMenu(&CusItems, &CusMenu[0], FixupCustom);
2884
2885 switch (which) {
2886 case 0:
2887 DefineMouseBtns();
2888 DrawCustMouse(1);
2889 break;
2890
2891 case 2:
2892 DefineJoyBtns();
2893 DrawCustJoy(0);
2894 break;
2895
2896 case 4:
2897 DefineKeyBtns();
2898 DrawCustKeybd(0);
2899 break;
2900
2901 case 5:
2902 DefineKeyMove();
2903 DrawCustKeys(0);
2904 }
2905 } while (which >= 0);
2906
2907
2908
2909 ::MenuFadeOut();
2910 }
2911
DefineMouseBtns()2912 void DefineMouseBtns()
2913 {
2914 CustomCtrls mouseallowed = { 1, 1, 1, 1 };
2915 EnterCtrlData(2, &mouseallowed, DrawCustMouse, PrintCustMouse, MOUSE);
2916 }
2917
DefineJoyBtns()2918 void DefineJoyBtns()
2919 {
2920 CustomCtrls joyallowed = { 1, 1, 1, 1 };
2921 EnterCtrlData(5, &joyallowed, DrawCustJoy, PrintCustJoy, JOYSTICK);
2922 }
2923
DefineKeyBtns()2924 void DefineKeyBtns()
2925 {
2926 CustomCtrls keyallowed = { 1, 1, 1, 1 };
2927 EnterCtrlData(8, &keyallowed, DrawCustKeybd, PrintCustKeybd, KEYBOARDBTNS);
2928 }
2929
DefineKeyMove()2930 void DefineKeyMove()
2931 {
2932 CustomCtrls keyallowed = { 1, 1, 1, 1 };
2933 EnterCtrlData(10, &keyallowed, DrawCustKeys, PrintCustKeys, KEYBOARDMOVE);
2934 }
2935
TestForValidKey(ScanCode Scan)2936 bool TestForValidKey(
2937 ScanCode Scan)
2938 {
2939 auto found = false;
2940
2941 auto it = std::find(buttonscan.begin(), buttonscan.end(), Scan);
2942
2943 if (it == buttonscan.end()) {
2944 it = std::find(dirscan.begin(), dirscan.end(), Scan);
2945
2946 found = (it != dirscan.end());
2947 }
2948
2949 if (found) {
2950 *it = ScanCode::sc_none;
2951 ::sd_play_player_sound(SHOOTDOORSND, bstone::AC_ITEM);
2952 ::DrawCustomScreen();
2953 }
2954
2955 return !found;
2956 }
2957
2958
2959 enum ControlButton2 {
2960 FWRD,
2961 RIGHT,
2962 BKWD,
2963 LEFT
2964 }; // ControlButton2
2965
2966 int16_t moveorder[4] = { LEFT, RIGHT, FWRD, BKWD };
2967
2968 // --------------------------------------------------------------------------
2969 // EnterCtrlData() - ENTER CONTROL DATA FOR ANY TYPE OF CONTROL
2970 // --------------------------------------------------------------------------
EnterCtrlData(int16_t index,CustomCtrls * cust,void (* DrawRtn)(int16_t),void (* PrintRtn)(int16_t),int16_t type)2971 void EnterCtrlData(
2972 int16_t index,
2973 CustomCtrls* cust,
2974 void (* DrawRtn)(int16_t),
2975 void (* PrintRtn)(int16_t),
2976 int16_t type)
2977 {
2978 int16_t j;
2979 int16_t exit;
2980 int16_t tick;
2981 int16_t redraw;
2982 int16_t which = 0;
2983 int16_t x = 0;
2984 int16_t picked;
2985 ControlInfo ci;
2986 bool clean_display = true;
2987
2988 ShootSnd();
2989 PrintY = CST_Y + 13 * index;
2990 IN_ClearKeysDown();
2991 exit = 0;
2992 redraw = 1;
2993
2994 CA_CacheGrChunk(STARTFONT + fontnumber);
2995
2996 //
2997 // FIND FIRST SPOT IN ALLOWED ARRAY
2998 //
2999 for (j = 0; j < 4; j++) {
3000 if (cust->allowed[j]) {
3001 which = j;
3002 break;
3003 }
3004 }
3005
3006 do {
3007 if (redraw) {
3008 x = CST_START + CST_SPC * which;
3009 DrawRtn(1);
3010
3011 VWB_Bar(x - 1, PrintY - 1, CST_SPC, 7, HIGHLIGHT_BOX_COLOR);
3012 SETFONTCOLOR(HIGHLIGHT_TEXT_COLOR, HIGHLIGHT_BOX_COLOR);
3013 PrintRtn(which);
3014 PrintX = x;
3015 SETFONTCOLOR(HIGHLIGHT_TEXT_COLOR, TERM_BACK_COLOR);
3016 VW_UpdateScreen();
3017 WaitKeyUp();
3018 redraw = 0;
3019 }
3020
3021 ReadAnyControl(&ci);
3022
3023 if (type == MOUSE || type == JOYSTICK) {
3024 if (IN_KeyDown(ScanCode::sc_return) || IN_KeyDown(ScanCode::sc_control) || IN_KeyDown(ScanCode::sc_alt)) {
3025 IN_ClearKeysDown();
3026 ci.button0 = ci.button1 = false;
3027 }
3028 }
3029
3030 //
3031 // CHANGE BUTTON VALUE?
3032 //
3033
3034 if ((ci.button0 | ci.button1 | ci.button2 | ci.button3) ||
3035 ((type == KEYBOARDBTNS || type == KEYBOARDMOVE) && LastScan == ScanCode::sc_return))
3036 {
3037 tick = 0;
3038 TimeCount = 0;
3039 picked = 0;
3040 SETFONTCOLOR(HIGHLIGHT_TEXT_COLOR, HIGHLIGHT_BOX_COLOR);
3041
3042 do {
3043 int16_t button, result = 0;
3044
3045 if (type == KEYBOARDBTNS || type == KEYBOARDMOVE) {
3046 IN_ClearKeysDown();
3047 }
3048
3049 // BBi
3050 ::in_handle_events();
3051
3052 //
3053 // FLASH CURSOR
3054 //
3055
3056 if (TimeCount > 10) {
3057 switch (tick) {
3058 case 0:
3059 VWB_Bar(x - 1, PrintY - 1, CST_SPC, 7, HIGHLIGHT_BOX_COLOR);
3060 break;
3061
3062 case 1:
3063 PrintX = x;
3064 US_Print("?");
3065
3066 ::sd_play_player_sound(
3067 HITWALLSND, bstone::AC_ITEM);
3068 }
3069
3070 tick ^= 1;
3071 TimeCount = 0;
3072 VW_UpdateScreen();
3073 }
3074
3075 //
3076 // WHICH TYPE OF INPUT DO WE PROCESS?
3077 //
3078
3079 switch (type) {
3080 case MOUSE:
3081 button = ::IN_MouseButtons();
3082
3083 switch (button) {
3084 case 1: result = 1;
3085 break;
3086 case 2: result = 2;
3087 break;
3088 case 4: result = 3;
3089 break;
3090 }
3091
3092 if (result) {
3093 int16_t z;
3094
3095 for (z = 0; z < 4; z++) {
3096 if (order[which] == buttonmouse[z]) {
3097 buttonmouse[z] = bt_nobutton;
3098 break;
3099 }
3100 }
3101
3102 buttonmouse[result - 1] = static_cast<int16_t>(order[which]);
3103 picked = 1;
3104
3105 ::sd_play_player_sound(
3106 SHOOTDOORSND, bstone::AC_ITEM);
3107
3108 clean_display = false;
3109 }
3110 break;
3111
3112 case JOYSTICK:
3113 if (ci.button0) {
3114 result = 1;
3115 } else if (ci.button1) {
3116 result = 2;
3117 } else if (ci.button2) {
3118 result = 3;
3119 } else if (ci.button3) {
3120 result = 4;
3121 }
3122
3123 if (result) {
3124 int16_t z;
3125
3126 for (z = 0; z < 4; z++) {
3127 if (order[which] == buttonjoy[z]) {
3128 buttonjoy[z] = bt_nobutton;
3129 break;
3130 }
3131 }
3132
3133 buttonjoy[result - 1] = static_cast<int16_t>(order[which]);
3134 picked = 1;
3135
3136 ::sd_play_player_sound(SHOOTDOORSND, bstone::AC_ITEM);
3137
3138 clean_display = false;
3139 }
3140 break;
3141
3142 case KEYBOARDBTNS:
3143 if (LastScan != ScanCode::sc_none) {
3144 if (LastScan == ScanCode::sc_escape) {
3145 break;
3146 }
3147
3148 auto it = std::find(
3149 special_keys.cbegin(),
3150 special_keys.cend(),
3151 LastScan);
3152
3153 if (it != special_keys.cend()) {
3154 ::sd_play_player_sound(NOWAYSND, bstone::AC_ITEM);
3155 } else {
3156 clean_display = TestForValidKey(LastScan);
3157
3158 if (clean_display) {
3159 ShootSnd();
3160 }
3161
3162 buttonscan[order[which]] = LastScan;
3163
3164 picked = 1;
3165 }
3166 IN_ClearKeysDown();
3167 }
3168 break;
3169
3170
3171 case KEYBOARDMOVE:
3172 if (LastScan != ScanCode::sc_none) {
3173 if (LastScan == ScanCode::sc_escape) {
3174 break;
3175 }
3176
3177 auto it = std::find(
3178 special_keys.cbegin(),
3179 special_keys.cend(),
3180 LastScan);
3181
3182 if (it != special_keys.cend()) {
3183 ::sd_play_player_sound(NOWAYSND, bstone::AC_ITEM);
3184 } else {
3185 clean_display = TestForValidKey(LastScan);
3186
3187 if (clean_display) {
3188 ShootSnd();
3189 }
3190
3191 dirscan[moveorder[which]] = LastScan;
3192 picked = 1;
3193 }
3194 IN_ClearKeysDown();
3195 }
3196 break;
3197 }
3198
3199
3200 //
3201 // EXIT INPUT?
3202 //
3203
3204 if (IN_KeyDown(ScanCode::sc_escape)) {
3205 picked = 1;
3206 continue;
3207 }
3208
3209 } while (!picked);
3210
3211 if (!clean_display) {
3212 DrawCustomScreen();
3213 }
3214
3215 SETFONTCOLOR(HIGHLIGHT_TEXT_COLOR, TERM_BACK_COLOR);
3216 redraw = 1;
3217 WaitKeyUp();
3218 continue;
3219 }
3220
3221 if (ci.button1 || IN_KeyDown(ScanCode::sc_escape)) {
3222 exit = 1;
3223 }
3224
3225 //
3226 // MOVE TO ANOTHER SPOT?
3227 //
3228 switch (ci.dir) {
3229
3230 case dir_West:
3231 VWB_Bar(x - 1, PrintY - 1, CST_SPC, 7, ::menu_background_color);
3232 SETFONTCOLOR(HIGHLIGHT_TEXT_COLOR, TERM_BACK_COLOR);
3233 PrintRtn(which);
3234 do {
3235 which--;
3236 if (which < 0) {
3237 which = 3;
3238 }
3239 } while (!cust->allowed[which]);
3240
3241 redraw = 1;
3242
3243 ::sd_play_player_sound(MOVEGUN1SND, bstone::AC_ITEM);
3244
3245 while (ReadAnyControl(&ci), ci.dir != dir_None) {
3246 }
3247 IN_ClearKeysDown();
3248 break;
3249
3250
3251
3252 case dir_East:
3253 VWB_Bar(x - 1, PrintY - 1, CST_SPC, 7, ::menu_background_color);
3254 SETFONTCOLOR(HIGHLIGHT_TEXT_COLOR, TERM_BACK_COLOR);
3255 PrintRtn(which);
3256 do {
3257 which++;
3258 if (which > 3) {
3259 which = 0;
3260 }
3261 } while (!cust->allowed[which]);
3262
3263 redraw = 1;
3264
3265 ::sd_play_player_sound(MOVEGUN1SND, bstone::AC_ITEM);
3266
3267 while (ReadAnyControl(&ci), ci.dir != dir_None) {
3268 }
3269
3270 IN_ClearKeysDown();
3271 break;
3272
3273 case dir_North:
3274 case dir_South:
3275 exit = 1;
3276
3277 default:
3278 break;
3279 }
3280
3281 } while (!exit);
3282
3283 FREEFONT(STARTFONT + fontnumber);
3284
3285 ::sd_play_player_sound(ESCPRESSEDSND, bstone::AC_ITEM);
3286
3287 WaitKeyUp();
3288 }
3289
3290 // --------------------------------------------------------------------------
3291 // FIXUP GUN CURSOR OVERDRAW SHIT
3292 // --------------------------------------------------------------------------
FixupCustom(int16_t w)3293 void FixupCustom(
3294 int16_t w)
3295 {
3296 static int16_t lastwhich = -1;
3297
3298 switch (w) {
3299 case 0: DrawCustMouse(1);
3300 break;
3301 case 2: DrawCustJoy(1);
3302 break;
3303 case 4: DrawCustKeybd(1);
3304 break;
3305 case 5: DrawCustKeys(1);
3306 }
3307
3308
3309 if (lastwhich >= 0) {
3310 if (lastwhich != w) {
3311 switch (lastwhich) {
3312 case 0: DrawCustMouse(0);
3313 break;
3314 case 2: DrawCustJoy(0);
3315 break;
3316 case 4: DrawCustKeybd(0);
3317 break;
3318 case 5: DrawCustKeys(0);
3319 }
3320 }
3321 }
3322
3323 lastwhich = w;
3324 }
3325
DrawCustomScreen()3326 void DrawCustomScreen()
3327 {
3328 int16_t i;
3329
3330 ClearMScreen();
3331 DrawMenuTitle("CUSTOMIZE");
3332 DrawInstructions(IT_STANDARD);
3333
3334 //
3335 // MOUSE
3336 //
3337
3338 WindowX = 32;
3339 WindowW = 244;
3340
3341 fontnumber = 4;
3342
3343 SETFONTCOLOR(0x0C, TERM_BACK_COLOR);
3344
3345
3346 PrintY = 49;
3347 US_CPrint("MOUSE\n");
3348 PrintY = 79;
3349 US_CPrint("JOYSTICK/GRAVIS GAMEPAD\n");
3350 PrintY = 109;
3351 US_CPrint("KEYBOARD\n");
3352
3353 fontnumber = 2;
3354
3355 SETFONTCOLOR(DISABLED_TEXT_COLOR, TERM_BACK_COLOR);
3356
3357 for (i = 60; i <= 120; i += 30) {
3358 ShadowPrint("RUN", CST_START, i);
3359 ShadowPrint("OPEN", CST_START + CST_SPC * 1, i);
3360 ShadowPrint("FIRE", CST_START + CST_SPC * 2, i);
3361 ShadowPrint("STRAFE", CST_START + CST_SPC * 3, i);
3362 }
3363
3364 ShadowPrint("LEFT", CST_START, 135);
3365 ShadowPrint("RIGHT", CST_START + CST_SPC * 1, 135);
3366 ShadowPrint("FWRD", CST_START + CST_SPC * 2, 135);
3367 ShadowPrint("BKWRD", CST_START + CST_SPC * 3, 135);
3368
3369
3370 DrawCustMouse(0);
3371 DrawCustJoy(0);
3372 DrawCustKeybd(0);
3373 DrawCustKeys(0);
3374
3375 //
3376 // PICK STARTING POINT IN MENU
3377 //
3378 if (CusItems.curpos < 0) {
3379 for (i = 0; i < CusItems.amount; i++) {
3380 if (CusMenu[i].active) {
3381 CusItems.curpos = static_cast<int8_t>(i);
3382 break;
3383 }
3384 }
3385 }
3386
3387 VW_UpdateScreen();
3388 MenuFadeIn();
3389 }
3390
PrintCustMouse(int16_t i)3391 void PrintCustMouse(
3392 int16_t i)
3393 {
3394 int16_t j;
3395
3396 for (j = 0; j < 4; j++) {
3397 if (order[i] == buttonmouse[j]) {
3398 PrintX = CST_START + CST_SPC * i;
3399 US_Print(mbarray[j]);
3400 break;
3401 }
3402 }
3403 }
3404
DrawCustMouse(int16_t hilight)3405 void DrawCustMouse(
3406 int16_t hilight)
3407 {
3408 int16_t i, color;
3409
3410 color = ENABLED_TEXT_COLOR;
3411
3412 if (hilight) {
3413 color = HIGHLIGHT_TEXT_COLOR;
3414 }
3415
3416 SETFONTCOLOR(color, TERM_BACK_COLOR);
3417
3418 if (!mouseenabled) {
3419 SETFONTCOLOR(DISABLED_TEXT_COLOR, TERM_BACK_COLOR);
3420 CusMenu[0].active = AT_DISABLED;
3421 } else {
3422 CusMenu[0].active = AT_ENABLED;
3423 }
3424
3425 PrintY = CST_Y + 7;
3426 for (i = 0; i < 4; i++) {
3427 PrintCustMouse(i);
3428 }
3429 }
3430
PrintCustJoy(int16_t i)3431 void PrintCustJoy(
3432 int16_t i)
3433 {
3434 int16_t j;
3435
3436 for (j = 0; j < 4; j++) {
3437 if (order[i] == buttonjoy[j]) {
3438 PrintX = CST_START + CST_SPC * i;
3439 US_Print(mbarray[j]);
3440 break;
3441 }
3442 }
3443 }
3444
DrawCustJoy(int16_t hilight)3445 void DrawCustJoy(
3446 int16_t hilight)
3447 {
3448 int16_t i, color;
3449
3450
3451 color = ENABLED_TEXT_COLOR;
3452 if (hilight) {
3453 color = HIGHLIGHT_TEXT_COLOR;
3454 }
3455
3456 SETFONTCOLOR(color, TERM_BACK_COLOR);
3457
3458 if (!joystickenabled) {
3459 SETFONTCOLOR(DISABLED_TEXT_COLOR, TERM_BACK_COLOR);
3460 CusMenu[2].active = AT_DISABLED;
3461 } else {
3462 CusMenu[2].active = AT_ENABLED;
3463 }
3464
3465 PrintY = CST_Y + 37;
3466 for (i = 0; i < 4; i++) {
3467 PrintCustJoy(i);
3468 }
3469 }
3470
PrintCustKeybd(int16_t i)3471 void PrintCustKeybd(
3472 int16_t i)
3473 {
3474 PrintX = CST_START + CST_SPC * i;
3475 US_Print(IN_GetScanName(buttonscan[order[i]]).c_str());
3476 }
3477
DrawCustKeybd(int16_t hilight)3478 void DrawCustKeybd(
3479 int16_t hilight)
3480 {
3481 int16_t i, color;
3482
3483 if (hilight) {
3484 color = HIGHLIGHT_TEXT_COLOR;
3485 } else {
3486 color = ENABLED_TEXT_COLOR;
3487 }
3488
3489 SETFONTCOLOR(color, TERM_BACK_COLOR);
3490
3491 PrintY = CST_Y + 67;
3492
3493 for (i = 0; i < 4; i++) {
3494 PrintCustKeybd(i);
3495 }
3496 }
3497
PrintCustKeys(int16_t i)3498 void PrintCustKeys(
3499 int16_t i)
3500 {
3501 PrintX = CST_START + CST_SPC * i;
3502 US_Print(IN_GetScanName(dirscan[moveorder[i]]).c_str());
3503 }
3504
DrawCustKeys(int16_t hilight)3505 void DrawCustKeys(
3506 int16_t hilight)
3507 {
3508 int16_t i, color;
3509
3510 color = ENABLED_TEXT_COLOR;
3511
3512 if (hilight) {
3513 color = HIGHLIGHT_TEXT_COLOR;
3514 }
3515
3516 SETFONTCOLOR(color, TERM_BACK_COLOR);
3517
3518 PrintY = CST_Y + 82;
3519 for (i = 0; i < 4; i++) {
3520 PrintCustKeys(i);
3521 }
3522 }
3523
CP_Quit()3524 void CP_Quit()
3525 {
3526 if (Confirm(QuitToDosStr)) {
3527 ExitGame();
3528 }
3529
3530 DrawMainMenu();
3531 }
3532
3533 // ---------------------------------------------------------------------------
3534 // Clear Menu screens to dark red
3535 // ---------------------------------------------------------------------------
ClearMScreen()3536 void ClearMScreen()
3537 {
3538 VWB_Bar(SCREEN_X, SCREEN_Y, SCREEN_W, SCREEN_H, ::menu_background_color);
3539 }
3540
3541 // ---------------------------------------------------------------------------
3542 // Un/Cache a LUMP of graphics
3543 // ---------------------------------------------------------------------------
CacheLump(int16_t lumpstart,int16_t lumpend)3544 void CacheLump(
3545 int16_t lumpstart,
3546 int16_t lumpend)
3547 {
3548 int16_t i;
3549
3550 for (i = lumpstart; i <= lumpend; i++) {
3551 CA_CacheGrChunk(i);
3552 }
3553 }
3554
UnCacheLump(int16_t lumpstart,int16_t lumpend)3555 void UnCacheLump(
3556 int16_t lumpstart,
3557 int16_t lumpend)
3558 {
3559 int16_t i;
3560
3561 for (i = lumpstart; i <= lumpend; i++) {
3562 FREEFONT(i);
3563 }
3564 }
3565
DrawWindow(int16_t x,int16_t y,int16_t w,int16_t h,int16_t wcolor)3566 void DrawWindow(
3567 int16_t x,
3568 int16_t y,
3569 int16_t w,
3570 int16_t h,
3571 int16_t wcolor)
3572 {
3573 VWB_Bar(x, y, w, h, static_cast<uint8_t>(wcolor));
3574 DrawOutline(x, y, w, h, BORD2COLOR, DEACTIVE);
3575 }
3576
DrawOutline(int16_t x,int16_t y,int16_t w,int16_t h,int16_t color1,int16_t color2)3577 void DrawOutline(
3578 int16_t x,
3579 int16_t y,
3580 int16_t w,
3581 int16_t h,
3582 int16_t color1,
3583 int16_t color2)
3584 {
3585 VWB_Hlin(x, x + w, y, static_cast<uint8_t>(color2));
3586 VWB_Vlin(y, y + h, x, static_cast<uint8_t>(color2));
3587 VWB_Hlin(x, x + w, y + h, static_cast<uint8_t>(color1));
3588 VWB_Vlin(y, y + h, x + w, static_cast<uint8_t>(color1));
3589 }
3590
SetupControlPanel()3591 void SetupControlPanel()
3592 {
3593 // BBi
3594 SwitchItems.amount = (::is_ps() ? 7 : 9);
3595 SwitchItems.y = MENU_Y + (::is_ps() ? 15 : 7);
3596 // BBi
3597
3598 ControlPanelAlloc();
3599
3600 fontnumber = 2;
3601
3602 WindowH = 200;
3603
3604 if (!ingame) {
3605 CA_LoadAllSounds();
3606 } else {
3607 MainMenu[MM_SAVE_MISSION].active = AT_ENABLED;
3608 }
3609
3610 ReadGameNames();
3611 }
3612
ReadGameNames()3613 void ReadGameNames()
3614 {
3615 for (int i = 0; i < 10; ++i) {
3616 auto name = ::get_saved_game_base_name();
3617 name += static_cast<char>('0' + i);
3618
3619 auto name_path = ::get_profile_dir() + name;
3620
3621 bstone::FileStream stream(name_path);
3622
3623 if (!stream.is_open()) {
3624 continue;
3625 }
3626
3627 SaveGamesAvail[i] = 1;
3628
3629 int chunk_size = ::FindChunk(&stream, "DESC");
3630
3631 if (chunk_size > 0) {
3632 char temp[GAME_DESCRIPTION_LEN + 1];
3633
3634 std::uninitialized_fill_n(
3635 temp,
3636 GAME_DESCRIPTION_LEN,
3637 '\0');
3638
3639 auto temp_size = std::min(GAME_DESCRIPTION_LEN, chunk_size);
3640
3641 stream.read(temp, temp_size);
3642
3643 ::strcpy(&SaveGameNames[i][0], temp);
3644 } else {
3645 ::strcpy(&SaveGameNames[i][0], "DESCRIPTION LOST");
3646 }
3647 }
3648 }
3649
CleanupControlPanel()3650 void CleanupControlPanel()
3651 {
3652 if (!loadedgame) {
3653 FreeMusic();
3654 }
3655 ControlPanelFree();
3656 fontnumber = 4;
3657 }
3658
3659 // ---------------------------------------------------------------------------
3660 // ControlPanelFree() - This FREES the control panel lump from memory
3661 // and REALLOCS the ScaledDirectory
3662 // ---------------------------------------------------------------------------
ControlPanelFree()3663 void ControlPanelFree()
3664 {
3665 UnCacheLump(CONTROLS_LUMP_START, CONTROLS_LUMP_END);
3666 NewViewSize();
3667 }
3668
3669 // ---------------------------------------------------------------------------
3670 // ControlPanelAlloc() - This CACHEs the control panel lump into memory
3671 // and FREEs the ScaledDirectory.
3672 // ---------------------------------------------------------------------------
ControlPanelAlloc()3673 void ControlPanelAlloc()
3674 {
3675 CacheLump(CONTROLS_LUMP_START, CONTROLS_LUMP_END);
3676 }
3677
3678 // ---------------------------------------------------------------------------
3679 // ShadowPrint() - Shadow Prints given text @ a given x & y in default font
3680 //
3681 // NOTE: Font MUST already be loaded
3682 // ---------------------------------------------------------------------------
ShadowPrint(const char * strng,int16_t x,int16_t y)3683 void ShadowPrint(
3684 const char* strng,
3685 int16_t x,
3686 int16_t y)
3687 {
3688 int16_t old_bc, old_fc;
3689
3690 old_fc = fontcolor;
3691 old_bc = backcolor;
3692
3693 PrintX = x + 1;
3694 PrintY = y + 1;
3695
3696 SETFONTCOLOR(TERM_SHADOW_COLOR, TERM_BACK_COLOR);
3697 US_Print(strng);
3698
3699 PrintX = x;
3700 PrintY = y;
3701 SETFONTCOLOR(old_fc, old_bc);
3702 US_Print(strng);
3703 }
3704
3705 // ---------------------------------------------------------------------------
3706 // HandleMenu() - Handle moving gun around a menu
3707 // ---------------------------------------------------------------------------
HandleMenu(CP_iteminfo * item_i,CP_itemtype * items,void (* routine)(int16_t w))3708 int16_t HandleMenu(
3709 CP_iteminfo* item_i,
3710 CP_itemtype* items,
3711 void (* routine)(int16_t w))
3712 {
3713 #define box_on item_i->cursor.on
3714 int8_t key;
3715 static int16_t redrawitem = 1;
3716
3717 int16_t i, x, y, basey, exit, which, flash_tics;
3718 ControlInfo ci;
3719
3720 which = item_i->curpos;
3721 x = item_i->x;
3722 basey = item_i->y;
3723 y = basey + which * item_i->y_spacing;
3724 box_on = 1;
3725 DrawGun(item_i, items, x, &y, which, basey, routine);
3726
3727 SetTextColor(items + which, 1);
3728
3729 if (redrawitem) {
3730 ShadowPrint((items + which)->string, item_i->x + item_i->indent, item_i->y + which * item_i->y_spacing);
3731 }
3732
3733 //
3734 // CALL CUSTOM ROUTINE IF IT IS NEEDED
3735 //
3736
3737 if (routine) {
3738 routine(which);
3739 }
3740
3741 VW_UpdateScreen();
3742
3743 flash_tics = 40;
3744 exit = 0;
3745 TimeCount = 0;
3746 IN_ClearKeysDown();
3747
3748 do {
3749 CalcTics();
3750 flash_tics -= tics;
3751
3752 CycleColors();
3753
3754 //
3755 // CHANGE GUN SHAPE
3756 //
3757
3758 if (flash_tics <= 0) {
3759 flash_tics = 40;
3760
3761 box_on ^= 1;
3762
3763 if (box_on) {
3764 DrawGun(item_i, items, x, &y, which, basey, routine);
3765 } else {
3766 EraseGun(item_i, items, x, y, which);
3767 if (routine) {
3768 routine(which);
3769 }
3770 }
3771
3772
3773 VW_UpdateScreen();
3774 }
3775
3776 CheckPause();
3777
3778
3779 //
3780 // SEE IF ANY KEYS ARE PRESSED FOR INITIAL CHAR FINDING
3781 //
3782
3783 key = LastASCII;
3784 if (key) {
3785 int16_t ok = 0;
3786
3787 if (key >= 'a') {
3788 key -= 'a' - 'A';
3789 }
3790
3791 for (i = which + 1; i < item_i->amount; i++) {
3792 if ((items + i)->active && (items + i)->string[0] == key) {
3793 EraseGun(item_i, items, x, y, which);
3794 which = i;
3795 item_i->curpos = static_cast<int8_t>(which); // jtr -testing
3796 box_on = 1;
3797 DrawGun(item_i, items, x, &y, which, basey, routine);
3798 VW_UpdateScreen();
3799
3800 ok = 1;
3801 IN_ClearKeysDown();
3802 break;
3803 }
3804 }
3805
3806 //
3807 // DIDN'T FIND A MATCH FIRST TIME THRU. CHECK AGAIN.
3808 //
3809
3810 if (!ok) {
3811 for (i = 0; i < which; i++) {
3812 if ((items + i)->active && (items + i)->string[0] == key) {
3813 EraseGun(item_i, items, x, y, which);
3814 which = i;
3815 item_i->curpos = static_cast<int8_t>(which); // jtr -testing
3816 box_on = 1;
3817 DrawGun(item_i, items, x, &y, which, basey, routine);
3818 VW_UpdateScreen();
3819
3820 IN_ClearKeysDown();
3821 break;
3822 }
3823 }
3824 }
3825 }
3826
3827 //
3828 // GET INPUT
3829 //
3830
3831 ReadAnyControl(&ci);
3832
3833 switch (ci.dir) {
3834 // ------------------------
3835 // MOVE UP
3836 //
3837 case dir_North:
3838 EraseGun(item_i, items, x, y, which);
3839
3840 do {
3841 if (!which) {
3842 which = item_i->amount - 1;
3843 } else {
3844 which--;
3845 }
3846
3847 } while (!(items + which)->active);
3848
3849 item_i->curpos = static_cast<int8_t>(which); // jtr -testing
3850
3851 box_on = 1;
3852 DrawGun(item_i, items, x, &y, which, basey, routine);
3853
3854 VW_UpdateScreen();
3855
3856 TicDelay(20);
3857 break;
3858
3859 // --------------------------
3860 // MOVE DOWN
3861 //
3862 case dir_South:
3863 EraseGun(item_i, items, x, y, which);
3864
3865 do {
3866 if (which == item_i->amount - 1) {
3867 which = 0;
3868 } else {
3869 which++;
3870 }
3871 } while (!(items + which)->active);
3872
3873 item_i->curpos = static_cast<int8_t>(which); // jtr -testing
3874
3875 box_on = 1;
3876 DrawGun(item_i, items, x, &y, which, basey, routine);
3877
3878 VW_UpdateScreen();
3879
3880 TicDelay(20);
3881 break;
3882
3883 default:
3884 break;
3885 }
3886
3887 if (ci.button0 || Keyboard[ScanCode::sc_space] || Keyboard[ScanCode::sc_return]) {
3888 exit = 1;
3889 }
3890
3891 if (ci.button1 || Keyboard[ScanCode::sc_escape]) {
3892 exit = 2;
3893 }
3894
3895 } while (!exit);
3896
3897 IN_ClearKeysDown();
3898
3899 //
3900 // ERASE EVERYTHING
3901 //
3902
3903 box_on = 0;
3904 redrawitem = 1;
3905 EraseGun(item_i, items, x, y, which);
3906
3907 if (routine) {
3908 routine(which);
3909 }
3910
3911 VW_UpdateScreen();
3912
3913 item_i->curpos = static_cast<int8_t>(which);
3914
3915 switch (exit) {
3916 case 1:
3917 //
3918 // CALL THE ROUTINE
3919 //
3920 if ((items + which)->routine) {
3921 // Make sure there's room to save when CP_SaveGame() is called.
3922 //
3923 if (reinterpret_cast<size_t>(items[which].routine) == reinterpret_cast<size_t>(CP_SaveGame)) {
3924 if (!CheckDiskSpace(DISK_SPACE_NEEDED, CANT_SAVE_GAME_TXT, cds_menu_print)) {
3925 return which;
3926 }
3927 }
3928
3929 //
3930 // ALREADY IN A GAME?
3931 //
3932 if (::is_ps() && ingame && ((items + which)->routine == CP_NewGame)) {
3933 if (!Confirm(CURGAME)) {
3934 ::MenuFadeOut();
3935 return 0;
3936 }
3937 }
3938
3939 ShootSnd();
3940 ::MenuFadeOut();
3941 (items + which)->routine(0);
3942 }
3943 return which;
3944
3945 case 2:
3946 ::sd_play_player_sound(ESCPRESSEDSND, bstone::AC_ITEM);
3947
3948 return -1;
3949 }
3950
3951 return 0; // JUST TO SHUT UP THE ERROR MESSAGES!
3952 }
3953
3954 // ---------------------------------------------------------------------------
3955 // ERASE GUN & DE-HIGHLIGHT STRING
3956 // ---------------------------------------------------------------------------
EraseGun(CP_iteminfo * item_i,CP_itemtype * items,int16_t x,int16_t y,int16_t which)3957 void EraseGun(
3958 CP_iteminfo* item_i,
3959 CP_itemtype* items,
3960 int16_t x,
3961 int16_t y,
3962 int16_t which)
3963 {
3964 static_cast<void>(x);
3965
3966 VWB_Bar(item_i->cursor.x, y + item_i->cursor.y_ofs, item_i->cursor.width, item_i->cursor.height, ::menu_background_color);
3967 SetTextColor(items + which, 0);
3968
3969 ShadowPrint((items + which)->string, item_i->x + item_i->indent, y);
3970 }
3971
3972 // ---------------------------------------------------------------------------
3973 // DrawGun() - DRAW GUN AT NEW POSITION
3974 // ---------------------------------------------------------------------------
DrawGun(CP_iteminfo * item_i,CP_itemtype * items,int16_t x,int16_t * y,int16_t which,int16_t basey,void (* routine)(int16_t w))3975 void DrawGun(
3976 CP_iteminfo* item_i,
3977 CP_itemtype* items,
3978 int16_t x,
3979 int16_t* y,
3980 int16_t which,
3981 int16_t basey,
3982 void (* routine)(int16_t w))
3983 {
3984 static_cast<void>(x);
3985
3986 *y = basey + which * item_i->y_spacing;
3987
3988 VWB_Bar(item_i->cursor.x, *y + item_i->cursor.y_ofs, item_i->cursor.width, item_i->cursor.height, HIGHLIGHT_BOX_COLOR);
3989 SetTextColor(items + which, 1);
3990
3991 ShadowPrint((items + which)->string, item_i->x + item_i->indent, item_i->y + which * item_i->y_spacing);
3992
3993 //
3994 // CALL CUSTOM ROUTINE IF IT IS NEEDED
3995 //
3996
3997 if (routine) {
3998 routine(which);
3999 }
4000 }
4001
4002 // ---------------------------------------------------------------------------
4003 // TicDelay() - DELAY FOR AN AMOUNT OF TICS OR UNTIL CONTROLS ARE INACTIVE
4004 // ---------------------------------------------------------------------------
TicDelay(int16_t count)4005 void TicDelay(
4006 int16_t count)
4007 {
4008 ControlInfo ci;
4009
4010 TimeCount = 0;
4011
4012 do {
4013 ReadAnyControl(&ci);
4014 } while (TimeCount < static_cast<uint32_t>(count) && ci.dir != dir_None);
4015 }
4016
4017 // ---------------------------------------------------------------------------
4018 // DrawMenu() - Draw a menu
4019 //
4020 // This also calculates the Y position of the current items in the
4021 // CP_itemtype structures.
4022 // ---------------------------------------------------------------------------
DrawMenu(CP_iteminfo * item_i,CP_itemtype * items)4023 void DrawMenu(
4024 CP_iteminfo* item_i,
4025 CP_itemtype* items)
4026 {
4027 int16_t i, which = item_i->curpos;
4028
4029 WindowX = PrintX = item_i->x + item_i->indent;
4030 WindowY = PrintY = item_i->y;
4031
4032 WindowW = 320;
4033 WindowH = 200;
4034
4035 for (i = 0; i < item_i->amount; i++) {
4036 SetTextColor(items + i, which == i);
4037 ShadowPrint((items + i)->string, WindowX, item_i->y + i * item_i->y_spacing);
4038 }
4039 }
4040
4041 // ---------------------------------------------------------------------------
4042 // SET TEXT COLOR (HIGHLIGHT OR NO)
4043 // ---------------------------------------------------------------------------
SetTextColor(CP_itemtype * items,int16_t hlight)4044 void SetTextColor(
4045 CP_itemtype* items,
4046 int16_t hlight)
4047 {
4048 if (hlight) {
4049 SETFONTCOLOR(color_hlite[items->active], TERM_BACK_COLOR);
4050 } else {
4051 SETFONTCOLOR(color_norml[items->active], TERM_BACK_COLOR);
4052 }
4053 }
4054
4055 // ---------------------------------------------------------------------------
4056 // WAIT FOR CTRLKEY-UP OR BUTTON-UP
4057 // ---------------------------------------------------------------------------
WaitKeyUp()4058 void WaitKeyUp()
4059 {
4060 for (auto quit = false; !quit; ) {
4061 ControlInfo ci;
4062
4063 ::ReadAnyControl(&ci);
4064
4065 quit = !(
4066 ci.button0 != 0 ||
4067 ci.button1 != 0 ||
4068 ci.button2 != 0 ||
4069 ci.button3 != 0 ||
4070 Keyboard[ScanCode::sc_space] ||
4071 Keyboard[ScanCode::sc_return] ||
4072 Keyboard[ScanCode::sc_escape]);
4073 }
4074 }
4075
4076 // ---------------------------------------------------------------------------
4077 // READ KEYBOARD, JOYSTICK AND MOUSE FOR INPUT
4078 // ---------------------------------------------------------------------------
ReadAnyControl(ControlInfo * ci)4079 void ReadAnyControl(
4080 ControlInfo* ci)
4081 {
4082 bool mouseactive = false;
4083
4084 ::IN_ReadControl(0, ci);
4085
4086 //
4087 // UNDO some of the ControlInfo vars that were init
4088 // with IN_ReadControl() for the mouse...
4089 //
4090 if (ControlTypeUsed == ctrl_Mouse) {
4091 //
4092 // Clear directions & buttons (if enabled or not)
4093 //
4094 ci->dir = dir_None;
4095 ci->button0 = 0;
4096 ci->button1 = 0;
4097 ci->button2 = 0;
4098 ci->button3 = 0;
4099 }
4100
4101 if (mouseenabled) {
4102 int mousex;
4103 int mousey;
4104
4105 // READ MOUSE MOTION COUNTERS
4106 // RETURN DIRECTION
4107 // HOME MOUSE
4108 // CHECK MOUSE BUTTONS
4109
4110 ::in_get_mouse_deltas(mousex, mousey);
4111 ::in_clear_mouse_deltas();
4112
4113 const int DELTA_THRESHOLD = 10;
4114
4115 if (mousey < -DELTA_THRESHOLD) {
4116 ci->dir = dir_North;
4117 mouseactive = true;
4118 } else if (mousey > DELTA_THRESHOLD) {
4119 ci->dir = dir_South;
4120 mouseactive = true;
4121 }
4122
4123 if (mousex < -DELTA_THRESHOLD) {
4124 ci->dir = dir_West;
4125 mouseactive = true;
4126 } else if (mousex > DELTA_THRESHOLD) {
4127 ci->dir = dir_East;
4128 mouseactive = true;
4129 }
4130
4131 int buttons = ::IN_MouseButtons();
4132
4133 if (buttons != 0) {
4134 ci->button0 = buttons & 1;
4135 ci->button1 = buttons & 2;
4136 ci->button2 = buttons & 4;
4137 ci->button3 = false;
4138 mouseactive = true;
4139 }
4140 }
4141
4142 if (joystickenabled && !mouseactive) {
4143 int jx;
4144 int jy;
4145 int16_t jb;
4146
4147 ::INL_GetJoyDelta(joystickport, &jx, &jy);
4148
4149 if (jy < -SENSITIVE) {
4150 ci->dir = dir_North;
4151 } else if (jy > SENSITIVE) {
4152 ci->dir = dir_South;
4153 }
4154
4155 if (jx < -SENSITIVE) {
4156 ci->dir = dir_West;
4157 } else if (jx > SENSITIVE) {
4158 ci->dir = dir_East;
4159 }
4160
4161 jb = ::IN_JoyButtons();
4162
4163 if (jb != 0) {
4164 ci->button0 = jb & 1;
4165 ci->button1 = jb & 2;
4166
4167 if (joypadenabled) {
4168 ci->button2 = jb & 4;
4169 ci->button3 = jb & 8;
4170 } else {
4171 ci->button2 = false;
4172 ci->button3 = false;
4173 }
4174 }
4175 }
4176 }
4177
4178 ////////////////////////////////////////////////////////////////////
4179 //
4180 // DRAW DIALOG AND CONFIRM YES OR NO TO QUESTION
4181 //
4182 ////////////////////////////////////////////////////////////////////
Confirm(const char * string)4183 int16_t Confirm(
4184 const char* string)
4185 {
4186 int16_t xit = 0, x, y, tick = 0, whichsnd[2] = { ESCPRESSEDSND, SHOOTSND };
4187
4188
4189 Message(string);
4190
4191 // Next two lines needed for flashing cursor ...
4192 //
4193 SETFONTCOLOR(BORDER_TEXT_COLOR, BORDER_MED_COLOR);
4194 CA_CacheGrChunk(STARTFONT + fontnumber);
4195
4196 IN_ClearKeysDown();
4197
4198 //
4199 // BLINK CURSOR
4200 //
4201 x = PrintX;
4202 y = PrintY;
4203 TimeCount = 0;
4204 do {
4205 if (TimeCount >= 10) {
4206 switch (tick) {
4207 case 0:
4208 VWB_Bar(x, y, 8, 13, BORDER_MED_COLOR);
4209 break;
4210
4211 case 1:
4212 PrintX = x;
4213 PrintY = y;
4214 US_Print("_");
4215 }
4216
4217 VW_UpdateScreen();
4218 tick ^= 1;
4219 TimeCount = 0;
4220 }
4221
4222 // BBi
4223 IN_CheckAck();
4224 } while (!Keyboard[ScanCode::sc_y] && !Keyboard[ScanCode::sc_n] && !Keyboard[ScanCode::sc_escape]);
4225
4226
4227 if (Keyboard[ScanCode::sc_y]) {
4228 xit = 1;
4229 ShootSnd();
4230 }
4231
4232 while (Keyboard[ScanCode::sc_y] || Keyboard[ScanCode::sc_n] || Keyboard[ScanCode::sc_escape]) {
4233 IN_CheckAck();
4234 }
4235
4236 IN_ClearKeysDown();
4237
4238 ::sd_play_player_sound(
4239 whichsnd[xit],
4240 bstone::AC_ITEM);
4241
4242 FREEFONT(STARTFONT + fontnumber);
4243
4244 return xit;
4245 }
4246
4247 // ---------------------------------------------------------------------------
4248 // PRINT A MESSAGE IN A WINDOW
4249 // ---------------------------------------------------------------------------
Message(const char * string)4250 void Message(
4251 const char* string)
4252 {
4253 int16_t h = 0, w = 0, mw = 0;
4254 size_t i;
4255 fontstruct* font;
4256 uint16_t OldPrintX, OldPrintY;
4257
4258 fontnumber = 1;
4259 CA_CacheGrChunk(STARTFONT + 1);
4260
4261 font = static_cast<fontstruct*>(grsegs[STARTFONT + fontnumber]);
4262
4263 h = font->height;
4264 for (i = 0; i < strlen(string); i++) {
4265 if (string[i] == '\n') {
4266 if (w > mw) {
4267 mw = w;
4268 }
4269 w = 0;
4270 h += font->height;
4271 } else {
4272 w += font->width[static_cast<int>(string[i])];
4273 }
4274 }
4275
4276 if (w + 10 > mw) {
4277 mw = w + 10;
4278 }
4279
4280 OldPrintY = PrintY = (WindowH / 2) - h / 2;
4281 OldPrintX = PrintX = WindowX = 160 - mw / 2;
4282
4283 // bump down and to right for shadow
4284
4285 PrintX++;
4286 PrintY++;
4287 WindowX++;
4288
4289 BevelBox(WindowX - 6, PrintY - 6, mw + 10, h + 10, BORDER_HI_COLOR, BORDER_MED_COLOR, BORDER_LO_COLOR);
4290
4291 SETFONTCOLOR(BORDER_LO_COLOR, BORDER_MED_COLOR);
4292 US_Print(string);
4293
4294 PrintY = OldPrintY;
4295 WindowX = PrintX = OldPrintX;
4296
4297 SETFONTCOLOR(BORDER_TEXT_COLOR, BORDER_MED_COLOR);
4298 US_Print(string);
4299
4300 FREEFONT(STARTFONT + 1);
4301
4302 VW_UpdateScreen();
4303 }
4304
4305 // --------------------------------------------------------------------------
4306 // Searches for an "^XX" and replaces with a 0 (NULL)
4307 // --------------------------------------------------------------------------
TerminateStr(char * pos)4308 void TerminateStr(
4309 char* pos)
4310 {
4311 pos = strstr(pos, "^XX");
4312 *pos = 0;
4313 }
4314
4315 // ---------------------------------------------------------------------------
4316 // Caches and prints a message in a window.
4317 // ---------------------------------------------------------------------------
CacheMessage(uint16_t MessageNum)4318 void CacheMessage(
4319 uint16_t MessageNum)
4320 {
4321 char* string;
4322
4323 CA_CacheGrChunk(MessageNum);
4324 string = (char*)grsegs[MessageNum];
4325
4326 TerminateStr(string);
4327
4328 Message(string);
4329
4330 FREEFONT(MessageNum);
4331 }
4332
4333 // ---------------------------------------------------------------------------
4334 // CacheCompData() - Caches and Decompresses data from the VGAGRAPH
4335 //
4336 // NOTE: - User is responsible for freeing loaded data
4337 // - Returns the size of the data
4338 // - Does not call TerminateStr() for loaded TEXT data
4339 //
4340 // RETURNS: Lenght of loaded (decompressed) data
4341 //
4342 // ---------------------------------------------------------------------------
CacheCompData(uint16_t item_number,void ** dst_ptr)4343 uint32_t CacheCompData(
4344 uint16_t item_number,
4345 void** dst_ptr)
4346 {
4347 char* chunk;
4348 char* dst;
4349 CompHeader_t CompHeader {};
4350 uint32_t data_length;
4351
4352 // Load compressed data
4353 CA_CacheGrChunk(item_number);
4354 chunk = (char*)grsegs[item_number];
4355
4356 if (!::is_ps()) {
4357 data_length = ::ca_gr_last_expanded_size;
4358 } else {
4359 memcpy(CompHeader.NameId, &chunk[0], 4);
4360 CompHeader.OriginalLen = ((uint32_t*)&chunk[4])[0];
4361 CompHeader.CompType = (ct_TYPES)((int16_t*)&chunk[8])[0];
4362 CompHeader.CompressLen = ((uint32_t*)&chunk[10])[0];
4363
4364 data_length = CompHeader.OriginalLen;
4365
4366 chunk += 14;
4367 }
4368
4369 // Allocate Dest Memory
4370
4371 dst = new char[data_length];
4372 *dst_ptr = dst;
4373
4374 if (!::is_ps()) {
4375 std::copy(
4376 chunk,
4377 &chunk[data_length],
4378 dst);
4379 } else {
4380 // Decompress and terminate string
4381
4382 if (!LZH_Startup()) {
4383 Quit("out of memory");
4384 }
4385
4386 ::LZH_Decompress(
4387 chunk,
4388 dst,
4389 data_length,
4390 CompHeader.CompressLen);
4391
4392 LZH_Shutdown();
4393 }
4394
4395 // Free compressed data
4396 UNCACHEGRCHUNK(item_number);
4397
4398 // Return loaded size
4399 return data_length;
4400 }
4401
StartCPMusic(int16_t song)4402 void StartCPMusic(
4403 int16_t song)
4404 {
4405 int chunk;
4406
4407 lastmenumusic = song;
4408
4409 SD_MusicOff();
4410 chunk = song;
4411 CA_CacheAudioChunk(static_cast<int16_t>(STARTMUSIC + chunk));
4412 ::SD_StartMusic(chunk);
4413 }
4414
FreeMusic()4415 void FreeMusic()
4416 {
4417 SD_MusicOff();
4418 }
4419
4420
4421 #ifdef CACHE_KEY_DATA
4422 // ---------------------------------------------------------------------------
4423 // IN_GetScanName() - Returns a string containing the name of the
4424 // specified scan code
4425 // ---------------------------------------------------------------------------
IN_GetScanName(ScanCode scan)4426 uint8_t far* IN_GetScanName(
4427 ScanCode scan)
4428 {
4429 uint8_t* p;
4430 ScanCode* s;
4431
4432 for (s = ExtScanCodes, p = ExtScanNames; *s; p += 7, s++) {
4433 if (*s == scan) {
4434 return (uint8_t*)p;
4435 }
4436 }
4437
4438 return (uint8_t*)(ScanNames + (scan << 1));
4439 }
4440 #else
4441 // ---------------------------------------------------------------------------
4442 // IN_GetScanName() - Returns a string containing the name of the
4443 // specified scan code
4444 // ---------------------------------------------------------------------------
IN_GetScanName(ScanCode scan)4445 const std::string& IN_GetScanName(
4446 ScanCode scan)
4447 {
4448 for (auto i = 0; ext_scan_codes[i] != ScanCode::sc_none; ++i) {
4449 if (ext_scan_codes[i] == scan) {
4450 return ext_scan_names[i];
4451 }
4452 }
4453
4454 return scan_names[static_cast<int>(scan)];
4455 }
4456 #endif
4457
4458 // ---------------------------------------------------------------------------
4459 // CHECK FOR PAUSE KEY (FOR MUSIC ONLY)
4460 // ---------------------------------------------------------------------------
CheckPause()4461 void CheckPause()
4462 {
4463 if (Paused) {
4464 switch (SoundStatus) {
4465 case 0:
4466 SD_MusicOn();
4467 break;
4468
4469 case 1:
4470 SD_MusicOff();
4471 break;
4472 }
4473
4474 SoundStatus ^= 1;
4475 VW_WaitVBL(3);
4476 IN_ClearKeysDown();
4477 Paused = false;
4478 }
4479 }
4480
4481 // -------------------------------------------------------------------------
4482 // DRAW GUN CURSOR AT CORRECT POSITION IN MENU
4483 // -------------------------------------------------------------------------
DrawMenuGun(CP_iteminfo * iteminfo)4484 void DrawMenuGun(
4485 CP_iteminfo* iteminfo)
4486 {
4487 int16_t x, y;
4488
4489 x = iteminfo->cursor.x;
4490 y = iteminfo->y + iteminfo->curpos * iteminfo->y_spacing + iteminfo->cursor.y_ofs;
4491
4492 VWB_Bar(x, y, iteminfo->cursor.width, iteminfo->cursor.height, HIGHLIGHT_BOX_COLOR);
4493 }
4494
ShootSnd()4495 void ShootSnd()
4496 {
4497 ::sd_play_player_sound(SHOOTSND, bstone::AC_ITEM);
4498 }
4499
ShowPromo()4500 void ShowPromo()
4501 {
4502 const auto PROMO_MUSIC = HIDINGA_MUS;
4503
4504 // Load and start music
4505 //
4506 ::CA_CacheAudioChunk(STARTMUSIC + PROMO_MUSIC);
4507 ::SD_StartMusic(PROMO_MUSIC);
4508
4509 // Show promo screen 1
4510 //
4511 ::MenuFadeOut();
4512 ::CA_CacheScreen(PROMO1PIC);
4513 VW_UpdateScreen();
4514 MenuFadeIn();
4515 ::IN_UserInput(TickBase * 20);
4516
4517 // Show promo screen 2
4518 //
4519 ::MenuFadeOut();
4520 ::CA_CacheScreen(PROMO2PIC);
4521 VW_UpdateScreen();
4522 MenuFadeIn();
4523 ::IN_UserInput(TickBase * 20);
4524
4525 // Music off and freed!
4526 //
4527 ::StopMusic();
4528 }
4529
ExitGame()4530 void ExitGame()
4531 {
4532 VW_FadeOut();
4533
4534 if (::is_aog_sw() && !::no_screens) {
4535 ::ShowPromo();
4536 }
4537
4538 SD_MusicOff();
4539 SD_StopSound();
4540 Quit();
4541 }
4542
4543 // BBi
4544 int volume_index = 0;
4545 int* const volumes[2] = { &sd_sfx_volume, &sd_music_volume };
4546
draw_volume_control(int index,int volume,bool is_enabled)4547 void draw_volume_control(
4548 int index,
4549 int volume,
4550 bool is_enabled)
4551 {
4552 int16_t slider_color =
4553 is_enabled ? ENABLED_TEXT_COLOR : DISABLED_TEXT_COLOR;
4554
4555 int16_t outline_color =
4556 is_enabled ? HIGHLIGHT_TEXT_COLOR : DEACTIAVED_TEXT_COLOR;
4557
4558 int y = 82 + (index * 40);
4559
4560 VWB_Bar(74, static_cast<int16_t>(y), 160, 8, HIGHLIGHT_BOX_COLOR);
4561 DrawOutline(73, static_cast<int16_t>(y - 1), 161, 9,
4562 outline_color, outline_color);
4563 VWB_Bar(static_cast<int16_t>(74 + ((160 * volume) / (::sd_max_volume + 1))),
4564 static_cast<int16_t>(y), 16, 8, static_cast<uint8_t>(slider_color));
4565 }
4566
draw_volume_controls()4567 void draw_volume_controls()
4568 {
4569 for (int i = 0; i < 2; ++i) {
4570 draw_volume_control(i, *(volumes[i]), i == volume_index);
4571 }
4572 }
4573
cp_sound_volume(int16_t)4574 void cp_sound_volume(
4575 int16_t)
4576 {
4577 ClearMScreen();
4578 DrawMenuTitle("SOUND VOLUME");
4579 DrawInstructions(IT_SOUND_VOLUME);
4580
4581 fontnumber = 4;
4582
4583 SETFONTCOLOR(HIGHLIGHT_TEXT_COLOR, TERM_BACK_COLOR);
4584
4585 PrintX = 150;
4586 PrintY = 60;
4587 US_Print("SFX");
4588
4589 PrintX = 145;
4590 PrintY = 105;
4591 US_Print("MUSIC");
4592
4593 for (int i = 0; i < 2; ++i) {
4594 PrintX = 36;
4595 PrintY = static_cast<uint16_t>(81 + (i * 40));
4596 US_Print("MUTE");
4597
4598 PrintX = 242;
4599 US_Print("LOUD");
4600 }
4601
4602 draw_volume_controls();
4603
4604 VW_UpdateScreen();
4605 MenuFadeIn();
4606
4607 ControlInfo ci;
4608
4609 int old_volumes[2];
4610 for (int i = 0; i < 2; ++i) {
4611 old_volumes[i] = -1;
4612 }
4613
4614 for (bool quit = false; !quit; ) {
4615 bool update_volumes = false;
4616 bool redraw_controls = false;
4617
4618 ReadAnyControl(&ci);
4619
4620 switch (ci.dir) {
4621 case dir_North:
4622 if (volume_index == 1) {
4623 redraw_controls = true;
4624 volume_index = 0;
4625 draw_volume_controls();
4626 VW_UpdateScreen();
4627 }
4628
4629 while (Keyboard[ScanCode::sc_up_arrow]) {
4630 ::in_handle_events();
4631 }
4632 break;
4633
4634 case dir_South:
4635 if (volume_index == 0) {
4636 redraw_controls = true;
4637 volume_index = 1;
4638 draw_volume_controls();
4639 VW_UpdateScreen();
4640 }
4641
4642 while (Keyboard[ScanCode::sc_down_arrow]) {
4643 ::in_handle_events();
4644 }
4645 break;
4646
4647 case dir_West:
4648 if (*volumes[volume_index] > ::sd_min_volume) {
4649 redraw_controls = true;
4650 update_volumes = true;
4651 --(*volumes[volume_index]);
4652 draw_volume_controls();
4653 VW_UpdateScreen();
4654 }
4655
4656 while (Keyboard[ScanCode::sc_left_arrow]) {
4657 ::in_handle_events();
4658 }
4659 break;
4660
4661 case dir_East:
4662 if (*volumes[volume_index] < ::sd_max_volume) {
4663 redraw_controls = true;
4664 update_volumes = true;
4665 ++(*volumes[volume_index]);
4666 }
4667
4668 while (Keyboard[ScanCode::sc_right_arrow]) {
4669 ::in_handle_events();
4670 }
4671 break;
4672
4673 default:
4674 break;
4675 }
4676
4677 if (update_volumes) {
4678 update_volumes = false;
4679
4680 if (old_volumes[0] != *volumes[0]) {
4681 sd_set_sfx_volume(sd_sfx_volume);
4682 sd_play_player_sound(MOVEGUN1SND, bstone::AC_ITEM);
4683 }
4684
4685 if (old_volumes[1] != *volumes[1]) {
4686 sd_set_music_volume(sd_music_volume);
4687 }
4688 }
4689
4690 if (redraw_controls) {
4691 redraw_controls = false;
4692 draw_volume_controls();
4693 VW_UpdateScreen();
4694 }
4695
4696 quit = (ci.button1 || Keyboard[ScanCode::sc_escape]);
4697 }
4698
4699 sd_play_player_sound(ESCPRESSEDSND, bstone::AC_ITEM);
4700
4701 WaitKeyUp();
4702 MenuFadeIn();
4703 }
4704
4705 ///
draw_video_descriptions(int16_t which)4706 void draw_video_descriptions(
4707 int16_t which)
4708 {
4709 const char* instructions[] = {
4710 "STRETCHES RENDERED IMAGE TO THE WHOLE WINDOW",
4711 };
4712
4713 ::fontnumber = 2;
4714
4715 ::WindowX = 48;
4716 ::WindowY = 144;
4717 ::WindowW = 236;
4718 ::WindowH = 8;
4719
4720 ::VWB_Bar(
4721 ::WindowX,
4722 ::WindowY - 1,
4723 ::WindowW,
4724 ::WindowH,
4725 ::menu_background_color);
4726
4727 ::SETFONTCOLOR(TERM_SHADOW_COLOR, TERM_BACK_COLOR);
4728 ::US_PrintCentered(instructions[which]);
4729
4730 --::WindowX;
4731 --::WindowY;
4732
4733 SETFONTCOLOR(INSTRUCTIONS_TEXT_COLOR, TERM_BACK_COLOR);
4734 ::US_PrintCentered(instructions[which]);
4735 }
4736
video_draw_menu()4737 void video_draw_menu()
4738 {
4739 ::CA_CacheScreen(BACKGROUND_SCREENPIC);
4740 ::ClearMScreen();
4741 ::DrawMenuTitle("VIDEO SETTINGS");
4742 ::DrawInstructions(IT_STANDARD);
4743 ::DrawMenu(&video_items, video_menu);
4744 VW_UpdateScreen();
4745 }
4746
video_draw_switch(int16_t which)4747 void video_draw_switch(
4748 int16_t which)
4749 {
4750 uint16_t Shape;
4751
4752 for (int i = 0; i < video_items.amount; i++) {
4753 if (video_menu[i].string[0]) {
4754 Shape = ::C_NOTSELECTEDPIC;
4755
4756 if (video_items.cursor.on) {
4757 if (i == which) {
4758 Shape += 2;
4759 }
4760 }
4761
4762 switch (i) {
4763 case mvl_stretch_to_window:
4764 if (::vid_widescreen) {
4765 Shape++;
4766 }
4767 break;
4768
4769 default:
4770 break;
4771 }
4772
4773 ::VWB_DrawPic(
4774 video_items.x - 16,
4775 video_items.y + i * video_items.y_spacing - 1,
4776 Shape);
4777 }
4778 }
4779
4780 draw_video_descriptions(which);
4781 }
4782
cp_video(int16_t)4783 void cp_video(
4784 int16_t)
4785 {
4786 int16_t which;
4787
4788 ::CA_CacheScreen(BACKGROUND_SCREENPIC);
4789 ::video_draw_menu();
4790 ::MenuFadeIn();
4791 ::WaitKeyUp();
4792
4793 do {
4794 which = ::HandleMenu(&video_items, video_menu, video_draw_switch);
4795
4796 switch (which) {
4797 case mvl_stretch_to_window:
4798 ::vid_widescreen = !::vid_widescreen;
4799 ::ShootSnd();
4800 ::video_draw_switch(video_items.curpos);
4801 ::vl_update_widescreen();
4802 ::SetupWalls();
4803 ::NewViewSize();
4804 ::SetPlaneViewSize();
4805 ::VL_RefreshScreen();
4806 break;
4807
4808 default:
4809 break;
4810 }
4811 } while (which >= 0);
4812
4813 ::MenuFadeOut();
4814 }
4815 ///
4816
MenuFadeOut()4817 void MenuFadeOut()
4818 {
4819 if (::is_aog()) {
4820 ::VL_FadeOut(0, 255, 44, 0, 0, 10);
4821 } else {
4822 ::VL_FadeOut(0, 255, 40, 44, 44, 10);
4823 }
4824 }
4825 // BBi
4826