Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * Portions of this file are copyright Rebirth contributors and licensed as
3
 * described in COPYING.txt.
4
 * Portions of this file are copyright Parallax Software and licensed
5
 * according to the Parallax license below.
6
 * See COPYING.txt for license details.
7
 
8
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
9
SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
10
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
11
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
12
IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
13
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
14
FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
15
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
16
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
17
COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
18
*/
19
 
20
/*
21
 *
22
 * Routines to display title screens...
23
 *
24
 */
25
 
26
 
27
#include "dxxsconf.h"
28
#include <stdlib.h>
29
#include <stdio.h>
30
#include <string.h>
31
 
32
#if DXX_USE_OGL
33
#include "ogl_init.h"
34
#endif
35
#include "pstypes.h"
36
#include "timer.h"
37
#include "key.h"
38
#include "gr.h"
39
#include "palette.h"
40
#include "iff.h"
41
#include "pcx.h"
42
#include "physfsx.h"
43
#include "u_mem.h"
44
#include "joy.h"
45
#include "titles.h"
46
#include "gamefont.h"
47
#include "gameseq.h"
48
#include "dxxerror.h"
49
#include "robot.h"
50
#include "textures.h"
51
#include "screens.h"
52
#include "multi.h"
53
#include "player.h"
54
#include "digi.h"
55
#include "text.h"
56
#include "kmatrix.h"
57
#include "piggy.h"
58
#include "songs.h"
59
#include "newmenu.h"
60
#include "state.h"
61
#if defined(DXX_BUILD_DESCENT_II)
62
#include "movie.h"
63
#endif
64
#include "menu.h"
65
#include "mouse.h"
66
#include "console.h"
67
#include "args.h"
68
#include "strutil.h"
69
 
70
#include "compiler-range_for.h"
71
#include "partial_range.h"
72
#include <memory>
73
 
74
#if defined(DXX_BUILD_DESCENT_I)
75
constexpr std::true_type EMULATING_D1{};
76
#endif
77
 
78
#if defined(DXX_BUILD_DESCENT_II)
79
#define SHAREWARE_ENDING_FILENAME       "ending.tex"
80
#endif
81
#define DEFAULT_BRIEFING_BKG            "brief03.pcx"
82
 
83
namespace dcx {
84
 
85
static std::array<color_t, 7> Briefing_text_colors;
86
static color_t *Current_color;
87
static color_t Erase_color;
88
 
89
// added by Jan Bobrowski for variable-size menu screen
90
static int rescale_x(const grs_bitmap &cv_bitmap, int x)
91
{
92
        return x * cv_bitmap.bm_w / 320;
93
}
94
 
95
static int rescale_y(const grs_bitmap &cv_bitmap, int y)
96
{
97
        return y * cv_bitmap.bm_h / 200;
98
}
99
 
100
static int get_message_num(const char *&message)
101
{
102
        char *p;
103
        auto num = strtoul(message, &p, 10);
104
        while (*p && *p++ != '\n')              //      Get and drop eoln
105
                ;
106
        message = p;
107
        return num;
108
}
109
 
110
namespace {
111
 
112
struct title_screen : ignore_window_pointer_t
113
{
114
        grs_main_bitmap title_bm;
115
        fix64 timer;
116
        int allow_keys;
117
};
118
 
119
}
120
 
121
static window_event_result title_handler(window *, const d_event &event, title_screen *ts)
122
{
123
        window_event_result result;
124
 
125
        switch (event.type)
126
        {
127
                case EVENT_MOUSE_BUTTON_DOWN:
128
                        if (event_mouse_get_button(event) != 0)
129
                                return window_event_result::ignored;
130
                        else if (ts->allow_keys)
131
                        {
132
                                return window_event_result::close;
133
                        }
134
                        break;
135
 
136
                case EVENT_KEY_COMMAND:
137
                        if ((result = call_default_handler(event)) == window_event_result::ignored)
138
                                if (ts->allow_keys)
139
                                {
140
                                        return window_event_result::close;
141
                                }
142
                        return result;
143
 
144
                case EVENT_JOYSTICK_BUTTON_DOWN:
145
                        if (ts->allow_keys)
146
                        {
147
                                return window_event_result::close;
148
                        }
149
                        break;
150
 
151
                case EVENT_IDLE:
152
                        timer_delay2(50);
153
 
154
                        if (timer_query() > ts->timer)
155
                        {
156
                                return window_event_result::close;
157
                        }
158
                        break;
159
 
160
                case EVENT_WINDOW_DRAW:
161
                        gr_set_default_canvas();
162
                        show_fullscr(*grd_curcanv, ts->title_bm);
163
                        break;
164
 
165
                case EVENT_WINDOW_CLOSE:
166
                        break;
167
 
168
                default:
169
                        break;
170
        }
171
        return window_event_result::ignored;
172
}
173
 
174
static void show_title_screen(const char * filename, int allow_keys, int from_hog_only )
175
{
176
        char new_filename[PATH_MAX] = "";
177
 
178
        auto ts = std::make_unique<title_screen>();
179
        ts->allow_keys = allow_keys;
180
 
181
        (void)from_hog_only;
182
 
183
        strcat(new_filename,filename);
184
        filename = new_filename;
185
 
186
        ts->timer = timer_query() + i2f(3);
187
        const auto pcx_error = pcx_read_bitmap(filename, ts->title_bm, gr_palette);
188
        if (pcx_error != pcx_result::SUCCESS)
189
        {
190
                con_printf(CON_URGENT, "%s:%u: error: loading briefing screen <%s> failed: PCX load error: %s (%u)", __FILE__, __LINE__, filename, pcx_errormsg(pcx_error), static_cast<unsigned>(pcx_error));
191
                return;
192
        }
193
 
194
        gr_palette_load( gr_palette );
195
 
196
        const auto wind = window_create(grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, title_handler, ts.get());
197
        if (!wind)
198
        {
199
                return;
200
        }
201
 
202
        event_process_all();
203
}
204
 
205
static void show_first_found_title_screen(const char *oem, const char *share, const char *macshare)
206
{
207
        const char *filename = oem;
208
        if ((PHYSFSX_exists(filename, 1)) ||
209
                (filename = share, PHYSFSX_exists(filename, 1)) ||
210
                (filename = macshare, PHYSFSX_exists(filename, 1))
211
                )
212
                show_title_screen(filename, 1, 1);
213
}
214
 
215
}
216
 
