GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/eathena/skillrecv.cpp Lines: 1 268 0.4 %
Date: 2018-11-12 Branches: 0 254 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-2018  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
extern int itemIdLen;
64
65
namespace EAthena
66
{
67
68
void SkillRecv::processPlayerSkills(Net::MessageIn &msg)
69
{
70
    msg.readInt16("len");
71
    const int sz = (serverVersion > 0) ? 41 : 37;
72
    const int skillCount = (msg.getLength() - 4) / sz;
73
    int updateSkill = 0;
74
75
    if (skillDialog != nullptr)
76
        skillDialog->hideSkills(SkillOwner::Player);
77
    for (int k = 0; k < skillCount; k++)
78
    {
79
        const int skillId = msg.readInt16("skill id");
80
        const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
81
            msg.readInt32("inf"));
82
        if (serverVersion > 0)
83
            msg.readInt32("inf2");
84
        const int level = msg.readInt16("skill level");
85
        const int sp = msg.readInt16("sp");
86
        const int range = msg.readInt16("range");
87
        const std::string name = msg.readString(24, "skill name");
88
        const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
89
        const int oldLevel = PlayerInfo::getSkillLevel(skillId);
90
        if ((oldLevel != 0) && oldLevel != level)
91
            updateSkill = skillId;
92
        PlayerInfo::setSkillLevel(skillId, level);
93
        if (skillDialog != nullptr)
94
        {
95
            if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
96
            {
97
                skillDialog->addSkill(SkillOwner::Player,
98
                    skillId, name, level, range, up, inf, sp);
99
            }
100
        }
101
    }
102
    if (skillDialog != nullptr)
103
    {
104
        skillDialog->update();
105
        skillDialog->updateModelsHidden();
106
        if (updateSkill != 0)
107
            skillDialog->playUpdateEffect(updateSkill);
108
    }
109
}
110
111
void SkillRecv::processSkillAdd(Net::MessageIn &msg)
112
{
113
    int updateSkill = 0;
114
    const int skillId = msg.readInt16("skill id");
115
    const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
116
        msg.readInt32("inf"));
117
    const int level = msg.readInt16("skill level");
118
    const int sp = msg.readInt16("sp");
119
    const int range = msg.readInt16("range");
120
    const std::string name = msg.readString(24, "skill name");
121
    const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
122
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
123
    if ((oldLevel != 0) && oldLevel != level)
124
        updateSkill = skillId;
125
    PlayerInfo::setSkillLevel(skillId, level);
126
    if (skillDialog != nullptr)
127
    {
128
        if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
129
        {
130
            skillDialog->addSkill(SkillOwner::Player,
131
                skillId, name, level, range, up, inf, sp);
132
        }
133
        skillDialog->update();
134
        if (updateSkill != 0)
135
            skillDialog->playUpdateEffect(updateSkill);
136
    }
137
}
138
139
void SkillRecv::processSkillAdd2(Net::MessageIn &msg)
140
{
141
    int updateSkill = 0;
142
    msg.readInt16("len");  // for now unused
143
    const int skillId = msg.readInt16("skill id");
144
    const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
145
        msg.readInt32("inf"));
146
    msg.readInt32("inf2");
147
    const int level = msg.readInt16("skill level");
148
    const int sp = msg.readInt16("sp");
149
    const int range = msg.readInt16("range");
150
    const std::string name = msg.readString(24, "skill name");
151
    const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
152
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
153
    if ((oldLevel != 0) && oldLevel != level)
154
        updateSkill = skillId;
155
    PlayerInfo::setSkillLevel(skillId, level);
156
    if (skillDialog != nullptr)
157
    {
158
        if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
159
        {
160
            skillDialog->addSkill(SkillOwner::Player,
161
                skillId, name, level, range, up, inf, sp);
162
        }
163
        skillDialog->update();
164
        if (updateSkill != 0)
165
            skillDialog->playUpdateEffect(updateSkill);
166
    }
167
}
168
169
void SkillRecv::processSkillUpdate(Net::MessageIn &msg)
170
{
171
    int updateSkill = 0;
172
    const int skillId = msg.readInt16("skill id");
173
    const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
174
        msg.readInt32("inf"));
175
    const int level = msg.readInt16("skill level");
176
    const int sp = msg.readInt16("sp");
177
    const int range = msg.readInt16("range");
178
    const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
179
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
180
    if ((oldLevel != 0) && oldLevel != level)
181
        updateSkill = skillId;
