1 // _________ __ __
2 // / _____// |_____________ _/ |______ ____ __ __ ______
3 // \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
4 // / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
5 // /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
6 // \/ \/ \//_____/ \/
7 // ______________________ ______________________
8 // T H E W A R B E G I N S
9 // Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name button_checks.cpp - The button checks. */
12 //
13 // (c) Copyright 1999-2015 by Lutz Sammer, Vladi Belperchinov-Shabanski
14 // and Andrettin
15 //
16 // This program is free software; you can redistribute it and/or modify
17 // it under the terms of the GNU General Public License as published by
18 // the Free Software Foundation; only version 2 of the License.
19 //
20 // This program is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU General Public License for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with this program; if not, write to the Free Software
27 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 // 02111-1307, USA.
29 //
30
31 //@{
32
33 /*----------------------------------------------------------------------------
34 -- Includes
35 ----------------------------------------------------------------------------*/
36
37 #include "stratagus.h"
38
39 #include "actions.h"
40 //Wyrmgus start
41 #include "action/action_research.h"
42 #include "action/action_train.h"
43 #include "action/action_upgradeto.h"
44 //Wyrmgus end
45 #include "network.h"
46 #include "player.h"
47 #include "ui/button_action.h"
48 #include "ui/interface.h"
49 #include "unit/unit.h"
50 #include "unit/unittype.h"
51 #include "upgrade/dependency.h"
52 #include "upgrade/upgrade.h"
53
54 #include <stdio.h>
55 /*----------------------------------------------------------------------------
56 -- Functions
57 ----------------------------------------------------------------------------*/
58
59 /**
60 ** ButtonCheck for button enabled, always true.
61 ** This needed to overwrite the internal tests.
62 **
63 ** @param unit Pointer to unit for button.
64 ** @param button Pointer to button to check/enable.
65 **
66 ** @return True if enabled.
67 */
ButtonCheckTrue(const CUnit &,const ButtonAction &)68 bool ButtonCheckTrue(const CUnit &, const ButtonAction &)
69 {
70 return true;
71 }
72
73 /**
74 ** Check for button enabled, always false.
75 ** This needed to overwrite the internal tests.
76 **
77 ** @param unit Pointer to unit for button.
78 ** @param button Pointer to button to check/enable.
79 **
80 ** @return True if enabled.
81 */
ButtonCheckFalse(const CUnit &,const ButtonAction &)82 bool ButtonCheckFalse(const CUnit &, const ButtonAction &)
83 {
84 return false;
85 }
86
87 /**
88 ** Check for button enabled, if upgrade is ready.
89 **
90 ** @param unit Pointer to unit for button.
91 ** @param button Pointer to button to check/enable.
92 **
93 ** @return True if enabled.
94 */
ButtonCheckUpgrade(const CUnit & unit,const ButtonAction & button)95 bool ButtonCheckUpgrade(const CUnit &unit, const ButtonAction &button)
96 {
97 CPlayer *player = unit.Player;
98 char *buf = new_strdup(button.AllowStr.c_str());
99
100 for (const char *s = strtok(buf, ","); s; s = strtok(nullptr, ",")) {
101 if (UpgradeIdentAllowed(*unit.Player, s) != 'R') {
102 delete[] buf;
103 return false;
104 }
105 }
106 delete[] buf;
107 return true;
108 }
109
110 /**
111 ** Check for the button being enabled, if the upgrade has not been acquired.
112 **
113 ** @param unit Pointer to unit for button.
114 ** @param button Pointer to button to check/enable.
115 **
116 ** @return True if enabled.
117 */
ButtonCheckUpgradeNot(const CUnit & unit,const ButtonAction & button)118 bool ButtonCheckUpgradeNot(const CUnit &unit, const ButtonAction &button)
119 {
120 return !ButtonCheckUpgrade(unit, button);
121 }
122
123 /**
124 ** Check for button enabled, if upgrade is ready.
125 **
126 ** @param unit Pointer to unit for button.
127 ** @param button Pointer to button to check/enable.
128 **
129 ** @return True if enabled.
130 */
ButtonCheckUpgradeOr(const CUnit & unit,const ButtonAction & button)131 bool ButtonCheckUpgradeOr(const CUnit &unit, const ButtonAction &button)
132 {
133 CPlayer *player = unit.Player;
134 char *buf = new_strdup(button.AllowStr.c_str());
135
136 for (const char *s = strtok(buf, ","); s; s = strtok(nullptr, ",")) {
137 if (UpgradeIdentAllowed(*unit.Player, s) == 'R') {
138 delete[] buf;
139 return true;
140 }
141 }
142 delete[] buf;
143 return false;
144 }
145
146 /**
147 ** Check for button enabled, if unit has an individual upgrade.
148 **
149 ** @param unit Pointer to unit for button.
150 ** @param button Pointer to button to check/enable.
151 **
152 ** @return True if enabled.
153 */
ButtonCheckIndividualUpgrade(const CUnit & unit,const ButtonAction & button)154 bool ButtonCheckIndividualUpgrade(const CUnit &unit, const ButtonAction &button)
155 {
156 char *buf = new_strdup(button.AllowStr.c_str());
157
158 for (const char *s = strtok(buf, ","); s; s = strtok(nullptr, ",")) {
159 if (unit.GetIndividualUpgrade(CUpgrade::Get(s)) == 0) {
160 delete[] buf;
161 return false;
162 }
163 }
164 delete[] buf;
165 return true;
166 }
167
168 /**
169 ** Check for button enabled, if unit has any of the individual upgrades.
170 **
171 ** @param unit Pointer to unit for button.
172 ** @param button Pointer to button to check/enable.
173 **
174 ** @return True if enabled.
175 */
ButtonCheckIndividualUpgradeOr(const CUnit & unit,const ButtonAction & button)176 bool ButtonCheckIndividualUpgradeOr(const CUnit &unit, const ButtonAction &button)
177 {
178 char *buf = new_strdup(button.AllowStr.c_str());
179
180 for (const char *s = strtok(buf, ","); s; s = strtok(nullptr, ",")) {
181 if (unit.GetIndividualUpgrade(CUpgrade::Get(s)) > 0) {
182 delete[] buf;
183 return true;
184 }
185 }
186 delete[] buf;
187 return false;
188 }
189
190 /**
191 ** Check for button enabled, if unit's variables pass the condition check.
192 **
193 ** @param unit Pointer to unit for button.
194 ** @param button Pointer to button to check/enable.
195 **
196 ** @return True if enabled.
197 */
ButtonCheckUnitVariable(const CUnit & unit,const ButtonAction & button)198 bool ButtonCheckUnitVariable(const CUnit &unit, const ButtonAction &button)
199 {
200 char *buf = new_strdup(button.AllowStr.c_str());
201
202 for (const char *var = strtok(buf, ","); var; var = strtok(nullptr, ",")) {
203 const char *type = strtok(nullptr, ",");
204 const char *binop = strtok(nullptr, ",");
205 const char *value = strtok(nullptr, ",");
206 const int index = UnitTypeVar.VariableNameLookup[var];// User variables
207 if (index == -1) {
208 fprintf(stderr, "Bad variable name '%s'\n", var);
209 Exit(1);
210 return false;
211 }
212 int varValue;
213 if (!strcmp(type, "Value")) {
214 //Wyrmgus start
215 // varValue = unit.Variable[index].Value;
216 varValue = unit.GetModifiedVariable(index, VariableValue);
217 //Wyrmgus end
218 } else if (!strcmp(type, "Max")) {
219 //Wyrmgus start
220 // varValue = unit.Variable[index].Max;
221 varValue = unit.GetModifiedVariable(index, VariableMax);
222 //Wyrmgus end
223 } else if (!strcmp(type, "Increase")) {
224 //Wyrmgus start
225 // varValue = unit.Variable[index].Increase;
226 varValue = unit.GetModifiedVariable(index, VariableIncrease);
227 //Wyrmgus end
228 } else if (!strcmp(type, "Enable")) {
229 varValue = unit.Variable[index].Enable;
230 } else if (!strcmp(type, "Percent")) {
231 //Wyrmgus start
232 // varValue = unit.Variable[index].Value * 100 / unit.Variable[index].Max;
233 varValue = unit.GetModifiedVariable(index, VariableValue) * 100 / unit.GetModifiedVariable(index, VariableMax);
234 //Wyrmgus end
235 } else {
236 fprintf(stderr, "Bad variable type '%s'\n", type);
237 Exit(1);
238 return false;
239 }
240 const int cmpValue = atoi(value);
241 bool cmpResult = false;
242 if (!strcmp(binop, ">")) {
243 cmpResult = varValue > cmpValue;
244 } else if (!strcmp(binop, ">=")) {
245 cmpResult = varValue >= cmpValue;
246 } else if (!strcmp(binop, "<")) {
247 cmpResult = varValue < cmpValue;
248 } else if (!strcmp(binop, "<=")) {
249 cmpResult = varValue <= cmpValue;
250 } else if (!strcmp(binop, "==")) {
251 cmpResult = varValue == cmpValue;
252 } else if (!strcmp(binop, "!=")) {
253 cmpResult = varValue != cmpValue;
254 } else {
255 fprintf(stderr, "Bad compare type '%s'\n", binop);
256 Exit(1);
257 return false;
258 }
259 if (cmpResult == false) {
260 delete[] buf;
261 return false;
262 }
263 }
264 delete[] buf;
265 return true;
266 }
267
268 /**
269 ** Check for button enabled, if any unit is available.
270 **
271 ** @param unit Pointer to unit for button.
272 ** @param button Pointer to button to check/enable.
273 **
274 ** @return True if enabled.
275 */
ButtonCheckUnitsOr(const CUnit & unit,const ButtonAction & button)276 bool ButtonCheckUnitsOr(const CUnit &unit, const ButtonAction &button)
277 {
278 CPlayer *player = unit.Player;
279 char *buf = new_strdup(button.AllowStr.c_str());
280
281 for (const char *s = strtok(buf, ","); s; s = strtok(nullptr, ",")) {
282 if (player->HaveUnitTypeByIdent(s)) {
283 delete[] buf;
284 return true;
285 }
286 }
287 delete[] buf;
288 return false;
289 }
290
291 /**
292 ** Check for button enabled, if all units are available.
293 **
294 ** @param unit Pointer to unit for button.
295 ** @param button Pointer to button to check/enable.
296 **
297 ** @return True if enabled.
298 */
ButtonCheckUnitsAnd(const CUnit & unit,const ButtonAction & button)299 bool ButtonCheckUnitsAnd(const CUnit &unit, const ButtonAction &button)
300 {
301 CPlayer *player = unit.Player;
302 char *buf = new_strdup(button.AllowStr.c_str());
303
304 for (const char *s = strtok(buf, ","); s; s = strtok(nullptr, ",")) {
305 if (!player->HaveUnitTypeByIdent(s)) {
306 delete[] buf;
307 return false;
308 }
309 }
310 delete[] buf;
311 return true;
312 }
313
314 /**
315 ** Check for button enabled, if no unit is available.
316 **
317 ** @param unit Pointer to unit for button.
318 ** @param button Pointer to button to check/enable.
319 **
320 ** @return True if enabled.
321 */
ButtonCheckUnitsNot(const CUnit & unit,const ButtonAction & button)322 bool ButtonCheckUnitsNot(const CUnit &unit, const ButtonAction &button)
323 {
324 return !ButtonCheckUnitsAnd(unit, button);
325 }
326
327 /**
328 ** Check if network play is enabled.
329 **
330 ** @param unit Pointer to unit for button.
331 ** @param button Pointer to button to check/enable.
332 **
333 ** @return True if enabled.
334 **
335 ** @note: this check could also be moved into intialisation.
336 */
ButtonCheckNetwork(const CUnit &,const ButtonAction &)337 bool ButtonCheckNetwork(const CUnit &, const ButtonAction &)
338 {
339 return IsNetworkGame();
340 }
341
342 /**
343 ** Check if network play is disabled.
344 **
345 ** @param unit Pointer to unit for button.
346 ** @param button Pointer to button to check/enable.
347 **
348 ** @return True if disabled.
349 **
350 ** @note: this check could also be moved into intialisation.
351 */
ButtonCheckNoNetwork(const CUnit &,const ButtonAction &)352 bool ButtonCheckNoNetwork(const CUnit &, const ButtonAction &)
353 {
354 return !IsNetworkGame();
355 }
356
357 /**
358 ** Check for button enabled, if the unit isn't working.
359 ** Working is training, upgrading, researching.
360 **
361 ** @param unit Pointer to unit for button.
362 ** @param button Pointer to button to check/enable.
363 **
364 ** @return True if enabled.
365 */
ButtonCheckNoWork(const CUnit & unit,const ButtonAction &)366 bool ButtonCheckNoWork(const CUnit &unit, const ButtonAction &)
367 {
368 int action = unit.CurrentAction();
369 //Wyrmgus start
370 // return action != UnitActionTrain
371 // && action != UnitActionUpgradeTo
372 // && action != UnitActionResearch;
373 //don't stop showing the button for a quick moment if the time cost is 0
374 return (action != UnitActionTrain || static_cast<COrder_Train *>(unit.CurrentOrder())->GetUnitType().Stats[unit.Player->Index].Costs[TimeCost] == 0)
375 && (action != UnitActionUpgradeTo || static_cast<COrder_UpgradeTo *>(unit.CurrentOrder())->GetUnitType().Stats[unit.Player->Index].Costs[TimeCost] == 0)
376 && (action != UnitActionResearch || static_cast<COrder_Research *>(unit.CurrentOrder())->GetUpgrade().Costs[TimeCost] == 0);
377 //Wyrmgus end
378 }
379
380 /**
381 ** Check for button enabled, if the unit isn't researching.
382 **
383 ** @param unit Pointer to unit for button.
384 ** @param button Pointer to button to check/enable.
385 **
386 ** @return True if enabled.
387 */
ButtonCheckNoResearch(const CUnit & unit,const ButtonAction &)388 bool ButtonCheckNoResearch(const CUnit &unit, const ButtonAction &)
389 {
390 int action = unit.CurrentAction();
391 return action != UnitActionUpgradeTo && action != UnitActionResearch;
392 }
393
394 /**
395 ** Check for button enabled, if all requirements for an upgrade to unit
396 ** are met.
397 **
398 ** @param unit Pointer to unit for button.
399 ** @param button Pointer to button to check/enable.
400 **
401 ** @return True if enabled.
402 */
ButtonCheckUpgradeTo(const CUnit & unit,const ButtonAction & button)403 bool ButtonCheckUpgradeTo(const CUnit &unit, const ButtonAction &button)
404 {
405 if (unit.CurrentAction() != UnitActionStill) {
406 return false;
407 }
408 return CheckDependencies(UnitTypes[button.Value], unit.Player, false, true);
409 }
410
411 /**
412 ** Check if all requirements for an attack are met.
413 **
414 ** @param unit Pointer to unit for button.
415 ** @param button Pointer to button to check/enable.
416 **
417 ** @return True if enabled.
418 */
ButtonCheckAttack(const CUnit & unit,const ButtonAction &)419 bool ButtonCheckAttack(const CUnit &unit, const ButtonAction &)
420 {
421 //Wyrmgus start
422 // return unit.Type->CanAttack;
423 return unit.CanAttack(true);
424 //Wyrmgus end
425 }
426
427 /**
428 ** Check if all requirements for upgrade research are met.
429 **
430 ** @param unit Pointer to unit for button.
431 ** @param button Pointer to button to check/enable.
432 **
433 ** @return True if enabled.
434 */
ButtonCheckResearch(const CUnit & unit,const ButtonAction & button)435 bool ButtonCheckResearch(const CUnit &unit, const ButtonAction &button)
436 {
437 // don't show any if working
438 if (!ButtonCheckNoWork(unit, button)) {
439 return false;
440 }
441
442 // check if allowed
443 if (!CheckDependencies(AllUpgrades[button.Value], unit.Player, false, true)) {
444 return false;
445 }
446 if (!strncmp(button.ValueStr.c_str(), "upgrade-", 8)
447 && UpgradeIdentAllowed(*unit.Player, button.ValueStr) != 'A' && UpgradeIdentAllowed(*unit.Player, button.ValueStr) != 'R') {
448 return false;
449 }
450 return true;
451 }
452
453 /**
454 ** Check if all requirements for upgrade research are met only one
455 ** running research allowed.
456 **
457 ** @param unit Pointer to unit for button.
458 ** @param button Pointer to button to check/enable.
459 **
460 ** @return True if enabled.
461 */
ButtonCheckSingleResearch(const CUnit & unit,const ButtonAction & button)462 bool ButtonCheckSingleResearch(const CUnit &unit, const ButtonAction &button)
463 {
464 if (ButtonCheckResearch(unit, button)
465 //Wyrmgus start
466 // && !unit.Player->UpgradeTimers.Upgrades[UpgradeIdByIdent(button.ValueStr)]) {
467 && (!unit.Player->UpgradeTimers.Upgrades[UpgradeIdByIdent(button.ValueStr)] || unit.Player->UpgradeTimers.Upgrades[UpgradeIdByIdent(button.ValueStr)] == AllUpgrades[UpgradeIdByIdent(button.ValueStr)]->Costs[TimeCost])
468 ) {
469 //Wyrmgus end
470 return true;
471 }
472 return false;
473 }
474
475 //Wyrmgus start
476 /**
477 ** Check for button enabled, if the unit has an inventory.
478 **
479 ** @param unit Pointer to unit for button.
480 ** @param button Pointer to button to check/enable.
481 **
482 ** @return True if enabled.
483 */
ButtonCheckHasInventory(const CUnit & unit,const ButtonAction & button)484 bool ButtonCheckHasInventory(const CUnit &unit, const ButtonAction &button)
485 {
486 return Selected.size() == 1 && unit.HasInventory();
487 }
488
489 /**
490 ** Check for button enabled, if the button level it leads to has any sub buttons.
491 **
492 ** @param unit Pointer to unit for button.
493 ** @param button Pointer to button to check/enable.
494 **
495 ** @return True if enabled.
496 */
ButtonCheckHasSubButtons(const CUnit & unit,const ButtonAction & button)497 bool ButtonCheckHasSubButtons(const CUnit &unit, const ButtonAction &button)
498 {
499 for (size_t i = 0; i < UnitButtonTable.size(); ++i) {
500 if (UnitButtonTable[i]->GetLevelID() != button.Value) {
501 continue;
502 }
503
504 if (UnitButtonTable[i]->Action == ButtonButton && (UnitButtonTable[i]->Value == button.GetLevelID() || UnitButtonTable[i]->Value == 0)) { //don't count buttons to return to the level where this button is, or buttons to return to the default level
505 continue;
506 }
507
508 char unit_ident[128];
509 sprintf(unit_ident, ",%s,", unit.Type->Ident.c_str());
510 if (UnitButtonTable[i]->UnitMask[0] != '*' && !strstr(UnitButtonTable[i]->UnitMask.c_str(), unit_ident)) {
511 continue;
512 }
513
514 if (!UnitButtonTable[i]->AlwaysShow && !IsButtonAllowed(unit, *UnitButtonTable[i])) {
515 continue;
516 }
517
518 return true;
519 }
520
521 return false;
522 }
523 //Wyrmgus end
524
525 //@}
526