cp_produce.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_popup.h"
00029 #include "cp_campaign.h"
00030 #include "cp_ufo.h"
00031 #include "cp_produce.h"
00032 #include "cp_produce_callbacks.h"
00033 #include "save/save_produce.h"
00034 
00036 const int PRODUCE_FACTOR = 1;
00037 const int PRODUCE_DIVISOR = 1;
00038 
00041 static const int PRODUCE_WORKERS = 10;
00042 
00043 static cvar_t* mn_production_limit;     
00044 static cvar_t* mn_production_workers;       
00045 static cvar_t* mn_production_amount;    
00057 float PR_CalculateProductionPercentDone (const base_t *base, const technology_t *tech, const storedUFO_t *const storedUFO)
00058 {
00059     signed int allWorkers = 0;
00060     signed int maxWorkers = 0;
00061     signed int timeDefault = 0;
00062     float distanceFactor = 0.0f;
00063 
00064     assert(base);
00065     assert(tech);
00066 
00067     /* Check how many workers hired in this base. */
00068     allWorkers = E_CountHired(base, EMPL_WORKER);
00069     /* We will not use more workers than base capacity. */
00070     maxWorkers = min(allWorkers, base->capacities[CAP_WORKSPACE].max);
00071 
00072     if (!storedUFO) {
00073         /* This is the default production time for 10 workers. */
00074         timeDefault = tech->produceTime;
00075     } else {
00076         assert(storedUFO->comp);
00077         /* This is the default disassembly time for 10 workers. */
00078         timeDefault = storedUFO->comp->time;
00079         /* Production is 4 times longer when installation is on Antipodes */
00080         distanceFactor = GetDistanceOnGlobe(storedUFO->installation->pos, base->pos) / 45.0f;
00081         assert(distanceFactor >= 0.0f);
00082         /* Penalty starts when distance is greater than 45 degrees */
00083         distanceFactor = max(1.0f, distanceFactor);
00084         Com_DPrintf(DEBUG_CLIENT, "PR_CalculatePercentDone: distanceFactor is %f\n", distanceFactor);
00085     }
00086     if (maxWorkers == PRODUCE_WORKERS) {
00087         /* No need to calculate: timeDefault is for PRODUCE_WORKERS workers. */
00088         const float fraction =  1.0f / ((NULL != storedUFO) ? (distanceFactor * timeDefault) : timeDefault);
00089         Com_DPrintf(DEBUG_CLIENT, "PR_CalculatePercentDone: workers: %i, tech: %s, percent: %f\n",
00090             maxWorkers, tech->id, fraction);
00091         return fraction;
00092     } else {
00093         /* Calculate the fraction of item produced for our amount of workers. */
00094         const float fraction = ((float)maxWorkers / (PRODUCE_WORKERS * ((NULL != storedUFO) ? (distanceFactor * timeDefault) : timeDefault)));
00095         Com_DPrintf(DEBUG_CLIENT, "PR_CalculatePercentDone: workers: %i, tech: %s, percent: %f\n",
00096             maxWorkers, tech->id, fraction);
00097         /* Don't allow to return fraction greater than 1 (you still need at least 1 hour to produce an item). */
00098         return min(fraction, 1.0f);
00099     }
00100 }
00101 
00108 void PR_UpdateRequiredItemsInBasestorage (base_t *base, int amount, const requirements_t const *reqs)
00109 {
00110     int i;
00111 
00112     if (!base)
00113         return;
00114 
00115     if (amount == 0)
00116         return;
00117 
00118     for (i = 0; i < reqs->numLinks; i++) {
00119         const requirement_t const *req = &reqs->links[i];
00120         switch (req->type) {
00121         case RS_LINK_ITEM: {
00122             const objDef_t *item = (const objDef_t *)req->link;
00123             assert(item);
00124             B_AddToStorage(base, item, req->amount * amount);
00125             break;
00126         }
00127         case RS_LINK_ANTIMATTER:
00128             if (req->amount > 0)
00129                 B_ManageAntimatter(base, req->amount * amount, qtrue);
00130             else if (req->amount < 0)
00131                 B_ManageAntimatter(base, req->amount * -amount, qfalse);
00132             break;
00133         case RS_LINK_TECH:
00134         case RS_LINK_TECH_NOT:
00135             break;
00136         default:
00137             Com_Error(ERR_DROP, "Invalid requirement for production!\n");
00138         }
00139     }
00140 }
00141 
00149 int PR_RequirementsMet (int amount, const requirements_t const *reqs, base_t *base)
00150 {
00151     int i;
00152     int producibleAmount = amount;
00153 
00154     for (i = 0; i < reqs->numLinks; i++) {
00155         const requirement_t const *req = &reqs->links[i];
00156 
00157         switch (req->type) {
00158         case RS_LINK_ITEM: {
00159                 const int items = min(amount, B_ItemInBase(req->link, base) / ((req->amount) ? req->amount : 1));
00160                 producibleAmount = min(producibleAmount, items);
00161                 break;
00162             }
00163         case RS_LINK_ANTIMATTER: {
00164                 const int am = min(amount, B_AntimatterInBase(base) / ((req->amount) ? req->amount : 1));
00165                 producibleAmount = min(producibleAmount, am);
00166                 break;
00167             }
00168         case RS_LINK_TECH:
00169             producibleAmount = (RS_IsResearched_ptr(req->link)) ? producibleAmount : 0;
00170             break;
00171         case RS_LINK_TECH_NOT:
00172             producibleAmount = (RS_IsResearched_ptr(req->link)) ? 0 : producibleAmount;
00173             break;
00174         default:
00175             break;
00176         }
00177     }
00178 
00179     return producibleAmount;
00180 }
00181 
00186 int PR_QueueFreeSpace (const production_queue_t const *queue)
00187 {
00188     base_t *base = PR_ProductionQueueBase(queue);
00189     int numWorkshops;
00190 
00191     assert(queue);
00192     assert(base);
00193 
00194     numWorkshops = max(B_GetNumberOfBuildingsInBaseByBuildingType(base, B_WORKSHOP), 0);
00195 
00196     return min(MAX_PRODUCTIONS, numWorkshops * MAX_PRODUCTIONS_PER_WORKSHOP - queue->numItems);
00197 }
00198 
00208 production_t *PR_QueueNew (base_t *base, production_queue_t *queue, objDef_t *item, aircraft_t *aircraftTemplate, storedUFO_t *ufo, signed int amount)
00209 {
00210     production_t *prod;
00211     const technology_t *tech;
00212 
00213     assert((item && !aircraftTemplate && !ufo) || (!item && aircraftTemplate && !ufo) || (!item && !aircraftTemplate && ufo));
00214     assert(base);
00215 
00216     if (PR_QueueFreeSpace(queue) <= 0)
00217         return NULL;
00218     if (E_CountHired(base, EMPL_WORKER) <= 0)
00219         return NULL;
00220 
00221     /* Initialize */
00222     prod = &queue->items[queue->numItems];
00223     memset(prod, 0, sizeof(*prod));
00224 
00225     /* self-reference. */
00226     prod->idx = queue->numItems;
00227 
00228     if (item) {
00229         tech = RS_GetTechForItem(item);
00230     } else if (aircraftTemplate) {
00231         tech = aircraftTemplate->tech;
00232     } else {
00233         tech = ufo->ufoTemplate->tech;
00234         amount = 1;
00235     }
00236 
00237     if (!tech)
00238         return NULL;
00239 
00240     amount = PR_RequirementsMet(amount, &tech->requireForProduction, base);
00241     if (amount == 0)
00242         return NULL;
00243 
00244     PR_UpdateRequiredItemsInBasestorage(base, -amount, &tech->requireForProduction);
00245     if (tech->requireForProduction.numLinks)
00246 
00247     /* We cannot queue new aircraft if no free hangar space. */
00249     if (aircraftTemplate) {
00250         if (!B_GetBuildingStatus(base, B_COMMAND)) {
00252             UI_Popup(_("Hangars not ready"), _("You cannot queue aircraft.\nNo command centre in this base.\n"));
00253             return NULL;
00254         } else if (!B_GetBuildingStatus(base, B_HANGAR) && !B_GetBuildingStatus(base, B_SMALL_HANGAR)) {
00256             UI_Popup(_("Hangars not ready"), _("You cannot queue aircraft.\nNo hangars in this base.\n"));
00257             return NULL;
00258         }
00260         if (AIR_CalculateHangarStorage(aircraftTemplate, base, 0) <= 0) {
00261             UI_Popup(_("Hangars not ready"), _("You cannot queue aircraft.\nNo free space in hangars.\n"));
00262             return NULL;
00263         }
00264     }
00265 
00266     prod->item = item;
00267     prod->aircraft = aircraftTemplate;
00268     prod->ufo = ufo;
00269     prod->amount = amount;
00270     prod->percentDone = 0.0f;
00271 
00272     if (ufo) {
00273         /* Disassembling. */
00274         prod->production = qfalse;
00275         ufo->disassembly = prod;
00276     } else {
00277         /* Production. */
00278         prod->production = qtrue;
00279 
00280         /* Don't try to add to queue an item which is not producible. */
00281         if (tech->produceTime < 0)
00282             return NULL;
00283     }
00284 
00285     queue->numItems++;
00286     return prod;
00287 }
00288 
00295 void PR_QueueDelete (base_t *base, production_queue_t *queue, int index)
00296 {
00297     int i;
00298     production_t *prod = &queue->items[index];
00299     technology_t *tech = NULL;
00300 
00301     if (!base)
00302         base = PR_ProductionQueueBase(queue);
00303     assert(base);
00304 
00305     if (prod->item) {
00306         tech = RS_GetTechForItem(prod->item);
00307     } else if (prod->aircraft) {
00308         tech = prod->aircraft->tech;
00309     } else if (prod->ufo) {
00310         assert(prod->ufo->ufoTemplate);
00311         tech = prod->ufo->ufoTemplate->tech;
00312         prod->ufo->disassembly = NULL;
00313     }
00314     assert(tech);
00315 
00316     PR_UpdateRequiredItemsInBasestorage(base, prod->amount, &tech->requireForProduction);
00317 
00318     REMOVE_ELEM_ADJUST_IDX(queue->items, index, queue->numItems);
00319 
00320     /* Adjust ufos' disassembly pointer */
00321     for (i = index; i < queue->numItems; i++) {
00322         production_t *disassembly = &queue->items[i];
00323 
00324         if (disassembly->ufo)
00325             disassembly->ufo->disassembly = disassembly;
00326     }
00327 }
00328 
00335 void PR_QueueMove (production_queue_t *queue, int index, int dir)
00336 {
00337     const int newIndex = max(0, min(index + dir, queue->numItems - 1));
00338     int i;
00339     production_t saved;
00340 
00341     if (newIndex == index)
00342         return;
00343 
00344     saved = queue->items[index];
00345 
00346     /* copy up */
00347     for (i = index; i < newIndex; i++) {
00348         queue->items[i] = queue->items[i + 1];
00349         queue->items[i].idx = i;
00350         if (queue->items[i].ufo)
00351             queue->items[i].ufo->disassembly = &(queue->items[i]);
00352     }
00353 
00354     /* copy down */
00355     for (i = index; i > newIndex; i--) {
00356         queue->items[i] = queue->items[i - 1];
00357         queue->items[i].idx = i;
00358         if (queue->items[i].ufo)
00359             queue->items[i].ufo->disassembly = &(queue->items[i]);
00360     }
00361 
00362     /* insert item */
00363     queue->items[newIndex] = saved;
00364     queue->items[newIndex].idx = newIndex;
00365     if (queue->items[newIndex].ufo)
00366         queue->items[newIndex].ufo->disassembly = &(queue->items[newIndex]);
00367 }
00368 
00373 void PR_QueueNext (base_t *base)
00374 {
00375     production_queue_t *queue = &ccs.productions[base->idx];
00376 
00377     PR_QueueDelete(base, queue, 0);
00378 
00379     if (queue->numItems == 0) {
00380         Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Production queue for %s is empty"), base->name);
00381         MSO_CheckAddNewMessage(NT_PRODUCTION_QUEUE_EMPTY, _("Production queue empty"), cp_messageBuffer, qfalse, MSG_PRODUCTION, NULL);
00382     }
00383 }
00384 
00388 static void PR_EmptyQueue (base_t *base)
00389 {
00390     production_queue_t *queue;
00391 
00392     if (!base)
00393         return;
00394 
00395     queue = &ccs.productions[base->idx];
00396     if (!queue)
00397         return;
00398 
00399     while (queue->numItems)
00400         PR_QueueDelete(base, queue, 0);
00401 }
00402 
00406 static void PR_ProductionRollBottom_f (void)
00407 {
00408     production_queue_t *queue;
00409     base_t *base = B_GetCurrentSelectedBase();
00410 
00411     if (!base)
00412         return;
00413 
00414     queue = &ccs.productions[base->idx];
00415 
00416     if (queue->numItems < 2)
00417         return;
00418 
00419     PR_QueueMove(queue, 0, queue->numItems - 1);
00420 }
00421 
00430 static int PR_DisassembleItem (base_t *base, components_t *comp, float condition, qboolean calculate)
00431 {
00432     int i;
00433     int size = 0;
00434 
00435     if (!calculate && !base)    /* We need base only if this is real disassembling. */
00436         Com_Error(ERR_DROP, "PR_DisassembleItem: No base given");
00437 
00438     assert(comp);
00439     for (i = 0; i < comp->numItemtypes; i++) {
00440         const objDef_t *compOd = comp->items[i];
00441         const int amount = (condition < 1 && comp->itemAmount2[i] != COMP_ITEMCOUNT_SCALED) ? comp->itemAmount2[i] : round(comp->itemAmount[i] * condition);
00442 
00443         assert(compOd);
00444         size += compOd->size * amount;
00445         /* Add to base storage only if this is real disassembling, not calculation of size. */
00446         if (!calculate) {
00447             if (!strcmp(compOd->id, ANTIMATTER_TECH_ID)) {
00448                 B_ManageAntimatter(base, amount, qtrue);
00449             } else {
00450                 technology_t *tech = RS_GetTechForItem(compOd);
00451                 B_UpdateStorageAndCapacity(base, compOd, amount, qfalse, qfalse);
00452                 RS_MarkCollected(tech);
00453             }
00454             Com_DPrintf(DEBUG_CLIENT, "PR_DisassembleItem: added %i amounts of %s\n", amount, compOd->id);
00455         }
00456     }
00457     return size;
00458 }
00459 
00467 static void PR_ProductionFrame (base_t* base, production_t *prod)
00468 {
00469     const objDef_t *od;
00470     const aircraft_t *aircraft;
00471 
00472     if (!prod->production)
00473         return;
00474 
00475     if (!prod->item && !prod->aircraft)
00476         return;
00477 
00478     if (prod->item) {
00479         od = prod->item;
00480         aircraft = NULL;
00481     } else if (prod->aircraft) {
00482         od = NULL;
00483         aircraft = prod->aircraft;
00484     }
00485 
00486     if (od) {
00487         /* Not enough money to produce more items in this base. */
00488         if (od->price * PRODUCE_FACTOR / PRODUCE_DIVISOR > ccs.credits) {
00489             if (!prod->creditMessage) {
00490                 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Not enough credits to finish production in %s."), base->name);
00491                 MSO_CheckAddNewMessage(NT_PRODUCTION_FAILED, _("Notice"), cp_messageBuffer, qfalse, MSG_STANDARD, NULL);
00492                 prod->creditMessage = qtrue;
00493             }
00494             PR_ProductionRollBottom_f();
00495             return;
00496         }
00497         /* Not enough free space in base storage for this item. */
00498         if (base->capacities[CAP_ITEMS].max - base->capacities[CAP_ITEMS].cur < od->size) {
00499             if (!prod->spaceMessage) {
00500                 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Not enough free storage space in %s. Production postponed."), base->name);
00501                 MSO_CheckAddNewMessage(NT_PRODUCTION_FAILED, _("Notice"), cp_messageBuffer, qfalse, MSG_STANDARD, NULL);
00502                 prod->spaceMessage = qtrue;
00503             }
00504             PR_ProductionRollBottom_f();
00505             return;
00506         }
00507         prod->percentDone += (PR_CalculateProductionPercentDone(base, RS_GetTechForItem(od), NULL) / MINUTES_PER_HOUR);
00508     } else if (aircraft) {
00509         /* Not enough money to produce more items in this base. */
00510         if (aircraft->price * PRODUCE_FACTOR / PRODUCE_DIVISOR > ccs.credits) {
00511             if (!prod->creditMessage) {
00512                 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Not enough credits to finish production in %s."), base->name);
00513                 MSO_CheckAddNewMessage(NT_PRODUCTION_FAILED, _("Notice"), cp_messageBuffer, qfalse, MSG_STANDARD, NULL);
00514                 prod->creditMessage = qtrue;
00515             }
00516             PR_ProductionRollBottom_f();
00517             return;
00518         }
00519         /* Not enough free space in hangars for this aircraft. */
00520         if (AIR_CalculateHangarStorage(prod->aircraft, base, 0) <= 0) {
00521             if (!prod->spaceMessage) {
00522                 Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Not enough free hangar space in %s. Production postponed."), base->name);
00523                 MSO_CheckAddNewMessage(NT_PRODUCTION_FAILED, _("Notice"), cp_messageBuffer, qfalse, MSG_STANDARD, NULL);
00524                 prod->spaceMessage = qtrue;
00525             }
00526             PR_ProductionRollBottom_f();
00527             return;
00528         }
00529         prod->percentDone += (PR_CalculateProductionPercentDone(base, aircraft->tech, NULL) / MINUTES_PER_HOUR);
00530     }
00531 
00532     if (prod->percentDone >= 1.0f) {
00533         const char *name = NULL;
00534         technology_t *tech = NULL;
00535 
00536         prod->percentDone = 0.0f;
00537         prod->amount--;
00538 
00539         if (od) {
00540             CL_UpdateCredits(ccs.credits - (od->price * PRODUCE_FACTOR / PRODUCE_DIVISOR));
00541             /* Now add it to equipment and update capacity. */
00542             B_UpdateStorageAndCapacity(base, prod->item, 1, qfalse, qfalse);
00543             name = _(od->name);
00544             tech = RS_GetTechForItem(od);
00545         } else if (aircraft) {
00546             CL_UpdateCredits(ccs.credits - (aircraft->price * PRODUCE_FACTOR / PRODUCE_DIVISOR));
00547             /* Now add new aircraft. */
00548             AIR_NewAircraft(base, aircraft->id);
00549             name = _(aircraft->tpl->name);
00550             tech = aircraft->tech;
00551         }
00552 
00553         /* queue the next production */
00554         if (prod->amount <= 0) {
00555             Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("The production of %s at %s has finished."), name, base->name);
00556             MSO_CheckAddNewMessage(NT_PRODUCTION_FINISHED, _("Production finished"), cp_messageBuffer, qfalse, MSG_PRODUCTION, tech);
00557             PR_QueueNext(base);
00558         }
00559     }
00560 }
00561 
00569 static void PR_DisassemblingFrame (base_t* base, production_t* prod)
00570 {
00571     storedUFO_t *ufo;
00572 
00573     if (prod->production)
00574         return;
00575 
00576     if (!prod->ufo)
00577         return;
00578 
00579     ufo = prod->ufo;
00580 
00581     if (base->capacities[CAP_ITEMS].max - base->capacities[CAP_ITEMS].cur < PR_DisassembleItem(NULL, ufo->comp, ufo->condition, qtrue)) {
00582         if (!prod->spaceMessage) {
00583             Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Not enough free storage space in %s. Disassembling postponed."), base->name);
00584             MSO_CheckAddNewMessage(NT_PRODUCTION_FAILED, _("Notice"), cp_messageBuffer, qfalse, MSG_STANDARD, NULL);
00585             prod->spaceMessage = qtrue;
00586         }
00587         PR_ProductionRollBottom_f();
00588         return;
00589     }
00590     prod->percentDone += (PR_CalculateProductionPercentDone(base, ufo->ufoTemplate->tech, ufo) / MINUTES_PER_HOUR);
00591 
00592     if (prod->percentDone >= 1.0f) {
00593         base->capacities[CAP_ITEMS].cur += PR_DisassembleItem(base, ufo->comp, ufo->condition, qfalse);
00594 
00595         Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("The disassembling of %s at %s has finished."), UFO_TypeToName(ufo->ufoTemplate->ufotype), base->name);
00596         MSO_CheckAddNewMessage(NT_PRODUCTION_FINISHED, _("Production finished"), cp_messageBuffer, qfalse, MSG_PRODUCTION, ufo->ufoTemplate->tech);
00597 
00598         /* Removing UFO will remove the production too */
00599         US_RemoveStoredUFO(ufo);
00600     }
00601 }
00602 
00609 int PR_IncreaseProduction (production_t *prod, int amount)
00610 {
00611     base_t *base;
00612     technology_t *tech = NULL;
00613 
00614     assert(prod);
00615     base = PR_ProductionBase(prod);
00616     assert(base);
00617 
00618     if (prod->ufo)
00619         return 0;
00620 
00621     /* amount limit per one production */
00622     if (prod->amount + amount > MAX_PRODUCTION_AMOUNT) {
00623         amount = max(0, MAX_PRODUCTION_AMOUNT - prod->amount);
00624     }
00625 
00626     if (prod->item) {
00627         tech = RS_GetTechForItem(prod->item);
00628     } else if (prod->aircraft) {
00629         tech = prod->aircraft->tech;
00630     }
00631     assert(tech);
00632 
00633     amount = PR_RequirementsMet(amount, &tech->requireForProduction, base);
00634     if (amount == 0)
00635         return 0;
00636 
00637     prod->amount += amount;
00638     PR_UpdateRequiredItemsInBasestorage(base, -amount, &tech->requireForProduction);
00639     
00640     return amount;
00641 }
00642 
00650 int PR_DecreaseProduction (production_t *prod, int amount)
00651 {
00652     base_t *base;
00653     technology_t *tech = NULL;
00654     production_queue_t *queue;
00655 
00656     assert(prod);
00657     base = PR_ProductionBase(prod);
00658     assert(base);
00659 
00660     queue = &ccs.productions[base->idx];
00661 
00662     if (prod->ufo)
00663         return 0;
00664 
00665     if (prod->amount <= amount) {
00666         amount = prod->amount;
00667         PR_QueueDelete(base, queue, prod->idx);
00668         return amount;
00669     }
00670 
00671     if (prod->item) {
00672         tech = RS_GetTechForItem(prod->item);
00673     } else if (prod->aircraft) {
00674         tech = prod->aircraft->tech;
00675     } else if (prod->ufo) {
00676         assert(prod->ufo->ufoTemplate);
00677         tech = prod->ufo->ufoTemplate->tech;
00678     }
00679     assert(tech);
00680 
00681     prod->amount += -amount;
00682     PR_UpdateRequiredItemsInBasestorage(base, amount, &tech->requireForProduction);
00683     
00684     return amount;
00685 }
00686 
00693 void PR_ProductionRun (void)
00694 {
00695     int i;
00696     production_t *prod;
00697 
00698     /* Loop through all founded bases. Then check productions
00699      * in global data array. Then increase prod->percentDone and check
00700      * whether an item is produced. Then add to base storage. */
00701     for (i = 0; i < MAX_BASES; i++) {
00702         base_t *base = B_GetFoundedBaseByIDX(i);
00703         if (!base)
00704             continue;
00705 
00706         /* not actually any active productions */
00707         if (ccs.productions[i].numItems <= 0)
00708             continue;
00709 
00710         /* Workshop is disabled because their dependences are disabled */
00711         if (!PR_ProductionAllowed(base))
00712             continue;
00713 
00714         prod = &ccs.productions[i].items[0];
00715 
00716         PR_ProductionFrame(base, prod);
00717         PR_DisassemblingFrame(base, prod);
00718     }
00719 }
00720 
00726 qboolean PR_ProductionAllowed (const base_t* base)
00727 {
00728     assert(base);
00729     if (base->baseStatus != BASE_UNDER_ATTACK
00730      && B_GetBuildingStatus(base, B_WORKSHOP)
00731      && E_CountHired(base, EMPL_WORKER) > 0) {
00732         return qtrue;
00733     } else {
00734         return qfalse;
00735     }
00736 }
00737 
00738 void PR_ProductionInit (void)
00739 {
00740     mn_production_limit = Cvar_Get("mn_production_limit", "0", 0, NULL);
00741     mn_production_workers = Cvar_Get("mn_production_workers", "0", 0, NULL);
00742     mn_production_amount = Cvar_Get("mn_production_amount", "0", 0, NULL);
00743 }
00744 
00749 void PR_UpdateProductionCap (base_t *base)
00750 {
00751     assert(base);
00752 
00753     if (base->capacities[CAP_WORKSPACE].max <= 0) {
00754         PR_EmptyQueue(base);
00755     }
00756 
00757     if (base->capacities[CAP_WORKSPACE].max >= E_CountHired(base, EMPL_WORKER)) {
00758         base->capacities[CAP_WORKSPACE].cur = E_CountHired(base, EMPL_WORKER);
00759     } else {
00760         base->capacities[CAP_WORKSPACE].cur = base->capacities[CAP_WORKSPACE].max;
00761     }
00762 }
00763 
00768 qboolean PR_ItemIsProduceable (const objDef_t const *item)
00769 {
00770     const technology_t *tech = RS_GetTechForItem(item);
00771     return tech->produceTime != -1;
00772 }
00773 
00779 base_t *PR_ProductionBase (production_t *production)
00780 {
00781     int i;
00782     for (i = 0; i < ccs.numBases; i++) {
00783         base_t *base = B_GetBaseByIDX(i);
00784         const ptrdiff_t diff = ((ptrdiff_t)((production) - ccs.productions[i].items));
00785 
00786         if (diff >= 0 && diff < MAX_PRODUCTIONS)
00787             return base;
00788     }
00789     return NULL;
00790 }
00791 
00797 base_t *PR_ProductionQueueBase (const production_queue_t const *queue)
00798 {
00799     const ptrdiff_t baseIDX = (ptrdiff_t)(queue - ccs.productions);
00800     base_t *base = B_GetFoundedBaseByIDX(baseIDX);
00801 
00802     return base;
00803 }
00804 
00811 qboolean PR_SaveXML (mxml_node_t *p)
00812 {
00813     int i;
00814     mxml_node_t *node = mxml_AddNode(p, SAVE_PRODUCE_PRODUCTION);
00815 
00816     for (i = 0; i < ccs.numBases; i++) {
00817         const production_queue_t *pq = &ccs.productions[i];
00818         int j;
00819 
00820         mxml_node_t *snode = mxml_AddNode(node, SAVE_PRODUCE_QUEUE);
00821         mxml_AddInt(snode, SAVE_PRODUCE_QUEUEIDX, i);
00822 
00823         for (j = 0; j < pq->numItems; j++) {
00824             const objDef_t *item = pq->items[j].item;
00825             const aircraft_t *aircraft = pq->items[j].aircraft;
00826             const storedUFO_t *ufo = pq->items[j].ufo;
00827 
00828             mxml_node_t * ssnode = mxml_AddNode(snode, SAVE_PRODUCE_ITEM);
00829             assert(item || aircraft || ufo);
00830             if (item)
00831                 mxml_AddString(ssnode, SAVE_PRODUCE_ITEMID, item->id);
00832             else if (aircraft)
00833                 mxml_AddString(ssnode, SAVE_PRODUCE_AIRCRAFTID, aircraft->id);
00834             else if (ufo)
00835                 mxml_AddInt(ssnode, SAVE_PRODUCE_UFOIDX, ufo->idx);
00836             mxml_AddInt(ssnode, SAVE_PRODUCE_AMOUNT, pq->items[j].amount);
00837             mxml_AddFloatValue(ssnode, SAVE_PRODUCE_PERCENTDONE, pq->items[j].percentDone);
00838         }
00839     }
00840     return qtrue;
00841 }
00842 
00849 qboolean PR_LoadXML (mxml_node_t *p)
00850 {
00851     mxml_node_t *node, *snode;
00852 
00853     node = mxml_GetNode(p, SAVE_PRODUCE_PRODUCTION);
00854 
00855     for (snode = mxml_GetNode(node, SAVE_PRODUCE_QUEUE); snode;
00856             snode = mxml_GetNextNode(snode, node, SAVE_PRODUCE_QUEUE)) {
00857         mxml_node_t *ssnode;
00858         int baseIDX = mxml_GetInt(snode, SAVE_PRODUCE_QUEUEIDX, MAX_BASES);
00859         production_queue_t *pq;
00860 
00861         if (baseIDX < 0 || baseIDX >= ccs.numBases) {
00862             Com_Printf("Invalid production queue index %i\n", baseIDX);
00863             continue;
00864         }
00865 
00866         pq = &ccs.productions[baseIDX];
00867 
00868         for (ssnode = mxml_GetNode(snode, SAVE_PRODUCE_ITEM); pq->numItems < MAX_PRODUCTIONS && ssnode;
00869                 ssnode = mxml_GetNextNode(ssnode, snode, SAVE_PRODUCE_ITEM)) {
00870             const char *s1 = mxml_GetString(ssnode, SAVE_PRODUCE_ITEMID);
00871             const char *s2;
00872             int ufoIDX;
00873 
00874             pq->items[pq->numItems].idx = pq->numItems;
00875             pq->items[pq->numItems].amount = mxml_GetInt(ssnode, SAVE_PRODUCE_AMOUNT, 0);
00876             pq->items[pq->numItems].percentDone = mxml_GetFloat(ssnode, SAVE_PRODUCE_PERCENTDONE, 0.0);
00877 
00878             /* amount */
00879             if (pq->items[pq->numItems].amount <= 0) {
00880                 Com_Printf("PR_Load: Production with amount <= 0 dropped (baseidx=%i, production idx=%i).\n", baseIDX, pq->numItems);
00881                 continue;
00882             }
00883             /* item */
00884             if (s1[0] != '\0')
00885                 pq->items[pq->numItems].item = INVSH_GetItemByID(s1);
00886             /* UFO */
00887             ufoIDX = mxml_GetInt(ssnode, SAVE_PRODUCE_UFOIDX, -1);
00888             if (ufoIDX != -1) {
00889                 storedUFO_t *ufo = US_GetStoredUFOByIDX(ufoIDX);
00890 
00891                 if (!ufo) {
00892                     Com_Printf("PR_Load: Could not find ufo idx: %i\n", ufoIDX);
00893                     continue;
00894                 }
00895 
00896                 pq->items[pq->numItems].ufo = ufo;
00897                 pq->items[pq->numItems].production = qfalse;
00898                 pq->items[pq->numItems].ufo->disassembly = &(pq->items[pq->numItems]);
00899             } else {
00900                 pq->items[pq->numItems].production = qtrue;
00901             }
00902             /* aircraft */
00903             s2 = mxml_GetString(ssnode, SAVE_PRODUCE_AIRCRAFTID);
00904             if (s2[0] != '\0')
00905                 pq->items[pq->numItems].aircraft = AIR_GetAircraft(s2);
00906 
00907             if (!pq->items[pq->numItems].item && !pq->items[pq->numItems].ufo && !pq->items[pq->numItems].aircraft) {
00908                 Com_Printf("PR_Load: Production is not an item an aircraft nor a disassembly\n");
00909                 continue;
00910             }
00911 
00912             pq->numItems++;
00913         }
00914     }
00915     return qtrue;
00916 }
00917 

Generated by  doxygen 1.6.2