GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/iteminfo.cpp Lines: 85 196 43.4 %
Date: 2021-03-17 Branches: 34 150 22.7 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2019  The ManaPlus Developers
6
 *  Copyright (C) 2019-2021  Andrei Karas
7
 *
8
 *  This file is part of The ManaPlus Client.
9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or
13
 *  any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
21
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
#include "resources/iteminfo.h"
25
26
#include "const/resources/spriteaction.h"
27
28
#include "const/resources/map/map.h"
29
30
#include "enums/resources/spritedirection.h"
31
32
#include "resources/itemmenuitem.h"
33
34
#include "resources/db/colordb.h"
35
#include "resources/db/itemdb.h"
36
37
#include "utils/checkutils.h"
38
#include "utils/dtor.h"
39
#include "utils/stringutils.h"
40
41
#include "debug.h"
42
43
49
ItemInfo::ItemInfo() :
44
    mDisplay(),
45
    mMissile(),
46
    mName(),
47
    mNameEn(),
48
    mDescription(),
49
    mEffect(),
50
    mUseButton(),
51
    mUseButton2(),
52
    mType(ItemDbType::UNUSABLE),
53
    mWeight(0),
54
    mView(0),
55
    mId(0),
56
    mIsRemoveSprites(false),
57
    mSpriteToItemReplaceList(),
58
    mAttackAction(SpriteAction::INVALID),
59
    mSkyAttackAction(SpriteAction::INVALID),
60
    mWaterAttackAction(SpriteAction::INVALID),
61
    mRideAttackAction(SpriteAction::INVALID),
62
    mAttackRange(0),
63
    mMissileParticle(),
64
    mAnimationFiles(),
65
    mSounds(),
66
    mTags(),
67
    mColorsList(nullptr),
68
    mIconColorsList(nullptr),
69
    mInventoryMenu(),
70
    mStorageMenu(),
71
    mCartMenu(),
72
    mColorsListName(),
73
    mIconColorsListName(),
74
    mCardColor(ItemColor_zero),
75
    mHitEffectId(-1),
76
    mCriticalHitEffectId(-1),
77
    mMissEffectId(-1),
78
    maxFloorOffsetX(mapTileSize),
79
    maxFloorOffsetY(mapTileSize),
80
    mPickupCursor(Cursor::CURSOR_POINTER),
81
1127
    mProtected(false)
82
{
83
539
    for (int f = 0; f < 10; f ++)
84
    {
85
490
        mSpriteToItemReplaceMap[f] = nullptr;
86
490
        mDrawBefore[f] = -1;
87
490
        mDrawAfter[f] = -1;
88
490
        mDrawPriority[f] = 0;
89
    }
90
49
}
91
92
980
ItemInfo::~ItemInfo()
93
{
94
98
    delete_all(mSpriteToItemReplaceList);
95
98
    mSpriteToItemReplaceList.clear();
96
539
    for (int f = 0; f < 10; f ++)
97
490
        mSpriteToItemReplaceMap[f] = nullptr;
98
49
}
99
100
27
const std::string &ItemInfo::getSprite(const GenderT gender,
101
                                       const BeingTypeId race) const
