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 "ResearchInfoState.h"
20 #include "../Engine/Action.h"
21 #include "../Engine/Game.h"
22 #include "../Resource/ResourcePack.h"
23 #include "../Engine/Language.h"
24 #include "../Engine/Palette.h"
25 #include "../Engine/Options.h"
26 #include "../Interface/TextButton.h"
27 #include "../Interface/Window.h"
28 #include "../Interface/Text.h"
29 #include "../Savegame/Base.h"
30 #include "../Ruleset/RuleResearch.h"
31 #include "../Ruleset/Ruleset.h"
32 #include "../Savegame/ItemContainer.h"
33 #include "../Savegame/ResearchProject.h"
34 #include "../Interface/ArrowButton.h"
35 #include "../Engine/Timer.h"
36 #include "../Engine/RNG.h"
37 #include <sstream>
38 #include <limits>
39
40 namespace OpenXcom
41 {
42
43 /**
44 * Initializes all the elements in the ResearchProject screen.
45 * @param game Pointer to the core game.
46 * @param base Pointer to the base to get info from.
47 * @param rule A RuleResearch which will be used to create a new ResearchProject
48 */
ResearchInfoState(Game * game,Base * base,RuleResearch * rule)49 ResearchInfoState::ResearchInfoState(Game *game, Base *base, RuleResearch * rule) : State(game), _base(base), _project(new ResearchProject(rule, int(rule->getCost() * OpenXcom::RNG::generate(50, 150)/100))), _rule(rule)
50 {
51 buildUi();
52 }
53
54 /**
55 * Initializes all the elements in the ResearchProject screen.
56 * @param game Pointer to the core game.
57 * @param base Pointer to the base to get info from.
58 * @param project A ResearchProject to modify
59 */
ResearchInfoState(Game * game,Base * base,ResearchProject * project)60 ResearchInfoState::ResearchInfoState(Game *game, Base *base, ResearchProject * project) : State(game), _base(base), _project(project), _rule(0)
61 {
62 buildUi();
63 }
64
65 /**
66 * Builds dialog.
67 */
buildUi()68 void ResearchInfoState::buildUi()
69 {
70 _screen = false;
71
72 _window = new Window(this, 230, 140, 45, 30);
73 _txtTitle = new Text(210, 17, 61, 40);
74
75 _txtAvailableScientist = new Text(210, 9, 61, 60);
76 _txtAvailableSpace = new Text(210, 9, 61, 70);
77 _txtAllocatedScientist = new Text(210, 17, 61, 80);
78 _txtMore = new Text(110, 17, 85, 100);
79 _txtLess = new Text(110, 17, 85, 120);
80 _btnCancel = new TextButton(90, 16, 61, 145);
81 _btnOk = new TextButton(83, 16, 169, 145);
82
83 _btnMore = new ArrowButton(ARROW_BIG_UP, 13, 14, 195, 100);
84 _btnLess = new ArrowButton(ARROW_BIG_DOWN, 13, 14, 195, 120);
85
86 _surfaceScientists = new InteractiveSurface(230, 140, 45, 30);
87 _surfaceScientists->onMouseClick((ActionHandler)&ResearchInfoState::handleWheel, 0);
88
89 // Set palette
90 setPalette("PAL_BASESCAPE", 1);
91
92 add(_surfaceScientists);
93 add(_window);
94 add(_btnOk);
95 add(_btnCancel);
96 add(_txtTitle);
97 add(_txtAvailableScientist);
98 add(_txtAvailableSpace);
99 add(_txtAllocatedScientist);
100 add(_txtMore);
101 add(_txtLess);
102 add(_btnMore);
103 add(_btnLess);
104
105 centerAllSurfaces();
106
107 // Set up objects
108 _window->setColor(Palette::blockOffset(13)+5);
109 _window->setBackground(_game->getResourcePack()->getSurface("BACK05.SCR"));
110 _txtTitle->setColor(Palette::blockOffset(13)+5);
111 _txtTitle->setBig();
112
113 _txtTitle->setText(_rule ? tr(_rule->getName()) : tr(_project->getRules ()->getName()));
114
115 _txtAvailableScientist->setColor(Palette::blockOffset(13)+5);
116 _txtAvailableScientist->setSecondaryColor(Palette::blockOffset(13));
117
118 _txtAvailableSpace->setColor(Palette::blockOffset(13)+5);
119 _txtAvailableSpace->setSecondaryColor(Palette::blockOffset(13));
120
121 _txtAllocatedScientist->setColor(Palette::blockOffset(13)+5);
122 _txtAllocatedScientist->setSecondaryColor(Palette::blockOffset(13));
123 _txtAllocatedScientist->setBig();
124
125 _txtMore->setText(tr("STR_INCREASE"));
126 _txtLess->setText(tr("STR_DECREASE"));
127
128 _txtMore->setColor(Palette::blockOffset(13)+5);
129 _txtLess->setColor(Palette::blockOffset(13)+5);
130
131 _txtMore->setBig();
132 _txtLess->setBig();
133
134 if (_rule)
135 {
136 _base->addResearch(_project);
137 if (_rule->needItem() &&
138 (_game->getRuleset()->getUnit(_rule->getName()) ||
139 Options::spendResearchedItems))
140 {
141 _base->getItems()->removeItem(_rule->getName(), 1);
142 }
143 }
144 setAssignedScientist();
145 _btnMore->setColor(Palette::blockOffset(13)+5);
146 _btnLess->setColor(Palette::blockOffset(13)+5);
147 _btnMore->onMousePress((ActionHandler)&ResearchInfoState::morePress);
148 _btnMore->onMouseRelease((ActionHandler)&ResearchInfoState::moreRelease);
149 _btnMore->onMouseClick((ActionHandler)&ResearchInfoState::moreClick, 0);
150 _btnLess->onMousePress((ActionHandler)&ResearchInfoState::lessPress);
151 _btnLess->onMouseRelease((ActionHandler)&ResearchInfoState::lessRelease);
152 _btnLess->onMouseClick((ActionHandler)&ResearchInfoState::lessClick, 0);
153
154 _timerMore = new Timer(250);
155 _timerMore->onTimer((StateHandler)&ResearchInfoState::more);
156 _timerLess = new Timer(250);
157 _timerLess->onTimer((StateHandler)&ResearchInfoState::less);
158
159 _btnOk->setColor(Palette::blockOffset(13)+10);
160 _btnOk->onMouseClick((ActionHandler)&ResearchInfoState::btnOkClick);
161 _btnOk->onKeyboardPress((ActionHandler)&ResearchInfoState::btnOkClick, Options::keyOk);
162 _btnCancel->setColor(Palette::blockOffset(13)+10);
163 if (_rule)
164 {
165 _btnOk->setText(tr("STR_START_PROJECT"));
166 _btnCancel->setText(tr("STR_CANCEL_UC"));
167 _btnCancel->onKeyboardPress((ActionHandler)&ResearchInfoState::btnCancelClick, Options::keyCancel);
168 }
169 else
170 {
171 _btnOk->setText(tr("STR_OK"));
172 _btnCancel->setText(tr("STR_CANCEL_PROJECT"));
173 _btnOk->onKeyboardPress((ActionHandler)&ResearchInfoState::btnOkClick, Options::keyCancel);
174 }
175 _btnCancel->onMouseClick((ActionHandler)&ResearchInfoState::btnCancelClick);
176 }
177
178 /**
179 * Returns to the previous screen.
180 * @param action Pointer to an action.
181 */
btnOkClick(Action *)182 void ResearchInfoState::btnOkClick(Action *)
183 {
184 _game->popState();
185 }
186
187 /**
188 * Returns to the previous screen, removing the current project from the active
189 * research list.
190 * @param action Pointer to an action.
191 */
btnCancelClick(Action *)192 void ResearchInfoState::btnCancelClick(Action *)
193 {
194 const RuleResearch *ruleResearch = _rule ? _rule : _project->getRules();
195 if (ruleResearch->needItem() &&
196 (_game->getRuleset()->getUnit(ruleResearch->getName()) ||
197 Options::spendResearchedItems))
198 {
199 _base->getItems()->addItem(ruleResearch->getName(), 1);
200 }
201 _base->removeResearch(_project);
202 _game->popState();
203 }
204
205 /**
206 * Updates count of assigned/free scientists and available lab space.
207 */
setAssignedScientist()208 void ResearchInfoState::setAssignedScientist()
209 {
210 _txtAvailableScientist->setText(tr("STR_SCIENTISTS_AVAILABLE_UC").arg(_base->getAvailableScientists()));
211 _txtAvailableSpace->setText(tr("STR_LABORATORY_SPACE_AVAILABLE_UC").arg(_base->getFreeLaboratories()));
212 _txtAllocatedScientist->setText(tr("STR_SCIENTISTS_ALLOCATED").arg(_project->getAssigned()));
213 }
214
215 /**
216 * Increases or decreases the scientists according the mouse-wheel used.
217 * @param action Pointer to an Action.
218 */
handleWheel(Action * action)219 void ResearchInfoState::handleWheel(Action *action)
220 {
221 if (action->getDetails()->button.button == SDL_BUTTON_WHEELUP) moreByValue(Options::changeValueByMouseWheel);
222 else if (action->getDetails()->button.button == SDL_BUTTON_WHEELDOWN) lessByValue(Options::changeValueByMouseWheel);
223 }
224
225 /**
226 * Starts the timeMore timer.
227 * @param action Pointer to an Action.
228 */
morePress(Action * action)229 void ResearchInfoState::morePress(Action *action)
230 {
231 if (action->getDetails()->button.button == SDL_BUTTON_LEFT) _timerMore->start();
232 }
233
234 /**
235 * Stops the timeMore timer.
236 * @param action Pointer to an Action.
237 */
moreRelease(Action * action)238 void ResearchInfoState::moreRelease(Action *action)
239 {
240 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
241 {
242 _timerMore->setInterval(250);
243 _timerMore->stop();
244 }
245 }
246
247 /**
248 * Allocates scientists to the current project;
249 * one scientist on left-click, all scientists on right-click.
250 * @param action Pointer to an Action.
251 */
moreClick(Action * action)252 void ResearchInfoState::moreClick(Action *action)
253 {
254 if (action->getDetails()->button.button == SDL_BUTTON_RIGHT)
255 moreByValue(std::numeric_limits<int>::max());
256 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
257 moreByValue(1);
258 }
259
260 /**
261 * Starts the timeLess timer.
262 * @param action Pointer to an Action.
263 */
lessPress(Action * action)264 void ResearchInfoState::lessPress(Action *action)
265 {
266 if (action->getDetails()->button.button == SDL_BUTTON_LEFT) _timerLess->start ();
267 }
268
269 /**
270 * Stops the timeLess timer.
271 * @param action Pointer to an Action.
272 */
lessRelease(Action * action)273 void ResearchInfoState::lessRelease(Action *action)
274 {
275 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
276 {
277 _timerLess->setInterval(250);
278 _timerLess->stop ();
279 }
280 }
281
282 /**
283 * Removes scientists from the current project;
284 * one scientist on left-click, all scientists on right-click.
285 * @param action Pointer to an Action.
286 */
lessClick(Action * action)287 void ResearchInfoState::lessClick(Action *action)
288 {
289 if (action->getDetails()->button.button == SDL_BUTTON_RIGHT)
290 lessByValue(std::numeric_limits<int>::max());
291 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
292 lessByValue(1);
293 }
294
295 /**
296 * Adds one scientist to the project if possible.
297 */
more()298 void ResearchInfoState::more()
299 {
300 _timerMore->setInterval(50);
301 moreByValue(1);
302 }
303
304 /**
305 * Adds the given number of scientists to the project if possible.
306 * @param change Number of scientists to add.
307 */
moreByValue(int change)308 void ResearchInfoState::moreByValue(int change)
309 {
310 if (0 >= change) return;
311 int freeScientist = _base->getAvailableScientists();
312 int freeSpaceLab = _base->getFreeLaboratories();
313 if (freeScientist > 0 && freeSpaceLab > 0)
314 {
315 change = std::min(std::min(freeScientist, freeSpaceLab), change);
316 _project->setAssigned(_project->getAssigned()+change);
317 _base->setScientists(_base->getScientists()-change);
318 setAssignedScientist();
319 }
320 }
321
322 /**
323 * Removes one scientist from the project if possible.
324 */
less()325 void ResearchInfoState::less()
326 {
327 _timerLess->setInterval(50);
328 lessByValue(1);
329 }
330
331 /**
332 * Removes the given number of scientists from the project if possible.
333 * @param change Number of scientists to subtract.
334 */
lessByValue(int change)335 void ResearchInfoState::lessByValue(int change)
336 {
337 if (0 >= change) return;
338 int assigned = _project->getAssigned();
339 if (assigned > 0)
340 {
341 change = std::min(assigned, change);
342 _project->setAssigned(assigned-change);
343 _base->setScientists(_base->getScientists()+change);
344 setAssignedScientist();
345 }
346 }
347
348 /**
349 * Runs state functionality every cycle (used to update the timer).
350 */
think()351 void ResearchInfoState::think()
352 {
353 State::think();
354
355 _timerLess->think (this, 0);
356 _timerMore->think (this, 0);
357 }
358 }
359