Subversion Repositories Kolibri OS

Rev

Rev 300 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
298 serge 1
// Emacs style mode select   -*- C++ -*-
2
//-----------------------------------------------------------------------------
3
//
4
// $Id:$
5
//
6
// Copyright (C) 1993-1996 by id Software, Inc.
7
//
8
// This source is available for distribution and/or modification
9
// only under the terms of the DOOM Source Code License as
10
// published by id Software. All rights reserved.
11
//
12
// The source is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15
// for more details.
16
//
17
// $Log:$
18
//
19
// DESCRIPTION:
550 serge 20
//      DOOM selection menu, options, episode etc.
21
//      Sliders and icons. Kinda widget stuff.
298 serge 22
//
23
//-----------------------------------------------------------------------------
24
 
25
static const char
26
rcsid[] = "$Id: m_menu.c,v 1.7 1997/02/03 22:45:10 b1 Exp $";
27
 
28
#include 
29
#include 
30
 
31
#include "m_swap.h"
32
#include "doomdef.h"
33
#include "dstrings.h"
34
 
35
#include "d_main.h"
36
 
37
#include "i_system.h"
38
#include "i_video.h"
39
#include "z_zone.h"
40
#include "v_video.h"
41
#include "w_wad.h"
42
 
43
#include "r_local.h"
44
 
45
 
46
#include "hu_stuff.h"
47
 
48
#include "g_game.h"
49
 
50
#include "m_argv.h"
51
 
52
#include "s_sound.h"
53
 
54
#include "doomstat.h"
55
 
56
// Data.
57
#include "sounds.h"
58
 
59
#include "m_menu.h"
60
 
61
 
62
 
550 serge 63
extern patch_t*         hu_font[HU_FONTSIZE];
64
extern boolean          message_dontfuckwithme;
298 serge 65
 
550 serge 66
extern boolean          chat_on;                // in heads-up code
298 serge 67
 
68
//
69
// defaulted values
70
//
550 serge 71
int                     mouseSensitivity;       // has default
298 serge 72
 
73
// Show messages has default, 0 = off, 1 = on
550 serge 74
int                     showMessages;
75
 
298 serge 76
 
77
// Blocky mode, has default, 0 = high, 1 = normal
550 serge 78
int                     detailLevel;
79
int                     screenblocks;           // has default
298 serge 80
 
81
// temp for screenblocks (0-9)
550 serge 82
int                     screenSize;
298 serge 83
 
84
// -1 = no quicksave slot picked!
550 serge 85
int                     quickSaveSlot;
298 serge 86
 
87
 // 1 = message to be printed
550 serge 88
int                     messageToPrint;
298 serge 89
// ...and here is the message string!
550 serge 90
char*                   messageString;
298 serge 91
 
92
// message x & y
550 serge 93
int                     messx;
94
int                     messy;
95
int                     messageLastMenuActive;
298 serge 96
 
97
// timed message = no input from user
550 serge 98
boolean                 messageNeedsInput;
298 serge 99
 
100
void    (*messageRoutine)(int response);
101
 
550 serge 102
#define SAVESTRINGSIZE  24
298 serge 103
 
104
char gammamsg[5][26] =
105
{
106
    GAMMALVL0,
107
    GAMMALVL1,
108
    GAMMALVL2,
109
    GAMMALVL3,
110
    GAMMALVL4
111
};
112
 
113
// we are going to be entering a savegame string
550 serge 114
int                     saveStringEnter;
115
int                     saveSlot;       // which slot to save in
116
int                     saveCharIndex;  // which char we're editing
298 serge 117
// old save description before edit
550 serge 118
char                    saveOldString[SAVESTRINGSIZE];
298 serge 119
 
550 serge 120
boolean                 inhelpscreens;
121
boolean                 menuactive;
298 serge 122
 
550 serge 123
#define SKULLXOFF               -32
124
#define LINEHEIGHT              16
298 serge 125
 
550 serge 126
extern boolean          sendpause;
127
char                    savegamestrings[10][SAVESTRINGSIZE];
298 serge 128
 
550 serge 129
char    endstring[160];
298 serge 130
 
131
 
132
//
133
// MENU TYPEDEFS
134
//
135
typedef struct
136
{
137
    // 0 = no cursor here, 1 = ok, 2 = arrows ok
550 serge 138
    short       status;
298 serge 139
 
550 serge 140
    char        name[10];
298 serge 141
 
142
    // choice = menu item #.
143
    // if status = 2,
144
    //   choice=0:leftarrow,1:rightarrow
550 serge 145
    void        (*routine)(int choice);
298 serge 146
 
147
    // hotkey in menu
550 serge 148
    char        alphaKey;
298 serge 149
} menuitem_t;
150
 
151
 
152
 
153
typedef struct menu_s
154
{
550 serge 155
    short               numitems;       // # of menu items
156
    struct menu_s*      prevMenu;       // previous menu
157
    menuitem_t*         menuitems;      // menu items
158
    void                (*routine)();   // draw routine
159
    short               x;
160
    short               y;              // x,y of menu
161
    short               lastOn;         // last item user was on in menu
298 serge 162
} menu_t;
163
 
550 serge 164
short           itemOn;                 // menu item skull is on
165
short           skullAnimCounter;       // skull animation counter
166
short           whichSkull;             // which skull to draw
298 serge 167
 
168
// graphic name of skulls
169
// warning: initializer-string for array of chars is too long
170
char    skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
171
 
172
// current menudef
550 serge 173
menu_t* currentMenu;
298 serge 174
 
175
//
176
// PROTOTYPES
177
//
178
void M_NewGame(int choice);
179
void M_Episode(int choice);
180
void M_ChooseSkill(int choice);
181
void M_LoadGame(int choice);
182
void M_SaveGame(int choice);
183
void M_Options(int choice);
184
void M_EndGame(int choice);
185
void M_ReadThis(int choice);
186
void M_ReadThis2(int choice);
187
void M_QuitDOOM(int choice);
188
 
189
void M_ChangeMessages(int choice);
190
void M_ChangeSensitivity(int choice);
191
void M_SfxVol(int choice);
192
void M_MusicVol(int choice);
193
void M_ChangeDetail(int choice);
194
void M_SizeDisplay(int choice);
195
void M_StartGame(int choice);
196
void M_Sound(int choice);
197
 
198
void M_FinishReadThis(int choice);
199
void M_LoadSelect(int choice);
200
void M_SaveSelect(int choice);
201
void M_ReadSaveStrings(void);
202
void M_QuickSave(void);
203
void M_QuickLoad(void);
204
 
205
void M_DrawMainMenu(void);
206
void M_DrawReadThis1(void);
207
void M_DrawReadThis2(void);
208
void M_DrawNewGame(void);
209
void M_DrawEpisode(void);
210
void M_DrawOptions(void);
211
void M_DrawSound(void);
212
void M_DrawLoad(void);
213
void M_DrawSave(void);
214
 
215
void M_DrawSaveLoadBorder(int x,int y);
216
void M_SetupNextMenu(menu_t *menudef);
217
void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
218
void M_DrawEmptyCell(menu_t *menu,int item);
219
void M_DrawSelCell(menu_t *menu,int item);
220
void M_WriteText(int x, int y, char *string);
221
int  M_StringWidth(char *string);
222
int  M_StringHeight(char *string);
223
void M_StartControlPanel(void);
224
void M_StartMessage(char *string,void *routine,boolean input);
225
void M_StopMessage(void);
226
void M_ClearMenus (void);
227
 
