GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/equipmentwindow.cpp Lines: 130 447 29.1 %
Date: 2021-03-17 Branches: 86 428 20.1 %

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 "gui/windows/equipmentwindow.h"
25
26
#include "configuration.h"
27
#include "dragdrop.h"
28
29
#include "being/localplayer.h"
30
#include "being/playerinfo.h"
31
32
#include "gui/fonts/font.h"
33
34
#include "gui/popups/popupmenu.h"
35
#include "gui/popups/itempopup.h"
36
37
#include "gui/windows/setupwindow.h"
38
39
#include "gui/widgets/button.h"
40
#include "gui/widgets/equipmentbox.h"
41
#include "gui/widgets/equipmentpage.h"
42
#include "gui/widgets/playerbox.h"
43
#include "gui/widgets/tabstrip.h"
44
45
#include "render/vertexes/imagecollection.h"
46
47
#include "resources/imageset.h"
48
49
#include "utils/checkutils.h"
50
#include "utils/delete2.h"
51
#include "utils/dtor.h"
52
#include "utils/foreach.h"
53
#include "utils/gettext.h"
54
55
#include "net/inventoryhandler.h"
56
57
#include "debug.h"
58
59
EquipmentWindow *equipmentWindow = nullptr;
60
EquipmentWindow *beingEquipmentWindow = nullptr;
61
static const int BOX_COUNT = 27;
62
1
StringIntMap EquipmentWindow::mSlotNames;
63
64
1
EquipmentWindow::EquipmentWindow(Equipment *const equipment,
65
                                 Being *const being,
66
1
                                 const bool foring) :
67
    // TRANSLATORS: equipment window name
68
1
    Window(_("Equipment"), Modal_false, nullptr, "equipment.xml"),
69
    ActionListener(),
70
    mEquipment(equipment),
71
    mPlayerBox(new PlayerBox(this,
72
        "equipment_playerbox.xml",
73

1
        "equipment_selectedplayerbox.xml")),
74
    // TRANSLATORS: equipment window button
75

2
    mUnequip(new Button(this, _("Unequip"), "unequip", BUTTON_SKIN, this)),
76
    mImageSet(nullptr),
77
    mBeing(being),
78
    mSlotBackground(),
79
    mSlotHighlightedBackground(),
80

1
    mVertexes(new ImageCollection),
81
    mPages(),
82
    mTabs(nullptr),
83
2
    mHighlightColor(getThemeColor(ThemeColorId::HIGHLIGHT, 255U)),
84
2
    mBorderColor(getThemeColor(ThemeColorId::BORDER, 255U)),
85
2
    mLabelsColor(getThemeColor(ThemeColorId::LABEL, 255U)),
86
2
    mLabelsColor2(getThemeColor(ThemeColorId::LABEL_OUTLINE, 255U)),
87
    mSelected(-1),
88

4
    mItemPadding(getOption("itemPadding", 0)),
89

4
    mBoxSize(getOption("boxSize", 0)),
90

4
    mButtonPadding(getOption("buttonPadding", 5)),
91
    mMinX(180),
92
    mMinY(345),
93
    mMaxX(0),
94
    mMaxY(0),
95
    mYPadding(0),
96
    mSelectedTab(0),
97
    mForing(foring),
98



32
    mHaveDefaultPage(false)
