GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/eathena/skillrecv.cpp Lines: 1 264 0.4 %
Date: 2017-11-29 Branches: 0 248 0.0 %

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-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "net/eathena/skillrecv.h"
24
25
#include "notifymanager.h"
26
27
#include "being/localplayer.h"
28
#include "being/playerinfo.h"
29
30
#include "const/net/skill.h"
31
32
#include "enums/resources/notifytypes.h"
33
34
#include "gui/widgets/createwidget.h"
35
36
#include "gui/windows/skilldialog.h"
37
#include "gui/windows/textselectdialog.h"
38
39
#include "listeners/skillwarplistener.h"
40
41
#include "net/messagein.h"
42
43
#include "net/eathena/menu.h"
44
45
#include "resources/iteminfo.h"
46
47
#include "resources/db/itemdb.h"
48
49
#include "resources/skill/skillinfo.h"
50
51
#include "utils/gettext.h"
52
#include "utils/stringutils.h"
53
54
#include "debug.h"
55
56
static const unsigned int RFAIL                = 10;
57
static const unsigned int RFAIL_SUMMON         = 19;
58
static const unsigned int RFAIL_NEED_ITEM      = 71;
59
static const unsigned int RFAIL_NEED_EQUIPMENT = 72;
60
static const unsigned int RFAIL_SPIRITS        = 74;
61
62
extern int serverVersion;
63
64
namespace EAthena
65
{
66
67
void SkillRecv::processPlayerSkills(Net::MessageIn &msg)
68
{
69
    msg.readInt16("len");
70
    const int sz = (serverVersion >= 15) ? 41 : 37;
71
    const int skillCount = (msg.getLength() - 4) / sz;
72
    int updateSkill = 0;
73
74
    if (skillDialog != nullptr)
75
        skillDialog->hideSkills(SkillOwner::Player);
76
    for (int k = 0; k < skillCount; k++)
77
    {
78
        const int skillId = msg.readInt16("skill id");
79
        const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
80
            msg.readInt32("inf"));
81
        if (serverVersion >= 15)
82
            msg.readInt32("inf2");
83
        const int level = msg.readInt16("skill level");
84
        const int sp = msg.readInt16("sp");
85
        const int range = msg.readInt16("range");
86
        const std::string name = msg.readString(24, "skill name");
87
        const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
88
        const int oldLevel = PlayerInfo::getSkillLevel(skillId);
89
        if ((oldLevel != 0) && oldLevel != level)
90
            updateSkill = skillId;
91
        PlayerInfo::setSkillLevel(skillId, level);
92
        if (skillDialog != nullptr)
93
        {
94
            if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
95
            {
96
                skillDialog->addSkill(SkillOwner::Player,
97
                    skillId, name, level, range, up, inf, sp);
98
            }
99
        }
100
    }
101
    if (skillDialog != nullptr)
102
    {
103
        skillDialog->update();
104
        if (updateSkill != 0)
105
            skillDialog->playUpdateEffect(updateSkill);
106
    }
107
}
108
109
void SkillRecv::processSkillAdd(Net::MessageIn &msg)
110
{
111
    int updateSkill = 0;
112
    const int skillId = msg.readInt16("skill id");
113
    const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
114
        msg.readInt32("inf"));
115
    const int level = msg.readInt16("skill level");
116
    const int sp = msg.readInt16("sp");
117
    const int range = msg.readInt16("range");
118
    const std::string name = msg.readString(24, "skill name");
119
    const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
120
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
121
    if ((oldLevel != 0) && oldLevel != level)
122
        updateSkill = skillId;
123
    PlayerInfo::setSkillLevel(skillId, level);
124
    if (skillDialog != nullptr)
125
    {
126
        if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
127
        {
128
            skillDialog->addSkill(SkillOwner::Player,
129
                skillId, name, level, range, up, inf, sp);
130
        }
131
        skillDialog->update();
132
        if (updateSkill != 0)
133
            skillDialog->playUpdateEffect(updateSkill);
134
    }
135
}
136
137
void SkillRecv::processSkillAdd2(Net::MessageIn &msg)
138
{
139
    int updateSkill = 0;
140
    msg.readInt16("len");  // for now unused
141
    const int skillId = msg.readInt16("skill id");
142
    const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
143
        msg.readInt32("inf"));
144
    msg.readInt32("inf2");
145
    const int level = msg.readInt16("skill level");
146
    const int sp = msg.readInt16("sp");
147
    const int range = msg.readInt16("range");