228
 
229
 
230
 
231
//
232
// DOOM MENU
233
//
234
enum
235
{
236
    newgame = 0,
237
    options,
238
    loadgame,
239
    savegame,
240
    readthis,
241
    quitdoom,
242
    main_end
243
} main_e;
244
 
245
menuitem_t MainMenu[]=
246
{
247
    {1,"M_NGAME",M_NewGame,'n'},
248
    {1,"M_OPTION",M_Options,'o'},
249
    {1,"M_LOADG",M_LoadGame,'l'},
250
    {1,"M_SAVEG",M_SaveGame,'s'},
251
    // Another hickup with Special edition.
252
    {1,"M_RDTHIS",M_ReadThis,'r'},
253
    {1,"M_QUITG",M_QuitDOOM,'q'}
254
};
255
 
256
menu_t  MainDef =
257
{
258
    main_end,
259
    NULL,
260
    MainMenu,
261
    M_DrawMainMenu,
262
    97,64,
263
 
264
};
265
 
266
 
267
//
268
// EPISODE SELECT
269
//
270
enum
271
{
272
    ep1,
273
    ep2,
274
    ep3,
275
    ep4,
276
    ep_end
277
} episodes_e;
278
 
279
menuitem_t EpisodeMenu[]=
280
{
281
    {1,"M_EPI1", M_Episode,'k'},
282
    {1,"M_EPI2", M_Episode,'t'},
283
    {1,"M_EPI3", M_Episode,'i'},
284
    {1,"M_EPI4", M_Episode,'t'}
285
};
286
 
287
menu_t  EpiDef =
288
{
550 serge 289
    ep_end,             // # of menu items
290
    &MainDef,           // previous menu
291
    EpisodeMenu,        // menuitem_t ->
292
    M_DrawEpisode,      // drawing routine ->
298 serge 293
    48,63,              // x,y
550 serge 294
    ep1                 // lastOn
298 serge 295
};
296
 
297
//
298
// NEW GAME
299
//
300
enum
301
{
302
    killthings,
303
    toorough,
304
    hurtme,
305
    violence,
306
    nightmare,
307
    newg_end
308
} newgame_e;
309
 
310
menuitem_t NewGameMenu[]=
311
{
550 serge 312
    {1,"M_JKILL",       M_ChooseSkill, 'i'},
313
    {1,"M_ROUGH",       M_ChooseSkill, 'h'},
314
    {1,"M_HURT",        M_ChooseSkill, 'h'},
315
    {1,"M_ULTRA",       M_ChooseSkill, 'u'},
316
    {1,"M_NMARE",       M_ChooseSkill, 'n'}
298 serge 317
};
318
 
319
menu_t  NewDef =
320
{
550 serge 321
    newg_end,           // # of menu items
322
    &EpiDef,            // previous menu
323
    NewGameMenu,        // menuitem_t ->
324
    M_DrawNewGame,      // drawing routine ->
298 serge 325
    48,63,              // x,y
550 serge 326
    hurtme              // lastOn
298 serge 327
};
328
 
329
 
330
 
331
//
332
// OPTIONS MENU
333
//
334
enum
335
{
336
    endgame,
337
    messages,
338
    detail,
339
    scrnsize,
340
    option_empty1,
341
    mousesens,
342
    option_empty2,
343
    soundvol,
344
    opt_end
345
} options_e;
346
 
347
menuitem_t OptionsMenu[]=
348
{
550 serge 349
    {1,"M_ENDGAM",      M_EndGame,'e'},
350
    {1,"M_MESSG",       M_ChangeMessages,'m'},
351
    {1,"M_DETAIL",      M_ChangeDetail,'g'},
352
    {2,"M_SCRNSZ",      M_SizeDisplay,'s'},
298 serge 353
    {-1,"",0},
550 serge 354
    {2,"M_MSENS",       M_ChangeSensitivity,'m'},
298 serge 355
    {-1,"",0},
550 serge 356
    {1,"M_SVOL",        M_Sound,'s'}
298 serge 357
};
358
 
359
menu_t  OptionsDef =
360
{
361
    opt_end,
362
    &MainDef,
363
    OptionsMenu,
364
    M_DrawOptions,
365
    60,37,
366
 
367
};
368
 
369
//
370
// Read This! MENU 1 & 2
371
//
372
enum
373
{
374
    rdthsempty1,
375
    read1_end
376
} read_e;
377
 
378
menuitem_t ReadMenu1[] =
379
{
380
    {1,"",M_ReadThis2,0}
381
};
382
 
383
menu_t  ReadDef1 =
384
{
385
    read1_end,
386
    &MainDef,
387
    ReadMenu1,
388
    M_DrawReadThis1,
389
    280,185,
390
 
391
};
392
 
393
enum
394
{
395
    rdthsempty2,
396
    read2_end
397
} read_e2;
398
 
399
menuitem_t ReadMenu2[]=
400
{
401
    {1,"",M_FinishReadThis,0}
402
};
403
 
404
menu_t  ReadDef2 =
405
{
406
    read2_end,
407
    &ReadDef1,
408
    ReadMenu2,
409
    M_DrawReadThis2,
410
    330,175,
411
 
412
};
413
 
414
//
415
// SOUND VOLUME MENU
416
//
417
enum
418
{
419
    sfx_vol,
420
    sfx_empty1,
421
    music_vol,
422
    sfx_empty2,
423
    sound_end
424
} sound_e;
425
 
426
menuitem_t SoundMenu[]=
427
{
428
    {2,"M_SFXVOL",M_SfxVol,'s'},
429
    {-1,"",0},
430
    {2,"M_MUSVOL",M_MusicVol,'m'},
431
    {-1,"",0}
432
};
433
 
434
menu_t  SoundDef =
435
{
436
    sound_end,
437
    &OptionsDef,
438
    SoundMenu,
439
    M_DrawSound,
440
    80,64,
441
 
442
};
443
 
444
//
445
// LOAD GAME MENU
446
//
447
enum
448
{
449
    load1,
450
    load2,
451
    load3,
452
    load4,
453
    load5,
454
    load6,
455
    load_end
456
} load_e;
457
 
458
menuitem_t LoadMenu[]=
459
{
460
    {1,"", M_LoadSelect,'1'},
461
    {1,"", M_LoadSelect,'2'},
462
    {1,"", M_LoadSelect,'3'},
463
    {1,"", M_LoadSelect,'4'},
464
    {1,"", M_LoadSelect,'5'},
465
    {1,"", M_LoadSelect,'6'}
466
};
467
 
468
menu_t  LoadDef =
469
{
470
    load_end,
471
    &MainDef,
472
    LoadMenu,
473
    M_DrawLoad,
474
    80,54,
475
 
476
};
477
 
478
//
479
// SAVE GAME MENU
480
//
481
menuitem_t SaveMenu[]=
482
{
483
    {1,"", M_SaveSelect,'1'},
484
    {1,"", M_SaveSelect,'2'},
485
    {1,"", M_SaveSelect,'3'},
486
    {1,"", M_SaveSelect,'4'},
487
    {1,"", M_SaveSelect,'5'},
488
    {1,"", M_SaveSelect,'6'}
489
};
490
 
