00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00068 allWorkers = E_CountHired(base, EMPL_WORKER);
00069
00070 maxWorkers = min(allWorkers, base->capacities[CAP_WORKSPACE].max);
00071
00072 if (!storedUFO) {
00073
00074 timeDefault = tech->produceTime;
00075 } else {
00076 assert(storedUFO->comp);
00077
00078 timeDefault = storedUFO->comp->time;
00079
00080 distanceFactor = GetDistanceOnGlobe(storedUFO->installation->pos, base->pos) / 45.0f;
00081 assert(distanceFactor >= 0.0f);
00082
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
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
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
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
00222 prod = &queue->items[queue->numItems];
00223 memset(prod, 0, sizeof(*prod));
00224
00225
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
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
00274 prod->production = qfalse;
00275 ufo->disassembly = prod;
00276 } else {
00277
00278 prod->production = qtrue;
00279
00280
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
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
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
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
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)
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
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
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
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
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
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
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
00548 AIR_NewAircraft(base, aircraft->id);
00549 name = _(aircraft->tpl->name);
00550 tech = aircraft->tech;
00551 }
00552
00553
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
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
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
00699
00700
00701 for (i = 0; i < MAX_BASES; i++) {
00702 base_t *base = B_GetFoundedBaseByIDX(i);
00703 if (!base)
00704 continue;
00705
00706
00707 if (ccs.productions[i].numItems <= 0)
00708 continue;
00709
00710
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
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
00884 if (s1[0] != '\0')
00885 pq->items[pq->numItems].item = INVSH_GetItemByID(s1);
00886
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
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