1 /*
2 * Copyright 2010, 2011, 2012, 2013, 2014, 2016 Peter Olsson
3 *
4 * This file is part of Brum Brum Rally.
5 *
6 * Brum Brum Rally is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Brum Brum Rally is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "StateManager.h"
21 #include "GameState.h"
22 #include "Path.h"
23 #include "KeyboardDriver.h"
24 #include "KeyboardDevice.h"
25 #include "MouseDevice.h"
26 #include "JoystickDevice.h"
27 #include "JoystickDriver.h"
28 #include "NearestNeighbor.h"
29 #include "Bilinear.h"
30 #include "BilinearLessBlur.h"
31 #include "Hqx.h"
32 #include "Network.h"
33 #include "background.h"
34 #include <algorithm>
35 #include <fstream>
36 #include <cassert>
37 #include <cstdlib>
38 #include <cctype>
39
40 const int GAME_WIDTH = 320;
41 const int GAME_HEIGHT = 240;
42
StateManager()43 StateManager::StateManager()
44 : currentState(0),
45 stateChanged(false),
46 screenZoom(1),
47 screenPaddingX(0),
48 screenPaddingY(0),
49 fullscreen(0),
50 xAxis(0),
51 yAxis(0),
52 bpp(0),
53 network(),
54 lastMenuEvent()
55 {
56 // Load settings.
57 Path settingsPath(configPath() + "/settings");
58 std::ifstream in(settingsPath.c_str());
59 Settings::load(in);
60
61 fullscreen = Settings::graphics.fullscreen;
62
63 switch (Settings::graphics.scaler)
64 {
65 case 0:
66 default:
67 scaler = new NearestNeighbor;
68 break;
69 case 1:
70 scaler = new Bilinear;
71 break;
72 case 2:
73 scaler = new Hqx;
74 break;
75 case 3:
76 scaler = new BilinearLessBlur;
77 break;
78 }
79
80 // Make sure bit depth is supported by the scaler.
81 const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo();
82 bpp = videoInfo->vfmt->BitsPerPixel;
83 if (!scaler->isValidBpp(bpp))
84 {
85 bpp = 32;
86 }
87
88 // set the fullscreen dimensions
89 if (Settings::graphics.fullscreenWidth == 0 || Settings::graphics.fullscreenHeight == 0)
90 {
91 screenWidth[1] = videoInfo->current_w;
92 screenHeight[1] = videoInfo->current_h;
93 }
94 else
95 {
96 screenWidth[1] = std::max(Settings::graphics.fullscreenWidth, GAME_WIDTH);
97 screenHeight[1] = std::max(Settings::graphics.fullscreenHeight, GAME_HEIGHT);
98 }
99
100 // set the window dimensions
101 int maxZoom = std::min(videoInfo->current_w / GAME_WIDTH, videoInfo->current_h / GAME_HEIGHT);
102 screenZoom = std::max(maxZoom - 1, 1);
103 screenWidth[0] = GAME_WIDTH * screenZoom;
104 screenHeight[0] = GAME_HEIGHT * screenZoom;
105
106 updateVideoMode();
107
108 screenBuffer = Surface(GAME_WIDTH, GAME_HEIGHT);
109 background = createBackground(),
110
111 // Read input devices
112 devices.push_back(new KeyboardDevice());
113 devices.push_back(new MouseDevice());
114 int nJoysticks = SDL_NumJoysticks();
115 for (int i = 0; i < nJoysticks; ++i)
116 {
117 devices.push_back(new JoystickDevice(i));
118 }
119
120 // load human drivers
121 drivers.resize(8);
122 if (in)
123 {
124 std::string deviceName;
125 for (std::size_t i = 0; i < 8 && std::getline(in, deviceName); ++i)
126 {
127 for (std::size_t j = 0; j < devices.size(); ++j)
128 {
129 if (devices[j]->getName() == deviceName)
130 {
131 Driver* driver = devices[j]->createDriver();
132 driver->load(in);
133 driver->setDeviceIndex(j);
134 drivers[i] = driver;
135 break;
136 }
137 }
138 if (!drivers[i])
139 {
140 // Ignore key line.
141 in.ignore(1000, '\n');
142 }
143 }
144 }
145
146 for (std::size_t i = 0; i < 8; ++i)
147 {
148 if (!drivers[i])
149 {
150 Driver* driver = 0;
151 switch (i)
152 {
153 case 0:
154 driver = new KeyboardDriver(SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT);
155 break;
156 case 1:
157 driver = new KeyboardDriver(SDLK_w, SDLK_s, SDLK_a, SDLK_d);
158 break;
159 case 2:
160 driver = new KeyboardDriver(SDLK_i, SDLK_k, SDLK_j, SDLK_l);
161 break;
162 case 3:
163 driver = new KeyboardDriver(SDLK_t, SDLK_g, SDLK_f, SDLK_h);
164 break;
165 case 4:
166 driver = new KeyboardDriver(SDLK_KP8, SDLK_KP5, SDLK_KP4, SDLK_KP6);
167 break;
168 case 5:
169 driver = new KeyboardDriver(SDLK_HOME, SDLK_END, SDLK_DELETE, SDLK_PAGEDOWN);
170 break;
171 case 6:
172 driver = new KeyboardDriver(SDLK_F4, SDLK_F3, SDLK_F1, SDLK_F2);
173 break;
174 case 7:
175 driver = new KeyboardDriver(SDLK_F10, SDLK_F9, SDLK_F7, SDLK_F8);
176 break;
177 }
178 driver->setDeviceIndex(0);
179 drivers[i] = driver;
180 }
181 }
182
183 forceHideFullscreenPointer();
184 }
185
resize(int width,int height)186 void StateManager::resize(int width, int height)
187 {
188 screenWidth[fullscreen] = std::max(GAME_WIDTH, width);
189 screenHeight[fullscreen] = std::max(GAME_HEIGHT, height);
190 scaler->update(screenWidth[fullscreen], screenHeight[fullscreen]);
191 updateVideoMode();
192 }
193
updateVideoMode()194 void StateManager::updateVideoMode()
195 {
196 scaler->update(screenWidth[fullscreen], screenHeight[fullscreen]);
197
198 // update SDL window
199 Uint32 flags = SDL_SWSURFACE|(fullscreen?SDL_FULLSCREEN|SDL_NOFRAME:SDL_RESIZABLE);
200 SDL_Surface* screen = SDL_SetVideoMode(screenWidth[fullscreen], screenHeight[fullscreen], bpp, flags);
201 if (!screen)
202 {
203 if (fullscreen)
204 {
205 // This could happen if the user has a weird fullscreen
206 // resolution so switching to window mode might help.
207 fullscreen = false;
208 updateVideoMode();
209 return;
210 }
211 else
212 {
213 // I have no idea why this happened so we better quit now.
214 std::exit(EXIT_FAILURE);
215 }
216 }
217
218 pointer.setFullScreen(fullscreen);
219 pointer.setScaling(Settings::graphics.scalePointer > (fullscreen ? 0 : 1));
220 pointer.setType(Settings::graphics.pointer);
221
222 // updateWholeScreen() will have to be called afterwards if needed
223 }
224
updateScreen()225 void StateManager::updateScreen()
226 {
227 // draw background
228 assert(currentState);
229 currentState->background.draw(screenBuffer,0,0);
230
231 pointer.update(!currentState->menu.isVisible());
232
233 std::vector<RenderObject*>& renderObjects = currentState->renderObjects;
234 std::vector<RenderObject*>::iterator it;
235
236 Rect rect1;
237 Rect rect2;
238 for (it = renderObjects.begin(); it != renderObjects.end(); ++it)
239 {
240 RenderObject* ro = *it;
241 ro->draw(screenBuffer);
242 if (ro->isUpdated())
243 {
244 ro->updateRects(rect1, rect2);
245 addUpdateRect(rect1);
246 addUpdateRect(rect2);
247 }
248 }
249
250 pointer.draw(screenBuffer);
251 if (pointer.isUpdated())
252 {
253 pointer.updateRects(rect1, rect2);
254 addUpdateRect(rect1);
255 addUpdateRect(rect2);
256 }
257
258 std::list<Rect>::iterator rit;
259 for (rit = updateRects.begin(); rit != updateRects.end(); ++rit)
260 {
261 SDL_Rect rect;
262
263 rect.x = (rit->x1);
264 rect.y = (rit->y1);
265 rect.w = (rit->x2 - rit->x1);
266 rect.h = (rit->y2 - rit->y1);
267
268 scaler->render(screenBuffer, &rect);
269
270 updateSDLRects.push_back(rect);
271 }
272
273 if (!updateSDLRects.empty())
274 {
275 SDL_UpdateRects(SDL_GetVideoSurface(), updateRects.size(), &updateSDLRects[0]);
276 updateSDLRects.clear();
277 updateRects.clear();
278 }
279 }
280
updateWholeScreen()281 void StateManager::updateWholeScreen()
282 {
283 // Fill screen with black
284 SDL_FillRect(SDL_GetVideoSurface(), 0, 0);
285
286 // draw background
287 assert(currentState);
288 currentState->background.draw(screenBuffer, 0, 0);
289
290 // draw render objects
291 std::vector<RenderObject*>& renderObjects = currentState->renderObjects;
292 std::vector<RenderObject*>::iterator it;
293 Rect rect1;
294 Rect rect2;
295 for (it = renderObjects.begin(); it != renderObjects.end(); ++it)
296 {
297 RenderObject* ro = *it;
298 ro->draw(screenBuffer);
299 if (ro->isUpdated())
300 {
301 // we need to call updateRects even if we don't use the
302 // rects to update them.
303 ro->updateRects(rect1, rect2);
304 }
305 }
306
307 pointer.draw(screenBuffer);
308 if (pointer.isUpdated())
309 {
310 pointer.updateRects(rect1, rect2);
311 }
312
313 scaler->render(screenBuffer, 0);
314
315 SDL_Flip(SDL_GetVideoSurface());
316 }
317
addUpdateRect(Rect & rect)318 void StateManager::addUpdateRect(Rect& rect)
319 {
320 if (rect.x1 < 0)
321 {
322 rect.x1 = 0;
323 }
324 if (rect.y1 < 0)
325 {
326 rect.y1 = 0;
327 }
328 if (rect.x2 > GAME_WIDTH)
329 {
330 rect.x2 = GAME_WIDTH;
331 }
332 if (rect.y2 > GAME_HEIGHT)
333 {
334 rect.y2 = GAME_HEIGHT;
335 }
336
337 if (rect.x1 >= rect.x2 || rect.y1 >= rect.y2)
338 {
339 return;
340 }
341
342 std::list<Rect>::iterator it;
343 for (it = updateRects.begin(); it != updateRects.end(); ++it)
344 {
345 if (overlap(rect, *it))
346 {
347 rect.combine(*it);
348
349 updateRects.erase(it);
350
351 // start loop from start
352 // because the new rect can be much larger
353 it = updateRects.begin();
354 }
355 }
356 updateRects.push_front(rect);
357 }
358
getDriver(int index)359 Driver* StateManager::getDriver(int index)
360 {
361 assert(static_cast<unsigned>(index) < drivers.size());
362 return drivers[index];
363 }
364
getDevice(int index)365 InputDevice* StateManager::getDevice(int index)
366 {
367 assert(static_cast<unsigned>(index) < devices.size());
368 return devices[index];
369 }
370
getDeviceNames() const371 std::vector<std::string> StateManager::getDeviceNames() const
372 {
373 std::vector<std::string> names;
374 for (std::size_t i = 0; i < devices.size(); ++i)
375 {
376 names.push_back(devices[i]->getName());
377 }
378 return names;
379 }
380
setDriver(int i,Driver * driver)381 void StateManager::setDriver(int i, Driver* driver)
382 {
383 delete drivers[i];
384 drivers[i] = driver;
385 }
386
cleanUp()387 void StateManager::cleanUp()
388 {
389 // Save settings.
390 Path settingsPath(configPath() + "/settings");
391 std::ofstream out(settingsPath.c_str());
392 Settings::save(out);
393
394 // Save (and delete) human drivers.
395 for (std::size_t i = 0; i < drivers.size(); ++i)
396 {
397 drivers[i]->save(out);
398 delete drivers[i];
399 }
400
401 for (std::size_t i = 0; i < devices.size(); ++i)
402 {
403 delete devices[i];
404 }
405
406 delete network;
407 }
408
getInstance()409 StateManager& StateManager::getInstance()
410 {
411 static StateManager instance;
412 return instance;
413 }
414
run()415 void StateManager::run()
416 {
417 SDL_Event event;
418 while (currentState)
419 {
420 stateChanged = false;
421
422 // handle events
423 while (SDL_PollEvent(&event))
424 {
425 handleEvent(event);
426 if (stateChanged)
427 {
428 break;
429 }
430 }
431 if (stateChanged)
432 {
433 // this one is needed because the other check inside the event
434 // loop doesn't break out of the main loop
435 continue;
436 }
437
438 // update state
439 currentState->update();
440 if (stateChanged)
441 {
442 continue;
443 }
444 // render
445 updateScreen();
446
447 // sleep
448 int st = currentState->sleepTime();
449 if (st > 0)
450 {
451 if (network)
452 {
453 network->sleep(st);
454 }
455 else
456 {
457 SDL_Delay(st);
458 }
459 }
460 }
461 }
462
handleEvent(const SDL_Event & event)463 void StateManager::handleEvent(const SDL_Event& event)
464 {
465 switch(event.type)
466 {
467 case SDL_KEYDOWN:
468 if (SDL_GetModState() & KMOD_ALT)
469 {
470 switch (event.key.keysym.sym)
471 {
472 case SDLK_F4:
473 quit();
474 return;
475 case SDLK_RETURN:
476 toggleFullscreen();
477 return;
478 default:
479 ;
480 }
481 }
482 switch (event.key.keysym.sym)
483 {
484 case SDLK_F11:
485 toggleFullscreen();
486 return;
487 default:
488 ;
489 }
490 break;
491 case SDL_QUIT:
492 quit();
493 return;
494 case SDL_VIDEORESIZE:
495 resize(event.resize.w, event.resize.h);
496 updateWholeScreen();
497 return;
498 case SDL_VIDEOEXPOSE:
499 updateWholeScreen();
500 return;
501 case SDL_MOUSEMOTION:
502 pointer.move(scaler->dst2src_x(event.motion.x), scaler->dst2src_y(event.motion.y), currentState->menu.isInteractive());
503 break;
504 case SDL_ACTIVEEVENT:
505 if (event.active.state & SDL_APPMOUSEFOCUS)
506 {
507 if (event.active.gain)
508 {
509 pointer.show();
510 }
511 else
512 {
513 pointer.hide(true);
514 }
515 }
516 break;
517 default:
518 ;
519 }
520
521 currentState->onEvent(event);
522 }
523
quit()524 void StateManager::quit()
525 {
526 delete currentState;
527 currentState = 0;
528 stateChanged = true;
529 }
530
enter(GameState * newState)531 void StateManager::enter(GameState* newState)
532 {
533 newState->setStateInfo(oldStateInfo.empty() ? 0 : oldStateInfo[0]);
534
535 if (lastMenuEvent.type != MENU_MOUSE_CLICK1)
536 {
537 pointer.hide();
538 }
539
540 oldStateInfo.clear();
541 delete currentState;
542 currentState = newState;
543
544 stateChanged = true;
545 if (currentState)
546 {
547 updateWholeScreen();
548 }
549 }
550
enter(GameState * newState,int x)551 void StateManager::enter(GameState* newState, int x)
552 {
553 int stateInfo = 0;
554 if (x > 0)
555 {
556 assert(x == 1);
557 if (currentState)
558 {
559 oldStateInfo.push_back(currentState->getStateInfo());
560 }
561 }
562 else if (x < 0)
563 {
564 if (newState)
565 {
566 std::size_t i = oldStateInfo.size() + x;
567 assert(i < oldStateInfo.size());
568 stateInfo = oldStateInfo[i];
569 oldStateInfo.resize(i);
570 }
571 }
572 newState->setStateInfo(stateInfo);
573
574 if (lastMenuEvent.type != MENU_MOUSE_CLICK1)
575 {
576 pointer.hide();
577 }
578
579 delete currentState;
580 currentState = newState;
581
582 stateChanged = true;
583 if (currentState)
584 {
585 updateWholeScreen();
586 }
587 }
588
589 // When entering a new state we sometimes want to use the old content of
590 // the screen as a background. This is useful for ingame menus. Call this
591 // method before creating the state object to make use of this.
screenToBackgound()592 void StateManager::screenToBackgound()
593 {
594 assert(currentState);
595 screenBuffer.draw(currentState->background, 0, 0);
596 }
597
toggleFullscreen()598 void StateManager::toggleFullscreen()
599 {
600 fullscreen = !fullscreen;
601 updateVideoMode();
602 updateWholeScreen();
603
604 forceHideFullscreenPointer();
605 }
606
forceHideFullscreenPointer()607 void StateManager::forceHideFullscreenPointer()
608 {
609 if (fullscreen)
610 {
611 // It doesn't look nice getting that big pointer in the middle
612 // of the screen so lets just hide the pointer when switching to
613 // fullscreen mode.
614 SDL_Event e;
615 while (SDL_PollEvent(&e));
616 pointer.hide();
617 }
618 }
619
getMenuEvent(const SDL_Event & event)620 MenuEvent StateManager::getMenuEvent(const SDL_Event& event)
621 {
622 MenuEvent e = MenuEvent(); // Zero initialized.
623 switch (event.type)
624 {
625 case SDL_KEYDOWN:
626 switch (event.key.keysym.sym)
627 {
628 case SDLK_DOWN:
629 e.type = MENU_NEXT;
630 break;
631 case SDLK_UP:
632 e.type = MENU_PREV;
633 break;
634 case SDLK_LEFT:
635 e.type = MENU_DEC;
636 break;
637 case SDLK_RIGHT:
638 e.type = MENU_INC;
639 break;
640 case SDLK_RETURN:
641 case SDLK_KP_ENTER:
642 e.type = MENU_ACTION;
643 break;
644 case SDLK_ESCAPE:
645 e.type = MENU_ESC;
646 break;
647 case SDLK_HOME:
648 e.type = MENU_MIN;
649 break;
650 case SDLK_END:
651 e.type = MENU_MAX;
652 break;
653 case SDLK_PAGEUP:
654 e.type = MENU_FIRST;
655 break;
656 case SDLK_PAGEDOWN:
657 e.type = MENU_LAST;
658 break;
659 case SDLK_BACKSPACE:
660 e.type = MENU_ERASE;
661 break;
662 case SDLK_DELETE:
663 e.type = MENU_DELETE;
664 break;
665 default:
666 e.c = unicode2char(event.key.keysym.unicode);
667 if (std::isprint(e.c))
668 {
669 e.type = MENU_TEXT;
670 }
671 }
672 break;
673 case SDL_JOYAXISMOTION:
674 {
675 int newAxis = 0;
676 if (event.jaxis.value > AXIS_THRESHOLD)
677 {
678 newAxis = 1;
679 }
680 else if (std::abs(event.jaxis.value) < AXIS_THRESHOLD / 2)
681 {
682 newAxis = 0;
683 }
684 else if (event.jaxis.value < -AXIS_THRESHOLD)
685 {
686 newAxis = -1;
687 }
688
689 if (event.jaxis.axis & 1)
690 {
691 if (newAxis != yAxis)
692 {
693 if (newAxis == 1)
694 {
695 e.type = MENU_NEXT;
696 }
697 else if (newAxis == -1)
698 {
699 e.type = MENU_PREV;
700 }
701 yAxis = newAxis;
702 }
703 }
704 else
705 {
706 if (newAxis != xAxis)
707 {
708 if (newAxis == 1)
709 {
710 e.type = MENU_INC;
711 }
712 else if (newAxis == -1)
713 {
714 e.type = MENU_DEC;
715 }
716 xAxis = newAxis;
717 }
718 }
719 break;
720 }
721 case SDL_JOYHATMOTION:
722 switch (event.jhat.value)
723 {
724 case SDL_HAT_DOWN:
725 e.type = MENU_NEXT;
726 break;
727 case SDL_HAT_UP:
728 e.type = MENU_PREV;
729 break;
730 case SDL_HAT_LEFT:
731 e.type = MENU_DEC;
732 break;
733 case SDL_HAT_RIGHT:
734 e.type = MENU_INC;
735 break;
736 }
737 break;
738 case SDL_JOYBUTTONDOWN:
739 switch (event.jbutton.button)
740 {
741 case 0:
742 e.type = MENU_ACTION;
743 break;
744 case 1:
745 e.type = MENU_ESC;
746 break;
747 }
748 break;
749 case SDL_MOUSEMOTION:
750 e.type = MENU_MOUSE_MOVE;
751 e.x = scaler->dst2src_x(event.motion.x);
752 e.y = scaler->dst2src_y(event.motion.y);
753 break;
754 case SDL_MOUSEBUTTONDOWN:
755 if (!pointer.isVisible())
756 {
757 return e;
758 }
759 switch (event.button.button)
760 {
761 case SDL_BUTTON_LEFT:
762 e.type = MENU_MOUSE_CLICK1;
763 break;
764 case SDL_BUTTON_RIGHT:
765 e.type = MENU_MOUSE_CLICK2;
766 break;
767 case SDL_BUTTON_WHEELUP:
768 e.type = MENU_INC;
769 break;
770 case SDL_BUTTON_WHEELDOWN:
771 e.type = MENU_DEC;
772 break;
773 default:
774 e.type = MENU_ESC;
775 }
776 e.x = scaler->dst2src_x(event.motion.x);
777 e.y = scaler->dst2src_y(event.motion.y);
778 break;
779 case SDL_MOUSEBUTTONUP:
780 e.type = MENU_MOUSE_RELEASE;
781 break;
782 }
783 lastMenuEvent = e;
784 return e;
785 }
786
forgetLastMenuEvent()787 void StateManager::forgetLastMenuEvent()
788 {
789 lastMenuEvent.type = MENU_UNKNOWN;
790 }
791
updateGraphicsSettings(const Settings::Graphics & gfx)792 void StateManager::updateGraphicsSettings(const Settings::Graphics& gfx)
793 {
794 // This function is not very efficient because it calls
795 // updateVideoMode() and updateWholeScreen() multiple times.
796
797 updateScaler(gfx.scaler);
798 updateStretch(gfx.stretch, gfx.keepAspectRatio);
799 updatePointerType(gfx.pointer);
800 updatePointerScaling(gfx.scalePointer);
801
802 // These settings only have an effect when the game is started.
803 Settings::graphics.fullscreen = gfx.fullscreen;
804 Settings::graphics.fullscreenWidth = gfx.fullscreenWidth;
805 Settings::graphics.fullscreenHeight = gfx.fullscreenHeight;
806 }
807
updateScaler(int newScaler)808 void StateManager::updateScaler(int newScaler)
809 {
810 if (newScaler != Settings::graphics.scaler)
811 {
812 delete scaler;
813 switch (newScaler)
814 {
815 case 0:
816 default:
817 scaler = new NearestNeighbor;
818 break;
819 case 1:
820 scaler = new Bilinear;
821 break;
822 case 2:
823 scaler = new Hqx;
824 break;
825 case 3:
826 scaler = new BilinearLessBlur;
827 break;
828 }
829
830 const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo();
831 bpp = videoInfo->vfmt->BitsPerPixel;
832 if (!scaler->isValidBpp(bpp))
833 {
834 bpp = 32;
835 }
836 updateVideoMode();
837
838 // Make sure the buffer has the correct bit depth.
839 screenBuffer = Surface(GAME_WIDTH, GAME_HEIGHT);
840
841 Settings::graphics.scaler = newScaler;
842 updateWholeScreen();
843 }
844 }
845
updateStretch(bool newStretch,bool newKeepAspectRatio)846 void StateManager::updateStretch(bool newStretch, bool newKeepAspectRatio)
847 {
848 if (newStretch != Settings::graphics.stretch ||
849 newKeepAspectRatio != Settings::graphics.keepAspectRatio)
850 {
851 Settings::graphics.stretch = newStretch;
852 Settings::graphics.keepAspectRatio = newKeepAspectRatio;
853 updateVideoMode();
854 updateWholeScreen();
855 }
856 }
857
updatePointerType(const std::string & pointerType)858 void StateManager::updatePointerType(const std::string& pointerType)
859 {
860 if (pointerType != Settings::graphics.pointer)
861 {
862 pointer.setType(pointerType);
863 Settings::graphics.pointer = pointerType;
864
865 // Make sure offset is updated correctly.
866 int x;
867 int y;
868 SDL_GetMouseState(&x, &y);
869 pointer.move(scaler->dst2src_x(x), scaler->dst2src_y(y));
870
871 updateWholeScreen();
872 }
873 }
874
updatePointerScaling(int scalePointer)875 void StateManager::updatePointerScaling(int scalePointer)
876 {
877 if (scalePointer != Settings::graphics.scalePointer)
878 {
879 pointer.setScaling(scalePointer > (fullscreen ? 0 : 1));
880 pointer.setType(Settings::graphics.pointer);
881 Settings::graphics.scalePointer = scalePointer;
882 updateWholeScreen();
883 }
884 }
885
886
887 // The purpose of this function is to give the StateManager
888 // responsibility to delete the network.
setNetwork(Network * net)889 void StateManager::setNetwork(Network* net)
890 {
891 delete network;
892 network = net;
893 }
894
getBackground() const895 Surface StateManager::getBackground() const
896 {
897 return background;
898 }
899
getLastMenuEvent() const900 const MenuEvent& StateManager::getLastMenuEvent() const
901 {
902 return lastMenuEvent;
903 }
904
unicode2char(Uint16 unicode)905 char unicode2char(Uint16 unicode)
906 {
907 if (unicode < 128)
908 {
909 return std::tolower(static_cast<char>(unicode));
910 }
911 switch (unicode)
912 {
913 case 192:
914 case 193:
915 case 194:
916 case 195:
917 case 196:
918 case 197:
919 case 198:
920 case 224:
921 case 225:
922 case 226:
923 case 227:
924 case 228:
925 case 229:
926 case 230:
927 return 'a';
928 case 199:
929 case 231:
930 return 'c';
931 case 200:
932 case 201:
933 case 202:
934 case 203:
935 case 232:
936 case 233:
937 case 234:
938 case 235:
939 return 'e';
940 case 204:
941 case 205:
942 case 206:
943 case 207:
944 case 236:
945 case 237:
946 case 238:
947 case 239:
948 return 'i';
949 case 208:
950 case 240:
951 return 'd';
952 case 209:
953 case 241:
954 return 'n';
955 case 210:
956 case 211:
957 case 212:
958 case 213:
959 case 214:
960 case 216:
961 case 242:
962 case 243:
963 case 244:
964 case 245:
965 case 246:
966 case 248:
967 return 'o';
968 case 217:
969 case 218:
970 case 219:
971 case 220:
972 case 249:
973 case 250:
974 case 251:
975 case 252:
976 return 'u';
977 case 221:
978 case 253:
979 case 255:
980 return 'y';
981 }
982
983 return '\0';
984 }
985