491
menu_t  SaveDef =
492
{
493
    load_end,
494
    &MainDef,
495
    SaveMenu,
496
    M_DrawSave,
497
    80,54,
498
 
499
};
500
 
501
 
502
//
503
// M_ReadSaveStrings
504
//  read the strings from the savegame files
505
//
506
void M_ReadSaveStrings(void)
507
{
508
    FILE           *handle;
509
    int             count;
510
    int             i;
511
    char    name[256];
550 serge 512
 
298 serge 513
    for (i = 0;i < load_end;i++)
514
    {
550 serge 515
        sprintf(name,"doomsav%d.dsg",i);
298 serge 516
 
550 serge 517
        handle = fopen (name, "r");
518
        if (handle == NULL)
519
        {
520
            strcpy(&savegamestrings[i][0],EMPTYSTRING);
521
            LoadMenu[i].status = 0;
522
            continue;
523
        }
524
        count = fread (&savegamestrings[i], 1, SAVESTRINGSIZE, handle);
525
        fclose (handle);
526
        LoadMenu[i].status = 1;
298 serge 527
    }
528
}
529
 
530
 
531
//
532
// M_LoadGame & Cie.
533
//
534
void M_DrawLoad(void)
535
{
536
    int             i;
550 serge 537
 
298 serge 538
    V_DrawPatchDirect (72,28,0,W_CacheLumpName("M_LOADG",PU_CACHE));
539
    for (i = 0;i < load_end; i++)
540
    {
550 serge 541
        M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
542
        M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
298 serge 543
    }
544
}
545
 
546
 
547
 
548
//
549
// Draw border for the savegame description
550
//
551
void M_DrawSaveLoadBorder(int x,int y)
552
{
553
    int             i;
550 serge 554
 
298 serge 555
    V_DrawPatchDirect (x-8,y+7,0,W_CacheLumpName("M_LSLEFT",PU_CACHE));
550 serge 556
 
298 serge 557
    for (i = 0;i < 24;i++)
558
    {
550 serge 559
        V_DrawPatchDirect (x,y+7,0,W_CacheLumpName("M_LSCNTR",PU_CACHE));
560
        x += 8;
298 serge 561
    }
562
 
563
    V_DrawPatchDirect (x,y+7,0,W_CacheLumpName("M_LSRGHT",PU_CACHE));
564
}
565
 
566
 
567
 
568
//
569
// User wants to load this game
570
//
571
void M_LoadSelect(int choice)
572
{
573
    char    name[256];
550 serge 574
 
575
//    if (M_CheckParm("-cdrom"))
576
//        sprintf(name,"c:\\doomdata\\doomsav%d.dsg",choice);
577
//    else
578
        sprintf(name,"doomsav%d.dsg",choice);
579
 
298 serge 580
    G_LoadGame (name);
581
    M_ClearMenus ();
582
}
583
 
584
//
585
// Selected from DOOM menu
586
//
587
void M_LoadGame (int choice)
588
{
589
    if (netgame)
590
    {
550 serge 591
        M_StartMessage(LOADNET,NULL,false);
592
        return;
298 serge 593
    }
550 serge 594
 
298 serge 595
    M_SetupNextMenu(&LoadDef);
596
    M_ReadSaveStrings();
597
}
598
 
599
 
600
//
601
//  M_SaveGame & Cie.
602
//
603
void M_DrawSave(void)
604
{
605
    int             i;
550 serge 606
 
298 serge 607
    V_DrawPatchDirect (72,28,0,W_CacheLumpName("M_SAVEG",PU_CACHE));
608
    for (i = 0;i < load_end; i++)
609
    {
550 serge 610
        M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
611
        M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
298 serge 612
    }
550 serge 613
 
298 serge 614
    if (saveStringEnter)
615
    {
550 serge 616
        i = M_StringWidth(savegamestrings[saveSlot]);
617
        M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
298 serge 618
    }
619
}
620
 
621
//
622
// M_Responder calls this when user is finished
623
//
624
void M_DoSave(int slot)
625
{
550 serge 626
 
298 serge 627
    G_SaveGame (slot,savegamestrings[slot]);
628
    M_ClearMenus ();
629
 
630
    // PICK QUICKSAVE SLOT YET?
631
    if (quickSaveSlot == -2)
550 serge 632
        quickSaveSlot = slot;
298 serge 633
}
634
 
635
//
636
// User wants to save. Start string input for M_Responder
637
//
638
void M_SaveSelect(int choice)
639
{
640
    // we are going to be intercepting all chars
641
    saveStringEnter = 1;
642
 
643
    saveSlot = choice;
644
    strcpy(saveOldString,savegamestrings[choice]);
645
    if (!strcmp(savegamestrings[choice],EMPTYSTRING))
550 serge 646
        savegamestrings[choice][0] = 0;
298 serge 647
    saveCharIndex = strlen(savegamestrings[choice]);
648
}
649
 
650
//
651
// Selected from DOOM menu
652
//
653
void M_SaveGame (int choice)
654
{
655
    if (!usergame)
656
    {
550 serge 657
        M_StartMessage(SAVEDEAD,NULL,false);
658
        return;
298 serge 659
    }
550 serge 660
 
298 serge 661
    if (gamestate != GS_LEVEL)
550 serge 662
        return;
663
 
298 serge 664
    M_SetupNextMenu(&SaveDef);
665
    M_ReadSaveStrings();
666
}
667
 
668
 
669
 
670
//
671
//      M_QuickSave
672
//
673
char    tempstring[80];
674
 
675
void M_QuickSaveResponse(int ch)
676
{
677
    if (ch == 'y')
678
    {
550 serge 679
        M_DoSave(quickSaveSlot);
680
        S_StartSound(NULL,sfx_swtchx);
298 serge 681
    }
682
}
683
 
684
void M_QuickSave(void)
685
{
686
    if (!usergame)
687
    {
550 serge 688
        S_StartSound(NULL,sfx_oof);
689
        return;
298 serge 690
    }
691
 
692
    if (gamestate != GS_LEVEL)
550 serge 693
        return;
694
 
298 serge 695
    if (quickSaveSlot < 0)
696
    {
550 serge 697
        M_StartControlPanel();
698
        M_ReadSaveStrings();
699
        M_SetupNextMenu(&SaveDef);
700
        quickSaveSlot = -2;     // means to pick a slot now
701
        return;
298 serge 702
    }
703
    sprintf(tempstring,QSPROMPT,savegamestrings[quickSaveSlot]);
704
    M_StartMessage(tempstring,M_QuickSaveResponse,true);
705
}
706
 
707
 
708
 
709
//
710
// M_QuickLoad
711
//
712
void M_QuickLoadResponse(int ch)
713
{
714
    if (ch == 'y')
715
    {
550 serge 716
        M_LoadSelect(quickSaveSlot);
717
        S_StartSound(NULL,sfx_swtchx);
298 serge 718
    }
719
}
720
 
721
 
722
void M_QuickLoad(void)
723
{
724
    if (netgame)
725
    {
550 serge 726
        M_StartMessage(QLOADNET,NULL,false);
727
        return;
298 serge 728
    }
550 serge 729
 
298 serge 730
    if (quickSaveSlot < 0)
731
    {
550 serge 732
        M_StartMessage(QSAVESPOT,NULL,false);
733
        return;
298 serge 734
    }
735
    sprintf(tempstring,QLPROMPT,savegamestrings[quickSaveSlot]);
736
    M_StartMessage(tempstring,M_QuickLoadResponse,true);
737
}
738
 
