GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/eathena/playerhandler.cpp Lines: 8 459 1.7 %
Date: 2021-03-17 Branches: 0 653 0.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2019  The ManaPlus Developers
6
 *  Copyright (C) 2019-2021  Andrei Karas
7
 *
8
 *  This file is part of The ManaPlus Client.
9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or
13
 *  any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
21
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
#include "net/eathena/playerhandler.h"
25
26
#include "notifymanager.h"
27
#include "party.h"
28
29
#include "being/localplayer.h"
30
#include "being/playerinfo.h"
31
32
#include "const/net/nostat.h"
33
34
#include "enums/resources/notifytypes.h"
35
36
#include "gui/windows/skilldialog.h"
37
#include "gui/windows/statuswindow.h"
38
39
#include "net/ea/inventoryhandler.h"
40
41
#include "net/eathena/messageout.h"
42
#include "net/eathena/protocolout.h"
43
#include "net/eathena/sp.h"
44
45
#include "resources/db/unitsdb.h"
46
47
#include "debug.h"
48
49
extern int packetVersion;
50
extern int packetVersionMain;
51
extern int packetVersionRe;
52
extern int packetVersionZero;
53
extern int serverVersion;
54
55
namespace EAthena
56
{
57
58
77
PlayerHandler::PlayerHandler() :
59
77
    Ea::PlayerHandler()
60
{
61
77
    playerHandler = this;
62
77
}
63
64
231
PlayerHandler::~PlayerHandler()
65
{
66
77
    playerHandler = nullptr;
67
77
}
68
69
void PlayerHandler::attack(const BeingId id,
70
                           const Keep keep) const
71
{
72
    createOutPacket(CMSG_PLAYER_CHANGE_ACT);
73
    outMsg.writeBeingId(id, "target id");
74
    if (keep == Keep_true)
75
        outMsg.writeInt8(7, "action");
76
    else
77
        outMsg.writeInt8(0, "action");
78
}
79
80
void PlayerHandler::stopAttack() const
81
{
82
    createOutPacket(CMSG_PLAYER_STOP_ATTACK);
83
}
84
85
void PlayerHandler::emote(const uint8_t emoteId) const
86
{
87
    createOutPacket(CMSG_PLAYER_EMOTE);
88
    outMsg.writeInt8(emoteId, "emote id");
89
}
90
91
void PlayerHandler::increaseAttribute(const AttributesT attr,
92
                                      const int amount) const
93
{
94
    if (attr >= Attributes::PLAYER_STR && attr <= Attributes::PLAYER_LUK)
95
    {
96
        createOutPacket(CMSG_STAT_UPDATE_REQUEST);
97
        outMsg.writeInt16(CAST_S16(attr), "attribute id");
98
        outMsg.writeInt8(CAST_S8(amount), "increase");
99
    }
100
}
101
102
void PlayerHandler::increaseSkill(const uint16_t skillId) const
103
{
104
    if (PlayerInfo::getAttribute(Attributes::PLAYER_SKILL_POINTS) <= 0)
105
        return;
106
107
    createOutPacket(CMSG_SKILL_LEVELUP_REQUEST);
108
    outMsg.writeInt16(skillId, "skill id");
109
}
110
111
void PlayerHandler::pickUp(const FloorItem *const floorItem) const
112
{
113
    if (floorItem == nullptr)
114
        return;
115
116
    createOutPacket(CMSG_ITEM_PICKUP);
117
    const BeingId id = floorItem->getId();
118
    if (packetVersion >= 20101124)
119
    {
120
        outMsg.writeBeingId(id, "object id");
121
    }
122
    else if (packetVersion >= 20080827)
123
    {
124
        outMsg.writeInt32(0, "unused");
125
        outMsg.writeInt8(0, "unused");
126
        outMsg.writeBeingId(id, "object id");
127
    }
128
    else if (packetVersion >= 20070212)
129
    {
130
        outMsg.writeInt32(0, "unused");
131
        outMsg.writeBeingId(id, "object id");
132
    }
133
    else if (packetVersion >= 20070108)
134
    {
135
        outMsg.writeInt32(0, "unused");
136
        outMsg.writeInt8(0, "unused");
137
        outMsg.writeBeingId(id, "object id");
138
    }
139
    else if (packetVersion >= 20050719)
140
    {
141
        outMsg.writeInt32(0, "unused");
142
        outMsg.writeInt16(0, "unused");
143
        outMsg.writeInt8(0, "unused");
144
        outMsg.writeBeingId(id, "object id");
145
    }
146
    else if (packetVersion >= 20050718)
147
    {
148
        outMsg.writeInt8(0, "unused");
149
        outMsg.writeBeingId(id, "object id");
150
    }
151
    else if (packetVersion >= 20050628)
152
    {
153
        outMsg.writeInt32(0, "unused");
154
        outMsg.writeInt8(0, "unused");
155
        outMsg.writeBeingId(id, "object id");
156
    }
157
    else if (packetVersion >= 20050509)
158
    {
159
        outMsg.writeInt16(0, "unused");
160
        outMsg.writeBeingId(id, "object id");
161
    }
162
    else if (packetVersion >= 20050110)
163
    {
164
        outMsg.writeInt16(0, "unused");
165
        outMsg.writeInt8(0, "unused");
166
        outMsg.writeBeingId(id, "object id");
167
    }
168
    else if (packetVersion >= 20041129)
169
    {
170
        outMsg.writeInt8(0, "unused");
171
        outMsg.writeBeingId(id, "object id");
172
    }
173
    else if (packetVersion >= 20041025)
174
    {
175
        outMsg.writeInt16(0, "unused");
176
        outMsg.writeInt8(0, "unused");
177
        outMsg.writeBeingId(id, "object id");
178
    }
179
    else if (packetVersion >= 20041005)
180
    {
181
        outMsg.writeInt32(0, "unused");
182
        outMsg.writeBeingId(id, "object id");
183
    }
184
    else if (packetVersion >= 20040920)
185
    {
186
        outMsg.writeInt32(0, "unused");
187
        outMsg.writeInt32(0, "unused");
188
        outMsg.writeBeingId(id, "object id");
189
    }
190
    else if (packetVersion >= 20040906)
191
    {
192
        outMsg.writeInt32(0, "unused");
193
        outMsg.writeInt8(0, "unused");
194
        outMsg.writeBeingId(id, "object id");
195
    }
196
    else if (packetVersion >= 20040809)
197
    {
198
        outMsg.writeInt32(0, "unused");
199
        outMsg.writeInt16(0, "unused");
200
        outMsg.writeInt8(0, "unused");
201
        outMsg.writeBeingId(id, "object id");
202
    }
203
    else if (packetVersion >= 20040713)
204
    {
205
        outMsg.writeInt32(0, "unused");
206
        outMsg.writeBeingId(id, "object id");
207
    }
208
    else
209
    {
210
        outMsg.writeBeingId(id, "object id");
211
    }
212
213
    Ea::InventoryHandler::pushPickup(floorItem->getId());
214
}
215
216
void PlayerHandler::setDirection(const unsigned char direction) const
217
{
218
    createOutPacket(CMSG_PLAYER_CHANGE_DIR);
219
    if (packetVersion >= 20101124)
220
    {
221
        outMsg.writeInt8(0, "head direction");
222
        outMsg.writeInt8(0, "unused");
223
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
224
            "player direction");
225
    }
226
    else if (packetVersion >= 20080827)
227
    {
228
        outMsg.writeInt16(0, "unused");
229
        outMsg.writeInt8(0, "head direction");
230
        outMsg.writeInt32(0, "unused");
231
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
232
            "player direction");
233
    }
