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