739
 
740
 
741
 
742
//
743
// Read This Menus
744
// Had a "quick hack to fix romero bug"
745
//
746
void M_DrawReadThis1(void)
747
{
748
    inhelpscreens = true;
749
    switch ( gamemode )
750
    {
751
      case commercial:
550 serge 752
        V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP",PU_CACHE));
753
        break;
298 serge 754
      case shareware:
755
      case registered:
756
      case retail:
550 serge 757
        V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP1",PU_CACHE));
758
        break;
298 serge 759
      default:
550 serge 760
        break;
298 serge 761
    }
762
    return;
763
}
764
 
765
 
766
 
767
//
768
// Read This Menus - optional second page.
769
//
770
void M_DrawReadThis2(void)
771
{
772
    inhelpscreens = true;
773
    switch ( gamemode )
774
    {
775
      case retail:
776
      case commercial:
550 serge 777
        // This hack keeps us from having to change menus.
778
        V_DrawPatchDirect (0,0,0,W_CacheLumpName("CREDIT",PU_CACHE));
779
        break;
298 serge 780
      case shareware:
781
      case registered:
550 serge 782
        V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP2",PU_CACHE));
783
        break;
298 serge 784
      default:
550 serge 785
        break;
298 serge 786
    }
787
    return;
788
}
789
 
790
 
791
//
792
// Change Sfx & Music volumes
793
//
794
void M_DrawSound(void)
795
{
796
    V_DrawPatchDirect (60,38,0,W_CacheLumpName("M_SVOL",PU_CACHE));
797
 
798
    M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),
550 serge 799
                 16,snd_SfxVolume);
298 serge 800
 
801
    M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),
550 serge 802
                 16,snd_MusicVolume);
298 serge 803
}
804
 
805
void M_Sound(int choice)
806
{
807
    M_SetupNextMenu(&SoundDef);
808
}
809
 
810
void M_SfxVol(int choice)
811
{
812
    switch(choice)
813
    {
814
      case 0:
550 serge 815
        if (snd_SfxVolume)
816
            snd_SfxVolume--;
817
        break;
298 serge 818
      case 1:
550 serge 819
        if (snd_SfxVolume < 15)
820
            snd_SfxVolume++;
821
        break;
298 serge 822
    }
550 serge 823
 
298 serge 824
    S_SetSfxVolume(snd_SfxVolume /* *8 */);
825
}
826
 
827
void M_MusicVol(int choice)
828
{
829
    switch(choice)
830
    {
831
      case 0:
550 serge 832
        if (snd_MusicVolume)
833
            snd_MusicVolume--;
834
        break;
298 serge 835
      case 1:
550 serge 836
        if (snd_MusicVolume < 15)
837
            snd_MusicVolume++;
838
        break;
298 serge 839
    }
550 serge 840
 
298 serge 841
    S_SetMusicVolume(snd_MusicVolume /* *8 */);
842
}
843
 
844
 
845
 
846
 
847
//
848
// M_DrawMainMenu
849
//
850
void M_DrawMainMenu(void)
851
{
852
    V_DrawPatchDirect (94,2,0,W_CacheLumpName("M_DOOM",PU_CACHE));
853
}
854
 
855
 
856
 
857
 
858
//
859
// M_NewGame
860
//
861
void M_DrawNewGame(void)
862
{
863
    V_DrawPatchDirect (96,14,0,W_CacheLumpName("M_NEWG",PU_CACHE));
864
    V_DrawPatchDirect (54,38,0,W_CacheLumpName("M_SKILL",PU_CACHE));
865
}
866
 
867
void M_NewGame(int choice)
868
{
869
    if (netgame && !demoplayback)
870
    {
550 serge 871
        M_StartMessage(NEWGAME,NULL,false);
872
        return;
298 serge 873
    }
550 serge 874
 
298 serge 875
    if ( gamemode == commercial )
550 serge 876
        M_SetupNextMenu(&NewDef);
298 serge 877
    else
550 serge 878
        M_SetupNextMenu(&EpiDef);
298 serge 879
}
880
 
881
 
882
//
883
//      M_Episode
884
//
885
int     epi;
886
 
887
void M_DrawEpisode(void)
888
{
889
    V_DrawPatchDirect (54,38,0,W_CacheLumpName("M_EPISOD",PU_CACHE));
890
}
891
 
892
void M_VerifyNightmare(int ch)
893
{
894
    if (ch != 'y')
550 serge 895
        return;
896
 
298 serge 897
    G_DeferedInitNew(nightmare,epi+1,1);
898
    M_ClearMenus ();
899
}
900
 
901
void M_ChooseSkill(int choice)
902
{
903
    if (choice == nightmare)
904
    {
550 serge 905
        M_StartMessage(NIGHTMARE,M_VerifyNightmare,true);
906
        return;
298 serge 907
    }
550 serge 908
 
298 serge 909
    G_DeferedInitNew(choice,epi+1,1);
910
    M_ClearMenus ();
911
}
912
 
913
void M_Episode(int choice)
914
{
915
    if ( (gamemode == shareware)
550 serge 916
         && choice)
298 serge 917
    {
550 serge 918
        M_StartMessage(SWSTRING,NULL,false);
919
        M_SetupNextMenu(&ReadDef1);
920
        return;
298 serge 921
    }
922
 
923
    // Yet another hack...
924
    if ( (gamemode == registered)
550 serge 925
         && (choice > 2))
298 serge 926
    {
927
 //     __libclog_printf("M_Episode: 4th episode requires UltimateDOOM\n");
928
      choice = 0;
929
    }
550 serge 930
 
298 serge 931
    epi = choice;
932
    M_SetupNextMenu(&NewDef);
933
}
934
 
935
 
936
 
937
//
938
// M_Options
939
//
550 serge 940
char    detailNames[2][9]       = {"M_GDHIGH","M_GDLOW"};
941
char    msgNames[2][9]          = {"M_MSGOFF","M_MSGON"};
298 serge 942
 
943
 
944
void M_DrawOptions(void)
945
{
946
    V_DrawPatchDirect (108,15,0,W_CacheLumpName("M_OPTTTL",PU_CACHE));
550 serge 947
 
298 serge 948
    V_DrawPatchDirect (OptionsDef.x + 175,OptionsDef.y+LINEHEIGHT*detail,0,
550 serge 949
                       W_CacheLumpName(detailNames[detailLevel],PU_CACHE));
298 serge 950
 
951
    V_DrawPatchDirect (OptionsDef.x + 120,OptionsDef.y+LINEHEIGHT*messages,0,
550 serge 952
                       W_CacheLumpName(msgNames[showMessages],PU_CACHE));
298 serge 953
 
954
    M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(mousesens+1),
550 serge 955
                 10,mouseSensitivity);
956
 
298 serge 957
    M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
550 serge 958
                 9,screenSize);
298 serge 959
}
960
 
961
void M_Options(int choice)
962
{
963
    M_SetupNextMenu(&OptionsDef);
964
}
965
 
966
 
967
 
