00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "../client.h"
00028 #include "../cl_game.h"
00029 #include "../cl_team.h"
00030 #include "../ui/ui_main.h"
00031 #include "../ui/ui_popup.h"
00032 #include "cp_campaign.h"
00033 #include "cp_employee_callbacks.h"
00034 #include "cp_rank.h"
00035 #include "save/save_employee.h"
00036
00043 employee_t* E_GetNext (employeeType_t type, employee_t *lastEmployee)
00044 {
00045 employee_t* endOfEmployees = &ccs.employees[type][ccs.numEmployees[type]];
00046 employee_t* employee;
00047
00048 if (!ccs.numEmployees[type])
00049 return NULL;
00050
00051 if (!lastEmployee)
00052 return ccs.employees[type];
00053 assert(lastEmployee >= ccs.employees[type]);
00054 assert(lastEmployee < endOfEmployees);
00055
00056 employee = lastEmployee;
00057
00058 employee++;
00059 if (employee >= endOfEmployees)
00060 return NULL;
00061 else
00062 return employee;
00063 }
00064
00065
00073 employee_t* E_GetNextFromBase (employeeType_t type, employee_t *lastEmployee, const base_t *base)
00074 {
00075 employee_t* employee = lastEmployee;
00076
00077 while ((employee = E_GetNext(type, employee))) {
00078 if (E_IsInBase(employee, base))
00079 break;
00080 }
00081 return employee;
00082 }
00083
00084
00091 employee_t* E_GetNextHired (employeeType_t type, employee_t *lastEmployee)
00092 {
00093 employee_t* employee = lastEmployee;
00094
00095 while ((employee = E_GetNext(type, employee))) {
00096 if (E_IsHired(employee))
00097 break;
00098 }
00099 return employee;
00100 }
00101
00107 qboolean E_IsAwayFromBase (const employee_t *employee)
00108 {
00109 base_t *base;
00110 aircraft_t *aircraft;
00111
00112 assert(employee);
00113
00114
00115 if (!E_IsHired(employee))
00116 return qfalse;
00117
00118
00119 if (employee->transfer)
00120 return qtrue;
00121
00122
00123 if (employee->type != EMPL_SOLDIER && employee->type != EMPL_ROBOT
00124 && employee->type != EMPL_PILOT)
00125 return qfalse;
00126
00127 base = employee->baseHired;
00128
00129 aircraft = NULL;
00130 while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL)
00131 if (!AIR_IsAircraftInBase(aircraft) && AIR_IsInAircraftTeam(aircraft, employee))
00132 return qtrue;
00133
00134 return qfalse;
00135 }
00136
00144 void E_HireForBuilding (base_t* base, building_t * building, int num)
00145 {
00146 if (num < 0)
00147 num = building->maxEmployees;
00148
00149 if (num) {
00150 employeeType_t employeeType;
00151 switch (building->buildingType) {
00152 case B_WORKSHOP:
00153 employeeType = EMPL_WORKER;
00154 break;
00155 case B_LAB:
00156 employeeType = EMPL_SCIENTIST;
00157 break;
00158 case B_HANGAR:
00159 employeeType = EMPL_SOLDIER;
00160 break;
00161 case B_MISC:
00162 Com_DPrintf(DEBUG_CLIENT, "E_HireForBuilding: Misc building type: %i with employees: %i.\n", building->buildingType, num);
00163 return;
00164 default:
00165 Com_DPrintf(DEBUG_CLIENT, "E_HireForBuilding: Unknown building type: %i.\n", building->buildingType);
00166 return;
00167 }
00168
00169 if (num > ccs.numEmployees[employeeType])
00170 num = ccs.numEmployees[employeeType];
00171 for (;num--;) {
00172 assert(base);
00173 if (!E_HireEmployeeByType(base, employeeType)) {
00174 Com_DPrintf(DEBUG_CLIENT, "E_HireForBuilding: Hiring %i employee(s) of type %i failed.\n", num, employeeType);
00175 return;
00176 }
00177 }
00178 }
00179 }
00180
00185 qboolean E_IsInBase (const employee_t* empl, const base_t* const base)
00186 {
00187 assert(empl != NULL);
00188 assert(base != NULL);
00189
00190 if (!E_IsHired(empl))
00191 return qfalse;
00192 if (empl->baseHired == base)
00193 return qtrue;
00194 return qfalse;
00195 }
00196
00205 qboolean E_MoveIntoNewBase (employee_t *employee, base_t *newBase)
00206 {
00207 if (employee) {
00208 base_t *oldBase = employee->baseHired;
00209 assert(oldBase);
00210 employee->baseHired = newBase;
00211 newBase->capacities[CAP_EMPLOYEES].cur++;
00212 oldBase->capacities[CAP_EMPLOYEES].cur--;
00213 return qtrue;
00214 }
00215
00216 return qfalse;
00217 }
00218
00224 const char* E_GetEmployeeString (employeeType_t type)
00225 {
00226 switch (type) {
00227 case EMPL_SOLDIER:
00228 return _("Soldier");
00229 case EMPL_SCIENTIST:
00230 return _("Scientist");
00231 case EMPL_WORKER:
00232 return _("Worker");
00233 case EMPL_PILOT:
00234 return _("Pilot");
00235 case EMPL_ROBOT:
00236 return _("UGV");
00237 default:
00238 Com_Error(ERR_DROP, "Unknown employee type '%i'\n", type);
00239 }
00240 }
00241
00248 employeeType_t E_GetEmployeeType (const char* type)
00249 {
00250 if (!type)
00251 return MAX_EMPL;
00252
00253 if (!strcmp(type, "EMPL_SCIENTIST"))
00254 return EMPL_SCIENTIST;
00255 else if (!strcmp(type, "EMPL_SOLDIER"))
00256 return EMPL_SOLDIER;
00257 else if (!strcmp(type, "EMPL_WORKER"))
00258 return EMPL_WORKER;
00259 else if (!strcmp(type, "EMPL_PILOT"))
00260 return EMPL_PILOT;
00261 else if (!strcmp(type, "EMPL_ROBOT"))
00262 return EMPL_ROBOT;
00263
00264 return MAX_EMPL;
00265 }
00266
00272 void E_ResetEmployees (void)
00273 {
00274 int i;
00275
00276 Com_DPrintf(DEBUG_CLIENT, "E_ResetEmployees: Delete all employees\n");
00277 for (i = EMPL_SOLDIER; i < MAX_EMPL; i++)
00278 if (ccs.numEmployees[i]) {
00279 memset(ccs.employees[i], 0, sizeof(ccs.employees[i]));
00280 ccs.numEmployees[i] = 0;
00281 }
00282 }
00283
00292 employee_t* E_GetEmployee (const base_t* const base, employeeType_t type, int idx)
00293 {
00294 employee_t *employee = NULL;
00295
00296 if (!base || type >= MAX_EMPL || idx < 0)
00297 return NULL;
00298
00299 while ((employee = E_GetNext(type, employee))) {
00300 if (employee->idx == idx && (!E_IsHired(employee) || E_IsInBase(employee, base)))
00301 return employee;
00302 }
00303
00304 return NULL;
00305 }
00306
00316 static employee_t* E_GetUnhiredEmployee (employeeType_t type, int idx)
00317 {
00318 int j = -1;
00319 employee_t *employee = NULL;
00320
00321 if (type >= MAX_EMPL) {
00322 Com_Printf("E_GetUnhiredEmployee: Unknown EmployeeType: %i\n", type);
00323 return NULL;
00324 }
00325
00326 while ((employee = E_GetNext(type, employee))) {
00327 if (employee->idx == idx) {
00328 if (E_IsHired(employee)) {
00329 Com_Printf("E_GetUnhiredEmployee: Warning: employee is already hired!\n");
00330 return NULL;
00331 }
00332 return employee;
00333 } else if (idx < 0 && !E_IsHired(employee)) {
00334 if (idx == j)
00335 return employee;
00336 j--;
00337 }
00338 }
00339 Com_Printf("Could not get unhired employee with index: %i of type %i (available: %i)\n", idx, type, ccs.numEmployees[type]);
00340 return NULL;
00341 }
00342
00349 employee_t* E_GetUnhiredRobot (const ugv_t *ugvType)
00350 {
00351 employee_t *employee = NULL;
00352
00353 while ((employee = E_GetNext(EMPL_ROBOT, employee))) {
00354 if (!E_IsHired(employee)) {
00355
00356 if (!ugvType || employee->ugv == ugvType)
00357 return employee;
00358 }
00359 }
00360 Com_Printf("Could not get unhired ugv/robot.\n");
00361 return NULL;
00362 }
00363
00371 int E_GetHiredEmployees (const base_t* const base, employeeType_t type, linkedList_t **hiredEmployees)
00372 {
00373 employee_t *employee;
00374
00375 if (type >= MAX_EMPL) {
00376 Com_Printf("E_GetHiredEmployees: Unknown EmployeeType: %i\n", type);
00377 *hiredEmployees = NULL;
00378 return -1;
00379 }
00380
00381 LIST_Delete(hiredEmployees);
00382
00383 employee = NULL;
00384 while ((employee = E_GetNextHired(type, employee))) {
00385 if (!employee->transfer && (!base || E_IsInBase(employee, base))) {
00386 LIST_AddPointer(hiredEmployees, employee);
00387 }
00388 }
00389
00390 if (hiredEmployees == NULL)
00391 return 0;
00392 return LIST_Count(*hiredEmployees);
00393 }
00394
00402 employee_t* E_GetHiredRobot (const base_t* const base, const ugv_t *ugvType)
00403 {
00404 linkedList_t *hiredEmployees = NULL;
00405 linkedList_t *hiredEmployeesTemp;
00406 employee_t *employee;
00407
00408 E_GetHiredEmployees(base, EMPL_ROBOT, &hiredEmployees);
00409 hiredEmployeesTemp = hiredEmployees;
00410
00411 employee = NULL;
00412 while (hiredEmployeesTemp) {
00413 employee = (employee_t*)hiredEmployeesTemp->data;
00414
00415 if ((employee->ugv == ugvType || !ugvType)
00416 && E_IsInBase(employee, base)) {
00417 assert(E_IsHired(employee));
00418 break;
00419 }
00420
00421 hiredEmployeesTemp = hiredEmployeesTemp->next;
00422 }
00423
00424 LIST_Delete(&hiredEmployees);
00425
00426 if (!employee)
00427 Com_DPrintf(DEBUG_CLIENT, "Could not get unhired ugv/robot.\n");
00428
00429 return employee;
00430 }
00431
00438 static inline qboolean E_EmployeeIsUnassigned (const employee_t * employee)
00439 {
00440 if (!employee)
00441 Com_Error(ERR_DROP, "E_EmployeeIsUnassigned: Employee is NULL.\n");
00442
00443 return (!employee->building);
00444 }
00445
00454 employee_t* E_GetAssignedEmployee (const base_t* const base, const employeeType_t type)
00455 {
00456 employee_t *employee = NULL;
00457 while ((employee = E_GetNextFromBase(type, employee, base))) {
00458 if (!E_EmployeeIsUnassigned(employee))
00459 return employee;
00460 }
00461 return NULL;
00462 }
00463
00472 employee_t* E_GetUnassignedEmployee (const base_t* const base, const employeeType_t type)
00473 {
00474 employee_t *employee = NULL;
00475 while ((employee = E_GetNextFromBase(type, employee, base))) {
00476 if (E_EmployeeIsUnassigned(employee))
00477 return employee;
00478 }
00479 return NULL;
00480 }
00481
00490 qboolean E_HireEmployee (base_t* base, employee_t* employee)
00491 {
00492 if (base->capacities[CAP_EMPLOYEES].cur >= base->capacities[CAP_EMPLOYEES].max) {
00493 UI_Popup(_("Not enough quarters"), _("You don't have enough quarters for your employees.\nBuild more quarters."));
00494 return qfalse;
00495 }
00496
00497 if (employee) {
00498
00499 employee->baseHired = base;
00500
00501 switch (employee->type) {
00502 case EMPL_WORKER:
00503 base->capacities[CAP_EMPLOYEES].cur++;
00504 PR_UpdateProductionCap(base);
00505 break;
00506 case EMPL_PILOT:
00507 AIR_AutoAddPilotToAircraft(base, employee);
00508 case EMPL_SCIENTIST:
00509 case EMPL_SOLDIER:
00510 base->capacities[CAP_EMPLOYEES].cur++;
00511 break;
00512 case EMPL_ROBOT:
00513 base->capacities[CAP_ITEMS].cur += UGV_SIZE;
00514 break;
00515 case MAX_EMPL:
00516 break;
00517 }
00518 return qtrue;
00519 }
00520 return qfalse;
00521 }
00522
00530 qboolean E_HireEmployeeByType (base_t* base, employeeType_t type)
00531 {
00532 employee_t* employee = E_GetUnhiredEmployee(type, -1);
00533 return employee ? E_HireEmployee(base, employee) : qfalse;
00534 }
00535
00542 qboolean E_HireRobot (base_t* base, const ugv_t *ugvType)
00543 {
00544 employee_t* employee = E_GetUnhiredRobot(ugvType);
00545 return employee ? E_HireEmployee(base, employee) : qfalse;
00546 }
00547
00555 void E_ResetEmployee (employee_t *employee)
00556 {
00557 assert(employee);
00558 assert(E_IsHired(employee));
00559
00560
00561 E_RemoveEmployeeFromBuildingOrAircraft(employee);
00562
00563 cls.i.DestroyInventory(&cls.i, &employee->chr.i);
00564 }
00565
00577 qboolean E_UnhireEmployee (employee_t* employee)
00578 {
00579 if (employee && E_IsHired(employee) && !employee->transfer) {
00580 base_t *base = employee->baseHired;
00581
00582
00583
00584 E_ResetEmployee(employee);
00585
00586 employee->baseHired = NULL;
00587
00588
00589 switch (employee->type) {
00590 case EMPL_PILOT:
00591 case EMPL_WORKER:
00592 case EMPL_SCIENTIST:
00593 case EMPL_SOLDIER:
00594 base->capacities[CAP_EMPLOYEES].cur--;
00595 break;
00596 case EMPL_ROBOT:
00597 base->capacities[CAP_ITEMS].cur -= UGV_SIZE;
00598 break;
00599 case MAX_EMPL:
00600 break;
00601 }
00602
00603 return qtrue;
00604 } else
00605 Com_DPrintf(DEBUG_CLIENT, "Could not fire employee\n");
00606 return qfalse;
00607 }
00608
00614 void E_UnhireAllEmployees (base_t* base, employeeType_t type)
00615 {
00616 employee_t *employee;
00617
00618 if (!base)
00619 return;
00620
00621 assert(type < MAX_EMPL);
00622
00623 employee = NULL;
00624 while ((employee = E_GetNextFromBase(type, employee, base))) {
00625 E_UnhireEmployee(employee);
00626 }
00627 }
00628
00638 static employee_t* E_CreateEmployeeAtIndex (employeeType_t type, nation_t *nation, const ugv_t *ugvType, const int emplIdx)
00639 {
00640 employee_t* employee;
00641 int curEmployeeIdx;
00642 const char *teamID;
00643 char teamDefName[MAX_VAR];
00644 const char* rank;
00645
00646 if (type >= MAX_EMPL)
00647 return NULL;
00648
00649 if (emplIdx >= 0) {
00650 curEmployeeIdx = emplIdx;
00651 } else {
00652 curEmployeeIdx = ccs.numEmployees[type];
00653 }
00654
00655 if (curEmployeeIdx >= MAX_EMPLOYEES) {
00656 Com_DPrintf(DEBUG_CLIENT, "E_CreateEmployee: MAX_EMPLOYEES exceeded for type %i\n", type);
00657 return NULL;
00658 }
00659
00660 employee = &ccs.employees[type][curEmployeeIdx];
00661 memset(employee, 0, sizeof(*employee));
00662
00663 employee->idx = curEmployeeIdx;
00664 employee->baseHired = NULL;
00665 employee->building = NULL;
00666 employee->type = type;
00667 employee->nation = nation;
00668
00669 if (ccs.curCampaign->team != TEAM_ALIEN)
00670 teamID = Com_ValueToStr(&ccs.curCampaign->team, V_TEAM, 0);
00671 else {
00673 teamID = GAME_GetTeamDef();
00674 }
00675
00676
00677 switch (type) {
00678 case EMPL_SOLDIER:
00679 rank = "rifleman";
00680 Q_strncpyz(teamDefName, teamID, sizeof(teamDefName));
00681 break;
00682 case EMPL_SCIENTIST:
00683 rank = "scientist";
00684 Com_sprintf(teamDefName, sizeof(teamDefName), "%s_scientist", teamID);
00685 break;
00686 case EMPL_PILOT:
00687 rank = "pilot";
00688 Com_sprintf(teamDefName, sizeof(teamDefName), "%s_pilot", teamID);
00689 break;
00690 case EMPL_WORKER:
00691 rank = "worker";
00692 Com_sprintf(teamDefName, sizeof(teamDefName), "%s_worker", teamID);
00693 break;
00694 case EMPL_ROBOT:
00695 if (!ugvType)
00696 Com_Error(ERR_DROP, "CL_GenerateCharacter: no type given for generation of EMPL_ROBOT employee.");
00697
00698 rank = "ugv";
00699
00700 Com_sprintf(teamDefName, sizeof(teamDefName), "%s%s", teamID, ugvType->actors);
00701 break;
00702 default:
00703 Com_Error(ERR_DROP, "Unknown employee type\n");
00704 }
00705
00706 CL_GenerateCharacter(&employee->chr, teamDefName);
00707 switch (type) {
00708 case EMPL_SOLDIER:
00709 break;
00710 case EMPL_SCIENTIST:
00711 case EMPL_PILOT:
00712 case EMPL_WORKER:
00713 employee->speed = 100;
00714 break;
00715 case EMPL_ROBOT:
00716 if (!ugvType)
00717 Com_Error(ERR_DROP, "E_CreateEmployee: No ugvType given!\n");
00718 employee->ugv = ugvType;
00719 break;
00720 default:
00721 break;
00722 }
00723
00724 employee->chr.score.rank = CL_GetRankIdx(rank);
00725
00726 Com_DPrintf(DEBUG_CLIENT, "Generate character for type: %i\n", type);
00727
00728 if (emplIdx < 0)
00729 ccs.numEmployees[type]++;
00730
00731 return employee;
00732 }
00733
00742 employee_t* E_CreateEmployee (employeeType_t type, nation_t *nation, const ugv_t *ugvType)
00743 {
00744
00745 return E_CreateEmployeeAtIndex(type, nation, ugvType, -1);
00746 }
00747
00762 qboolean E_DeleteEmployee (employee_t *employee, employeeType_t type)
00763 {
00764 int i;
00765 qboolean found = qfalse;
00766
00767 if (!employee)
00768 return qfalse;
00769
00770
00771
00772
00773
00774 if (employee->baseHired) {
00775
00776 employee->transfer = qfalse;
00777 E_UnhireEmployee(employee);
00778 }
00779
00780
00781 for (i = 0; i < ccs.numEmployees[type]; i++) {
00782 if (&ccs.employees[type][i] == employee)
00783 found = qtrue;
00784
00785 if (found) {
00786 if (i < MAX_EMPLOYEES - 1) {
00787
00788 ccs.employees[type][i] = ccs.employees[type][i + 1];
00789 ccs.employees[type][i].idx = i;
00790 }
00791 }
00792 }
00793
00794 if (found) {
00795 transfer_t *transfer;
00796 int j;
00797
00798 for (j = 0; j < MAX_BASES; j++) {
00799 base_t *base = B_GetFoundedBaseByIDX(j);
00800 aircraft_t *aircraft;
00801
00802 aircraft = NULL;
00803 while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL) {
00804 linkedList_t* l;
00805
00806 for (l = aircraft->acTeam; l != NULL; l = l->next) {
00807
00808
00809
00810
00811
00812
00814 if ((employee_t *)l->data >= employee)
00815 l->data -= sizeof(employee_t);
00816 }
00817 if (employee->type == EMPL_PILOT && aircraft->pilot >= employee)
00818 aircraft->pilot--;
00819 }
00820 }
00821 for (i = 0, transfer = ccs.transfers; i < ccs.numTransfers; i++, transfer++) {
00822 if (!transfer->active)
00823 continue;
00824 for (j = 0; j < MAX_EMPL; j++) {
00825 int k;
00826 for (k = 0; k < MAX_EMPLOYEES; k++) {
00827 if (transfer->employeeArray[j][k] > employee)
00828 transfer->employeeArray[j][k]--;
00829 else if (transfer->employeeArray[j][k] == employee)
00832 transfer->employeeArray[j][k] = NULL;
00833 }
00834 }
00835 }
00836
00837 ccs.numEmployees[type]--;
00838 } else {
00839 Com_DPrintf(DEBUG_CLIENT, "E_DeleteEmployee: Employee wasn't in the global list.\n");
00840 return qfalse;
00841 }
00842
00843 return qtrue;
00844 }
00845
00851 void E_DeleteAllEmployees (base_t* base)
00852 {
00853 int i;
00854 employeeType_t type;
00855
00856 if (!base)
00857 return;
00858
00859 Com_DPrintf(DEBUG_CLIENT, "E_DeleteAllEmployees: starting ...\n");
00860
00861 for (type = EMPL_SOLDIER; type < MAX_EMPL; type++) {
00862 Com_DPrintf(DEBUG_CLIENT, "E_DeleteAllEmployees: Removing empl-type %i | num %i\n", type, ccs.numEmployees[type]);
00863
00864
00865
00866 for (i = ccs.numEmployees[type] - 1; i >= 0; i--) {
00867 employee_t *employee = &ccs.employees[type][i];
00868 Com_DPrintf(DEBUG_CLIENT, "E_DeleteAllEmployees: %i\n", i);
00869 if (E_IsInBase(employee, base)) {
00870 E_DeleteEmployee(employee, type);
00871 Com_DPrintf(DEBUG_CLIENT, "E_DeleteAllEmployees: Removing empl.\n");
00872 } else if (employee->baseHired) {
00873 Com_DPrintf(DEBUG_CLIENT, "E_DeleteAllEmployees: Not removing empl. (other base)\n");
00874 }
00875 }
00876 }
00877 Com_DPrintf(DEBUG_CLIENT, "E_DeleteAllEmployees: ... finished\n");
00878 }
00879
00880
00889 void E_DeleteEmployeesExceedingCapacity (base_t *base)
00890 {
00891 int type, i;
00892
00893
00894 if (base->capacities[CAP_EMPLOYEES].cur <= base->capacities[CAP_EMPLOYEES].max)
00895 return;
00896
00897
00898 for (type = MAX_EMPL - 1; type >= 0; type--) {
00899
00900 if (type == EMPL_ROBOT)
00901 continue;
00902
00903
00904
00905
00906 for (i = ccs.numEmployees[type] - 1; i >= 0 && ccs.numEmployees[type] >= 0; i--) {
00907 employee_t *employee = &ccs.employees[type][i];
00908
00909
00910 if (!E_IsInBase(employee, base))
00911 continue;
00912
00913 E_DeleteEmployee(employee, type);
00914 if (base->capacities[CAP_EMPLOYEES].cur <= base->capacities[CAP_EMPLOYEES].max)
00915 return;
00916 }
00917 }
00918
00919 Com_Printf("E_DeleteEmployeesExceedingCapacity: Warning, removed all employees from base '%s', but capacity is still > 0\n", base->name);
00920 }
00921
00930 void E_RefreshUnhiredEmployeeGlobalList (const employeeType_t type, const qboolean excludeUnhappyNations)
00931 {
00932 nation_t *happyNations[MAX_NATIONS];
00933 int numHappyNations = 0;
00934 int idx, nationIdx;
00935
00936 happyNations[0] = NULL;
00937
00938
00939 for (idx = 0; idx < ccs.numNations; idx++) {
00940 if (ccs.nations[idx].stats[0].happiness > 0 || !excludeUnhappyNations) {
00941 happyNations[numHappyNations] = &ccs.nations[idx];
00942 numHappyNations++;
00943 }
00944 }
00945
00946 if (!numHappyNations)
00947 return;
00948
00949 nationIdx = 0;
00950
00951
00952 for (idx = 0; idx < MAX_EMPLOYEES; idx++) {
00953 const employee_t *employee = &ccs.employees[type][idx];
00954
00955
00956 if (!E_IsHired(employee)) {
00957 E_CreateEmployeeAtIndex(type, happyNations[nationIdx], NULL, idx);
00958 nationIdx = (nationIdx + 1) % numHappyNations;
00959 }
00960 }
00961 }
00962
00963
00972 qboolean E_RemoveEmployeeFromBuildingOrAircraft (employee_t *employee)
00973 {
00974 base_t *base;
00975
00976 assert(employee);
00977
00978
00979 if (!employee->building) {
00980
00981 if (employee->type != EMPL_SOLDIER && employee->type != EMPL_ROBOT
00982 && employee->type != EMPL_PILOT)
00983 return qfalse;
00984 }
00985
00986
00987 base = employee->baseHired;
00988 if (!base)
00989 Com_Error(ERR_DROP, "Employee (type: %i) is not hired", employee->type);
00990
00991 switch (employee->type) {
00992 case EMPL_SCIENTIST:
00993 RS_RemoveFiredScientist(base, employee);
00994 break;
00995
00996 case EMPL_ROBOT:
00997 case EMPL_SOLDIER:
00998
00999 if (AIR_IsEmployeeInAircraft(employee, NULL))
01000 AIR_RemoveEmployee(employee, NULL);
01001 break;
01002
01003 case EMPL_PILOT:
01004 AIR_RemovePilotFromAssignedAircraft(base, employee);
01005 break;
01006
01007 case EMPL_WORKER:
01008
01009 PR_UpdateProductionCap(base);
01010 break;
01011
01012
01013 case MAX_EMPL:
01014 break;
01015 }
01016
01017 return qtrue;
01018 }
01019
01026 int E_CountHired (const base_t* const base, employeeType_t type)
01027 {
01028 int count = 0;
01029 employee_t *employee = NULL;
01030
01031 while ((employee = E_GetNextHired(type, employee))) {
01032 if (!base || E_IsInBase(employee, base))
01033 count++;
01034 }
01035 return count;
01036 }
01037
01044 int E_CountHiredRobotByType (const base_t* const base, const ugv_t *ugvType)
01045 {
01046 int count = 0;
01047 employee_t *employee = NULL;
01048
01049 while ((employee = E_GetNextHired(EMPL_ROBOT, employee))) {
01050 if (employee->ugv == ugvType && (!base || E_IsInBase(employee, base)))
01051 count++;
01052 }
01053 return count;
01054 }
01055
01056
01064 int E_CountAllHired (const base_t* const base)
01065 {
01066 employeeType_t type;
01067 int count;
01068
01069 if (!base)
01070 return 0;
01071
01072 count = 0;
01073 for (type = 0; type < MAX_EMPL; type++)
01074 count += E_CountHired(base, type);
01075
01076 return count;
01077 }
01078
01084 int E_CountUnhired (employeeType_t type)
01085 {
01086 int count = 0;
01087 employee_t *employee = NULL;
01088 while ((employee = E_GetNext(type, employee))) {
01089 if (!E_IsHired(employee))
01090 count++;
01091 }
01092 return count;
01093 }
01094
01100 int E_CountUnhiredRobotsByType (const ugv_t *ugvType)
01101 {
01102 int count = 0;
01103 employee_t *employee = NULL;
01104
01105 while ((employee = E_GetNext(EMPL_ROBOT, employee))) {
01106 if (!E_IsHired(employee) && employee->ugv == ugvType)
01107 count++;
01108 }
01109 return count;
01110 }
01111
01117 int E_CountUnassigned (const base_t* const base, employeeType_t type)
01118 {
01119 int count;
01120 employee_t *employee;
01121
01122 if (!base)
01123 return 0;
01124
01125 count = 0;
01126 employee = NULL;
01127 while ((employee = E_GetNextFromBase(type, employee, base))) {
01128 if (!employee->building)
01129 count++;
01130 }
01131 return count;
01132 }
01133
01137 static inline nation_t *E_RandomNation (void)
01138 {
01139 const int nationIndex = rand() % ccs.numNations;
01140 return &ccs.nations[nationIndex];
01141 }
01142
01143 void E_InitialEmployees (void)
01144 {
01145 campaign_t *campaign = ccs.curCampaign;
01146 int i;
01147 int j = 0;
01148
01149
01150 for (i = 0; i < campaign->soldiers; i++)
01151 E_CreateEmployee(EMPL_SOLDIER, E_RandomNation(), NULL);
01152 for (i = 0; i < campaign->scientists; i++)
01153 E_CreateEmployee(EMPL_SCIENTIST, E_RandomNation(), NULL);
01154 for (i = 0; i < campaign->ugvs; i++) {
01155 if (frand() > 0.5)
01156 E_CreateEmployee(EMPL_ROBOT, E_RandomNation(), Com_GetUGVByID("ugv_ares_w"));
01157 else
01158 E_CreateEmployee(EMPL_ROBOT, E_RandomNation(), Com_GetUGVByID("ugv_phoenix"));
01159 }
01160 for (i = 0; i < campaign->workers; i++)
01161 E_CreateEmployee(EMPL_WORKER, E_RandomNation(), NULL);
01162
01163
01164 for (i = 0; i < MAX_EMPLOYEES; i++) {
01165 nation_t *nation = &ccs.nations[++j % ccs.numNations];
01166 if (!E_CreateEmployee(EMPL_PILOT, nation, NULL))
01167 break;
01168 }
01169 }
01170
01171 #ifdef DEBUG
01172
01175 static void E_ListHired_f (void)
01176 {
01177 employeeType_t emplType;
01178
01179 for (emplType = 0; emplType < MAX_EMPL; emplType++) {
01180 employee_t *employee = NULL;
01181 while ((employee = E_GetNextHired(emplType, employee))) {
01182 Com_Printf("Employee: %s (idx: %i) %s at %s\n", E_GetEmployeeString(employee->type), employee->idx,
01183 employee->chr.name, employee->baseHired->name);
01184 if (employee->type != emplType)
01185 Com_Printf("Warning: EmployeeType mismatch: %i != %i\n", emplType, employee->type);
01186 }
01187 }
01188 }
01189 #endif
01190
01196 void E_InitStartup (void)
01197 {
01198 #ifdef DEBUG
01199 Cmd_AddCommand("debug_listhired", E_ListHired_f, "Debug command to list all hired employee");
01200 #endif
01201 }
01202
01207 employee_t* E_GetEmployeeFromChrUCN (int uniqueCharacterNumber)
01208 {
01209 int j;
01210
01211
01212 for (j = 0; j < MAX_EMPL; j++) {
01213 employee_t *employee = NULL;
01214 while ((employee = E_GetNext(j, employee))) {
01215 if (employee->chr.ucn == uniqueCharacterNumber)
01216 return employee;
01217 }
01218 }
01219
01220 return NULL;
01221 }
01222
01223
01233 qboolean E_SaveXML (mxml_node_t *p)
01234 {
01235 employeeType_t j;
01236
01237 Com_RegisterConstList(saveEmployeeConstants);
01238 for (j = 0; j < MAX_EMPL; j++) {
01239 mxml_node_t *snode = mxml_AddNode(p, SAVE_EMPLOYEE_EMPLOYEES);
01240 employee_t *e = NULL;
01241
01242 mxml_AddString(snode, SAVE_EMPLOYEE_TYPE, Com_GetConstVariable(SAVE_EMPLOYEETYPE_NAMESPACE, j));
01243 while ((e = E_GetNext(j, e))) {
01244 mxml_node_t * chrNode;
01245 mxml_node_t *ssnode = mxml_AddNode(snode, SAVE_EMPLOYEE_EMPLOYEE);
01246
01248 mxml_AddInt(ssnode, SAVE_EMPLOYEE_IDX, e->idx);
01249 if (e->baseHired)
01250 mxml_AddInt(ssnode, SAVE_EMPLOYEE_BASEHIRED, e->baseHired->idx);
01251 if (e->building)
01252 mxml_AddInt(ssnode, SAVE_EMPLOYEE_BUILDING, e->building->idx);
01253
01254 assert(e->nation);
01255 mxml_AddString(ssnode, SAVE_EMPLOYEE_NATION, e->nation->id);
01256
01257 if (e->ugv)
01258 mxml_AddString(ssnode, SAVE_EMPLOYEE_UGV, e->ugv->id);
01259
01260 chrNode = mxml_AddNode(ssnode, SAVE_EMPLOYEE_CHR);
01261 CL_SaveCharacterXML(chrNode, &e->chr);
01262 }
01263 }
01264 Com_UnregisterConstList(saveEmployeeConstants);
01265
01266 return qtrue;
01267 }
01268
01273 qboolean E_LoadXML (mxml_node_t *p)
01274 {
01275 mxml_node_t * snode;
01276 qboolean success = qtrue;
01277
01278 Com_RegisterConstList(saveEmployeeConstants);
01279 for (snode = mxml_GetNode(p, SAVE_EMPLOYEE_EMPLOYEES); snode;
01280 snode = mxml_GetNextNode(snode, p , SAVE_EMPLOYEE_EMPLOYEES)) {
01281 int i;
01282 mxml_node_t * ssnode;
01283 employeeType_t emplType;
01284 const char *type = mxml_GetString(snode, SAVE_EMPLOYEE_TYPE);
01285
01286 if (!Com_GetConstIntFromNamespace(SAVE_EMPLOYEETYPE_NAMESPACE, type, (int*) &emplType)) {
01287 Com_Printf("Invaild employee type '%s'\n", type);
01288 success = qfalse;
01289 break;
01290 }
01291
01292 for (ssnode = mxml_GetNode(snode, SAVE_EMPLOYEE_EMPLOYEE), i = 0; i < MAX_EMPLOYEES && ssnode;
01293 ssnode = mxml_GetNextNode(ssnode, snode, SAVE_EMPLOYEE_EMPLOYEE), i++) {
01294 int baseIDX;
01295 int buildingIDX;
01296 mxml_node_t * chrNode;
01297 employee_t *e = &ccs.employees[emplType][i];
01298
01300 e->idx = mxml_GetInt(ssnode, SAVE_EMPLOYEE_IDX, MAX_EMPLOYEES);
01301 if (e->idx >= MAX_EMPLOYEES) {
01302 Com_Printf("Invalid employeeIDX\n");
01303 success = qfalse;
01304 break;
01305 }
01306 e->type = emplType;
01307
01308 assert(ccs.numBases);
01309 baseIDX = mxml_GetInt(ssnode, SAVE_EMPLOYEE_BASEHIRED, -1);
01310 e->baseHired = (baseIDX >= 0) ? B_GetBaseByIDX(baseIDX) : NULL;
01311
01313 buildingIDX = mxml_GetInt(ssnode, SAVE_EMPLOYEE_BUILDING, -1);
01314 e->building = (e->baseHired && buildingIDX >= 0) ? &ccs.buildings[e->baseHired->idx][buildingIDX] : NULL;
01315
01316 e->nation = NAT_GetNationByID(mxml_GetString(ssnode, SAVE_EMPLOYEE_NATION));
01317 if (!e->nation) {
01318 Com_Printf("No nation defined for employee\n");
01319 success = qfalse;
01320 break;
01321 }
01322
01323 e->ugv = Com_GetUGVByIDSilent(mxml_GetString(ssnode, SAVE_EMPLOYEE_UGV));
01324
01325 chrNode = mxml_GetNode(ssnode, SAVE_EMPLOYEE_CHR);
01326 if (!chrNode) {
01327 Com_Printf("No character definition found for employee\n");
01328 success = qfalse;
01329 break;
01330 }
01331 if (!CL_LoadCharacterXML(chrNode, &e->chr)) {
01332 Com_Printf("Error loading character definition for employee\n");
01333 success = qfalse;
01334 break;
01335 }
01336 }
01337 if (!success)
01338 break;
01339 ccs.numEmployees[emplType] = i;
01340 }
01341 Com_UnregisterConstList(saveEmployeeConstants);
01342
01343 return success;
01344 }
01345
01350 qboolean E_HireAllowed (const base_t* base)
01351 {
01352 if (base->baseStatus != BASE_UNDER_ATTACK && B_GetBuildingStatus(base, B_QUARTERS))
01353 return qtrue;
01354 else
01355 return qfalse;
01356 }
01357
01362 void E_RemoveInventoryFromStorage (employee_t *employee)
01363 {
01364 containerIndex_t container;
01365 const character_t *chr = &employee->chr;
01366
01367 assert(employee->baseHired);
01368
01369 for (container = 0; container < csi.numIDs; container++) {
01370 const invList_t *invList = CONTAINER(chr, container);
01371
01372 if (INVDEF(container)->temp)
01373 continue;
01374
01375 while (invList) {
01376
01377 if (invList->item.m && invList->item.m != invList->item.t)
01378 B_UpdateStorageAndCapacity(employee->baseHired, invList->item.m, -1, qfalse, qfalse);
01379
01380 if (invList->item.t)
01381 B_UpdateStorageAndCapacity(employee->baseHired, invList->item.t, -1, qfalse, qfalse);
01382
01383 invList = invList->next;
01384 }
01385 }
01386 }
01387