00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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
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
00204 for (i = 0; i < MAX_MARKET_MENU_ENTRIES; i++) {
00205 UI_ExecuteConfunc("buy_autoselli %i", i);
00206 }
00207
00208
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
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
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
00330 switch (buyCat) {
00331 case FILTER_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:
00360
00361 for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) {
00362 if (!BS_IsOnMarket(od))
00363 continue;
00364
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:
00387 {
00388
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,
00409 unhiredRobot,
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
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
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:
00452 if (buyCat < MAX_SOLDIER_FILTERTYPES || buyCat == FILTER_DUMMY) {
00453
00454 for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) {
00455 if (!BS_IsOnMarket(od))
00456 continue;
00457
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
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
00485 UI_ExecuteConfunc("buy_autoselli %i", j);
00486 UI_ExecuteConfunc("buy_hide %i", j);
00487 }
00488
00489
00490
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
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
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
00521 if (currentSelectedMenuEntry)
00522 INV_ItemDescription(currentSelectedMenuEntry);
00523 else
00524 INV_ItemDescription(buyList.l[0].item);
00525 break;
00526 }
00527 } else {
00528
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
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
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
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
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
00670 aircraftOutNote = qtrue;
00671 continue;
00672 }
00673 found = qtrue;
00674 break;
00675 }
00676 }
00677
00678
00679 if (found) {
00680 int j;
00681
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
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
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
00699 BS_AddAircraftToMarket(aircraft, 1);
00700 CL_UpdateCredits(ccs.credits + BS_GetAircraftSellingPrice(aircraft));
00701
00702 AIR_DeleteAircraft(aircraft);
00703
00704
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
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
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
00773 B_UpdateStorageAndCapacity(base, ugvWeapon, 1, qfalse, qfalse);
00774 BS_RemoveItemFromMarket(ugvWeapon, 1);
00775
00776
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
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
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
00830 const ugv_t *ugv = buyList.l[num + buyList.scroll].ugv;
00831 const objDef_t *ugvWeapon;
00832
00833 UP_UGVDescription(ugv);
00834
00835
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
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
00856 const int numItems = min(base->storage.numItems[item->idx], BS_GetBuySellFactor());
00857
00858 assert(item);
00859 currentSelectedMenuEntry = item;
00860 INV_ItemDescription(item);
00861
00862
00863 if (numItems) {
00864
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
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
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
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
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 }