/** * @brief Check whether ent can reaction fire at target, i.e. that it can see it and neither is dead etc. * @param[in] ent The entity that might be firing * @param[in] target The entity that might be fired at * @return @c true if 'ent' can actually fire at 'target', @c false otherwise */ static bool G_ReactionFireIsPossible (const edict_t *ent, const edict_t *target) { float actorVis; bool frustum; /* an entity can't reaction fire at itself */ if (ent == target) return false; /* Don't react in your own turn */ if (ent->team == level.activeTeam) return false; /* ent can't use RF if is in STATE_DAZED (flashbang impact) */ if (G_IsDazed(ent)) return false; if (G_IsDead(target)) return false; /* check ent has reaction fire enabled */ if (!G_IsShaken(ent) && !G_IsReaction(ent)) return false; /* check ent has weapon in RF hand */ /* @todo Should this situation even happen when G_IsReaction(ent) is true? */ if (!ACTOR_GET_INV(ent, ent->chr.RFmode.hand)) { /* print character info if this happens, for now */ gi.DPrintf("Reaction fire enabled but no weapon for hand (name=%s,hand=%i,fmIdx=%i)\n", ent->chr.name, ent->chr.RFmode.hand, ent->chr.RFmode.fmIdx); return false; } if (!G_IsVisibleForTeam(target, ent->team)) return false; /* If reaction fire is triggered by a friendly unit * and the shooter is still sane, don't shoot; * well, if the shooter isn't sane anymore... */ if (G_IsCivilian(target) || target->team == ent->team) if (!G_IsShaken(ent) || (float) ent->morale / mor_shaken->value > frand()) return false; /* check in range and visible */ if (VectorDistSqr(ent->origin, target->origin) > MAX_SPOT_DIST * MAX_SPOT_DIST) return false; frustum = G_FrustumVis(ent, target->origin); if (!frustum) return false; actorVis = G_ActorVis(ent->origin, ent, target, true); if (actorVis <= 0.2) return false; /* okay do it then */ return true; }
/** * @brief Check whether ent can reaction fire at target, i.e. that it can see it and neither is dead etc. * @param[in] ent The entity that might be firing * @param[in] target The entity that might be fired at * @return @c true if 'ent' can actually fire at 'target', @c false otherwise */ static qboolean G_ReactionFireIsPossible (const edict_t *ent, const edict_t *target) { float actorVis; qboolean frustum; /* an entity can't reaction fire at itself */ if (ent == target) return qfalse; /* Don't react in your own turn */ if (ent->team == level.activeTeam) return qfalse; /* ent can't use RF if is in STATE_DAZED (flashbang impact) */ if (G_IsDazed(ent)) return qfalse; if (G_IsDead(target)) return qfalse; /* check ent has reaction fire enabled */ if (!G_IsShaken(ent) && !G_IsReaction(ent)) return qfalse; if (!G_IsVisibleForTeam(target, ent->team)) return qfalse; /* If reaction fire is triggered by a friendly unit * and the shooter is still sane, don't shoot; * well, if the shooter isn't sane anymore... */ if (G_IsCivilian(target) || target->team == ent->team) if (!G_IsShaken(ent) || (float) ent->morale / mor_shaken->value > frand()) return qfalse; /* check in range and visible */ if (VectorDistSqr(ent->origin, target->origin) > MAX_SPOT_DIST * MAX_SPOT_DIST) return qfalse; frustum = G_FrustumVis(ent, target->origin); if (!frustum) return qfalse; actorVis = G_ActorVis(ent->origin, target, qtrue); if (actorVis <= 0.2) return qfalse; /* okay do it then */ return qtrue; }
/** * @brief Perform the reaction fire shot * @param[in] player The player this action belongs to (the human player or the ai) * @param[in] shooter The actor that is trying to shoot * @param[in] at Position to fire on. * @param[in] type What type of shot this is (left, right reaction-left etc...). * @param[in] firemode The firemode index of the ammo for the used weapon (objDef.fd[][x]) . * @return true if everything went ok (i.e. the shot(s) where fired ok), otherwise false. * @sa G_ClientShoot */ static bool G_ReactionFireShoot (const player_t *player, edict_t *shooter, const pos3_t at, shoot_types_t type, fireDefIndex_t firemode) { const int minhit = 30; shot_mock_t mock; int ff, i; /* this is the max amount of friendly units that were hit during the mock calculation */ int maxff; if (G_IsInsane(shooter)) maxff = 100; else if (G_IsRaged(shooter)) maxff = 60; else if (G_IsPaniced(shooter)) maxff = 30; else if (G_IsShaken(shooter)) maxff = 15; else maxff = 5; /* calculate the mock values - e.g. how many friendly units we would hit * when opening the reaction fire */ OBJZERO(mock); for (i = 0; i < 100; i++) if (!G_ClientShoot(player, shooter, at, type, firemode, &mock, false, 0)) break; ff = mock.friendCount + (G_IsAlien(shooter) ? 0 : mock.civilian); if (ff <= maxff && mock.enemyCount >= minhit) return G_ClientShoot(player, shooter, at, type, firemode, NULL, false, 0); return false; }
/** * @brief Check whether ent can reaction fire at target, i.e. that it can see it and neither is dead etc. * @param[in] ent The entity that might be firing * @param[in] target The entity that might be fired at * @return @c true if 'ent' can actually fire at 'target', @c false otherwise */ static bool G_ReactionFireIsPossible (Edict *ent, const Edict *target) { /* an entity can't reaction fire at itself */ if (ent == target) return false; /* Don't react in your own turn */ if (ent->team == level.activeTeam) return false; /* ent can't use RF if is in STATE_DAZED (flashbang impact) */ if (G_IsDazed(ent)) return false; if (G_IsDead(target)) return false; /* check ent has reaction fire enabled */ if (!G_IsReaction(ent)) return false; /* check ent has weapon in RF hand */ if (!ent->getHandItem(ent->chr.RFmode.getHand())) { /* print character info if this happens, for now */ gi.DPrintf("Reaction fire enabled but no weapon for hand (name=%s,entnum=%i,hand=%i,fmIdx=%i)\n", ent->chr.name, ent->number, ent->chr.RFmode.getHand(), ent->chr.RFmode.getFmIdx()); G_RemoveReaction(ent); return false; } if (!G_IsVisibleForTeam(target, ent->team)) return false; /* If reaction fire is triggered by a friendly unit * and the shooter is still sane, don't shoot; * well, if the shooter isn't sane anymore... */ if (G_IsCivilian(target) || target->team == ent->team) if (!G_IsShaken(ent) || (float) ent->morale / mor_shaken->value > frand()) return false; /* check in range and visible */ const int spotDist = G_VisCheckDist(ent); if (VectorDistSqr(ent->origin, target->origin) > spotDist * spotDist) return false; const bool frustum = G_FrustumVis(ent, target->origin); if (!frustum) return false; const float actorVis = G_ActorVis(ent->origin, ent, target, true); if (actorVis <= 0.2) return false; /* okay do it then */ return true; }
/** * @brief Changes the state of a player/soldier. * @param[in,out] player The player who controlls the actor * @param[in] ent the edict to perform the state change for * @param[in] reqState The bit-map of the requested state change * @param[in] checkaction only activate the events - network stuff is handled in the calling function * don't even use the G_ActionCheckForCurrentTeam function * @note Use checkaction true only for e.g. spawning values */ void G_ClientStateChange (const player_t* player, edict_t* ent, int reqState, bool checkaction) { /* Check if any action is possible. */ if (checkaction && !G_ActionCheckForCurrentTeam(player, ent, 0)) return; if (!reqState) return; switch (reqState) { case STATE_CROUCHED: /* Toggle between crouch/stand. */ /* Check if player has enough TUs (TU_CROUCH TUs for crouch/uncrouch). */ if (!checkaction || G_ActionCheckForCurrentTeam(player, ent, TU_CROUCH)) { if (G_IsCrouched(ent)) { if (!gi.CanActorStandHere(ent->fieldSize, ent->pos)) break; } G_ToggleCrouched(ent); G_ActorUseTU(ent, TU_CROUCH); G_ActorSetMaxs(ent); } break; case ~STATE_REACTION: /* Request to turn off reaction fire. */ if (G_IsReaction(ent)) { if (G_IsShaken(ent)) { G_ClientPrintf(player, PRINT_HUD, _("Currently shaken, won't let their guard down.")); } else { /* Turn off reaction fire. */ G_RemoveReaction(ent); G_ActorReserveTUs(ent, 0, ent->chr.reservedTus.shot, ent->chr.reservedTus.crouch); } } break; /* Request to turn on multi- or single-reaction fire mode. */ case STATE_REACTION: /* Disable reaction fire. */ G_RemoveReaction(ent); if (G_ReactionFireSettingsReserveTUs(ent)) { /* Enable requested reaction fire. */ G_SetState(ent, reqState); } break; default: gi.DPrintf("G_ClientStateChange: unknown request %i, ignoring\n", reqState); return; } /* Only activate the events - network stuff is handled in the calling function */ if (!checkaction) return; G_ClientStateChangeUpdate(ent); }