File: | client/cgame/campaign/cp_aliencont.cpp |
Location: | line 673, column 3 |
Description: | Value stored to 'containment' is never read |
1 | /** |
2 | * @file |
3 | * @brief Deals with the Alien Containment stuff. |
4 | * @note Collecting and managing aliens functions prefix: AL_ |
5 | * @note Alien Containment menu functions prefix: AC_ |
6 | */ |
7 | |
8 | /* |
9 | Copyright (C) 2002-2011 UFO: Alien Invasion. |
10 | |
11 | This program is free software; you can redistribute it and/or |
12 | modify it under the terms of the GNU General Public License |
13 | as published by the Free Software Foundation; either version 2 |
14 | of the License, or (at your option) any later version. |
15 | |
16 | This program is distributed in the hope that it will be useful, |
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
19 | |
20 | See the GNU General Public License for more details. |
21 | |
22 | You should have received a copy of the GNU General Public License |
23 | along with this program; if not, write to the Free Software |
24 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
25 | */ |
26 | |
27 | #include "../../cl_shared.h" |
28 | #include "cp_campaign.h" |
29 | #include "cp_capacity.h" |
30 | #include "cp_aliencont_callbacks.h" |
31 | #include "save/save_aliencont.h" |
32 | |
33 | /** |
34 | * Collecting aliens functions for aircraft |
35 | */ |
36 | |
37 | /** |
38 | * @brief Searches an existing index in the alien cargo of an aircraft, or returns the next free index of |
39 | * the alien cargo if the team definition wasn't found in the current alien cargo. |
40 | * @param[in] aircraft The aircraft that should have the given team definition in its alien cargo |
41 | * @param[in] teamDef The team definition that should be searched for |
42 | * @return The index of the team definition in the alien cargo of the given aircraft |
43 | */ |
44 | static inline int AL_GetCargoIndexForTeamDefinition (const aircraft_t *aircraft, const teamDef_t *teamDef) |
45 | { |
46 | const aliensTmp_t *cargo = AL_GetAircraftAlienCargo(aircraft)(aircraft)->alienCargo; |
47 | const int alienCargoTypes = AL_GetAircraftAlienCargoTypes(aircraft)((aircraft)->alienCargoTypes); |
48 | int i; |
49 | |
50 | for (i = 0; i < alienCargoTypes; i++, cargo++) { |
51 | if (cargo->teamDef == teamDef) |
52 | break; |
53 | } |
54 | |
55 | /* in case teamdef wasn't found, return the next free index */ |
56 | assert(i < MAX_CARGO)(__builtin_expect(!(i < 32), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 56, "i < MAX_CARGO") : (void)0); |
57 | return i; |
58 | } |
59 | |
60 | /** |
61 | * @brief Adds an alientype to an aircraft cargo |
62 | * @param[in] aircraft The aircraft that owns the alien cargo to add the alien race to |
63 | * @param[in] teamDef The team definition of the alien race to add to the alien cargo container of the |
64 | * given aircraft |
65 | * @param[in] amount The amount of aliens of the given race (@c teamDef ) that should be added to |
66 | * the alien cargo |
67 | * @param[in] dead true for cases where the aliens should be added as dead to the alien cargo - false for |
68 | * living aliens |
69 | * @todo Return false for cases where the alien race could not be added to the alien cargo of the aircraft |
70 | * @returns Currently always true |
71 | */ |
72 | bool AL_AddAlienTypeToAircraftCargo (aircraft_t *aircraft, const teamDef_t *teamDef, int amount, bool dead) |
73 | { |
74 | aliensTmp_t *cargo = AL_GetAircraftAlienCargo(aircraft)(aircraft)->alienCargo; |
75 | const int alienCargoTypes = AL_GetAircraftAlienCargoTypes(aircraft)((aircraft)->alienCargoTypes); |
76 | const int index = AL_GetCargoIndexForTeamDefinition(aircraft, teamDef); |
77 | aliensTmp_t *c = &cargo[index]; |
78 | |
79 | if (!c->teamDef) |
80 | AL_SetAircraftAlienCargoTypes(aircraft, alienCargoTypes + 1)(aircraft)->alienCargoTypes = (alienCargoTypes + 1); |
81 | c->teamDef = teamDef; |
82 | |
83 | if (dead) |
84 | c->amountDead += amount; |
85 | else |
86 | c->amountAlive += amount; |
87 | |
88 | return true; |
89 | } |
90 | |
91 | /** |
92 | * General Collecting aliens functions |
93 | */ |
94 | |
95 | /** |
96 | * @brief Prepares Alien Containment - names, states, and zeroed amount. |
97 | * @param[in] base Pointer to the base with AC. |
98 | * @sa B_BuildBase |
99 | * @sa AL_AddAliens |
100 | */ |
101 | void AL_FillInContainment (base_t *base) |
102 | { |
103 | int i, counter = 0; |
104 | aliensCont_t *containment; |
105 | |
106 | assert(base)(__builtin_expect(!(base), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 106, "base") : (void)0); |
107 | containment = base->alienscont; |
108 | |
109 | for (i = 0; i < csi.numTeamDefs; i++) { |
110 | const teamDef_t *td = &csi.teamDef[i]; |
111 | if (!CHRSH_IsTeamDefAlien(td)) |
112 | continue; |
113 | if (counter >= MAX_ALIENCONT_CAP32) |
114 | Com_Error(ERR_DROP1, "Overflow in AL_FillInContainment"); |
115 | containment->teamDef = td; /* Link to global race index. */ |
116 | containment->amountAlive = 0; |
117 | containment->amountDead = 0; |
118 | /* for sanity checking */ |
119 | containment->tech = ccs.teamDefTechs[td->idx]; |
120 | if (!containment->tech) |
121 | Com_Error(ERR_DROP1, "Could not find a valid tech for '%s'\n", td->name); |
122 | Com_DPrintf(DEBUG_CLIENT0x20, "AL_FillInContainment: type: %s tech-index: %i\n", td->name, containment->tech->idx); |
123 | containment++; |
124 | counter++; |
125 | } |
126 | CAP_SetCurrent(base, CAP_ALIENS, 0); |
127 | } |
128 | |
129 | /** |
130 | * @brief Puts alien cargo into Alien Containment. |
131 | * @param[in] aircraft Aircraft transporting cargo to homebase. |
132 | * @sa B_AircraftReturnedToHomeBase |
133 | * @sa AL_FillInContainment |
134 | * @note an event mail about missing breathing tech will be triggered if necessary. |
135 | */ |
136 | void AL_AddAliens (aircraft_t *aircraft) |
137 | { |
138 | base_t *toBase; |
139 | const aliensTmp_t *cargo; |
140 | int alienCargoTypes; |
141 | int i; |
142 | int j; |
143 | bool limit = false; |
144 | bool messageAlreadySet = false; |
145 | technology_t *breathingTech; |
146 | bool alienBreathing = false; |
147 | |
148 | assert(aircraft)(__builtin_expect(!(aircraft), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 148, "aircraft") : (void)0); |
149 | toBase = aircraft->homebase; |
150 | assert(toBase)(__builtin_expect(!(toBase), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 150, "toBase") : (void)0); |
151 | |
152 | cargo = AL_GetAircraftAlienCargo(aircraft)(aircraft)->alienCargo; |
153 | alienCargoTypes = AL_GetAircraftAlienCargoTypes(aircraft)((aircraft)->alienCargoTypes); |
154 | |
155 | if (alienCargoTypes == 0) |
156 | return; |
157 | |
158 | if (!B_GetBuildingStatus(toBase, B_ALIEN_CONTAINMENT)) { |
159 | MS_AddNewMessage(_("Notice")gettext("Notice"), _("You cannot process aliens yet. Alien Containment not ready in this base.")gettext("You cannot process aliens yet. Alien Containment not ready in this base." )); |
160 | return; |
161 | } |
162 | |
163 | breathingTech = RS_GetTechByID(BREATHINGAPPARATUS_TECH"rs_alien_breathing"); |
164 | if (!breathingTech) |
165 | Com_Error(ERR_DROP1, "AL_AddAliens: Could not get breathing apparatus tech definition"); |
166 | alienBreathing = RS_IsResearched_ptr(breathingTech); |
167 | |
168 | for (i = 0; i < alienCargoTypes; i++) { |
169 | for (j = 0; j < ccs.numAliensTD; j++) { |
170 | aliensCont_t *ac = &toBase->alienscont[j]; |
171 | assert(ac->teamDef)(__builtin_expect(!(ac->teamDef), 0) ? __assert_rtn(__func__ , "src/client/cgame/campaign/cp_aliencont.cpp", 171, "ac->teamDef" ) : (void)0); |
172 | assert(cargo[i].teamDef)(__builtin_expect(!(cargo[i].teamDef), 0) ? __assert_rtn(__func__ , "src/client/cgame/campaign/cp_aliencont.cpp", 172, "cargo[i].teamDef" ) : (void)0); |
173 | |
174 | if (ac->teamDef == cargo[i].teamDef) { |
175 | const bool isRobot = CHRSH_IsTeamDefRobot(cargo[i].teamDef); |
176 | ac->amountDead += cargo[i].amountDead; |
177 | |
178 | if (cargo[i].amountAlive <= 0) |
179 | continue; |
180 | if (!alienBreathing && !isRobot) { |
181 | /* We can not store living (i.e. no robots or dead bodies) aliens without rs_alien_breathing tech */ |
182 | ac->amountDead += cargo[i].amountAlive; |
183 | /* only once */ |
184 | if (!messageAlreadySet) { |
185 | MS_AddNewMessage(_("Notice")gettext("Notice"), _("You can't hold live aliens yet. Aliens died.")gettext("You can't hold live aliens yet. Aliens died."), MSG_DEATH); |
186 | messageAlreadySet = true; |
187 | } |
188 | if (!ccs.breathingMailSent) { |
189 | CL_EventAddMail("alienbreathing"); |
190 | ccs.breathingMailSent = true; |
191 | } |
192 | } else { |
193 | int k; |
194 | |
195 | for (k = 0; k < cargo[i].amountAlive; k++) { |
196 | /* Check base capacity. */ |
197 | if (AL_CheckAliveFreeSpace(toBase, NULL__null, 1)) { |
198 | AL_ChangeAliveAlienNumber(toBase, ac, 1); |
199 | } else { |
200 | /* Every exceeding alien is killed |
201 | * Display a message only when first one is killed */ |
202 | if (!limit) { |
203 | CAP_SetCurrent(toBase, CAP_ALIENS, CAP_GetMax(toBase, CAP_ALIENS)(toBase)->capacities[(CAP_ALIENS)].max); |
204 | MS_AddNewMessage(_("Notice")gettext("Notice"), _("You don't have enough space in Alien Containment. Some aliens got killed.")gettext("You don't have enough space in Alien Containment. Some aliens got killed." )); |
205 | limit = true; |
206 | } |
207 | /* Just kill aliens which don't fit the limit. */ |
208 | ac->amountDead++; |
209 | } |
210 | } |
211 | /* only once */ |
212 | if (!messageAlreadySet) { |
213 | MS_AddNewMessage(_("Notice")gettext("Notice"), _("You've captured new aliens.")gettext("You've captured new aliens.")); |
214 | messageAlreadySet = true; |
215 | } |
216 | } |
217 | break; |
218 | } |
219 | } |
220 | } |
221 | |
222 | for (i = 0; i < ccs.numAliensTD; i++) { |
223 | aliensCont_t *ac = &toBase->alienscont[i]; |
224 | technology_t *tech = ac->tech; |
225 | #ifdef DEBUG1 |
226 | if (!tech) |
227 | Sys_Error("AL_AddAliens: Failed to initialize the tech for '%s'\n", ac->teamDef->name); |
228 | #endif |
229 | /* we need this to let RS_Collected_ return true */ |
230 | if (ac->amountAlive + ac->amountDead > 0) |
231 | RS_MarkCollected(tech); |
232 | #ifdef DEBUG1 |
233 | /* print all of them */ |
234 | if (ac->amountAlive > 0) |
235 | Com_DPrintf(DEBUG_CLIENT0x20, "AL_AddAliens alive: %s amount: %i\n", ac->teamDef->name, ac->amountAlive); |
236 | if (ac->amountDead > 0) |
237 | Com_DPrintf(DEBUG_CLIENT0x20, "AL_AddAliens bodies: %s amount: %i\n", ac->teamDef->name, ac->amountDead); |
238 | #endif |
239 | } |
240 | |
241 | /* we shouldn't have any more aliens on the aircraft after this */ |
242 | AL_SetAircraftAlienCargoTypes(aircraft, 0)(aircraft)->alienCargoTypes = (0); |
243 | } |
244 | |
245 | /** |
246 | * @brief Removes alien(s) from Alien Containment. |
247 | * @param[in,out] base Pointer to the base where we will perform action (remove, add, ... aliens). |
248 | * @param[in] alienType Type of the alien (a teamDef_t pointer) |
249 | * @param[in] amount Amount of aliens to be removed. |
250 | * @param[in] action Type of action (see alienCalcType_t). |
251 | * @sa AC_KillAll_f |
252 | * @sa AC_KillOne_f |
253 | * @note Call with NULL name when no matters what type to remove. |
254 | * @todo integrate this with research system |
255 | */ |
256 | void AL_RemoveAliens (base_t *base, const teamDef_t *alienType, int amount, const alienCalcType_t action) |
257 | { |
258 | int j, toremove; |
259 | aliensCont_t *containment; |
260 | |
261 | assert(base)(__builtin_expect(!(base), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 261, "base") : (void)0); |
262 | containment = base->alienscont; |
263 | |
264 | switch (action) { |
265 | case AL_RESEARCH: |
266 | if (!alienType) { |
267 | int maxidx = 0; |
268 | int maxamount = 0; /* amount (of alien type), which is max in Containment) */ |
269 | /* Search for the type of alien, which has max amount |
270 | * in Alien Containment, then remove (amount). */ |
271 | while (amount > 0) { |
272 | /* Find the type with maxamount. */ |
273 | for (j = 0; j < ccs.numAliensTD; j++) { |
274 | const aliensCont_t *ac = &containment[j]; |
275 | if (maxamount < ac->amountAlive) { |
276 | maxamount = ac->amountAlive; |
277 | maxidx = j; |
278 | } |
279 | } |
280 | if (maxamount == 0) { |
281 | /* That should never happen. */ |
282 | Com_Printf("AL_RemoveAliens: unable to find alive aliens\n"); |
283 | return; |
284 | } |
285 | if (maxamount == 1) { |
286 | /* If only one here, just remove. */ |
287 | AL_ChangeAliveAlienNumber(base, &containment[maxidx], -1); |
288 | containment[maxidx].amountDead++; |
289 | --amount; |
290 | } else { |
291 | /* If more than one, remove the amount. */ |
292 | toremove = maxamount - 1; |
293 | if (toremove > amount) |
294 | toremove = amount; |
295 | AL_ChangeAliveAlienNumber(base, &containment[maxidx], -toremove); |
296 | containment[maxidx].amountDead += toremove; |
297 | amount -= toremove; |
298 | } |
299 | } |
300 | } |
301 | break; |
302 | case AL_KILL: |
303 | /* We ignore 2nd and 3rd parameter of AL_RemoveAliens() here. */ |
304 | for (j = 0; j < ccs.numAliensTD; j++) { |
305 | aliensCont_t *ac = &containment[j]; |
306 | if (ac->amountAlive > 0) { |
307 | ac->amountDead += ac->amountAlive; |
308 | AL_ChangeAliveAlienNumber(base, ac, -ac->amountAlive); |
309 | } |
310 | } |
311 | break; |
312 | case AL_KILLONE: |
313 | /* We ignore 3rd parameter of AL_RemoveAliens() here. */ |
314 | for (j = 0; j < ccs.numAliensTD; j++) { |
315 | aliensCont_t *ac = &containment[j]; |
316 | assert(ac->teamDef)(__builtin_expect(!(ac->teamDef), 0) ? __assert_rtn(__func__ , "src/client/cgame/campaign/cp_aliencont.cpp", 316, "ac->teamDef" ) : (void)0); |
317 | if (ac->teamDef == alienType) { |
318 | if (ac->amountAlive == 0) |
319 | return; |
320 | /* We are killing only one here, so we |
321 | * don't care about amount param. */ |
322 | AL_ChangeAliveAlienNumber(base, ac, -1); |
323 | ac->amountDead++; |
324 | break; |
325 | } |
326 | } |
327 | break; |
328 | default: |
329 | Sys_Error("AL_RemoveAliens: Use AL_AddAliens for action %i", action); |
330 | } |
331 | } |
332 | |
333 | #ifdef DEBUG1 |
334 | /** |
335 | * @todo find a better name (or rename the other AL_AddAliens function |
336 | * @todo use this function more often - the containment[j].amountDead and containment[j].amountAlive counter |
337 | * are used all over the code |
338 | */ |
339 | static void AL_AddAliens2 (base_t *base, const teamDef_t *alienType, const bool dead) |
340 | { |
341 | int j; |
342 | aliensCont_t *containment; |
343 | |
344 | assert(base)(__builtin_expect(!(base), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 344, "base") : (void)0); |
345 | containment = base->alienscont; |
346 | |
347 | if (dead) { |
348 | for (j = 0; j < ccs.numAliensTD; j++) { |
349 | aliensCont_t *ac = &containment[j]; |
350 | assert(ac->teamDef)(__builtin_expect(!(ac->teamDef), 0) ? __assert_rtn(__func__ , "src/client/cgame/campaign/cp_aliencont.cpp", 350, "ac->teamDef" ) : (void)0); |
351 | if (ac->teamDef == alienType) { |
352 | ac->amountDead++; |
353 | break; |
354 | } |
355 | } |
356 | } else { |
357 | /* We ignore 3rd parameter of AL_RemoveAliens() here: add only 1 alien */ |
358 | if (!AL_CheckAliveFreeSpace(base, NULL__null, 1)) { |
359 | return; /* stop because we will else exceed the max of aliens */ |
360 | } |
361 | for (j = 0; j < ccs.numAliensTD; j++) { |
362 | aliensCont_t *ac = &containment[j]; |
363 | assert(ac->teamDef)(__builtin_expect(!(ac->teamDef), 0) ? __assert_rtn(__func__ , "src/client/cgame/campaign/cp_aliencont.cpp", 363, "ac->teamDef" ) : (void)0); |
364 | if (ac->teamDef == alienType) { |
365 | AL_ChangeAliveAlienNumber(base, ac, 1); |
366 | break; |
367 | } |
368 | } |
369 | } |
370 | } |
371 | #endif |
372 | |
373 | /** |
374 | * @brief Get index of alien. |
375 | * @param[in] alienType Pointer to alien type. |
376 | * @return Index of alien in alien containment (so less than @c ccs.numAliensTD) |
377 | * @note It does NOT return the global team index from @c csi.teamDef array. |
378 | * That would be @c alienType->idx |
379 | * @sa RS_AssignTechLinks |
380 | * @sa AL_GetAlienGlobalIDX |
381 | */ |
382 | static int AL_GetAlienIDX (const teamDef_t *alienType) |
383 | { |
384 | int i, index; |
385 | |
386 | index = 0; |
387 | for (i = 0; i < csi.numTeamDefs; i++) { |
388 | const teamDef_t *td = &csi.teamDef[i]; |
389 | if (alienType == td) |
390 | return index; |
391 | if (CHRSH_IsTeamDefAlien(td)) |
392 | index++; |
393 | } |
394 | |
395 | Com_Printf("AL_GetAlienIDX: Alien \"%s\" not found!\n", alienType->id); |
396 | return -1; |
397 | } |
398 | |
399 | /** |
400 | * @brief Returns teamdef for global alien idx. |
401 | * @param[in] alienTeamDefIdx Alien index |
402 | * @sa AL_GetAlienIDX |
403 | */ |
404 | const teamDef_t* AL_GetAlienTeamDef (int alienTeamDefIdx) |
405 | { |
406 | int i, counter = 0; |
407 | |
408 | for (i = 0; i < csi.numTeamDefs; i++) { |
409 | const teamDef_t *td = &csi.teamDef[i]; |
410 | if (CHRSH_IsTeamDefAlien(td)) { |
411 | if (counter == alienTeamDefIdx) |
412 | return td; |
413 | counter++; |
414 | } |
415 | } |
416 | Com_Printf("AL_GetAlienGlobalIDX: Alien with AC index %i not found!\n", alienTeamDefIdx); |
417 | return NULL__null; |
418 | } |
419 | |
420 | /** |
421 | * @brief Get amount of live aliens or alien bodies stored in Containment. |
422 | * @param[in] alienType The alien type to check for |
423 | * @param[in] base The base to count in |
424 | * @param[in] reqtype Requirement type (RS_LINK_ALIEN/RS_LINK_ALIEN_DEAD). |
425 | * @return Amount of desired alien/body. |
426 | * @sa RS_RequirementsMet |
427 | * @sa RS_CheckCollected |
428 | */ |
429 | int AL_GetAlienAmount (const teamDef_t *alienType, requirementType_t reqtype, const base_t *base) |
430 | { |
431 | const aliensCont_t *containment; |
432 | int alienTypeIndex; |
433 | |
434 | assert(alienType)(__builtin_expect(!(alienType), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 434, "alienType") : (void)0); |
435 | assert(base)(__builtin_expect(!(base), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 435, "base") : (void)0); |
436 | alienTypeIndex = AL_GetAlienIDX(alienType); |
437 | assert(alienTypeIndex >= 0)(__builtin_expect(!(alienTypeIndex >= 0), 0) ? __assert_rtn (__func__, "src/client/cgame/campaign/cp_aliencont.cpp", 437, "alienTypeIndex >= 0") : (void)0); |
438 | containment = &base->alienscont[alienTypeIndex]; |
439 | |
440 | switch (reqtype) { |
441 | case RS_LINK_ALIEN: |
442 | return containment->amountAlive; |
443 | case RS_LINK_ALIEN_DEAD: |
444 | return containment->amountDead; |
445 | default: |
446 | return containment->amountDead; |
447 | } |
448 | } |
449 | |
450 | /** |
451 | * @brief Counts live aliens in base. |
452 | * @param[in] base Pointer to the base |
453 | * @return amount of all live aliens stored in containment |
454 | * @note must not return 0 if hasBuilding[B_ALIEN_CONTAINMENT] is false: used to update capacity |
455 | * @sa AL_ChangeAliveAlienNumber |
456 | * @sa B_ResetAllStatusAndCapacities_f |
457 | */ |
458 | int AL_CountInBase (const base_t *base) |
459 | { |
460 | int j; |
461 | int amount = 0; |
462 | |
463 | assert(base)(__builtin_expect(!(base), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 463, "base") : (void)0); |
464 | |
465 | for (j = 0; j < ccs.numAliensTD; j++) { |
466 | if (base->alienscont[j].teamDef) |
467 | amount += base->alienscont[j].amountAlive; |
468 | } |
469 | |
470 | return amount; |
471 | } |
472 | |
473 | /** |
474 | * @brief Add / Remove live aliens to Alien Containment. |
475 | * @param[in] base Pointer to the base where Alien Cont. should be checked. |
476 | * @param[in] containment Pointer to the containment |
477 | * @param[in] num Number of alien to be added/removed |
478 | * @pre free space has already been checked |
479 | * @todo handle containment[j].amountDead++; in case the @c num is negative? |
480 | */ |
481 | void AL_ChangeAliveAlienNumber (base_t *base, aliensCont_t *containment, int num) |
482 | { |
483 | assert(base)(__builtin_expect(!(base), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 483, "base") : (void)0); |
484 | assert(containment)(__builtin_expect(!(containment), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp", 484, "containment" ) : (void)0); |
485 | |
486 | /* Just a sanity check -- should never be reached */ |
487 | if (!AL_CheckAliveFreeSpace(base, containment, num)) |
488 | Com_Error(ERR_DROP1, "AL_ChangeAliveAlienNumber: Can't add/remove %i live aliens, (capacity: %i/%i, Alien Containment Status: %i)\n", |
489 | num, CAP_GetCurrent(base, CAP_ALIENS)(base)->capacities[(CAP_ALIENS)].cur, CAP_GetMax(base, CAP_ALIENS)(base)->capacities[(CAP_ALIENS)].max, |
490 | B_GetBuildingStatus(base, B_ALIEN_CONTAINMENT)); |
491 | |
492 | containment->amountAlive += num; |
493 | CAP_AddCurrent(base, CAP_ALIENS, num); |
494 | |
495 | #ifdef DEBUG1 |
496 | if (CAP_GetCurrent(base, CAP_ALIENS)(base)->capacities[(CAP_ALIENS)].cur != AL_CountInBase(base)) |
497 | Com_Printf("AL_ChangeAliveAlienNumber: Wrong capacity in Alien containment: %i instead of %i\n", |
498 | CAP_GetCurrent(base, CAP_ALIENS)(base)->capacities[(CAP_ALIENS)].cur, AL_CountInBase(base)); |
499 | #endif |
500 | } |
501 | |
502 | /** |
503 | * @brief Remove aliens that exceed containment capacity |
504 | * @note called on destroying an Alien Containment (from building_ondestroy) |
505 | * @param[in, out] base Pointer to the base to check |
506 | */ |
507 | void AL_RemoveAliensExceedingCapacity (base_t *base) |
508 | { |
509 | const int max = CAP_GetMax(base, CAP_ALIENS)(base)->capacities[(CAP_ALIENS)].max; |
510 | int current = CAP_GetCurrent(base, CAP_ALIENS)(base)->capacities[(CAP_ALIENS)].cur; |
511 | int i; |
512 | |
513 | assert(base)(__builtin_expect(!(base), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 513, "base") : (void)0); |
514 | assert(max >= 0)(__builtin_expect(!(max >= 0), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp", 514, "max >= 0" ) : (void)0); |
515 | |
516 | for (i = 0; i < ccs.numAliensTD; i++) { |
517 | const int remove = std::min(base->alienscont[i].amountAlive, current - max); |
518 | |
519 | if (!base->alienscont[i].teamDef) |
520 | continue; |
521 | |
522 | /* remove dead aliens if there is no alien containment */ |
523 | if (max == 0) |
524 | base->alienscont[i].amountDead = 0; |
525 | |
526 | if (remove > 0) { |
527 | base->alienscont[i].amountAlive -= remove; |
528 | CAP_SetCurrent(base, CAP_ALIENS, current - remove); |
529 | current = CAP_GetCurrent(base, CAP_ALIENS)(base)->capacities[(CAP_ALIENS)].cur; |
530 | } |
531 | } |
532 | |
533 | assert(max >= current)(__builtin_expect(!(max >= current), 0) ? __assert_rtn(__func__ , "src/client/cgame/campaign/cp_aliencont.cpp", 533, "max >= current" ) : (void)0); |
534 | } |
535 | |
536 | /** |
537 | * @brief Check if live aliens can be added/removed to Alien Containment. |
538 | * @param[in] base Pointer to the base where Alien Cont. should be checked. |
539 | * @param[in] containment Pointer to the containment (may be @c NULL when adding |
540 | * aliens or if you don't care about alien type of alien you're removing) |
541 | * @param[in] num Number of alien to be added/removed |
542 | * @return true if action may be performed in base |
543 | */ |
544 | bool AL_CheckAliveFreeSpace (const base_t *base, const aliensCont_t *containment, const int num) |
545 | { |
546 | if (num > 0) { |
547 | /* We add aliens */ |
548 | /* you need Alien Containment and it's dependencies to handle aliens */ |
549 | if (!B_GetBuildingStatus(base, B_ALIEN_CONTAINMENT)) |
550 | return false; |
551 | if (CAP_GetFreeCapacity(base, CAP_ALIENS) < num) |
552 | return false; |
553 | } else { |
554 | /* @note don't check building status here. |
555 | * dependencies may have been destroyed before alien container (B_Destroy) */ |
556 | if (CAP_GetCurrent(base, CAP_ALIENS)(base)->capacities[(CAP_ALIENS)].cur + num < 0) |
557 | return false; |
558 | if (containment && (containment->amountAlive + num < 0)) |
559 | return false; |
560 | } |
561 | |
562 | return true; |
563 | } |
564 | |
565 | /** |
566 | * Menu functions |
567 | */ |
568 | |
569 | /** |
570 | * @brief Counts live aliens in all bases. |
571 | * @note This should be called whenever you add or remove |
572 | * @note aliens from alien containment. |
573 | * @return amount of all live aliens stored in containments |
574 | * @sa B_AircraftReturnedToHomeBase |
575 | * @sa AC_Init_f |
576 | */ |
577 | int AL_CountAll (void) |
578 | { |
579 | int amount = 0; |
580 | base_t *base = NULL__null; |
581 | |
582 | while ((base = B_GetNext(base)) != NULL__null) { |
583 | int j; |
584 | if (!B_GetBuildingStatus(base, B_ALIEN_CONTAINMENT)) |
585 | continue; |
586 | for (j = 0; j < ccs.numAliensTD; j++) { |
587 | const aliensCont_t *ac = &base->alienscont[j]; |
588 | if (ac->teamDef) |
589 | amount += ac->amountAlive; |
590 | } |
591 | } |
592 | return amount; |
593 | } |
594 | |
595 | /** |
596 | * @brief Kill all aliens in given base. |
597 | * @param[in] base The base in which you want to kill all aliens |
598 | * @sa AC_KillAll_f |
599 | */ |
600 | void AC_KillAll (base_t *base) |
601 | { |
602 | int i; |
603 | bool aliens = false; |
604 | |
605 | assert(base)(__builtin_expect(!(base), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 605, "base") : (void)0); |
606 | |
607 | /* Are there aliens here at all? */ |
608 | for (i = 0; i < ccs.numAliensTD; i++) { |
609 | if (base->alienscont[i].amountAlive > 0) { |
610 | aliens = true; |
611 | break; |
612 | } |
613 | } |
614 | |
615 | /* No aliens, return. */ |
616 | if (!aliens) |
617 | return; |
618 | |
619 | AL_RemoveAliens(base, NULL__null, 0, AL_KILL); |
620 | } |
621 | |
622 | #ifdef DEBUG1 |
623 | /** |
624 | * @brief Add a single alien of a given type. |
625 | */ |
626 | static void AC_AddOne_f (void) |
627 | { |
628 | const char *alienName; |
629 | const teamDef_t *alienType; |
630 | aliensCont_t *containment; |
631 | bool updateAlive = true; |
632 | int j; |
633 | base_t *base = B_GetCurrentSelectedBase(); |
634 | |
635 | /* Can be called from everywhere. */ |
636 | if (!base) |
637 | return; |
638 | |
639 | /* arg parsing */ |
640 | if (Cmd_Argc() < 2) { |
641 | Com_Printf("Usage: %s <alientype> [dead:true|false]\n", Cmd_Argv(0)); |
642 | return; |
643 | } |
644 | |
645 | alienName = Cmd_Argv(1); |
646 | alienType = Com_GetTeamDefinitionByID(alienName); |
647 | |
648 | if (!alienType) { |
649 | Com_Printf("AC_AddOne_f: Team definition '%s' does not exist.\n", alienName); |
650 | return; |
651 | } |
652 | |
653 | /* Check that alientType exists */ |
654 | containment = base->alienscont; |
655 | for (j = 0; j < ccs.numAliensTD; j++) { |
656 | aliensCont_t *ac = &containment[j]; |
657 | assert(ac->teamDef)(__builtin_expect(!(ac->teamDef), 0) ? __assert_rtn(__func__ , "src/client/cgame/campaign/cp_aliencont.cpp", 657, "ac->teamDef" ) : (void)0); |
658 | if (ac->teamDef == alienType) |
659 | break; |
660 | } |
661 | if (j == ccs.numAliensTD) { |
662 | Com_Printf("AC_AddOne_f: Alien Type '%s' does not exist. Available choices are:\n", alienName); |
663 | for (j = 0; j < ccs.numAliensTD; j++) |
664 | Com_Printf("\t* %s\n", containment[j].teamDef->name); |
665 | return; |
666 | } |
667 | |
668 | if (Cmd_Argc() == 3) |
669 | updateAlive = Com_ParseBoolean(Com_Argv(2)); |
670 | |
671 | /* update alien counter*/ |
672 | if (B_GetBuildingStatus(base, B_ALIEN_CONTAINMENT)) { |
673 | containment = base->alienscont; |
Value stored to 'containment' is never read | |
674 | } else { |
675 | return; |
676 | } |
677 | |
678 | /* call the function that actually changes the persistent datastructure */ |
679 | AL_AddAliens2(base, alienType, !updateAlive); |
680 | } |
681 | #endif |
682 | |
683 | /** |
684 | * @brief Defines commands and cvars for the alien containment menu(s). |
685 | * @sa UI_InitStartup |
686 | */ |
687 | void AC_InitStartup (void) |
688 | { |
689 | /* add commands */ |
690 | #ifdef DEBUG1 |
691 | Cmd_AddCommand("debug_addalientocont", AC_AddOne_f, "Add one alien of a given type"); |
692 | #endif |
693 | AC_InitCallbacks(); |
694 | } |
695 | |
696 | /** |
697 | * @brief Savecallback for saving in XML Format |
698 | * @sa AC_LoadXML |
699 | * @sa B_SaveXML |
700 | * @sa SAV_GameSaveXML |
701 | */ |
702 | bool AC_SaveXML (xmlNode_tmxml_node_t * parent) |
703 | { |
704 | xmlNode_tmxml_node_t *aliencont; |
705 | base_t *base; |
706 | |
707 | aliencont = XML_AddNode(parent, SAVE_ALIENCONT_ALIENCONT"alienCont"); |
708 | XML_AddBoolValue(aliencont, SAVE_ALIENCONT_BREATHINGMAILSENT"breathingMailSent", ccs.breathingMailSent); |
709 | |
710 | base = NULL__null; |
711 | while ((base = B_GetNext(base)) != NULL__null) { |
712 | xmlNode_tmxml_node_t *node; |
713 | int k; |
714 | |
715 | if (!AC_ContainmentAllowed(base)) |
716 | continue; |
717 | |
718 | node = XML_AddNode(aliencont, SAVE_ALIENCONT_CONT"cont"); |
719 | XML_AddInt(node, SAVE_ALIENCONT_BASEIDX"baseIDX", base->idx); |
720 | for (k = 0; k < MAX_ALIENCONT_CAP32 && k < ccs.numAliensTD; k++) { |
721 | xmlNode_tmxml_node_t * snode = XML_AddNode(node, SAVE_ALIENCONT_ALIEN"alien"); |
722 | |
723 | assert(base->alienscont)(__builtin_expect(!(base->alienscont), 0) ? __assert_rtn(__func__ , "src/client/cgame/campaign/cp_aliencont.cpp", 723, "base->alienscont" ) : (void)0); |
724 | assert(base->alienscont[k].teamDef)(__builtin_expect(!(base->alienscont[k].teamDef), 0) ? __assert_rtn (__func__, "src/client/cgame/campaign/cp_aliencont.cpp", 724, "base->alienscont[k].teamDef") : (void)0); |
725 | assert(base->alienscont[k].teamDef->id)(__builtin_expect(!(base->alienscont[k].teamDef->id), 0 ) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_aliencont.cpp" , 725, "base->alienscont[k].teamDef->id") : (void)0); |
726 | |
727 | XML_AddString(snode, SAVE_ALIENCONT_TEAMID"id", base->alienscont[k].teamDef->id); |
728 | XML_AddIntValue(snode, SAVE_ALIENCONT_AMOUNTALIVE"amountAlive", base->alienscont[k].amountAlive); |
729 | XML_AddIntValue(snode, SAVE_ALIENCONT_AMOUNTDEAD"amountDead", base->alienscont[k].amountDead); |
730 | } |
731 | } |
732 | |
733 | return true; |
734 | } |
735 | |
736 | /** |
737 | * @brief Load callback for savin in XML Format |
738 | * @sa AC_LoadXML |
739 | * @sa B_SaveXML |
740 | * @sa SAV_GameLoadXML |
741 | */ |
742 | bool AC_LoadXML (xmlNode_tmxml_node_t * parent) |
743 | { |
744 | xmlNode_tmxml_node_t *aliencont; |
745 | xmlNode_tmxml_node_t *contNode; |
746 | int i; |
747 | |
748 | aliencont = XML_GetNode(parent, SAVE_ALIENCONT_ALIENCONT"alienCont"); |
749 | ccs.breathingMailSent = XML_GetBool(aliencont, SAVE_ALIENCONT_BREATHINGMAILSENT"breathingMailSent", false); |
750 | |
751 | /* Init alienContainers */ |
752 | for (i = 0; i < MAX_BASES8; i++) { |
753 | base_t *base = B_GetBaseByIDX(i); |
754 | |
755 | AL_FillInContainment(base); |
756 | } |
757 | /* Load data */ |
758 | for (contNode = XML_GetNode(aliencont, SAVE_ALIENCONT_CONT"cont"); contNode; |
759 | contNode = XML_GetNextNode(contNode, aliencont, SAVE_ALIENCONT_CONT"cont")) { |
760 | int j = XML_GetInt(contNode, SAVE_ALIENCONT_BASEIDX"baseIDX", MAX_BASES8); |
761 | base_t *base = B_GetFoundedBaseByIDX(j); |
762 | int k; |
763 | xmlNode_tmxml_node_t *alienNode; |
764 | |
765 | if (!base) { |
766 | Com_Printf("AC_LoadXML: Invalid base idx '%i'\n", j); |
767 | continue; |
768 | } |
769 | |
770 | for (k = 0, alienNode = XML_GetNode(contNode, SAVE_ALIENCONT_ALIEN"alien"); alienNode && k < MAX_ALIENCONT_CAP32; alienNode = XML_GetNextNode(alienNode, contNode, SAVE_ALIENCONT_ALIEN"alien"), k++) { |
771 | const char *const s = XML_GetString(alienNode, SAVE_ALIENCONT_TEAMID"id"); |
772 | /* Fill Alien Containment with default values like the tech pointer. */ |
773 | base->alienscont[k].teamDef = Com_GetTeamDefinitionByID(s); |
774 | if (base->alienscont[k].teamDef) { |
775 | base->alienscont[k].amountAlive = XML_GetInt(alienNode, SAVE_ALIENCONT_AMOUNTALIVE"amountAlive", 0); |
776 | base->alienscont[k].amountDead = XML_GetInt(alienNode, SAVE_ALIENCONT_AMOUNTDEAD"amountDead", 0); |
777 | } |
778 | } |
779 | } |
780 | |
781 | return true; |
782 | } |
783 | |
784 | /** |
785 | * @brief Returns true if the current base is able to handle captured aliens |
786 | * @sa B_BaseInit_f |
787 | * @note Alien cont. must be accessible during base attack to kill aliens. |
788 | */ |
789 | bool AC_ContainmentAllowed (const base_t* base) |
790 | { |
791 | if (B_GetBuildingStatus(base, B_ALIEN_CONTAINMENT)) { |
792 | return true; |
793 | } else { |
794 | return false; |
795 | } |
796 | } |