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