217
namespace dsx {
218
#if defined(DXX_BUILD_DESCENT_II)
219
int intro_played;
220
static int DefineBriefingBox(const grs_bitmap &, const char *&buf);
221
#endif
222
 
223
void show_titles(void)
224
{
225
#if defined(DXX_BUILD_DESCENT_I)
226
        songs_play_song(SONG_TITLE, 1);
227
#endif
228
        if (CGameArg.SysNoTitles)
229
                return;
230
#if defined(DXX_BUILD_DESCENT_I)
231
 
232
        show_first_found_title_screen(
233
                "macplay.pcx"// Mac Shareware
234
                "mplaycd.pcx"// Mac Registered
235
                "iplogo1.pcx"   // PC. Only down here because it's lowres ;-)
236
        );
237
        const bool resolution_at_least_640_480 = (SWIDTH >= 640 && SHEIGHT >= 480);
238
        auto &logo_hires_pcx = "logoh.pcx";
239
        auto &descent_hires_pcx = "descenth.pcx";
240
        show_title_screen((resolution_at_least_640_480 && PHYSFSX_exists(logo_hires_pcx, 1)) ? logo_hires_pcx : "logo.pcx", 1, 1);
241
        show_title_screen((resolution_at_least_640_480 && PHYSFSX_exists(descent_hires_pcx, 1)) ? descent_hires_pcx : "descent.pcx", 1, 1);
242
#elif defined(DXX_BUILD_DESCENT_II)
243
        int played=MOVIE_NOT_PLAYED;    //default is not played
244
        int song_playing = 0;
245
 
246
#define MOVIE_REQUIRED 1        //(!is_D2_OEM && !is_SHAREWARE && !is_MAC_SHARE)        // causes segfault
247
 
248
        const auto hiresmode = HIRESMODE;
249
        {       //show bundler screens
250
                played=MOVIE_NOT_PLAYED;        //default is not played
251
 
252
                played = PlayMovie(NULL, "pre_i.mve",0);
253
 
254
                if (!played) {
255
                        char filename[12];
256
                        strcpy(filename, hiresmode ? "pre_i1b.pcx" : "pre_i1.pcx");
257
 
258
                        while (PHYSFSX_exists(filename,0))
259
                        {
260
                                show_title_screen( filename, 1, 0 );
261
                                filename[5]++;
262
                        }
263
                }
264
        }
265
 
266
        played = PlayMovie("intro.tex", "intro.mve",MOVIE_REQUIRED);
267
 
268
        if (played != MOVIE_NOT_PLAYED)
269
                intro_played = 1;
270
        else
271
        {                                               //didn't get intro movie, try titles
272
 
273
                played = PlayMovie(NULL, "titles.mve",MOVIE_REQUIRED);
274
 
275
                if (played == MOVIE_NOT_PLAYED)
276
                {
277
                        con_puts(CON_DEBUG, "Playing title song...");
278
                        songs_play_song( SONG_TITLE, 1);
279
                        song_playing = 1;
280
                        con_puts(CON_DEBUG, "Showing logo screens...");
281
 
282
                        show_first_found_title_screen(
283
                                hiresmode ? "iplogo1b.pcx" : "iplogo1.pcx", // OEM
284
                                "iplogo1.pcx", // SHAREWARE
285
                                "mplogo.pcx" // MAC SHAREWARE
286
                                );
287
                        show_first_found_title_screen(
288
                                hiresmode ? "logob.pcx" : "logo.pcx", // OEM
289
                                "logo.pcx", // SHAREWARE
290
                                "plogo.pcx" // MAC SHAREWARE
291
                                );
292
                }
293
        }
294
 
295
        {       //show bundler movie or screens
296
                played=MOVIE_NOT_PLAYED;        //default is not played
297
 
298
                //check if OEM movie exists, so we don't stop the music if it doesn't
299
                if (RAIIPHYSFS_File{PHYSFS_openRead("oem.mve")})
300
                {
301
                        played = PlayMovie(NULL, "oem.mve",0);
302
                        song_playing = 0;               //movie will kill sound
303
                }
304
 
305
                if (!played)
306
                {
307
                        char filename[12];
308
                        strcpy(filename, hiresmode ? "oem1b.pcx" : "oem1.pcx");
309
                        while (PHYSFSX_exists(filename,0))
310
                        {
311
                                show_title_screen( filename, 1, 0 );
312
                                filename[3]++;
313
                        }
314
                }
315
        }
316
 
317
        if (!song_playing)
318
        {
319
                con_puts(CON_DEBUG, "Playing title song...");
320
                songs_play_song( SONG_TITLE, 1);
321
        }
322
        con_puts(CON_DEBUG, "Showing logo screen...");
323
        const auto filename = hiresmode ? "descentb.pcx" : "descent.pcx";
324
        if (PHYSFSX_exists(filename,1))
325
                show_title_screen(filename, 1, 1);
326
#endif
327
}
328
 
329
void show_order_form()
330
{
331
        if (CGameArg.SysNoTitles)
332
                return;
333
 
334
#if defined(DXX_BUILD_DESCENT_I)
335
        show_first_found_title_screen(
336
                "warning.pcx"// D1 Registered
337
                "apple.pcx",    // D1 Mac OEM Demo
338
                "order01.pcx"   // D1 Demo
339
        );
340
#elif defined(DXX_BUILD_DESCENT_II)
341
#if !DXX_USE_EDITOR
342
        key_flush();
343
        const auto hiresmode = HIRESMODE;
344
        /*
345
         * If D2 registered, all checks fail and nothing is shown.
346
         */
347
        const char *exit_screen = hiresmode ? "ordrd2ob.pcx" : "ordrd2o.pcx"; // OEM
348
        if ((PHYSFSX_exists(exit_screen, 1)) ||
349
                // SHAREWARE, prefer mac if hires
350
                (exit_screen = hiresmode ? "orderd2b.pcx" : "orderd2.pcx", PHYSFSX_exists(exit_screen, 1)) ||
351
                // SHAREWARE, have to rescale
352
                (exit_screen = hiresmode ? "orderd2.pcx" : "orderd2b.pcx", PHYSFSX_exists(exit_screen, 1)) ||
353
                // D1
354
                (exit_screen = hiresmode ? "warningb.pcx" : "warning.pcx", PHYSFSX_exists(exit_screen, 1))
355
                )
356
                show_title_screen(exit_screen,1,0);
357
#endif
358
#endif
359
}
360
}
361
 
362
namespace dcx {
363
namespace {
364
 
365
//-----------------------------------------------------------------------------
366
struct briefing_screen {
367
        char    bs_name[13];                //  filename, eg merc01.  Assumes .lbm suffix.
368
        sbyte   level_num;
369
        sbyte   message_num;
370
        short   text_ulx, text_uly;         //  upper left x,y of text window
371
        short   text_width, text_height;    //  width and height of text window
372
};
373
 
374
#define ENDING_LEVEL_NUM_OEMSHARE 0x7f
375
#define ENDING_LEVEL_NUM_REGISTER 0x7e
376
 
377
}
378
 
379
static grs_subcanvas_ptr create_spinning_robot_sub_canvas(grs_canvas &canvas)
380
{
381
        return gr_create_sub_canvas(canvas, rescale_x(canvas.cv_bitmap, 138), rescale_y(canvas.cv_bitmap, 55), rescale_x(canvas.cv_bitmap, 166), rescale_y(canvas.cv_bitmap, 138));
382
}
383
 
384
static void get_message_name(const char *&message, std::array<char, 32> &result, const char *const trailer)
385
{
386
        auto p = message;
387
        for (; *p == ' '; ++p)
388
        {
389
        }
390
        const auto e = std::prev(result.end(), sizeof(".bbm"));
391
        auto i = result.begin();
392
        char c;
393
        for (; (c = *p) && c != ' ' && c != '\n'; ++p)
394
        {
395
                *i++ = c;
396
                if (i == e)
397
                        /* Avoid buffer overflow; this was not present in the
398
                         * original code.
399
                         */
400
                        break;
401
        }
402
        /* This is inconsistent.  If the copy loop terminated on a newline,
403
         * then `p` points to the newline and the next loop is skipped.  If
404
         * the copy loop terminated on a null, the next loop is attempted,
405
         * but exits immediately.  In both those cases, `p` is unchanged.
406
         * If the copy loop terminated on any other character, the next loop
407
         * will advance `p` to point to a null (consistent with the copy
408
         * loop terminating on a null) or past the newline (inconsistent
409
         * with the copy loop).
410
         *
411
         * This inconsistency was present in the prior version of the code,
412
         * and is retained in case there exist briefings which rely on this
413
         * inconsistency.
414
         */
415
        if (c != '\n')
416
                while ((c = *p) && (++p, c) != '\n')            //      Get and drop eoln
417
                {
418
                }
419
        message = p;
420
        strcpy(i, trailer);
421
}
422
}
423
 
