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