/** * @brief Buys the given UGV * @param[in] ugv The ugv template of the UGV to buy * @param[out] base Base to buy at * @return @c true if the ugv could get bought, @c false otherwise * @todo Implement this correctly once we have UGV */ bool BS_BuyUGV (const ugv_t* ugv, base_t* base) { const objDef_t* ugvWeapon; if (!ugv) cgi->Com_Error(ERR_DROP, "BS_BuyUGV: Called on nullptr UGV!"); if (!base) cgi->Com_Error(ERR_DROP, "BS_BuyUGV: Called on nullptr base!"); ugvWeapon = INVSH_GetItemByID(ugv->weapon); if (!ugvWeapon) cgi->Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get weapon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id); if (ccs.credits < ugv->price) return false; if (E_CountUnhiredRobotsByType(ugv) <= 0) return false; if (BS_GetItemOnMarket(ugvWeapon) <= 0) return false; if (CAP_GetFreeCapacity(base, CAP_ITEMS) < UGV_SIZE + ugvWeapon->size) return false; if (!E_HireRobot(base, ugv)) return false; BS_RemoveItemFromMarket(ugvWeapon, 1); CP_UpdateCredits(ccs.credits - ugv->price); B_AddToStorage(base, ugvWeapon, 1); return true; }
/** * @brief Sells the given UGV with all the equipment. * @param robot The employee record of the UGV to sell * @return @c true if the ugv could get sold, @c false otherwise * @todo Implement this correctly once we have UGV */ bool BS_SellUGV (Employee* robot) { const objDef_t* ugvWeapon; const ugv_t* ugv; base_t* base; if (!robot) cgi->Com_Error(ERR_DROP, "Selling nullptr UGV!"); if (!robot->getUGV()) cgi->Com_Error(ERR_DROP, "Selling invalid UGV with UCN: %i", robot->chr.ucn); ugv = robot->getUGV(); base = robot->baseHired; /* Check if we have a weapon for this ugv in the market to sell it. */ ugvWeapon = INVSH_GetItemByID(ugv->weapon); if (!ugvWeapon) cgi->Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get wepaon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id); if (!robot->unhire()) { /** @todo message - Couldn't fire employee. */ Com_DPrintf(DEBUG_CLIENT, "Couldn't sell/fire robot/ugv.\n"); return false; } BS_AddItemToMarket(ugvWeapon, 1); CP_UpdateCredits(ccs.credits + ugv->price); B_AddToStorage(base, ugvWeapon, -1); return true; }
/** * @brief Run actions on finishing disassembling of a ufo * @param base The base to produce in * @param prod The production that is running */ static void PR_FinishDisassembly (base_t* base, production_t* prod) { storedUFO_t* ufo = prod->data.data.ufo; assert(ufo); for (int i = 0; i < ufo->comp->numItemtypes; i++) { const objDef_t* compOd = ufo->comp->items[i]; const int amount = (ufo->condition < 1 && ufo->comp->itemAmount2[i] != COMP_ITEMCOUNT_SCALED) ? ufo->comp->itemAmount2[i] : round(ufo->comp->itemAmount[i] * ufo->condition); assert(compOd); if (amount <= 0) continue; if (Q_streq(compOd->id, ANTIMATTER_ITEM_ID)) { B_AddAntimatter(base, amount); } else { technology_t* tech = RS_GetTechForItem(compOd); B_AddToStorage(base, compOd, amount); RS_MarkCollected(tech); } } Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("The disassembling of %s at %s has finished."), UFO_TypeToName(ufo->ufoTemplate->getUfoType()), base->name); MSO_CheckAddNewMessage(NT_PRODUCTION_FINISHED, _("Production finished"), cp_messageBuffer, MSG_PRODUCTION, ufo->ufoTemplate->tech); /* Removing UFO will remove the production too */ US_RemoveStoredUFO(ufo); }
/** * @brief Run actions on finishing production of one item/aircraft/UGV.. * @param base The base to produce in * @param prod The production that is running */ static void PR_FinishProduction (base_t* base, production_t* prod) { const char* name = PR_GetName(&prod->data); technology_t* tech = PR_GetTech(&prod->data); prod->frame = 0; prod->amount--; if (PR_IsItem(prod)) { CP_UpdateCredits(ccs.credits - PR_GetPrice(prod->data.data.item)); /* Now add it to equipment and update capacity. */ B_AddToStorage(base, prod->data.data.item, 1); } else if (PR_IsAircraft(prod)) { CP_UpdateCredits(ccs.credits - PR_GetPrice(prod->data.data.aircraft)); /* Now add new aircraft. */ AIR_NewAircraft(base, prod->data.data.aircraft); } if (prod->amount > 0) return; Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Work on %s at %s has finished."), name, base->name); MSO_CheckAddNewMessage(NT_PRODUCTION_FINISHED, _("Production finished"), cp_messageBuffer, MSG_PRODUCTION, tech); /* queue the next production */ PR_QueueNext(base); }
/** * @brief Remove or add the required items from/to the a base. * @param[in] base Pointer to base. * @param[in] amount How many items are planned to be added (positive number) or removed (negative number). * @param[in] reqs The production requirements of the item that is to be produced. These included numbers are multiplied with 'amount') */ void PR_UpdateRequiredItemsInBasestorage (base_t* base, int amount, const requirements_t* reqs) { if (!base) return; if (amount == 0) return; for (int i = 0; i < reqs->numLinks; i++) { const requirement_t* req = &reqs->links[i]; switch (req->type) { case RS_LINK_ITEM: { const objDef_t* item = req->link.od; assert(item); B_AddToStorage(base, item, req->amount * amount); break; } case RS_LINK_ANTIMATTER: B_AddAntimatter(base, req->amount * amount); break; case RS_LINK_TECH: case RS_LINK_TECH_NOT: break; default: cgi->Com_Error(ERR_DROP, "Invalid requirement for production!\n"); } } }
/** * @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 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++) {
/** * @brief Sells items from the market * @param[in] od pointer to the item (Object Definition record) * @param[out] base Base to sell at * @param[in ] count Number of items to sell * @return @c true if the ugv could get sold, @c false otherwise */ bool BS_SellItem (const objDef_t* od, base_t* base, int count) { if (!od) cgi->Com_Error(ERR_DROP, "BS_SellItem: Called on nullptr objDef!"); if (count <= 0) return false; if (!BS_IsOnMarket(od)) return false; if (base) { if (B_ItemInBase(od, base) < count) return false; B_AddToStorage(base, od, -count); } BS_AddItemToMarket(od, count); CP_UpdateCredits(ccs.credits + BS_GetItemSellingPrice(od) * count); return true; }
/** * @brief Buys items from the market * @param[in] od pointer to the item (Object Definition record) * @param[out] base Base to buy at * @param[in ] count Number of items to buy * @return @c true if the ugv could get bought, @c false otherwise */ bool BS_BuyItem (const objDef_t* od, base_t* base, int count) { if (!od) cgi->Com_Error(ERR_DROP, "BS_BuyItem: Called on nullptr objDef!"); if (!base) cgi->Com_Error(ERR_DROP, "BS_BuyItem: Called on nullptr base!"); if (count <= 0) return false; if (!BS_IsOnMarket(od)) return false; if (ccs.credits < BS_GetItemBuyingPrice(od) * count) return false; if (BS_GetItemOnMarket(od) < count) return false; if (CAP_GetFreeCapacity(base, CAP_ITEMS) < od->size * count) return false; B_AddToStorage(base, od, count); BS_RemoveItemFromMarket(od, count); CP_UpdateCredits(ccs.credits - BS_GetItemBuyingPrice(od) * count); return true; }