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