GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/being/playerinfo.cpp Lines: 37 280 13.2 %
Date: 2021-03-17 Branches: 10 210 4.8 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2010  The Mana Developers
4
 *  Copyright (C) 2011-2019  The ManaPlus Developers
5
 *  Copyright (C) 2019-2021  Andrei Karas
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 "being/playerinfo.h"
24
25
#include "configuration.h"
26
#include "itemsoundmanager.h"
27
#include "settings.h"
28
29
#include "being/localplayer.h"
30
31
#include "being/homunculusinfo.h"
32
#include "being/mercenaryinfo.h"
33
#include "being/petinfo.h"
34
35
#include "gui/windows/inventorywindow.h"
36
#include "gui/windows/npcdialog.h"
37
38
#include "listeners/statlistener.h"
39
40
#include "net/homunculushandler.h"
41
#include "net/inventoryhandler.h"
42
#include "net/mercenaryhandler.h"
43
#include "net/playerhandler.h"
44
45
#include "resources/item/item.h"
46
47
#include "utils/delete2.h"
48
49
#include "utils/translation/translationmanager.h"
50
51
#include "debug.h"
52
53
namespace PlayerInfo
54
{
55
56
1
PlayerInfoBackend mData;
57
int mCharId = 0;
58
59
Inventory *mInventory = nullptr;
60
Inventory *mCartInventory = nullptr;
61
MercenaryInfo *mMercenary = nullptr;
62
HomunculusInfo *mHomunculus = nullptr;
63
PetInfo *mPet = nullptr;
64
1
std::string mRoomName;
65
Equipment *mEquipment = nullptr;
66
BeingId mPetBeingId = BeingId_zero;
67
GuildPositionFlags::Type mGuildPositionFlags = GuildPositionFlags::None;
68
BeingId mElementalId = BeingId_zero;
69
70
Trading mTrading = Trading_false;
71
bool mVending = false;
72
int mLevelProgress = 0;
73
int mServerLanguage = -1;
74
1
std::set<int> mProtectedItems;
75
76
// --- Triggers ---------------------------------------------------------------
77
78
void triggerAttr(const AttributesT id,
79
                 const int64_t old)
80
{
81
    AttributeListener::distributeEvent(id, old,
82
        mData.mAttributes.find(id)->second);
83
}
84
85
void triggerStat(const AttributesT id,
86
                 const int old1,
87
                 const int old2)
88
{
89
188
    StatListener::distributeEvent(id, old1, old2);
90
}
91
92
// --- Attributes -------------------------------------------------------------
93
94
3
int64_t getAttribute64(const AttributesT id)
95
{
96
6
    const AtrIntMap::const_iterator it = mData.mAttributes.find(id);
97
3
    if (it != mData.mAttributes.end())
98
        return it->second;
99
    return 0;
100
}
101
102
22
int32_t getAttribute(const AttributesT id)
103
{
104
44
    const AtrIntMap::const_iterator it = mData.mAttributes.find(id);
105
22
    if (it != mData.mAttributes.end())
106
        return CAST_S32(it->second);
107
    return 0;
108
}
109
110
void setAttribute(const AttributesT id,
111
                  const int64_t value,
112
                  const Notify notify)
113
{
114
    const int64_t old = mData.mAttributes[id];
115
    mData.mAttributes[id] = value;
116
    if (notify == Notify_true)
117
        triggerAttr(id, old);
118
}
119
120
int getSkillLevel(const int id)
121
{
122
    const IntMap::const_iterator it = mData.mSkills.find(id);
123
    if (it != mData.mSkills.end())
124
        return it->second;
125
    return 0;
126
}
127
128
void setSkillLevel(const int id, const int value)
129
{
130
    mData.mSkills[id] = value;
131
}
132
133
// --- Stats ------------------------------------------------------------------
134
135
int getStatBase(const AttributesT id)
136
{
137
    const StatMap::const_iterator it = mData.mStats.find(id);
138
    if (it != mData.mStats.end())
139
        return it->second.base;
140
    return 0;
141
}
142
143
94
void setStatBase(const AttributesT id, const int value, const Notify notify)
144
{
145
94
    const int old = mData.mStats[id].base;
146
94
    mData.mStats[id].base = value;
147
94
    if (notify == Notify_true)
148
94
        triggerStat(id, old, 0);
149
94
}
150
151
int getStatMod(const AttributesT id)
152
{
153
    const StatMap::const_iterator it = mData.mStats.find(id);
154
    if (it != mData.mStats.end())
155
        return it->second.mod;
156
    return 0;
157
}
158
159
94
void setStatMod(const AttributesT id, const int value, const Notify notify)
160
{
161
94
    const int old = mData.mStats[id].mod;
162
94
    mData.mStats[id].mod = value;
163
94
    if (notify == Notify_true)
164
94
        triggerStat(id, old, 0);
165
94
}
166
167
6
int getStatEffective(const AttributesT id)
168
{
169
12
    const StatMap::const_iterator it = mData.mStats.find(id);
170
6
    if (it != mData.mStats.end())
171
        return it->second.base + it->second.mod;
172
    return 0;
173
}
174
175
const std::pair<int, int> getStatExperience(const AttributesT id)
176
{
177
    const StatMap::const_iterator it = mData.mStats.find(id);
178
    int a;
179
    int b;
180
    if (it != mData.mStats.end())
181
    {
182
        a = it->second.exp;
183
        b = it->second.expNeed;
184
    }
185
    else
186
    {
187
        a = 0;
188
        b = 0;
189
    }
190
    return std::pair<int, int>(a, b);
191
}
192
193
// --- Inventory / Equipment --------------------------------------------------
194
195
79
Inventory *getInventory()
196
{
197
79
    return mInventory;
198
}
199
200
Inventory *getStorageInventory()
201
{
202
    if (inventoryHandler != nullptr)
203
        return inventoryHandler->getStorage();
204
    return nullptr;
205
}
206
207
Inventory *getCartInventory()
208
{
209
    return mCartInventory;
210
}
211
212
215
void clearInventory()
213
{
214
215
    if (mEquipment != nullptr)
215
        mEquipment->clear();
216
215
    if (mInventory != nullptr)
217
        mInventory->clear();
218
215
}
219
220
Equipment *getEquipment()
221
{
222
    return mEquipment;
223
}
224
225
const Item *getEquipment(const unsigned int slot)
226
{
227
    if (mEquipment != nullptr)
228
        return mEquipment->getEquipment(slot);
229
    return nullptr;
230
}
231
232
void setEquipmentBackend(Equipment::Backend *const backend)
233
{
234
    if (mEquipment != nullptr)
235
        mEquipment->setBackend(backend);
236
}
237
238
void equipItem(const Item *const item, const Sfx sfx)
239
{
240
    if (sfx == Sfx_true)
241
        ItemSoundManager::playSfx(item, ItemSoundEvent::EQUIP);
242
    if (inventoryHandler != nullptr)
243
        inventoryHandler->equipItem(item);
244
}
245
246
void unequipItem(const Item *const item, const Sfx sfx)
247
{
248
    if (sfx == Sfx_true)
249
        ItemSoundManager::playSfx(item, ItemSoundEvent::UNEQUIP);
250
    if (inventoryHandler != nullptr)
251
        inventoryHandler->unequipItem(item);
252
}
253
254
void useItem(const Item *const item, const Sfx sfx)
255
{
256
    if (sfx == Sfx_true)
257
        ItemSoundManager::playSfx(item, ItemSoundEvent::USE);
258
    if (inventoryHandler != nullptr)
259
        inventoryHandler->useItem(item);
260
}
261
262
void useEquipItem(const Item *const item,
263
                  const int16_t useType,
264
                  const Sfx sfx)
265
{
266
    if (item != nullptr)
267
    {
268
        if (item->getType() == ItemType::Card)
269
        {
270
            if (mProtectedItems.find(item->getId()) == mProtectedItems.end())
271
            {
272
                if (inventoryHandler != nullptr)
273
                    inventoryHandler->useCard(item);
274
                if (sfx == Sfx_true)
275
                    ItemSoundManager::playSfx(item, ItemSoundEvent::USECARD);
276
            }
277
        }
278
        else if (item->isEquipment() == Equipm_true)
279
        {
280
            if (item->isEquipped() == Equipped_true)
281
            {
282
                if (sfx == Sfx_true)
283
                    ItemSoundManager::playSfx(item, ItemSoundEvent::UNEQUIP);
284
                if (inventoryHandler != nullptr)
285
                    inventoryHandler->unequipItem(item);
286
            }
287
            else
288
            {
289
                if (sfx == Sfx_true)
290
                    ItemSoundManager::playSfx(item, ItemSoundEvent::EQUIP);
291
                if (inventoryHandler != nullptr)
292
                    inventoryHandler->equipItem(item);
293
            }
294
        }
295
        else
296
        {
297
            if (mProtectedItems.find(item->getId()) == mProtectedItems.end())
298
            {
299
                if (inventoryHandler != nullptr)
300
                {
301
                    if (useType == 0)
302
                        inventoryHandler->useItem(item);
303
                    else
304
                        inventoryHandler->useItem(item, useType);
305
                }
306
                if (sfx == Sfx_true)
307
                    ItemSoundManager::playSfx(item, ItemSoundEvent::USE);
308
            }
309
        }
310
    }
311
}
312
313
void useEquipItem2(const Item *const item,
314
                   const int16_t useType,
315
                   const Sfx sfx)
316
{
317
    if (item != nullptr)
318
    {
319
        if (item->isEquipment() == Equipm_false)
320
        {
321
            if (item->isEquipped() == Equipped_true)
322
            {
323
                if (sfx == Sfx_true)
324
                    ItemSoundManager::playSfx(item, ItemSoundEvent::UNEQUIP);
325
                if (inventoryHandler != nullptr)
326
                    inventoryHandler->unequipItem(item);
327
            }
328
            else
329
            {
330
                if (sfx == Sfx_true)
331
                    ItemSoundManager::playSfx(item, ItemSoundEvent::EQUIP);
332
                if (inventoryHandler != nullptr)
333
                    inventoryHandler->equipItem(item);
334
            }
335
        }
336
        else
337
        {
338
            if (mProtectedItems.find(item->getId()) == mProtectedItems.end())
339
            {
340
                if (sfx == Sfx_true)
341
                    ItemSoundManager::playSfx(item, ItemSoundEvent::USE);
342
                if (inventoryHandler != nullptr)
343
                {
344
                    if (useType == 0)
345
                        inventoryHandler->useItem(item);
346
                    else
347
                        inventoryHandler->useItem(item, useType);
348
                }
349
            }
350
        }
351
    }
352
}
353
354
void dropItem(const Item *const item, const int amount, const Sfx sfx)
355
{
356
    if (item != nullptr &&
357
        mProtectedItems.find(item->getId()) == mProtectedItems.end())
358
    {
359
        if (sfx == Sfx_true)
360
            ItemSoundManager::playSfx(item, ItemSoundEvent::DROP);
361
        if (inventoryHandler != nullptr)
362
            inventoryHandler->dropItem(item, amount);
363
    }
364
}
365
366
void pickUpItem(const FloorItem *const item, const Sfx sfx)
367
{
368
    if (sfx == Sfx_true)
369
        ItemSoundManager::playSfx(item, ItemSoundEvent::PICKUP);
370
    if (playerHandler != nullptr)
371
        playerHandler->pickUp(item);
372
}
373
374
// --- Misc -------------------------------------------------------------------
375
376
void setBackend(const PlayerInfoBackend &backend)
377
{
378
    mData = backend;
379
}
380
381
void setCharId(const int charId)
382
{
383
    mCharId = charId;
384
}
385
386
int getCharId()
387
{
388
    return mCharId;
389
}
390
391
Trading isTrading()
392
{
393
    return mTrading;
394
}
395
396
void setTrading(const Trading trading)
397
{
398
    mTrading = trading;
399
}
400
401
#define updateAttackStat(atk, delay, speed) \
402
    attackDelay = getStatBase(delay); \
403
    if (attackDelay != 0) \
404
    { \
405
        setStatBase(speed, \
406
            getStatBase(atk) * 1000 / attackDelay, \
407
            Notify_false); \
408
        setStatMod(speed, \
409
            getStatMod(atk) * 1000 / attackDelay, \
410
            Notify_true); \
411
    } \
412
    else \
413
    { \
414
        setStatBase(speed, 0, \
415
            Notify_false); \
416
        setStatMod(speed, 0, \
417
            Notify_true); \
418
    }
419
420
void updateAttrs()
421
{
422
    int attackDelay;
423
    updateAttackStat(Attributes::PLAYER_ATK,
424
        Attributes::PLAYER_ATTACK_DELAY,
425
        Attributes::PLAYER_ATTACK_SPEED)
426
    updateAttackStat(Attributes::HOMUN_ATK,
427
        Attributes::HOMUN_ATTACK_DELAY,
428
        Attributes::HOMUN_ATTACK_SPEED)
429
    updateAttackStat(Attributes::MERC_ATK,
430
        Attributes::MERC_ATTACK_DELAY,
431
        Attributes::MERC_ATTACK_SPEED)
432
}
433
434
void init()
435
{
436
}
437
438
215
void deinit()
439
{
440
215
    clearInventory();
441
215
    delete2(mMercenary)
442
215
    mPetBeingId = BeingId_zero;
443
215
}
444
445
void loadData()
446
{
447
    mProtectedItems.clear();
448
    splitToIntSet(mProtectedItems,
449
        serverConfig.getStringValue("protectedItems"), ',');
450
}
451
452
void clear()
453
{
454
    mData.mSkills.clear();
455
    mPetBeingId = BeingId_zero;
456
}
457
458
bool isTalking()
459
{
460
    return NpcDialog::isActive() || InventoryWindow::isStorageActive();
461
}
462
463
void gameDestroyed()
464
{
465
    delete2(mInventory)
466
    delete2(mEquipment)
467
    delete2(mCartInventory)
468
}
469
470
void stateChange(const StateT state)
471
{
472
    if (state == State::GAME)
473
    {
474
        if (mInventory == nullptr)
475
        {
476
            mInventory = new Inventory(InventoryType::Inventory,
477
                settings.fixedInventorySize);
478
            mEquipment = new Equipment;
479
            mCartInventory = new Inventory(InventoryType::Cart, -1);
480
        }
481
    }
482
}
483
484
static void saveProtectedItems()
485
{
486
    std::string str;
487
    std::set<int>::const_iterator it = mProtectedItems.begin();
488
    std::set<int>::const_iterator it_end = mProtectedItems.end();
489
    if (it != it_end)
490
    {
491
        str.append(toString(*it));
492
        ++ it;
493
    }
494
    while (it != it_end)
495
    {
496
        str.append(",").append(toString(*it));
497
        ++ it;
498
    }
499
    serverConfig.setValue("protectedItems", str);
500
    serverConfig.write();
501
}
502
503
void protectItem(const int id)
504
{
505
    mProtectedItems.insert(id);
506
    saveProtectedItems();
507
}
508
509
void unprotectItem(const int id)
510
{
511
    mProtectedItems.erase(id);
512
    saveProtectedItems();
513
}
514
515
bool isItemProtected(const int id)
516
{
517
    return mProtectedItems.find(id) != mProtectedItems.end();
518
}
519
520
void setMercenary(MercenaryInfo *const info)
521
{
522
    delete mMercenary;
523
    mMercenary = info;
524
}
525
526
void setMercenaryBeing(Being *const being)
527
{
528
    if (being == nullptr ||
529
        mMercenary == nullptr)
530
    {
531
        return;
532
    }
533
    being->setName(mMercenary->name);
534
    being->setOwner(localPlayer);
535
    being->setLevel(mMercenary->level);
536
    being->setAttackRange(mMercenary->range);
537
}
538
539
void setElemental(const BeingId id)
540
{
541
    mElementalId = id;
542
}
543
544
BeingId getElementalId()
545
{
546
    return mElementalId;
547
}
548
549
MercenaryInfo *getMercenary()
550
{
551
    return mMercenary;
552
}
553
554
void setPet(PetInfo *const info)
555
{
556
    delete mPet;
557
    mPet = info;
558
}
559
560
void setPetBeing(Being *const being)
561
{
562
    if (being != nullptr)
563
        mPetBeingId = being->getId();
564
    else
565
        mPetBeingId = BeingId_zero;
566
    if (being == nullptr ||
567
        mPet == nullptr)
568
    {
569
        return;
570
    }
571
    being->setName(mPet->name);
572
    being->setOwner(localPlayer);
573
    being->setLevel(mPet->level);
574
}
575
576
PetInfo *getPet()
577
{
578
    return mPet;
579
}
580
581
BeingId getPetBeingId()
582
{
583
    return mPetBeingId;
584
}
585
586
void setHomunculus(HomunculusInfo *const info)
587
{
588
    delete mHomunculus;
589
    mHomunculus = info;
590
}
591
592
void setHomunculusBeing(Being *const being)
593
{
594
    if (being == nullptr ||
595
        mHomunculus == nullptr)
596
    {
597
        return;
598
    }
599
    being->setName(mHomunculus->name);
600
    being->setOwner(localPlayer);
601
}
602
603
HomunculusInfo *getHomunculus()
604
{
605
    return mHomunculus;
606
}
607
608
BeingId getHomunculusId()
609
{
610
    return mHomunculus != nullptr ? mHomunculus->id : BeingId_zero;
611
}
612
613
BeingId getMercenaryId()
614
{
615
    return mMercenary != nullptr ? mMercenary->id : BeingId_zero;
616
}
617
618
void updateAttackAi(const BeingId targetId,
619
                    const Keep keep)
620
{
621
    if (mMercenary != nullptr &&
622
        mercenaryHandler != nullptr)
623
    {
624
        mercenaryHandler->attack(targetId, keep);
625
    }
626
    if (mHomunculus != nullptr &&
627
        homunculusHandler != nullptr)
628
    {
629
        homunculusHandler->attack(targetId, keep);
630
    }
631
}
632
633
std::string getRoomName()
634
{
635
    return mRoomName;
636
}
637
638
void setRoomName(const std::string &name)
639
{
640
    mRoomName = name;
641
}
642
643
bool isInRoom()
644
{
645
    return !mRoomName.empty();
646
}
647
648
void setGuildPositionFlags(const GuildPositionFlags::Type pos)
649
{
650
    mGuildPositionFlags = pos;
651
}
652
653
GuildPositionFlags::Type getGuildPositionFlags()
654
{
655
    return mGuildPositionFlags;
656
}
657
658
void enableVending(const bool b)
659
{
660
    mVending = b;
661
}
662
663
bool isVending()
664
{
665
    return mVending;
666
}
667
668
void setServerLanguage(const int lang)
669
{
670
    if (lang != mServerLanguage)
671
    {
672
        mServerLanguage = lang;
673
        TranslationManager::loadDictionaryLang();
674
    }
675
}
676
677
int getServerLanguage()
678
{
679
    return mServerLanguage;
680
}
681
682

3
}  // namespace PlayerInfo