GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/shopwindow.cpp Lines: 131 529 24.8 %
Date: 2017-11-29 Branches: 127 802 15.8 %

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-2017  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 "gui/windows/shopwindow.h"
24
25
#include "const/resources/currency.h"
26
27
#ifdef TMWA_SUPPORT
28
#include "gui/windows/buydialog.h"
29
#include "gui/windows/chatwindow.h"
30
#include "gui/windows/confirmdialog.h"
31
#include "gui/windows/shopselldialog.h"
32
#include "gui/windows/tradewindow.h"
33
34
#include "const/gui/chat.h"
35
#endif  // TMWA_SUPPORT
36
37
#include "enums/gui/layouttype.h"
38
39
#include "gui/windows/editdialog.h"
40
41
#include "gui/windows/itemamountwindow.h"
42
#include "gui/windows/setupwindow.h"
43
44
#include "gui/models/shopitems.h"
45
46
#include "gui/widgets/button.h"
47
#include "gui/widgets/checkbox.h"
48
#include "gui/widgets/containerplacer.h"
49
#include "gui/widgets/createwidget.h"
50
#include "gui/widgets/layout.h"
51
#include "gui/widgets/scrollarea.h"
52
#include "gui/widgets/shoplistbox.h"
53
#include "gui/widgets/tabstrip.h"
54
55
#include "listeners/shoprenamelistener.h"
56
57
#ifdef TMWA_SUPPORT
58
#include "actormanager.h"
59
#include "soundmanager.h"
60
#endif  // TMWA_SUPPORT
61
#include "configuration.h"
62
#include "settings.h"
63
64
#include "being/localplayer.h"
65
#include "being/playerinfo.h"
66
67
#ifdef TMWA_SUPPORT
68
#include "being/playerrelations.h"
69
#include "net/chathandler.h"
70
#endif  // TMWA_SUPPORT
71
#include "net/buyingstorehandler.h"
72
#include "net/vendinghandler.h"
73
#include "net/net.h"
74
#ifdef TMWA_SUPPORT
75
#include "net/tradehandler.h"
76
#endif  // TMWA_SUPPORT
77
78
#include "utils/checkutils.h"
79
#include "utils/delete2.h"
80
#include "utils/foreach.h"
81
#include "utils/gettext.h"
82
83
#ifdef TMWA_SUPPORT
84
#include "resources/iteminfo.h"
85
#endif  // TMWA_SUPPORT
86
87
#include "resources/inventory/inventory.h"
88
89
#include "resources/item/shopitem.h"
90
91
#include <sys/stat.h>
92
93
#include <sstream>
94
95
#include "debug.h"
96
97
ShopWindow *shopWindow = nullptr;
98
extern std::string tradePartnerName;
99
2
ShopWindow::DialogList ShopWindow::instances;
100
101
2
ShopWindow::ShopWindow() :
102
    // TRANSLATORS: shop window name
103
2
    Window(_("Personal Shop"), Modal_false, nullptr, "shop.xml"),
104
    VendingModeListener(),
105
    VendingSlotsListener(),
106
    BuyingStoreModeListener(),
107
    BuyingStoreSlotsListener(),
108
    ActionListener(),
109
    SelectionListener(),
110
    // TRANSLATORS: shop window button
111

4
    mCloseButton(new Button(this, _("Close"), "close", this)),
112

2
    mBuyShopItems(new ShopItems(false, DEFAULT_CURRENCY)),
113

2
    mSellShopItems(new ShopItems(false, DEFAULT_CURRENCY)),
114
    mTradeItem(nullptr),
115

2
    mBuyShopItemList(CREATEWIDGETR(ShopListBox,
116
        this, mBuyShopItems, mBuyShopItems, ShopListBoxType::BuyShop)),
117

2
    mSellShopItemList(CREATEWIDGETR(ShopListBox,
118
        this, mSellShopItems, mSellShopItems, ShopListBoxType::SellShop)),
119
    mCurrentShopItemList(nullptr),
120
2
    mScrollArea(new ScrollArea(this, mBuyShopItemList,
121

8
        fromBool(getOptionBool("showbuybackground"), Opaque),
122

4
        "shop_buy_background.xml")),
123
    // TRANSLATORS: shop window label
124

4
    mAddButton(new Button(this, _("Add"), "add", this)),
125
    // TRANSLATORS: shop window label
126

4
    mDeleteButton(new Button(this, _("Delete"), "delete", this)),
127
    mAnnounceButton(nullptr),
128
    mPublishButton(nullptr),
129
    mRenameButton(nullptr),
130
    mAnnounceLinks(nullptr),
131
    mTabs(nullptr),
132
    mAcceptPlayer(),
133
    mTradeNick(),
134
    mSellShopName(serverConfig.getStringValue("sellShopName")),
135
    mSelectedItem(-1),
136
    mAnnonceTime(0),
137
    mLastRequestTimeList(0),
138
    mLastRequestTimeItem(0),