234
    else if (packetVersion >= 20070212)
235
    {
236
        outMsg.writeInt32(0, "unused");
237
        outMsg.writeInt16(0, "unused");
238
        outMsg.writeInt8(0, "head direction");
239
        outMsg.writeInt16(0, "unused");
240
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
241
            "player direction");
242
    }
243
    else if (packetVersion >= 20070108)
244
    {
245
        outMsg.writeInt32(0, "unused");
246
        outMsg.writeInt32(0, "unused");
247
        outMsg.writeInt8(0, "head direction");
248
        outMsg.writeInt16(0, "unused");
249
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
250
            "player direction");
251
    }
252
    else if (packetVersion >= 20060327)
253
    {
254
        outMsg.writeInt32(0, "unused");
255
        outMsg.writeInt8(0, "unused");
256
        outMsg.writeInt8(0, "head direction");
257
        outMsg.writeInt8(0, "unused");
258
        outMsg.writeInt16(0, "unused");
259
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
260
            "player direction");
261
    }
262
    else if (packetVersion >= 20050719)
263
    {
264
        outMsg.writeInt32(0, "unused");
265
        outMsg.writeInt16(0, "unused");
266
        outMsg.writeInt8(0, "head direction");
267
        outMsg.writeInt8(0, "unused");
268
        outMsg.writeInt32(0, "unused");
269
        outMsg.writeInt16(0, "unused");
270
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
271
            "player direction");