424
namespace dsx {
425
namespace {
426
 
427
#if defined(DXX_BUILD_DESCENT_II)
428
 
429
static std::array<briefing_screen, 60> Briefing_screens{{
430
        {"brief03.pcx",0,3,8,8,257,177}
431
}}; // default=0!!!
432
#endif
433
 
434
constexpr briefing_screen D1_Briefing_screens_full[] = {
435
        { "brief01.pcx",   0,  1,  13, 140, 290,  59 },
436
        { "brief02.pcx",   0,  2,  27,  34, 257, 177 },
437
        { "brief03.pcx",   0,  3,  20,  22, 257, 177 },
438
        { "brief02.pcx",   0,  4,  27,  34, 257, 177 },
439
        { "moon01.pcx",    1,  5,  10,  10, 300, 170 }, // level 1
440
        { "moon01.pcx",    2,  6,  10,  10, 300, 170 }, // level 2
441
        { "moon01.pcx",    3,  7,  10,  10, 300, 170 }, // level 3
442
        { "venus01.pcx",   4,  8,  15, 15, 300,  200 }, // level 4
443
        { "venus01.pcx",   5,  9,  15, 15, 300,  200 }, // level 5
444
        { "brief03.pcx",   6, 10,  20,  22, 257, 177 },
445
        { "merc01.pcx",    6, 11,  10, 15, 300, 200 },  // level 6
446
        { "merc01.pcx",    7, 12,  10, 15, 300, 200 },  // level 7
447
        { "brief03.pcx",   8, 13,  20,  22, 257, 177 },
448
        { "mars01.pcx",    8, 14,  10, 100, 300,  200 }, // level 8
449
        { "mars01.pcx",    9, 15,  10, 100, 300,  200 }, // level 9
450
        { "brief03.pcx",  10, 16,  20,  22, 257, 177 },
451
        { "mars01.pcx",   10, 17,  10, 100, 300,  200 }, // level 10
452
        { "jup01.pcx",    11, 18,  10, 40, 300,  200 }, // level 11
453
        { "jup01.pcx",    12, 19,  10, 40, 300,  200 }, // level 12
454
        { "brief03.pcx",  13, 20,  20,  22, 257, 177 },
455
        { "jup01.pcx",    13, 21,  10, 40, 300,  200 }, // level 13
456
        { "jup01.pcx",    14, 22,  10, 40, 300,  200 }, // level 14
457
        { "saturn01.pcx", 15, 23,  10, 40, 300,  200 }, // level 15
458
        { "brief03.pcx",  16, 24,  20,  22, 257, 177 },
459
        { "saturn01.pcx", 16, 25,  10, 40, 300,  200 }, // level 16
460
        { "brief03.pcx",  17, 26,  20,  22, 257, 177 },
461
        { "saturn01.pcx", 17, 27,  10, 40, 300,  200 }, // level 17
462
        { "uranus01.pcx", 18, 28,  100, 100, 300,  200 }, // level 18
463
        { "uranus01.pcx", 19, 29,  100, 100, 300,  200 }, // level 19
464
        { "uranus01.pcx", 20, 30,  100, 100, 300,  200 }, // level 20
465
        { "uranus01.pcx", 21, 31,  100, 100, 300,  200 }, // level 21
466
        { "neptun01.pcx", 22, 32,  10, 20, 300,  200 }, // level 22
467
        { "neptun01.pcx", 23, 33,  10, 20, 300,  200 }, // level 23
468
        { "neptun01.pcx", 24, 34,  10, 20, 300,  200 }, // level 24
469
        { "pluto01.pcx",  25, 35,  10, 20, 300,  200 }, // level 25
470
        { "pluto01.pcx",  26, 36,  10, 20, 300,  200 }, // level 26
471
        { "pluto01.pcx",  27, 37,  10, 20, 300,  200 }, // level 27
472
        { "aster01.pcx",  -1, 38,  10, 90, 300,  200 }, // secret level -1
473
        { "aster01.pcx",  -2, 39,  10, 90, 300,  200 }, // secret level -2
474
        { "aster01.pcx",  -3, 40,  10, 90, 300,  200 }, // secret level -3
475
        { "end01.pcx",   ENDING_LEVEL_NUM_OEMSHARE,  1,  23, 40, 320, 200 },   //  OEM and shareware end
476
        { "end02.pcx",   ENDING_LEVEL_NUM_REGISTER,  1,  5, 5, 300, 200 },    // registered end
477
        { "end01.pcx",   ENDING_LEVEL_NUM_REGISTER,  2,  23, 40, 320, 200 },  // registered end
478
        { "end03.pcx",   ENDING_LEVEL_NUM_REGISTER,  3,  5, 5, 300, 200 },    // registered end
479
};
480
 
481
constexpr briefing_screen D1_Briefing_screens_share[] = {
482
        { "brief01.pcx",   0,  1,  13, 140, 290,  59 },
483
        { "brief02.pcx",   0,  2,  27,  34, 257, 177 },
484
        { "brief03.pcx",   0,  3,  20,  22, 257, 177 },
485
        { "brief02.pcx",   0,  4,  27,  34, 257, 177 },
486
        { "moon01.pcx",    1,  5,  10,  10, 300, 170 }, // level 1
487
        { "moon01.pcx",    2,  6,  10,  10, 300, 170 }, // level 2
488
        { "moon01.pcx",    3,  7,  10,  10, 300, 170 }, // level 3
489
        { "venus01.pcx",   4,  8,  15, 15, 300,  200 }, // level 4
490
        { "venus01.pcx",   5,  9,  15, 15, 300,  200 }, // level 5
491
        { "brief03.pcx",   6, 10,  20,  22, 257, 177 },
492
        { "merc01.pcx",    6, 10,  10, 15, 300, 200 }, // level 6
493
        { "merc01.pcx",    7, 11,  10, 15, 300, 200 }, // level 7
494
        { "end01.pcx",   ENDING_LEVEL_NUM_OEMSHARE,  1,  23, 40, 320, 200 }, // shareware end
495
};
496
 
497
struct msgstream
498
{
499
        int x;
500
        int y;
501
        color_t color;
502
        char ch;
503
};
504
 
505
constexpr const briefing_screen *get_d1_briefing_screens(const unsigned descent_hog_size)
506
{
507
        if (descent_hog_size == D1_SHAREWARE_MISSION_HOGSIZE || descent_hog_size == D1_SHAREWARE_10_MISSION_HOGSIZE)
508
                return D1_Briefing_screens_share;
509
        return D1_Briefing_screens_full;
510
}
511
 
512
#if defined(DXX_BUILD_DESCENT_I)
513
using briefing_screen_deleter = std::default_delete<briefing_screen>;
514
#elif defined(DXX_BUILD_DESCENT_II)
515
class briefing_screen_deleter : std::default_delete<briefing_screen>
516
{
517
        typedef std::default_delete<briefing_screen> base_deleter;
518
public:
519
        briefing_screen_deleter() = default;
520
        briefing_screen_deleter(base_deleter &&b) : base_deleter(std::move(b)) {}
521
        void operator()(briefing_screen *const p) const
522
        {
523
                if (p >= &Briefing_screens.front() && p <= &Briefing_screens.back())
524
                        return;
525
                this->base_deleter::operator()(p);
526
        }
527
};
528
#endif
529
 
530
struct briefing : ignore_window_pointer_t
531
{
532
        unsigned streamcount;
533
        short   level_num;
534
        short   cur_screen;
535
        std::unique_ptr<briefing_screen, briefing_screen_deleter> screen;
536
        grs_main_bitmap background;
537
#if defined(DXX_BUILD_DESCENT_II)
538
        int             got_z;
539
        RAIIdigi_sound          hum_channel, printing_channel;
540
        MVESTREAM_ptr_t pMovie;
541
#endif
542
        std::unique_ptr<char[]> text;
543
        const char      *message;
544
        int             text_x, text_y;
545
        std::array<msgstream, 2048> messagestream;
546
        short   tab_stop;
547
        ubyte   flashing_cursor;
548
        ubyte   new_page;
549
        int             new_screen;
550
#if defined(DXX_BUILD_DESCENT_II)
551
        ubyte   dumb_adjust;
552
        ubyte   line_adjustment;
553
        char    robot_playing;
554
        short   chattering;
555
#endif
556
        fix64           start_time;
557
        fix64           delay_count;
558
        int             robot_num;
559
        grs_subcanvas_ptr       robot_canv;
560
        vms_angvec      robot_angles;
561
        std::array<char, 32> bitmap_name;
562
        grs_main_bitmap  guy_bitmap;
563
        sbyte   door_dir, door_div_count, animating_bitmap_type;
564
        sbyte   prev_ch;
565
        std::array<char, 16> background_name;
566
};
567
 
568
}
569
 
570
static void briefing_init(briefing *br, short level_num)
571
{
572
        br->level_num = level_num;
573
        if (EMULATING_D1 && (br->level_num == 1))
574
                br->level_num = 0;      // for start of game stuff
575
 
576
        br->cur_screen = 0;
577
        br->background_name.back() = 0;
578
        strncpy(br->background_name.data(), DEFAULT_BRIEFING_BKG, br->background_name.size() - 1);
579
#if defined(DXX_BUILD_DESCENT_II)
580
        br->robot_playing = 0;
581
#endif
582
        br->robot_num = 0;
583
        br->robot_angles = {};
584
        br->bitmap_name[0] = '\0';
585
        br->door_dir = 1;
586
        br->door_div_count = 0;
587
        br->animating_bitmap_type = 0;
588
}
589
 
590
//-----------------------------------------------------------------------------
591
//      Load Descent briefing text.
592
static int load_screen_text(const d_fname &filename, std::unique_ptr<char[]> &buf)
593
{
594
        int len, have_binary = 0;
595
        auto e = end(filename);
596
        auto ext = std::find(begin(filename), e, '.');
597
        if (ext == e)
598
                return (0);
599
        if (!d_stricmp(&*ext, ".txb"))
600
                have_binary = 1;
601
 
602
        auto tfile = PHYSFSX_openReadBuffered(filename);
603
        if (!tfile)
604
                return (0);
605
 
606
        len = PHYSFS_fileLength(tfile);
607
        buf = std::make_unique<char[]>(len + 1);
608
        PHYSFS_read(tfile, buf.get(), 1, len);
609
#if defined(DXX_BUILD_DESCENT_I)
610
        const auto endbuf = &buf[len];
611
#elif defined(DXX_BUILD_DESCENT_II)
612
        const auto endbuf = std::remove(&buf[0], &buf[len], 13);
613
#endif
614
        *endbuf = 0;
615
 
616
        if (have_binary)
617
                decode_text(buf.get(), len);
618
 
619
        return (1);
620
}
621
 
622
#if defined(DXX_BUILD_DESCENT_II)
623
static void set_briefing_fontcolor(struct briefing &br);
624
static int get_new_message_num(const char *&message)
625
{
626
        char *p;
627
        const auto num = strtoul(message, &p, 10);
628
        message = p + 1;
629
        return num;
630
}
631
#endif
632
 
633
// Return a pointer to the start of text for screen #screen_num.
634
static const char * get_briefing_message(const briefing *br, int screen_num)
635
{
636
        const char      *tptr = br->text.get();
637
        int     cur_screen=0;
638
        int     ch;
639
 
640
        Assert(screen_num >= 0);
641
 
642
        while ( (*tptr != 0 ) && (screen_num != cur_screen)) {
643
                ch = *tptr++;
644
                if (ch == '$') {
645
                        ch = *tptr++;
646
                        if (ch == 'S')
647
                                cur_screen = get_message_num(tptr);
648
                }
649
        }
650
 
651
        if (screen_num!=cur_screen)
652
                return (NULL);
653
 
654
        return tptr;
655
}
656
 
657
static void init_char_pos(briefing *br, int x, int y)
658
{
659
        br->text_x = x;
660
        br->text_y = y;
661
}
662
 
663
// Make sure the text stays on the screen
664
// Return 1 if new page required
665
// 0 otherwise
666
static int check_text_pos(briefing *br)
667
{
668
        if (br->text_x > br->screen->text_ulx + br->screen->text_width)
669
        {
670
                br->text_x = br->screen->text_ulx;
671
                br->text_y += br->screen->text_uly;
672
        }
673
 
674
        if (br->text_y > br->screen->text_uly + br->screen->text_height)
675
        {
676
                br->new_page = 1;
677
                return 1;
678
        }
679
 
680
        return 0;
681
}
682
 
683
static void put_char_delay(const grs_font &cv_font, briefing *const br, const char ch)
684
{
685
        char str[2];
686
        int     w;
687
 
688
        str[0] = ch; str[1] = '\0';
689
        if (br->delay_count && (timer_query() < br->start_time + br->delay_count))
690
        {
691
                br->message--;          // Go back to same character
692
                return;
693
        }
694
 
695
        if (br->streamcount >= br->messagestream.size())
696
                return;
697
        br->messagestream[br->streamcount].x = br->text_x;
698
        br->messagestream[br->streamcount].y = br->text_y;
699
        br->messagestream[br->streamcount].color = *Current_color;
700
        br->messagestream[br->streamcount].ch = ch;
701
        br->streamcount++;
702
 
703
        br->prev_ch = ch;
704
        gr_get_string_size(cv_font, str, &w, nullptr, nullptr);
705
        br->text_x += w;
706
 
707
#if defined(DXX_BUILD_DESCENT_II)
708
        if (!EMULATING_D1 && !br->chattering) {
709
                br->printing_channel.reset(digi_start_sound(digi_xlat_sound(SOUND_BRIEFING_PRINTING), F1_0, 0xFFFF/2, 1, -1, -1, sound_object_none));
710
                br->chattering=1;
711
        }
712
#endif
713
 
714
        br->start_time = timer_query();
715
}
716
 
717
static void init_spinning_robot(grs_canvas &canvas, briefing &br);
718
static int load_briefing_screen(grs_canvas &, briefing *br, const char *fname);
719
 
720
// Process a character for the briefing,
721
// including special characters preceded by a '$'.
722
// Return 1 when page is finished, 0 otherwise
723
static int briefing_process_char(grs_canvas &canvas, briefing *const br)
724
{
725
        auto &game_font = *GAME_FONT;
726
        char ch = *br->message++;
727
        if (ch == '$') {
728
                ch = *br->message++;
729
#if defined(DXX_BUILD_DESCENT_II)
730
                if (ch=='D') {
731
                        br->cur_screen = DefineBriefingBox(canvas.cv_bitmap, br->message);
732
                        br->screen.reset(&Briefing_screens[br->cur_screen]);
733
                        init_char_pos(br, br->screen->text_ulx, br->screen->text_uly);
734
                        br->line_adjustment=0;
735
                        br->prev_ch = 10;                                   // read to eoln
736
                } else if (ch=='U') {
737
                        br->cur_screen = get_message_num(br->message);
738
                        br->screen.reset(&Briefing_screens[br->cur_screen]);
739
                        init_char_pos(br, br->screen->text_ulx, br->screen->text_uly);
740
                        br->prev_ch = 10;                                   // read to eoln
741
                } else
742
#endif
743
                if (ch == 'C') {
744
                        auto cc = get_message_num(br->message) - 1;
745
                        if (cc < 0)
746
                                cc = 0;
747
                        else if (cc > Briefing_text_colors.size() - 1)
748
                                cc = Briefing_text_colors.size() - 1;
749
                        Current_color = &Briefing_text_colors[cc];
750
                        br->prev_ch = 10;
751
                } else if (ch == 'F') {     // toggle flashing cursor
752
                        br->flashing_cursor = !br->flashing_cursor;
753
                        br->prev_ch = 10;
754
                        while (*br->message++ != 10)
755
                                ;
756
                } else if (ch == 'T') {
757
                        br->tab_stop = get_message_num(br->message);
758
                        br->prev_ch = 10;                                                       //      read to eoln
759
                } else if (ch == 'R') {
760
                        br->robot_canv.reset();
761
#if defined(DXX_BUILD_DESCENT_II)
762
                        if (br->robot_playing) {
763
                                DeInitRobotMovie(br->pMovie);
764
                                br->robot_playing=0;
765
                        }
766
#endif
767
 
768
                        if (EMULATING_D1) {
769
                                init_spinning_robot(canvas, *br);
770
                                br->robot_num = get_message_num(br->message);
771
#if defined(DXX_BUILD_DESCENT_II)
772
                                while (*br->message++ != 10)
773
                                        ;
774
#endif
775
                        } else {
776
#if defined(DXX_BUILD_DESCENT_II)
777
                                char spinRobotName[]="RBA.MVE", kludge;  // matt don't change this!
778
 
779
                                kludge=*br->message++;
780
                                spinRobotName[2]=kludge; // ugly but proud
781
 
782
                                br->robot_playing=InitRobotMovie(spinRobotName, br->pMovie);
783
 
784
                                // gr_remap_bitmap_good( &grd_curcanv->cv_bitmap, pal, -1, -1 );
785
 
786
                                if (br->robot_playing) {
787
                                        RotateRobot(br->pMovie);
788
                                        set_briefing_fontcolor(*br);
789
                                }
790
#endif
791
                        }
792
                        br->prev_ch = 10;                           // read to eoln
793
                }
794
                else if ((ch == 'N' && (br->animating_bitmap_type = 0, true)) ||
795
                                (ch == 'O' && (br->animating_bitmap_type = 1, true)))
796
                {
797
                        br->robot_canv.reset();
798
                        br->prev_ch = 10;
799
                        get_message_name(br->message, br->bitmap_name, "#0");
800
                } else if (ch=='A') {
801
#if defined(DXX_BUILD_DESCENT_II)
802
                        br->line_adjustment=1-br->line_adjustment;
803
#endif
804
                } else if (ch=='Z') {
805
#if defined(DXX_BUILD_DESCENT_II)
806
                        char fname[15];
807
                        int i;
808
 
809
                        br->got_z=1;
810
                        br->dumb_adjust=1;
811
                        i=0;
812
                        while ((fname[i]=*br->message) != '\n') {
813
                                i++;
814
                                br->message++;
815
                        }
816
                        fname[i]=0;
817
                        if (*br->message != 10)
818
                                while (*br->message++ != 10)    //  Get and drop eoln
819
                                        ;
820
 
821
                        {
822
                                char fname2[15];
823
 
824
                                i=0;
825
                                while (fname[i]!='.') {
826
                                        fname2[i] = fname[i];
827
                                        i++;
828
                                }
829
                                fname2[i++]='b';
830
                                fname2[i++]='.';
831
                                fname2[i++]='p';
832
                                fname2[i++]='c';
833
                                fname2[i++]='x';
834
                                fname2[i++]=0;
835
 
836
                                if ((HIRESMODE && PHYSFSX_exists(fname2,1)) || !PHYSFSX_exists(fname,1))
837
                                        strcpy(fname,fname2);
838
                                load_briefing_screen(*grd_curcanv, br, fname);
839
                        }
840
 
841
#endif
842
                } else if (ch == 'B') {
843
                        std::array<char, 32> bitmap_name;
844
                        palette_array_t         temp_palette;
845
                        int             iff_error;
846
                        br->robot_canv.reset();
847
                        get_message_name(br->message, bitmap_name, ".bbm");
848
                        br->guy_bitmap.reset();
849
                        iff_error = iff_read_bitmap(&bitmap_name[0], br->guy_bitmap, &temp_palette);
850
#if defined(DXX_BUILD_DESCENT_II)
851
                        gr_remap_bitmap_good( br->guy_bitmap, temp_palette, -1, -1 );
852
#endif
853
                        Assert(iff_error == IFF_NO_ERROR);
854
                        (void)iff_error;
855
 
856
                        br->prev_ch = 10;
857
                } else if (ch == 'S') {
858
#if defined(DXX_BUILD_DESCENT_II)
859
                        br->chattering = 0;
860
                        br->printing_channel.reset();
861
#endif
862
 
863
                        br->new_screen = 1;
864
                        return 1;
865
                } else if (ch == 'P') {         //      New page.
866
#if defined(DXX_BUILD_DESCENT_II)
867
                        if (!br->got_z) {
868
                                Int3(); // Hey ryan!!!! You gotta load a screen before you start
869
                                // printing to it! You know, $Z !!!
870
                                load_briefing_screen(*grd_curcanv, br, HIRESMODE ? "end01b.pcx" : "end01.pcx");
871
                        }
872
 
873
                        br->chattering = 0;
874
                        br->printing_channel.reset();
875
#endif
876
 
877
                        br->new_page = 1;
878
 
879
                        while (*br->message != 10) {
880
                                br->message++;  //      drop carriage return after special escape sequence
881
                        }
882
                        br->message++;
883
                        br->prev_ch = 10;
884
 
885
                        return 1;
886
                }
887
#if defined(DXX_BUILD_DESCENT_II)
888
                else if (ch == ':') {
889
                        br->prev_ch = 10;
890
                        auto p = br->message;
891
                        /* Legacy clients do not understand $: and will instead show
892
                         * the remainder of the line.  However, if the next two
893
                         * characters after $: are $F, legacy clients will treat
894
                         * the $F as above, toggle the flashing_cursor flag, then
895
                         * discard the rest of the line.  This special case allows
896
                         * briefing authors to hide the directive from legacy
897
                         * clients, but get the same state of flashing_cursor for
898
                         * both legacy and aware clients.  Briefing authors will
899
                         * likely need an additional $F nearby to balance this
900
                         * toggle, but no additional code here is needed to support
901
                         * that.
902
                         *
903
                         * The trailing colon is cosmetic, so that the compatibility
904
                         * $F is not directly adjacent to the directive.
905
                         */
906
                        if (!strncmp(p, "$F:", 3))
907
                        {
908
                                br->flashing_cursor = !br->flashing_cursor;
909
                                p += 3;
910
                        }
911
                        auto &rotate_robot_label = "Rebirth.rotate.robot ";
912
                        constexpr auto rotate_robot_len = sizeof(rotate_robot_label) - 1;
913
                        if (!strncmp(p, rotate_robot_label, rotate_robot_len))
914
                        {
915
                                char *p2;
916
                                const auto id = strtoul(p + rotate_robot_len, &p2, 10);
917
                                if (*p2 == '\n')
918
                                {
919
                                        p = p2;
920
                                        br->robot_canv.reset();
921
                                        if (br->robot_playing)
922
                                        {
923
                                                br->robot_playing = 0;
924
                                                DeInitRobotMovie(br->pMovie);
925
                                        }
926
                                        init_spinning_robot(canvas, *br);
927
                                        /* This modifies the appearance of the frame, which
928
                                         * is unfortunate.  However, without it, all robots
929
                                         * come out blue shifted.
930
                                         */
931
                                        gr_use_palette_table("groupa.256");
932
                                        br->robot_num = id;
933
                                }
934
                        }
935
                        else
936
                        {
937
                                const char *p2 = p;
938
                                /* Suppress non-printing characters.  No need to support
939
                                 * encodings.
940
                                 */
941
                                for (char c; (c = *p2) >= ' ' && c <= '~'; ++p2)
942
                                {
943
                                }
944
                                con_printf(CON_VERBOSE, "warning: unknown briefing directive \"%.*s\"", DXX_ptrdiff_cast_int(p2 - p), p);
945
                        }
946
                        for (char c; (c = *p) && (++p, c) != '\n';)
947
                        {
948
                                /* Discard through newline.  On break, *p is '\0' or
949
                                 * p[-1] is '\n'.
950
                                 */
951
                        }
952
                        br->message = p;
953
                }
954
#endif
955
                else if (ch == '$' || ch == ';') // Print a $/;
956
                        put_char_delay(game_font, br, ch);
957
        } else if (ch == '\t') {                //      Tab
958
                const auto &&fspacx = FSPACX();
959
                if (br->text_x - br->screen->text_ulx < fspacx(br->tab_stop))
960
                        br->text_x = br->screen->text_ulx + fspacx(br->tab_stop);
961
        } else if ((ch == ';') && (br->prev_ch == 10)) {
962
                while (*br->message++ != 10)
963
                        ;
964
                br->prev_ch = 10;
965
        } else if (ch == '\\') {
966
                br->prev_ch = ch;
967
        } else if (ch == 10) {
968
                if (br->prev_ch != '\\') {
969
                        br->prev_ch = ch;
970
#if defined(DXX_BUILD_DESCENT_II)
971
                        if (br->dumb_adjust)
972
                                br->dumb_adjust--;
973
                        else
974
#endif
975
                                br->text_y += FSPACY(5)+FSPACY(5)*3/5;
976
                        br->text_x = br->screen->text_ulx;
977
                        if (br->text_y > br->screen->text_uly + br->screen->text_height) {
978
#if defined(DXX_BUILD_DESCENT_I)
979
                                const auto descent_hog_size = PHYSFSX_fsize("descent.hog");
980
                                load_briefing_screen(*grd_curcanv, br, get_d1_briefing_screens(descent_hog_size)[br->cur_screen].bs_name);
981
#elif defined(DXX_BUILD_DESCENT_II)
982
                                load_briefing_screen(*grd_curcanv, br, Briefing_screens[br->cur_screen].bs_name);
983
#endif
984
                                br->text_x = br->screen->text_ulx;
985
                                br->text_y = br->screen->text_uly;
986
                        }
987
                } else {
988
                        if (ch == 13)           //Can this happen? Above says ch==10
989
                                Int3();
990
                        br->prev_ch = ch;
991
                }
992
        } else {
993
#if defined(DXX_BUILD_DESCENT_II)
994
                if (!br->got_z) {
995
                        LevelError("briefing wrote to screen without using $Z to load a screen; loading default.");
996
                        //Int3(); // Hey ryan!!!! You gotta load a screen before you start
997
                        // printing to it! You know, $Z !!!
998
                        load_briefing_screen(*grd_curcanv, br, HIRESMODE ? "end01b.pcx" : "end01.pcx");
999
                }
1000
#endif
1001
                put_char_delay(game_font, br, ch);
1002
        }
1003
 
1004
        return 0;
1005
}
1006
 
1007
#if defined(DXX_BUILD_DESCENT_I)
1008
static void set_briefing_fontcolor()
1009
#elif defined(DXX_BUILD_DESCENT_II)
1010
static void set_briefing_fontcolor(briefing &br)
1011
#endif
1012
{
1013
        struct rgb
1014
        {
1015
                int r, g, b;
1016
        };
1017
        std::array<rgb, 3> colors;
1018
        if (EMULATING_D1) {
1019
                //green
1020
                colors[0] = {0, 54, 0};
1021
                //white
1022
                colors[1] = {42, 38, 32};
1023
                //Begin D1X addition
1024
                //red
1025
                colors[2] = {63, 0, 0};
1026
        }
1027
        else
1028
        {
1029
                colors[0] = {0, 40, 0};
1030
                colors[1] = {40, 33, 35};
1031
                colors[2] = {8, 31, 54};
1032
        }
1033
 
1034
#if defined(DXX_BUILD_DESCENT_II)
1035
        if (br.robot_playing)
1036
        {
1037
                colors[0] = {0, 31, 0};
1038
        }
1039
#endif
1040
        Briefing_text_colors[0] = gr_find_closest_color_current(colors[0].r, colors[0].g, colors[0].b);
1041
        Briefing_text_colors[1] = gr_find_closest_color_current(colors[1].r, colors[1].g, colors[1].b);
1042
        Briefing_text_colors[2] = gr_find_closest_color_current(colors[2].r, colors[2].g, colors[2].b);
1043
 
1044
        //blue
1045
        Briefing_text_colors[3] = gr_find_closest_color_current( 0, 0, 54);
1046
        //gray
1047
        Briefing_text_colors[4] = gr_find_closest_color_current( 14, 14, 14);
1048
        //yellow
1049
        Briefing_text_colors[5] = gr_find_closest_color_current( 54, 54, 0);
1050
        //purple
1051
        Briefing_text_colors[6] = gr_find_closest_color_current( 0, 54, 54);
1052
        //End D1X addition
1053
 
1054
        Erase_color = gr_find_closest_color_current(0, 0, 0);
1055
}
1056
}
1057
 