102
{
103
27
    if (mView != 0)
104
    {
105
        // Forward the request to the item defining how to view this item
106
        return ItemDB::get(mView).getSprite(gender, race);
107
    }
108

28
    static const std::string empty;
109
    std::map<int, std::string>::const_iterator i =
110
27
        mAnimationFiles.find(CAST_S32(gender) +
111
81
        toInt(race, int) * 4);
112
113
54
    if (i != mAnimationFiles.end())
114
27
        return i->second;
115
    i = mAnimationFiles.find(CAST_S32(gender));
116
    if (i != mAnimationFiles.end())
117
        return i->second;
118
    return empty;
119
}
120
121
36
void ItemInfo::setAttackAction(const std::string &attackAction)
122
{
123
36
    if (attackAction.empty())
124
36
        mAttackAction = SpriteAction::ATTACK;  // (Equal to unarmed animation)
125
    else
126
        mAttackAction = attackAction;
127
36
}
128
129
36
void ItemInfo::setSkyAttackAction(const std::string &attackAction)
130
{
131
36
    if (attackAction.empty())
132
36
        mSkyAttackAction = SpriteAction::ATTACKSKY;
133
    else
134
        mSkyAttackAction = attackAction;
135
36
}
136
137
36
void ItemInfo::setWaterAttackAction(const std::string &attackAction)
138
{
139
36
    if (attackAction.empty())
140
36
        mWaterAttackAction = SpriteAction::ATTACKWATER;
141
    else
142
        mWaterAttackAction = attackAction;
143
36
}
144
145
36
void ItemInfo::setRideAttackAction(const std::string &attackAction)
146
{
147
36
    if (attackAction.empty())
148
36
        mRideAttackAction = SpriteAction::ATTACKRIDE;
149
    else
150
        mRideAttackAction = attackAction;
151
36
}
152
153
48
void ItemInfo::addSound(const ItemSoundEvent::Type event,
154
                        const std::string &filename, const int delay)
155
{
156
96
    mSounds[event].push_back(SoundInfo(
157
        filename,
158
48
        delay));
159
48
}
160
161
const SoundInfo &ItemInfo::getSound(const ItemSoundEvent::Type event) const
162
{
163
    static const SoundInfo empty("", 0);
164
    std::map<ItemSoundEvent::Type, SoundInfoVect>::const_iterator i;
165
166
    i = mSounds.find(event);
167
168
    if (i == mSounds.end())
169
        return empty;
170
    return (!i->second.empty()) ? i->second[CAST_U32(rand())
171
        % i->second.size()] : empty;
172
}
173
174
IntMap *ItemInfo::addReplaceSprite(const int sprite,
175
                                   const int direction)
176
{
177
    if (direction < 0 || direction >= 10)
178
        return nullptr;
179
180
    SpriteToItemMap *spMap = mSpriteToItemReplaceMap[direction];
181
182
    if (spMap == nullptr)
183
    {
184
        spMap = new SpriteToItemMap;
185
        mSpriteToItemReplaceMap[direction] = spMap;
186
        mSpriteToItemReplaceList.push_back(spMap);
187
    }
188
189
    SpriteToItemMap::iterator it = spMap->find(sprite);
190
    if (it == spMap->end())
191
    {
192
        IntMap tmp;
193
        (*mSpriteToItemReplaceMap[direction])[sprite] = tmp;
194
        it = mSpriteToItemReplaceMap[direction]->find(sprite);
195
    }
196
    return &it->second;
197
}
198
199
36
void ItemInfo::setColorsList(const std::string &name)
200
{
201
36
    if (name.empty())
202
    {
203
30
        mColorsList = nullptr;
204
30
        mColorsListName.clear();
205
    }
206
    else
207
    {
208
6
        mColorsList = ColorDB::getColorsList(name);
209
6
        mColorsListName = name;
210
    }
211
36
}
212
213
36
void ItemInfo::setIconColorsList(const std::string &name)
214
{
215
36
    if (name.empty())
216
    {
217
30
        mIconColorsList = nullptr;
218
30
        mIconColorsListName.clear();
219
    }
220
    else
221
    {
222
6
        mIconColorsList = ColorDB::getColorsList(name);
223
6
        mIconColorsListName = name;
224
    }
225
36
}
226
227
std::string ItemInfo::getDyeColorsString(const ItemColor color) const
228
{
229
    if ((mColorsList == nullptr) || mColorsListName.empty())
230
        return "";
231
232
    const std::map <ItemColor, ItemColorData>::const_iterator
233
        it = mColorsList->find(color);
234
    if (it == mColorsList->end())
235
        return "";
236
237
    return it->second.color;
238
}
239
240
2
std::string ItemInfo::getDyeIconColorsString(const ItemColor color) const
241
{
242

2
    if ((mIconColorsList == nullptr) || mIconColorsListName.empty())
243
4
        return "";
244
245
    const std::map <ItemColor, ItemColorData>::const_iterator
246
        it = mIconColorsList->find(color);
247
    if (it == mIconColorsList->end())
248
        return "";
249
250
    return it->second.color;
251
}
252
253
const std::string ItemInfo::getDescription(const ItemColor color) const
254
{
255
    return replaceColors(mDescription, color);
256
}
257
258
1
const std::string ItemInfo::getName(const ItemColor color) const
259
{
260
3
    return replaceColors(mName, color);
261
}
262
263
const std::string ItemInfo::getNameEn(const ItemColor color) const
264
{
265
    return replaceColors(mNameEn, color);
266
}
267
268
1
const std::string ItemInfo::replaceColors(std::string str,
269
                                          const ItemColor color) const
