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