/** * @brief Update the current capacity of Workshop * @param[in] base Pointer to the base containing workshop. * @param[in] workerChange Number of workers going to be hired/fired */ void PR_UpdateProductionCap (base_t* base, int workerChange) { assert(base); capacities_t* workspaceCapacity = CAP_Get(base, CAP_WORKSPACE); if (workspaceCapacity->max <= 0) PR_EmptyQueue(base); const int workers = E_CountHired(base, EMPL_WORKER) + workerChange; if (workspaceCapacity->max >= workers) workspaceCapacity->cur = workers; else workspaceCapacity->cur = workspaceCapacity->max; /* recalculate time to finish */ production_queue_t* q = PR_GetProductionForBase(base); /* not actually any active productions */ if (q->numItems <= 0) return; /* Workshop is disabled because their dependences are disabled */ if (!PR_ProductionAllowed(base)) return; for (int i = 0; i < q->numItems; i++) { production_t* prod = &q->items[i]; prod->totalFrames = std::max(prod->frame, PR_CalculateTotalFrames(base, &prod->data)); } }
/** * @brief Checks whether an item is finished. * @note One call each game time minute * @sa CP_CampaignRun * @sa PR_DisassemblingFrame * @sa PR_ProductionFrame */ void PR_ProductionRun (void) { /* Loop through all founded bases. Then check productions * in global data array. Then increase prod->percentDone and check * whether an item is produced. Then add to base storage. */ base_t* base = nullptr; while ((base = B_GetNext(base)) != nullptr) { production_queue_t* q = PR_GetProductionForBase(base); /* not actually any active productions */ if (q->numItems <= 0) continue; /* Workshop is disabled because their dependences are disabled */ if (!PR_ProductionAllowed(base)) continue; production_t* prod = &q->items[0]; prod->totalFrames = PR_CalculateTotalFrames(base, &prod->data); if (!PR_CheckFrame(base, prod)) return; prod->frame++; /* If Production/Disassembly is not finished yet, we're done, check next base */ if (!PR_IsReady(prod)) continue; if (PR_IsProduction(prod)) PR_FinishProduction(base, prod); else if (PR_IsDisassembly(prod)) PR_FinishDisassembly(base, prod); } }
/** * @brief Set percentDone values after loading the campaign * @note it need to be done after B_PostLoadInitCapacity * @sa PR_PostLoadInit */ static bool PR_PostLoadInitProgress (void) { base_t* base = nullptr; while ((base = B_GetNext(base)) != nullptr) { production_queue_t* pq = PR_GetProductionForBase(base); for (int j = 0; j < pq->numItems; j++) { production_t* prod = &pq->items[j]; prod->totalFrames = PR_CalculateTotalFrames(base, &prod->data); } } return true; }
/** * @brief Add a new item to the bottom of the production queue. * @param[in] base Pointer to base, where the queue is. * @param[in] data The production data * @param[in] amount Desired amount to produce. * @return @c NULL in case the production wasn't enqueued, otherwise the production pointer */ production_t* PR_QueueNew (base_t* base, const productionData_t* data, signed int amount) { production_queue_t* queue = PR_GetProductionForBase(base); if (queue->numItems >= MAX_PRODUCTIONS) return nullptr; /* Initialize */ production_t* prod = &queue->items[queue->numItems]; OBJZERO(*prod); /* self-reference. */ prod->idx = queue->numItems; prod->data = *data; prod->amount = amount; const technology_t* tech = PR_GetTech(&prod->data); if (tech == nullptr) return nullptr; /* only one item for disassemblies */ if (PR_IsDisassemblyData(data)) amount = 1; else if (tech->produceTime < 0) /* Don't try to add an item to the queue which is not producible. */ return nullptr; amount = PR_RequirementsMet(amount, &tech->requireForProduction, base); if (amount == 0) return nullptr; prod->totalFrames = PR_CalculateTotalFrames(base, data); PR_UpdateRequiredItemsInBasestorage(base, -amount, &tech->requireForProduction); PR_SetUFODisassembly(prod); queue->numItems++; return prod; }
/** * @brief Calculates the production time (in hours) for a technology * @param[in] base Pointer to the base to calculate production time at * @param[in] prodData Pointer to the production data structure */ int PR_GetProductionHours (const base_t* base, const productionData_t* prodData) { return round(PR_CalculateTotalFrames(base, prodData) / (double)MINUTES_PER_HOUR); }
/** * @brief Calculates the production time (in hours) for a technology * @param[in] base Pointer to the base to calculate production time at * @param[in] prodData Pointer to the production data structure */ int PR_GetProductionHours (const base_t* base, const productionData_t* prodData) { return round(PR_CalculateTotalFrames(base, prodData) / std::max(1, PR_WorkersAvailable(base)) / (double)MINUTES_PER_HOUR); }
/** * @brief Load callback for xml savegames * @param[in] p XML Node structure, where we get the information from * @sa PR_SaveXML * @sa SAV_GameLoadXML */ bool PR_LoadXML (xmlNode_t* p) { xmlNode_t* node = cgi->XML_GetNode(p, SAVE_PRODUCE_PRODUCTION); for (xmlNode_t* snode = cgi->XML_GetNode(node, SAVE_PRODUCE_QUEUE); snode; snode = cgi->XML_GetNextNode(snode, node, SAVE_PRODUCE_QUEUE)) { xmlNode_t* ssnode; const int baseIDX = cgi->XML_GetInt(snode, SAVE_PRODUCE_QUEUEIDX, MAX_BASES); base_t* base = B_GetBaseByIDX(baseIDX); production_queue_t* pq; if (base == nullptr) { Com_Printf("Invalid production queue index %i\n", baseIDX); continue; } pq = PR_GetProductionForBase(base); for (ssnode = cgi->XML_GetNode(snode, SAVE_PRODUCE_ITEM); pq->numItems < MAX_PRODUCTIONS && ssnode; ssnode = cgi->XML_GetNextNode(ssnode, snode, SAVE_PRODUCE_ITEM)) { const char* s1 = cgi->XML_GetString(ssnode, SAVE_PRODUCE_ITEMID); production_t* prod = &pq->items[pq->numItems]; prod->idx = pq->numItems; prod->amount = cgi->XML_GetInt(ssnode, SAVE_PRODUCE_AMOUNT, 0); prod->frame = cgi->XML_GetInt(ssnode, SAVE_PRODUCE_PROGRESS, 0); /* amount */ if (prod->amount <= 0) { Com_Printf("PR_LoadXML: Production with amount <= 0 dropped (baseidx=%i, production idx=%i).\n", baseIDX, pq->numItems); continue; } /* item */ if (s1[0] != '\0') PR_SetData(&prod->data, PRODUCTION_TYPE_ITEM, INVSH_GetItemByID(s1)); /* UFO */ const int ufoIDX = cgi->XML_GetInt(ssnode, SAVE_PRODUCE_UFOIDX, -1); if (ufoIDX != -1) { storedUFO_t* ufo = US_GetStoredUFOByIDX(ufoIDX); if (!ufo) { Com_Printf("PR_LoadXML: Could not find ufo idx: %i\n", ufoIDX); continue; } PR_SetData(&prod->data, PRODUCTION_TYPE_DISASSEMBLY, ufo); PR_SetUFODisassembly(prod); } /* aircraft */ const char* s2 = cgi->XML_GetString(ssnode, SAVE_PRODUCE_AIRCRAFTID); if (s2[0] != '\0') PR_SetData(&prod->data, PRODUCTION_TYPE_AIRCRAFT, AIR_GetAircraft(s2)); if (!PR_IsDataValid(&prod->data)) { Com_Printf("PR_LoadXML: Production is not an item an aircraft nor a disassembly\n"); continue; } prod->totalFrames = PR_CalculateTotalFrames(base, &prod->data); pq->numItems++; } } return true; }