/** * @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); }
/** * @brief Gets an assigned employee of a given type from the given base. * @param[in] base Which base the employee should be hired in. * @param[in] type The type of employee to search. * @return employee_t * @sa E_EmployeeIsUnassigned * @note unassigned is not unhired - they are already hired in a base but are at quarters */ employee_t* E_GetUnassignedEmployee (const base_t* const base, const employeeType_t type) { employee_t *employee; E_Foreach(type, employee) { if (!E_IsInBase(employee, base)) continue; if (E_EmployeeIsUnassigned(employee)) return employee; } return NULL; }
/** * @brief Counts 'hired' (i.e. bought or produced UGVs and other robots of a given ugv-type in a given base. * @param[in] base The base where we count (@c NULL to count all). * @param[in] ugvType What type of robot/ugv we are looking for. * @return Count of Robots/UGVs. */ int E_CountHiredRobotByType (const base_t* const base, const ugv_t *ugvType) { int count = 0; employee_t *employee; E_Foreach(EMPL_ROBOT, employee) { if (!E_IsHired(employee)) continue; if (employee->ugv == ugvType && (!base || E_IsInBase(employee, base))) count++; } return count; }
/** * @brief Counts hired employees of a given type in a given base * @param[in] base The base where we count (@c NULL to count all). * @param[in] type The type of employee to search. * @return count of hired employees of a given type in a given base */ int E_CountHired (const base_t* const base, employeeType_t type) { int count = 0; employee_t *employee; E_Foreach(type, employee) { if (!E_IsHired(employee)) continue; if (!base || E_IsInBase(employee, base)) count++; } return count; }
/** * @brief Reset the hired flag for all employees of a given type in a given base * @param[in] base Which base the employee should be fired from. * @param[in] type Which employee type do we search. */ void E_UnhireAllEmployees (base_t* base, employeeType_t type) { employee_t *employee; if (!base) return; assert(type < MAX_EMPL); E_Foreach(type, employee) { if (!E_IsInBase(employee, base)) continue; E_UnhireEmployee(employee); } }
/** * @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; } } }
/** * @brief Counts unassigned employees of a given type in a given base * @param[in] type The type of employee to search. * @param[in] base The base where we count */ int E_CountUnassigned (const base_t* const base, employeeType_t type) { int count; employee_t *employee; if (!base) return 0; count = 0; E_Foreach(type, employee) { if (!E_IsInBase(employee, base)) continue; if (E_EmployeeIsUnassigned(employee)) count++; } return count; }
/** * @brief Return a "hired" ugv-employee pointer of a given ugv-type in a given base. * @param[in] base Which base the ugv should be searched in.c * @param[in] ugvType What type of robot we want. * @return employee_t pointer on success or NULL on error. * @sa E_GetUnhiredRobot */ employee_t* E_GetHiredRobot (const base_t* const base, const ugv_t *ugvType) { linkedList_t *hiredEmployees = NULL; employee_t *employee; E_GetHiredEmployees(base, EMPL_ROBOT, &hiredEmployees); LIST_Foreach(hiredEmployees, employee_t, employee) { if ((employee->ugv == ugvType || !ugvType) /* If no type was given we return the first ugv we find. */ && E_IsInBase(employee, base)) { /* It has to be in the defined base. */ assert(E_IsHired(employee)); break; } } LIST_Delete(&hiredEmployees); if (!employee) Com_DPrintf(DEBUG_CLIENT, "Could not get unhired ugv/robot.\n"); return employee; }
/** * @brief Return a list of hired employees in the given base of a given type * @param[in] base Which base the employee should be searched in. If NULL is given employees in all bases will be listed. * @param[in] type Which employee type to search for. * @param[out] hiredEmployees Linked list of hired employees in the base. * @return Number of hired employees in the base that are currently not on a transfer. Or @c -1 in case of an error. */ int E_GetHiredEmployees (const base_t* const base, employeeType_t type, linkedList_t **hiredEmployees) { employee_t *employee; if (type >= MAX_EMPL) { Com_Printf("E_GetHiredEmployees: Unknown EmployeeType: %i\n", type); *hiredEmployees = NULL; return -1; } LIST_Delete(hiredEmployees); E_Foreach(type, employee) { if (!E_IsHired(employee)) continue; if (!employee->transfer && (!base || E_IsInBase(employee, base))) { LIST_AddPointer(hiredEmployees, employee); } } if (hiredEmployees == NULL) return 0; return LIST_Count(*hiredEmployees); }
/** * @brief Updates the hospital menu. * @sa HOS_Init_f */ static void HOS_UpdateMenu (void) { char name[128]; char rank[128]; int j, type; int entry; base_t *base = B_GetCurrentSelectedBase(); if (!base) return; /* Reset list. */ cgi->UI_ExecuteConfunc("hospital_clear"); for (type = 0, j = 0, entry = 0; type < MAX_EMPL; type++) { E_Foreach(type, employee) { float injuryLevel = HOS_InjuryLevel(&employee->chr); if (!E_IsInBase(employee, base)) continue; /* Don't show soldiers who are gone in mission */ if (E_IsAwayFromBase(employee)) continue; /* Don't show healthy employees */ if (employee->chr.HP >= employee->chr.maxHP && injuryLevel <= 0) continue; if (j >= hospitalFirstEntry && entry < HOS_MENU_MAX_ENTRIES) { /* Print name. */ Q_strncpyz(name, employee->chr.name, sizeof(name)); /* Print rank for soldiers or type for other personel. */ if (type == EMPL_SOLDIER) { const rank_t *rankPtr = CL_GetRankByIdx(employee->chr.score.rank); Q_strncpyz(rank, _(rankPtr->name), sizeof(rank)); } else Q_strncpyz(rank, E_GetEmployeeString(employee->type, 1), sizeof(rank)); Com_DPrintf(DEBUG_CLIENT, "%s ucn: %i entry: %i\n", name, employee->chr.ucn, entry); /* If the employee is seriously wounded (HP <= 50% maxHP), make him red. */ if (employee->chr.HP <= (int) (employee->chr.maxHP * 0.5) || injuryLevel >= 0.5) cgi->UI_ExecuteConfunc("hospitalserious %i", entry); /* If the employee is semi-seriously wounded (HP <= 85% maxHP), make him yellow. */ else if (employee->chr.HP <= (int) (employee->chr.maxHP * 0.85) || injuryLevel >= 0.15) cgi->UI_ExecuteConfunc("hospitalmedium %i", entry); else cgi->UI_ExecuteConfunc("hospitallight %i", entry); /* Display name in the correct list-entry. */ cgi->Cvar_Set(va("mn_hos_item%i", entry), name); /* Display rank in the correct list-entry. */ cgi->Cvar_Set(va("mn_hos_rank%i", entry), rank); /* Prepare the health bar */ cgi->Cvar_Set(va("mn_hos_hp%i", entry), va("%i", employee->chr.HP)); cgi->Cvar_Set(va("mn_hos_hpmax%i", entry), va("%i", employee->chr.maxHP)); /* Send wound info */ HOS_EntryWoundData(&employee->chr, entry); /* Increase the counter of list entries. */ entry++; } j++; } }
/** * @brief Fill market item list */ static void BS_FillMarket_f (void) { const base_t *base = B_GetCurrentSelectedBase(); itemFilterTypes_t type; if (cgi->Cmd_Argc() < 2) { Com_Printf("Usage: %s <category>\n", cgi->Cmd_Argv(0)); return; } if (cgi->Cmd_Argc() >= 3) base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(2))); if (!base) { Com_Printf("No/invalid base selected.\n"); return; } type = INV_GetFilterTypeID(cgi->Cmd_Argv(1)); cgi->UI_ExecuteConfunc("ui_market_clear"); switch (type) { case FILTER_UGVITEM: /* show own UGV */ E_Foreach(EMPL_ROBOT, robot) { const ugv_t *ugv = robot->ugv; const technology_t* tech = RS_GetTechByProvided(ugv->id); if (!E_IsInBase(robot, base)) continue; cgi->UI_ExecuteConfunc("ui_market_add \"ugv-%d\" \"%s\" 1 0 0 %d - \"%s\"", robot->chr.ucn, _(tech->name), ugv->price, E_IsAwayFromBase(robot) ? _("UGV is away from home") : "-"); } /* show buyable UGV */ for (int i = 0; i < cgi->csi->numUGV; i++) { const ugv_t *ugv = &cgi->csi->ugvs[i]; const technology_t* tech = RS_GetTechByProvided(ugv->id); const objDef_t *ugvWeapon = INVSH_GetItemByID(ugv->weapon); const int buyable = std::min(E_CountUnhiredRobotsByType(ugv), BS_GetItemOnMarket(ugvWeapon)); assert(tech); if (!RS_IsResearched_ptr(tech)) continue; if (buyable <= 0) continue; cgi->UI_ExecuteConfunc("ui_market_add %s \"%s\" 0 %d %d %d - -", ugv->id, _(tech->name), buyable, ugv->price, ugv->price); } /* show (UGV) items */ case FILTER_S_PRIMARY: case FILTER_S_SECONDARY: case FILTER_S_HEAVY: case FILTER_S_MISC: case FILTER_S_ARMOUR: case FILTER_DUMMY: case FILTER_CRAFTITEM: case MAX_FILTERTYPES: { for (int i = 0; i < cgi->csi->numODs; i++) { const objDef_t *od = &cgi->csi->ods[i]; const technology_t *tech = RS_GetTechForItem(od); if (!BS_IsOnMarket(od)) continue; if (B_ItemInBase(od, base) + BS_GetItemOnMarket(od) <= 0) continue; if (type != MAX_FILTERTYPES && !INV_ItemMatchesFilter(od, type)) continue; cgi->UI_ExecuteConfunc("ui_market_add %s \"%s\" %d %d %d %d %s -", od->id, _(od->name), B_ItemInBase(od, base), BS_GetItemOnMarket(od), BS_GetItemBuyingPrice(od), BS_GetItemSellingPrice(od), RS_IsResearched_ptr(tech) ? va("%d", ccs.eMarket.autosell[i]) : "-"); } break; } case FILTER_AIRCRAFT: { AIR_ForeachFromBase(aircraft, base) { cgi->UI_ExecuteConfunc("ui_market_add \"aircraft-%d\" \"%s\" 1 0 0 %d - \"%s\"", aircraft->idx, aircraft->name, BS_GetAircraftSellingPrice(aircraft), AIR_IsAircraftInBase(aircraft) ? "-" : _("Aircraft is away from home")); } for (int i = 0; i < ccs.numAircraftTemplates; i++) { const aircraft_t *aircraft = &ccs.aircraftTemplates[i]; if (!BS_AircraftIsOnMarket(aircraft)) continue; if (!RS_IsResearched_ptr(aircraft->tech)) continue; cgi->UI_ExecuteConfunc("ui_market_add \"%s\" \"%s\" 0 %d %d %d - -", aircraft->id, _(aircraft->tech->name), BS_GetAircraftOnMarket(aircraft), BS_GetAircraftBuyingPrice(aircraft), BS_GetAircraftSellingPrice(aircraft)); } break; } default: break; }