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