968
//
969
//      Toggle messages on/off
970
//
971
void M_ChangeMessages(int choice)
972
{
973
    // warning: unused parameter `int choice'
974
    choice = 0;
975
    showMessages = 1 - showMessages;
550 serge 976
 
298 serge 977
    if (!showMessages)
550 serge 978
        players[consoleplayer].message = MSGOFF;
298 serge 979
    else
550 serge 980
        players[consoleplayer].message = MSGON ;
298 serge 981
 
982
    message_dontfuckwithme = true;
983
}
984
 
985
 
986
//
987
// M_EndGame
988
//
989
void M_EndGameResponse(int ch)
990
{
991
    if (ch != 'y')
550 serge 992
        return;
993
 
298 serge 994
    currentMenu->lastOn = itemOn;
995
    M_ClearMenus ();
996
    D_StartTitle ();
997
}
998
 
999
void M_EndGame(int choice)
1000
{
1001
    choice = 0;
1002
    if (!usergame)
1003
    {
550 serge 1004
        S_StartSound(NULL,sfx_oof);
1005
        return;
298 serge 1006
    }
550 serge 1007
 
298 serge 1008
    if (netgame)
1009
    {
550 serge 1010
        M_StartMessage(NETEND,NULL,false);
1011
        return;
298 serge 1012
    }
550 serge 1013
 
298 serge 1014
    M_StartMessage(ENDGAME,M_EndGameResponse,true);
1015
}
1016
 
1017
 
1018
 
1019
 
1020
//
1021
// M_ReadThis
1022
//
1023
void M_ReadThis(int choice)
1024
{
1025
    choice = 0;
1026
    M_SetupNextMenu(&ReadDef1);
1027
}
1028
 
1029
void M_ReadThis2(int choice)
1030
{
1031
    choice = 0;
1032
    M_SetupNextMenu(&ReadDef2);
1033
}
1034
 
1035
void M_FinishReadThis(int choice)
1036
{
1037
    choice = 0;
1038
    M_SetupNextMenu(&MainDef);
1039
}
1040
 
1041
 
1042
 
1043
 
1044
//
1045
// M_QuitDOOM
1046
//
1047
int     quitsounds[8] =
1048
{
1049
    sfx_pldeth,
1050
    sfx_dmpain,
1051
    sfx_popain,
1052
    sfx_slop,
1053
    sfx_telept,
1054
    sfx_posit1,
1055
    sfx_posit3,
1056
    sfx_sgtatk
1057
};
1058
 
1059
int     quitsounds2[8] =
1060
{
1061
    sfx_vilact,
1062
    sfx_getpow,
1063
    sfx_boscub,
1064
    sfx_slop,
1065
    sfx_skeswg,
1066
    sfx_kntdth,
1067
    sfx_bspact,
1068
    sfx_sgtatk
1069
};
1070
 
1071
 
1072
 
1073
void M_QuitResponse(int ch)
1074
{
1075
    if (ch != 'y')
550 serge 1076
        return;
298 serge 1077
    if (!netgame)
1078
    {
550 serge 1079
        if (gamemode == commercial)
1080
            S_StartSound(NULL,quitsounds2[(gametic>>2)&7]);
1081
        else
1082
            S_StartSound(NULL,quitsounds[(gametic>>2)&7]);
1083
        I_WaitVBL(105);
298 serge 1084
    }
1085
    I_Quit ();
1086
}
1087
 
1088
 
1089
 
1090
 
1091
void M_QuitDOOM(int choice)
1092
{
1093
  // We pick index 0 which is language sensitive,
1094
  //  or one at random, between 1 and maximum number.
1095
  if (language != english )
1096
    sprintf(endstring,"%s\n\n"DOSY, endmsg[0] );
1097
  else
1098
    sprintf(endstring,"%s\n\n"DOSY, endmsg[ (gametic%(NUM_QUITMESSAGES-2))+1 ]);
1099
 
1100
  M_StartMessage(endstring,M_QuitResponse,true);
1101
}
1102
 
1103
 
1104
 
1105
void M_ChangeSensitivity(int choice)
1106
{
1107
    switch(choice)
1108
    {
1109
      case 0:
550 serge 1110
        if (mouseSensitivity)
1111
            mouseSensitivity--;
1112
        break;
298 serge 1113
      case 1:
550 serge 1114
        if (mouseSensitivity < 9)
1115
            mouseSensitivity++;
1116
        break;
298 serge 1117
    }
1118
}
1119
 
1120
 
1121
 
1122
 
1123
void M_ChangeDetail(int choice)
1124
{
1125
    choice = 0;
1126
    detailLevel = 1 - detailLevel;
1127
 
1128
    // FIXME - does not work. Remove anyway?
1129
//    __libclog_printf("M_ChangeDetail: low detail mode n.a.\n");
1130
 
1131
    return;
1132
 
1133
    /*R_SetViewSize (screenblocks, detailLevel);
1134
 
1135
    if (!detailLevel)
550 serge 1136
        players[consoleplayer].message = DETAILHI;
298 serge 1137
    else
550 serge 1138
        players[consoleplayer].message = DETAILLO;*/
298 serge 1139
}
1140
 
1141
 
1142
 
1143
 
1144
void M_SizeDisplay(int choice)
1145
{
1146
    switch(choice)
1147
    {
1148
      case 0:
550 serge 1149
        if (screenSize > 0)
1150
        {
1151
            screenblocks--;
1152
            screenSize--;
1153
        }
1154
        break;
298 serge 1155
      case 1:
550 serge 1156
        if (screenSize < 8)
1157
        {
1158
            screenblocks++;
1159
            screenSize++;
1160
        }
1161
        break;
298 serge 1162
    }
550 serge 1163
 
298 serge 1164
 
1165
    R_SetViewSize (screenblocks, detailLevel);
1166
}
1167
 
1168
 
1169
 
1170
 
1171
//
1172
//      Menu Functions
1173
//
1174
void
1175
M_DrawThermo
550 serge 1176
( int   x,
1177
  int   y,
1178
  int   thermWidth,
1179
  int   thermDot )
