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 "CraftInfoState.h"
20 #include <cmath>
21 #include <sstream>
22 #include "../Engine/Game.h"
23 #include "../Resource/ResourcePack.h"
24 #include "../Engine/Language.h"
25 #include "../Engine/Palette.h"
26 #include "../Engine/Options.h"
27 #include "../Interface/TextButton.h"
28 #include "../Interface/Window.h"
29 #include "../Interface/Text.h"
30 #include "../Interface/TextEdit.h"
31 #include "../Engine/SurfaceSet.h"
32 #include "../Engine/Action.h"
33 #include "../Savegame/Craft.h"
34 #include "../Ruleset/RuleCraft.h"
35 #include "../Savegame/CraftWeapon.h"
36 #include "../Ruleset/RuleCraftWeapon.h"
37 #include "../Savegame/Base.h"
38 #include "../Savegame/SavedGame.h"
39 #include "CraftSoldiersState.h"
40 #include "CraftWeaponsState.h"
41 #include "CraftEquipmentState.h"
42 #include "CraftArmorState.h"
43 
44 namespace OpenXcom
45 {
46 
47 /**
48  * Initializes all the elements in the Craft Info screen.
49  * @param game Pointer to the core game.
50  * @param base Pointer to the base to get info from.
51  * @param craftId ID of the selected craft.
52  */
CraftInfoState(Game * game,Base * base,size_t craftId)53 CraftInfoState::CraftInfoState(Game *game, Base *base, size_t craftId) : State(game), _base(base), _craftId(craftId)
54 {
55 	// Create objects
56 	if (_game->getSavedGame()->getMonthsPassed() != -1)
57 	{
58 		_window = new Window(this, 320, 200, 0, 0, POPUP_BOTH);
59 	}
60 	else
61 	{
62 		_window = new Window(this, 320, 200, 0, 0, POPUP_NONE);
63 	}
64 	_btnOk = new TextButton(64, 24, 128, 168);
65 	_btnW1 = new TextButton(24, 32, 14, 48);
66 	_btnW2 = new TextButton(24, 32, 282, 48);
67 	_btnCrew = new TextButton(64, 16, 14, 96);
68 	_btnEquip = new TextButton(64, 16, 14, 120);
69 	_btnArmor = new TextButton(64, 16, 14, 144);
70 	_edtCraft = new TextEdit(this, 140, 16, 80, 8);
71 	_txtDamage = new Text(100, 17, 14, 24);
72 	_txtFuel = new Text(82, 17, 228, 24);
73 	_txtW1Name = new Text(75, 16, 46, 48);
74 	_txtW1Ammo = new Text(75, 24, 46, 64);
75 	_txtW2Name = new Text(75, 16, 204, 48);
76 	_txtW2Ammo = new Text(75, 24, 204, 64);
77 	_sprite = new Surface(32, 40, 144, 52);
78 	_weapon1 = new Surface(15, 17, 121, 63);
79 	_weapon2 = new Surface(15, 17, 184, 63);
80 	_crew = new Surface(220, 18, 85, 96);
81 	_equip = new Surface(220, 18, 85, 121);
82 
83 	// Set palette
84 	setPalette("PAL_BASESCAPE", 3);
85 
86 	add(_window);
87 	add(_btnOk);
88 	add(_btnW1);
89 	add(_btnW2);
90 	add(_btnCrew);
91 	add(_btnEquip);
92 	add(_btnArmor);
93 	add(_edtCraft);
94 	add(_txtDamage);
95 	add(_txtFuel);
96 	add(_txtW1Name);
97 	add(_txtW1Ammo);
98 	add(_txtW2Name);
99 	add(_txtW2Ammo);
100 	add(_sprite);
101 	add(_weapon1);
102 	add(_weapon2);
103 	add(_crew);
104 	add(_equip);
105 
106 	centerAllSurfaces();
107 
108 	// Set up objects
109 	_window->setColor(Palette::blockOffset(13)+10);
110 	_window->setBackground(_game->getResourcePack()->getSurface("BACK14.SCR"));
111 
112 	_btnOk->setColor(Palette::blockOffset(13)+10);
113 	_btnOk->setText(tr("STR_OK"));
114 	_btnOk->onMouseClick((ActionHandler)&CraftInfoState::btnOkClick);
115 	_btnOk->onKeyboardPress((ActionHandler)&CraftInfoState::btnOkClick, Options::keyCancel);
116 
117 	_btnW1->setColor(Palette::blockOffset(13)+10);
118 	_btnW1->setText(L"1");
119 	_btnW1->onMouseClick((ActionHandler)&CraftInfoState::btnW1Click);
120 
121 	_btnW2->setColor(Palette::blockOffset(13)+10);
122 	_btnW2->setText(L"2");
123 	_btnW2->onMouseClick((ActionHandler)&CraftInfoState::btnW2Click);
124 
125 	_btnCrew->setColor(Palette::blockOffset(13)+10);
126 	_btnCrew->setText(tr("STR_CREW"));
127 	_btnCrew->onMouseClick((ActionHandler)&CraftInfoState::btnCrewClick);
128 
129 	_btnEquip->setColor(Palette::blockOffset(13)+10);
130 	_btnEquip->setText(tr("STR_EQUIPMENT_UC"));
131 	_btnEquip->onMouseClick((ActionHandler)&CraftInfoState::btnEquipClick);
132 
133 	_btnArmor->setColor(Palette::blockOffset(13)+10);
134 	_btnArmor->setText(tr("STR_ARMOR"));
135 	_btnArmor->onMouseClick((ActionHandler)&CraftInfoState::btnArmorClick);
136 
137 	_edtCraft->setColor(Palette::blockOffset(13)+10);
138 	_edtCraft->setBig();
139 	_edtCraft->setAlign(ALIGN_CENTER);
140 	_edtCraft->onChange((ActionHandler)&CraftInfoState::edtCraftChange);
141 
142 	_txtDamage->setColor(Palette::blockOffset(13)+10);
143 	_txtDamage->setSecondaryColor(Palette::blockOffset(13));
144 
145 	_txtFuel->setColor(Palette::blockOffset(13)+10);
146 	_txtFuel->setSecondaryColor(Palette::blockOffset(13));
147 
148 	_txtW1Name->setColor(Palette::blockOffset(13)+5);
149 	_txtW1Name->setWordWrap(true);
150 
151 	_txtW1Ammo->setColor(Palette::blockOffset(13)+10);
152 	_txtW1Ammo->setSecondaryColor(Palette::blockOffset(13)+5);
153 
154 	_txtW2Name->setColor(Palette::blockOffset(13)+5);
155 	_txtW2Name->setWordWrap(true);
156 
157 	_txtW2Ammo->setColor(Palette::blockOffset(13)+10);
158 	_txtW2Ammo->setSecondaryColor(Palette::blockOffset(13)+5);
159 }
160 
161 /**
162  *
163  */
~CraftInfoState()164 CraftInfoState::~CraftInfoState()
165 {
166 
167 }
168 
169 /**
170  * The craft info can change
171  * after going into other screens.
172  */
init()173 void CraftInfoState::init()
174 {
175 	State::init();
176 
177 	_craft = _base->getCrafts()->at(_craftId);
178 
179 	_edtCraft->setText(_craft->getName(_game->getLanguage()));
180 
181 	SurfaceSet *texture = _game->getResourcePack()->getSurfaceSet("BASEBITS.PCK");
182 	texture->getFrame(_craft->getRules()->getSprite() + 33)->setX(0);
183 	texture->getFrame(_craft->getRules()->getSprite() + 33)->setY(0);
184 	texture->getFrame(_craft->getRules()->getSprite() + 33)->blit(_sprite);
185 
186 	std::wostringstream ss;
187 	ss << tr("STR_DAMAGE_UC_").arg(Text::formatPercentage(_craft->getDamagePercentage()));
188 	if (_craft->getStatus() == "STR_REPAIRS" && _craft->getDamage() > 0)
189 	{
190 		int damageHours = (int)ceil((double)_craft->getDamage() / _craft->getRules()->getRepairRate());
191 		ss << formatTime(damageHours);
192 	}
193 	_txtDamage->setText(ss.str());
194 
195 	std::wostringstream ss2;
196 	ss2 << tr("STR_FUEL").arg(Text::formatPercentage(_craft->getFuelPercentage()));
197 	if (_craft->getStatus() == "STR_REFUELLING" && _craft->getRules()->getMaxFuel() - _craft->getFuel() > 0)
198 	{
199 		int fuelHours = (int)ceil((double)(_craft->getRules()->getMaxFuel() - _craft->getFuel()) / _craft->getRules()->getRefuelRate() / 2.0);
200 		ss2 << formatTime(fuelHours);
201 	}
202 	_txtFuel->setText(ss2.str());
203 
204 	if (_craft->getRules()->getSoldiers() > 0)
205 	{
206 		_crew->clear();
207 		_equip->clear();
208 
209 		Surface *frame1 = texture->getFrame(38);
210 		frame1->setY(0);
211 		for (int i = 0, x = 0; i < _craft->getNumSoldiers(); ++i, x += 10)
212 		{
213 			frame1->setX(x);
214 			frame1->blit(_crew);
215 		}
216 
217 		Surface *frame2 = texture->getFrame(40);
218 		frame2->setY(0);
219 		int x = 0;
220 		for (int i = 0; i < _craft->getNumVehicles(); ++i, x += 10)
221 		{
222 			frame2->setX(x);
223 			frame2->blit(_equip);
224 		}
225 		Surface *frame3 = texture->getFrame(39);
226 		for (int i = 0; i < _craft->getNumEquipment(); i += 4, x += 10)
227 		{
228 			frame3->setX(x);
229 			frame3->blit(_equip);
230 		}
231 	}
232 	else
233 	{
234 		_crew->setVisible(false);
235 		_equip->setVisible(false);
236 		_btnCrew->setVisible(false);
237 		_btnEquip->setVisible(false);
238 		_btnArmor->setVisible(false);
239 	}
240 
241 	if (_craft->getRules()->getWeapons() > 0)
242 	{
243 		CraftWeapon *w1 = _craft->getWeapons()->at(0);
244 
245 		if (w1 != 0)
246 		{
247 			Surface *frame = texture->getFrame(w1->getRules()->getSprite() + 48);
248 			frame->setX(0);
249 			frame->setY(0);
250 			frame->blit(_weapon1);
251 
252 			_txtW1Name->setText(tr(w1->getRules()->getType()));
253 			std::wostringstream ss;
254 			ss << tr("STR_AMMO_").arg(w1->getAmmo()) << L"\n\x01";
255 			ss << tr("STR_MAX").arg(w1->getRules()->getAmmoMax());
256 			if (_craft->getStatus() == "STR_REARMING" && w1->getAmmo() < w1->getRules()->getAmmoMax())
257 			{
258 				int rearmHours = (int)ceil((double)(w1->getRules()->getAmmoMax() - w1->getAmmo()) / w1->getRules()->getRearmRate());
259 				ss << formatTime(rearmHours);
260 			}
261 			_txtW1Ammo->setText(ss.str());
262 		}
263 		else
264 		{
265 			_weapon1->clear();
266 			_txtW1Name->setText(L"");
267 			_txtW1Ammo->setText(L"");
268 		}
269 	}
270 	else
271 	{
272 		_weapon1->setVisible(false);
273 		_btnW1->setVisible(false);
274 		_txtW1Name->setVisible(false);
275 		_txtW1Ammo->setVisible(false);
276 	}
277 
278 	if (_craft->getRules()->getWeapons() > 1)
279 	{
280 		CraftWeapon *w2 = _craft->getWeapons()->at(1);
281 
282 		if (w2 != 0)
283 		{
284 			Surface *frame = texture->getFrame(w2->getRules()->getSprite() + 48);
285 			frame->setX(0);
286 			frame->setY(0);
287 			frame->blit(_weapon2);
288 
289 			_txtW2Name->setText(tr(w2->getRules()->getType()));
290 			std::wostringstream ss;
291 			ss << tr("STR_AMMO_").arg(w2->getAmmo()) << L"\n\x01";
292 			ss << tr("STR_MAX").arg(w2->getRules()->getAmmoMax());
293 			if (_craft->getStatus() == "STR_REARMING" && w2->getAmmo() < w2->getRules()->getAmmoMax())
294 			{
295 				int rearmHours = (int)ceil((double)(w2->getRules()->getAmmoMax() - w2->getAmmo()) / w2->getRules()->getRearmRate());
296 				ss << formatTime(rearmHours);
297 			}
298 			_txtW2Ammo->setText(ss.str());
299 		}
300 		else
301 		{
302 			_weapon2->clear();
303 			_txtW2Name->setText(L"");
304 			_txtW2Ammo->setText(L"");
305 		}
306 	}
307 	else
308 	{
309 		_weapon2->setVisible(false);
310 		_btnW2->setVisible(false);
311 		_txtW2Name->setVisible(false);
312 		_txtW2Ammo->setVisible(false);
313 	}
314 	_defaultName = tr("STR_CRAFTNAME").arg(tr(_craft->getRules()->getType())).arg(_craft->getId());
315 }
316 
317 /**
318  * Turns an amount of time into a
319  * day/hour string.
320  * @param total
321  */
formatTime(int total)322 std::wstring CraftInfoState::formatTime(int total)
323 {
324 	std::wostringstream ss;
325 	int days = total / 24;
326 	int hours = total % 24;
327 	ss << L"\n(";
328 	if (days > 0)
329 	{
330 		ss << tr("STR_DAY", days) << L"/";
331 	}
332 	if (hours > 0)
333 	{
334 		ss << tr("STR_HOUR", hours);
335 	}
336 	ss << L")";
337 	return ss.str();
338 }
339 
340 /**
341  * Returns to the previous screen.
342  * @param action Pointer to an action.
343  */
btnOkClick(Action *)344 void CraftInfoState::btnOkClick(Action *)
345 {
346 	_game->popState();
347 }
348 
349 /**
350  * Goes to the Select Armament window for
351  * the first weapon.
352  * @param action Pointer to an action.
353  */
btnW1Click(Action *)354 void CraftInfoState::btnW1Click(Action *)
355 {
356 	_game->pushState(new CraftWeaponsState(_game, _base, _craftId, 0));
357 }
358 
359 /**
360  * Goes to the Select Armament window for
361  * the second weapon.
362  * @param action Pointer to an action.
363  */
btnW2Click(Action *)364 void CraftInfoState::btnW2Click(Action *)
365 {
366 	_game->pushState(new CraftWeaponsState(_game, _base, _craftId, 1));
367 }
368 
369 /**
370  * Goes to the Select Squad screen.
371  * @param action Pointer to an action.
372  */
btnCrewClick(Action *)373 void CraftInfoState::btnCrewClick(Action *)
374 {
375 	_game->pushState(new CraftSoldiersState(_game, _base, _craftId));
376 }
377 
378 /**
379  * Goes to the Select Equipment screen.
380  * @param action Pointer to an action.
381  */
btnEquipClick(Action *)382 void CraftInfoState::btnEquipClick(Action *)
383 {
384 	_game->pushState(new CraftEquipmentState(_game, _base, _craftId));
385 }
386 
387 /**
388  * Goes to the Select Armor screen.
389  * @param action Pointer to an action.
390  */
btnArmorClick(Action *)391 void CraftInfoState::btnArmorClick(Action *)
392 {
393 	_game->pushState(new CraftArmorState(_game, _base, _craftId));
394 }
395 
396 /**
397  * Changes the Craft name.
398  * @param action Pointer to an action.
399  */
edtCraftChange(Action * action)400 void CraftInfoState::edtCraftChange(Action *action)
401 {
402 	_craft->setName(_edtCraft->getText());
403 	if (_craft->getName(_game->getLanguage()) == _defaultName)
404 	{
405 		_craft->setName(L"");
406 	}
407 	if (action->getDetails()->key.keysym.sym == SDLK_RETURN ||
408 		action->getDetails()->key.keysym.sym == SDLK_KP_ENTER)
409 	{
410 		_edtCraft->setText(_craft->getName(_game->getLanguage()));
411 	}
412 }
413 
414 }
415