Nuclide
Software Development Kit for id Tech
defs.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016-2024 Vera Visions LLC.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
14 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*/
16
17typedef entity id;
18
19/* networking helpers */
20#define NETWORKED_INT(x) int x; int x ##_net;
21#define NETWORKED_FLOAT(x) float x; float x ##_net;
22#define NETWORKED_VECTOR(x) vector x; vector x ##_net;
23#define NETWORKED_ENT(x) entity x; entity x ##_net;
24#define NETWORKED_STRING(x) string x; string x ##_net;
25#define NETWORKED_BOOL(x) bool x; bool x ##_net;
26#define NETWORKED_MODELINDEX(x) float x; float x ##_net;
27
28#define NETWORKED_INT_N(x) int x ##_net;
29#define NETWORKED_FLOAT_N(x) float x ##_net;
30#define NETWORKED_VECTOR_N(x) vector x ##_net;
31#define NETWORKED_STRING_N(x) string x ##_net;
32
33#define PREDICTED_INT(x) int x; int x ##_net;
34#define PREDICTED_FLOAT(x) float x; float x ##_net;
35#define PREDICTED_VECTOR(x) vector x; vector x ##_net;
36#define PREDICTED_ENT(x) entity x; entity x ##_net;
37#define PREDICTED_STRING(x) string x; string x ##_net;
38#define PREDICTED_BOOL(x) bool x; bool x ##_net;
39
40#define PREDICTED_INT_N(x) int x ##_net;
41#define PREDICTED_FLOAT_N(x) float x ##_net;
42#define PREDICTED_VECTOR_N(x) vector x ##_net;
43#define PREDICTED_STRING_N(x) string x ##_net;
44
45#ifdef CLIENT
46#define NSENTITY_READENTITY(x, y) \
47 { \
48 local x x ##_e = ( x )self;\
49 if (y == true) { \
50 self.classname = strcat("spawnfunc_", #x); \
51 callfunction(self.classname); \
52 } \
53 x ##_e.ReceiveEntity( y, readfloat() );\
54 x ##_e.Relink();\
55 }
56#else
57
58#endif
59
60#define NETWORKED_DEFAULT(x, y) x ##_net = x = y;
61
62#define ROLL_BACK(x) x = x ##_net;
63#define SAVE_STATE(x) x ##_net = x;
64#define SAVE_STATE_FIELD(x, y) x ##_net[y] = x[y];
65#define ATTR_CHANGED(x) (x ##_net != x)
66#define VEC_CHANGED(x,y) (x ##_net[y] != x[y])
67
68#ifndef MAX_AMMO_TYPES
69#define MAX_AMMO_TYPES 16i
70#endif
71
72noref const float SVC_TEMPENTITY = 23;
73
74#ifdef CLIENT
76#endif
77
78#include "global.h"
79#include "cloader.h"
80#include "sound.h"
81#include "effects.h"
82#include "math.h"
83
84#ifdef CLIENT
85#include "../gs-entbase/client/defs.h"
86#else
87#include "../gs-entbase/server/defs.h"
88#endif
89
90#include "NSDecal.h"
91
92#include "../botlib/botinfo.h"
93#include "sentences.h"
94
95#include "NSIO.h"
96#include "NSDict.h"
97#include "NSTrigger.h"
98#include "NSEntity.h"
99#include "NSTimer.h"
100#include "NSRenderableEntity.h"
101#include "NSSurfacePropEntity.h"
102#include "NSMoverEntity.h"
103#include "NSPhysicsConstraint.h"
104#include "NSPhysicsEntity.h"
105#include "NSBrushTrigger.h"
106#include "NSPointTrigger.h"
107#include "NSItem.h"
108#include "NSWeapon.h"
109#include "NSNavAI.h"
110#include "NSWeapon_NSNavAI.h"
111#include "NSMonster.h"
112#include "NSSquadMonster.h"
113#include "NSTalkMonster.h"
114#include "NSSpawnPoint.h"
115#include "NSSoundScape.h"
116#include "NSProjectile.h"
117#include "NSSpraylogo.h"
118#include "NSPortal.h"
119#include "NSDebris.h"
120
121#include "../xr/defs.h"
122#include "../botlib/NSBot.h"
123#include "NSClient.h"
124#include "NSClientSpectator.h"
125#include "NSClientPlayer.h"
126
127#include "NSVehicle.h"
128
129#include "materials.h"
130#include "damage.h"
131#include "flags.h"
132#include "entities.h"
133#include "events.h"
134#include "flags.h"
135#include "hitmesh.h"
136#include "pmove.h"
137#include "memory.h"
138#include "platform.h"
139#include "propdata.h"
140#include "surfaceproperties.h"
141#include "decalgroups.h"
142#include "colors.h"
143#include "motd.h"
144#include "util.h"
145#include "ammo.h"
146
147#define BSPVER_PREREL 28
148#define BSPVER_Q1 29
149#define BSPVER_HL 30
150#define BSPVER_Q2 38
151#define BSPVER_Q2W 69
152#define BSPVER_Q3 46
153#define BSPVER_RTCW 47
154#define BSPVER_RBSP 1
155
156#define CLASSEXPORT(a,b) void a(void) { if (!isfunction(#b)) { self.classname = strcat("spawnfunc_", #b); } else { self.classname = #b; } callfunction(self.classname); }
157
158const vector VEC_HULL_MIN = [-16,-16,-36];
159const vector VEC_HULL_MAX = [16,16,36];
160const vector VEC_CHULL_MIN = [-16,-16,-18];
161const vector VEC_CHULL_MAX = [16,16,18];
162
163// Actually used by input_button etc.
164#define INPUT_BUTTON0 0x00000001 /* attack 1*/
165#define INPUT_BUTTON2 0x00000002 /* jumping */
166#define INPUT_BUTTON3 0x00000004 /* prone */
167#define INPUT_BUTTON4 0x00000008 /* reload */
168#define INPUT_BUTTON5 0x00000010 /* secondary */
169#define INPUT_BUTTON6 0x00000020 /* use */
170#define INPUT_BUTTON7 0x00000040 /* reserved */
171#define INPUT_BUTTON8 0x00000080 /* crouching */
172
173#define INPUT_PRIMARY INPUT_BUTTON0
174#define INPUT_JUMP INPUT_BUTTON2
175#define INPUT_PRONE INPUT_BUTTON3
176#define INPUT_RELOAD INPUT_BUTTON4
177#define INPUT_SECONDARY INPUT_BUTTON6
178#define INPUT_USE INPUT_BUTTON5 /* This can NEVER change. Engine hard-coded. */
179#define INPUT_SPRINT INPUT_BUTTON7
180#define INPUT_CROUCH INPUT_BUTTON8
181
182/* sendflags */
183#define UPDATE_ALL 16777215
184
185#define clamp(d,min,max) bound(min,d,max)
186
188{
196
197.float jumptime;
200.float gflags;
201
202void
203Empty(void)
204{
205
206}
207
208void Util_Destroy(void);
209string Util_TimeToString(float fTime);
210bool Util_IsTeamplay(void);
211bool Util_IsPaused(void);
212
213__wrap void
214dprint(string m)
215{
216 if (cvar("developer") == 1)
217 return prior(m);
218}
219
220void
221crossprint(string m)
222{
223#ifdef CLIENT
224 print(strcat("CLIENT: ", m));
225#else
226 print(strcat("SERVER: ", m));
227#endif
228}
229
230#if 0
231__wrap string
232precache_model(string m)
233{
234 if not (m) {
235 breakpoint();
236 return "";
237 }
238
239 if (m == "") {
240 breakpoint();
241 return "";
242 }
243
244 return prior(m);
245}
246#endif
247
248__wrap string
249precache_sound(string sample)
250{
251 if (sample != "") /* not empty */
252 if not(whichpack(strcat("sound/", sample))) { /* not present on disk */
253 NSError("SFX sample %S does not exist.", sample);
254 return "misc/missing.wav";
255 }
256
257 return prior(sample);
258}
259
260/* this could probably be a lot better, use this from now on so that it can be improved later */
261noref float input_sequence;
262float
264{
265 float seed = (float)input_sequence % 5.0f;
266 seed += (float)input_sequence % 8.0f;
267 seed += (float)input_sequence % 4.0f;
268 seed += (float)input_sequence % 13.0f;
269 seed += (float)input_sequence % 70.0f;
270
271 /* like the engine its random(), never return 0, never return 1 */
272 return bound(0.01, (seed) / 100.0f, 0.99f);
273}
274
275#if 0
276__wrap void
277WriteByte(float to, float val)
278{
279 breakpoint();
280 prior(to, val);
281}
282
283__wrap void
284WriteChar(float to, float val)
285{
286 breakpoint();
287 prior(to, val);
288}
289
290__wrap void
291WriteShort(float to, float val)
292{
293 breakpoint();
294 prior(to, val);
295}
296
297__wrap void
298WriteLong(float to, float val)
299{
300 breakpoint();
301 prior(to, val);
302}
303
304__wrap void
305WriteCoord(float to, float val)
306{
307 breakpoint();
308 prior(to, val);
309}
310
311__wrap void
312WriteAngle(float to, float val)
313{
314 breakpoint();
315 prior(to, val);
316}
317
318__wrap void
319WriteString(float to, string val)
320{
321 breakpoint();
322 prior(to, val);
323}
324
325__wrap void
326WriteEntity(float to, entity val)
327{
328 breakpoint();
329 prior(to, val);
330}
331#endif
332
333__wrap void
334setmodel(entity ent, string mname)
335{
336 if (mname != "") /* not empty */
337 if (substring(mname, 0, 1) != "*") /* not a brush */
338 if not(whichpack(mname)) /* not present on disk */
339 return prior(ent, "models/error.vvm");
340
341 return prior(ent, mname);
342}
343
344__wrap __variant*
345memalloc(int size)
346{
347#if 0
348 if (size > 55000)
349 breakpoint();
350
351 print(sprintf("memalloc: %i\n", size));
352#endif
353 return prior(size);
354}
355
356.float identity;
357.float removed;
358__wrap void
360{
361 /* it's an NSEntity sub-class */
362 if (target.identity) {
363 NSEntity ent = (NSEntity)target;
364
365 /* if we're calling remove() on it and not .Destroy()... it's being uncleanly removed! */
366 if (ent.removed == 0) {
367 ent.OnRemoveEntity();
368 breakpoint();
369 print(sprintf("^1WARNING: Entity %d of class %s uncleanly removed!\n", num_for_edict(ent), ent.classname));
370 ent.removed = 1;
371 }
372 }
373
374 target.removed = 0;
375 prior(target);
376}
377
378__wrap void
379traceline(vector v1, vector v2, float flags, entity ent)
380{
381#ifdef SERVER
382 if (autocvar(com_showTracers, 0) == 1) {
383 WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
384 WriteByte(MSG_MULTICAST, EV_TRACEDEBUG);
385 WriteCoord(MSG_MULTICAST, v1[0]);
386 WriteCoord(MSG_MULTICAST, v1[1]);
387 WriteCoord(MSG_MULTICAST, v1[2]);
388 WriteCoord(MSG_MULTICAST, v2[0]);
389 WriteCoord(MSG_MULTICAST, v2[1]);
390 WriteCoord(MSG_MULTICAST, v2[2]);
391 msg_entity = world;
392 multicast(v1, MULTICAST_PVS_R);
393 }
394#endif
395
396#ifdef CLIENT
397 // TODO
398#endif
399 prior(v1, v2, flags, ent);
400}
401
402void
403setorigin_safe(entity target, vector testorg)
404{
405 for (int i = 0; i < 16; i++) {
406 tracebox(testorg, target.mins, target.maxs, testorg, MOVE_NORMAL, target);
407
408 if (!trace_startsolid) {
409 break;
410 }
411
412 testorg[2] += 1.0;
413 }
414
415 setorigin(target, testorg);
416}
417
418#ifdef NO_LEGACY
419void
420readcmd(string foo)
421{
422 localcmd(foo);
423}
424#else
425void(string cmd) readcmd = #0:readcmd;
426#endif
427
428/* This is required because people who use Hammer do awful things
429 to get their models to update. We get a multitude of juicy
430 hacks and symbols that Half-Life's engine strips and now we have to
431 replicate this behaviour. Be thankful this is not done in-engine for
432 every game/mod ever.
433*/
434string Util_FixModel(string mdl)
435{
436 if (!mdl) {
437 return "";
438 }
439
440 int c = tokenizebyseparator(mdl, "/", "\\ ", "!");
441 string newpath = "";
442
443 for (int i = 0; i < c; i++) {
444 newpath = sprintf("%s/%s", newpath, argv(i));
445 }
446
447 /* Kill the first / */
448 newpath = substring(newpath, 1, strlen(newpath)-1);
449
450 /* Now we need to fix \/ because I hate people */
451 c = tokenizebyseparator(newpath, "\\/");
452 mdl = "";
453 for (int i = 0; i < c; i++) {
454 mdl = sprintf("%s/%s", mdl, argv(i));
455 }
456 /* Kill the first / again */
457 mdl = substring(mdl, 1, strlen(mdl)-1);
458
459 if (substring(mdl, 0, 1) == "/")
460 mdl = substring(mdl, 1, -1);
461
462 return mdl;
463}
464
467string
468Util_ChangeExtension(string baseString, string newExtension)
469{
470 float stringOffset = 0;
471 string tempString = "";
472 float foundOffset = 0;
473
474 while ((tempString = substring(baseString, stringOffset, 1))) {
475 if (tempString == ".")
476 foundOffset = stringOffset;
477 if (tempString == "")
478 break;
479 if not (tempString)
480 break;
481
482 stringOffset++;
483 }
484
485 return strcat(substring(baseString, 0, foundOffset), ".", newExtension);
486}
487
488bool
490{
491#ifdef SERVER
492 /* playerslots 1 is always singleplayer */
493 if (cvar("sv_playerslots") == 1)
494 return true;
495
496 /* only when coop is 1, only in multiplayer */
497 if (cvar("coop") == 1 && cvar("sv_playerslots") > 1)
498 return true;
499#endif
500
501 /* else we're multiplayer */
502 return false;
503}
504
505float
507{
508 return ((random() - 0.5f) * 2.0f);
509}
510
511string
512dirname(string input)
513{
514 if (!input) {
515 return "";
516 }
517
518 int c = tokenizebyseparator(input, "/", "\\ ", "!");
519 string newpath = "";
520
521 for (int i = 0; i < (c-1); i++) {
522 newpath = sprintf("%s/%s", newpath, argv(i));
523 }
524
525 /* Kill the first / */
526 newpath = substring(newpath, 1, strlen(newpath)-1);
527
528 return newpath;
529}
530
531string
532textfile_to_string(string filename)
533{
534 string fileContents = __NULL__;
535
536 filestream fileHandle = fopen(filename, FILE_READ);
537 string temp;
538
539 if (fileHandle != -1) {
540 while ((temp = fgets(fileHandle))) {
541 fileContents = strcat(fileContents, temp, "\n");
542 }
543 } else {
544 fileContents = __NULL__;
545 }
546
547 return fileContents;
548}
549
550/* moved from src/botlib/route.qc */
551/* Get's a velocity vector with which we can successfully jump from one place to another */
552vector
553Route_GetJumpVelocity(vector vecFrom, vector vecTo, float flGravMod)
554{
555#if 1
556 float flHeight, flGravity, flTime, flDistance, flDir;
557 vector vecJump = [0,0,0];
558
559 if (flGravMod <= 0.0)
560 flGravMod = 1.0f;
561
562 flGravity = serverkeyfloat("phy_gravity") * flGravMod;
563 flHeight = vecTo[2] - vecFrom[2];
564
565 /* this may not be a much verticality to this jump, use distance instead */
566 if (flHeight <= 0) {
567 flHeight = vlen(vecTo - vecFrom);
568 flTime = flHeight / flGravity;
569 } else {
570 flTime = sqrt(flHeight / (flGravity * 0.5f));
571 if (flTime <= 0) {
572 return [0,0,0];
573 }
574 }
575
576 vecJump = vecTo - vecFrom;
577 vecJump[2] = 0;
578 flDistance = vlen(normalize(vecJump));
579
580 flDir = flDistance / flTime;
581 vecJump *= flDir;
582 vecJump[2] = flTime * flGravity;
583#else
584 vector vecJump = [0,0,0];
585 float flDist = vlen(vecTo - vecFrom);
586 makevectors(vectoangles(vecTo - vecFrom));
587 vecJump = v_forward * flDist;
588 vecJump[2] = 280;
589#endif
590 return vecJump;
591}
592
593bool
594FileExists(string filePath)
595{
596 if (filePath != "") /* not empty */
597 if not(whichpack(filePath)) /* not present on disk */
598 return false;
599
600 return true;
601}
602
603void
604DebugBox(vector absPos, vector minSize, vector maxSize, vector boxColor, float boxAlpha)
605{
606 vector a, b, c, d;
607 vector w, x, y, z;
608
609 a[0] = absPos[0] + minSize[0];
610 a[1] = absPos[1] + maxSize[1];
611
612 b[0] = absPos[0] + maxSize[0];
613 b[1] = absPos[1] + maxSize[1];
614
615 c[0] = absPos[0] + maxSize[0];
616 c[1] = absPos[1] + minSize[1];
617
618 d[0] = absPos[0] + minSize[0];
619 d[1] = absPos[1] + minSize[1];
620
621 a[2] = absPos[2] + maxSize[2];
622 c[2] = absPos[2] + maxSize[2];
623 d[2] = absPos[2] + maxSize[2];
624 b[2] = absPos[2] + maxSize[2];
625
626 w = a;
627 x = b;
628 y = c;
629 z = d;
630
631 w[2] = absPos[2] + minSize[2];
632 x[2] = absPos[2] + minSize[2];
633 y[2] = absPos[2] + minSize[2];
634 z[2] = absPos[2] + minSize[2];
635
636 /* top */
637 R_BeginPolygon("", 0, 0);
638 R_PolygonVertex(a, [1,1], boxColor, boxAlpha);
639 R_PolygonVertex(b, [0,1], boxColor, boxAlpha);
640 R_PolygonVertex(c, [0,0], boxColor, boxAlpha);
641 R_PolygonVertex(d, [1,0], boxColor, boxAlpha);
642 R_EndPolygon();
643
644 /* front */
645 R_BeginPolygon("", 0, 0);
646 R_PolygonVertex(d, [1,1], boxColor * 0.9f, boxAlpha);
647 R_PolygonVertex(c, [0,1], boxColor * 0.9f, boxAlpha);
648 R_PolygonVertex(y, [0,0], boxColor * 0.9f, boxAlpha);
649 R_PolygonVertex(z, [1,0], boxColor * 0.9f, boxAlpha);
650 R_EndPolygon();
651
652 /* back */
653 R_BeginPolygon("", 0, 0);
654 R_PolygonVertex(w, [1,1], boxColor * 0.9f, boxAlpha);
655 R_PolygonVertex(x, [0,1], boxColor * 0.9f, boxAlpha);
656 R_PolygonVertex(b, [0,0], boxColor * 0.9f, boxAlpha);
657 R_PolygonVertex(a, [1,0], boxColor * 0.9f, boxAlpha);
658 R_EndPolygon();
659
660 /* left */
661 R_BeginPolygon("", 0, 0);
662 R_PolygonVertex(a, [1,1], boxColor * 0.8f, boxAlpha);
663 R_PolygonVertex(d, [0,1], boxColor * 0.8f, boxAlpha);
664 R_PolygonVertex(z, [0,0], boxColor * 0.8f, boxAlpha);
665 R_PolygonVertex(w, [1,0], boxColor * 0.8f, boxAlpha);
666 R_EndPolygon();
667
668 /* right */
669 R_BeginPolygon("", 0, 0);
670 R_PolygonVertex(c, [1,1], boxColor * 0.8f, boxAlpha);
671 R_PolygonVertex(b, [0,1], boxColor * 0.8f, boxAlpha);
672 R_PolygonVertex(x, [0,0], boxColor * 0.8f, boxAlpha);
673 R_PolygonVertex(y, [1,0], boxColor * 0.8f, boxAlpha);
674 R_EndPolygon();
675
676 /* bottom */
677 R_BeginPolygon("", 0, 0);
678 R_PolygonVertex(z, [1,1], boxColor, boxAlpha);
679 R_PolygonVertex(y, [0,1], boxColor, boxAlpha);
680 R_PolygonVertex(x, [0,0], boxColor, boxAlpha);
681 R_PolygonVertex(w, [1,0], boxColor, boxAlpha);
682 R_EndPolygon();
683}
684
685/* doxygen definitions */
686
NSEntity is the lowest of the user-accessible entity class.
Definition: NSEntity.h:54
virtual void OnRemoveEntity(void)
Handles what happens before the entity gets removed from the client game.
Definition: NSEntity.qc:1145
@ EV_TRACEDEBUG
Definition: events.h:62
#define NSError(...)
Logs an error message, with timestamp.
Definition: global.h:85
#define enumflags
Doxygen doesn't know what enumflags (aka bitfields) are, used as e.g.
Definition: global.h:34
#define vectoangles
Definition: math.h:43
vector v_forward
Definition: math.h:45
void makevectors(vector angles)
Definition: math.h:48
float flags
Definition: sound.h:113
string target
Definition: defs.h:23
Vector Math Helper Functions.
float(float modidx, string framename) frameforname
string __fullspawndata
Definition: defs.h:121
void(void) PlayerUse
vector Route_GetJumpVelocity(vector vecFrom, vector vecTo, float flGravMod)
Definition: defs.h:553
const vector VEC_HULL_MIN
Definition: defs.h:158
noref float input_sequence
Definition: defs.h:261
@ SEARCH_MULTISEARCH
Definition: defs.h:193
@ SEARCH_FORCESEARCH
Definition: defs.h:192
@ SEARCH_NAMESORT
Definition: defs.h:194
@ SEARCH_FULLPACKAGE
Definition: defs.h:190
@ SEARCH_INSENSITIVE
Definition: defs.h:189
@ SEARCH_ALLOWDUPES
Definition: defs.h:191
__wrap void remove(entity target)
Definition: defs.h:359
__wrap void dprint(string m)
Definition: defs.h:214
float identity
Definition: defs.h:356
void DebugBox(vector absPos, vector minSize, vector maxSize, vector boxColor, float boxAlpha)
Definition: defs.h:604
noref const float SVC_TEMPENTITY
Definition: defs.h:72
__wrap void setmodel(entity ent, string mname)
Definition: defs.h:334
float pseudorandom()
Definition: defs.h:263
float gflags
Definition: defs.h:200
float teleport_time
Definition: defs.h:198
bool FileExists(string filePath)
Definition: defs.h:594
void crossprint(string m)
Definition: defs.h:221
__wrap __variant * memalloc(int size)
Definition: defs.h:345
const vector VEC_CHULL_MAX
Definition: defs.h:161
bool Util_IsSingleplayer(void)
Definition: defs.h:489
__wrap string precache_sound(string sample)
Definition: defs.h:249
string Util_FixModel(string mdl)
Definition: defs.h:434
float crandom(void)
Definition: defs.h:506
bool Util_IsTeamplay(void)
Definition: util.qc:56
float removed
Definition: defs.h:357
__wrap void traceline(vector v1, vector v2, float flags, entity ent)
Definition: defs.h:379
const vector VEC_HULL_MAX
Definition: defs.h:159
string textfile_to_string(string filename)
Definition: defs.h:532
float jumptime
Definition: defs.h:197
void Empty(void)
Definition: defs.h:203
vector basevelocity
Definition: defs.h:199
const vector VEC_CHULL_MIN
Definition: defs.h:160
void setorigin_safe(entity target, vector testorg)
Definition: defs.h:403
void Util_Destroy(void)
Definition: util.qc:28
string Util_TimeToString(float fTime)
Definition: util.qc:34
entity id
Definition: defs.h:17
bool Util_IsPaused(void)
Definition: util.qc:18
string Util_ChangeExtension(string baseString, string newExtension)
Returns a string (usually filename) with only the file extension at the end replaced with a given,...
Definition: defs.h:468
string dirname(string input)
Definition: defs.h:512