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 //
26 // Warning!
27 //
28 // All functions in this source file are designated usable by the memory
29 // manager after program initialization.
30 //
31 
32 
33 #include "3d_def.h"
34 
35 
36 extern SpanStart spanstart;
37 extern StepScale stepscale;
38 extern BaseDist basedist;
39 extern PlaneYLookup planeylookup;
40 extern MirrorOfs mirrorofs;
41 
42 
43 void CA_CannotOpen(
44     const std::string& string);
45 
46 void CAL_GetGrChunkLength(
47     int16_t chunk);
48 
49 void CA_CacheScreen(
50     int16_t chunk);
51 
52 void VH_UpdateScreen();
53 void IN_StartAck();
54 bool IN_CheckAck();
55 void OpenMapFile();
56 void CloseMapFile();
57 void ClearMemory();
58 void ShutdownId();
59 void InitRedShifts();
60 
61 void CAL_OptimizeNodes(
62     huffnode* table);
63 
64 void OpenAudioFile();
65 void ReadConfig();
66 void read_high_scores();
67 
68 void initialize_sprites();
69 void initialize_states();
70 void initialize_audio_constants();
71 void initialize_songs();
72 void initialize_gfxv_contants();
73 void initialize_tp_shape_table();
74 void initialize_tp_animation_table();
75 void initialize_static_info_constants();
76 void initialize_weapon_constants();
77 void initialize_grenade_shape_constants();
78 void initialize_static_health_table();
79 void initialize_boss_constants();
80 void initialize_messages();
81 void initialize_ca_constants();
82 
83 void SDL_SetupDigi();
84 
85 
86 static uint8_t wolfdigimap[] = {
87     // These first sounds are in the upload version
88 
89     ATKIONCANNONSND, 0,
90     ATKCHARGEDSND, 1,
91     ATKBURSTRIFLESND, 2,
92     ATKGRENADESND, 46,
93 
94     OPENDOORSND, 3,
95     CLOSEDOORSND, 4,
96     HTECHDOOROPENSND, 5,
97     HTECHDOORCLOSESND, 6,
98 
99     INFORMANTDEATHSND, 7,
100     SCIENTISTHALTSND, 19,
101     SCIENTISTDEATHSND, 20,
102 
103     GOLDSTERNHALTSND, 8,
104     GOLDSTERNLAUGHSND, 24,
105 
106     HALTSND, 9, // Rent-A-Cop 1st sighting
107     RENTDEATH1SND, 10, // Rent-A-Cop Death
108 
109     EXPLODE1SND, 11,
110 
111     GGUARDHALTSND, 12,
112     GGUARDDEATHSND, 17,
113 
114     PROHALTSND, 16,
115     PROGUARDDEATHSND, 13,
116 
117     BLUEBOYDEATHSND, 18,
118     BLUEBOYHALTSND, 51,
119 
120     SWATHALTSND, 22,
121     SWATDIESND, 47,
122 
123     SCANHALTSND, 15,
124     SCANDEATHSND, 23,
125 
126     PODHATCHSND, 26,
127     PODHALTSND, 50,
128     PODDEATHSND, 49,
129 
130     ELECTSHOTSND, 27,
131 
132     DOGBOYHALTSND, 14,
133     DOGBOYDEATHSND, 21,
134     ELECARCDAMAGESND, 25,
135     ELECAPPEARSND, 28,
136     ELECDIESND, 29,
137 
138     INFORMDEATH2SND, 39, // Informant Death #2
139     RENTDEATH2SND, 34, // Rent-A-Cop Death #2
140     PRODEATH2SND, 42, // PRO Death #2
141     SWATDEATH2SND, 48, // SWAT Death #2
142     SCIDEATH2SND, 53, // Gen. Sci Death #2
143 
144     LIQUIDDIESND, 30,
145 
146     GURNEYSND, 31,
147     GURNEYDEATHSND, 41,
148 
149     WARPINSND, 32,
150     WARPOUTSND, 33,
151 
152     EXPLODE2SND, 35,
153 
154     LCANHALTSND, 36,
155     LCANDEATHSND, 37,
156 
157     // RENTDEATH3SND, 38, // Rent-A-Cop Death #3
158     INFORMDEATH3SND, 40, // Informant Death #3
159     PRODEATH3SND, 43, // PRO Death #3
160     SWATDEATH3SND, 52, // Swat Guard #3
161     SCIDEATH3SND, 54, // Gen. Sci Death #3
162 
163     LCANBREAKSND, 44,
164     SCANBREAKSND, 45,
165     CLAWATTACKSND, 56,
166     SPITATTACKSND, 55,
167     PUNCHATTACKSND, 57,
168 
169     LASTSOUND,
170 };
171 
172 
173 extern const uint8_t colormap[16896];
174 const uint8_t* lightsource;
175 
176 
177 // ------------------ ID Software 'startup' functions ---------------------
178 
179 
180 /*
181 ==================
182 =
183 = BuildTables
184 =
185 = Calculates:
186 =
187 = scale                 projection constant
188 = sintable/costable     overlapping fractional tables
189 =
190 ==================
191 */
192 
193 const float radtoint = static_cast<float>(FINEANGLES / 2 / PI);
194 
195 
BuildTables()196 void BuildTables()
197 {
198     int16_t i;
199     float angle, anglestep;
200     double tang;
201     fixed value;
202 
203 
204 //
205 // calculate fine tangents
206 //
207 
208     for (i = 0; i < FINEANGLES / 8; i++) {
209         tang = tan((i + 0.5) / radtoint);
210         finetangent[i] = static_cast<int32_t>(tang * TILEGLOBAL);
211         finetangent[FINEANGLES / 4 - 1 - i] = static_cast<int32_t>(1 / tang * TILEGLOBAL);
212     }
213 
214 //
215 // costable overlays sintable with a quarter phase shift
216 // ANGLES is assumed to be divisable by four
217 //
218 // The low word of the value is the fraction, the high bit is the sign bit,
219 // bits 16-30 should be 0
220 //
221 
222     angle = 0.0F;
223     anglestep = static_cast<float>(PI / 2 / ANGLEQUAD);
224     for (i = 0; i <= ANGLEQUAD; i++) {
225         value = static_cast<fixed>(GLOBAL1 * sin(static_cast<double>(angle)));
226         sintable[i] =
227             sintable[i + ANGLES] =
228                 sintable[ANGLES / 2 - i] = value;
229         sintable[ANGLES - i] =
230             sintable[ANGLES / 2 + i] = value | 0x80000000l;
231         angle += anglestep;
232     }
233 
234     lightsource = colormap;
235 }
236 
237 // Map tile values to scaled pics
SetupWalls()238 void SetupWalls()
239 {
240     //
241     // Hey! Yea You! This is where you can VERY easly setup to use a
242     // specific 'BANK' of wall graphics.... JTR
243     //
244 
245     for (int i = 1; i < MAXWALLTILES; ++i)
246     {
247         ::horizwall[i] = (i - 1) * 2;
248         ::vertwall[i] = ::horizwall[i] + 1;
249     }
250 
251     WallHeight().swap(wallheight);
252     wallheight.resize(::vga_width);
253 
254 
255     const int k_half_height = ::vga_height / 2;
256 
257     SpanStart().swap(spanstart);
258     spanstart.resize(k_half_height);
259 
260     StepScale().swap(stepscale);
261     stepscale.resize(k_half_height);
262 
263     BaseDist().swap(basedist);
264     basedist.resize(k_half_height);
265 
266     PlaneYLookup().swap(planeylookup);
267     planeylookup.resize(k_half_height);
268 
269     MirrorOfs().swap(mirrorofs);
270     mirrorofs.resize(k_half_height);
271 }
272 
InitDigiMap()273 void InitDigiMap()
274 {
275     char* map;
276 
277     for (map = reinterpret_cast<char*>(wolfdigimap); *map != LASTSOUND; map += 2) {
278         DigiMap[static_cast<int>(map[0])] = map[1];
279     }
280 }
281 
CAL_SetupAudioFile()282 void CAL_SetupAudioFile()
283 {
284     bstone::FileStream handle;
285     int32_t length;
286     std::string fname;
287 
288 //
289 // load maphead.ext (offsets and tileinfo for map file)
290 //
291 #ifndef AUDIOHEADERLINKED
292     fname = ::data_dir + ::aheadname + ::extension;
293 
294     handle.open(fname);
295     if (!handle.is_open()) {
296         ::CA_CannotOpen(fname);
297     }
298 
299     length = static_cast<int32_t>(handle.get_size());
300     ::audiostarts = new int32_t[length / 4];
301     handle.read(::audiostarts, length);
302     handle.close();
303 #else
304     audiohuffman = (huffnode*)&audiodict;
305     CAL_OptimizeNodes(audiohuffman);
306     audiostarts = (int32_t*)FP_SEG(&audiohead);
307 #endif
308 
309 //
310 // open the data file
311 //
312     ::OpenAudioFile();
313 }
314 
CAL_SetupGrFile()315 void CAL_SetupGrFile()
316 {
317     std::string fname;
318     bstone::FileStream handle;
319     uint8_t* compseg;
320 
321     //
322     // load ???dict.ext (huffman dictionary for graphics files)
323     //
324 
325     fname = ::data_dir + ::gdictname + ::extension;
326 
327     handle.open(fname);
328 
329     if (!handle.is_open()) {
330         ::CA_CannotOpen(fname);
331     }
332 
333     handle.read(&::grhuffman, sizeof(::grhuffman));
334 
335     //
336     // load the data offsets from ???head.ext
337     //
338     int grstarts_size = (NUMCHUNKS + 1) * FILEPOSSIZE;
339 
340     ::grstarts = new int32_t[(grstarts_size + 3) / 4];
341 
342     fname = ::data_dir + ::gheadname + ::extension;
343 
344     handle.open(fname);
345 
346     if (!handle.is_open()) {
347         ::CA_CannotOpen(fname);
348     }
349 
350     handle.read(::grstarts, grstarts_size);
351 
352     //
353     // Open the graphics file, leaving it open until the game is finished
354     //
355     ::OpenGrFile();
356 
357     //
358     // load the pic and sprite headers into the arrays in the data segment
359     //
360     ::pictable = new pictabletype[NUMPICS];
361     ::CAL_GetGrChunkLength(STRUCTPIC); // position file pointer
362     compseg = new uint8_t[::chunkcomplen];
363     ::grhandle.read(compseg, ::chunkcomplen);
364 
365     ::CAL_HuffExpand(
366         compseg,
367         reinterpret_cast<uint8_t*>(pictable),
368         NUMPICS * sizeof(pictabletype),
369         ::grhuffman);
370 
371     delete [] compseg;
372 }
373 
CAL_SetupMapFile()374 void CAL_SetupMapFile()
375 {
376     int16_t i;
377     bstone::FileStream handle;
378     int32_t pos;
379     std::string fname;
380     mapfiletype header;
381     maptype* map_header;
382 
383     //
384     // load maphead.ext (offsets and tileinfo for map file)
385     //
386 
387     fname = ::data_dir + ::mheadname + ::extension;
388 
389     handle.open(fname);
390 
391     if (!handle.is_open()) {
392         CA_CannotOpen(fname);
393     }
394 
395     handle.read(&header.RLEWtag, sizeof(header.RLEWtag));
396     handle.read(&header.headeroffsets, sizeof(header.headeroffsets));
397 
398     rlew_tag = header.RLEWtag;
399 
400     //
401     // open the data file
402     //
403     OpenMapFile();
404 
405     //
406     // load all map header
407     //
408     for (i = 0; i < NUMMAPS; ++i) {
409         pos = header.headeroffsets[i];
410 
411         if (pos < 0) {
412             continue;
413         }
414 
415         mapheaderseg[i] = new maptype();
416         map_header = mapheaderseg[i];
417 
418         maphandle.set_position(pos);
419 
420         maphandle.read(
421             &map_header->planestart,
422             sizeof(map_header->planestart));
423 
424         maphandle.read(
425             &map_header->planelength,
426             sizeof(map_header->planelength));
427 
428         maphandle.read(
429             &map_header->width,
430             sizeof(map_header->width));
431 
432         maphandle.read(
433             &map_header->height,
434             sizeof(map_header->height));
435 
436         maphandle.read(
437             &map_header->name,
438             sizeof(map_header->name));
439     }
440 
441     //
442     // allocate space for 3 64*64 planes
443     //
444     for (i = 0; i < MAPPLANES; ++i) {
445         mapsegs[i] = new uint16_t[64 * 64];
446     }
447 
448     CloseMapFile();
449 }
450 
451 
452 // --------------------- Other general functions ------------------------
453 
454 extern CP_itemtype NewEmenu[];
455 extern int16_t EpisodeSelect[];
456 
457 
458 namespace {
459 
460 
get_ref_vgahead_offset_count(GameType game_type)461 int get_ref_vgahead_offset_count(
462     GameType game_type)
463 {
464     switch (game_type) {
465     case GameType::aog_sw:
466         return 213;
467 
468     case GameType::aog_full_v1_0:
469         return 213;
470 
471     case GameType::aog_full_v2_x:
472         return 224;
473 
474     case GameType::aog_full_v3_0:
475         return 226;
476 
477     case GameType::ps:
478         return 249;
479 
480     default:
481         throw std::invalid_argument("Invalid game type.");
482     }
483 }
484 
get_file_names(GameType game_type)485 const bstone::StringList& get_file_names(
486     GameType game_type)
487 {
488     static const bstone::StringList aog_sw_file_names = {
489         "AUDIOHED.BS1",
490         "AUDIOT.BS1",
491         "IANIM.BS1",
492         "MAPHEAD.BS1",
493         "MAPTEMP.BS1",
494         "SANIM.BS1",
495         "VGADICT.BS1",
496         "VGAGRAPH.BS1",
497         "VGAHEAD.BS1",
498         "VSWAP.BS1",
499     }; // aog_sw_file_names
500 
501     static const bstone::StringList aog_full_file_names = {
502         "AUDIOHED.BS6",
503         "AUDIOT.BS6",
504         "EANIM.BS6",
505         "GANIM.BS6",
506         "IANIM.BS6",
507         "MAPHEAD.BS6",
508         "MAPTEMP.BS6",
509         "SANIM.BS6",
510         "VGADICT.BS6",
511         "VGAGRAPH.BS6",
512         "VGAHEAD.BS6",
513         "VSWAP.BS6",
514     }; // aog_file_names
515 
516     static const bstone::StringList ps_file_names = {
517         "AUDIOHED.VSI",
518         "AUDIOT.VSI",
519         "EANIM.VSI",
520         "IANIM.VSI",
521         "MAPHEAD.VSI",
522         "MAPTEMP.VSI",
523         "VGADICT.VSI",
524         "VGAGRAPH.VSI",
525         "VGAHEAD.VSI",
526         "VSWAP.VSI",
527     }; // ps_file_names
528 
529 
530     switch (game_type) {
531     case GameType::aog_sw:
532         return aog_sw_file_names;
533 
534     case GameType::aog_full_v1_0:
535     case GameType::aog_full_v2_x:
536     case GameType::aog_full_v3_0:
537         return aog_full_file_names;
538 
539     case GameType::ps:
540         return ps_file_names;
541 
542     default:
543         throw std::invalid_argument("Invalid game type.");
544     }
545 }
546 
get_file_extension(GameType game_type)547 const std::string& get_file_extension(
548     GameType game_type)
549 {
550     static const std::string aog_sw_extension = "BS1";
551     static const std::string aog_full_extension = "BS6";
552     static const std::string ps_extension = "VSI";
553 
554     switch (game_type) {
555     case GameType::aog_sw:
556         return aog_sw_extension;
557 
558     case GameType::aog_full_v1_0:
559     case GameType::aog_full_v2_x:
560     case GameType::aog_full_v3_0:
561         return aog_full_extension;
562 
563     case GameType::ps:
564         return ps_extension;
565 
566     default:
567         throw std::invalid_argument("Invalid game type.");
568     }
569 }
570 
are_files_exist(GameType game_type)571 bool are_files_exist(
572     GameType game_type)
573 {
574     auto&& file_names = get_file_names(game_type);
575 
576     for (const auto& file_name : file_names) {
577         auto file_path = ::data_dir + file_name;
578 
579         if (!bstone::FileStream::is_exists(file_path)) {
580             return false;
581         }
582     }
583 
584     return true;
585 }
586 
get_vgahead_offset_count(GameType game_type)587 int get_vgahead_offset_count(
588     GameType game_type)
589 {
590     auto file_name = "VGAHEAD." + get_file_extension(game_type);
591 
592     bstone::FileStream stream(::data_dir + file_name);
593 
594     if (!stream.is_open()) {
595         return 0;
596     }
597 
598     auto file_size = stream.get_size();
599 
600     if ((file_size % FILEPOSSIZE) != 0) {
601         return 0;
602     }
603 
604     return static_cast<int>(file_size / FILEPOSSIZE);
605 }
606 
check_vgahead_offset_count(GameType game_type)607 bool check_vgahead_offset_count(
608     GameType game_type)
609 {
610     auto offset_count = get_vgahead_offset_count(game_type);
611     return offset_count == get_ref_vgahead_offset_count(game_type);
612 }
613 
set_game_type(GameType game_type)614 static bool set_game_type(
615     GameType game_type)
616 {
617     if (!are_files_exist(game_type)) {
618         return false;
619     }
620 
621     if (!check_vgahead_offset_count(game_type)) {
622         return false;
623     }
624 
625     ::g_game_type = game_type;
626 
627     return true;
628 }
629 
630 
631 } // namespace
632 
633 
CheckForEpisodes()634 void CheckForEpisodes()
635 {
636     bool is_succeed = true;
637 
638     ::g_game_type = GameType::none;
639 
640     if (::g_args.has_option("aog_sw")) {
641         bstone::Log::write("Forcing Aliens Of Gold (shareware, v3.0).\n");
642 
643         if (!::set_game_type(GameType::aog_sw)) {
644             is_succeed = false;
645         }
646     } else if (::g_args.has_option("aog_10")) {
647         bstone::Log::write("Forcing Aliens Of Gold (full, v1.0).\n");
648 
649         if (!::set_game_type(GameType::aog_full_v1_0)) {
650             is_succeed = false;
651         }
652     } else if (::g_args.has_option("aog_2x")) {
653         bstone::Log::write("Forcing Aliens Of Gold (full, v2.x).\n");
654 
655         if (!::set_game_type(GameType::aog_full_v2_x)) {
656             is_succeed = false;
657         }
658     } else if (::g_args.has_option("aog_30")) {
659         bstone::Log::write("Forcing Aliens Of Gold (full, v3.0).\n");
660 
661         if (!::set_game_type(GameType::aog_full_v3_0)) {
662             is_succeed = false;
663         }
664     } else if (::g_args.has_option("ps")) {
665         bstone::Log::write("Forcing Planet Strike (full, v1.0/v1.1).\n");
666 
667         if (!::set_game_type(GameType::ps)) {
668             is_succeed = false;
669         }
670     } else {
671         bool is_found = false;
672 
673         bstone::Log::write("Searching for data files...");
674 
675         if (!is_found) {
676             is_found = ::set_game_type(GameType::aog_full_v3_0);
677         }
678 
679         if (!is_found) {
680             is_found = ::set_game_type(GameType::aog_full_v2_x);
681         }
682 
683         if (!is_found) {
684             is_found = ::set_game_type(GameType::aog_full_v1_0);
685         }
686 
687         if (!is_found) {
688             is_found = ::set_game_type(GameType::ps);
689         }
690 
691         if (!is_found) {
692             is_found = ::set_game_type(GameType::aog_sw);
693         }
694 
695         if (is_found) {
696             switch (::g_game_type) {
697             case GameType::aog_sw:
698                 bstone::Log::write("Found Aliens Of Gold (shareware, v3.0).\n");
699                 break;
700 
701             case GameType::aog_full_v1_0:
702                 bstone::Log::write("Found Aliens Of Gold (full, v1.0).\n");
703                 break;
704 
705             case GameType::aog_full_v2_x:
706                 bstone::Log::write("Found Aliens Of Gold (full, v2.x).\n");
707                 break;
708 
709             case GameType::aog_full_v3_0:
710                 bstone::Log::write("Found Aliens Of Gold (full, v3.0).\n");
711                 break;
712 
713             case GameType::ps:
714                 bstone::Log::write("Found Planet Strike (v1.x).\n");
715                 break;
716 
717             default:
718                 is_succeed = false;
719                 break;
720             }
721         } else {
722             is_succeed = false;
723         }
724     }
725 
726     if (!is_succeed) {
727         ::Quit("Data files not found.");
728     }
729 
730 
731     ::extension = ::get_file_extension(::g_game_type);
732 
733     for (int i = 0; i < mv_NUM_MOVIES; ++i) {
734         ::movies[i].file_name += ::extension;
735     }
736 
737     if (::is_aog_full()) {
738         for (int i = 1; i < 6; ++i) {
739             ::NewEmenu[i].active = AT_ENABLED;
740             ::EpisodeSelect[i] = 1;
741         }
742     }
743 
744     ::PageFileName += ::extension;
745     ::audioname += ::extension;
746 }
747 
748 
749 extern const char* MainStrs[];
750 extern char bc_buffer[];
751 
752 
PreDemo()753 void PreDemo()
754 {
755     if (::no_screens) {
756         return;
757     }
758 
759     VL_SetPaletteIntensity(0, 255, vgapal, 0);
760 
761     if (!(gamestate.flags & GS_NOWAIT)) {
762         if (::is_aog_full()) {
763             // ---------------------
764             // Anti-piracy screen
765             // ---------------------
766 
767             // Cache pic
768             //
769             CA_CacheScreen(PIRACYPIC);
770 
771             // Cache and set palette.  AND  Fade it in!
772             //
773             CA_CacheGrChunk(PIRACYPALETTE);
774             VL_SetPalette(0, 256, static_cast<const uint8_t*>(grsegs[PIRACYPALETTE]));
775             VL_SetPaletteIntensity(0, 255, static_cast<const uint8_t*>(grsegs[PIRACYPALETTE]), 0);
776             VW_UpdateScreen();
777 
778             VL_FadeOut(0, 255, 0, 0, 25, 20);
779             VL_FadeIn(0, 255, static_cast<const uint8_t*>(grsegs[PIRACYPALETTE]), 30);
780 
781             // Wait a little
782             //
783             IN_UserInput(TickBase * 20);
784 
785             // Free palette
786             //
787             UNCACHEGRCHUNK(PIRACYPALETTE);
788 
789             VL_FadeOut(0, 255, 0, 0, 25, 20);
790             VW_FadeOut();
791 
792             // Cleanup screen for upcoming SetPalette call
793             //
794             ::VL_Bar(0, 0, 320, 200, 0);
795         }
796 
797         // ---------------------
798         // Apogee presents
799         // ---------------------
800 
801         // Cache pic
802         //
803         CA_CacheScreen(APOGEEPIC);
804 
805         // Load and start music
806         //
807         CA_CacheAudioChunk(STARTMUSIC + APOGFNFM_MUS);
808 
809         ::SD_StartMusic(APOGFNFM_MUS);
810 
811         // Cache and set palette.  AND  Fade it in!
812         //
813         CA_CacheGrChunk(APOGEEPALETTE);
814         VL_SetPalette(0, 256, static_cast<const uint8_t*>(grsegs[APOGEEPALETTE]));
815         VL_SetPaletteIntensity(0, 255, static_cast<const uint8_t*>(grsegs[APOGEEPALETTE]), 0);
816         VW_UpdateScreen();
817         if (::is_aog()) {
818             VL_FadeOut(0, 255, 0, 0, 0, 20);
819         } else {
820             VL_FadeOut(0, 255, 25, 29, 53, 20);
821         }
822         VL_FadeIn(0, 255, static_cast<const uint8_t*>(grsegs[APOGEEPALETTE]), 30);
823 
824         // Wait for end of fanfare
825         //
826         if (::sd_is_music_enabled) {
827             IN_StartAck();
828             while ((!sqPlayedOnce) && (!IN_CheckAck())) {
829             }
830         } else {
831             IN_UserInput(TickBase * 6);
832         }
833 
834         SD_MusicOff();
835 
836         // Free palette and music.  AND  Restore palette
837         //
838         UNCACHEGRCHUNK(APOGEEPALETTE);
839 
840         delete [] audiosegs[STARTMUSIC + APOGFNFM_MUS];
841         audiosegs[STARTMUSIC + APOGFNFM_MUS] = nullptr;
842 
843         if (::is_ps()) {
844             // Do A Blue Flash!
845             ::VL_FadeOut(0, 255, 25, 29, 53, 20);
846         } else {
847             ::VL_FadeOut(0, 255, 0, 0, 0, 30);
848         }
849 
850         // ---------------------
851         // JAM logo intro
852         // ---------------------
853 
854         // Load and start music
855         //
856         CA_CacheAudioChunk(STARTMUSIC + TITLE_LOOP_MUSIC);
857         ::SD_StartMusic(TITLE_LOOP_MUSIC);
858 
859         // Show JAM logo
860         //
861         if (!DoMovie(mv_intro, 0)) {
862             ::Quit("JAM animation (IANIM.xxx) does not exist.");
863         }
864 
865         // ---------------------
866         // PC-13
867         // ---------------------
868         VL_Bar(0, 0, 320, 200, 0x14);
869         CacheDrawPic(0, 64, PC13PIC);
870         VW_UpdateScreen();
871         VW_FadeIn();
872         IN_UserInput(TickBase * 2);
873 
874         // Do A Red Flash!
875 
876         if (::is_aog()) {
877             ::VL_FadeOut(0, 255, 39, 0, 0, 20);
878         } else {
879             ::VL_FadeOut(0, 255, 0, 0, 0, 20);
880         }
881 
882         VW_FadeOut();
883     }
884 }
885 
InitGame()886 void InitGame()
887 {
888     int16_t i, x, y;
889     uint16_t* blockstart;
890 
891     CA_Startup();
892     VW_Startup();
893     IN_Startup();
894     PM_Startup();
895     SD_Startup();
896     US_Startup();
897 
898     VL_SetPalette(0, 256, vgapal);
899 
900     //
901     // build some tables
902     //
903 
904     InitDigiMap();
905 
906     for (i = 0; i < MAPSIZE; i++) {
907         nearmapylookup[i] = &tilemap[0][0] + MAPSIZE * i;
908         farmapylookup[i] = i * 64;
909     }
910 
911     for (i = 0; i < PORTTILESHIGH; i++) {
912         uwidthtable[i] = UPDATEWIDE * i;
913     }
914 
915     blockstart = &blockstarts[0];
916     for (y = 0; y < UPDATEHIGH; y++) {
917         for (x = 0; x < UPDATEWIDE; x++) {
918             *blockstart++ = SCREENWIDTH * 16 * y + x * TILEWIDTH;
919         }
920     }
921 
922     updateptr = &update[0];
923 
924     bufferofs = 0;
925 
926     ::ReadConfig();
927     ::read_high_scores();
928 
929 
930     //
931     // load in and lock down some basic chunks
932     //
933 
934     LoadFonts();
935 
936     LoadLatchMem();
937     BuildTables(); // trig tables
938     SetupWalls();
939     NewViewSize();
940 
941     //
942     // initialize variables
943     //
944 
945     InitRedShifts();
946 }
947 
scan_atoi(const char * s)948 uint16_t scan_atoi(
949     const char* s)
950 {
951     while (*s && (!isdigit(*s))) { // First scans for a digit...
952         s++;
953     }
954 
955     return static_cast<uint16_t>(atoi(s)); // Then converts to integer...
956 }
957 
958 
959 extern const char* MainStrs[];
960 extern int16_t starting_episode, starting_level, starting_difficulty;
961 
962 
freed_main()963 void freed_main()
964 {
965     if (::g_args.has_option("version")) {
966         bstone::Log::write_version();
967         ::Quit();
968     }
969 
970     // Setup for APOGEECD thingie.
971     //
972     ::InitDestPath();
973 
974     // Make sure there's room to play the game
975     //
976     ::CheckDiskSpace(DISK_SPACE_NEEDED, CANT_PLAY_TXT, cds_dos_print);
977 
978     // Which version is this? (SHAREWARE? 1-3? 1-6?)
979     //
980     ::CheckForEpisodes();
981 
982     // BBi
983     ::initialize_sprites();
984     ::initialize_gfxv_contants();
985     ::initialize_states();
986     ::initialize_tp_shape_table();
987     ::initialize_tp_animation_table();
988     ::initialize_audio_constants();
989     ::initialize_songs();
990     ::initialize_static_info_constants();
991     ::initialize_weapon_constants();
992     ::initialize_grenade_shape_constants();
993     ::initialize_static_health_table();
994     ::initialize_boss_constants();
995     ::initialize_messages();
996     ::initialize_ca_constants();
997     ::gamestuff.initialize();
998 
999     if (::g_args.has_option("no_screens")) {
1000         ::no_screens = true;
1001     }
1002 
1003     if (::g_args.has_option("cheats")) {
1004         ::DebugOk = true;
1005     }
1006 
1007     ::InitGame();
1008 
1009     ::PreDemo();
1010 }
1011