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