GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/tmwa/beingrecv.cpp Lines: 1 747 0.1 %
Date: 2017-11-29 Branches: 0 562 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/tmwa/beingrecv.h"
24
25
#include "actormanager.h"
26
#include "configuration.h"
27
#include "effectmanager.h"
28
#include "guild.h"
29
#include "party.h"
30
31
#include "being/localplayer.h"
32
33
#include "particle/particleengine.h"
34
35
#include "input/keyboardconfig.h"
36
37
#include "gui/windows/okdialog.h"
38
#include "gui/windows/outfitwindow.h"
39
#include "gui/windows/socialwindow.h"
40
41
#include "net/beinghandler.h"
42
#include "net/serverfeatures.h"
43
44
#include "net/messagein.h"
45
46
#include "net/ea/beingrecv.h"
47
48
#include "net/tmwa/guildmanager.h"
49
#include "net/tmwa/sprite.h"
50
51
#include "resources/iteminfo.h"
52
53
#include "resources/db/itemdb.h"
54
55
#include "utils/timer.h"
56
57
#include "debug.h"
58
59
extern OkDialog *deathNotice;
60
61
namespace TmwAthena
62
{
63
64
static void setGm(Being *const dstBeing,
65
                  const uint16_t gmstatus)
66
{
67
    if (dstBeing != localPlayer)
68
    {
69
        if ((gmstatus & 0x80) != 0)
70
        {
71
            dstBeing->setGroupId(paths.getIntValue("gmDefaultLevel"));
72
            dstBeing->setGM(true);
73
        }
74
        else
75
        {
76
            dstBeing->setGroupId(0);
77
            dstBeing->setGM(false);
78
        }
79
    }
80
    else
81
    {
82
        if ((gmstatus & 0x80) != 0)
83
            dstBeing->setGM(true);
84
        else
85
            dstBeing->setGM(false);
86
    }
87
}
88
89
void BeingRecv::processBeingChangeLook(Net::MessageIn &msg)
90
{
91
    BLOCK_START("BeingRecv::processBeingChangeLook")
92
    if (actorManager == nullptr)
93
    {
94
        BLOCK_END("BeingRecv::processBeingChangeLook")
95
        return;
96
    }
97
98
    Being *const dstBeing = actorManager->findBeing(
99
        msg.readBeingId("being id"));
100
101
    const uint8_t type = msg.readUInt8("type");
102
    const int16_t id = CAST_S16(msg.readUInt8("id"));
103
    const int id2 = 1;
104
105
    if ((localPlayer == nullptr) || (dstBeing == nullptr))
106
    {
107
        BLOCK_END("BeingRecv::processBeingChangeLook")
108
        return;
109
    }
110
    processBeingChangeLookContinue(msg, dstBeing, type, id, id2);
111
    BLOCK_END("BeingRecv::processBeingChangeLook")
112
}
113
114
void BeingRecv::processBeingChangeLook2(Net::MessageIn &msg)
115
{
116
    BLOCK_START("BeingRecv::processBeingChangeLook")
117
    if (actorManager == nullptr)
118
    {
119
        BLOCK_END("BeingRecv::processBeingChangeLook")
120
        return;
121
    }
122
123
    Being *const dstBeing = actorManager->findBeing(
124
        msg.readBeingId("being id"));
125
126
    const uint8_t type = msg.readUInt8("type");
127
    int id2 = 0;
128
129
    const int16_t id = msg.readInt16("id1");
130
    if (type == 2)
131
    {
132
        id2 = msg.readInt16("id2");
133
    }
134
    else
135
    {
136
        msg.readInt16("id2");
137
        id2 = 1;
138
    }
139
140
    if ((localPlayer == nullptr) || (dstBeing == nullptr))
141
    {
142
        BLOCK_END("BeingRecv::processBeingChangeLook")
143
        return;
144
    }
145
    processBeingChangeLookContinue(msg, dstBeing, type, id, id2);
146
    BLOCK_END("BeingRecv::processBeingChangeLook")
147
}
148
149
void BeingRecv::processBeingChangeLookContinue(const Net::MessageIn &msg,
150
                                               Being *const dstBeing,
151
                                               const uint8_t type,
152
                                               const int id,
153
                                               const int id2)
154
{
155
    if (dstBeing->getType() == ActorType::Player)
156
        dstBeing->setOtherTime();
157
158
    switch (type)
159
    {
160
        case 0:     // change race
161
            dstBeing->setSubtype(fromInt(id, BeingTypeId),
162
                dstBeing->getLook());
163
            break;
164
        case 1:     // eAthena LOOK_HAIR
165
        {
166
            const uint16_t look = CAST_U16(id / 256);
167
            const int hair = id % 256;
168
            dstBeing->setHairStyle(SPRITE_HAIR_COLOR, hair * -1);
169
            dstBeing->setLook(look);
170
            break;
171
        }
172
        case 2:     // Weapon ID in id, Shield ID in id2
173
            dstBeing->setSpriteId(SPRITE_BODY,
174
                id);
175
            dstBeing->setWeaponId(id);
176
            dstBeing->setSpriteId(SPRITE_FLOOR,
177
                id2);
178
            localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
179
            break;
180
        case 3:     // Change lower headgear for eAthena, pants for us
181
            dstBeing->setSpriteId(SPRITE_WEAPON,
182
                id);
183
            localPlayer->imitateOutfit(dstBeing, SPRITE_WEAPON);
184
            break;
185
        case 4:     // Change upper headgear for eAthena, hat for us
186
            dstBeing->setSpriteId(SPRITE_CLOTHES_COLOR,
187
                id);
188
            localPlayer->imitateOutfit(dstBeing, SPRITE_CLOTHES_COLOR);
189
            break;
190
        case 5:     // Change middle headgear for eathena, armor for us
191
            dstBeing->setSpriteId(SPRITE_HEAD_BOTTOM,
192
                id);
193
            localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_BOTTOM);
194
            break;
195
        case 6:     // eAthena LOOK_HAIR_COLOR
196
            dstBeing->setHairColor(SPRITE_HAIR_COLOR,
197
                fromInt(id, ItemColor));
198
            break;
199
        case 7:     // Clothes color
200
            // ignoring it
201
            break;
202
        case 8:     // eAthena LOOK_SHIELD
203
            dstBeing->setSpriteId(SPRITE_FLOOR,
204
                id);
205
            localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
206
            break;
207
        case 9:     // eAthena LOOK_SHOES
208
            dstBeing->setSpriteId(SPRITE_HAIR,
209
                id);
210
            localPlayer->imitateOutfit(dstBeing, SPRITE_HAIR);
211
            break;
212
        case 10:   // LOOK_GLOVES
213
            dstBeing->setSpriteId(SPRITE_SHOES,
214
                id);
215
            localPlayer->imitateOutfit(dstBeing, SPRITE_SHOES);
216
            break;
217
        case 11:  // LOOK_CAPE
218
            dstBeing->setSpriteId(SPRITE_SHIELD,
219
                id);
220
            localPlayer->imitateOutfit(dstBeing, SPRITE_SHIELD);
221
            break;
222
        case 12:
223
            dstBeing->setSpriteId(SPRITE_HEAD_TOP,
224
                id);
225
            localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_TOP);
226
            break;
227
        case 13:
228
            dstBeing->setSpriteId(SPRITE_HEAD_MID,
229
                id);
230
            localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_MID);