298 serge 1180
{
550 serge 1181
    int         xx;
1182
    int         i;
298 serge 1183
 
1184
    xx = x;
1185
    V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERML",PU_CACHE));
1186
    xx += 8;
1187
    for (i=0;i
1188
    {
550 serge 1189
        V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERMM",PU_CACHE));
1190
        xx += 8;
298 serge 1191
    }
1192
    V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERMR",PU_CACHE));
1193
 
1194
    V_DrawPatchDirect ((x+8) + thermDot*8,y,
550 serge 1195
                       0,W_CacheLumpName("M_THERMO",PU_CACHE));
298 serge 1196
}
1197
 
1198
 
1199
 
1200
void
1201
M_DrawEmptyCell
550 serge 1202
( menu_t*       menu,
1203
  int           item )
298 serge 1204
{
1205
    V_DrawPatchDirect (menu->x - 10,        menu->y+item*LINEHEIGHT - 1, 0,
550 serge 1206
                       W_CacheLumpName("M_CELL1",PU_CACHE));
298 serge 1207
}
1208
 
1209
void
1210
M_DrawSelCell
550 serge 1211
( menu_t*       menu,
1212
  int           item )
298 serge 1213
{
1214
    V_DrawPatchDirect (menu->x - 10,        menu->y+item*LINEHEIGHT - 1, 0,
550 serge 1215
                       W_CacheLumpName("M_CELL2",PU_CACHE));
298 serge 1216
}
1217
 
1218
 
1219
void
1220
M_StartMessage
550 serge 1221
( char*         string,
1222
  void*         routine,
1223
  boolean       input )
298 serge 1224
{
1225
    messageLastMenuActive = menuactive;
1226
    messageToPrint = 1;
1227
    messageString = string;
1228
    messageRoutine = routine;
1229
    messageNeedsInput = input;
1230
    menuactive = true;
1231
    return;
1232
}
1233
 
1234
 
1235
 
1236
void M_StopMessage(void)
1237
{
1238
    menuactive = messageLastMenuActive;
1239
    messageToPrint = 0;
1240
}
1241
 
1242
 
1243
 
1244
//
1245
// Find string width from hu_font chars
1246
//
1247
int M_StringWidth(char* string)
1248
{
1249
    int             i;
1250
    int             w = 0;
1251
    int             c;
550 serge 1252
 
298 serge 1253
    for (i = 0;i < strlen(string);i++)
1254
    {
550 serge 1255
        c = toupper(string[i]) - HU_FONTSTART;
1256
        if (c < 0 || c >= HU_FONTSIZE)
1257
            w += 4;
1258
        else
1259
            w += SHORT (hu_font[c]->width);
298 serge 1260
    }
550 serge 1261
 
298 serge 1262
    return w;
1263
}
1264
 
1265
 
1266
 
1267
//
1268
//      Find string height from hu_font chars
1269
//
1270
int M_StringHeight(char* string)
1271
{
1272
    int             i;
1273
    int             h;
1274
    int             height = SHORT(hu_font[0]->height);
550 serge 1275
 
298 serge 1276
    h = height;
1277
    for (i = 0;i < strlen(string);i++)
550 serge 1278
        if (string[i] == '\n')
1279
            h += height;
1280
 
298 serge 1281
    return h;
1282
}
1283
 
1284
 
1285
//
1286
//      Write a string using the hu_font
1287
//
1288
void
1289
M_WriteText
550 serge 1290
( int           x,
1291
  int           y,
1292
  char*         string)
298 serge 1293
{
550 serge 1294
    int         w;
1295
    char*       ch;
1296
    int         c;
1297
    int         cx;
1298
    int         cy;
1299
 
298 serge 1300
 
1301
    ch = string;
1302
    cx = x;
1303
    cy = y;
550 serge 1304
 
298 serge 1305
    while(1)
1306
    {
550 serge 1307
        c = *ch++;
1308
        if (!c)
1309
            break;
1310
        if (c == '\n')
1311
        {
1312
            cx = x;
1313
            cy += 12;
1314
            continue;
1315
        }
1316
 
1317
        c = toupper(c) - HU_FONTSTART;
1318
        if (c < 0 || c>= HU_FONTSIZE)
1319
        {
1320
            cx += 4;
1321
            continue;
1322
        }
1323
 
1324
        w = SHORT (hu_font[c]->width);
1325
        if (cx+w > SCREENWIDTH)
1326
            break;
1327
        V_DrawPatchDirect(cx, cy, 0, hu_font[c]);
1328
        cx+=w;
298 serge 1329
    }
1330
}
1331
 
1332
 
1333
 
1334
//
1335
// CONTROL PANEL
1336
//
1337
 
1338
//
1339
// M_Responder
1340
//
1341
boolean M_Responder (event_t* ev)
1342
{
1343
    int             ch;
1344
    int             i;
1345
    static  int     joywait = 0;
1346
    static  int     mousewait = 0;
1347
    static  int     mousey = 0;
1348
    static  int     lasty = 0;
1349
    static  int     mousex = 0;
1350
    static  int     lastx = 0;
550 serge 1351
 
298 serge 1352
    ch = -1;
550 serge 1353
 
298 serge 1354
    if (ev->type == ev_joystick && joywait < I_GetTime())
1355
    {
550 serge 1356
        if (ev->data3 == -1)
1357
        {
1358
            ch = KEY_UPARROW;
1359
            joywait = I_GetTime() + 5;
1360
        }
1361
        else if (ev->data3 == 1)
1362
        {
1363
            ch = KEY_DOWNARROW;
1364
            joywait = I_GetTime() + 5;
1365
        }
1366
 
1367
        if (ev->data2 == -1)
1368
        {
1369
            ch = KEY_LEFTARROW;
1370
            joywait = I_GetTime() + 2;
1371
        }
1372
        else if (ev->data2 == 1)
1373
        {
1374
            ch = KEY_RIGHTARROW;
1375
            joywait = I_GetTime() + 2;
1376
        }
1377
 
1378
        if (ev->data1&1)
1379
        {
1380
            ch = KEY_ENTER;
1381
            joywait = I_GetTime() + 5;
1382
        }
1383
        if (ev->data1&2)
1384
        {
1385
            ch = KEY_BACKSPACE;
1386
            joywait = I_GetTime() + 5;
1387
        }
298 serge 1388
    }
1389
    else
1390
    {
550 serge 1391
        if (ev->type == ev_mouse && mousewait < I_GetTime())
1392
        {
1393
            mousey += ev->data3;
1394
            if (mousey < lasty-30)
1395
            {
1396
                ch = KEY_DOWNARROW;
1397
                mousewait = I_GetTime() + 5;
1398
                mousey = lasty -= 30;
1399
            }
1400
            else if (mousey > lasty+30)
1401
            {
1402
                ch = KEY_UPARROW;
1403
                mousewait = I_GetTime() + 5;
1404
                mousey = lasty += 30;
1405
            }
1406
 
1407
            mousex += ev->data2;
1408
            if (mousex < lastx-30)
1409
            {
1410
                ch = KEY_LEFTARROW;
1411
                mousewait = I_GetTime() + 5;
1412
                mousex = lastx -= 30;
1413
            }
1414
            else if (mousex > lastx+30)
1415
            {
1416
                ch = KEY_RIGHTARROW;
1417
                mousewait = I_GetTime() + 5;
1418
                mousex = lastx += 30;
1419
            }
1420
 
1421
            if (ev->data1&1)
1422
            {
1423
                ch = KEY_ENTER;
1424
                mousewait = I_GetTime() + 15;
1425
            }
1426
 
1427
            if (ev->data1&2)
1428
            {
1429
                ch = KEY_BACKSPACE;
1430
                mousewait = I_GetTime() + 15;
1431
            }
1432
        }
1433
        else
1434
            if (ev->type == ev_keydown)
1435
            {
1436
                ch = ev->data1;
1437
            }
298 serge 1438
    }
1439
 
1440
    if (ch == -1)
550 serge 1441
        return false;
298 serge 1442
 
1443
 
1444
    // Save Game string input
1445
    if (saveStringEnter)
1446
    {
550 serge 1447
        switch(ch)
1448
        {
1449
          case KEY_BACKSPACE:
1450
            if (saveCharIndex > 0)
1451
            {
1452
                saveCharIndex--;
1453
                savegamestrings[saveSlot][saveCharIndex] = 0;
1454
            }
1455
            break;
1456
 
1457
          case KEY_ESCAPE:
1458
            saveStringEnter = 0;
1459
            strcpy(&savegamestrings[saveSlot][0],saveOldString);
1460
            break;
1461
 
1462
          case KEY_ENTER:
1463
            saveStringEnter = 0;
1464
            if (savegamestrings[saveSlot][0])
1465
                M_DoSave(saveSlot);
1466
            break;
1467
 
1468
          default:
1469
            ch = toupper(ch);
1470
            if (ch != 32)
1471
                if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE)
1472
                    break;
1473
            if (ch >= 32 && ch <= 127 &&
1474
                saveCharIndex < SAVESTRINGSIZE-1 &&
1475
                M_StringWidth(savegamestrings[saveSlot]) <
1476
                (SAVESTRINGSIZE-2)*8)
1477
            {
1478
                savegamestrings[saveSlot][saveCharIndex++] = ch;
1479
                savegamestrings[saveSlot][saveCharIndex] = 0;
1480
            }
1481
            break;
1482
        }
1483
        return true;
298 serge 1484
    }
1485
 
1486
    // Take care of any messages that need input
1487
    if (messageToPrint)
1488
    {
550 serge 1489
        if (messageNeedsInput == true &&
1490
            !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE))
1491
            return false;
1492
 
1493
        menuactive = messageLastMenuActive;
1494
        messageToPrint = 0;
1495
        if (messageRoutine)
1496
            messageRoutine(ch);
1497
 
1498
        menuactive = false;
1499
        S_StartSound(NULL,sfx_swtchx);
1500
        return true;
298 serge 1501
    }