99
{
100

4
    const int size = config.getIntValue("fontSize")
101

4
        + getOption("tabHeightAdjust", 16);
102

4
    mTabs = new TabStrip(this, "equipment", size, 0);
103
1
    mTabs->addActionListener(this);
104
5
    mTabs->setActionEventId("tab_");
105
2
    mTabs->setSelectable(false);
106
107

5
    mYPadding = mTabs->getHeight() + getOption("tabPadding", 2);
108
109
1
    if (setupWindow != nullptr)
110
        setupWindow->registerWindowForReset(this);
111
112
1
    if (mBoxSize == 0)
113
        mBoxSize = 36;
114
115
    // Control that shows the Player
116
2
    mPlayerBox->setDimension(Rect(50, 80 + mYPadding, 74, 168));
117
2
    mPlayerBox->setPlayer(being);
118
2
    mPlayerBox->setSelectable(false);
119
120
1
    if (foring)
121
        setWindowName("Being equipment");
122
    else
123
5
        setWindowName("Equipment");
124
125
1
    setCloseButton(true);
126
2
    setSaveVisible(true);
127
1
    setStickyButtonLock(true);
128
129
1
    fillBoxes();
130
1
    recalcSize();
131
1
    updatePage();
132
1
    loadWindowState();
133
1
}
134
135
1
void EquipmentWindow::postInit()
136
{
137
1
    Window::postInit();
138
2
    const Rect &area = getChildrenArea();
139
2
    mUnequip->setPosition(area.width  - mUnequip->getWidth() - mButtonPadding,
140
3
        area.height - mUnequip->getHeight() - mButtonPadding);
141
2
    mUnequip->setEnabled(false);
142
143
1
    ImageRect rect;
144

7
    theme->loadRect(rect, "equipment_background.xml", "", 0, 1);
145
1
    mSlotBackground = rect.grid[0];
146
1
    mSlotHighlightedBackground = rect.grid[1];
147
1
    add(mTabs);
148
1
    add(mPlayerBox);
149
1
    add(mUnequip);
150
2
    enableVisibleSound(true);
151
5
    mPlayerBox->setActionEventId("playerbox");
152
1
    mPlayerBox->addActionListener(this);
153
1
}
154
155
5
EquipmentWindow::~EquipmentWindow()
156
{
157
1
    if (this == beingEquipmentWindow)
158
    {
159
        if (mEquipment != nullptr)
160
            delete mEquipment->getBackend();
161
        delete2(mEquipment)
162
    }
163
6
    FOR_EACH (STD_VECTOR<EquipmentPage*>::iterator, it, mPages)
164
    {
165
2
        STD_VECTOR<EquipmentBox*> &boxes = (*it)->boxes;
166
2
        delete_all(boxes);
167
2
        boxes.clear();
168
4
        delete *it;
169
    }
170
1
    if (mImageSet != nullptr)
171
    {
172
1
        mImageSet->decRef();
173
1
        mImageSet = nullptr;
174
    }
175
1
    if (mSlotBackground != nullptr)
176
1
        mSlotBackground->decRef();
177
1
    if (mSlotHighlightedBackground != nullptr)
178
1
        mSlotHighlightedBackground->decRef();
179
1
    delete2(mVertexes)
180
2
}
181
182
void EquipmentWindow::draw(Graphics *const graphics)
183
{
184
    BLOCK_START("EquipmentWindow::draw")
185
    // Draw window graphics
186
    Window::draw(graphics);
187
188
    int i = 0;
189
    Font *const font = getFont();
190
    const int fontHeight = font->getHeight();
191
    const STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
192
193
    if (mLastRedraw)
194
    {
195
        mVertexes->clear();
196
        FOR_EACH (STD_VECTOR<EquipmentBox*>::const_iterator, it, boxes)
197
        {
198
            const EquipmentBox *const box = *it;
199
            if (box == nullptr)
200
            {
201
                i ++;
202
                continue;
203
            }
204
            if (i == mSelected)
205
            {
206
                graphics->calcTileCollection(mVertexes,
207
                    mSlotHighlightedBackground,
208
                    box->x, box->y);
209
            }
210
            else
211
            {
212
                graphics->calcTileCollection(mVertexes,
213
                    mSlotBackground,
214
                    box->x, box->y);
215
            }
216
            i ++;
217
        }
218
        graphics->finalize(mVertexes);
219
    }
220
    graphics->drawTileCollection(mVertexes);
221
222
    if (mEquipment == nullptr)
223
    {
224
        BLOCK_END("EquipmentWindow::draw")
225
        return;
226
    }
227
228
    i = 0;
229
    const int projSlot = inventoryHandler->getProjectileSlot();
230
    for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
231
         it_end = boxes.end(); it != it_end; ++ it, ++ i)