148
    const std::string name = msg.readString(24, "skill name");
149
    const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
150
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
151
    if ((oldLevel != 0) && oldLevel != level)
152
        updateSkill = skillId;
153
    PlayerInfo::setSkillLevel(skillId, level);
154
    if (skillDialog != nullptr)
155
    {
156
        if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
157
        {
158
            skillDialog->addSkill(SkillOwner::Player,
159
                skillId, name, level, range, up, inf, sp);
160
        }
161
        skillDialog->update();
162
        if (updateSkill != 0)
163
            skillDialog->playUpdateEffect(updateSkill);
164
    }
165
}
166
167
void SkillRecv::processSkillUpdate(Net::MessageIn &msg)
168
{
169
    int updateSkill = 0;
170
    const int skillId = msg.readInt16("skill id");
171
    const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
172
        msg.readInt32("inf"));
173
    const int level = msg.readInt16("skill level");
174
    const int sp = msg.readInt16("sp");
175
    const int range = msg.readInt16("range");
176
    const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
177
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
178
    if ((oldLevel != 0) && oldLevel != level)
179
        updateSkill = skillId;
180
    PlayerInfo::setSkillLevel(skillId, level);
181
    if (skillDialog != nullptr)
182
    {
183
        if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
184
        {
185
            skillDialog->addSkill(SkillOwner::Player,
186
                skillId, "", level, range, up, inf, sp);
187
        }
188
        skillDialog->update();
189
        if (updateSkill != 0)
190
            skillDialog->playUpdateEffect(updateSkill);
191
    }
192
}
193
194
void SkillRecv::processSkillUpdate2(Net::MessageIn &msg)
195
{
196
    int updateSkill = 0;
197
    msg.readInt16("len");  // for now unused
198
    const int skillId = msg.readInt16("skill id");
199
    const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
200
        msg.readInt32("inf"));
201
    msg.readInt32("inf2");
202
    const int level = msg.readInt16("skill level");
203
    const int sp = msg.readInt16("sp");
204
    const int range = msg.readInt16("range");
205
    const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
206
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
207
    if ((oldLevel != 0) && oldLevel != level)
208
        updateSkill = skillId;
209
    PlayerInfo::setSkillLevel(skillId, level);
210
    if (skillDialog != nullptr)
211
    {
212
        if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
213
        {
214
            skillDialog->addSkill(SkillOwner::Player,
215
                skillId, "", level, range, up, inf, sp);
216
        }
217
        skillDialog->update();
218
        if (updateSkill != 0)
219
            skillDialog->playUpdateEffect(updateSkill);
220
    }