139
    mRandCounter(0),
140
    mTradeMoney(0),
141
    mSellShopSize(0),
142
    mBuyShopSize(0),
143
    isBuySelected(true),
144
2
    mHaveVending(Net::getNetworkType() != ServerType::TMWATHENA),
145
    mEnableBuyingStore(false),
146








92
    mEnableVending(false)
147
{
148
10
    setWindowName("Personal Shop");
149
2
    setResizable(true);
150
2
    setCloseButton(true);
151
2
    setStickyButtonLock(true);
152
2
    setMinWidth(300);
153
2
    setMinHeight(220);
154
2
    if (mainGraphics->mWidth > 600)
155
2
        setDefaultSize(500, 300, ImagePosition::CENTER);
156
    else
157
        setDefaultSize(380, 300, ImagePosition::CENTER);
158
159
2
    if (setupWindow != nullptr)
160
        setupWindow->registerWindowForReset(this);
161
162

8
    const int size = config.getIntValue("fontSize")
163

8
        + getOption("tabHeightAdjust", 16);
164

8
    mTabs = new TabStrip(this, "shop", size);
165
2
    mTabs->addActionListener(this);
166
10
    mTabs->setActionEventId("tab_");
167
    // TRANSLATORS: shop window tab name
168

14
    mTabs->addButton(_("Buy"), "buy", true);
169
    // TRANSLATORS: shop window tab name
170

14
    mTabs->addButton(_("Sell"), "sell", false);
171
4
    mTabs->setSelectable(false);
172
4
    mScrollArea->setSelectable(false);
173
174
2
    loadList();
175
176
2
    mBuyShopItemList->setPriceCheck(false);
177
2
    mSellShopItemList->setPriceCheck(false);
178
179
2
    mScrollArea->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
180
181
2
    mBuyShopItemList->addSelectionListener(this);
182
2
    mSellShopItemList->addSelectionListener(this);
183
184
2
    ContainerPlacer placer;
185
2
    placer = getPlacer(0, 0);
186
187
4
    placer(0, 0, mTabs, 8).setPadding(3);
188
189
2
    if (mHaveVending)
190
    {
191
        // TRANSLATORS: shop window button
192


14
        mPublishButton = new Button(this, _("Publish"), "publish", this);
193
        // TRANSLATORS: shop window button
194


14
        mRenameButton = new Button(this, _("Rename"), "rename", this);
195
2
        placer(2, 6, mPublishButton);
196
2
        placer(3, 6, mRenameButton);
197
    }
198
    else
199
    {
200
        // TRANSLATORS: shop window button
201
        mAnnounceButton = new Button(this, _("Announce"), "announce", this);
202
        // TRANSLATORS: shop window checkbox
203
        mAnnounceLinks = new CheckBox(this, _("Show links in announce"), false,
204
            this, "link announce");
205
206
        placer(2, 6, mAnnounceButton);
207
        placer(0, 7, mAnnounceLinks, 7);
208
    }
209
210
4
    placer(0, 1, mScrollArea, 8, 5).setPadding(3);
211
2
    placer(0, 6, mAddButton);
212
2
    placer(1, 6, mDeleteButton);
213
2
    placer(7, 6, mCloseButton);
214
215
2
    Layout &layout = getLayout();
216
2
    layout.setRowHeight(0, LayoutType::SET);
217
218
2
    center();
219
2
    loadWindowState();
220
2
    updateShopName();
221
4
    instances.push_back(this);
222
2
}
223
224
2
void ShopWindow::postInit()
225
{
226
2
    Window::postInit();
227
2
    setVisible(Visible_false);
228
4
    enableVisibleSound(true);
229
2
    updateSelection();
230
2
}
231
232
16
ShopWindow::~ShopWindow()
233
{
234
2
    saveList();
235
236
2
    delete2(mBuyShopItemList);
237
2
    delete2(mSellShopItemList);
238
2
    delete2(mBuyShopItems);
239
2
    delete2(mSellShopItems);
240
2
    delete2(mTradeItem);
241
242
2
    instances.remove(this);
243
4
}
244
245
void ShopWindow::action(const ActionEvent &event)
246
{
247
    const std::string &eventId = event.getId();
248
    if (eventId == "close")
249
    {
250
        close();
251
        return;
252
    }
253
#ifdef TMWA_SUPPORT
254
    else if (eventId == "yes")
255
    {
256
        startTrade();
257
    }
258
    else if (eventId == "no")
259
    {
260
        mTradeNick.clear();
261
    }
262
    else if (eventId == "ignore")
263
    {
264
        playerRelations.ignoreTrade(mTradeNick);
265
        mTradeNick.clear();
266
    }
267
    else if (eventId == "announce")
268
    {
269
        if (isBuySelected)
270
        {
271
            if (mBuyShopItems->getNumberOfElements() > 0)
272
                announce(mBuyShopItems, BUY);
273
        }
274
        else if (mSellShopItems->getNumberOfElements() > 0)
275
        {
276
            announce(mSellShopItems, SELL);
277
        }
278
    }
279
#endif  // TMWA_SUPPORT
280
    else if (eventId == "delete")
281
    {
282
        if (isBuySelected)
283
        {
284
            if (mBuyShopItemList != nullptr &&
285
                mBuyShopItemList->getSelected() >= 0)
286
            {
287
                mBuyShopItems->del(mBuyShopItemList->getSelected());
288
                if (isShopEmpty() && (localPlayer != nullptr))
289
                    localPlayer->updateStatus();
290
            }
291
        }
292
        else if ((mSellShopItemList != nullptr)
293
                 && mSellShopItemList->getSelected() >= 0)
294
        {
295
            mSellShopItems->del(mSellShopItemList->getSelected());
296
            if (isShopEmpty() && (localPlayer != nullptr))
297
                localPlayer->updateStatus();
298
        }
299
    }
300
    else if (eventId == "tab_buy")
301
    {
302
        isBuySelected = true;
303
        updateSelection();
304
    }
305
    else if (eventId == "tab_sell")
306
    {
307
        isBuySelected = false;
308
        updateSelection();
309
    }
310
    else if (eventId == "publish")
311
    {
312
        if (isBuySelected)
313
        {
314
            if (mEnableBuyingStore)
315
            {
316
                buyingStoreHandler->close();
317
                BuyingStoreModeListener::distributeEvent(false);
318
            }
319
            else
320
            {
321
                STD_VECTOR<ShopItem*> &items = mBuyShopItems->items();
322
                if (!items.empty())
323
                {
324
                    buyingStoreHandler->create(mSellShopName,
325
                        PlayerInfo::getAttribute(Attributes::MONEY),
326
                        true,
327
                        items);
328
                }
329
            }
330
        }
331
        else
332
        {
333
            if (mEnableVending)
334
            {
335
                vendingHandler->close();
336
                VendingModeListener::distributeEvent(false);
337
            }
338
            else
339
            {
340
                STD_VECTOR<ShopItem*> &oldItems = mSellShopItems->items();
341
                STD_VECTOR<ShopItem*> items;
342
                const Inventory *const inv = PlayerInfo::getCartInventory();
343
                if (inv == nullptr)
344
                    return;
345
                FOR_EACH (STD_VECTOR<ShopItem*>::iterator, it, oldItems)
346
                {
347
                    ShopItem *const item = *it;
348
                    if (item == nullptr)
349
                        continue;
350
                    const Item *const cartItem = inv->findItem(item->getId(),
351
                        item->getColor());
352
                    if (cartItem == nullptr)
353
                        continue;
354
                    item->setInvIndex(cartItem->getInvIndex());
355
                    const int amount = cartItem->getQuantity();
356
                    if (amount == 0)
357
                        continue;
358
                    if (item->getQuantity() > amount)
359
                        item->setQuantity(amount);
360
                    items.push_back(item);
361
                    if (static_cast<signed int>(items.size()) >= mSellShopSize)
362
                        break;
363
                }
364
                if (!items.empty())
365
                    vendingHandler->createShop(mSellShopName, true, items);
366
            }
367
        }
368
    }
369
    else if (eventId == "rename")
370
    {
371
        EditDialog *const dialog = CREATEWIDGETR(EditDialog,
372
            // TRANSLATORS: shop rename dialog title
373
            _("Please enter new shop name"),
374
            mSellShopName,
375
            "OK");
376
        shopRenameListener.setDialog(dialog);
377
        dialog->addActionListener(&shopRenameListener);
378
    }
379
380
    if (mSelectedItem < 1)
381
        return;
382
383
    const Inventory *const inv = mHaveVending && !isBuySelected
384
        ? PlayerInfo::getCartInventory() : PlayerInfo::getInventory();
385
    if (inv == nullptr)
386
        return;
387
388
    // +++ need support for colors
389
    Item *const item = inv->findItem(mSelectedItem, ItemColor_zero);
390
    if (item != nullptr)
391
    {
392
        if (eventId == "add")
393
        {
394
            if (isBuySelected)
395
            {
396
                ItemAmountWindow::showWindow(ItemAmountWindowUsage::ShopBuyAdd,
397
                    this,
398
                    item,
399
                    sumAmount(item));
400
            }
401
            else
402
            {
403
                ItemAmountWindow::showWindow(
404
                    ItemAmountWindowUsage::ShopSellAdd,
405
                    this,
406
                    item,
407
                    sumAmount(item));
408
            }
409
        }
410
    }
411
}
412
413
void ShopWindow::valueChanged(const SelectionEvent &event A_UNUSED)
414
{
415
    updateButtonsAndLabels();
416
}
417
418
2
void ShopWindow::updateButtonsAndLabels()
419
{
420
2
    bool allowDel(false);
421
2
    bool allowAdd(false);
422
4
    const bool sellNotEmpty = mSellShopItems->getNumberOfElements() > 0;
423
2
    if (isBuySelected)
424
    {
425
2
        allowAdd = !mEnableBuyingStore;
426
2
        allowDel = !mEnableBuyingStore
427
4
            && mBuyShopItemList->getSelected() != -1
428

2
            && mBuyShopItems->getNumberOfElements() > 0;
429
2
        if (mPublishButton != nullptr)
430
        {
431
2
            if (mEnableBuyingStore)
432
            {
433
                // TRANSLATORS: unpublish shop button
434
                mPublishButton->setCaption(_("Unpublish"));
435
            }
436
            else
437
            {
438
                // TRANSLATORS: publish shop button
439
10
                mPublishButton->setCaption(_("Publish"));
440
            }
441
2
            mPublishButton->adjustSize();
442
2
            if (mBuyShopSize > 0)
443
                mPublishButton->setEnabled(true);
444
            else
445
2
                mPublishButton->setEnabled(false);
446
        }
447
    }
448
    else
449
    {
450
        allowAdd = !mEnableVending && mSelectedItem != -1;
451
        allowDel = !mEnableVending
452
            && mSellShopItemList->getSelected() != -1
453
            && sellNotEmpty;
454
        if (mPublishButton != nullptr)
455
        {
456
            if (mEnableVending)
457
            {
458
                // TRANSLATORS: unpublish shop button
459
                mPublishButton->setCaption(_("Unpublish"));
460
            }
461
            else
462
            {
463
                // TRANSLATORS: publish shop button
464
                mPublishButton->setCaption(_("Publish"));
465
            }
466
            mPublishButton->adjustSize();
467
            if (sellNotEmpty
468
                && mSellShopSize > 0
469
                && (localPlayer != nullptr)
470
                && localPlayer->getHaveCart())
471
            {
472
                mPublishButton->setEnabled(true);
473
            }
474
            else
475
            {
476
                mPublishButton->setEnabled(false);
477
            }
478
        }
479
    }
480
4
    mAddButton->setEnabled(allowAdd);
481
4
    mDeleteButton->setEnabled(allowDel);
482
2
    if (mRenameButton != nullptr)
483
2
        mRenameButton->setEnabled(!mEnableVending);
484
2
}
485
486
void ShopWindow::setVisible(Visible visible)
487
{
488
2
    Window::setVisible(visible);
489
}
490
491
void ShopWindow::addBuyItem(const Item *const item, const int amount,
492
                            const int price)
