/**
 * @brief This removes an employee from the global list so that
 * he/she is no longer hireable.
 */
static void E_EmployeeDelete_f (void)
{
	/* Check syntax. */
	if (cgi->Cmd_Argc() < 2) {
		Com_Printf("Usage: %s <num>\n", cgi->Cmd_Argv(0));
		return;
	}

	/* num - menu index (line in text) */
	int num = employeeScrollPos + atoi(cgi->Cmd_Argv(1));

	Employee* employee = E_GetEmployeeByMenuIndex(num);
	/* empty slot selected */
	if (!employee)
		return;

	if (employee->isHired()) {
		if (!employee->unhire()) {
			cgi->UI_DisplayNotice(_("Could not fire employee"), 2000, "employees");
			Com_DPrintf(DEBUG_CLIENT, "Couldn't fire employee\n");
			return;
		}
	}
	E_DeleteEmployee(employee);
	cgi->Cbuf_AddText("employee_init %i\n", employeeCategory);

	num = std::max(0, num - 1);
	cgi->Cbuf_AddText("employee_select %i\n", num);
	cgi->Cbuf_AddText("hire_select %i\n", num);

	cgi->Cbuf_AddText("employee_update_count\n");
}
Beispiel #2
0
/**
 * @brief Removes employee until all employees fit in quarters capacity.
 * @param[in] base Pointer to the base where the number of employees should be updated.
 * @note employees are killed, and not just unhired (if base is destroyed, you can't recruit the same employees elsewhere)
 *	if you want to unhire employees, you should do it before calling this function.
 * @note employees are not randomly chosen. Reason is that all Quarter will be destroyed at the same time,
 *	so all employees are going to be killed anyway.
 */
