GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
* The ManaPlus Client |
||
3 |
* Copyright (C) 2004-2009 The Mana World Development Team |
||
4 |
* Copyright (C) 2009-2010 The Mana Developers |
||
5 |
* Copyright (C) 2011-2019 The ManaPlus Developers |
||
6 |
* Copyright (C) 2019-2021 Andrei Karas |
||
7 |
* |
||
8 |
* This file is part of The ManaPlus Client. |
||
9 |
* |
||
10 |
* This program is free software; you can redistribute it and/or modify |
||
11 |
* it under the terms of the GNU General Public License as published by |
||
12 |
* the Free Software Foundation; either version 2 of the License, or |
||
13 |
* any later version. |
||
14 |
* |
||
15 |
* This program is distributed in the hope that it will be useful, |
||
16 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
17 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
18 |
* GNU General Public License for more details. |
||
19 |
* |
||
20 |
* You should have received a copy of the GNU General Public License |
||
21 |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
22 |
*/ |
||
23 |
|||
24 |
#include "gui/windows/skilldialog.h" |
||
25 |
|||
26 |
#include "configuration.h" |
||
27 |
#include "effectmanager.h" |
||
28 |
#include "spellmanager.h" |
||
29 |
|||
30 |
#include "being/localplayer.h" |
||
31 |
#include "being/playerinfo.h" |
||
32 |
|||
33 |
#include "const/resources/spriteaction.h" |
||
34 |
|||
35 |
#include "enums/resources/skill/skillsettype.h" |
||
36 |
|||
37 |
#include "gui/shortcut/itemshortcut.h" |
||
38 |
|||
39 |
#include "gui/windows/setupwindow.h" |
||
40 |
#include "gui/windows/shortcutwindow.h" |
||
41 |
|||
42 |
#include "gui/widgets/button.h" |
||
43 |
#include "gui/widgets/createwidget.h" |
||
44 |
#include "gui/widgets/label.h" |
||
45 |
#include "gui/widgets/scrollarea.h" |
||
46 |
#include "gui/widgets/tabbedarea.h" |
||
47 |
|||
48 |
#include "gui/widgets/tabs/skilltab.h" |
||
49 |
|||
50 |
#include "gui/windows/textdialog.h" |
||
51 |
|||
52 |
#include "listeners/textskilllistener.h" |
||
53 |
|||
54 |
#include "net/playerhandler.h" |
||
55 |
#include "net/skillhandler.h" |
||
56 |
|||
57 |
#include "utils/checkutils.h" |
||
58 |
#include "utils/dtor.h" |
||
59 |
#include "utils/gettext.h" |
||
60 |
#include "utils/timer.h" |
||
61 |
|||
62 |
#include "resources/beingcommon.h" |
||
63 |
|||
64 |
#include "debug.h" |
||
65 |
|||
66 |
SkillDialog *skillDialog = nullptr; |
||
67 |
|||
68 |
namespace |
||
69 |
{ |
||
70 |
1 |
TextSkillListener textSkillListener; |
|
71 |
} // namespace |
||
72 |
|||
73 |
static SkillOwner::Type parseOwner(const std::string &str) |
||
74 |
{ |
||
75 |
if (str == "player") |
||
76 |
return SkillOwner::Player; |
||
77 |
else if (str == "mercenary") |
||
78 |
return SkillOwner::Mercenary; |
||
79 |
else if (str == "homunculus") |
||
80 |
return SkillOwner::Homunculus; |
||
81 |
return SkillOwner::Player; |
||
82 |
} |
||
83 |
|||
84 |
1 |
SkillDialog::SkillDialog() : |
|
85 |
// TRANSLATORS: skills dialog name |
||
86 |
1 |
Window(_("Skills"), Modal_false, nullptr, "skills.xml"), |
|
87 |
ActionListener(), |
||
88 |
mSkills(), |
||
89 |
mDurations(), |
||
90 |
✓✗✓✗ ✓✗✓✗ ✓✗ |
1 |
mTabs(CREATEWIDGETR(TabbedArea, this)), |
91 |
mDeleteTabs(), |
||
92 |
✓✗✓✗ |
1 |
mPointsLabel(new Label(this, "0")), |
93 |
// TRANSLATORS: skills dialog button |
||
94 |
✓✗✓✗ |
2 |
mUseButton(new Button(this, _("Use"), "use", BUTTON_SKIN, this)), |
95 |
// TRANSLATORS: skills dialog button |
||
96 |
✓✗✓✗ |
2 |
mIncreaseButton(new Button(this, _("Up"), "inc", BUTTON_SKIN, this)), |
97 |
mDefaultModel(nullptr), |
||
98 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗ |
30 |
mDefaultTab(nullptr) |
99 |
{ |
||
100 |
✓✗ | 5 |
setWindowName("Skills"); |
101 |
✓✗ | 1 |
setCloseButton(true); |
102 |
✓✗ | 1 |
setResizable(true); |
103 |
2 |
setSaveVisible(true); |
|
104 |
✓✗ | 1 |
setStickyButtonLock(true); |
105 |
✓✗ | 2 |
setDefaultSize(windowContainer->getWidth() - 280, 30, 275, 425); |
106 |
✗✓ | 1 |
if (setupWindow != nullptr) |
107 |
setupWindow->registerWindowForReset(this); |
||
108 |
|||
109 |
2 |
mUseButton->setEnabled(false); |
|
110 |
2 |
mIncreaseButton->setEnabled(false); |
|
111 |
2 |
mTabs->setSelectable(false); |
|
112 |
3 |
mTabs->getTabContainer()->setSelectable(false); |
|
113 |
3 |
mTabs->getWidgetContainer()->setSelectable(false); |
|
114 |
|||
115 |
✓✗✓✗ |
1 |
place(0, 0, mTabs, 5, 5); |
116 |
✓✗ | 1 |
place(0, 5, mPointsLabel, 4, 1); |
117 |
✓✗ | 1 |
place(3, 5, mUseButton, 1, 1); |
118 |
✓✗ | 1 |
place(4, 5, mIncreaseButton, 1, 1); |
119 |
1 |
} |
|
120 |
|||
121 |
1 |
void SkillDialog::postInit() |
|
122 |
{ |
||
123 |
1 |
Window::postInit(); |
|
124 |
2 |
setLocationRelativeTo(getParent()); |
|
125 |
1 |
loadWindowState(); |
|
126 |
2 |
enableVisibleSound(true); |
|
127 |
1 |
} |
|
128 |
|||
129 |
7 |
SkillDialog::~SkillDialog() |
|
130 |
{ |
||
131 |
1 |
clearSkills(); |
|
132 |
2 |
} |
|
133 |
|||
134 |
void SkillDialog::addDefaultTab() |
||
135 |
{ |
||
136 |
mDefaultModel = new SkillModel; |
||
137 |
SkillListBox *const listbox = new SkillListBox(this, |
||
138 |
mDefaultModel); |
||
139 |
listbox->setActionEventId("sel"); |
||
140 |
listbox->addActionListener(this); |
||
141 |
ScrollArea *const scroll = new ScrollArea(this, |
||
142 |
listbox, |
||
143 |
Opaque_false, |
||
144 |
std::string()); |
||
145 |
scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); |
||
146 |
scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); |
||
147 |
// TRANSLATORS: unknown skills tab name |
||
148 |
mDefaultTab = new SkillTab(this, _("Unknown"), listbox); |
||
149 |
mDeleteTabs.push_back(mDefaultTab); |
||
150 |
mDefaultTab->setVisible(Visible_false); |
||
151 |
mTabs->addTab(mDefaultTab, scroll); |
||
152 |
mTabs->adjustTabPositions(); |
||
153 |
mTabs->setSelectedTabDefault(); |
||
154 |
} |
||
155 |
|||
156 |
void SkillDialog::action(const ActionEvent &event) |
||
157 |
{ |
||
158 |
const std::string &eventId = event.getId(); |
||
159 |
if (eventId == "inc") |
||
160 |
{ |
||
161 |
if (playerHandler == nullptr) |
||
162 |
return; |
||
163 |
const SkillTab *const tab = static_cast<const SkillTab *>( |
||
164 |
mTabs->getSelectedTab()); |
||
165 |
if (tab != nullptr) |
||
166 |
{ |
||
167 |
if (const SkillInfo *const info = tab->getSelectedInfo()) |
||
168 |
playerHandler->increaseSkill(CAST_U16(info->id)); |
||
169 |
} |
||
170 |
} |
||
171 |
else if (eventId == "sel") |
||
172 |
{ |
||
173 |
const SkillTab *const tab = static_cast<const SkillTab *>( |
||
174 |
mTabs->getSelectedTab()); |
||
175 |
if (tab != nullptr) |
||
176 |
{ |
||
177 |
if (const SkillInfo *const info = tab->getSelectedInfo()) |
||
178 |
{ |
||
179 |
mUseButton->setEnabled(info->isUsable()); |
||
180 |
mUseButton->setCaption(info->useButton); |
||
181 |
mIncreaseButton->setEnabled(info->id < SKILL_VAR_MIN_ID); |
||
182 |
const int num = itemShortcutWindow->getTabIndex(); |
||
183 |
if (num >= 0 && num < CAST_S32(SHORTCUT_TABS) |
||
184 |
&& (itemShortcut[num] != nullptr)) |
||
185 |
{ |
||
186 |
itemShortcut[num]->setItemSelected( |
||
187 |
info->id + SKILL_MIN_ID); |
||
188 |
} |
||
189 |
} |
||
190 |
else |
||
191 |
{ |
||
192 |
mUseButton->setEnabled(false); |
||
193 |
mIncreaseButton->setEnabled(false); |
||
194 |
// TRANSLATORS: skills dialog button |
||
195 |
mUseButton->setCaption(_("Use")); |
||
196 |
} |
||
197 |
} |
||
198 |
} |
||
199 |
else if (eventId == "use") |
||
200 |
{ |
||
201 |
const SkillTab *const tab = static_cast<const SkillTab *>( |
||
202 |
mTabs->getSelectedTab()); |
||
203 |
if (tab != nullptr) |
||
204 |
{ |
||
205 |
const SkillInfo *const info = tab->getSelectedInfo(); |
||
206 |
if (info == nullptr) |
||
207 |
return; |
||
208 |
useSkill(info, |
||
209 |
fromBool(config.getBoolValue("skillAutotarget"), AutoTarget), |
||
210 |
info->customSelectedLevel, |
||
211 |
info->useTextParameter, |
||
212 |
std::string(), |
||
213 |
info->customCastType, |
||
214 |
info->customOffsetX, |
||
215 |
info->customOffsetY); |
||
216 |
} |
||
217 |
} |
||
218 |
else if (eventId == "close") |
||
219 |
{ |
||
220 |
setVisible(Visible_false); |
||
221 |
} |
||
222 |
} |
||
223 |
|||
224 |
std::string SkillDialog::update(const int id) |
||
225 |
{ |
||
226 |
const SkillMap::const_iterator i = mSkills.find(id); |
||
227 |
|||
228 |
if (i != mSkills.end()) |
||
229 |
{ |
||
230 |
SkillInfo *const info = i->second; |
||
231 |
if (info != nullptr) |
||
232 |
{ |
||
233 |
info->update(); |
||
234 |
return info->data->name; |
||
235 |
} |
||
236 |
} |
||
237 |
|||
238 |
return std::string(); |
||
239 |
} |
||
240 |
|||
241 |
void SkillDialog::update() |
||
242 |
{ |
||
243 |
// TRANSLATORS: skills dialog label |
||
244 |
mPointsLabel->setCaption(strprintf(_("Skill points available: %d"), |
||
245 |
PlayerInfo::getAttribute(Attributes::PLAYER_SKILL_POINTS))); |
||
246 |
mPointsLabel->adjustSize(); |
||
247 |
|||
248 |
ItemShortcut *const shortcuts = itemShortcut[SHORTCUT_AUTO_TAB]; |
||
249 |
shortcuts->clear(); |
||
250 |
size_t idx = 0; |
||
251 |
|||
252 |
FOR_EACH (SkillMap::const_iterator, it, mSkills) |
||
253 |
{ |
||
254 |
SkillInfo *const info = (*it).second; |
||
255 |
if (info == nullptr) |
||
256 |
continue; |
||
257 |
if (info->modifiable == Modifiable_true) |
||
258 |
info->update(); |
||
259 |
if (info->visible == Visible_false || |
||
260 |
idx >= SHORTCUT_ITEMS || |
||
261 |
!info->data->autoTab) |
||
262 |
{ |
||
263 |
continue; |
||
264 |
} |
||
265 |
const SkillType::SkillType type = info->type; |
||
266 |
if (type == SkillType::Attack || |
||
267 |
type == SkillType::Ground || |
||
268 |
type == SkillType::Self || |
||
269 |
type == SkillType::Support) |
||
270 |
{ |
||
271 |
shortcuts->setItemFast(idx, |
||
272 |
info->id + SKILL_MIN_ID, |
||
273 |
fromInt(info->customSelectedLevel, ItemColor)); |
||
274 |
|||
275 |
shortcuts->setItemData(idx, |
||
276 |
info->toDataStr()); |
||
277 |
idx ++; |
||
278 |
} |
||
279 |
} |
||
280 |
|||
281 |
skillPopup->reset(); |
||
282 |
} |
||
283 |
|||
284 |
void SkillDialog::updateModels() |
||
285 |
{ |
||
286 |
std::set<SkillModel*> models; |
||
287 |
|||
288 |
FOR_EACH (SkillMap::const_iterator, it, mSkills) |
||
289 |
{ |
||
290 |
SkillInfo *const info = (*it).second; |
||
291 |
if (info != nullptr) |
||
292 |
{ |
||
293 |
SkillModel *const model = info->model; |
||
294 |
if (model != nullptr) |
||
295 |
models.insert(model); |
||
296 |
} |
||
297 |
} |
||
298 |
FOR_EACH (std::set<SkillModel*>::iterator, it, models) |
||
299 |
{ |
||
300 |
SkillModel *const model = *it; |
||
301 |
if (model != nullptr) |
||
302 |
model->updateVisibilities(); |
||
303 |
} |
||
304 |
} |
||
305 |
|||
306 |
void SkillDialog::updateModelsHidden() |
||
307 |
{ |
||
308 |
std::set<SkillModel*> models; |
||
309 |
|||
310 |
FOR_EACH (SkillMap::const_iterator, it, mSkills) |
||
311 |
{ |
||
312 |
SkillInfo *const info = (*it).second; |
||
313 |
if (info != nullptr) |
||
314 |
{ |
||
315 |
if (info->visible == Visible_false) |
||
316 |
{ |
||
317 |
SkillModel *const model = info->model; |
||
318 |
if (model != nullptr) |
||
319 |
models.insert(model); |
||
320 |
} |
||
321 |
} |
||
322 |
} |
||
323 |
FOR_EACH (std::set<SkillModel*>::iterator, it, models) |
||
324 |
{ |
||
325 |
SkillModel *const model = *it; |
||
326 |
if (model != nullptr) |
||
327 |
model->updateVisibilities(); |
||
328 |
} |
||
329 |
} |
||
330 |
|||
331 |
1 |
void SkillDialog::clearSkills() |
|
332 |
{ |
||
333 |
1 |
mTabs->removeAll(true); |
|
334 |
2 |
mDeleteTabs.clear(); |
|
335 |
1 |
mDefaultTab = nullptr; |
|
336 |
1 |
mDefaultModel = nullptr; |
|
337 |
|||
338 |
2 |
delete_all(mSkills); |
|
339 |
2 |
mSkills.clear(); |
|
340 |
2 |
mDurations.clear(); |
|
341 |
1 |
} |
|
342 |
|||
343 |
void SkillDialog::hideSkills(const SkillOwner::Type owner) |
||
344 |
{ |
||
345 |
FOR_EACH (SkillMap::iterator, it, mSkills) |
||
346 |
{ |
||
347 |
SkillInfo *const info = (*it).second; |
||
348 |
if ((info != nullptr) && info->owner == owner) |
||
349 |
{ |
||
350 |
PlayerInfo::setSkillLevel(info->id, 0); |
||
351 |
if (info->alwaysVisible == Visible_false) |
||
352 |
info->visible = Visible_false; |
||
353 |
} |
||
354 |
} |
||
355 |
} |
||
356 |
|||
357 |
void SkillDialog::loadSkills() |
||
358 |
{ |
||
359 |
clearSkills(); |
||
360 |
loadXmlFile(paths.getStringValue("skillsFile"), SkipError_false); |
||
361 |
if (mSkills.empty()) |
||
362 |
loadXmlFile(paths.getStringValue("skillsFile2"), SkipError_false); |
||
363 |
loadXmlFile(paths.getStringValue("skillsPatchFile"), SkipError_true); |
||
364 |
loadXmlDir("skillsPatchDir", loadXmlFile) |
||
365 |
addDefaultTab(); |
||
366 |
|||
367 |
update(); |
||
368 |
} |
||
369 |
|||
370 |
void SkillDialog::loadXmlFile(const std::string &fileName, |
||
371 |
const SkipError skipError) |
||
372 |
{ |
||
373 |
XML::Document doc(fileName, |
||
374 |
UseVirtFs_true, |
||
375 |
skipError); |
||
376 |
XmlNodePtrConst root = doc.rootNode(); |
||
377 |
|||
378 |
int setCount = 0; |
||
379 |
|||
380 |
if ((root == nullptr) || !xmlNameEqual(root, "skills")) |
||
381 |
{ |
||
382 |
logger->log("Error loading skills: " + fileName); |
||
383 |
return; |
||
384 |
} |
||
385 |
|||
386 |
for_each_xml_child_node(set, root) |
||
387 |
{ |
||
388 |
if (xmlNameEqual(set, "include")) |
||
389 |
{ |
||
390 |
const std::string name = XML::getProperty(set, "name", ""); |
||
391 |
if (!name.empty()) |
||
392 |
loadXmlFile(name, skipError); |
||
393 |
continue; |
||
394 |
} |
||
395 |
else if (xmlNameEqual(set, "set")) |
||
396 |
{ |
||
397 |
setCount++; |
||
398 |
const std::string setName = XML::getProperty(set, "name", |
||
399 |
// TRANSLATORS: skills dialog default skill tab |
||
400 |
strprintf(_("Skill Set %d"), setCount)); |
||
401 |
|||
402 |
const std::string setTypeStr = XML::getProperty(set, "type", ""); |
||
403 |
SkillSetTypeT setType = SkillSetType::VerticalList; |
||
404 |
if (setTypeStr.empty() || |
||
405 |
setTypeStr == "list" || |
||
406 |
setTypeStr == "vertical") |
||
407 |
{ |
||
408 |
setType = SkillSetType::VerticalList; |
||
409 |
} |
||
410 |
else if (setTypeStr == "rectangle") |
||
411 |
{ |
||
412 |
setType = SkillSetType::Rectangle; |
||
413 |
} |
||
414 |
|||
415 |
bool alwaysVisible = false; |
||
416 |
SkillModel *const model = new SkillModel; |
||
417 |
SkillTab *tab = nullptr; |
||
418 |
ScrollArea *scroll = nullptr; |
||
419 |
|||
420 |
switch (setType) |
||
421 |
{ |
||
422 |
case SkillSetType::VerticalList: |
||
423 |
{ |
||
424 |
// possible leak listbox, scroll |
||
425 |
SkillListBox *const listbox = new SkillListBox(this, |
||
426 |
model); |
||
427 |
listbox->setActionEventId("sel"); |
||
428 |
listbox->addActionListener(this); |
||
429 |
scroll = new ScrollArea(this, |
||
430 |
listbox, |
||
431 |
Opaque_false, |
||
432 |
std::string()); |
||
433 |
scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); |
||
434 |
scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); |
||
435 |
tab = new SkillTab(this, setName, listbox); |
||
436 |
break; |
||
437 |
} |
||
438 |
case SkillSetType::Rectangle: |
||
439 |
{ |
||
440 |
SkillRectangleListBox *const listbox = |
||
441 |
new SkillRectangleListBox(this, |
||
442 |
model); |
||
443 |
listbox->setActionEventId("sel"); |
||
444 |
listbox->addActionListener(this); |
||
445 |
scroll = new ScrollArea(this, |
||
446 |
listbox, |
||
447 |
Opaque_false, |
||
448 |
std::string()); |
||
449 |
scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); |
||
450 |
scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); |
||
451 |
tab = new SkillTab(this, setName, listbox); |
||
452 |
break; |
||
453 |
} |
||
454 |
default: |
||
455 |
reportAlways("Unsupported skillset type: %s", |
||
456 |
setTypeStr.c_str()) |
||
457 |
return; |
||
458 |
} |
||
459 |
if (mDefaultModel == nullptr) |
||
460 |
{ |
||
461 |
mDefaultModel = model; |
||
462 |
mDefaultTab = tab; |
||
463 |
} |
||
464 |
|||
465 |
mDeleteTabs.push_back(tab); |
||
466 |
if (alwaysVisible == true) |
||
467 |
tab->setVisible(Visible_true); |
||
468 |
else |
||
469 |
tab->setVisible(Visible_false); |
||
470 |
mTabs->addTab(tab, scroll); |
||
471 |
|||
472 |
for_each_xml_child_node(node, set) |
||
473 |
{ |
||
474 |
if (xmlNameEqual(node, "skill")) |
||
475 |
{ |
||
476 |
SkillInfo *const skill = loadSkill(node, model); |
||
477 |
if (skill == nullptr) |
||
478 |
continue; |
||
479 |
if (skill->alwaysVisible == Visible_true) |
||
480 |
alwaysVisible = true; |
||
481 |
skill->tab = tab; |
||
482 |
for_each_xml_child_node(levelNode, node) |
||
483 |
{ |
||
484 |
if (!xmlNameEqual(levelNode, "level")) |
||
485 |
continue; |
||
486 |
loadSkillData(node, skill); |
||
487 |
} |
||
488 |
} |
||
489 |
} |
||
490 |
|||
491 |
model->updateVisibilities(); |
||
492 |
} |
||
493 |
} |
||
494 |
} |
||
495 |
|||
496 |
SkillInfo *SkillDialog::loadSkill(XmlNodeConstPtr node, |
||
497 |
SkillModel *const model) |
||
498 |
{ |
||
499 |
int id = XML::getIntProperty(node, "id", -1, -1, 1000000); |
||
500 |
if (id == -1) |
||
501 |
{ |
||
502 |
id = XML::getIntProperty(node, "var", -1, -1, 100000); |
||
503 |
if (id == -1) |
||
504 |
return nullptr; |
||
505 |
id += SKILL_VAR_MIN_ID; |
||
506 |
} |
||
507 |
|||
508 |
SkillInfo *skill = getSkill(id); |
||
509 |
if (skill == nullptr) |
||
510 |
{ |
||
511 |
std::string name = XML::langProperty(node, "name", |
||
512 |
// TRANSLATORS: skills dialog. skill id |
||
513 |
strprintf(_("Skill %d"), id)); |
||
514 |
|||
515 |
skill = new SkillInfo; |
||
516 |
skill->id = CAST_U32(id); |
||
517 |
skill->modifiable = Modifiable_false; |
||
518 |
skill->model = model; |
||
519 |
skill->update(); |
||
520 |
skill->useButton = XML::getProperty( |
||
521 |
// TRANSLATORS: skills dialog button |
||
522 |
node, "useButton", _("Use")); |
||
523 |
skill->owner = parseOwner(XML::getProperty( |
||
524 |
node, "owner", "player")); |
||
525 |
skill->errorText = XML::getProperty( |
||
526 |
node, "errorText", name); |
||
527 |
skill->alwaysVisible = fromBool(XML::getBoolProperty( |
||
528 |
node, "alwaysVisible", false), Visible); |
||
529 |
skill->castingAction = XML::getProperty(node, |
||
530 |
"castingAction", SpriteAction::CAST); |
||
531 |
skill->castingRideAction = XML::getProperty(node, |
||
532 |
"castingRideAction", SpriteAction::CASTRIDE); |
||
533 |
skill->castingSkyAction = XML::getProperty(node, |
||
534 |
"castingSkyAction", SpriteAction::CASTSKY); |
||
535 |
skill->castingWaterAction = XML::getProperty(node, |
||
536 |
"castingWaterAction", SpriteAction::CASTWATER); |
||
537 |
skill->useTextParameter = XML::getBoolProperty( |
||
538 |
node, "useTextParameter", false); |
||
539 |
skill->x = XML::getProperty(node, |
||
540 |
"x", 0); |
||
541 |
skill->y = XML::getProperty(node, |
||
542 |
"y", 0); |
||
543 |
skill->visible = skill->alwaysVisible; |
||
544 |
model->addSkill(skill); |
||
545 |
mSkills[id] = skill; |
||
546 |
} |
||
547 |
|||
548 |
loadSkillData(node, skill); |
||
549 |
return skill; |
||
550 |
} |
||
551 |
|||
552 |
void SkillDialog::loadSkillData(XmlNodeConstPtr node, |
||
553 |
SkillInfo *const skill) |
||
554 |
{ |
||
555 |
if (skill == nullptr) |
||
556 |
return; |
||
557 |
const int level = (skill->alwaysVisible == Visible_true) ? |
||
558 |
0 : XML::getProperty(node, "level", 0); |
||
559 |
SkillData *data = skill->getData(level); |
||
560 |
if (data == nullptr) |
||
561 |
data = new SkillData; |
||
562 |
|||
563 |
const std::string name = XML::langProperty(node, "name", |
||
564 |
// TRANSLATORS: skills dialog. skill id |
||
565 |
strprintf(_("Skill %u"), skill->id)); |
||
566 |
data->name = name; |
||
567 |
const std::string icon = XML::getProperty(node, "icon", ""); |
||
568 |
if (icon.empty()) |
||
569 |
{ |
||
570 |
data->setIcon(paths.getStringValue("missingSkillIcon")); |
||
571 |
data->haveIcon = false; |
||
572 |
} |
||
573 |
else |
||
574 |
{ |
||
575 |
data->setIcon(icon); |
||
576 |
data->haveIcon = true; |
||
577 |
} |
||
578 |
if (skill->id < SKILL_VAR_MIN_ID) |
||
579 |
{ |
||
580 |
data->dispName = strprintf("%s, %u", |
||
581 |
name.c_str(), |
||
582 |
skill->id); |
||
583 |
} |
||
584 |
else |
||
585 |
{ |
||
586 |
data->dispName = strprintf("%s, (%u)", |
||
587 |
name.c_str(), |
||
588 |
skill->id - SKILL_VAR_MIN_ID); |
||
589 |
} |
||
590 |
data->shortName = XML::langProperty(node, |
||
591 |
"shortName", name.substr(0, 3)); |
||
592 |
data->description = XML::langProperty( |
||
593 |
node, "description", ""); |
||
594 |
|||
595 |
MissileInfo &missile = data->missile; |
||
596 |
missile.particle = XML::getProperty( |
||
597 |
node, "missile-particle", ""); |
||
598 |
missile.z = XML::getFloatProperty( |
||
599 |
node, "missile-z", 32.0F); |
||
600 |
missile.lifeTime = XML::getProperty( |
||
601 |
node, "missile-lifetime", 500); |
||
602 |
missile.speed = XML::getFloatProperty( |
||
603 |
node, "missile-speed", 7.0F); |
||
604 |
missile.dieDistance = XML::getFloatProperty( |
||
605 |
node, "missile-diedistance", 8.0F); |
||
606 |
|||
607 |
MissileInfo &castingMissile = data->castingMissile; |
||
608 |
castingMissile.particle = XML::getProperty( |
||
609 |
node, "castingMissile-particle", ""); |
||
610 |
castingMissile.z = XML::getFloatProperty( |
||
611 |
node, "castingMissile-z", 32.0F); |
||
612 |
castingMissile.lifeTime = XML::getProperty( |
||
613 |
node, "castingMissile-lifetime", 500); |
||
614 |
castingMissile.speed = XML::getFloatProperty( |
||
615 |
node, "castingMissile-speed", 7.0F); |
||
616 |
castingMissile.dieDistance = XML::getFloatProperty( |
||
617 |
node, "castingMissile-diedistance", 8.0F); |
||
618 |
|||
619 |
data->castingAnimation = XML::getProperty( |
||
620 |
node, |
||
621 |
"castingAnimation", |
||
622 |
paths.getStringValue("skillCastingAnimation")); |
||
623 |
|||
624 |
data->soundHit.sound = XML::getProperty( |
||
625 |
node, "soundHit", ""); |
||
626 |
data->soundHit.delay = XML::getProperty( |
||
627 |
node, "soundHitDelay", 0); |
||
628 |
data->soundMiss.sound = XML::getProperty( |
||
629 |
node, "soundMiss", ""); |
||
630 |
data->soundMiss.delay = XML::getProperty( |
||
631 |
node, "soundMissDelay", 0); |
||
632 |
data->invokeCmd = XML::getProperty( |
||
633 |
node, "invokeCmd", ""); |
||
634 |
data->updateEffectId = XML::getProperty( |
||
635 |
node, "levelUpEffectId", -1); |
||
636 |
data->removeEffectId = XML::getProperty( |
||
637 |
node, "removeEffectId", -1); |
||
638 |
data->hitEffectId = XML::getProperty( |
||
639 |
node, "hitEffectId", -1); |
||
640 |
data->missEffectId = XML::getProperty( |
||
641 |
node, "missEffectId", -1); |
||
642 |
data->castingSrcEffectId = XML::getProperty( |
||
643 |
node, "castingSrcEffectId", -1); |
||
644 |
data->castingDstEffectId = XML::getProperty( |
||
645 |
node, "castingDstEffectId", -1); |
||
646 |
data->srcEffectId = XML::getProperty( |
||
647 |
node, "srcEffectId", -1); |
||
648 |
data->dstEffectId = XML::getProperty( |
||
649 |
node, "dstEffectId", -1); |
||
650 |
data->castingGroundEffectId = XML::getProperty( |
||
651 |
node, "castingGroundEffectId", -1); |
||
652 |
data->autoTab = XML::getBoolProperty( |
||
653 |
node, "autoTab", true); |
||
654 |
|||
655 |
skill->addData(level, data); |
||
656 |
} |
||
657 |
|||
658 |
void SkillDialog::removeSkill(const int id) |
||
659 |
{ |
||
660 |
const SkillMap::const_iterator it = mSkills.find(id); |
||
661 |
|||
662 |
if (it != mSkills.end()) |
||
663 |
{ |
||
664 |
SkillInfo *const info = it->second; |
||
665 |
if (info != nullptr) |
||
666 |
{ |
||
667 |
info->level = 0; |
||
668 |
info->update(); |
||
669 |
PlayerInfo::setSkillLevel(id, 0); |
||
670 |
if (info->alwaysVisible == Visible_false) |
||
671 |
info->visible = Visible_false; |
||
672 |
} |
||
673 |
} |
||
674 |
} |
||
675 |
|||
676 |
bool SkillDialog::updateSkill(const int id, |
||
677 |
const int range, |
||
678 |
const Modifiable modifiable, |
||
679 |
const SkillType::SkillType type, |
||
680 |
const int sp) |
||
681 |
{ |
||
682 |
const SkillMap::const_iterator it = mSkills.find(id); |
||
683 |
|||
684 |
if (it != mSkills.end()) |
||
685 |
{ |
||
686 |
SkillInfo *const info = it->second; |
||
687 |
if (info != nullptr) |
||
688 |
{ |
||
689 |
info->modifiable = modifiable; |
||
690 |
info->range = range; |
||
691 |
info->type = type; |
||
692 |
info->sp = sp; |
||
693 |
info->update(); |
||
694 |
if (info->tab != nullptr) |
||
695 |
{ |
||
696 |
info->tab->setVisible(Visible_true); |
||
697 |
mTabs->adjustTabPositions(); |
||
698 |
mTabs->setSelectedTabDefault(); |
||
699 |
} |
||
700 |
} |
||
701 |
return true; |
||
702 |
} |
||
703 |
return false; |
||
704 |
} |
||
705 |
|||
706 |
std::string SkillDialog::getDefaultSkillIcon(const SkillType::SkillType type) |
||
707 |
{ |
||
708 |
std::string icon; |
||
709 |
switch (type) |
||
710 |
{ |
||
711 |
case SkillType::Attack: |
||
712 |
icon = paths.getStringValue("attackSkillIcon"); |
||
713 |
break; |
||
714 |
case SkillType::Ground: |
||
715 |
icon = paths.getStringValue("groundSkillIcon"); |
||
716 |
break; |
||
717 |
case SkillType::Self: |
||
718 |
icon = paths.getStringValue("selfSkillIcon"); |
||
719 |
break; |
||
720 |
case SkillType::Unused: |
||
721 |
icon = paths.getStringValue("unusedSkillIcon"); |
||
722 |
break; |
||
723 |
case SkillType::Support: |
||
724 |
icon = paths.getStringValue("supportSkillIcon"); |
||
725 |
break; |
||
726 |
case SkillType::TargetTrap: |
||
727 |
icon = paths.getStringValue("trapSkillIcon"); |
||
728 |
break; |
||
729 |
case SkillType::Unknown: |
||
730 |
icon = paths.getStringValue("unknownSkillIcon"); |
||
731 |
break; |
||
732 |
default: |
||
733 |
break; |
||
734 |
} |
||
735 |
return icon; |
||
736 |
} |
||
737 |
|||
738 |
void SkillDialog::addSkill(const SkillOwner::Type owner, |
||
739 |
const int id, |
||
740 |
const std::string &name, |
||
741 |
const int level, |
||
742 |
const int range, |
||
743 |
const Modifiable modifiable, |
||
744 |
const SkillType::SkillType type, |
||
745 |
const int sp) |
||
746 |
{ |
||
747 |
if (mDefaultModel != nullptr) |
||
748 |
{ |
||
749 |
SkillInfo *const skill = new SkillInfo; |
||
750 |
skill->id = CAST_U32(id); |
||
751 |
skill->type = type; |
||
752 |
skill->owner = owner; |
||
753 |
SkillData *const data = skill->data; |
||
754 |
if (name.empty()) |
||
755 |
{ |
||
756 |
data->name = "Unknown skill Id: " + toString(id); |
||
757 |
data->dispName = data->name; |
||
758 |
} |
||
759 |
else |
||
760 |
{ |
||
761 |
data->name = name; |
||
762 |
data->dispName = strprintf("%s, %u", name.c_str(), skill->id); |
||
763 |
} |
||
764 |
data->description.clear(); |
||
765 |
const std::string icon = getDefaultSkillIcon(type); |
||
766 |
if (icon.empty()) |
||
767 |
{ |
||
768 |
data->setIcon(paths.getStringValue("missingSkillIcon")); |
||
769 |
data->haveIcon = false; |
||
770 |
} |
||
771 |
else |
||
772 |
{ |
||
773 |
data->setIcon(icon); |
||
774 |
data->haveIcon = true; |
||
775 |
} |
||
776 |
data->autoTab = settings.unknownSkillsAutoTab; |
||
777 |
data->shortName = toString(skill->id); |
||
778 |
skill->modifiable = modifiable; |
||
779 |
skill->visible = Visible_false; |
||
780 |
skill->alwaysVisible = Visible_false; |
||
781 |
skill->model = mDefaultModel; |
||
782 |
skill->level = level; |
||
783 |
// TRANSLATORS: skills dialog. skill level |
||
784 |
skill->skillLevel = strprintf(_("Lvl: %d"), level); |
||
785 |
skill->range = range; |
||
786 |
skill->sp = sp; |
||
787 |
skill->update(); |
||
788 |
// TRANSLATORS: skills dialog button |
||
789 |
skill->useButton = _("Use"); |
||
790 |
// TRANSLATORS: skill error message |
||
791 |
skill->errorText = strprintf(_("Failed skill: %s"), name.c_str()); |
||
792 |
skill->tab = mDefaultTab; |
||
793 |
mDefaultModel->addSkill(skill); |
||
794 |
mDefaultTab->setVisible(Visible_true); |
||
795 |
mTabs->adjustTabPositions(); |
||
796 |
mTabs->setSelectedTabDefault(); |
||
797 |
|||
798 |
mSkills[id] = skill; |
||
799 |
mDefaultModel->updateVisibilities(); |
||
800 |
} |
||
801 |
} |
||
802 |
|||
803 |
SkillInfo* SkillDialog::getSkill(const int id) const |
||
804 |
{ |
||
805 |
SkillMap::const_iterator it = mSkills.find(id); |
||
806 |
if (it != mSkills.end()) |
||
807 |
return (*it).second; |
||
808 |
return nullptr; |
||
809 |
} |
||
810 |
|||
811 |
SkillInfo* SkillDialog::getSkillByItem(const int itemId) const |
||
812 |
{ |
||
813 |
SkillMap::const_iterator it = mSkills.find(itemId - SKILL_MIN_ID); |
||
814 |
if (it != mSkills.end()) |
||
815 |
return (*it).second; |
||
816 |
return nullptr; |
||
817 |
} |
||
818 |
|||
819 |
void SkillDialog::setSkillDuration(const SkillOwner::Type owner, |
||
820 |
const int id, |
||
821 |
const int duration) |
||
822 |
{ |
||
823 |
SkillMap::const_iterator it = mSkills.find(id); |
||
824 |
SkillInfo *info = nullptr; |
||
825 |
if (it == mSkills.end()) |
||
826 |
{ |
||
827 |
addSkill(owner, id, "", 0, 0, Modifiable_false, SkillType::Unknown, 0); |
||
828 |
it = mSkills.find(id); |
||
829 |
} |
||
830 |
if (it != mSkills.end()) |
||
831 |
{ |
||
832 |
info = (*it).second; |
||
833 |
} |
||
834 |
if (info != nullptr) |
||
835 |
{ |
||
836 |
info->duration = duration; |
||
837 |
info->durationTime = tick_time; |
||
838 |
addSkillDuration(info); |
||
839 |
} |
||
840 |
} |
||
841 |
|||
842 |
1 |
void SkillDialog::widgetResized(const Event &event) |
|
843 |
{ |
||
844 |
1 |
Window::widgetResized(event); |
|
845 |
|||
846 |
✓✗ | 1 |
if (mTabs != nullptr) |
847 |
1 |
mTabs->adjustSize(); |
|
848 |
1 |
} |
|
849 |
|||
850 |
void SkillDialog::useItem(const int itemId, |
||
851 |
const AutoTarget autoTarget, |
||
852 |
const int level, |
||
853 |
const std::string &data) const |
||
854 |
{ |
||
855 |
const std::map<int, SkillInfo*>::const_iterator |
||
856 |
it = mSkills.find(itemId - SKILL_MIN_ID); |
||
857 |
if (it == mSkills.end()) |
||
858 |
return; |
||
859 |
|||
860 |
const SkillInfo *const info = (*it).second; |
||
861 |
CastTypeT castType = CastType::Default; |
||
862 |
int offsetX = 0; |
||
863 |
int offsetY = 0; |
||
864 |
|||
865 |
if (!data.empty()) |
||
866 |
{ |
||
867 |
STD_VECTOR<int> vect; |
||
868 |
splitToIntVector(vect, data, ' '); |
||
869 |
const size_t sz = vect.size(); |
||
870 |
if (sz > 0) |
||
871 |
castType = static_cast<CastTypeT>(vect[0]); |
||
872 |
if (sz > 2) |
||
873 |
{ |
||
874 |
offsetX = vect[1]; |
||
875 |
offsetY = vect[2]; |
||
876 |
} |
||
877 |
} |
||
878 |
useSkill(info, |
||
879 |
autoTarget, |
||
880 |
level, |
||
881 |
false, |
||
882 |
std::string(), |
||
883 |
castType, |
||
884 |
offsetX, |
||
885 |
offsetY); |
||
886 |
} |
||
887 |
|||
888 |
void SkillDialog::updateTabSelection() |
||
889 |
{ |
||
890 |
const SkillTab *const tab = static_cast<SkillTab*>( |
||
891 |
mTabs->getSelectedTab()); |
||
892 |
if (tab != nullptr) |
||
893 |
{ |
||
894 |
if (const SkillInfo *const info = tab->getSelectedInfo()) |
||
895 |
{ |
||
896 |
mUseButton->setEnabled(info->range > 0); |
||
897 |
mIncreaseButton->setEnabled(info->id < SKILL_VAR_MIN_ID); |
||
898 |
mUseButton->setCaption(info->useButton); |
||
899 |
} |
||
900 |
else |
||
901 |
{ |
||
902 |
mUseButton->setEnabled(false); |
||
903 |
// TRANSLATORS: inventory button |
||
904 |
mUseButton->setCaption(_("Use")); |
||
905 |
} |
||
906 |
} |
||
907 |
} |
||
908 |
|||
909 |
void SkillDialog::updateQuest(const int var, |
||
910 |
const int val1, |
||
911 |
const int val2 A_UNUSED, |
||
912 |
const int val3 A_UNUSED, |
||
913 |
const int time1 A_UNUSED) |
||
914 |
{ |
||
915 |
const int id = var + SKILL_VAR_MIN_ID; |
||
916 |
const SkillMap::const_iterator it = mSkills.find(id); |
||
917 |
|||
918 |
if (it != mSkills.end()) |
||
919 |
{ |
||
920 |
SkillInfo *const info = it->second; |
||
921 |
if (info != nullptr) |
||
922 |
{ |
||
923 |
PlayerInfo::setSkillLevel(id, val1); |
||
924 |
info->level = val1; |
||
925 |
info->update(); |
||
926 |
} |
||
927 |
} |
||
928 |
} |
||
929 |
|||
930 |
SkillData *SkillDialog::getSkillData(const int id) const |
||
931 |
{ |
||
932 |
const SkillMap::const_iterator it = mSkills.find(id); |
||
933 |
if (it != mSkills.end()) |
||
934 |
{ |
||
935 |
SkillInfo *const info = it->second; |
||
936 |
if (info != nullptr) |
||
937 |
return info->data; |
||
938 |
} |
||
939 |
return nullptr; |
||
940 |
} |
||
941 |
|||
942 |
SkillData *SkillDialog::getSkillDataByLevel(const int id, |
||
943 |
const int level) const |
||
944 |
{ |
||
945 |
const SkillMap::const_iterator it = mSkills.find(id); |
||
946 |
if (it != mSkills.end()) |
||
947 |
{ |
||
948 |
SkillInfo *const info = it->second; |
||
949 |
if (info != nullptr) |
||
950 |
return info->getData1(level); |
||
951 |
} |
||
952 |
return nullptr; |
||
953 |
} |
||
954 |
|||
955 |
void SkillDialog::playUpdateEffect(const int id) const |
||
956 |
{ |
||
957 |
if (effectManager == nullptr) |
||
958 |
return; |
||
959 |
const SkillData *const data = getSkillData(id); |
||
960 |
if (data == nullptr) |
||
961 |
return; |
||
962 |
effectManager->triggerDefault(data->updateEffectId, |
||
963 |
localPlayer, |
||
964 |
paths.getIntValue("skillLevelUpEffectId")); |
||
965 |
} |
||
966 |
|||
967 |
void SkillDialog::playRemoveEffect(const int id) const |
||
968 |
{ |
||
969 |
if (effectManager == nullptr) |
||
970 |
return; |
||
971 |
const SkillData *const data = getSkillData(id); |
||
972 |
if (data == nullptr) |
||
973 |
return; |
||
974 |
effectManager->triggerDefault(data->removeEffectId, |
||
975 |
localPlayer, |
||
976 |
paths.getIntValue("skillRemoveEffectId")); |
||
977 |
} |
||
978 |
|||
979 |
void SkillDialog::playCastingDstTileEffect(const int id, |
||
980 |
const int level, |
||
981 |
const int x, |
||
982 |
const int y, |
||
983 |
const int delay) const |
||
984 |
{ |
||
985 |
if (effectManager == nullptr) |
||
986 |
return; |
||
987 |
SkillData *const data = getSkillDataByLevel(id, level); |
||
988 |
if (data == nullptr) |
||
989 |
return; |
||
990 |
effectManager->triggerDefault(data->castingGroundEffectId, |
||
991 |
x * 32, |
||
992 |
y * 32, |
||
993 |
cur_time + delay / 1000, // end time in seconds |
||
994 |
paths.getIntValue("skillCastingGroundEffectId")); |
||
995 |
} |
||
996 |
|||
997 |
void SkillDialog::useSkill(const int skillId, |
||
998 |
const AutoTarget autoTarget, |
||
999 |
int level, |
||
1000 |
const bool withText, |
||
1001 |
const std::string &text, |
||
1002 |
CastTypeT castType, |
||
1003 |
const int offsetX, |
||
1004 |
const int offsetY) |
||
1005 |
{ |
||
1006 |
SkillInfo *const info = skillDialog->getSkill(skillId); |
||
1007 |
if (info == nullptr) |
||
1008 |
return; |
||
1009 |
if (castType == CastType::Default) |
||
1010 |
castType = info->customCastType; |
||
1011 |
useSkill(info, |
||
1012 |
autoTarget, |
||
1013 |
level, |
||
1014 |
withText, |
||
1015 |
text, |
||
1016 |
castType, |
||
1017 |
offsetX, |
||
1018 |
offsetY); |
||
1019 |
} |
||
1020 |
|||
1021 |
void SkillDialog::useSkill(const SkillInfo *const info, |
||
1022 |
const AutoTarget autoTarget, |
||
1023 |
int level, |
||
1024 |
const bool withText, |
||
1025 |
const std::string &text, |
||
1026 |
const CastTypeT castType, |
||
1027 |
const int offsetX, |
||
1028 |
const int offsetY) |
||
1029 |
{ |
||
1030 |
if ((info == nullptr) || (localPlayer == nullptr)) |
||
1031 |
return; |
||
1032 |
if (level == 0) |
||
1033 |
level = info->level; |
||
1034 |
|||
1035 |
const SkillData *data = info->getData1(level); |
||
1036 |
if (data != nullptr) |
||
1037 |
{ |
||
1038 |
const std::string cmd = data->invokeCmd; |
||
1039 |
if (!cmd.empty()) |
||
1040 |
SpellManager::invokeCommand(cmd, localPlayer->getTarget()); |
||
1041 |
} |
||
1042 |
switch (castType) |
||
1043 |
{ |
||
1044 |
default: |
||
1045 |
case CastType::Default: |
||
1046 |
useSkillDefault(info, |
||
1047 |
autoTarget, |
||
1048 |
level, |
||
1049 |
withText, |
||
1050 |
text, |
||
1051 |
offsetX, |
||
1052 |
offsetY); |
||
1053 |
break; |
||
1054 |
case CastType::Target: |
||
1055 |
{ |
||
1056 |
const Being *const being = localPlayer->getTarget(); |
||
1057 |
useSkillTarget(info, |
||
1058 |
autoTarget, |
||
1059 |
level, |
||
1060 |
withText, |
||
1061 |
text, |
||
1062 |
being, |
||
1063 |
offsetX, |
||
1064 |
offsetY); |
||
1065 |
break; |
||
1066 |
} |
||
1067 |
case CastType::Position: |
||
1068 |
{ |
||
1069 |
int x = 0; |
||
1070 |
int y = 0; |
||
1071 |
viewport->getMouseTile(x, y); |
||
1072 |
useSkillPosition(info, |
||
1073 |
level, |
||
1074 |
withText, |
||
1075 |
text, |
||
1076 |
x, |
||
1077 |
y, |
||
1078 |
offsetX, |
||
1079 |
offsetY); |
||
1080 |
break; |
||
1081 |
} |
||
1082 |
case CastType::Self: |
||
1083 |
// +++ probably need call useSkillSelf |
||
1084 |
useSkillTarget(info, |
||
1085 |
autoTarget, |
||
1086 |
level, |
||
1087 |
withText, |
||
1088 |
text, |
||
1089 |
localPlayer, |
||
1090 |
offsetX, |
||
1091 |
offsetY); |
||
1092 |
break; |
||
1093 |
} |
||
1094 |
} |
||
1095 |
|||
1096 |
void SkillDialog::useSkillTarget(const SkillInfo *const info, |
||
1097 |
const AutoTarget autoTarget, |
||
1098 |
int level, |
||
1099 |
const bool withText, |
||
1100 |
const std::string &text, |
||
1101 |
const Being *being, |
||
1102 |
int offsetX, |
||
1103 |
int offsetY) |
||
1104 |
{ |
||
1105 |
SkillType::SkillType type = info->type; |
||
1106 |
if ((type & SkillType::Attack) != 0) |
||
1107 |
{ |
||
1108 |
if ((being == nullptr) && autoTarget == AutoTarget_true) |
||
1109 |
{ |
||
1110 |
if (localPlayer != nullptr) |
||
1111 |
{ |
||
1112 |
being = localPlayer->setNewTarget(ActorType::Monster, |
||
1113 |
AllowSort_true); |
||
1114 |
} |
||
1115 |
} |
||
1116 |
if (being != nullptr) |
||
1117 |
{ |
||
1118 |
skillHandler->useBeing(info->id, |
||
1119 |
level, |
||
1120 |
being->getId()); |
||
1121 |
} |
||
1122 |
} |
||
1123 |
else if ((type & SkillType::Support) != 0) |
||
1124 |
{ |
||
1125 |
if (being == nullptr) |
||
1126 |
being = localPlayer; |
||
1127 |
if (being != nullptr) |
||
1128 |
{ |
||
1129 |
skillHandler->useBeing(info->id, |
||
1130 |
level, |
||
1131 |
being->getId()); |
||
1132 |
} |
||
1133 |
} |
||
1134 |
else if ((type & SkillType::Self) != 0) |
||
1135 |
{ |
||
1136 |
skillHandler->useBeing(info->id, |
||
1137 |
level, |
||
1138 |
localPlayer->getId()); |
||
1139 |
} |
||
1140 |
else if ((type & SkillType::Ground) != 0) |
||
1141 |
{ |
||
1142 |
if (being == nullptr) |
||
1143 |
return; |
||
1144 |
being->fixDirectionOffsets(offsetX, offsetY); |
||
1145 |
const int x = being->getTileX() + offsetX; |
||
1146 |
const int y = being->getTileY() + offsetY; |
||
1147 |
if (info->useTextParameter) |
||
1148 |
{ |
||
1149 |
if (withText) |
||
1150 |
{ |
||
1151 |
skillHandler->usePos(info->id, |
||
1152 |
level, |
||
1153 |
x, y, |
||
1154 |
text); |
||
1155 |
} |
||
1156 |
else |
||
1157 |
{ |
||
1158 |
const SkillData *data = info->getData1(level); |
||
1159 |
textSkillListener.setSkill(info->id, |
||
1160 |
x, |
||
1161 |
y, |
||
1162 |
level); |
||
1163 |
TextDialog *const dialog = CREATEWIDGETR(TextDialog, |
||
1164 |
// TRANSLATORS: text skill dialog header |
||
1165 |
strprintf(_("Add text to skill %s"), |
||
1166 |
data->name.c_str()), |
||
1167 |
// TRANSLATORS: text skill dialog field |
||
1168 |
_("Text: "), |
||
1169 |
nullptr, |
||
1170 |
false); |
||
1171 |
dialog->setModal(Modal_true); |
||
1172 |
textSkillListener.setDialog(dialog); |
||
1173 |
dialog->setActionEventId("ok"); |
||
1174 |
dialog->addActionListener(&textSkillListener); |
||
1175 |
} |
||
1176 |
} |
||
1177 |
else |
||
1178 |
{ |
||
1179 |
skillHandler->usePos(info->id, |
||
1180 |
level, |
||
1181 |
x, y); |
||
1182 |
} |
||
1183 |
} |
||
1184 |
else if ((type & SkillType::TargetTrap) != 0) |
||
1185 |
{ |
||
1186 |
// for now unused |
||
1187 |
} |
||
1188 |
else if (type == SkillType::Unknown || |
||
1189 |
type == SkillType::Unused) |
||
1190 |
{ |
||
1191 |
// unknown / unused |
||
1192 |
} |
||
1193 |
else |
||
1194 |
{ |
||
1195 |
reportAlways("Unsupported skill type: %d", type) |
||
1196 |
} |
||
1197 |
} |
||
1198 |
|||
1199 |
void SkillDialog::useSkillPosition(const SkillInfo *const info, |
||
1200 |
int level, |
||
1201 |
const bool withText, |
||
1202 |
const std::string &text, |
||
1203 |
const int x, |
||
1204 |
const int y, |
||
1205 |
int offsetX, |
||
1206 |
int offsetY) |
||
1207 |
{ |
||
1208 |
SkillType::SkillType type = info->type; |
||
1209 |
if ((type & SkillType::Ground) != 0) |
||
1210 |
{ |
||
1211 |
localPlayer->fixDirectionOffsets(offsetX, offsetY); |
||
1212 |
if (info->useTextParameter) |
||
1213 |
{ |
||
1214 |
if (withText) |
||
1215 |
{ |
||
1216 |
skillHandler->usePos(info->id, |
||
1217 |
level, |
||
1218 |
x + offsetX, |
||
1219 |
y + offsetY, |
||
1220 |
text); |
||
1221 |
} |
||
1222 |
else |
||
1223 |
{ |
||
1224 |
const SkillData *data = info->getData1(level); |
||
1225 |
textSkillListener.setSkill(info->id, |
||
1226 |
x + offsetX, |
||
1227 |
y + offsetY, |
||
1228 |
level); |
||
1229 |
TextDialog *const dialog = CREATEWIDGETR(TextDialog, |
||
1230 |
// TRANSLATORS: text skill dialog header |
||
1231 |
strprintf(_("Add text to skill %s"), |
||
1232 |
data->name.c_str()), |
||
1233 |
// TRANSLATORS: text skill dialog field |
||
1234 |
_("Text: "), |
||
1235 |
nullptr, |
||
1236 |
false); |
||
1237 |
dialog->setModal(Modal_true); |
||
1238 |
textSkillListener.setDialog(dialog); |
||
1239 |
dialog->setActionEventId("ok"); |
||
1240 |
dialog->addActionListener(&textSkillListener); |
||
1241 |
} |
||
1242 |
} |
||
1243 |
else |
||
1244 |
{ |
||
1245 |
skillHandler->usePos(info->id, |
||
1246 |
level, |
||
1247 |
x + offsetX, |
||
1248 |
y + offsetY); |
||
1249 |
} |
||
1250 |
} |
||
1251 |
else if ((type & SkillType::Support) != 0) |
||
1252 |
{ |
||
1253 |
// wrong type |
||
1254 |
skillHandler->useBeing(info->id, |
||
1255 |
level, |
||
1256 |
localPlayer->getId()); |
||
1257 |
} |
||
1258 |
else if ((type & SkillType::Self) != 0) |
||
1259 |
{ |
||
1260 |
skillHandler->useBeing(info->id, |
||
1261 |
level, |
||
1262 |
localPlayer->getId()); |
||
1263 |
} |
||
1264 |
else if ((type & SkillType::Attack) != 0) |
||
1265 |
{ |
||
1266 |
// do nothing |
||
1267 |
// +++ probably need select some target on x,y position? |
||
1268 |
} |
||
1269 |
else if ((type & SkillType::TargetTrap) != 0) |
||
1270 |
{ |
||
1271 |
// for now unused |
||
1272 |
} |
||
1273 |
else if (type == SkillType::Unknown || |
||
1274 |
type == SkillType::Unused) |
||
1275 |
{ |
||
1276 |
// unknown / unused |
||
1277 |
} |
||
1278 |
else |
||
1279 |
{ |
||
1280 |
reportAlways("Unsupported skill type: %d", type) |
||
1281 |
} |
||
1282 |
} |
||
1283 |
|||
1284 |
void SkillDialog::useSkillDefault(const SkillInfo *const info, |
||
1285 |
const AutoTarget autoTarget, |
||
1286 |
int level, |
||
1287 |
const bool withText, |
||
1288 |
const std::string &text, |
||
1289 |
int offsetX, |
||
1290 |
int offsetY) |
||
1291 |
{ |
||
1292 |
SkillType::SkillType type = info->type; |
||
1293 |
if ((type & SkillType::Attack) != 0) |
||
1294 |
{ |
||
1295 |
const Being *being = localPlayer->getTarget(); |
||
1296 |
if ((being == nullptr) && autoTarget == AutoTarget_true) |
||
1297 |
{ |
||
1298 |
being = localPlayer->setNewTarget(ActorType::Monster, |
||
1299 |
AllowSort_true); |
||
1300 |
} |
||
1301 |
if (being != nullptr) |
||
1302 |
{ |
||
1303 |
skillHandler->useBeing(info->id, |
||
1304 |
level, |
||
1305 |
being->getId()); |
||
1306 |
} |
||
1307 |
} |
||
1308 |
else if ((type & SkillType::Support) != 0) |
||
1309 |
{ |
||
1310 |
const Being *being = localPlayer->getTarget(); |
||
1311 |
if (being == nullptr) |
||
1312 |
being = localPlayer; |
||
1313 |
if (being != nullptr) |
||
1314 |
{ |
||
1315 |
skillHandler->useBeing(info->id, |
||
1316 |
level, |
||
1317 |
being->getId()); |
||
1318 |
} |
||
1319 |
} |
||
1320 |
else if ((type & SkillType::Self) != 0) |
||
1321 |
{ |
||
1322 |
skillHandler->useBeing(info->id, |
||
1323 |
level, |
||
1324 |
localPlayer->getId()); |
||
1325 |
} |
||
1326 |
else if ((type & SkillType::Ground) != 0) |
||
1327 |
{ |
||
1328 |
int x = 0; |
||
1329 |
int y = 0; |
||
1330 |
viewport->getMouseTile(x, y); |
||
1331 |
localPlayer->fixDirectionOffsets(offsetX, offsetY); |
||
1332 |
x += offsetX; |
||
1333 |
y += offsetY; |
||
1334 |
if (info->useTextParameter) |
||
1335 |
{ |
||
1336 |
if (withText) |
||
1337 |
{ |
||
1338 |
skillHandler->usePos(info->id, |
||
1339 |
level, |
||
1340 |
x, y, |
||
1341 |
text); |
||
1342 |
} |
||
1343 |
else |
||
1344 |
{ |
||
1345 |
const SkillData *data = info->getData1(level); |
||
1346 |
textSkillListener.setSkill(info->id, |
||
1347 |
x, |
||
1348 |
y, |
||
1349 |
level); |
||
1350 |
TextDialog *const dialog = CREATEWIDGETR(TextDialog, |
||
1351 |
// TRANSLATORS: text skill dialog header |
||
1352 |
strprintf(_("Add text to skill %s"), |
||
1353 |
data->name.c_str()), |
||
1354 |
// TRANSLATORS: text skill dialog field |
||
1355 |
_("Text: "), |
||
1356 |
nullptr, |
||
1357 |
false); |
||
1358 |
dialog->setModal(Modal_true); |
||
1359 |
textSkillListener.setDialog(dialog); |
||
1360 |
dialog->setActionEventId("ok"); |
||
1361 |
dialog->addActionListener(&textSkillListener); |
||
1362 |
} |
||
1363 |
} |
||
1364 |
else |
||
1365 |
{ |
||
1366 |
skillHandler->usePos(info->id, |
||
1367 |
level, |
||
1368 |
x, y); |
||
1369 |
} |
||
1370 |
} |
||
1371 |
else if ((type & SkillType::TargetTrap) != 0) |
||
1372 |
{ |
||
1373 |
// for now unused |
||
1374 |
} |
||
1375 |
else if (type == SkillType::Unknown || |
||
1376 |
type == SkillType::Unused) |
||
1377 |
{ |
||
1378 |
// unknown / unused |
||
1379 |
} |
||
1380 |
else |
||
1381 |
{ |
||
1382 |
reportAlways("Unsupported skill type: %d", type) |
||
1383 |
} |
||
1384 |
} |
||
1385 |
|||
1386 |
void SkillDialog::addSkillDuration(SkillInfo *const skill) |
||
1387 |
{ |
||
1388 |
if (skill == nullptr) |
||
1389 |
return; |
||
1390 |
|||
1391 |
FOR_EACH (STD_VECTOR<SkillInfo*>::const_iterator, it, mDurations) |
||
1392 |
{ |
||
1393 |
if ((*it)->id == skill->id) |
||
1394 |
return; |
||
1395 |
} |
||
1396 |
mDurations.push_back(skill); |
||
1397 |
} |
||
1398 |
|||
1399 |
void SkillDialog::slowLogic() |
||
1400 |
{ |
||
1401 |
FOR_EACH_SAFE (STD_VECTOR<SkillInfo*>::iterator, it, mDurations) |
||
1402 |
{ |
||
1403 |
SkillInfo *const skill = *it; |
||
1404 |
if (skill != nullptr) |
||
1405 |
{ |
||
1406 |
const int time = get_elapsed_time(skill->durationTime); |
||
1407 |
if (time >= skill->duration) |
||
1408 |
{ |
||
1409 |
it = mDurations.erase(it); |
||
1410 |
skill->cooldown = 0; |
||
1411 |
skill->duration = 0; |
||
1412 |
skill->durationTime = 0; |
||
1413 |
if (it == mDurations.end()) |
||
1414 |
return; |
||
1415 |
if (it != mDurations.begin()) |
||
1416 |
-- it; |
||
1417 |
} |
||
1418 |
else if (time != 0) |
||
1419 |
{ |
||
1420 |
skill->cooldown = skill->duration * 100 / time; |
||
1421 |
} |
||
1422 |
} |
||
1423 |
} |
||
1424 |
} |
||
1425 |
|||
1426 |
void SkillDialog::selectSkillLevel(const int skillId, |
||
1427 |
const int level) |
||
1428 |
{ |
||
1429 |
SkillInfo *const info = getSkill(skillId); |
||
1430 |
if (info == nullptr) |
||
1431 |
return; |
||
1432 |
if (level > info->level) |
||
1433 |
info->customSelectedLevel = info->level; |
||
1434 |
else |
||
1435 |
info->customSelectedLevel = level; |
||
1436 |
info->update(); |
||
1437 |
} |
||
1438 |
|||
1439 |
void SkillDialog::selectSkillCastType(const int skillId, |
||
1440 |
const CastTypeT type) |
||
1441 |
{ |
||
1442 |
SkillInfo *const info = getSkill(skillId); |
||
1443 |
if (info == nullptr) |
||
1444 |
return; |
||
1445 |
info->customCastType = type; |
||
1446 |
info->update(); |
||
1447 |
} |
||
1448 |
|||
1449 |
void SkillDialog::setSkillOffsetX(const int skillId, |
||
1450 |
const int offset) |
||
1451 |
{ |
||
1452 |
SkillInfo *const info = getSkill(skillId); |
||
1453 |
if (info == nullptr) |
||
1454 |
return; |
||
1455 |
info->customOffsetX = offset; |
||
1456 |
info->update(); |
||
1457 |
} |
||
1458 |
|||
1459 |
void SkillDialog::setSkillOffsetY(const int skillId, |
||
1460 |
const int offset) |
||
1461 |
{ |
||
1462 |
SkillInfo *const info = getSkill(skillId); |
||
1463 |
if (info == nullptr) |
||
1464 |
return; |
||
1465 |
info->customOffsetY = offset; |
||
1466 |
info->update(); |
||
1467 |
✓✗✓✗ |
3 |
} |
Generated by: GCOVR (Version 3.3) |