493
{
494
    if (item == nullptr)
495
        return;
496
    const bool emp = isShopEmpty();
497
    mBuyShopItems->addItemNoDup(item->getId(),
498
        item->getType(),
499
        item->getColor(),
500
        amount,
501
        price);
502
    if (emp && (localPlayer != nullptr))
503
        localPlayer->updateStatus();
504
505
    updateButtonsAndLabels();
506
}
507
508
void ShopWindow::addSellItem(const Item *const item, const int amount,
509
                             const int price)
510
{
511
    if (item == nullptr)
512
        return;
513
    const bool emp = isShopEmpty();
514
    mSellShopItems->addItemNoDup(item->getId(),
515
        item->getType(),
516
        item->getColor(),
517
        amount,
518
        price);
519
    if (emp && (localPlayer != nullptr))
520
        localPlayer->updateStatus();
521
522
    updateButtonsAndLabels();
523
}
524
525
2
void ShopWindow::loadList()
526
{
527
4
    std::ifstream shopFile;
528
    struct stat statbuf;
529
530
2
    mBuyShopItems->clear();
531
2
    mSellShopItems->clear();
532
533
    const std::string shopListName = settings.serverConfigDir
534
4
        + "/shoplist.txt";
535
536

5
    if (stat(shopListName.c_str(), &statbuf) == 0 &&
537
1
        S_ISREG(statbuf.st_mode))
538
    {
539
1
        shopFile.open(shopListName.c_str(), std::ios::in);
540
1
        if (!shopFile.is_open())
541
        {
542
            reportAlways("Error opening file for reading: %s",
543
                shopListName.c_str());
544
            shopFile.close();
545
            return;
546
        }
547
        char line[101];
548

2
        while (shopFile.getline(line, 100))
549
        {
550
            std::string buf;
551
            const std::string str = line;
552
            if (!str.empty())
553
            {
554
                STD_VECTOR<int> tokens;
555
                std::stringstream ss(str);
556
557
                while (ss >> buf)
558
                    tokens.push_back(atoi(buf.c_str()));
559
560
                if (tokens.size() == 5 && (tokens[0] != 0))
561
                {
562
                    // +++ need impliment colors?
563
                    if ((tokens[1] != 0) && (tokens[2] != 0))
564
                    {
565
                        mBuyShopItems->addItem(
566
                            tokens[0],
567
                            ItemType::Unknown,
568
                            ItemColor_one,
569
                            tokens[1],
570
                            tokens[2]);
571
                    }
572
                    if ((tokens[3] != 0) && (tokens[4] != 0))
573
                    {
574
                        mSellShopItems->addItem(
575
                            tokens[0],
576
                            ItemType::Unknown,
577
                            ItemColor_one,
578
                            tokens[3],
579
                            tokens[4]);
580
                    }
581
                }
582
            }
583
        }
584
1
        shopFile.close();
585
    }
586
}
587
588
2
void ShopWindow::saveList() const
589
{
590
4
    std::ofstream shopFile;
591
    const std::string shopListName = settings.serverConfigDir
592
4
        + "/shoplist.txt";
593
4
    std::map<int, ShopItem*> mapItems;
594
595
2
    shopFile.open(shopListName.c_str(), std::ios::binary);
596
2
    if (!shopFile.is_open())
597
    {
598
        reportAlways("Error opening file writing: %s",
599
            shopListName.c_str());
600
        return;
601
    }
602
603
6
    STD_VECTOR<ShopItem*> items = mBuyShopItems->items();
604
10
    FOR_EACH (STD_VECTOR<ShopItem*>::const_iterator, it, items)
605
    {
606
        ShopItem *const item = *(it);
607
        if (item != nullptr)
608
            mapItems[item->getId()] = item;
609
    }
610
611
4
    items = mSellShopItems->items();
612
10
    FOR_EACH (STD_VECTOR<ShopItem*>::const_iterator, it, items)
613
    {
614
        if ((*it) == nullptr)
615
            continue;
616
        const ShopItem *const sellItem = *(it);
617
        const ShopItem *const buyItem = mapItems[sellItem->getId()];
618
619
        shopFile << sellItem->getId();
620
        if (buyItem != nullptr)
621
        {
622
            shopFile << strprintf(" %d %d ", buyItem->getQuantity(),
623
                buyItem->getPrice());
624
            mapItems.erase(sellItem->getId());
625
        }
626
        else
627
        {
628
            shopFile << " 0 0 ";
629
        }
630
631
        shopFile << strprintf("%d %d", sellItem->getQuantity(),
632
            sellItem->getPrice()) << std::endl;
633
    }
634
635
4
    for (std::map<int, ShopItem*>::const_iterator mapIt = mapItems.begin(),
636
4
         mapIt_fend = mapItems.end();
637
2
         mapIt != mapIt_fend;
638
         ++mapIt)
639
    {
640
        const ShopItem *const buyItem = (*mapIt).second;
641
        if (buyItem != nullptr)
642
        {
643
            shopFile << buyItem->getId();
644
            shopFile << strprintf(" %d %d ", buyItem->getQuantity(),
645
                                  buyItem->getPrice());
646
            shopFile << "0 0" << std::endl;
647
        }
648
    }
649
650
2
    shopFile.close();
651
2
}
652
653
#ifdef TMWA_SUPPORT
654
void ShopWindow::announce(ShopItems *const list, const int mode)
655
{
656
    if (list == nullptr)
657
        return;
658
659
    std::string data;
660
    if (mode == BUY)
661
        data.append("Buy ");
662
    else
663
        data.append("Sell ");
664
665
    if (mAnnonceTime != 0 &&
666
        (mAnnonceTime + (2 * 60) > cur_time || mAnnonceTime > cur_time))
667
    {
668
        return;
669
    }
670
671
    mAnnonceTime = cur_time;
672
    if (mAnnounceButton != nullptr)
673
        mAnnounceButton->setEnabled(false);
674
675
    STD_VECTOR<ShopItem*> items = list->items();
676
677
    FOR_EACH (STD_VECTOR<ShopItem*>::const_iterator, it, items)
678
    {
679
        const ShopItem *const item = *(it);
680
        if (item->getQuantity() > 1)
681
        {
682
            if (mAnnounceLinks->isSelected())
683
            {
684
                data.append(strprintf("[@@%d|%[email protected]@] (%dGP) %d, ", item->getId(),
685
                    item->getInfo().getName().c_str(),
686
                    item->getPrice(), item->getQuantity()));
687
            }
688
            else
689
            {
690
                data.append(strprintf("%s (%dGP) %d, ",
691
                    item->getInfo().getName().c_str(),
692
                    item->getPrice(), item->getQuantity()));
693
            }
694
        }
695
        else
696
        {
697
            if (mAnnounceLinks->isSelected())
698
            {
699
                data.append(strprintf("[@@%d|%[email protected]@] (%dGP), ", item->getId(),
700
                    item->getInfo().getName().c_str(), item->getPrice()));
701
            }
702
            else
703
            {
704
                data.append(strprintf("%s (%dGP), ",
705
                    item->getInfo().getName().c_str(), item->getPrice()));
706
            }
707
        }
708
    }
709
710
    chatHandler->channelMessage(TRADE_CHANNEL, data);
711
}
712
713
void ShopWindow::startTrade()
714
{
715
    if (actorManager == nullptr ||
716
        tradeWindow == nullptr)
717
    {
718
        return;
719
    }
720
721
    const Being *const being = actorManager->findBeingByName(
722
        mTradeNick, ActorType::Player);
723
    tradeWindow->clear();
724
    if (mTradeMoney != 0)
725
    {
726
        tradeWindow->addAutoMoney(mTradeNick, mTradeMoney);
727
    }
728
    else
729
    {
730
        tradeWindow->addAutoItem(mTradeNick, mTradeItem,
731
            mTradeItem->getQuantity());
732
    }
733
    tradeHandler->request(being);
734
    tradePartnerName = mTradeNick;
735
    mTradeNick.clear();
736
}
737
738
void ShopWindow::giveList(const std::string &nick, const int mode)
739
{
740
    if (!checkFloodCounter(mLastRequestTimeList))
741
        return;
742
743
    std::string data("\302\202");
744
745
    ShopItems *list;
746
    if (mode == BUY)
747
    {
748
        list = mBuyShopItems;
749
        data.append("S1");
750
    }
751
    else
752
    {
753
        list = mSellShopItems;
754
        data.append("B1");
755
    }
756
    if (list == nullptr)
757
        return;
758
759
    const Inventory *const inv = PlayerInfo::getInventory();
760
    if (inv == nullptr)
761
        return;
762
763
    STD_VECTOR<ShopItem*> items = list->items();
764
765
    FOR_EACH (STD_VECTOR<ShopItem*>::const_iterator, it, items)
766
    {
767
        const ShopItem *const item = *(it);
768
        if (item == nullptr)
769
            continue;
770
771
        if (mode == SELL)
772
        {
773
            const Item *const item2 = inv->findItem(item->getId(),
774
                ItemColor_zero);
775
            if (item2 != nullptr)
776
            {
777
                int amount = item->getQuantity();
778
                if (item2->getQuantity() < amount)
779
                    amount = item2->getQuantity();
780
781
                if (amount != 0)
782
                {
783
                    data.append(strprintf("%s%s%s",
784
                        encodeStr(item->getId(), 2).c_str(),
785
                        encodeStr(item->getPrice(), 4).c_str(),
786
                        encodeStr(amount, 3).c_str()));
787
                }
788
            }
789
        }
790
        else
791
        {
792
            int amount = item->getQuantity();
793
            if (item->getPrice() * amount > PlayerInfo::getAttribute(
794
                Attributes::MONEY))
795
            {
796
                amount = PlayerInfo::getAttribute(Attributes::MONEY)
797
                    / item->getPrice();
798
            }
799
800
            if (amount > 0)
801
            {
802
                data.append(strprintf("%s%s%s",
803
                    encodeStr(item->getId(), 2).c_str(),
804
                    encodeStr(item->getPrice(), 4).c_str(),
805
                    encodeStr(amount, 3).c_str()));
806
            }
807
        }
808
    }
809
    sendMessage(nick, data, true);
810
}
811
812
void ShopWindow::sendMessage(const std::string &nick,
813
                             std::string data,
814
                             const bool random)