272
    }
273
    else if (packetVersion >= 20050718)
274
    {
275
        outMsg.writeInt32(0, "unused");
276
        outMsg.writeInt8(0, "head direction");
277
        outMsg.writeInt8(0, "unused");
278
        outMsg.writeInt16(0, "unused");
279
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
280
            "player direction");
281
    }
282
    else if (packetVersion >= 20050628)
283
    {
284
        outMsg.writeInt32(0, "unused");
285
        outMsg.writeInt16(0, "unused");
286
        outMsg.writeInt8(0, "head direction");
287
        outMsg.writeInt8(0, "unused");
288
        outMsg.writeInt32(0, "unused");
289
        outMsg.writeInt16(0, "unused");
290
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
291
            "player direction");
292
    }
293
    else if (packetVersion >= 20050509)
294
    {
295
        outMsg.writeInt8(0, "unused");
296
        outMsg.writeInt32(0, "unused");
297
        outMsg.writeInt16(0, "unused");
298
        outMsg.writeInt8(0, "head direction");
299
        outMsg.writeInt8(0, "unused");
300
        outMsg.writeInt16(0, "unused");
301
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
302
            "player direction");
303
    }
304
    else if (packetVersion >= 20050110)
305
    {
306
        outMsg.writeInt32(0, "unused");
307
        outMsg.writeInt32(0, "unused");
308
        outMsg.writeInt16(0, "unused");
309
        outMsg.writeInt8(0, "head direction");
310
        outMsg.writeInt8(0, "unused");
311
        outMsg.writeInt32(0, "unused");
312
        outMsg.writeInt32(0, "unused");
313
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
314
            "player direction");
315
    }
316
    else if (packetVersion >= 20041129)
317
    {
318
        outMsg.writeInt8(0, "unused");
319
        outMsg.writeInt8(0, "head direction");
320
        outMsg.writeInt8(0, "unused");
321
        outMsg.writeInt16(0, "unused");
322
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
323
            "player direction");
324
    }
325
    else if (packetVersion >= 20041025)
326
    {
327
        outMsg.writeInt32(0, "unused");
328
        outMsg.writeInt8(0, "head direction");
329
        outMsg.writeInt8(0, "unused");
330
        outMsg.writeInt32(0, "unused");
331
        outMsg.writeInt16(0, "unused");
332
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
333
            "player direction");
334
    }
335
    else if (packetVersion >= 20041005)
336
    {
337
        outMsg.writeInt16(0, "unused");
338
        outMsg.writeInt8(0, "unused");
339
        outMsg.writeInt8(0, "head direction");
340
        outMsg.writeInt32(0, "unused");
341
        outMsg.writeInt16(0, "unused");
342
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
343
            "player direction");