182
    PlayerInfo::setSkillLevel(skillId, level);
183
    if (skillDialog != nullptr)
184
    {
185
        if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
186
        {
187
            skillDialog->addSkill(SkillOwner::Player,
188
                skillId, "", level, range, up, inf, sp);
189
        }
190
        skillDialog->update();
191
        if (updateSkill != 0)
192
            skillDialog->playUpdateEffect(updateSkill);
193
    }
194
}
195
196
void SkillRecv::processSkillUpdate2(Net::MessageIn &msg)
197
{
198
    int updateSkill = 0;
199
    msg.readInt16("len");  // for now unused
200
    const int skillId = msg.readInt16("skill id");
201
    const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
202
        msg.readInt32("inf"));
203
    msg.readInt32("inf2");
204
    const int level = msg.readInt16("skill level");
205
    const int sp = msg.readInt16("sp");
206
    const int range = msg.readInt16("range");
207
    const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
208
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
209
    if ((oldLevel != 0) && oldLevel != level)
210
        updateSkill = skillId;
211
    PlayerInfo::setSkillLevel(skillId, level);
212
    if (skillDialog != nullptr)
213
    {
214
        if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
215
        {
216
            skillDialog->addSkill(SkillOwner::Player,
217
                skillId, "", level, range, up, inf, sp);
218
        }
219
        skillDialog->update();
220
        if (updateSkill != 0)
221
            skillDialog->playUpdateEffect(updateSkill);
222
    }
