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 "BasescapeState.h"
20 #include "../Engine/Game.h"
21 #include "../Resource/ResourcePack.h"
22 #include "../Engine/Language.h"
23 #include "../Engine/Palette.h"
24 #include "../Engine/Options.h"
25 #include "../Interface/TextButton.h"
26 #include "../Interface/Text.h"
27 #include "../Interface/TextEdit.h"
28 #include "BaseView.h"
29 #include "MiniBaseView.h"
30 #include "../Savegame/SavedGame.h"
31 #include "../Savegame/Base.h"
32 #include "../Savegame/BaseFacility.h"
33 #include "../Ruleset/RuleBaseFacility.h"
34 #include "../Savegame/Region.h"
35 #include "../Ruleset/RuleRegion.h"
36 #include "../Geoscape/GeoscapeState.h"
37 #include "../Menu/ErrorMessageState.h"
38 #include "DismantleFacilityState.h"
39 #include "../Geoscape/BuildNewBaseState.h"
40 #include "../Engine/Action.h"
41 #include "../Savegame/Craft.h"
42 #include "BaseInfoState.h"
43 #include "SoldiersState.h"
44 #include "CraftsState.h"
45 #include "BuildFacilitiesState.h"
46 #include "ResearchState.h"
47 #include "ManageAlienContainmentState.h"
48 #include "ManufactureState.h"
49 #include "PurchaseState.h"
50 #include "SellState.h"
51 #include "TransferBaseState.h"
52 #include "CraftInfoState.h"
53 #include "../Geoscape/AllocatePsiTrainingState.h"
54 
55 namespace OpenXcom
56 {
57 
58 /**
59  * Initializes all the elements in the Basescape screen.
60  * @param game Pointer to the core game.
61  * @param base Pointer to the base to get info from.
62  * @param globe Pointer to the Geoscape globe.
63  */
BasescapeState(Game * game,Base * base,Globe * globe)64 BasescapeState::BasescapeState(Game *game, Base *base, Globe *globe) : State(game), _base(base), _globe(globe)
65 {
66 	// Create objects
67 	_txtFacility = new Text(192, 9, 0, 0);
68 	_view = new BaseView(192, 192, 0, 8);
69 	_mini = new MiniBaseView(128, 16, 192, 41);
70 	_edtBase = new TextEdit(this, 127, 17, 193, 0);
71 	_txtLocation = new Text(126, 9, 194, 16);
72 	_txtFunds = new Text(126, 9, 194, 24);
73 	_btnNewBase = new TextButton(128, 12, 192, 58);
74 	_btnBaseInfo = new TextButton(128, 12, 192, 71);
75 	_btnSoldiers = new TextButton(128, 12, 192, 84);
76 	_btnCrafts = new TextButton(128, 12, 192, 97);
77 	_btnFacilities = new TextButton(128, 12, 192, 110);
78 	_btnResearch = new TextButton(128, 12, 192, 123);
79 	_btnManufacture = new TextButton(128, 12, 192, 136);
80 	_btnTransfer = new TextButton(128, 12, 192, 149);
81 	_btnPurchase = new TextButton(128, 12, 192, 162);
82 	_btnSell = new TextButton(128, 12, 192, 175);
83 	_btnGeoscape = new TextButton(128, 12, 192, 188);
84 
85 	// Set palette
86 	setPalette("PAL_BASESCAPE");
87 
88 	add(_view);
89 	add(_mini);
90 	add(_txtFacility);
91 	add(_edtBase);
92 	add(_txtLocation);
93 	add(_txtFunds);
94 	add(_btnNewBase);
95 	add(_btnBaseInfo);
96 	add(_btnSoldiers);
97 	add(_btnCrafts);
98 	add(_btnFacilities);
99 	add(_btnResearch);
100 	add(_btnManufacture);
101 	add(_btnTransfer);
102 	add(_btnPurchase);
103 	add(_btnSell);
104 	add(_btnGeoscape);
105 
106 	centerAllSurfaces();
107 
108 	// Set up objects
109 	_view->setTexture(_game->getResourcePack()->getSurfaceSet("BASEBITS.PCK"));
110 	_view->onMouseClick((ActionHandler)&BasescapeState::viewLeftClick, SDL_BUTTON_LEFT);
111 	_view->onMouseClick((ActionHandler)&BasescapeState::viewRightClick, SDL_BUTTON_RIGHT);
112 	_view->onMouseOver((ActionHandler)&BasescapeState::viewMouseOver);
113 	_view->onMouseOut((ActionHandler)&BasescapeState::viewMouseOut);
114 
115 	_mini->setTexture(_game->getResourcePack()->getSurfaceSet("BASEBITS.PCK"));
116 	_mini->setBases(_game->getSavedGame()->getBases());
117 	_mini->onMouseClick((ActionHandler)&BasescapeState::miniClick);
118 	_mini->onKeyboardPress((ActionHandler)&BasescapeState::handleKeyPress);
119 
120 	_txtFacility->setColor(Palette::blockOffset(13)+10);
121 
122 	_edtBase->setColor(Palette::blockOffset(15)+1);
123 	_edtBase->setBig();
124 	_edtBase->onChange((ActionHandler)&BasescapeState::edtBaseChange);
125 
126 	_txtLocation->setColor(Palette::blockOffset(15)+6);
127 
128 	_txtFunds->setColor(Palette::blockOffset(13)+10);
129 
130 	_btnNewBase->setColor(Palette::blockOffset(13)+5);
131 	_btnNewBase->setText(tr("STR_BUILD_NEW_BASE_UC"));
132 	_btnNewBase->onMouseClick((ActionHandler)&BasescapeState::btnNewBaseClick);
133 
134 	_btnBaseInfo->setColor(Palette::blockOffset(13)+5);
135 	_btnBaseInfo->setText(tr("STR_BASE_INFORMATION"));
136 	_btnBaseInfo->onMouseClick((ActionHandler)&BasescapeState::btnBaseInfoClick);
137 
138 	_btnSoldiers->setColor(Palette::blockOffset(13)+5);
139 	_btnSoldiers->setText(tr("STR_SOLDIERS_UC"));
140 	_btnSoldiers->onMouseClick((ActionHandler)&BasescapeState::btnSoldiersClick);
141 
142 	_btnCrafts->setColor(Palette::blockOffset(13)+5);
143 	_btnCrafts->setText(tr("STR_EQUIP_CRAFT"));
144 	_btnCrafts->onMouseClick((ActionHandler)&BasescapeState::btnCraftsClick);
145 
146 	_btnFacilities->setColor(Palette::blockOffset(13)+5);
147 	_btnFacilities->setText(tr("STR_BUILD_FACILITIES"));
148 	_btnFacilities->onMouseClick((ActionHandler)&BasescapeState::btnFacilitiesClick);
149 
150 	_btnResearch->setColor(Palette::blockOffset(13)+5);
151 	_btnResearch->setText(tr("STR_RESEARCH"));
152 	_btnResearch->onMouseClick((ActionHandler)&BasescapeState::btnResearchClick);
153 
154 	_btnManufacture->setColor(Palette::blockOffset(13)+5);
155 	_btnManufacture->setText(tr("STR_MANUFACTURE"));
156 	_btnManufacture->onMouseClick((ActionHandler)&BasescapeState::btnManufactureClick);
157 
158 	_btnTransfer->setColor(Palette::blockOffset(13)+5);
159 	_btnTransfer->setText(tr("STR_TRANSFER_UC"));
160 	_btnTransfer->onMouseClick((ActionHandler)&BasescapeState::btnTransferClick);
161 
162 	_btnPurchase->setColor(Palette::blockOffset(13)+5);
163 	_btnPurchase->setText(tr("STR_PURCHASE_RECRUIT"));
164 	_btnPurchase->onMouseClick((ActionHandler)&BasescapeState::btnPurchaseClick);
165 
166 	_btnSell->setColor(Palette::blockOffset(13)+5);
167 	_btnSell->setText(tr("STR_SELL_SACK_UC"));
168 	_btnSell->onMouseClick((ActionHandler)&BasescapeState::btnSellClick);
169 
170 	_btnGeoscape->setColor(Palette::blockOffset(13)+5);
171 	_btnGeoscape->setText(tr("STR_GEOSCAPE_UC"));
172 	_btnGeoscape->onMouseClick((ActionHandler)&BasescapeState::btnGeoscapeClick);
173 	_btnGeoscape->onKeyboardPress((ActionHandler)&BasescapeState::btnGeoscapeClick, Options::keyCancel);
174 }
175 
176 /**
177  *
178  */
~BasescapeState()179 BasescapeState::~BasescapeState()
180 {
181 	// Clean up any temporary bases
182 	bool exists = false;
183 	for (std::vector<Base*>::iterator i = _game->getSavedGame()->getBases()->begin(); i != _game->getSavedGame()->getBases()->end() && !exists; ++i)
184 	{
185 		if (*i == _base)
186 		{
187 			exists = true;
188 			break;
189 		}
190 	}
191 	if (!exists)
192 	{
193 		delete _base;
194 	}
195 }
196 
197 /**
198  * The player can change the selected base
199  * or change info on other screens.
200  */
init()201 void BasescapeState::init()
202 {
203 	State::init();
204 
205 	setBase(_base);
206 	_view->setBase(_base);
207 	_mini->draw();
208 	_edtBase->setText(_base->getName());
209 
210 	// Get area
211 	for (std::vector<Region*>::iterator i = _game->getSavedGame()->getRegions()->begin(); i != _game->getSavedGame()->getRegions()->end(); ++i)
212 	{
213 		if ((*i)->getRules()->insideRegion(_base->getLongitude(), _base->getLatitude()))
214 		{
215 			_txtLocation->setText(tr((*i)->getRules()->getType()));
216 			break;
217 		}
218 	}
219 
220 	_txtFunds->setText(tr("STR_FUNDS").arg(Text::formatFunding(_game->getSavedGame()->getFunds())));
221 
222 	_btnNewBase->setVisible(_game->getSavedGame()->getBases()->size() < MiniBaseView::MAX_BASES);
223 }
224 
225 /**
226  * Changes the base currently displayed on screen.
227  * @param base Pointer to new base to display.
228  */
setBase(Base * base)229 void BasescapeState::setBase(Base *base)
230 {
231 	if (!_game->getSavedGame()->getBases()->empty())
232 	{
233 		// Check if base still exists
234 		bool exists = false;
235 		for (size_t i = 0; i < _game->getSavedGame()->getBases()->size(); ++i)
236 		{
237 			if (_game->getSavedGame()->getBases()->at(i) == base)
238 			{
239 				_base = base;
240 				_mini->setSelectedBase(i);
241 				_game->getSavedGame()->setSelectedBase(i);
242 				exists = true;
243 				break;
244 			}
245 		}
246 		// If base was removed, select first one
247 		if (!exists)
248 		{
249 			_base = _game->getSavedGame()->getBases()->front();
250 			_mini->setSelectedBase(0);
251 			_game->getSavedGame()->setSelectedBase(0);
252 		}
253 	}
254 	else
255 	{
256 		// Use a blank base for special case when player has no bases
257 		_base = new Base(_game->getRuleset());
258 		_mini->setSelectedBase(0);
259 		_game->getSavedGame()->setSelectedBase(0);
260 	}
261 }
262 
263 /**
264  * Goes to the Build New Base screen.
265  * @param action Pointer to an action.
266  */
btnNewBaseClick(Action *)267 void BasescapeState::btnNewBaseClick(Action *)
268 {
269 	Base *base = new Base(_game->getRuleset());
270 	_game->popState();
271 	_game->pushState(new BuildNewBaseState(_game, base, _globe, false));
272 }
273 
274 /**
275  * Goes to the Base Info screen.
276  * @param action Pointer to an action.
277  */
btnBaseInfoClick(Action *)278 void BasescapeState::btnBaseInfoClick(Action *)
279 {
280 	_game->pushState(new BaseInfoState(_game, _base, this));
281 }
282 
283 /**
284  * Goes to the Soldiers screen.
285  * @param action Pointer to an action.
286  */
btnSoldiersClick(Action *)287 void BasescapeState::btnSoldiersClick(Action *)
288 {
289 	_game->pushState(new SoldiersState(_game, _base));
290 }
291 
292 /**
293  * Goes to the Crafts screen.
294  * @param action Pointer to an action.
295  */
btnCraftsClick(Action *)296 void BasescapeState::btnCraftsClick(Action *)
297 {
298 	_game->pushState(new CraftsState(_game, _base));
299 }
300 
301 /**
302  * Opens the Build Facilities window.
303  * @param action Pointer to an action.
304  */
btnFacilitiesClick(Action *)305 void BasescapeState::btnFacilitiesClick(Action *)
306 {
307 	_game->pushState(new BuildFacilitiesState(_game, _base, this));
308 }
309 
310 /**
311  * Goes to the Research screen.
312  * @param action Pointer to an action.
313  */
btnResearchClick(Action *)314 void BasescapeState::btnResearchClick(Action *)
315 {
316 	_game->pushState(new ResearchState(_game, _base));
317 }
318 
319 /**
320  * Goes to the Manufacture screen.
321  * @param action Pointer to an action.
322  */
btnManufactureClick(Action *)323 void BasescapeState::btnManufactureClick(Action *)
324 {
325 	_game->pushState(new ManufactureState(_game, _base));
326 }
327 
328 /**
329  * Goes to the Purchase screen.
330  * @param action Pointer to an action.
331  */
btnPurchaseClick(Action *)332 void BasescapeState::btnPurchaseClick(Action *)
333 {
334 	_game->pushState(new PurchaseState(_game, _base));
335 }
336 
337 /**
338  * Goes to the Sell screen.
339  * @param action Pointer to an action.
340  */
btnSellClick(Action *)341 void BasescapeState::btnSellClick(Action *)
342 {
343 	_game->pushState(new SellState(_game, _base));
344 }
345 
346 /**
347  * Goes to the Select Destination Base window.
348  * @param action Pointer to an action.
349  */
btnTransferClick(Action *)350 void BasescapeState::btnTransferClick(Action *)
351 {
352 	_game->pushState(new TransferBaseState(_game, _base));
353 }
354 
355 /**
356  * Returns to the previous screen.
357  * @param action Pointer to an action.
358  */
btnGeoscapeClick(Action *)359 void BasescapeState::btnGeoscapeClick(Action *)
360 {
361 	_game->popState();
362 }
363 
364 /**
365  * Processes clicking on facilities.
366  * @param action Pointer to an action.
367  */
viewLeftClick(Action *)368 void BasescapeState::viewLeftClick(Action *)
369 {
370 	BaseFacility *fac = _view->getSelectedFacility();
371 	if (fac != 0)
372 	{
373 		// Is facility in use?
374 		if (fac->inUse())
375 		{
376 			_game->pushState(new ErrorMessageState(_game, "STR_FACILITY_IN_USE", _palette, Palette::blockOffset(15)+1, "BACK13.SCR", 6));
377 		}
378 		// Would base become disconnected?
379 		else if (!_base->getDisconnectedFacilities(fac).empty())
380 		{
381 			_game->pushState(new ErrorMessageState(_game, "STR_CANNOT_DISMANTLE_FACILITY", _palette, Palette::blockOffset(15)+1, "BACK13.SCR", 6));
382 		}
383 		else
384 		{
385 			_game->pushState(new DismantleFacilityState(_game, _base, _view, fac));
386 		}
387 	}
388 }
389 
390 /**
391  * Processes right clicking on facilities.
392  * @param action Pointer to an action.
393  */
viewRightClick(Action *)394 void BasescapeState::viewRightClick(Action *)
395 {
396 	BaseFacility *f = _view->getSelectedFacility();
397 	if (f == 0)
398 	{
399 		_game->pushState(new BaseInfoState(_game, _base, this));
400 	}
401 	else if (f->getRules()->getCrafts() > 0)
402 	{
403 		if (f->getCraft() == 0)
404 		{
405 			_game->pushState(new CraftsState(_game, _base));
406 		}
407 		else
408 			for (size_t craft = 0; craft < _base->getCrafts()->size(); ++craft)
409 			{
410 				if (f->getCraft() == _base->getCrafts()->at(craft))
411 				{
412 					_game->pushState(new CraftInfoState(_game, _base, craft));
413 					break;
414 				}
415 			}
416 	}
417 	else if (f->getRules()->getStorage() > 0)
418 	{
419 		_game->pushState(new SellState(_game, _base));
420 	}
421 	else if (f->getRules()->getPersonnel() > 0)
422 	{
423 		_game->pushState(new SoldiersState(_game, _base));
424 	}
425 	else if (f->getRules()->getPsiLaboratories() > 0 && Options::anytimePsiTraining && _base->getAvailablePsiLabs() > 0)
426 	{
427 		_game->pushState(new AllocatePsiTrainingState(_game, _base));
428 	}
429 	else if (f->getRules()->getLaboratories() > 0)
430 	{
431 		_game->pushState(new ResearchState(_game, _base));
432 	}
433 	else if (f->getRules()->getWorkshops() > 0)
434 	{
435 		_game->pushState(new ManufactureState(_game, _base));
436 	}
437 	else if (f->getRules()->getAliens() > 0)
438 	{
439 		_game->pushState(new ManageAlienContainmentState(_game, _base, OPT_GEOSCAPE));
440 	}
441 	else if (f->getRules()->isLift() || f->getRules()->getRadarRange() > 0)
442 	{
443 		_game->popState();
444 	}
445 }
446 
447 /**
448  * Displays the name of the facility the mouse is over.
449  * @param action Pointer to an action.
450  */
viewMouseOver(Action *)451 void BasescapeState::viewMouseOver(Action *)
452 {
453 	BaseFacility *f = _view->getSelectedFacility();
454 	std::wostringstream ss;
455 	if (f != 0)
456 	{
457 		if (f->getRules()->getCrafts() == 0 || f->getBuildTime() > 0)
458 		{
459 			ss << tr(f->getRules()->getType());
460 		}
461 		else
462 		{
463 			ss << tr(f->getRules()->getType());
464 			if (f->getCraft() != 0)
465 			{
466 				ss << L" " << tr("STR_CRAFT_").arg(f->getCraft()->getName(_game->getLanguage()));
467 			}
468 		}
469 	}
470 	_txtFacility->setText(ss.str());
471 }
472 
473 /**
474  * Clears the facility name.
475  * @param action Pointer to an action.
476  */
viewMouseOut(Action *)477 void BasescapeState::viewMouseOut(Action *)
478 {
479 	_txtFacility->setText(L"");
480 }
481 
482 /**
483  * Selects a new base to display.
484  * @param action Pointer to an action.
485  */
miniClick(Action *)486 void BasescapeState::miniClick(Action *)
487 {
488 	size_t base = _mini->getHoveredBase();
489 	if (base < _game->getSavedGame()->getBases()->size())
490 	{
491 		_base = _game->getSavedGame()->getBases()->at(base);
492 		init();
493 	}
494 }
495 
496 /**
497  * Selects a new base to display.
498  * @param action Pointer to an action.
499  */
handleKeyPress(Action * action)500 void BasescapeState::handleKeyPress(Action *action)
501 {
502 	if (action->getDetails()->type == SDL_KEYDOWN)
503 	{
504 		SDLKey baseKeys[] = {Options::keyBaseSelect1,
505 			                 Options::keyBaseSelect2,
506 			                 Options::keyBaseSelect3,
507 			                 Options::keyBaseSelect4,
508 			                 Options::keyBaseSelect5,
509 			                 Options::keyBaseSelect6,
510 			                 Options::keyBaseSelect7,
511 			                 Options::keyBaseSelect8};
512 		int key = action->getDetails()->key.keysym.sym;
513 		for (size_t i = 0; i < _game->getSavedGame()->getBases()->size(); ++i)
514 		{
515 			if (key == baseKeys[i])
516 			{
517 				_base = _game->getSavedGame()->getBases()->at(i);
518 				init();
519 				break;
520 			}
521 		}
522 	}
523 }
524 
525 /**
526  * Changes the Base name.
527  * @param action Pointer to an action.
528  */
edtBaseChange(Action * action)529 void BasescapeState::edtBaseChange(Action *action)
530 {
531 	_base->setName(_edtBase->getText());
532 }
533 
534 }
535