815
{
816
    if (chatWindow == nullptr)
817
        return;
818
819
    if (random)
820
    {
821
        mRandCounter ++;
822
        if (mRandCounter > 200)
823
            mRandCounter = 0;
824
        data.append(encodeStr(mRandCounter, 2));
825
    }
826
827
    if (config.getBoolValue("hideShopMessages"))
828
        chatHandler->privateMessage(nick, data);
829
    else
830
        chatWindow->addWhisper(nick, data, ChatMsgType::BY_PLAYER);
831
}
832
833
void ShopWindow::showList(const std::string &nick, std::string data)
834
{
835
    const Inventory *const inv = PlayerInfo::getInventory();
836
    if (inv == nullptr)
837
        return;
838
839
    BuyDialog *buyDialog = nullptr;
840
    SellDialog *sellDialog = nullptr;
841
    if (data.find("B1") == 0)
842
    {
843
        data = data.substr(2);
844
        CREATEWIDGETV(buyDialog, BuyDialog, nick, DEFAULT_CURRENCY);
845
    }
846
    else if (data.find("S1") == 0)
847
    {
848
        data = data.substr(2);
849
        CREATEWIDGETV(sellDialog, ShopSellDialog, nick);
850
    }
851
    else
852
    {
853
        return;
854
    }
855
856
    if (buyDialog != nullptr)
857
        buyDialog->setMoney(PlayerInfo::getAttribute(Attributes::MONEY));
858
    if (sellDialog != nullptr)
859
        sellDialog->setMoney(PlayerInfo::getAttribute(Attributes::MONEY));
860
861
    for (unsigned f = 0; f < data.length(); f += 9)
862
    {
863
        if (f + 9 > data.length())
864
            break;
865
866
        const int id = decodeStr(data.substr(f, 2));
867
        const int price = decodeStr(data.substr(f + 2, 4));
868
        int amount = decodeStr(data.substr(f + 6, 3));
869
        if (buyDialog != nullptr && amount > 0)
870
        {
871
            buyDialog->addItem(id,
872
                ItemType::Unknown,
873
                ItemColor_one,
874
                amount,
875
                price);
876
        }
877
        if (sellDialog != nullptr)
878
        {
879
            const Item *const item = inv->findItem(id, ItemColor_zero);
880
            if (item != nullptr)
881
            {
882
                if (item->getQuantity() < amount)
883
                    amount = item->getQuantity();
884
            }
885
            else
886
            {
887
                amount = 0;
888
            }
889
            ShopItem *const shopItem = sellDialog->addItem(id,
890
                ItemType::Unknown,
891
                ItemColor_one,
892
                amount,
893
                price);
894
895
            if (shopItem != nullptr && amount <= 0)
896
                shopItem->setDisabled(true);
897
        }
898
    }
899
    if (buyDialog != nullptr)
900
        buyDialog->sort();
901
}
902
903
void ShopWindow::processRequest(const std::string &nick,
904
                                std::string data,
905
                                const int mode)