550 serge 1502
 
298 serge 1503
    if (devparm && ch == KEY_F1)
1504
    {
550 serge 1505
        G_ScreenShot ();
1506
        return true;
298 serge 1507
    }
550 serge 1508
 
298 serge 1509
 
1510
    // F-Keys
1511
    if (!menuactive)
550 serge 1512
        switch(ch)
1513
        {
1514
          case KEY_MINUS:         // Screen size down
1515
            if (automapactive || chat_on)
1516
                return false;
1517
            M_SizeDisplay(0);
1518
            S_StartSound(NULL,sfx_stnmov);
1519
            return true;
1520
 
1521
          case KEY_EQUALS:        // Screen size up
1522
            if (automapactive || chat_on)
1523
                return false;
1524
            M_SizeDisplay(1);
1525
            S_StartSound(NULL,sfx_stnmov);
1526
            return true;
1527
 
1528
          case KEY_F1:            // Help key
1529
            M_StartControlPanel ();
298 serge 1530
 
550 serge 1531
            if ( gamemode == retail )
1532
              currentMenu = &ReadDef2;
1533
            else
1534
              currentMenu = &ReadDef1;
1535
 
1536
            itemOn = 0;
1537
            S_StartSound(NULL,sfx_swtchn);
1538
            return true;
1539
 
1540
          case KEY_F2:            // Save
1541
            M_StartControlPanel();
1542
            S_StartSound(NULL,sfx_swtchn);
1543
            M_SaveGame(0);
1544
            return true;
1545
 
1546
          case KEY_F3:            // Load
1547
            M_StartControlPanel();
1548
            S_StartSound(NULL,sfx_swtchn);
1549
            M_LoadGame(0);
1550
            return true;
1551
 
1552
          case KEY_F4:            // Sound Volume
1553
            M_StartControlPanel ();
1554
            currentMenu = &SoundDef;
1555
            itemOn = sfx_vol;
1556
            S_StartSound(NULL,sfx_swtchn);
1557
            return true;
1558
 
1559
          case KEY_F5:            // Detail toggle
1560
            M_ChangeDetail(0);
1561
            S_StartSound(NULL,sfx_swtchn);
1562
            return true;
1563
 
1564
          case KEY_F6:            // Quicksave
1565
            S_StartSound(NULL,sfx_swtchn);
1566
            M_QuickSave();
1567
            return true;
1568
 
1569
          case KEY_F7:            // End game
1570
            S_StartSound(NULL,sfx_swtchn);
1571
            M_EndGame(0);
1572
            return true;
1573
 
1574
          case KEY_F8:            // Toggle messages
1575
            M_ChangeMessages(0);
1576
            S_StartSound(NULL,sfx_swtchn);
1577
            return true;
1578
 
1579
          case KEY_F9:            // Quickload
1580
            S_StartSound(NULL,sfx_swtchn);
1581
            M_QuickLoad();
1582
            return true;
1583
 
1584
          case KEY_F10:           // Quit DOOM
1585
            S_StartSound(NULL,sfx_swtchn);
1586
            M_QuitDOOM(0);
1587
            return true;
1588
 
1589
          case KEY_F11:           // gamma toggle
1590
            usegamma++;
1591
            if (usegamma > 4)
1592
                usegamma = 0;
1593
            players[consoleplayer].message = gammamsg[usegamma];
1594
            I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE));
1595
            return true;
1596
 
1597
        }
298 serge 1598
 
1599
 
1600
    // Pop-up menu?
1601
    if (!menuactive)
1602
    {
550 serge 1603
        if (ch == KEY_ESCAPE)
1604
        {
1605
            M_StartControlPanel ();
1606
            S_StartSound(NULL,sfx_swtchn);
1607
            return true;
1608
        }
1609
        return false;
298 serge 1610
    }
1611
 
1612
 
1613
    // Keys usable within menu
1614
    switch (ch)
1615
    {
1616
      case KEY_DOWNARROW:
550 serge 1617
        do
1618
        {
1619
            if (itemOn+1 > currentMenu->numitems-1)
1620
                itemOn = 0;
1621
            else itemOn++;
1622
            S_StartSound(NULL,sfx_pstop);
1623
        } while(currentMenu->menuitems[itemOn].status==-1);
1624
        return true;
1625
 
298 serge 1626
      case KEY_UPARROW:
550 serge 1627
        do
1628
        {
1629
            if (!itemOn)
1630
                itemOn = currentMenu->numitems-1;
1631
            else itemOn--;
1632
            S_StartSound(NULL,sfx_pstop);
1633
        } while(currentMenu->menuitems[itemOn].status==-1);
1634
        return true;
298 serge 1635
 
1636
      case KEY_LEFTARROW:
550 serge 1637
        if (currentMenu->menuitems[itemOn].routine &&
1638
            currentMenu->menuitems[itemOn].status == 2)
1639
        {
1640
            S_StartSound(NULL,sfx_stnmov);
1641
            currentMenu->menuitems[itemOn].routine(0);
1642
        }
1643
        return true;
1644
 
298 serge 1645
      case KEY_RIGHTARROW:
550 serge 1646
        if (currentMenu->menuitems[itemOn].routine &&
1647
            currentMenu->menuitems[itemOn].status == 2)
1648
        {
1649
            S_StartSound(NULL,sfx_stnmov);
1650
            currentMenu->menuitems[itemOn].routine(1);
1651
        }
1652
        return true;
298 serge 1653
 
1654
      case KEY_ENTER:
550 serge 1655
        if (currentMenu->menuitems[itemOn].routine &&
1656
            currentMenu->menuitems[itemOn].status)
1657
        {
1658
            currentMenu->lastOn = itemOn;
1659
            if (currentMenu->menuitems[itemOn].status == 2)
1660
            {
1661
                currentMenu->menuitems[itemOn].routine(1);      // right arrow
1662
                S_StartSound(NULL,sfx_stnmov);
1663
            }
1664
            else
1665
            {
1666
                currentMenu->menuitems[itemOn].routine(itemOn);
1667
                S_StartSound(NULL,sfx_pistol);
1668
            }
1669
        }
1670
        return true;
1671
 
298 serge 1672
      case KEY_ESCAPE:
550 serge 1673
        currentMenu->lastOn = itemOn;
1674
        M_ClearMenus ();
1675
        S_StartSound(NULL,sfx_swtchx);
1676
        return true;
1677
 
298 serge 1678
      case KEY_BACKSPACE:
550 serge 1679
        currentMenu->lastOn = itemOn;
1680
        if (currentMenu->prevMenu)
1681
        {
1682
            currentMenu = currentMenu->prevMenu;
1683
            itemOn = currentMenu->lastOn;
1684
            S_StartSound(NULL,sfx_swtchn);
1685
        }
1686
        return true;
1687
 
298 serge 1688
      default:
550 serge 1689
        for (i = itemOn+1;i < currentMenu->numitems;i++)
1690
            if (currentMenu->menuitems[i].alphaKey == ch)
1691
            {
1692
                itemOn = i;
1693
                S_StartSound(NULL,sfx_pstop);
1694
                return true;
1695
            }
1696
        for (i = 0;i <= itemOn;i++)
1697
            if (currentMenu->menuitems[i].alphaKey == ch)
1698
            {
1699
                itemOn = i;
1700
                S_StartSound(NULL,sfx_pstop);
1701
                return true;
1702
            }
1703
        break;
1704
 
298 serge 1705
    }