344
    }
345
    else if (packetVersion >= 20040920)
346
    {
347
        outMsg.writeInt32(0, "unused");
348
        outMsg.writeInt16(0, "unused");
349
        outMsg.writeInt8(0, "head direction");
350
        outMsg.writeInt32(0, "unused");
351
        outMsg.writeInt32(0, "unused");
352
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
353
            "player direction");
354
    }
355
    else if (packetVersion >= 20040906)
356
    {
357
        outMsg.writeInt16(0, "unused");
358
        outMsg.writeInt8(0, "head direction");
359
        outMsg.writeInt16(0, "unused");
360
        outMsg.writeInt16(0, "unused");
361
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
362
            "player direction");
363
    }
364
    else if (packetVersion >= 20040809)
365
    {
366
        outMsg.writeInt16(0, "unused");
367
        outMsg.writeInt16(0, "unused");
368
        outMsg.writeInt8(0, "unused");
369
        outMsg.writeInt8(0, "head direction");
370
        outMsg.writeInt16(0, "unused");
371
        outMsg.writeInt8(0, "unused");
372
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
373
            "player direction");
374
    }
375
    else if (packetVersion >= 20040713)
376
    {
377
        outMsg.writeInt8(0, "unused");
378
        outMsg.writeInt8(0, "unused");
379
        outMsg.writeInt8(0, "unused");
380
        outMsg.writeInt8(0, "head direction");
381
        outMsg.writeInt16(0, "unused");
382
        outMsg.writeInt16(0, "unused");
383
        outMsg.writeInt16(0, "unused");
384
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
385
            "player direction");
386
    }
387
    else
388
    {
389
        outMsg.writeInt8(0, "head direction");
390
        outMsg.writeInt8(0, "unused");
391
        outMsg.writeInt8(MessageOut::toServerDirection(direction),
392
            "player direction");
393
    }
394
}
395
396
void PlayerHandler::setDestination(const int x, const int y,
397
                                   const int direction) const
398
{
399
    createOutPacket(CMSG_PLAYER_CHANGE_DEST);
400
    if (packetVersion >= 20080827 && packetVersion < 20101124)
401
        outMsg.writeInt32(0, "unused");
402
    outMsg.writeCoordinates(CAST_U16(x),
403
        CAST_U16(y),
404
        CAST_U8(direction), "destination");
405
}
406
407
void PlayerHandler::changeAction(const BeingActionT &action) const
408
{
409
    unsigned char type;
410
    switch (action)
411
    {
412
        case BeingAction::SIT:
413
            type = 2;
414
            break;
415
        case BeingAction::STAND:
416
        case BeingAction::PRESTAND:
417
            type = 3;
418
            break;
419
        default:
420
        case BeingAction::MOVE:
421
        case BeingAction::ATTACK:
422
        case BeingAction::DEAD:
423
        case BeingAction::HURT:
424
        case BeingAction::SPAWN:
425
        case BeingAction::CAST:
426
            return;
427
    }
428
429
    createOutPacket(CMSG_PLAYER_CHANGE_ACT);
430
    outMsg.writeInt32(0, "unused");
431
    outMsg.writeInt8(type, "action");
432
}
433
434
void PlayerHandler::respawn() const
435
{
436
    createOutPacket(CMSG_PLAYER_RESTART);
437
    outMsg.writeInt8(0, "action");
438
}
439
440
void PlayerHandler::requestOnlineList() const
441
{
442
    createOutPacket(CMSG_ONLINE_LIST);
443
}
444
445
void PlayerHandler::updateStatus(const uint8_t status) const
446
{
447
    createOutPacket(CMSG_SET_STATUS);
448
    outMsg.writeInt8(status, "status");
449
    outMsg.writeInt8(0, "unused");
450
}
451
452
void PlayerHandler::setShortcut(const int idx,
453
                                const int tab,
454
                                const uint8_t type,
455
                                const int id,
456
                                const int level) const
