cp_market_callbacks.c

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 2002-2010 UFO: Alien Invasion.
00007 
00008 This program is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU General Public License
00010 as published by the Free Software Foundation; either version 2
00011 of the License, or (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016 
00017 See the GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00023 */
00024 
00025 #include "../cl_shared.h"
00026 #include "../cl_inventory.h"
00027 #include "../ui/ui_main.h"
00028 #include "../ui/ui_popup.h"
00029 #include "cp_campaign.h"
00030 #include "cp_market.h"
00031 #include "cp_market_callbacks.h"
00032 
00033 #define MAX_BUYLIST     64
00034 
00035 #define MAX_MARKET_MENU_ENTRIES 22
00036 
00041 typedef struct buyListEntry_s {
00042     const objDef_t *item;           
00043     const ugv_t *ugv;               
00045     const aircraft_t *aircraft; 
00046 } buyListEntry_t;
00047 
00048 typedef struct buyList_s {
00049     buyListEntry_t l[MAX_BUYLIST];  
00050     int length;     
00051     int scroll;     
00052 } buyList_t;
00053 
00054 static buyList_t buyList;   
00055 static const objDef_t *currentSelectedMenuEntry;    
00056 static int buyCat = FILTER_S_PRIMARY;   
00060 static const int MAX_BS_FACTORS = 500;
00061 
00067 static qboolean BS_AircraftIsOnMarket (const aircraft_t *aircraft)
00068 {
00069     return aircraft->type != AIRCRAFT_UFO && aircraft->price != -1;
00070 }
00071 
00075 static inline int BS_GetBuySellFactor (void)
00076 {
00077     return 1;
00078 }
00079 
00080 static const objDef_t *BS_GetObjectDefition (const buyListEntry_t *entry)
00081 {
00082     assert(entry);
00083     if (entry->item)
00084         return entry->item;
00085     else if (entry->ugv)
00086         return NULL;
00087     else if (entry->aircraft)
00088         return NULL;
00089 
00090     Com_Error(ERR_DROP, "You should not check an empty buy list entry");
00091 }
00092 
00093 
00100 static void BS_MarketAircraftDescription (const aircraft_t *aircraftTemplate)
00101 {
00102     const technology_t *tech;
00103 
00104     /* Break if no aircraft was given or if  it's no sample-aircraft (i.e. template). */
00105     if (!aircraftTemplate || aircraftTemplate != aircraftTemplate->tpl)
00106         return;
00107 
00108     tech = aircraftTemplate->tech;
00109     assert(tech);
00110     UP_AircraftDescription(tech);
00111     Cvar_Set("mn_aircraftname", _(aircraftTemplate->name));
00112     Cvar_Set("mn_item", aircraftTemplate->id);
00113 }
00114 
00115 
00122 static int BS_GetStorageAmountInBase (const base_t* base, const char *aircraftID)
00123 {
00124     aircraft_t *aircraft;
00125     int storage = 0;
00126 
00127     assert(base);
00128 
00129     /* Get storage amount in the base. */
00130     aircraft = NULL;
00131     while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL) {
00132         if (!strcmp(aircraft->id, aircraftID))
00133             storage++;
00134     }
00135     return storage;
00136 }
00137 
00138 static inline qboolean BS_GetMinMaxValueByItemID (const base_t *base, int itemNum, int *min, int *max, int *value)
00139 {
00140     assert(base);
00141 
00142     if (itemNum < 0 || itemNum + buyList.scroll >= buyList.length)
00143         return qfalse;
00144 
00145     if (buyCat == FILTER_UGVITEM && buyList.l[itemNum + buyList.scroll].ugv) {
00147         *min = 0;
00148         *value = 10000;
00149         *max = 20000;
00150     } else if (buyCat == FILTER_AIRCRAFT && buyList.l[itemNum + buyList.scroll].aircraft) {
00151         const aircraft_t *aircraft = buyList.l[itemNum + buyList.scroll].aircraft;
00152         if (!aircraft)
00153             return qfalse;
00154         *value = BS_GetStorageAmountInBase(base, aircraft->id);
00155         *max = BS_GetStorageAmountInBase(base, aircraft->id) + BS_GetAircraftOnMarket(aircraft);
00156         *min = 0;
00157     } else {
00158         const objDef_t *item = BS_GetObjectDefition(&buyList.l[itemNum + buyList.scroll]);
00159         if (!item)
00160             return qfalse;
00161         *value = base->storage.numItems[item->idx];
00162         *max = base->storage.numItems[item->idx] + ccs.eMarket.numItems[item->idx];
00163         *min = 0;
00164     }
00165 
00166     return qtrue;
00167 }
00168 
00173 static void BS_UpdateItem (const base_t *base, int itemNum)
00174 {
00175     int min, max, value;
00176 
00177     if (BS_GetMinMaxValueByItemID(base, itemNum, &min, &max, &value))
00178         UI_ExecuteConfunc("buy_updateitem %d %d %d %d", itemNum, value, min, max);
00179 }
00180 
00186 static void BS_MarketScroll_f (void)
00187 {
00188     int i;
00189     base_t *base = B_GetCurrentSelectedBase();
00190 
00191     if (!base || buyCat >= MAX_FILTERTYPES || buyCat < 0)
00192         return;
00193 
00194     if (Cmd_Argc() < 2) {
00195         Com_Printf("Usage: %s <scrollpos>\n", Cmd_Argv(0));
00196         return;
00197     }
00198 
00199     buyList.scroll = atoi(Cmd_Argv(1));
00200     assert(buyList.scroll >= 0);
00201     assert(!((buyList.length > MAX_MARKET_MENU_ENTRIES && buyList.scroll >= buyList.length - MAX_MARKET_MENU_ENTRIES)));
00202 
00203     /* now update the menu pics */
00204     for (i = 0; i < MAX_MARKET_MENU_ENTRIES; i++) {
00205         UI_ExecuteConfunc("buy_autoselli %i", i);
00206     }
00207 
00208     /* get item list */
00209     for (i = buyList.scroll; i < buyList.length - buyList.scroll; i++) {
00210         if (i >= MAX_MARKET_MENU_ENTRIES)
00211             break;
00212         else {
00213             const objDef_t *od = BS_GetObjectDefition(&buyList.l[i]);
00214             /* Check whether the item matches the proper filter, storage in current base and market. */
00215             if (od && (base->storage.numItems[od->idx] || ccs.eMarket.numItems[od->idx]) && INV_ItemMatchesFilter(od, buyCat)) {
00216                 UI_ExecuteConfunc("buy_show %i", i - buyList.scroll);
00217                 BS_UpdateItem(base, i - buyList.scroll);
00218                 if (ccs.eMarket.autosell[od->idx])
00219                     UI_ExecuteConfunc("buy_autoselle %i", i - buyList.scroll);
00220                 else
00221                     UI_ExecuteConfunc("buy_autoselld %i", i - buyList.scroll);
00222             }
00223         }
00224     }
00225 }
00226 
00232 static void BS_MarketClick_f (void)
00233 {
00234     int num;
00235 
00236     if (Cmd_Argc() < 2) {
00237         Com_Printf("Usage: %s <num>\n", Cmd_Argv(0));
00238         return;
00239     }
00240 
00241     num = atoi(Cmd_Argv(1));
00242     if (num >= buyList.length || num < 0)
00243         return;
00244 
00245     Cvar_Set("mn_item", "");
00246 
00247     switch (buyCat) {
00248     case FILTER_AIRCRAFT:
00249         assert(buyList.l[num].aircraft);
00250         BS_MarketAircraftDescription(buyList.l[num].aircraft->tpl);
00251         break;
00252     case FILTER_CRAFTITEM:
00253         UP_AircraftItemDescription(buyList.l[num].item);
00254         Cvar_Set("mn_aircraftname", "");
00255         break;
00256     case FILTER_UGVITEM:
00257         if (buyList.l[num].ugv) {
00258             UP_UGVDescription(buyList.l[num].ugv);
00259             currentSelectedMenuEntry = NULL;
00260         } else {
00261             INV_ItemDescription(buyList.l[num].item);
00262             currentSelectedMenuEntry = buyList.l[num].item;
00263         }
00264         break;
00265     case MAX_FILTERTYPES:
00266         break;
00267     default:
00268         INV_ItemDescription(buyList.l[num].item);
00269         currentSelectedMenuEntry = buyList.l[num].item;
00270         break;
00271     }
00272 
00273     /* update selected element */
00274     UI_ExecuteConfunc("buy_selectitem %i", num);
00275 }
00276 
00281 static void BS_MarketInfoClick_f (void)
00282 {
00283     const technology_t *tech = RS_GetTechByProvided(Cvar_GetString("mn_item"));
00284 
00285     if (tech)
00286         UP_OpenWith(tech->id);
00287 }
00288 
00290 static linkedList_t *bsMarketNames;
00291 static linkedList_t *bsMarketStorage;
00292 static linkedList_t *bsMarketMarket;
00293 static linkedList_t *bsMarketPrices;
00294 
00300 static void BS_AddToList (const char *name, int storage, int market, int price)
00301 {
00302     LIST_AddString(&bsMarketNames, _(name));
00303     LIST_AddString(&bsMarketStorage, va("%i", storage));
00304     LIST_AddString(&bsMarketMarket, va("%i", market));
00305     LIST_AddString(&bsMarketPrices, va(_("%i c"), price));
00306 }
00307 
00312 static void BS_BuyType (const base_t *base)
00313 {
00314     const objDef_t *od;
00315     int i, j = 0;
00316     char tmpbuf[MAX_VAR];
00317 
00318     if (!base || buyCat >= MAX_FILTERTYPES || buyCat < 0)
00319         return;
00320 
00321     CL_UpdateCredits(ccs.credits);
00322 
00323     bsMarketNames = NULL;
00324     bsMarketStorage = NULL;
00325     bsMarketMarket = NULL;
00326     bsMarketPrices = NULL;
00327     UI_ResetData(TEXT_ITEMDESCRIPTION);
00328 
00329     /* 'normal' items */
00330     switch (buyCat) {
00331     case FILTER_AIRCRAFT:   /* Aircraft */
00332         {
00333         const technology_t* tech;
00334         const aircraft_t *aircraftTemplate;
00335         for (i = 0, j = 0, aircraftTemplate = ccs.aircraftTemplates; i < ccs.numAircraftTemplates; i++, aircraftTemplate++) {
00336             if (!BS_AircraftIsOnMarket(aircraftTemplate))
00337                 continue;
00338             tech = aircraftTemplate->tech;
00339             assert(tech);
00340             if (BS_GetStorageAmountInBase(base, aircraftTemplate->id) + BS_GetAircraftOnMarket(aircraftTemplate) > 0) {
00341                 if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) {
00342                     UI_ExecuteConfunc("buy_autoselli %i", j - buyList.scroll);
00343                     UI_ExecuteConfunc("buy_show %i", j - buyList.scroll);
00344                 }
00345                 BS_AddToList(aircraftTemplate->name, BS_GetStorageAmountInBase(base, aircraftTemplate->id),
00346                         BS_GetAircraftOnMarket(aircraftTemplate), BS_GetAircraftBuyingPrice(aircraftTemplate));
00347                 if (j >= MAX_BUYLIST)
00348                     Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much items\n");
00349                 buyList.l[j].item = NULL;
00350                 buyList.l[j].ugv = NULL;
00351                 buyList.l[j].aircraft = aircraftTemplate;
00352                 buyList.length = j + 1;
00353                 BS_UpdateItem(base, j - buyList.scroll);
00354                 j++;
00355             }
00356         }
00357         }
00358         break;
00359     case FILTER_CRAFTITEM:  /* Aircraft items */
00360         /* get item list */
00361         for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) {
00362             if (!BS_IsOnMarket(od))
00363                 continue;
00364             /* Check whether the item matches the proper filter, storage in current base and market. */
00365             if ((base->storage.numItems[i] || ccs.eMarket.numItems[i])
00366              && INV_ItemMatchesFilter(od, FILTER_CRAFTITEM)) {
00367                 if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) {
00368                     UI_ExecuteConfunc("buy_show %i", j - buyList.scroll);
00369                     if (ccs.eMarket.autosell[i])
00370                         UI_ExecuteConfunc("buy_autoselle %i", j - buyList.scroll);
00371                     else
00372                         UI_ExecuteConfunc("buy_autoselld %i", j - buyList.scroll);
00373                 }
00374                 BS_AddToList(od->name, base->storage.numItems[i], ccs.eMarket.numItems[i], BS_GetItemBuyingPrice(od));
00375                 if (j >= MAX_BUYLIST)
00376                     Com_Error(ERR_DROP, "Increase the MAX_FILTERLIST value to handle that much items\n");
00377                 buyList.l[j].item = od;
00378                 buyList.l[j].ugv = NULL;
00379                 buyList.l[j].aircraft = NULL;
00380                 buyList.length = j + 1;
00381                 BS_UpdateItem(base, j - buyList.scroll);
00382                 j++;
00383             }
00384         }
00385         break;
00386     case FILTER_UGVITEM:    /* Heavy equipment like UGVs and it's weapons/ammo. */
00387         {
00388         /* Get item list. */
00389         j = 0;
00390         for (i = 0; i < csi.numUGV; i++) {
00392             ugv_t *ugv = &csi.ugvs[i];
00393             const technology_t* tech = RS_GetTechByProvided(ugv->id);
00394             assert(tech);
00395             if (RS_IsResearched_ptr(tech)) {
00396                 const int hiredRobot = E_CountHiredRobotByType(base, ugv);
00397                 const int unhiredRobot = E_CountUnhiredRobotsByType(ugv);
00398 
00399                 if (hiredRobot + unhiredRobot <= 0)
00400                     continue;
00401 
00402                 if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) {
00403                     UI_ExecuteConfunc("buy_show %i", j - buyList.scroll);
00404                 }
00405 
00407                 BS_AddToList(tech->name,
00408                     hiredRobot,         /* numInStorage */
00409                     unhiredRobot,           /* numOnMarket */
00410                     ugv->price);
00411 
00412                 if (j >= MAX_BUYLIST)
00413                     Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much entries.\n");
00414                 buyList.l[j].item = NULL;
00415                 buyList.l[j].ugv = ugv;
00416                 buyList.l[j].aircraft = NULL;
00417                 buyList.length = j + 1;
00418                 BS_UpdateItem(base, j - buyList.scroll);
00419                 j++;
00420             }
00421         }
00422 
00423         for (i = 0, od = csi.ods; i < csi.numODs; i++, od++) {
00424             if (!BS_IsOnMarket(od))
00425                 continue;
00426 
00427             /* Check whether the item matches the proper filter, storage in current base and market. */
00428             if (INV_ItemMatchesFilter(od, FILTER_UGVITEM) && (base->storage.numItems[i] || ccs.eMarket.numItems[i])) {
00429                 BS_AddToList(od->name, base->storage.numItems[i], ccs.eMarket.numItems[i], BS_GetItemBuyingPrice(od));
00430                 /* Set state of Autosell button. */
00431                 if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) {
00432                     UI_ExecuteConfunc("buy_show %i", j - buyList.scroll);
00433                     if (ccs.eMarket.autosell[i])
00434                         UI_ExecuteConfunc("buy_autoselle %i", j - buyList.scroll);
00435                     else
00436                         UI_ExecuteConfunc("buy_autoselld %i", j - buyList.scroll);
00437                 }
00438 
00439                 if (j >= MAX_BUYLIST)
00440                     Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much items\n");
00441                 buyList.l[j].item = od;
00442                 buyList.l[j].ugv = NULL;
00443                 buyList.l[j].aircraft = NULL;
00444                 buyList.length = j + 1;
00445                 BS_UpdateItem(base, j - buyList.scroll);
00446                 j++;
00447             }
00448         }
00449         }
00450         break;
00451     default:    /* Normal items */
00452         if (buyCat < MAX_SOLDIER_FILTERTYPES || buyCat == FILTER_DUMMY) {
00453             /* get item list */
00454             for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) {
00455                 if (!BS_IsOnMarket(od))
00456                     continue;
00457                 /* Check whether the item matches the proper filter, storage in current base and market. */
00458                 if ((base->storage.numItems[i] || ccs.eMarket.numItems[i]) && INV_ItemMatchesFilter(od, buyCat)) {
00459                     BS_AddToList(od->name, base->storage.numItems[i], ccs.eMarket.numItems[i], BS_GetItemBuyingPrice(od));
00460                     /* Set state of Autosell button. */
00461                     if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) {
00462                         UI_ExecuteConfunc("buy_show %i", j - buyList.scroll);
00463                         if (ccs.eMarket.autosell[i])
00464                             UI_ExecuteConfunc("buy_autoselle %i", j - buyList.scroll);
00465                         else
00466                             UI_ExecuteConfunc("buy_autoselld %i", j - buyList.scroll);
00467                     }
00468 
00469                     if (j >= MAX_BUYLIST)
00470                         Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much items\n");
00471                     buyList.l[j].item = od;
00472                     buyList.l[j].ugv = NULL;
00473                     buyList.l[j].aircraft = NULL;
00474                     buyList.length = j + 1;
00475                     BS_UpdateItem(base, j - buyList.scroll);
00476                     j++;
00477                 }
00478             }
00479         }
00480         break;
00481     }
00482 
00483     for (; j < MAX_MARKET_MENU_ENTRIES; j++) {
00484         /* Hide the rest of the entries. */
00485         UI_ExecuteConfunc("buy_autoselli %i", j);
00486         UI_ExecuteConfunc("buy_hide %i", j);
00487     }
00488 
00489     /* Update some menu cvars. */
00490     /* Set up base capacities. */
00491     Com_sprintf(tmpbuf, sizeof(tmpbuf), "%i/%i", base->capacities[CAP_ITEMS].cur,
00492         base->capacities[CAP_ITEMS].max);
00493     Cvar_Set("mn_bs_storage", tmpbuf);
00494 
00495     /* select first item */
00496     if (buyList.length) {
00497         switch (buyCat) {   
00498         case FILTER_AIRCRAFT:
00499             BS_MarketAircraftDescription(buyList.l[0].aircraft);
00500             break;
00501         case FILTER_CRAFTITEM:
00502             Cvar_Set("mn_aircraftname", "");    
00503             /* Select current item or first one. */
00504             if (currentSelectedMenuEntry)
00505                 UP_AircraftItemDescription(currentSelectedMenuEntry);
00506             else
00507                 UP_AircraftItemDescription(buyList.l[0].item);
00508             break;
00509         case FILTER_UGVITEM:
00511             if (currentSelectedMenuEntry)
00512                 INV_ItemDescription(currentSelectedMenuEntry);
00513             else if (buyList.l[0].ugv)
00514                 UP_UGVDescription(buyList.l[0].ugv);
00515             else if (buyList.l[0].item)
00516                 INV_ItemDescription(buyList.l[0].item);
00517             break;
00518         default:
00519             assert(buyCat != MAX_FILTERTYPES);
00520             /* Select current item or first one. */
00521             if (currentSelectedMenuEntry)
00522                 INV_ItemDescription(currentSelectedMenuEntry);
00523             else
00524                 INV_ItemDescription(buyList.l[0].item);
00525             break;
00526         }
00527     } else {
00528         /* reset description */
00529         INV_ItemDescription(NULL);
00530     }
00531 
00532     UI_RegisterLinkedListText(TEXT_MARKET_NAMES, bsMarketNames);
00533     UI_RegisterLinkedListText(TEXT_MARKET_STORAGE, bsMarketStorage);
00534     UI_RegisterLinkedListText(TEXT_MARKET_MARKET, bsMarketMarket);
00535     UI_RegisterLinkedListText(TEXT_MARKET_PRICES, bsMarketPrices);
00536 }
00537 
00541 static void BS_BuyType_f (void)
00542 {
00543     base_t *base = B_GetCurrentSelectedBase();
00544 
00545     if (Cmd_Argc() == 2) {
00546         buyCat = INV_GetFilterTypeID(Cmd_Argv(1));
00547 
00548         if (buyCat == FILTER_DISASSEMBLY)
00549             buyCat--;
00550         if (buyCat < 0) {
00551             buyCat = MAX_FILTERTYPES - 1;
00552             if (buyCat == FILTER_DISASSEMBLY)
00553                 buyCat--;
00554         } else if (buyCat >= MAX_FILTERTYPES) {
00555             buyCat = 0;
00556         }
00557 
00558         Cvar_Set("mn_itemtype", INV_GetFilterType(buyCat));
00559         currentSelectedMenuEntry = NULL;
00560     }
00561 
00562     BS_BuyType(base);
00563     buyList.scroll = 0;
00564     UI_ExecuteConfunc("sync_market_scroll 0 %d", buyList.scroll);
00565     UI_ExecuteConfunc("market_scroll %d", buyList.scroll);
00566     UI_ExecuteConfunc("market_click 0");
00567 }
00568 
00573 static void BS_BuyAircraft_f (void)
00574 {
00575     int num;
00576     const aircraft_t *aircraftTemplate;
00577     base_t *base = B_GetCurrentSelectedBase();
00578 
00579     if (Cmd_Argc() < 2) {
00580         Com_Printf("Usage: %s <num>\n", Cmd_Argv(0));
00581         return;
00582     }
00583 
00584     if (!base)
00585         return;
00586 
00587     num = atoi(Cmd_Argv(1));
00588     if (num < 0 || num >= buyList.length)
00589         return;
00590 
00591     if (buyCat == FILTER_AIRCRAFT) {
00592         int freeSpace;
00593         /* We cannot buy aircraft if there is no power in our base. */
00594         if (!B_GetBuildingStatus(base, B_POWER)) {
00595             UI_Popup(_("Note"), _("No power supplies in this base.\nHangars are not functional."));
00596             return;
00597         }
00598         /* We cannot buy aircraft without any hangar. */
00599         if (!B_GetBuildingStatus(base, B_HANGAR) && !B_GetBuildingStatus(base, B_SMALL_HANGAR)) {
00600             UI_Popup(_("Note"), _("Build a hangar first."));
00601             return;
00602         }
00603         aircraftTemplate = buyList.l[num].aircraft;
00604         freeSpace = AIR_CalculateHangarStorage(aircraftTemplate, base, 0);
00605 
00606         /* Check free space in hangars. */
00607         if (freeSpace < 0) {
00608             Com_Printf("BS_BuyAircraft_f: something bad happened, AIR_CalculateHangarStorage returned -1!\n");
00609             return;
00610         }
00611 
00612         if (freeSpace == 0) {
00613             UI_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough space in hangars.\n"));
00614             return;
00615         } else {
00616             const int price = BS_GetAircraftBuyingPrice(aircraftTemplate);
00617             if (ccs.credits < price) {
00618                 UI_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough credits.\n"));
00619                 return;
00620             } else {
00621                 /* Hangar capacities are being updated in AIR_NewAircraft().*/
00622                 BS_RemoveAircraftFromMarket(aircraftTemplate, 1);
00623                 CL_UpdateCredits(ccs.credits - price);
00624                 AIR_NewAircraft(base, aircraftTemplate->id);
00625                 Cmd_ExecuteString(va("buy_type %s", INV_GetFilterType(FILTER_AIRCRAFT)));
00626             }
00627         }
00628     }
00629 }
00630 
00635 static void BS_SellAircraft_f (void)
00636 {
00637     int num;
00638     base_t *base = B_GetCurrentSelectedBase();
00639 
00640     if (Cmd_Argc() < 2) {
00641         Com_Printf("Usage: %s <num>\n", Cmd_Argv(0));
00642         return;
00643     }
00644 
00645     if (!base)
00646         return;
00647 
00648     num = atoi(Cmd_Argv(1));
00649     if (num < 0 || num >= buyList.length)
00650         return;
00651 
00652     if (buyCat == FILTER_AIRCRAFT) {
00653         qboolean aircraftOutNote = qfalse;
00654         qboolean teamNote = qfalse;
00655         qboolean found = qfalse;
00656         aircraft_t *aircraft;
00657         const aircraft_t *aircraftTemplate = buyList.l[num].aircraft;
00658         if (!aircraftTemplate)
00659             return;
00660 
00661         aircraft = NULL;
00662         while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL) {
00663             if (!strcmp(aircraft->id, aircraftTemplate->id)) {
00664                 if (AIR_GetTeamSize(aircraft) > 0) {
00665                     teamNote = qtrue;
00666                     continue;
00667                 }
00668                 if (!AIR_IsAircraftInBase(aircraft)) {
00669                     /* aircraft is not in base */
00670                     aircraftOutNote = qtrue;
00671                     continue;
00672                 }
00673                 found = qtrue;
00674                 break;
00675             }
00676         }
00677         /* ok, we've found an empty aircraft (no team) in a base
00678          * so now we can sell it */
00679         if (found) {
00680             int j;
00681             /* sell off any items which are mounted on it */
00682             for (j = 0; j < aircraft->maxWeapons; j++) {
00683                 BS_ProcessCraftItemSale(aircraft->weapons[j].item, 1);
00684                 BS_ProcessCraftItemSale(aircraft->weapons[j].ammo, 1);
00685             }
00686 
00687             BS_ProcessCraftItemSale(aircraft->shield.item, 1);
00688             /* there should be no ammo here, but checking can't hurt */
00689             BS_ProcessCraftItemSale(aircraft->shield.ammo, 1);
00690 
00691             for (j = 0; j < aircraft->maxElectronics; j++) {
00692                 BS_ProcessCraftItemSale(aircraft->electronics[j].item, 1);
00693                 /* there should be no ammo here, but checking can't hurt */
00694                 BS_ProcessCraftItemSale(aircraft->electronics[j].ammo, 1);
00695             }
00696 
00697             Com_DPrintf(DEBUG_CLIENT, "BS_SellAircraft_f: Selling aircraft with IDX %i\n", aircraft->idx);
00698             /* the capacities are also updated here */
00699             BS_AddAircraftToMarket(aircraft, 1);
00700             CL_UpdateCredits(ccs.credits + BS_GetAircraftSellingPrice(aircraft));
00701 
00702             AIR_DeleteAircraft(aircraft);
00703 
00704             /* reinit the menu */
00705             BS_BuyType(base);
00706         } else {
00707             if (teamNote)
00708                 UI_Popup(_("Note"), _("You can't sell an aircraft if it still has a team assigned"));
00709             else if (aircraftOutNote)
00710                 UI_Popup(_("Note"), _("You can't sell an aircraft that is not in base"));
00711             else
00712                 Com_DPrintf(DEBUG_CLIENT, "BS_SellAircraft_f: There are no aircraft available (with no team assigned) for selling\n");
00713         }
00714     }
00715 }
00716 
00723 static void BS_BuyItem_f (void)
00724 {
00725     int num;
00726     base_t *base = B_GetCurrentSelectedBase();
00727 
00728     if (Cmd_Argc() < 2) {
00729         Com_Printf("Usage: %s <num>\n", Cmd_Argv(0));
00730         return;
00731     }
00732 
00733     if (!base)
00734         return;
00735 
00736     if (buyCat == FILTER_AIRCRAFT) {
00737         Com_DPrintf(DEBUG_CLIENT, "BS_BuyItem_f: Redirects to BS_BuyAircraft_f\n");
00738         BS_BuyAircraft_f();
00739         return;
00740     }
00741 
00742     num = atoi(Cmd_Argv(1));
00743     if (num < 0 || num >= buyList.length)
00744         return;
00745 
00746     UI_ExecuteConfunc("buy_selectitem %i", num + buyList.scroll);
00747 
00748     if (buyCat == FILTER_UGVITEM && buyList.l[num + buyList.scroll].ugv) {
00749         /* The list entry is an actual ugv/robot */
00750         const ugv_t *ugv = buyList.l[num + buyList.scroll].ugv;
00751 
00752         UP_UGVDescription(ugv);
00753 
00754         if (ccs.credits >= ugv->price && E_CountUnhiredRobotsByType(ugv) > 0) {
00755             qboolean ugvWeaponBuyable;
00756             /* Check if we have a weapon for this ugv in the market and there is enough storage-room for it. */
00757             const objDef_t *ugvWeapon = INVSH_GetItemByID(ugv->weapon);
00758             if (!ugvWeapon)
00759                 Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get weapon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id);
00760 
00761             ugvWeaponBuyable = qtrue;
00762             if (!ccs.eMarket.numItems[ugvWeapon->idx])
00763                 ugvWeaponBuyable = qfalse;
00764 
00765             if (base->capacities[CAP_ITEMS].max - base->capacities[CAP_ITEMS].cur <
00766                 UGV_SIZE + ugvWeapon->size) {
00767                 UI_Popup(_("Not enough storage space"), _("You cannot buy this item.\nNot enough space in storage.\nBuild more storage facilities."));
00768                 ugvWeaponBuyable = qfalse;
00769             }
00770 
00771             if (ugvWeaponBuyable && E_HireRobot(base, ugv)) {
00772                 /* Move the item into the storage. */
00773                 B_UpdateStorageAndCapacity(base, ugvWeapon, 1, qfalse, qfalse);
00774                 BS_RemoveItemFromMarket(ugvWeapon, 1);
00775 
00776                 /* Update Display/List and credits. */
00777                 BS_BuyType(base);
00778                 CL_UpdateCredits(ccs.credits - ugv->price); 
00779             } else {
00780                 Com_Printf("Could not buy this item.\n");
00781             }
00782         }
00783     } else {
00784         /* Normal item (or equipment for UGVs/Robots if buyCategory==BUY_HEAVY) */
00785         const objDef_t *item = BS_GetObjectDefition(&buyList.l[num + buyList.scroll]);
00786         assert(item);
00787         currentSelectedMenuEntry = item;
00788         INV_ItemDescription(item);
00789         Com_DPrintf(DEBUG_CLIENT, "BS_BuyItem_f: item %s\n", item->id);
00790         BS_CheckAndDoBuyItem(base, item, BS_GetBuySellFactor());
00791         /* reinit the menu */
00792         BS_BuyType(base);
00793         BS_UpdateItem(base, num);
00794     }
00795 }
00796 
00803 static void BS_SellItem_f (void)
00804 {
00805     int num;
00806     base_t *base = B_GetCurrentSelectedBase();
00807 
00808     if (Cmd_Argc() < 2) {
00809         Com_Printf("Usage: %s <num>\n", Cmd_Argv(0));
00810         return;
00811     }
00812 
00813     if (!base)
00814         return;
00815 
00816     if (buyCat == FILTER_AIRCRAFT) {
00817         Com_DPrintf(DEBUG_CLIENT, "BS_SellItem_f: Redirects to BS_SellAircraft_f\n");
00818         BS_SellAircraft_f();
00819         return;
00820     }
00821 
00822     num = atoi(Cmd_Argv(1));
00823     if (num < 0 || num >= buyList.length)
00824         return;
00825 
00826     UI_ExecuteConfunc("buy_selectitem %i", num + buyList.scroll);
00827     if (buyCat == FILTER_UGVITEM && buyList.l[num + buyList.scroll].ugv) {
00828         employee_t *employee;
00829         /* The list entry is an actual ugv/robot */
00830         const ugv_t *ugv = buyList.l[num + buyList.scroll].ugv;
00831         const objDef_t *ugvWeapon;
00832 
00833         UP_UGVDescription(ugv);
00834 
00835         /* Check if we have a weapon for this ugv in the market to sell it. */
00836         ugvWeapon = INVSH_GetItemByID(ugv->weapon);
00837         if (!ugvWeapon)
00838             Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get wepaon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id);
00839 
00840         employee = E_GetHiredRobot(base, ugv);
00841         if (!E_UnhireEmployee(employee)) {
00843             Com_DPrintf(DEBUG_CLIENT, "Couldn't sell/fire robot/ugv.\n");
00844         } else {
00845             if (base->storage.numItems[ugvWeapon->idx]) {
00846                 /* If we have a weapon we sell it as well. */
00847                 B_UpdateStorageAndCapacity(base, ugvWeapon, -1, qfalse, qfalse);
00848                 BS_AddItemToMarket(ugvWeapon, 1);
00849             }
00850             BS_BuyType(base);
00851             CL_UpdateCredits(ccs.credits + ugv->price); 
00852         }
00853     } else {
00854         const objDef_t *item = BS_GetObjectDefition(&buyList.l[num + buyList.scroll]);
00855         /* don't sell more items than we have */
00856         const int numItems = min(base->storage.numItems[item->idx], BS_GetBuySellFactor());
00857         /* Normal item (or equipment for UGVs/Robots if buyCategory==BUY_HEAVY) */
00858         assert(item);
00859         currentSelectedMenuEntry = item;
00860         INV_ItemDescription(item);
00861 
00862         /* don't sell more items than we have */
00863         if (numItems) {
00864             /* reinit the menu */
00865             B_UpdateStorageAndCapacity(base, item, -numItems, qfalse, qfalse);
00866             BS_AddItemToMarket(item, numItems);
00867             BS_BuyType(base);
00868             CL_UpdateCredits(ccs.credits + BS_GetItemSellingPrice(item) * numItems);
00869             BS_UpdateItem(base, num);
00870         }
00871     }
00872 }
00873 
00874 static void BS_BuySellItem_f (void)
00875 {
00876     float value;
00877 
00878     if (Cmd_Argc() < 3) {
00879         /* num is used in the other callbacks to do the real buy or sell */
00880         Com_Printf("Usage: %s <num> <value>\n", Cmd_Argv(0));
00881         return;
00882     }
00883 
00884     value = atof(Cmd_Argv(2));
00885     if (value == 0)
00886         return;
00887 
00888     if (value > 0) {
00889         BS_BuyItem_f();
00890     } else {
00891         BS_SellItem_f();
00892     }
00893 }
00894 
00898 static void BS_Autosell_f (void)
00899 {
00900     int num;
00901     const objDef_t *item;
00902     base_t *base = B_GetCurrentSelectedBase();
00903 
00904     /* Can be called from everywhere. */
00905     if (!base)
00906         return;
00907 
00908     if (Cmd_Argc() < 2) {
00909         Com_Printf("Usage: %s <num>\n", Cmd_Argv(0));
00910         return;
00911     }
00912 
00913     num = atoi(Cmd_Argv(1));
00914     Com_DPrintf(DEBUG_CLIENT, "BS_Autosell_f: listnumber %i\n", num);
00915     if (num < 0 || num >= buyList.length)
00916         return;
00917 
00918     item = BS_GetObjectDefition(&buyList.l[num + buyList.scroll]);
00919     assert(item);
00920 
00921     if (ccs.eMarket.autosell[item->idx]) {
00922         ccs.eMarket.autosell[item->idx] = qfalse;
00923         Com_DPrintf(DEBUG_CLIENT, "item name: %s, autosell false\n", item->name);
00924     } else {
00925         const technology_t *tech = RS_GetTechForItem(item);
00926         /* Don't allow to enable autosell for items not researched. */
00927         if (!RS_IsResearched_ptr(tech))
00928             return;
00929         ccs.eMarket.autosell[item->idx] = qtrue;
00930         Com_DPrintf(DEBUG_CLIENT, "item name: %s, autosell true\n", item->name);
00931     }
00932 
00933     /* Reinit the menu. */
00934     BS_BuyType(base);
00935 }
00936 
00937 
00938 
00939 void BS_InitCallbacks(void)
00940 {
00941     Cmd_AddCommand("buy_type", BS_BuyType_f, NULL);
00942     Cmd_AddCommand("market_click", BS_MarketClick_f, "Click function for buy menu text node");
00943     Cmd_AddCommand("market_scroll", BS_MarketScroll_f, "Scroll function for buy menu");
00944     Cmd_AddCommand("mn_buysell", BS_BuySellItem_f, NULL);
00945     Cmd_AddCommand("mn_buy", BS_BuyItem_f, NULL);
00946     Cmd_AddCommand("mn_sell", BS_SellItem_f, NULL);
00947     Cmd_AddCommand("buy_autosell", BS_Autosell_f, "Enable or disable autosell option for given item.");
00948     Cmd_AddCommand("market_openpedia", BS_MarketInfoClick_f, "Open UFOPedia entry for selected item");
00949 
00950     memset(&buyList, 0, sizeof(buyList));
00951     buyList.length = -1;
00952 }
00953 
00954 void BS_ShutdownCallbacks(void)
00955 {
00956     Cmd_RemoveCommand("buy_type");
00957     Cmd_RemoveCommand("market_click");
00958     Cmd_RemoveCommand("market_scroll");
00959     Cmd_RemoveCommand("mn_buysell");
00960     Cmd_RemoveCommand("mn_buy");
00961     Cmd_RemoveCommand("mn_sell");
00962     Cmd_RemoveCommand("buy_autosell");
00963     Cmd_RemoveCommand("market_openpedia");
00964 }

Generated by  doxygen 1.6.2