1706
 
1707
    return false;
1708
}
1709
 
1710
 
1711
 
1712
//
1713
// M_StartControlPanel
1714
//
1715
void M_StartControlPanel (void)
1716
{
1717
    // intro might call this repeatedly
1718
    if (menuactive)
550 serge 1719
        return;
298 serge 1720
 
1721
    menuactive = 1;
1722
    currentMenu = &MainDef;         // JDC
1723
    itemOn = currentMenu->lastOn;   // JDC
1724
}
1725
 
1726
 
1727
//
1728
// M_Drawer
1729
// Called after the view has been rendered,
1730
// but before it has been blitted.
1731
//
1732
void M_Drawer (void)
1733
{
550 serge 1734
    static short        x;
1735
    static short        y;
1736
    short               i;
1737
    short               max;
300 serge 1738
    char *p;
1739
    int len;
550 serge 1740
    char                string[40];
1741
    int                 start;
298 serge 1742
 
1743
    inhelpscreens = false;
1744
 
1745
    // Horiz. & Vertically center string and print it.
1746
    if (messageToPrint)
1747
    {
550 serge 1748
          y = 100 - M_StringHeight(messageString)/2;
1749
          p = messageString;
1750
          len = strlen(p);
1751
          while(*p)
1752
          {
300 serge 1753
        for (i = 0;len;i++,len--)
1754
        {
550 serge 1755
              if (*(p+i) == '\n')
1756
                  { memset(string,0,40);
1757
                    strncpy(string,p,i);
1758
                    p+= i+1;
1759
                    len-= 1;
1760
                    break;
1761
                  };
1762
            };
1763
 
300 serge 1764
        if (len == 0)
1765
        { strncpy(string,p,i);
1766
          p+=i;
1767
        };
1768
        x = 160 - M_StringWidth(string)/2;
1769
        M_WriteText(x,y,string);
1770
        y += SHORT(hu_font[0]->height);
550 serge 1771
          };
1772
          return;
300 serge 1773
    };
298 serge 1774
 
1775
    if (!menuactive)
550 serge 1776
        return;
298 serge 1777
 
1778
    if (currentMenu->routine)
550 serge 1779
        currentMenu->routine();         // call Draw routine
298 serge 1780
 
1781
    // DRAW MENU
1782
    x = currentMenu->x;
1783
    y = currentMenu->y;
1784
    max = currentMenu->numitems;
1785
 
1786
    for (i=0;i
1787
    {
550 serge 1788
        if (currentMenu->menuitems[i].name[0])
1789
            V_DrawPatchDirect (x,y,0,
1790
                               W_CacheLumpName(currentMenu->menuitems[i].name ,PU_CACHE));
1791
        y += LINEHEIGHT;
298 serge 1792
    }
1793
 
1794
 
1795
    // DRAW SKULL
1796
    V_DrawPatchDirect(x + SKULLXOFF,currentMenu->y - 5 + itemOn*LINEHEIGHT, 0,
550 serge 1797
                      W_CacheLumpName(skullName[whichSkull],PU_CACHE));
298 serge 1798
 
1799
}
1800
 
1801
 
1802
//
1803
// M_ClearMenus
1804
//
1805
void M_ClearMenus (void)
1806
{
1807
    menuactive = 0;
1808
    // if (!netgame && usergame && paused)
1809
    //       sendpause = true;
1810
}
1811
 
1812
 
1813
 
1814
 
1815
//
1816
// M_SetupNextMenu
1817
//
1818
void M_SetupNextMenu(menu_t *menudef)
1819
{
1820
    currentMenu = menudef;
1821
    itemOn = currentMenu->lastOn;
1822
}
1823
 
1824
 
1825
//
1826
// M_Ticker
1827
//
1828
void M_Ticker (void)
1829
{
1830
    if (--skullAnimCounter <= 0)
1831
    {
550 serge 1832
        whichSkull ^= 1;
1833
        skullAnimCounter = 8;
298 serge 1834
    }
1835
}
1836
 
1837
 
1838
//
1839
// M_Init
1840
//
1841
void M_Init (void)
1842
{
1843
    currentMenu = &MainDef;
1844
    menuactive = 0;
1845
    itemOn = currentMenu->lastOn;
1846
    whichSkull = 0;
1847
    skullAnimCounter = 10;
1848
    screenSize = screenblocks - 3;
1849
    messageToPrint = 0;
1850
    messageString = NULL;
1851
    messageLastMenuActive = menuactive;
1852
    quickSaveSlot = -1;
1853
 
1854
    // Here we could catch other version dependencies,
1855
    //  like HELP1/2, and four episodes.
1856
 
1857
 
1858
    switch ( gamemode )
1859
    {
1860
      case commercial:
550 serge 1861
        // This is used because DOOM 2 had only one HELP
298 serge 1862
        //  page. I use CREDIT as second page now, but
550 serge 1863
        //  kept this hack for educational purposes.
1864
        MainMenu[readthis] = MainMenu[quitdoom];
1865
        MainDef.numitems--;
1866
        MainDef.y += 8;
1867
        NewDef.prevMenu = &MainDef;
1868
        ReadDef1.routine = M_DrawReadThis1;
1869
        ReadDef1.x = 330;
1870
        ReadDef1.y = 165;
1871
        ReadMenu1[0].routine = M_FinishReadThis;
1872
        break;
298 serge 1873
      case shareware:
550 serge 1874
        // Episode 2 and 3 are handled,
1875
        //  branching to an ad screen.
298 serge 1876
      case registered:
550 serge 1877
        // We need to remove the fourth episode.
1878
        EpiDef.numitems--;
1879
        break;
298 serge 1880
      case retail:
550 serge 1881
        // We are fine.
298 serge 1882
      default:
550 serge 1883
        break;
298 serge 1884
    }
1885
 
1886
}
1887