906
{
907
    if (localPlayer == nullptr ||
908
        !mTradeNick.empty() ||
909
        PlayerInfo::isTrading() == Trading_true ||
910
        actorManager == nullptr ||
911
        actorManager->findBeingByName(nick, ActorType::Player) == nullptr)
912
    {
913
        return;
914
    }
915
916
    const Inventory *const inv = PlayerInfo::getInventory();
917
    if (inv == nullptr)
918
        return;
919
920
    const size_t idx = data.find(' ');
921
    if (idx == std::string::npos)
922
        return;
923
924
    if (!checkFloodCounter(mLastRequestTimeItem))
925
        return;
926
927
    if (!mTradeNick.empty())
928
    {
929
        sendMessage(nick,
930
            // TRANSLATORS: error buy/sell shop request
931
            _("error: player busy") + std::string(" "),
932
            true);
933
        return;
934
    }
935
936
    data = data.substr(idx + 1);
937
938
    std::string part1;
939
    std::string part2;
940
    std::string part3;
941
    std::stringstream ss(data);
942
    int id;
943
    int price;
944
    int amount;
945
946
    if (!(ss >> part1))
947
        return;
948
949
    if (!(ss >> part2))
950
        return;
951
952
    if (!(ss >> part3))
953
        return;
954
955
    id = atoi(part1.c_str());
956
    price = atoi(part2.c_str());
957
    amount = atoi(part3.c_str());
958
959
    delete mTradeItem;
960
    // +++ need impliment colors?
961
    mTradeItem = new ShopItem(-1,
962
        id,
963
        ItemType::Unknown,
964
        ItemColor_one,
965
        amount,
966
        price,
967
        DEFAULT_CURRENCY);
968
969
    if (mode == BUY)
970
    {
971
        // +++ need support for colors
972
        const Item *const item2 = inv->findItem(mTradeItem->getId(),
973
            ItemColor_zero);
974
        if (item2 == nullptr ||
975
            item2->getQuantity() < amount ||
976
            !findShopItem(mTradeItem, SELL))
977
        {
978
            sendMessage(nick,
979
                // TRANSLATORS: error buy/sell shop request
980
                _("error: Can't sell this item") + std::string(" "),
981
                true);
982
            return;
983
        }
984
        mTradeMoney = 0;
985
    }
986
    else
987
    {
988
        if (!findShopItem(mTradeItem, BUY))
989
        {
990
            sendMessage(nick,
991
                // TRANSLATORS: error buy/sell shop request
992
                _("error: Can't buy this item") + std::string(" "),
993
                true);
994
            return;
995
        }
996
        mTradeMoney = mTradeItem->getPrice() * mTradeItem->getQuantity();
997
    }
998
999
    mTradeNick = nick;
1000
1001
    if (config.getBoolValue("autoShop"))
1002
    {
1003
        soundManager.playGuiSound(SOUND_TRADE);
1004
        startTrade();
1005
    }
1006
    else
1007
    {
1008
        std::string msg;
1009
        if (mode == BUY)
1010
        {
1011
            // TRANSLATORS: buy shop request (nick, item)
1012
            msg = strprintf(_("%s wants to buy %s do you accept?"),
1013
                nick.c_str(),
1014
                mTradeItem->getInfo().getName().c_str());
1015
        }
1016
        else
1017
        {
1018
            // TRANSLATORS: sell shop request (nick, item)
1019
            msg = strprintf(_("%s wants to sell %s do you accept?"),
1020
                nick.c_str(),
1021
                mTradeItem->getInfo().getName().c_str());
1022
        }
1023
1024
        ConfirmDialog *const confirmDlg = CREATEWIDGETR(ConfirmDialog,
1025
            // TRANSLATORS: shop window dialog
1026
            _("Request for Trade"),
1027
            msg,
1028
            SOUND_REQUEST,
1029
            true);
1030
        confirmDlg->addActionListener(this);
1031
    }
1032
}
1033
1034
void ShopWindow::updateTimes()
1035
{
1036
    BLOCK_START("ShopWindow::updateTimes")
1037
    if (mAnnounceButton == nullptr)
1038
    {
1039
        BLOCK_END("ShopWindow::updateTimes")
1040
        return;
1041
    }
1042
    if (mAnnonceTime + (2 * 60) < cur_time ||
1043
        mAnnonceTime > cur_time)
1044
    {
1045
        mAnnounceButton->setEnabled(true);
1046
    }
1047
    BLOCK_END("ShopWindow::updateTimes")
1048
}
1049
1050
bool ShopWindow::checkFloodCounter(time_t &counterTime)
1051
{
1052
    if (counterTime == 0 || counterTime > cur_time)
1053
        counterTime = cur_time;
1054
    else if (counterTime + 10 > cur_time)
1055
        return false;
1056
    else
1057
        counterTime = cur_time;
1058
    return true;
1059
}
1060
1061
bool ShopWindow::findShopItem(const ShopItem *const shopItem,
1062
                              const int mode) const
