UFO: Alien Invasion
Loading...
Searching...
No Matches
g_morale.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, 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
38static 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
78static 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
96static 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
118static 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
136static 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
156void 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}
bool CHRSH_IsTeamDefRobot(const teamDef_t *const td)
Check if a team definition is a robot.
@ ABILITY_MIND
Definition chr_shared.h:40
#define INVDEF(containerID)
Definition cl_shared.h:48
An Edict of type Actor.
Definition g_edict.h:348
bool isPanicked() const
Definition g_edict.h:356
bool isInsane() const
Definition g_edict.h:359
bool isRaged() const
Definition g_edict.h:358
void setInsane()
Definition g_edict.h:370
void removeCrouched()
Definition g_edict.h:382
void setPanicked()
Definition g_edict.h:367
void removePanicked()
Definition g_edict.h:377
void removeInsane()
Definition g_edict.h:380
void setShaken()
Definition g_edict.h:365
void removeRaged()
Definition g_edict.h:379
void setRaged()
Definition g_edict.h:369
teammask_t visflags
Definition g_edict.h:82
character_t chr
Definition g_edict.h:116
int getIdNum() const
Definition g_edict.h:231
Item * getRightHandItem() const
Definition g_edict.h:249
Item * getLeftHandItem() const
Definition g_edict.h:252
Player & getPlayer() const
Definition g_edict.h:265
entity_type_t type
Definition g_edict.h:81
int morale
Definition g_edict.h:91
#define NONE
Definition defines.h:68
void G_ActorSetTU(Edict *ent, int tus)
Definition g_actor.cpp:267
void G_ActorSetMaxs(Actor *actor)
Sets correct bounding box for actor (state dependent).
Definition g_actor.cpp:226
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
void AI_ActorRun(Player &player, Actor *actor)
Definition g_ai.cpp:1655
Artificial Intelligence functions.
void G_ClientStateChange(const Player &player, Actor *actor, int reqState, bool checkaction)
Changes the state of a player/soldier.
Definition g_client.cpp:473
playermask_t G_VisToPM(teammask_t teamMask)
Converts vis mask to player mask.
Definition g_client.cpp:186
Interface for g_client.cpp.
Actor * G_EdictsGetNextLivingActorOfTeam(Actor *lastEnt, const int team)
Iterate through the living actor entities of the given team.
Definition g_edicts.cpp:216
functions to handle the storage and lifecycle of all edicts in the game module.
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_EventSendState(playermask_t playerMask, const Edict &ent)
Definition g_events.cpp:466
Local definitions for game module.
cvar_t * m_panic_stop
Definition g_main.cpp:109
cvar_t * mor_shaken
Definition g_main.cpp:102
#define MORALE_RANDOM(mod)
Definition g_local.h:248
cvar_t * mor_panic
Definition g_main.cpp:103
cvar_t * m_rage
Definition g_main.cpp:107
cvar_t * m_sanity
Definition g_main.cpp:106
void G_SendStats(Edict &ent)
Send stats to network buffer.
Definition g_stats.cpp:34
cvar_t * sv_enablemorale
Definition g_main.cpp:55
#define G_IsSinglePlayer()
Definition g_local.h:146
cvar_t * m_rage_stop
Definition g_main.cpp:108
cvar_t * mor_regeneration
Definition g_main.cpp:101
static void G_MoraleStopRage(Actor *actor)
Stops the rage state of an actor.
Definition g_morale.cpp:118
void G_MoraleBehaviour(int team)
Applies morale behaviour on actors.
Definition g_morale.cpp:156
static void G_MoraleRage(Actor *actor)
Definition g_morale.cpp:96
static void G_MoraleStopPanic(Actor *actor)
Stops the panic state of an actor.
Definition g_morale.cpp:78
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
static void G_MoralePanic(Actor *actor)
Definition g_morale.cpp:38
void G_PrintStats(const char *format,...)
Prints stats to game console and stats log file.
Definition g_utils.cpp:304
Misc utility functions for game module.
#define CID_FLOOR
Definition inv_shared.h:55
#define CID_LEFT
Definition inv_shared.h:48
#define CID_RIGHT
Definition inv_shared.h:47
float frand(void)
Return random values between 0 and 1.
Definition mathlib.cpp:506
@ ET_ACTOR
Definition q_shared.h:148
#define STATE_REACTION
Definition q_shared.h:272
#define GET_MORALE(ab)
Definition q_shared.h:290
#define TEAM_CIVILIAN
Definition q_shared.h:61
const teamDef_t * teamDef
Definition chr_shared.h:413
chrScoreGlobal_t score
Definition chr_shared.h:406
char name[MAX_VAR]
Definition chr_shared.h:390
int skills[SKILL_NUM_TYPES]
Definition chr_shared.h:122
bool weapons
Definition chr_shared.h:335