457
{
458
    createOutPacket(CMSG_SET_SHORTCUTS);
459
    if (packetVersionMain >= 20190522 ||
460
        packetVersionRe >= 20190508 ||
461
        packetVersionZero >= 20190605)
462
    {
463
        outMsg.writeInt16(CAST_S16(tab), "tab");
464
    }
465
    outMsg.writeInt16(CAST_S16(idx), "index");
466
    outMsg.writeInt8(CAST_S8(type), "type");
467
    outMsg.writeInt32(id, "id");
468
    outMsg.writeInt16(CAST_S16(level), "level");
469
}
470
471
void PlayerHandler::shortcutShiftRow(const int row,
472
                                     const int tab) const
473
{
474
    if (packetVersion < 20140129)
475
        return;
476
    createOutPacket(CMSG_SHORTCUTS_ROW_SHIFT);
477
    if (packetVersionMain >= 20190522 ||
478
        packetVersionRe >= 20190508 ||
479
        packetVersionZero >= 20190605)
480
    {
481
        outMsg.writeInt16(CAST_S16(tab), "tab");
482
    }
483
    outMsg.writeInt8(CAST_S8(row), "row");
484
}
485
486
void PlayerHandler::removeOption() const
487
{
488
    createOutPacket(CMSG_REMOVE_OPTION);
489
}
490
491
void PlayerHandler::changeCart(const int type) const
492
{
493
    createOutPacket(CMSG_CHANGE_CART);
494
    outMsg.writeInt16(CAST_S16(type), "type");
495
}
496
497
void PlayerHandler::setMemo() const
498
{
499
    createOutPacket(CMSG_PLAYER_SET_MEMO);
500
}
501
502
void PlayerHandler::doriDori() const
503
{
504
    createOutPacket(CMSG_DORI_DORI);
505
}
506
507
void PlayerHandler::explosionSpirits() const
508
{
509
    createOutPacket(CMSG_EXPLOSION_SPIRITS);
510
}
511
512
void PlayerHandler::requestPvpInfo() const
513
{
514
    createOutPacket(CMSG_PVP_INFO);
515
    outMsg.writeInt32(0, "char id");
516
    outMsg.writeInt32(0, "account id");
517
}
518
519
void PlayerHandler::revive() const
520
{
521
    createOutPacket(CMSG_PLAYER_AUTO_REVIVE);
522
}
523
524
void PlayerHandler::setConfigOption(const int id,
525
                                    const int data) const
526
{
527
    createOutPacket(CMSG_SET_CONFIG_OPTION);
528
    outMsg.writeInt32(id, "config option");
529
    outMsg.writeInt32(data, "config data");
530
}
531
532
#define setStatComplex(stat) \
533
    PlayerInfo::setStatBase(stat, CAST_S32(base), notify); \
534
    if (mod != NoStat) \
535
        PlayerInfo::setStatMod(stat, mod, Notify_true)
536
537
void PlayerHandler::setStat(Net::MessageIn &msg,
538
                            const int type,
539
                            const int64_t base,
540
                            const int mod,
541
                            const Notify notify) const