1058
static void redraw_messagestream(grs_canvas &canvas, const grs_font &cv_font, const msgstream &stream, unsigned &lastcolor)
1059
{
1060
        char msgbuf[2] = {stream.ch, 0};
1061
        if (lastcolor != stream.color)
1062
        {
1063
                lastcolor = stream.color;
1064
                gr_set_fontcolor(canvas, stream.color, -1);
1065
        }
1066
        gr_string(canvas, cv_font, stream.x + 1, stream.y, msgbuf);
1067
}
1068
 
1069
namespace dsx {
1070
static void flash_cursor(grs_canvas &canvas, const grs_font &cv_font, briefing *const br, const int cursor_flag)
1071
{
1072
        if (cursor_flag == 0)
1073
                return;
1074
        gr_set_fontcolor(canvas, (timer_query() % (F1_0 / 2)) > F1_0 / 4 ? *Current_color : Erase_color, -1);
1075
        gr_string(canvas, cv_font, br->text_x, br->text_y, "_");
1076
}
1077
 
1078
#define EXIT_DOOR_MAX   14
1079
#define OTHER_THING_MAX 10      // Adam: This is the number of frames in your new animating thing.
1080
#define DOOR_DIV_INIT   6
1081
 
1082
//-----------------------------------------------------------------------------
1083
static void show_animated_bitmap(grs_canvas &canvas, briefing *br)
1084
{
1085
        grs_bitmap      *bitmap_ptr;
1086
#if DXX_USE_OGL
1087
        float scale = 1.0;
1088
 
1089
        if ((static_cast<float>(SWIDTH)/320) < (static_cast<float>(SHEIGHT)/200))
1090
                scale = (static_cast<float>(SWIDTH)/320);
1091
        else
1092
                scale = (static_cast<float>(SHEIGHT)/200);
1093
#endif
1094
 
1095
        // Only plot every nth frame.
1096
        if (br->door_div_count) {
1097
                if (br->bitmap_name[0] != 0) {
1098
                        bitmap_index bi;
1099
                        bi = piggy_find_bitmap(&br->bitmap_name[0]);
1100
                        bitmap_ptr = &GameBitmaps[bi.index];
1101
                        PIGGY_PAGE_IN( bi );
1102
#if DXX_USE_OGL
1103
                        ogl_ubitmapm_cs(canvas, rescale_x(canvas.cv_bitmap, 220), rescale_y(canvas.cv_bitmap, 45), bitmap_ptr->bm_w * scale, bitmap_ptr->bm_h * scale, *bitmap_ptr, 255, F1_0);
1104
#else
1105
                        gr_bitmapm(canvas, rescale_x(canvas.cv_bitmap, 220), rescale_y(canvas.cv_bitmap, 45), *bitmap_ptr);
1106
#endif
1107
                }
1108
                br->door_div_count--;
1109
                return;
1110
        }
1111
 
1112
        br->door_div_count = DOOR_DIV_INIT;
1113
 
1114
        if (br->bitmap_name[0] != 0) {
1115
                char            *pound_signp;
1116
                int             num, dig1, dig2;
1117
                bitmap_index bi;
1118
                grs_subcanvas_ptr bitmap_canv;
1119
 
1120
                switch (br->animating_bitmap_type) {
1121
                        case 0:
1122
                                bitmap_canv = gr_create_sub_canvas(canvas, rescale_x(canvas.cv_bitmap, 220), rescale_y(canvas.cv_bitmap, 45), 64, 64);
1123
                                break;
1124
                        case 1:
1125
                                bitmap_canv = gr_create_sub_canvas(canvas, rescale_x(canvas.cv_bitmap, 220), rescale_y(canvas.cv_bitmap, 45), 94, 94);
1126
                                break; // Adam: Change here for your new animating bitmap thing. 94, 94 are bitmap size.
1127
                        default:        Int3(); // Impossible, illegal value for br->animating_bitmap_type
1128
                }
1129
 
1130
                auto &subcanvas = *bitmap_canv.get();
1131
 
1132
                pound_signp = strchr(&br->bitmap_name[0], '#');
1133
                Assert(pound_signp != NULL);
1134
 
1135
                dig1 = *(pound_signp+1);
1136
                dig2 = *(pound_signp+2);
1137
                if (dig2 == 0)
1138
                        num = dig1-'0';
1139
                else
1140
                        num = (dig1-'0')*10 + (dig2-'0');
1141
 
1142
                switch (br->animating_bitmap_type) {
1143
                        case 0:
1144
                                num += br->door_dir;
1145
                                if (num > EXIT_DOOR_MAX) {
1146
                                        num = EXIT_DOOR_MAX;
1147
                                        br->door_dir = -1;
1148
                                } else if (num < 0) {
1149
                                        num = 0;
1150
                                        br->door_dir = 1;
1151
                                }
1152
                                break;
1153
                        case 1:
1154
                                num++;
1155
                                if (num > OTHER_THING_MAX)
1156
                                        num = 0;
1157
                                break;
1158
                }
1159
 
1160
                Assert(num < 100);
1161
                if (num >= 10) {
1162
                        *(pound_signp+1) = (num / 10) + '0';
1163
                        *(pound_signp+2) = (num % 10) + '0';
1164
                        *(pound_signp+3) = 0;
1165
                } else {
1166
                        *(pound_signp+1) = (num % 10) + '0';
1167
                        *(pound_signp+2) = 0;
1168
                }
1169
 
1170
                bi = piggy_find_bitmap(&br->bitmap_name[0]);
1171
                bitmap_ptr = &GameBitmaps[bi.index];
1172
                PIGGY_PAGE_IN( bi );
1173
#if DXX_USE_OGL
1174
                ogl_ubitmapm_cs(subcanvas, 0, 0, bitmap_ptr->bm_w*scale, bitmap_ptr->bm_h*scale, *bitmap_ptr, 255, F1_0);
1175
#else
1176
                gr_bitmapm(subcanvas, 0, 0, *bitmap_ptr);
1177
#endif
1178
 
1179
                switch (br->animating_bitmap_type) {
1180
                        case 0:
1181
                                if (num == EXIT_DOOR_MAX) {
1182
                                        br->door_dir = -1;
1183
                                        br->door_div_count = 64;
1184
                                } else if (num == 0) {
1185
                                        br->door_dir = 1;
1186
                                        br->door_div_count = 64;
1187
                                }
1188
                                break;
1189
                        case 1:
1190
                                break;
1191
                }
1192
        }
1193
}
1194
 
1195
}
1196
 
