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 <Gosu/Graphics.hpp> // for Gosu::Graphics
28 #include <Gosu/Timing.hpp>
29 #include <Gosu/Utility.hpp>
31 #include "client-conf.h"
36 #define ASSERT(x) if (!(x)) { return false; }
38 // Garbage collection called every X milliseconds
39 #define GC_CALL_PERIOD 10 * 1000
43 * Enable 1980s-style graphics scaling: nearest-neighbor filtering.
44 * Call this function before creating any Gosu::Image.
46 void enableUndocumentedRetrofication() {
47 extern bool undocumentedRetrofication
;
48 undocumentedRetrofication
= true;
52 static GameWindow
* globalWindow
= NULL
;
54 GameWindow
& GameWindow::instance()
59 GameWindow::GameWindow()
60 // Gosu emulates the requested screen resolution on fullscreen,
61 // but this breaks our aspect ratio-correcting letterbox.
62 // Ergo we just make a window the size of the screen.
64 conf
.fullscreen
? Gosu::screenWidth() :
65 (unsigned)conf
.windowSize
.x
,
66 conf
.fullscreen
? Gosu::screenHeight() :
67 (unsigned)conf
.windowSize
.y
,
70 now(Gosu::milliseconds()),
74 Gosu::enableUndocumentedRetrofication();
77 GameWindow::~GameWindow()
81 bool GameWindow::init()
83 world
.reset(new World());
87 int GameWindow::width() const
89 return (int)graphics().width();
92 int GameWindow::height() const
94 return (int)graphics().height();
97 void GameWindow::buttonDown(const Gosu::Button btn
)
99 now
= (int)Gosu::milliseconds();
100 if (btn
== Gosu::kbEscape
&&
101 (input().down(Gosu::kbLeftShift
) ||
102 input().down(Gosu::kbRightShift
))) {
106 if (keystates
.find(btn
) == keystates
.end()) {
107 keystate
& state
= keystates
[btn
];
109 state
.initiallyResolved
= false;
110 state
.consecutive
= false;
112 // We process the initial buttonDown here so that it
113 // gets handled even if we receive a buttonUp before an
115 world
->buttonDown(btn
);
120 void GameWindow::buttonUp(const Gosu::Button btn
)
122 keystates
.erase(btn
);
123 world
->buttonUp(btn
);
126 void GameWindow::draw()
131 bool GameWindow::needsRedraw() const
133 return world
->needsRedraw();
136 void GameWindow::update()
138 now
= Gosu::milliseconds();
140 if (conf
.moveMode
== TURN
)
141 handleKeyboardInput(now
);
144 if (now
> lastGCtime
+ GC_CALL_PERIOD
) {
146 Reader::garbageCollect();
150 time_t GameWindow::time() const
155 void GameWindow::handleKeyboardInput(time_t now
)
157 std::map
<Gosu::Button
, keystate
>::iterator it
;
159 // Persistent input handling code
160 for (it
= keystates
.begin(); it
!= keystates
.end(); it
++) {
161 Gosu::Button btn
= it
->first
;
162 keystate
& state
= it
->second
;
164 // If there is persistCons milliseconds of latency
165 // between when a button is depressed and when we first look at
166 // it here, we'll incorrectly try to fire off a second round of
168 // This can happen if an intermediary function blocks the thread
170 if (!state
.initiallyResolved
) {
171 state
.initiallyResolved
= true;
175 time_t delay
= state
.consecutive
?
176 conf
.persistCons
: conf
.persistInit
;
177 if (now
>= state
.since
+ delay
) {
179 world
->buttonDown(btn
);
180 state
.consecutive
= true;