270
{
271
2
    std::string name;
272

1
    if ((mColorsList != nullptr) && !mColorsListName.empty())
273
    {
274
        const std::map <ItemColor, ItemColorData>::const_iterator
275
            it = mColorsList->find(color);
276
        if (it == mColorsList->end())
277
            name = "unknown";
278
        else
279
            name = it->second.name;
280
    }
281
    else
282
    {
283
        name = "unknown";
284
    }
285
286

5
    str = replaceAll(str, "%color%", name);
287
1
    if (!name.empty())
288
2
        name[0] = CAST_S8(toupper(name[0]));
289
290

6
    return replaceAll(str, "%Color%", name);
291
}
292
293
const SpriteToItemMap *ItemInfo::getSpriteToItemReplaceMap(const int direction)
294
                                                           const
295
{
296
    if (direction < 0 || direction >= 10)
297
        return nullptr;
298
299
    const SpriteToItemMap *const spMap = mSpriteToItemReplaceMap[direction];
300
    if (spMap != nullptr)
301
        return spMap;
302
    if (direction == SpriteDirection::UPLEFT
303
        || direction == SpriteDirection::UPRIGHT)
304
    {
305
        return mSpriteToItemReplaceMap[SpriteDirection::UP];
306
    }
307
308
    if (direction == SpriteDirection::DOWNLEFT
309
        || direction == SpriteDirection::DOWNRIGHT)
310
    {
311
        return mSpriteToItemReplaceMap[SpriteDirection::DOWN];
312
    }
313
314
    return nullptr;
315
}
316
317
108
void ItemInfo::setSpriteOrder(int *const ptr,
318
                              const int direction,
319
                              const int n,
320
                              const int def)
