1 
2 /* Battle Tanks Game
3  * Copyright (C) 2006-2009 Battle Tanks team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19 
20 /*
21  * Additional rights can be granted beyond the GNU General Public License
22  * on the terms provided in the Exception. If you modify this file,
23  * you may extend this exception to your version of the file,
24  * but you are not obligated to do so. If you do not wish to provide this
25  * exception without modification, you must delete this exception statement
26  * from your version and license this file solely under the GPL without exception.
27 */
28 #include "options_menu.h"
29 #include "button.h"
30 #include "chooser.h"
31 #include "menu.h"
32 #include "control_picker.h"
33 #include "simple_gamepad_setup.h"
34 #include "i18n.h"
35 #include "label.h"
36 #include "slider.h"
37 #include "config.h"
38 #include "checkbox.h"
39 #include "sound/mixer.h"
40 #include "redefine_keys.h"
41 #include "player_manager.h"
42 #include "game_monitor.h"
43 #include "window.h"
44 #include "game.h"
45 #include "sdlx/joystick.h"
46 
OptionsMenu(const int w,const int h)47 OptionsMenu::OptionsMenu(const int w, const int h) : _shoot(0.5f, false), _gamepad(NULL) {
48 	Mixer->loadSample("shot.ogg");
49 	bool has_gamepad = sdlx::Joystick::getCount() > 0;
50 
51 	_background.init("menu/background_box.png", w - 100, h - 100);
52 	int bw, bh;
53 
54 	int mx, my;
55 	_background.getMargins(mx, my);
56 	_bx = ( w - _background.w ) / 2;
57 	_by = ( h - _background.h ) / 2;
58 	int base_x = _bx + 3 * _background.w / 4;
59 
60 	_b_ok = new Button("medium_dark", I18n->get("menu", "ok"));
61 	_b_ok->get_size(bw, bh);
62 	add(_by + my + 3 * _background.w / 4 - bw / 2, h -  my - bh - _by, _b_ok);
63 
64 	_b_revert = new Button("medium_dark", I18n->get("menu", "revert-to-defaults"));
65 	_b_revert->get_size(bw, bh);
66 	add(_by + my + _background.w / 4 - bw / 2, h -  my - bh - _by, _b_revert);
67 
68 	int width = _background.w - 2 * mx;
69 
70 	int sw, sh;
71 	int yp = my * 2 + _by;
72 
73 	std::vector<std::string> langs;
74 	langs.push_back(I18n->get("menu/language", "default"));
75 	{
76 		I18n->getSupportedLanguages(_langs);
77 		for(std::set<std::string>::const_iterator i = _langs.begin(); i != _langs.end(); ++i) {
78 			langs.push_back(I18n->has("menu/language", *i)?I18n->get("menu/language", *i): *i);
79 		}
80 	}
81 
82 	_lang = new Chooser("medium", langs);
83 	_lang->get_size(sw, sh);
84 	add(_bx + mx, yp, new Label("medium", I18n->get("menu/language", "language")));
85 	add(_bx + base_x - sw / 2, yp, _lang);
86 	yp += sh + 10;
87 
88 	sp = new ControlPicker(width, "medium", I18n->get("menu", "single-player"), "control-method", "keys", std::string());
89 	sp->get_size(sw, sh);
90 	add(_bx + mx, yp, sp);
91 	yp += sh;
92 
93 	sp1 = new ControlPicker(width, "medium", I18n->get("menu", "split-player-1"), "control-method-1", "keys-1", "split");
94 	sp1->get_size(sw, sh);
95 	add(_bx + mx, yp, sp1);
96 	yp += sh;
97 
98 	sp2 = new ControlPicker(width, "medium", I18n->get("menu", "split-player-2"), "control-method-2", "keys-2", "split");
99 	sp2->get_size(sw, sh);
100 	add(_bx + mx, yp, sp2);
101 	yp += sh;
102 
103 
104 	_b_redefine = new Button("medium_dark", I18n->get("menu", "redefine-keys"));
105 	_b_redefine->get_size(sw, sh);
106 	add(has_gamepad? w / 2 - sw - my: (w - sw) / 2, yp + 6, _b_redefine);
107 
108 	if (has_gamepad) {
109 		_b_setup_gamepad = new Button("medium_dark", I18n->get("menu", "setup-gamepad"));
110 		_b_setup_gamepad->get_size(sw, sh);
111 		add(w / 2, yp + 6, _b_setup_gamepad);
112 	} else {
113 		_b_setup_gamepad = NULL;
114 	}
115 
116 	yp += sh + 20;
117 	//volume controls
118 
119 	float volume;
120 	Config->get("engine.sound.volume.music", volume, 1.0f);
121 
122 	Label *l = new Label("medium", I18n->get("menu", "music-volume"));
123 	Slider *s = _music = new Slider(volume);
124 
125 	add(_bx + mx, yp, l);
126 	l->get_size(sw, sh);
127 	{
128 		int w, h;
129 		s->get_size(w, h);
130 		add(_bx + base_x - w / 2, yp + (sh - h) / 2, s);
131 		if (h > sh)
132 			sh = h;
133 	}
134 
135 	yp += sh + 10;
136 
137 ////////////////////
138 
139 	Config->get("engine.sound.volume.fx", volume, 0.66f);
140 
141 	l = new Label("medium", I18n->get("menu", "fx-volume"));
142 	s = _fx = new Slider(volume);
143 	add(_bx + mx, yp, l);
144 	l->get_size(sw, sh);
145 	{
146 		int w, h;
147 		s->get_size(w, h);
148 		add(_bx + base_x - w / 2, yp + (sh - h) / 2, s);
149 		if (h > sh)
150 			sh = h;
151 	}
152 
153 	yp += sh + 10;
154 
155 /////////////////
156 
157 	Config->get("engine.sound.volume.ambience", volume, 0.5f);
158 
159 	l = new Label("medium", I18n->get("menu", "ambience-volume"));
160 	s = _ambient = new Slider(volume);
161 	add(_bx + mx, yp, l);
162 	l->get_size(sw, sh);
163 	{
164 		int w, h;
165 		s->get_size(w, h);
166 		add(_bx + base_x - w / 2, yp + (sh - h) / 2, s);
167 		if (h > sh)
168 			sh = h;
169 	}
170 
171 	yp += sh + 10;
172 
173 
174 	int screen_w, screen_h;
175 	Config->get("engine.window.width", screen_w, 800);
176 	Config->get("engine.window.height", screen_h, 600);
177 
178 	{
179 		std::vector<std::string> res;
180 		bool standard = false;
181 		for(unsigned i = 0; i < Window->resolutions.size(); ++i) {
182 			if (screen_w == Window->resolutions[i].w && screen_h == Window->resolutions[i].h)
183 				standard = true;
184 			res.push_back(mrt::format_string("%ux%u", Window->resolutions[i].w, Window->resolutions[i].h));
185 		}
186 		if (!standard)
187 			res.push_back(mrt::format_string("%ux%u", screen_w, screen_h));
188 
189 		_c_res = new Chooser("medium", res);
190 	}
191 
192 
193 	l = new Label("medium", I18n->get("menu", "screen-resolution"));
194 	add(_bx + mx, yp, l);
195 	l->get_size(sw, sh);
196 	{
197 		int w, h;
198 		_c_res->get_size(w, h);
199 		add(_bx + base_x - w / 2, yp + (sh - h) / 2, _c_res);
200 		if (h > sh)
201 			sh = h;
202 	}
203 	yp += sh + 10;
204 
205 	TRY {
206 		_c_res->set(mrt::format_string("%dx%d", screen_w, screen_h));
207 	} CATCH("default resolution setup", {});
208 
209 	l = new Label("medium", I18n->get("menu", "fullscreen-mode"));
210 	add(_bx + mx, yp, l);
211 	l->get_size(sw, sh);
212 
213 	_fsmode = new Checkbox();
214 	{
215 		int w, h;
216 		_fsmode->get_size(w, h);
217 		add(_bx + base_x - w / 2 + 48, yp + (sh - h) / 2, _fsmode);
218 		if (h > sh)
219 			sh = h;
220 	}
221 	yp += sh + 10;
222 
223 	l = new Label("medium", I18n->get("menu", "do-not-show-donation-screen"));
224 	add(_bx + mx, yp, l);
225 	l->get_size(sw, sh);
226 
227 	_donate = new Checkbox();
228 	{
229 		int w, h;
230 		_donate->get_size(w, h);
231 		add(_bx + base_x - w / 2 + 48, yp + (sh - h) / 2, _donate);
232 		if (h > sh)
233 			sh = h;
234 	}
235 	yp += sh + 10;
236 
237 	l = new Label("medium", I18n->get("menu", "enable-fog-of-war"));
238 	add(_bx + mx, yp, l);
239 	l->get_size(sw, sh);
240 
241 	_fog_of_war = new Checkbox();
242 	{
243 		int w, h;
244 		_fog_of_war->get_size(w, h);
245 		add(_bx + base_x - w / 2 + 48, yp + (sh - h) / 2, _fog_of_war);
246 		if (h > sh)
247 			sh = h;
248 	}
249 	yp += sh + 10;
250 
251 
252 	//dialogs
253 
254 	_keys = new RedefineKeys;
255 	_keys->get_size(sw, sh);
256 	add((w - sw) / 2, (h - sh) / 2, _keys);
257 	_keys->hide();
258 
259 	if (has_gamepad) {
260 		_gamepad = new SimpleGamepadSetup();
261 		_gamepad->get_size(sw, sh);
262 
263 		add((w - sw) / 2, (h - sh) / 2, _gamepad);
264 		_gamepad->hide();
265 	}
266 
267 	load();
268 }
269 
get_size(int & w,int & h) const270 void OptionsMenu::get_size(int &w, int &h) const {
271 	w = _background.w;
272 	h = _background.h;
273 }
274 
revert_to_defaults()275 void OptionsMenu::revert_to_defaults() {
276 	Config->remove("engine.sound.volume.music");
277 	Config->remove("engine.sound.volume.fx");
278 	Config->remove("engine.sound.volume.ambience");
279 	Config->remove("engine.language");
280 	Config->remove("engine.window.width");
281 	Config->remove("engine.window.height");
282 	Config->remove("engine.window.fullscreen");
283 	Config->remove("engine.donate-screen-duration");
284 	Config->remove("engine.fog-of-war.enabled");
285 	load();
286 }
287 
load()288 void OptionsMenu::load() {
289 	LOG_DEBUG(("loading options..."));
290 	sp->reload();
291 	sp1->reload();
292 	sp2->reload();
293 
294 	float volume;
295 	Config->get("engine.sound.volume.music", volume, 1.0f);
296 	_music->set(volume);
297 
298 	Config->get("engine.sound.volume.fx", volume, 0.66f);
299 	_fx->set(volume);
300 
301 	Config->get("engine.sound.volume.ambience", volume, 0.5f);
302 	_ambient->set(volume);
303 
304 	_keys->load();
305 
306 	std::string lang;
307 	if (Config->has("engine.language"))
308 		Config->get("engine.language", lang, std::string());
309 
310 	//rewrite it to the simplier and extensible manner.
311 	if (lang.empty()) {
312 		_lang->set(0);
313 	} else {
314 		int idx = 1;
315 		for(std::set<std::string>::const_iterator i = _langs.begin(); i != _langs.end(); ++i, ++idx) {
316 			if (*i == lang) {
317 				_lang->set(idx);
318 				break;
319 			}
320 		}
321 	}
322 
323 	TRY {
324 		int w, h;
325 		Config->get("engine.window.width", w, 800);
326 		Config->get("engine.window.height", h, 600);
327 		_c_res->set(mrt::format_string("%dx%d", w, h));
328 	} CATCH("default resolution setup", {});
329 
330 	bool fs;
331 	Config->get("engine.window.fullscreen", fs, false);
332 	_fsmode->set(fs);
333 	float donate;
334 	Config->get("engine.donate-screen-duration", donate, 1.5f);
335 	_donate->set(donate <= 0);
336 	bool fog;
337 	Config->get("engine.fog-of-war.enabled", fog, false);
338 	_fog_of_war->set(fog);
339 }
340 
341 #include "window.h"
342 
save()343 void OptionsMenu::save() {
344 	LOG_DEBUG(("saving options..."));
345 	sp->save();
346 	sp1->save();
347 	sp2->save();
348 
349 	Config->set("engine.sound.volume.fx", _fx->get());
350 	Config->set("engine.sound.volume.music", _music->get());
351 	Config->set("engine.sound.volume.ambience", _ambient->get());
352 
353 	bool need_restart = false;
354 	TRY {
355 		int idx = _lang->get();
356 		if (idx < 0 || idx > (int)_langs.size())
357 			throw_ex(("language index %d is invalid", idx));
358 
359 		std::string lang;
360 		if (idx > 0) {
361 			std::set<std::string>::iterator lang_i = _langs.begin();
362 			for(int i = 1; i < idx; ++i)
363 				++lang_i;
364 			lang = *lang_i;
365 		}
366 
367 		std::string old_lang;
368 		if (Config->has("engine.language"))
369 			Config->get("engine.language", old_lang, std::string());
370 
371 		if (old_lang != lang) {
372 			if (!lang.empty())
373 				Config->set("engine.language", lang);
374 			else
375 				Config->remove("engine.language");
376 			need_restart = true;
377 		}
378 	} CATCH("saving language", {});
379 
380 	TRY {
381 		int screen_w, screen_h;
382 		Config->get("engine.window.width", screen_w, 800);
383 		Config->get("engine.window.height", screen_h, 600);
384 		std::vector<std::string> res;
385 		mrt::split(res, _c_res->getValue(), "x", 2);
386 		res.resize(2);
387 		int w, h;
388 		w = atoi(res[0].c_str());
389 		h = atoi(res[1].c_str());
390 		LOG_DEBUG(("parsed window size: %dx%d", w, h));
391 
392 		if (w > 0 && h > 0 && (w != screen_w || h != screen_h)) {
393 			Config->set("engine.window.width", w);
394 			Config->set("engine.window.height", h);
395 			need_restart = true;
396 		}
397 
398 	//this doesnt work without restart.
399 	/*
400 		Window->deinit();
401 		SDL_Quit();
402 		Window->initSDL();
403 		Window->createMainWindow();
404 	*/
405 	} CATCH("setting video mode", {});
406 
407 	bool fsmode;
408 	Config->get("engine.window.fullscreen", fsmode, false);
409 	if (fsmode != _fsmode->get()) {
410 		Config->set("engine.window.fullscreen", _fsmode->get());
411 		need_restart = true;
412 	}
413 	Config->set("engine.donate-screen-duration", (_donate->get())?0.0f:1.5f);
414 	Config->set("engine.fog-of-war.enabled", _fog_of_war->get());
415 
416 	PlayerManager->update_controls();
417 
418 	if (need_restart)
419 		GameMonitor->displayMessage("messages", "restart-game", 2.0f);
420 }
421 
422 
tick(const float dt)423 void OptionsMenu::tick(const float dt) {
424 	if (_fx->changed() || _fx->tracking()) {
425 		_fx->reset();
426 		Mixer->setFXVolume(_fx->get());
427 		if (_shoot.tick(dt)) {
428 			Mixer->set_listener(v3<float>(), v3<float>(), 64);
429 			Mixer->playSample(NULL, "shot.ogg", false);
430 			_shoot.reset();
431 		}
432 	}
433 	if (_music->changed()) {
434 		_music->reset();
435 		Mixer->setMusicVolume(_music->get());
436 	}
437 	if (_ambient->changed()) {
438 		_ambient->reset();
439 		Mixer->setAmbienceVolume(_ambient->get());
440 	}
441 	if (_b_revert->changed()) {
442 		_b_revert->reset();
443 		revert_to_defaults();
444 	}
445 	if (_b_ok->changed()) {
446 		_b_ok->reset();
447 		save();
448 		hide();
449 	}
450 	if (_b_redefine->changed()) {
451 		_b_redefine->reset();
452 		_keys->hide(false);
453 	}
454 	if (_b_setup_gamepad != NULL && _b_setup_gamepad->changed()) {
455 		_b_setup_gamepad->reset();
456 		if (_gamepad != NULL) //does not really needed
457 			_gamepad->hide(false);
458 	}
459 	Container::tick(dt);
460 }
461 
render(sdlx::Surface & surface,const int x,const int y) const462 void OptionsMenu::render(sdlx::Surface &surface, const int x, const int y) const {
463 	_background.render(surface, _bx, _by);
464 	Container::render(surface, x, y);
465 }
466 
onKey(const SDL_keysym sym)467 bool OptionsMenu::onKey(const SDL_keysym sym) {
468 	if (Container::onKey(sym))
469 		return true;
470 
471 	switch(sym.sym) {
472 
473 	case SDLK_KP_ENTER:
474 	case SDLK_RETURN:
475 	case SDLK_ESCAPE:
476 		save();
477 		hide();
478 		return true;
479 
480 	case SDLK_j:
481 	case SDLK_g:
482 		if (_gamepad != NULL && _keys->hidden()) {
483 			_gamepad->hide(false);
484 		}
485 
486 		return true;
487 
488 	case SDLK_r:
489 		if (_gamepad == NULL || _gamepad->hidden())
490 			_keys->hide(false);
491 		return true;
492 
493 	default: ;
494 	}
495 	return false;
496 }
497 
~OptionsMenu()498 OptionsMenu::~OptionsMenu() {}
499