1063
{
1064
    if (shopItem == nullptr)
1065
        return false;
1066
1067
    STD_VECTOR<ShopItem*> items;
1068
    if (mode == SELL)
1069
        items = mSellShopItems->items();
1070
    else
1071
        items = mBuyShopItems->items();
1072
1073
    FOR_EACH (STD_VECTOR<ShopItem*>::const_iterator, it, items)
1074
    {
1075
        const ShopItem *const item = *(it);
1076
        if (item == nullptr)
1077
            continue;
1078
1079
        if (item->getId() == shopItem->getId()
1080
            && item->getPrice() == shopItem->getPrice()
1081
            && item->getQuantity() >= shopItem->getQuantity())
1082
        {
1083
            return true;
1084
        }
1085
    }
1086
    return false;
1087
}
1088
#endif  // TMWA_SUPPORT
1089
1090
int ShopWindow::sumAmount(const Item *const shopItem)
1091
{
1092
    if ((localPlayer == nullptr) || (shopItem == nullptr))
1093
        return 0;
1094
1095
    const Inventory *const inv = PlayerInfo::getInventory();
1096
    if (inv == nullptr)
1097
        return 0;
1098
    int sum = 0;
1099
1100
    for (unsigned f = 0; f < inv->getSize(); f ++)
1101
    {
1102
        const Item *const item = inv->getItem(f);
1103
        if ((item != nullptr) && item->getId() == shopItem->getId())
1104
            sum += item->getQuantity();
1105
    }
1106
    return sum;
1107
}
1108
1109
bool ShopWindow::isShopEmpty() const
1110
{
1111
    if (mBuyShopItems->empty() && mSellShopItems->empty())
1112
        return true;
1113
    return false;
1114
}
1115
1116
2
void ShopWindow::updateSelection()
1117
{
1118
2
    if (isBuySelected)
1119
2
        mCurrentShopItemList = mBuyShopItemList;
1120
    else
1121
        mCurrentShopItemList = mSellShopItemList;
1122
2
    mScrollArea->setContent(mCurrentShopItemList);
1123
2
    updateButtonsAndLabels();
1124
2
}
1125
1126
2
void ShopWindow::updateShopName()
1127
{
1128
4
    if (mSellShopName.empty())
1129
    {
1130
        // TRANSLATORS: shop window name
1131
        setCaption(_("Personal Shop"));
1132
    }
1133
    else
1134
    {
1135
        // TRANSLATORS: shop window name
1136
8
        setCaption(strprintf(_("Personal Shop - %s"), mSellShopName.c_str()));
1137
    }
1138
2
}
1139
1140
void ShopWindow::setShopName(const std::string &name)
1141
{
1142
    mSellShopName = name;
1143
    serverConfig.setValue("sellShopName", mSellShopName);
1144
    updateShopName();
1145
}
1146
1147
void ShopWindow::vendingSlotsChanged(const int slots)
1148
{
1149
    mSellShopSize = slots;
1150
    updateButtonsAndLabels();
1151
}
1152
1153
void ShopWindow::vendingEnabled(const bool b)
1154
{
1155
    mEnableVending = b;
1156
    localPlayer->enableShop(b);
1157
    if (!b)
1158
        mSellShopSize = 0;
1159
    updateButtonsAndLabels();
1160
}
1161
1162
void ShopWindow::buyingStoreSlotsChanged(const int slots)
1163
{
1164
    mBuyShopSize = slots;
1165
    updateButtonsAndLabels();
1166
}
1167
1168
void ShopWindow::buyingStoreEnabled(const bool b)
1169
{
1170
    mEnableBuyingStore = b;
1171
    localPlayer->enableShop(b);
1172
    if (!b)
1173
        mBuyShopSize = 0;
1174
    updateButtonsAndLabels();
1175

6
}