cp_market.c

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2002-2010 UFO: Alien Invasion.
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019 See the GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024 
00025 */
00026 
00027 #include "../cl_shared.h"
00028 #include "../ui/ui_main.h"
00029 #include "../ui/ui_popup.h"
00030 #include "../cl_inventory.h" /* INV_GetEquipmentDefinitionByID */
00031 #include "cp_campaign.h"
00032 #include "cp_market.h"
00033 #include "cp_market_callbacks.h"
00034 #include "save/save_market.h"
00035 
00036 void BS_AddItemToMarket (const objDef_t *od, int amount)
00037 {
00038     assert(amount >= 0);
00039     ccs.eMarket.numItems[od->idx] += amount;
00040 }
00041 
00042 void BS_RemoveItemFromMarket (const objDef_t *od, int amount)
00043 {
00044     assert(amount >= 0);
00045     ccs.eMarket.numItems[od->idx] -= amount;
00046     if (ccs.eMarket.numItems[od->idx] < 0)
00047         ccs.eMarket.numItems[od->idx] = 0;
00048 }
00049 
00050 void BS_AddAircraftToMarket (const aircraft_t *aircraft, int amount)
00051 {
00052     const humanAircraftType_t type = Com_DropShipShortNameToID(aircraft->id);
00053     assert(amount >= 0);
00054     assert(aircraft->type != AIRCRAFT_UFO);
00055     ccs.eMarket.numAircraft[type] += amount;
00056 }
00057 
00058 void BS_RemoveAircraftFromMarket (const aircraft_t *aircraft, int amount)
00059 {
00060     const humanAircraftType_t type = Com_DropShipShortNameToID(aircraft->id);
00061     assert(amount >= 0);
00062     assert(aircraft->type != AIRCRAFT_UFO);
00063     ccs.eMarket.numAircraft[type] -= amount;
00064     if (ccs.eMarket.numAircraft[type] < 0)
00065         ccs.eMarket.numAircraft[type] = 0;
00066 }
00067 
00073 int BS_GetAircraftOnMarket (const aircraft_t *aircraft)
00074 {
00075     const humanAircraftType_t type = Com_DropShipShortNameToID(aircraft->id);
00076     assert(aircraft->type != AIRCRAFT_UFO);
00077     return ccs.eMarket.numAircraft[type];
00078 }
00079 
00085 int BS_GetAircraftSellingPrice (const aircraft_t *aircraft)
00086 {
00087     const humanAircraftType_t type = Com_DropShipShortNameToID(aircraft->id);
00088     assert(aircraft->type != AIRCRAFT_UFO);
00089     return ccs.eMarket.bidAircraft[type];
00090 }
00091 
00097 int BS_GetAircraftBuyingPrice (const aircraft_t *aircraft)
00098 {
00099     const humanAircraftType_t type = Com_DropShipShortNameToID(aircraft->id);
00100     assert(aircraft->type != AIRCRAFT_UFO);
00101     return ccs.eMarket.askAircraft[type];
00102 }
00103 
00109 int BS_GetItemSellingPrice (const objDef_t *od)
00110 {
00111     return ccs.eMarket.bidItems[od->idx];
00112 }
00113 
00119 int BS_GetItemBuyingPrice (const objDef_t *od)
00120 {
00121     return ccs.eMarket.askItems[od->idx];
00122 }
00123 
00130 qboolean BS_CheckAndDoBuyItem (base_t* base, const objDef_t *item, int number)
00131 {
00132     int numItems;
00133     const int price = BS_GetItemBuyingPrice(item);
00134 
00135     assert(base);
00136 
00137     /* you can't buy more items than there are on market */
00138     numItems = min(number, ccs.eMarket.numItems[item->idx]);
00139 
00140     /* you can't buy more items than you have credits for */
00142     if (price)
00143         numItems = min(numItems, ccs.credits / price);
00144     if (numItems <= 0)
00145         return qfalse;
00146 
00147     /* you can't buy more items than you have room for */
00149     if (item->size)
00150         numItems = min(numItems, (base->capacities[CAP_ITEMS].max - base->capacities[CAP_ITEMS].cur) / item->size);
00151     /* make sure that numItems is > 0 (can be negative because capacities.cur may be greater than
00152      * capacities.max if storage is disabled or if alien items have been collected on mission */
00153     if (numItems <= 0) {
00154         UI_Popup(_("Not enough storage space"), _("You cannot buy this item.\nNot enough space in storage.\nBuild more storage facilities."));
00155         return qfalse;
00156     }
00157 
00158     B_UpdateStorageAndCapacity(base, item, numItems, qfalse, qfalse);
00159     BS_RemoveItemFromMarket(item, numItems);
00160     CL_UpdateCredits(ccs.credits - price * numItems);
00161     return qtrue;
00162 }
00163 
00164 
00169 void BS_ProcessCraftItemSale (const objDef_t *craftitem, const int numItems)
00170 {
00171     if (craftitem) {
00172         BS_AddItemToMarket(craftitem, numItems);
00173         CL_UpdateCredits(ccs.credits + BS_GetItemSellingPrice(craftitem) * numItems);
00174     }
00175 }
00176 
00183 qboolean BS_SaveXML (mxml_node_t *parent)
00184 {
00185     int i;
00186     mxml_node_t *node;
00187     /* store market */
00188     node = mxml_AddNode(parent, SAVE_MARKET_MARKET);
00189     for (i = 0; i < csi.numODs; i++) {
00190         const objDef_t *od = INVSH_GetItemByIDX(i);
00191         if (BS_IsOnMarket(od)) {
00192             mxml_node_t * snode = mxml_AddNode(node, SAVE_MARKET_ITEM);
00193             mxml_AddString(snode, SAVE_MARKET_ID, od->id);
00194             mxml_AddIntValue(snode, SAVE_MARKET_NUM, ccs.eMarket.numItems[i]);
00195             mxml_AddIntValue(snode, SAVE_MARKET_BID, ccs.eMarket.bidItems[i]);
00196             mxml_AddIntValue(snode, SAVE_MARKET_ASK, ccs.eMarket.askItems[i]);
00197             mxml_AddDoubleValue(snode, SAVE_MARKET_EVO, ccs.eMarket.currentEvolutionItems[i]);
00198             mxml_AddBoolValue(snode, SAVE_MARKET_AUTOSELL, ccs.eMarket.autosell[i]);
00199         }
00200     }
00201     for (i = 0; i < AIRCRAFTTYPE_MAX; i++) {
00202         market_t *market = &ccs.eMarket;
00203         if (market->bidAircraft[i] > 0 || market->askAircraft[i] > 0) {
00204             mxml_node_t * snode = mxml_AddNode(node, SAVE_MARKET_AIRCRAFT);
00205             mxml_AddString(snode, SAVE_MARKET_ID, Com_DropShipTypeToShortName(i));
00206             mxml_AddIntValue(snode, SAVE_MARKET_NUM, market->numAircraft[i]);
00207             mxml_AddIntValue(snode, SAVE_MARKET_BID, market->bidAircraft[i]);
00208             mxml_AddIntValue(snode, SAVE_MARKET_ASK, market->askAircraft[i]);
00209             mxml_AddDoubleValue(snode, SAVE_MARKET_EVO, market->currentEvolutionAircraft[i]);
00210         }
00211     }
00212     return qtrue;
00213 }
00214 
00221 qboolean BS_LoadXML (mxml_node_t *parent)
00222 {
00223     mxml_node_t *node, *snode;
00224     node = mxml_GetNode(parent, SAVE_MARKET_MARKET);
00225 
00226     if (!node)
00227         return qfalse;
00228 
00229     for (snode = mxml_GetNode(node, SAVE_MARKET_ITEM); snode; snode = mxml_GetNextNode(snode, node, SAVE_MARKET_ITEM)) {
00230         const char *s = mxml_GetString(snode, SAVE_MARKET_ID);
00231         const objDef_t *od = INVSH_GetItemByID(s);
00232 
00233         if (!od) {
00234             Com_Printf("BS_LoadXML: Could not find item '%s'\n", s);
00235             continue;
00236         }
00237 
00238         ccs.eMarket.numItems[od->idx] = mxml_GetInt(snode, SAVE_MARKET_NUM, 0);
00239         ccs.eMarket.bidItems[od->idx] = mxml_GetInt(snode, SAVE_MARKET_BID, 0);
00240         ccs.eMarket.askItems[od->idx] = mxml_GetInt(snode, SAVE_MARKET_ASK, 0);
00241         ccs.eMarket.currentEvolutionItems[od->idx] = mxml_GetDouble(snode, SAVE_MARKET_EVO, 0.0);
00242         ccs.eMarket.autosell[od->idx] = mxml_GetBool(snode, SAVE_MARKET_AUTOSELL, qfalse);
00243     }
00244     for (snode = mxml_GetNode(node, SAVE_MARKET_AIRCRAFT); snode; snode = mxml_GetNextNode(snode, node, SAVE_MARKET_AIRCRAFT)) {
00245         const char *s = mxml_GetString(snode, SAVE_MARKET_ID);
00246         humanAircraftType_t type = Com_DropShipShortNameToID(s);
00247         
00248         ccs.eMarket.numAircraft[type] = mxml_GetInt(snode, SAVE_MARKET_NUM, 0);
00249         ccs.eMarket.bidAircraft[type] = mxml_GetInt(snode, SAVE_MARKET_BID, 0);
00250         ccs.eMarket.askAircraft[type] = mxml_GetInt(snode, SAVE_MARKET_ASK, 0);
00251         ccs.eMarket.currentEvolutionAircraft[type] = mxml_GetDouble(snode, SAVE_MARKET_EVO, 0.0);
00252     }
00253 
00254     return qtrue;
00255 }
00256 
00264 void BS_InitMarket (void)
00265 {
00266     int i;
00267     campaign_t *campaign = ccs.curCampaign;
00268     market_t *market = &ccs.eMarket;
00269 
00270     /* find the relevant markets */
00271     campaign->marketDef = INV_GetEquipmentDefinitionByID(campaign->market);
00272     campaign->asymptoticMarketDef = INV_GetEquipmentDefinitionByID(campaign->asymptoticMarket);
00273 
00274     for (i = 0; i < csi.numODs; i++) {
00275         const objDef_t *od = INVSH_GetItemByIDX(i);
00276         if (market->askItems[i] == 0) {
00277             market->askItems[i] = od->price;
00278             market->bidItems[i] = floor(market->askItems[i] * BID_FACTOR);
00279         }
00280 
00281         if (campaign->marketDef->numItems[i] <= 0)
00282             continue;
00283 
00284         if (RS_IsResearched_ptr(RS_GetTechForItem(od))) {
00285             /* the other relevant values were already set above */
00286             market->numItems[i] = campaign->marketDef->numItems[i];
00287         } else {
00288             Com_Printf("BS_InitMarket: Could not add item %s to the market - not marked as researched in campaign %s\n",
00289                     od->id, campaign->id);
00290         }
00291     }
00292 
00293     for (i = 0; i < AIRCRAFTTYPE_MAX; i++) {
00294         const char* name = Com_DropShipTypeToShortName(i);
00295         const aircraft_t *aircraft = AIR_GetAircraft(name);
00296         if (market->askAircraft[i] == 0) {
00297             market->askAircraft[i] = aircraft->price;
00298             market->bidAircraft[i] = floor(market->askAircraft[i] * BID_FACTOR);
00299         }
00300 
00301         if (campaign->marketDef->numAircraft[i] <= 0)
00302             continue;
00303 
00304         if (RS_IsResearched_ptr(aircraft->tech)) {
00305             /* the other relevant values were already set above */
00306             market->numAircraft[i] = campaign->marketDef->numAircraft[i];
00307         } else {
00308             Com_Printf("BS_InitMarket: Could not add aircraft %s to the market - not marked as researched in campaign %s\n",
00309                     aircraft->id, campaign->id);
00310         }
00311     }
00312 }
00313 
00321 void CL_CampaignRunMarket (void)
00322 {
00323     int i;
00324     campaign_t *campaign = ccs.curCampaign;
00325     const float TYPICAL_TIME = 10.f;            
00326     const int RESEARCH_LIMIT_DELAY = 30;        
00329     assert(campaign->marketDef);
00330     assert(campaign->asymptoticMarketDef);
00331 
00332     for (i = 0; i < csi.numODs; i++) {
00333         const objDef_t *od = INVSH_GetItemByIDX(i);
00334         const technology_t *tech = RS_GetTechForItem(od);
00335         int asymptoticNumber;
00336 
00337         if (RS_IsResearched_ptr(tech) && (campaign->marketDef->numItems[i] != 0 || ccs.date.day > tech->researchedDate.day + RESEARCH_LIMIT_DELAY)) {
00338             /* if items are researched for more than RESEARCH_LIMIT_DELAY or was on the initial market,
00339              * there number tend to the value defined in equipment.ufo.
00340              * This value is the asymptotic value if it is not 0, or initial value else */
00341             asymptoticNumber = campaign->asymptoticMarketDef->numItems[i] ? campaign->asymptoticMarketDef->numItems[i] : campaign->marketDef->numItems[i];
00342         } else {
00343             /* items that have just been researched don't appear on market, but they can disappear */
00344             asymptoticNumber = 0;
00345         }
00346 
00347         /* Store the evolution of the market in currentEvolution */
00348         ccs.eMarket.currentEvolutionItems[i] += (asymptoticNumber - ccs.eMarket.numItems[i]) / TYPICAL_TIME;
00349 
00350         /* Check if new items appeared or disappeared on market */
00351         if (fabs(ccs.eMarket.currentEvolutionItems[i]) >= 1.0f) {
00352             const int num = (int)(ccs.eMarket.currentEvolutionItems[i]);
00353             if (num >= 0)
00354                 BS_AddItemToMarket(od, num);
00355             else
00356                 BS_RemoveItemFromMarket(od, -num);
00357             ccs.eMarket.currentEvolutionItems[i] -= num;
00358         }
00359     }
00360 
00361     for (i = 0; i < AIRCRAFTTYPE_MAX; i++) {
00362         const humanAircraftType_t type = i;
00363         const char *aircraftID = Com_DropShipTypeToShortName(type);
00364         const aircraft_t* aircraft = AIR_GetAircraft(aircraftID);
00365         const technology_t *tech = aircraft->tech;
00366         int asymptoticNumber;
00367 
00368         if (RS_IsResearched_ptr(tech) && (campaign->marketDef->numAircraft[i] != 0 || ccs.date.day > tech->researchedDate.day + RESEARCH_LIMIT_DELAY)) {
00369             /* if aircraft is researched for more than RESEARCH_LIMIT_DELAY or was on the initial market,
00370              * there number tend to the value defined in equipment.ufo.
00371              * This value is the asymptotic value if it is not 0, or initial value else */
00372             asymptoticNumber = campaign->asymptoticMarketDef->numAircraft[i] ? campaign->asymptoticMarketDef->numAircraft[i] : campaign->marketDef->numAircraft[i];
00373         } else {
00374             /* items that have just been researched don't appear on market, but they can disappear */
00375             asymptoticNumber = 0;
00376         }
00377         /* Store the evolution of the market in currentEvolution */
00378         ccs.eMarket.currentEvolutionAircraft[i] += (asymptoticNumber - ccs.eMarket.numAircraft[i]) / TYPICAL_TIME;
00379 
00380         /* Check if new items appeared or disappeared on market */
00381         if (fabs(ccs.eMarket.currentEvolutionAircraft[i]) >= 1.0f) {
00382             const int num = (int)(ccs.eMarket.currentEvolutionAircraft[i]);
00383             if (num >= 0)
00384                 BS_AddAircraftToMarket(aircraft, num);
00385             else
00386                 BS_RemoveAircraftFromMarket(aircraft, -num);
00387             ccs.eMarket.currentEvolutionAircraft[i] -= num;
00388         }
00389     }
00390 }
00391 
00397 qboolean BS_IsOnMarket (const objDef_t const* item)
00398 {
00399     assert(item);
00400     return !(item->isVirtual || item->notOnMarket);
00401 }
00402 
00408 qboolean BS_BuySellAllowed (const base_t* base)
00409 {
00410     if (base->baseStatus != BASE_UNDER_ATTACK
00411      && B_GetBuildingStatus(base, B_STORAGE)) {
00412         return qtrue;
00413     } else {
00414         return qfalse;
00415     }
00416 }
00417 

Generated by  doxygen 1.6.2