cp_employee.c

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2002-2010 UFO: Alien Invasion.
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019 See the GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024 
00025 */
00026 
00027 #include "../client.h" /* cls */
00028 #include "../cl_game.h" /* GAME_GetTeamDef */
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     /* Check that employee is hired */
00115     if (!E_IsHired(employee))
00116         return qfalse;
00117 
00118     /* Check if employee is currently transferred. */
00119     if (employee->transfer)
00120         return qtrue;
00121 
00122     /* for now only soldiers, ugvs and pilots can be assigned to an aircraft */
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: /* the Dropship 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         /* don't try to hire more that available - see E_CreateEmployee */
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; /* The number of found unhired employees. Ignore the minus. */
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             /* If no type was given we return the first ugv we find. */
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)  /* If no type was given we return the first ugv we find. */
00416          && E_IsInBase(employee, base)) {       /* It has to be in the defined 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         /* Now uses quarter space. */
00499         employee->baseHired = base;
00500         /* Update other capacities */
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     /* Remove employee from building (and tech/production). */
00561     E_RemoveEmployeeFromBuildingOrAircraft(employee);
00562     /* Destroy the inventory of the employee (carried items will remain in base->storage) */
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         /* Any effect of removing an employee (e.g. removing a scientist from a research project)
00583          * should take place in E_RemoveEmployeeFromBuildingOrAircraft */
00584         E_ResetEmployee(employee);
00585         /* Set all employee-tags to 'unhired'. */
00586         employee->baseHired = NULL;
00587 
00588         /* Remove employee from corresponding capacity */
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     /* Generate character stats, models & names. */
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     /* Runs the create employee function with a -1 index parameter, which means at to end of list. */
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     /* Fire the employee. This will also:
00771      * 1) remove him from buildings&work
00772      * 2) remove his inventory */
00773 
00774     if (employee->baseHired) {
00775         /* make sure that this employee is really unhired */
00776         employee->transfer = qfalse;
00777         E_UnhireEmployee(employee);
00778     }
00779 
00780     /* Remove the employee from the global list. */
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) { /* Just in case we have _that much_ employees. :) */
00787                 /* Move all the following employees in the list one place forward and correct its index. */
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                     /* no need to check for == here, the employee should
00808                      * no longer be in this list, due to the E_UnhireEmployee
00809                      * call which will also remove any assignments for the
00810                      * aircraft - checking >= because the employee after the
00811                      * removed on in ccs.employees is now on the same position
00812                      * where the removed employee was before */
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         /* Warning:
00864          * ccs.numEmployees[type] is changed in E_DeleteAllEmployees! (it's decreased by 1 per call)
00865          * For this reason we start this loop from the back of the empl-list. toward 0. */
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     /* Check if there are too many employees */
00894     if (base->capacities[CAP_EMPLOYEES].cur <= base->capacities[CAP_EMPLOYEES].max)
00895         return;
00896 
00897     /* do a reverse loop in order to finish by soldiers (the most important employees) */
00898     for (type = MAX_EMPL - 1; type >= 0; type--) {
00899         /* UGV are not stored in Quarters */
00900         if (type == EMPL_ROBOT)
00901             continue;
00902 
00903         /* Warning:
00904          * ccs.numEmployees[type] is changed in E_DeleteAllEmployees! (it's decreased by 1 per call)
00905          * For this reason we start this loop from the back of the empl-list. toward 0. */
00906         for (i = ccs.numEmployees[type] - 1; i >= 0 && ccs.numEmployees[type] >= 0; i--) {
00907             employee_t *employee = &ccs.employees[type][i];
00908 
00909             /* check if the employee is hired on this base */
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     /* get a list of nations,  if excludeHappyNations is qtrue then also exclude
00938      * unhappy nations (unhappy nation: happiness <= 0) from the list */
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     /* Fill the global data employee list with employees, evenly distributed
00951      * between nations in the happyNations list */
00952     for (idx = 0; idx < MAX_EMPLOYEES; idx++) {
00953         const employee_t *employee = &ccs.employees[type][idx];
00954 
00955         /* we dont want to overwrite employees that have already been hired */
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     /* not assigned to any building... */
00979     if (!employee->building) {
00980         /* ... and no aircraft handling needed? */
00981         if (employee->type != EMPL_SOLDIER && employee->type != EMPL_ROBOT
00982          && employee->type != EMPL_PILOT)
00983             return qfalse;
00984     }
00985 
00986     /* get the base where the employee is hired in */
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         /* Remove soldier from aircraft/team if he was assigned to one. */
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         /* Update current capacity and production times if worker is being counted there. */
01009         PR_UpdateProductionCap(base);
01010         break;
01011 
01012     /* otherwise the compiler would print a warning */
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     /* setup initial employee count */
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     /* Fill the global data employee list with pilots, evenly distributed between nations */
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     /* MAX_EMPLOYEES and not numWholeTeam - maybe some other soldier died */
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             /* Store the nations identifier string. */
01254             assert(e->nation);
01255             mxml_AddString(ssnode, SAVE_EMPLOYEE_NATION, e->nation->id);
01256             /* Store the ugv-type identifier string. (Only exists for EMPL_ROBOT). */
01257             if (e->ugv)
01258                 mxml_AddString(ssnode, SAVE_EMPLOYEE_UGV, e->ugv->id);
01259             /* Character Data */
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             /* base */
01308             assert(ccs.numBases);   /* Just in case the order is ever changed. */
01309             baseIDX = mxml_GetInt(ssnode, SAVE_EMPLOYEE_BASEHIRED, -1);
01310             e->baseHired = (baseIDX >= 0) ? B_GetBaseByIDX(baseIDX) : NULL;
01311             /* building */
01313             buildingIDX = mxml_GetInt(ssnode, SAVE_EMPLOYEE_BUILDING, -1);
01314             e->building = (e->baseHired && buildingIDX >= 0) ? &ccs.buildings[e->baseHired->idx][buildingIDX] : NULL;
01315             /* nation */
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             /* UGV-Type */
01323             e->ugv = Com_GetUGVByIDSilent(mxml_GetString(ssnode, SAVE_EMPLOYEE_UGV));
01324             /* Character Data */
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             /* Remove ammo */
01377             if (invList->item.m && invList->item.m != invList->item.t)
01378                 B_UpdateStorageAndCapacity(employee->baseHired, invList->item.m, -1, qfalse, qfalse);
01379             /* Remove Item */
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 

Generated by  doxygen 1.6.2