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