void E_DeleteEmployeesExceedingCapacity (base_t *base)
{
	int type;

	/* Check if there are too many employees */
	if (base->capacities[CAP_EMPLOYEES].cur <= base->capacities[CAP_EMPLOYEES].max)
		return;

	/* do a reverse loop in order to finish by soldiers (the most important employees) */
	for (type = MAX_EMPL - 1; type >= 0; type--) {
		employee_t *employee;

		/* UGV are not stored in Quarters */
		if (type == EMPL_ROBOT)
			continue;

		E_Foreach(type, employee) {
			if (E_IsInBase(employee, base))
				E_DeleteEmployee(employee);

			if (base->capacities[CAP_EMPLOYEES].cur <= base->capacities[CAP_EMPLOYEES].max)
				return;
		}
	}

	Com_Printf("E_DeleteEmployeesExceedingCapacity: Warning, removed all employees from base '%s', but capacity is still > 0\n", base->name);
}
Beispiel #3
0
static void testEmployeeHandling (void)
{
	employeeType_t type;

	ResetCampaignData();

	for (type = 0; type < MAX_EMPL; type++) {
		if (type != EMPL_ROBOT) {
			int cnt;
			employee_t *e = E_CreateEmployee(type, NULL, NULL);
			CU_ASSERT_PTR_NOT_NULL(e);

			cnt = E_CountUnhired(type);
			CU_ASSERT_EQUAL(cnt, 1);

			E_DeleteEmployee(e);

			cnt = E_CountUnhired(type);
			CU_ASSERT_EQUAL(cnt, 0);
		}
	}

	{
		int i;
		const int amount = 3;
		for (i = 0; i < amount; i++) {
			employee_t *e = E_CreateEmployee(EMPL_SOLDIER, NULL, NULL);
			CU_ASSERT_PTR_NOT_NULL(e);
		}
		{
			employee_t *e;
			int cnt = 0;
			E_Foreach(EMPL_SOLDIER, e) {
				cnt++;
			}

			CU_ASSERT_EQUAL(cnt, amount);

			E_Foreach(EMPL_SOLDIER, e) {
				CU_ASSERT_TRUE(E_DeleteEmployee(e));
			}

			cnt = E_CountUnhired(EMPL_SOLDIER);
			CU_ASSERT_EQUAL(cnt, 0)
		}
	}
Beispiel #4
0
TEST_F(CampaignTest, testEmployeeHandling)
{
	int i;

	for (i = 0; i < MAX_EMPL; i++) {
		employeeType_t type = (employeeType_t)i;
		if (type != EMPL_ROBOT) {
			int cnt;
			Employee* e = E_CreateEmployee(type, nullptr, nullptr);
			ASSERT_TRUE(nullptr != e);

			cnt = E_CountUnhired(type);
			ASSERT_EQ(cnt, 1);

			E_DeleteEmployee(e);

			cnt = E_CountUnhired(type);
			ASSERT_EQ(cnt, 0);
		}
	}

	{
		const int amount = 3;
		for (i = 0; i < amount; i++) {
			Employee* e = E_CreateEmployee(EMPL_SOLDIER, nullptr, nullptr);
			ASSERT_TRUE(nullptr != e);
		}
		{
			int cnt = 0;
			E_Foreach(EMPL_SOLDIER, e) {
				(void)e;
				cnt++;
			}

			ASSERT_EQ(cnt, amount);

			E_Foreach(EMPL_SOLDIER, e) {
				ASSERT_TRUE(E_DeleteEmployee(e));
			}

			cnt = E_CountUnhired(EMPL_SOLDIER);
			ASSERT_EQ(cnt, 0);
		}
Beispiel #5
0
/**
 * @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;
				}
			}
		}
	}
Beispiel #6
0
/**
 * @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));
}
Beispiel #7
0
/**
 * @brief Removes all employees completely from the game (buildings + global list) from a given base.
 * @note Used if the base e.g is destroyed by the aliens.
 * @param[in] base Which base the employee should be fired from.
 */
void E_DeleteAllEmployees (base_t* base)
{
	employeeType_t type;

	for (type = EMPL_SOLDIER; type < MAX_EMPL; type++) {
		employee_t *lastEmployee = NULL;
		employee_t *employee = NULL;

		E_Foreach(type, employee) {
			if ((base == NULL || E_IsInBase(employee, base)) && E_DeleteEmployee(employee))
				employee = lastEmployee;
			else
				lastEmployee = employee;
		}
	}
}
Beispiel #8
0
/**
 * @brief Recreates all the employees for a particular employee type in the global list.
 * But it does not overwrite any employees already hired.
 * @param[in] type The type of the employee list to process.
 * @param[in] excludeUnhappyNations True if a nation is unhappy then they wont
 * send any pilots, false if happiness of nations in not considered.
 * @sa CP_NationHandleBudget
 */
int E_RefreshUnhiredEmployeeGlobalList (const employeeType_t type, const qboolean excludeUnhappyNations)
{
	const nation_t *happyNations[MAX_NATIONS];
	int numHappyNations = 0;
	int idx, nationIdx, cnt;
	employee_t *employee;

	happyNations[0] = NULL;
	/* get a list of nations,  if excludeHappyNations is qtrue then also exclude
	 * unhappy nations (unhappy nation: happiness <= 0) from the list */
	for (idx = 0; idx < ccs.numNations; idx++) {
		const nation_t *nation = NAT_GetNationByIDX(idx);
		const nationInfo_t *stats = NAT_GetCurrentMonthInfo(nation);
		if (stats->happiness > 0 || !excludeUnhappyNations) {
			happyNations[numHappyNations] = nation;
			numHappyNations++;
		}
	}

	if (!numHappyNations)
		return 0;

	idx = 0;
	/* Fill the global data employee list with employees, evenly distributed
	 * between nations in the happyNations list */
	E_Foreach(type, employee) {
		/* we don't want to overwrite employees that have already been hired */
		if (!E_IsHired(employee)) {
			E_DeleteEmployee(employee);
			idx++;
		}
	}

	nationIdx = 0;
	cnt = 0;
	while (idx-- > 0) {
		if (E_CreateEmployee(type, happyNations[nationIdx], NULL) != NULL)
			cnt++;
		nationIdx = (nationIdx + 1) % numHappyNations;
	}

	return cnt;
}