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 "SellState.h"
20 #include <sstream>
21 #include <climits>
22 #include <cmath>
23 #include <iomanip>
24 #include "../Engine/Action.h"
25 #include "../Engine/Game.h"
26 #include "../Resource/ResourcePack.h"
27 #include "../Engine/Language.h"
28 #include "../Engine/Palette.h"
29 #include "../Interface/TextButton.h"
30 #include "../Interface/Window.h"
31 #include "../Interface/Text.h"
32 #include "../Interface/TextList.h"
33 #include "../Savegame/BaseFacility.h"
34 #include "../Savegame/SavedGame.h"
35 #include "../Savegame/Base.h"
36 #include "../Savegame/Soldier.h"
37 #include "../Savegame/Craft.h"
38 #include "../Savegame/ItemContainer.h"
39 #include "../Ruleset/Ruleset.h"
40 #include "../Ruleset/RuleItem.h"
41 #include "../Ruleset/Armor.h"
42 #include "../Ruleset/RuleCraft.h"
43 #include "../Savegame/CraftWeapon.h"
44 #include "../Savegame/Transfer.h"
45 #include "../Ruleset/RuleCraftWeapon.h"
46 #include "../Engine/Timer.h"
47 #include "../Engine/Options.h"
48
49 namespace OpenXcom
50 {
51
52 /**
53 * Initializes all the elements in the Sell/Sack screen.
54 * @param game Pointer to the core game.
55 * @param base Pointer to the base to get info from.
56 * @param origin Game section that originated this state.
57 */
SellState(Game * game,Base * base,OptionsOrigin origin)58 SellState::SellState(Game *game, Base *base, OptionsOrigin origin) : State(game), _base(base), _qtys(), _soldiers(), _crafts(), _items(), _sel(0), _itemOffset(0), _total(0), _hasSci(0), _hasEng(0), _spaceChange(0), _origin(origin)
59 {
60 bool overfull = Options::storageLimitsEnforced && _base->storesOverfull();
61
62 // Create objects
63 _window = new Window(this, 320, 200, 0, 0);
64 _btnOk = new TextButton(overfull? 288:148, 16, overfull? 16:8, 176);
65 _btnCancel = new TextButton(148, 16, 164, 176);
66 _txtTitle = new Text(310, 17, 5, 8);
67 _txtSales = new Text(150, 9, 10, 24);
68 _txtFunds = new Text(150, 9, 160, 24);
69 _txtSpaceUsed = new Text(150, 9, 160, 34);
70 _txtItem = new Text(130, 9, 10, Options::storageLimitsEnforced? 44:33);
71 _txtQuantity = new Text(54, 9, 126, Options::storageLimitsEnforced? 44:33);
72 _txtSell = new Text(96, 9, 180, Options::storageLimitsEnforced? 44:33);
73 _txtValue = new Text(40, 9, 260, Options::storageLimitsEnforced? 44:33);
74 _lstItems = new TextList(287, Options::storageLimitsEnforced? 112:120, 8, Options::storageLimitsEnforced? 55:44);
75
76 // Set palette
77 if (origin == OPT_BATTLESCAPE)
78 {
79 setPalette("PAL_GEOSCAPE", 0);
80 _color = Palette::blockOffset(15)-1;
81 _color2 = Palette::blockOffset(8)+10;
82 _color3 = Palette::blockOffset(8)+5;
83 _colorAmmo = Palette::blockOffset(15)+6;
84 }
85 else
86 {
87 setPalette("PAL_BASESCAPE", 0);
88 _color = Palette::blockOffset(13)+10;
89 _color2 = Palette::blockOffset(13);
90 _color3 = Palette::blockOffset(13)+5;
91 _colorAmmo = Palette::blockOffset(15)+6;
92 }
93
94 add(_window);
95 add(_btnOk);
96 add(_btnCancel);
97 add(_txtTitle);
98 add(_txtSales);
99 add(_txtFunds);
100 add(_txtSpaceUsed);
101 add(_txtItem);
102 add(_txtQuantity);
103 add(_txtSell);
104 add(_txtValue);
105 add(_lstItems);
106
107 centerAllSurfaces();
108
109 // Set up objects
110 _window->setColor(_color);
111 _window->setBackground(_game->getResourcePack()->getSurface("BACK13.SCR"));
112
113 _btnOk->setColor(_color);
114 _btnOk->setText(tr("STR_SELL_SACK"));
115 _btnOk->onMouseClick((ActionHandler)&SellState::btnOkClick);
116 _btnOk->onKeyboardPress((ActionHandler)&SellState::btnOkClick, Options::keyOk);
117
118 _btnCancel->setColor(_color);
119 _btnCancel->setText(tr("STR_CANCEL"));
120 _btnCancel->onMouseClick((ActionHandler)&SellState::btnCancelClick);
121 _btnCancel->onKeyboardPress((ActionHandler)&SellState::btnCancelClick, Options::keyCancel);
122
123 if (overfull)
124 {
125 _btnCancel->setVisible(false);
126 _btnOk->setVisible(false);
127 }
128
129 _txtTitle->setColor(_color);
130 _txtTitle->setBig();
131 _txtTitle->setAlign(ALIGN_CENTER);
132 _txtTitle->setText(tr("STR_SELL_ITEMS_SACK_PERSONNEL"));
133
134 _txtSales->setColor(_color);
135 _txtSales->setSecondaryColor(_color2);
136 _txtSales->setText(tr("STR_VALUE_OF_SALES").arg(Text::formatFunding(_total)));
137
138 _txtFunds->setColor(_color);
139 _txtFunds->setSecondaryColor(_color2);
140 _txtFunds->setText(tr("STR_FUNDS").arg(Text::formatFunding(_game->getSavedGame()->getFunds())));
141
142 _txtSpaceUsed->setColor(_color);
143 _txtSpaceUsed->setSecondaryColor(_color2);
144 _txtSpaceUsed->setVisible(Options::storageLimitsEnforced);
145
146 std::wostringstream ss5;
147 ss5 << _base->getUsedStores() << ":" << _base->getAvailableStores();
148 _txtSpaceUsed->setText(ss5.str());
149 _txtSpaceUsed->setText(tr("STR_SPACE_USED").arg(ss5.str()));
150
151 _txtItem->setColor(_color);
152 _txtItem->setText(tr("STR_ITEM"));
153
154 _txtQuantity->setColor(_color);
155 _txtQuantity->setText(tr("STR_QUANTITY_UC"));
156
157 _txtSell->setColor(_color);
158 _txtSell->setText(tr("STR_SELL_SACK"));
159
160 _txtValue->setColor(_color);
161 _txtValue->setText(tr("STR_VALUE"));
162
163 _lstItems->setColor(_color);
164 _lstItems->setArrowColumn(182, ARROW_VERTICAL);
165 _lstItems->setColumns(4, 156, 54, 24, 53);
166 _lstItems->setSelectable(true);
167 _lstItems->setBackground(_window);
168 _lstItems->setMargin(2);
169 _lstItems->onLeftArrowPress((ActionHandler)&SellState::lstItemsLeftArrowPress);
170 _lstItems->onLeftArrowRelease((ActionHandler)&SellState::lstItemsLeftArrowRelease);
171 _lstItems->onLeftArrowClick((ActionHandler)&SellState::lstItemsLeftArrowClick);
172 _lstItems->onRightArrowPress((ActionHandler)&SellState::lstItemsRightArrowPress);
173 _lstItems->onRightArrowRelease((ActionHandler)&SellState::lstItemsRightArrowRelease);
174 _lstItems->onRightArrowClick((ActionHandler)&SellState::lstItemsRightArrowClick);
175 _lstItems->onMousePress((ActionHandler)&SellState::lstItemsMousePress);
176
177 for (std::vector<Soldier*>::iterator i = _base->getSoldiers()->begin(); i != _base->getSoldiers()->end(); ++i)
178 {
179 if ((*i)->getCraft() == 0)
180 {
181 _qtys.push_back(0);
182 _soldiers.push_back(*i);
183 _lstItems->addRow(4, (*i)->getName(true).c_str(), L"1", L"0", Text::formatFunding(0).c_str());
184 ++_itemOffset;
185 }
186 }
187 for (std::vector<Craft*>::iterator i = _base->getCrafts()->begin(); i != _base->getCrafts()->end(); ++i)
188 {
189 if ((*i)->getStatus() != "STR_OUT")
190 {
191 _qtys.push_back(0);
192 _crafts.push_back(*i);
193 _lstItems->addRow(4, (*i)->getName(_game->getLanguage()).c_str(), L"1", L"0", Text::formatFunding((*i)->getRules()->getSellCost()).c_str());
194 ++_itemOffset;
195 }
196 }
197 if (_base->getAvailableScientists() > 0)
198 {
199 _qtys.push_back(0);
200 _hasSci = 1;
201 std::wostringstream ss;
202 ss << _base->getAvailableScientists();
203 _lstItems->addRow(4, tr("STR_SCIENTIST").c_str(), ss.str().c_str(), L"0", Text::formatFunding(0).c_str());
204 ++_itemOffset;
205 }
206 if (_base->getAvailableEngineers() > 0)
207 {
208 _qtys.push_back(0);
209 _hasEng = 1;
210 std::wostringstream ss;
211 ss << _base->getAvailableEngineers();
212 _lstItems->addRow(4, tr("STR_ENGINEER").c_str(), ss.str().c_str(), L"0", Text::formatFunding(0).c_str());
213 ++_itemOffset;
214 }
215 const std::vector<std::string> &items = _game->getRuleset()->getItemsList();
216 for (std::vector<std::string>::const_iterator i = items.begin(); i != items.end(); ++i)
217 {
218 int qty = _base->getItems()->getItem(*i);
219 if (Options::storageLimitsEnforced && origin == OPT_BATTLESCAPE)
220 {
221 for (std::vector<Transfer*>::iterator j = _base->getTransfers()->begin(); j != _base->getTransfers()->end(); ++j)
222 {
223 if ((*j)->getItems() == *i)
224 {
225 qty += (*j)->getQuantity();
226 }
227 }
228 for (std::vector<Craft*>::iterator j = _base->getCrafts()->begin(); j != _base->getCrafts()->end(); ++j)
229 {
230 qty += (*j)->getItems()->getItem(*i);
231 }
232 }
233 if (qty > 0 && (Options::canSellLiveAliens || !_game->getRuleset()->getItem(*i)->getAlien()))
234 {
235 _qtys.push_back(0);
236 _items.push_back(*i);
237 RuleItem *rule = _game->getRuleset()->getItem(*i);
238 std::wostringstream ss;
239 ss << qty;
240 std::wstring item = tr(*i);
241 if (rule->getBattleType() == BT_AMMO || (rule->getBattleType() == BT_NONE && rule->getClipSize() > 0))
242 {
243 item.insert(0, L" ");
244 _lstItems->addRow(4, item.c_str(), ss.str().c_str(), L"0", Text::formatFunding(rule->getSellCost()).c_str());
245 _lstItems->setRowColor(_qtys.size() - 1, _colorAmmo);
246 }
247 else
248 {
249 _lstItems->addRow(4, item.c_str(), ss.str().c_str(), L"0", Text::formatFunding(rule->getSellCost()).c_str());
250 }
251 }
252 }
253
254 _timerInc = new Timer(250);
255 _timerInc->onTimer((StateHandler)&SellState::increase);
256 _timerDec = new Timer(250);
257 _timerDec->onTimer((StateHandler)&SellState::decrease);
258 }
259
260 /**
261 *
262 */
~SellState()263 SellState::~SellState()
264 {
265 delete _timerInc;
266 delete _timerDec;
267 }
268
269 /**
270 * Runs the arrow timers.
271 */
think()272 void SellState::think()
273 {
274 State::think();
275
276 _timerInc->think(this, 0);
277 _timerDec->think(this, 0);
278 }
279
280 /**
281 * Gets the index of selected craft.
282 * @param selected Selected craft.
283 * @return Index of the selected craft.
284 */
getCraftIndex(size_t selected) const285 size_t SellState::getCraftIndex(size_t selected) const
286 {
287 return selected - _soldiers.size();
288 }
289
290 /**
291 * Sells the selected items.
292 * @param action Pointer to an action.
293 */
btnOkClick(Action *)294 void SellState::btnOkClick(Action *)
295 {
296 _game->getSavedGame()->setFunds(_game->getSavedGame()->getFunds() + _total);
297 for (size_t i = 0; i < _qtys.size(); ++i)
298 {
299 if (_qtys[i] > 0)
300 {
301 switch (getType(i))
302 {
303 case SELL_SOLDIER:
304 for (std::vector<Soldier*>::iterator s = _base->getSoldiers()->begin(); s != _base->getSoldiers()->end(); ++s)
305 {
306 if (*s == _soldiers[i])
307 {
308 if((*s)->getArmor()->getStoreItem() != "STR_NONE")
309 {
310 _base->getItems()->addItem((*s)->getArmor()->getStoreItem());
311 }
312 _base->getSoldiers()->erase(s);
313 break;
314 }
315 }
316 delete _soldiers[i];
317 break;
318
319 case SELL_CRAFT:
320 {
321 Craft *craft = _crafts[getCraftIndex(i)];
322
323 // Remove weapons from craft
324 for (std::vector<CraftWeapon*>::iterator w = craft->getWeapons()->begin(); w != craft->getWeapons()->end(); ++w)
325 {
326 if ((*w) != 0)
327 {
328 _base->getItems()->addItem((*w)->getRules()->getLauncherItem());
329 _base->getItems()->addItem((*w)->getRules()->getClipItem(), (*w)->getClipsLoaded(_game->getRuleset()));
330 }
331 }
332
333 // Remove items from craft
334 for (std::map<std::string, int>::iterator it = craft->getItems()->getContents()->begin(); it != craft->getItems()->getContents()->end(); ++it)
335 {
336 _base->getItems()->addItem(it->first, it->second);
337 }
338
339 // Remove soldiers from craft
340 for (std::vector<Soldier*>::iterator s = _base->getSoldiers()->begin(); s != _base->getSoldiers()->end(); ++s)
341 {
342 if ((*s)->getCraft() == craft)
343 {
344 (*s)->setCraft(0);
345 }
346 }
347
348 // Clear Hangar
349 for (std::vector<BaseFacility*>::iterator f = _base->getFacilities()->begin(); f != _base->getFacilities()->end(); ++f)
350 {
351 if ((*f)->getCraft() == craft)
352 {
353 (*f)->setCraft(0);
354 break;
355 }
356 }
357
358 // Remove craft
359 for (std::vector<Craft*>::iterator c = _base->getCrafts()->begin(); c != _base->getCrafts()->end(); ++c)
360 {
361 if (*c == craft)
362 {
363 _base->getCrafts()->erase(c);
364 break;
365 }
366 }
367 delete craft;
368 }
369 break;
370
371 case SELL_SCIENTIST:
372 _base->setScientists(_base->getScientists() - _qtys[i]);
373 break;
374
375 case SELL_ENGINEER:
376 _base->setEngineers(_base->getEngineers() - _qtys[i]);
377 break;
378
379 case SELL_ITEM:
380 if (_base->getItems()->getItem(_items[getItemIndex(i)]) < _qtys[i])
381 {
382 const std::string itemName = _items[getItemIndex(i)];
383 int toRemove = _qtys[i] - _base->getItems()->getItem(itemName);
384
385 // remove all of said items from base
386 _base->getItems()->removeItem(itemName, INT_MAX);
387
388 // if we still need to remove any, remove them from the crafts first, and keep a running tally
389 for (std::vector<Craft*>::iterator j = _base->getCrafts()->begin(); j != _base->getCrafts()->end() && toRemove; ++j)
390 {
391 if ((*j)->getItems()->getItem(itemName) < toRemove)
392 {
393 toRemove -= (*j)->getItems()->getItem(itemName);
394 (*j)->getItems()->removeItem(itemName, INT_MAX);
395 }
396 else
397 {
398 (*j)->getItems()->removeItem(itemName, toRemove);
399 toRemove = 0;
400 }
401 }
402
403 // if there are STILL any left to remove, take them from the transfers, and if necessary, delete it.
404 for (std::vector<Transfer*>::iterator j = _base->getTransfers()->begin(); j != _base->getTransfers()->end() && toRemove;)
405 {
406 if ((*j)->getItems() == itemName)
407 {
408 if ((*j)->getQuantity() <= toRemove)
409 {
410 toRemove -= (*j)->getQuantity();
411 delete *j;
412 j = _base->getTransfers()->erase(j);
413 }
414 else
415 {
416 (*j)->setItems((*j)->getItems(), (*j)->getQuantity() - toRemove);
417 toRemove = 0;
418 }
419 }
420 else
421 {
422 ++j;
423 }
424 }
425 }
426 else
427 {
428 _base->getItems()->removeItem(_items[getItemIndex(i)], _qtys[i]);
429 }
430 }
431 }
432 }
433 _game->popState();
434 }
435
436 /**
437 * Returns to the previous screen.
438 * @param action Pointer to an action.
439 */
btnCancelClick(Action *)440 void SellState::btnCancelClick(Action *)
441 {
442 _game->popState();
443 }
444
445 /**
446 * Starts increasing the item.
447 * @param action Pointer to an action.
448 */
lstItemsLeftArrowPress(Action * action)449 void SellState::lstItemsLeftArrowPress(Action *action)
450 {
451 _sel = _lstItems->getSelectedRow();
452 if (action->getDetails()->button.button == SDL_BUTTON_LEFT && !_timerInc->isRunning()) _timerInc->start();
453 }
454
455 /**
456 * Stops increasing the item.
457 * @param action Pointer to an action.
458 */
lstItemsLeftArrowRelease(Action * action)459 void SellState::lstItemsLeftArrowRelease(Action *action)
460 {
461 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
462 {
463 _timerInc->stop();
464 }
465 }
466
467 /**
468 * Increases the selected item;
469 * by one on left-click, to max on right-click.
470 * @param action Pointer to an action.
471 */
lstItemsLeftArrowClick(Action * action)472 void SellState::lstItemsLeftArrowClick(Action *action)
473 {
474 if (action->getDetails()->button.button == SDL_BUTTON_RIGHT) changeByValue(INT_MAX, 1);
475 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
476 {
477 changeByValue(1,1);
478 _timerInc->setInterval(250);
479 _timerDec->setInterval(250);
480 }
481 }
482
483 /**
484 * Starts decreasing the item.
485 * @param action Pointer to an action.
486 */
lstItemsRightArrowPress(Action * action)487 void SellState::lstItemsRightArrowPress(Action *action)
488 {
489 _sel = _lstItems->getSelectedRow();
490 if (action->getDetails()->button.button == SDL_BUTTON_LEFT && !_timerDec->isRunning()) _timerDec->start();
491 }
492
493 /**
494 * Stops decreasing the item.
495 * @param action Pointer to an action.
496 */
lstItemsRightArrowRelease(Action * action)497 void SellState::lstItemsRightArrowRelease(Action *action)
498 {
499 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
500 {
501 _timerDec->stop();
502 }
503 }
504
505 /**
506 * Decreases the selected item;
507 * by one on left-click, to 0 on right-click.
508 * @param action Pointer to an action.
509 */
lstItemsRightArrowClick(Action * action)510 void SellState::lstItemsRightArrowClick(Action *action)
511 {
512 if (action->getDetails()->button.button == SDL_BUTTON_RIGHT) changeByValue(INT_MAX, -1);
513 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
514 {
515 changeByValue(1,-1);
516 _timerInc->setInterval(250);
517 _timerDec->setInterval(250);
518 }
519 }
520
521 /**
522 * Handles the mouse-wheels on the arrow-buttons.
523 * @param action Pointer to an action.
524 */
lstItemsMousePress(Action * action)525 void SellState::lstItemsMousePress(Action *action)
526 {
527 _sel = _lstItems->getSelectedRow();
528 if (action->getDetails()->button.button == SDL_BUTTON_WHEELUP)
529 {
530 _timerInc->stop();
531 _timerDec->stop();
532 if (action->getAbsoluteXMouse() >= _lstItems->getArrowsLeftEdge() &&
533 action->getAbsoluteXMouse() <= _lstItems->getArrowsRightEdge())
534 {
535 changeByValue(Options::changeValueByMouseWheel, 1);
536 }
537 }
538 else if (action->getDetails()->button.button == SDL_BUTTON_WHEELDOWN)
539 {
540 _timerInc->stop();
541 _timerDec->stop();
542 if (action->getAbsoluteXMouse() >= _lstItems->getArrowsLeftEdge() &&
543 action->getAbsoluteXMouse() <= _lstItems->getArrowsRightEdge())
544 {
545 changeByValue(Options::changeValueByMouseWheel, -1);
546 }
547 }
548 }
549
550 /**
551 * Gets the price of the currently selected item.
552 * @return Price of the selected item.
553 */
getPrice()554 int SellState::getPrice()
555 {
556 // Personnel/craft aren't worth anything
557 switch(getType(_sel))
558 {
559 case SELL_SOLDIER:
560 case SELL_ENGINEER:
561 case SELL_SCIENTIST:
562 return 0;
563 case SELL_ITEM:
564 return _game->getRuleset()->getItem(_items[getItemIndex(_sel)])->getSellCost();
565 case SELL_CRAFT:
566 Craft *craft = _crafts[getCraftIndex(_sel)];
567 return craft->getRules()->getSellCost();
568 }
569 return 0;
570 }
571
572 /**
573 * Gets the quantity of the currently selected item
574 * on the base.
575 * @return Quantity of selected item on the base.
576 */
getQuantity()577 int SellState::getQuantity()
578 {
579 int qty = 0;
580 // Soldiers/crafts are individual
581 switch(getType(_sel))
582 {
583 case SELL_SOLDIER:
584 case SELL_CRAFT:
585 return 1;
586 case SELL_SCIENTIST:
587 return _base->getAvailableScientists();
588 case SELL_ENGINEER:
589 return _base->getAvailableEngineers();
590 case SELL_ITEM:
591 qty = _base->getItems()->getItem(_items[getItemIndex(_sel)]);
592 if (Options::storageLimitsEnforced && _origin == OPT_BATTLESCAPE)
593 {
594 for (std::vector<Transfer*>::iterator j = _base->getTransfers()->begin(); j != _base->getTransfers()->end(); ++j)
595 {
596 if ((*j)->getItems() == _items[getItemIndex(_sel)])
597 {
598 qty += (*j)->getQuantity();
599 }
600 }
601 for (std::vector<Craft*>::iterator j = _base->getCrafts()->begin(); j != _base->getCrafts()->end(); ++j)
602 {
603 qty += (*j)->getItems()->getItem(_items[getItemIndex(_sel)]);
604 }
605 }
606 return qty;
607 }
608
609 return 0;
610 }
611
612 /**
613 * Increases the quantity of the selected item to sell by one.
614 */
increase()615 void SellState::increase()
616 {
617 _timerDec->setInterval(50);
618 _timerInc->setInterval(50);
619 changeByValue(1,1);
620 }
621
622 /**
623 * Increases or decreases the quantity of the selected item to sell.
624 * @param change How much we want to add or remove.
625 * @param dir Direction to change, +1 to increase or -1 to decrease.
626 */
changeByValue(int change,int dir)627 void SellState::changeByValue(int change, int dir)
628 {
629 if (dir > 0)
630 {
631 if (0 >= change || getQuantity() <=_qtys[_sel]) return;
632 change = std::min(getQuantity() - _qtys[_sel], change);
633 }
634 else
635 {
636 if (0 >= change || 0 >= _qtys[_sel]) return;
637 change = std::min(_qtys[_sel], change);
638 }
639 _qtys[_sel] += dir * change;
640 _total += dir * getPrice() * change;
641
642 // Calculate the change in storage space.
643 Craft *craft;
644 RuleItem *armor, *item, *weapon, *ammo;
645 double total = 0.0;
646 switch (getType(_sel))
647 {
648 case SELL_SOLDIER:
649 if (_soldiers[_sel]->getArmor()->getStoreItem() != "STR_NONE")
650 {
651 armor = _game->getRuleset()->getItem(_soldiers[_sel]->getArmor()->getStoreItem());
652 _spaceChange += dir * armor->getSize();
653 }
654 break;
655 case SELL_CRAFT:
656 craft = _crafts[getCraftIndex(_sel)];
657 for (std::vector<CraftWeapon*>::iterator w = craft->getWeapons()->begin(); w != craft->getWeapons()->end(); ++w)
658 {
659 if (*w)
660 {
661 weapon = _game->getRuleset()->getItem((*w)->getRules()->getLauncherItem());
662 total += weapon->getSize();
663 ammo = _game->getRuleset()->getItem((*w)->getRules()->getClipItem());
664 if (ammo)
665 total += ammo->getSize() * (*w)->getClipsLoaded(_game->getRuleset());
666 }
667 }
668 _spaceChange += dir * total;
669 break;
670 case SELL_ITEM:
671 item = _game->getRuleset()->getItem(_items[getItemIndex(_sel)]);
672 _spaceChange -= dir * change * item->getSize();
673 break;
674 default:
675 break;
676 }
677
678 updateItemStrings();
679 }
680
681 /**
682 * Decreases the quantity of the selected item to sell by one.
683 */
decrease()684 void SellState::decrease()
685 {
686 _timerInc->setInterval(50);
687 _timerDec->setInterval(50);
688 changeByValue(1,-1);
689 }
690
691 /**
692 * Updates the quantity-strings of the selected item.
693 */
updateItemStrings()694 void SellState::updateItemStrings()
695 {
696 std::wostringstream ss, ss2, ss5;
697 ss << _qtys[_sel];
698 _lstItems->setCellText(_sel, 2, ss.str());
699 ss2 << getQuantity() - _qtys[_sel];
700 _lstItems->setCellText(_sel, 1, ss2.str());
701 _txtSales->setText(tr("STR_VALUE_OF_SALES").arg(Text::formatFunding(_total)));
702
703 if (_qtys[_sel] > 0)
704 {
705 _lstItems->setRowColor(_sel, _color2);
706 }
707 else
708 {
709 _lstItems->setRowColor(_sel, _color);
710 if (_sel > _itemOffset)
711 {
712 RuleItem *rule = _game->getRuleset()->getItem(_items[_sel - _itemOffset]);
713 if (rule->getBattleType() == BT_AMMO || (rule->getBattleType() == BT_NONE && rule->getClipSize() > 0))
714 {
715 _lstItems->setRowColor(_sel, _colorAmmo);
716 }
717 }
718 }
719
720 ss5 << _base->getUsedStores();
721 if (std::abs(_spaceChange) > 0.05)
722 {
723 ss5 << "(";
724 if (_spaceChange > 0.05)
725 ss5 << "+";
726 ss5 << std::fixed << std::setprecision(1) << _spaceChange << ")";
727 }
728 ss5 << ":" << _base->getAvailableStores();
729 _txtSpaceUsed->setText(tr("STR_SPACE_USED").arg(ss5.str()));
730 if (Options::storageLimitsEnforced)
731 {
732 _btnOk->setVisible(!_base->storesOverfull(_spaceChange));
733 }
734 }
735
736 /**
737 * Gets the Type of the selected item.
738 * @param selected Currently selected item.
739 * @return The type of the selected item.
740 */
getType(size_t selected) const741 enum SellType SellState::getType(size_t selected) const
742 {
743 size_t max = _soldiers.size();
744
745 if (selected < max)
746 return SELL_SOLDIER;
747 if (selected < (max += _crafts.size()) )
748 return SELL_CRAFT;
749 if (selected < (max += _hasSci))
750 return SELL_SCIENTIST;
751 if (selected < (max += _hasEng))
752 return SELL_ENGINEER;
753
754 return SELL_ITEM;
755 }
756
757 /**
758 * Gets the index of the selected item.
759 * @param selected Currently selected item.
760 * @return Index of the selected item.
761 */
getItemIndex(size_t selected) const762 size_t SellState::getItemIndex(size_t selected) const
763 {
764 return selected - _soldiers.size() - _crafts.size() - _hasSci - _hasEng;
765 }
766
767 }
768