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