From 3eeae12c498d1a4dbe969462d2ba841f77ee3ccb Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Sun, 2 Jan 2011 01:48:38 +0200 Subject: Initial commit. This code based on mana client http://www.gitorious.org/mana/mana and my private repository. --- src/gui/shopwindow.cpp | 788 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 788 insertions(+) create mode 100644 src/gui/shopwindow.cpp (limited to 'src/gui/shopwindow.cpp') diff --git a/src/gui/shopwindow.cpp b/src/gui/shopwindow.cpp new file mode 100644 index 000000000..410e79dbb --- /dev/null +++ b/src/gui/shopwindow.cpp @@ -0,0 +1,788 @@ +/* + * The Mana Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/shopwindow.h" + +#include "gui/buy.h" +#include "gui/itemamount.h" +#include "gui/sell.h" +#include "gui/setup.h" +#include "gui/trade.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/chattab.h" +#include "gui/widgets/checkbox.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/shopitems.h" +#include "gui/widgets/shoplistbox.h" +#include "gui/widgets/slider.h" +#include "gui/widgets/tradetab.h" + +#include "actorspritemanager.h" +#include "configuration.h" +#include "confirmdialog.h" +#include "inventory.h" +#include "item.h" +#include "localplayer.h" +#include "playerinfo.h" +#include "playerrelations.h" +#include "shopitem.h" +#include "sound.h" +#include "units.h" + +#include "net/net.h" +#include "net/chathandler.h" +#include "net/npchandler.h" +#include "net/tradehandler.h" + +#include "resources/iteminfo.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include + +#include + +extern std::string tradePartnerName; +ShopWindow::DialogList ShopWindow::instances; + +ShopWindow::ShopWindow(): + Window(_("Personal Shop")), + mSelectedItem(-1), + mAnnonceTime(0), + mLastRequestTimeList(0), + mLastRequestTimeItem(0), + mRandCounter(0), + mAcceptPlayer(""), + mTradeItem(0), + mTradeNick(""), + mTradeMoney(0) +{ + setWindowName("Personal Shop"); + setResizable(true); + setCloseButton(true); + setMinWidth(260); + setMinHeight(230); + setDefaultSize(380, 300, ImageRect::CENTER); + + mBuyShopItems = new ShopItems; + mSellShopItems = new ShopItems; + + mAnnounceCounter[BUY] = 0; + mAnnounceCounter[SELL] = 0; + + loadList(); + + mBuyShopItemList = new ShopListBox(mBuyShopItems, mBuyShopItems); + mSellShopItemList = new ShopListBox(mSellShopItems, mSellShopItems); + + mBuyShopItemList->setPriceCheck(false); + mSellShopItemList->setPriceCheck(false); + + mBuyScrollArea = new ScrollArea(mBuyShopItemList); + mBuyScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mSellScrollArea = new ScrollArea(mSellShopItemList); + mSellScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + mCloseButton = new Button(_("Close"), "close", this); + + mBuyShopItemList->addSelectionListener(this); + mSellShopItemList->addSelectionListener(this); + + mBuyLabel = new Label(_("Buy items")); + mSellLabel = new Label(_("Sell items")); + + mBuyAddButton = new Button(_("Add"), "add buy", this); + mBuyDeleteButton = new Button(_("Delete"), "delete buy", this); + mBuyAnnounceButton = new Button(_("Announce"), "announce buy", this); + mSellAddButton = new Button(_("Add"), "add sell", this); + mSellDeleteButton = new Button(_("Delete"), "delete sell", this); + mSellAnnounceButton = new Button(_("Announce"), "announce sell", this); + mAnnounceLinks = new CheckBox(_("Show links in announce"), false, + this, "link announce"); + + ContainerPlacer place; + place = getPlacer(0, 0); + + place(0, 0, mBuyLabel, 8).setPadding(3); + place(8, 0, mSellLabel, 8).setPadding(3); + place(0, 1, mBuyScrollArea, 8, 5).setPadding(3); + place(8, 1, mSellScrollArea, 8, 5).setPadding(3); + place(0, 6, mBuyAddButton); + place(1, 6, mBuyDeleteButton); + place(3, 6, mBuyAnnounceButton); + place(8, 6, mSellAddButton); + place(9, 6, mSellDeleteButton); + place(11, 6, mSellAnnounceButton); + place(0, 7, mAnnounceLinks, 8); + place(15, 7, mCloseButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + center(); + loadWindowState(); + + instances.push_back(this); + setVisible(false); + + updateButtonsAndLabels(); +} + +ShopWindow::~ShopWindow() +{ + saveList(); + + delete mBuyShopItems; + mBuyShopItems = 0; + + delete mSellShopItems; + mSellShopItems = 0; + + instances.remove(this); +} + +void ShopWindow::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "close") + { + close(); + return; + } + + if (event.getId() == "yes") + { + startTrade(); + } + else if (event.getId() == "no") + { + mTradeNick = ""; + } + else if (event.getId() == "ignore") + { + player_relations.ignoreTrade(mTradeNick); + mTradeNick = ""; + } + else if (event.getId() == "delete buy" && mBuyShopItemList + && mBuyShopItemList->getSelected() >= 0) + { + mBuyShopItems->erase(mBuyShopItemList->getSelected()); + } + else if (event.getId() == "delete sell" && mSellShopItemList + && mSellShopItemList->getSelected() >= 0) + { + mSellShopItems->erase(mSellShopItemList->getSelected()); + } + else if (event.getId() == "announce buy" && mBuyShopItems + && mBuyShopItems->getNumberOfElements() > 0) + { + announce(mBuyShopItems, BUY); + } + else if (event.getId() == "announce sell" && mSellShopItems + && mSellShopItems->getNumberOfElements() > 0) + { + announce(mSellShopItems, SELL); + } + + if (mSelectedItem < 1) + return; + + Inventory *inv = PlayerInfo::getInventory(); + if (!inv) + return; + + Item *item = inv->findItem(mSelectedItem); + if (item) + { + if (event.getId() == "add buy") + { + ItemAmountWindow::showWindow(ItemAmountWindow::ShopBuyAdd, + this, item, sumAmount(item)); + } + else if (event.getId() == "add sell") + { + ItemAmountWindow::showWindow(ItemAmountWindow::ShopSellAdd, + this, item, sumAmount(item)); + } + } + +} + +void ShopWindow::startTrade() +{ + if (!actorSpriteManager || !tradeWindow) + return; + + Being *being = actorSpriteManager->findBeingByName( + mTradeNick, Being::PLAYER); + tradeWindow->clear(); + if (mTradeMoney) + { + tradeWindow->addAutoMoney(mTradeNick, mTradeMoney); + } + else + { + tradeWindow->addAutoItem(mTradeNick, mTradeItem, + mTradeItem->getQuantity()); + } + Net::getTradeHandler()->request(being); + tradePartnerName = mTradeNick; + mTradeNick = ""; +} + +void ShopWindow::valueChanged(const gcn::SelectionEvent &event _UNUSED_) +{ + updateButtonsAndLabels(); +} + +void ShopWindow::updateButtonsAndLabels() +{ + mBuyAddButton->setEnabled(mSelectedItem != -1); + mSellAddButton->setEnabled(mSelectedItem != -1); + mBuyDeleteButton->setEnabled( + mBuyShopItemList->getSelected() != -1 + && mBuyShopItems->getNumberOfElements() > 0); + mSellDeleteButton->setEnabled( + mSellShopItemList->getSelected() != -1 + && mSellShopItems->getNumberOfElements() > 0); +} + +void ShopWindow::setVisible(bool visible) +{ + Window::setVisible(visible); +} + +void ShopWindow::addBuyItem(Item *item, int amount, int price) +{ + if (!mBuyShopItems || !item) + return; + mBuyShopItems->addItemNoDup(item->getId(), amount, price); + updateButtonsAndLabels(); +} + +void ShopWindow::addSellItem(Item *item, int amount, int price) +{ + if (!mBuyShopItems || !item) + return; + mSellShopItems->addItemNoDup(item->getId(), amount, price); + updateButtonsAndLabels(); +} + +void ShopWindow::loadList() +{ + if (!mBuyShopItems || !mSellShopItems) + return; + + std::ifstream shopFile; + struct stat statbuf; + + mBuyShopItems->clear(); + mSellShopItems->clear(); + + std::string shopListName = Client::getServerConfigDirectory() + + "/shoplist.txt"; + + if (!stat(shopListName.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) + { + shopFile.open(shopListName.c_str(), std::ios::in); + char line[101]; + while (shopFile.getline(line, 100)) + { + std::string buf; + std::string str = line; + if (!str.empty()) + { + std::vector tokens; + + std::stringstream ss(str); + + while (ss >> buf) + tokens.push_back(atoi(buf.c_str())); + + if (tokens.size() == 5 && tokens[0]) + { + if (tokens[1] && tokens[2] && mBuyShopItems) + { + mBuyShopItems->addItem( + tokens[0], tokens[1], tokens[2]); + } + if (tokens[3] && tokens[4] && mSellShopItems) + { + mSellShopItems->addItem( + tokens[0], tokens[3], tokens[4]); + } + } + } + } + shopFile.close(); + } +} + +void ShopWindow::saveList() +{ + if (!mBuyShopItems || !mSellShopItems) + return; + + std::ofstream shopFile; + std::string shopListName = Client::getServerConfigDirectory() + + "/shoplist.txt"; + std::list procesList; + std::map mapItems; + + shopFile.open(shopListName.c_str(), std::ios::binary); + if (!shopFile.is_open()) + { + logger->log1("Unable to open shoplist.txt for writing"); + return; + } + + std::vector items = mBuyShopItems->items(); + std::vector::iterator it; + for (it = items.begin(); it != items.end(); it++) + { + ShopItem *item = *(it); + if (item) + mapItems[item->getId()] = item; + } + + items = mSellShopItems->items(); + for (it = items.begin(); it != items.end(); it++) + { + ShopItem *sellItem = *(it); + ShopItem *buyItem = mapItems[sellItem->getId()]; + + shopFile << sellItem->getId(); + if (buyItem) + { + shopFile << strprintf(" %d %d ", buyItem->getQuantity(), + buyItem->getPrice()); + mapItems.erase(sellItem->getId()); + } + else + { + shopFile << " 0 0 "; + } + + if (sellItem) + { + shopFile << strprintf("%d %d", sellItem->getQuantity(), + sellItem->getPrice()) << std::endl; + } + } + + std::map::iterator mapIt; + for (mapIt = mapItems.begin(); mapIt != mapItems.end(); mapIt++) + { + ShopItem *buyItem = (*mapIt).second; + if (buyItem) + { + shopFile << buyItem->getId(); + shopFile << strprintf(" %d %d ", buyItem->getQuantity(), + buyItem->getPrice()); + shopFile << "0 0" << std::endl; + } + } + + shopFile.close(); +} + +void ShopWindow::announce(ShopItems *list, int mode) +{ + if (!list) + return; + + std::string data = "\302\202"; + if (mode == BUY) + data += "Buy "; + else + data += "Sell "; + + if (mAnnonceTime && (mAnnonceTime + (2 * 60) > cur_time + || mAnnonceTime > cur_time)) + { + return; + } + + mAnnonceTime = cur_time; + if (mBuyAnnounceButton) + mBuyAnnounceButton->setEnabled(false); + if (mSellAnnounceButton) + mSellAnnounceButton->setEnabled(false); + + std::vector items = list->items(); + std::vector::iterator it; + + for (it = items.begin(); it != items.end(); it++) + { + ShopItem *item = *(it); + if (item->getQuantity() > 1) + { + if (mAnnounceLinks->isSelected()) + { + data += strprintf("[@@%d|%s@@] (%dGP) %d, ", item->getId(), + item->getInfo().getName().c_str(), + item->getPrice(), item->getQuantity()); + } + else + { + data += strprintf("%s (%dGP) %d, ", + item->getInfo().getName().c_str(), + item->getPrice(), item->getQuantity()); + } + } + else + { + if (mAnnounceLinks->isSelected()) + { + data += strprintf("[@@%d|%s@@] (%dGP), ", item->getId(), + item->getInfo().getName().c_str(), + item->getPrice()); + } + else + { + data += strprintf("%s (%dGP), ", + item->getInfo().getName().c_str(), + item->getPrice()); + } + } + } + + Net::getChatHandler()->talk(data); +} + +void ShopWindow::giveList(const std::string &nick, int mode) +{ + if (!checkFloodCounter(mLastRequestTimeList)) + return; + + std::string data = "\302\202"; + + ShopItems *list; + if (mode == BUY) + { + list = mBuyShopItems; + data += "S1"; + } + else + { + list = mSellShopItems; + data += "B1"; + } + if (!list) + return; + + Inventory *inv = PlayerInfo::getInventory(); + if (!inv) + return; + + std::vector items = list->items(); + std::vector::iterator it; + + for (it = items.begin(); it != items.end(); it++) + { + ShopItem *item = *(it); + if (!item) + continue; + + if (mode == SELL) + { + Item *item2 = inv->findItem(item->getId()); + if (item2) + { + int amount = item->getQuantity(); + if (item2->getQuantity() < amount) + amount = item2->getQuantity(); + + if (amount) + { + data += strprintf("%s%s%s", + encodeStr(item->getId(), 2).c_str(), + encodeStr(item->getPrice(), 4).c_str(), + encodeStr(amount, 3).c_str()); + } + } + } + else + { + int amount = item->getQuantity(); + if (item->getPrice() * amount > PlayerInfo::getAttribute(MONEY)) + amount = PlayerInfo::getAttribute(MONEY) / item->getPrice(); + + if (amount > 0) + { + data += strprintf("%s%s%s", + encodeStr(item->getId(), 2).c_str(), + encodeStr(item->getPrice(), 4).c_str(), + encodeStr(amount, 3).c_str()); + } + } + } + sendMessage(nick, data, true); +} + +void ShopWindow::sendMessage(const std::string &nick, + std::string data, bool random) +{ + if (!chatWindow) + return; + + if (random) + { + mRandCounter ++; + if (mRandCounter > 200) + mRandCounter = 0; + data += encodeStr(mRandCounter, 2); + } + + if (config.getBoolValue("hideShopMessages")) + Net::getChatHandler()->privateMessage(nick, data); + else if (chatWindow) + chatWindow->whisper(nick, data, BY_PLAYER); +//here was true +} + +void ShopWindow::showList(const std::string &nick, std::string data) +{ + BuyDialog *buyDialog = 0; + SellDialog *sellDialog = 0; + if (data.find("B1") == 0) + { + data = data.substr(2); + buyDialog = new BuyDialog(nick); + } + else if (data.find("S1") == 0) + { + data = data.substr(2); + sellDialog = new SellDialog(nick); + } + else + { + return; + } + + Inventory *inv = PlayerInfo::getInventory(); + if (!inv) + return; + + if (buyDialog) + buyDialog->setMoney(PlayerInfo::getAttribute(MONEY)); + if (sellDialog) + sellDialog->setMoney(PlayerInfo::getAttribute(MONEY)); + + for (unsigned f = 0; f < data.length(); f += 9) + { + if (f + 9 > data.length()) + break; + + int id = decodeStr(data.substr(f, 2)); + int price = decodeStr(data.substr(f + 2, 4)); + int amount = decodeStr(data.substr(f + 6, 3)); + if (buyDialog && amount > 0) + buyDialog->addItem(id, amount, price); + if (sellDialog) + { + Item *item = inv->findItem(id); + if (item) + { + if (item->getQuantity() < amount) + amount = item->getQuantity(); + if (amount > 0) + sellDialog->addItem(id, amount, price); + else + sellDialog->addItem(id, -1, price); + } + } + } +} + +void ShopWindow::processRequest(std::string nick, std::string data, int mode) +{ + if (!player_node || !mTradeNick.empty() || PlayerInfo::isTrading() + || !actorSpriteManager + || !actorSpriteManager->findBeingByName(nick, Being::PLAYER)) + { + return; + } + + Inventory *inv = PlayerInfo::getInventory(); + if (!inv) + return; + + unsigned long idx = 0; + + idx = data.find(" "); + if (idx == std::string::npos) + return; + + if (!checkFloodCounter(mLastRequestTimeItem)) + return; + + if (!mTradeNick.empty()) + { + sendMessage(nick, "error: player busy ", true); + return; + } + + data = data.substr(idx + 1); + + std::string part1; + std::string part2; + std::string part3; + std::stringstream ss(data); + std::string msg; + int id; + int price; + int amount; + + if (!(ss >> part1)) + return; + + if (!(ss >> part2)) + return; + + if (!(ss >> part3)) + return; + + id = atoi(part1.c_str()); + price = atoi(part2.c_str()); + amount = atoi(part3.c_str()); + + delete mTradeItem; + mTradeItem = new ShopItem(-1, id, amount, price); + + if (mode == BUY) + { + Item *item2 = inv->findItem(mTradeItem->getId()); + if (!item2 || item2->getQuantity() < amount + || !findShopItem(mTradeItem, SELL)) + { + sendMessage(nick, "error: Cant sell this item ", true); + return; + } + msg = "buy"; + mTradeMoney = 0; + } + else + { + if (!findShopItem(mTradeItem, BUY)) + { + sendMessage(nick, "error: Cant buy this item ", true); + return; + } + msg = "sell"; + mTradeMoney = mTradeItem->getPrice() * mTradeItem->getQuantity(); + } + + mTradeNick = nick; + + if (config.getBoolValue("autoShop")) + { + sound.playGuiSfx("system/newmessage.ogg"); + startTrade(); + } + else + { + ConfirmDialog *confirmDlg = new ConfirmDialog(_("Request for Trade"), + strprintf(_("%s wants to %s %s do you " + "accept?"), nick.c_str(), msg.c_str(), + mTradeItem->getInfo().getName().c_str()), true); + confirmDlg->addActionListener(this); + } +} + +void ShopWindow::updateTimes() +{ + if (mAnnonceTime + (2 * 60) < cur_time + || mAnnonceTime > cur_time) + { + mBuyAnnounceButton->setEnabled(true); + mSellAnnounceButton->setEnabled(true); + } +} + +bool ShopWindow::checkFloodCounter(int &counterTime) +{ + if (!counterTime || counterTime > cur_time) + counterTime = cur_time; + else if (counterTime + 10 > cur_time) + return false; + + counterTime = cur_time; + return true; +} + +bool ShopWindow::findShopItem(ShopItem *shopItem, int mode) +{ + if (!shopItem) + return false; + + std::vector items; + std::vector::iterator it; + if (mode == SELL) + { + if (!mSellShopItems) + return false; + items = mSellShopItems->items(); + } + else + { + if (!mBuyShopItems) + return false; + items = mBuyShopItems->items(); + } + + for (it = items.begin(); it != items.end(); it++) + { + ShopItem *item = *(it); + if (!item) + continue; + + if (item && item->getId() == shopItem->getId() + && item->getPrice() == shopItem->getPrice() + && item->getQuantity() >= shopItem->getQuantity()) + { + return true; + } + } + return false; +} + +int ShopWindow::sumAmount(Item *shopItem) +{ + if (!player_node || !shopItem) + return 0; + + Inventory *inv = PlayerInfo::getInventory(); + if (!inv) + return 0; + int sum = 0; + + for (unsigned f = 0; f < inv->getSize(); f ++) + { + Item *item = inv->getItem(f); + if (item && item->getId() == shopItem->getId()) + sum += item->getQuantity(); + } + return sum; +} -- cgit v1.2.3-60-g2f50