231
            break;
232
        case 14:
233
            dstBeing->setSpriteId(SPRITE_ROBE,
234
                id);
235
            localPlayer->imitateOutfit(dstBeing, SPRITE_ROBE);
236
            break;
237
        case 15:
238
            dstBeing->setSpriteId(SPRITE_EVOL2,
239
                id);
240
            localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL2);
241
            break;
242
        case 16:
243
            dstBeing->setLook(CAST_U16(id));
244
            break;
245
        default:
246
            UNIMPLEMENTEDPACKETFIELD(type);
247
            break;
248
    }
249
}
250
251
void BeingRecv::processPlayerUpdate1(Net::MessageIn &msg)
252
{
253
    BLOCK_START("BeingRecv::processPlayerMoveUpdate")
254
    if ((actorManager == nullptr) || (localPlayer == nullptr))
255
    {
256
        BLOCK_END("BeingRecv::processPlayerMoveUpdate")
257
        return;
258
    }
259
260
    // An update about a player, potentially including movement.
261
    const BeingId id = msg.readBeingId("account id");
262
    const int16_t speed = msg.readInt16("speed");
263
    const uint32_t opt1 = msg.readInt16("opt1");
264
    const uint32_t opt2 = msg.readInt16("opt2");
265
    const uint32_t option = msg.readInt16("option");
266
    const int16_t job = msg.readInt16("job");
267
    int disguiseId = 0;
268
    if (toInt(id, int) < 110000000 && job >= 1000)
269
        disguiseId = job;
270
271
    Being *dstBeing = actorManager->findBeing(id);
272
    if (dstBeing == nullptr)
273
    {
274
        if (actorManager->isBlocked(id) == true)
275
        {
276
            BLOCK_END("BeingRecv::processPlayerMoveUpdate")
277
            return;
278
        }
279
280
        dstBeing = Ea::BeingRecv::createBeing(id, job);
281
282
        if (dstBeing == nullptr)
283
        {
284
            BLOCK_END("BeingRecv::processPlayerMoveUpdate")
285
            return;
286
        }
287
    }
288
    else if (disguiseId != 0)
289
    {
290
        actorManager->undelete(dstBeing);
291
        beingHandler->requestNameById(id);
292
    }
293
294
    uint8_t dir = dstBeing->getDirectionDelayed();
295
    if (dir != 0u)
296
    {
297
        if (dir != dstBeing->getDirection())
298
            dstBeing->setDirection(dir);
299
    }
300
301
    if (Party *const party = localPlayer->getParty())
302
    {
303
        if (party->isMember(id))
304
            dstBeing->setParty(party);
305
    }
306
307
    dstBeing->setWalkSpeed(speed);
308
309
    const uint8_t hairStyle = msg.readUInt8("hair style");
310
    const uint16_t look = msg.readUInt8("look");
311
    dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
312
    const uint16_t weapon = msg.readInt16("weapon");
313
    const uint16_t shield = msg.readInt16("shield");
314
    const uint16_t headBottom = msg.readInt16("head bottom");
315
316
    const uint16_t headTop = msg.readInt16("head top");
317
    const uint16_t headMid = msg.readInt16("head mid");
318
    const ItemColor hairColor = fromInt(
319
        msg.readUInt8("hair color"), ItemColor);
320
    msg.readUInt8("unused");
321
    msg.readInt32("unused");
322
323
    const int guild = msg.readInt32("guild");
324
325
    if ((guildManager == nullptr) || !GuildManager::getEnableGuildBot())
326
    {
327
        if (guild == 0)
328
            dstBeing->clearGuilds();
329
        else
330
            dstBeing->setGuild(Guild::getGuild(CAST_S16(guild)));
331
    }
332
333
    msg.readInt16("emblem");
334
    dstBeing->setManner(msg.readInt16("manner"));
335
    const uint32_t opt3 = msg.readInt16("opt3");
336
    dstBeing->setKarma(msg.readUInt8("karma"));
337
    // reserving bit for future usage
338
    dstBeing->setGender(Being::intToGender(
339
        CAST_U8(msg.readUInt8("gender") & 3)));
340
341
    if (disguiseId == 0)
342
    {
343
        // Set these after the gender, as the sprites may be gender-specific
344
        dstBeing->updateSprite(SPRITE_BODY,
345
            weapon,
346
            "");
347
        dstBeing->setWeaponId(weapon);
348
        dstBeing->updateSprite(SPRITE_FLOOR, shield);
349
        dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
350
        dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
351
        dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
352
        if (hairStyle == 0)
353
        {
354
            dstBeing->updateSprite(SPRITE_HAIR_COLOR,
355
                0,
356
                std::string());
357
        }
358
        else
359
        {
360
            dstBeing->updateSprite(SPRITE_HAIR_COLOR,
361
                hairStyle * -1,
362
                ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
363
        }
364
        dstBeing->setHairColor(hairColor);
365
    }
366
    localPlayer->imitateOutfit(dstBeing);
367
368
    uint16_t x, y;
369
    msg.readCoordinates(x, y, dir, "position");
370
    dstBeing->setTileCoords(x, y);
371
    dstBeing->setDirection(dir);
372
373
    localPlayer->imitateDirection(dstBeing, dir);
374
375
    const uint16_t gmstatus = msg.readInt16("gm status");
376
377
    setGm(dstBeing, gmstatus);
378
379
    applyPlayerAction(msg, dstBeing, msg.readUInt8("action type"));
380
    const int level = CAST_S32(msg.readUInt8("level"));
381
    if (level != 0)
382
        dstBeing->setLevel(level);
383
384
    msg.readUInt8("unused");
385
386
    dstBeing->setActionTime(tick_time);
387
388
    dstBeing->setStatusEffectOpitons(option,
389
        opt1,
390
        opt2,
391
        opt3);
392
393
    BLOCK_END("BeingRecv::processPlayerMoveUpdate")
394
}
395
396
void BeingRecv::processPlayerUpdate2(Net::MessageIn &msg)
397
{
398
    BLOCK_START("BeingRecv::processPlayerMoveUpdate")
399
    if ((actorManager == nullptr) || (localPlayer == nullptr))
400
    {
401
        BLOCK_END("BeingRecv::processPlayerMoveUpdate")
402
        return;
403
    }
404
405
    // An update about a player, potentially including movement.
406
    const BeingId id = msg.readBeingId("account id");
407
    const int16_t speed = msg.readInt16("speed");
408
    const uint32_t opt1 = msg.readInt16("opt1");
409
    const uint32_t opt2 = msg.readInt16("opt2");
410
    const uint32_t option = msg.readInt16("option");
411
    const int16_t job = msg.readInt16("job");
412
    int disguiseId = 0;
413
    if (toInt(id, int) < 110000000 && job >= 1000)
414
        disguiseId = job;
415
416
    Being *dstBeing = actorManager->findBeing(id);
417
    if (dstBeing == nullptr)
418
    {
419
        if (actorManager->isBlocked(id) == true)
420
        {
421
            BLOCK_END("BeingRecv::processPlayerMoveUpdate")
422
            return;
423
        }
424
425
        dstBeing = Ea::BeingRecv::createBeing(id, job);
426
427
        if (dstBeing == nullptr)
428
        {
429
            BLOCK_END("BeingRecv::processPlayerMoveUpdate")
430
            return;
431
        }
432
    }
433
    else if (disguiseId != 0)
434
    {
435
        actorManager->undelete(dstBeing);
436
        beingHandler->requestNameById(id);
437
    }
438
439
    uint8_t dir = dstBeing->getDirectionDelayed();
440
    if (dir != 0u)
441
    {
442
        if (dir != dstBeing->getDirection())
443
            dstBeing->setDirection(dir);
444
    }
445
446
    if (Party *const party = localPlayer->getParty())
447
    {
448
        if (party->isMember(id))
449
            dstBeing->setParty(party);
450
    }
451
452
    dstBeing->setWalkSpeed(speed);
453
454
    const uint8_t hairStyle = msg.readUInt8("hair style");
455
    const uint16_t look = msg.readUInt8("look");
456
    dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
457
    const uint16_t weapon = msg.readInt16("weapon");
458
    const uint16_t shield = msg.readInt16("shield");
459
    const uint16_t headBottom = msg.readInt16("head bottom");
460
    const uint16_t headTop = msg.readInt16("head top");
461
    const uint16_t headMid = msg.readInt16("head mid");
462
    const ItemColor hairColor = fromInt(
463
        msg.readUInt8("hair color"), ItemColor);
464
    msg.readUInt8("unused");
465
    msg.readInt32("unused");
466
467
    const int guild = msg.readInt32("guild");
468
469
    if ((guildManager == nullptr) || !GuildManager::getEnableGuildBot())
470
    {
471
        if (guild == 0)
472
            dstBeing->clearGuilds();
473
        else
474
            dstBeing->setGuild(Guild::getGuild(CAST_S16(guild)));
475
    }
476
477
    msg.readInt16("emblem");
478
    dstBeing->setManner(msg.readInt16("manner"));
479
    const uint32_t opt3 = msg.readInt16("opt3");
480
    dstBeing->setKarma(msg.readUInt8("karma"));
481
    // reserving bit for future usage
482
    dstBeing->setGender(Being::intToGender(
483
        CAST_U8(msg.readUInt8("gender") & 3)));
484
485
    if (disguiseId == 0)
486
    {
487
        // Set these after the gender, as the sprites may be gender-specific
488
        dstBeing->updateSprite(SPRITE_BODY,
489
            weapon,
490
            "");
491
        dstBeing->setWeaponId(weapon);
492
        dstBeing->updateSprite(SPRITE_FLOOR, shield);
493
        dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
494
        dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
495
        dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
496
        if (hairStyle == 0)
497
        {
498
            dstBeing->updateSprite(SPRITE_HAIR_COLOR,
499
                0,
500
                std::string());
501
        }
502
        else
503
        {
504
            dstBeing->updateSprite(SPRITE_HAIR_COLOR,
505
                hairStyle * -1,
506
                ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
507
        }
508
        dstBeing->setHairColor(hairColor);
509
    }
510
    localPlayer->imitateOutfit(dstBeing);
511
512
    uint16_t x, y;
513
    msg.readCoordinates(x, y, dir, "position");
514
    dstBeing->setTileCoords(x, y);
515
    dstBeing->setDirection(dir);
516
517
    localPlayer->imitateDirection(dstBeing, dir);
518
519
    const uint16_t gmstatus = msg.readInt16("gm status");
520
521
    setGm(dstBeing, gmstatus);
522
523
    applyPlayerAction(msg, dstBeing, msg.readUInt8("action type"));
524
    const int level = CAST_S32(msg.readUInt8("level"));
525
    if (level != 0)
526
        dstBeing->setLevel(level);
527
528
    dstBeing->setActionTime(tick_time);
529
    dstBeing->setStatusEffectOpitons(option,
530
        opt1,
531
        opt2,
532
        opt3);
533
534
    BLOCK_END("BeingRecv::processPlayerMoveUpdate")
535
}
536
537
void BeingRecv::processPlayerMove(Net::MessageIn &msg)
538
{
539
    BLOCK_START("BeingRecv::processPlayerMoveUpdate")
540
    if ((actorManager == nullptr) || (localPlayer == nullptr))
541
    {
542
        BLOCK_END("BeingRecv::processPlayerMoveUpdate")
543
        return;
544
    }
545
546
    // An update about a player, potentially including movement.
547
    const BeingId id = msg.readBeingId("account id");
548
    const int16_t speed = msg.readInt16("speed");
549
    const uint32_t opt1 = msg.readInt16("opt1");
550
    const uint32_t opt2 = msg.readInt16("opt2");
551
    const uint32_t option = msg.readInt16("option");
552
    const int16_t job = msg.readInt16("job");
553
    int disguiseId = 0;
554
    if (toInt(id, int) < 110000000 && job >= 1000)
555
        disguiseId = job;
556
557
    Being *dstBeing = actorManager->findBeing(id);
558
    if (dstBeing == nullptr)
559
    {
560
        if (actorManager->isBlocked(id) == true)
561
        {
562
            BLOCK_END("BeingRecv::processPlayerMoveUpdate")
563
            return;
564
        }
565
566
        dstBeing = Ea::BeingRecv::createBeing(id, job);
567
568
        if (dstBeing == nullptr)
569
        {
570
            BLOCK_END("BeingRecv::processPlayerMoveUpdate")
571
            return;
572
        }
573
    }
574
    else if (disguiseId != 0)
575
    {
576
        actorManager->undelete(dstBeing);
577
        beingHandler->requestNameById(id);
578
    }
579
580
    const uint8_t dir = dstBeing->getDirectionDelayed();
581
    if (dir != 0u)
582
    {
583
        if (dir != dstBeing->getDirection())
584
            dstBeing->setDirection(dir);
585
    }
586
587
    if (Party *const party = localPlayer->getParty())
588
    {
589
        if (party->isMember(id))
590
            dstBeing->setParty(party);
591
    }
592
593
    dstBeing->setWalkSpeed(speed);
594
595
    const uint8_t hairStyle = msg.readUInt8("hair style");
596
    const uint16_t look = msg.readUInt8("look");
597
    dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
598
    const uint16_t weapon = msg.readInt16("weapon");
599
    const uint16_t shield = msg.readInt16("shield");
600
    const uint16_t headBottom = msg.readInt16("head bottom");
601
602
    msg.readInt32("tick");
603
604
    const uint16_t headTop = msg.readInt16("head top");
605
    const uint16_t headMid = msg.readInt16("head mid");
606
    const ItemColor hairColor = fromInt(
607
        msg.readUInt8("hair color"), ItemColor);
608
    msg.readUInt8("unused");
609
    msg.readInt32("unused");
610
611
    const int guild = msg.readInt32("guild");
612
613
    if ((guildManager == nullptr) || !GuildManager::getEnableGuildBot())
614
    {
615
        if (guild == 0)
616
            dstBeing->clearGuilds();
617
        else
618
            dstBeing->setGuild(Guild::getGuild(CAST_S16(guild)));
619
    }
620
621
    msg.readInt16("emblem");
622
    dstBeing->setManner(msg.readInt16("manner"));
623
    const uint32_t opt3 = msg.readInt16("opt3");
624
    dstBeing->setKarma(msg.readUInt8("karma"));
625
    // reserving bit for future usage
626
    dstBeing->setGender(Being::intToGender(
627
        CAST_U8(msg.readUInt8("gender") & 3)));
628
629
    if (disguiseId == 0)
630
    {
631
        // Set these after the gender, as the sprites may be gender-specific
632
        dstBeing->updateSprite(SPRITE_BODY,
633
            weapon,
634
            "");
635
        dstBeing->setWeaponId(weapon);
636
        dstBeing->updateSprite(SPRITE_FLOOR, shield);
637
        dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
638
        dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
639
        dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
640
        if (hairStyle == 0)
641
        {
642
            dstBeing->updateSprite(SPRITE_HAIR_COLOR,
643
                0,
644
                std::string());
645
        }
646
        else
647
        {
648
            dstBeing->updateSprite(SPRITE_HAIR_COLOR,
649
                hairStyle * -1,
650
                ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
651
        }
652
        dstBeing->setHairColor(hairColor);
653
    }
654
    localPlayer->imitateOutfit(dstBeing);
655
656
    uint16_t srcX, srcY, dstX, dstY;
657
    msg.readCoordinatePair(srcX, srcY, dstX, dstY, "moving path");
658
659
    localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
660
661
    dstBeing->setTileCoords(srcX, srcY);
662
    dstBeing->setDestination(dstX, dstY);
663
664
    // because server don't send direction in move packet,
665
    // we fixing it
666
667
    if (srcX != dstX || srcY != dstY)
668
    {
669
        const int d = dstBeing->calcDirection(dstX, dstY);
670
671
        if ((d != 0) && dstBeing->getDirection() != d)
672
            dstBeing->setDirectionDelayed(CAST_U8(d));
673
    }
674
675
    if (localPlayer->getCurrentAction() != BeingAction::STAND)
676
        localPlayer->imitateAction(dstBeing, BeingAction::STAND);
677
    if (localPlayer->getDirection() != dstBeing->getDirection())
678
    {
679
        localPlayer->imitateDirection(dstBeing,
680
            dstBeing->getDirection());
681
    }
682
683
    const uint16_t gmstatus = msg.readInt16("gm status");
684
685
    setGm(dstBeing, gmstatus);
686
687
    msg.readUInt8("unused");
688
689
    const int level = CAST_S32(msg.readUInt8("level"));
690
    if (level != 0)
691
        dstBeing->setLevel(level);
692
693
    msg.readUInt8("unused");
694
695
    if (dstBeing->getType() != ActorType::Player)
696
        dstBeing->setActionTime(tick_time);
697
698
    dstBeing->setStatusEffectOpitons(option,
699
        opt1,
700
        opt2,
701
        opt3);
702
703
    if (dstBeing->getType() == ActorType::Player)
704
        dstBeing->setMoveTime();
705
    BLOCK_END("BeingRecv::processPlayerMoveUpdate")
706
}
707
708
void BeingRecv::processBeingVisible(Net::MessageIn &msg)
709
{
710
    BLOCK_START("BeingRecv::processBeingVisibleOrMove")
711
    if (actorManager == nullptr)
712
    {
713
        BLOCK_END("BeingRecv::processBeingVisibleOrMove")
714
        return;
715
    }
716
717
    BeingId spawnId;
718
719
    // Information about a being in range
720
    const BeingId id = msg.readBeingId("being id");
721
    if (id == Ea::BeingRecv::mSpawnId)
722
        spawnId = Ea::BeingRecv::mSpawnId;
723
    else
724
        spawnId = BeingId_zero;
725
    Ea::BeingRecv::mSpawnId = BeingId_zero;
726
    int16_t speed = msg.readInt16("speed");
727
    const uint32_t opt1 = msg.readInt16("opt1");
728
    const uint32_t opt2 = msg.readInt16("opt2");
729
    const uint32_t option = msg.readInt16("option");
730
    const int16_t job = msg.readInt16("class");
731
    int disguiseId = 0;
732
    if (id == localPlayer->getId() && job >= 1000)
733
        disguiseId = job;
734
735
    Being *dstBeing = actorManager->findBeing(id);
736
737
    if ((dstBeing != nullptr) && dstBeing->getType() == ActorType::Monster
738
        && !dstBeing->isAlive())
739
    {
740
        actorManager->destroy(dstBeing);
741
        actorManager->erase(dstBeing);
742
        dstBeing = nullptr;
743
    }
744
745
    if (dstBeing == nullptr)
746
    {
747
        // Being with id >= 110000000 and job 0 are better
748
        // known as ghosts, so don't create those.
749
        if (job == 0 && toInt(id, int) >= 110000000)
750
        {
751
            BLOCK_END("BeingRecv::processBeingVisibleOrMove")
752
            return;
753
        }
754
755
        if (actorManager->isBlocked(id) == true)
756
        {
757
            BLOCK_END("BeingRecv::processBeingVisibleOrMove")
758
            return;
759
        }
760
761
        dstBeing = Ea::BeingRecv::createBeing(id, job);
762
763
        if (dstBeing == nullptr)
764
        {
765
            BLOCK_END("BeingRecv::processBeingVisibleOrMove")
766
            return;
767
        }
768
    }
769
    else
770
    {
771
        if (dstBeing->getType() == ActorType::Npc)
772
        {
773
            actorManager->undelete(dstBeing);
774
            beingHandler->requestNameById(id);
775
        }
776
    }
777
778
    if (dstBeing->getType() == ActorType::Player)
779
        dstBeing->setMoveTime();
780
781
    if (spawnId != BeingId_zero)
782
    {
783
        dstBeing->setAction(BeingAction::SPAWN, 0);
784
    }
785
    else
786
    {
787
        dstBeing->clearPath();
788
        dstBeing->setActionTime(tick_time);
789
        dstBeing->setAction(BeingAction::STAND, 0);
790
    }
791
792
    // Prevent division by 0 when calculating frame
793
    if (speed == 0)
794
        speed = 150;
795
796
    const uint8_t hairStyle = msg.readUInt8("hair style");
797
    const uint16_t look = msg.readUInt8("look");
798
    dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
799
    if (dstBeing->getType() == ActorType::Monster && (localPlayer != nullptr))
800
        localPlayer->checkNewName(dstBeing);
801
    dstBeing->setWalkSpeed(speed);
802
    const uint16_t weapon = msg.readInt16("weapon");
803
    const uint16_t headBottom = msg.readInt16("head bottom");
804
805
    const uint16_t shield = msg.readInt16("shield");
806
    const uint16_t headTop = msg.readInt16("head top");
807
    const uint16_t headMid = msg.readInt16("head mid");
808
    const ItemColor hairColor = fromInt(msg.readUInt8("hair color"),
809
        ItemColor);
810
    msg.readUInt8("unused");
811
    const uint16_t shoes = msg.readInt16("shoes / clothes color");
812
813
    uint16_t gloves;
814
    if (dstBeing->getType() == ActorType::Monster)
815
    {
816
        if (serverFeatures->haveServerHp())
817
        {
818
            const int hp = msg.readInt32("hp");
819
            const int maxHP = msg.readInt32("max hp");
820
            if ((hp != 0) && (maxHP != 0))
821
            {
822
                dstBeing->setMaxHP(maxHP);
823
                const int oldHP = dstBeing->getHP();
824
                if ((oldHP == 0) || oldHP > hp)
825
                    dstBeing->setHP(hp);
826
            }
827
        }
828
        else
829
        {
830
            msg.readInt32("unused");
831
            msg.readInt32("unused");
832
        }
833
        gloves = 0;
834
    }
835
    else
836
    {
837
        gloves = msg.readInt16("gloves / head dir");
838
        msg.readInt32("guild");
839
        msg.readInt16("guild emblem");
840
    }
841
842
    dstBeing->setManner(msg.readInt16("manner"));
843
    const uint32_t opt3 = msg.readInt16("opt3");
844
    if (serverFeatures->haveMonsterAttackRange()
845
        && dstBeing->getType() == ActorType::Monster)
846
    {
847
        const int attackRange = CAST_S32(
848
            msg.readUInt8("attack range (was karma)"));
849
        dstBeing->setAttackRange(attackRange);
850
    }
851
    else
852
    {
853
        dstBeing->setKarma(msg.readUInt8("karma"));
854
    }
855
    uint8_t gender = msg.readUInt8("gender");
856
857
    if ((disguiseId == 0) && dstBeing->getType() == ActorType::Player)
858
    {
859
        // reserving bits for future usage
860
        gender &= 3;
861
        dstBeing->setGender(Being::intToGender(gender));
862
        // Set these after the gender, as the sprites may be gender-specific
863
        if (hairStyle == 0)
864
        {
865
            dstBeing->updateSprite(SPRITE_HAIR_COLOR, 0);
866
        }
867
        else
868
        {
869
            dstBeing->updateSprite(SPRITE_HAIR_COLOR,
870
                hairStyle * -1,
871
                ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
872
        }
873
        dstBeing->setHairColor(hairColor);
874
        dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
875
        dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
876
        dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
877
        dstBeing->updateSprite(SPRITE_HAIR, shoes);
878
        dstBeing->updateSprite(SPRITE_SHOES, gloves);
879
        dstBeing->updateSprite(SPRITE_BODY, weapon);
880
        dstBeing->setWeaponId(weapon);
881
        dstBeing->updateSprite(SPRITE_FLOOR, shield);
882
    }
883
    else if (dstBeing->getType() == ActorType::Npc
884
             && serverFeatures->haveNpcGender())
885
    {
886
        setServerGender(dstBeing, gender);
887
    }
888
889
    uint8_t dir;
890
    uint16_t x, y;
891
    msg.readCoordinates(x, y, dir, "position");
892
    dstBeing->setTileCoords(x, y);
893
894
    if (job == 45 && (socialWindow != nullptr) && (outfitWindow != nullptr))
895
    {
896
        const int num = socialWindow->getPortalIndex(x, y);
897
        if (num >= 0)
898
        {
899
            dstBeing->setName(KeyboardConfig::getKeyShortString(
900
                OutfitWindow::keyName(num)));
901
        }
902
        else
903
        {
904
            dstBeing->setName("");
905
        }
906
    }
907
908
    dstBeing->setDirection(dir);
909
910
    msg.readUInt8("unknown");
911
    msg.readUInt8("unknown");
912
    msg.readUInt8("unknown");
913
    msg.readUInt8("unknown");
914
    msg.readUInt8("unknown");
915
916
    dstBeing->setStatusEffectOpitons(option,
917
        opt1,
918
        opt2,
919
        opt3);
920
    BLOCK_END("BeingRecv::processBeingVisibleOrMove")
921
}
922
923
void BeingRecv::processBeingMove(Net::MessageIn &msg)
924
{
925
    BLOCK_START("BeingRecv::processBeingVisibleOrMove")
926
    if (actorManager == nullptr)
927
    {
928
        BLOCK_END("BeingRecv::processBeingVisibleOrMove")
929
        return;
930
    }
931
932
    BeingId spawnId;
933
934
    // Information about a being in range
935
    const BeingId id = msg.readBeingId("being id");
936
    if (id == Ea::BeingRecv::mSpawnId)
937
        spawnId = Ea::BeingRecv::mSpawnId;
938
    else
939
        spawnId = BeingId_zero;
940
    Ea::BeingRecv::mSpawnId = BeingId_zero;
941
    int16_t speed = msg.readInt16("speed");
942
    const uint32_t opt1 = msg.readInt16("opt1");
943
    const uint32_t opt2 = msg.readInt16("opt2");
944
    const uint32_t option = msg.readInt16("option");
945
    const int16_t job = msg.readInt16("class");
946
    int disguiseId = 0;
947
    if (id == localPlayer->getId() && job >= 1000)
948
        disguiseId = job;
949
950
    Being *dstBeing = actorManager->findBeing(id);
951
952
    if ((dstBeing != nullptr) && dstBeing->getType() == ActorType::Monster
953
        && !dstBeing->isAlive())
954
    {
955
        actorManager->destroy(dstBeing);
956
        actorManager->erase(dstBeing);
957
        dstBeing = nullptr;
958
    }
959
960
    if (dstBeing == nullptr)
961
    {
962
        // Being with id >= 110000000 and job 0 are better
963
        // known as ghosts, so don't create those.
964
        if (job == 0 && toInt(id, int) >= 110000000)
965
        {
966
            BLOCK_END("BeingRecv::processBeingVisibleOrMove")
967
            return;
968
        }
969
970
        if (actorManager->isBlocked(id) == true)
971
        {
972
            BLOCK_END("BeingRecv::processBeingVisibleOrMove")
973
            return;
974
        }
975
976
        dstBeing = Ea::BeingRecv::createBeing(id, job);
977
978
        if (dstBeing == nullptr)
979
        {
980
            BLOCK_END("BeingRecv::processBeingVisibleOrMove")
981
            return;
982
        }
983
    }
984
    else
985
    {
986
        if (dstBeing->getType() == ActorType::Npc)
987
        {
988
            actorManager->undelete(dstBeing);
989
            beingHandler->requestNameById(id);
990
        }
991
    }
992
993
    if (dstBeing->getType() == ActorType::Player)
994
        dstBeing->setMoveTime();
995
996
    if (spawnId != BeingId_zero)
997
        dstBeing->setAction(BeingAction::SPAWN, 0);
998
999
    // Prevent division by 0 when calculating frame
1000
    if (speed == 0)
1001
        speed = 150;
1002
1003
    const uint8_t hairStyle = msg.readUInt8("hair style");
1004
    const uint16_t look = msg.readUInt8("look");
1005
    dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
1006
    if (dstBeing->getType() == ActorType::Monster && (localPlayer != nullptr))
1007
        localPlayer->checkNewName(dstBeing);
1008
    dstBeing->setWalkSpeed(speed);
1009
    const uint16_t weapon = msg.readInt16("weapon");
1010
    const uint16_t headBottom = msg.readInt16("head bottom");
1011
1012
    msg.readInt32("tick");
1013
1014
    const uint16_t shield = msg.readInt16("shield");
1015
    const uint16_t headTop = msg.readInt16("head top");
1016
    const uint16_t headMid = msg.readInt16("head mid");
1017
    const ItemColor hairColor = fromInt(
1018
        msg.readUInt8("hair color"), ItemColor);
1019
    msg.readUInt8("unused");
1020
    const uint16_t shoes = msg.readInt16("shoes / clothes color");
1021
1022
    uint16_t gloves;
1023
    if (dstBeing->getType() == ActorType::Monster)
1024
    {
1025
        if (serverFeatures->haveServerHp())
1026
        {
1027
            const int hp = msg.readInt32("hp");
1028
            const int maxHP = msg.readInt32("max hp");
1029
            if ((hp != 0) && (maxHP != 0))
1030
            {
1031
                dstBeing->setMaxHP(maxHP);
1032
                const int oldHP = dstBeing->getHP();
1033
                if ((oldHP == 0) || oldHP > hp)
1034
                    dstBeing->setHP(hp);
1035
            }
1036
        }
1037
        else
1038
        {
1039
            msg.readInt32("unused");
1040
            msg.readInt32("unused");
1041
        }
1042
        gloves = 0;
1043
    }
1044
    else
1045
    {
1046
        gloves = msg.readInt16("gloves / head dir");
1047
        msg.readInt32("guild");
1048
        msg.readInt16("guild emblem");
1049
    }
1050
1051
    dstBeing->setManner(msg.readInt16("manner"));
1052
    const uint32_t opt3 = msg.readInt16("opt3");
1053
    if (serverFeatures->haveMonsterAttackRange()
1054
        && dstBeing->getType() == ActorType::Monster)
1055
    {
1056
        const int attackRange = CAST_S32(
1057
            msg.readUInt8("attack range (was karma)"));
1058
        dstBeing->setAttackRange(attackRange);
1059
    }
1060
    else
1061
    {
1062
        dstBeing->setKarma(msg.readUInt8("karma"));
1063
    }
1064
    uint8_t gender = msg.readUInt8("gender");
1065
1066
    if ((disguiseId == 0) && dstBeing->getType() == ActorType::Player)
1067
    {
1068
        // reserving bits for future usage
1069
        gender &= 3;
1070
        dstBeing->setGender(Being::intToGender(gender));
1071
        // Set these after the gender, as the sprites may be gender-specific
1072
        if (hairStyle == 0)
1073
        {
1074
            dstBeing->updateSprite(SPRITE_HAIR_COLOR, 0);
1075
        }
1076
        else
1077
        {
1078
            dstBeing->updateSprite(SPRITE_HAIR_COLOR,
1079
                hairStyle * -1,
1080
                ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
1081
        }
1082
        dstBeing->setHairColor(hairColor);
1083
        dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
1084
        dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
1085
        dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
1086
        dstBeing->updateSprite(SPRITE_HAIR, shoes);
1087
        dstBeing->updateSprite(SPRITE_SHOES, gloves);
1088
        dstBeing->updateSprite(SPRITE_BODY, weapon);
1089
        dstBeing->setWeaponId(weapon);
1090
        dstBeing->updateSprite(SPRITE_FLOOR, shield);
1091
    }
1092
    else if (dstBeing->getType() == ActorType::Npc
1093
             && serverFeatures->haveNpcGender())
1094
    {
1095
        setServerGender(dstBeing, gender);
1096
    }
1097
1098
    uint16_t srcX, srcY, dstX, dstY;
1099
    msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
1100
    if (disguiseId == 0)
1101
    {
1102
        dstBeing->setAction(BeingAction::STAND, 0);
1103
        dstBeing->setTileCoords(srcX, srcY);
1104
        if (serverFeatures->haveMove3())
1105
            dstBeing->setCachedDestination(dstX, dstY);
1106
        else
1107
            dstBeing->setDestination(dstX, dstY);
1108
    }
1109
1110
    msg.readUInt8("unknown");
1111
    msg.readUInt8("unknown");
1112
    msg.readUInt8("unknown");
1113
    msg.readUInt8("unknown");
1114
    msg.readUInt8("unknown");
1115
1116
    dstBeing->setStatusEffectOpitons(option,
1117
        opt1,
1118
        opt2,
1119
        opt3);
1120
    BLOCK_END("BeingRecv::processBeingVisibleOrMove")
1121
}
1122
1123
void BeingRecv::processBeingSpawn(Net::MessageIn &msg)
1124
{
1125
    BLOCK_START("BeingRecv::processBeingSpawn")
1126
    // skipping this packet
1127
    Ea::BeingRecv::mSpawnId = msg.readBeingId("being id");
1128
    msg.readInt16("speed");
1129
    msg.readInt16("opt1");
1130
    msg.readInt16("opt2");
1131
    msg.readInt16("option");
1132
    msg.readInt16("disguise");
1133
    msg.skip(25, "unused");
1134
    BLOCK_END("BeingRecv::processBeingSpawn")
1135
}
1136
1137
void BeingRecv::processSkillCasting(Net::MessageIn &msg)
1138
{
1139
    msg.readInt32("src id");
1140
    msg.readInt32("dst id");
1141
    msg.readInt16("dst x");
1142
    msg.readInt16("dst y");
1143
    msg.readInt16("skill num");
1144
    msg.readInt32("skill get p1");
1145
    msg.readInt32("cast time");
1146
}
1147
1148
void BeingRecv::processBeingStatusChange(Net::MessageIn &msg)
1149
{
1150
    BLOCK_START("BeingRecv::processBeingStatusChange")
1151
    if (actorManager == nullptr)
1152
    {
1153
        BLOCK_END("BeingRecv::processBeingStatusChange")
1154
        return;
1155
    }
1156
1157
    // Status change
1158
    const uint16_t status = msg.readInt16("status");
1159
    const BeingId id = msg.readBeingId("being id");
1160
    const Enable flag = fromBool(
1161
        msg.readUInt8("flag: 0: stop, 1: start"), Enable);
1162
1163
    Being *const dstBeing = actorManager->findBeing(id);
1164
    if (dstBeing != nullptr)
1165
    {
1166
        // dont know on legacy servers is effect really started
1167
        // or not. Because this always sending IsStart_true
1168
        dstBeing->setStatusEffect(status, flag, IsStart_true);
1169
    }
1170
    BLOCK_END("BeingRecv::processBeingStatusChange")
1171
}
1172
1173
void BeingRecv::processBeingMove2(Net::MessageIn &msg)
1174
{
1175
    BLOCK_START("BeingRecv::processBeingMove2")
1176
    if (actorManager == nullptr)
1177
    {
1178
        BLOCK_END("BeingRecv::processBeingMove2")
1179
        return;
1180
    }
1181
1182
    /*
1183
      * A simplified movement packet, used by the
1184
      * later versions of eAthena for both mobs and
1185
      * players
1186
      */
1187
    Being *const dstBeing = actorManager->findBeing(
1188
        msg.readBeingId("being id"));
1189
1190
    /*
1191
      * This packet doesn't have enough info to actually
1192
      * create a new being, so if the being isn't found,
1193
      * we'll just pretend the packet didn't happen
1194
      */
1195
1196
    if (dstBeing == nullptr)
1197
    {
1198
        BLOCK_END("BeingRecv::processBeingMove2")
1199
        return;
1200
    }
1201
1202
    uint16_t srcX, srcY, dstX, dstY;
1203
    msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
1204
    msg.readInt32("tick");
1205
1206
    dstBeing->setAction(BeingAction::STAND, 0);
1207
    dstBeing->setTileCoords(srcX, srcY);
1208
    dstBeing->setDestination(dstX, dstY);
1209
    if (dstBeing->getType() == ActorType::Player)
1210
        dstBeing->setMoveTime();
1211
    BLOCK_END("BeingRecv::processBeingMove2")
1212
}
1213
1214
void BeingRecv::processBeingChangeDirection(Net::MessageIn &msg)
1215
{
1216
    BLOCK_START("BeingRecv::processBeingChangeDirection")
1217
    if (actorManager == nullptr)
1218
    {
1219
        BLOCK_END("BeingRecv::processBeingChangeDirection")
1220
        return;
1221
    }
1222
1223
    Being *const dstBeing = actorManager->findBeing(
1224
        msg.readBeingId("being id"));
1225
1226
    if (dstBeing == nullptr)
1227
    {
1228
        DEBUGLOGSTR("invisible player?");
1229
        msg.readInt16("unused");
1230
        msg.readUInt8("direction");
1231
        BLOCK_END("BeingRecv::processBeingChangeDirection");
1232
        return;
1233
    }
1234
1235
    msg.readInt16("unused");
1236
1237
    const uint8_t dir = Net::MessageIn::fromServerDirection(
1238
        CAST_U8(msg.readUInt8("direction") & 0x0FU));
1239
    dstBeing->setDirection(dir);
1240
    if (localPlayer != nullptr)
1241
        localPlayer->imitateDirection(dstBeing, dir);
1242
    BLOCK_END("BeingRecv::processBeingChangeDirection")
1243
}
1244
1245
void BeingRecv::processPlayerStatusChange(Net::MessageIn &msg)
1246
{
1247
    BLOCK_START("BeingRecv::processPlayerStop")
1248
    if (actorManager == nullptr)
1249
    {
1250
        BLOCK_END("BeingRecv::processPlayerStop")
1251
        return;
1252
    }
1253
1254
    // Change in players' flags
1255
    const BeingId id = msg.readBeingId("account id");
1256
    Being *const dstBeing = actorManager->findBeing(id);
1257
    if (dstBeing == nullptr)
1258
    {
1259
        DEBUGLOGSTR("invisible player?");
1260
        msg.readInt16("stun mode");
1261
        msg.readInt16("status effect");
1262
        msg.readInt16("opt?");
1263
        msg.readUInt8("Unused?");
1264
        return;
1265
    }
1266
1267
    const uint32_t opt1 = msg.readInt16("opt1");
1268
    const uint32_t opt2 = msg.readInt16("opt2");
1269
    const uint32_t option = msg.readInt16("option");
1270
    msg.readUInt8("Unused?");
1271
1272
    dstBeing->setStatusEffectOpitons(option,
1273
        opt1,
1274
        opt2);
1275
    BLOCK_END("BeingRecv::processPlayerStop")
1276
}
1277
1278
void BeingRecv::processBeingResurrect(Net::MessageIn &msg)
1279
{
1280
    BLOCK_START("BeingRecv::processBeingResurrect")
1281
    if (actorManager == nullptr || localPlayer == nullptr)
1282
    {
1283
        BLOCK_END("BeingRecv::processBeingResurrect")
1284
        return;
1285
    }
1286
1287
    // A being changed mortality status
1288
1289
    const BeingId id = msg.readBeingId("being id");
1290
    Being *const dstBeing = actorManager->findBeing(id);
1291
    if (dstBeing == nullptr)
1292
    {
1293
        DEBUGLOGSTR("insible player?");
1294
        msg.readInt16("flag?");
1295
        BLOCK_END("BeingRecv::processBeingResurrect")
1296
        return;
1297
    }
1298
1299
    // If this is player's current target, clear it.
1300
    if (dstBeing == localPlayer->getTarget())
1301
        localPlayer->stopAttack();
1302
    if (dstBeing == localPlayer &&
1303
        deathNotice != nullptr)
1304
    {
1305
        deathNotice->scheduleDelete();
1306
        deathNotice = nullptr;
1307
    }
1308
1309
    if (msg.readInt16("flag?") == 1)
1310
        dstBeing->setAction(BeingAction::STAND, 0);
1311
    BLOCK_END("BeingRecv::processBeingResurrect")
1312
}
1313
1314
void BeingRecv::processPlayerGuilPartyInfo(Net::MessageIn &msg)
1315
{
1316
    BLOCK_START("BeingRecv::processPlayerGuilPartyInfo")
1317
    if (actorManager == nullptr)
1318
    {
1319
        BLOCK_END("BeingRecv::processPlayerGuilPartyInfo")
1320
        return;
1321
    }
1322
1323
    Being *const dstBeing = actorManager->findBeing(
1324
        msg.readBeingId("being id"));
1325
1326
    if (dstBeing != nullptr)
1327
    {
1328
        dstBeing->setPartyName(msg.readString(24, "party name"));
1329
        if ((guildManager == nullptr) || !GuildManager::getEnableGuildBot())
1330
        {
1331
            dstBeing->setGuildName(msg.readString(24, "guild name"));
1332
            dstBeing->setGuildPos(msg.readString(24, "guild pos"));
1333
        }
1334
        else
1335
        {
1336
            msg.readString(24, "guild name");
1337
            msg.readString(24, "guild pos");
1338
        }
1339
        dstBeing->addToCache();
1340
        msg.readString(24, "?");
1341
    }
1342
    else
1343
    {
1344
        msg.readString(24, "party name");
1345
        msg.readString(24, "guild name");
1346
        msg.readString(24, "guild pos");
1347
        msg.readString(24, "?");
1348
    }
1349
    BLOCK_END("BeingRecv::processPlayerGuilPartyInfo")
1350
}
1351
1352
void BeingRecv::processBeingSelfEffect(Net::MessageIn &msg)
1353
{
1354
    BLOCK_START("BeingRecv::processBeingSelfEffect")
1355
    if ((effectManager == nullptr) || (actorManager == nullptr))
1356
    {
1357
        BLOCK_END("BeingRecv::processBeingSelfEffect")
1358
        return;
1359
    }
1360
1361
    const BeingId id = msg.readBeingId("being id");
1362
    Being *const being = actorManager->findBeing(id);
1363
    if (being == nullptr)
1364
    {
1365
        DEBUGLOGSTR("insible player?");
1366
        msg.readInt32("effect type");
1367
        BLOCK_END("BeingRecv::processBeingSelfEffect")
1368
        return;
1369
    }
1370
1371
    const int effectType = msg.readInt32("effect type");
1372
1373
    if (ParticleEngine::enabled)
1374
        effectManager->trigger(effectType, being);
1375
1376
    // +++ need dehard code effectType == 3
1377
    if (effectType == 3 && being->getType() == ActorType::Player
1378
        && (socialWindow != nullptr))
1379
    {   // reset received damage
1380
        socialWindow->resetDamage(being->getName());
1381
    }
1382
    BLOCK_END("BeingRecv::processBeingSelfEffect")
1383
}
1384
1385
void BeingRecv::processSkillCastCancel(Net::MessageIn &msg)
1386
{
1387
    msg.readInt32("skill id");
1388
}
1389
1390
void BeingRecv::processIpResponse(Net::MessageIn &msg)
1391
{
1392
    BLOCK_START("BeingRecv::processIpResponse")
1393
    if (actorManager == nullptr)
1394
    {
1395
        BLOCK_END("BeingRecv::processIpResponse")
1396
        return;
1397
    }
1398
1399
    Being *const dstBeing = actorManager->findBeing(
1400
        msg.readBeingId("being id"));
1401
    if (dstBeing != nullptr)
1402
    {
1403
        const std::string ip = ipToString(msg.readInt32("ip address"));
1404
        dstBeing->setIp(ip);
1405
    }
1406
    else
1407
    {
1408
        msg.readInt32("ip address");
1409
        DEBUGLOGSTR("invisible player?");
1410
    }
1411
1412
    BLOCK_END("BeingRecv::processIpResponse")
1413
}
1414
1415
void BeingRecv::processPvpSet(Net::MessageIn &msg)
1416
{
1417
    BLOCK_START("BeingRecv::processPvpSet")
1418
    const BeingId id = msg.readBeingId("being id");
1419
    const int rank = msg.readInt32("rank");
1420
    int teamId = 0;
1421
    teamId = msg.readInt32("team");
1422
    if (actorManager != nullptr)
1423
    {
1424
        Being *const dstBeing = actorManager->findBeing(id);
1425
        if (dstBeing != nullptr)
1426
        {
1427
            dstBeing->setPvpRank(rank);
1428
            dstBeing->setTeamId(CAST_U16(teamId));
1429
            dstBeing->addToCache();
1430
        }
1431
    }
1432
    BLOCK_END("BeingRecv::processPvpSet")
1433
}
1434
1435
void BeingRecv::applyPlayerAction(Net::MessageIn &msg,
1436
                                  Being *const being,
1437
                                  const uint8_t type)
1438
{
1439
    if (being == nullptr)
1440
        return;
1441
    switch (type)
1442
    {
1443
        case 0:
1444
            being->setAction(BeingAction::STAND, 0);
1445
            localPlayer->imitateAction(being, BeingAction::STAND);
1446
            break;
1447
1448
        case 1:
1449
            if (being->getCurrentAction() != BeingAction::DEAD)
1450
            {
1451
                being->setAction(BeingAction::DEAD, 0);
1452
                being->recalcSpritesOrder();
1453
            }
1454
            break;
1455
1456
        case 2:
1457
            being->setAction(BeingAction::SIT, 0);
1458
            localPlayer->imitateAction(being, BeingAction::SIT);
1459
            break;
1460
1461
        default:
1462
            UNIMPLEMENTEDPACKETFIELD(type);
1463
            break;
1464
    }
1465
}
1466
1467
void BeingRecv::processSkillDamage(Net::MessageIn &msg)
1468
{
1469
    BLOCK_START("BeingRecv::processSkillDamage")
1470
    if (actorManager == nullptr)
1471
    {
1472
        BLOCK_END("BeingRecv::processSkillDamage")
1473
        return;
1474
    }
1475
1476
    const int id = msg.readInt16("skill id");
1477
    Being *const srcBeing = actorManager->findBeing(
1478
        msg.readBeingId("src being id"));
1479
    Being *const dstBeing = actorManager->findBeing(
1480
        msg.readBeingId("dst being id"));
1481
    msg.readInt32("tick");
1482
    msg.readInt32("src speed");
1483
    msg.readInt32("dst speed");
1484
    const int param1 = msg.readInt32("damage");
1485
    const int level = msg.readInt16("skill level");
1486
    msg.readInt16("div");
1487
    msg.readUInt8("skill hit/type?");
1488
    if (srcBeing != nullptr)
1489
        srcBeing->handleSkill(dstBeing, param1, id, level);
1490
    if (dstBeing != nullptr)
1491
        dstBeing->takeDamage(srcBeing, param1, AttackType::SKILL, id, level);
1492
    BLOCK_END("BeingRecv::processSkillDamage")
1493
}
1494
1495
void BeingRecv::setServerGender(Being *const being,
1496
                                const uint8_t gender)
1497
{
1498
    if (being == nullptr)
1499
        return;
1500
    switch (gender)
1501
    {
1502
        case 2:
1503
            being->setGender(Gender::FEMALE);
1504
            break;
1505
        case 3:
1506
            being->setGender(Gender::MALE);
1507
            break;
1508
        case 4:
1509
            being->setGender(Gender::OTHER);
1510
            break;
1511
        default:
1512
            being->setGender(Gender::UNSPECIFIED);
1513
            break;
1514
    }
1515
}
1516
1517
4
}  // namespace TmwAthena