223
}
224
225
void SkillRecv::processSkillDelete(Net::MessageIn &msg)
226
{
227
    int updateSkill = 0;
228
    const int skillId = msg.readInt16("skill id");
229
    const int oldLevel = PlayerInfo::getSkillLevel(skillId);
230
    if (oldLevel != 0)
231
        updateSkill = skillId;
232
    PlayerInfo::setSkillLevel(skillId, 0);
233
    if (skillDialog != nullptr)
234
    {
235
        skillDialog->removeSkill(skillId);
236
        skillDialog->update();
237
        if (updateSkill != 0)
238
            skillDialog->playRemoveEffect(updateSkill);
239
    }
240
}
241
242
void SkillRecv::processSkillCoolDown(Net::MessageIn &msg)
243
{
244
    const int skillId = msg.readInt16("skill id");
245
    const int duration = msg.readInt32("duration");
246
    if (skillDialog != nullptr)
247
        skillDialog->setSkillDuration(SkillOwner::Player, skillId, duration);
248
}
249
250
void SkillRecv::processSkillCoolDownList(Net::MessageIn &msg)
251
{
252
    int packetLen;
253
    if (msg.getVersion() >= 20120604)
254
        packetLen = 10;
255
    else
256
        packetLen = 6;
257
    const int count = (msg.readInt16("len") - 4) / packetLen;
258
    for (int f = 0; f < count; f ++)
259
    {
260
        const int skillId = msg.readInt16("skill id");
261
        if (msg.getVersion() >= 20120604)
262
            msg.readInt32("total");
263
        const int duration = msg.readInt32("duration");
264
        if (skillDialog != nullptr)
265
        {
266
            skillDialog->setSkillDuration(SkillOwner::Player,
267
                skillId, duration);
268
        }
269
    }
270
}
271
272
void SkillRecv::processSkillFailed(Net::MessageIn &msg)
273
{
274
    // Action failed (ex. sit because you have not reached the
275
    // right level)
276
    const int skillId = msg.readInt16("skill id");
277
    const int bskill  = msg.readItemId("btype");
278
    const int itemId  = msg.readItemId("item id");
279
    const signed char success = msg.readUInt8("success");
280
    const signed char reason  = msg.readUInt8("reason");
281
    if (success != CAST_S32(SKILL_FAILED)
282
        && bskill == CAST_S32(BSKILL_EMOTE))
283
    {
284
        logger->log("Action: %d/%d", bskill, success);
285
    }
286
287
    if (localPlayer != nullptr)
288
        localPlayer->stopCast(true);
289
    std::string txt;
290
    if (success == CAST_S32(SKILL_FAILED) && bskill != 0)
291
    {
292
        if ((localPlayer != nullptr) && bskill == CAST_S32(BSKILL_EMOTE)
293
            && reason == CAST_S32(RFAIL_SKILLDEP))
294
        {
295
            localPlayer->stopAdvert();
296
        }
297
298
        const SkillInfo *const info = skillDialog->getSkill(bskill);
299
        if (info != nullptr)
300
        {
301
            txt = info->errorText;
302
        }
303
        else
304
        {
305
            // TRANSLATORS: skill error message
306
            txt = strprintf(_("Unknown skill error: %d"), bskill);
307
        }
308
    }
309
    else
310
    {
311
        const SkillInfo *const info = skillDialog->getSkill(skillId);
312
        if (info != nullptr)
313
        {
314
            txt = info->errorText + ".";
315
        }
316
        else
317
        {
318
            // TRANSLATORS: skill error message
319
            txt = strprintf(_("Unknown skill error: %d."), skillId);
320
        }
321
    }
322
323
    txt.append(" ");
324
    switch (reason)
325
    {
326
        case RFAIL_SKILLDEP:
327
            // TRANSLATORS: error message
328
            txt.append(_("You have not yet reached a high enough lvl!"));
329
            break;
330
        case RFAIL_INSUFHP:
331
            // TRANSLATORS: error message
332
            txt.append(_("Insufficient HP!"));
333
            break;
334
        case RFAIL_INSUFSP:
335
            // TRANSLATORS: error message
336
            txt.append(_("Insufficient SP!"));
337
            break;
338
        case RFAIL_NOMEMO:
339
            // TRANSLATORS: error message
340
            txt.append(_("You have no memos!"));
341
            break;
342
        case RFAIL_SKILLDELAY:
343
            // TRANSLATORS: error message
344
            txt.append(_("You cannot do that right now!"));
345
            break;
346
        case RFAIL_ZENY:
347
            // TRANSLATORS: error message
348
            txt.append(_("Seems you need more money... ;-)"));
349
            break;
350
        case RFAIL_WEAPON:
351
            // TRANSLATORS: error message
352
            txt.append(_("You cannot use this skill with that "
353
                "kind of weapon!"));
354
            break;
355
        case RFAIL_REDGEM:
356
            // TRANSLATORS: error message
357
            txt.append(_("You need another red gem!"));
358
            break;
359
        case RFAIL_BLUEGEM:
360
            // TRANSLATORS: error message
361
            txt.append(_("You need another blue gem!"));
362
            break;
363
        case RFAIL_OVERWEIGHT:
364
            // TRANSLATORS: error message
365
            txt.append(_("You're carrying to much to do this!"));
366
            break;
367
        case RFAIL_SUMMON:
368
            // TRANSLATORS: error message
369
            txt.append(_("Fail summon."));
370
            break;
371
        case RFAIL_SPIRITS:
372
            // TRANSLATORS: error message
373
            txt.append(_("Need spirits."));
374
            break;
375
        case RFAIL_NEED_EQUIPMENT:
376
        {
377
            const int amount = bskill;
378
            const ItemInfo &info = ItemDB::get(itemId);
379
            if (amount == 1)
380
            {
381
                // TRANSLATORS: skill error message
382
                txt.append(strprintf(_("Need equipment %s."),
383
                    info.getLink().c_str()));
384
            }
385
            else
386
            {
387
                // TRANSLATORS: skill error message
388
                txt.append(strprintf(_("Need equipment %s and amount %d"),
389
                    info.getLink().c_str(),
390
                    amount));
391
            }
392
            break;
393
        }
394
        case RFAIL_NEED_ITEM:
395
        {
396
            const int amount = bskill;
397
            const ItemInfo &info = ItemDB::get(itemId);
398
            if (amount == 1)
399
            {
400
                // TRANSLATORS: skill error message
401
                txt.append(strprintf(_("Need item %s."),
402
                    info.getLink().c_str()));
403
            }
404
            else
405
            {
406
                // TRANSLATORS: skill error message
407
                txt.append(strprintf(_("Need item %s and amount %d"),
408
                    info.getLink().c_str(),
409
                    amount));
410
            }
411
            break;
412
        }
413
        case RFAIL:
414
        {
415
            // TRANSLATORS: error message
416
            txt.append(_("Skill failed!"));
417
            break;
418
        }
419
420
        default:
421
            UNIMPLEMENTEDPACKETFIELD(reason);
422
            break;
423
    }
424
425
    NotifyManager::notify(NotifyTypes::SKILL_FAIL_MESSAGE, txt);
426
}
427
428
void SkillRecv::processSkillWarpPoint(Net::MessageIn &msg)
429
{
430
    const int skillId = msg.readInt16("skill id");
431
432
    TextSelectDialog *const dialog = CREATEWIDGETR(TextSelectDialog,
433
        // TRANSLATORS: warp select window name
434
        _("Select warp target"),
435
        // TRANSLATORS: warp select button
436
        _("Warp"),
437
        AllowQuit_false);
438
    skillWarpListener.setDialog(dialog);
439
    skillWarpListener.setSkill(skillId);
440
    dialog->addActionListener(&skillWarpListener);
441
    for (int f = 0; f < 4; f ++)
442
        dialog->addText(msg.readString(16, "map name"));
443
}
444
445
void SkillRecv::processSkillWarpPoint2(Net::MessageIn &msg)
446
{
447
    const int count = (msg.readInt16("len") - 6) / 16;
448
    const int skillId = msg.readInt16("skill id");
449
450
    TextSelectDialog *const dialog = CREATEWIDGETR(TextSelectDialog,
451
        // TRANSLATORS: warp select window name
452
        _("Select warp target"),
453
        // TRANSLATORS: warp select button
454
        _("Warp"),
455
        AllowQuit_false);
456
    skillWarpListener.setDialog(dialog);
457
    skillWarpListener.setSkill(skillId);
458
    dialog->addActionListener(&skillWarpListener);
459
    for (int f = 0; f < count; f ++)
460
        dialog->addText(msg.readString(16, "map name"));
461
}
462
463
void SkillRecv::processSkillMemoMessage(Net::MessageIn &msg)
464
{
465
    const int type = msg.readUInt8("type");
466
    switch (type)
467
    {
468
        case 0:
469
            NotifyManager::notify(NotifyTypes::SKILL_MEMO_SAVED);
470
            break;
471
        case 1:
472
            NotifyManager::notify(NotifyTypes::SKILL_MEMO_ERROR_LEVEL);
473
            break;
474
        case 2:
475
            NotifyManager::notify(NotifyTypes::SKILL_MEMO_ERROR_SKILL);
476
            break;
477
        default:
478
            UNIMPLEMENTEDPACKETFIELD(type);
479
            break;
480
    }
481
}
482
483
void SkillRecv::processSkillProduceMixList(Net::MessageIn &msg)
484
{
485
    UNIMPLEMENTEDPACKET;
486
487
    const int count = (msg.readInt16("len") - 4) / 4 * itemIdLen;
488
    for (int f = 0; f < count; f ++)
489
    {
490
        msg.readItemId("item id");
491
        for (int d = 0; d < 3; d ++)
492
            msg.readItemId("material id");
493
    }
494
}
495
496
void SkillRecv::processSkillProduceEffect(Net::MessageIn &msg)
497
{
498
    UNIMPLEMENTEDPACKET;
499
500
    msg.readInt16("flag");
501
    msg.readItemId("item id");
502
}
503
504
void SkillRecv::processSkillUnitUpdate(Net::MessageIn &msg)
505
{
506
    UNIMPLEMENTEDPACKET;
507
508
    msg.readBeingId("being id");
509
}
510
511
void SkillRecv::processSkillArrowCreateList(Net::MessageIn &msg)
512
{
513
    UNIMPLEMENTEDPACKET;
514
515
    const int count = (msg.readInt16("len") - 4) / itemIdLen;
516
    for (int f = 0; f < count; f ++)
517
        msg.readItemId("item id");
518
}
519
520
void SkillRecv::processSkillAutoSpells(Net::MessageIn &msg)
521
{
522
    UNIMPLEMENTEDPACKET;
523
524
    for (int f = 0; f < 7; f ++)
525
        msg.readInt32("skill id");
526
527
    menu = MenuType::AutoSpell;
528
}
529
530
void SkillRecv::processSkillDevotionEffect(Net::MessageIn &msg)
531
{
532
    UNIMPLEMENTEDPACKET;
533
534
    msg.readBeingId("being id");
535
    for (int f = 0; f < 5; f ++)
536
        msg.readInt32("devotee id");
537
    msg.readInt16("range");
538
}
539
540
void SkillRecv::processSkillItemListWindow(Net::MessageIn &msg)
541
{
542
    UNIMPLEMENTEDPACKET;
543
544
    msg.readInt32("skill level");
545
    msg.readInt32("unused");
546
}
547
548
void SkillRecv::processSkillScale(Net::MessageIn &msg)
549
{
550
    msg.readBeingId("being id");
551
    msg.readInt16("skill id");
552
    msg.readInt16("skill level");
553
    msg.readInt16("x");
554
    msg.readInt16("y");
555
    msg.readInt32("cast time");
556
}
557
558
2
}  // namespace EAthena