EconomyFreeMarket.cpp

Go to the documentation of this file.
00001 ///////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <weapons/EconomyFreeMarket.h>
00022 #include <weapons/AccessoryStore.h>
00023 #include <server/ScorchedServer.h>
00024 #include <common/Defines.h>
00025 #include <common/OptionsScorched.h>
00026 #include <common/Logger.h>
00027 #include <XML/XMLFile.h>
00028 #include <XML/XMLParser.h>
00029 #include <tank/Tank.h>
00030 #include <tank/TankScore.h>
00031 #include <tank/TankAccessories.h>
00032 #include <stdlib.h>
00033 
00034 REGISTER_CLASS_SOURCE(EconomyFreeMarket);
00035 
00036 static std::string getEconomyFileName()
00037 {
00038         return S3D::getSettingsFile(S3D::formatStringBuffer("freemarket-%s-%i.xml",
00039                 ScorchedServer::instance()->getOptionsGame().getMod(),
00040                 ScorchedServer::instance()->getOptionsGame().getPortNo()));
00041 }
00042 
00043 static bool validAccessory(Accessory *accessory)
00044 {
00045         return 
00046                 accessory->getStartingNumber() != -1 &&
00047                 accessory->getMaximumNumber() != 0 &&
00048                 !accessory->getAIOnly() &&
00049                 !accessory->getBotOnly();
00050 }
00051 
00052 EconomyFreeMarket::EconomyFreeMarket()
00053 {
00054 }
00055 
00056 EconomyFreeMarket::~EconomyFreeMarket()
00057 {
00058 }
00059 
00060 bool EconomyFreeMarket::loadPrices()
00061 {
00062         // Parse the file containing the last used prices
00063         XMLFile file;
00064         if (!file.readFile(getEconomyFileName()))
00065         {
00066                 S3D::dialogMessage("EconomyFreeMarket", S3D::formatStringBuffer(
00067                         "Failed to parse freemarket.xml file : %s",
00068                         file.getParserError()));
00069                 return false;
00070         }
00071 
00072         // If there are entries in the file
00073         economyPrices_.clear();
00074         XMLNode *rootnode = file.getRootNode();
00075         if (rootnode)
00076         {
00077                 std::list<XMLNode *> &nodes = rootnode->getChildren();
00078                 std::list<XMLNode *>::iterator itor;
00079                 for (itor = nodes.begin();
00080                         itor != nodes.end();
00081                         itor++)
00082                 {
00083                         XMLNode *node = *itor;
00084                         XMLNode *nameNode, *buyNode;
00085                         if (!node->getNamedChild("name", nameNode)) return false;
00086                         if (!node->getNamedChild("buyprice", buyNode)) return false;
00087 
00088                         Accessory *accessory = ScorchedServer::instance()->getAccessoryStore().
00089                                 findByPrimaryAccessoryName(nameNode->getContent());
00090                         if (accessory)
00091                         {       
00092                                 // Check that this accessory is still valid
00093                                 // (just in case the file has been changed)
00094                                 if (validAccessory(accessory))
00095                                 {
00096                                         // Set the actual accessory price (based on the last used market prices)
00097                                         int price = atoi(buyNode->getContent());
00098                                         economyPrices_[accessory->getAccessoryId()] = price;
00099                                 }
00100                         }
00101                 }
00102         }
00103         calculatePrices();
00104 
00105         return true;    
00106 }
00107 
00108 bool EconomyFreeMarket::savePrices()
00109 {
00110         FileLines file;
00111         file.addLine("<prices source=\"Scorched3D\">");
00112         std::map<unsigned int, int>::iterator itor;
00113         for (itor = economyPrices_.begin();
00114                 itor != economyPrices_.end();
00115                 itor++)
00116         {
00117                 unsigned int accessoryId = itor->first;
00118                 int price = itor->second;
00119 
00120                 Accessory *accessory = 
00121                         ScorchedServer::instance()->getAccessoryStore().findByAccessoryId(accessoryId);
00122                 if (accessory && validAccessory(accessory))
00123                 {
00124                         std::string cleanName;
00125                         std::string dirtyName(accessory->getName());
00126                         XMLNode::removeSpecialChars(dirtyName, cleanName);
00127                         file.addLine("  <accessory>");
00128                         file.addLine(S3D::formatStringBuffer("    <!-- %s, original Price %i -->", 
00129                                 cleanName.c_str(), accessory->getOriginalPrice()));
00130                         file.addLine(S3D::formatStringBuffer("    <name>%s</name>", cleanName.c_str()));
00131                         file.addLine(S3D::formatStringBuffer("    <buyprice>%i</buyprice>", price));
00132                         file.addLine("  </accessory>");
00133                 }
00134         }
00135         file.addLine("</prices>");
00136 
00137         if (!file.writeFile(getEconomyFileName())) return false;
00138 
00139         return true;
00140 }
00141 
00142 void EconomyFreeMarket::calculatePrices()
00143 {
00144         std::map<unsigned int, int>::iterator itor;
00145         for (itor = economyPrices_.begin();
00146                 itor != economyPrices_.end();
00147                 itor++)
00148         {
00149                 unsigned int accessoryId = itor->first;
00150                 int price = itor->second;
00151 
00152                 Accessory *accessory = 
00153                         ScorchedServer::instance()->getAccessoryStore().findByAccessoryId(accessoryId);
00154                 if (accessory && validAccessory(accessory))
00155                 {
00156                         setPrice(accessory, price);
00157                 }
00158         }
00159 }
00160 
00161 void EconomyFreeMarket::accessoryBought(Tank *tank, 
00162                 const char *accessoryName)
00163 {
00164         // Find the bought accessory
00165         Accessory *boughtAccessory = 
00166                 ScorchedServer::instance()->getAccessoryStore().
00167                 findByPrimaryAccessoryName(accessoryName);
00168         DIALOG_ASSERT(boughtAccessory);
00169 
00170         // Find the list of accessories that this player could have bought
00171         // This list comprises of weapons that are similar in price to the one
00172         // that has been bought
00173         std::list<Accessory *> possibleAccessories;
00174         {
00175                 std::list<Accessory *> weapons = 
00176                         ScorchedServer::instance()->getAccessoryStore().
00177                         getAllAccessories();
00178                 std::list<Accessory *>::iterator itor;
00179                 for (itor = weapons.begin();
00180                         itor != weapons.end();
00181                         itor++)
00182                 {
00183                         Accessory *accessory = *itor;
00184 
00185                         int accessoryPrice = 
00186                                 accessory->getOriginalPrice() / accessory->getBundle(); 
00187                         int boughtAccessoryPrice = 
00188                                 boughtAccessory->getOriginalPrice() / accessory->getBundle(); 
00189                         if (accessoryPrice >= int(float(boughtAccessoryPrice) * 0.33f) && 
00190                                 accessoryPrice <= int(float(boughtAccessoryPrice) * 3.33f) && 
00191                                 tank->getAccessories().accessoryAllowed(accessory, accessory->getBundle()) && 
00192                                 validAccessory(accessory)) 
00193                         { 
00194                                 possibleAccessories.push_back(accessory); 
00195                         }
00196                 }
00197         }
00198 
00199         // Nothing to do if we can only buy 1 item
00200         if (possibleAccessories.size() <= 1) return;
00201 
00202         // How much should each accessory get (on average)
00203         int moneyShouldAquire = boughtAccessory->getPrice() / possibleAccessories.size();
00204         
00205         // Alter prices
00206         {
00207                 std::list<Accessory *>::iterator itor;
00208                 for (itor = possibleAccessories.begin();
00209                         itor != possibleAccessories.end();
00210                         itor++)
00211                 {
00212                         Accessory *accessory = (*itor);
00213 
00214                         // Figure out how much money was spent on this weapon
00215                         int moneyDidAquire = 0;
00216                         if (accessory == boughtAccessory) moneyDidAquire = 
00217                                 boughtAccessory->getPrice();
00218 
00219                         // Figure out if this is more or less money than on average
00220                         // should be spent on this weapon
00221                         int adjustment = 
00222                                 ScorchedServer::instance()->getOptionsGame().
00223                                 getFreeMarketAdjustment();
00224                         int priceDiff = 0;
00225                         if (moneyDidAquire < moneyShouldAquire)
00226                         {
00227                                 // This weapon was not bought, decrease its price
00228                                 priceDiff = -adjustment / int(possibleAccessories.size());
00229                                 //priceDiff /= 2;
00230                         }
00231                         else if (moneyDidAquire >= moneyShouldAquire)
00232                         {
00233                                 // This weapon was bought, increase its price
00234                                 priceDiff = int((float(adjustment) * (float(possibleAccessories.size()) - 1.0f))
00235                                         / float(possibleAccessories.size()));
00236                         }
00237 
00238                         // Update the price difference for this weapon
00239                         std::map<unsigned int, int>::iterator findItor = 
00240                                 economyPrices_.find(accessory->getAccessoryId());
00241                         if (findItor == economyPrices_.end()) 
00242                         {
00243                                 economyPrices_[accessory->getAccessoryId()] = 
00244                                         accessory->getOriginalPrice() + priceDiff;
00245                         }
00246                         else 
00247                         {
00248                                 economyPrices_[accessory->getAccessoryId()] += 
00249                                         priceDiff;
00250                         }
00251                 }
00252         }
00253 }
00254 
00255 void EconomyFreeMarket::setPrice(Accessory *accessory, int price)
00256 {
00257         float limit = float(accessory->getFreeMarketLimits()) / 100.0f;
00258         limit *= ScorchedServer::instance()->getOptionsGame().getFreeMarketLimits();
00259         if (limit == 0) // No limits accessory should stay at fixed price
00260         {
00261                 price = accessory->getOriginalPrice();
00262         }
00263         else // Make sure price is within limits
00264         {
00265                 // Make suse price does not get greater than 1.5X the original price
00266                 if (price > int(float(accessory->getOriginalPrice()) * limit))
00267                         price = int(float(accessory->getOriginalPrice()) * limit);
00268                 // Make sure price does not get lower than 1.5X the original price
00269                 else if (price < int(float(accessory->getOriginalPrice()) / limit))
00270                         price = int(float(accessory->getOriginalPrice()) / limit);
00271         }
00272         price = (price / 10) * 10; // Round to 10
00273 
00274         // Set Buy Price
00275         accessory->setPrice(price);
00276 
00277         // Set sell price to 0.8X the buy price
00278         int selPrice = int(float(accessory->getPrice()) /
00279                 float(accessory->getBundle()) * 0.8f);
00280         selPrice = (selPrice / 10) * 10; // Round to 10
00281         accessory->setSellPrice(selPrice);
00282 }
00283 
00284 void EconomyFreeMarket::accessorySold(Tank *tank, 
00285                 const char *accessoryName)
00286 {
00287         // Do nothing (yet) on a sold item
00288 }
00289 

Generated on Mon Feb 16 15:14:52 2009 for Scorched3D by  doxygen 1.5.3