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