232
    {
233
        const EquipmentBox *const box = *it;
234
        if (box == nullptr)
235
            continue;
236
        const Item *const item = mEquipment->getEquipment(i);
237
        if (item != nullptr)
238
        {
239
            // Draw Item.
240
            Image *const image = item->getImage();
241
            if (image != nullptr)
242
            {
243
                image->setAlpha(1.0F);  // Ensure the image is drawn
244
                                        // with maximum opacity
245
                graphics->drawImage(image, box->x + mItemPadding,
246
                    box->y + mItemPadding);
247
                if (i == projSlot)
248
                {
249
                    const std::string str = toString(item->getQuantity());
250
                    font->drawString(graphics,
251
                        mLabelsColor,
252
                        mLabelsColor2,
253
                        str,
254
                        box->x + (mBoxSize - font->getWidth(str)) / 2,
255
                        box->y - fontHeight);
256
                }
257
            }
258
        }
259
        else if (box->image != nullptr)
260
        {
261
            graphics->drawImage(box->image,
262
                box->x + mItemPadding,
263
                box->y + mItemPadding);
264
        }
265
    }
266
    BLOCK_END("EquipmentWindow::draw")
267
}
268
269
void EquipmentWindow::safeDraw(Graphics *const graphics)
270
{
271
    BLOCK_START("EquipmentWindow::draw")
272
    // Draw window graphics
273
    Window::safeDraw(graphics);
274
275
    int i = 0;
276
    Font *const font = getFont();
277
    const int fontHeight = font->getHeight();
278
    const STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
279
280
    for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
281
         it_end = boxes.end(); it != it_end; ++ it, ++ i)
282
    {
283
        const EquipmentBox *const box = *it;
284
        if (box == nullptr)
285
            continue;
286
        if (i == mSelected)
287
        {
288
            graphics->drawImage(mSlotHighlightedBackground,
289
                box->x, box->y);
290
        }
291
        else
292
        {
293
            graphics->drawImage(mSlotBackground, box->x, box->y);
294
        }
295
    }
296
297
    if (mEquipment == nullptr)
298
    {
299
        BLOCK_END("EquipmentWindow::draw")
300
        return;
301
    }
302
303
    i = 0;
304
    const int projSlot = inventoryHandler->getProjectileSlot();
305
    for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
306
         it_end = boxes.end(); it != it_end; ++ it, ++ i)
307
    {
308
        const EquipmentBox *const box = *it;
309
        if (box == nullptr)
310
            continue;
311
        const Item *const item = mEquipment->getEquipment(i);
312
        if (item != nullptr)
313
        {
314
            // Draw Item.
315
            Image *const image = item->getImage();
316
            if (image != nullptr)
317
            {
318
                image->setAlpha(1.0F);  // Ensure the image is drawn
319
                                        // with maximum opacity
320
                graphics->drawImage(image, box->x + mItemPadding,
321
                    box->y + mItemPadding);
322
                if (i == projSlot)
323
                {
324
                    const std::string str = toString(item->getQuantity());
325
                    font->drawString(graphics,
326
                        mLabelsColor,
327
                        mLabelsColor2,
328
                        str,
329
                        box->x + (mBoxSize - font->getWidth(str)) / 2,
330
                        box->y - fontHeight);
331
                }
332
            }
333
        }
334
        else if (box->image != nullptr)
335
        {
336
            graphics->drawImage(box->image,
337
                box->x + mItemPadding,
338
                box->y + mItemPadding);
339
        }
340
    }
341
    BLOCK_END("EquipmentWindow::draw")