542
{
543
    switch (type)
544
    {
545
        case Sp::SPEED:
546
            localPlayer->setWalkSpeed(CAST_S32(base));
547
            PlayerInfo::setStatBase(Attributes::PLAYER_WALK_SPEED,
548
                CAST_S32(base),
549
                Notify_true);
550
            PlayerInfo::setStatMod(Attributes::PLAYER_WALK_SPEED,
551
                0,
552
                Notify_true);
553
            break;
554
        case Sp::BASEEXP:
555
            PlayerInfo::setAttribute(Attributes::PLAYER_EXP,
556
                base,
557
                Notify_true);
558
            break;
559
        case Sp::JOBEXP:
560
            PlayerInfo::setAttribute(Attributes::PLAYER_JOB_EXP,
561
                base,
562
                Notify_true);
563
            break;
564
        case Sp::KARMA:
565
            PlayerInfo::setStatBase(Attributes::PLAYER_KARMA,
566
                CAST_S32(base),
567
                Notify_true);
568
            PlayerInfo::setStatMod(Attributes::PLAYER_KARMA,
569
                0,
570
                Notify_true);
571
            break;
572
        case Sp::MANNER:
573
            PlayerInfo::setStatBase(Attributes::PLAYER_MANNER,
574
                CAST_S32(base),
575
                Notify_true);
576
            PlayerInfo::setStatMod(Attributes::PLAYER_MANNER,
577
                0,
578
                Notify_true);
579
            break;
580
        case Sp::HP:
581
            PlayerInfo::setAttribute(Attributes::PLAYER_HP,
582
                base,
583
                Notify_true);
584
            if (localPlayer->isInParty() && (Party::getParty(1) != nullptr))
585
            {
586
                PartyMember *const m = Party::getParty(1)
587
                    ->getMember(localPlayer->getId());
588
                if (m != nullptr)
589
                {
590
                    m->setHp(CAST_S32(base));
591
                    m->setMaxHp(PlayerInfo::getAttribute(
592
                        Attributes::PLAYER_MAX_HP));
593
                }
594
            }
595
            break;
596
        case Sp::MAXHP:
597
            PlayerInfo::setAttribute(Attributes::PLAYER_MAX_HP,
598
                base,
599
                Notify_true);
600
601
            if (localPlayer->isInParty() && (Party::getParty(1) != nullptr))
602
            {
603
                PartyMember *const m = Party::getParty(1)->getMember(
604
                    localPlayer->getId());
605
                if (m != nullptr)
606
                {
607
                    m->setHp(PlayerInfo::getAttribute(Attributes::PLAYER_HP));
608
                    m->setMaxHp(CAST_S32(base));
609
                }
610
            }
611
            break;
612
        case Sp::SP:
613
            PlayerInfo::setAttribute(Attributes::PLAYER_MP,
614
                base,
615
                Notify_true);
616
            break;
617
        case Sp::MAXSP:
618
            PlayerInfo::setAttribute(Attributes::PLAYER_MAX_MP,
619
                base,
620
                Notify_true);
621
            break;
622
        case Sp::STATUSPOINT:
623
            PlayerInfo::setAttribute(Attributes::PLAYER_CHAR_POINTS,
624
                base,
625
                Notify_true);
626
            break;
627
        case Sp::BASELEVEL:
628
            PlayerInfo::setAttribute(Attributes::PLAYER_BASE_LEVEL,
629
                base,
630
                Notify_true);
631
            if (localPlayer != nullptr)
632
            {
633
                localPlayer->setLevel(CAST_S32(base));
634
                localPlayer->updateName();
635
            }
636
            break;
637
        case Sp::SKILLPOINT:
638
            PlayerInfo::setAttribute(Attributes::PLAYER_SKILL_POINTS,
639
                base,
640
                Notify_true);
641
            if (skillDialog != nullptr)
642
                skillDialog->update();
643
            break;
644
        case Sp::STR:
645
            setStatComplex(Attributes::PLAYER_STR);
646
            break;
647
        case Sp::AGI:
648
            setStatComplex(Attributes::PLAYER_AGI);
649
            break;
650
        case Sp::VIT:
651
            setStatComplex(Attributes::PLAYER_VIT);
652
            break;
653
        case Sp::INT:
654
            setStatComplex(Attributes::PLAYER_INT);
655
            break;
656
        case Sp::DEX:
657
            setStatComplex(Attributes::PLAYER_DEX);
658
            break;
659
        case Sp::LUK:
660
            setStatComplex(Attributes::PLAYER_LUK);
661
            break;
662
        case Sp::ZENY:
663
        {
664
            const int oldMoney = PlayerInfo::getAttribute(Attributes::MONEY);
665
            const int newMoney = CAST_S32(base);
666
            if (newMoney > oldMoney)
667
            {
668
                NotifyManager::notify(NotifyTypes::MONEY_GET,
669
                    UnitsDb::formatCurrency(newMoney - oldMoney));
670
            }
671
            else if (newMoney < oldMoney)
672
            {
673
                NotifyManager::notify(NotifyTypes::MONEY_SPENT,
674
                    UnitsDb::formatCurrency(oldMoney - newMoney).c_str());
675
            }
676
677
            PlayerInfo::setAttribute(Attributes::MONEY,
678
                newMoney,
679
                Notify_true);
680
            break;
681
        }
682
        case Sp::NEXTBASEEXP:
683
            PlayerInfo::setAttribute(Attributes::PLAYER_EXP_NEEDED,
684
                base,
685
                Notify_true);
686
            break;
687
        case Sp::NEXTJOBEXP:
688
            PlayerInfo::setAttribute(Attributes::PLAYER_JOB_EXP_NEEDED,
689
                base,
690
                Notify_true);
691
            break;
692
        case Sp::WEIGHT:
693
            PlayerInfo::setAttribute(Attributes::TOTAL_WEIGHT,
694
                base,
695
                Notify_true);
696
            break;
697
        case Sp::MAXWEIGHT:
698
            PlayerInfo::setAttribute(Attributes::MAX_WEIGHT,
699
                base,
700
                Notify_true);
701
            break;
702
        case Sp::USTR:
703
            statusWindow->setPointsNeeded(Attributes::PLAYER_STR,
704
                CAST_S32(base));
705
            break;
706
        case Sp::UAGI:
707
            statusWindow->setPointsNeeded(Attributes::PLAYER_AGI,
708
                CAST_S32(base));
709
            break;
710
        case Sp::UVIT:
711
            statusWindow->setPointsNeeded(Attributes::PLAYER_VIT,
712
                CAST_S32(base));
713
            break;
714
        case Sp::UINT:
715
            statusWindow->setPointsNeeded(Attributes::PLAYER_INT,
716
                CAST_S32(base));
717
            break;
718
        case Sp::UDEX:
719
            statusWindow->setPointsNeeded(Attributes::PLAYER_DEX,
720
                CAST_S32(base));
721
            break;
722
        case Sp::ULUK:
723
            statusWindow->setPointsNeeded(Attributes::PLAYER_LUK,
724
                CAST_S32(base));
725
            break;
726
727
        case Sp::ATK1:
728
            PlayerInfo::setStatBase(Attributes::PLAYER_ATK,
729
                CAST_S32(base),
730
                Notify_true);
731
            PlayerInfo::updateAttrs();
732
            break;
733
        case Sp::ATK2:
734
            PlayerInfo::setStatMod(Attributes::PLAYER_ATK,
735
                CAST_S32(base),
736
                Notify_true);
737
            PlayerInfo::updateAttrs();
738
            break;
739
        case Sp::MATK1:
740
            PlayerInfo::setStatBase(Attributes::PLAYER_MATK,
741
                CAST_S32(base),
742
                Notify_true);
743
            break;
744
        case Sp::MATK2:
745
            PlayerInfo::setStatMod(Attributes::PLAYER_MATK,
746
                CAST_S32(base),
747
                Notify_true);
748
            break;
749
        case Sp::DEF1:
750
            PlayerInfo::setStatBase(Attributes::PLAYER_DEF,
751
                CAST_S32(base),
752
                Notify_true);
753
            break;
754
        case Sp::DEF2:
755
            PlayerInfo::setStatMod(Attributes::PLAYER_DEF,
756
                CAST_S32(base),
757
                Notify_true);
758
            break;
759
        case Sp::MDEF1:
760
            PlayerInfo::setStatBase(Attributes::PLAYER_MDEF,
761
                CAST_S32(base),
762
                Notify_true);
763
            break;
764
        case Sp::MDEF2:
765
            PlayerInfo::setStatMod(Attributes::PLAYER_MDEF,
766
                CAST_S32(base),
767
                Notify_true);
768
            break;
769
        case Sp::HIT:
770
            PlayerInfo::setStatBase(Attributes::PLAYER_HIT,
771
                CAST_S32(base),
772
                Notify_true);
773
            break;
774
        case Sp::FLEE1:
775
            PlayerInfo::setStatBase(Attributes::PLAYER_FLEE,
776
                CAST_S32(base),
777
                Notify_true);
778
            break;
779
        case Sp::FLEE2:
780
            PlayerInfo::setStatMod(Attributes::PLAYER_FLEE,
781
                CAST_S32(base),
782
                Notify_true);
783
            break;
784
        case Sp::CRITICAL:
785
            PlayerInfo::setStatBase(Attributes::PLAYER_CRIT,
786
                CAST_S32(base),
787
                Notify_true);
788
            break;
789
        case Sp::ASPD:
790
            localPlayer->setAttackSpeed(CAST_S32(base));
791
            PlayerInfo::setStatBase(Attributes::PLAYER_ATTACK_DELAY,
792
                CAST_S32(base),
793
                Notify_true);
794
            PlayerInfo::setStatMod(Attributes::PLAYER_ATTACK_DELAY,
795
                0,
796
                Notify_true);
797
            PlayerInfo::updateAttrs();
798
            break;
799
        case Sp::JOBLEVEL:
800
            PlayerInfo::setAttribute(Attributes::PLAYER_JOB_LEVEL,
801
                base,
802
                Notify_true);
803
            break;
804
805
        default:
806
            UNIMPLEMENTEDPACKETFIELD(type);
807
            break;
808
    }
809
}
810
811
void PlayerHandler::selectStyle(const int headColor,
812
                                const int headStyle,
813
                                const int bodyColor,
814
                                const int topStyle,
815
                                const int middleStyle,
816
                                const int bottomStyle,
817
                                const int bodyStyle) const
