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