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