UFO: Alien Invasion
Loading...
Searching...
No Matches
g_func.cpp
Go to the documentation of this file.
1
5
6/*
7All original material Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9Original file from Quake 2 v3.21: quake2-2.31/game/g_spawn.c
10Copyright (C) 1997-2001 Id Software, Inc.
11
12This program is free software; you can redistribute it and/or
13modify it under the terms of the GNU General Public License
14as published by the Free Software Foundation; either version 2
15of the License, or (at your option) any later version.
16
17This program is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20
21See the GNU General Public License for more details.
22
23You should have received a copy of the GNU General Public License
24along with this program; if not, write to the Free Software
25Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27*/
28
29#include "g_func.h"
30#include "g_actor.h"
31#include "g_ai.h"
32#include "g_match.h"
33#include "g_move.h"
34#include "g_spawn.h"
35#include "g_trigger.h"
36#include "g_utils.h"
37#include "g_vis.h"
38
46static bool Touch_Breakable (Edict* self, Edict* activator)
47{
49 if (G_IsActor(activator))
50 G_TriggerAddToList(self, activator);
51
52 return false;
53}
54
55static bool Destroy_Breakable (Edict* self)
56{
58 const char* model = self->model;
59
60 self->absBox.getCenter(origin);
61
62 const char* breakSound = nullptr;
63 switch (self->material) {
64 case MAT_GLASS:
65 breakSound = "misc/breakglass+";
66 break;
67 case MAT_METAL:
68 breakSound = "misc/breakmetal+";
69 break;
70 case MAT_ELECTRICAL:
71 breakSound = "misc/breakelectric+";
72 break;
73 case MAT_WOOD:
74 breakSound = "misc/breakwood+";
75 break;
76 case MAT_MAX:
77 break;
78 }
79
80 /* the HP value is used to decide whether this was a triggered call or a
81 * call during a fight - a triggered call will be handled differently in
82 * terms of timing and the related particle effects in the client code */
83 if (self->HP == 0)
84 G_EventModelExplodeTriggered(*self, breakSound);
85 else
86 G_EventModelExplode(*self, breakSound);
87
88 if (self->particle)
90
91 G_TouchEdicts(self, 10.0f);
92 linkedList_t* touchedList = self->touchedList;
93
94 /* destroy the door trigger */
95 if (self->child()) {
96 Edict* trigger = self->child();
97 /* Remove all activators and reset client actions before removing the trigger */
98 linkedList_t* list = trigger->touchedList;
99 while (list) {
100 linkedList_t* next = list->next;
101 Edict* activator = static_cast<Edict*>(list->data);
102 G_TriggerRemoveFromList(trigger, activator);
103 if (trigger->reset != nullptr)
104 trigger->reset(trigger, activator);
105 list = next;
106 }
107 G_FreeEdict(trigger);
108 }
109
110 /* now we can destroy the edict completely */
111 G_FreeEdict(self);
112
113 AABB oldAABB;
114 gi.GetInlineModelAABB(model, oldAABB);
115 GridBox rerouteOldBox;
116 rerouteOldBox.set(oldAABB);
117 G_RecalcRouting(model, rerouteOldBox);
118
119 LIST_Foreach(touchedList, Edict, activator) {
120 if (G_IsActor(activator))
121 G_ActorFall(activator);
122 }
123
124 return true;
125}
126
127static bool Use_Breakable (Edict* self, Edict* activator)
128{
129 self->HP = 0;
130 return Destroy_Breakable(self);
131}
132
145{
146 ent->classname = "breakable";
147 ent->type = ET_BREAKABLE;
148
149 ent->flags |= FL_DESTROYABLE;
150
151 /* set an inline model */
152 gi.SetModel(ent, ent->model);
153 ent->solid = SOLID_BSP;
154 gi.LinkEdict(ent);
155
156 char boxStr[AABB_STRING];
157 ent->entBox.asIntString(boxStr, sizeof(boxStr));
158 Com_DPrintf(DEBUG_GAME, "func_breakable: model (%s) num: %i %s origin: %i %i %i\n",
159 ent->model, ent->mapNum, boxStr,
160 (int)ent->origin[0], (int)ent->origin[1], (int)ent->origin[2]);
161
163 ent->use = Use_Breakable;
165}
166
167/*
168=============================================================================
169DOOR FUNCTIONS
170=============================================================================
171*/
172
180static void Door_SlidingUse (Edict* door)
181{
182 const bool open = door->doorState == STATE_OPENED;
183
184 /* get the movement angle vector - a negative speed value will close the door*/
185 vec3_t moveAngles;
186 GET_SLIDING_DOOR_SHIFT_VECTOR(door->dir, open ? 1 : -1, moveAngles);
187
188 /* get the direction vector from the movement angles that were set on the entity */
189 vec3_t moveDir;
190 AngleVectors(moveAngles, moveDir, nullptr, nullptr);
191 VectorAbs(moveDir);
192
193 /* calculate the distance from the movement angles and the entity size. This is the
194 * distance the door has to slide to fully open or close */
195 const int distance = DotProduct(moveDir, door->size);
196
197 /* the door is moved in one step on the server side - lerping is not needed here - so we
198 * perform the scalar multiplication with the distance the door must move in order to
199 * fully close/open */
200 vec3_t distanceVec;
201 VectorMul(distance, moveAngles, distanceVec);
202
203 /* set the updated position. The bounding boxes that are used for tracing must be
204 * shifted when the door state changes. As the mins and maxs of the aabb are absolute
205 * world coordinates in the map we have to translate the position by the above
206 * calculated movement vector */
207 VectorAdd(door->origin, distanceVec, door->origin); /* calc new model position */
208// gi.SetInlineModelOrientation(door->model, door->origin, door->angles); /* move the model out of the way */
209}
210
217static bool Door_Use (Edict* door, Edict* activator)
218{
219 int opening = 1;
220
221 if (door->doorState == STATE_CLOSED) {
222 door->doorState = STATE_OPENED;
223 opening = 1;
224 } else if (door->doorState == STATE_OPENED) {
225 door->doorState = STATE_CLOSED;
226 opening = -1;
227 } else {
228 return false;
229 }
230
231 /* remember the old location */
232 AABB oldAABB;
233 gi.GetInlineModelAABB(door->model, oldAABB);
234 GridBox rerouteOldBox;
235 rerouteOldBox.set(oldAABB);
236
237 /* change rotation and relink */
238 if (door->type == ET_DOOR) {
239 if (door->dir & DOOR_OPEN_REVERSE)
240 opening *= -1;
241 door->angles[door->dir & 3] += DOOR_ROTATION_ANGLE * opening;
242 } else if (door->type == ET_DOOR_SLIDING) {
243 Door_SlidingUse(door);
244 }
245 gi.LinkEdict(door);
246
247 /* maybe the server called this because the door starts opened */
248 if (G_MatchIsRunning()) {
249 /* let everybody know, that the door moves */
250 if (door->doorState == STATE_OPENED)
251 G_EventDoorOpen(*door);
252 else
253 G_EventDoorClose(*door);
254 if (Q_strvalid(door->noise)) {
255 const playermask_t playerMask = G_GetClosePlayerMask(door->origin, UNIT_SIZE * 10);
256 G_EventSpawnSound(playerMask, *door, door->origin, door->noise);
257 }
258 }
259
260 /* Update model orientation */
261 gi.SetInlineModelOrientation(door->model, door->origin, door->angles);
262 AABB newAabb;
263 gi.GetInlineModelAABB(door->model, newAabb);
264 GridBox rerouteNewBox;
265 rerouteNewBox.set(newAabb);
266 Com_DPrintf(DEBUG_GAME, "Server processed door movement.\n");
267
268 /* Update path finding table for the new location of the model */
269 G_RecalcRouting(door->model, rerouteOldBox); /* Update path finding table */
270 G_RecalcRouting(door->model, rerouteNewBox);
271
272 if (activator && G_IsLivingActor(activator)) {
273 /* Check if the player appears/perishes, seen from other teams. */
274 G_CheckVis(activator);
275
276 /* Calc new vis for the activator. */
277 G_CheckVisTeamAll(activator->getTeam(), 0, activator);
278 }
279
280 return true;
281}
282
290static bool Touch_DoorTrigger (Edict* self, Edict* activator)
291{
292 if (!self->owner())
293 return false;
294 if (!self->owner()->inuse)
295 return false;
296 if (!G_IsActor(activator))
297 return false;
298
299 Actor* actor = makeActor(activator);
300 if (G_IsAI(actor)) {
301 /* let the ai interact with the door */
302 if (self->flags & FL_GROUPSLAVE)
303 self = self->groupMaster;
304 if (AI_CheckUsingDoor(actor, self->owner()))
305 G_ActorUseDoor(actor, self->owner());
306 /* we don't want the client action stuff to be send for ai actors */
307 return false;
308 }
309
310 /* prepare for client action */
311 G_ActorSetClientAction(actor, self->owner());
312 return true;
313}
314
320static void Reset_DoorTrigger (Edict* self, Edict* activator)
321{
322 if (activator->clientAction == self->owner())
323 G_ActorSetClientAction(activator, nullptr);
324}
325
326#define REVERSE 0x00000200
327
336{
337 ent->classname = "door";
338 ent->type = ET_DOOR;
339 if (!ent->noise)
340 ent->noise = "doors/open_close";
341
342 /* set an inline model */
343 gi.SetModel(ent, ent->model);
344 ent->solid = SOLID_BSP;
345 gi.LinkEdict(ent);
346 ent->doorState = STATE_CLOSED;
347 ent->dir = YAW;
348
349 if (ent->spawnflags & REVERSE)
350 ent->dir |= DOOR_OPEN_REVERSE;
351
352 if (ent->HP)
353 ent->flags |= FL_DESTROYABLE;
354 ent->flags |= FL_CLIENTACTION;
355
356 /* spawn the trigger entity */
357 Edict* other = G_TriggerSpawn(ent);
359 other->reset = Reset_DoorTrigger;
360 ent->setChild(other);
361
363 if (!ent->speed)
364 ent->speed = 10;
365 ent->use = Door_Use;
366
367 /* the door should start opened */
368 if (ent->spawnflags & FL_TRIGGERED)
369 G_UseEdict(ent, nullptr);
370
372}
373
375{
376 ent->classname = "doorsliding";
377 ent->type = ET_DOOR_SLIDING;
378 if (!ent->noise)
379 ent->noise = "doors/slide";
380
381 /* set an inline model */
382 gi.SetModel(ent, ent->model);
383 ent->solid = SOLID_BSP;
384 gi.LinkEdict(ent);
385
386 if (ent->spawnflags & REVERSE)
387 ent->dir |= DOOR_OPEN_REVERSE;
388
389 if (ent->HP)
390 ent->flags |= FL_DESTROYABLE;
391
392 ent->doorState = STATE_CLOSED;
393 if (!ent->speed)
394 ent->speed = 10;
395 ent->use = Door_Use;
396
398}
399
406{
407 ent->classname = "rotating";
408 ent->type = ET_ROTATING;
409
410 /* set an inline model */
411 gi.SetModel(ent, ent->model);
412 ent->solid = SOLID_BSP;
413 gi.LinkEdict(ent);
414
415 /* the lower, the faster */
416 if (!ent->speed)
417 ent->speed = 50;
418
419 if (ent->HP)
420 ent->flags |= FL_DESTROYABLE;
421
423}
#define AABB_STRING
Definition aabb.h:40
Definition aabb.h:42
void asIntString(char *str, size_t len)
Prints a representation of the box.
Definition aabb.h:167
void getCenter(vec3_t center) const
Calculates the center of the bounding box.
Definition aabb.h:155
An Edict of type Actor.
Definition g_edict.h:348
int flags
Definition g_edict.h:169
const char * classname
Definition g_edict.h:67
Edict * child()
Definition g_edict.h:237
vec3_t origin
Definition g_edict.h:53
const char * particle
Definition g_edict.h:128
Edict * owner()
Definition g_edict.h:240
int HP
Definition g_edict.h:89
int doorState
Definition g_edict.h:158
const char * noise
Definition g_edict.h:132
byte dir
Definition g_edict.h:86
vec3_t angles
Definition g_edict.h:54
vec3_t size
Definition g_edict.h:62
Edict * clientAction
Definition g_edict.h:113
bool(* use)(Edict *self, Edict *activator)
Definition g_edict.h:154
void setTouch(bool(*touch_)(Edict *self, Edict *activator))
Definition g_edict.h:321
bool inuse
Definition g_edict.h:47
int getTeam() const
Definition g_edict.h:269
AABB entBox
Definition g_edict.h:60
void setChild(Edict *child)
Definition g_edict.h:192
int mapNum
Definition g_edict.h:73
bool(* destroy)(Edict *self)
Definition g_edict.h:155
void(* reset)(Edict *self, Edict *activator)
Definition g_edict.h:148
AABB absBox
Definition g_edict.h:61
int spawnflags
Definition g_edict.h:118
linkedList_t * touchedList
Definition g_edict.h:157
solid_t solid
Definition g_edict.h:58
entity_type_t type
Definition g_edict.h:81
Edict * groupMaster
Definition g_edict.h:168
int speed
Definition g_edict.h:124
edictMaterial_t material
Definition g_edict.h:133
const char * model
Definition g_edict.h:74
void set(const pos3_t mini, const pos3_t maxi)
Definition mathlib.h:148
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
#define STATE_CLOSED
Definition defines.h:88
#define STATE_OPENED
Definition defines.h:87
#define UNIT_SIZE
Definition defines.h:121
#define DEBUG_GAME
Definition defines.h:61
#define TU_DOOR_ACTION
Definition defines.h:78
void G_ActorSetClientAction(Edict *actor, Edict *ent)
Handles the client actions (interaction with the world).
Definition g_actor.cpp:82
void G_ActorUseDoor(Actor *actor, Edict *door)
Make the actor use (as in open/close) a door edict.
Definition g_actor.cpp:55
void G_ActorSetTU(Edict *ent, int tus)
Definition g_actor.cpp:267
bool G_IsLivingActor(const Edict *ent)
Checks whether the given edict is a living actor.
Definition g_actor.cpp:43
bool AI_CheckUsingDoor(const Edict *ent, const Edict *door)
Checks whether the AI controlled actor wants to use a door.
Definition g_ai.cpp:396
Artificial Intelligence functions.
Actor * makeActor(Edict *ent)
Convert an Edict pointer into an Actor pointer.
Definition g_edicts.cpp:327
void G_EventDoorOpen(const Edict &door)
Definition g_events.cpp:677
void G_EventSpawnSound(playermask_t playerMask, const Edict &ent, const vec3_t origin, const char *sound)
Spawns a sound (that will be spatialized on the client side).
Definition g_events.cpp:40
void G_EventDoorClose(const Edict &door)
Definition g_events.cpp:683
void G_EventModelExplode(const Edict &ent, const char *sound)
Definition g_events.cpp:697
void G_EventModelExplodeTriggered(const Edict &ent, const char *sound)
Definition g_events.cpp:689
unsigned int playermask_t
Definition g_events.h:34
#define REVERSE
Definition g_func.cpp:326
static bool Door_Use(Edict *door, Edict *activator)
Opens/closes a door.
Definition g_func.cpp:217
static bool Touch_DoorTrigger(Edict *self, Edict *activator)
Trigger to open the door we are standing in front of it.
Definition g_func.cpp:290
void SP_func_breakable(Edict *ent)
func_breakable (0.3 0.3 0.3) ? Used for breakable objects.
Definition g_func.cpp:144
void SP_func_door(Edict *ent)
func_door (0 .5 .8) ? "health" if set, door is destroyable
Definition g_func.cpp:335
void SP_func_door_sliding(Edict *ent)
Definition g_func.cpp:374
static bool Destroy_Breakable(Edict *self)
Definition g_func.cpp:55
void SP_func_rotating(Edict *ent)
Spawns a rotating solid inline brush model.
Definition g_func.cpp:405
static void Reset_DoorTrigger(Edict *self, Edict *activator)
Left the door trigger zone - reset the client action.
Definition g_func.cpp:320
static bool Use_Breakable(Edict *self, Edict *activator)
Definition g_func.cpp:127
static void Door_SlidingUse(Edict *door)
Slides a door.
Definition g_func.cpp:180
static bool Touch_Breakable(Edict *self, Edict *activator)
If an actor was standing on the breakable that is going to get destroyed, we have to let him fall to ...
Definition g_func.cpp:46
func_* edicts
#define FL_TRIGGERED
Trigger the edict at spawn.
Definition g_local.h:302
#define G_IsActor(ent)
Definition g_local.h:127
#define G_IsAI(ent)
Definition g_local.h:141
#define FL_GROUPSLAVE
not the first on the team
Definition g_local.h:294
game_import_t gi
Definition g_main.cpp:39
#define FL_CLIENTACTION
Edict flag to indicate, that the edict can be used in the context of a client action.
Definition g_local.h:298
@ MAT_WOOD
Definition g_local.h:271
@ MAT_METAL
Definition g_local.h:269
@ MAT_GLASS
Definition g_local.h:268
@ MAT_ELECTRICAL
Definition g_local.h:270
@ MAT_MAX
Definition g_local.h:273
#define FL_DESTROYABLE
If an edict is destroyable (like ET_BREAKABLE, ET_DOOR [if health set] or maybe a ET_MISSION [if heal...
Definition g_local.h:289
bool G_MatchIsRunning(void)
Checks whether the game is running (active team and no intermission time).
Definition g_match.cpp:320
Match related functions.
void G_ActorFall(Edict *ent)
Let an actor fall down if e.g. the func_breakable the actor was standing on was destroyed.
Definition g_move.cpp:118
Edict * G_SpawnParticle(const vec3_t origin, int spawnflags, const char *particle)
Definition g_spawn.cpp:551
Brings new objects into the world.
Edict * G_TriggerSpawn(Edict *owner)
void G_TriggerAddToList(Edict *self, Edict *activator)
Adds the activator to the list of recognized edicts for this trigger_touch edict.
Definition g_trigger.cpp:67
bool G_TriggerRemoveFromList(Edict *self, Edict *activator)
Removes an activator from the list of recognized edicts.
Definition g_trigger.cpp:87
Trigger functions.
void G_RecalcRouting(const char *model, const GridBox &box)
Definition g_utils.cpp:452
bool G_UseEdict(Edict *ent, Edict *activator)
Call the 'use' function for the given edict and all its group members.
Definition g_utils.cpp:117
playermask_t G_GetClosePlayerMask(const vec3_t origin, float radius)
Assembles a player mask for those players that have a living team member close to the given location.
Definition g_utils.cpp:288
void G_TouchEdicts(Edict *trigger, float extend)
Call after linking a new trigger in or destroying a bmodel during gameplay to force all entities it c...
Definition g_utils.cpp:625
void G_FreeEdict(Edict *ent)
Marks the edict as free.
Definition g_utils.cpp:41
Misc utility functions for game module.
int G_CheckVisTeamAll(const int team, const vischeckflags_t visFlags, const Edict *ent)
Do G_CheckVisTeam for all entities ent is the one that is looking at the others.
Definition g_vis.cpp:376
void G_CheckVis(Edict *check, const vischeckflags_t visFlags)
Check if the edict appears/perishes for the other teams. If they appear for other teams,...
Definition g_vis.cpp:409
@ SOLID_BSP
Definition game.h:157
voidpf uLong int origin
Definition ioapi.h:45
#define LIST_Foreach(list, type, var)
Iterates over a linked list, it's safe to delete the returned entry from the list while looping over ...
Definition list.h:41
void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Create the rotation matrix in order to rotate something.
Definition mathlib.cpp:631
#define YAW
Definition mathlib.h:55
#define DOOR_ROTATION_ANGLE
Definition q_shared.h:187
@ ET_ROTATING
Definition q_shared.h:158
@ ET_BREAKABLE
Definition q_shared.h:150
@ ET_DOOR
Definition q_shared.h:156
@ ET_DOOR_SLIDING
Definition q_shared.h:157
#define DOOR_OPEN_REVERSE
Definition q_shared.h:293
#define GET_SLIDING_DOOR_SHIFT_VECTOR(dir, speed, vecout)
Definition q_shared.h:294
#define Q_strvalid(string)
Definition shared.h:141
void * data
Definition list.h:31
linkedList_t * next
Definition list.h:32
vec_t vec3_t[3]
Definition ufotypes.h:39
#define VectorMul(scalar, b, dest)
Definition vector.h:48
#define VectorAbs(a)
Definition vector.h:81
#define VectorAdd(a, b, dest)
Definition vector.h:47
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition vector.h:44