221
}
222
223
void SkillRecv::processSkillDelete(Net::MessageIn &msg)
224
{
225
    int updateSkill = 0;
226
    const int skillId = msg.readInt16("skill id");
227
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
228
    if (oldLevel != 0)
229
        updateSkill = skillId;
230
    PlayerInfo::setSkillLevel(skillId, 0);
231
    if (skillDialog != nullptr)
232
    {
233
        skillDialog->removeSkill(skillId);
234
        skillDialog->update();
235
        if (updateSkill != 0)
236
            skillDialog->playRemoveEffect(updateSkill);
237
    }
238
}
239
240
void SkillRecv::processSkillCoolDown(Net::MessageIn &msg)
241
{
242
    const int skillId = msg.readInt16("skill id");
243
    const int duration = msg.readInt32("duration");
244
    if (skillDialog != nullptr)
245
        skillDialog->setSkillDuration(SkillOwner::Player, skillId, duration);
246
}
247
248
void SkillRecv::processSkillCoolDownList(Net::MessageIn &msg)
249
{
250
    int packetLen;
251
    if (msg.getVersion() >= 20120604)
252
        packetLen = 10;
253
    else
254
        packetLen = 6;
255
    const int count = (msg.readInt16("len") - 4) / packetLen;
256
    for (int f = 0; f < count; f ++)
257
    {
258
        const int skillId = msg.readInt16("skill id");
259
        if (msg.getVersion() >= 20120604)
260
            msg.readInt32("total");
261
        const int duration = msg.readInt32("duration");
262
        if (skillDialog != nullptr)
263
        {
264
            skillDialog->setSkillDuration(SkillOwner::Player,
265
                skillId, duration);
266
        }
267
    }
268
}
269
270
void SkillRecv::processSkillFailed(Net::MessageIn &msg)
271
{
272
    // Action failed (ex. sit because you have not reached the
273
    // right level)
274
    const int skillId = msg.readInt16("skill id");
275
    const int bskill  = msg.readInt32("btype");
276
    const signed char success = msg.readUInt8("success");
277
    const signed char reason  = msg.readUInt8("reason");
278
    if (success != CAST_S32(SKILL_FAILED)
279
        && bskill == CAST_S32(BSKILL_EMOTE))
280
    {
281
        logger->log("Action: %d/%d", bskill, success);
282
    }
283
284
    if (localPlayer != nullptr)
285
        localPlayer->stopCast(true);
286
    std::string txt;
287
    if (success == CAST_S32(SKILL_FAILED) && bskill != 0)
288
    {
289
        if ((localPlayer != nullptr) && bskill == CAST_S32(BSKILL_EMOTE)
290
            && reason == CAST_S32(RFAIL_SKILLDEP))
291
        {
292
            localPlayer->stopAdvert();
293
        }
294
295
        const SkillInfo *const info = skillDialog->getSkill(bskill);
296
        if (info != nullptr)
297
        {
298
            txt = info->errorText;
299
        }
300
        else
301
        {
302
            // TRANSLATORS: skill error message
303
            txt = strprintf(_("Unknown skill error: %d"), bskill);
304
        }
305
    }
306
    else
307
    {
308
        const SkillInfo *const info = skillDialog->getSkill(skillId);
309
        if (info != nullptr)
310
        {
311
            txt = info->errorText + ".";
312
        }
313
        else
314
        {
315
            // TRANSLATORS: skill error message
316
            txt = strprintf(_("Unknown skill error: %d."), skillId);
317
        }
318
    }
319
320
    txt.append(" ");
321
    switch (reason)
322
    {
323
        case RFAIL_SKILLDEP:
324
            // TRANSLATORS: error message
325
            txt.append(_("You have not yet reached a high enough lvl!"));
326
            break;
327
        case RFAIL_INSUFHP:
328
            // TRANSLATORS: error message
329
            txt.append(_("Insufficient HP!"));
330
            break;
331
        case RFAIL_INSUFSP:
332
            // TRANSLATORS: error message
333
            txt.append(_("Insufficient SP!"));
334
            break;
335
        case RFAIL_NOMEMO:
336
            // TRANSLATORS: error message
337
            txt.append(_("You have no memos!"));
338
            break;
339
        case RFAIL_SKILLDELAY:
340
            // TRANSLATORS: error message
341
            txt.append(_("You cannot do that right now!"));
342
            break;
343
        case RFAIL_ZENY:
344
            // TRANSLATORS: error message
345
            txt.append(_("Seems you need more money... ;-)"));
346
            break;
347
        case RFAIL_WEAPON:
348
            // TRANSLATORS: error message
349
            txt.append(_("You cannot use this skill with that "
350
                "kind of weapon!"));
351
            break;
352
        case RFAIL_REDGEM:
353
            // TRANSLATORS: error message
354
            txt.append(_("You need another red gem!"));
355
            break;
356
        case RFAIL_BLUEGEM:
357
            // TRANSLATORS: error message
358
            txt.append(_("You need another blue gem!"));
359
            break;
360
        case RFAIL_OVERWEIGHT:
361
            // TRANSLATORS: error message
362
            txt.append(_("You're carrying to much to do this!"));
363
            break;
364
        case RFAIL_SUMMON:
365
            // TRANSLATORS: error message
366
            txt.append(_("Fail summon."));
367
            break;
368
        case RFAIL_SPIRITS:
369
            // TRANSLATORS: error message
370
            txt.append(_("Need spirits."));
371
            break;
372
        case RFAIL_NEED_EQUIPMENT:
373
        {
374
            const int itemId = bskill >> 16U;
375
            const int amount = bskill & 0xFFFFU;
376
            const ItemInfo &info = ItemDB::get(itemId);
377
            if (amount == 1)
378
            {
379
                // TRANSLATORS: skill error message
380
                txt.append(strprintf(_("Need equipment %s."),
381
                    info.getLink().c_str()));
382
            }
383
            else
384
            {
385
                // TRANSLATORS: skill error message
386
                txt.append(strprintf(_("Need equipment %s and amount %d"),
387
                    info.getLink().c_str(),
388
                    amount));
389
            }
390
            break;
391
        }
392
        case RFAIL_NEED_ITEM:
393
        {
394
            const int itemId = bskill >> 16U;
395
            const int amount = bskill & 0xFFFFU;
396
            const ItemInfo &info = ItemDB::get(itemId);
397
            if (amount == 1)
398
            {
399
                // TRANSLATORS: skill error message
400
                txt.append(strprintf(_("Need item %s."),
401
                    info.getLink().c_str()));
402
            }
403
            else
404
            {
405
                // TRANSLATORS: skill error message
406
                txt.append(strprintf(_("Need item %s and amount %d"),
407
                    info.getLink().c_str(),
408
                    amount));
409
            }
410
            break;
411
        }
412
        case RFAIL:
413
        {
414
            // TRANSLATORS: error message
415
            txt.append(_("Skill failed!"));
416
            break;
417
        }
418
419
        default:
420
            UNIMPLEMENTEDPACKETFIELD(reason);
421
            break;
422
    }
423
424
    NotifyManager::notify(NotifyTypes::SKILL_FAIL_MESSAGE, txt);
425
}
426
427
void SkillRecv::processSkillWarpPoint(Net::MessageIn &msg)
428
{
429
    const int skillId = msg.readInt16("skill id");
430
431
    TextSelectDialog *const dialog = CREATEWIDGETR(TextSelectDialog,
432
        // TRANSLATORS: warp select window name
433
        _("Select warp target"),
434
        // TRANSLATORS: warp select button
435
        _("Warp"),
436
        AllowQuit_false);
437
    skillWarpListener.setDialog(dialog);
438
    skillWarpListener.setSkill(skillId);
439
    dialog->addActionListener(&skillWarpListener);
440
    for (int f = 0; f < 4; f ++)
441
        dialog->addText(msg.readString(16, "map name"));
442
}
443
444
void SkillRecv::processSkillMemoMessage(Net::MessageIn &msg)
445
{
446
    const int type = msg.readUInt8("type");
447
    switch (type)
448
    {
449
        case 0:
450
            NotifyManager::notify(NotifyTypes::SKILL_MEMO_SAVED);
451
            break;
452
        case 1:
453
            NotifyManager::notify(NotifyTypes::SKILL_MEMO_ERROR_LEVEL);
454
            break;
455
        case 2:
456
            NotifyManager::notify(NotifyTypes::SKILL_MEMO_ERROR_SKILL);
457
            break;
458
        default:
459
            UNIMPLEMENTEDPACKETFIELD(type);
460
            break;
461
    }
462
}
463
464
void SkillRecv::processSkillProduceMixList(Net::MessageIn &msg)
465
{
466
    UNIMPLEMENTEDPACKET;
467
468
    const int count = (msg.readInt16("len") - 8) / 8;
469
    for (int f = 0; f < count; f ++)
470
    {
471
        msg.readInt16("item id");
472
        for (int d = 0; d < 3; d ++)
473
            msg.readInt16("material id");
474
    }
475
}
476
477
void SkillRecv::processSkillProduceEffect(Net::MessageIn &msg)
478
{
479
    UNIMPLEMENTEDPACKET;
480
481
    msg.readInt16("flag");
482
    msg.readInt16("item id");
483
}
484
485
void SkillRecv::processSkillUnitUpdate(Net::MessageIn &msg)
486
{
487
    UNIMPLEMENTEDPACKET;
488
489
    msg.readBeingId("being id");
490
}
491
492
void SkillRecv::processSkillArrowCreateList(Net::MessageIn &msg)
493
{
494
    UNIMPLEMENTEDPACKET;
495
496
    const int count = (msg.readInt16("len") - 4) / 2;
497
    for (int f = 0; f < count; f ++)
498
        msg.readInt16("item id");
499
}
500
501
void SkillRecv::processSkillAutoSpells(Net::MessageIn &msg)
502
{
503
    UNIMPLEMENTEDPACKET;
504
505
    for (int f = 0; f < 7; f ++)
506
        msg.readInt32("skill id");
507
508
    menu = MenuType::AutoSpell;
509
}
510
511
void SkillRecv::processSkillDevotionEffect(Net::MessageIn &msg)
512
{
513
    UNIMPLEMENTEDPACKET;
514
515
    msg.readBeingId("being id");
516
    for (int f = 0; f < 5; f ++)
517
        msg.readInt32("devotee id");
518
    msg.readInt16("range");
519
}
520
521
void SkillRecv::processSkillItemListWindow(Net::MessageIn &msg)
522
{
523
    UNIMPLEMENTEDPACKET;
524
525
    msg.readInt32("skill level");
526
    msg.readInt32("unused");
527
}
528
529
4
}  // namespace EAthena