321
{
322

108
    switch (direction)
323
    {
324
        case -1:
325
        {
326
2268
            for (int f = 0; f < 10; f ++)
327
            {
328
1080
                if (ptr[f] == def)
329
1080
                    ptr[f] = n;
330
            }
331
            return;
332
        }
333
        case -2:
334
        {
335
            ptr[SpriteDirection::DOWN] = n;
336
            ptr[SpriteDirection::DOWNLEFT] = n;
337
            ptr[SpriteDirection::DOWNRIGHT] = n;
338
            return;
339
        }
340
        case -3:
341
        {
342
            ptr[SpriteDirection::UP] = n;
343
            ptr[SpriteDirection::UPLEFT] = n;
344
            ptr[SpriteDirection::UPRIGHT] = n;
345
            return;
346
        }
347
        default:
348
            break;
349
    }
350
    if (direction < 0 || direction >= 9)
351
        return;
352
353
    if (direction == SpriteDirection::UP)
354
    {
355
        if (ptr[SpriteDirection::UPLEFT] == def)
356
            ptr[SpriteDirection::UPLEFT] = n;
357
        if (ptr[SpriteDirection::UPRIGHT] == def)
358
            ptr[SpriteDirection::UPRIGHT] = n;
359
    }
360
    else if (direction == SpriteDirection::DOWN)
361
    {
362
        if (ptr[SpriteDirection::DOWNLEFT] == def)
363
            ptr[SpriteDirection::DOWNLEFT] = n;
364
        if (ptr[SpriteDirection::DOWNRIGHT] == def)
365
            ptr[SpriteDirection::DOWNRIGHT] = n;
366
    }
367
    ptr[direction] = n;
368
}
369
370
36
void ItemInfo::setDrawBefore(const int direction, const int n)
371
{
372
36
    setSpriteOrder(&mDrawBefore[0], direction, n, -1);
373
36
}
374
375
36
void ItemInfo::setDrawAfter(const int direction, const int n)
376
{
377
36
    setSpriteOrder(&mDrawAfter[0], direction, n, -1);
378
36
}
379
380
36
void ItemInfo::setDrawPriority(const int direction, const int n)
381
{
382
36
    setSpriteOrder(&mDrawPriority[0], direction, n, 0);
383
36
}
384
385
int ItemInfo::getDrawBefore(const int direction) const
386
{
387
    if (direction < 0 || direction >= 10)
388
        return -1;
389
    return mDrawBefore[direction];
390
}
391
392
int ItemInfo::getDrawAfter(const int direction) const
393
{
394
    if (direction < 0 || direction >= 10)
395
        return -1;
396
    return mDrawAfter[direction];
397
}
398
399
int ItemInfo::getDrawPriority(const int direction) const
400
{
401
    if (direction < 0 || direction >= 10)
402
        return 0;
403
    return mDrawPriority[direction];
404
}
405
406
87
void ItemInfo::setSprite(const std::string &animationFile,
407
                         const GenderT gender,
408
                         const int race)
409
{
410
174
    mAnimationFiles[CAST_S32(gender) + race * 4] = animationFile;
411
87
}
412
413
std::string ItemInfo::getColorName(const ItemColor idx) const
414
{
415
    if (mColorsList == nullptr)
416
        return std::string();
417
418
    const std::map <ItemColor, ItemColorData>::const_iterator
419
        it = mColorsList->find(idx);
420
    if (it == mColorsList->end())
421
    {
422
        reportAlways("Color %d for palette %s not found",
423
            CAST_S32(idx),
424
            mColorsListName.c_str())
425
        return std::string();
426
    }
427
    return it->second.name;
428
}
429
430
std::string ItemInfo::getColor(const ItemColor idx) const
431
{
432
    if (mColorsList == nullptr)
433
        return std::string();
434
435
    const std::map <ItemColor, ItemColorData>::const_iterator
436
        it = mColorsList->find(idx);
437
    if (it == mColorsList->end())
438
    {
439
        reportAlways("Color %d for palette %s not found",
440
            CAST_S32(idx),
441
            mColorsListName.c_str())
442
        return std::string();
443
    }
444
    return it->second.color;
445
}
446
447
std::string ItemInfo::getIconColorName(const ItemColor idx) const
448
{
449
    if (mIconColorsList == nullptr)
450
        return std::string();
451
452
    const std::map <ItemColor, ItemColorData>::const_iterator
453
        it = mIconColorsList->find(idx);
454
    if (it == mIconColorsList->end())
455
    {
456
        reportAlways("Color %d for palette %s not found",
457
            CAST_S32(idx),
458
            mColorsListName.c_str())
459
        return std::string();
460
    }
461
    return it->second.name;
462
}
463
464
std::string ItemInfo::getIconColor(const ItemColor idx) const
465
{
466
    if (mIconColorsList == nullptr)
467
        return std::string();
468
469
    const std::map <ItemColor, ItemColorData>::const_iterator
470
        it = mIconColorsList->find(idx);
471
    if (it == mIconColorsList->end())
472
    {
473
        reportAlways("Color %d for palette %s not found",
474
            CAST_S32(idx),
475
            mColorsListName.c_str())
476
        return std::string();
477
    }
478
    return it->second.color;
479
}
480
481
const std::string ItemInfo::getLink() const
482
{
483
    return strprintf("[@@%d|%s@@]", mId, mName.c_str());
484

3
}