/** * @brief Tells you if a employee is away from his home base (gone in mission). * @param[in] employee Pointer to the employee. * @return qboolean qtrue if the employee is away in mission, qfalse if he is not or he is unhired. */ qboolean E_IsAwayFromBase (const employee_t *employee) { const base_t *base; aircraft_t *aircraft; assert(employee); /* Check that employee is hired */ if (!E_IsHired(employee)) return qfalse; /* Check if employee is currently transferred. */ if (employee->transfer) return qtrue; /* for now only soldiers, ugvs and pilots can be assigned to an aircraft */ if (employee->type != EMPL_SOLDIER && employee->type != EMPL_ROBOT && employee->type != EMPL_PILOT) return qfalse; base = employee->baseHired; /* Crashed aircraft no longer belongs to any base but poor pilot/soldiers assigned * to it are definetly away from the base so we need to iterate trought all aircraft */ AIR_Foreach(aircraft) { if (aircraft->homebase != base) continue; if (!AIR_IsAircraftInBase(aircraft) && AIR_IsEmployeeInAircraft(employee, aircraft)) return qtrue; } return qfalse; }
/** * @brief Fires an employee. * @note also remove him from the aircraft * @param[in] employee The employee who will be fired * @sa E_HireEmployee * @sa E_HireEmployeeByType * @sa CL_RemoveSoldierFromAircraft * @sa E_ResetEmployee * @sa E_RemoveEmployeeFromBuildingOrAircraft * @todo handle EMPL_ROBOT capacities here? */ qboolean E_UnhireEmployee (employee_t* employee) { if (employee && E_IsHired(employee) && !employee->transfer) { base_t *base = employee->baseHired; /* Any effect of removing an employee (e.g. removing a scientist from a research project) * should take place in E_RemoveEmployeeFromBuildingOrAircraft */ E_ResetEmployee(employee); /* Set all employee-tags to 'unhired'. */ employee->baseHired = NULL; /* Remove employee from corresponding capacity */ switch (employee->type) { case EMPL_PILOT: case EMPL_WORKER: case EMPL_SCIENTIST: case EMPL_SOLDIER: base->capacities[CAP_EMPLOYEES].cur--; break; case EMPL_ROBOT: base->capacities[CAP_ITEMS].cur -= UGV_SIZE; break; case MAX_EMPL: break; } return qtrue; } else Com_DPrintf(DEBUG_CLIENT, "Could not fire employee\n"); return qfalse; }
/** * @brief Iterates through unhired employees * @param[in] type Employee type to look for * @sa employeeType_t */ employee_t* E_GetUnhired (employeeType_t type) { employee_t* employee; E_Foreach(type, employee) { if (!E_IsHired(employee)) break; } return employee; }
/** * @brief Removes the inventory of the employee and also removes him from buildings * @note This is used in the transfer start function (when you transfer an employee * this must be called for him to make him no longer useable in the current base) * and is also used when you completely unhire an employee. * @sa E_UnhireEmployee */ void E_ResetEmployee (employee_t *employee) { assert(employee); assert(E_IsHired(employee)); /* Remove employee from building (and tech/production). */ E_RemoveEmployeeFromBuildingOrAircraft(employee); /* Destroy the inventory of the employee (carried items will remain in base->storage) */ cls.i.DestroyInventory(&cls.i, &employee->chr.i); }
/** * @brief Counts all available Robots/UGVs that are for sale. * @param[in] ugvType What type of robot/ugv we are looking for. * @return count of available robots/ugvs. */ int E_CountUnhiredRobotsByType (const ugv_t *ugvType) { int count = 0; employee_t *employee; E_Foreach(EMPL_ROBOT, employee) { if (!E_IsHired(employee) && employee->ugv == ugvType) count++; } return count; }
/** * @brief Counts unhired employees of a given type in a given base * @param[in] type The type of employee to search. * @return count of hired employees of a given type in a given base */ int E_CountUnhired (employeeType_t type) { int count = 0; employee_t *employee; E_Foreach(type, employee) { if (!E_IsHired(employee)) count++; } return count; }
/** * @brief Checks whether the given employee is in the given base * @sa E_EmployeeIsCurrentlyInBase */ qboolean E_IsInBase (const employee_t* empl, const base_t* const base) { assert(empl != NULL); assert(base != NULL); if (!E_IsHired(empl)) return qfalse; if (empl->baseHired == base) return qtrue; return qfalse; }
/** * @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 Return a "not hired" ugv-employee pointer of a given ugv-type. * @param[in] ugvType What type of robot we want. * @return employee_t pointer on success or NULL on error. * @sa E_GetHiredRobot */ employee_t* E_GetUnhiredRobot (const ugv_t *ugvType) { employee_t *employee; E_Foreach(EMPL_ROBOT, employee) { if (!E_IsHired(employee)) { /* If no type was given we return the first ugv we find. */ if (!ugvType || employee->ugv == ugvType) return employee; } } return employee; }
/** * @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; }
/** * @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 Shows the current stats from stats_t stats * @todo This is very redundant with NAT_HandleBudget Ivestigate and clean up. */ void CP_StatsUpdate_f (void) { char *pos; static char statsBuffer[MAX_STATS_BUFFER]; int hired[MAX_EMPL]; int i, costs = 0, sum = 0, totalfunds = 0; base_t *base; const campaign_t *campaign = ccs.curCampaign; const salary_t *salary = &campaign->salaries; const rank_t *rank; /* delete buffer */ OBJZERO(statsBuffer); OBJZERO(hired); pos = statsBuffer; /* missions */ cgi->UI_RegisterText(TEXT_STATS_MISSION, pos); Com_sprintf(pos, MAX_STATS_BUFFER, _("Won:\t%i\nLost:\t%i\n\n"), ccs.campaignStats.missionsWon, ccs.campaignStats.missionsLost); /* bases */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_BASES, pos); Com_sprintf(pos, (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos), _("Built:\t%i\nActive:\t%i\nAttacked:\t%i\n"), ccs.campaignStats.basesBuilt, B_GetCount(), ccs.campaignStats.basesAttacked), /* installations */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_INSTALLATIONS, pos); INS_Foreach(inst) { Q_strcat(pos, va("%s\n", inst->name), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); } /* nations */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_NATIONS, pos); for (i = 0; i < ccs.numNations; i++) { const nation_t *nation = NAT_GetNationByIDX(i); Q_strcat(pos, va(_("%s\t%s\n"), _(nation->name), NAT_GetHappinessString(nation)), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); totalfunds += NAT_GetFunding(nation, 0); } Q_strcat(pos, va(_("\nFunding this month:\t%d"), totalfunds), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); /* costs */ for (i = 0; i < MAX_EMPL; i++) { E_Foreach(i, employee) { const employeeType_t type = (employeeType_t)i; if (!E_IsHired(employee)) continue; rank = CL_GetRankByIdx(employee->chr.score.rank); costs += CP_GetSalaryBaseEmployee(salary, type) + rank->level * CP_GetSalaryRankBonusEmployee(salary, type); hired[employee->type]++; } } /* employees - this is between the two costs parts to count the hired employees */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_EMPLOYEES, pos); for (i = 0; i < MAX_EMPL; i++) { const employeeType_t type = (employeeType_t)i; Q_strcat(pos, va(_("%s\t%i\n"), E_GetEmployeeString(type, hired[i]), hired[i]), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); } /* costs - second part */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_COSTS, pos); Q_strcat(pos, va(_("Employees:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; costs = 0; AIR_Foreach(aircraft) { if (aircraft->status == AIR_CRASHED) continue; costs += aircraft->price * salary->aircraftFactor / salary->aircraftDivisor; } Q_strcat(pos, va(_("Aircraft:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; base = NULL; while ((base = B_GetNext(base)) != NULL) { costs = CP_GetSalaryUpKeepBase(salary, base); Q_strcat(pos, va(_("Base (%s):\t%i c\n"), base->name, costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; } costs = CP_GetSalaryAdministrative(salary); Q_strcat(pos, va(_("Administrative costs:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; if (ccs.credits < 0) { const float interest = ccs.credits * campaign->salaries.debtInterest; costs = (int)ceil(interest); Q_strcat(pos, va(_("Debt:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; } Q_strcat(pos, va(_("\n\t-------\nSum:\t%i c\n"), sum), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); /* campaign */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_GENERIC, pos); Q_strcat(pos, va(_("Max. allowed debts: %ic\n"), campaign->negativeCreditsUntilLost), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); /* only show the xvi spread data when it's available */ if (CP_IsXVIVisible()) { Q_strcat(pos, va(_("Max. allowed eXtraterrestial Viral Infection: %i%%\n" "Current eXtraterrestial Viral Infection: %i%%"), campaign->maxAllowedXVIRateUntilLost, CP_GetAverageXVIRate()), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); } }