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