/** * @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 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); }
/** * @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 Updates the reaction fire settings in case something was moved into a hand or from a hand * that would make the current settings invalid * @param[in,out] ent The actor edict to check the settings for * @param[in] fmIdx The fire mode index that should be used for reaction fire * @param[in] hand The hand that should be used for reaction fire * @param[in] od The object/weapon for the reaction fire */ void G_ReactionFireSettingsUpdate (Edict *ent, fireDefIndex_t fmIdx, actorHands_t hand, const objDef_t *od) { ent->chr.RFmode.set(hand, fmIdx, od); /* FiremodeSettings */ if (!G_ActorHasWorkingFireModeSet(ent)) { /* Disable reaction fire if no valid firemode was found. */ G_ClientStateChange(ent->getPlayer(), ent, ~STATE_REACTION, true); return; } G_EventReactionFireChange(*ent); /* If reaction fire is active, update the reserved TUs */ if (G_IsReaction(ent)) { G_ReactionFireSettingsReserveTUs(ent); } }
/** * @brief Updates the reaction fire settings in case something was moved into a hand or from a hand * that would make the current settings invalid * @param[in,out] ent The actor edict to check the settings for * @param[in] fmIdx The fire mode index that should be used for reaction fire * @param[in] hand The hand that should be used for reaction fire * @param[in] od The object/weapon for the reaction fire */ void G_ReactionFireUpdate (edict_t *ent, fireDefIndex_t fmIdx, actorHands_t hand, const objDef_t *od) { chrFiremodeSettings_t *fm = &ent->chr.RFmode; fm->fmIdx = fmIdx; fm->hand = hand; fm->weapon = od; if (!G_ActorHasWorkingFireModeSet(ent)) { /* Disable reaction fire if no valid firemode was found. */ G_ClientStateChange(G_PLAYER_FROM_ENT(ent), ent, ~STATE_REACTION, true); return; } G_EventReactionFireChange(ent); /* If reaction fire is active, update the reserved TUs */ if (G_IsReaction(ent)) { G_ReactionFireSettingsReserveTUs(ent); } }
/** * @brief Sets the actor's reaction fire mode. */ static int AIL_reactionfire (lua_State *L) { int reactionState = 0; if (lua_gettop(L) > 0) { if (lua_isstring(L, 1)) { /* get reaction fire mode */ const char* cmd = lua_tostring(L, 1); reactionState = Q_streq(cmd, "disable") ? ~STATE_REACTION : STATE_REACTION; } if (reactionState && lua_gettop(L) > 1 && lua_isboolean(L, 2)) { const int state = lua_toboolean(L, 2); G_ClientStateChange(AIL_player, AIL_ent, reactionState, (state) ? true : false); } else { AIL_invalidparameter(reactionState ? 2 : 1); } } lua_pushboolean(L, G_IsReaction(AIL_ent)); return 1; }