Bug Summary

File:game/g_move.cpp
Location:line 312, column 5
Description:Value stored to 'length' is never read

Annotated Source Code

1/**
2 * @file
3 */
4
5/*
6Copyright (C) 2002-2011 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "g_local.h"
26
27#define ACTOR_SPEED_NORMAL100 100
28#define ACTOR_SPEED_CROUCHED(100 / 2) (ACTOR_SPEED_NORMAL100 / 2)
29static const float FALLING_DAMAGE_FACTOR = 10.0f;
30
31/**
32 * @brief The forbidden list is a list of entity positions that are occupied by an entity.
33 * This list is checked everytime an actor wants to walk there.
34 */
35static pos_t *forbiddenList[MAX_FORBIDDENLIST(1024 * 4)];
36static int forbiddenListLength;
37
38/**
39 * @brief Build the forbidden list for the pathfinding (server side).
40 * @param[in] team The team number if the list should be calculated from the eyes of that team. Use 0 to ignore team.
41 * @param[in] movingActor The moving actor to build the forbidden list for. If this is an AI actor, everything other actor will be
42 * included in the forbidden list - even the invisible ones. This is needed to ensure that they are not walking into each other
43 * (civilians <=> aliens, aliens <=> civilians)
44 * @sa G_MoveCalc
45 * @sa Grid_CheckForbidden
46 * @sa CL_BuildForbiddenList <- shares quite some code
47 * @note This is used for pathfinding.
48 * It is a list of where the selected unit can not move to because others are standing there already.
49 */
50static void G_BuildForbiddenList (int team, const edict_t *movingActor)
51{
52 edict_t *ent = NULL__null;
53 int visMask;
54
55 forbiddenListLength = 0;
56
57 /* team visibility */
58 if (team)
59 visMask = G_TeamToVisMask(team)(1 << (team));
60 else
61 visMask = TEAM_ALL0xFFFFFFFF;
62
63 while ((ent = G_EdictsGetNextInUse(ent))) {
64 /* Dead 2x2 unit will stop walking, too. */
65 if (G_IsBlockingMovementActor(ent)(((ent)->type == ET_ACTOR && !((ent)->state &
(0x0003))) || ent->type == ET_ACTOR2x2)
&& (G_IsAI(movingActor)((game.players + ((movingActor))->pnum)->pers.ai) || (ent->visflags & visMask))) {
66 forbiddenList[forbiddenListLength++] = ent->pos;
67 forbiddenList[forbiddenListLength++] = (byte*) &ent->fieldSize;
68 } else if (ent->type == ET_SOLID) {
69 int j;
70 for (j = 0; j < ent->forbiddenListSize; j++) {
71 forbiddenList[forbiddenListLength++] = ent->forbiddenListPos[j];
72 forbiddenList[forbiddenListLength++] = (byte*) &ent->fieldSize;
73 }
74 }
75 }
76
77 if (forbiddenListLength > MAX_FORBIDDENLIST(1024 * 4))
78 gi.Error("G_BuildForbiddenList: list too long\n");
79}
80
81/**
82 * @brief Precalculates a move table for a given team and a given starting position.
83 * This will calculate a routing table for all reachable fields with the given distance
84 * from the given spot with the given actorsize
85 * @param[in] team The current team (see G_BuildForbiddenList)
86 * @param[in] from Position in the map to start the move-calculation from.
87 * @param[in] crouchingState The crouching state of the actor. 0=stand, 1=crouch
88 * @param[in] distance The distance in TUs to calculate the move for.
89 * @param[in] movingActor The actor to calculate the move for
90 * @sa G_BuildForbiddenList
91 * @sa G_MoveCalcLocal
92 */
93void G_MoveCalc (int team, const edict_t *movingActor, const pos3_t from, byte crouchingState, int distance)
94{
95 G_MoveCalcLocal(level.pathingMap, team, movingActor, from, crouchingState, distance);
96}
97
98/**
99 * @brief Same as @c G_MoveCalc, except that it uses the pathing table passed as the first param
100 * @param[in] pt the pathfinding table
101 * @param[in] team The current team (see G_BuildForbiddenList)
102 * @param[in] from Position in the map to start the move-calculation from.
103 * @param[in] crouchingState The crouching state of the actor. 0=stand, 1=crouch
104 * @param[in] distance The distance in TUs to calculate the move for.
105 * @param[in] movingActor The actor to calculate the move for
106 * @sa G_MoveCalc
107 * @sa G_BuildForbiddenList
108 */
109void G_MoveCalcLocal (pathing_t *pt, int team, const edict_t *movingActor, const pos3_t from, byte crouchingState, int distance)
110{
111 G_BuildForbiddenList(team, movingActor);
112 gi.MoveCalc(gi.routingMap, movingActor->fieldSize, pt, from, crouchingState, distance,
113 forbiddenList, forbiddenListLength);
114}
115
116/**
117 * @brief Let an actor fall down if e.g. the func_breakable the actor was standing on was destroyed.
118 * @param[in,out] ent The actor that should fall down
119 * @todo Handle cases where the grid position the actor would fall to is occupied by another actor already.
120 */
121void G_ActorFall (edict_t *ent)
122{
123 edict_t* entAtPos;
124 const int oldZ = ent->pos[2];
125
126 ent->pos[2] = gi.GridFall(gi.routingMap, ent->fieldSize, ent->pos);
127
128 if (oldZ == ent->pos[2])
129 return;
130
131 entAtPos = G_GetEdictFromPos(ent->pos, ET_NULL);
132 if (entAtPos != NULL__null && (G_IsBreakable(entAtPos)((entAtPos)->flags & 0x00000004) || G_IsBlockingMovementActor(entAtPos)(((entAtPos)->type == ET_ACTOR && !((entAtPos)->
state & (0x0003))) || entAtPos->type == ET_ACTOR2x2)
)) {
133 const int diff = oldZ - ent->pos[2];
134 G_TakeDamage(entAtPos, (int)(FALLING_DAMAGE_FACTOR * (float)diff));
135 }
136
137 G_EdictCalcOrigin(ent);
138 gi.LinkEdict(ent);
139
140 G_CheckVis(ent, true);
141
142 G_EventActorFall(ent);
143
144 gi.EndEvents();
145}
146
147/**
148 * @brief Checks whether the actor should stop movement
149 * @param ent The actors edict
150 * @param visState The visibility check state @c VIS_PERISH, @c VIS_APPEAR
151 * @return @c true if the actor should stop movement, @c false otherwise
152 */
153static bool G_ActorShouldStopInMidMove (const edict_t *ent, int visState, dvec_t* dvtab, int max)
154{
155 if (visState & VIS_STOP4)
156 return true;
157
158 /* check that the appearing unit is not on a grid position the actor wanted to walk to.
159 * this might be the case if the edict got visible in mid mode */
160 if (visState & VIS_APPEAR1) {
161 pos3_t pos;
162 VectorCopy(ent->pos, pos)((pos)[0]=(ent->pos)[0],(pos)[1]=(ent->pos)[1],(pos)[2]
=(ent->pos)[2])
;
163 while (max >= 0) {
164 int tmp = 0;
165 const edict_t *blockEdict;
166
167 PosAddDV(pos, tmp, dvtab[max])((pos)[0]+=dvecs[((dvtab[max]) >> 8)][0], (pos)[1]+=dvecs
[((dvtab[max]) >> 8)][1], (pos)[2]=((dvtab[max]) & 0x0007
), (tmp)+=dvecs[((dvtab[max]) >> 8)][3])
;
168 max--;
169 blockEdict = G_GetLivingActorFromPos(pos);
170
171 if (blockEdict && G_IsBlockingMovementActor(blockEdict)(((blockEdict)->type == ET_ACTOR && !((blockEdict)
->state & (0x0003))) || blockEdict->type == ET_ACTOR2x2
)
) {
172 const bool visible = G_IsVisibleForTeam(blockEdict, ent->team)((blockEdict)->visflags & (1 << (ent->team)));
173 if (visible)
174 return true;
175 }
176 }
177 }
178 return false;
179}
180
181/**
182 * @brief Writes a step of the move event to the net
183 * @param[in] ent Edict to move
184 * @param[in] stepAmount Pointer to the amount of steps in this move-event
185 * @param[in] dvec The direction vector for the step to be added
186 * @param[in] contentFlags The material we are walking over
187 */
188static void G_WriteStep (edict_t* ent, byte** stepAmount, const int dvec, const int contentFlags)
189{
190 /* write move header if not yet done */
191 if (gi.GetEvent() != EV_ACTOR_MOVE) {
192 gi.AddEvent(G_VisToPM(ent->visflags), EV_ACTOR_MOVE);
193 gi.WriteShort(ent->number);
194 /* stepAmount is a pointer to a location in the netchannel
195 * the value of this pointer depends on how far the actor walks
196 * and this might be influenced at a later stage inside this
197 * loop. That's why we can modify the value of this byte
198 * if e.g. a VIS_STOP occurred and no more steps should be made.
199 * But keep in mind, that no other events might be between
200 * this event and its successful end - otherwise the
201 * stepAmount pointer would no longer be valid and you would
202 * modify data in the new event. */
203 *stepAmount = gi.WriteDummyByte(0);
204 /* Add three more dummy bytes. These will be the final actor position. */
205 gi.WriteDummyByte(0); /* x */
206 gi.WriteDummyByte(0); /* y */
207 gi.WriteDummyByte(0); /* z */
208 } else if (!*stepAmount) {
209 gi.DPrintf("Event %i activate and no stepAmount pointer set\n", gi.GetEvent());
210 return;
211 }
212
213 /* the moveinfo stuff is used inside the G_PhysicsStep think function */
214 if (ent->moveinfo.steps >= MAX_DVTAB32) {
215 ent->moveinfo.steps = 0;
216 ent->moveinfo.currentStep = 0;
217 }
218 ent->moveinfo.contentFlags[ent->moveinfo.steps] = contentFlags;
219 ent->moveinfo.visflags[ent->moveinfo.steps] = ent->visflags;
220 ent->moveinfo.steps++;
221
222 /* store steps in netchannel */
223 byte *pStep = *stepAmount;
224 (*pStep)++;
225 /* store the position too */
226 *(pStep + 1) = ent->pos[0];
227 *(pStep + 2) = ent->pos[1];
228 *(pStep + 3) = ent->pos[2];
229
230 /* write move header and always one step after another - because the next step
231 * might already be the last one due to some stop event */
232 gi.WriteShort(dvec);
233 gi.WriteShort(ent->speed);
234 gi.WriteShort(contentFlags);
235}
236
237static int G_FillDirectionTable (dvec_t *dvtab, size_t size, byte crouchingState, pos3_t pos)
238{
239 int dvec;
240 int numdv = 0;
241 while ((dvec = gi.MoveNext(level.pathingMap, pos, crouchingState))
242 != ROUTING_UNREACHABLE-1) {
243 const int oldZ = pos[2];
244 /* dvec indicates the direction traveled to get to the new cell and the original cell height. */
245 /* We are going backwards to the origin. */
246 PosSubDV(pos, crouchingState, dvec)((pos)[0]-=dvecs[((dvec) >> 8)][0], (pos)[1]-=dvecs[((dvec
) >> 8)][1], (pos)[2]=((dvec) & 0x0007), (crouchingState
)-=dvecs[((dvec) >> 8)][3])
;
247 /* Replace the z portion of the DV value so we can get back to where we were. */
248 dvtab[numdv++] = setDVz(dvec, oldZ)(((dvec) & (~0x0007)) | ((oldZ) & 0x0007));
249 if (numdv >= size)
250 break;
251 }
252
253 return numdv;
254}
255
256/**
257 * @brief Generates the client events that are send over the netchannel to move an actor
258 * @param[in] player Player who is moving an actor
259 * @param[in] visTeam The team to check the visibility for - if this is 0 we build the forbidden list
260 * above all edicts - for the human controlled actors this would mean that clicking to a grid
261 * position that is not reachable because an invisible actor is standing there would not result in
262 * a single step - as the movement is aborted before. For AI movement this is in general @c 0 - but
263 * not if they e.g. hide.
264 * @param[in] ent Edict to move
265 * @param[in] to The grid position to walk to
266 * @sa CL_ActorStartMove
267 * @sa PA_MOVE
268 */
269void G_ClientMove (const player_t * player, int visTeam, edict_t* ent, const pos3_t to)
270{
271 int status, initTU;
272 dvec_t dvtab[MAX_DVTAB32];
273 int dir;
274 byte numdv, length;
275 pos3_t pos;
276 float div;
277 int oldState;
278 int oldHP;
279 bool autoCrouchRequired = false;
280 byte crouchingState;
281
282 if (VectorCompare(ent->pos, to)((ent->pos)[0]==(to)[0]?(ent->pos)[1]==(to)[1]?(ent->
pos)[2]==(to)[2]?1:0:0:0)
)
283 return;
284
285 /* check if action is possible */
286 if (!G_ActionCheckForCurrentTeam(player, ent, TU_MOVE_STRAIGHT2))
287 return;
288
289 crouchingState = G_IsCrouched(ent)((ent)->state & (0x0004)) ? 1 : 0;
290 oldState = oldHP = 0;
291
292 /* calculate move table */
293 G_MoveCalc(visTeam, ent, ent->pos, crouchingState, ent->TU);
294 length = gi.MoveLength(level.pathingMap, to, crouchingState, false);
295
296 /* length of ROUTING_NOT_REACHABLE means not reachable */
297 if (length && length >= ROUTING_NOT_REACHABLE0xFF)
298 return;
299
300 /* Autostand: check if the actor is crouched and player wants autostanding...*/
301 if (crouchingState && player->autostand) {
302 /* ...and if this is a long walk... */
303 if (SHOULD_USE_AUTOSTAND(length)((float) (2.0f * 3) * 1.5 / (1.5 - 1.0f) < (float) (length
))
) {
304 /* ...make them stand first. If the player really wants them to walk a long
305 * way crouched, he can move the actor in several stages.
306 * Uses the threshold at which standing, moving and crouching again takes
307 * fewer TU than just crawling while crouched. */
308 G_ClientStateChange(player, ent, STATE_CROUCHED0x0004, true); /* change to stand state */
309 crouchingState = G_IsCrouched(ent)((ent)->state & (0x0004)) ? 1 : 0;
310 if (!crouchingState) {
311 G_MoveCalc(visTeam, ent, ent->pos, crouchingState, ent->TU);
312 length = gi.MoveLength(level.pathingMap, to, crouchingState, false);
Value stored to 'length' is never read
313 autoCrouchRequired = true;
314 }
315 }
316 }
317
318 /* this let the footstep sounds play even over network */
319 ent->think = G_PhysicsStep;
320 ent->nextthink = level.time;
321
322 /* assemble dvec-encoded move data */
323 VectorCopy(to, pos)((pos)[0]=(to)[0],(pos)[1]=(to)[1],(pos)[2]=(to)[2]);
324 initTU = ent->TU;
325
326 numdv = G_FillDirectionTable(dvtab, lengthof(dvtab)(sizeof(dvtab) / sizeof(*(dvtab))), crouchingState, pos);
327
328 /* make sure to end any other pending events - we rely on EV_ACTOR_MOVE not being active anymore */
329 gi.EndEvents();
330
331 /* everything ok, found valid route? */
332 if (VectorCompare(pos, ent->pos)((pos)[0]==(ent->pos)[0]?(pos)[1]==(ent->pos)[1]?(pos)[
2]==(ent->pos)[2]?1:0:0:0)
) {
333 byte* stepAmount = NULL__null;
334 int usedTUs = 0;
335 /* no floor inventory at this point */
336 FLOOR(ent)(((ent)->chr.i.c[(gi.csi->idFloor)])) = NULL__null;
337
338 while (numdv > 0) {
339 /* A flag to see if we needed to change crouch state */
340 int crouchFlag;
341 const byte oldDir = ent->dir;
342 int dvec;
343
344 /* get next dvec */
345 numdv--;
346 dvec = dvtab[numdv];
347 /* This is the direction to make the step into */
348 dir = getDVdir(dvec)((dvec) >> 8);
349
350 /* turn around first */
351 status = G_ActorDoTurn(ent, dir);
352 if (status & VIS_STOP4) {
353 autoCrouchRequired = false;
354 if (ent->moveinfo.steps == 0)
355 usedTUs += TU_TURN1;
356 break;
357 }
358
359 if (G_ActorShouldStopInMidMove(ent, status, dvtab, numdv)) {
360 /* don't autocrouch if new enemy becomes visible */
361 autoCrouchRequired = false;
362 /* if something appears on our route that didn't trigger a VIS_STOP, we have to
363 * send the turn event if this is our first step */
364 if (oldDir != ent->dir && ent->moveinfo.steps == 0) {
365 G_EventActorTurn(ent);
366 usedTUs += TU_TURN1;
367 }
368 break;
369 }
370
371 /* decrease TUs */
372 div = gi.GetTUsForDirection(dir, G_IsCrouched(ent)((ent)->state & (0x0004)));
373 if ((int) (usedTUs + div) > ent->TU)
374 break;
375 usedTUs += div;
376
377 /* This is now a flag to indicate a change in crouching - we need this for
378 * the stop in mid move call(s), because we need the updated entity position */
379 crouchFlag = 0;
380 /* Calculate the new position after the decrease in TUs, otherwise the game
381 * remembers the false position if the time runs out */
382 PosAddDV(ent->pos, crouchFlag, dvec)((ent->pos)[0]+=dvecs[((dvec) >> 8)][0], (ent->pos
)[1]+=dvecs[((dvec) >> 8)][1], (ent->pos)[2]=((dvec)
& 0x0007), (crouchFlag)+=dvecs[((dvec) >> 8)][3])
;
383
384 /* slower if crouched */
385 if (G_IsCrouched(ent)((ent)->state & (0x0004)))
386 ent->speed = ACTOR_SPEED_CROUCHED(100 / 2);
387 else
388 ent->speed = ACTOR_SPEED_NORMAL100;
389 ent->speed *= g_actorspeed->value;
390
391 if (crouchFlag == 0) { /* No change in crouch */
392 edict_t* clientAction;
393 int contentFlags;
394 vec3_t pointTrace;
395
396 G_EdictCalcOrigin(ent);
397 VectorCopy(ent->origin, pointTrace)((pointTrace)[0]=(ent->origin)[0],(pointTrace)[1]=(ent->
origin)[1],(pointTrace)[2]=(ent->origin)[2])
;
398 pointTrace[2] += PLAYER_MIN-24;
399
400 contentFlags = gi.PointContents(pointTrace);
401
402 /* link it at new position - this must be done for every edict
403 * movement - to let the server know about it. */
404 gi.LinkEdict(ent);
405
406 /* Only the PHALANX team has these stats right now. */
407 if (ent->chr.scoreMission) {
408 float truediv = gi.GetTUsForDirection(dir, 0); /* regardless of crouching ! */
409 if (G_IsCrouched(ent)((ent)->state & (0x0004)))
410 ent->chr.scoreMission->movedCrouched += truediv;
411 else
412 ent->chr.scoreMission->movedNormal += truediv;
413 }
414 /* write the step to the net */
415 G_WriteStep(ent, &stepAmount, dvec, contentFlags);
416
417 /* check if player appears/perishes, seen from other teams */
418 G_CheckVis(ent, true);
419
420 /* check for anything appearing, seen by "the moving one" */
421 status = G_CheckVisTeamAll(ent->team, false, ent);
422
423 /* Set ent->TU because the reaction code relies on ent->TU being accurate. */
424 G_ActorSetTU(ent, initTU - usedTUs);
425
426 clientAction = ent->clientAction;
427 oldState = ent->state;
428 oldHP = ent->HP;
429 /* check triggers at new position */
430 if (G_TouchTriggers(ent)) {
431 if (!clientAction)
432 status |= VIS_STOP4;
433 }
434
435 G_TouchSolids(ent, 10.0f);
436
437 /* state has changed - maybe we walked on a trigger_hurt */
438 if (oldState != ent->state)
439 status |= VIS_STOP4;
440 else if (oldHP != ent->HP)
441 status |= VIS_STOP4;
442 } else if (crouchFlag == 1) {
443 /* Actor is standing */
444 G_ClientStateChange(player, ent, STATE_CROUCHED0x0004, true);
445 } else if (crouchFlag == -1) {
446 /* Actor is crouching and should stand up */
447 G_ClientStateChange(player, ent, STATE_CROUCHED0x0004, false);
448 }
449
450 /* check for reaction fire */
451 if (G_ReactionFireOnMovement(ent)) {
452 status |= VIS_STOP4;
453
454 autoCrouchRequired = false;
455 }
456
457 /* check for death */
458 if (((oldHP != 0 && oldHP != ent->HP) || (oldState != ent->state)) && !G_IsDazed(ent)((ent)->state & (0x0080))) {
459 /** @todo Handle dazed via trigger_hurt */
460 /* maybe this was due to rf - then the G_ActorDie was already called */
461 if (!G_IsDead(ent)((ent)->state & (0x0003))) {
462 G_CheckDeathOrKnockout(ent, NULL__null, NULL__null, oldHP - ent->HP);
463 }
464 return;
465 }
466
467 if (G_ActorShouldStopInMidMove(ent, status, dvtab, numdv - 1)) {
468 /* don't autocrouch if new enemy becomes visible */
469 autoCrouchRequired = false;
470 break;
471 }
472
473 /* Restore ent->TU because the movement code relies on it not being modified! */
474 G_ActorSetTU(ent, initTU);
475 }
476
477 /* submit the TUs / round down */
478 if (g_notu != NULL__null && g_notu->integer)
479 G_ActorSetTU(ent, initTU);
480 else
481 G_ActorSetTU(ent, initTU - usedTUs);
482
483 G_SendStats(ent);
484
485 /* end the move */
486 G_GetFloorItems(ent);
487 gi.EndEvents();
488 }
489
490 if (autoCrouchRequired) {
491 /* toggle back to crouched state */
492 G_ClientStateChange(player, ent, STATE_CROUCHED0x0004, true);
493 }
494}