1 
2 /**
3  * @file gamemenu.cpp
4  *
5  * Implementation of the in-game menu functions.
6  */
7 #include "all.h"
8 #include "options.h"
9 
10 DEVILUTION_BEGIN_NAMESPACE
11 
12 bool gbRunInTown = false;
13 
14 /** Contains the game menu items of the single player menu. */
15 TMenuItem sgSingleMenu[] = {
16 	// clang-format off
17 //	  dwFlags,       pszStr,         fnMenu
18 	{ GMENU_ENABLED, "Save Game",     &gamemenu_save_game  },
19 	{ GMENU_ENABLED, "Options",       &gamemenu_options    },
20 	{ GMENU_ENABLED, "New Game",      &gamemenu_new_game   },
21 	{ GMENU_ENABLED, "Load Game",     &gamemenu_load_game  },
22 	{ GMENU_ENABLED, "Quit Game",     &gamemenu_quit_game  },
23 	{ GMENU_ENABLED, NULL,            NULL }
24 	// clang-format on
25 };
26 /** Contains the game menu items of the multi player menu. */
27 TMenuItem sgMultiMenu[] = {
28 	// clang-format off
29 //	  dwFlags,       pszStr,            fnMenu
30 	{ GMENU_ENABLED, "Options",         &gamemenu_options      },
31 	{ GMENU_ENABLED, "New Game",        &gamemenu_new_game     },
32 	{ GMENU_ENABLED, "Restart In Town", &gamemenu_restart_town },
33 	{ GMENU_ENABLED, "Quit Game",       &gamemenu_quit_game    },
34 	{ GMENU_ENABLED, NULL,              NULL                   },
35 	// clang-format on
36 };
37 TMenuItem sgOptionsMenu[] = {
38 	// clang-format off
39 //	  dwFlags,                      pszStr,          fnMenu
40 	{ GMENU_ENABLED | GMENU_SLIDER, NULL,            &gamemenu_music_volume  },
41 	{ GMENU_ENABLED | GMENU_SLIDER, NULL,            &gamemenu_sound_volume  },
42 	{ GMENU_ENABLED | GMENU_SLIDER, "Gamma",         &gamemenu_gamma         },
43 //	{ GMENU_ENABLED               , NULL,            &gamemenu_color_cycling },
44 	{ GMENU_ENABLED | GMENU_SLIDER, "Speed",         &gamemenu_speed         },
45 //	{ GMENU_ENABLED | GMENU_SLIDER, NULL,            &gamemenu_loadjog       },
46 	{ GMENU_ENABLED               , "Previous Menu", &gamemenu_previous      },
47 	{ GMENU_ENABLED               , NULL,            NULL                    },
48 	// clang-format on
49 };
50 /** Specifies the menu names for music enabled and disabled. */
51 const char *const music_toggle_names[] = {
52 	"Music",
53 	"Music Disabled",
54 };
55 /** Specifies the menu names for sound enabled and disabled. */
56 const char *const sound_toggle_names[] = {
57 	"Sound",
58 	"Sound Disabled",
59 };
60 const char *jogging_toggle_names[] = {
61 	"Jog",
62 	"Walk",
63 };
64 /** Specifies the menu names for color cycling disabled and enabled. */
65 const char *const color_cycling_toggle_names[] = { "Color Cycling Off", "Color Cycling On" };
66 
gamemenu_update_single(TMenuItem * pMenuItems)67 static void gamemenu_update_single(TMenuItem *pMenuItems)
68 {
69 	BOOL enable;
70 
71 	gmenu_enable(&sgSingleMenu[3], gbValidSaveFile);
72 
73 	enable = FALSE;
74 	if (plr[myplr]._pmode != PM_DEATH && !deathflag)
75 		enable = TRUE;
76 
77 	gmenu_enable(&sgSingleMenu[0], enable);
78 }
79 
gamemenu_update_multi(TMenuItem * pMenuItems)80 static void gamemenu_update_multi(TMenuItem *pMenuItems)
81 {
82 	gmenu_enable(&sgMultiMenu[2], deathflag);
83 }
84 
gamemenu_on()85 void gamemenu_on()
86 {
87 	if (!gbIsMultiplayer) {
88 		gmenu_set_items(sgSingleMenu, gamemenu_update_single);
89 	} else {
90 		gmenu_set_items(sgMultiMenu, gamemenu_update_multi);
91 	}
92 	PressEscKey();
93 }
94 
gamemenu_off()95 void gamemenu_off()
96 {
97 	gmenu_set_items(NULL, NULL);
98 }
99 
gamemenu_handle_previous()100 void gamemenu_handle_previous()
101 {
102 	if (gmenu_is_active())
103 		gamemenu_off();
104 	else
105 		gamemenu_on();
106 }
107 
gamemenu_previous(BOOL bActivate)108 void gamemenu_previous(BOOL bActivate)
109 {
110 	gamemenu_on();
111 }
112 
gamemenu_new_game(BOOL bActivate)113 void gamemenu_new_game(BOOL bActivate)
114 {
115 	int i;
116 
117 	for (i = 0; i < MAX_PLRS; i++) {
118 		plr[i]._pmode = PM_QUIT;
119 		plr[i]._pInvincible = TRUE;
120 	}
121 
122 	deathflag = FALSE;
123 	force_redraw = 255;
124 	scrollrt_draw_game_screen(TRUE);
125 	CornerStone.activated = FALSE;
126 	gbRunGame = FALSE;
127 	gamemenu_off();
128 }
129 
gamemenu_quit_game(BOOL bActivate)130 void gamemenu_quit_game(BOOL bActivate)
131 {
132 	gamemenu_new_game(bActivate);
133 	gbRunGameResult = FALSE;
134 }
135 
gamemenu_load_game(BOOL bActivate)136 void gamemenu_load_game(BOOL bActivate)
137 {
138 	WNDPROC saveProc = SetWindowProc(DisableInputWndProc);
139 	gamemenu_off();
140 	SetCursor_(CURSOR_NONE);
141 	InitDiabloMsg(EMSG_LOADING);
142 	force_redraw = 255;
143 	DrawAndBlit();
144 	LoadGame(FALSE);
145 	ClrDiabloMsg();
146 	CornerStone.activated = FALSE;
147 	PaletteFadeOut(8);
148 	deathflag = FALSE;
149 	force_redraw = 255;
150 	DrawAndBlit();
151 	LoadPWaterPalette();
152 	PaletteFadeIn(8);
153 	SetCursor_(CURSOR_HAND);
154 	interface_msg_pump();
155 	SetWindowProc(saveProc);
156 }
157 
gamemenu_save_game(BOOL bActivate)158 void gamemenu_save_game(BOOL bActivate)
159 {
160 	if (pcurs != CURSOR_HAND) {
161 		return;
162 	}
163 
164 	if (plr[myplr]._pmode == PM_DEATH || deathflag) {
165 		gamemenu_off();
166 		return;
167 	}
168 
169 	WNDPROC saveProc = SetWindowProc(DisableInputWndProc);
170 	SetCursor_(CURSOR_NONE);
171 	gamemenu_off();
172 	InitDiabloMsg(EMSG_SAVING);
173 	force_redraw = 255;
174 	DrawAndBlit();
175 	SaveGame();
176 	ClrDiabloMsg();
177 	force_redraw = 255;
178 	SetCursor_(CURSOR_HAND);
179 	if (CornerStone.activated) {
180 		items_427A72();
181 	}
182 	interface_msg_pump();
183 	SetWindowProc(saveProc);
184 }
185 
gamemenu_restart_town(BOOL bActivate)186 void gamemenu_restart_town(BOOL bActivate)
187 {
188 	NetSendCmd(TRUE, CMD_RETOWN);
189 }
190 
gamemenu_sound_music_toggle(const char * const * names,TMenuItem * menu_item,int volume)191 static void gamemenu_sound_music_toggle(const char *const *names, TMenuItem *menu_item, int volume)
192 {
193 	if (gbSndInited) {
194 		menu_item->dwFlags |= GMENU_ENABLED | GMENU_SLIDER;
195 		menu_item->pszStr = *names;
196 		gmenu_slider_steps(menu_item, 17);
197 		gmenu_slider_set(menu_item, VOLUME_MIN, VOLUME_MAX, volume);
198 		return;
199 	}
200 
201 	menu_item->dwFlags &= ~(GMENU_ENABLED | GMENU_SLIDER);
202 	menu_item->pszStr = names[1];
203 }
204 
gamemenu_slider_music_sound(TMenuItem * menu_item)205 static int gamemenu_slider_music_sound(TMenuItem *menu_item)
206 {
207 	return gmenu_slider_get(menu_item, VOLUME_MIN, VOLUME_MAX);
208 }
209 
gamemenu_get_music()210 static void gamemenu_get_music()
211 {
212 	gamemenu_sound_music_toggle(music_toggle_names, sgOptionsMenu, sound_get_or_set_music_volume(1));
213 }
214 
gamemenu_get_sound()215 static void gamemenu_get_sound()
216 {
217 	gamemenu_sound_music_toggle(sound_toggle_names, &sgOptionsMenu[1], sound_get_or_set_sound_volume(1));
218 }
219 
gamemenu_jogging()220 static void gamemenu_jogging()
221 {
222 	gmenu_slider_steps(&sgOptionsMenu[3], 2);
223 	gmenu_slider_set(&sgOptionsMenu[3], 0, 1, sgOptions.Gameplay.bRunInTown);
224 	sgOptionsMenu[3].pszStr = jogging_toggle_names[!sgOptions.Gameplay.bRunInTown ? 1 : 0];
225 }
226 
gamemenu_get_gamma()227 static void gamemenu_get_gamma()
228 {
229 	gmenu_slider_steps(&sgOptionsMenu[2], 15);
230 	gmenu_slider_set(&sgOptionsMenu[2], 30, 100, UpdateGamma(0));
231 }
232 
gamemenu_get_speed()233 static void gamemenu_get_speed()
234 {
235 	if (gbIsMultiplayer) {
236 		sgOptionsMenu[3].dwFlags &= ~(GMENU_ENABLED | GMENU_SLIDER);
237 		if (gnTickRate >= 50)
238 			sgOptionsMenu[3].pszStr = "Speed: Fastest";
239 		else if (gnTickRate >= 40)
240 			sgOptionsMenu[3].pszStr = "Speed: Faster";
241 		else if (gnTickRate >= 30)
242 			sgOptionsMenu[3].pszStr = "Speed: Fast";
243 		else if (gnTickRate == 20)
244 			sgOptionsMenu[3].pszStr = "Speed: Normal";
245 		return;
246 	}
247 
248 	sgOptionsMenu[3].dwFlags |= GMENU_ENABLED | GMENU_SLIDER;
249 
250 	sgOptionsMenu[3].pszStr = "Speed";
251 	gmenu_slider_steps(&sgOptionsMenu[3], 46);
252 	gmenu_slider_set(&sgOptionsMenu[3], 20, 50, gnTickRate);
253 }
254 
gamemenu_get_color_cycling()255 static void gamemenu_get_color_cycling()
256 {
257 	sgOptionsMenu[3].pszStr = color_cycling_toggle_names[sgOptions.Graphics.bColorCycling ? 1 : 0];
258 }
259 
gamemenu_slider_gamma()260 static int gamemenu_slider_gamma()
261 {
262 	return gmenu_slider_get(&sgOptionsMenu[2], 30, 100);
263 }
264 
gamemenu_options(BOOL bActivate)265 void gamemenu_options(BOOL bActivate)
266 {
267 	gamemenu_get_music();
268 	gamemenu_get_sound();
269 	//gamemenu_jogging();
270 	gamemenu_get_gamma();
271 	gamemenu_get_speed();
272 	//gamemenu_get_color_cycling();
273 	gmenu_set_items(sgOptionsMenu, NULL);
274 }
275 
gamemenu_music_volume(BOOL bActivate)276 void gamemenu_music_volume(BOOL bActivate)
277 {
278 	int volume;
279 
280 	if (bActivate) {
281 		if (gbMusicOn) {
282 			gbMusicOn = FALSE;
283 			music_stop();
284 			sound_get_or_set_music_volume(VOLUME_MIN);
285 		} else {
286 			gbMusicOn = TRUE;
287 			sound_get_or_set_music_volume(VOLUME_MAX);
288 			int lt;
289 			if (currlevel >= 17) {
290 				if (currlevel > 20)
291 					lt = TMUSIC_L5;
292 				else
293 					lt = TMUSIC_L6;
294 			} else
295 				lt = leveltype;
296 			music_start(lt);
297 		}
298 	} else {
299 		volume = gamemenu_slider_music_sound(&sgOptionsMenu[0]);
300 		sound_get_or_set_music_volume(volume);
301 		if (volume == VOLUME_MIN) {
302 			if (gbMusicOn) {
303 				gbMusicOn = FALSE;
304 				music_stop();
305 			}
306 		} else if (!gbMusicOn) {
307 			gbMusicOn = TRUE;
308 			int lt;
309 			if (currlevel >= 17) {
310 				if (currlevel > 20)
311 					lt = TMUSIC_L5;
312 				else
313 					lt = TMUSIC_L6;
314 			} else
315 				lt = leveltype;
316 			music_start(lt);
317 		}
318 	}
319 	gamemenu_get_music();
320 }
321 
gamemenu_sound_volume(BOOL bActivate)322 void gamemenu_sound_volume(BOOL bActivate)
323 {
324 	int volume;
325 	if (bActivate) {
326 		if (gbSoundOn) {
327 			gbSoundOn = FALSE;
328 			sound_stop();
329 			sound_get_or_set_sound_volume(VOLUME_MIN);
330 		} else {
331 			gbSoundOn = TRUE;
332 			sound_get_or_set_sound_volume(VOLUME_MAX);
333 		}
334 	} else {
335 		volume = gamemenu_slider_music_sound(&sgOptionsMenu[1]);
336 		sound_get_or_set_sound_volume(volume);
337 		if (volume == VOLUME_MIN) {
338 			if (gbSoundOn) {
339 				gbSoundOn = FALSE;
340 				sound_stop();
341 			}
342 		} else if (!gbSoundOn) {
343 			gbSoundOn = TRUE;
344 		}
345 	}
346 	PlaySFX(IS_TITLEMOV);
347 	gamemenu_get_sound();
348 }
349 
gamemenu_loadjog(BOOL bActivate)350 void gamemenu_loadjog(BOOL bActivate)
351 {
352 	if (!gbIsMultiplayer) {
353 		sgOptions.Gameplay.bRunInTown = !sgOptions.Gameplay.bRunInTown;
354 		gbRunInTown = sgOptions.Gameplay.bRunInTown;
355 		PlaySFX(IS_TITLEMOV);
356 		gamemenu_jogging();
357 	}
358 }
359 
gamemenu_gamma(BOOL bActivate)360 void gamemenu_gamma(BOOL bActivate)
361 {
362 	int gamma;
363 	if (bActivate) {
364 		gamma = UpdateGamma(0);
365 		if (gamma == 30)
366 			gamma = 100;
367 		else
368 			gamma = 30;
369 	} else {
370 		gamma = gamemenu_slider_gamma();
371 	}
372 
373 	UpdateGamma(gamma);
374 	gamemenu_get_gamma();
375 }
376 
gamemenu_speed(BOOL bActivate)377 void gamemenu_speed(BOOL bActivate)
378 {
379 	if (bActivate) {
380 		if (gnTickRate != 20)
381 			gnTickRate = 20;
382 		else
383 			gnTickRate = 50;
384 		gmenu_slider_set(&sgOptionsMenu[3], 20, 50, gnTickRate);
385 	} else {
386 		gnTickRate = gmenu_slider_get(&sgOptionsMenu[3], 20, 50);
387 	}
388 
389 	sgOptions.Gameplay.nTickRate = gnTickRate;
390 	gnTickDelay = 1000 / gnTickRate;
391 }
392 
gamemenu_color_cycling(BOOL bActivate)393 void gamemenu_color_cycling(BOOL bActivate)
394 {
395 	sgOptions.Graphics.bColorCycling = !sgOptions.Graphics.bColorCycling;
396 	sgOptionsMenu[3].pszStr = color_cycling_toggle_names[sgOptions.Graphics.bColorCycling ? 1 : 0];
397 }
398 
399 DEVILUTION_END_NAMESPACE
400