UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
g_morale.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 2002-2020 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_local.h"
26 #include "g_actor.h"
27 #include "g_ai.h"
28 #include "g_client.h"
29 #include "g_edicts.h"
30 #include "g_utils.h"
31 
38 static void G_MoralePanic (Actor* actor)
39 {
40  G_PrintStats("%s panics (entnum %i).", actor->chr.name, actor->getIdNum());
41  /* drop items in hands */
42  if (actor->isInsane() && actor->chr.teamDef->weapons) {
43  if (actor->getRightHandItem())
45  INVDEF(CID_FLOOR), NONE, NONE, true);
46  if (actor->getLeftHandItem())
48  INVDEF(CID_FLOOR), NONE, NONE, true);
49  G_ClientStateChange(actor->getPlayer(), actor, ~STATE_REACTION, false);
50  }
51 
52  /* get up */
53  actor->removeCrouched();
54  G_ActorSetMaxs(actor);
55 
56  /* send panic */
57  actor->setPanicked();
58  G_EventSendState(G_VisToPM(actor->visflags), *actor);
59 
60  /* center view */
61  G_EventCenterView(*actor);
62 
63  /* move around a bit, try to avoid opponents */
64  AI_ActorRun(actor->getPlayer(), actor);
65 
66  /* kill TUs */
67  G_ActorSetTU(actor, 0);
68 }
69 
78 static void G_MoraleStopPanic (Actor* actor)
79 {
80  actor->removeInsane();
81  if (actor->morale / mor_panic->value > m_panic_stop->value * frand()) {
82  actor->removePanicked();
83  G_PrintStats("%s is no longer panicked (entnum %i).", actor->chr.name, actor->getIdNum());
84  G_EventSendState(G_VisToPM(actor->visflags), *actor);
85  } else {
86  G_MoralePanic(actor);
87  }
88 }
89 
96 static void G_MoraleRage (Actor* actor)
97 {
98  actor->setRaged();
99  if (!actor->isInsane()) {
100  G_PrintStats("%s is on a rampage (entnum %i).", actor->chr.name, actor->getIdNum());
101  } else {
102  G_PrintStats("%s is consumed by mad rage (entnum %i).", actor->chr.name, actor->getIdNum());
103  }
104  G_EventSendState(G_VisToPM(actor->visflags), *actor);
105  G_ClientStateChange(actor->getPlayer(), actor, ~STATE_REACTION, false);
106 
107  AI_ActorRun(actor->getPlayer(), actor);
108 }
109 
118 static void G_MoraleStopRage (Actor* actor)
119 {
120  /* regains sanity */
121  actor->removeInsane();
122  if (actor->morale / mor_panic->value > m_rage_stop->value * frand()) {
123  actor->removeRaged();
124  G_EventSendState(G_VisToPM(actor->visflags), *actor);
125  G_PrintStats("%s is no longer insane (entnum %i).", actor->chr.name, actor->getIdNum());
126  } else {
127  G_MoralePanic(actor);
128  }
129 }
130 
136 static bool G_IsMoraleEnabled (int team)
137 {
138  if (G_IsSinglePlayer())
139  return true;
140 
141  /* multiplayer */
142  if (team == TEAM_CIVILIAN || sv_enablemorale->integer == 1)
143  return true;
144 
145  return false;
146 }
147 
156 void G_MoraleBehaviour (int team)
157 {
158  const bool enabled = G_IsMoraleEnabled(team);
159  if (!enabled)
160  return;
161 
162  Actor* actor = nullptr;
163  while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team)) != nullptr) {
164  /* this only applies to ET_ACTOR but not to ET_ACTOR2x2 */
165  if (actor->type != ET_ACTOR || CHRSH_IsTeamDefRobot(actor->chr.teamDef))
166  continue;
167 
168  /* if panic, determine what kind of panic happens: */
169  if (!actor->isPanicked() && !actor->isRaged()) {
170  if (actor->morale <= mor_panic->integer) {
171  const float ratio = (float) actor->morale / mor_panic->value;
172  const bool sanity = ratio > (m_sanity->value * frand());
173  if (!sanity)
174  actor->setInsane();
175  if (ratio > (m_rage->value * frand()))
176  G_MoralePanic(actor);
177  else
178  G_MoraleRage(actor);
179  /* if shaken, well .. be shaken; */
180  } else if (actor->morale <= mor_shaken->integer) {
181  /* shaken is later reset along with reaction fire */
182  actor->setShaken();
183  G_ClientStateChange(actor->getPlayer(), actor, STATE_REACTION, false);
184  G_EventSendState(G_VisToPM(actor->visflags), *actor);
185  G_PrintStats("%s is shaken (entnum %i).", actor->chr.name, actor->getIdNum());
186  }
187  } else {
188  if (actor->isPanicked())
189  G_MoraleStopPanic(actor);
190  else if (actor->isRaged())
191  G_MoraleStopRage(actor);
192  }
193 
194  G_ActorSetMaxs(actor);
195 
196  /* morale-regeneration, capped at max: */
197  const int newMorale = actor->morale + MORALE_RANDOM(mor_regeneration->value);
198  const int maxMorale = GET_MORALE(actor->chr.score.skills[ABILITY_MIND]);
199  if (newMorale > maxMorale)
200  actor->morale = maxMorale;
201  else
202  actor->morale = newMorale;
203 
204  /* send phys data and state: */
205  G_SendStats(*actor);
206  }
207 }
void G_EventCenterView(const Edict &ent)
Centers the view for all clients that are seeing the given edict on the world position of the edict...
Definition: g_events.cpp:479
void G_MoraleBehaviour(int team)
Applies morale behaviour on actors.
Definition: g_morale.cpp:156
int getIdNum() const
Definition: g_edict.h:231
void removeCrouched()
Definition: g_edict.h:382
#define MORALE_RANDOM(mod)
Definition: g_local.h:248
chrScoreGlobal_t score
Definition: chr_shared.h:387
void setRaged()
Definition: g_edict.h:369
cvar_t * m_rage
Definition: g_main.cpp:107
void G_PrintStats(const char *format,...)
Prints stats to game console and stats log file.
Definition: g_utils.cpp:304
cvar_t * m_sanity
Definition: g_main.cpp:106
bool isRaged() const
Definition: g_edict.h:358
const teamDef_t * teamDef
Definition: chr_shared.h:394
Artificial Intelligence functions.
Misc utility functions for game module.
void G_ClientStateChange(const Player &player, Actor *actor, int reqState, bool checkaction)
Changes the state of a player/soldier.
Definition: g_client.cpp:473
void setPanicked()
Definition: g_edict.h:367
#define STATE_REACTION
Definition: q_shared.h:272
bool isPanicked() const
Definition: g_edict.h:356
character_t chr
Definition: g_edict.h:116
float value
Definition: cvar.h:80
void removePanicked()
Definition: g_edict.h:377
#define TEAM_CIVILIAN
Definition: q_shared.h:61
static bool G_IsMoraleEnabled(int team)
Checks whether the morale handling is activated for this game. This is always the case in singleplaye...
Definition: g_morale.cpp:136
void removeRaged()
Definition: g_edict.h:379
static void G_MoraleStopRage(Actor *actor)
Stops the rage state of an actor.
Definition: g_morale.cpp:118
int integer
Definition: cvar.h:81
void G_ActorSetMaxs(Actor *actor)
Sets correct bounding box for actor (state dependent).
Definition: g_actor.cpp:226
Player & getPlayer() const
Definition: g_edict.h:265
cvar_t * m_rage_stop
Definition: g_main.cpp:108
Item * getRightHandItem() const
Definition: g_edict.h:249
void G_EventSendState(playermask_t playerMask, const Edict &ent)
Definition: g_events.cpp:466
#define CID_LEFT
Definition: inv_shared.h:48
void removeInsane()
Definition: g_edict.h:380
#define CID_RIGHT
Definition: inv_shared.h:47
cvar_t * sv_enablemorale
Definition: g_main.cpp:55
teammask_t visflags
Definition: g_edict.h:82
cvar_t * mor_panic
Definition: g_main.cpp:103
An Edict of type Actor.
Definition: g_edict.h:348
#define CID_FLOOR
Definition: inv_shared.h:55
bool isInsane() const
Definition: g_edict.h:359
bool CHRSH_IsTeamDefRobot(const teamDef_t *const td)
Check if a team definition is a robot.
Definition: chr_shared.cpp:102
static void G_MoraleRage(Actor *actor)
Definition: g_morale.cpp:96
playermask_t G_VisToPM(teammask_t teamMask)
Converts vis mask to player mask.
Definition: g_client.cpp:186
#define INVDEF(containerID)
Definition: cl_shared.h:47
cvar_t * mor_regeneration
Definition: g_main.cpp:101
bool G_ActorInvMove(Actor *actor, const invDef_t *fromContType, Item *fItem, const invDef_t *toContType, int tx, int ty, bool checkaction)
Moves an item inside an inventory. Floors are handled special.
Definition: g_actor.cpp:506
#define G_IsSinglePlayer()
Definition: g_local.h:146
Actor * G_EdictsGetNextLivingActorOfTeam(Actor *lastEnt, const int team)
Iterate through the living actor entities of the given team.
Definition: g_edicts.cpp:216
float frand(void)
Return random values between 0 and 1.
Definition: mathlib.cpp:506
Local definitions for game module.
static void G_MoraleStopPanic(Actor *actor)
Stops the panic state of an actor.
Definition: g_morale.cpp:78
entity_type_t type
Definition: g_edict.h:81
void G_ActorSetTU(Edict *ent, int tus)
Definition: g_actor.cpp:267
functions to handle the storage and lifecycle of all edicts in the game module.
char name[MAX_VAR]
Definition: chr_shared.h:371
int morale
Definition: g_edict.h:91
static void G_MoralePanic(Actor *actor)
Definition: g_morale.cpp:38
#define GET_MORALE(ab)
Definition: q_shared.h:290
cvar_t * m_panic_stop
Definition: g_main.cpp:109
#define NONE
Definition: defines.h:68
void setShaken()
Definition: g_edict.h:365
void AI_ActorRun(Player &player, Actor *actor)
Definition: g_ai.cpp:1655
void G_SendStats(Edict &ent)
Send stats to network buffer.
Definition: g_stats.cpp:34
cvar_t * mor_shaken
Definition: g_main.cpp:102
Item * getLeftHandItem() const
Definition: g_edict.h:252
bool weapons
Definition: chr_shared.h:324
void setInsane()
Definition: g_edict.h:370
int skills[SKILL_NUM_TYPES]
Definition: chr_shared.h:122
Interface for g_client.cpp.