342
}
343
344
void EquipmentWindow::action(const ActionEvent &event)
345
{
346
    const std::string &eventId = event.getId();
347
    if (eventId == "unequip")
348
    {
349
        if ((mEquipment == nullptr) || mSelected == -1)
350
            return;
351
352
        const Item *const item = mEquipment->getEquipment(mSelected);
353
        PlayerInfo::unequipItem(item, Sfx_true);
354
        setSelected(-1);
355
    }
356
    else if (eventId.find("tab_") == 0U)
357
    {
358
        Button *const button = dynamic_cast<Button*>(event.getSource());
359
        if (button == nullptr)
360
            return;
361
        mSelectedTab = button->getTag();
362
        updatePage();
363
    }
364
    else if (eventId == "playerbox")
365
    {
366
        const DragDropSourceT src = dragDrop.getSource();
367
        if (dragDrop.isEmpty() || (src != DragDropSource::Inventory
368
            && src != DragDropSource::Equipment))
369
        {
370
            return;
371
        }
372
        Inventory *const inventory = localPlayer != nullptr
373
            ? PlayerInfo::getInventory() : nullptr;
374
        if (inventory == nullptr)
375
            return;
376
        Item *const item = inventory->findItem(dragDrop.getItem(),
377
            dragDrop.getItemColor());
378
        if (item == nullptr)
379
            return;
380
381
        if (dragDrop.getSource() == DragDropSource::Inventory)
382
        {
383
            if (item->isEquipment() == Equipm_true)
384
            {
385
                if (item->isEquipped() == Equipped_false)
386
                    PlayerInfo::equipItem(item, Sfx_true);
387
            }
388
        }
389
    }
390
}
391
392
1
void EquipmentWindow::updatePage()
393
{
394
2
    EquipmentPage *const page = mPages[mSelectedTab];
395
1
    const Visible visible = fromBool(page->showPlayerBox, Visible);
396
1
    mPlayerBox->setVisible(visible);
397
1
    if (visible == Visible_true)
398
    {
399
3
        mPlayerBox->setDimension(Rect(page->x, page->y,
400
1
            page->width, page->height));
401
    }
402
1
    mRedraw = true;
403
1
}
404
405
const Item *EquipmentWindow::getItem(const int x, const int y) const
406
{
407
    if (mEquipment == nullptr)
408
        return nullptr;
409
410
    int i = 0;
411
412
    STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
413
    for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
414
         it_end = boxes.end(); it != it_end; ++ it, ++ i)
415
    {
416
        const EquipmentBox *const box = *it;
417
        if (box == nullptr)
418
            continue;
419
        const Rect tRect(box->x, box->y, mBoxSize, mBoxSize);
420
421
        if (tRect.isPointInRect(x, y))
422
            return mEquipment->getEquipment(i);
423
    }
424
    return nullptr;
