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_action.cpp - The button action source file. */
12 //
13 //      (c) Copyright 1998-2019 by Lutz Sammer, Jimmy Salmon, Pali Rohár and Andrettin
14 //
15 //      This program is free software; you can redistribute it and/or modify
16 //      it under the terms of the GNU General Public License as published by
17 //      the Free Software Foundation; only version 2 of the License.
18 //
19 //      This program is distributed in the hope that it will be useful,
20 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //      GNU General Public License for more details.
23 //
24 //      You should have received a copy of the GNU General Public License
25 //      along with this program; if not, write to the Free Software
26 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 //      02111-1307, USA.
28 //
29 
30 //@{
31 
32 /*----------------------------------------------------------------------------
33 --  Includes
34 ----------------------------------------------------------------------------*/
35 
36 #include "stratagus.h"
37 
38 #include "ui/button_action.h"
39 
40 #include "config.h"
41 #include "trigger.h"
42 #include "ui/button_level.h"
43 #include "ui/interface.h"
44 #include "unit/unit.h"
45 #include "unit/unit_manager.h"
46 #include "video.h"
47 #include "widgets.h"
48 
49 /*----------------------------------------------------------------------------
50 --  Functions
51 ----------------------------------------------------------------------------*/
52 
53 /**
54 **	@brief	Process data provided by a configuration file
55 **
56 **	@param	config_data	The configuration data
57 */
ProcessConfigData(const CConfigData * config_data)58 void ButtonAction::ProcessConfigData(const CConfigData *config_data)
59 {
60 	ButtonAction ba;
61 
62 	for (size_t i = 0; i < config_data->Properties.size(); ++i) {
63 		std::string key = config_data->Properties[i].first;
64 		std::string value = config_data->Properties[i].second;
65 
66 		if (key == "pos") {
67 			ba.Pos = std::stoi(value);
68 		} else if (key == "level") {
69 			value = FindAndReplaceString(value, "_", "-");
70 			ba.Level = CButtonLevel::GetButtonLevel(value);
71 		} else if (key == "always_show") {
72 			ba.AlwaysShow = StringToBool(value);
73 		} else if (key == "icon") {
74 			value = FindAndReplaceString(value, "_", "-");
75 			ba.Icon.Name = value;
76 		} else if (key == "action") {
77 			value = FindAndReplaceString(value, "_", "-");
78 			const int button_action_id = GetButtonActionIdByName(value);
79 			if (button_action_id != -1) {
80 				ba.Action = ButtonCmd(button_action_id);
81 			} else {
82 				fprintf(stderr, "Invalid button action: \"%s\".\n", value.c_str());
83 			}
84 		} else if (key == "value") {
85 			value = FindAndReplaceString(value, "_", "-");
86 			ba.ValueStr = value;
87 		} else if (key == "allowed") {
88 			if (value == "check_true") {
89 				ba.Allowed = ButtonCheckTrue;
90 			} else if (value == "check_false") {
91 				ba.Allowed = ButtonCheckFalse;
92 			} else if (value == "check_upgrade") {
93 				ba.Allowed = ButtonCheckUpgrade;
94 			} else if (value == "check_upgrade_not") {
95 				ba.Allowed = ButtonCheckUpgradeNot;
96 			} else if (value == "check_upgrade_or") {
97 				ba.Allowed = ButtonCheckUpgradeOr;
98 			} else if (value == "check_individual_upgrade") {
99 				ba.Allowed = ButtonCheckIndividualUpgrade;
100 			} else if (value == "check_individual_upgrade_or") {
101 				ba.Allowed = ButtonCheckIndividualUpgradeOr;
102 			} else if (value == "check_unit_variable") {
103 				ba.Allowed = ButtonCheckUnitVariable;
104 			} else if (value == "check_units_or") {
105 				ba.Allowed = ButtonCheckUnitsOr;
106 			} else if (value == "check_units_and") {
107 				ba.Allowed = ButtonCheckUnitsAnd;
108 			} else if (value == "check_units_not") {
109 				ba.Allowed = ButtonCheckUnitsNot;
110 			} else if (value == "check_network") {
111 				ba.Allowed = ButtonCheckNetwork;
112 			} else if (value == "check_no_network") {
113 				ba.Allowed = ButtonCheckNoNetwork;
114 			} else if (value == "check_no_work") {
115 				ba.Allowed = ButtonCheckNoWork;
116 			} else if (value == "check_no_research") {
117 				ba.Allowed = ButtonCheckNoResearch;
118 			} else if (value == "check_attack") {
119 				ba.Allowed = ButtonCheckAttack;
120 			} else if (value == "check_upgrade_to") {
121 				ba.Allowed = ButtonCheckUpgradeTo;
122 			} else if (value == "check_research") {
123 				ba.Allowed = ButtonCheckResearch;
124 			} else if (value == "check_single_research") {
125 				ba.Allowed = ButtonCheckSingleResearch;
126 			} else if (value == "check_has_inventory") {
127 				ba.Allowed = ButtonCheckHasInventory;
128 			} else if (value == "check_has_sub_buttons") {
129 				ba.Allowed = ButtonCheckHasSubButtons;
130 			} else {
131 				fprintf(stderr, "Invalid button check: \"%s\".\n", value.c_str());
132 			}
133 		} else if (key == "allow_arg") {
134 			value = FindAndReplaceString(value, "_", "-");
135 			if (!ba.AllowStr.empty()) {
136 				ba.AllowStr += ",";
137 			}
138 			ba.AllowStr += value;
139 		} else if (key == "key") {
140 			ba.Key = GetHotKey(value);
141 		} else if (key == "hint") {
142 			ba.Hint = value;
143 		} else if (key == "description") {
144 			ba.Description = value;
145 		} else if (key == "comment_sound") {
146 			value = FindAndReplaceString(value, "_", "-");
147 			ba.CommentSound.Name = value;
148 		} else if (key == "button_cursor") {
149 			value = FindAndReplaceString(value, "_", "-");
150 			ba.ButtonCursor = value;
151 		} else if (key == "popup") {
152 			value = FindAndReplaceString(value, "_", "-");
153 			ba.Popup = value;
154 		} else if (key == "for_unit") {
155 			if (value == "*") {
156 				ba.UnitMask = value;
157 			} else {
158 				value = FindAndReplaceString(value, "_", "-");
159 				if (ba.UnitMask.empty()) {
160 					ba.UnitMask += ",";
161 				}
162 				ba.UnitMask += value;
163 				ba.UnitMask += ",";
164 			}
165 		} else {
166 			fprintf(stderr, "Invalid button property: \"%s\".\n", key.c_str());
167 		}
168 	}
169 
170 	AddButton(ba.Pos, ba.Level, ba.Icon.Name, ba.Action, ba.ValueStr, ba.Payload, ba.Allowed, ba.AllowStr, ba.Key, ba.Hint, ba.Description, ba.CommentSound.Name, ba.ButtonCursor, ba.UnitMask, ba.Popup, ba.AlwaysShow, ba.Mod);
171 }
172 
SetTriggerData() const173 void ButtonAction::SetTriggerData() const
174 {
175 	if (this->Action != ButtonUnit && this->Action != ButtonBuy) {
176 		TriggerData.Type = UnitTypes[this->Value];
177 	} else {
178 		TriggerData.Type = UnitTypes[UnitManager.GetSlotUnit(this->Value).Type->Slot];
179 		TriggerData.Unit = &UnitManager.GetSlotUnit(this->Value);
180 	}
181 	if (this->Action == ButtonResearch || this->Action == ButtonLearnAbility) {
182 		TriggerData.Upgrade = AllUpgrades[this->Value];
183 	} else if (this->Action == ButtonFaction) {
184 		TriggerData.Faction = PlayerRaces.Factions[ThisPlayer->Faction]->DevelopsTo[this->Value];
185 		if (!PlayerRaces.Factions[ThisPlayer->Faction]->DevelopsTo[this->Value]->FactionUpgrade.empty()) {
186 			TriggerData.Upgrade = CUpgrade::Get(PlayerRaces.Factions[ThisPlayer->Faction]->DevelopsTo[this->Value]->FactionUpgrade);
187 		}
188 	}
189 }
190 
CleanTriggerData() const191 void ButtonAction::CleanTriggerData() const
192 {
193 	TriggerData.Type = nullptr;
194 	TriggerData.Unit = nullptr;
195 	TriggerData.Upgrade = nullptr;
196 	TriggerData.Resource = nullptr;
197 	TriggerData.Faction = nullptr;
198 }
199 
GetLevelID() const200 int ButtonAction::GetLevelID() const
201 {
202 	if (this->Level) {
203 		return this->Level->ID;
204 	} else {
205 		return 0;
206 	}
207 }
208 
GetKey() const209 int ButtonAction::GetKey() const
210 {
211 	if ((this->Action == ButtonBuild || this->Action == ButtonTrain || this->Action == ButtonResearch || this->Action == ButtonLearnAbility || this->Action == ButtonExperienceUpgradeTo || this->Action == ButtonUpgradeTo) && !IsButtonUsable(*Selected[0], *this)) {
212 		return 0;
213 	}
214 
215 	if (this->Key == gcn::Key::K_ESCAPE || this->Key == gcn::Key::K_DELETE || this->Key == gcn::Key::K_PAGE_DOWN || this->Key == gcn::Key::K_PAGE_UP) {
216 		return this->Key;
217 	}
218 
219 	if ((Preference.HotkeySetup == 1 || (Preference.HotkeySetup == 2 && (this->Action == ButtonBuild || this->Action == ButtonTrain || this->Action == ButtonResearch || this->Action == ButtonLearnAbility || this->Action == ButtonExperienceUpgradeTo || this->Action == ButtonUpgradeTo || this->Action == ButtonRallyPoint || this->Action == ButtonSalvage || this->Action == ButtonEnterMapLayer))) && this->Key != 0) {
220 		if (this->Pos == 1) {
221 			return 'q';
222 		} else if (this->Pos == 2) {
223 			return 'w';
224 		} else if (this->Pos == 3) {
225 			return 'e';
226 		} else if (this->Pos == 4) {
227 			return 'r';
228 		} else if (this->Pos == 5) {
229 			return 'a';
230 		} else if (this->Pos == 6) {
231 			return 's';
232 		} else if (this->Pos == 7) {
233 			return 'd';
234 		} else if (this->Pos == 8) {
235 			return 'f';
236 		} else if (this->Pos == 9) {
237 			return 'z';
238 		} else if (this->Pos == 10) {
239 			return 'x';
240 		} else if (this->Pos == 11) {
241 			return 'c';
242 		} else if (this->Pos == 12) {
243 			return 'v';
244 		} else if (this->Pos == 13) {
245 			return 't';
246 		} else if (this->Pos == 14) {
247 			return 'g';
248 		} else if (this->Pos == 15) {
249 			return 'b';
250 		} else if (this->Pos == 16) {
251 			return 'y';
252 		}
253 	}
254 	return this->Key;
255 }
256 
GetHint() const257 std::string ButtonAction::GetHint() const
258 {
259 	if ((this->Action == ButtonBuild || this->Action == ButtonTrain || this->Action == ButtonResearch || this->Action == ButtonLearnAbility || this->Action == ButtonExperienceUpgradeTo || this->Action == ButtonUpgradeTo) && !IsButtonUsable(*Selected[0], *this) && this->Key != 0 && !this->Hint.empty()) {
260 		std::string hint = this->Hint;
261 		hint = FindAndReplaceString(hint, "~!", "");
262 		return hint;
263 	}
264 
265 	if (this->Key == gcn::Key::K_ESCAPE) {
266 		return this->Hint;
267 	}
268 
269 	if ((Preference.HotkeySetup == 1 || (Preference.HotkeySetup == 2 && (this->Action == ButtonBuild || this->Action == ButtonTrain || this->Action == ButtonResearch || this->Action == ButtonLearnAbility || this->Action == ButtonExperienceUpgradeTo || this->Action == ButtonUpgradeTo || this->Action == ButtonRallyPoint || this->Action == ButtonSalvage || this->Action == ButtonEnterMapLayer))) && this->Key != 0 && !this->Hint.empty()) {
270 		std::string hint = this->Hint;
271 		hint = FindAndReplaceString(hint, "~!", "");
272 		hint += " (~!";
273 		hint += CapitalizeString(SdlKey2Str(this->GetKey()));
274 		hint += ")";
275 		return hint;
276 	}
277 
278 	return this->Hint;
279 }
280 
GetButtonActionNameById(const int button_action)281 std::string GetButtonActionNameById(const int button_action)
282 {
283 	if (button_action == ButtonMove) {
284 		return "attack";
285 	} else if (button_action == ButtonStop) {
286 		return "stop";
287 	} else if (button_action == ButtonAttack) {
288 		return "attack";
289 	} else if (button_action == ButtonRepair) {
290 		return "repair";
291 	} else if (button_action == ButtonHarvest) {
292 		return "harvest";
293 	} else if (button_action == ButtonButton) {
294 		return "button";
295 	} else if (button_action == ButtonBuild) {
296 		return "build";
297 	} else if (button_action == ButtonTrain) {
298 		return "train-unit";
299 	} else if (button_action == ButtonPatrol) {
300 		return "patrol";
301 	} else if (button_action == ButtonStandGround) {
302 		return "stand-ground";
303 	} else if (button_action == ButtonAttackGround) {
304 		return "attack-ground";
305 	} else if (button_action == ButtonReturn) {
306 		return "return-goods";
307 	} else if (button_action == ButtonSpellCast) {
308 		return "cast-spell";
309 	} else if (button_action == ButtonResearch) {
310 		return "research";
311 	} else if (button_action == ButtonLearnAbility) {
312 		return "learn-ability";
313 	} else if (button_action == ButtonExperienceUpgradeTo) {
314 		return "experience-upgrade-to";
315 	} else if (button_action == ButtonUpgradeTo) {
316 		return "upgrade-to";
317 	} else if (button_action == ButtonUnload) {
318 		return "unload";
319 	} else if (button_action == ButtonRallyPoint) {
320 		return "rally-point";
321 	} else if (button_action == ButtonFaction) {
322 		return "faction";
323 	} else if (button_action == ButtonQuest) {
324 		return "quest";
325 	} else if (button_action == ButtonBuy) {
326 		return "buy";
327 	} else if (button_action == ButtonProduceResource) {
328 		return "produce-resource";
329 	} else if (button_action == ButtonSellResource) {
330 		return "sell-resource";
331 	} else if (button_action == ButtonBuyResource) {
332 		return "buy-resource";
333 	} else if (button_action == ButtonSalvage) {
334 		return "salvage";
335 	} else if (button_action == ButtonEnterMapLayer) {
336 		return "enter-map-layer";
337 	} else if (button_action == ButtonUnit) {
338 		return "unit";
339 	} else if (button_action == ButtonEditorUnit) {
340 		return "editor-unit";
341 	} else if (button_action == ButtonCancel) {
342 		return "cancel";
343 	} else if (button_action == ButtonCancelUpgrade) {
344 		return "cancel-upgrade";
345 	} else if (button_action == ButtonCancelTrain) {
346 		return "cancel-train-unit";
347 	} else if (button_action == ButtonCancelBuild) {
348 		return "cancel-build";
349 	}
350 
351 	return "";
352 }
353 
GetButtonActionIdByName(const std::string & button_action)354 int GetButtonActionIdByName(const std::string &button_action)
355 {
356 	if (button_action == "move") {
357 		return ButtonMove;
358 	} else if (button_action == "stop") {
359 		return ButtonStop;
360 	} else if (button_action == "attack") {
361 		return ButtonAttack;
362 	} else if (button_action == "repair") {
363 		return ButtonRepair;
364 	} else if (button_action == "harvest") {
365 		return ButtonHarvest;
366 	} else if (button_action == "button") {
367 		return ButtonButton;
368 	} else if (button_action == "build") {
369 		return ButtonBuild;
370 	} else if (button_action == "train-unit") {
371 		return ButtonTrain;
372 	} else if (button_action == "patrol") {
373 		return ButtonPatrol;
374 	} else if (button_action == "stand-ground") {
375 		return ButtonStandGround;
376 	} else if (button_action == "attack-ground") {
377 		return ButtonAttackGround;
378 	} else if (button_action == "return-goods") {
379 		return ButtonReturn;
380 	} else if (button_action == "cast-spell") {
381 		return ButtonSpellCast;
382 	} else if (button_action == "research") {
383 		return ButtonResearch;
384 	} else if (button_action == "learn-ability") {
385 		return ButtonLearnAbility;
386 	} else if (button_action == "experience-upgrade-to") {
387 		return ButtonExperienceUpgradeTo;
388 	} else if (button_action == "upgrade-to") {
389 		return ButtonUpgradeTo;
390 	} else if (button_action == "unload") {
391 		return ButtonUnload;
392 	} else if (button_action == "rally-point") {
393 		return ButtonRallyPoint;
394 	} else if (button_action == "faction") {
395 		return ButtonFaction;
396 	} else if (button_action == "quest") {
397 		return ButtonQuest;
398 	} else if (button_action == "buy") {
399 		return ButtonBuy;
400 	} else if (button_action == "produce-resource") {
401 		return ButtonProduceResource;
402 	} else if (button_action == "sell-resource") {
403 		return ButtonSellResource;
404 	} else if (button_action == "buy-resource") {
405 		return ButtonBuyResource;
406 	} else if (button_action == "salvage") {
407 		return ButtonSalvage;
408 	} else if (button_action == "enter-map-layer") {
409 		return ButtonEnterMapLayer;
410 	} else if (button_action == "unit") {
411 		return ButtonUnit;
412 	} else if (button_action == "editor-unit") {
413 		return ButtonEditorUnit;
414 	} else if (button_action == "cancel") {
415 		return ButtonCancel;
416 	} else if (button_action == "cancel-upgrade") {
417 		return ButtonCancelUpgrade;
418 	} else if (button_action == "cancel-train-unit") {
419 		return ButtonCancelTrain;
420 	} else if (button_action == "cancel-build") {
421 		return ButtonCancelBuild;
422 	}
423 
424 	return -1;
425 }
426 
IsNeutralUsableButtonAction(const int button_action)427 bool IsNeutralUsableButtonAction(const int button_action)
428 {
429 	return button_action == ButtonTrain || button_action == ButtonCancelTrain || button_action == ButtonBuy || button_action == ButtonSellResource || button_action == ButtonBuyResource || button_action == ButtonResearch;
430 }
431 
432 //@}
433