1 /***************************************
2 ** Tsunagari Tile Engine **
4 ** Copyright 2011-2013 PariahSoft LLC **
5 ***************************************/
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 #include <boost/foreach.hpp>
28 #include <Gosu/Graphics.hpp> // for Gosu::Graphics
29 #include <Gosu/Timing.hpp>
30 #include <Gosu/Utility.hpp>
32 #include "client-conf.h"
37 #define ASSERT(x) if (!(x)) { return false; }
39 // Garbage collection called every X milliseconds
40 #define GC_CALL_PERIOD 10 * 1000
44 * Enable 1980s-style graphics scaling: nearest-neighbor filtering.
45 * Call this function before creating any Gosu::Image.
47 void enableUndocumentedRetrofication() {
48 extern bool undocumentedRetrofication
;
49 undocumentedRetrofication
= true;
53 static GameWindow
* globalWindow
= NULL
;
55 GameWindow
& GameWindow::instance()
60 GameWindow::GameWindow()
61 // Gosu emulates the requested screen resolution on fullscreen,
62 // but this breaks our aspect ratio-correcting letterbox.
63 // Ergo we just make a window the size of the screen.
65 conf
.fullscreen
? Gosu::screenWidth() :
66 (unsigned)conf
.windowSize
.x
,
67 conf
.fullscreen
? Gosu::screenHeight() :
68 (unsigned)conf
.windowSize
.y
,
71 now(Gosu::milliseconds()),
75 Gosu::enableUndocumentedRetrofication();
78 GameWindow::~GameWindow()
82 bool GameWindow::init()
84 world
.reset(new World());
88 int GameWindow::width() const
90 return (int)graphics().width();
93 int GameWindow::height() const
95 return (int)graphics().height();
98 void GameWindow::buttonDown(const Gosu::Button btn
)
100 now
= (int)Gosu::milliseconds();
101 if (btn
== Gosu::kbEscape
&&
102 (input().down(Gosu::kbLeftShift
) ||
103 input().down(Gosu::kbRightShift
))) {
107 if (keystates
.find(btn
) == keystates
.end()) {
108 keystate
& state
= keystates
[btn
];
110 state
.initiallyResolved
= false;
111 state
.consecutive
= false;
113 // We process the initial buttonDown here so that it
114 // gets handled even if we receive a buttonUp before an
116 world
->buttonDown(btn
);
121 void GameWindow::buttonUp(const Gosu::Button btn
)
123 keystates
.erase(btn
);
124 world
->buttonUp(btn
);
127 void GameWindow::draw()
132 bool GameWindow::needsRedraw() const
134 return world
->needsRedraw();
137 void GameWindow::update()
139 now
= Gosu::milliseconds();
141 if (conf
.moveMode
== TURN
)
142 handleKeyboardInput(now
);
145 if (now
> lastGCtime
+ GC_CALL_PERIOD
) {
147 Reader::garbageCollect();
151 time_t GameWindow::time() const
156 void GameWindow::handleKeyboardInput(time_t now
)
158 std::map
<Gosu::Button
, keystate
>::iterator it
;
160 // Persistent input handling code
161 for (it
= keystates
.begin(); it
!= keystates
.end(); it
++) {
162 Gosu::Button btn
= it
->first
;
163 keystate
& state
= it
->second
;
165 // If there is persistCons milliseconds of latency
166 // between when a button is depressed and when we first look at
167 // it here, we'll incorrectly try to fire off a second round of
169 // This can happen if an intermediary function blocks the thread
171 if (!state
.initiallyResolved
) {
172 state
.initiallyResolved
= true;
176 time_t delay
= state
.consecutive
?
177 conf
.persistCons
: conf
.persistInit
;
178 if (now
>= state
.since
+ delay
) {
180 world
->buttonDown(btn
);
181 state
.consecutive
= true;