/** * @brief Make sure values of items after parsing are proper. */ static qboolean CP_ItemsSanityCheck (void) { int i; qboolean result = qtrue; for (i = 0; i < csi.numODs; i++) { const objDef_t *item = INVSH_GetItemByIDX(i); /* Warn if item has no size set. */ if (item->size <= 0 && B_ItemIsStoredInBaseStorage(item)) { result = qfalse; Com_Printf("CP_ItemsSanityCheck: Item %s has zero size set.\n", item->id); } /* Warn if no price is set. */ if (item->price <= 0 && BS_IsOnMarket(item)) { result = qfalse; Com_Printf("CP_ItemsSanityCheck: Item %s has zero price set.\n", item->id); } if (item->price > 0 && !BS_IsOnMarket(item) && !PR_ItemIsProduceable(item)) { result = qfalse; Com_Printf("CP_ItemsSanityCheck: Item %s has a price set though it is neither available on the market and production.\n", item->id); } /* extension and headgear are mutual exclusive */ if (item->extension && item->headgear) { result = qfalse; Com_Printf("CP_ItemsSanityCheck: Item %s has both extension and headgear set.\n", item->id); } } return result; }
/** * @brief Unloads transfer cargo when finishing the transfer or destroys it when no buildings/base. * @param[in,out] destination The destination base - might be nullptr in case the base * is already destroyed * @param[in] transfer Pointer to transfer in ccs.transfers. * @param[in] success True if the transfer reaches dest base, false if the base got destroyed. * @sa TR_TransferEnd */ static void TR_EmptyTransferCargo (base_t* destination, transfer_t* transfer, bool success) { assert(transfer); /* antimatter */ if (transfer->antimatter > 0 && success) { if (B_GetBuildingStatus(destination, B_ANTIMATTER)) { B_AddAntimatter(destination, transfer->antimatter); } else { Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Antimatter Storage, antimatter are removed!"), destination->name); MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, MSG_TRANSFERFINISHED); } } /* items */ if (transfer->itemCargo != nullptr) { if (success) { linkedList_t* cargo = transfer->itemCargo->list(); LIST_Foreach(cargo, itemCargo_t, item) { if (item->amount <= 0) continue; if (!B_ItemIsStoredInBaseStorage(item->objDef)) continue; B_AddToStorage(destination, item->objDef, item->amount); } cgi->LIST_Delete(&cargo); } delete transfer->alienCargo; transfer->alienCargo = nullptr; } /* Employee */ if (transfer->hasEmployees && transfer->srcBase) { /* Employees. (cannot come from a mission) */ for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) { const employeeType_t type = (employeeType_t)i; TR_ForeachEmployee(employee, transfer, type) { employee->transfer = false; if (!success) { E_DeleteEmployee(employee); continue; } switch (type) { case EMPL_WORKER: PR_UpdateProductionCap(destination, 0); break; case EMPL_PILOT: AIR_AutoAddPilotToAircraft(destination, employee); break; default: break; } } } }
/** * @brief Remove items until everything fits in storage. * @note items will be randomly selected for removal. * @param[in] base Pointer to the base */ void CAP_RemoveItemsExceedingCapacity (base_t *base) { int i; int objIdx[MAX_OBJDEFS]; /**< Will contain idx of items that can be removed */ int num, cnt; if (CAP_GetFreeCapacity(base, CAP_ITEMS) >= 0) return; for (i = 0, num = 0; i < cgi->csi->numODs; i++) { const objDef_t *obj = INVSH_GetItemByIDX(i); if (!B_ItemIsStoredInBaseStorage(obj)) continue; /* Don't count item that we don't have in base */ if (B_ItemInBase(obj, base) <= 0) continue; objIdx[num++] = i; } cnt = E_CountHired(base, EMPL_ROBOT); /* UGV takes room in storage capacity: we store them with a value MAX_OBJDEFS that can't be used by objIdx */ for (i = 0; i < cnt; i++) { objIdx[num++] = MAX_OBJDEFS; } while (num && CAP_GetFreeCapacity(base, CAP_ITEMS) < 0) { /* Select the item to remove */ const int randNumber = rand() % num; if (objIdx[randNumber] >= MAX_OBJDEFS) { /* A UGV is destroyed: get first one */ Employee* employee = E_GetHiredRobot(base, 0); /* There should be at least a UGV */ assert(employee); E_DeleteEmployee(employee); } else { /* items are destroyed. We guess that all items of a given type are stored in the same location * => destroy all items of this type */ const int idx = objIdx[randNumber]; const objDef_t *od = INVSH_GetItemByIDX(idx); B_UpdateStorageAndCapacity(base, od, -B_ItemInBase(od, base), false); } REMOVE_ELEM(objIdx, randNumber, num); /* Make sure that we don't have an infinite loop */ if (num <= 0) break; } Com_DPrintf(DEBUG_CLIENT, "B_RemoveItemsExceedingCapacity: Remains %i in storage for a maximum of %i\n", CAP_GetCurrent(base, CAP_ITEMS), CAP_GetMax(base, CAP_ITEMS)); }
/** * @brief Unloads transfer cargo when finishing the transfer or destroys it when no buildings/base. * @param[in,out] destination The destination base - might be NULL in case the base * is already destroyed * @param[in] transfer Pointer to transfer in ccs.transfers. * @param[in] success True if the transfer reaches dest base, false if the base got destroyed. * @sa TR_TransferEnd */ static void TR_EmptyTransferCargo (base_t *destination, transfer_t *transfer, qboolean success) { assert(transfer); if (transfer->hasItems && success) { /* Items. */ const objDef_t *od = INVSH_GetItemByID(ANTIMATTER_TECH_ID); int i; /* antimatter */ if (transfer->itemAmount[od->idx] > 0) { if (B_GetBuildingStatus(destination, B_ANTIMATTER)) { B_ManageAntimatter(destination, transfer->itemAmount[od->idx], qtrue); } else { Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Antimatter Storage, antimatter are removed!"), destination->name); MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, qfalse, MSG_TRANSFERFINISHED, NULL); } } /* items */ for (i = 0; i < csi.numODs; i++) { od = INVSH_GetItemByIDX(i); if (transfer->itemAmount[od->idx] <= 0) continue; if (!B_ItemIsStoredInBaseStorage(od)) continue; if (!B_GetBuildingStatus(destination, B_STORAGE)) { Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Storage, items are removed!"), destination->name); MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, qfalse, MSG_TRANSFERFINISHED, NULL); break; } B_UpdateStorageAndCapacity(destination, od, transfer->itemAmount[od->idx], qfalse, qtrue); } } if (transfer->hasEmployees && transfer->srcBase) { /* Employees. (cannot come from a mission) */ if (!success || !B_GetBuildingStatus(destination, B_QUARTERS)) { /* Employees will be unhired. */ employeeType_t i; if (success) { Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Living Quarters, employees got unhired!"), destination->name); MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, qfalse, MSG_TRANSFERFINISHED, NULL); } for (i = EMPL_SOLDIER; i < MAX_EMPL; i++) { employee_t *employee; TR_ForeachEmployee(employee, transfer, i) { employee->baseHired = transfer->srcBase; /* Restore back the original baseid. */ employee->transfer = qfalse; E_UnhireEmployee(employee); } } } else {
/** * @brief Update Storage Capacity. * @param[in] base Pointer to the base * @sa B_ResetAllStatusAndCapacities_f */ void CAP_UpdateStorageCap (base_t* base) { CAP_SetCurrent(base, CAP_ITEMS, 0); for (int i = 0; i < cgi->csi->numODs; i++) { const objDef_t* obj = INVSH_GetItemByIDX(i); if (!B_ItemIsStoredInBaseStorage(obj)) continue; CAP_AddCurrent(base, CAP_ITEMS, B_ItemInBase(obj, base) * obj->size); } /* UGV takes room in storage capacity */ CAP_AddCurrent(base, CAP_ITEMS, UGV_SIZE * E_CountHired(base, EMPL_ROBOT)); }
/** * @brief Unloads transfer cargo when finishing the transfer or destroys it when no buildings/base. * @param[in,out] destination The destination base - might be nullptr in case the base * is already destroyed * @param[in] transfer Pointer to transfer in ccs.transfers. * @param[in] success True if the transfer reaches dest base, false if the base got destroyed. * @sa TR_TransferEnd */ static void TR_EmptyTransferCargo (base_t* destination, transfer_t* transfer, bool success) { assert(transfer); if (transfer->hasItems && success) { /* Items. */ const objDef_t* od = INVSH_GetItemByID(ANTIMATTER_ITEM_ID); int i; /* antimatter */ if (transfer->itemAmount[od->idx] > 0) { if (B_GetBuildingStatus(destination, B_ANTIMATTER)) { B_ManageAntimatter(destination, transfer->itemAmount[od->idx], true); } else { Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Antimatter Storage, antimatter are removed!"), destination->name); MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, MSG_TRANSFERFINISHED); } } /* items */ for (i = 0; i < cgi->csi->numODs; i++) { od = INVSH_GetItemByIDX(i); if (transfer->itemAmount[od->idx] <= 0) continue; if (!B_ItemIsStoredInBaseStorage(od)) continue; B_AddToStorage(destination, od, transfer->itemAmount[od->idx]); } } if (transfer->hasEmployees && transfer->srcBase) { /* Employees. (cannot come from a mission) */ if (!success) { /* Employees will be unhired. */ for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) { const employeeType_t type = (employeeType_t)i; TR_ForeachEmployee(employee, transfer, type) { employee->baseHired = transfer->srcBase; /* Restore back the original baseid. */ employee->transfer = false; employee->unhire(); } } } else { for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) {