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