1197
//-----------------------------------------------------------------------------
1198
static void show_briefing_bitmap(grs_canvas &canvas, grs_bitmap *bmp)
1199
{
1200
        const bool hiresmode = HIRESMODE;
1201
        const auto w = static_cast<float>(SWIDTH) / (hiresmode ? 640 : 320);
1202
        const auto h = static_cast<float>(SHEIGHT) / (hiresmode ? 480 : 200);
1203
        const float scale = (w < h) ? w : h;
1204
 
1205
        auto bitmap_canv = gr_create_sub_canvas(canvas, rescale_x(canvas.cv_bitmap, 220), rescale_y(canvas.cv_bitmap, 55), bmp->bm_w*scale, bmp->bm_h*scale);
1206
        show_fullscr(*bitmap_canv, *bmp);
1207
}
1208
 
1209
//-----------------------------------------------------------------------------
1210
namespace dsx {
1211
static void init_spinning_robot(grs_canvas &canvas, briefing &br) //(int x,int y,int w,int h)
1212
{
1213
        br.robot_canv = create_spinning_robot_sub_canvas(canvas);
1214
}
1215
 
1216
static void show_spinning_robot_frame(briefing *br, int robot_num)
1217
{
1218
        auto &Robot_info = LevelSharedRobotInfoState.Robot_info;
1219
        if (robot_num != -1) {
1220
                br->robot_angles.p = br->robot_angles.b = 0;
1221
                br->robot_angles.h += 150;
1222
 
1223
                Assert(Robot_info[robot_num].model_num != -1);
1224
                draw_model_picture(*br->robot_canv.get(), Robot_info[robot_num].model_num, br->robot_angles);
1225
        }
1226
}
1227
 
1228
//-----------------------------------------------------------------------------
1229
#define KEY_DELAY_DEFAULT       ((F1_0*20)/1000)
1230
 
1231
static void init_new_page(briefing *br)
1232
{
1233
        br->new_page = 0;
1234
        br->robot_num = -1;
1235
 
1236
        load_briefing_screen(*grd_curcanv, br, br->background_name.data());
1237
        br->text_x = br->screen->text_ulx;
1238
        br->text_y = br->screen->text_uly;
1239
 
1240
        br->streamcount=0;
1241
        br->guy_bitmap.reset();
1242
 
1243
#if defined(DXX_BUILD_DESCENT_II)
1244
        if (br->robot_playing)
1245
        {
1246
                DeInitRobotMovie(br->pMovie);
1247
                br->robot_playing=0;
1248
        }
1249
#endif
1250
 
1251
        br->start_time = 0;
1252
        br->delay_count = KEY_DELAY_DEFAULT;
1253
}
1254
 
1255
#if defined(DXX_BUILD_DESCENT_II)
1256
static int DefineBriefingBox(const grs_bitmap &cv_bitmap, const char *&buf)
1257
{
1258
        int i=0;
1259
        char name[20];
1260
 
1261
        const auto n = get_new_message_num (buf);
1262
 
1263
        assert(n < Briefing_screens.size());
1264
 
1265
        while (*buf != ' ')
1266
        {
1267
                name[i++]= *buf;
1268
                ++buf;
1269
        }
1270
 
1271
        name[i]='\0';   // slap a delimiter on this guy
1272
 
1273
        strcpy (Briefing_screens[n].bs_name,name);
1274
        Briefing_screens[n].level_num=get_new_message_num (buf);
1275
        Briefing_screens[n].message_num=get_new_message_num (buf);
1276
        Briefing_screens[n].text_ulx=get_new_message_num (buf);
1277
        Briefing_screens[n].text_uly=get_new_message_num (buf);
1278
        Briefing_screens[n].text_width=get_new_message_num (buf);
1279
        Briefing_screens[n].text_height = get_message_num (buf);  // NOTICE!!!
1280
 
1281
        Briefing_screens[n].text_ulx = rescale_x(cv_bitmap, Briefing_screens[n].text_ulx);
1282
        Briefing_screens[n].text_uly = rescale_y(cv_bitmap, Briefing_screens[n].text_uly);
1283
        Briefing_screens[n].text_width = rescale_x(cv_bitmap, Briefing_screens[n].text_width);
1284
        Briefing_screens[n].text_height = rescale_y(cv_bitmap, Briefing_screens[n].text_height);
1285
 
1286
        return (n);
1287
}
1288
#endif
1289
 
1290
static void free_briefing_screen(briefing *br);
1291
 
1292
//      -----------------------------------------------------------------------------
1293
//      loads a briefing screen
1294
static int load_briefing_screen(grs_canvas &canvas, briefing *const br, const char *const fname)
1295
{
1296
#if defined(DXX_BUILD_DESCENT_I)
1297
        const auto descent_hog_size = PHYSFSX_fsize("descent.hog");
1298
        char forigin[PATH_MAX];
1299
        decltype(br->background_name) fname2a;
1300
 
1301
        free_briefing_screen(br);
1302
 
1303
        snprintf(fname2a.data(), fname2a.size(), "%s", fname);
1304
        snprintf(forigin, sizeof(forigin), "%s", PHYSFS_getRealDir(fname));
1305
        d_strlwr(forigin);
1306
 
1307
        // check if we have a hires version of this image (not included in PC-version by default)
1308
        // Also if this hires image comes via external AddOn pack, only apply if requested image would be loaded from descent.hog - not a seperate mission which might want to show something else.
1309
        if (SWIDTH >= 640 && SHEIGHT >= 480 && (strstr(forigin,"descent.hog") != NULL))
1310
        {
1311
                const auto fb = fname2a.begin();
1312
                auto ptr = fb;
1313
                for (; const char c = *ptr; ++ptr)
1314
                {
1315
                        if (c == '.')
1316
                        {
1317
                                *ptr = 0;
1318
                                break;
1319
                        }
1320
                }
1321
                auto &hires_pcx = "h.pcx";
1322
                const size_t len_fname2 = std::distance(fb, ptr);
1323
                if (len_fname2 + sizeof(hires_pcx) < fname2a.size())
1324
                {
1325
                        strcpy(ptr, hires_pcx);
1326
                        if (!PHYSFSX_exists(fname2a.data(), 1))
1327
                                snprintf(fname2a.data(), fname2a.size(), "%s", fname);
1328
                }
1329
        }
1330
        br->background_name = fname2a;
1331
        const auto fname2 = fname2a.data();
1332
 
1333
        pcx_result pcx_error;
1334
        if ((!d_stricmp(fname2, "brief02.pcx") || !d_stricmp(fname2, "brief02h.pcx")) && cheats.baldguy &&
1335
                bald_guy_load("btexture.xxx", br->background, gr_palette) == pcx_result::SUCCESS)
1336
        {
1337
        }
1338
        else if ((pcx_error = pcx_read_bitmap(fname2, br->background, gr_palette)) != pcx_result::SUCCESS)
1339
        {
1340
                con_printf(CON_URGENT, "%s:%u: error: loading briefing screen <%s> failed: PCX load error: %s (%u)", __FILE__, __LINE__, fname2, pcx_errormsg(pcx_error), static_cast<unsigned>(pcx_error));
1341
        }
1342
 
1343
        // Hack: Make sure black parts of robot are shown black
1344
        if (MacPig && gr_palette[0].r == 63 &&
1345
                (!d_stricmp(fname2, "brief03.pcx") || !d_stricmp(fname2, "end01.pcx") ||
1346
                !d_stricmp(fname2, "brief03h.pcx") || !d_stricmp(fname2, "end01h.pcx")
1347
                ))
1348
        {
1349
                swap_0_255(br->background);
1350
                gr_palette[0].r = gr_palette[0].g = gr_palette[0].b = 0;
1351
                gr_palette[255].r = gr_palette[255].g = gr_palette[255].b = 63;
1352
        }
1353
        show_fullscr(canvas, br->background);
1354
        gr_palette_load(gr_palette);
1355
 
1356
        set_briefing_fontcolor();
1357
 
1358
        br->screen = std::make_unique<briefing_screen>(get_d1_briefing_screens(descent_hog_size)[br->cur_screen]);
1359
        br->screen->text_ulx = rescale_x(canvas.cv_bitmap, br->screen->text_ulx);
1360
        br->screen->text_uly = rescale_y(canvas.cv_bitmap, br->screen->text_uly);
1361
        br->screen->text_width = rescale_x(canvas.cv_bitmap, br->screen->text_width);
1362
        br->screen->text_height = rescale_y(canvas.cv_bitmap, br->screen->text_height);
1363
        init_char_pos(br, br->screen->text_ulx, br->screen->text_uly);
1364
#elif defined(DXX_BUILD_DESCENT_II)
1365
        free_briefing_screen(br);
1366
        const auto bndata = br->background_name.data();
1367
        if (fname != bndata)
1368
        {
1369
                br->background_name.back() = 0;
1370
                strncpy(bndata, fname, br->background_name.size() - 1);
1371
        }
1372
 
1373
        pcx_result pcx_error;
1374
        if ((pcx_error = pcx_read_bitmap(fname, br->background, gr_palette)) != pcx_result::SUCCESS)
1375
        {
1376
                con_printf(CON_URGENT, "%s:%u: error: loading briefing screen <%s> failed: PCX load error: %s (%u)", __FILE__, __LINE__, fname, pcx_errormsg(pcx_error), static_cast<unsigned>(pcx_error));
1377
                return 0;
1378
        }
1379
        show_fullscr(canvas, br->background);
1380
        if (EMULATING_D1 && !d_stricmp(fname, "brief03.pcx")) // HACK, FIXME: D1 missions should use their own palette (PALETTE.256), but texture replacements not complete
1381
                gr_use_palette_table("groupa.256");
1382
 
1383
        gr_palette_load(gr_palette);
1384
 
1385
        set_briefing_fontcolor(*br);
1386
 
1387
        if (EMULATING_D1)
1388
        {
1389
                br->got_z = 1;
1390
                br->screen = std::make_unique<briefing_screen>(Briefing_screens[br->cur_screen]);
1391
                br->screen->text_ulx = rescale_x(canvas.cv_bitmap, br->screen->text_ulx);
1392
                br->screen->text_uly = rescale_y(canvas.cv_bitmap, br->screen->text_uly);
1393
                br->screen->text_width = rescale_x(canvas.cv_bitmap, br->screen->text_width);
1394
                br->screen->text_height = rescale_y(canvas.cv_bitmap, br->screen->text_height);
1395
                init_char_pos(br, br->screen->text_ulx, br->screen->text_uly);
1396
        }
1397
 
1398
#endif
1399
        return 1;
1400
}
1401
 
1402
static void free_briefing_screen(briefing *br)
1403
{
1404
        br->background.reset();
1405
#if defined(DXX_BUILD_DESCENT_II)
1406
        if (br->robot_playing)
1407
        {
1408
                DeInitRobotMovie(br->pMovie);
1409
                br->robot_playing=0;
1410
        }
1411
#endif
1412
        br->robot_canv.reset();
1413
#if defined(DXX_BUILD_DESCENT_II)
1414
        br->printing_channel.reset();
1415
#endif
1416
        if (EMULATING_D1)
1417
                br->screen.reset();
1418
}
1419
 
1420
static int new_briefing_screen(briefing *br, int first)
1421
{
1422
        br->new_screen = 0;
1423
        const auto descent_hog_size = PHYSFSX_fsize("descent.hog");
1424
        const auto num_d1_briefing_screens = (
1425
                (descent_hog_size == D1_SHAREWARE_MISSION_HOGSIZE || descent_hog_size == D1_SHAREWARE_10_MISSION_HOGSIZE)
1426
                ? std::size(D1_Briefing_screens_share)
1427
                : std::size(D1_Briefing_screens_full)
1428
        );
1429
#if defined(DXX_BUILD_DESCENT_I)
1430
 
1431
        if (!first)
1432
                br->cur_screen++;
1433
 
1434
        auto &&d1_briefing_screens = get_d1_briefing_screens(descent_hog_size);
1435
        while (br->cur_screen < num_d1_briefing_screens && d1_briefing_screens[br->cur_screen].level_num != br->level_num)
1436
        {
1437
                br->cur_screen++;
1438
                if (br->cur_screen == num_d1_briefing_screens && br->level_num == 0)
1439
                {
1440
                        // Showed the pre-game briefing, now show level 1 briefing
1441
                        br->level_num++;
1442
                        br->cur_screen = 0;
1443
                }
1444
        }
1445
 
1446
        if (br->cur_screen == num_d1_briefing_screens)
1447
                return 0;               // finished
1448
 
1449
        if (!load_briefing_screen(*grd_curcanv, br, d1_briefing_screens[br->cur_screen].bs_name))
1450
                return 0;
1451
 
1452
        br->message = get_briefing_message(br, d1_briefing_screens[br->cur_screen].message_num);
1453
#elif defined(DXX_BUILD_DESCENT_II)
1454
        br->got_z = 0;
1455
 
1456
        if (EMULATING_D1)
1457
        {
1458
                auto &&d1_briefing_screens = get_d1_briefing_screens(descent_hog_size);
1459
                if (!first)
1460
                        br->cur_screen++;
1461
                else
1462
                        for (int i = 0; i < num_d1_briefing_screens; i++)
1463
                                Briefing_screens[i] = d1_briefing_screens[i];
1464
 
1465
                while (br->cur_screen < num_d1_briefing_screens && Briefing_screens[br->cur_screen].level_num != br->level_num)
1466
                {
1467
                        br->cur_screen++;
1468
                        if (br->cur_screen == num_d1_briefing_screens && br->level_num == 0)
1469
                        {
1470
                                // Showed the pre-game briefing, now show level 1 briefing
1471
                                br->level_num++;
1472
                                br->cur_screen = 0;
1473
                        }
1474
                }
1475
 
1476
                if (br->cur_screen == num_d1_briefing_screens)
1477
                        return 0;               // finished
1478
 
1479
                if (!load_briefing_screen(*grd_curcanv, br, Briefing_screens[br->cur_screen].bs_name))
1480
                        return 0;
1481
        }
1482
        else if (first)
1483
        {
1484
                br->cur_screen = br->level_num;
1485
                br->screen.reset(&Briefing_screens[0]);
1486
                init_char_pos(br, br->screen->text_ulx, br->screen->text_uly-(8*(1+HIRESMODE)));
1487
        }
1488
        else
1489
                return 0;       // finished
1490
 
1491
        br->message = get_briefing_message(br, EMULATING_D1 ? Briefing_screens[br->cur_screen].message_num : br->cur_screen);
1492
        br->printing_channel.reset();
1493
        br->dumb_adjust = 0;
1494
        br->line_adjustment = 1;
1495
        br->chattering = 0;
1496
        br->robot_playing=0;
1497
#endif
1498
 
1499
        if (br->message==NULL)
1500
                return 0;
1501
 
1502
        Current_color = &Briefing_text_colors.front();
1503
        br->streamcount = 0;
1504
        br->tab_stop = 0;
1505
        br->flashing_cursor = 0;
1506
        br->new_page = 0;
1507
        br->start_time = 0;
1508
        br->delay_count = KEY_DELAY_DEFAULT;
1509
        br->robot_num = -1;
1510
        br->bitmap_name[0] = 0;
1511
        br->guy_bitmap.reset();
1512
        br->prev_ch = -1;
1513
 
1514
#if defined(DXX_BUILD_DESCENT_II)
1515
        if (songs_is_playing() == -1 && !br->hum_channel)
1516
                br->hum_channel.reset(digi_start_sound(digi_xlat_sound(SOUND_BRIEFING_HUM), F1_0/2, 0xFFFF/2, 1, -1, -1, sound_object_none));
1517
#endif
1518
 
1519
        return 1;
1520
}
1521
 
1522
 
1523
//-----------------------------------------------------------------------------
1524
static window_event_result briefing_handler(window *, const d_event &event, briefing *br)
1525
{
1526
        window_event_result result;
1527
 
1528
        switch (event.type)
1529
        {
1530
                case EVENT_WINDOW_ACTIVATED:
1531
                case EVENT_WINDOW_DEACTIVATED:
1532
                        key_flush();
1533
                        break;
1534
 
1535
                case EVENT_MOUSE_BUTTON_DOWN:
1536
                        if (event_mouse_get_button(event) == 0)
1537
                        {
1538
                                if (br->new_screen)
1539
                                {
1540
                                        if (!new_briefing_screen(br, 0))
1541
                                        {
1542
                                                return window_event_result::close;
1543
                                        }
1544
                                }
1545
                                else if (br->new_page)
1546
                                        init_new_page(br);
1547
                                else
1548
                                        br->delay_count = 0;
1549
                                return window_event_result::handled;
1550
                        }
1551
                        break;
1552
 
1553
#if DXX_MAX_JOYSTICKS // Pierre-Marie Baty -- missing preprocessor condition
1554
                case EVENT_JOYSTICK_BUTTON_DOWN:
1555
                        // using joy_translate_menu_key doesn't work here for unclear
1556
                        // reasons, so we build a reasonable facsimile right here
1557
                        if (event_joystick_get_button(event) == 1)
1558
                                return window_event_result::close;
1559
                        if (br->new_screen)
1560
                        {
1561
                                if (!new_briefing_screen(br, 0))
1562
                                {
1563
                                        return window_event_result::close;
1564
                                }
1565
                        }
1566
                        else if (br->new_page)
1567
                                init_new_page(br);
1568
                        else
1569
                                br->delay_count = 0;
1570
                        return window_event_result::handled;
1571
#endif
1572
 
1573
                case EVENT_KEY_COMMAND:
1574
                {
1575
                        int key = event_key_get(event);
1576
 
1577
                        switch (key)
1578
                        {
1579
#if defined(DXX_BUILD_DESCENT_I)
1580
                                case KEY_ALTED + KEY_B: // B - ALTED... BALT... BALD... get it? 
1581
                                        cheats.baldguy = !cheats.baldguy;
1582
                                        break;
1583
#endif
1584
                                case KEY_ESC:
1585
                                        return window_event_result::close;
1586
                                case KEY_SPACEBAR:
1587
                                case KEY_ENTER:
1588
                                        br->delay_count = 0;
1589
                                        DXX_BOOST_FALLTHROUGH;
1590
                                default:
1591
                                        if ((result = call_default_handler(event)) != window_event_result::ignored)
1592
                                                return result;
1593
                                        else if (br->new_screen)
1594
                                        {
1595
                                                if (!new_briefing_screen(br, 0))
1596
                                                {
1597
                                                        return window_event_result::close;
1598
                                                }
1599
                                        }
1600
                                        else if (br->new_page)
1601
                                                init_new_page(br);
1602
                                        break;
1603
                        }
1604
                        break;
1605
                }
1606
 
1607
                case EVENT_WINDOW_DRAW:
1608
                {
1609
                        gr_set_default_canvas();
1610
                        auto &canvas = *grd_curcanv;
1611
 
1612
                        timer_delay2(50);
1613
 
1614
                        if (!(br->new_screen || br->new_page))
1615
                                while (!briefing_process_char(canvas, br) && !br->delay_count)
1616
                                {
1617
                                        check_text_pos(br);
1618
                                        if (br->new_page)
1619
                                                break;
1620
                                }
1621
                        check_text_pos(br);
1622
 
1623
                        if (br->background.bm_data)
1624
                                show_fullscr(canvas, br->background);
1625
 
1626
                        if (br->guy_bitmap.bm_data)
1627
                                show_briefing_bitmap(canvas, &br->guy_bitmap);
1628
                        if (br->bitmap_name[0] != 0)
1629
                                show_animated_bitmap(canvas, br);
1630
#if defined(DXX_BUILD_DESCENT_II)
1631
                        if (br->robot_playing)
1632
                                RotateRobot(br->pMovie);
1633
#endif
1634
                        if (br->robot_num != -1)
1635
                                show_spinning_robot_frame(br, br->robot_num);
1636
 
1637
                        auto &game_font = *GAME_FONT;
1638
 
1639
                        gr_set_fontcolor(canvas, *Current_color, -1);
1640
                        {
1641
                                unsigned lastcolor = ~0u;
1642
                                range_for (const auto b, partial_const_range(br->messagestream, br->streamcount))
1643
                                        redraw_messagestream(canvas, game_font, b, lastcolor);
1644
                        }
1645
 
1646
                        if (br->new_page || br->new_screen)
1647
                                flash_cursor(canvas, game_font, br, br->flashing_cursor);
1648
                        else if (br->flashing_cursor)
1649
                                gr_string(canvas, game_font, br->text_x, br->text_y, "_");
1650
                        break;
1651
                }
1652
                case EVENT_WINDOW_CLOSE:
1653
                        free_briefing_screen(br);
1654
#if defined(DXX_BUILD_DESCENT_II)
1655
                        br->hum_channel.reset();
1656
#endif
1657
                        break;
1658
 
1659
                default:
1660
                        break;
1661
        }
1662
        return window_event_result::ignored;
1663
}
1664
 
1665
void do_briefing_screens(const d_fname &filename, int level_num)
1666
{
1667
        if (!*static_cast<const char *>(filename))
1668
                return;
1669
 
1670
        auto br = std::make_unique<briefing>();
1671
        briefing_init(br.get(), level_num);
1672
 
1673
        if (!load_screen_text(filename, br->text))
1674
        {
1675
                return;
1676
        }
1677
 
1678
        const auto wind = window_create(grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, briefing_handler, br.get());
1679
        if (!wind)
1680
        {
1681
                return;
1682
        }
1683
 
1684
#if defined(DXX_BUILD_DESCENT_II)
1685
        if (!(EMULATING_D1 || is_SHAREWARE || is_MAC_SHARE || is_D2_OEM || !PLAYING_BUILTIN_MISSION))
1686
                songs_stop_all();
1687
        else
1688
#endif
1689
        {
1690
                if ((songs_is_playing() != SONG_BRIEFING) && (songs_is_playing() != SONG_ENDGAME))
1691
                        songs_play_song( SONG_BRIEFING, 1 );
1692
        }
1693
 
1694
#if defined(DXX_BUILD_DESCENT_I)
1695
        set_screen_mode( SCREEN_MENU );
1696
#elif defined(DXX_BUILD_DESCENT_II)
1697
        // set screen correctly for robot movies
1698
        set_screen_mode( SCREEN_MOVIE );
1699
#endif
1700
 
1701
        gr_set_default_canvas();
1702
 
1703
        if (!new_briefing_screen(br.get(), 1))
1704
        {
1705
                window_close(wind);
1706
                return;
1707
        }
1708
 
1709
        // Stay where we are in the stack frame until briefing done
1710
        // Too complicated otherwise
1711
        event_process_all();
1712
}
1713
 
1714
void do_end_briefing_screens(const d_fname &filename)
1715
{
1716
        int level_num_screen = Current_level_num, showorder = 0;
1717
 
1718
        if (!*static_cast<const char *>(filename))
1719
                return; // no filename, no ending
1720
 
1721
        if (EMULATING_D1)
1722
        {
1723
                unsigned song;
1724
                if (d_stricmp(filename, BIMD1_ENDING_FILE_OEM) == 0)
1725
                {
1726
                        song = SONG_ENDGAME;
1727
                        level_num_screen = ENDING_LEVEL_NUM_OEMSHARE;
1728
#if defined(DXX_BUILD_DESCENT_I)
1729
                        showorder = 1;
1730
#endif
1731
                }
1732
                else if (d_stricmp(filename, BIMD1_ENDING_FILE_SHARE) == 0)
1733
                {
1734
                        song = SONG_BRIEFING;
1735
                        level_num_screen = ENDING_LEVEL_NUM_OEMSHARE;
1736
#if defined(DXX_BUILD_DESCENT_I)
1737
                        showorder = 1;
1738
#endif
1739
                }
1740
                else
1741
                {
1742
                        song = SONG_ENDGAME;
1743
                        level_num_screen = ENDING_LEVEL_NUM_REGISTER;
1744
                }
1745
                songs_play_song(song, 1);
1746
        }
1747
#if defined(DXX_BUILD_DESCENT_II)
1748
        else if (PLAYING_BUILTIN_MISSION)
1749
        {
1750
                unsigned song;
1751
                if ((d_stricmp(filename, BIMD2_ENDING_FILE_OEM) == 0 && (song = SONG_TITLE, true)) ||
1752
                        (d_stricmp(filename, BIMD2_ENDING_FILE_SHARE) == 0 && (song = SONG_ENDGAME, true)))
1753
                {
1754
                        songs_play_song(song, 1);
1755
                        level_num_screen = 1;
1756
                        showorder = 1;
1757
                }
1758
        }
1759
        else
1760
        {
1761
                songs_play_song( SONG_ENDGAME, 1 );
1762
                level_num_screen = Last_level + 1;
1763
        }
1764
#endif
1765
 
1766
        do_briefing_screens(filename, level_num_screen);
1767
        if (showorder)
1768
                show_order_form();
1769
}
1770
 
1771
}