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