UFO: Alien Invasion
g_health.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 2002-2022 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 #include "g_health.h"
26 #include "g_actor.h"
27 #include "g_client.h"
28 #include "g_combat.h"
29 #include "g_edicts.h"
30 #include "g_match.h"
31 #include "g_utils.h"
32 
33 static byte G_GetImpactDirection(const Edict* const target, const vec3_t impact)
34 {
35  vec3_t vec1, vec2;
36 
37  VectorSubtract(impact, target->origin, vec1);
38  vec1[2] = 0;
39  VectorNormalize(vec1);
40  VectorCopy(dvecs[target->dir], vec2);
41  VectorNormalize(vec2);
42 
43  return AngleToDir(VectorAngleBetween(vec2, vec1) * todeg);
44 }
45 
52 void G_DamageActor (Edict* target, const int damage, const vec3_t impact)
53 {
54  assert(target->chr.teamDef);
55 
56  G_TakeDamage(target, damage);
57  if (damage > 0 && target->HP > 0) {
58  const teamDef_t* const teamDef = target->chr.teamDef;
59  if (impact) {
60  /* Direct hit */
61  const byte impactDirection = G_GetImpactDirection(target, impact);
62  const float impactHeight = impact[2] / (target->absBox.mins[2] + target->absBox.maxs[2]);
63  const int bodyPart = teamDef->bodyTemplate->getHitBodyPart(impactDirection, impactHeight);
64  target->chr.wounds.woundLevel[bodyPart] += damage;
65  } else {
66  /* No direct hit (splash damage) */
67  for (int bodyPart = 0; bodyPart < teamDef->bodyTemplate->numBodyParts(); ++bodyPart)
68  target->chr.wounds.woundLevel[bodyPart] += teamDef->bodyTemplate->getArea(bodyPart) * damage;
69  }
70  G_SendWoundStats(target);
71  }
72 }
73 
81 void G_TreatActor (Actor* target, const fireDef_t* const fd, const int heal, const int healerTeam)
82 {
83  assert(target->chr.teamDef);
84 
85  /* Treat wounds */
86  if (fd->dmgweight == gi.csi->damNormal) {
87  int mostWounded = 0;
88  woundInfo_t* wounds = &target->chr.wounds;
89 
90  /* Find the worst not treated wound */
91  for (int bodyPart = 0; bodyPart < target->chr.teamDef->bodyTemplate->numBodyParts(); ++bodyPart)
92  if (wounds->woundLevel[bodyPart] > wounds->woundLevel[mostWounded])
93  mostWounded = bodyPart;
94 
95  if (wounds->woundLevel[mostWounded] > 0) {
96  const int woundsHealed = std::min(static_cast<int>(abs(heal) / target->chr.teamDef->bodyTemplate->bleedingFactor(mostWounded)),
97  wounds->woundLevel[mostWounded]);
98  G_TakeDamage(target, heal);
99  wounds->woundLevel[mostWounded] -= woundsHealed;
100  wounds->treatmentLevel[mostWounded] += woundsHealed;
101 
102  /* Update stats here to get info on how many HP the target received. */
103  if (target->chr.scoreMission)
104  target->chr.scoreMission->heal += abs(heal);
105  }
106  }
107 
108  /* Treat stunned actors */
109  if (fd->dmgweight == gi.csi->damStunElectro && target->isStunned()) {
110  if (CHRSH_IsTeamDefAlien(target->chr.teamDef) && target->getTeam() != healerTeam)
113  target->setStun(std::min(255, target->getStun() - heal));
114  else
115  target->setStun(std::max(0, target->getStun() + heal));
116  G_ActorCheckRevitalise(target);
117  }
118 
119  /* Increase morale */
120  if (fd->dmgweight == gi.csi->damShock)
121  target->setMorale(std::min(GET_MORALE(target->chr.score.skills[ABILITY_MIND]), target->morale - heal));
122 
123  G_SendWoundStats(target);
124 }
125 
130 void G_BleedWounds (const int team)
131 {
132  Actor* actor = nullptr;
133 
134  while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) {
135  if (CHRSH_IsTeamDefRobot(actor->chr.teamDef))
136  continue;
137  const teamDef_t* const teamDef = actor->chr.teamDef;
138  const woundInfo_t& wounds = actor->chr.wounds;
139  int damage = 0;
140  for (int bodyPart = 0; bodyPart < teamDef->bodyTemplate->numBodyParts(); ++bodyPart)
141  if (wounds.woundLevel[bodyPart] > actor->chr.maxHP * teamDef->bodyTemplate->woundThreshold(bodyPart))
142  damage += wounds.woundLevel[bodyPart] * teamDef->bodyTemplate->bleedingFactor(bodyPart);
143  if (damage > 0) {
144  G_PrintStats("%s is bleeding (damage: %i)", actor->chr.name, damage);
145  G_TakeDamage(actor, damage);
146  G_CheckDeathOrKnockout(actor, nullptr, nullptr, damage);
147  }
148  }
149  /* Maybe the last team member bled to death */
150  G_MatchEndCheck();
151 }
152 
157 void G_SendWoundStats (Edict* const ent)
158 {
159  for (int i = 0; i < ent->chr.teamDef->bodyTemplate->numBodyParts(); ++i) {
160  /* Sanity checks */
161  woundInfo_t& wounds = ent->chr.wounds;
162  wounds.woundLevel[i] = std::max(0, wounds.woundLevel[i]);
163  wounds.treatmentLevel[i] = std::max(0, wounds.treatmentLevel[i]);
164  wounds.woundLevel[i] = std::min(255, wounds.woundLevel[i]);
165  wounds.treatmentLevel[i] = std::min(255, wounds.treatmentLevel[i]);
166  if (wounds.woundLevel[i] + wounds.treatmentLevel[i] > 0)
167  G_EventActorWound(*ent, i);
168  }
169 }
170 
177 float G_ActorGetInjuryPenalty (const Edict* const ent, const modifier_types_t type)
178 {
179  float penalty = 0;
180 
181  const teamDef_t* const teamDef = ent->chr.teamDef;
182  for (int bodyPart = 0; bodyPart < teamDef->bodyTemplate->numBodyParts(); ++bodyPart) {
183  const int threshold = ent->chr.maxHP * teamDef->bodyTemplate->woundThreshold(bodyPart);
184  const int injury = (ent->chr.wounds.woundLevel[bodyPart] + ent->chr.wounds.treatmentLevel[bodyPart] * 0.5);
185  if (injury > threshold)
186  penalty += 2 * teamDef->bodyTemplate->penalty(bodyPart, type) * injury / ent->chr.maxHP;
187  }
188 
189  switch (type) {
190  case MODIFIER_REACTION:
192  break;
193  case MODIFIER_SHOOTING:
194  case MODIFIER_ACCURACY:
195  ++penalty;
196  break;
197  case MODIFIER_TU:
198  case MODIFIER_SIGHT:
199  penalty = 1 - penalty;
200  break;
201  case MODIFIER_MOVEMENT:
202  penalty = ceil(penalty);
203  break;
204  default:
205  gi.DPrintf("G_ActorGetInjuryPenalty: Unknown modifier type %i\n", type);
206  penalty = 0;
207  break;
208  }
209 
210  return penalty;
211 }
212 
213 bool G_IsActorWounded (const Edict* ent, bool serious)
214 {
215  if (ent == nullptr || !G_IsLivingActor(ent) || ent->chr.teamDef == nullptr)
216  return false;
217  const character_t& chr = ent->chr;
218  const BodyData* bodyTmp = chr.teamDef->bodyTemplate;
219  for (int i = 0; i < bodyTmp->numBodyParts(); ++i)
220  if (chr.wounds.woundLevel[i] > serious ? chr.maxHP * bodyTmp->woundThreshold(i) : 0)
221  return true;
222 
223  return false;
224 }
#define VectorCopy(src, dest)
Definition: vector.h:51
bool isStunned() const
Definition: g_edict.h:355
int getStun() const
Definition: g_edict.h:308
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
void G_PrintStats(const char *format,...)
Prints stats to game console and stats log file.
Definition: g_utils.cpp:304
int skills[SKILL_NUM_TYPES]
Definition: chr_shared.h:122
Misc utility functions for game module.
int woundLevel[BODYPART_MAXTYPE]
Definition: chr_shared.h:362
short numBodyParts(void) const
Definition: chr_shared.cpp:389
const BodyData * bodyTemplate
Definition: chr_shared.h:350
character_t chr
Definition: g_edict.h:116
Describes a character with all its attributes.
Definition: chr_shared.h:388
AABB absBox
Definition: g_edict.h:61
const vec4_t dvecs[PATHFINDING_DIRECTIONS]
Definition: mathlib.cpp:58
bool CHRSH_IsTeamDefAlien(const teamDef_t *const td)
Check if a team definition is alien.
Definition: chr_shared.cpp:83
const teamDef_t * teamDef
Definition: chr_shared.h:413
vec3_t maxs
Definition: aabb.h:258
byte dir
Definition: g_edict.h:86
float bleedingFactor(const short bodyPart) const
Definition: chr_shared.cpp:379
this is a fire definition for our weapons/ammo
Definition: inv_shared.h:110
void G_CheckDeathOrKnockout(Actor *target, Actor *attacker, const fireDef_t *fd, int damage)
Definition: g_combat.cpp:499
bool G_IsLivingActor(const Edict *ent)
Checks whether the given edict is a living actor.
Definition: g_actor.cpp:43
Info on a wound.
Definition: chr_shared.h:361
int AngleToDir(int angle)
Returns the index of array directionAngles[DIRECTIONS] whose value is the closest to angle...
Definition: mathlib.cpp:130
int damStunElectro
Definition: q_shared.h:535
#define todeg
Definition: mathlib.h:51
Match related functions.
byte dmgweight
Definition: inv_shared.h:141
int getTeam() const
Definition: g_edict.h:269
game_import_t gi
Definition: g_main.cpp:39
static byte G_GetImpactDirection(const Edict *const target, const vec3_t impact)
Definition: g_health.cpp:33
short getHitBodyPart(const byte direction, const float height) const
Definition: chr_shared.cpp:405
float woundThreshold(const short bodyPart) const
Definition: chr_shared.cpp:384
float penalty(const short bodyPart, const modifier_types_t type) const
Definition: chr_shared.cpp:374
All parts of the main game logic that are combat related.
int treatmentLevel[BODYPART_MAXTYPE]
Definition: chr_shared.h:363
An Edict of type Actor.
Definition: g_edict.h:348
woundInfo_t wounds
Definition: chr_shared.h:402
bool CHRSH_IsTeamDefRobot(const teamDef_t *const td)
Check if a team definition is a robot.
Definition: chr_shared.cpp:103
void G_DamageActor(Edict *target, const int damage, const vec3_t impact)
Deals damage and causes wounds.
Definition: g_health.cpp:52
void G_BleedWounds(const int team)
Deal damage to each wounded team member.
Definition: g_health.cpp:130
int damShock
Definition: q_shared.h:529
float getArea(const short bodyPart) const
Definition: chr_shared.cpp:427
void G_TakeDamage(Edict *ent, int damage)
Applies the given damage value to an edict that is either an actor or has the FL_DESTROYABLE flag set...
Definition: g_utils.cpp:215
void setMorale(int mor)
Definition: g_edict.h:311
void setStun(int stu)
Definition: g_edict.h:302
bool G_IsActorWounded(const Edict *ent, bool serious)
Definition: g_health.cpp:213
Actor * G_EdictsGetNextLivingActorOfTeam(Actor *lastEnt, const int team)
Iterate through the living actor entities of the given team.
Definition: g_edicts.cpp:216
QGL_EXTERN GLint i
Definition: r_gl.h:113
modifier_types_t
Definition: chr_shared.h:255
void G_EventActorWound(const Edict &ent, const int bodyPart)
Send info about an actor&#39;s wounds to the client.
Definition: g_events.cpp:399
vec_t VectorNormalize(vec3_t v)
Calculate unit vector for a given vec3_t.
Definition: mathlib.cpp:745
chrScoreGlobal_t score
Definition: chr_shared.h:406
void G_ActorCheckRevitalise(Actor *actor)
Definition: g_actor.cpp:386
functions to handle the storage and lifecycle of all edicts in the game module.
vec3_t origin
Definition: g_edict.h:53
vec_t vec3_t[3]
Definition: ufotypes.h:39
char name[MAX_VAR]
Definition: chr_shared.h:390
int morale
Definition: g_edict.h:91
void G_MatchEndCheck(void)
Checks whether there are still actors to fight with left. If none are the match end will be triggered...
Definition: g_match.cpp:280
vec3_t mins
Definition: aabb.h:257
#define GET_MORALE(ab)
Definition: q_shared.h:290
void G_SendWoundStats(Edict *const ent)
Send wound stats to network buffer.
Definition: g_health.cpp:157
Definition: g_edict.h:45
float VectorAngleBetween(const vec3_t vec1, const vec3_t vec2)
Calculates the angle (in radians) between the two given vectors.
Definition: mathlib.cpp:484
uint8_t byte
Definition: ufotypes.h:34
float G_ActorGetInjuryPenalty(const Edict *const ent, const modifier_types_t type)
Returns the penalty to the given stat caused by the actor wounds.
Definition: g_health.cpp:177
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
void G_TreatActor(Actor *target, const fireDef_t *const fd, const int heal, const int healerTeam)
Heals a target and treats wounds.
Definition: g_health.cpp:81
Interface for g_client.cpp.
chrScoreMission_t * scoreMission
Definition: chr_shared.h:407
const csi_t * csi
Definition: game.h:176
int damNormal
Definition: q_shared.h:528
int HP
Definition: g_edict.h:89