425
}
426
427
void EquipmentWindow::mousePressed(MouseEvent& event)
428
{
429
    if (mEquipment == nullptr)
430
    {
431
        Window::mousePressed(event);
432
        return;
433
    }
434
435
    const int x = event.getX();
436
    const int y = event.getY();
437
438
    if (event.getButton() == MouseButton::LEFT)
439
    {
440
        if (mForing)
441
        {
442
            Window::mousePressed(event);
443
            return;
444
        }
445
        // Checks if any of the presses were in the equip boxes.
446
        int i = 0;
447
448
        bool inBox(false);
449
450
        STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
451
        for (STD_VECTOR<EquipmentBox*>::const_iterator it = boxes.begin(),
452
             it_end = boxes.end(); it != it_end; ++ it, ++ i)
453
        {
454
            const EquipmentBox *const box = *it;
455
            if (box == nullptr)
456
                continue;
457
            const Item *const item = mEquipment->getEquipment(i);
458
            const Rect tRect(box->x, box->y, mBoxSize, mBoxSize);
459
460
            if (tRect.isPointInRect(x, y))
461
            {
462
                inBox = true;
463
                if (item != nullptr)
464
                {
465
                    event.consume();
466
                    setSelected(i);
467
                    dragDrop.dragItem(item, DragDropSource::Equipment, 0);
468
                    return;
469
                }
470
            }
471
            if (inBox)
472
                return;
473
        }
474
    }
475
    else if (event.getButton() == MouseButton::RIGHT)
476
    {
477
        if (const Item *const item = getItem(x, y))
478
        {
479
            if (itemPopup != nullptr)
480
                itemPopup->setVisible(Visible_false);
481
482
            /* Convert relative to the window coordinates to absolute screen
483
             * coordinates.
484
             */
485
            const int mx = x + getX();
486
            const int my = y + getY();
487
            if (popupMenu != nullptr)
488
            {
489
                event.consume();
490
                if (mForing)
491
                {
492
                    popupMenu->showUndressPopup(mx, my, mBeing, item);
493
                }
494
                else
495
                {
496
                    popupMenu->showPopup(this, mx, my, item,
497
                        InventoryType::Inventory);
498
                }
499
                return;
500
            }
501
        }
502
    }
503
    Window::mousePressed(event);
504
}
505
506
void EquipmentWindow::mouseReleased(MouseEvent &event)
507
{
508
    Window::mouseReleased(event);
509
    const DragDropSourceT src = dragDrop.getSource();
510
    if (dragDrop.isEmpty() || (src != DragDropSource::Inventory
511
        && src != DragDropSource::Equipment))
512
    {
513
        return;
514
    }
515
    Inventory *const inventory = localPlayer != nullptr
516
        ? PlayerInfo::getInventory() : nullptr;
517
    if (inventory == nullptr)
518
        return;
519
520
    Item *const item = inventory->findItem(dragDrop.getItem(),
521
        dragDrop.getItemColor());
522
    if (item == nullptr)
523
        return;
524
525
    if (dragDrop.getSource() == DragDropSource::Inventory)
526
    {
527
        if (item->isEquipment() == Equipm_true)
528
        {
529
            if (item->isEquipped() == Equipped_false)
530
                PlayerInfo::equipItem(item, Sfx_true);
531
        }
532
    }
533
    else if (dragDrop.getSource() == DragDropSource::Equipment)
534
    {
535
        if (item->isEquipment() == Equipm_true)
536
        {
537
            const int x = event.getX();
538
            const int y = event.getY();
539
            STD_VECTOR<EquipmentBox*> &boxes = mPages[mSelectedTab]->boxes;
540
            for (STD_VECTOR<EquipmentBox*>::const_iterator
541
                 it = boxes.begin(), it_end = boxes.end();
542
                 it != it_end; ++ it)
543
            {
544
                const EquipmentBox *const box = *it;
545
                if (box == nullptr)
546
                    continue;
547
                const Rect tRect(box->x, box->y, mBoxSize, mBoxSize);
548
549
                if (tRect.isPointInRect(x, y))
550
                    return;
551
            }
552
553
            if (item->isEquipped() == Equipped_true)
554
                PlayerInfo::unequipItem(item, Sfx_true);
555
        }
556
    }
557
    dragDrop.clear();
558
    dragDrop.deselect();
559
}
560
561
// Show ItemTooltip
562
void EquipmentWindow::mouseMoved(MouseEvent &event)
563
{
564
    Window::mouseMoved(event);
565
566
    if (itemPopup == nullptr)
567
        return;
568
569
    const int x = event.getX();
570
    const int y = event.getY();
571
572
    const Item *const item = getItem(x, y);
573
574
    if (item != nullptr)
575
    {
576
        itemPopup->setItem(item, false);
577
        itemPopup->position(x + getX(), y + getY());
578
    }
579
    else
580
    {
581
        itemPopup->setVisible(Visible_false);
582
    }
583
}
584
585
// Hide ItemTooltip
586
void EquipmentWindow::mouseExited(MouseEvent &event A_UNUSED)
587
{
588
    if (itemPopup != nullptr)
589
        itemPopup->setVisible(Visible_false);
590
}
591
592
void EquipmentWindow::setSelected(const int index)
593
{
594
    mSelected = index;
595
    mRedraw = true;
596
    if (mUnequip != nullptr)
597
        mUnequip->setEnabled(mSelected != -1);
598
    if (itemPopup != nullptr)
599
        itemPopup->setVisible(Visible_false);
600
}
601
602
void EquipmentWindow::setBeing(Being *const being)
603
{
604
    mPlayerBox->setPlayer(being);
605
    mBeing = being;
606
    if (mEquipment != nullptr)
607
        delete mEquipment->getBackend();
608
    delete mEquipment;
609
    if (being == nullptr)
610
    {
611
        mEquipment = nullptr;
612
        return;
613
    }
614
    mEquipment = being->getEquipment();
615
}
616
617
void EquipmentWindow::updateBeing(Being *const being)
618
{
619
    if (being == mBeing)
620
        setBeing(being);
621
}
622
623
void EquipmentWindow::resetBeing(const Being *const being)
624
{
625
    if (being == mBeing)
626
        setBeing(nullptr);
627
}
628
629
1
void EquipmentWindow::fillBoxes()
630
{
631
    XML::Document *const doc = new XML::Document(
632
5
        paths.getStringValue("equipmentWindowFile"),
633
        UseVirtFs_true,
634

1
        SkipError_false);
635
1
    XmlNodeConstPtr root = doc->rootNode();
636
1
    if (root == nullptr)
637
    {
638
        delete doc;
639
        fillDefault();
640
        return;
641
    }
642
643
1
    if (mImageSet != nullptr)
644
        mImageSet->decRef();
645
646

5
    mImageSet = Theme::getImageSetFromTheme(XML::getProperty(
647
        root, "image", "equipmentbox.png"), 32, 32);
648
649
6
    for_each_xml_child_node(node, root)
650
    {
651
5
        if (xmlNameEqual(node, "page"))
652
        {
653
2
            loadPage(node);
654
        }
655
    }
656
1
    delete doc;
657

2
    if (reportTrue(mPages.empty()))
658
        fillDefault();
659
}
660
661
void EquipmentWindow::addDefaultPage()
662
{
663
    if (!mHaveDefaultPage)
664
    {
665
        mHaveDefaultPage = true;
666
        // TRANSLATORS: equipment window tab
667
        addPage(_("default"));
668
    }
669
}
670
671
2
void EquipmentWindow::loadPage(XmlNodeConstPtr node)
672
{
673
2
    if (node == nullptr)
674
        return;
675
    // TRANSLATORS: unknown equipment page name
676
8
    const std::string &name = XML::langProperty(node, "name", _("Unknown"));
677
2
    const int page = addPage(name);
678
80
    for_each_xml_child_node(childNode, node)
679
    {
680

78
        if (xmlNameEqual(childNode, "playerbox"))
681
1
            loadPlayerBox(childNode, page);
682

77
        else if (xmlNameEqual(childNode, "slot"))
683
37
            loadSlot(childNode, mImageSet, page);
684
    }
685
}
686
687
1
void EquipmentWindow::loadPlayerBox(XmlNodeConstPtr playerBoxNode,
688
                                    const int page)
