1 /**
2  * @file
3  * @brief Reaction fire code
4  *
5  * Note that in a turn-based game, reaction fire is a design bug in the first place,
6  * causing several logic problems. But we want it and we need it, so we'll have to
7  * work around those problems.
8  *
9  * Imagine the following situations:
10  * One of your soldiers is standing next to a house by a street. There is an alien down
11  * the street with a gun in snap shot mode (8 TUs). The soldier steps out on street, trying
12  * to cross it (and entering the line of sight of that alien). After 4 more paces or spending
13  * 8 TUs, your soldier is shot by the alien. Sounds reasonable? Fine. That's the basic idea
14  * of reaction fire.
15  *
16  * Now assume you have 5 soldiers next to that house. They all step out on the street. Nothing
17  * happens because they all just entered the line of sight of the alien. The first soldier
18  * starts walking and gets shot after 4 paces like above. The second soldier will walk 7 paces
19  * unharmed and get shot after 8 paces and the third soldier will be shot after 12 paces/24 TUs.
20  * This is because when the alien shoots at one target, all his other targets will receive a
21  * bonus equal to the amount of TUs the alien used for his shot. Still sounds reasonable? Fine.
22  *
23  * A slight modification: only one of the 5 soldiers steps out and gets shot after 4 paces.
24  * Then the 2nd steps out and gets shot after 4 paces as well. Likewise the 3rd soldier.
25  * That's because the soldiers hidden behind the house are not among the targets of the alien
26  * and thus don't receive the bonus when the alien shoots,
27  *
28  * There is also a problem at end of turn. Imagine your sniper is set to react with an aimed
29  * shot (18 Tus). An alien steps into his line of sight and fires two snap shots, totaling
30  * 16 TUs. Then the alien decides to do nothing for the rest of his round. You would love to
31  * see your sniper do his aimed shot, right ? But reaction fire rules don't allow that.
32  * On the other hand: if you (were stupid enough to) move one of your soldiers with his last
33  * 2 TUs out from cover and into the sight of an alien on RF with all his TUs still available,
34  * your soldier will receive no RF, due to the same RF rules. You love that, right ?
35  *
36  * Reaction fire is involved in the following situations:
37  * 1. G_ReactionFireOnMovement()
38  *		calls	G_ReactionFireCheckExecution()
39  *				calls	G_ReactionFireTryToShoot()
40  *		calls	G_ReactionFireTargetsUpdateAll()
41  * 2. G_ClientShoot()
42  *		calls	G_ReactionFirePreShot()
43  *				calls	G_ReactionFireTargetsUpdateAll()
44  *				calls	G_ReactionFireTryToShoot()
45  *		calls	G_ReactionFirePostShot()
46  *				calls	G_ReactionFireCheckExecution()
47  *						calls	G_ReactionFireTryToShoot()
48  * 3. G_ClientEndRound()
49  *		calls	G_ReactionFireOnEndTurn()
50  *				calls	G_ReactionFireTryToShoot()
51  *		calls	G_ReactionFireReset()
52  */
53 
54 /*
55 Copyright (C) 2002-2013 UFO: Alien Invasion.
56 
57 This program is free software; you can redistribute it and/or
58 modify it under the terms of the GNU General Public License
59 as published by the Free Software Foundation; either version 2
60 of the License, or (at your option) any later version.
61 
62 This program is distributed in the hope that it will be useful,
63 but WITHOUT ANY WARRANTY; without even the implied warranty of
64 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
65 
66 See the GNU General Public License for more details.
67 
68 You should have received a copy of the GNU General Public License
69 along with this program; if not, write to the Free Software
70 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
71 
72 */
73 
74 #include "g_reaction.h"
75 #include "g_actor.h"
76 #include "g_client.h"
77 #include "g_combat.h"
78 #include "g_edicts.h"
79 #include "g_match.h"
80 #include "g_vis.h"
81 
82 #define MAX_RF_TARGETS 10
83 #define MAX_RF_DATA 128
84 
85 #define DEBUG_RF 0
86 
87 /** @brief A single relation between a shooter and his target. */
88 class ReactionFireTarget
89 {
90 public:
91 	Edict const *target;
92 	int triggerTUs;		/* the amount of TUS of the target(!) at which the reaction takes place */
93 };
94 
95 #define RF_NO_ENTNUM -1
96 
97 /** @brief A list of relations between a shooter and all his targets. */
98 class ReactionFireTargetList
99 {
100 public:
101 	int entnum;
102 	int count;
103 	ReactionFireTarget targets[MAX_RF_TARGETS];
104 
ReactionFireTargetList()105 	ReactionFireTargetList () {
106 		init();
107 	}
108 
init(void)109 	inline void init (void) {
110 		entnum = RF_NO_ENTNUM;
111 		count = 0;
112 	}
113 
reset(void)114 	inline void reset (void) {
115 		count = 0;
116 	}
117 };
118 
119 /** @brief A table with all the relations between all shooters and all their targets. */
120 class ReactionFireTargets
121 {
122 public:
123 	void init();
124 	void add(const Edict* shooter, const Edict* target, const int tusForShot);
125 	void remove(const Edict* shooter, const Edict* target);
126 	bool hasExpired(const Edict* shooter, const Edict* target, const int tusTarget);
127 	int getTriggerTUs(const Edict* shooter, const Edict* target);
128 	void advance(const Edict* shooter, const int tusShot);
129 	void reset();
130 	void notifyClientMove(const Edict* target, int step, bool startMove);
131 	void notifyClientOnStep(const Edict* target, int step);
132 	void create(const Edict* shooter);
133 	void resetTargetList(const Edict* shooter);
134 	void notifyClientOnShot(const Edict* target, int step);
135 
136 private:
137 	ReactionFireTargetList rfData[MAX_RF_DATA];
138 	ReactionFireTargetList* find (const Edict* shooter);
139 };
140 
141 static ReactionFireTargets rft;
142 
143 /**
144  * @brief Initialize the reaction fire table for all entities.
145  */
init(void)146 void ReactionFireTargets::init (void)
147 {
148 	for (int i = 0; i < MAX_RF_DATA; i++) {
149 		rfData[i].init();
150 	}
151 }
152 
153 /**
154  * @brief Reset the target count in the reaction fire table for all entities.
155  */
reset(void)156 void ReactionFireTargets::reset (void)
157 {
158 	for (int i = 0; i < MAX_RF_DATA; i++) {
159 		rfData[i].reset();
160 	}
161 }
162 
notifyClientOnStep(const Edict * target,int step)163 void ReactionFireTargets::notifyClientOnStep (const Edict* target, int step)
164 {
165 	for (int i = 0; i < MAX_RF_DATA; i++) {
166 		ReactionFireTargetList *rfts = &rfData[i];
167 		if (rfts->entnum == RF_NO_ENTNUM)
168 			continue;
169 		const Edict* shooter = G_EdictsGetByNum(rfts->entnum);
170 		for (int j = 0; j < rfts->count; j++) {
171 			ReactionFireTarget& t = rfts->targets[j];
172 			if (t.target != target)
173 				continue;
174 			const int tus = std::max(0, target->TU - t.triggerTUs);
175 			G_EventReactionFireTargetUpdate(*shooter, *target, tus, step);
176 		}
177 	}
178 }
179 
notifyClientOnShot(const Edict * target,int tusTarget)180 void ReactionFireTargets::notifyClientOnShot (const Edict* target, int tusTarget)
181 {
182 	for (int i = 0; i < MAX_RF_DATA; i++) {
183 		ReactionFireTargetList* rfts = &rfData[i];
184 		if (rfts->entnum == RF_NO_ENTNUM)
185 			continue;
186 		const Edict* shooter = G_EdictsGetByNum(rfts->entnum);
187 		for (int j = 0; j < rfts->count; j++) {
188 			ReactionFireTarget& t = rfts->targets[j];
189 			if (t.target != target)
190 				continue;
191 			const int tus = std::max(0, target->TU - tusTarget - t.triggerTUs);
192 			G_EventReactionFireTargetUpdate(*shooter, *target, tus, MAX_ROUTE);
193 		}
194 	}
195 }
196 
notifyClientMove(const Edict * target,int step,bool startMove)197 void ReactionFireTargets::notifyClientMove (const Edict* target, int step, bool startMove)
198 {
199 	for (int i = 0; i < MAX_RF_DATA; i++) {
200 		ReactionFireTargetList *rfts = &rfData[i];
201 		if (rfts->entnum == RF_NO_ENTNUM)
202 			continue;
203 		const Edict* shooter = G_EdictsGetByNum(rfts->entnum);
204 		for (int j = 0; j < rfts->count; j++) {
205 			if (rfts->targets[j].target != target)
206 				continue;
207 			if (startMove) {
208 				const int tus = target->TU - rfts->targets[j].triggerTUs;
209 				G_EventReactionFireAddTarget(*shooter, *target, tus, step);
210 			} else {
211 				G_EventReactionFireRemoveTarget(*shooter, *target, step);
212 			}
213 		}
214 	}
215 }
216 
217 /**
218  * @brief Find the given edict's table of reaction fire targets.
219  * @param[in] shooter The reaction firing actor
220  */
find(const Edict * shooter)221 ReactionFireTargetList* ReactionFireTargets::find (const Edict* shooter)
222 {
223 	for (int i = 0; i < MAX_RF_DATA; i++) {
224 		ReactionFireTargetList *rfts = &rfData[i];
225 		if (rfts->entnum == shooter->number) {
226 			return rfts;
227 		}
228 	}
229 	return nullptr;
230 }
231 
232 
233 /**
234  * @brief Create a table of reaction fire targets for the given edict.
235  * @param[in] shooter The reaction firing actor
236  */
create(const Edict * shooter)237 void ReactionFireTargets::create (const Edict* shooter)
238 {
239 	ReactionFireTargetList *rfts = find(shooter);
240 
241 	if (rfts)
242 		gi.Error("Entity already has rfData");
243 
244 	for (int i = 0; i < MAX_RF_DATA; i++) {
245 		ReactionFireTargetList& data = rfData[i];
246 		if (data.entnum != RF_NO_ENTNUM)
247 			continue;
248 		data.entnum = shooter->number;
249 		return;
250 	}
251 
252 	gi.Error("Not enough rfData");
253 }
254 
255 /**
256  * @brief Add a reaction fire target for the given shooter.
257  * @param[in] shooter The reaction firing actor
258  * @param[in] target The potential reaction fire victim
259  * @param[in] tusForShot The TUs needed for the shot
260  */
add(const Edict * shooter,const Edict * target,const int tusForShot)261 void ReactionFireTargets::add (const Edict* shooter, const Edict* target, const int tusForShot)
262 {
263 	int i;
264 	ReactionFireTargetList *rfts = find(shooter);
265 
266 	assert(rfts);
267 	assert(target);
268 
269 	for (i = 0; i < rfts->count; i++) {
270 		/* check if shooter already knows that target */
271 		if (rfts->targets[i].target == target)
272 			return;
273 	}
274 	if (i >= MAX_RF_TARGETS)
275 		return;
276 	rfts->targets[i].target = target;
277 	rfts->targets[i].triggerTUs = target->TU - tusForShot;
278 	rfts->count++;
279 	G_EventReactionFireAddTarget(*shooter, *target, tusForShot, target->moveinfo.steps - 1);
280 #if DEBUG_RF
281 	if (!(G_IsAlien(shooter) || G_IsCivilian(shooter)))
282 		Com_Printf("S%i: added\n", shooter->number);
283 #endif
284 }
285 
286 /**
287  * @brief Remove a reaction fire target for the given shooter.
288  * @param[in] shooter The reaction firing actor
289  * @param[in] target The potential reaction fire victim
290  */
remove(const Edict * shooter,const Edict * target)291 void ReactionFireTargets::remove (const Edict* shooter, const Edict* target)
292 {
293 	ReactionFireTargetList *rfts = find(shooter);
294 
295 	assert(rfts);
296 	assert(target);
297 
298 	for (int i = 0; i < rfts->count; i++) {
299 		ReactionFireTarget &t = rfts->targets[i];
300 		if (t.target != target)
301 			continue;
302 
303 		/* not the last one? */
304 		if (i != rfts->count - 1) {
305 			t.target = rfts->targets[rfts->count - 1].target;
306 			t.triggerTUs = rfts->targets[rfts->count - 1].triggerTUs;
307 		}
308 		rfts->count--;
309 		G_EventReactionFireRemoveTarget(*shooter, *target, target->moveinfo.steps - 1);
310 #if DEBUG_RF
311 		if (!(G_IsAlien(shooter) || G_IsCivilian(shooter)))
312 			Com_Printf("S%i: removed\n", shooter->number);
313 #endif
314 	}
315 }
316 
resetTargetList(const Edict * shooter)317 void ReactionFireTargets::resetTargetList (const Edict* shooter)
318 {
319 	ReactionFireTargetList* rfts = find(shooter);
320 	for (int i = rfts->count - 1; i >= 0; --i)
321 		remove(shooter, rfts->targets[i].target);
322 
323 	rfts->reset();
324 }
325 
326 /**
327  * @brief Check if the given shooter is ready to reaction fire at the given target.
328  * @param[in] shooter The reaction firing actor
329  * @param[in] target The potential reaction fire victim
330  * @return The TUs the target will need to reach until the RF shot goes off.
331  */
getTriggerTUs(const Edict * shooter,const Edict * target)332 int ReactionFireTargets::getTriggerTUs (const Edict* shooter, const Edict* target)
333 {
334 	const ReactionFireTargetList *rfts = find(shooter);
335 
336 	if (!rfts)
337 		return -2;	/* the shooter doesn't aim at anything */
338 
339 	assert(target);
340 
341 	for (int i = 0; i < rfts->count; i++) {
342 		const ReactionFireTarget &t = rfts->targets[i];
343 		if (t.target == target)
344 			return t.triggerTUs;
345 	}
346 
347 	return -1;	/* the shooter doesn't aim at this target */
348 }
349 
350 
351 /**
352  * @brief Check if the given shooter is ready to reaction fire at the given target.
353  * @param[in] shooter The reaction firing actor
354  * @param[in] target The potential reaction fire victim
355  * @param[in] tusTarget The TUs the target will need for the shot, 0 for just moving
356  */
hasExpired(const Edict * shooter,const Edict * target,const int tusTarget)357 bool ReactionFireTargets::hasExpired (const Edict* shooter, const Edict* target, const int tusTarget)
358 {
359 	const ReactionFireTargetList *rfts = find(shooter);
360 
361 	if (!rfts)
362 		return false;	/* the shooter doesn't aim at anything */
363 
364 	assert(target);
365 
366 	for (int i = 0; i < rfts->count; i++) {
367 		const ReactionFireTarget &t = rfts->targets[i];
368 		if (t.target == target)
369 			return t.triggerTUs >= target->TU - tusTarget;
370 	}
371 
372 	return false;	/* the shooter doesn't aim at this target */
373 }
374 
375 
376 /**
377  * @brief Increase the triggertime for the next RF shot for all targets of the shooter (after a reaction fire).
378  * @param[in] shooter The reaction firing actor
379  * @param[in] tusShot The TUs the shooter will need for the next shot
380  */
advance(const Edict * shooter,const int tusShot)381 void ReactionFireTargets::advance (const Edict* shooter, const int tusShot)
382 {
383 	ReactionFireTargetList *rfts = find(shooter);
384 	assert(rfts);
385 
386 	for (int i = 0; i < rfts->count; i++) {
387 		ReactionFireTarget &t = rfts->targets[i];
388 		t.triggerTUs -= tusShot;
389 	}
390 }
391 
392 /**
393  * @brief free function to initialize the reaction fire table for all entities.
394  */
G_ReactionFireTargetsInit(void)395 void G_ReactionFireTargetsInit (void)
396 {
397 	rft.init();
398 }
399 
400 /**
401  * @brief free function to create a table of reaction fire targets for the given edict.
402  * @param[in] shooter The reaction firing actor
403  */
G_ReactionFireTargetsCreate(const Edict * shooter)404 void G_ReactionFireTargetsCreate (const Edict* shooter)
405 {
406 	rft.create(shooter);
407 }
408 
409 class ReactionFire
410 {
411 private:
412 	bool isEnemy(const Edict* shooter, const Edict* target) const;
413 	bool canReact(Edict* shooter, const Edict* target) const;
414 	bool canSee(const Edict* shooter, const Edict* target) const;
415 	bool shoot(Edict* shooter, const pos3_t at, shoot_types_t type, fireDefIndex_t firemode);
416 	bool isPossible(Edict* shooter, const Edict* target) const;
417 public:
418 	void notifyClientOnStep(const Edict* target, int step);
419 	bool checkExecution(const Edict* target);
420 	void updateAllTargets(const Edict* target);
421 	bool tryToShoot(Edict* shooter, const Edict* target);
422 	bool isInWeaponRange(const Edict* shooter, const Edict* target, const fireDef_t* fd) const;
423 	const fireDef_t* getFireDef(const Edict* shooter) const;
424 	void resetTargets(const Edict* shooter);
425 	void notifyClientOnShot(const Edict* target, int tusTarget);
426 };
427 static ReactionFire rf;
428 
429 /**
430  * @brief Get the fireDef for the RF settings of the shooter.
431  * @param[in] shooter The reaction firing actor
432  * @return nullptr if something is wrong
433  */
getFireDef(const Edict * shooter) const434 const fireDef_t* ReactionFire::getFireDef (const Edict* shooter) const
435 {
436 	const FiremodeSettings *fmSetting = &shooter->chr.RFmode;
437 	if (!fmSetting->isSaneFiremode())
438 		return nullptr;
439 
440 	const Item* weapon = shooter->getHandItem(fmSetting->getHand());
441 
442 	if (weapon && weapon->ammoDef() && weapon->isWeapon() && !weapon->mustReload()) {
443 		const fireDef_t* fdArray = weapon->getFiredefs();
444 		if (fdArray == nullptr)
445 			return nullptr;
446 
447 		const fireDefIndex_t fmIdx = fmSetting->getFmIdx();
448 		return &fdArray[fmIdx];
449 	}
450 	return nullptr;
451 }
452 
isInWeaponRange(const Edict * shooter,const Edict * target,const fireDef_t * fd) const453 bool ReactionFire::isInWeaponRange (const Edict* shooter, const Edict* target, const fireDef_t* fd) const
454 {
455 	assert(fd);
456 	return fd->range >= VectorDist(shooter->origin, target->origin);
457 }
458 
459 /**
460  * @brief Get the weapon firing TUs of the item in the hand of the shooter.
461  * @return -1 if no firedef was found for the item or the reaction fire mode is not activated.
462  * @param[in] shooter The reaction firing actor
463  * @param[in] target The target to check reaction fire for (e.g. check whether the weapon that was marked for
464  * using in reaction fire situations can handle the distance between the shooter and the target)
465  */
G_ReactionFireGetTUsForItem(const Edict * shooter,const Edict * target)466 static int G_ReactionFireGetTUsForItem (const Edict* shooter, const Edict* target)
467 {
468 	const fireDef_t* fd = rf.getFireDef(shooter);
469 	if (!fd)
470 		return -1;
471 
472 	const int tus = G_ActorGetModifiedTimeForFiredef(shooter, fd, true);
473 
474 	if (tus <= shooter->TU && rf.isInWeaponRange(shooter, target, fd)) {
475 		return tus;
476 	}
477 
478 	return -1;
479 }
480 
481 /**
482  * @brief Checks if the currently selected firemode is usable with the defined weapon.
483  * @param[in] actor The actor to check the firemode for.
484  */
G_ActorHasWorkingFireModeSet(const Edict * actor)485 static bool G_ActorHasWorkingFireModeSet (const Edict* actor)
486 {
487 	const FiremodeSettings *fmSettings = &actor->chr.RFmode;
488 	if (!fmSettings->isSaneFiremode())	/* just checks for valid values */
489 		return false;
490 
491 	const Item* weapon = actor->getHandItem(fmSettings->getHand());
492 	if (!weapon)
493 		return false;
494 	const fireDef_t* fd = weapon->getFiredefs();
495 	if (fd == nullptr)
496 		return false;
497 
498 	if (fd->obj->weapons[fd->weapFdsIdx] == fmSettings->getWeapon()
499 		&& fmSettings->getFmIdx() < fd->obj->numFiredefs[fd->weapFdsIdx]) {
500 		return true;
501 	}
502 
503 	return false;
504 }
505 
506 /**
507  * @brief Updates the reaction fire settings in case something was moved into a hand or from a hand
508  * that would make the current settings invalid
509  * @param[in,out] ent The actor edict to check the settings for
510  * @param[in] fmIdx The fire mode index that should be used for reaction fire
511  * @param[in] hand The hand that should be used for reaction fire
512  * @param[in] od The object/weapon for the reaction fire
513  */
G_ReactionFireSettingsUpdate(Edict * ent,fireDefIndex_t fmIdx,actorHands_t hand,const objDef_t * od)514 void G_ReactionFireSettingsUpdate (Edict* ent, fireDefIndex_t fmIdx, actorHands_t hand, const objDef_t* od)
515 {
516 	ent->chr.RFmode.set(hand, fmIdx, od);	/* FiremodeSettings */
517 
518 	if (!G_ActorHasWorkingFireModeSet(ent)) {
519 		/* Disable reaction fire if no valid firemode was found. */
520 		G_ClientStateChange(ent->getPlayer(), ent, ~STATE_REACTION, true);
521 		return;
522 	}
523 
524 	G_EventReactionFireChange(*ent);
525 
526 	/* If reaction fire is active, update the reserved TUs */
527 	if (G_IsReaction(ent)) {
528 		G_ReactionFireSettingsReserveTUs(ent);
529 	}
530 }
531 
532 /**
533  * @brief Checks whether an actor has enough TUs left to activate reaction fire.
534  * @param[in] ent The actors edict to check for TUs for
535  * @return @c true if the given actor has enough TUs left to activate reaction fire, @c false otherwise.
536  */
G_ActorHasEnoughTUsReactionFire(const Edict * ent)537 static bool G_ActorHasEnoughTUsReactionFire (const Edict* ent)
538 {
539 	const int TUs = G_ActorGetTUForReactionFire(ent);
540 	const chrReservations_t* res = &ent->chr.reservedTus;
541 	return ent->TU - TUs >= res->shot + res->crouch;
542 }
543 
544 /**
545  * @param ent The actor to set the reaction fire for
546  * @return @c true if the needed settings could have been made or settings are
547  * already valid, @c false otherwise.
548  */
G_ReactionFireSettingsSetDefault(Edict * ent)549 static bool G_ReactionFireSettingsSetDefault (Edict* ent)
550 {
551 	if (G_ActorHasWorkingFireModeSet(ent))
552 		return true;
553 
554 	actorHands_t hand = ACTOR_HAND_RIGHT;
555 	const Item* item = ent->getHandItem(hand);
556 	if (!item) {
557 		hand = ACTOR_HAND_LEFT;
558 		item = ent->getHandItem(hand);
559 	}
560 
561 	if (!item)
562 		return false;
563 
564 	const objDef_t* weapon = item->getReactionFireWeaponType();
565 	if (!weapon)
566 		return false;
567 
568 	ent->chr.RFmode.set(hand, 0, weapon);	/* no special firemode */
569 
570 	if (!G_ActorHasWorkingFireModeSet(ent))
571 		return false;
572 
573 	if (!G_IsAI(ent))
574 		G_EventReactionFireChange(*ent);
575 
576 	return true;
577 }
578 
579 /**
580  * @brief Checks whether the actor is allowed to activate reaction fire and will informs the player about
581  * the reason if this would not work.
582  * @param[in] ent The actor to check
583  * @return @c true if the actor is allowed to activate it, @c false otherwise
584  */
G_ReactionFireCanBeEnabled(const Edict * ent)585 static bool G_ReactionFireCanBeEnabled (const Edict* ent)
586 {
587 	/* check ent is a suitable shooter */
588 	if (!ent->inuse || !G_IsLivingActor(ent))
589 		return false;
590 
591 	if (G_MatchIsRunning() && ent->team != level.activeTeam)
592 		return false;
593 
594 	/* actor may not carry weapons at all - so no further checking is needed */
595 	if (!ent->chr.teamDef->weapons)
596 		return false;
597 
598 	if (!ent->chr.inv.holdsReactionFireWeapon()) {
599 		G_ClientPrintf(ent->getPlayer(), PRINT_HUD, _("No reaction fire enabled weapon."));
600 		return false;
601 	}
602 
603 	if (!G_ActorHasWorkingFireModeSet(ent)) {
604 		G_ClientPrintf(ent->getPlayer(), PRINT_HUD, _("No fire mode selected for reaction fire."));
605 		return false;
606 	}
607 
608 	if (!G_ActorHasEnoughTUsReactionFire(ent)) {
609 		G_ClientPrintf(ent->getPlayer(), PRINT_HUD, _("Not enough TUs left for activating reaction fire."));
610 		return false;
611 	}
612 
613 	return true;
614 }
615 
616 /**
617  * @brief Set the reaction fire TU reservation for an actor
618  * @param[in,out] ent The actor edict to set the TUs for
619  * @return @c true if TUs for reaction fire were reserved, @c false if the reservation was set
620  * back to @c 0
621  */
G_ReactionFireSettingsReserveTUs(Edict * ent)622 bool G_ReactionFireSettingsReserveTUs (Edict* ent)
623 {
624 	if (G_ReactionFireSettingsSetDefault(ent) && G_ReactionFireCanBeEnabled(ent)) {
625 		const int TUs = G_ActorGetTUForReactionFire(ent);
626 		/* Enable requested reaction fire. */
627 		G_ActorReserveTUs(ent, TUs, ent->chr.reservedTus.shot, ent->chr.reservedTus.crouch);
628 		return true;
629 	}
630 
631 	G_ActorReserveTUs(ent, 0, ent->chr.reservedTus.shot, ent->chr.reservedTus.crouch);
632 	return false;
633 }
634 
isPossible(Edict * shooter,const Edict * target) const635 inline bool ReactionFire::isPossible (Edict* shooter, const Edict* target) const
636 {
637 	return isEnemy(shooter, target) && canReact(shooter, target) && canSee(shooter, target);
638 }
639 
640 /**
641  * @brief Check whether we want to shoot at the target.
642  * @param[in] shooter The entity that might be firing
643  * @param[in] target The entity that might be fired at
644  */
isEnemy(const Edict * shooter,const Edict * target) const645 bool ReactionFire::isEnemy (const Edict* shooter, const Edict* target) const
646 {
647 	/* an entity can't reaction fire at itself */
648 	if (shooter == target)
649 		return false;
650 
651 	/* Don't react in your own turn */
652 	if (shooter->team == level.activeTeam)
653 		return false;
654 
655 	if (G_IsDead(target))
656 		return false;
657 
658 	/* If reaction fire is triggered by a friendly unit
659 	 * and the shooter is still sane, don't shoot;
660 	 * well, if the shooter isn't sane anymore... */
661 	if (G_IsCivilian(target) || target->team == shooter->team)
662 		if (!G_IsShaken(shooter) || (float) shooter->morale / mor_shaken->value > frand())
663 			return false;
664 
665 	return true;
666 }
667 
668 /**
669  * @brief Check whether shooter can reaction fire at target at all.
670  * @param[in] shooter The entity that might be firing
671  * @param[in] target The entity that might be fired at
672  */
canReact(Edict * shooter,const Edict * target) const673 bool ReactionFire::canReact (Edict* shooter, const Edict* target) const
674 {
675 	/* shooter can't use RF if is in STATE_DAZED (flashbang impact) */
676 	if (G_IsDazed(shooter))
677 		return false;
678 
679 	/* check shooter has reaction fire enabled */
680 	if (!G_IsReaction(shooter))
681 		return false;
682 
683 	/* check shooter has weapon in RF hand */
684 	if (!shooter->getHandItem(shooter->chr.RFmode.getHand())) {
685 		/* print character info if this happens, for now */
686 		gi.DPrintf("Reaction fire enabled but no weapon for hand (name=%s,entnum=%i,hand=%i,fmIdx=%i)\n",
687 				shooter->chr.name, shooter->number, shooter->chr.RFmode.getHand(), shooter->chr.RFmode.getFmIdx());
688 		G_RemoveReaction(shooter);
689 		return false;
690 	}
691 	return true;
692 }
693 
694 /**
695  * @brief Check whether shooter can see his target well enough
696  * @param[in] shooter The entity that might be firing
697  * @param[in] target The entity that might be fired at
698  */
canSee(const Edict * shooter,const Edict * target) const699 bool ReactionFire::canSee (const Edict* shooter, const Edict* target) const
700 {
701 	if (!G_IsVisibleForTeam(target, shooter->team))
702 		return false;
703 
704 	/* check in range and visible */
705 	const int spotDist = G_VisCheckDist(shooter);
706 	if (VectorDistSqr(shooter->origin, target->origin) > spotDist * spotDist)
707 		return false;
708 
709 	const bool frustum = G_FrustumVis(shooter, target->origin);
710 	if (!frustum)
711 		return false;
712 
713 	const float actorVis = G_ActorVis(shooter->origin, shooter, target, true);
714 	if (actorVis < 0.1)
715 		return false;
716 
717 	return true;
718 }
719 
720 /**
721  * @brief Check whether 'target' has just triggered any new reaction fire
722  * @param[in] target The entity triggering fire
723  */
updateAllTargets(const Edict * target)724 void ReactionFire::updateAllTargets (const Edict* target)
725 {
726 	Edict* shooter = nullptr;
727 
728 	/* check all possible shooters */
729 	while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
730 		/* check whether reaction fire is possible (friend/foe, LoS) */
731 		if (isPossible(shooter, target)) {
732 			const int TUs = G_ReactionFireGetTUsForItem(shooter, target);
733 			if (TUs < 0)
734 				continue;	/* no suitable weapon */
735 			rft.add(shooter, target, TUs);
736 		} else {
737 			rft.remove(shooter, target);
738 		}
739 	}
740 }
741 
resetTargets(const Edict * shooter)742 void ReactionFire::resetTargets (const Edict *shooter)
743 {
744 	rft.resetTargetList(shooter);
745 }
746 
747 /**
748  * @brief Perform the reaction fire shot
749  * @param[in] shooter The actor that is trying to shoot
750  * @param[in] at Position to fire on.
751  * @param[in] type What type of shot this is (left, right reaction-left etc...).
752  * @param[in] firemode The firemode index of the ammo for the used weapon (objDef.fd[][x])  .
753  * @return true if everything went ok (i.e. the shot(s) where fired ok), otherwise false.
754  * @sa G_ClientShoot
755  */
shoot(Edict * shooter,const pos3_t at,shoot_types_t type,fireDefIndex_t firemode)756 bool ReactionFire::shoot (Edict* shooter, const pos3_t at, shoot_types_t type, fireDefIndex_t firemode)
757 {
758 	const int minhit = 30;
759 	shot_mock_t mock;
760 	int i;
761 	const Player &player = shooter->getPlayer();
762 	/* this is the max amount of friendly units that were hit during the mock calculation */
763 	int maxff;
764 
765 	if (G_IsInsane(shooter))
766 		maxff = 100;
767 	else if (G_IsRaged(shooter))
768 		maxff = 60;
769 	else if (G_IsPanicked(shooter))
770 		maxff = 30;
771 	else if (G_IsShaken(shooter))
772 		maxff = 15;
773 	else
774 		maxff = 5;
775 
776 	/* calculate the mock values - e.g. how many friendly units we would hit
777 	 * when opening the reaction fire */
778 	for (i = 0; i < 100; i++)
779 		if (!G_ClientShoot(player, shooter, at, type, firemode, &mock, false, 0))
780 			break;
781 
782 	const int ff = mock.friendCount + (G_IsAlien(shooter) ? 0 : mock.civilian);
783 	if (ff <= maxff && mock.enemyCount >= minhit)
784 		return G_ClientShoot(player, shooter, at, type, firemode, nullptr, false, 0);
785 
786 	return false;
787 }
788 
789 /**
790  * @brief Resolve the reaction fire for an entity, this checks that the entity can fire and then takes the shot
791  * @param[in] shooter The entity using reaction fire
792  * @param[in] target The victim of the reaction fire
793  * @return true if the entity fired, false otherwise
794  */
tryToShoot(Edict * shooter,const Edict * target)795 bool ReactionFire::tryToShoot (Edict* shooter, const Edict* target)
796 {
797 	/* check for valid target */
798 	assert(target);
799 
800 	/* shooter can't take a reaction shot if it's not possible - and check that
801 	 * the target is still alive */
802 	if (!isPossible(shooter, target)) {
803 		rft.remove(shooter, target);
804 		return false;
805 	}
806 
807 	/* take the shot */
808 	const bool tookShot = rf.shoot(shooter, target->pos, ST_RIGHT_REACTION, shooter->chr.RFmode.getFmIdx());
809 
810 	if (tookShot) {
811 		/* clear any shakenness */
812 		G_RemoveShaken(shooter);
813 	}
814 
815 	return tookShot;
816 }
817 
notifyClientOnShot(const Edict * target,int tusTarget)818 void ReactionFire::notifyClientOnShot (const Edict* target, int tusTarget)
819 {
820 	rft.notifyClientOnShot(target, tusTarget);
821 }
822 
notifyClientOnStep(const Edict * target,int step)823 void ReactionFire::notifyClientOnStep (const Edict* target, int step)
824 {
825 	rft.notifyClientOnStep(target, step);
826 }
827 
828 /**
829  * @brief Check all entities to see whether target has caused reaction fire to resolve.
830  * @param[in] target The entity that might be resolving reaction fire
831  * @returns whether any entity fired (or would fire) upon target
832  * @sa G_ReactionFireOnMovement
833  * @sa G_ReactionFirePostShot
834  */
checkExecution(const Edict * target)835 bool ReactionFire::checkExecution (const Edict* target)
836 {
837 	Edict* shooter = nullptr;
838 	bool fired = false;
839 
840 	/* check all possible shooters */
841 	while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
842 		const int tus = G_ReactionFireGetTUsForItem(shooter, target);
843 		/* indicates an RF weapon is there */
844 		if (tus <= 1)
845 			continue;
846 		if (!rft.hasExpired(shooter, target, 0))
847 			continue;
848 		if (!rf.tryToShoot(shooter, target))
849 			continue;
850 		rft.advance(shooter, tus);
851 		fired |= true;
852 	}
853 	return fired;
854 }
855 
856 #if DEBUG_RF
857 /**
858  * @brief Prints some reaction fire data to the console
859  * @param[in] target The target entity
860  */
G_ReactionFirePrintSituation(Edict * target)861 static void G_ReactionFirePrintSituation (Edict* target)
862 {
863 	if (!G_IsAlien(target))
864 		return;
865 
866 	Com_Printf("Alien %i at %i/%i/%i TU:%i\n", target->number, target->pos[0], target->pos[1], target->pos[2], target->TU);
867 
868 	Edict* shooter = nullptr;
869 	/* check all possible shooters */
870 	while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
871 		if (G_IsAlien(shooter) || G_IsCivilian(shooter))
872 			continue;
873 		char msgHdr[100];
874 		Com_sprintf(msgHdr, sizeof(msgHdr), "S%i: at %i/%i/%i RF: ", shooter->number, shooter->pos[0], shooter->pos[1], shooter->pos[2]);
875 		int ttus = rft.getTriggerTUs(shooter, target);
876 		if (ttus == -2)
877 			Com_Printf("%s not initialized\n", msgHdr);
878 		if (ttus == -1)
879 			Com_Printf("%s not aiming\n", msgHdr);
880 		else if (rft.hasExpired(shooter, target, 0))
881 			Com_Printf("expired\n", msgHdr);
882 		else
883 			Com_Printf("%s not yet: %i\n", msgHdr, ttus);
884 	}
885 }
886 #endif
887 
888 /**
889  * @brief Called when 'target' moves, possibly triggering or resolving reaction fire
890  * @param[in] target The target entity
891  * @return true If any shots were (or would be) taken
892  * @sa G_ClientMove
893  */
G_ReactionFireOnMovement(Edict * target,int step)894 bool G_ReactionFireOnMovement (Edict* target, int step)
895 {
896 #if DEBUG_RF
897 	G_ReactionFirePrintSituation(target);
898 #endif
899 	rf.notifyClientOnStep(target, step);
900 
901 	/* Check to see whether this resolves any reaction fire */
902 	const bool fired = rf.checkExecution(target);
903 
904 	/* Check to see whether this triggers any reaction fire */
905 	rf.updateAllTargets(target);
906 
907 	return fired;
908 }
909 
G_ReactionFireNofityClientStartShot(const Edict * target)910 static void G_ReactionFireNofityClientStartShot (const Edict* target)
911 {
912 	rft.notifyClientMove(target, MAX_ROUTE, true);
913 }
914 
G_ReactionFireNofityClientEndShot(const Edict * target)915 static void G_ReactionFireNofityClientEndShot (const Edict* target)
916 {
917 	rft.notifyClientMove(target, MAX_ROUTE, false);
918 }
919 
920 /**
921  * @brief Called when 'target' is about to shoot, this forces a 'draw' to decide who gets the first shot
922  * @param[in] target The entity about to shoot
923  * @param[in] fdTime The TU of the shot
924  * @sa G_ClientShoot
925  */
G_ReactionFirePreShot(const Edict * target,const int fdTime)926 void G_ReactionFirePreShot (const Edict* target, const int fdTime)
927 {
928 	bool repeat = true;
929 
930 	/* Check to see whether this triggers any reaction fire */
931 	G_ReactionFireNofityClientStartShot(target);
932 	rf.updateAllTargets(target);
933 	rf.notifyClientOnShot(target, fdTime);
934 
935 	/* if any reaction fire occurs, we have to loop through all entities again to allow
936 	 * multiple (fast) RF snap shots before a (slow) aimed shot from the target occurs. */
937 	while (repeat) {
938 		Edict* shooter = nullptr;
939 		repeat = false;
940 		/* check all ents to see who wins and who loses a draw */
941 		while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
942 			const int entTUs = G_ReactionFireGetTUsForItem(shooter, target);
943 			/* indicates an RF weapon is there */
944 			if (entTUs <= 1)
945 				continue;
946 			if (!rft.hasExpired(shooter, target, fdTime))
947 				continue;
948 			if (!rf.tryToShoot(shooter, target))
949 				continue;
950 			repeat = true;
951 			rft.advance(shooter, fdTime);
952 		}
953 	}
954 }
955 
956 /**
957  * @brief Removes the given target from the reaction fire lists
958  * @param[in] target The target to remove from the lists
959  */
G_ReactionFireOnDead(const Edict * target)960 void G_ReactionFireOnDead (const Edict* target)
961 {
962 	assert(G_IsDead(target));
963 	rf.updateAllTargets(target);
964 	rf.resetTargets(target);
965 }
966 
967 /**
968  * @brief Called after 'target' has fired, this might trigger more reaction fire or resolve outstanding reaction fire (because target is out of time)
969  * @param[in] target The entity that has just fired
970  * @sa G_ClientShoot
971  */
G_ReactionFirePostShot(Edict * target)972 void G_ReactionFirePostShot (Edict* target)
973 {
974 	/* Check to see whether this resolves any reaction fire */
975 	rf.notifyClientOnShot(target, 0);
976 	rf.checkExecution(target);
977 	G_ReactionFireNofityClientEndShot(target);
978 }
979 
980 /**
981  * @brief Called at the end of turn, all outstanding reaction fire is resolved
982  * @sa G_ClientEndRound
983  */
G_ReactionFireOnEndTurn(void)984 void G_ReactionFireOnEndTurn (void)
985 {
986 	/* we explicitly do nothing at end of turn, just reset the table */
987 	rft.reset();
988 }
989 
990 /**
991  * @brief Guess! Reset all "shaken" states on end of turn?
992  * @note Normally called on end of turn.
993  * @sa G_ClientStateChange
994  * @param[in] team Index of team to loop through.
995  */
G_ReactionFireReset(int team)996 void G_ReactionFireReset (int team)
997 {
998 	Edict* ent = nullptr;
999 
1000 	while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, team))) {
1001 		G_RemoveShaken(ent);
1002 	}
1003 }
1004 
G_ReactionFireNofityClientStartMove(const Edict * target)1005 void G_ReactionFireNofityClientStartMove (const Edict* target)
1006 {
1007 	/* note that this is sent _before_ the actual move event, so we can't use the step number */
1008 	rft.notifyClientMove(target, MAX_ROUTE, true);
1009 }
1010 
G_ReactionFireNofityClientEndMove(const Edict * target)1011 void G_ReactionFireNofityClientEndMove (const Edict* target)
1012 {
1013 	rft.notifyClientMove(target, target->moveinfo.steps - 1, false);
1014 }
1015