818
{
819
    if (packetVersion < 20151104)
820
        return;
821
    if (packetVersionMain >= 20180516 ||
822
        packetVersionRe >= 20180516 ||
823
        packetVersionZero >= 20180523)
824
    {
825
        createOutPacket(CMSG_PLAYER_SELECT_STYLE2);
826
        outMsg.writeInt16(CAST_S16(headColor), "head color");
827
        outMsg.writeInt16(CAST_S16(headStyle), "head style");
828
        outMsg.writeInt16(CAST_S16(bodyColor), "body color");
829
        outMsg.writeInt16(CAST_S16(topStyle), "top style");
830
        outMsg.writeInt16(CAST_S16(middleStyle), "middle style");
831
        outMsg.writeInt16(CAST_S16(bottomStyle), "bottom style");
832
        outMsg.writeInt16(CAST_S16(bodyStyle), "body style");
833
    }
834
    else
835
    {
836
        createOutPacket(CMSG_PLAYER_SELECT_STYLE);
837
        outMsg.writeInt16(CAST_S16(headColor), "head color");
838
        outMsg.writeInt16(CAST_S16(headStyle), "head style");
839
        outMsg.writeInt16(CAST_S16(bodyColor), "body color");
840
        outMsg.writeInt16(CAST_S16(topStyle), "top style");
841
        outMsg.writeInt16(CAST_S16(middleStyle), "middle style");
842
        outMsg.writeInt16(CAST_S16(bottomStyle), "bottom style");
843
    }
844
}
845
846
void PlayerHandler::setTitle(const int titleId) const
847
{
848
    if (packetVersion < 20140903)
849
        return;
850
    createOutPacket(CMSG_PLAYER_SET_TITLE);
851
    outMsg.writeInt32(titleId, "title");
852
}
853
854
void PlayerHandler::closeStyleWindow() const
855
{
856
    if (packetVersion < 20151104)
857
        return;
858
    createOutPacket(CMSG_PLAYER_STYLE_CLOSE);
859
}
860
861
#undef setStatComplex
862
863
2
}  // namespace EAthena