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

3
}  // namespace PlayerInfo