GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/eathena/playerrecv.cpp Lines: 1 289 0.3 %
Date: 2019-10-15 Branches: 0 132 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-2019  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/playerrecv.h"
24
25
#include "actormanager.h"
26
#include "configuration.h"
27
#include "notifymanager.h"
28
#include "party.h"
29
30
#include "being/beingflag.h"
31
#include "being/localplayer.h"
32
#include "being/playerinfo.h"
33
34
#include "const/net/nostat.h"
35
36
#include "enums/resources/notifytypes.h"
37
38
#include "gui/onlineplayer.h"
39
40
#include "gui/windows/statuswindow.h"
41
#include "gui/windows/whoisonline.h"
42
43
#include "gui/widgets/tabs/chat/chattab.h"
44
45
#include "net/eathena/sp.h"
46
#include "net/playerhandler.h"
47
48
#include "utils/gettext.h"
49
50
#include "debug.h"
51
52
namespace EAthena
53
{
54
55
void PlayerRecv::processPlayerShortcuts1(Net::MessageIn &msg)
56
{
57
    // +++ player shortcuts ignored. It also disabled on server side.
58
    // may be in future better use it?
59
    for (int f = 0; f < 38; f ++)
60
    {
61
        msg.readUInt8("type 0: item, 1: skill");
62
        msg.readInt32("item or skill id");
63
        msg.readInt16("skill level");
64
    }
65
}
66
67
void PlayerRecv::processPlayerShortcuts2(Net::MessageIn &msg)
68
{
69
    // +++ player shortcuts ignored. It also disabled on server side.
70
    // may be in future better use it?
71
    msg.readUInt8("rotate");
72
    for (int f = 0; f < 38; f ++)
73
    {
74
        msg.readUInt8("type 0: item, 1: skill");
75
        msg.readInt32("item or skill id");
76
        msg.readInt16("skill level");
77
    }
78
}
79
80
void PlayerRecv::processPlayerShortcuts3(Net::MessageIn &msg)
81
{
82
    // +++ player shortcuts ignored. It also disabled on server side.
83
    // may be in future better use it?
84
    msg.readUInt8("rotate");
85
    msg.readInt16("tab");
86
    for (int f = 0; f < 38; f ++)
87
    {
88
        msg.readUInt8("type 0: item, 1: skill");
89
        msg.readInt32("item or skill id");
90
        msg.readInt16("skill level");
91
    }
92
}
93
94
void PlayerRecv::processPlayerShowEquip(Net::MessageIn &msg)
95
{
96
    // +++ for now server allow only switch this option but not using it.
97
    msg.readUInt8("show equip");  // 1 mean need open "equipment" window
98
}
99
100
void PlayerRecv::processPlayerStatUpdate5(Net::MessageIn &msg)
101
{
102
    BLOCK_START("PlayerRecv::processPlayerStatUpdate5")
103
    PlayerInfo::setAttribute(Attributes::PLAYER_CHAR_POINTS,
104
        msg.readInt16("char points"),
105
        Notify_true);
106
107
    unsigned int val = msg.readUInt8("str");
108
    PlayerInfo::setStatBase(Attributes::PLAYER_STR,
109
        val,
110
        Notify_true);
111
    if (statusWindow != nullptr)
112
    {
113
        statusWindow->setPointsNeeded(Attributes::PLAYER_STR,
114
            msg.readUInt8("str cost"));
115
    }
116
    else
117
    {
118
        msg.readUInt8("str need");
119
    }
120
121
    val = msg.readUInt8("agi");
122
    PlayerInfo::setStatBase(Attributes::PLAYER_AGI, val, Notify_true);
123
    if (statusWindow != nullptr)
124
    {
125
        statusWindow->setPointsNeeded(Attributes::PLAYER_AGI,
126
            msg.readUInt8("agi cost"));
127
    }
128
    else
129
    {
130
        msg.readUInt8("agi cost");
131
    }
132
133
    val = msg.readUInt8("vit");
134
    PlayerInfo::setStatBase(Attributes::PLAYER_VIT, val, Notify_true);
135
    if (statusWindow != nullptr)
136
    {
137
        statusWindow->setPointsNeeded(Attributes::PLAYER_VIT,
138
            msg.readUInt8("vit cost"));
139
    }
140
    else
141
    {
142
        msg.readUInt8("vit cost");
143
    }
144
145
    val = msg.readUInt8("int");
146
    PlayerInfo::setStatBase(Attributes::PLAYER_INT, val, Notify_true);
147
    if (statusWindow != nullptr)
148
    {
149
        statusWindow->setPointsNeeded(Attributes::PLAYER_INT,
150
            msg.readUInt8("int cost"));
151
    }
152
    else
153
    {
154
        msg.readUInt8("int cost");
155
    }
156
157
    val = msg.readUInt8("dex");
158
    PlayerInfo::setStatBase(Attributes::PLAYER_DEX, val, Notify_true);
159
    if (statusWindow != nullptr)
160
    {
161
        statusWindow->setPointsNeeded(Attributes::PLAYER_DEX,
162
            msg.readUInt8("dex cost"));
163
    }
164
    else
165
    {
166
        msg.readUInt8("dex cost");
167
    }
168
169
    val = msg.readUInt8("luk");
170
    PlayerInfo::setStatBase(Attributes::PLAYER_LUK, val, Notify_true);
171
    if (statusWindow != nullptr)
172
    {
173
        statusWindow->setPointsNeeded(Attributes::PLAYER_LUK,
174
            msg.readUInt8("luk cost"));
175
    }
176
    else
177
    {
178
        msg.readUInt8("luk cost");
179
    }
180
181
    PlayerInfo::setStatBase(Attributes::PLAYER_ATK,
182
        msg.readInt16("left atk"),
183
        Notify_false);
184
    PlayerInfo::setStatMod(Attributes::PLAYER_ATK,
185
        msg.readInt16("right atk"),
186
        Notify_true);
187
    PlayerInfo::updateAttrs();
188
189
    val = msg.readInt16("right matk");
190
    PlayerInfo::setStatBase(Attributes::PLAYER_MATK, val, Notify_false);
191
192
    val = msg.readInt16("left matk");
193
    PlayerInfo::setStatMod(Attributes::PLAYER_MATK,
194
        val,
195
        Notify_true);
196
197
    PlayerInfo::setStatBase(Attributes::PLAYER_DEF,
198
        msg.readInt16("left def"),
199
        Notify_false);
200
    PlayerInfo::setStatMod(Attributes::PLAYER_DEF,
201
        msg.readInt16("right def"),
202
        Notify_true);
203
204
    PlayerInfo::setStatBase(Attributes::PLAYER_MDEF,
205
        msg.readInt16("left mdef"),
206
        Notify_false);
207
    PlayerInfo::setStatMod(Attributes::PLAYER_MDEF,
208
        msg.readInt16("right mdef"),
209
        Notify_true);
210
211
    PlayerInfo::setStatBase(Attributes::PLAYER_HIT,
212
        msg.readInt16("hit"),
213
        Notify_true);
214
215
    PlayerInfo::setStatBase(Attributes::PLAYER_FLEE,
216
        msg.readInt16("flee"),
217
        Notify_false);
218
    PlayerInfo::setStatMod(Attributes::PLAYER_FLEE,
219
        msg.readInt16("flee2/10"),
220
        Notify_true);
221
222
    PlayerInfo::setStatBase(Attributes::PLAYER_CRIT,
223
        msg.readInt16("crit/10"),
224
        Notify_true);
225
226
    PlayerInfo::setAttribute(Attributes::PLAYER_ATTACK_DELAY,
227
        msg.readInt16("attack speed"),
228
        Notify_true);
229
    msg.readInt16("plus speed = 0");
230
231
    BLOCK_END("PlayerRecv::processPlayerStatUpdate5")
232
}
233
234
void PlayerRecv::processPlayerGetExp(Net::MessageIn &msg)
235
{
236
    if (localPlayer == nullptr)
237
        return;
238
    const BeingId id = msg.readBeingId("player id");
239
    const int exp = msg.readInt32("exp amount");
240
    const int stat = msg.readInt16("exp type");
241
    const bool fromQuest = msg.readInt16("is from quest") != 0;
242
    if (!fromQuest && id == localPlayer->getId())
243
    {
244
        if (stat == 1)
245
            localPlayer->addXpMessage(exp);
246
        else if (stat == 2)
247
            localPlayer->addJobMessage(exp);
248
        else
249
            UNIMPLEMENTEDPACKETFIELD(stat);
250
    }
251
    // need show particle depend on isQuest flag, for now ignored
252
}
253
254
void PlayerRecv::processPlayerGetExp2(Net::MessageIn &msg)
255
{
256
    if (localPlayer == nullptr)
257
        return;
258
    const BeingId id = msg.readBeingId("player id");
259
    const int64_t exp = msg.readInt64("exp amount");
260
    const int stat = msg.readInt16("exp type");
261
    const bool fromQuest = msg.readInt16("is from quest") != 0;
262
    if (!fromQuest && id == localPlayer->getId())
263
    {
264
        if (stat == 1)
265
            localPlayer->addXpMessage(exp);
266
        else if (stat == 2)
267
            localPlayer->addJobMessage(exp);
268
        else
269
            UNIMPLEMENTEDPACKETFIELD(stat);
270
    }
271
    // need show particle depend on isQuest flag, for now ignored
272
}
273
274
void PlayerRecv::processWalkResponse(Net::MessageIn &msg)
275
{
276
    BLOCK_START("PlayerRecv::processWalkResponse")
277
    /*
278
      * This client assumes that all walk messages succeed,
279
      * and that the server will send a correction notice
280
      * otherwise.
281
      */
282
    uint16_t srcX;
283
    uint16_t srcY;
284
    uint16_t dstX;
285
    uint16_t dstY;
286
    msg.readInt32("tick");
287
    msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
288
    msg.readUInt8("(sx<<4) | (sy&0x0f)");
289
    if (localPlayer != nullptr)
290
        localPlayer->setRealPos(dstX, dstY);
291
    BLOCK_END("PlayerRecv::processWalkResponse")
292
}
293
294
void PlayerRecv::processWalkError(Net::MessageIn &msg)
295
{
296
    msg.readInt32("tick");
297
    const int x = msg.readInt16("x");
298
    const int y = msg.readInt16("y");
299
    if (localPlayer != nullptr)
300
        localPlayer->failMove(x, y);
301
}
302
303
void PlayerRecv::processPvpInfo(Net::MessageIn &msg)
304
{
305
    UNIMPLEMENTEDPACKET;
306
    msg.readInt32("char id");
307
    msg.readBeingId("account id");
308
    msg.readInt32("pvp won");
309
    msg.readInt32("pvp lost");
310
    msg.readInt32("pvp point");
311
}
312
313
void PlayerRecv::processPlayerHeal(Net::MessageIn &msg)
314
{
315
    if (localPlayer == nullptr)
316
        return;
317
318
    const int type = msg.readInt16("var id");
319
    int amount;
320
    if (msg.getVersion() >= 20150513)
321
        amount = msg.readInt32("value");
322
    else
323
        amount = msg.readInt16("value");
324
    if (type == Sp::HP)
325
    {
326
        const int base = PlayerInfo::getAttribute(Attributes::PLAYER_HP) +
327
            amount;
328
        PlayerInfo::setAttribute(Attributes::PLAYER_HP,
329
            base,
330
            Notify_true);
331
        if (localPlayer->isInParty() && (Party::getParty(1) != nullptr))
332
        {
333
            PartyMember *const m = Party::getParty(1)
334
                ->getMember(localPlayer->getId());
335
            if (m != nullptr)
336
            {
337
                m->setHp(base);
338
                m->setMaxHp(PlayerInfo::getAttribute(
339
                    Attributes::PLAYER_MAX_HP));
340
            }
341
        }
342
        localPlayer->addHpMessage(amount);
343
    }
344
    else if (type == Sp::SP)
345
    {
346
        localPlayer->addSpMessage(amount);
347
    }
348
}
349
350
void PlayerRecv::processPlayerSkillMessage(Net::MessageIn &msg)
351
{
352
    const int message = msg.readInt32("type");
353
    switch (message)
354
    {
355
        case 0x15:
356
            NotifyManager::notify(NotifyTypes::SKILL_END_ALL_NEGATIVE_STATUS);
357
            break;
358
        case 0x16:
359
            NotifyManager::notify(NotifyTypes::SKILL_IMMUNITY_TO_ALL_STATUSES);
360
            break;
361
        case 0x17:
362
            NotifyManager::notify(NotifyTypes::SKILL_MAX_HP);
363
            break;
364
        case 0x18:
365
            NotifyManager::notify(NotifyTypes::SKILL_MAX_SP);
366
            break;
367
        case 0x19:
368
            NotifyManager::notify(NotifyTypes::SKILL_ALL_STATUS_PLUS_20);
369
            break;
370
        case 0x1c:
371
            NotifyManager::notify(NotifyTypes::SKILL_ENCHANT_WEAPON_HOLY);
372
            break;
373
        case 0x1d:
374
            NotifyManager::notify(NotifyTypes::SKILL_ENCHANT_ARMOR_HOLY);
375
            break;
376
        case 0x1e:
377
            NotifyManager::notify(NotifyTypes::SKILL_DEF_PLUS_25);
378
            break;
379
        case 0x1f:
380
            NotifyManager::notify(NotifyTypes::SKILL_ATTACK_PLUS_100);
381
            break;
382
        case 0x20:
383
            NotifyManager::notify(NotifyTypes::SKILL_FLEE_PLUS_50);
384
            break;
385
        case 0x28:
386
            NotifyManager::notify(NotifyTypes::SKILL_FULL_STRIP_FAILED);
387
            break;
388
        default:
389
            NotifyManager::notify(NotifyTypes::SKILL_MESSAGE_UNKNOWN);
390
            break;
391
    }
392
}
393
394
void PlayerRecv::processNotifyMapInfo(Net::MessageIn &msg)
395
{
396
    UNIMPLEMENTEDPACKET;
397
    msg.readInt16("type");
398
}
399
400
void PlayerRecv::processPlayerFameBlacksmith(Net::MessageIn &msg)
401
{
402
    UNIMPLEMENTEDPACKET;
403
    msg.readInt32("points");
404
    msg.readInt32("total points");
405
}
406
407
void PlayerRecv::processPlayerFameAlchemist(Net::MessageIn &msg)
408
{
409
    UNIMPLEMENTEDPACKET;
410
    msg.readInt32("points");
411
    msg.readInt32("total points");
412
}
413
414
void PlayerRecv::processPlayerUpgradeMessage(Net::MessageIn &msg)
415
{
416
    UNIMPLEMENTEDPACKET;
417
    msg.readInt32("result");
418
    msg.readItemId("item id");
419
}
420
421
void PlayerRecv::processPlayerFameTaekwon(Net::MessageIn &msg)
422
{
423
    UNIMPLEMENTEDPACKET;
424
    msg.readInt32("points");
425
    msg.readInt32("total points");
426
}
427
428
void PlayerRecv::processPlayerReadBook(Net::MessageIn &msg)
429
{
430
    UNIMPLEMENTEDPACKET;
431
    msg.readInt32("book id");
432
    msg.readInt32("page");
433
}
434
435
void PlayerRecv::processPlayerZCConfig(Net::MessageIn &msg)
436
{
437
    UNIMPLEMENTEDPACKET;
438
    msg.readInt32("type");
439
    msg.readInt32("flag");
440
}
441
442
void PlayerRecv::processPlayerAutoShadowSpellList(Net::MessageIn &msg)
443
{
444
    UNIMPLEMENTEDPACKET;
445
    const int count = (msg.readInt16("len") - 8) / 2;
446
    for (int f = 0; f < count; f ++)
447
        msg.readInt16("skill id");
448
}
449
450
void PlayerRecv::processPlayerRankPoints(Net::MessageIn &msg)
451
{
452
    UNIMPLEMENTEDPACKET;
453
    msg.readInt16("type");
454
    msg.readInt32("points");
455
    msg.readInt32("fame");
456
}
457
458
void PlayerRecv::processOnlineList(Net::MessageIn &msg)
459
{
460
    if (whoIsOnline == nullptr)
461
        return;
462
463
    BLOCK_START("PlayerRecv::processOnlineList")
464
    const int size = msg.readInt16("len") - 4;
465
    STD_VECTOR<OnlinePlayer*> arr;
466
467
    if (size == 0)
468
    {
469
        if (whoIsOnline != nullptr)
470
            whoIsOnline->loadList(arr);
471
        BLOCK_END("PlayerRecv::processOnlineList")
472
        return;
473
    }
474
475
    char *const start = reinterpret_cast<char*>(msg.readBytes(size, "nicks"));
476
    if (start == nullptr)
477
    {
478
        BLOCK_END("PlayerRecv::processOnlineList")
479
        return;
480
    }
481
482
    const char *buf = start;
483
484
    int addVal = 3;
485
486
    while (buf - start + 1 < size
487
           && (*(buf + CAST_SIZE(addVal)) != 0))
488
    {
489
        const unsigned char status = *buf;
490
        buf ++;
491
        const unsigned char level = *buf;
492
        buf ++;
493
        const unsigned char ver = *buf;
494
        buf ++;
495
496
        GenderT gender = Gender::UNSPECIFIED;
497
        if (config.getBoolValue("showgender"))
498
        {
499
            if ((status & BeingFlag::GENDER_MALE) != 0)
500
                gender = Gender::MALE;
501
            else if ((status & BeingFlag::GENDER_HIDDEN) != 0)
502
                gender = Gender::HIDDEN;
503
            else
504
                gender = Gender::FEMALE;
505
        }
506
        arr.push_back(new OnlinePlayer(static_cast<const char*>(buf),
507
            status, level, gender, ver, -1));
508
        buf += strlen(buf) + 1;
509
    }
510
511
    if (whoIsOnline != nullptr)
512
        whoIsOnline->loadList(arr);
513
    delete [] start;
514
    BLOCK_END("PlayerRecv::processOnlineList")
515
}
516
517
void PlayerRecv::processDressRoomOpen(Net::MessageIn &msg)
518
{
519
    UNIMPLEMENTEDPACKET;
520
    msg.readInt16("view");
521
}
522
523
void PlayerRecv::processKilledBy(Net::MessageIn &msg)
524
{
525
    if (actorManager == nullptr)
526
        return;
527
    const BeingId id = msg.readBeingId("killer id");
528
    const Being *const dstBeing = actorManager->findBeing(id);
529
    if (id == BeingId_zero)
530
    {
531
        debugMsg(
532
            // TRANSLATORS: player killed message
533
            _("You were killed by unknown source."))
534
    }
535
    else
536
    {
537
        std::string name;
538
        if (dstBeing != nullptr)
539
            name = dstBeing->getName();
540
        else
541
            name = strprintf("?%u", CAST_U32(id));
542
        debugMsg(strprintf(
543
            // TRANSLATORS: player killed message
544
            _("You were killed by %s."),
545
            name.c_str()))
546
    }
547
}
548
549
void PlayerRecv::processPlayerAttrs(Net::MessageIn &msg)
550
{
551
    const int len = msg.readInt16("len");
552
    if (len < 8)
553
        return;
554
555
    const int groupId = msg.readInt32("group id");
556
557
    if (localPlayer == nullptr)
558
        return;
559
560
    localPlayer->setGroupId(groupId);
561
}
562
563
void PlayerRecv::processPlayerStatUpdate7(Net::MessageIn &msg)
564
{
565
    BLOCK_START("PlayerRecv::processPlayerStatUpdate7")
566
    const int type = msg.readInt16("type");
567
    const int64_t value = msg.readInt64("value");
568
    playerHandler->setStat(msg, type, value, NoStat, Notify_true);
569
    BLOCK_END("PlayerRecv::processPlayerStatUpdate7")
570
}
571
572
void PlayerRecv::processSelectStyleAck(Net::MessageIn &msg)
573
{
574
    UNIMPLEMENTEDPACKET;
575
    msg.readUInt8("flag");
576
}
577
578
void PlayerRecv::processSetTitleAck(Net::MessageIn &msg)
579
{
580
    UNIMPLEMENTEDPACKET;
581
    msg.readUInt8("fail flag");
582
    msg.readInt32("title");
583
}
584
585
2
}  // namespace EAthena