/** * @brief Build the forbidden list for the pathfinding (server side). * @param[in] team The team number if the list should be calculated from the eyes of that team. Use 0 to ignore team. * @param[in] movingActor The moving actor to build the forbidden list for. If this is an AI actor, everything other actor will be * included in the forbidden list - even the invisible ones. This is needed to ensure that they are not walking into each other * (civilians <=> aliens, aliens <=> civilians) * @sa G_MoveCalc * @sa Grid_CheckForbidden * @sa CL_BuildForbiddenList <- shares quite some code * @note This is used for pathfinding. * It is a list of where the selected unit can not move to because others are standing there already. */ static void G_BuildForbiddenList (int team, const edict_t *movingActor) { edict_t *ent = NULL; int visMask; forbiddenListLength = 0; /* team visibility */ if (team) visMask = G_TeamToVisMask(team); else visMask = TEAM_ALL; while ((ent = G_EdictsGetNextInUse(ent))) { /* Dead 2x2 unit will stop walking, too. */ if (G_IsBlockingMovementActor(ent) && (G_IsAI(movingActor) || (ent->visflags & visMask))) { forbiddenList[forbiddenListLength++] = ent->pos; forbiddenList[forbiddenListLength++] = (byte*) &ent->fieldSize; } else if (ent->type == ET_SOLID) { int j; for (j = 0; j < ent->forbiddenListSize; j++) { forbiddenList[forbiddenListLength++] = ent->forbiddenListPos[j]; forbiddenList[forbiddenListLength++] = (byte*) &ent->fieldSize; } } } if (forbiddenListLength > MAX_FORBIDDENLIST) gi.Error("G_BuildForbiddenList: list too long\n"); }
/** * @brief Let an actor fall down if e.g. the func_breakable the actor was standing on was destroyed. * @param[in,out] ent The actor that should fall down * @todo Handle cases where the grid position the actor would fall to is occupied by another actor already. */ void G_ActorFall (edict_t *ent) { edict_t* entAtPos; const int oldZ = ent->pos[2]; ent->pos[2] = gi.GridFall(gi.routingMap, ent->fieldSize, ent->pos); if (oldZ == ent->pos[2]) return; entAtPos = G_GetEdictFromPos(ent->pos, ET_NULL); if (entAtPos != NULL && (G_IsBreakable(entAtPos) || G_IsBlockingMovementActor(entAtPos))) { const int diff = oldZ - ent->pos[2]; G_TakeDamage(entAtPos, (int)(FALLING_DAMAGE_FACTOR * (float)diff)); } G_EdictCalcOrigin(ent); gi.LinkEdict(ent); G_CheckVis(ent, true); G_EventActorFall(ent); gi.EndEvents(); }
/** * @brief Checks whether the actor should stop movement * @param ent The actors edict * @param visState The visibility check state @c VIS_PERISH, @c VIS_APPEAR * @return @c true if the actor should stop movement, @c false otherwise */ static bool G_ActorShouldStopInMidMove (const edict_t *ent, int visState, dvec_t* dvtab, int max) { if (visState & VIS_STOP) return true; /* check that the appearing unit is not on a grid position the actor wanted to walk to. * this might be the case if the edict got visible in mid mode */ if (visState & VIS_APPEAR) { pos3_t pos; VectorCopy(ent->pos, pos); while (max >= 0) { int tmp = 0; const edict_t *blockEdict; PosAddDV(pos, tmp, dvtab[max]); max--; blockEdict = G_GetLivingActorFromPos(pos); if (blockEdict && G_IsBlockingMovementActor(blockEdict)) { const bool visible = G_IsVisibleForTeam(blockEdict, ent->team); if (visible) return true; } } } return false; }
void G_ActorCheckRevitalise (Edict* ent) { if (G_IsStunned(ent) && ent->STUN < ent->HP) { /* check that we could move after we stood up */ Edict* otherActor = nullptr; while ((otherActor = G_EdictsGetNextInUse(otherActor))) { if (!VectorCompare(ent->pos, otherActor->pos)) continue; if (G_IsBlockingMovementActor(otherActor)) return; } G_ActorRevitalise(ent); G_EventActorRevitalise(*ent); G_SendStats(*ent); } }