1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4 
5 This file is part of Shadow Warrior version 1.2
6 
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 
22 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 #include "build.h"
27 #include "osd.h"
28 
29 #include "keys.h"
30 #include "names2.h"
31 #include "panel.h"
32 #include "game.h"
33 #include "tags.h"
34 #include "sector.h"
35 #include "sprite.h"
36 #include "weapon.h"
37 #include "player.h"
38 #include "jsector.h"
39 #include "control.h"
40 #include "menus.h"
41 #include "sw_strs.h"
42 #include "pal.h"
43 #include "demo.h"
44 
45 #include "function.h"
46 #include "gamedefs.h"
47 #include "config.h"
48 #include "net.h"
49 #include "fx_man.h"
50 #include "music.h"
51 #include "text.h"
52 
53 #include "colormap.h"
54 
55 //#define PLOCK_VERSION TRUE
56 
57 
58 short TimeLimitTable[9] = {0,3,5,10,15,20,30,45,60};
59 
60 short QuickLoadNum = -1;
61 char QuickLoadDescrDialog[32];
62 BOOL QuickSaveMode = FALSE;
63 BOOL SavePrompt = FALSE;
64 extern BOOL InMenuLevel, LoadGameOutsideMoveLoop, LoadGameFromDemo;
65 extern BYTE RedBookSong[40];
66 extern BOOL ExitLevel, NewGame;
67 extern short Level, Skill;
68 extern BOOL MusicInitialized, FxInitialized;
69 BOOL MNU_CheckUserMap(MenuItem *item);
70 BOOL MNU_SaveGameCheck(MenuItem_p item);
71 BOOL MNU_TeamPlayCheck(MenuItem *item);
72 BOOL MNU_CoopPlayCheck(MenuItem *item);
73 BOOL MNU_StatCheck(MenuItem *item);
74 BOOL MNU_LoadGameCheck(MenuItem *item);
75 static BOOL MNU_TryMusicInit(void);
76 static void MNU_UpLevel(void);
77 
78 BOOL MNU_LoadSaveDraw(UserCall call, MenuItem * item);
79 BOOL MNU_LoadSaveMove(UserCall call, MenuItem * item);
80 
81 BOOL MenuButtonAutoRun = FALSE;
82 BOOL MenuButtonAutoAim = FALSE;
83 // misc load-save vars
84 short LastSaveNum = 99;
85 char SaveGameDescr[10][80];
86 char BackupSaveGameDescr[80];
87 short screen_tile = -1;
88 
89 BOOL MenuInputMode = FALSE;
90 SHORT MenuTextShade = 0;
91 BOOL passwordvalid = FALSE;
92 
93 BOOL MNU_HurtTeammateCheck(MenuItem *item);
94 BOOL MNU_TeamPlayChange(void);
95 
96 // Font pic table
97 unsigned short xlatfont[] = {
98     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 32
99     2274, 2294, 2274, 2277, 2278, 2280, 2295, 2282, 2283, 2281, 2286, 2297, 2285,       // 45
100     2299, 2301, 2271, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2270,     // 57
101     2292, 2293, 2296, 2287, 2298, 2300, 2275, 2236, 2237, 2238, 2239, 2240,     // 69
102     2241, 2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252,     // 81
103     2253, 2254, 2255, 2256, 2257, 2258, 2259, 2260, 2261, 2290, 2289, 2291,     // 93
104     2279, 2284, 2295, 2236, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2244,     // 105
105     2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256,     // 117
106     2257, 2258, 2259, 2260, 2261, 2282, 2288, 2283, 2272        // 126
107     };
108 
109 int slidersettings [sldr_max] =
110     {
111     0, SENSE_DEFAULT, FXVOL_DEFAULT, MUSIC_DEFAULT, SCRSIZE_DEFAULT,
112         BRIGHTNESS_DEFAULT, BORDERTILE_DEFAULT, GAMETYPE_DEFAULT, NETLEVEL_DEFAULT,
113         MONSTERS_DEFAULT, KILLLIMIT_DEFAULT, TIMELIMIT_DEFAULT, PLAYERCOLOR_DEFAULT,
114     0,0,    // video mode
115     32767>>12, 32767>>12,  // advanced mouse scale
116     0, 0, 0, 0,   // joystick axis configuration
117     PANELSCALE_DEFAULT
118     };
119 
120 short buttonsettings[btn_max];
121 
122 // EXTERNS ////////////////////////////
123 #define XDIM    320
124 #define YDIM    200
125 extern char DefaultPalette[];
126 extern BOOL QuitFlag;
127 
128 void TerminateGame(void);
129 void ResetKeys(void);
130 
131 // GLOBALS ////////////////////////////
132 
133 char playertextbuffer[80];              // Used for various input strings
134 char playerbuflen = 0;                  // Current length of the string in
135                                         // the buffer
136 char maxtextlen;                        // max length allowed for current
137 
138 static VMODE validresolutions[MAXVALIDMODES];
139 static int numvalidresolutions = 0, validbpps[8], numvalidbpps = 0;
140 
UpdateValidModes(int bpp,int fs)141 static void UpdateValidModes(int bpp, int fs)
142 {
143 	int i, j;
144 
145 	numvalidresolutions = numvalidbpps = 0;
146 	for (i=0; i<validmodecnt; i++) {
147 		if ((validmode[i].fs & 1) != fs) continue;
148 
149 		for (j=0; j<numvalidbpps; j++)
150 			if (validbpps[j] == validmode[i].bpp) break;
151 		if (j==numvalidbpps) validbpps[numvalidbpps++] = validmode[i].bpp;
152 
153 		if (validmode[i].bpp != bpp) continue;
154 
155 		validresolutions[numvalidresolutions].x = validmode[i].xdim;
156 		validresolutions[numvalidresolutions].y = validmode[i].ydim;
157         validresolutions[numvalidresolutions].bpp = validmode[i].bpp;
158         validresolutions[numvalidresolutions].fs = validmode[i].fs;
159 		numvalidresolutions++;
160 	}
161 }
162 
163 
164 MenuItem sound_i[] =
165 {
166     {DefButton(btn_music, 0, "Music"), OPT_XS,                OPT_LINE(0), 1, m_defshade, 0, MNU_TryMusicInit, MNU_MusicCheck, NULL},
167     {DefSlider(sldr_musicvolume, 0, "Music Volume"), OPT_XS,  OPT_LINE(1), 1, m_defshade, 0, MNU_TryMusicInit, MNU_MusicCheck, NULL},
168     {DefInert(0, NULL), OPT_XSIDE,                            OPT_LINE(1), 0, m_defshade, 0, NULL, NULL, NULL},
169 
170     {DefButton(btn_sound, 0, "Sounds"), OPT_XS,               OPT_LINE(2), 1, m_defshade, 0, NULL, MNU_FxCheck, NULL},
171     {DefSlider(sldr_sndfxvolume, 0, "Sound Volume"), OPT_XS,  OPT_LINE(3), 1, m_defshade, 0, NULL, MNU_FxCheck, NULL},
172     {DefInert(0, NULL), OPT_XSIDE,                            OPT_LINE(3), 0, m_defshade, 0, NULL, NULL, NULL},
173 
174     //{DefButton(btn_talking, 0, "Talking"), OPT_XS,            OPT_LINE(4), 1, m_defshade, 0, NULL, MNU_FxCheck, NULL},
175     {DefButton(btn_ambience, 0, "Ambience"), OPT_XS,          OPT_LINE(4), 1, m_defshade, 0, NULL, MNU_FxCheck, NULL},
176     {DefButton(btn_flipstereo, 0, "Flip Stereo"), OPT_XS,     OPT_LINE(5), 1, m_defshade, 0, NULL, MNU_FxCheck, NULL},
177     //{DefButton(btn_playcd, 0, "Play CD"), OPT_XS,         OPT_LINE(6), 1, m_defshade, 0, NULL, NULL, NULL},
178     {DefNone}
179 };
180 
181 MenuGroup soundgroup = {110,5,"^Sound",sound_i,pic_optionstitl,0,m_defshade, NULL,NULL, 0};
182 
183 MenuItem parental_i[] =
184     {
185     {DefButton(btn_parental, 0, "Kid Mode"), OPT_XS, OPT_LINE(0), 1, m_defshade, 0, NULL, NULL, NULL},
186     {DefOption(KEYSC_P, "Change Password"),              OPT_XS, OPT_LINE(1), 1, m_defshade, 0, MNU_ParentalCustom, NULL, NULL},
187     {DefNone}
188     };
189 
190 MenuGroup parentalgroup = {65, 5, "^Kid Mode", parental_i, pic_newgametitl, 0, m_defshade, MNU_DoParentalPassword,NULL,0};
191 
192 MenuItem screen_i[] =
193     {
194     {DefSlider(sldr_scrsize, 0, "Screen Size"), OPT_XS,          OPT_LINE(0), 1, m_defshade, 0, NULL, NULL, NULL},//, MNU_BorderCheck},
195     {DefInert(0, NULL), OPT_XSIDE,                               OPT_LINE(0), 0, m_defshade, 0, NULL, NULL, NULL},
196 
197     {DefSlider(sldr_bordertile, 0, "Border Tile"), OPT_XS,       OPT_LINE(1), 1, m_defshade, 0, NULL, NULL, NULL},//, MNU_BorderCheck},
198     {DefInert(0, NULL), OPT_XSIDE,                               OPT_LINE(1), 0, m_defshade, 0, NULL, NULL, NULL},
199 
200     {DefSlider(sldr_brightness, KEYSC_B, "Brightness"), OPT_XS,  OPT_LINE(2), 1, m_defshade, 0, NULL, NULL, NULL},
201     {DefInert(0, NULL), OPT_XSIDE,                               OPT_LINE(2), 0, m_defshade, 0, NULL, NULL, NULL},
202 
203     {DefSlider(sldr_panelscale, 0, "Panel Scale"), OPT_XS,       OPT_LINE(3), 1, m_defshade, 0, NULL, NULL, NULL},
204     {DefInert(0, NULL), OPT_XSIDE,                               OPT_LINE(3), 0, m_defshade, 0, NULL, NULL, NULL},
205 
206 #if USE_POLYMOST && USE_OPENGL
207     {DefButton(btn_texfilter, 0, "Filtering"), OPT_XS,           OPT_LINE(5), 1, m_defshade, 0, NULL, MNU_TexFilterCheck, NULL},
208 #endif
209     {DefButton(btn_videofs, 0, "Fullscreen"), OPT_XS,            OPT_LINE(6), 1, m_defshade, 0, NULL, NULL, NULL},
210     {DefSlider(sldr_videobpp, 0, "Colour"), OPT_XS,              OPT_LINE(7), 1, m_defshade, 0, NULL, NULL, NULL},
211     {DefInert(0, NULL), OPT_XSIDE,                               OPT_LINE(7), 0, m_defshade, 0, NULL, NULL, NULL},
212     {DefSlider(sldr_videores, 0, "Resolution"), OPT_XS,          OPT_LINE(8), 1, m_defshade, 0, NULL, NULL, NULL},
213     {DefInert(0, NULL), OPT_XSIDE,                               OPT_LINE(8), 0, m_defshade, 0, NULL, NULL, NULL},
214     {DefOption(0, "Apply Settings"), OPT_XSIDE,                 OPT_LINE(10), 1, m_defshade, 0, MNU_ApplyVideoModeSettings, NULL, NULL},
215     {DefNone}
216     };
217 
218 MenuGroup screengroup = {65, 5, "^Screen", screen_i, pic_newgametitl, 0, m_defshade, NULL,NULL, 0};
219 
220 MenuItem mouse_i[] =
221     {
222     {DefSlider(sldr_mouse, 0, "Mouse Speed"), OPT_XS,            OPT_LINE(0), 1, m_defshade, 0, NULL, MNU_MouseCheck, NULL},
223     {DefInert(0, NULL), OPT_XSIDE,                               OPT_LINE(0), 0, m_defshade, 0, NULL, NULL, NULL},    // Blank line for mouse
224 
225     {DefButton(btn_mouse_aim, 0, "Mouse Aiming"), OPT_XS,        OPT_LINE(1), 1, m_defshade, 0, NULL, MNU_MouseCheck, NULL},
226     {DefButton(btn_mouse_invert, 0, "Invert Mouse"), OPT_XS,     OPT_LINE(2), 1, m_defshade, 0, NULL, MNU_MouseCheck, NULL},
227     {DefNone}
228     };
229 
230 MenuGroup mousegroup = {65, 5, "^Mouse", mouse_i, pic_newgametitl, 0, m_defshade, NULL,NULL, 0};
231 
232 MenuGroup keysetupgroup = {0, 0, NULL, NULL, 0, 0, m_defshade, MNU_KeySetupCustom, NULL, 0};
233 
234 static char MouseButtonFunctions[MAXMOUSEBUTTONS][2][MAXFUNCTIONLENGTH];
235 static BOOL MNU_SetMouseButtonFunctions(MenuItem_p item);
236 static BOOL MNU_MouseButtonPostProcess(MenuItem_p item);
237 static BOOL MNU_MouseButtonSetupCustom(UserCall call, MenuItem_p item);
238 MenuGroup mousebuttongroup = {0, 0, NULL, NULL, 0, 0, m_defshade, MNU_MouseButtonSetupCustom, NULL, 0};
239 MenuItem mousesetup_i[] =
240     {
241     {DefLayer(0, "Left", &mousebuttongroup),                         OPT_XS, OPT_LINE(0), 1, m_defshade, mousebutton_Left,       NULL, NULL, MNU_MouseButtonPostProcess},
242     {DefInert(0, MouseButtonFunctions[mousebutton_Left][0]),      OPT_XSIDE, OPT_LINE(0), 1, m_defshade, mousebutton_Left,       NULL, MNU_SetMouseButtonFunctions, NULL},
243     {DefLayer(0, "Double Left", &mousebuttongroup),                  OPT_XS, OPT_LINE(1), 1, m_defshade, 128+mousebutton_Left,   NULL, NULL, MNU_MouseButtonPostProcess},
244     {DefInert(0, MouseButtonFunctions[mousebutton_Left][1]),      OPT_XSIDE, OPT_LINE(1), 1, m_defshade, 128+mousebutton_Left,   NULL, MNU_SetMouseButtonFunctions, NULL},
245     {DefLayer(0, "Right", &mousebuttongroup),                        OPT_XS, OPT_LINE(2), 1, m_defshade, mousebutton_Right,      NULL, NULL, MNU_MouseButtonPostProcess},
246     {DefInert(0, MouseButtonFunctions[mousebutton_Right][0]),     OPT_XSIDE, OPT_LINE(2), 1, m_defshade, mousebutton_Right,      NULL, MNU_SetMouseButtonFunctions, NULL},
247     {DefLayer(0, "Double Right", &mousebuttongroup),                 OPT_XS, OPT_LINE(3), 1, m_defshade, 128+mousebutton_Right,  NULL, NULL, MNU_MouseButtonPostProcess},
248     {DefInert(0, MouseButtonFunctions[mousebutton_Right][1]),     OPT_XSIDE, OPT_LINE(3), 1, m_defshade, 128+mousebutton_Right,  NULL, MNU_SetMouseButtonFunctions, NULL},
249     {DefLayer(0, "Middle", &mousebuttongroup),                       OPT_XS, OPT_LINE(4), 1, m_defshade, mousebutton_Middle,     NULL, NULL, MNU_MouseButtonPostProcess},
250     {DefInert(0, MouseButtonFunctions[mousebutton_Middle][0]),    OPT_XSIDE, OPT_LINE(4), 1, m_defshade, mousebutton_Middle,     NULL, MNU_SetMouseButtonFunctions, NULL},
251     {DefLayer(0, "Double Middle", &mousebuttongroup),                OPT_XS, OPT_LINE(5), 1, m_defshade, 128+mousebutton_Middle, NULL, NULL, MNU_MouseButtonPostProcess},
252     {DefInert(0, MouseButtonFunctions[mousebutton_Middle][1]),    OPT_XSIDE, OPT_LINE(5), 1, m_defshade, 128+mousebutton_Middle, NULL, MNU_SetMouseButtonFunctions, NULL},
253     {DefLayer(0, "Thumb", &mousebuttongroup),                        OPT_XS, OPT_LINE(6), 1, m_defshade, mousebutton_Thumb,      NULL, NULL, MNU_MouseButtonPostProcess},
254     {DefInert(0, MouseButtonFunctions[mousebutton_Thumb][0]),     OPT_XSIDE, OPT_LINE(6), 1, m_defshade, mousebutton_Thumb,      NULL, MNU_SetMouseButtonFunctions, NULL},
255     {DefLayer(0, "Double Thumb", &mousebuttongroup),                 OPT_XS, OPT_LINE(7), 1, m_defshade, 128+mousebutton_Thumb,  NULL, NULL, MNU_MouseButtonPostProcess},
256     {DefInert(0, MouseButtonFunctions[mousebutton_Thumb][1]),     OPT_XSIDE, OPT_LINE(7), 1, m_defshade, 128+mousebutton_Thumb,  NULL, MNU_SetMouseButtonFunctions, NULL},
257     {DefLayer(0, "Wheel Up", &mousebuttongroup),                     OPT_XS, OPT_LINE(8), 1, m_defshade, mousebutton_WheelUp,    NULL, NULL, MNU_MouseButtonPostProcess},
258     {DefInert(0, MouseButtonFunctions[mousebutton_WheelUp][0]),   OPT_XSIDE, OPT_LINE(8), 1, m_defshade, mousebutton_WheelUp,    NULL, MNU_SetMouseButtonFunctions, NULL},
259     {DefLayer(0, "Wheel Down", &mousebuttongroup),                   OPT_XS, OPT_LINE(9), 1, m_defshade, mousebutton_WheelDown,  NULL, NULL, MNU_MouseButtonPostProcess},
260     {DefInert(0, MouseButtonFunctions[mousebutton_WheelDown][0]), OPT_XSIDE, OPT_LINE(9), 1, m_defshade, mousebutton_WheelDown,  NULL, MNU_SetMouseButtonFunctions, NULL},
261     {DefNone}
262     };
263 MenuGroup mousesetupgroup = {65, 5, "^Mouse Buttons", mousesetup_i, pic_newgametitl, 0, m_defshade, NULL, NULL, 0};
264 
265 #define MAXJOYSTICKBUTTONPAGES 4
266 static char JoystickButtonFunctions[MAXJOYBUTTONS][2][MAXFUNCTIONLENGTH];
267 static int JoystickButtonPage = 0;
268 static BOOL MNU_JoystickButtonsInitialise(MenuItem_p item);
269 static BOOL MNU_SetJoystickButtonFunctions(MenuItem_p item);
270 static BOOL MNU_JoystickButtonPostProcess(MenuItem_p item);
271 static BOOL MNU_JoystickButtonSetupCustom(UserCall call, MenuItem_p item);
272 static BOOL MNU_JoystickButtonNextPage(void);
273 MenuGroup joybuttonsgroup = {0, 0, NULL, NULL, 0, 0, m_defshade, MNU_JoystickButtonSetupCustom, NULL, 0};
274 MenuItem joybuttons_i[MAXJOYSTICKBUTTONPAGES][20] =
275     {
276         {
277         {DefLayer(0, "A", &joybuttonsgroup),                           OPT_XS, OPT_LINE(0), 1, m_defshade, joybutton_A,         NULL, NULL, MNU_JoystickButtonPostProcess},
278         {DefInert(0, JoystickButtonFunctions[joybutton_A][0]),      OPT_XSIDE, OPT_LINE(0), 1, m_defshade, joybutton_A,         NULL, MNU_SetJoystickButtonFunctions, NULL},
279         {DefLayer(0, "Double A", &joybuttonsgroup),                    OPT_XS, OPT_LINE(1), 1, m_defshade, 128+joybutton_A,     NULL, NULL, MNU_JoystickButtonPostProcess},
280         {DefInert(0, JoystickButtonFunctions[joybutton_A][1]),      OPT_XSIDE, OPT_LINE(1), 1, m_defshade, 128+joybutton_A,     NULL, MNU_SetJoystickButtonFunctions, NULL},
281         {DefLayer(0, "B", &joybuttonsgroup),                           OPT_XS, OPT_LINE(2), 1, m_defshade, joybutton_B,         NULL, NULL, MNU_JoystickButtonPostProcess},
282         {DefInert(0, JoystickButtonFunctions[joybutton_B][0]),      OPT_XSIDE, OPT_LINE(2), 1, m_defshade, joybutton_B,         NULL, MNU_SetJoystickButtonFunctions, NULL},
283         {DefLayer(0, "Double B", &joybuttonsgroup),                    OPT_XS, OPT_LINE(3), 1, m_defshade, 128+joybutton_B,     NULL, NULL, MNU_JoystickButtonPostProcess},
284         {DefInert(0, JoystickButtonFunctions[joybutton_B][1]),      OPT_XSIDE, OPT_LINE(3), 1, m_defshade, 128+joybutton_B,     NULL, MNU_SetJoystickButtonFunctions, NULL},
285         {DefLayer(0, "X", &joybuttonsgroup),                           OPT_XS, OPT_LINE(4), 1, m_defshade, joybutton_X,         NULL, NULL, MNU_JoystickButtonPostProcess},
286         {DefInert(0, JoystickButtonFunctions[joybutton_X][0]),      OPT_XSIDE, OPT_LINE(4), 1, m_defshade, joybutton_X,         NULL, MNU_SetJoystickButtonFunctions, NULL},
287         {DefLayer(0, "Double X", &joybuttonsgroup),                    OPT_XS, OPT_LINE(5), 1, m_defshade, 128+joybutton_X,     NULL, NULL, MNU_JoystickButtonPostProcess},
288         {DefInert(0, JoystickButtonFunctions[joybutton_X][1]),      OPT_XSIDE, OPT_LINE(5), 1, m_defshade, 128+joybutton_X,     NULL, MNU_SetJoystickButtonFunctions, NULL},
289         {DefLayer(0, "Y", &joybuttonsgroup),                           OPT_XS, OPT_LINE(6), 1, m_defshade, joybutton_Y,         NULL, NULL, MNU_JoystickButtonPostProcess},
290         {DefInert(0, JoystickButtonFunctions[joybutton_Y][0]),      OPT_XSIDE, OPT_LINE(6), 1, m_defshade, joybutton_Y,         NULL, MNU_SetJoystickButtonFunctions, NULL},
291         {DefLayer(0, "Double Y", &joybuttonsgroup),                    OPT_XS, OPT_LINE(7), 1, m_defshade, 128+joybutton_Y,     NULL, NULL, MNU_JoystickButtonPostProcess},
292         {DefInert(0, JoystickButtonFunctions[joybutton_Y][1]),      OPT_XSIDE, OPT_LINE(7), 1, m_defshade, 128+joybutton_Y,     NULL, MNU_SetJoystickButtonFunctions, NULL},
293 
294         {DefInert(0, "Page 1 / 4"),                          OPT_XS, OPT_LINE(10), 1, m_defshade, 0, NULL, NULL, NULL },
295         {DefOption(0, "Next..."),                         OPT_XSIDE, OPT_LINE(10), 1, m_defshade, 0, MNU_JoystickButtonNextPage, NULL, NULL },
296         {DefNone}
297         },
298 
299         {
300         {DefLayer(0, "Left stick", &joybuttonsgroup),                         OPT_XS, OPT_LINE(0), 1, m_defshade, joybutton_LeftStick,         NULL, NULL, MNU_JoystickButtonPostProcess},
301         {DefInert(0, JoystickButtonFunctions[joybutton_LeftStick][0]),     OPT_XSIDE, OPT_LINE(0), 1, m_defshade, joybutton_LeftStick,         NULL, MNU_SetJoystickButtonFunctions, NULL},
302         {DefLayer(0, "Dbl Left stick", &joybuttonsgroup),                     OPT_XS, OPT_LINE(1), 1, m_defshade, 128+joybutton_LeftStick,     NULL, NULL, MNU_JoystickButtonPostProcess},
303         {DefInert(0, JoystickButtonFunctions[joybutton_LeftStick][1]),     OPT_XSIDE, OPT_LINE(1), 1, m_defshade, 128+joybutton_LeftStick,     NULL, MNU_SetJoystickButtonFunctions, NULL},
304         {DefLayer(0, "Right stick", &joybuttonsgroup),                        OPT_XS, OPT_LINE(2), 1, m_defshade, joybutton_RightStick,        NULL, NULL, MNU_JoystickButtonPostProcess},
305         {DefInert(0, JoystickButtonFunctions[joybutton_RightStick][0]),    OPT_XSIDE, OPT_LINE(2), 1, m_defshade, joybutton_RightStick,        NULL, MNU_SetJoystickButtonFunctions, NULL},
306         {DefLayer(0, "Dbl Right stick", &joybuttonsgroup),                    OPT_XS, OPT_LINE(3), 1, m_defshade, 128+joybutton_RightStick,    NULL, NULL, MNU_JoystickButtonPostProcess},
307         {DefInert(0, JoystickButtonFunctions[joybutton_RightStick][1]),    OPT_XSIDE, OPT_LINE(3), 1, m_defshade, 128+joybutton_RightStick,    NULL, MNU_SetJoystickButtonFunctions, NULL},
308         {DefLayer(0, "Left shoulder", &joybuttonsgroup),                      OPT_XS, OPT_LINE(4), 1, m_defshade, joybutton_LeftShoulder,      NULL, NULL, MNU_JoystickButtonPostProcess},
309         {DefInert(0, JoystickButtonFunctions[joybutton_LeftShoulder][0]),  OPT_XSIDE, OPT_LINE(4), 1, m_defshade, joybutton_LeftShoulder,      NULL, MNU_SetJoystickButtonFunctions, NULL},
310         {DefLayer(0, "Dbl Lt shoulder", &joybuttonsgroup),                    OPT_XS, OPT_LINE(5), 1, m_defshade, 128+joybutton_LeftShoulder,  NULL, NULL, MNU_JoystickButtonPostProcess},
311         {DefInert(0, JoystickButtonFunctions[joybutton_LeftShoulder][1]),  OPT_XSIDE, OPT_LINE(5), 1, m_defshade, 128+joybutton_LeftShoulder,  NULL, MNU_SetJoystickButtonFunctions, NULL},
312         {DefLayer(0, "Right shoulder", &joybuttonsgroup),                     OPT_XS, OPT_LINE(6), 1, m_defshade, joybutton_RightShoulder,     NULL, NULL, MNU_JoystickButtonPostProcess},
313         {DefInert(0, JoystickButtonFunctions[joybutton_RightShoulder][0]), OPT_XSIDE, OPT_LINE(6), 1, m_defshade, joybutton_RightShoulder,     NULL, MNU_SetJoystickButtonFunctions, NULL},
314         {DefLayer(0, "Dbl Rt shoulder", &joybuttonsgroup),                    OPT_XS, OPT_LINE(7), 1, m_defshade, 128+joybutton_RightShoulder, NULL, NULL, MNU_JoystickButtonPostProcess},
315         {DefInert(0, JoystickButtonFunctions[joybutton_RightShoulder][1]), OPT_XSIDE, OPT_LINE(7), 1, m_defshade, 128+joybutton_RightShoulder, NULL, MNU_SetJoystickButtonFunctions, NULL},
316 
317         {DefInert(0, "Page 2 / 4"),                          OPT_XS, OPT_LINE(10), 1, m_defshade, 0, NULL, NULL, NULL },
318         {DefOption(0, "Next..."),                         OPT_XSIDE, OPT_LINE(10), 1, m_defshade, 0, MNU_JoystickButtonNextPage, NULL, NULL },
319         {DefNone}
320         },
321 
322         {
323         {DefLayer(0, "Dpad up", &joybuttonsgroup),                        OPT_XS, OPT_LINE(0), 1, m_defshade, joybutton_DpadUp,        NULL, NULL, MNU_JoystickButtonPostProcess},
324         {DefInert(0, JoystickButtonFunctions[joybutton_DpadUp][0]),    OPT_XSIDE, OPT_LINE(0), 1, m_defshade, joybutton_DpadUp,        NULL, MNU_SetJoystickButtonFunctions, NULL},
325         {DefLayer(0, "Dbl Dpad up", &joybuttonsgroup),                    OPT_XS, OPT_LINE(1), 1, m_defshade, 128+joybutton_DpadUp,    NULL, NULL, MNU_JoystickButtonPostProcess},
326         {DefInert(0, JoystickButtonFunctions[joybutton_DpadUp][1]),    OPT_XSIDE, OPT_LINE(1), 1, m_defshade, 128+joybutton_DpadUp,    NULL, MNU_SetJoystickButtonFunctions, NULL},
327         {DefLayer(0, "Dpad down", &joybuttonsgroup),                      OPT_XS, OPT_LINE(2), 1, m_defshade, joybutton_DpadDown,      NULL, NULL, MNU_JoystickButtonPostProcess},
328         {DefInert(0, JoystickButtonFunctions[joybutton_DpadDown][0]),  OPT_XSIDE, OPT_LINE(2), 1, m_defshade, joybutton_DpadDown,      NULL, MNU_SetJoystickButtonFunctions, NULL},
329         {DefLayer(0, "Dbl Dpad down", &joybuttonsgroup),                  OPT_XS, OPT_LINE(3), 1, m_defshade, 128+joybutton_DpadDown,  NULL, NULL, MNU_JoystickButtonPostProcess},
330         {DefInert(0, JoystickButtonFunctions[joybutton_DpadDown][1]),  OPT_XSIDE, OPT_LINE(3), 1, m_defshade, 128+joybutton_DpadDown,  NULL, MNU_SetJoystickButtonFunctions, NULL},
331         {DefLayer(0, "Dpad left", &joybuttonsgroup),                      OPT_XS, OPT_LINE(4), 1, m_defshade, joybutton_DpadLeft,      NULL, NULL, MNU_JoystickButtonPostProcess},
332         {DefInert(0, JoystickButtonFunctions[joybutton_DpadLeft][0]),  OPT_XSIDE, OPT_LINE(4), 1, m_defshade, joybutton_DpadLeft,      NULL, MNU_SetJoystickButtonFunctions, NULL},
333         {DefLayer(0, "Dbl Dpad left", &joybuttonsgroup),                  OPT_XS, OPT_LINE(5), 1, m_defshade, 128+joybutton_DpadLeft,  NULL, NULL, MNU_JoystickButtonPostProcess},
334         {DefInert(0, JoystickButtonFunctions[joybutton_DpadLeft][1]),  OPT_XSIDE, OPT_LINE(5), 1, m_defshade, 128+joybutton_DpadLeft,  NULL, MNU_SetJoystickButtonFunctions, NULL},
335         {DefLayer(0, "Dpad right", &joybuttonsgroup),                     OPT_XS, OPT_LINE(6), 1, m_defshade, joybutton_DpadRight,     NULL, NULL, MNU_JoystickButtonPostProcess},
336         {DefInert(0, JoystickButtonFunctions[joybutton_DpadRight][0]), OPT_XSIDE, OPT_LINE(6), 1, m_defshade, joybutton_DpadRight,     NULL, MNU_SetJoystickButtonFunctions, NULL},
337         {DefLayer(0, "Dbl Dpad right", &joybuttonsgroup),                 OPT_XS, OPT_LINE(7), 1, m_defshade, 128+joybutton_DpadRight, NULL, NULL, MNU_JoystickButtonPostProcess},
338         {DefInert(0, JoystickButtonFunctions[joybutton_DpadRight][1]), OPT_XSIDE, OPT_LINE(7), 1, m_defshade, 128+joybutton_DpadRight, NULL, MNU_SetJoystickButtonFunctions, NULL},
339 
340         {DefInert(0, "Page 3 / 4"),                          OPT_XS, OPT_LINE(10), 1, m_defshade, 0, NULL, NULL, NULL },
341         {DefOption(0, "Next..."),                         OPT_XSIDE, OPT_LINE(10), 1, m_defshade, 0, MNU_JoystickButtonNextPage, NULL, NULL },
342         {DefNone}
343         },
344 
345         {
346         {DefLayer(0, "Back", &joybuttonsgroup),                       OPT_XS, OPT_LINE(0), 1, m_defshade, joybutton_Back,      NULL, NULL, MNU_JoystickButtonPostProcess},
347         {DefInert(0, JoystickButtonFunctions[joybutton_Back][0]),  OPT_XSIDE, OPT_LINE(0), 1, m_defshade, joybutton_Back,      NULL, MNU_SetJoystickButtonFunctions, NULL},
348         {DefLayer(0, "Dbl Back", &joybuttonsgroup),                   OPT_XS, OPT_LINE(1), 1, m_defshade, 128+joybutton_Back,  NULL, NULL, MNU_JoystickButtonPostProcess},
349         {DefInert(0, JoystickButtonFunctions[joybutton_Back][1]),  OPT_XSIDE, OPT_LINE(1), 1, m_defshade, 128+joybutton_Back,  NULL, MNU_SetJoystickButtonFunctions, NULL},
350         {DefLayer(0, "Guide", &joybuttonsgroup),                      OPT_XS, OPT_LINE(2), 1, m_defshade, joybutton_Guide,     NULL, NULL, MNU_JoystickButtonPostProcess},
351         {DefInert(0, JoystickButtonFunctions[joybutton_Guide][0]), OPT_XSIDE, OPT_LINE(2), 1, m_defshade, joybutton_Guide,     NULL, MNU_SetJoystickButtonFunctions, NULL},
352         {DefLayer(0, "Dbl Guide", &joybuttonsgroup),                  OPT_XS, OPT_LINE(3), 1, m_defshade, 128+joybutton_Guide, NULL, NULL, MNU_JoystickButtonPostProcess},
353         {DefInert(0, JoystickButtonFunctions[joybutton_Guide][1]), OPT_XSIDE, OPT_LINE(3), 1, m_defshade, 128+joybutton_Guide, NULL, MNU_SetJoystickButtonFunctions, NULL},
354         {DefLayer(0, "Start", &joybuttonsgroup),                      OPT_XS, OPT_LINE(4), 1, m_defshade, joybutton_Start,     NULL, NULL, MNU_JoystickButtonPostProcess},
355         {DefInert(0, JoystickButtonFunctions[joybutton_Start][0]), OPT_XSIDE, OPT_LINE(4), 1, m_defshade, joybutton_Start,     NULL, MNU_SetJoystickButtonFunctions, NULL},
356         {DefLayer(0, "Dbl Start", &joybuttonsgroup),                  OPT_XS, OPT_LINE(5), 1, m_defshade, 128+joybutton_Start, NULL, NULL, MNU_JoystickButtonPostProcess},
357         {DefInert(0, JoystickButtonFunctions[joybutton_Start][1]), OPT_XSIDE, OPT_LINE(5), 1, m_defshade, 128+joybutton_Start, NULL, MNU_SetJoystickButtonFunctions, NULL},
358 
359         {DefInert(0, "Page 4 / 4"),                          OPT_XS, OPT_LINE(10), 1, m_defshade, 0, NULL, NULL, NULL },
360         {DefOption(0, "Next..."),                         OPT_XSIDE, OPT_LINE(10), 1, m_defshade, 0, MNU_JoystickButtonNextPage, NULL, NULL },
361         {DefNone}
362         },
363     };
364 MenuGroup joybuttonssetupgroup = {65, 5, "^Joystick Setup", joybuttons_i[0], pic_newgametitl, 0, m_defshade, NULL, NULL, 0};
365 
366 static char JoystickAxisName[64];
367 static char JoystickAxisPageName[64];
368 static char JoystickAxisFunctions[2][MAXFUNCTIONLENGTH];
369 static int JoystickAxisPage = 0;
370 static BOOL MNU_JoystickAxesInitialise(MenuItem_p item);
371 static BOOL MNU_SetJoystickAxisFunctions(MenuItem_p item);
372 static BOOL MNU_JoystickAxisPostProcess(MenuItem_p item);
373 static BOOL MNU_JoystickAxisSetupCustom(UserCall call, MenuItem_p item);
374 static BOOL MNU_JoystickAxisNextPage(void);
375 MenuGroup joyaxesgroup = {0, 0, NULL, NULL, 0, 0, m_defshade, MNU_JoystickAxisSetupCustom, NULL, 0};
376 MenuItem joyaxes_i[] =
377     {
378     {DefInert(0, JoystickAxisName), OPT_XS, OPT_LINE(0), 1, MENU_SHADE_INACTIVE, 0, NULL, NULL, NULL},
379 
380     {DefSlider(sldr_joyaxisscale, 0, "Axis Scale"),     OPT_XS, OPT_LINE(2), 1, m_defshade, 0, NULL, NULL, NULL},
381     {DefInert(0, NULL),                              OPT_XSIDE, OPT_LINE(2), 0, m_defshade, 0, NULL, NULL, NULL},
382     {DefButton(btn_joyaxis_invert, 0, "Invert"),        OPT_XS, OPT_LINE(3), 1, m_defshade, 0, NULL, NULL, NULL},
383     {DefSlider(sldr_joyaxisanalog, 0, "Analog"),        OPT_XS, OPT_LINE(4), 1, m_defshade, 0, NULL, NULL, NULL},
384     {DefInert(0, NULL),                              OPT_XSIDE, OPT_LINE(4), 0, m_defshade, 0, NULL, NULL, NULL},
385     {DefLayer(0, "Digital +ve", &joyaxesgroup),         OPT_XS, OPT_LINE(5), 1, m_defshade, 1, NULL, NULL, MNU_JoystickAxisPostProcess},
386     {DefInert(0, JoystickAxisFunctions[1]),          OPT_XSIDE, OPT_LINE(5), 1, m_defshade, 1, NULL, MNU_SetJoystickAxisFunctions, NULL},
387     {DefLayer(0, "Digital -ve", &joyaxesgroup),         OPT_XS, OPT_LINE(6), 1, m_defshade, 0, NULL, NULL, MNU_JoystickAxisPostProcess},
388     {DefInert(0, JoystickAxisFunctions[0]),          OPT_XSIDE, OPT_LINE(6), 1, m_defshade, 0, NULL, MNU_SetJoystickAxisFunctions, NULL},
389 
390     {DefSlider(sldr_joyaxisdead, 0, "Dead Zone"),       OPT_XS, OPT_LINE(8), 1, m_defshade, 0, NULL, NULL, NULL},
391     {DefInert(0, NULL),                              OPT_XSIDE, OPT_LINE(8), 0, m_defshade, 0, NULL, NULL, NULL},
392     {DefSlider(sldr_joyaxissatur, 0, "Saturate"),       OPT_XS, OPT_LINE(9), 1, m_defshade, 0, NULL, NULL, NULL},
393     {DefInert(0, NULL),                              OPT_XSIDE, OPT_LINE(9), 0, m_defshade, 0, NULL, NULL, NULL},
394 
395     {DefInert(0, JoystickAxisPageName),                 OPT_XS, OPT_LINE(11), 1, m_defshade, 0, NULL, NULL, NULL},
396     {DefOption(0, "Next..."),                        OPT_XSIDE, OPT_LINE(11), 1, m_defshade, 0, MNU_JoystickAxisNextPage, NULL, NULL},
397 
398     {DefNone},
399     };
400 MenuGroup joyaxessetupgroup = {65, 5, "^Joystick Axes", joyaxes_i, pic_newgametitl, 0, m_defshade, NULL, NULL, 1};
401 
402 
403 static char MouseAxisFunctions[MAXMOUSEAXES][2][MAXAXISFUNCTIONLENGTH] = { {"", ""}, {"", ""} };
404 static BOOL MNU_SetMouseAxisFunctions(MenuItem_p item);
405 static BOOL MNU_MouseDigitalPostProcess(MenuItem_p item);
406 static BOOL MNU_MouseDigitalSetupCustom(UserCall call, MenuItem_p item);
407 MenuGroup mouseaxesdigigroup =     {0, 0, NULL, NULL, 0, 0, m_defshade, MNU_MouseDigitalSetupCustom, NULL, 0};
408 MenuItem mouseaxes_i[] =
409     {
410     {DefSlider(sldr_mousescalex, 0, "X-Axis Scale"), OPT_XS,     OPT_LINE(0), 1, m_defshade, 0, NULL, NULL, NULL},
411     {DefInert(0, NULL), OPT_XSIDE,                               OPT_LINE(0), 0, m_defshade, 0, NULL, NULL, NULL},
412     {DefSlider(sldr_mousescaley, 0, "Y-Axis Scale"), OPT_XS,     OPT_LINE(1), 1, m_defshade, 0, NULL, NULL, NULL},
413     {DefInert(0, NULL), OPT_XSIDE,                               OPT_LINE(1), 0, m_defshade, 0, NULL, NULL, NULL},
414     {DefLayer(0, "Digital Left", &mouseaxesdigigroup),   OPT_XS, OPT_LINE(3), 1, m_defshade, 0+0, NULL, NULL, MNU_MouseDigitalPostProcess},
415     {DefInert(0, MouseAxisFunctions[0][0]),           OPT_XSIDE, OPT_LINE(3), 1, m_defshade, 0+0, NULL, MNU_SetMouseAxisFunctions, NULL},
416     {DefLayer(0, "Digital Right", &mouseaxesdigigroup),  OPT_XS, OPT_LINE(4), 1, m_defshade, 0+1, NULL, NULL, MNU_MouseDigitalPostProcess},
417     {DefInert(0, MouseAxisFunctions[0][1]),           OPT_XSIDE, OPT_LINE(4), 1, m_defshade, 0+1, NULL, MNU_SetMouseAxisFunctions, NULL},
418     {DefLayer(0, "Digital Up", &mouseaxesdigigroup),     OPT_XS, OPT_LINE(5), 1, m_defshade, 2+0, NULL, NULL, MNU_MouseDigitalPostProcess},
419     {DefInert(0, MouseAxisFunctions[1][0]),           OPT_XSIDE, OPT_LINE(5), 1, m_defshade, 2+0, NULL, MNU_SetMouseAxisFunctions, NULL},
420     {DefLayer(0, "Digital Down", &mouseaxesdigigroup),   OPT_XS, OPT_LINE(6), 1, m_defshade, 2+1, NULL, NULL, MNU_MouseDigitalPostProcess},
421     {DefInert(0, MouseAxisFunctions[1][1]),           OPT_XSIDE, OPT_LINE(6), 1, m_defshade, 2+1, NULL, MNU_SetMouseAxisFunctions, NULL},
422     {DefNone}
423     };
424 MenuGroup mouseaxesgroup = {65, 5, "^Mouse Axes", mouseaxes_i, pic_newgametitl, 0, m_defshade, NULL, NULL, 0};
425 
426 MenuItem inputsetup_i[] =
427     {
428     {DefLayer(0, "Keys Setup", &keysetupgroup),OPT_XS,                 OPT_LINE(0),1,m_defshade,0,NULL,NULL,NULL},
429     {DefLayer(0, "Mouse Options", &mousegroup),OPT_XS,                 OPT_LINE(2), 1, m_defshade,0,NULL, MNU_MouseCheck, NULL},
430     {DefLayer(0, "Mouse Buttons Setup", &mousesetupgroup),OPT_XS,      OPT_LINE(3),1,m_defshade,0,NULL,NULL,NULL},
431     {DefLayer(0, "Mouse Axes Setup", &mouseaxesgroup),OPT_XS,          OPT_LINE(4),1,m_defshade,0,NULL,NULL,NULL},
432     {DefLayer(0, "Joystick Buttons Setup", &joybuttonssetupgroup),OPT_XS,OPT_LINE(6),1,m_defshade,0,NULL,MNU_JoystickCheck,MNU_JoystickButtonsInitialise},
433     {DefLayer(0, "Joystick Axes Setup", &joyaxessetupgroup), OPT_XS,   OPT_LINE(7),1,m_defshade,0,NULL,MNU_JoystickCheck,MNU_JoystickAxesInitialise},
434     {DefOption(0, "Apply Modern Defaults"), OPT_XS,                    OPT_LINE(9),1,m_defshade,0,MNU_LoadModernDefaults,NULL,NULL},
435     {DefOption(0, "Apply Classic Defaults"), OPT_XS,                   OPT_LINE(10),1,m_defshade,0,MNU_LoadClassicDefaults,NULL,NULL},
436     {DefNone}
437     };
438 MenuGroup inputsetupgroup = {65, 5, "^Input", inputsetup_i, pic_newgametitl, 0, m_defshade, NULL,NULL, 0};
439 
440 MenuItem player_i[] =
441     {
442     {DefOption(0, "Player Name"),                        OPT_XS, OPT_LINE(0), 1, m_defshade, 0, MNU_PlayerNameCustom, NULL, NULL},
443     {DefInert(0, CommPlayerName),                     OPT_XSIDE, OPT_LINE(0), 1, m_defshade, 0, NULL, NULL, NULL},
444     {DefSlider(sldr_playercolor, 0, "Player Color"),     OPT_XS, OPT_LINE(1), 1, m_defshade, 0, NULL, NULL, NULL},
445     {DefInert(0, NULL),                               OPT_XSIDE, OPT_LINE(1), 0, m_defshade, 0, NULL, NULL, NULL},
446     {DefNone}
447     };
448 MenuGroup playergroup = {50, 5, "^Player", player_i, pic_optionstitl, 0, m_defshade, MNU_DoPlayerName, NULL, 0};
449 
450 MenuItem options_i[] =
451     {
452     {DefLayer(0, "Screen Menu", &screengroup),OPT_XS,            OPT_LINE(0), 1, m_defshade,0,NULL, NULL, NULL},
453     {DefLayer(0, "Sound Menu", &soundgroup),OPT_XS,              OPT_LINE(1), 1, m_defshade,0,MNU_TryMusicInit, MNU_MusicFxCheck, NULL},
454     {DefLayer(0, "Input Menu", &inputsetupgroup),OPT_XS,         OPT_LINE(2), 1,m_defshade,0,NULL,NULL,NULL},
455     {DefLayer(0, "Player Menu", &playergroup),OPT_XS,            OPT_LINE(3), 1, m_defshade,0,NULL,NULL,NULL},
456     #ifndef PLOCK_VERSION // No need for this in weener version
457     {DefLayer(0, "Kid Mode", &parentalgroup),OPT_XS,             OPT_LINE(4), 1, m_defshade,0,NULL, NULL, NULL},
458     #endif
459     {DefButton(btn_messages, 0, "Messages"), OPT_XS,             OPT_LINE(5), 1, m_defshade, 0, NULL, NULL, NULL},
460 //    {DefButton(btn_bobbing, 0, "View Bobbing"), OPT_XS,          OPT_LINE(7), 1, m_defshade, 0, NULL, NULL, NULL},
461     {DefButton(btn_shadows, 0, "Shadows"), OPT_XS,               OPT_LINE(6), 1, m_defshade, 0, NULL, NULL, NULL},
462     {DefButton(btn_auto_run, 0, "Auto Run"), OPT_XS,             OPT_LINE(7), 1, m_defshade, 0, NULL, NULL, NULL},
463     {DefButton(btn_crosshair, 0, "Crosshair"), OPT_XS,           OPT_LINE(8), 1, m_defshade, 0, NULL, NULL, NULL},
464     {DefButton(btn_auto_aim, 0, "Auto-Aiming"), OPT_XS,          OPT_LINE(9), 1, m_defshade, 0, NULL, NULL, NULL},
465     {DefButton(btn_voxels, 0, "Voxel Sprites"), OPT_XS,          OPT_LINE(10), 1, m_defshade, 0, NULL, NULL, NULL},
466     {DefButton(btn_stats, 0, "Level Stats"), OPT_XS,             OPT_LINE(11), 1, m_defshade, 0, NULL, MNU_StatCheck, NULL},
467     {DefNone}
468     };
469 
470 MenuGroup optiongroup = {100, 5, "^Options", options_i, pic_optionstitl, 0, m_defshade, NULL,NULL, 0};
471 
472 MenuItem skill_i[] =
473     {
474     {DefOption(KEYSC_E, &SkillNames[0][0]), 30, 46, pic_easy, m_defshade, 0, MNU_StartGame, NULL, NULL},
475     {DefOption(KEYSC_N, &SkillNames[1][0]), 30, 62, pic_normal, m_defshade, 0, MNU_StartGame, NULL, NULL},
476     {DefOption(KEYSC_H, &SkillNames[2][0]), 30, 78, pic_hard, m_defshade, 0, MNU_StartGame, NULL, NULL},
477     {DefOption(KEYSC_I, &SkillNames[3][0]), 30, 94, pic_impossible, m_defshade, 0, MNU_StartGame, NULL, NULL},
478     {DefNone}
479     };
480 
481 MenuGroup skillgroup = {100, 5, "^Skill", skill_i, pic_newgametitl, 0, m_defshade, NULL, NULL, 2};
482 
483 MenuItem episode_i[] =
484     {
485     {DefLayer(KEYSC_S, &EpisodeNames[0][0], &skillgroup), 30, 46, pic_episode1, m_defshade, 0, MNU_EpisodeCustom, NULL, NULL},
486     {DefLayer(KEYSC_F, &EpisodeNames[1][0], &skillgroup), 30, 78, pic_episode2, m_defshade, 0, MNU_EpisodeCustom, MNU_ShareWareCheck, MNU_ShareWareMessage},
487     //{DefLayer(KEYSC_S, NULL, &skillgroup), 60, 30, pic_episode1, m_defshade, 0, MNU_EpisodeCustom},
488     //{DefLayer(KEYSC_F, NULL, &skillgroup), 60, 46, pic_episode2, m_defshade, 0, MNU_EpisodeCustom},
489     //{DefLayer(KEYSC_T, NULL, &skillgroup), 60, 62, pic_episode3, m_defshade, 0, MNU_EpisodeCustom},
490     {DefNone}
491     };
492 
493 MenuGroup episodegroup = {100, 5, "^Episode", episode_i, pic_newgametitl, 0, m_defshade, MNU_DoEpisodeSelect, NULL, 0};
494 
495 extern char UserMapName[80];
496 
497 MenuItem network_extra_i[] =
498 {
499     {DefSlider(sldr_monsters, 0, "Monsters"),OPT_XS, OPT_LINE(0), 1, m_defshade, 0, NULL, NULL, NULL},
500     {DefInert(0, NULL),               OPT_XSIDE,OPT_LINE(0), 0, m_defshade, 0, NULL, NULL, NULL},
501 
502     {DefButton(btn_teamplay,     0, "Team Play"),    OPT_XS, OPT_LINE(1), 1, m_defshade, 0, MNU_TeamPlayChange, MNU_TeamPlayCheck, NULL},
503     {DefButton(btn_friendlyfire, 0, "Hurt Teammate"),OPT_XS, OPT_LINE(2), 1, m_defshade, 0, NULL, MNU_HurtTeammateCheck, NULL},
504     {DefButton(btn_nuke,         0, "Play with Nuke"),OPT_XS, OPT_LINE(3), 1, m_defshade, 0, NULL, NULL, NULL},
505     {DefNone}
506 };
507 
508 MenuGroup networkextragroup = {50, 5, "^Net Options", network_extra_i, pic_newgametitl, 0, m_defshade, NULL, NULL, 0};
509 
510 MenuItem network_i[] =
511     {
512     {DefSlider(sldr_gametype, 0, "Game Type"),   OPT_XS,         OPT_LINE(0), 1, m_defshade, 0, NULL, NULL, NULL},
513     {DefInert(0, NULL),                          OPT_XSIDE-38,   OPT_LINE(0), 0, m_defshade, 0, NULL, NULL, NULL},
514 
515     {DefSlider(sldr_netlevel, 0, "Level"),       OPT_XS,         OPT_LINE(1), 1, m_defshade, 0, NULL, MNU_CheckUserMap, NULL},
516     {DefInert(0, NULL),                          OPT_XSIDE-70,   OPT_LINE(1), 0, m_defshade, 0, NULL, MNU_CheckUserMap, NULL},
517     {DefInert(0, " "),                           OPT_XS,         OPT_LINE(2), pic_episode1, m_defshade, 0, NULL, MNU_CheckUserMap, NULL},
518 
519     {DefButton(btn_markers,      0, "Markers"),  OPT_XS,         OPT_LINE(3), 1, m_defshade, 0, NULL, NULL, NULL},
520 
521     {DefSlider(sldr_killlimit, 0, "Kill Limit"),OPT_XS,          OPT_LINE(4), 1, m_defshade, 0, NULL, MNU_CoopPlayCheck, NULL},
522     {DefInert(0, NULL),               OPT_XSIDE,                 OPT_LINE(4), 0, m_defshade, 0, NULL, MNU_CoopPlayCheck, NULL},
523 
524     {DefSlider(sldr_timelimit, 0, "Time Limit"),OPT_XS,          OPT_LINE(5), 1, m_defshade, 0, NULL, MNU_CoopPlayCheck, NULL},
525     {DefInert(0, NULL),               OPT_XSIDE,                 OPT_LINE(5), 0, m_defshade, 0, NULL, MNU_CoopPlayCheck, NULL},
526 
527     {DefLayer(0, "Other Options", &networkextragroup),OPT_XS,    OPT_LINE(7), 1, m_defshade,0,NULL, NULL, NULL},
528 
529     {DefInert(0, UserMapName),         OPT_XSIDE,                OPT_LINE(8), pic_episode1, m_defshade, 0, NULL, NULL, NULL},
530     {DefOption(KEYSC_S, "Start Game"),   OPT_XS,                    OPT_LINE(8), pic_episode1, m_defshade, 0, MNU_StartNetGame, NULL, NULL},
531 
532     {DefNone}
533 
534     };
535 
536 MenuGroup networkgroup = {50, 5, "^Network Game", network_i, pic_newgametitl, 0, m_defshade, NULL, NULL, 0};
537 
538 MenuItem load_i[] =
539     {
540 #define SD_YSTART 26
541 #define SD_XSTART 5
542 #define SD_YOFF 13
543 #define SD_LINE(line) (SD_YSTART + (line * SD_YOFF))
544     {DefOption(0, NULL), SD_XSTART, SD_LINE(0), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
545     {DefOption(0, NULL), SD_XSTART, SD_LINE(1), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
546     {DefOption(0, NULL), SD_XSTART, SD_LINE(2), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
547     {DefOption(0, NULL), SD_XSTART, SD_LINE(3), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
548     {DefOption(0, NULL), SD_XSTART, SD_LINE(4), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
549     {DefOption(0, NULL), SD_XSTART, SD_LINE(5), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
550     {DefOption(0, NULL), SD_XSTART, SD_LINE(6), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
551     {DefOption(0, NULL), SD_XSTART, SD_LINE(7), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
552     {DefOption(0, NULL), SD_XSTART, SD_LINE(8), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
553     {DefOption(0, NULL), SD_XSTART, SD_LINE(9), 0, m_defshade, 0, MNU_GetLoadCustom, NULL, NULL},
554     {DefNone}
555     };
556 
557 MenuItem save_i[] =
558     {
559     {DefOption(0, NULL), SD_XSTART, SD_LINE(0), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
560     {DefOption(0, NULL), SD_XSTART, SD_LINE(1), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
561     {DefOption(0, NULL), SD_XSTART, SD_LINE(2), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
562     {DefOption(0, NULL), SD_XSTART, SD_LINE(3), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
563     {DefOption(0, NULL), SD_XSTART, SD_LINE(4), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
564     {DefOption(0, NULL), SD_XSTART, SD_LINE(5), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
565     {DefOption(0, NULL), SD_XSTART, SD_LINE(6), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
566     {DefOption(0, NULL), SD_XSTART, SD_LINE(7), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
567     {DefOption(0, NULL), SD_XSTART, SD_LINE(8), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
568     {DefOption(0, NULL), SD_XSTART, SD_LINE(9), 0, m_defshade, 0, MNU_GetSaveCustom, NULL, NULL},
569     {DefNone}
570     };
571 
572 // No actual submenus for this, just quit text.
573 MenuGroup quitgroup = {0, 0, NULL, NULL, 0, 0, m_defshade, MNU_QuitCustom, NULL, 0};
574 MenuGroup quickloadgroup = {0, 0, NULL, NULL, 0, 0, m_defshade, MNU_QuickLoadCustom, NULL, 0};
575 MenuGroup ordergroup = {0, 0, NULL, NULL, 0, 0, m_defshade, MNU_OrderCustom, NULL, 0};
576 
577 // save and load function calls
578 MenuGroup SaveGameGroup = {100, 5, "^Save Game", save_i, pic_savegame, 0, m_defshade, MNU_LoadSaveDraw, MNU_LoadSaveMove, 0};
579 MenuGroup LoadGameGroup = {100, 5, "^Load Game", load_i, pic_loadgame, 0, m_defshade, MNU_LoadSaveDraw, MNU_LoadSaveMove, 0};
580 
581 #define MAIN_YSTART 32
582 #define MAIN_YOFF 17
583 #define MAIN_XSTART 55
584 #define MAIN_LINE(line) (MAIN_YSTART + (MAIN_YOFF * line))
585 
586 #define MAIN_MENU_COOL_STUFF "^Cool Stuff"
587 #define MAIN_MENU_HOW_TO_ORDER "^How to Order"
588 
589 MenuItem main_i[] =
590     {
591     {DefLayer(KEYSC_N, "^New Game", &episodegroup),      MAIN_XSTART, MAIN_LINE(0), pic_newgame, m_defshade, 0, NULL, NULL, NULL},
592     {DefLayer(KEYSC_L, "^Load Game", &LoadGameGroup),    MAIN_XSTART, MAIN_LINE(1), pic_load, m_defshade, 0, NULL, MNU_LoadGameCheck, NULL},
593     {DefLayer(KEYSC_S, "^Save Game", &SaveGameGroup),    MAIN_XSTART, MAIN_LINE(2), pic_save, m_defshade, 0, NULL, MNU_SaveGameCheck, NULL},
594     {DefLayer(KEYSC_O, "^Options", &optiongroup),        MAIN_XSTART, MAIN_LINE(3), pic_options, m_defshade, 0, NULL, NULL, NULL},
595     {DefLayer(KEYSC_H, "^Oh Dear", &ordergroup),         MAIN_XSTART, MAIN_LINE(4), pic_orderinfo, m_defshade, 0, NULL, NULL, NULL},
596     {DefLayer(KEYSC_Q, "^Quit", &quitgroup),             MAIN_XSTART, MAIN_LINE(5), pic_quit, m_defshade, 0, NULL, NULL, NULL},
597     {DefNone}
598     };
599 
600 MenuGroup maingroup = {160, 15, NULL, main_i, pic_shadow_warrior, 0, m_defshade, NULL, NULL, 0};
601 
602 CTLType ControlPanelType;
603 
604 #define MaxLayers    10         // Maximum layers deep a menu can go
605 short       menuarrayptr;       // Index into menuarray
606 MenuGroup   *menuarray[MaxLayers], *currentmenu;
607 BOOL UsingMenus = FALSE;
608 BOOL ForceMenus = FALSE;
609 
610 #define MAXDIALOG       2       // Maximum number of dialog strings allowed
611 char *dialog[MAXDIALOG];
612 
613 // Global menu setting values ////////////////////////////////////////////////////////////////////
614 // Mouse slider vars
615 #define SENSE_MIN               75
616 #define SENSE_MUL               10
617 int SENSITIVITY = SENSE_MIN + (SENSE_DEFAULT * SENSE_MUL);
618 
619 // Sound vars
620 #define FX_MIN                  0
621 #define MUSIC_MIN               0
622 #define VOL_MUL                 16
623 
624 // User input data for all devices
625 UserInput mnu_input, mnu_input_buffered, order_input_buffered;
626 
627 // Menu function call back pointer for multiplay menus
628 BOOL(*cust_callback) (UserCall call, MenuItem_p item);
629 UserCall cust_callback_call;
630 MenuItem_p cust_callback_item;
631 
632 // Prototypes ///////////////////////////////////////////////////////////////////////////////////
633 
634 typedef enum {
635     dialog_NoAnswer = 0,
636     dialog_Yes = 1,
637     dialog_No = 2
638 } DialogResponse;
639 
640 static DialogResponse MNU_Dialog(void);
641 VOID LoadSaveMsg(char *msg);
642 static VOID MNU_ItemPreProcess(MenuGroup *group);
643 static void MNU_SelectItem(MenuGroup * group, short index, BOOL draw);
644 static void MNU_PushItem(MenuItem * item, BOOL draw);
645 
646 static int MNU_ControlAxisOffset(int num);
647 static int MNU_ControlAxisNum(int offset);
648 
649 
650 // F U N C T I O N S ////////////////////////////////////////////////////////////////////////////
651 
652 // CUSTOM ROUTINES ////////////////////////////////////////////////////////////////////////////////
653 
654 BOOL
MNU_DoEpisodeSelect(UserCall call,MenuItem * UNUSED (item))655 MNU_DoEpisodeSelect(UserCall call, MenuItem * UNUSED(item))
656     {
657     short w,h;
658     char TempString[80];
659     char *extra_text;
660 
661     if (call != uc_touchup)
662         return(TRUE);
663 
664     extra_text = EpisodeSubtitles[0];
665     MNU_MeasureString(extra_text, &w, &h);
666     MNU_DrawString(30, 63, extra_text, 1, 16);
667     extra_text = EpisodeSubtitles[1];
668     MNU_MeasureString(extra_text, &w, &h);
669     MNU_DrawString(30, 96, extra_text, 1, 16);
670 
671     return(TRUE);
672     }
673 
674 BOOL
MNU_DoParentalPassword(UserCall UNUSED (call),MenuItem_p UNUSED (item))675 MNU_DoParentalPassword(UserCall UNUSED(call), MenuItem_p UNUSED(item))
676     {
677     short w,h;
678     signed char MNU_InputString(char *, short);
679     static BOOL cur_show;
680     char TempString[80];
681     char *extra_text;
682 
683 
684     extra_text = "This mode should remove most of the";
685     MNU_MeasureString(extra_text, &w, &h);
686     MNU_DrawString(TEXT_XCENTER(w), 60, extra_text, 1, 16);
687     extra_text = "offensive content.  We still recommend";
688     MNU_MeasureString(extra_text, &w, &h);
689     MNU_DrawString(TEXT_XCENTER(w), 70, extra_text, 1, 16);
690     extra_text = "you review the game prior to play.";
691     MNU_MeasureString(extra_text, &w, &h);
692     MNU_DrawString(TEXT_XCENTER(w), 80, extra_text, 1, 16);
693 
694     // get input
695     if(MenuInputMode)
696     {
697     switch(MNU_InputString(MessageInputString, 80))
698         {
699         case -1: // Cancel Input (pressed ESC) or Err
700             KB_ClearKeysDown();
701             KB_FlushKeyboardQueue();
702             MenuInputMode = FALSE;
703             memset(MessageInputString, '\0', sizeof(MessageInputString));
704             break;
705         case FALSE: // Input finished (RETURN)
706             if (MessageInputString[0] == '\0')
707                 {
708                 MenuInputMode = FALSE;
709                 KB_ClearKeysDown();
710                 KB_FlushKeyboardQueue();
711                 memset(MessageInputString, '\0', sizeof(MessageInputString));
712                 }
713             else
714                 {
715                 MenuInputMode = FALSE;
716                 KB_ClearKeysDown();
717                 KB_FlushKeyboardQueue();
718 
719                 if(gs.Password[0] != '\0' && passwordvalid == FALSE)
720                     {
721                     if(!Bstrcasecmp(gs.Password,MessageInputString))
722                         {
723                         passwordvalid = TRUE;
724                         if (currentmenu->cursor == 0 && gs.ParentalLock == TRUE)
725                             {
726                             buttonsettings[btn_parental] = gs.ParentalLock = FALSE;
727                             if (!InMenuLevel)
728                             JS_ToggleLockouts();
729                             }
730 
731                         if (currentmenu->cursor == 1) // Is it on the password line?
732                             {
733                             MenuInputMode = TRUE;
734                             KB_ClearKeysDown();
735                             KB_FlushKeyboardQueue();
736                             }
737                         //memset(gs.Password, '\0', sizeof(gs.Password));
738                         }
739                     } else
740                     {
741                     if (currentmenu->cursor == 1) // Is it on the password line?
742                        {
743                        strcpy(gs.Password,MessageInputString);
744                        passwordvalid = FALSE;
745                        }
746                     }
747 
748                 memset(MessageInputString, '\0', sizeof(MessageInputString));
749                 }
750             break;
751         case TRUE: // Got input
752             break;
753         }
754 
755         //CON_Message("Password = '%s'",gs.Password);
756         //CON_Message("Passwordvalid = %d",passwordvalid);
757 
758         if(gs.Password[0] != '\0' && passwordvalid == FALSE && currentmenu->cursor == 1)
759             {
760             sprintf(TempString,"Enter Old Password");
761             MNU_MeasureString(TempString, &w, &h);
762             MNU_DrawString(TEXT_XCENTER(w), MESSAGE_LINE-10, TempString,1,16);
763             }
764         else
765         if (passwordvalid == TRUE && currentmenu->cursor == 1)
766             {
767             sprintf(TempString,"Enter New Password");
768             MNU_MeasureString(TempString, &w, &h);
769             MNU_DrawString(TEXT_XCENTER(w), MESSAGE_LINE-10, TempString,1,16);
770             }
771         else
772             {
773             sprintf(TempString,"Enter Password");
774             MNU_MeasureString(TempString, &w, &h);
775             MNU_DrawString(TEXT_XCENTER(w), MESSAGE_LINE-10, TempString,1,16);
776             }
777 
778         MNU_MeasureString(MessageInputString, &w, &h);
779 
780         cur_show ^= 1;
781         if (cur_show)
782             {
783             MNU_DrawString(TEXT_XCENTER(w), MESSAGE_LINE, MessageInputString,1,16);
784             rotatesprite((TEXT_XCENTER(w)+w+7)<<16,(MESSAGE_LINE+3)<<16,64<<9,0,COINCURSOR+((totalclock>>3)%7),0,0,MenuDrawFlags,0,0,xdim-1,ydim-1);
785             }
786         else
787             {
788             MNU_DrawString(TEXT_XCENTER(w), MESSAGE_LINE, MessageInputString,1,16);
789             rotatesprite((TEXT_XCENTER(w)+w+7)<<16,(MESSAGE_LINE+3)<<16,64<<9,0,COINCURSOR+((totalclock>>3)%7),0,0,MenuDrawFlags,0,0,xdim-1,ydim-1);
790             }
791 
792     }
793 
794     return(TRUE);
795     }
796 
797 BOOL
MNU_ParentalCustom(void)798 MNU_ParentalCustom(void)
799     {
800 
801     if (MenuInputMode)
802         {
803         // toggle edit mode
804         MenuInputMode = FALSE;
805         memset(MessageInputString, '\0', sizeof(MessageInputString));
806         }
807     else
808         {
809         // clear keyboard buffer
810         while (KB_KeyWaiting())
811             {
812             if (KB_Getch() == 0)
813                 KB_Getch();
814             }
815 
816         // toggle edit mode
817         MenuInputMode = TRUE;
818         }
819 
820     return (TRUE);
821     }
822 
823 BOOL
MNU_DoPlayerName(UserCall call,MenuItem_p item)824 MNU_DoPlayerName(UserCall call, MenuItem_p item)
825     {
826     short w,h;
827     signed char MNU_InputString(char *, short);
828     static BOOL cur_show;
829     char TempString[80];
830     char *extra_text;
831 
832     (void)call;
833     (void)item;
834 
835     // get input
836     if(MenuInputMode)
837     {
838     switch(MNU_InputString(MessageInputString, 80))
839         {
840         case -1: // Cancel Input (pressed ESC) or Err
841             KB_ClearKeysDown();
842             KB_FlushKeyboardQueue();
843             MenuInputMode = FALSE;
844             memset(MessageInputString, '\0', sizeof(MessageInputString));
845             break;
846         case FALSE: // Input finished (RETURN)
847             if (MessageInputString[0] != '\0')
848                 SendMulitNameChange(MessageInputString, -1);
849 
850             MenuInputMode = FALSE;
851             KB_ClearKeysDown();
852             KB_FlushKeyboardQueue();
853             memset(MessageInputString, '\0', sizeof(MessageInputString));
854             break;
855         case TRUE: // Got input
856             break;
857         }
858 
859         sprintf(TempString,"Enter a new Player Name");
860         MNU_MeasureString(TempString, &w, &h);
861         MNU_DrawString(TEXT_XCENTER(w), MESSAGE_LINE-10, TempString,1,16);
862 
863         MNU_MeasureString(MessageInputString, &w, &h);
864 
865         MNU_DrawString(TEXT_XCENTER(w), MESSAGE_LINE, MessageInputString,1,16);
866         rotatesprite((TEXT_XCENTER(w)+w+7)<<16,(MESSAGE_LINE+3)<<16,64<<9,0,COINCURSOR+((totalclock>>3)%7),0,0,MenuDrawFlags,0,0,xdim-1,ydim-1);
867         rotatesprite((TEXT_XCENTER(w)+w+7)<<16,(MESSAGE_LINE+3)<<16,64<<9,0,COINCURSOR+((totalclock>>3)%7),0,0,MenuDrawFlags,0,0,xdim-1,ydim-1);
868     }
869 
870     return(TRUE);
871     }
872 
873 BOOL
MNU_PlayerNameCustom(void)874 MNU_PlayerNameCustom(void)
875     {
876 
877     if (MenuInputMode)
878         {
879         // toggle edit mode
880         MenuInputMode = FALSE;
881         memset(MessageInputString, '\0', sizeof(MessageInputString));
882         }
883     else
884         {
885         // clear keyboard buffer
886         while (KB_KeyWaiting())
887             {
888             if (KB_Getch() == 0)
889                 KB_Getch();
890             }
891 
892         // toggle edit mode
893         MenuInputMode = TRUE;
894         }
895 
896     return (TRUE);
897     }
898 
MNU_KeySetupCustom(UserCall call,MenuItem * item)899 BOOL MNU_KeySetupCustom(UserCall call, MenuItem *item)
900 {
901 	static int currentkey = 0, currentcol = 0;
902 	static int currentmode = 0;
903 
904 	if (call == uc_touchup)
905         	return (TRUE);
906 
907 	if (cust_callback == NULL) {
908 		if (call != uc_setup)
909 			return (FALSE);
910 		currentkey = 0;
911 		currentcol = 0;
912 		currentmode = 0;
913 	}
914 
915 	cust_callback = MNU_KeySetupCustom;
916 	cust_callback_call = call;
917 	cust_callback_item = item;
918 
919 	{
920 		short w, h = 0;
921 		char *s = "Keys Setup";
922 		rotatesprite(10 << 16, (5-3) << 16, MZ, 0, 2427,
923 		    m_defshade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
924 		MNU_MeasureStringLarge(s, &w, &h);
925 		MNU_DrawStringLarge(TEXT_XCENTER(w), 5, s);
926 	}
927 
928 	if (currentmode) {
929 		// customising a key
930 		char *strs[] = { "Press the key to assign to", "\"%s\" %s", "or ESCAPE to cancel." };
931 		char *col[2] = { "(primary)", "(secondary)" };
932 		short w, h = 8;
933 		int i, j, y;
934 
935 		if (KEY_PRESSED(KEYSC_ESC)) {
936 			KB_ClearKeyDown(sc_Escape);
937 			currentmode = 0;
938 		} else if (KB_GetLastScanCode() > 0) {
939 			KB_ClearKeyDown( KB_GetLastScanCode() );
940 
941 			KeyboardKeys[currentkey][currentcol] = KB_GetLastScanCode();
942 			if (currentkey != gamefunc_Show_Console) {
943 				CONTROL_MapKey(currentkey,
944 					KeyboardKeys[currentkey][0],
945 					KeyboardKeys[currentkey][1]);
946 			} else {
947 				OSD_CaptureKey(KB_GetLastScanCode());
948 			}
949 
950 			currentmode = 0;
951 		}
952 
953 		MNU_MeasureString(strs[0], &w, &h);
954 
955 		y = (YDIM - (h+3) * SIZ(strs)) / 2;
956 
957 		for (i=0; i<(int)SIZ(strs); i++) {
958 			w = 0;
959 			sprintf(ds,strs[i],gamefunctions[currentkey],col[currentcol]);
960 			for (j=0; ds[j]; j++) if (ds[j] == '_') ds[j] = ' ';
961 			MNU_MeasureString(ds, &w, &h);
962 			MNU_DrawString((XDIM - w)/2, y, ds, 0, 16);
963 			y += h+3;
964 		}
965 
966 	} else {
967 		// key list
968 #define PGSIZ 14
969 		int topitem = 0, botitem = NUMGAMEFUNCTIONS;
970 		int i,j;
971 		char *morestr = "More...";
972 		const char *p;
973 
974 		UserInput inpt = {FALSE,FALSE,dir_None};
975 		CONTROL_GetUserInput(&inpt);
976 
977 		if (KEY_PRESSED(KEYSC_ESC) || inpt.button1) {
978 			KEY_PRESSED(KEYSC_ESC) = FALSE;
979 			cust_callback = NULL;
980             CONTROL_ClearUserInput(&inpt);
981 			return TRUE;
982 		}
983 		else if (KB_KeyPressed(sc_Delete)) {
984 			KB_ClearKeyDown(sc_Delete);
985 			if (currentkey != gamefunc_Show_Console) {
986 				KeyboardKeys[currentkey][currentcol] = 0xff;
987 				CONTROL_MapKey(currentkey,
988 					KeyboardKeys[currentkey][0],
989 					KeyboardKeys[currentkey][1]);
990 			}
991 		}
992 		else if (KB_KeyPressed(sc_Home)) {
993 			currentkey = 0;
994 			KB_ClearKeyDown(sc_Home);
995 		}
996 		else if (KB_KeyPressed(sc_End)) {
997 			currentkey = NUMGAMEFUNCTIONS-1;
998 			KB_ClearKeyDown(sc_End);
999 		}
1000 		else if (KB_KeyPressed(sc_PgDn)) {
1001 			currentkey += PGSIZ;
1002 			if (currentkey >= NUMGAMEFUNCTIONS) currentkey = NUMGAMEFUNCTIONS-1;
1003 			KB_ClearKeyDown(sc_PgDn);
1004 		}
1005 		else if (KB_KeyPressed(sc_PgUp)) {
1006 			currentkey -= PGSIZ;
1007 			if (currentkey < 0) currentkey = 0;
1008 			KB_ClearKeyDown(sc_PgUp);
1009 		}
1010 		else if (inpt.button0) {
1011 			currentmode = 1;
1012 			KB_ClearLastScanCode();
1013 			KB_ClearKeysDown();
1014 		}
1015 		else if (inpt.dir == dir_North) currentkey = max(0,currentkey-1);
1016 		else if (inpt.dir == dir_South) currentkey = min(NUMGAMEFUNCTIONS-1,currentkey+1);
1017 		else if (inpt.dir == dir_East)  currentcol = 1;
1018 		else if (inpt.dir == dir_West)  currentcol = 0;
1019 
1020 		if (currentkey == gamefunc_Show_Console) currentcol = 0;
1021 
1022 		CONTROL_ClearUserInput(&inpt);
1023 
1024 		if (NUMGAMEFUNCTIONS > PGSIZ) {
1025 			topitem = currentkey - PGSIZ/2;
1026 			botitem = topitem + PGSIZ;
1027 
1028 			if (topitem < 0) {
1029 				botitem += -topitem;
1030 				topitem = 0;
1031 			} else if (botitem >= NUMGAMEFUNCTIONS) {
1032 				botitem = NUMGAMEFUNCTIONS-1;
1033 				topitem = botitem - PGSIZ;
1034 			}
1035 		}
1036 
1037 		for (i = topitem; i <= botitem; i++) {
1038 			for (j = 0; gamefunctions[i][j]; j++) {
1039 				if (gamefunctions[i][j] == '_') ds[j] = ' ';
1040 				else ds[j] = gamefunctions[i][j];
1041 			}
1042 			ds[j] = 0;
1043 
1044 			j = OPT_LINE(0)+(i-topitem)*8;
1045 			MNU_DrawSmallString(OPT_XS, j, ds, (i==currentkey)?0:12, 16);
1046 
1047 			p = getkeyname(KeyboardKeys[i][0]);
1048 			if (!p || KeyboardKeys[i][0]==0xff) p = "  -";
1049 			MNU_DrawSmallString(OPT_XSIDE, j, (char*)p, (i==currentkey)?-5:12,
1050 					(i==currentkey && currentcol==0) ? 14:16);
1051 
1052 			if (i == gamefunc_Show_Console) continue;
1053 
1054 			p = getkeyname(KeyboardKeys[i][1]);
1055 			if (!p || KeyboardKeys[i][1]==0xff) p = "  -";
1056 			MNU_DrawSmallString(OPT_XSIDE + 4*14, j, (char*)p, (i==currentkey)?-5:12,
1057 					(i==currentkey && currentcol==1) ? 14:16);
1058 		}
1059 
1060 		{
1061 			short dx,dy;
1062 			dx = 0, dy = 8;
1063 			MNU_MeasureSmallString(morestr,&dx,&dy);
1064 			if (topitem > 0)
1065 				MNU_DrawSmallString(XDIM - OPT_XS - dx, OPT_LINE(0), morestr, 8,16);
1066 			if (botitem < NUMGAMEFUNCTIONS-1)
1067 				MNU_DrawSmallString(XDIM - OPT_XS - dx, OPT_LINE(0)+PGSIZ*8, morestr, 8,16);
1068 		}
1069 #undef PGSIZ
1070 	}
1071 
1072 	return (TRUE);
1073 }
1074 
MNU_SelectButtonFunction(const char * buttonname,int * currentfunc)1075 static int MNU_SelectButtonFunction(const char *buttonname, int *currentfunc)
1076 {
1077     const int PGSIZ = 9;
1078     const char *strs[] = { "Select the function to assign to", "%s", "or ESCAPE to cancel." };
1079     int topitem = 0, botitem = NUMGAMEFUNCTIONS-1;
1080     int i, j, y;
1081     short w, h=0;
1082     int returnval = 0;
1083 
1084     UserInput inpt = {FALSE,FALSE,dir_None};
1085     CONTROL_GetUserInput(&inpt);
1086 
1087     if (inpt.button1) {
1088         KB_ClearKeyDown(sc_Escape);
1089         returnval = -1;
1090     }
1091     else if (KB_KeyPressed(sc_Home)) {
1092         *currentfunc = 0;
1093         KB_ClearKeyDown(sc_Home);
1094     }
1095     else if (KB_KeyPressed(sc_End)) {
1096         *currentfunc = NUMGAMEFUNCTIONS-1;   // -1 because the last one is the console and the top is 'none'
1097         KB_ClearKeyDown(sc_End);
1098     }
1099     else if (KB_KeyPressed(sc_PgDn)) {
1100         *currentfunc += PGSIZ;
1101         if (*currentfunc >= NUMGAMEFUNCTIONS) *currentfunc = NUMGAMEFUNCTIONS-1;
1102         KB_ClearKeyDown(sc_PgDn);
1103     }
1104     else if (KB_KeyPressed(sc_PgUp)) {
1105         *currentfunc -= PGSIZ;
1106         if (*currentfunc < 0) *currentfunc = 0;
1107         KB_ClearKeyDown(sc_PgUp);
1108     }
1109     else if (inpt.button0) {
1110         returnval = 1;
1111     }
1112     else if (inpt.dir == dir_North) *currentfunc = max(0, *currentfunc-1);
1113     else if (inpt.dir == dir_South) *currentfunc = min(NUMGAMEFUNCTIONS-1, *currentfunc+1);
1114 
1115     CONTROL_ClearUserInput(&inpt);
1116 
1117     if (NUMGAMEFUNCTIONS-1 > PGSIZ) {
1118         topitem = *currentfunc - PGSIZ/2;
1119         botitem = topitem + PGSIZ;
1120 
1121         if (topitem < 0) {
1122             botitem += -topitem;
1123             topitem = 0;
1124         } else if (botitem >= NUMGAMEFUNCTIONS) {
1125             botitem = NUMGAMEFUNCTIONS-1;
1126             topitem = botitem - PGSIZ;
1127         }
1128     }
1129 
1130     y = OPT_LINE(0);
1131     for (i=0; i<(int)SIZ(strs); i++) {
1132         w = 0;
1133         sprintf(ds, strs[i], buttonname);
1134         for (j=0; ds[j]; j++) if (ds[j] == '_') ds[j] = ' ';
1135         MNU_MeasureString(ds, &w, &h);
1136         MNU_DrawString((XDIM - w)/2, y, ds, 0, 16);
1137         y += h;
1138     }
1139 
1140     for (i = topitem; i <= botitem; i++) {
1141         if (i == 0) {
1142             strcpy(ds, "  -none-");
1143         } else {
1144             for (j = 0; gamefunctions[i-1][j]; j++) {
1145                 if (gamefunctions[i-1][j] == '_') ds[j] = ' ';
1146                 else ds[j] = gamefunctions[i-1][j];
1147             }
1148             ds[j] = 0;
1149         }
1150 
1151         j = OPT_LINE(4)+(i-topitem)*8;
1152         MNU_DrawSmallString(130, j, ds, (i == *currentfunc)?0:12, 16);
1153     }
1154 
1155     {
1156         short dx = 0, dy = 8;
1157         const char *morestr = "More...";
1158 
1159         MNU_MeasureSmallString(morestr,&dx,&dy);
1160         if (topitem > 0)
1161             MNU_DrawSmallString(XDIM - OPT_XS - dx, OPT_LINE(4), morestr, 8,16);
1162         if (botitem < NUMGAMEFUNCTIONS-1)
1163             MNU_DrawSmallString(XDIM - OPT_XS - dx, OPT_LINE(4)+PGSIZ*8, morestr, 8,16);
1164     }
1165 
1166     return returnval;
1167 }
1168 
1169 
1170 static MenuItem_p mouse_button_item = NULL;
1171 
MNU_MouseButtonPostProcess(MenuItem_p item)1172 static BOOL MNU_MouseButtonPostProcess(MenuItem_p item)
1173 {
1174     mouse_button_item = item;
1175     return TRUE;
1176 }
1177 
MNU_MouseButtonSetupCustom(UserCall call,MenuItem_p item)1178 BOOL MNU_MouseButtonSetupCustom(UserCall call, MenuItem_p item)
1179 {
1180     int button, clicked, selection;
1181     static int currentfunc = 0;
1182 
1183     if (call == uc_touchup)
1184         return (TRUE);
1185 
1186     clicked = !!(mouse_button_item->tics & 128);
1187     button = (mouse_button_item->tics & 127);
1188 
1189     if (cust_callback == NULL)
1190         {
1191         if (call != uc_setup)
1192             return (FALSE);
1193         if (clicked)
1194             currentfunc = MouseButtonsClicked[button];
1195         else
1196             currentfunc = MouseButtons[button];
1197         currentfunc++;
1198 
1199         cust_callback = MNU_MouseButtonSetupCustom;
1200         cust_callback_call = call;
1201         cust_callback_item = item;
1202         }
1203 
1204     {
1205         short w, h = 0;
1206         const char *s = "Mouse Buttons";
1207 
1208         rotatesprite(10 << 16, (5-3) << 16, MZ, 0, 2427,
1209             m_defshade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
1210         MNU_MeasureStringLarge(s, &w, &h);
1211         MNU_DrawStringLarge(TEXT_XCENTER(w), 5, s);
1212     }
1213 
1214     selection = MNU_SelectButtonFunction(mouse_button_item->text, &currentfunc);
1215     switch (selection)
1216         {
1217         case -1:    //cancel
1218             cust_callback = NULL;
1219             break;
1220         case 1:     //acknowledge
1221             currentfunc--;
1222             if (clicked)
1223                 MouseButtonsClicked[button] = currentfunc;
1224             else
1225                 MouseButtons[button] = currentfunc;
1226             CONTROL_MapButton(currentfunc, button, clicked, controldevice_mouse);
1227             MNU_SetMouseButtonFunctions(mouse_button_item);
1228             cust_callback = NULL;
1229             break;
1230         default: break;
1231         }
1232 
1233     return TRUE;
1234 }
1235 
MNU_SetMouseButtonFunctions(MenuItem_p item)1236 static BOOL MNU_SetMouseButtonFunctions(MenuItem_p item)
1237 {
1238     int button, clicked, function;
1239     char *p;
1240 
1241     clicked = !!(item->tics & 128);
1242     button = (item->tics & 127);
1243     ASSERT(button >= 0 && button < MAXMOUSEBUTTONS);
1244 
1245     if (clicked)
1246         function = MouseButtonsClicked[button];
1247     else
1248         function = MouseButtons[button];
1249 
1250     if (function < 0)
1251         strcpy(MouseButtonFunctions[button][clicked], "  -");
1252     else
1253         {
1254         strcpy(MouseButtonFunctions[button][clicked], CONFIG_FunctionNumToName(function));
1255         for (p = MouseButtonFunctions[button][clicked]; *p; p++)
1256             if (*p == '_')
1257                 *p = ' ';
1258         }
1259     return TRUE;
1260 }
1261 
1262 
1263 static MenuItem_p mouse_digital_item = NULL;
1264 
MNU_MouseDigitalPostProcess(MenuItem_p item)1265 static BOOL MNU_MouseDigitalPostProcess(MenuItem_p item)
1266 {
1267     mouse_digital_item = item;
1268     return TRUE;
1269 }
1270 
MNU_MouseDigitalSetupCustom(UserCall call,MenuItem_p item)1271 static BOOL MNU_MouseDigitalSetupCustom(UserCall call, MenuItem_p item)
1272 {
1273     int axis, direction;
1274     static int currentfunc = 0;
1275 
1276     if (call == uc_touchup)
1277             return (TRUE);
1278 
1279     axis = !!(mouse_digital_item->tics & 2);
1280     direction = (mouse_digital_item->tics & 1);
1281 
1282     if (cust_callback == NULL) {
1283         if (call != uc_setup)
1284             return (FALSE);
1285         currentfunc = MouseDigitalAxes[axis][direction];
1286         currentfunc++;
1287 
1288         cust_callback = MNU_MouseDigitalSetupCustom;
1289         cust_callback_call = call;
1290         cust_callback_item = item;
1291     }
1292 
1293     {
1294         short w, h = 0;
1295         const char *s = "Adv'd Mouse";
1296 
1297         rotatesprite(10 << 16, (5-3) << 16, MZ, 0, 2427,
1298             m_defshade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
1299         MNU_MeasureStringLarge(s, &w, &h);
1300         MNU_DrawStringLarge(TEXT_XCENTER(w), 5, s);
1301     }
1302 
1303     int selection = MNU_SelectButtonFunction(mouse_digital_item->text, &currentfunc);
1304     switch (selection) {
1305         case -1:    //cancel
1306             cust_callback = NULL;
1307             break;
1308         case 1:     //acknowledge
1309             currentfunc--;
1310             MouseDigitalAxes[axis][direction] = currentfunc;
1311             CONTROL_MapDigitalAxis(axis, currentfunc, direction, controldevice_mouse);
1312             MNU_SetMouseAxisFunctions(mouse_digital_item);
1313             cust_callback = NULL;
1314             break;
1315         default: break;
1316     }
1317 
1318     return TRUE;
1319 }
1320 
MNU_SetMouseAxisFunctions(MenuItem_p item)1321 static BOOL MNU_SetMouseAxisFunctions(MenuItem_p item)
1322 {
1323     int axis, direction;
1324     char *p;
1325 
1326     axis = !!(item->tics & 2);
1327     direction = (item->tics & 1);
1328     ASSERT(axis >= 0 && axis < MAXMOUSEAXES);
1329 
1330     if (MouseDigitalAxes[axis][direction] < 0) {
1331         strcpy(MouseAxisFunctions[axis][direction], "  -");
1332     } else {
1333         strcpy(MouseAxisFunctions[axis][direction],
1334             CONFIG_FunctionNumToName(MouseDigitalAxes[axis][direction]));
1335         for (p = MouseAxisFunctions[axis][direction]; *p; p++) {
1336             if (*p == '_')
1337                 *p = ' ';
1338         }
1339     }
1340     return TRUE;
1341 }
1342 
1343 
1344 static MenuItem_p joystick_button_item = NULL;
1345 
MNU_JoystickButtonsInitialise(MenuItem_p UNUSED (mitem))1346 static BOOL MNU_JoystickButtonsInitialise(MenuItem_p UNUSED(mitem))
1347 {
1348     JoystickButtonPage = 0;
1349     joybuttonssetupgroup.items = &joybuttons_i[JoystickButtonPage][0];
1350     joybuttonssetupgroup.cursor = 0;
1351     return TRUE;
1352 }
1353 
MNU_JoystickButtonPostProcess(MenuItem_p item)1354 static BOOL MNU_JoystickButtonPostProcess(MenuItem_p item)
1355 {
1356     joystick_button_item = item;
1357     return TRUE;
1358 }
1359 
MNU_JoystickButtonSetupCustom(UserCall call,MenuItem * item)1360 static BOOL MNU_JoystickButtonSetupCustom(UserCall call, MenuItem *item)
1361 {
1362     int button, clicked, selection;
1363     static int currentfunc = 0;
1364 
1365     if (call == uc_touchup)
1366             return (TRUE);
1367 
1368     clicked = !!(joystick_button_item->tics & 128);
1369     button = joystick_button_item->tics & 127;
1370 
1371     if (cust_callback == NULL)
1372         {
1373         if (call != uc_setup)
1374             return (FALSE);
1375 
1376         if (clicked) {
1377             currentfunc = JoystickButtonsClicked[button];
1378         } else {
1379             currentfunc = JoystickButtons[button];
1380         }
1381         currentfunc++;
1382 
1383         cust_callback = MNU_JoystickButtonSetupCustom;
1384         cust_callback_call = call;
1385         cust_callback_item = item;
1386         }
1387 
1388     {
1389         short w, h = 0;
1390         const char *s = "Joystick Setup";
1391 
1392         rotatesprite(10 << 16, (5-3) << 16, MZ, 0, 2427,
1393             m_defshade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
1394         MNU_MeasureStringLarge(s, &w, &h);
1395         MNU_DrawStringLarge(TEXT_XCENTER(w), 5, s);
1396     }
1397 
1398     selection = MNU_SelectButtonFunction(joystick_button_item->text, &currentfunc);
1399     switch (selection) {
1400         case -1:    //cancel
1401             cust_callback = NULL;
1402             break;
1403         case 1:     //acknowledge
1404             currentfunc--;
1405             if (clicked)
1406                 JoystickButtonsClicked[button] = currentfunc;
1407             else
1408                 JoystickButtons[button] = currentfunc;
1409             CONTROL_MapButton(currentfunc, button, clicked, controldevice_joystick);
1410             MNU_SetJoystickButtonFunctions(joystick_button_item);
1411             cust_callback = NULL;
1412             break;
1413         default: break;
1414     }
1415 
1416     return TRUE;
1417 }
1418 
MNU_JoystickButtonNextPage(void)1419 static BOOL MNU_JoystickButtonNextPage(void)
1420 {
1421     JoystickButtonPage = (JoystickButtonPage + 1) % MAXJOYSTICKBUTTONPAGES;
1422     joybuttonssetupgroup.items = &joybuttons_i[JoystickButtonPage][0];
1423     joybuttonssetupgroup.cursor = 0;
1424     MNU_ItemPreProcess(&joybuttonssetupgroup);
1425     return TRUE;
1426 }
1427 
MNU_SetJoystickButtonFunctions(MenuItem_p item)1428 static BOOL MNU_SetJoystickButtonFunctions(MenuItem_p item)
1429 {
1430     int button, clicked, function;
1431     char *p;
1432 
1433     clicked = !!(item->tics & 128);
1434     button = item->tics & 127;
1435     ASSERT(button >= 0 && button < MAXJOYBUTTONS);
1436 
1437     if (clicked) {
1438         function = JoystickButtonsClicked[button];
1439     } else {
1440         function = JoystickButtons[button];
1441     }
1442     if (function < 0) {
1443         strcpy(JoystickButtonFunctions[button][clicked], "  -");
1444     } else {
1445         strcpy(JoystickButtonFunctions[button][clicked], CONFIG_FunctionNumToName(function));
1446         for (p = JoystickButtonFunctions[button][clicked]; *p; p++) {
1447             if (*p == '_')
1448                 *p = ' ';
1449         }
1450     }
1451     return TRUE;
1452 }
1453 
1454 
1455 static MenuItem_p joystick_axis_item = NULL;
1456 
MNU_JoystickAxesInitialise(MenuItem_p UNUSED (mitem))1457 static BOOL MNU_JoystickAxesInitialise(MenuItem_p UNUSED(mitem))
1458 {
1459     if (!CONTROL_JoyPresent) {
1460         return TRUE;
1461     }
1462     if (JoystickAxisPage < 0 || JoystickAxisPage >= joynumaxes) {
1463         JoystickAxisPage = 0;
1464     }
1465 
1466     strcpy(JoystickAxisName, getjoyname(0, JoystickAxisPage));
1467     sprintf(JoystickAxisPageName, "Page %d / %d", JoystickAxisPage+1, joynumaxes);
1468     slidersettings[sldr_joyaxisanalog] = MNU_ControlAxisOffset(JoystickAnalogAxes[JoystickAxisPage]);
1469     if (JoystickAnalogScale[JoystickAxisPage] < 0)
1470         {
1471         slidersettings[sldr_joyaxisscale] = klabs(JoystickAnalogScale[JoystickAxisPage]) >> 13;
1472         buttonsettings[btn_joyaxis_invert] = 1;
1473         }
1474     else
1475         {
1476         slidersettings[sldr_joyaxisscale] = JoystickAnalogScale[JoystickAxisPage] >> 13;
1477         buttonsettings[btn_joyaxis_invert] = 0;
1478         }
1479     slidersettings[sldr_joyaxisdead] = JoystickAnalogDead[JoystickAxisPage] >> 10;
1480     slidersettings[sldr_joyaxissatur] = JoystickAnalogSaturate[JoystickAxisPage] >> 10;
1481 
1482     return TRUE;
1483 }
1484 
MNU_JoystickAxisPostProcess(MenuItem_p item)1485 static BOOL MNU_JoystickAxisPostProcess(MenuItem_p item)
1486 {
1487     joystick_axis_item = item;
1488     return TRUE;
1489 }
1490 
MNU_JoystickAxisSetupCustom(UserCall call,MenuItem * item)1491 static BOOL MNU_JoystickAxisSetupCustom(UserCall call, MenuItem *item)
1492 {
1493     static int currentfunc = 0;
1494 
1495     if (call == uc_touchup)
1496             return (TRUE);
1497 
1498     if (cust_callback == NULL) {
1499         if (call != uc_setup)
1500             return (FALSE);
1501 
1502         currentfunc = JoystickDigitalAxes[JoystickAxisPage][joystick_axis_item->tics];
1503         currentfunc++;
1504 
1505         cust_callback = MNU_JoystickAxisSetupCustom;
1506         cust_callback_call = call;
1507         cust_callback_item = item;
1508     }
1509 
1510     {
1511         short w, h = 0;
1512         const char *s = "Joystick Axes";
1513 
1514         rotatesprite(10 << 16, (5-3) << 16, MZ, 0, 2427,
1515             m_defshade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
1516         MNU_MeasureStringLarge(s, &w, &h);
1517         MNU_DrawStringLarge(TEXT_XCENTER(w), 5, s);
1518     }
1519 
1520     int selection = MNU_SelectButtonFunction(joystick_axis_item->text, &currentfunc);
1521     switch (selection) {
1522         case -1:    //cancel
1523             cust_callback = NULL;
1524             break;
1525         case 1:     //acknowledge
1526             currentfunc--;
1527             JoystickDigitalAxes[JoystickAxisPage][joystick_axis_item->tics] = currentfunc;
1528             CONTROL_MapDigitalAxis(JoystickAxisPage, currentfunc, joystick_axis_item->tics, controldevice_joystick);
1529             MNU_SetJoystickAxisFunctions(joystick_axis_item);
1530             cust_callback = NULL;
1531             break;
1532         default: break;
1533     }
1534 
1535     return TRUE;
1536 }
1537 
MNU_JoystickAxisNextPage(void)1538 static BOOL MNU_JoystickAxisNextPage(void)
1539 {
1540     JoystickAxisPage = (JoystickAxisPage + 1) % joynumaxes;
1541     joyaxessetupgroup.cursor = 1;
1542     MNU_ItemPreProcess(&joyaxessetupgroup);
1543     MNU_JoystickAxesInitialise(NULL);
1544     return TRUE;
1545 }
1546 
MNU_SetJoystickAxisFunctions(MenuItem_p item)1547 static BOOL MNU_SetJoystickAxisFunctions(MenuItem_p item)
1548 {
1549     int function;
1550     char *p;
1551 
1552     function = JoystickDigitalAxes[JoystickAxisPage][item->tics];
1553     if (function < 0) {
1554         strcpy(JoystickAxisFunctions[item->tics], "  -");
1555     } else {
1556         strcpy(JoystickAxisFunctions[item->tics], CONFIG_FunctionNumToName(function));
1557         for (p = JoystickAxisFunctions[item->tics]; *p; p++) {
1558             if (*p == '_')
1559                 *p = ' ';
1560         }
1561     }
1562     return TRUE;
1563 }
1564 
1565 
1566 BOOL
MNU_OrderCustom(UserCall call,MenuItem * item)1567 MNU_OrderCustom(UserCall call, MenuItem * item)
1568     {
1569     static signed char on_screen = 0;
1570     UserInput order_input;
1571     static int limitmove=0;
1572     UserInput tst_input;
1573     BOOL select_held = FALSE;
1574     int zero = 0;
1575     static BOOL DidOrderSound = FALSE;
1576     short choose_snd;
1577     static int wanghandle;
1578 
1579     static short RegOrderScreen[] =
1580         {
1581         5262,
1582         5261,
1583         4979,
1584         5111,
1585         5118,
1586         5113,
1587         //5111,
1588         //5118,
1589         //4979,
1590         //5261,
1591         //5262
1592 
1593         5114    // JBF: for my credits
1594         };
1595     static short SWOrderScreen[] =
1596         {
1597         5262,
1598         5110,
1599         5112,
1600         5113,
1601         5111,
1602         5118,
1603         4979,
1604 
1605         5114    // JBF: for my credits
1606         };
1607     short *OrderScreen, OrderScreenSiz;
1608 
1609     if (SW_SHAREWARE) {
1610         OrderScreen = SWOrderScreen;
1611         OrderScreenSiz = SIZ(SWOrderScreen);
1612     } else {
1613         OrderScreen = RegOrderScreen;
1614         OrderScreenSiz = SIZ(RegOrderScreen);
1615     }
1616 
1617     // Ignore the special touchup calls
1618     if (call == uc_touchup)
1619         return (TRUE);
1620 
1621     if (cust_callback == NULL)
1622         {
1623         if (call != uc_setup)
1624             return (FALSE);
1625         cust_callback = MNU_OrderCustom;
1626         cust_callback_call = uc_draw;
1627         cust_callback_item = item;
1628         return (TRUE);
1629         }
1630 
1631     if (SW_SHAREWARE && on_screen == 0 && !DidOrderSound)
1632         {
1633         DidOrderSound = TRUE;
1634         choose_snd = STD_RANDOM_RANGE(1000);
1635         if (choose_snd > 500 && !FX_SoundActive(wanghandle))
1636             wanghandle = PlaySound(DIGI_WANGORDER1, &zero, &zero, &zero, v3df_dontpan);
1637         else
1638         if (!FX_SoundActive(wanghandle))
1639             wanghandle = PlaySound(DIGI_WANGORDER2, &zero, &zero, &zero, v3df_dontpan);
1640         }
1641 
1642     order_input.button0 = order_input.button1 = FALSE;
1643     order_input.dir = dir_None;
1644 
1645     // Zero out the input structure
1646     tst_input.button0 = tst_input.button1 = FALSE;
1647     tst_input.dir = dir_None;
1648 
1649     if(!select_held)
1650         {
1651         CONTROL_GetUserInput(&tst_input);
1652         //order_input_buffered.dir = tst_input.dir;
1653         // Support a few other keys too
1654         if (KEY_PRESSED(KEYSC_SPACE)||KEY_PRESSED(KEYSC_ENTER))
1655             {
1656             KEY_PRESSED(KEYSC_SPACE) = FALSE;
1657             KEY_PRESSED(KEYSC_ENTER) = FALSE;
1658             tst_input.dir = dir_South;
1659             }
1660         }
1661 
1662     if (order_input_buffered.button0 || order_input_buffered.button1 || order_input_buffered.dir != dir_None)
1663         {
1664         if(tst_input.button0 == order_input_buffered.button0 &&
1665            tst_input.button1 == order_input_buffered.button1 &&
1666            tst_input.dir == order_input_buffered.dir)
1667             {
1668             select_held = TRUE;
1669             }
1670         else
1671             {
1672             if (labs(totalclock - limitmove) > 7)
1673                 {
1674                 order_input.button0 = order_input_buffered.button0;
1675                 order_input.button1 = order_input_buffered.button1;
1676                 order_input.dir = order_input_buffered.dir;
1677 
1678                 order_input_buffered.button0 = tst_input.button0;
1679                 order_input_buffered.button1 = tst_input.button1;
1680                 order_input_buffered.dir = tst_input.dir;
1681 
1682                 limitmove = totalclock;
1683                 }
1684             }
1685         }
1686     else
1687         {
1688         select_held = FALSE;
1689         order_input_buffered.button0 = tst_input.button0;
1690         order_input_buffered.button1 = tst_input.button1;
1691         order_input_buffered.dir = tst_input.dir;
1692         }
1693 
1694     if (order_input_buffered.button1)
1695         {
1696         KEY_PRESSED(KEYSC_ESC) = FALSE;
1697         cust_callback = NULL;
1698         DidOrderSound = FALSE;
1699         on_screen = 0;
1700         ExitMenus();
1701         return(TRUE);
1702         }
1703 
1704     if (order_input.dir == dir_North)
1705         {
1706         on_screen--;
1707         }
1708     else
1709     if (order_input.dir == dir_South)
1710         {
1711         on_screen++;
1712         }
1713     else
1714     if (order_input.dir == dir_West)
1715         {
1716         on_screen--;
1717         }
1718     else
1719     if (order_input.dir == dir_East)
1720         {
1721         on_screen++;
1722         }
1723 
1724 // CTW MODIFICATION
1725 // I reversed the logic in here to allow the user to loop around.
1726 // Yeah... I changed default behavior just because I wanted to.
1727 // AND YOU CAN'T STOP ME SUCKER!!!
1728     if(on_screen < 0)
1729         on_screen = OrderScreenSiz-1;
1730 
1731     if(on_screen > OrderScreenSiz-1)
1732         on_screen = 0;
1733 // CTW MODIFICATION END
1734 
1735 	flushperms();
1736     rotatesprite(0,0,RS_SCALE,0,OrderScreen[on_screen],0,0,
1737         (ROTATE_SPRITE_CORNER|ROTATE_SPRITE_SCREEN_CLIP|ROTATE_SPRITE_NON_MASK|ROTATE_SPRITE_IGNORE_START_MOST),
1738         0, 0, xdim-1, ydim-1);
1739 	SetRedrawScreen(&Player[myconnectindex]);
1740 
1741     if (on_screen == OrderScreenSiz-1)
1742         {
1743         // Jonathon's credits page hack :-)
1744 
1745         static char *jtitle = "^Port Credits";
1746         static char *jtext[] = {
1747             "*GAME AND ENGINE PORT",
1748             " Jonathon \"JonoF\" Fowler",
1749             "-",
1750             "*\"POLYMOST\" 3D RENDERER",
1751             "*NETWORKING, OTHER CODE",
1752             " Ken \"Awesoken\" Silverman",
1753             "-",
1754             " Visit http://www.jonof.id.au/jfsw for the",
1755             " source code, latest news, and updates of this port."
1756         };
1757         static char *scroller[] = {
1758             "This program is free software; you can redistribute it",
1759             "and/or modify it under the terms of the GNU General",
1760             "Public License as published by the Free Software",
1761             "Foundation; either version 2 of the License, or (at your",
1762             "option) any later version.",
1763             "",
1764             "This program is distributed in the hope that it will be",
1765             "useful but WITHOUT ANY WARRANTY; without even the implied",
1766             "warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR",
1767             "PURPOSE. See the GNU General Public License (GPL.TXT) for",
1768             "more details.",
1769             "",
1770             "",
1771             "",
1772             "",
1773             "Thanks to these people for their input and contributions:",
1774             "",
1775             "Richard \"TerminX\" Gobeille,",
1776             "Par \"Parkar\" Karlsson", // "Pär \"Parkar\" Karlsson",
1777             "Ben \"ProAsm\" Smit",
1778             "",
1779             "and all those who submitted bug reports and ",
1780             "supported the project financially!",
1781             "",
1782             "",
1783             "--x--",
1784             "",
1785             "",
1786             "",
1787             ""
1788         };
1789         const int numscrollerlines = SIZ(scroller);
1790         short dimx, dimy;
1791         int ycur = 54;
1792         unsigned ji;
1793 
1794         dimy = 0; MNU_MeasureString(jtitle, &dimx, &dimy);
1795         MNU_DrawString(160-(dimx>>1), ycur, jtitle, 0, 0);
1796         ycur += dimy + 8;
1797 
1798         for (ji = 0; ji < SIZ(jtext); ji++)
1799             {
1800             switch (jtext[ji][0])
1801                 {
1802                 case '-':
1803                     ycur += 6;
1804                     break;
1805                 case '*':
1806                     dimx = dimy = 0;
1807                     MNU_MeasureString(&jtext[ji][1], &dimx, &dimy);
1808                     MNU_DrawString(160-(dimx>>1), ycur, &jtext[ji][1], 0, 16);
1809                     ycur += dimy+1;
1810                     break;
1811                 default:
1812                     if (ji>0 && jtext[ji-1][0] == '*') ycur += 3;
1813                     dimx = dimy = 0;
1814                     MNU_MeasureSmallString(&jtext[ji][1], &dimx, &dimy);
1815                     MNU_DrawSmallString(160-(dimx>>1), ycur, &jtext[ji][1], 0, 0);
1816                     ycur += dimy+1;
1817                     break;
1818                 }
1819             }
1820 
1821         int m,i;
1822         for (m=0, i=(totalclock/104)%numscrollerlines; m<4; m++,i++)
1823             {
1824             if (i == numscrollerlines)
1825                 i=0;
1826             dimx = dimy = 0;
1827             MNU_MeasureSmallString(scroller[i], &dimx, &dimy);
1828             MNU_DrawSmallString(160-(dimx>>1), 154+(m*7), scroller[i], 0, 8);
1829             }
1830         }
1831 
1832     //KB_ClearKeysDown();
1833 
1834     return (TRUE);
1835     }
1836 
MNU_LoadModernDefaults(void)1837 BOOL MNU_LoadModernDefaults(void)
1838     {
1839     CONFIG_SetDefaultKeyDefinitions(CONFIG_DEFAULTS_MODERN);
1840     CONFIG_SetMouseDefaults(CONFIG_DEFAULTS_MODERN);
1841     CONFIG_SetJoystickDefaults(CONFIG_DEFAULTS_MODERN);
1842     return TRUE;
1843     }
1844 
MNU_LoadClassicDefaults(void)1845 BOOL MNU_LoadClassicDefaults(void)
1846     {
1847     CONFIG_SetDefaultKeyDefinitions(CONFIG_DEFAULTS_CLASSIC);
1848     CONFIG_SetMouseDefaults(CONFIG_DEFAULTS_CLASSIC);
1849     CONFIG_SetJoystickDefaults(CONFIG_DEFAULTS_CLASSIC);
1850     return TRUE;
1851     }
1852 
1853 
1854 short EpisodeMenuSelection;
1855 
1856 void
ExitMenus(void)1857 ExitMenus(void)
1858     {
1859     ControlPanelType = ct_mainmenu;
1860     UsingMenus = FALSE;
1861 
1862     if (LoadGameOutsideMoveLoop)
1863         return;
1864 
1865     ResumeGame();
1866     SetRedrawScreen(&Player[myconnectindex]);
1867     }
1868 
1869 BOOL
MNU_StartGame(void)1870 MNU_StartGame(void)
1871     {
1872     PLAYERp pp = Player + screenpeek;
1873     int handle = 0;
1874     int zero = 0;
1875 
1876     // always assumed that a demo is playing
1877 
1878     ready2send = 0;
1879     Skill = currentmenu->cursor;
1880 
1881     if (EpisodeMenuSelection >= 1)
1882         Level = 5;
1883     else
1884         Level = 1;
1885 
1886     ExitMenus();
1887     DemoPlaying = FALSE;
1888     ExitLevel = TRUE;
1889     NewGame = TRUE;
1890     DemoMode = FALSE;
1891     CameraTestMode = FALSE;
1892 
1893     //InitNewGame();
1894 
1895     if(Skill == 0)
1896         handle = PlaySound(DIGI_TAUNTAI3,&zero,&zero,&zero,v3df_none);
1897     else
1898     if(Skill == 1)
1899         handle = PlaySound(DIGI_NOFEAR,&zero,&zero,&zero,v3df_none);
1900     else
1901     if(Skill == 2)
1902         handle = PlaySound(DIGI_WHOWANTSWANG,&zero,&zero,&zero,v3df_none);
1903     else
1904     if(Skill == 3)
1905         handle = PlaySound(DIGI_NOPAIN,&zero,&zero,&zero,v3df_none);
1906 
1907     if (handle >= FX_Ok)
1908         while(FX_SoundActive(handle))
1909 			handleevents();
1910 
1911     return (TRUE);
1912     }
1913 
ResetMenuInput(VOID)1914 VOID ResetMenuInput(VOID)
1915     {
1916     cust_callback = NULL;
1917     InputMode = FALSE;
1918     }
1919 
1920 BOOL
MNU_StartNetGame(void)1921 MNU_StartNetGame(void)
1922     {
1923     extern BOOL ExitLevel, ShortGameMode, DemoInitOnce, FirstTimeIntoGame;
1924     extern short Level, Skill;
1925     int pnum;
1926 
1927     // always assumed that a demo is playing
1928 
1929     ready2send = 0;
1930     // Skill can go negative here
1931     Skill = gs.NetMonsters-1;
1932     Level = gs.NetLevel + 1;
1933     if (!AutoNet)
1934         ExitMenus();
1935     DemoPlaying = FALSE;
1936     ExitLevel = TRUE;
1937     NewGame = TRUE;
1938     // restart demo for multi-play mode
1939     DemoInitOnce = FALSE;
1940     ResetMenuInput();
1941 
1942         // TENSW: return if a joiner
1943         if (/* CTW REMOVED gTenActivated && */!AutoNet && FirstTimeIntoGame)
1944                 return TRUE;
1945 
1946     // need to set gNet vars for self
1947     // everone else gets a packet to set them
1948     gNet.AutoAim            = gs.AutoAim;
1949     gNet.SpawnMarkers       = gs.NetSpawnMarkers;
1950     gNet.HurtTeammate       = gs.NetHurtTeammate;
1951     gNet.Nuke               = gs.NetNuke;
1952     gNet.KillLimit          = gs.NetKillLimit*10;
1953     gNet.TimeLimit          = TimeLimitTable[gs.NetTimeLimit]*60*120;
1954 
1955     if (ShortGameMode)
1956         {
1957         gNet.KillLimit /= 10;
1958         gNet.TimeLimit /= 2;
1959         }
1960 
1961     gNet.TimeLimitClock     = gNet.TimeLimit;
1962     gNet.TeamPlay           = gs.NetTeamPlay;
1963     gNet.MultiGameType      = gs.NetGameType+1;
1964 
1965     if (gNet.MultiGameType == MULTI_GAME_COMMBAT_NO_RESPAWN)
1966         {
1967         gNet.MultiGameType = MULTI_GAME_COMMBAT;
1968         gNet.NoRespawn = TRUE;
1969         }
1970     else
1971         {
1972         gNet.NoRespawn = FALSE;
1973         }
1974 
1975     if (CommEnabled)
1976         {
1977         PACKET_NEW_GAME p;
1978 
1979         p.PacketType = PACKET_TYPE_NEW_GAME;
1980         p.Level = Level;
1981         p.Skill = Skill;
1982         p.GameType = gs.NetGameType;
1983         p.AutoAim = gs.AutoAim;
1984         p.HurtTeammate = gs.NetHurtTeammate;
1985         p.TeamPlay = gs.NetTeamPlay;
1986         p.SpawnMarkers = gs.NetSpawnMarkers;
1987         p.KillLimit = gs.NetKillLimit;
1988         p.TimeLimit = gs.NetTimeLimit;
1989         p.Nuke = gs.NetNuke;
1990 
1991         netbroadcastpacket((BYTEp)(&p), sizeof(p));            // TENSW
1992         }
1993 
1994 
1995     return (TRUE);
1996     }
1997 
1998 
1999 BOOL
MNU_EpisodeCustom(void)2000 MNU_EpisodeCustom(void)
2001     {
2002     EpisodeMenuSelection = currentmenu->cursor;
2003 
2004     return (TRUE);
2005     }
2006 
2007 BOOL
MNU_QuitCustom(UserCall call,MenuItem_p item)2008 MNU_QuitCustom(UserCall call, MenuItem_p item)
2009     {
2010     int select;
2011     DialogResponse ret;
2012     extern BOOL DrawScreen;
2013 
2014     // Ignore the special touchup calls
2015     if (call == uc_touchup)
2016         return (TRUE);
2017 
2018     if (cust_callback == NULL)
2019         {
2020         if (call != uc_setup)
2021             return (FALSE);
2022 
2023         memset(dialog, 0, sizeof(dialog));
2024 
2025         dialog[0] = S_QUITYN;
2026 
2027         cust_callback = MNU_QuitCustom;
2028         cust_callback_call = uc_draw;
2029         cust_callback_item = item;
2030 
2031 		return(TRUE);
2032         }
2033 
2034     ret = MNU_Dialog();
2035 
2036     if (DrawScreen || ret == dialog_NoAnswer)
2037         return(TRUE);
2038 
2039     cust_callback = NULL;
2040     ExitMenus();
2041 
2042     if (ret == dialog_Yes)
2043         {
2044         if (CommPlayers >= 2)
2045             MultiPlayQuitFlag = TRUE;
2046         else
2047             QuitFlag = TRUE;
2048         }
2049 
2050     KB_ClearKeysDown();
2051 
2052     return (TRUE);
2053     }
2054 
2055 BOOL
MNU_QuickLoadCustom(UserCall call,MenuItem_p item)2056 MNU_QuickLoadCustom(UserCall call, MenuItem_p item)
2057     {
2058     int select;
2059     extern BOOL ReloadPrompt;
2060     int bak;
2061     PLAYERp pp = Player + myconnectindex;
2062     extern short GlobInfoStringTime;
2063     extern BOOL DrawScreen;
2064     DialogResponse ret;
2065 
2066     if (cust_callback == NULL)
2067         {
2068         if (call != uc_setup)
2069             return (FALSE);
2070 
2071         memset(dialog, 0, sizeof(dialog));
2072 
2073         dialog[0] = "Load saved game";
2074         sprintf(QuickLoadDescrDialog,"\"%s\" (Y/N)?",SaveGameDescr[QuickLoadNum]);
2075         dialog[1] = QuickLoadDescrDialog;
2076 
2077         cust_callback = MNU_QuickLoadCustom;
2078         cust_callback_call = uc_draw;
2079         cust_callback_item = item;
2080 
2081 		return(TRUE);
2082         }
2083 
2084     // Ignore the special touchup calls
2085     if (call == uc_touchup)
2086         return (TRUE);
2087 
2088     ret = MNU_Dialog();
2089 
2090     if (DrawScreen || ret == dialog_NoAnswer)
2091         {
2092         return(TRUE);
2093         }
2094 
2095     if (ret == dialog_No)
2096         {
2097         cust_callback = NULL;
2098         if (ReloadPrompt)
2099             {
2100             ReloadPrompt = FALSE;
2101             bak = GlobInfoStringTime;
2102             GlobInfoStringTime = 999;
2103             PutStringInfo(pp, "Press SPACE to restart");
2104             GlobInfoStringTime = bak;
2105             }
2106 
2107         KB_ClearKeysDown();
2108         ExitMenus();
2109         }
2110     else
2111         {
2112         // Y pressed
2113         cust_callback = NULL;
2114 
2115         KB_ClearKeysDown();
2116         LoadSaveMsg("Loading...");
2117 
2118         PauseAction();
2119 
2120         ReloadPrompt = FALSE;
2121         if (LoadGame(QuickLoadNum) == -1)
2122             {
2123             ResumeAction();
2124             return (FALSE);
2125             }
2126 
2127         ready2send = 1;
2128         LastSaveNum = -1;
2129 
2130         // do a load game here
2131         KB_ClearKeysDown();
2132         ExitMenus();
2133         }
2134 
2135     KB_ClearKeysDown();
2136 
2137     return (TRUE);
2138     }
2139 
2140 // MENU FUNCTIONS /////////////////////////////////////////////////////////////////////////////////
2141 ////////////////////////////////////////////////
2142 // Set some global menu related defaults
2143 ////////////////////////////////////////////////
2144 void
MNU_InitMenus(void)2145 MNU_InitMenus(void)
2146     {
2147     pClearTextLine(Player + myconnectindex, TEXT_INFO_LINE(0));
2148 
2149     slidersettings[sldr_mouse] = gs.MouseSpeed/(MOUSE_SENS_MAX_VALUE/SLDR_MOUSESENSEMAX);
2150 
2151     slidersettings[sldr_sndfxvolume] = gs.SoundVolume / (FX_VOL_MAX_VALUE/SLDR_SNDFXVOLMAX);
2152     slidersettings[sldr_musicvolume] = gs.MusicVolume / (MUSIC_VOL_MAX_VALUE/SLDR_MUSICVOLMAX);
2153     slidersettings[sldr_scrsize] = gs.BorderNum;
2154     slidersettings[sldr_brightness] = gs.Brightness;
2155     slidersettings[sldr_panelscale] = gs.PanelScale - 1;
2156     slidersettings[sldr_bordertile] = gs.BorderTile;
2157 
2158     {
2159 	int i,newx=xdim,newy=ydim;
2160 
2161 #if USE_POLYMOST && USE_OPENGL
2162     buttonsettings[btn_texfilter] = (gltexfiltermode & 1);
2163 #endif
2164 	buttonsettings[btn_videofs] = fullscreen;
2165 
2166 	UpdateValidModes(bpp,fullscreen);
2167 	for (i=0; i<numvalidbpps; i++)
2168 		if (validbpps[i] == bpp)
2169 			slidersettings[sldr_videobpp] = i;
2170 
2171 	i = checkvideomode(&newx, &newy, bpp, fullscreen, 1);
2172 	if (i != 0x7fffffff && i >= 0)
2173 		for (i=0; i<numvalidresolutions; i++)
2174 			if (validresolutions[i].x == newx && validresolutions[i].y == newy)
2175 				slidersettings[sldr_videores] = i;
2176     }
2177 
2178     buttonsettings[btn_auto_run] = gs.AutoRun;
2179     buttonsettings[btn_auto_aim] = gs.AutoAim;
2180     buttonsettings[btn_messages] = gs.Messages;
2181     buttonsettings[btn_crosshair] = gs.Crosshair;
2182     //    buttonsettings[btn_bobbing] = gs.Bobbing;
2183     buttonsettings[btn_shadows] = gs.Shadows;
2184 
2185     buttonsettings[btn_mouse_aim] = gs.MouseAimingType;
2186     buttonsettings[btn_mouse_invert] = gs.MouseInvert;
2187     buttonsettings[btn_sound] = gs.FxOn;
2188     buttonsettings[btn_music] = gs.MusicOn;
2189     buttonsettings[btn_talking] = gs.Talking;
2190 
2191     buttonsettings[btn_voxels] = gs.Voxels;
2192     buttonsettings[btn_ambience] = gs.Ambient;
2193     buttonsettings[btn_playcd] = gs.PlayCD;
2194     buttonsettings[btn_flipstereo] = gs.FlipStereo;
2195     buttonsettings[btn_stats] = gs.Stats;
2196 
2197     slidersettings[sldr_gametype] = gs.NetGameType;
2198     slidersettings[sldr_netlevel] = gs.NetLevel;
2199     slidersettings[sldr_monsters] = gs.NetMonsters;
2200     slidersettings[sldr_killlimit] = gs.NetKillLimit;
2201     slidersettings[sldr_timelimit] = gs.NetTimeLimit;
2202     slidersettings[sldr_playercolor] = gs.NetColor;
2203 
2204     buttonsettings[btn_nuke] = gs.NetNuke;
2205     buttonsettings[btn_markers] = gs.NetSpawnMarkers;
2206     buttonsettings[btn_teamplay] = gs.NetTeamPlay;
2207     buttonsettings[btn_friendlyfire] = gs.NetHurtTeammate;
2208     buttonsettings[btn_parental] = gs.ParentalLock;
2209 
2210     slidersettings[sldr_mousescalex] = MouseAnalogScale[0]>>13;
2211     slidersettings[sldr_mousescaley] = MouseAnalogScale[1]>>13;
2212 
2213     slidersettings[sldr_joyaxisscale] = 0;
2214     buttonsettings[btn_joyaxis_invert] = 0;
2215     slidersettings[sldr_joyaxisanalog] = 0;
2216     slidersettings[sldr_joyaxisdead] = 0;
2217     slidersettings[sldr_joyaxissatur] = 0;
2218 
2219     // Distinguish between Single or Multiplay for new game menu types
2220     if(CommPlayers > 1)
2221         main_i[0].child = &networkgroup;
2222     else
2223 //        #ifdef SW_SHAREWARE
2224         main_i[0].child = &episodegroup;
2225 //        #else
2226 //        main_i[0].child = &skillgroup;
2227 //        #endif
2228     main_i[4].text = (SW_SHAREWARE) ? MAIN_MENU_HOW_TO_ORDER : MAIN_MENU_COOL_STUFF;
2229     main_i[4].hotkey = (SW_SHAREWARE) ? KEYSC_H : KEYSC_C;
2230     }
2231 
2232 ////////////////////////////////////////////////
2233 // Measure the pixel width of a graphic string
2234 ////////////////////////////////////////////////
2235 static char lg_xlat_num[] = {0,1,2,3,4,5,6,7,8,9};
2236 #define FONT_LARGE_ALPHA 3706
2237 #define FONT_LARGE_DIGIT 3732
2238 
2239 void
MNU_MeasureStringLarge(const char * string,short * w,short * h)2240 MNU_MeasureStringLarge(const char *string, short *w, short *h)
2241     {
2242     short ndx, width, height;
2243     char c;
2244     short pic;
2245 
2246     width = 0;
2247     height = *h;
2248 
2249     for (ndx = 0; (c = string[ndx]) != 0; ndx++)
2250         {
2251         if (isalpha(c))
2252             {
2253             c = toupper(c);
2254             pic = FONT_LARGE_ALPHA + (c - 'A');
2255             }
2256         else
2257         if (isdigit(c))
2258             {
2259             pic = FONT_LARGE_DIGIT + lg_xlat_num[(c - '0')];
2260             }
2261         else
2262         if (c == ' ')
2263             {
2264             width += 10;                 // Special case for space char
2265             continue;
2266             }
2267         else
2268             {
2269             continue;
2270             }
2271 
2272         width += tilesizx[pic]+1;
2273         if (height < tilesizy[pic])
2274             height = tilesizy[pic];
2275         }
2276 
2277     *w = width;
2278     *h = height;
2279     }
2280 
2281 ////////////////////////////////////////////////
2282 // Draw a string using a graphic font
2283 ////////////////////////////////////////////////
2284 void
MNU_DrawStringLarge(short x,short y,const char * string)2285 MNU_DrawStringLarge(short x, short y, const char *string)
2286     {
2287     int ndx, offset;
2288     char c;
2289     short pic;
2290 
2291     offset = x;
2292 
2293     for (ndx = 0; (c = string[ndx]) != 0; ndx++)
2294         {
2295         if (isalpha(c))
2296             {
2297             c = toupper(c);
2298             pic = FONT_LARGE_ALPHA + (c - 'A');
2299             }
2300         else
2301         if (isdigit(c))
2302             {
2303             pic = FONT_LARGE_DIGIT + lg_xlat_num[(c - '0')];
2304             }
2305         else
2306         if (c == ' ')
2307             {
2308             offset += 10;
2309             continue;
2310             }
2311         else
2312             {
2313             continue;
2314             }
2315 
2316         rotatesprite(offset << 16, y << 16, MZ, 0, pic, MenuTextShade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
2317         offset += tilesizx[pic] + 1;
2318         }
2319 
2320     }
2321 
2322 
2323 ////////////////////////////////////////////////
2324 // Measure the pixel width of a graphic string
2325 ////////////////////////////////////////////////
2326 void
MNU_MeasureString(const char * string,short * w,short * h)2327 MNU_MeasureString(const char *string, short *w, short *h)
2328     {
2329     short ndx, width, height;
2330     char c;
2331     short ac;
2332 
2333     if (string[0] == '^')
2334         {
2335         MNU_MeasureStringLarge(&string[1], w, h);
2336         return;
2337         }
2338 
2339     width = 0;
2340     height = *h;
2341 
2342     for (ndx = 0; (c = string[ndx]) != 0; ndx++)
2343         {
2344         ac = c - '!' + STARTALPHANUM;
2345         if( (ac < STARTALPHANUM || ac > ENDALPHANUM)  && c != asc_Space )
2346             break;
2347 
2348         if (c > asc_Space && c < 127)
2349             {
2350             width += tilesizx[ac];
2351             if (height < tilesizy[ac])
2352                 height = tilesizy[ac];
2353             }
2354         else
2355         if (c == asc_Space)
2356             width += 4;                 // Special case for space char
2357         }
2358 
2359     *w = width;
2360     *h = height;
2361     }
2362 
2363 ////////////////////////////////////////////////
2364 // Draw a string using a graphic font
2365 //
2366 // MenuTextShade and MenuDrawFlags
2367 ////////////////////////////////////////////////
2368 void
MNU_DrawString(short x,short y,const char * string,short shade,short pal)2369 MNU_DrawString(short x, short y, const char *string, short shade, short pal)
2370 {
2371     int ndx, offset;
2372     char c;
2373     short ac;
2374 
2375     if (string[0] == '^')
2376     {
2377         MNU_DrawStringLarge(x,y, &string[1]);
2378         return;
2379     }
2380 
2381     offset = x;
2382 
2383     for (ndx = 0; (c = string[ndx]) != 0; ndx++)
2384     {
2385         ac = c - '!' + STARTALPHANUM;
2386         if( (ac < STARTALPHANUM || ac > ENDALPHANUM)  && c != asc_Space )
2387             break;
2388 
2389         if (c > asc_Space && c < 127)
2390         {
2391             rotatesprite(offset<<16,y<<16,MZ,0,ac, shade, pal, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
2392             offset += tilesizx[ac];
2393         } else
2394         if (c == asc_Space)
2395             offset += 4;                // Special case for space char
2396     }
2397 
2398 }
2399 /*   Original code
2400 void
2401 MNU_DrawString(short x, short y, char *string)
2402 {
2403     int ndx, offset;
2404     char c;
2405 
2406     if (string[0] == '^')
2407     {
2408         MNU_DrawStringLarge(x,y, &string[1]);
2409         return;
2410     }
2411 
2412     offset = x;
2413 
2414     for (ndx = 0; (c = string[ndx]) != 0; ndx++)
2415     {
2416         if (c > asc_Space && c < 127)
2417         {
2418             rotatesprite(offset << 16, y << 16, MZ, 0, xlatfont[c], MenuTextShade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
2419             offset += tilesizx[xlatfont[c]];
2420         } else
2421         if (c == asc_Space)
2422             offset += 4;                // Special case for space char
2423     }
2424 
2425 }
2426 */
2427 
2428 ////////////////////////////////////////////////
2429 // Measure the pixel width of a small font string
2430 ////////////////////////////////////////////////
2431 void
MNU_MeasureSmallString(const char * string,short * w,short * h)2432 MNU_MeasureSmallString(const char *string, short *w, short *h)
2433     {
2434     short ndx, width, height;
2435     char c;
2436     short ac;
2437 
2438     width = 0;
2439     height = *h;
2440 
2441     for (ndx = 0; (c = string[ndx]) != 0; ndx++)
2442         {
2443         ac = (c - '!') + 2930;
2444         if( (ac < 2930 || ac > 3023) && c != asc_Space )
2445             break;
2446 
2447         if (c > asc_Space && c < 127)
2448             {
2449             width += tilesizx[ac];
2450             if (height < tilesizy[ac])
2451                 height = tilesizy[ac];
2452             }
2453         else
2454         if (c == asc_Space)
2455             width += 4;                 // Special case for space char
2456         }
2457 
2458     *w = width;
2459     *h = height;
2460     }
2461 
2462 ////////////////////////////////////////////////
2463 // Draw a string using a small graphic font
2464 ////////////////////////////////////////////////
2465 void
MNU_DrawSmallString(short x,short y,const char * string,short shade,short pal)2466 MNU_DrawSmallString(short x, short y, const char *string, short shade, short pal)
2467 {
2468     int ndx;
2469     char c;
2470     short ac,offset;
2471 
2472 
2473     offset = x;
2474 
2475     for (ndx = 0; (c = string[ndx]) != 0; ndx++)
2476     {
2477         ac = c - '!' + 2930;
2478         if( (ac < 2930 || ac > 3023)  && c != asc_Space )
2479             break;
2480 
2481         if (c > asc_Space && c < 127)
2482         {
2483             rotatesprite(offset<<16,y<<16,MZ,0,ac, shade, pal, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
2484 
2485             offset += tilesizx[ac];
2486 
2487         } else
2488         if (c == asc_Space)
2489             {
2490             offset += 4;                // Special case for space char
2491             }
2492     }
2493 
2494 }
2495 
2496 ////////////////////////////////////////////////
2497 //  Get an input string from user using small font
2498 ////////////////////////////////////////////////
2499 
2500 signed char
MNU_InputSmallString(char * name,short pix_width)2501 MNU_InputSmallString(char *name, short pix_width)
2502     {
2503     char ch;
2504     short w, h;
2505     UserInput con_input;
2506 
2507 #define ascii_backspace 8
2508 #define ascii_esc 27
2509 #define ascii_return 13
2510 
2511     if (!MoveSkip4 && !MessageInputMode)
2512         {
2513         con_input.dir = dir_None;
2514         CONTROL_GetUserInput(&con_input);
2515 
2516         if (con_input.dir == dir_North)
2517             {
2518             CON_CommandHistory(1);
2519             }
2520         else
2521         if (con_input.dir == dir_South)
2522             {
2523             CON_CommandHistory(-1);
2524             }
2525         }
2526 
2527     while (KB_KeyWaiting())
2528         {
2529         ch = KB_Getch();
2530 
2531         // skip any extended key
2532         if (ch == 0)
2533             {
2534             ch = KB_Getch();
2535             if (ch == 104) // extended enter
2536                 ch = ascii_return;
2537             else
2538                 continue;
2539             }
2540 
2541         if (ch == ascii_backspace)
2542             {
2543             name[strlen(name) - 1] = '\0';
2544             continue;
2545             }
2546         else
2547         if (ch == ascii_esc)
2548             {
2549             return (-1);
2550             }
2551         else
2552         if (ch == ascii_return)
2553             {
2554             return (FALSE);
2555             }
2556         else
2557         if (!isprint(ch))
2558             continue;
2559 
2560         MNU_MeasureSmallString(name, &w, &h);
2561         if (w < pix_width)
2562             {
2563             if(strlen(name) < 256) // Dont let it go too far!
2564                 sprintf(name, "%s%c", name, ch);
2565             }
2566         }
2567 
2568     return (TRUE);
2569 
2570     }
2571 
2572 ////////////////////////////////////////////////
2573 // Draw dialog text on screen
2574 ////////////////////////////////////////////////
2575 static DialogResponse
MNU_Dialog(void)2576 MNU_Dialog(void)
2577     {
2578     short ndx, linecnt, w[MAXDIALOG], h, x, y;
2579 
2580     linecnt = 0;
2581     h = 8;
2582 
2583     for (ndx = 0; ndx < MAXDIALOG && dialog[ndx]; ndx++)
2584         {
2585         MNU_MeasureString(dialog[ndx], &w[ndx], &h);
2586         ASSERT(w[ndx] < XDIM);
2587         linecnt++;
2588         }
2589 
2590     y = ((YDIM - ((h * linecnt) + (linecnt * 2))) / 2);
2591 
2592     for (ndx = 0; ndx < linecnt; ndx++)
2593         {
2594         x = ((XDIM - w[ndx]) / 2);
2595         MNU_DrawString(x, y, dialog[ndx],1,16);
2596         y += (h + 3);
2597         }
2598 
2599     CONTROL_GetUserInput(&mnu_input);
2600 
2601     if (KB_KeyPressed(sc_Y) || KB_KeyPressed(sc_Enter) || mnu_input.button0)
2602         return dialog_Yes;
2603     else if (KB_KeyPressed(sc_N) || KB_KeyPressed(sc_Escape) || mnu_input.button1)
2604         return dialog_No;
2605     else
2606         return dialog_NoAnswer;
2607     }
2608 
2609 ////////////////////////////////////////////////
2610 //  Get an input string from user
2611 ////////////////////////////////////////////////
2612 
2613 signed char
MNU_InputString(char * name,short pix_width)2614 MNU_InputString(char *name, short pix_width)
2615     {
2616     char ch;
2617     short w, h;
2618 
2619 #define ascii_backspace 8
2620 #define ascii_esc 27
2621 #define ascii_return 13
2622 
2623     while (KB_KeyWaiting())
2624         {
2625         ch = KB_Getch();
2626 
2627         ////DSPRINTF(ds, "%c %d", ch, ch);
2628         //MONO_PRINT(ds);
2629 
2630         // skip most extended keys
2631         if (ch == 0)
2632             {
2633             ch = KB_Getch();
2634 
2635             ////DSPRINTF(ds, "extended key %c %d", ch, ch);
2636             //MONO_PRINT(ds);
2637 
2638             if (ch == 104) // extended enter
2639                 ch = ascii_return;
2640             else
2641                 continue;
2642             }
2643 
2644         if (ch == ascii_backspace)
2645             {
2646             name[strlen(name) - 1] = '\0';
2647             continue;
2648             }
2649         else
2650         if (ch == ascii_esc)
2651             {
2652             return (-1);
2653             }
2654         else
2655         if (ch == ascii_return)
2656             {
2657             return (FALSE);
2658             }
2659         else
2660         if (!isprint(ch))
2661             continue;
2662 
2663         MNU_MeasureString(name, &w, &h);
2664         if (w < pix_width)
2665             {
2666             sprintf(name, "%s%c", name, ch);
2667             }
2668         }
2669 
2670     return (TRUE);
2671 
2672     }
2673 
2674 #define SS_XSTART 146L
2675 #define SS_YSTART SD_YSTART
2676 #define SS_BORDER_SIZE 5L
2677 
LoadSaveMsg(char * msg)2678 VOID LoadSaveMsg(char *msg)
2679     {
2680     short w,h;
2681 
2682     flushperms();
2683     DrawMenuLevelScreen();
2684     strcpy((char*)ds, (char*)msg);
2685     MNU_MeasureString(ds, &w, &h);
2686     MNU_DrawString(TEXT_XCENTER(w), 170, ds, 1, 16);
2687     nextpage();
2688     }
2689 
2690 
2691 ////////////////////////////////////////////////
2692 //  Load Game menu
2693 //  This function gets called whenever you
2694 //  press enter on one of the load game
2695 //  spots.
2696 //  I'm figuring it need to do the following:
2697 //  . Load the game if there is one by calling: MNU_LoadGameCustom.
2698 ////////////////////////////////////////////////
2699 BOOL
MNU_GetLoadCustom(void)2700 MNU_GetLoadCustom(void)
2701     {
2702     short load_num;
2703 
2704     load_num = currentmenu->cursor;
2705 
2706     // no saved game exists - don't do anything
2707     if (SaveGameDescr[load_num][0] == '\0')
2708         return (FALSE);
2709 
2710     if (InMenuLevel || DemoMode || DemoPlaying)
2711         {
2712         LoadSaveMsg("Loading...");
2713 
2714         if (LoadGame(load_num) == -1)
2715             return (FALSE);
2716 
2717         QuickLoadNum = load_num;
2718         // the (Quick)Save menu should default to the last loaded game
2719         SaveGameGroup.cursor = load_num;
2720 
2721         ExitMenus();
2722         ExitLevel = TRUE;
2723         LoadGameOutsideMoveLoop = TRUE;
2724         if (DemoMode || DemoPlaying)
2725             LoadGameFromDemo = TRUE;
2726 
2727         return(TRUE);
2728         }
2729 
2730     LoadSaveMsg("Loading...");
2731 
2732     PauseAction();
2733 
2734     if (LoadGame(load_num) == -1)
2735         {
2736         ResumeAction();
2737         return (FALSE);
2738         }
2739 
2740     QuickLoadNum = load_num;
2741     // the (Quick)Save menu should default to the last loaded game
2742     SaveGameGroup.cursor = load_num;
2743 
2744     ready2send = 1;
2745     LastSaveNum = -1;
2746     ExitMenus();
2747 
2748     if (DemoMode)
2749         {
2750         ExitLevel = TRUE;
2751         DemoPlaying = FALSE;
2752         }
2753 
2754     return (TRUE);
2755     }
2756 
2757 ////////////////////////////////////////////////
2758 //  Save Game menu
2759 //  This function gets called whenever you
2760 //  press enter on one of the save game
2761 //  spots.
2762 //  I'm figuring it need to do the following:
2763 //  . Call MNU_GetInput to allow string input of description.
2764 //  . Save the game if there is one by calling: MNU_SaveGameCustom.
2765 ////////////////////////////////////////////////
2766 BOOL
MNU_GetSaveCustom(void)2767 MNU_GetSaveCustom(void)
2768     {
2769     short save_num;
2770     extern BOOL InMenuLevel, LoadGameOutsideMoveLoop;
2771 
2772     save_num = currentmenu->cursor;
2773 
2774     if (InMenuLevel)
2775         return(FALSE);
2776 
2777     if (MenuInputMode)
2778         {
2779         PauseAction();
2780 
2781         LoadSaveMsg("Saving...");
2782 
2783         if (SaveGame(save_num) != -1)
2784             {
2785             QuickLoadNum = save_num;
2786 
2787             LoadGameGroup.cursor = save_num;
2788             LastSaveNum = -1;
2789             }
2790 
2791         ResumeAction();
2792         ExitMenus();
2793 
2794         // toggle edit mode
2795         MenuInputMode = FALSE;
2796         }
2797     else
2798         {
2799         strcpy(BackupSaveGameDescr, SaveGameDescr[save_num]);
2800 
2801         // clear keyboard buffer
2802         while (KB_KeyWaiting())
2803             {
2804             if (KB_Getch() == 0)
2805                 KB_Getch();
2806             }
2807 
2808         // toggle edit mode
2809         MenuInputMode = TRUE;
2810         }
2811 
2812     return (TRUE);
2813     }
2814 
2815 ////////////////////////////////////////////////
2816 //  Load/Save Touchup function
2817 //  This function gets called each frame by DrawMenus
2818 ////////////////////////////////////////////////
2819 
2820 static BOOL
MNU_DrawLoadSave(short game_num)2821 MNU_DrawLoadSave(short game_num)
2822     {
2823     // screen border
2824     rotatesprite(SS_XSTART << 16, SS_YSTART << 16, MZ, 0, pic_loadsavescreen,
2825         0, 0, MenuDrawFlags | ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
2826 
2827     // description box
2828     rotatesprite((SD_XSTART) << 16, (SD_YSTART) << 16, MZ, 0, pic_savedescr,
2829         0, 0, MenuDrawFlags | ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
2830 
2831     // cursor for text boxes
2832     rotatesprite((SD_XSTART + 3) << 16, (SD_LINE(game_num) + 1) << 16, MZ, 0, pic_loadsavecursor,
2833         0, 0, MenuDrawFlags | ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
2834 
2835     return(TRUE);
2836     }
2837 
2838 static char SaveGameInfo1[80];
2839 static char SaveGameInfo2[80];
2840 
2841 BOOL
MNU_LoadSaveMove(UserCall UNUSED (call),MenuItem_p UNUSED (item))2842 MNU_LoadSaveMove(UserCall UNUSED(call), MenuItem_p UNUSED(item))
2843     {
2844     short i;
2845     short game_num;
2846     short tile;
2847     static short SaveGameEpisode, SaveGameLevel, SaveGameSkill;
2848     BOOL GotInput = FALSE;
2849 
2850     if (!UsingMenus)
2851         return(TRUE);
2852 
2853     game_num = currentmenu->cursor;
2854 
2855     // read all descr first time through - LastSaveNum starts at 99
2856     if (LastSaveNum == 99)
2857         {
2858         memset(SaveGameDescr, '\0', sizeof(SaveGameDescr));
2859 
2860         for (i = 0; i < 10; i++)
2861             LoadGameDescr(i, SaveGameDescr[i]);
2862         }
2863 
2864     // cursor has moved - read header
2865     if (game_num != LastSaveNum)
2866         {
2867         screen_tile = LoadGameFullHeader(game_num, SaveGameDescr[game_num],
2868             &SaveGameLevel, &SaveGameSkill);
2869 
2870         sprintf(SaveGameInfo1, "Level %d, Skill %d", SaveGameLevel, SaveGameSkill+1);
2871         SaveGameInfo2[0] = 0;
2872         }
2873 
2874     if (QuickSaveMode)
2875         {
2876         QuickSaveMode = FALSE;
2877         MenuInputMode = TRUE;
2878         strcpy(BackupSaveGameDescr, SaveGameDescr[game_num]);
2879         KB_ClearKeysDown();
2880         KB_FlushKeyboardQueue();
2881         }
2882 
2883     LastSaveNum = game_num;
2884 
2885     // input mode check
2886     if (MenuInputMode)
2887         {
2888         MenuItem *item = &currentmenu->items[currentmenu->cursor];
2889 
2890         if (SavePrompt)
2891             {
2892             if (KB_KeyPressed(sc_Y) || KB_KeyPressed(sc_Enter))
2893                 {
2894 		KB_ClearKeyDown(sc_Y);
2895 		KB_ClearKeyDown(sc_Enter);
2896                 SavePrompt = FALSE;
2897                 // use input
2898                 item->custom();
2899                 }
2900             else
2901             if (KB_KeyPressed(sc_N))
2902                 {
2903 		KB_ClearKeyDown(sc_N);
2904                 strcpy(SaveGameDescr[game_num], BackupSaveGameDescr);
2905                 SavePrompt = FALSE;
2906                 MenuInputMode = FALSE;
2907                 }
2908             }
2909         else
2910         // get input
2911         switch (MNU_InputString(SaveGameDescr[game_num], 114))
2912             {
2913         case -1:                        // Cancel Input (pressed ESC) or Err
2914             strcpy(SaveGameDescr[game_num], BackupSaveGameDescr);
2915             MenuInputMode = FALSE;
2916             KB_ClearKeysDown();
2917             break;
2918         case FALSE:                     // Input finished (RETURN)
2919             // no input
2920             if (SaveGameDescr[game_num][0] == '\0')
2921                 {
2922                 strcpy(SaveGameDescr[game_num], BackupSaveGameDescr);
2923                 MenuInputMode = FALSE;
2924                 }
2925             else
2926                 {
2927                 GotInput = TRUE;
2928                 }
2929 	    KB_ClearKeyDown(sc_Enter);
2930             break;
2931         case TRUE:                      // Got input
2932             break;
2933             }
2934 
2935         if (GotInput)
2936             {
2937             if (BackupSaveGameDescr[0])
2938                 SavePrompt = TRUE;
2939 
2940             if (!SavePrompt)
2941                 {
2942                 // use input
2943                 item->custom();
2944                 }
2945             }
2946         }
2947 
2948     return (TRUE);
2949     }
2950 
2951 BOOL
MNU_LoadSaveDraw(UserCall call,MenuItem_p UNUSED (item))2952 MNU_LoadSaveDraw(UserCall call, MenuItem_p UNUSED(item))
2953     {
2954     short i;
2955     short game_num;
2956     short tile;
2957 
2958     if (call != uc_touchup)
2959         return(TRUE);
2960 
2961     game_num = currentmenu->cursor;
2962 
2963     // misc drawing
2964     MNU_DrawLoadSave(game_num);
2965 
2966     // print game descriptions
2967     for (i = 0; i < 10; i++)
2968         {
2969         if (i == game_num && MenuInputMode && !SavePrompt)
2970             {
2971             static BOOL cur_show;
2972             char tmp[sizeof(SaveGameDescr[0])];
2973 
2974             //cur_show ^= 1;
2975 	    cur_show = (totalclock & 32);
2976             if (cur_show)
2977                 {
2978                 // add a cursor to the end
2979                 sprintf(tmp, "%s_", SaveGameDescr[i]);
2980                 }
2981             else
2982                 strcpy(tmp, SaveGameDescr[i]);
2983 
2984             MNU_DrawString(SD_XSTART + 4, SD_YSTART + (i * SD_YOFF) + 2, tmp, 1, 16);
2985             }
2986         else
2987         if (SaveGameDescr[i][0] != '\0')
2988             {
2989             MNU_DrawString(SD_XSTART + 4, SD_YSTART + (i * SD_YOFF) + 2, SaveGameDescr[i], 1, 16);
2990             }
2991         }
2992 
2993     if (screen_tile != -1)
2994         {
2995         // draw 160x100 save screen
2996         rotatesprite((SS_XSTART + SS_BORDER_SIZE) << 16, (SS_YSTART + SS_BORDER_SIZE) << 16, (1 << 16), 0 + 512, screen_tile,
2997             0, 0, MenuDrawFlags | ROTATE_SPRITE_CORNER | ROTATE_SPRITE_NON_MASK | ROTATE_SPRITE_YFLIP, 0, 0, xdim - 1, ydim - 1);
2998 
2999         // draw info string
3000         MNU_DrawString(SS_XSTART + 13, SS_YSTART + 100 + 10, SaveGameInfo1, 1, 16);
3001         MNU_DrawString(SS_XSTART + 13, SS_YSTART + 100 + 18, SaveGameInfo2, 1, 16);
3002 
3003         if (SavePrompt)
3004             {
3005             MNU_DrawString(SS_XSTART + SS_BORDER_SIZE + 5, SS_YSTART + SS_BORDER_SIZE + 47, "Overwrite previous", 1, 16);
3006             MNU_DrawString(SS_XSTART + SS_BORDER_SIZE + 5, SS_YSTART + SS_BORDER_SIZE + 47 + 12, "  saved game (Y/N)", 1, 16);
3007             }
3008         }
3009     else
3010         {
3011         // draw 160x100 black pic
3012         rotatesprite((SS_XSTART + SS_BORDER_SIZE) << 16, (SS_YSTART + SS_BORDER_SIZE) << 16, (1 << 16), 0, pic_loadsavescreenbak,
3013             0, 0, MenuDrawFlags | ROTATE_SPRITE_CORNER | ROTATE_SPRITE_NON_MASK, 0, 0, xdim - 1, ydim - 1);
3014 
3015         MNU_DrawString(SS_XSTART + SS_BORDER_SIZE + 60, SS_YSTART + SS_BORDER_SIZE + 47, "Empty", 1, 16);
3016         }
3017 
3018 
3019     return (TRUE);
3020     }
3021 
3022 BOOL
MNU_ShareWareCheck(MenuItem * item)3023 MNU_ShareWareCheck(MenuItem *item)
3024     {
3025     if (SW_SHAREWARE) {
3026         SET(item->flags, mf_disabled);
3027     }
3028 
3029     return (TRUE);
3030     }
3031 
3032 BOOL
MNU_CheckUserMap(MenuItem * item)3033 MNU_CheckUserMap(MenuItem *item)
3034     {
3035     if (UserMapName[0] == '\0')
3036         RESET(item->flags, mf_disabled);
3037     else
3038         SET(item->flags, mf_disabled);
3039     return (TRUE);
3040     }
3041 
3042 BOOL
MNU_ShareWareMessage(MenuItem * item)3043 MNU_ShareWareMessage(MenuItem *item)
3044     {
3045     char *extra_text;
3046     short w,h;
3047 
3048     if (SW_SHAREWARE) {
3049         extra_text = "Be sure to call 800-3DREALMS today";
3050         MNU_MeasureString(extra_text, &w, &h);
3051         MNU_DrawString(TEXT_XCENTER(w), 110, extra_text, 1, 16);
3052         extra_text = "and order the game.";
3053         MNU_MeasureString(extra_text, &w, &h);
3054         MNU_DrawString(TEXT_XCENTER(w), 120, extra_text, 1, 16);
3055         extra_text = "You are only playing the first ";
3056         MNU_MeasureString(extra_text, &w, &h);
3057         MNU_DrawString(TEXT_XCENTER(w), 130, extra_text, 1, 16);
3058         extra_text = "four levels, and are missing most";
3059         MNU_MeasureString(extra_text, &w, &h);
3060         MNU_DrawString(TEXT_XCENTER(w), 140, extra_text, 1, 16);
3061         extra_text = "of the game, weapons and monsters.";
3062         MNU_MeasureString(extra_text, &w, &h);
3063         MNU_DrawString(TEXT_XCENTER(w), 150, extra_text, 1, 16);
3064         extra_text = "See the ordering information.";
3065         MNU_MeasureString(extra_text, &w, &h);
3066         MNU_DrawString(TEXT_XCENTER(w), 160, extra_text, 1, 16);
3067         SET(item->flags, mf_disabled);
3068     }
3069     return (TRUE);
3070     }
3071 
3072 BOOL
MNU_SaveGameCheck(MenuItem * item)3073 MNU_SaveGameCheck(MenuItem *item)
3074     {
3075     extern BOOL InMenuLevel;
3076     extern BOOL DemoMode;
3077 
3078     if (CommEnabled || CommPlayers > 1 || DemoMode)
3079         {
3080         SET(item->flags, mf_disabled);
3081         return(TRUE);
3082         }
3083 
3084     if (InMenuLevel)
3085         SET(item->flags, mf_disabled);
3086     else
3087         {
3088         if (TEST(Player[myconnectindex].Flags, PF_DEAD))
3089             SET(item->flags, mf_disabled);
3090         else
3091             RESET(item->flags, mf_disabled);
3092         }
3093 
3094 
3095     return (TRUE);
3096     }
3097 
3098 BOOL
MNU_LoadGameCheck(MenuItem * item)3099 MNU_LoadGameCheck(MenuItem *item)
3100     {
3101     if (CommEnabled || CommPlayers > 1)
3102         {
3103         SET(item->flags, mf_disabled);
3104         return(TRUE);
3105         }
3106 
3107     return (TRUE);
3108     }
3109 
3110 BOOL
MNU_StatCheck(MenuItem * item)3111 MNU_StatCheck(MenuItem *item)
3112     {
3113     if (CommEnabled || CommPlayers > 1)
3114         {
3115         SET(item->flags, mf_disabled);
3116         return(TRUE);
3117         }
3118 
3119     return (TRUE);
3120     }
3121 
3122 BOOL
MNU_HurtTeammateCheck(MenuItem * item)3123 MNU_HurtTeammateCheck(MenuItem *item)
3124     {
3125     switch (gs.NetGameType+1)
3126         {
3127         // deathmatch and deathmatch no respawn
3128         case MULTI_GAME_COMMBAT:
3129         case MULTI_GAME_COMMBAT_NO_RESPAWN:
3130             if (gs.NetTeamPlay)
3131                 RESET(item->flags, mf_disabled);
3132             else
3133                 SET(item->flags, mf_disabled);
3134             break;
3135         // co-op
3136         case MULTI_GAME_COOPERATIVE:
3137             RESET(item->flags, mf_disabled);
3138             break;
3139         }
3140 
3141     return (TRUE);
3142     }
3143 
3144 BOOL
MNU_TeamPlayCheck(MenuItem * item)3145 MNU_TeamPlayCheck(MenuItem *item)
3146     {
3147     switch (gs.NetGameType+1)
3148         {
3149         // co-op
3150         case MULTI_GAME_COOPERATIVE:
3151             SET(item->flags, mf_disabled);
3152             break;
3153         default:
3154             RESET(item->flags, mf_disabled);
3155             break;
3156         }
3157 
3158     return (TRUE);
3159     }
3160 
3161 BOOL
MNU_CoopPlayCheck(MenuItem * item)3162 MNU_CoopPlayCheck(MenuItem *item)
3163     {
3164     switch (gs.NetGameType+1)
3165         {
3166         // co-op
3167         case MULTI_GAME_COOPERATIVE:
3168             SET(item->flags, mf_disabled);
3169             break;
3170         default:
3171             RESET(item->flags, mf_disabled);
3172             break;
3173         }
3174 
3175     return (TRUE);
3176     }
3177 
3178 BOOL
MNU_TeamPlayChange(void)3179 MNU_TeamPlayChange(void)
3180     {
3181     // if team play changes then do a pre process again
3182     MNU_ItemPreProcess(currentmenu);
3183     return (TRUE);
3184     }
3185 
3186 BOOL
MNU_TexFilterCheck(MenuItem * item)3187 MNU_TexFilterCheck(MenuItem *item)
3188     {
3189     if (bpp == 8)
3190         {
3191         SET(item->flags, mf_disabled);
3192         }
3193     else
3194         {
3195         RESET(item->flags, mf_disabled);
3196         }
3197 
3198     return (TRUE);
3199     }
3200 
3201 BOOL
MNU_MouseCheck(MenuItem * item)3202 MNU_MouseCheck(MenuItem *item)
3203     {
3204     if (!CONTROL_MousePresent)
3205         {
3206         SET(item->flags, mf_disabled);
3207         }
3208     else
3209         {
3210         RESET(item->flags, mf_disabled);
3211         }
3212 
3213     return (TRUE);
3214     }
3215 
3216 BOOL
MNU_JoystickCheck(MenuItem * item)3217 MNU_JoystickCheck(MenuItem *item)
3218     {
3219     if (!CONTROL_JoyPresent)
3220         {
3221         SET(item->flags, mf_disabled);
3222         }
3223     else
3224         {
3225         RESET(item->flags, mf_disabled);
3226         }
3227 
3228     return (TRUE);
3229     }
3230 
3231 // This is only called when Enter is pressed
3232 static BOOL
MNU_TryMusicInit(void)3233 MNU_TryMusicInit(void)
3234     {
3235     if (PlaySong(0, RedBookSong[Level], TRUE, FALSE))
3236         {
3237         if (currentmenu->cursor == 0)
3238             MNU_MusicCheck(&currentmenu->items[currentmenu->cursor+1]);
3239         }
3240 
3241     return (TRUE);
3242     }
3243 
3244 BOOL
MNU_MusicCheck(MenuItem * item)3245 MNU_MusicCheck(MenuItem *item)
3246     {
3247     if (SW_SHAREWARE) {
3248         if (MusicDevice < 0 || !MusicInitialized)
3249         {
3250         SET(item->flags, mf_disabled);
3251         }
3252     else
3253         {
3254         RESET(item->flags, mf_disabled);
3255         }
3256     } else {
3257     // Redbook audio stuff
3258     //JBF
3259 	//if (!cdvalid)
3260     //    {
3261     //    SET(item->flags, mf_disabled); // Just don't let CD Redbook ever be invalid!
3262     //    }
3263     //else
3264         {
3265         RESET(item->flags, mf_disabled);
3266         }
3267     }
3268 
3269     return (TRUE);
3270     }
3271 
3272 BOOL
MNU_FxCheck(MenuItem * item)3273 MNU_FxCheck(MenuItem *item)
3274     {
3275     if (FXDevice < 0 || !FxInitialized)
3276         {
3277         SET(item->flags, mf_disabled);
3278         }
3279     else
3280         {
3281         RESET(item->flags, mf_disabled);
3282         }
3283 
3284     return (TRUE);
3285     }
3286 
3287 BOOL
MNU_MusicFxCheck(MenuItem * item)3288 MNU_MusicFxCheck(MenuItem *item)
3289     {
3290     if (FXDevice < 0 && MusicDevice < 0)
3291         {
3292         SET(item->flags, mf_disabled);
3293         }
3294     else
3295         {
3296         RESET(item->flags, mf_disabled);
3297         }
3298 
3299     return (TRUE);
3300     }
3301 
3302 BOOL
MNU_ApplyVideoModeSettings(void)3303 MNU_ApplyVideoModeSettings(void)
3304     {
3305     int lastx, lasty, lastbpp, lastfs;
3306     int newx, newy, newbpp, newfs;
3307 
3308     lastx = xdim; lasty = ydim; lastbpp = bpp; lastfs = fullscreen;
3309     newx   = validresolutions[ slidersettings[sldr_videores] ].x;
3310     newy   = validresolutions[ slidersettings[sldr_videores] ].y;
3311     newbpp = validbpps[ slidersettings[sldr_videobpp] ];
3312     newfs  = buttonsettings[btn_videofs];
3313 
3314     if (lastx == newx && lasty == newy && lastbpp == newbpp && lastfs == newfs) return FALSE;
3315 
3316     if (setgamemode(newfs, newx, newy, newbpp))
3317         setgamemode(lastfs, lastx, lasty, lastbpp);
3318     else
3319         {
3320         ScreenMode = newfs;
3321         ScreenWidth = newx;
3322         ScreenHeight = newy;
3323         ScreenBPP = newbpp;
3324 
3325         SetupAspectRatio();
3326         SetRedrawScreen(Player + myconnectindex);
3327         }
3328     MNU_ItemPreProcess(currentmenu);
3329     return FALSE;
3330     }
3331 
3332 ////////////////////////////////////////////////
3333 // Do a toggle button
3334 ////////////////////////////////////////////////
3335 void
MNU_DoButton(MenuItem_p item,BOOL draw)3336 MNU_DoButton(MenuItem_p item, BOOL draw)
3337     {
3338     int x, y;
3339     BOOL state;
3340     int last_value;
3341     short shade = MENU_SHADE_DEFAULT;
3342     extern char LevelSong[];
3343     char *extra_text = NULL;
3344     PLAYERp pp = &Player[myconnectindex];
3345     int button_x,zero=0;
3346     int handle=0;
3347     extern BOOL MusicInitialized,FxInitialized;
3348 
3349     button_x = OPT_XSIDE;
3350 
3351     x = item->x;
3352     y = item->y;
3353 
3354     if (TEST(item->flags, mf_disabled))
3355         {
3356         shade = MENU_SHADE_INACTIVE;
3357         }
3358 
3359     if (!draw)
3360         {
3361         switch (item->button)
3362             {
3363         case btn_nuke:
3364             gs.NetNuke = state = buttonsettings[item->button];
3365             break;
3366         case btn_voxels:
3367             gs.Voxels = state = buttonsettings[item->button];
3368             break;
3369         case btn_stats:
3370             gs.Stats = state = buttonsettings[item->button];
3371             break;
3372         case btn_markers:
3373             gs.NetSpawnMarkers = state = buttonsettings[item->button];
3374             break;
3375         case btn_teamplay:
3376             gs.NetTeamPlay = state = buttonsettings[item->button];
3377             break;
3378         case btn_friendlyfire:
3379             gs.NetHurtTeammate = state = buttonsettings[item->button];
3380             break;
3381         case btn_crosshair:
3382             gs.Crosshair = state = buttonsettings[item->button];
3383             break;
3384         case btn_auto_aim:
3385             last_value = gs.AutoAim;
3386             gs.AutoAim = state = buttonsettings[item->button];
3387             if (gs.AutoAim != last_value)
3388                 MenuButtonAutoAim = TRUE;
3389             break;
3390         case btn_messages:
3391             gs.Messages = state = buttonsettings[item->button];
3392             break;
3393         case btn_auto_run:
3394             last_value = gs.AutoRun;
3395             gs.AutoRun = state = buttonsettings[item->button];
3396             if (gs.AutoRun != last_value)
3397                 MenuButtonAutoRun = TRUE;
3398             break;
3399         case btn_mouse_aim:
3400             last_value = gs.MouseAimingType;
3401             gs.MouseAimingType = state = buttonsettings[item->button];
3402             if (gs.MouseAimingType != last_value)
3403                 {
3404                 //RESET(pp->Flags, PF_MOUSE_AIMING_ON);
3405                 //gs.MouseAimingOn = FALSE;
3406                 }
3407             //extra_text = gs.MouseAimingType ? "Momentary" : "Toggle";
3408             break;
3409         case btn_mouse_invert:
3410             gs.MouseInvert = state = buttonsettings[item->button];
3411             break;
3412 //        case btn_bobbing:
3413 //            gs.Bobbing = state = buttonsettings[item->button];
3414 //            break;
3415         case btn_sound:
3416 
3417             if (!FxInitialized)
3418                  break;
3419 
3420             last_value = gs.FxOn;
3421             gs.FxOn = state = buttonsettings[item->button];
3422             if (gs.FxOn != last_value)
3423                 {
3424                 if (!gs.FxOn)
3425                     StopFX();
3426                 }
3427             break;
3428         case btn_music:
3429             last_value = gs.MusicOn;
3430             gs.MusicOn = state = buttonsettings[item->button];
3431             if (gs.MusicOn != last_value)
3432                 {
3433                 BOOL bak;
3434 
3435                 if (gs.MusicOn)
3436                     {
3437                     bak = DemoMode;
3438                     PlaySong(LevelSong, RedBookSong[Level], TRUE, TRUE);
3439                     DemoMode = bak;
3440                     }
3441                 else
3442                     {
3443                     bak = DemoMode;
3444                     StopSong();
3445                     DemoMode = bak;
3446 
3447                     if (SW_SHAREWARE)
3448 					    {
3449                         handle = PlaySound(DIGI_NOLIKEMUSIC,&zero,&zero,&zero,v3df_none);
3450 
3451                         if (handle >= FX_Ok)
3452                             while(FX_SoundActive(handle))
3453                                 handleevents();
3454                         }
3455 					}
3456                 }
3457             break;
3458         case btn_talking:
3459             gs.Talking = state = buttonsettings[item->button];
3460             break;
3461         case btn_playcd:
3462             last_value = gs.PlayCD;
3463             gs.PlayCD = state = buttonsettings[item->button];
3464             break;
3465         case btn_ambience:
3466             last_value = gs.Ambient;
3467             gs.Ambient = state = buttonsettings[item->button];
3468             if (gs.Ambient != last_value)
3469                 {
3470                 if(!InMenuLevel)
3471                     {
3472                     if (gs.Ambient)
3473                         StartAmbientSound();
3474                     else
3475                         StopAmbientSound();
3476                     }
3477                 }
3478             break;
3479         case btn_flipstereo:
3480             last_value = gs.FlipStereo;
3481             gs.FlipStereo = state = buttonsettings[item->button];
3482             if (gs.FlipStereo != last_value)
3483                 FlipStereo();
3484             break;
3485         case btn_shadows:
3486             gs.Shadows = state = buttonsettings[item->button];
3487             break;
3488 
3489         case btn_parental:
3490             if(gs.Password[0] != '\0' && gs.ParentalLock == TRUE)
3491             {
3492                 if(passwordvalid)
3493                 {
3494                     state = buttonsettings[btn_parental] = gs.ParentalLock = FALSE;
3495                     if (!InMenuLevel)
3496                     JS_ToggleLockouts();
3497                 } else
3498                     {
3499                     state = buttonsettings[btn_parental] = gs.ParentalLock = TRUE;
3500                     MenuInputMode = TRUE;
3501                     memset(MessageInputString, '\0', sizeof(MessageInputString));
3502                     KB_ClearKeysDown();
3503                     KB_FlushKeyboardQueue();
3504                     }
3505             } else
3506             {
3507                 gs.ParentalLock = state = buttonsettings[item->button];
3508                 if (!InMenuLevel)
3509                 JS_ToggleLockouts();
3510             }
3511             break;
3512 
3513         case btn_videofs:
3514             {
3515             int lastx, lasty, lastbpp, newoffset, i;
3516 
3517             state = buttonsettings[btn_videofs];
3518 
3519             lastx   = validresolutions[ slidersettings[sldr_videores] ].x;
3520             lasty   = validresolutions[ slidersettings[sldr_videores] ].y;
3521             lastbpp = validbpps[ slidersettings[sldr_videobpp] ];
3522             UpdateValidModes(lastbpp, buttonsettings[btn_videofs]);
3523 
3524             // check if the last bpp is still a valid choice
3525             for (i=0; i<numvalidbpps; i++)
3526                 if (validbpps[i] == lastbpp) break;
3527             if (i == numvalidbpps)
3528                 {
3529                 // it wasn't
3530                 slidersettings[sldr_videobpp] = 0;
3531                 lastbpp = validbpps[0];
3532                 UpdateValidModes(lastbpp, buttonsettings[btn_videofs]);
3533                 }
3534             else
3535                 slidersettings[sldr_videobpp] = i;
3536 
3537             // find the nearest resolution to the one last selected
3538             newoffset = 0;
3539             for (i=0; i<numvalidresolutions; i++)
3540                 {
3541                 if (abs(lastx * lasty - validresolutions[i].x         * validresolutions[i].y) <
3542                     abs(lastx * lasty - validresolutions[newoffset].x * validresolutions[newoffset].y))
3543                         newoffset = i;
3544                 }
3545             slidersettings[sldr_videores] = newoffset;
3546             }
3547             break;
3548 
3549         case btn_texfilter:
3550             {
3551             state = buttonsettings[item->button];
3552 #if USE_POLYMOST && USE_OPENGL
3553             if (state != (gltexfiltermode & 1))
3554                 {
3555                 // Preserve the mipmap level, toggling the nearest/linear filter.
3556                 gltexfiltermode = (gltexfiltermode & ~1) | state;
3557                 gltexapplyprops();
3558                 }
3559 #endif
3560             }
3561             break;
3562 
3563         case btn_joyaxis_invert:
3564             {
3565             int newscale;
3566 
3567             state = buttonsettings[item->button];
3568             newscale = klabs(JoystickAnalogScale[JoystickAxisPage]);
3569             if (state)
3570                 newscale = -newscale;
3571             JoystickAnalogScale[JoystickAxisPage] = newscale;
3572             CONTROL_SetAnalogAxisScale(JoystickAxisPage, newscale, controldevice_joystick);
3573             break;
3574             }
3575 
3576         default:
3577             state = buttonsettings[item->button];
3578             break;
3579             }
3580         }
3581 
3582     if (!draw)
3583         return;
3584 
3585     switch (item->button)
3586         {
3587         case btn_mouse_aim:
3588             extra_text = gs.MouseAimingType ? "Momentary" : "Toggle";
3589             break;
3590 	default: break;
3591         }
3592 
3593 
3594     state = buttonsettings[item->button];
3595 
3596     // Draw the button
3597     if (item->text)
3598         {
3599         if (state)
3600             {
3601             // set
3602             rotatesprite(button_x << 16, y << 16, MZ, 0, pic_radiobuttn2, shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
3603             }
3604         else
3605             {
3606             // not set
3607             rotatesprite(button_x << 16, y << 16, MZ, 0, pic_radiobuttn1, shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
3608             }
3609 
3610         MenuTextShade = shade;
3611         MNU_DrawString(x, y, item->text, MenuTextShade, 16);
3612 
3613         if (extra_text)
3614             MNU_DrawString(OPT_XSIDE + tilesizx[pic_radiobuttn1] + 6, y, extra_text, MenuTextShade, 16);
3615         MenuTextShade = MENU_SHADE_DEFAULT;
3616         }
3617     else
3618         {
3619         if (state)
3620             rotatesprite(x << 16, y << 16, MZ, 0, pic_radiobuttn2, 2, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
3621         else
3622             rotatesprite(x << 16, y << 16, MZ, 0, pic_radiobuttn1, 2, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
3623 
3624         x += tilesizx[pic_radiobuttn1] + 4;
3625 
3626         // Draw the menu item text
3627         rotatesprite(x << 16, y << 16, MZ, 0, item->pic, 2, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
3628         }
3629 
3630     }
3631 
3632 //char *gametype[] = {"War [Respawn]","Cooperative","War [No Respawn]"};
3633 char *gametype[] = {"WangBang (spawn)","WangBang (no spawn)","Cooperative"};
3634 char *playercolors[] = {"Brown","Gray","Purple","Red","Yellow","Olive","Green","Blue"};
3635 char *monsterskills[] = {"No Monsters","Easy","Normal","Hard","Insane!"};
3636 
3637 void
MNU_DoSlider(short dir,MenuItem_p item,BOOL draw)3638 MNU_DoSlider(short dir, MenuItem_p item, BOOL draw)
3639     {
3640     short offset, i, barwidth;
3641     int x, y, knobx;
3642     short shade = MENU_SHADE_DEFAULT;
3643     char *extra_text=NULL;
3644     char tmp_text[256];
3645 
3646     memset(tmp_text,0,256);
3647 
3648     if (TEST(item->flags, mf_disabled))
3649         {
3650         shade = MENU_SHADE_INACTIVE;
3651         dir = 0;
3652         }
3653 
3654     switch (item->slider)
3655         {
3656     case sldr_mouse:
3657         barwidth = SLDR_MOUSESENSEMAX;
3658         offset = slidersettings[sldr_mouse] += dir;
3659 
3660         if (TEST(item->flags, mf_disabled))
3661             break;
3662 
3663         offset = max(offset, 0);
3664         offset = min(offset, SLDR_MOUSESENSEMAX-1);
3665 
3666         slidersettings[sldr_mouse] = offset;
3667 
3668         gs.MouseSpeed = offset * (MOUSE_SENS_MAX_VALUE/SLDR_MOUSESENSEMAX);
3669         CONTROL_SetMouseSensitivity(gs.MouseSpeed);
3670         break;
3671 
3672     case sldr_sndfxvolume:
3673         barwidth = SLDR_SNDFXVOLMAX;
3674         offset = slidersettings[sldr_sndfxvolume] += dir;
3675 
3676         if (TEST(item->flags, mf_disabled))
3677             break;
3678 
3679         offset = max(offset, 0);
3680         offset = min(offset, SLDR_SNDFXVOLMAX-1);
3681 
3682         slidersettings[sldr_sndfxvolume] = offset;
3683         gs.SoundVolume = FX_MIN + (offset * VOL_MUL);
3684         FX_SetVolume(gs.SoundVolume);
3685         break;
3686 
3687     case sldr_musicvolume:
3688         barwidth = SLDR_MUSICVOLMAX;
3689         offset = slidersettings[sldr_musicvolume] += dir;
3690         if (TEST(item->flags, mf_disabled))
3691             break;
3692 
3693         offset = max(offset, 0);
3694         offset = min(offset, SLDR_MUSICVOLMAX-1);
3695 
3696         slidersettings[sldr_musicvolume] = offset;
3697         gs.MusicVolume = MUSIC_MIN + (offset * VOL_MUL);
3698 		SetSongVolume(gs.MusicVolume);
3699         break;
3700 
3701     case sldr_scrsize:
3702         {
3703         short bnum;
3704 
3705         barwidth = SLDR_SCRSIZEMAX;
3706         slidersettings[sldr_scrsize] = gs.BorderNum;
3707         slidersettings[sldr_scrsize] -= dir;
3708         offset = slidersettings[sldr_scrsize];
3709 
3710         if (TEST(item->flags, mf_disabled))
3711             break;
3712 
3713     ////DSPRINTF(ds,"BorderNum %d",gs.BorderNum);
3714     //MONO_PRINT(ds);
3715 
3716         offset = max(offset, 0);
3717         offset = min(offset, SLDR_SCRSIZEMAX - 1);
3718 
3719         bnum = offset;
3720 
3721         offset = (SLDR_SCRSIZEMAX-1) - offset;
3722         slidersettings[sldr_scrsize] = offset;
3723 
3724         if (!BorderAdjust)
3725             gs.BorderNum = bnum;
3726 
3727         SetBorder(&Player[myconnectindex], bnum);
3728 
3729         break;
3730         }
3731 
3732     case sldr_brightness:
3733         barwidth = SLDR_BRIGHTNESSMAX;
3734         offset = slidersettings[sldr_brightness] += dir;
3735 
3736         if (TEST(item->flags, mf_disabled))
3737             break;
3738 
3739         offset = max(offset, 0);
3740         offset = min(offset, SLDR_BRIGHTNESSMAX - 1);
3741         slidersettings[sldr_brightness] = offset;
3742 
3743         if (gs.Brightness != offset)
3744             {
3745             gs.Brightness = offset;
3746             COVERsetbrightness(gs.Brightness,&palette_data[0][0]);
3747             }
3748         break;
3749 
3750     case sldr_bordertile:
3751         barwidth = SLDR_BORDERTILEMAX;
3752         offset = slidersettings[sldr_bordertile] += dir;
3753 
3754         if (TEST(item->flags, mf_disabled))
3755             break;
3756 
3757         offset = max(offset, 0);
3758         offset = min(offset, SLDR_BORDERTILEMAX - 1);
3759         slidersettings[sldr_bordertile] = offset;
3760 
3761         if (gs.BorderTile != offset)
3762             {
3763             gs.BorderTile = offset;
3764 
3765             SetRedrawScreen(&Player[myconnectindex]);
3766             }
3767         break;
3768 
3769     case sldr_panelscale:
3770         barwidth = SLDR_PANELSCALEMAX;
3771         offset = slidersettings[sldr_panelscale] += dir;
3772 
3773         if (TEST(item->flags, mf_disabled))
3774             break;
3775 
3776         offset = max(offset, 0);
3777         offset = min(offset, SLDR_PANELSCALEMAX - 1);
3778         slidersettings[sldr_panelscale] = offset;
3779 
3780         if (gs.PanelScale != offset+1)
3781             {
3782             gs.PanelScale = offset+1;
3783             PanelScale = gs.PanelScale<<13;
3784             }
3785         break;
3786 
3787     case sldr_gametype:
3788         barwidth = SLDR_GAMETYPEMAX;
3789         offset = slidersettings[sldr_gametype] += dir;
3790 
3791         if (TEST(item->flags, mf_disabled))
3792             break;
3793 
3794         offset = max(offset, 0);
3795         offset = min(offset, SLDR_GAMETYPEMAX - 1);
3796         slidersettings[sldr_gametype] = offset;
3797 
3798         extra_text = gametype[offset];
3799         MNU_DrawString(OPT_XSIDE, item->y, extra_text, 1, 16);
3800         gs.NetGameType = offset;
3801         // friendly fire menu
3802         MNU_ItemPreProcess(currentmenu);
3803         break;
3804 
3805     case sldr_netlevel:
3806         barwidth = SLDR_NETLEVELMAX;
3807         offset = slidersettings[sldr_netlevel] += dir;
3808 
3809         if (TEST(item->flags, mf_disabled))
3810             break;
3811 
3812         offset = max(offset, 0);
3813         offset = min(offset, SLDR_NETLEVELMAX - 1);
3814         slidersettings[sldr_netlevel] = offset;
3815 
3816         // Show the currently selected level on next line
3817         //extra_text = MNU_LevelName[offset];
3818         //MNU_DrawString(OPT_XS, item->y+10, extra_text, 1, 16);
3819 	sprintf(tmp_text, "L%02d: %s", offset+1, LevelInfo[offset+1].Description);
3820         MNU_DrawString(OPT_XS, item->y+10, tmp_text, 1, 16);
3821         gs.NetLevel = offset;
3822         break;
3823 
3824     case sldr_monsters:
3825         barwidth = SLDR_MONSTERSMAX;
3826         offset = slidersettings[sldr_monsters] += dir;
3827 
3828         if (TEST(item->flags, mf_disabled))
3829             break;
3830 
3831         offset = max(offset, 0);
3832         offset = min(offset, SLDR_MONSTERSMAX - 1);
3833         slidersettings[sldr_monsters] = offset;
3834 
3835         extra_text = monsterskills[offset];
3836         MNU_DrawString(OPT_XSIDE+54, item->y, extra_text, 1, 16);
3837         gs.NetMonsters = offset;
3838         break;
3839 
3840     case sldr_killlimit:
3841         barwidth = SLDR_KILLLIMITMAX;
3842         offset = slidersettings[sldr_killlimit] += dir;
3843 
3844         if (TEST(item->flags, mf_disabled))
3845             break;
3846 
3847         offset = max(offset, 0);
3848         offset = min(offset, SLDR_KILLLIMITMAX - 1);
3849         slidersettings[sldr_killlimit] = offset;
3850 
3851         if(offset == 0)
3852             {
3853             strcpy(tmp_text,"Infinite\n");
3854             }
3855         else
3856             {
3857             sprintf(tmp_text,"%d",offset*10);
3858             //itoa(offset*10,tmp_text,10);
3859             }
3860         MNU_DrawString(OPT_XSIDE+101, item->y, tmp_text, 1, 16);
3861         gs.NetKillLimit = offset;
3862         break;
3863 
3864     case sldr_timelimit:
3865         barwidth = SLDR_TIMELIMITMAX;
3866         offset = slidersettings[sldr_timelimit] += dir;
3867 
3868         if (TEST(item->flags, mf_disabled))
3869             break;
3870 
3871         offset = max(offset, 0);
3872         offset = min(offset, SLDR_TIMELIMITMAX - 1);
3873         slidersettings[sldr_timelimit] = offset;
3874 
3875         if(offset == 0)
3876             {
3877             strcpy(tmp_text,"Infinite\n");
3878             }
3879         else
3880             {
3881             sprintf(tmp_text,"%d Minutes\n",TimeLimitTable[offset]);
3882             }
3883 
3884         MNU_DrawString(OPT_XSIDE+86, item->y, tmp_text, 1, 16);
3885         gs.NetTimeLimit = offset;
3886         break;
3887 
3888     case sldr_playercolor:
3889         barwidth = SLDR_PLAYERCOLORMAX;
3890         offset = slidersettings[sldr_playercolor] += dir;
3891 
3892         if (TEST(item->flags, mf_disabled))
3893             break;
3894 
3895         offset = max(offset, 0);
3896         offset = min(offset, SLDR_PLAYERCOLORMAX - 1);
3897         slidersettings[sldr_playercolor] = offset;
3898 
3899         extra_text = playercolors[offset];
3900         MNU_DrawString(OPT_XSIDE+78, item->y, extra_text, 1, PALETTE_PLAYER0+offset);
3901         SendMulitNameChange(NULL, offset);
3902         break;
3903 
3904     case sldr_videores:
3905 	{
3906 		offset = max(0,min(slidersettings[sldr_videores] + dir, numvalidresolutions-1));
3907 		barwidth = numvalidresolutions;
3908 
3909 		if (TEST(item->flags, mf_disabled))
3910 			break;
3911 
3912 		slidersettings[sldr_videores] = offset;
3913 
3914 		sprintf(tmp_text, "%dx%d", validresolutions[offset].x, validresolutions[offset].y);
3915 		MNU_DrawString(OPT_XSIDE, item->y+OPT_YINC, tmp_text, 1, 16);
3916 	} break;
3917 
3918     case sldr_videobpp:
3919 	{
3920 		offset = max(0,min(slidersettings[sldr_videobpp] + dir, numvalidbpps-1));
3921 		barwidth = numvalidbpps;
3922 
3923 		if (TEST(item->flags, mf_disabled))
3924 			break;
3925 
3926 		if (slidersettings[sldr_videobpp] != offset) {
3927 			int lastx, lasty, newoffset, i;
3928 
3929 			slidersettings[sldr_videobpp] = offset;
3930 
3931 			// find the nearest resolution to the one last selected
3932 			lastx = validresolutions[ slidersettings[sldr_videores] ].x;
3933 			lasty = validresolutions[ slidersettings[sldr_videores] ].y;
3934 			UpdateValidModes(validbpps[offset], buttonsettings[btn_videofs]);
3935 			newoffset = 0;
3936 			for (i=0; i<numvalidresolutions; i++) {
3937 				if (abs(lastx * lasty - validresolutions[i].x         * validresolutions[i].y) <
3938 				    abs(lastx * lasty - validresolutions[newoffset].x * validresolutions[newoffset].y))
3939 					newoffset = i;
3940 			}
3941 			slidersettings[sldr_videores] = newoffset;
3942 		}
3943 
3944 		sprintf(tmp_text, "%d bpp", validbpps[offset]);
3945 		MNU_DrawString(OPT_XSIDE+tilesizx[pic_slidelend]+tilesizx[pic_sliderend]+(barwidth+1)*tilesizx[pic_slidebar], item->y, tmp_text, 1, 16);
3946 	} break;
3947 
3948     case sldr_mousescalex:
3949     case sldr_mousescaley:
3950         barwidth = 8+1+8;
3951         offset = slidersettings[item->slider] + dir;
3952 
3953         if (TEST(item->flags, mf_disabled))
3954             break;
3955 
3956         offset = max(offset, 0);
3957         offset = min(offset, barwidth-1);
3958 
3959         if (slidersettings[item->slider] != offset)
3960             {
3961             slidersettings[item->slider] = offset;
3962             MouseAnalogScale[item->slider - sldr_mousescalex] = offset<<13;
3963             CONTROL_SetAnalogAxisScale(item->slider - sldr_mousescalex, offset<<13, controldevice_mouse);
3964             }
3965 
3966         sprintf(tmp_text, "%.2f", (float)(slidersettings[item->slider]<<13) / 65535.f);
3967         MNU_DrawSmallString(OPT_XSIDE+tilesizx[pic_slidelend]+tilesizx[pic_sliderend]+(MAX_SLDR_WIDTH+1)*tilesizx[pic_slidebar], item->y+4, tmp_text, 1, 16);
3968         break;
3969 
3970     case sldr_joyaxisscale:
3971         barwidth = 8+1+8;
3972         offset = slidersettings[item->slider] + dir;
3973 
3974         if (TEST(item->flags, mf_disabled))
3975             break;
3976 
3977         offset = max(offset, 0);
3978         offset = min(offset, barwidth-1);
3979 
3980         if (slidersettings[item->slider] != offset)
3981             {
3982             int newscale;
3983 
3984             slidersettings[item->slider] = offset;
3985             newscale = offset<<13;
3986             if (buttonsettings[btn_joyaxis_invert])
3987                 newscale = -newscale;
3988             JoystickAnalogScale[JoystickAxisPage] = newscale;
3989             CONTROL_SetAnalogAxisScale(JoystickAxisPage, newscale, controldevice_joystick);
3990             }
3991 
3992         sprintf(tmp_text, "%.2f", (float)(slidersettings[item->slider]<<13) / 65535.f);
3993         MNU_DrawSmallString(OPT_XSIDE+tilesizx[pic_slidelend]+tilesizx[pic_sliderend]+(MAX_SLDR_WIDTH+1)*tilesizx[pic_slidebar], item->y+4, tmp_text, 1, 16);
3994         break;
3995 
3996     case sldr_joyaxisanalog:
3997         {
3998         const char *p;
3999 
4000         barwidth = MNU_ControlAxisOffset(analog_maxtype);
4001         offset = slidersettings[item->slider] + dir;
4002 
4003         if (TEST(item->flags, mf_disabled))
4004             break;
4005 
4006         offset = max(offset, 0);
4007         offset = min(offset, barwidth-1);
4008 
4009         if (slidersettings[item->slider] != offset)
4010             {
4011             slidersettings[item->slider] = offset;
4012             JoystickAnalogAxes[JoystickAxisPage] = MNU_ControlAxisNum(offset);
4013             CONTROL_MapAnalogAxis(JoystickAxisPage, MNU_ControlAxisNum(offset), controldevice_joystick);
4014             }
4015 
4016         p = CONFIG_AnalogNumToName(MNU_ControlAxisNum(offset));
4017         if (!p)
4018             {
4019             p = "-";
4020             }
4021         else
4022             {
4023             // Skip past the "analog_" prefix.
4024             while (*p != 0 && *p != '_') p++;
4025             if (*p == '_') p++;
4026             }
4027         MNU_DrawSmallString(OPT_XSIDE+tilesizx[pic_slidelend]+tilesizx[pic_sliderend]+(barwidth+1)*tilesizx[pic_slidebar], item->y+4, p, 1, 16);
4028         }
4029         break;
4030 
4031     case sldr_joyaxisdead:
4032     case sldr_joyaxissatur:
4033         barwidth = (32768>>10)+1;
4034         offset = slidersettings[item->slider] + dir;
4035 
4036         if (TEST(item->flags, mf_disabled))
4037             break;
4038 
4039         offset = max(offset, 0);
4040         offset = min(offset, barwidth-1);
4041 
4042         if (slidersettings[item->slider] != offset)
4043             {
4044             slidersettings[item->slider] = offset;
4045             if (item->slider == sldr_joyaxisdead)
4046                 {
4047                 JoystickAnalogDead[JoystickAxisPage] = min((offset<<10), 32767);
4048                 CONTROL_SetJoyAxisDead(JoystickAxisPage, JoystickAnalogDead[JoystickAxisPage]);
4049                 }
4050             else
4051                 {
4052                 JoystickAnalogSaturate[JoystickAxisPage] = min((offset<<10), 32767);
4053                 CONTROL_SetJoyAxisSaturate(JoystickAxisPage, JoystickAnalogSaturate[JoystickAxisPage]);
4054                 }
4055             }
4056 
4057         sprintf(tmp_text, "%.2f", (float)(slidersettings[item->slider]<<10) / 32767.f);
4058         MNU_DrawSmallString(OPT_XSIDE+tilesizx[pic_slidelend]+tilesizx[pic_sliderend]+(MAX_SLDR_WIDTH+1)*tilesizx[pic_slidebar], item->y+4, tmp_text, 1, 16);
4059         break;
4060 
4061     default:
4062         return;
4063         }
4064 
4065     if (!draw)
4066         return;
4067 
4068     // Now draw it
4069     item++;
4070     x = item->x;
4071     y = item->y;
4072 
4073     // Draw the left end cap of the bar
4074     rotatesprite(x << 16, y << 16, MZ, 0, pic_slidelend, shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
4075 
4076     x += tilesizx[pic_slidelend];
4077     knobx = x;
4078 
4079     // Draw the in between sections
4080     for (i = 0; i < min(barwidth,MAX_SLDR_WIDTH); i++)
4081         {
4082         rotatesprite(x << 16, y << 16, MZ, 0, pic_slidebar, shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
4083         x += tilesizx[pic_slidebar];
4084         }
4085 
4086     // Draw the right end cap
4087     rotatesprite(x << 16, y << 16, MZ, 0, pic_sliderend, shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
4088 
4089     // Draw the knob, compressing the X coordinate if the bar is too wide
4090     if (barwidth > MAX_SLDR_WIDTH)
4091         {
4092 	knobx += offset * (MAX_SLDR_WIDTH*tilesizx[pic_slidebar]-tilesizx[pic_sliderknob]) / (barwidth-1);
4093         }
4094     else
4095         {
4096         knobx += tilesizx[pic_slidebar] * offset;
4097         }
4098     rotatesprite(knobx << 16, (y + 2) << 16, MZ, 0, pic_sliderknob, shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
4099     }
4100 
4101 ////////////////////////////////////////////////
4102 // Start up menu array
4103 ////////////////////////////////////////////////
4104 static void
MNU_SetupMenu(void)4105 MNU_SetupMenu(void)
4106     {
4107     MenuGroup *rootmenu;
4108 
4109     static MenuGroup *rootmenulist[] =
4110         {
4111         &maingroup,
4112         &SaveGameGroup,
4113         &LoadGameGroup,
4114         &soundgroup,
4115         &optiongroup,
4116         &quickloadgroup,
4117         &quitgroup,
4118         &ordergroup,
4119         &episodegroup,
4120         };
4121 
4122     rootmenu = rootmenulist[ControlPanelType];
4123     ASSERT(ControlPanelType < ct_max);
4124 
4125     menuarrayptr = 0;
4126     menuarray[0] = currentmenu = rootmenu;
4127 
4128     // Get currently held input state and invalidate it.
4129     CONTROL_GetUserInput(&mnu_input);
4130     CONTROL_ClearUserInput(&mnu_input);
4131 
4132     mnu_input_buffered.button0 = mnu_input_buffered.button1 = FALSE;
4133     mnu_input_buffered.dir = dir_None;
4134     order_input_buffered.button0 = order_input_buffered.button1 = FALSE;
4135     order_input_buffered.dir = dir_None;
4136     ResetKeys();
4137 
4138     // custom cust_callback starts out as null
4139     cust_callback = NULL;
4140 
4141     // for QuitCustom and QuickLoadCustom
4142     if (currentmenu->items == NULL)
4143         {
4144         if (currentmenu->draw_custom)
4145             currentmenu->draw_custom(uc_setup, NULL);
4146         }
4147 
4148     if(ControlPanelType == ct_mainmenu)
4149         currentmenu->cursor = 0;
4150 
4151     // disable any items necessary
4152     MNU_ItemPreProcess(currentmenu);
4153     }
4154 
4155 ////////////////////////////////////////////////
4156 // Draw an item
4157 ////////////////////////////////////////////////
4158 /*
4159 static void
4160 MNU_ClearFlags(MenuGroup * node)
4161     {
4162     MenuItem *i;
4163 
4164     if (!node->items)
4165         return;
4166 
4167     for (i = node->items; i->type != mt_none; i++)
4168         {
4169         i->flags &= ~MenuSelectFlags;
4170         if (i->child)
4171             MNU_ClearFlags((MenuGroup *) i->child);
4172         }
4173     }
4174 */
4175 ////////////////////////////////////////////////
4176 // Pop a group off the menu stack
4177 ////////////////////////////////////////////////
4178 static void
MNU_PopGroup(void)4179 MNU_PopGroup(void)
4180     {
4181     if (!menuarrayptr)
4182         return;
4183 
4184     currentmenu = menuarray[--menuarrayptr];
4185 
4186     SetFragBar(Player + myconnectindex);
4187     //PanelRefresh(Player + myconnectindex);
4188     }
4189 
4190 ////////////////////////////////////////////////
4191 // Push a group on to the menu stack
4192 ////////////////////////////////////////////////
4193 static void
MNU_PushGroup(MenuGroup * node)4194 MNU_PushGroup(MenuGroup * node)
4195     {
4196     if (menuarrayptr == MaxLayers - 1)
4197         return;
4198 
4199     currentmenu = menuarray[++menuarrayptr] = node;
4200 
4201     SetFragBar(Player + myconnectindex);
4202     }
4203 
4204 ////////////////////////////////////////////////
4205 // Setup a new menu subgroup
4206 ////////////////////////////////////////////////
4207 static void
MNU_SetupGroup(void)4208 MNU_SetupGroup(void)
4209     {
4210     MNU_SelectItem(currentmenu, currentmenu->cursor, FALSE);
4211     MNU_DrawMenu();
4212     }
4213 
4214 static VOID
MNU_ItemPreProcess(MenuGroup * group)4215 MNU_ItemPreProcess(MenuGroup * group)
4216     {
4217     MenuItem *item;
4218 
4219     if (!group->items)
4220         return;
4221 
4222     // process all items when going down a level
4223     // to see if anything is disabled
4224     for (item = group->items; item->type != mt_none; item++)
4225         {
4226         if (item->preprocess)
4227             item->preprocess(item);
4228         }
4229     }
4230 
4231 VOID
MNU_ItemPostProcess(MenuGroup * group)4232 MNU_ItemPostProcess(MenuGroup * group)
4233     {
4234     MenuItem *item;
4235     int zero = 0;
4236 
4237     if (!group->items)
4238         return;
4239 
4240     item = &currentmenu->items[currentmenu->cursor];
4241 
4242     if (item->postprocess)
4243         {
4244         item->postprocess(item);
4245         }
4246     }
4247 
4248 ////////////////////////////////////////////////
4249 // Go to next menu subgroup
4250 ////////////////////////////////////////////////
4251 static void
MNU_DownLevel(MenuGroup * group)4252 MNU_DownLevel(MenuGroup * group)
4253     {
4254 
4255     if (!group)
4256         {
4257         TerminateGame();
4258         printf("MNU_DownLevel() - NULL card\n");
4259         exit(0);
4260         }
4261 
4262     MNU_PushGroup(group);
4263 
4264     if (group->items == NULL)
4265         {
4266         if (group->draw_custom && group->draw_custom(uc_setup, NULL))
4267             MNU_PopGroup();
4268         }
4269 
4270     MNU_ItemPreProcess(currentmenu);
4271 
4272     MNU_SetupGroup();
4273 
4274     SetRedrawScreen(&Player[myconnectindex]);
4275     }
4276 
4277 ////////////////////////////////////////////////
4278 // Go to previous menu subgroup
4279 ////////////////////////////////////////////////
4280 static void
MNU_UpLevel(void)4281 MNU_UpLevel(void)
4282     {
4283     int zero = 0;
4284     static int handle1=0;
4285     // if run out of menus then EXIT
4286     if (!menuarrayptr)
4287         {
4288         if(!FX_SoundActive(handle1))
4289             handle1 = PlaySound(DIGI_STARCLINK,&zero,&zero,&zero,v3df_dontpan);
4290         ExitMenus();
4291         return;
4292         }
4293 
4294     if (currentmenu->items)
4295         currentmenu->items[currentmenu->cursor].flags &= ~mf_selected;
4296     MNU_PopGroup();
4297     MNU_SetupGroup();
4298 
4299     SetRedrawScreen(&Player[myconnectindex]);
4300     }
4301 
4302 ////////////////////////////////////////////////
4303 // Do a menu item action
4304 ////////////////////////////////////////////////
4305 static void
MNU_DoItem(void)4306 MNU_DoItem(void)
4307     {
4308     MenuItem *item;
4309 
4310     item = &currentmenu->items[currentmenu->cursor];
4311     if (!item) return;
4312 
4313     if (TEST(item->flags, mf_disabled))
4314         {
4315         // Try to process again
4316         if (item->preprocess)
4317             item->preprocess(item);
4318 
4319         // Check once more
4320         if (TEST(item->flags, mf_disabled))
4321             return;
4322         }
4323 
4324     switch (item->type)
4325         {
4326         case mt_option:
4327             if (item->custom != NULL)
4328                 item->custom();
4329             break;
4330         case mt_button:
4331             MNU_PushItem(item, FALSE);
4332             if (item->custom != NULL)
4333                 item->custom();
4334             break;
4335         case mt_layer:
4336             if (item->custom != NULL)
4337                 item->custom();
4338             MNU_DownLevel(item->child);
4339             break;
4340 	default: break;
4341         }
4342     }
4343 
4344 ////////////////////////////////////////////////
4345 // Draw an item icon or cursor
4346 ////////////////////////////////////////////////
4347 static void
MNU_DrawItemIcon(MenuItem * item)4348 MNU_DrawItemIcon(MenuItem * item)
4349     {
4350     //void BorderRefreshClip(PLAYERp pp, short x, short y, short x2, short y2);
4351     int x = item->x, y = item->y;
4352     int scale = MZ;
4353     short w,h;
4354 
4355     if (item->text)
4356         {
4357         scale /= 2;
4358         x -= mulscale17(tilesizx[pic_yinyang],scale) + 2;
4359         y += 4;
4360         }
4361     else
4362         {
4363         scale -= (1<<13);
4364         x -= ((tilesizx[pic_yinyang]) / 2) - 3;
4365         y += 8;
4366         }
4367 
4368     rotatesprite(x << 16, y << 16,
4369         scale, 0, pic_yinyang, item->shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
4370 
4371     SetRedrawScreen(&Player[myconnectindex]);
4372     //BorderRefreshClip(&Player[myconnectindex], x - 24, y - 24, x + 24, y + 24);
4373     }
4374 
4375 ////////////////////////////////////////////////
4376 // Draw an item
4377 ////////////////////////////////////////////////
4378 static void
MNU_DrawItem(MenuItem * item)4379 MNU_DrawItem(MenuItem * item)
4380     {
4381     char *ptr;
4382     short px, py;
4383 
4384     MNU_ItemPostProcess(currentmenu);  // Put this in so things can be drawn on item select
4385 
4386     if (!item->pic)
4387         return;
4388 
4389     MNU_DrawItemIcon(item);
4390 
4391     // if text string skip this part
4392     if (item->text)
4393         return;
4394 
4395     if (TEST(item->flags, mf_selected) && !TEST(item->flags, mf_disabled))
4396         {
4397         // Highlighted
4398         if (item->type != mt_button)
4399             rotatesprite(item->x << 16, item->y << 16, MZ, 0, item->pic,
4400                 -30 + STD_RANDOM_RANGE(50), PALETTE_MENU_HIGHLIGHT, MenuDrawFlags,
4401                  0, 0, xdim - 1, ydim - 1);
4402         else
4403             rotatesprite((item->x + tilesizx[pic_radiobuttn1] + 4) << 16, item->y << 16,
4404                 MZ, 0, item->pic, item->shade, PALETTE_MENU_HIGHLIGHT, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
4405         }
4406     else
4407         {
4408         // Un highlighted
4409         if (item->type != mt_button)
4410             rotatesprite(item->x << 16, item->y << 16, MZ, 0, item->pic,
4411                 item->shade, 0, MenuDrawFlags, 0, 319, 199, 0);
4412         else
4413             rotatesprite((item->x + tilesizx[pic_radiobuttn1] + 4) << 16, item->y << 16,
4414                 MZ, 0, item->pic, item->shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
4415         }
4416     }
4417 
4418 ////////////////////////////////////////////////
4419 // Draw the menu contents
4420 ////////////////////////////////////////////////
4421 static void
MNU_DrawMenuContents(void)4422 MNU_DrawMenuContents(void)
4423     {
4424     MenuItem *item;
4425     short w,h;
4426 
4427     ASSERT(currentmenu != NULL);
4428 
4429     if (currentmenu->text)
4430         {
4431         // Draw the backdrop bar
4432         rotatesprite(10 << 16, (currentmenu->y-3) << 16, MZ, 0, 2427,
4433             currentmenu->shade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
4434         MNU_MeasureStringLarge(currentmenu->text, &w, &h);
4435         MNU_DrawString(TEXT_XCENTER(w), currentmenu->y, currentmenu->text, 1, 16);
4436         }
4437     else
4438     if (currentmenu->titlepic)
4439         {
4440         rotatesprite(currentmenu->x << 16, currentmenu->y << 16, MZ, 0, currentmenu->titlepic,
4441             currentmenu->shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
4442         }
4443 
4444     if (!currentmenu->items)
4445         return;
4446 
4447     for (item = currentmenu->items; item->type != mt_none; item++)
4448         {
4449         if (item->pic)
4450             {
4451             if (item->type == mt_button)
4452                 {
4453                 // all drawing done here also
4454                 MNU_DoButton(item, TRUE);
4455                 }
4456             else
4457                 {
4458                 if (item->text)
4459                     {
4460                     if (TEST(item->flags, mf_disabled))
4461                         MenuTextShade = MENU_SHADE_INACTIVE;
4462                     MNU_DrawString(item->x, item->y, item->text, MenuTextShade, 16);
4463                     MenuTextShade = MENU_SHADE_DEFAULT;
4464                     }
4465                 else
4466                     {
4467                     rotatesprite(item->x << 16, item->y << 16, MZ, 0, item->pic,
4468                         item->shade, 0, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1);
4469                     }
4470                 }
4471             }
4472 
4473         // Is there a slider attached to this item?  Draw it.
4474         if (item->type == mt_slider)
4475             MNU_DoSlider(0, item, TRUE);
4476         }
4477 
4478     MNU_SelectItem(currentmenu, currentmenu->cursor, TRUE);
4479 
4480     if (currentmenu->draw_custom)
4481         currentmenu->draw_custom(uc_touchup, NULL);
4482     }
4483 
4484 ////////////////////////////////////////////////
4485 // Draw the menu
4486 ////////////////////////////////////////////////
4487 void
MNU_DrawMenu(void)4488 MNU_DrawMenu(void)
4489     {
4490     if (cust_callback != NULL)
4491         {
4492         cust_callback(cust_callback_call, cust_callback_item);
4493         return;
4494         }
4495 
4496     if (currentmenu->items || currentmenu->titlepic)
4497         {
4498         MNU_DrawMenuContents();
4499         }
4500     }
4501 
4502 ////////////////////////////////////////////////
4503 // Select a menu item
4504 ////////////////////////////////////////////////
4505 void
MNU_SelectItem(MenuGroup * group,short index,BOOL draw)4506 MNU_SelectItem(MenuGroup * group, short index, BOOL draw)
4507     {
4508     MenuItem *item;
4509 
4510     if (index != group->cursor)
4511         {
4512         item = &group->items[group->cursor];
4513         item->flags &= ~mf_selected;
4514         if (draw)
4515             MNU_DrawItem(item);
4516         }
4517 
4518     group->cursor = index;
4519     item = &group->items[group->cursor];
4520     item->flags |= mf_selected;
4521     if (draw)
4522         MNU_DrawItem(item);
4523     }
4524 
4525 ////////////////////////////////////////////////
4526 // Toggle a menu radio button on/off
4527 ////////////////////////////////////////////////
4528 static void
MNU_PushItem(MenuItem * item,BOOL draw)4529 MNU_PushItem(MenuItem * item, BOOL draw)
4530     {
4531     if (item->type != mt_button)
4532         return;
4533 
4534     buttonsettings[item->button] ^= 1;
4535 
4536 //    if (draw)
4537         MNU_DoButton(item, draw);
4538     }
4539 
4540 ////////////////////////////////////////////////
4541 // Go to next item on menu
4542 ////////////////////////////////////////////////
4543 static void
MNU_NextItem(void)4544 MNU_NextItem(void)
4545     {
4546     MenuTag type;
4547     MenuFlags flag;
4548 
4549     type = currentmenu->items[currentmenu->cursor + 1].type;
4550     flag = currentmenu->items[currentmenu->cursor + 1].flags;
4551 
4552     if (type == mt_none)
4553         MNU_SelectItem(currentmenu, 0, FALSE);
4554     else
4555         MNU_SelectItem(currentmenu, currentmenu->cursor + 1, FALSE);
4556 
4557     type = currentmenu->items[currentmenu->cursor].type;
4558     flag = currentmenu->items[currentmenu->cursor].flags;
4559 
4560     if (type == mt_inert || flag == mf_disabled)
4561         MNU_NextItem();
4562     }
4563 
4564 ////////////////////////////////////////////////
4565 // Go to previous item on menu
4566 ////////////////////////////////////////////////
4567 static void
MNU_PrevItem(void)4568 MNU_PrevItem(void)
4569     {
4570     MenuTag type;
4571     MenuFlags flag;
4572 
4573     if (!currentmenu->cursor)
4574         while (currentmenu->items[++currentmenu->cursor].type != mt_none);
4575 
4576     MNU_SelectItem(currentmenu, currentmenu->cursor - 1, FALSE);
4577 
4578     type = currentmenu->items[currentmenu->cursor].type;
4579     flag = currentmenu->items[currentmenu->cursor].flags;
4580     if (type == mt_inert || flag == mf_disabled)
4581         MNU_PrevItem();
4582     }
4583 
4584 ////////////////////////////////////////////////
4585 // Find hotkey press on current menu, if any.
4586 ////////////////////////////////////////////////
4587 static BOOL
MNU_DoHotkey(void)4588 MNU_DoHotkey(void)
4589     {
4590     MenuItem_p item;
4591     short index;
4592 
4593     if (!currentmenu->items) return FALSE;
4594 
4595     index = 0;
4596     for (item = currentmenu->items; item->type != mt_none; item++)
4597         {
4598         if (KEY_PRESSED(item->hotkey) && item->hotkey != 0)
4599             {
4600             MNU_SelectItem(currentmenu, index, FALSE);
4601             return (TRUE);
4602             }
4603         index++;
4604         }
4605 
4606     return (FALSE);
4607     }
4608 
4609 ////////////////////////////////////////////////
4610 // Setup Menus
4611 ////////////////////////////////////////////////
4612 void
SetupMenu(void)4613 SetupMenu(void)
4614     {
4615     if (!UsingMenus && !ConPanel)       // Doing this check for multiplay
4616                                         // menus
4617         {
4618         MNU_SetupMenu();
4619 
4620         // Clear the previous ESC key press
4621         KEY_PRESSED(KEYSC_ESC) = FALSE;
4622         UsingMenus = TRUE;
4623         }
4624     }
4625 
4626 ////////////////////////////////////////////////
4627 // Setup the main menu
4628 // This function will not loop if in modem
4629 // or network game, otherwise it stops the
4630 // game play until user finished in menus.
4631 ////////////////////////////////////////////////
4632 #define MNU_SENSITIVITY 10              // The menu's mouse sensitivity, should be real low
4633 
MNU_DoMenu(CTLType UNUSED (type),PLAYERp UNUSED (pp))4634 void MNU_DoMenu( CTLType UNUSED(type), PLAYERp UNUSED(pp) )
4635     {
4636     BOOL resetitem;
4637     UCHAR key;
4638     int zero = 0;
4639     static int handle2 = 0;
4640     static int limitmove=0;
4641 
4642     resetitem = TRUE;
4643 
4644     if (cust_callback != NULL)
4645         {
4646         cust_callback(cust_callback_call, cust_callback_item);
4647         return;
4648         }
4649 
4650     //ControlPanelType = type;
4651     SetupMenu();
4652 
4653     // Zero out the input structure
4654     mnu_input.button0 = mnu_input.button1 = FALSE;
4655     mnu_input.dir = dir_None;
4656 
4657     // should not get input if you are editing a save game slot
4658     if(totalclock < limitmove) limitmove = totalclock;
4659     if (!MenuInputMode)
4660         {
4661         UserInput tst_input;
4662         BOOL select_held = FALSE;
4663 
4664 
4665         // Zero out the input structure
4666         tst_input.button0 = tst_input.button1 = FALSE;
4667         tst_input.dir = dir_None;
4668 
4669         if(!select_held)
4670             {
4671             CONTROL_GetUserInput(&tst_input);
4672             mnu_input_buffered.dir = tst_input.dir;
4673             }
4674 
4675         if(mnu_input_buffered.button0 || mnu_input_buffered.button1)
4676             {
4677             if(tst_input.button0 == mnu_input_buffered.button0 &&
4678                tst_input.button1 == mnu_input_buffered.button1)
4679                 {
4680                 select_held = TRUE;
4681                 }
4682                 else
4683                 if(totalclock - limitmove > 7)
4684                 {
4685                 mnu_input.button0 = mnu_input_buffered.button0;
4686                 mnu_input.button1 = mnu_input_buffered.button1;
4687 
4688                 mnu_input_buffered.button0 = tst_input.button0;
4689                 mnu_input_buffered.button1 = tst_input.button1;
4690                 }
4691             } else
4692             {
4693             select_held = FALSE;
4694             mnu_input_buffered.button0 = tst_input.button0;
4695             mnu_input_buffered.button1 = tst_input.button1;
4696             }
4697 
4698         if(totalclock - limitmove > 7 && !select_held)
4699             {
4700             mnu_input.dir = mnu_input_buffered.dir;
4701 
4702             if (mnu_input.dir != dir_None)
4703                 if(!FX_SoundActive(handle2))
4704                     handle2 = PlaySound(DIGI_STAR,&zero,&zero,&zero,v3df_dontpan);
4705 
4706             limitmove = totalclock;
4707             mnu_input_buffered.dir = dir_None;
4708             }
4709         }
4710 
4711     if (mnu_input.dir == dir_North)
4712         {
4713         MNU_PrevItem();
4714         resetitem = TRUE;
4715         }
4716     else
4717     if (mnu_input.dir == dir_South)
4718         {
4719         MNU_NextItem();
4720         resetitem = TRUE;
4721         }
4722     else
4723     if (mnu_input.button0)
4724         {
4725         static int handle5=0;
4726         if(!FX_SoundActive(handle5))
4727             handle5 = PlaySound(DIGI_SWORDSWOOSH,&zero,&zero,&zero,v3df_dontpan);
4728         KB_ClearKeysDown();
4729         MNU_DoItem();
4730         resetitem = TRUE;
4731         }
4732     else
4733     if (mnu_input.dir == dir_West
4734         && currentmenu->items[currentmenu->cursor].type == mt_slider)
4735         {
4736         MNU_DoSlider(-1, &currentmenu->items[currentmenu->cursor], FALSE);
4737         resetitem = TRUE;
4738         }
4739     else
4740     if (mnu_input.dir == dir_East
4741         && currentmenu->items[currentmenu->cursor].type == mt_slider)
4742         {
4743         MNU_DoSlider(1, &currentmenu->items[currentmenu->cursor], FALSE);
4744         resetitem = TRUE;
4745         }
4746     else
4747     if (mnu_input.button1 || BUTTON(gamefunc_Show_Menu))
4748         {
4749         static int handle3=0;
4750         CONTROL_ClearButton(gamefunc_Show_Menu);
4751         if(!FX_SoundActive(handle3))
4752             handle3 = PlaySound(DIGI_SWORDSWOOSH,&zero,&zero,&zero,v3df_dontpan);
4753         MNU_UpLevel();
4754         resetitem = TRUE;
4755         }
4756     else
4757     if (MNU_DoHotkey())
4758         {
4759         static int handle4=0;
4760         if(!FX_SoundActive(handle4))
4761             handle4 = PlaySound(DIGI_STAR,&zero,&zero,&zero,v3df_dontpan);
4762         resetitem = TRUE;
4763         mnu_input_buffered.button0 = mnu_input_buffered.button1 = FALSE;
4764         }
4765     else
4766         resetitem = FALSE;
4767 
4768     // !FRANK! I added this because the old custom was only called for drawing
4769     // Needed one for drawing and moving.
4770     if (currentmenu->move_custom)
4771         currentmenu->move_custom(uc_setup, NULL);
4772 
4773     if (resetitem)
4774         {
4775         KB_ClearKeysDown();
4776         ResetKeys();
4777         }
4778     }
4779 
4780 ////////////////////////////////////////////////
4781 //  Checks to see if we should be in menus
4782 ////////////////////////////////////////////////
4783 void
MNU_CheckForMenus(void)4784 MNU_CheckForMenus(void)
4785     {
4786     extern BOOL GamePaused;
4787 
4788     if (UsingMenus)
4789         {
4790         //if (MoveSkip2 == 0)
4791             MNU_DoMenu(ct_mainmenu, Player + myconnectindex);
4792         }
4793     else
4794         {
4795         if ((ForceMenus || KEY_PRESSED(KEYSC_ESC) || BUTTON(gamefunc_Show_Menu)) && dimensionmode == 3 && !ConPanel)
4796             {
4797             KEY_PRESSED(KEYSC_ESC) = 0;
4798             CONTROL_ClearButton(gamefunc_Show_Menu);
4799             KB_ClearKeysDown();
4800             // setup sliders/buttons
4801             MNU_InitMenus();
4802             MNU_DoMenu(ct_mainmenu, Player + myconnectindex);
4803             pMenuClearTextLine(Player + myconnectindex);
4804             PauseGame();
4805             }
4806         }
4807 
4808     ForceMenus = FALSE;
4809     }
4810 
4811 void
MNU_CheckForMenusAnyKey(void)4812 MNU_CheckForMenusAnyKey(void)
4813     {
4814     if (UsingMenus)
4815         {
4816         //if (MoveSkip2 == 0)
4817             MNU_DoMenu(ct_mainmenu, Player + myconnectindex);
4818         }
4819     else
4820         {
4821         if (KeyPressed() || ForceMenus)
4822             {
4823             ResetKeys();
4824             KB_ClearKeysDown();
4825             MNU_InitMenus();
4826             MNU_DoMenu(ct_mainmenu, Player + myconnectindex);
4827             pMenuClearTextLine(Player + myconnectindex);
4828             }
4829         }
4830 
4831     ForceMenus = FALSE;
4832     }
4833 
MNU_ControlAxisOffset(int num)4834 static int MNU_ControlAxisOffset(int num)
4835 {
4836     switch (num) {
4837         case -1: return 0;
4838         case analog_turning: return 1;
4839         case analog_strafing: return 2;
4840         case analog_moving: return 3;
4841         case analog_lookingupanddown: return 4;
4842         case analog_maxtype: return 5;
4843         default: return 0;
4844     }
4845 }
4846 
MNU_ControlAxisNum(int offset)4847 static int MNU_ControlAxisNum(int offset)
4848 {
4849     switch (offset) {
4850         case 0: return -1;
4851         case 1: return analog_turning;
4852         case 2: return analog_strafing;
4853         case 3: return analog_moving;
4854         case 4: return analog_lookingupanddown;
4855         default: return -1;
4856     }
4857 }
4858 
4859 
4860 
4861 ///////////////////////////////////////////////////////////////////////////////////////////////////
4862 // Miscellaneous Routines
4863 ///////////////////////////////////////////////////////////////////////////////////////////////////
4864 
4865 typedef struct RGB_color_typ
4866     {
4867     unsigned char red;
4868     unsigned char green;
4869     unsigned char blue;
4870     } RGB_color, *RGB_color_ptr;
4871 
4872 #define PALETTE_MASK            0x3c6
4873 #define PALETTE_READ            0x3c7
4874 #define PALETTE_WRITE           0x3c8
4875 #define PALETTE_DATA            0x3c9
4876 
4877 unsigned char palette_data[256][3];     // Global palette array
4878 
4879 // V E R T I C A L   R E T R A C E   V A R I A B L E S //////////////////////////////////////////
4880 
4881 #define VGA_INPUT_STATUS_1      0x3DA   // VGA status register 1, bit 3 is the vsync
4882                     // 1 = retrace in progress
4883                     // 0 = no retrace
4884 #define VGA_VSYNC_MASK          0x08    // Masks off unwanted bits of status register.
4885 
4886 
4887 // These routines are not used and should not be used.  Would interfere with VESA palette
4888 // cards.
4889 #if 0
4890 /////////////////////////////////////////////////
4891 // WaitForVsync
4892 // Waits for a vertical retrace to occur.  If one is in progress, it waits for the next one.
4893 /////////////////////////////////////////////////
4894 void
4895 WaitForVsync(void)
4896     {
4897     while (inp(VGA_INPUT_STATUS_1) & VGA_VSYNC_MASK);
4898     // Retrace in progress, wait.
4899 
4900     // Wait for vsync, and exit.
4901     while (!inp(VGA_INPUT_STATUS_1) & VGA_VSYNC_MASK);
4902     }
4903 
4904 void
4905 Get_Palette(unsigned char *pal)
4906     {
4907     int i;
4908 
4909     outp(PALETTE_READ, 0);
4910     for (i = 0; i < 768; i++)
4911         pal[i] = inp(PALETTE_DATA);
4912     }
4913 void
4914 Set_Palette(unsigned char *buff)
4915     {
4916     int i;
4917 
4918     outp(PALETTE_WRITE, 0);             // Resets color ram pointer to 1st
4919                                         // color
4920     for (i = 0; i < 768; i++)
4921         outp(PALETTE_DATA, buff[i]);
4922     }
4923 
4924 #endif
4925 
4926 
4927 /*
4928 =================================================================================================
4929 =
4930 =       FadeOut - Fades the palette to color at assigned click rate
4931 =
4932 =================================================================================================
4933 */
4934 // Heres some temp timer junk for this routine.  Replace it with game timer stuff later.
4935 //unsigned int *clock  = (unsigned int *)0x046C;
4936 
4937 void
Fade_Timer(int clicks)4938 Fade_Timer(int clicks)
4939     {
4940 //        unsigned int now;
4941     int now;
4942 
4943     now = totalclock;
4944 
4945     while (abs(totalclock - now) < clicks) handleevents();
4946     }
4947 
4948 void
FadeIn(unsigned char startcolor,unsigned int clicks)4949 FadeIn(unsigned char startcolor, unsigned int clicks)
4950     {
4951     int i, palreg, usereg, tmpreg1 = 0, tmpreg2 = 0;
4952     RGB_color color;
4953     unsigned char temp_pal[768], *palette;
4954 
4955 #if USE_POLYMOST && USE_OPENGL
4956     if (getrendermode() >= 3) return;
4957 #endif
4958 
4959     palette = &palette_data[0][0];
4960 
4961     color.red = palette_data[startcolor][0];
4962     color.green = palette_data[startcolor][1];
4963     color.blue = palette_data[startcolor][2];
4964 
4965     usereg = 0;
4966     for (i = 0; i < 768; i++)
4967         {
4968         if (usereg == 0)
4969             temp_pal[i] = color.red;
4970         else
4971         if (usereg == 1)
4972             temp_pal[i] = color.green;
4973         else
4974             temp_pal[i] = color.blue;
4975 
4976         if (++usereg > 2)
4977             usereg = 0;
4978         }
4979 
4980     for (i = 0; i < 32; i++)
4981         {
4982         for (palreg = 0; palreg < 768; palreg++)
4983             {
4984             tmpreg1 = (int) (temp_pal[palreg]) + 2;
4985             tmpreg2 = (int) (temp_pal[palreg]) - 2;
4986             if (tmpreg1 > 255)
4987                 tmpreg1 = 255;
4988             if (tmpreg2 < 0)
4989                 tmpreg2 = 0;
4990 
4991             if (temp_pal[palreg] < palette[palreg])
4992                 {
4993                 if ((temp_pal[palreg] = tmpreg1) > palette[palreg])
4994                     temp_pal[palreg] = palette[palreg];
4995                 }
4996             else
4997             if (temp_pal[palreg] > palette[palreg])
4998                 if ((temp_pal[palreg] = tmpreg2) < palette[palreg])
4999                     temp_pal[palreg] = palette[palreg];
5000 
5001             }
5002 
5003         set_pal(&temp_pal[0]);
5004 
5005         // Delay clicks
5006         Fade_Timer(clicks);
5007         }
5008     }
5009 
5010 void
FadeOut(unsigned char targetcolor,unsigned int clicks)5011 FadeOut(unsigned char targetcolor, unsigned int clicks)
5012     {
5013     int i, palreg, usereg = 0, tmpreg1 = 0, tmpreg2 = 0;
5014     RGB_color color;
5015     unsigned char temp_pal[768];
5016 
5017 #if USE_POLYMOST && USE_OPENGL
5018     if (getrendermode() >= 3) return;
5019 #endif
5020 
5021     color.red = palette_data[targetcolor][0];
5022     color.green = palette_data[targetcolor][1];
5023     color.blue = palette_data[targetcolor][2];
5024 
5025     memcpy(&temp_pal[0], &palette_data[0][0], 768);
5026 
5027     for (i = 0; i < 32; i++)
5028         {
5029         for (palreg = 0; palreg < 768; palreg++)
5030             {
5031             tmpreg1 = (int) (temp_pal[palreg]) + 2;
5032             tmpreg2 = (int) (temp_pal[palreg]) - 2;
5033             if (tmpreg1 > 255)
5034                 tmpreg1 = 255;
5035             if (tmpreg2 < 0)
5036                 tmpreg2 = 0;
5037 
5038             if (usereg == 0)
5039                 {
5040                 if (temp_pal[palreg] < color.red)
5041                     {
5042                     if ((temp_pal[palreg] = tmpreg1) > color.red)
5043                         temp_pal[palreg] = color.red;
5044                     }
5045                 else
5046                 if (temp_pal[palreg] > color.red)
5047                     if ((temp_pal[palreg] = tmpreg2) < color.red)
5048                         temp_pal[palreg] = color.red;
5049                 }
5050             else
5051             if (usereg == 1)
5052                 {
5053                 if (temp_pal[palreg] < color.green)
5054                     {
5055                     if ((temp_pal[palreg] = tmpreg1) > color.green)
5056                         temp_pal[palreg] = color.green;
5057                     }
5058                 else
5059                 if (temp_pal[palreg] > color.green)
5060                     if ((temp_pal[palreg] = tmpreg2) < color.green)
5061                         temp_pal[palreg] = color.green;
5062                 }
5063             else
5064             if (usereg == 2)
5065                 {
5066                 if (temp_pal[palreg] < color.blue)
5067                     {
5068                     if ((temp_pal[palreg] = tmpreg1) > color.blue)
5069                         temp_pal[palreg] = color.blue;
5070                     }
5071                 else
5072                 if (temp_pal[palreg] > color.blue)
5073                     if ((temp_pal[palreg] = tmpreg2) < color.blue)
5074                         temp_pal[palreg] = color.blue;
5075                 }
5076 
5077             if (++usereg > 2)
5078                 usereg = 0;
5079             }
5080 
5081 
5082         set_pal(&temp_pal[0]);
5083 
5084         // Delay clicks
5085         Fade_Timer(clicks);
5086         }
5087     }
5088 
5089 //////////////////////////////////////////////////////////////////////////////
5090 #define FADE_DAMAGE_FACTOR  3   // 100 health / 32 shade cycles = 3.125
5091 
5092 // Fades from 100% to 62.5% somewhat quickly,
5093 //  then from 62.5% to 37.5% slowly,
5094 //  then from 37.5% to 0% quickly.
5095 // This seems to capture the pain caused by enemy shots, plus the extreme
5096 //  fade caused by being blinded or intense pain.
5097 // Perhaps the next step would be to apply a gentle smoothing to the
5098 //  intersections of these lines.
5099 static int faderamp[32] = {
5100 	64,60,56,52,48,44,	// y=64-4x
5101 
5102 	40,39,38,38,37,		// y=44.8-(16/20)x
5103 	36,35,34,34,33,
5104 	32,31,30,30,29,
5105 	28,27,26,26,25,
5106 
5107 	24,20,16,12,8, 4	// y=128-4x
5108 };
5109 
5110 unsigned char ppalette[MAX_SW_PLAYERS_REG][768];
5111 
5112 //////////////////////////////////////////
5113 // Set the amount of redness for damage
5114 // the player just took
5115 //////////////////////////////////////////
5116 void
SetFadeAmt(PLAYERp pp,short damage,unsigned char startcolor)5117 SetFadeAmt(PLAYERp pp, short damage, unsigned char startcolor)
5118     {
5119     int palreg, usereg = 0, tmpreg1 = 0, tmpreg2 = 0;
5120     short fadedamage=0;
5121     RGB_color color;
5122 
5123     //CON_ConMessage("SetAmt: fadeamt = %d, startcolor = %d, pp = %d",pp->FadeAmt,startcolor,pp->StartColor);
5124 
5125     if (abs(pp->FadeAmt) > 0 && startcolor == pp->StartColor)
5126         return;
5127 
5128     // Don't ever over ride flash bomb
5129     if (pp->StartColor == 1 && abs(pp->FadeAmt) > 0)
5130         return;
5131 
5132     // Reset the palette
5133     if(pp == Player + screenpeek)
5134         {
5135 #if USE_POLYMOST && USE_OPENGL
5136         if (getrendermode() >= 3)
5137             {
5138             setpalettefade(0,0,0,0);
5139             }
5140         else
5141 #endif
5142             {
5143             COVERsetbrightness(gs.Brightness,&palette_data[0][0]);
5144             }
5145         if (pp->FadeAmt <= 0)
5146             GetPaletteFromVESA(&ppalette[screenpeek][0]);
5147         }
5148 
5149     if(damage < -150 && damage > -1000) fadedamage = 150;
5150     else
5151     if(damage < -1000)  // Underwater
5152         fadedamage = abs(damage+1000);
5153     else
5154         fadedamage = abs(damage);
5155 
5156     if(damage >= -5 && damage < 0)
5157         fadedamage += 10;
5158 
5159     // Don't let red to TOO red
5160     if(startcolor == COLOR_PAIN && fadedamage > 100) fadedamage = 100;
5161 
5162     pp->FadeAmt = fadedamage / FADE_DAMAGE_FACTOR;
5163 
5164     if (pp->FadeAmt <= 0)
5165         {
5166         pp->FadeAmt = 0;
5167         return;
5168         }
5169 
5170     // It's a health item, just do a preset flash amount
5171     if (damage > 0)
5172         pp->FadeAmt = 3;
5173 
5174     pp->StartColor = startcolor;
5175 
5176     pp->FadeTics = 0;
5177 
5178     // Set player's palette to current game palette
5179     GetPaletteFromVESA(pp->temp_pal);
5180 
5181     color.red = palette_data[pp->StartColor][0];
5182     color.green = palette_data[pp->StartColor][1];
5183     color.blue = palette_data[pp->StartColor][2];
5184 
5185     for (palreg = 0; palreg < 768; palreg++)
5186         {
5187         tmpreg1 = (int) (pp->temp_pal[palreg]) + ((2 * pp->FadeAmt) + 4);
5188         tmpreg2 = (int) (pp->temp_pal[palreg]) - ((2 * pp->FadeAmt) + 4);
5189         if (tmpreg1 > 255)
5190             tmpreg1 = 255;
5191         if (tmpreg2 < 0)
5192             tmpreg2 = 0;
5193 
5194         if (usereg == 0)
5195             {
5196             if (pp->temp_pal[palreg] < color.red)
5197                 {
5198                 if ((pp->temp_pal[palreg] = tmpreg1) > color.red)
5199                     pp->temp_pal[palreg] = color.red;
5200                 }
5201             else
5202             if (pp->temp_pal[palreg] > color.red)
5203                 if ((pp->temp_pal[palreg] = tmpreg2) < color.red)
5204                     pp->temp_pal[palreg] = color.red;
5205             }
5206         else
5207         if (usereg == 1)
5208             {
5209             if (pp->temp_pal[palreg] < color.green)
5210                 {
5211                 if ((pp->temp_pal[palreg] = tmpreg1) > color.green)
5212                     pp->temp_pal[palreg] = color.green;
5213                 }
5214             else
5215             if (pp->temp_pal[palreg] > color.green)
5216                 if ((pp->temp_pal[palreg] = tmpreg2) < color.green)
5217                     pp->temp_pal[palreg] = color.green;
5218             }
5219         else
5220         if (usereg == 2)
5221             {
5222             if (pp->temp_pal[palreg] < color.blue)
5223                 {
5224                 if ((pp->temp_pal[palreg] = tmpreg1) > color.blue)
5225                     pp->temp_pal[palreg] = color.blue;
5226                 }
5227             else
5228             if (pp->temp_pal[palreg] > color.blue)
5229                 if ((pp->temp_pal[palreg] = tmpreg2) < color.blue)
5230                     pp->temp_pal[palreg] = color.blue;
5231             }
5232 
5233         if (++usereg > 2)
5234             usereg = 0;
5235         }
5236 
5237     // Do initial palette set
5238     if(pp == Player + screenpeek)
5239         {
5240 #if USE_POLYMOST && USE_OPENGL
5241         if (getrendermode() >= 3)
5242             {
5243             setpalettefade(color.red, color.green, color.blue, faderamp[ min(31,max(0,32-abs(pp->FadeAmt))) ] );
5244             }
5245     	else
5246 #endif
5247             {
5248             set_pal(pp->temp_pal);
5249             }
5250         if (damage < -1000)
5251             pp->FadeAmt = 1000;  // Don't call DoPaletteFlash for underwater stuff
5252         }
5253     }
5254 
5255 //////////////////////////////////////////
5256 // Do the screen reddness based on damage
5257 //////////////////////////////////////////
5258 #define MAXFADETICS     5
5259 void
DoPaletteFlash(PLAYERp pp)5260 DoPaletteFlash(PLAYERp pp)
5261     {
5262     int i, palreg, tmpreg1 = 0, tmpreg2 = 0;
5263     unsigned char *pal_ptr = &ppalette[screenpeek][0];
5264 
5265 
5266     if (pp->FadeAmt <= 1)
5267         {
5268         pp->FadeAmt = 0;
5269         pp->StartColor = 0;
5270         if(pp == Player + screenpeek)
5271             {
5272 #if USE_POLYMOST && USE_OPENGL
5273             if (getrendermode() >= 3)
5274                 {
5275                 setpalettefade(0,0,0,0);
5276                 }
5277             else
5278 #endif
5279                 {
5280                 COVERsetbrightness(gs.Brightness,&palette_data[0][0]);
5281                 }
5282             memcpy(pp->temp_pal, palette_data, sizeof(palette_data));
5283             DoPlayerDivePalette(pp);  // Check Dive again
5284             DoPlayerNightVisionPalette(pp);  // Check Night Vision again
5285             }
5286 
5287         return;
5288         }
5289 
5290 
5291     pp->FadeTics += synctics;           // Add this frame's tic amount to
5292                                         // counter
5293 
5294     if (pp->FadeTics >= MAXFADETICS)
5295         {
5296         while (pp->FadeTics >= MAXFADETICS)
5297             {
5298             pp->FadeTics -= MAXFADETICS;
5299 
5300             pp->FadeAmt--;              // Decrement FadeAmt till it gets to
5301                                         // 0 again.
5302             }
5303         }
5304     else
5305         return;                         // Return if they were not >
5306                                         // MAXFADETICS
5307 
5308     if (pp->FadeAmt > 32)
5309         return;
5310 
5311     if (pp->FadeAmt <= 1)
5312         {
5313         pp->FadeAmt = 0;
5314         pp->StartColor = 0;
5315         if(pp == Player + screenpeek)
5316             {
5317 #if USE_POLYMOST && USE_OPENGL
5318             if (getrendermode() >= 3)
5319                 {
5320                 setpalettefade(0,0,0,0);
5321                 }
5322             else
5323 #endif
5324                 {
5325                 COVERsetbrightness(gs.Brightness,&palette_data[0][0]);
5326                 }
5327             memcpy(pp->temp_pal, palette_data, sizeof(palette_data));
5328             DoPlayerDivePalette(pp);  // Check Dive again
5329             DoPlayerNightVisionPalette(pp);  // Check Night Vision again
5330             }
5331         return;
5332         }
5333     else
5334         {
5335         //CON_Message("gamavalues = %d, %d, %d",pp->temp_pal[pp->StartColor],pp->temp_pal[pp->StartColor+1],pp->temp_pal[pp->StartColor+2]);
5336         for (palreg = 0; palreg < 768; palreg++)
5337             {
5338             tmpreg1 = (int) (pp->temp_pal[palreg]) + 2;
5339             tmpreg2 = (int) (pp->temp_pal[palreg]) - 2;
5340             if (tmpreg1 > 255)
5341                 tmpreg1 = 255;
5342             if (tmpreg2 < 0)
5343                 tmpreg2 = 0;
5344 
5345             if (pp->temp_pal[palreg] < pal_ptr[palreg])
5346                 {
5347                 if ((pp->temp_pal[palreg] = tmpreg1) > pal_ptr[palreg])
5348                     pp->temp_pal[palreg] = pal_ptr[palreg];
5349                 }
5350             else
5351             if (pp->temp_pal[palreg] > pal_ptr[palreg])
5352                 if ((pp->temp_pal[palreg] = tmpreg2) < pal_ptr[palreg])
5353                     pp->temp_pal[palreg] = pal_ptr[palreg];
5354 
5355             }
5356 
5357         // Only hard set the palette if this is currently the player's view
5358         if(pp == Player + screenpeek)
5359             {
5360 #if USE_POLYMOST && USE_OPENGL
5361     	    if (getrendermode() >= 3)
5362                 {
5363                 setpalettefade(
5364                     palette_data[pp->StartColor][0],
5365                     palette_data[pp->StartColor][1],
5366                     palette_data[pp->StartColor][2],
5367                     faderamp[ min(31,max(0,32-abs(pp->FadeAmt))) ]
5368                     );
5369                 }
5370             else
5371 #endif
5372                 {
5373                 set_pal(pp->temp_pal);
5374                 }
5375             }
5376 
5377         }
5378 
5379     }
5380 
ResetPalette(PLAYERp pp)5381 VOID ResetPalette(PLAYERp pp)
5382     {
5383 #if USE_POLYMOST && USE_OPENGL
5384     if (getrendermode() >= 3)
5385         {
5386         setpalettefade(0,0,0,0);
5387         }
5388     else
5389 #endif
5390         {
5391         COVERsetbrightness(gs.Brightness,&palette_data[0][0]);
5392         }
5393     memcpy(pp->temp_pal, palette_data, sizeof(palette_data));
5394     //DoPlayerDivePalette(pp);  // Check Dive again
5395     //DoPlayerNightVisionPalette(pp);  // Check Night Vision again
5396     pp->FadeAmt = 0;
5397     pp->StartColor = 0;
5398     pp->FadeTics = 0;
5399     }
5400 
5401 // vim:ts=4:sw=4:enc=utf-8:
5402 
5403 
5404