GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/tmwa/beingrecv.cpp Lines: 1 718 0.1 %
Date: 2018-09-20 Branches: 0 522 0.0 %

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