1 /*
2 * Copyright 2010-2014 OpenXcom Developers.
3 *
4 * This file is part of OpenXcom.
5 *
6 * OpenXcom 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 * OpenXcom 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 OpenXcom. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "BuildNewBaseState.h"
20 #include <cmath>
21 #include "../fmath.h"
22 #include "../Engine/Game.h"
23 #include "../Engine/Action.h"
24 #include "../Resource/ResourcePack.h"
25 #include "../Engine/Language.h"
26 #include "../Engine/Palette.h"
27 #include "../Engine/Surface.h"
28 #include "../Engine/Timer.h"
29 #include "../Engine/Screen.h"
30 #include "../Interface/Window.h"
31 #include "Globe.h"
32 #include "../Interface/Text.h"
33 #include "../Interface/TextButton.h"
34 #include "../Savegame/Base.h"
35 #include "../Savegame/Craft.h"
36 #include "BaseNameState.h"
37 #include "ConfirmNewBaseState.h"
38 #include "../Engine/Options.h"
39
40 namespace OpenXcom
41 {
42
43 /**
44 * Initializes all the elements in the Build New Base window.
45 * @param game Pointer to the core game.
46 * @param base Pointer to the base to place.
47 * @param globe Pointer to the Geoscape globe.
48 * @param first Is this the first base in the game?
49 */
BuildNewBaseState(Game * game,Base * base,Globe * globe,bool first)50 BuildNewBaseState::BuildNewBaseState(Game *game, Base *base, Globe *globe, bool first) : State(game), _base(base), _globe(globe), _first(first), _oldlat(0), _oldlon(0), _mousex(0), _mousey(0)
51 {
52 int dx = _game->getScreen()->getDX();
53 int dy = _game->getScreen()->getDY();
54 _screen = false;
55
56 _oldshowradar = Options::globeRadarLines;
57 if (!_oldshowradar)
58 Options::globeRadarLines = true;
59 // Create objects
60 _btnRotateLeft = new InteractiveSurface(12, 10, 259 + dx * 2, 176 + dy);
61 _btnRotateRight = new InteractiveSurface(12, 10, 283 + dx * 2, 176 + dy);
62 _btnRotateUp = new InteractiveSurface(13, 12, 271 + dx * 2, 162 + dy);
63 _btnRotateDown = new InteractiveSurface(13, 12, 271 + dx * 2, 187 + dy);
64 _btnZoomIn = new InteractiveSurface(23, 23, 295 + dx * 2, 156 + dy);
65 _btnZoomOut = new InteractiveSurface(13, 17, 300 + dx * 2, 182 + dy);
66
67 _window = new Window(this, 256, 28, 0, 0);
68 _window->setX(dx);
69 _window->setDY(0);
70 _btnCancel = new TextButton(54, 12, 186 + dx, 8);
71 _txtTitle = new Text(180, 16, 8 + dx, 6);
72
73 _hoverTimer = new Timer(50);
74 _hoverTimer->onTimer((StateHandler)&BuildNewBaseState::hoverRedraw);
75 _hoverTimer->start();
76
77 // Set palette
78 setPalette("PAL_GEOSCAPE");
79
80 add(_btnRotateLeft);
81 add(_btnRotateRight);
82 add(_btnRotateUp);
83 add(_btnRotateDown);
84 add(_btnZoomIn);
85 add(_btnZoomOut);
86
87 add(_window);
88 add(_btnCancel);
89 add(_txtTitle);
90
91 // Set up objects
92 _globe->onMouseClick((ActionHandler)&BuildNewBaseState::globeClick);
93
94 _btnRotateLeft->onMousePress((ActionHandler)&BuildNewBaseState::btnRotateLeftPress);
95 _btnRotateLeft->onMouseRelease((ActionHandler)&BuildNewBaseState::btnRotateLeftRelease);
96 _btnRotateLeft->onKeyboardPress((ActionHandler)&BuildNewBaseState::btnRotateLeftPress, Options::keyGeoLeft);
97 _btnRotateLeft->onKeyboardRelease((ActionHandler)&BuildNewBaseState::btnRotateLeftRelease, Options::keyGeoLeft);
98
99 _btnRotateRight->onMousePress((ActionHandler)&BuildNewBaseState::btnRotateRightPress);
100 _btnRotateRight->onMouseRelease((ActionHandler)&BuildNewBaseState::btnRotateRightRelease);
101 _btnRotateRight->onKeyboardPress((ActionHandler)&BuildNewBaseState::btnRotateRightPress, Options::keyGeoRight);
102 _btnRotateRight->onKeyboardRelease((ActionHandler)&BuildNewBaseState::btnRotateRightRelease, Options::keyGeoRight);
103
104 _btnRotateUp->onMousePress((ActionHandler)&BuildNewBaseState::btnRotateUpPress);
105 _btnRotateUp->onMouseRelease((ActionHandler)&BuildNewBaseState::btnRotateUpRelease);
106 _btnRotateUp->onKeyboardPress((ActionHandler)&BuildNewBaseState::btnRotateUpPress, Options::keyGeoUp);
107 _btnRotateUp->onKeyboardRelease((ActionHandler)&BuildNewBaseState::btnRotateUpRelease, Options::keyGeoUp);
108
109 _btnRotateDown->onMousePress((ActionHandler)&BuildNewBaseState::btnRotateDownPress);
110 _btnRotateDown->onMouseRelease((ActionHandler)&BuildNewBaseState::btnRotateDownRelease);
111 _btnRotateDown->onKeyboardPress((ActionHandler)&BuildNewBaseState::btnRotateDownPress, Options::keyGeoDown);
112 _btnRotateDown->onKeyboardRelease((ActionHandler)&BuildNewBaseState::btnRotateDownRelease, Options::keyGeoDown);
113
114 _btnZoomIn->onMouseClick((ActionHandler)&BuildNewBaseState::btnZoomInLeftClick, SDL_BUTTON_LEFT);
115 _btnZoomIn->onMouseClick((ActionHandler)&BuildNewBaseState::btnZoomInRightClick, SDL_BUTTON_RIGHT);
116 _btnZoomIn->onKeyboardPress((ActionHandler)&BuildNewBaseState::btnZoomInLeftClick, Options::keyGeoZoomIn);
117
118 _btnZoomOut->onMouseClick((ActionHandler)&BuildNewBaseState::btnZoomOutLeftClick, SDL_BUTTON_LEFT);
119 _btnZoomOut->onMouseClick((ActionHandler)&BuildNewBaseState::btnZoomOutRightClick, SDL_BUTTON_RIGHT);
120 _btnZoomOut->onKeyboardPress((ActionHandler)&BuildNewBaseState::btnZoomOutLeftClick, Options::keyGeoZoomOut);
121
122 // dirty hacks to get the rotate buttons to work in "classic" style
123 _btnRotateLeft->setListButton();
124 _btnRotateRight->setListButton();
125 _btnRotateUp->setListButton();
126 _btnRotateDown->setListButton();
127
128 _window->setColor(Palette::blockOffset(15)-1);
129 _window->setBackground(_game->getResourcePack()->getSurface("BACK01.SCR"));
130
131 _btnCancel->setColor(Palette::blockOffset(15)-1);
132 _btnCancel->setText(tr("STR_CANCEL_UC"));
133 _btnCancel->onMouseClick((ActionHandler)&BuildNewBaseState::btnCancelClick);
134 _btnCancel->onKeyboardPress((ActionHandler)&BuildNewBaseState::btnCancelClick, Options::keyCancel);
135
136 _txtTitle->setColor(Palette::blockOffset(15)-1);
137 _txtTitle->setText(tr("STR_SELECT_SITE_FOR_NEW_BASE"));
138 _txtTitle->setVerticalAlign(ALIGN_MIDDLE);
139 _txtTitle->setWordWrap(true);
140
141 if (_first)
142 {
143 _btnCancel->setVisible(false);
144 }
145 }
146
147 /**
148 *
149 */
~BuildNewBaseState()150 BuildNewBaseState::~BuildNewBaseState()
151 {
152 if (Options::globeRadarLines != _oldshowradar)
153 {
154 Options::globeRadarLines = false;
155 }
156 delete _hoverTimer;
157 }
158
159 /**
160 * Stops the globe and adds radar hover effect.
161 */
init()162 void BuildNewBaseState::init()
163 {
164 State::init();
165 _globe->onMouseOver((ActionHandler)&BuildNewBaseState::globeHover);
166 _globe->rotateStop();
167 _globe->setNewBaseHover();
168 }
169
170 /**
171 * Runs the globe rotation timer.
172 */
think()173 void BuildNewBaseState::think()
174 {
175 State::think();
176 _globe->think();
177 _hoverTimer->think(this, 0);
178 }
179
180 /**
181 * Handles the globe.
182 * @param action Pointer to an action.
183 */
handle(Action * action)184 void BuildNewBaseState::handle(Action *action)
185 {
186 State::handle(action);
187 _globe->handle(action, this);
188 }
189
190 /**
191 * Processes mouse-hover event for base placement,
192 * @param action Pointer to an action.
193 */
globeHover(Action * action)194 void BuildNewBaseState::globeHover(Action *action)
195 {
196 _mousex = (int)floor(action->getAbsoluteXMouse());
197 _mousey = (int)floor(action->getAbsoluteYMouse());
198 if (!_hoverTimer->isRunning()) _hoverTimer->start();
199 }
200
hoverRedraw(void)201 void BuildNewBaseState::hoverRedraw(void)
202 {
203 double lon, lat;
204 _globe->cartToPolar(_mousex, _mousey, &lon, &lat);
205 if (lon == lon && lat == lat)
206 {
207 _globe->setNewBaseHoverPos(lon,lat);
208 _globe->setNewBaseHover();
209 }
210 if (Options::globeRadarLines && !(AreSame(_oldlat, lat) && AreSame(_oldlon, lon)) )
211 {
212 _oldlat=lat;
213 _oldlon=lon;
214 _globe->invalidate();
215 }
216 }
217
218 /**
219 * Processes any left-clicks for base placement,
220 * or right-clicks to scroll the globe.
221 * @param action Pointer to an action.
222 */
globeClick(Action * action)223 void BuildNewBaseState::globeClick(Action *action)
224 {
225 double lon, lat;
226 int mouseX = (int)floor(action->getAbsoluteXMouse()), mouseY = (int)floor(action->getAbsoluteYMouse());
227 _globe->cartToPolar(mouseX, mouseY, &lon, &lat);
228
229 // Ignore window clicks
230 if (mouseY < 28)
231 {
232 return;
233 }
234
235 // Clicking on land for a base location
236 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
237 {
238 if (_globe->insideLand(lon, lat))
239 {
240 _base->setLongitude(lon);
241 _base->setLatitude(lat);
242 for (std::vector<Craft*>::iterator i = _base->getCrafts()->begin(); i != _base->getCrafts()->end(); ++i)
243 {
244 (*i)->setLongitude(lon);
245 (*i)->setLatitude(lat);
246 }
247 if (_first)
248 {
249 _game->pushState(new BaseNameState(_game, _base, _globe, _first));
250 }
251 else
252 {
253 _game->pushState(new ConfirmNewBaseState(_game, _base, _globe));
254 }
255 }
256 }
257 }
258
259 /**
260 * Starts rotating the globe to the left.
261 * @param action Pointer to an action.
262 */
btnRotateLeftPress(Action *)263 void BuildNewBaseState::btnRotateLeftPress(Action *)
264 {
265 _globe->rotateLeft();
266 }
267
268 /**
269 * Stops rotating the globe to the left.
270 * @param action Pointer to an action.
271 */
btnRotateLeftRelease(Action *)272 void BuildNewBaseState::btnRotateLeftRelease(Action *)
273 {
274 _globe->rotateStopLon();
275 }
276
277 /**
278 * Starts rotating the globe to the right.
279 * @param action Pointer to an action.
280 */
btnRotateRightPress(Action *)281 void BuildNewBaseState::btnRotateRightPress(Action *)
282 {
283 _globe->rotateRight();
284 }
285
286 /**
287 * Stops rotating the globe to the right.
288 * @param action Pointer to an action.
289 */
btnRotateRightRelease(Action *)290 void BuildNewBaseState::btnRotateRightRelease(Action *)
291 {
292 _globe->rotateStopLon();
293 }
294
295 /**
296 * Starts rotating the globe upwards.
297 * @param action Pointer to an action.
298 */
btnRotateUpPress(Action *)299 void BuildNewBaseState::btnRotateUpPress(Action *)
300 {
301 _globe->rotateUp();
302 }
303
304 /**
305 * Stops rotating the globe upwards.
306 * @param action Pointer to an action.
307 */
btnRotateUpRelease(Action *)308 void BuildNewBaseState::btnRotateUpRelease(Action *)
309 {
310 _globe->rotateStopLat();
311 }
312
313 /**
314 * Starts rotating the globe downwards.
315 * @param action Pointer to an action.
316 */
btnRotateDownPress(Action *)317 void BuildNewBaseState::btnRotateDownPress(Action *)
318 {
319 _globe->rotateDown();
320 }
321
322 /**
323 * Stops rotating the globe downwards.
324 * @param action Pointer to an action.
325 */
btnRotateDownRelease(Action *)326 void BuildNewBaseState::btnRotateDownRelease(Action *)
327 {
328 _globe->rotateStopLat();
329 }
330
331 /**
332 * Zooms into the globe.
333 * @param action Pointer to an action.
334 */
btnZoomInLeftClick(Action *)335 void BuildNewBaseState::btnZoomInLeftClick(Action *)
336 {
337 _globe->zoomIn();
338 }
339
340 /**
341 * Zooms the globe maximum.
342 * @param action Pointer to an action.
343 */
btnZoomInRightClick(Action *)344 void BuildNewBaseState::btnZoomInRightClick(Action *)
345 {
346 _globe->zoomMax();
347 }
348
349 /**
350 * Zooms out of the globe.
351 * @param action Pointer to an action.
352 */
btnZoomOutLeftClick(Action *)353 void BuildNewBaseState::btnZoomOutLeftClick(Action *)
354 {
355 _globe->zoomOut();
356 }
357
358 /**
359 * Zooms the globe minimum.
360 * @param action Pointer to an action.
361 */
btnZoomOutRightClick(Action *)362 void BuildNewBaseState::btnZoomOutRightClick(Action *)
363 {
364 _globe->zoomMin();
365 }
366
367 /**
368 * Returns to the previous screen.
369 * @param action Pointer to an action.
370 */
btnCancelClick(Action *)371 void BuildNewBaseState::btnCancelClick(Action *)
372 {
373 delete _base;
374 _game->popState();
375 }
376
377 /**
378 * Updates the scale.
379 * @param dX delta of X;
380 * @param dY delta of Y;
381 */
resize(int & dX,int & dY)382 void BuildNewBaseState::resize(int &dX, int &dY)
383 {
384 for (std::vector<Surface*>::const_iterator i = _surfaces.begin(); i != _surfaces.end(); ++i)
385 {
386 (*i)->setX((*i)->getX() + dX / 2);
387 if (*i != _window && *i != _btnCancel && *i != _txtTitle)
388 {
389 (*i)->setY((*i)->getY() + dY / 2);
390 }
391 }
392 }
393 }
394