689
{
690
2
    EquipmentPage *const data = mPages[page];
691
1
    data->x = XML::getProperty(playerBoxNode, "x", 50);
692
1
    data->y = XML::getProperty(playerBoxNode, "y", 80) + mYPadding;
693
1
    data->width = XML::getProperty(playerBoxNode, "width", 74);
694
1
    data->height = XML::getProperty(playerBoxNode, "height", 168);
695
1
}
696
697
37
void EquipmentWindow::loadSlot(XmlNodeConstPtr slotNode,
698
                               const ImageSet *const imageset,
699
                               const int page)
700
{
701
37
    if (imageset == nullptr)
702
        return;
703
222
    const int slot = parseSlotName(XML::getProperty(slotNode, "name", ""));
704
37
    if (slot < 0)
705
        return;
706
707
    const int x = XML::getProperty(slotNode, "x", 0) + getPadding();
708
    const int y = XML::getProperty(slotNode, "y", 0)
709
        + getTitleBarHeight() + mYPadding;
710
    const int imageIndex = XML::getProperty(slotNode, "image", -1);
711
    Image *image = nullptr;
712
713
    if (imageIndex >= 0 && imageIndex < CAST_S32(imageset->size()))
714
        image = imageset->get(imageIndex);
715
716
    STD_VECTOR<EquipmentBox*> &boxes = mPages[page]->boxes;
717
    if (boxes[slot] != nullptr)
718
    {
719
        EquipmentBox *const box = boxes[slot];
720
        box->x = x;
721
        box->y = y;
722
        box->image = image;
723
    }
724
    else
725
    {
726
        boxes[slot] = new EquipmentBox(x, y, image);
727
    }
728
    if (x < mMinX)
729
        mMinX = x;
730
    if (y < mMinY)
731
        mMinY = y;
732
    if (x + mBoxSize > mMaxX)
733
        mMaxX = x + mBoxSize;
734
    if (y + mBoxSize > mMaxY)
735
        mMaxY = y + mBoxSize;
736
}
737
738
void EquipmentWindow::prepareSlotNames()
739
{
740
    mSlotNames.clear();
741
    XML::Document doc(paths.getStringValue("equipmentSlotsFile"),
742
        UseVirtFs_true,
743
        SkipError_false);
744
    XmlNodeConstPtrConst root = doc.rootNode();
745
    if (root == nullptr)
746
        return;
747
748
    for_each_xml_child_node(slotNode, root)
749
    {
750
        if (!xmlNameEqual(slotNode, "slot"))
751
            continue;
752
        const std::string name = XML::getProperty(slotNode, "name", "");
753
        if (name.empty())
754
        {
755
            reportAlways("Empty slot name detected.")
756
            continue;
757
        }
758
759
        const int slot = XML::getProperty(slotNode, "slot", -1);
760
        if (slot < 0 || slot >= BOX_COUNT)
761
        {
762
            reportAlways("Wrong slot id '%d' for slot with name '%s'",
763
                slot,
764
                name.c_str())
765
            continue;
766
        }
767
        mSlotNames[name] = slot;
768
    }
769
}
770
771
int EquipmentWindow::parseSlotName(const std::string &name)
772
{
773
74
    StringIntMapCIter it =  mSlotNames.find(name);
774

37
    if (it != mSlotNames.end())
775
        return (*it).second;
776
    return -1;
777
}
778
779
void EquipmentWindow::fillDefault()
780
{
781
    if (mImageSet != nullptr)
782
        mImageSet->decRef();
783
784
    addDefaultPage();
785
    mImageSet = Theme::getImageSetFromTheme(
786
        "equipmentbox.png", 32, 32);
787
788
    addBox(0, 90, 40, 0);     // torso
789
    addBox(1, 8, 78, 1);      // gloves
790
    addBox(2, 70, 0, 2);      // hat
791
    addBox(3, 50, 253, 3);    // pants
792
    addBox(4, 90, 253, 4);    // boots
793
    addBox(5, 8, 213, 5);     // FREE
794
    addBox(6, 129, 213, 6);   // wings
795
    addBox(7, 50, 40, 5);     // scarf
796
    addBox(8, 8, 168, 7);     // weapon
797
    addBox(9, 129, 168, 8);   // shield
798
    addBox(10, 129, 78, 9);   // ammo
799
    addBox(11, 8, 123, 5);    // amulet
800
    addBox(12, 129, 123, 5);  // ring
801
}
802
803
void EquipmentWindow::addBox(const int idx, int x, int y, const int imageIndex)
804
{
805
    Image *image = nullptr;
806
807
    if ((mImageSet != nullptr) && imageIndex >= 0 && imageIndex
808
        < CAST_S32(mImageSet->size()))
809
    {
810
        image = mImageSet->get(imageIndex);
811
    }
812
813
    x += getPadding();
814
    y += getTitleBarHeight() + mYPadding;
815
    STD_VECTOR<EquipmentBox*> &boxes = mPages[0]->boxes;
816
    boxes[idx] = new EquipmentBox(x, y, image);
817
818
    if (x < mMinX)
819
        mMinX = x;
820
    if (y < mMinY)
821
        mMinY = y;
822
    if (x + mBoxSize > mMaxX)
823
        mMaxX = x + mBoxSize;
824
    if (y + mBoxSize > mMaxY)
825
        mMaxY = y + mBoxSize;
826
}
827
828
1
void EquipmentWindow::recalcSize()
829
{
830
1
    mMaxX += mMinX;
831
1
    mMaxY += mMinY;
832
1
    mTabs->setWidth(mMaxX);
833
2
    mMaxY += mUnequip->getHeight() - mYPadding;
834
1
    setDefaultSize(mMaxX, mMaxY, ImagePosition::CENTER, 0, 0);
835
1
}
836
837
2
int EquipmentWindow::addPage(const std::string &name)
838
{
839
4
    EquipmentPage *const page = new EquipmentPage;
840
2
    mPages.push_back(page);
841
2
    STD_VECTOR<EquipmentBox*> &boxes = page->boxes;
842
843
2
    boxes.reserve(BOX_COUNT);
844
110
    for (int f = 0; f < BOX_COUNT; f ++)
845
108
        boxes.push_back(nullptr);
846
847
2
    mTabs->addButton(name, name, false);
848
4
    return CAST_S32(mPages.size()) - 1;
849

3
}