1 /*
2 sv_pr_cmds.c
3
4 (description)
5
6 Copyright (C) 1996-1997 Id Software, Inc.
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:
21
22 Free Software Foundation, Inc.
23 59 Temple Place - Suite 330
24 Boston, MA 02111-1307, USA
25
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif
34 #ifdef HAVE_STRINGS_H
35 # include <strings.h>
36 #endif
37 #include <ctype.h>
38
39 #include "QF/cbuf.h"
40 #include "QF/clip_hull.h"
41 #include "QF/cmd.h"
42 #include "QF/cvar.h"
43 #include "QF/msg.h"
44 #include "QF/ruamoko.h"
45 #include "QF/sys.h"
46 #include "QF/va.h"
47
48 #include "compat.h"
49 #include "crudefile.h"
50 #include "server.h"
51 #include "sv_gib.h"
52 #include "sv_progs.h"
53 #include "sv_recorder.h"
54 #include "world.h"
55
56 /* BUILT-IN FUNCTIONS */
57
58
59 /*
60 PF_error
61
62 This is a TERMINAL error, which will kill off the entire server.
63 Dumps self.
64
65 error (value)
66 // void (string e) error
67 */
68 static void
PF_error(progs_t * pr)69 PF_error (progs_t *pr)
70 {
71 const char *s;
72 edict_t *ed;
73
74 s = PF_VarString (pr, 0);
75 Sys_Printf ("======SERVER ERROR in %s:\n%s\n",
76 PR_GetString (pr, pr->pr_xfunction->descriptor->s_name), s);
77 ed = PROG_TO_EDICT (pr, *sv_globals.self);
78 ED_Print (pr, ed);
79
80 Sys_Error ("Program error");
81 }
82
83 /*
84 PF_objerror
85
86 Dumps out self, then an error message. The program is aborted and self is
87 removed, but the level can continue.
88
89 objerror (value)
90 // void (string e) objerror
91 */
92 static void
PF_objerror(progs_t * pr)93 PF_objerror (progs_t *pr)
94 {
95 const char *s;
96 edict_t *ed;
97
98 s = PF_VarString (pr, 0);
99 Sys_Printf ("======OBJECT ERROR in %s:\n%s\n",
100 PR_GetString (pr, pr->pr_xfunction->descriptor->s_name), s);
101 ed = PROG_TO_EDICT (pr, *sv_globals.self);
102 ED_Print (pr, ed);
103 ED_Free (pr, ed);
104
105 PR_RunError (pr, "object error");
106 }
107
108 /*
109 PF_makevectors
110
111 Writes new values for v_forward, v_up, and v_right based on angles
112 void (vector angles) makevectors
113 */
114 static void
PF_makevectors(progs_t * pr)115 PF_makevectors (progs_t *pr)
116 {
117 AngleVectors (P_VECTOR (pr, 0), *sv_globals.v_forward,
118 *sv_globals.v_right, *sv_globals.v_up);
119 }
120
121 /*
122 PF_setorigin
123
124 This is the only valid way to move an object without using the physics of
125 the world (setting velocity and waiting). Directly changing origin will
126 not set internal links correctly, so clipping would be messed up. This
127 should be called when an object is spawned, and then only if it is
128 teleported.
129
130 setorigin (entity, origin)
131 // void (entity e, vector o) setorigin
132 */
133 static void
PF_setorigin(progs_t * pr)134 PF_setorigin (progs_t *pr)
135 {
136 edict_t *e;
137 float *org;
138
139 e = P_EDICT (pr, 0);
140 org = P_VECTOR (pr, 1);
141 VectorCopy (org, SVvector (e, origin));
142 SV_LinkEdict (e, false);
143 }
144
145 /*
146 PF_setsize
147
148 the size box is rotated by the current angle
149
150 setsize (entity, minvector, maxvector)
151 // void (entity e, vector min, vector max) setsize
152 */
153 static void
PF_setsize(progs_t * pr)154 PF_setsize (progs_t *pr)
155 {
156 edict_t *e;
157 float *min, *max;
158
159 e = P_EDICT (pr, 0);
160 min = P_VECTOR (pr, 1);
161 max = P_VECTOR (pr, 2);
162 VectorCopy (min, SVvector (e, mins));
163 VectorCopy (max, SVvector (e, maxs));
164 VectorSubtract (max, min, SVvector (e, size));
165 SV_LinkEdict (e, false);
166 }
167
168 /*
169 PF_setmodel
170
171 setmodel (entity, model)
172 // void (entity e, string m) setmodel
173 Also sets size, mins, and maxs for inline bmodels
174 */
175 static void
PF_setmodel(progs_t * pr)176 PF_setmodel (progs_t *pr)
177 {
178 edict_t *e;
179 const char *m, **check;
180 int i;
181 model_t *mod;
182
183 e = P_EDICT (pr, 0);
184 m = P_GSTRING (pr, 1);
185
186 // check to see if model was properly precached
187 for (i = 0, check = sv.model_precache; *check; i++, check++)
188 if (!strcmp (*check, m))
189 break;
190
191 if (!*check)
192 PR_RunError (pr, "no precache: %s\n", m);
193
194 SVstring (e, model) = PR_SetString (pr, m);
195 SVfloat (e, modelindex) = i;
196
197 // if it is an inline model, get the size information for it
198 if (m[0] == '*') {
199 mod = Mod_ForName (m, true);
200 VectorCopy (mod->mins, SVvector (e, mins));
201 VectorCopy (mod->maxs, SVvector (e, maxs));
202 VectorSubtract (mod->maxs, mod->mins, SVvector (e, size));
203 SV_LinkEdict (e, false);
204 }
205 }
206
207 /*
208 PF_bprint
209
210 broadcast print to everyone on server
211
212 bprint (value)
213 // void (string s) bprint
214 */
215 static void
PF_bprint(progs_t * pr)216 PF_bprint (progs_t *pr)
217 {
218 const char *s;
219 int level;
220
221 level = P_FLOAT (pr, 0);
222
223 s = PF_VarString (pr, 1);
224 SV_BroadcastPrintf (level, "%s", s);
225 }
226
227 /*
228 PF_sprint
229
230 single print to a specific client
231
232 sprint (clientent, value)
233 // void (entity client, string s) sprint
234 */
235 static void
PF_sprint(progs_t * pr)236 PF_sprint (progs_t *pr)
237 {
238 const char *s;
239 client_t *client;
240 int entnum, level;
241
242 entnum = P_EDICTNUM (pr, 0);
243 level = P_FLOAT (pr, 1);
244
245 if (entnum < 1 || entnum > MAX_CLIENTS) {
246 Sys_Printf ("tried to sprint to a non-client\n");
247 return;
248 }
249
250 client = &svs.clients[entnum - 1];
251
252 if (client->state == cs_server) //FIXME record to mvd?
253 return;
254
255 s = PF_VarString (pr, 2);
256
257 SV_ClientPrintf (1, client, level, "%s", s);
258 }
259
260 /*
261 PF_centerprint
262
263 single print to a specific client
264
265 centerprint (clientent, value)
266 // void (...) centerprint
267 */
268 static void
PF_centerprint(progs_t * pr)269 PF_centerprint (progs_t *pr)
270 {
271 const char *s;
272 client_t *cl;
273 int entnum;
274
275 entnum = P_EDICTNUM (pr, 0);
276
277 if (entnum < 1 || entnum > MAX_CLIENTS) {
278 Sys_Printf ("tried to sprint to a non-client\n");
279 return;
280 }
281
282 cl = &svs.clients[entnum - 1];
283
284 if (cl->state == cs_server) //FIXME record to mvd?
285 return;
286
287 s = PF_VarString (pr, 1);
288
289 MSG_ReliableWrite_Begin (&cl->backbuf, svc_centerprint, 2 + strlen (s));
290 MSG_ReliableWrite_String (&cl->backbuf, s);
291
292 if (sv.recorders) {
293 sizebuf_t *dbuf;
294 dbuf = SVR_WriteBegin (dem_single, entnum - 1, 2 + strlen (s));
295 MSG_WriteByte (dbuf, svc_centerprint);
296 MSG_WriteString (dbuf, s);
297 }
298 }
299
300 /*
301 PF_ambientsound
302 // void (vector pos, string samp, float vol, float atten) ambientsound
303 */
304 static void
PF_ambientsound(progs_t * pr)305 PF_ambientsound (progs_t *pr)
306 {
307 const char **check;
308 const char *samp;
309 float *pos;
310 float vol, attenuation;
311 int soundnum;
312
313 pos = P_VECTOR (pr, 0);
314 samp = P_GSTRING (pr, 1);
315 vol = P_FLOAT (pr, 2);
316 attenuation = P_FLOAT (pr, 3);
317
318 // check to see if samp was properly precached
319 for (soundnum = 0, check = sv.sound_precache; *check; check++, soundnum++)
320 if (!strcmp (*check, samp))
321 break;
322
323 if (!*check) {
324 Sys_Printf ("no precache: %s\n", samp);
325 return;
326 }
327
328 // add an svc_spawnambient command to the level signon packet
329 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
330 MSG_WriteCoordV (&sv.signon, pos);
331 MSG_WriteByte (&sv.signon, soundnum);
332 MSG_WriteByte (&sv.signon, vol * 255);
333 MSG_WriteByte (&sv.signon, attenuation * 64);
334
335 }
336
337 /*
338 PF_sound
339
340 Each entity can have eight independant sound sources, like voice,
341 weapon, feet, etc.
342
343 Channel 0 is an auto-allocate channel, the others override anything
344 already running on that entity/channel pair.
345
346 An attenuation of 0 will play full volume everywhere in the level.
347 Larger attenuations will drop off.
348 // void (entity e, float chan, string samp) sound
349 */
350 static void
PF_sound(progs_t * pr)351 PF_sound (progs_t *pr)
352 {
353 const char *sample;
354 edict_t *entity;
355 float attenuation;
356 int channel, volume;
357
358 entity = P_EDICT (pr, 0);
359 channel = P_FLOAT (pr, 1);
360 sample = P_GSTRING (pr, 2);
361 volume = P_FLOAT (pr, 3) * 255;
362 attenuation = P_FLOAT (pr, 4);
363
364 SV_StartSound (entity, channel, sample, volume, attenuation);
365 }
366
367 /*
368 PF_traceline
369
370 Used for use tracing and shot targeting.
371 Traces are blocked by bbox and exact bsp entityes, and also slide box
372 entities if the tryents flag is set.
373
374 traceline (vector1, vector2, tryents)
375 // float (vector v1, vector v2, float tryents) traceline
376 */
377 static void
PF_traceline(progs_t * pr)378 PF_traceline (progs_t *pr)
379 {
380 float *v1, *v2;
381 edict_t *ent;
382 int nomonsters;
383 trace_t trace;
384
385 v1 = P_VECTOR (pr, 0);
386 v2 = P_VECTOR (pr, 1);
387 nomonsters = P_FLOAT (pr, 2);
388 ent = P_EDICT (pr, 3);
389
390 if (sv_antilag->int_val == 2)
391 nomonsters |= MOVE_LAGGED;
392
393 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
394
395 *sv_globals.trace_allsolid = trace.allsolid;
396 *sv_globals.trace_startsolid = trace.startsolid;
397 *sv_globals.trace_fraction = trace.fraction;
398 *sv_globals.trace_inwater = trace.inwater;
399 *sv_globals.trace_inopen = trace.inopen;
400 VectorCopy (trace.endpos, *sv_globals.trace_endpos);
401 VectorCopy (trace.plane.normal, *sv_globals.trace_plane_normal);
402 *sv_globals.trace_plane_dist = trace.plane.dist;
403
404 if (trace.ent)
405 *sv_globals.trace_ent = EDICT_TO_PROG (pr, trace.ent);
406 else
407 *sv_globals.trace_ent = EDICT_TO_PROG (pr, sv.edicts);
408 }
409
410 /*
411 PF_tracebox
412 // void (vector start, vector mins, vector maxs, vector end, float type,
413 // entity passent) tracebox
414
415 Wrapper around SV_Move, this makes PF_movetoground and PF_traceline
416 redundant.
417 */
418 static void
PF_tracebox(progs_t * pr)419 PF_tracebox (progs_t *pr)
420 {
421 edict_t *ent;
422 float *start, *end, *mins, *maxs;
423 int type;
424 trace_t trace;
425
426 start = P_VECTOR (pr, 0);
427 mins = P_VECTOR (pr, 1);
428 maxs = P_VECTOR (pr, 2);
429 end = P_VECTOR (pr, 3);
430 type = P_FLOAT (pr, 4);
431 ent = P_EDICT (pr, 5);
432
433 trace = SV_Move (start, mins, maxs, end, type, ent);
434
435 *sv_globals.trace_allsolid = trace.allsolid;
436 *sv_globals.trace_startsolid = trace.startsolid;
437 *sv_globals.trace_fraction = trace.fraction;
438 *sv_globals.trace_inwater = trace.inwater;
439 *sv_globals.trace_inopen = trace.inopen;
440 VectorCopy (trace.endpos, *sv_globals.trace_endpos);
441 VectorCopy (trace.plane.normal, *sv_globals.trace_plane_normal);
442 *sv_globals.trace_plane_dist = trace.plane.dist;
443 if (trace.ent)
444 *sv_globals.trace_ent = EDICT_TO_PROG (pr, trace.ent);
445 else
446 *sv_globals.trace_ent = EDICT_TO_PROG (pr, sv.edicts);
447 }
448
449 /*
450 PF_checkpos
451
452 Returns true if the given entity can move to the given position from it's
453 current position by walking or rolling.
454 FIXME: make work...
455 scalar checkpos (entity, vector)
456 */
457 static void __attribute__ ((used))
PF_checkpos(progs_t * pr)458 PF_checkpos (progs_t *pr)
459 {
460 }
461
462 byte checkpvs[MAX_MAP_LEAFS / 8];
463
464 static int
PF_newcheckclient(progs_t * pr,int check)465 PF_newcheckclient (progs_t *pr, int check)
466 {
467 byte *pvs;
468 edict_t *ent;
469 int i;
470 mleaf_t *leaf;
471 vec3_t org;
472
473 // cycle to the next one
474 if (check < 1)
475 check = 1;
476 if (check > MAX_CLIENTS)
477 check = MAX_CLIENTS;
478
479 if (check == MAX_CLIENTS)
480 i = 1;
481 else
482 i = check + 1;
483
484 for (;; i++) {
485 if (i == MAX_CLIENTS + 1)
486 i = 1;
487
488 ent = EDICT_NUM (pr, i);
489
490 if (i == check)
491 break; // didn't find anything else
492
493 if (ent->free)
494 continue;
495 if (SVfloat (ent, health) <= 0)
496 continue;
497 if ((int) SVfloat (ent, flags) & FL_NOTARGET)
498 continue;
499
500 // anything that is a client, or has a client as an enemy
501 break;
502 }
503
504 // get the PVS for the entity
505 VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org);
506 leaf = Mod_PointInLeaf (org, sv.worldmodel);
507 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
508 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs + 7) >> 3);
509
510 return i;
511 }
512
513 #define MAX_CHECK 16
514 int c_invis, c_notvis;
515
516 /*
517 PF_checkclient
518
519 Returns a client (or object that has a client enemy) that would be a
520 valid target.
521
522 If there are more than one valid options, they are cycled each frame
523
524 If (self.origin + self.viewofs) is not in the PVS of the current target,
525 it is not returned at all.
526
527 name checkclient ()
528 // entity () clientlist
529 */
530 static void
PF_checkclient(progs_t * pr)531 PF_checkclient (progs_t *pr)
532 {
533 edict_t *ent, *self;
534 int l;
535 mleaf_t *leaf;
536 vec3_t view;
537
538 // find a new check if on a new frame
539 if (sv.time - sv.lastchecktime >= 0.1) {
540 sv.lastcheck = PF_newcheckclient (pr, sv.lastcheck);
541 sv.lastchecktime = sv.time;
542 }
543 // return check if it might be visible
544 ent = EDICT_NUM (pr, sv.lastcheck);
545 if (ent->free || SVfloat (ent, health) <= 0) {
546 RETURN_EDICT (pr, sv.edicts);
547 return;
548 }
549 // if current entity can't possibly see the check entity, return 0
550 self = PROG_TO_EDICT (pr, *sv_globals.self);
551 VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view);
552 leaf = Mod_PointInLeaf (view, sv.worldmodel);
553 l = (leaf - sv.worldmodel->leafs) - 1;
554 if ((l < 0) || !(checkpvs[l >> 3] & (1 << (l & 7)))) {
555 c_notvis++;
556 RETURN_EDICT (pr, sv.edicts);
557 return;
558 }
559 // might be able to see it
560 c_invis++;
561 RETURN_EDICT (pr, ent);
562 }
563
564 /*
565 PF_stuffcmd
566
567 Sends text over to the client's execution buffer
568
569 stuffcmd (clientent, value)
570 // void (entity client, string s) stuffcmd
571 */
572 static void
PF_stuffcmd(progs_t * pr)573 PF_stuffcmd (progs_t *pr)
574 {
575 const char *str;
576 char *buf, *p;
577 client_t *cl;
578 int entnum;
579
580 entnum = P_EDICTNUM (pr, 0);
581 if (entnum < 1 || entnum > MAX_CLIENTS)
582 PR_RunError (pr, "Parm 0 not a client");
583
584 cl = &svs.clients[entnum - 1];
585
586 if (cl->state == cs_server) //FIXME record to mvd?
587 return;
588
589 str = P_GSTRING (pr, 1);
590
591 buf = cl->stufftext_buf;
592 if (strlen (buf) + strlen (str) >= MAX_STUFFTEXT)
593 PR_RunError (pr, "stufftext buffer overflow");
594 strcat (buf, str);
595
596 if (!strcmp (buf, "disconnect\n")) {
597 // so long and thanks for all the fish
598 cl->drop = true;
599 buf[0] = 0;
600 return;
601 }
602
603 p = strrchr (buf, '\n');
604 if (p) {
605 char t = p[1];
606 int len = (p - buf) + 2;
607 p[1] = 0;
608 MSG_ReliableWrite_Begin (&cl->backbuf, svc_stufftext, len + 1);
609 MSG_ReliableWrite_String (&cl->backbuf, buf);
610 if (sv.recorders) {
611 sizebuf_t *dbuf;
612 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, len + 1);
613 MSG_WriteByte (dbuf, svc_stufftext);
614 MSG_WriteString (dbuf, buf);
615 }
616 p[1] = t;
617 strcpy (buf, p + 1); // safe because this is a downward, in
618 // buffer move
619 }
620 }
621
622 /*
623 PF_localcmd
624
625 Inserts text into the server console's execution buffer
626
627 localcmd (string)
628 // void (string s) localcmd
629 */
630 static void
PF_localcmd(progs_t * pr)631 PF_localcmd (progs_t *pr)
632 {
633 const char *str;
634
635 str = P_GSTRING (pr, 0);
636 Cbuf_AddText (sv_cbuf, str);
637 }
638
639 /*
640 PF_findradius
641
642 Returns a chain of entities that have origins within a spherical area
643
644 findradius (origin, radius)
645 // entity (vector org, float rad) findradius
646 */
647 static void
PF_findradius(progs_t * pr)648 PF_findradius (progs_t *pr)
649 {
650 edict_t *ent, *chain;
651 float rsqr;
652 vec_t *emins, *emaxs, *org;
653 int i, j;
654 vec3_t eorg;
655
656 chain = (edict_t *) sv.edicts;
657
658 org = P_VECTOR (pr, 0);
659 rsqr = P_FLOAT (pr, 1);
660 rsqr *= rsqr; // Square early, sqrt never
661
662 ent = NEXT_EDICT (pr, sv.edicts);
663 for (i = 1; i < sv.num_edicts; i++, ent = NEXT_EDICT (pr, ent)) {
664 if (ent->free)
665 continue;
666 if (SVfloat (ent, solid) == SOLID_NOT
667 && !((int) SVfloat (ent, flags) & FL_FINDABLE_NONSOLID))
668 continue;
669 emins = SVvector (ent, absmin);
670 emaxs = SVvector (ent, absmax);
671 for (j = 0; j < 3; j++)
672 eorg[j] = org[j] - 0.5 * (emins[j] + emaxs[j]);
673 if (DotProduct (eorg, eorg) > rsqr)
674 continue;
675
676 SVentity (ent, chain) = EDICT_TO_PROG (pr, chain);
677 chain = ent;
678 }
679
680 RETURN_EDICT (pr, chain);
681 }
682
683 // entity () spawn
684 static void
PF_Spawn(progs_t * pr)685 PF_Spawn (progs_t *pr)
686 {
687 edict_t *ed;
688
689 ed = ED_Alloc (pr);
690 RETURN_EDICT (pr, ed);
691 }
692
693 cvar_t *pr_double_remove;
694
695 // void (entity e) remove
696 static void
PF_Remove(progs_t * pr)697 PF_Remove (progs_t *pr)
698 {
699 edict_t *ed;
700
701 ed = P_EDICT (pr, 0);
702 if (NUM_FOR_EDICT (pr, ed) < *pr->reserved_edicts) {
703 if (pr_double_remove->int_val == 1) {
704 PR_DumpState (pr);
705 Sys_Printf ("Reserved entity remove\n");
706 } else // == 2
707 PR_RunError (pr, "Reserved entity remove\n");
708 }
709 if (ed->free && pr_double_remove->int_val) {
710 if (pr_double_remove->int_val == 1) {
711 PR_DumpState (pr);
712 Sys_Printf ("Double entity remove\n");
713 } else // == 2
714 PR_RunError (pr, "Double entity remove\n");
715 }
716 ED_Free (pr, ed);
717 }
718
719 static void
PR_CheckEmptyString(progs_t * pr,const char * s)720 PR_CheckEmptyString (progs_t *pr, const char *s)
721 {
722 if (s[0] <= ' ')
723 PR_RunError (pr, "Bad string");
724 }
725
726 static void
do_precache(progs_t * pr,const char ** cache,int max,const char * name,const char * func)727 do_precache (progs_t *pr, const char **cache, int max, const char *name,
728 const char *func)
729 {
730 int i;
731 char *s;
732
733 if (sv.state != ss_loading)
734 PR_RunError (pr, "%s: Precache can be done only in spawn functions",
735 func);
736
737 PR_CheckEmptyString (pr, name);
738
739 s = Hunk_TempAlloc (strlen (name) + 1);
740 for (i = 0; *name; i++, name++) {
741 int c = (byte) *name;
742 s[i] = tolower (c);
743 }
744 s[i] = 0;
745
746 for (i = 0; i < MAX_SOUNDS; i++) {
747 if (!cache[i]) {
748 char *c = Hunk_Alloc (strlen (s) + 1);
749 strcpy (c, s);
750 cache[i] = c; // blah, const
751 Sys_MaskPrintf (SYS_DEV, "%s: %3d %s\n", func, i, s);
752 return;
753 }
754 if (!strcmp (cache[i], s))
755 return;
756 }
757 PR_RunError (pr, "%s: overflow", func);
758 }
759
760 // string (string s) precache_file
761 // string (string s) precache_file2
762 static void
PF_precache_file(progs_t * pr)763 PF_precache_file (progs_t *pr)
764 {
765 // precache_file is used only to copy files with qcc, it does nothing
766 R_INT (pr) = P_INT (pr, 0);
767 }
768
769 // void (string s) precache_sound
770 // string (string s) precache_sound2
771 static void
PF_precache_sound(progs_t * pr)772 PF_precache_sound (progs_t *pr)
773 {
774 do_precache (pr, sv.sound_precache, MAX_SOUNDS, P_GSTRING (pr, 0),
775 "precache_sound");
776 R_INT (pr) = P_INT (pr, 0);
777 }
778
779 // void (string s) precache_model
780 // string (string s) precache_model2
781 static void
PF_precache_model(progs_t * pr)782 PF_precache_model (progs_t *pr)
783 {
784 do_precache (pr, sv.model_precache, MAX_MODELS, P_GSTRING (pr, 0),
785 "precache_model");
786 R_INT (pr) = P_INT (pr, 0);
787 }
788
789 /*
790 PF_walkmove
791
792 float (float yaw, float dist) walkmove
793 // float (float yaw, float dist) walkmove
794 */
795 static void
PF_walkmove(progs_t * pr)796 PF_walkmove (progs_t *pr)
797 {
798 edict_t *ent;
799 float yaw, dist;
800 int oldself;
801 vec3_t move;
802
803 ent = PROG_TO_EDICT (pr, *sv_globals.self);
804 yaw = P_FLOAT (pr, 0);
805 dist = P_FLOAT (pr, 1);
806
807 if (!((int) SVfloat (ent, flags) & (FL_ONGROUND | FL_FLY | FL_SWIM))) {
808 R_FLOAT (pr) = 0;
809 return;
810 }
811
812 yaw = yaw * M_PI * 2 / 360;
813
814 move[0] = cos (yaw) * dist;
815 move[1] = sin (yaw) * dist;
816 move[2] = 0;
817
818 // save program state, because SV_movestep may call other progs
819 oldself = *sv_globals.self;
820
821 R_FLOAT (pr) = SV_movestep (ent, move, true);
822
823 // restore program state
824 *sv_globals.self = oldself;
825 }
826
827 /*
828 PF_droptofloor
829
830 void () droptofloor
831 // float () droptofloor
832 */
833 static void
PF_droptofloor(progs_t * pr)834 PF_droptofloor (progs_t *pr)
835 {
836 edict_t *ent;
837 trace_t trace;
838 vec3_t end;
839
840 ent = PROG_TO_EDICT (pr, *sv_globals.self);
841
842 VectorCopy (SVvector (ent, origin), end);
843 end[2] -= 256;
844
845 trace = SV_Move (SVvector (ent, origin), SVvector (ent, mins),
846 SVvector (ent, maxs), end, false, ent);
847
848 if (trace.fraction == 1 || trace.allsolid) {
849 R_FLOAT (pr) = 0;
850 } else {
851 VectorCopy (trace.endpos, SVvector (ent, origin));
852 SV_LinkEdict (ent, false);
853 SVfloat (ent, flags) = (int) SVfloat (ent, flags) | FL_ONGROUND;
854 SVentity (ent, groundentity) = EDICT_TO_PROG (pr, trace.ent);
855 R_FLOAT (pr) = 1;
856 }
857 }
858
859 /*
860 PF_lightstyle
861
862 void (float style, string value) lightstyle
863 // void (float style, string value) lightstyle
864 */
865 static void
PF_lightstyle(progs_t * pr)866 PF_lightstyle (progs_t *pr)
867 {
868 const char *val;
869 client_t *cl;
870 int style, j;
871
872 style = P_FLOAT (pr, 0);
873 val = P_GSTRING (pr, 1);
874
875 // change the string in sv
876 sv.lightstyles[style] = val;
877
878 // send message to all clients on this server
879 if (sv.state != ss_active)
880 return;
881
882 for (j = 0, cl = svs.clients; j < MAX_CLIENTS; j++, cl++)
883 if (cl->state == cs_spawned) {
884 MSG_ReliableWrite_Begin (&cl->backbuf, svc_lightstyle,
885 strlen (val) + 3);
886 MSG_ReliableWrite_Char (&cl->backbuf, style);
887 MSG_ReliableWrite_String (&cl->backbuf, val);
888 }
889 if (sv.recorders) {
890 sizebuf_t *dbuf;
891 dbuf = SVR_WriteBegin (dem_all, 0, strlen (val) + 3);
892 MSG_WriteByte (dbuf, svc_lightstyle);
893 MSG_WriteByte (dbuf, style);
894 MSG_WriteString (dbuf, val);
895 }
896 }
897
898 // float (entity e) checkbottom
899 static void
PF_checkbottom(progs_t * pr)900 PF_checkbottom (progs_t *pr)
901 {
902 edict_t *ent;
903
904 ent = P_EDICT (pr, 0);
905
906 R_FLOAT (pr) = SV_CheckBottom (ent);
907 }
908
909 // float (vector v) pointcontents
910 static void
PF_pointcontents(progs_t * pr)911 PF_pointcontents (progs_t *pr)
912 {
913 float *v;
914
915 v = P_VECTOR (pr, 0);
916
917 R_FLOAT (pr) = SV_PointContents (v);
918 }
919
920 cvar_t *sv_aim;
921
922 /*
923 PF_aim
924
925 Pick a vector for the player to shoot along
926 vector aim (entity, missilespeed)
927 // vector (entity e, float speed) aim
928 */
929 static void
PF_aim(progs_t * pr)930 PF_aim (progs_t *pr)
931 {
932 const char *noaim;
933 edict_t *ent, *check, *bestent;
934 float dist, bestdist, speed;
935 float *mins, *maxs, *org;
936 int i, j;
937 trace_t tr;
938 vec3_t start, dir, end, bestdir;
939
940 if (sv_aim->value >= 1.0) {
941 VectorCopy (*sv_globals.v_forward, R_VECTOR (pr));
942 return;
943 }
944
945 ent = P_EDICT (pr, 0);
946 // noaim option
947 i = NUM_FOR_EDICT (pr, ent);
948 if (i > 0 && i < MAX_CLIENTS) {
949 noaim = Info_ValueForKey (svs.clients[i - 1].userinfo, "noaim");
950 if (atoi (noaim) > 0) {
951 VectorCopy (*sv_globals.v_forward, R_VECTOR (pr));
952 return;
953 }
954 }
955
956 speed = P_FLOAT (pr, 1);
957 (void) speed; //FIXME
958
959 VectorCopy (SVvector (ent, origin), start);
960 start[2] += 20;
961
962 // try sending a trace straight
963 VectorCopy (*sv_globals.v_forward, dir);
964 VectorMultAdd (start, 2048, dir, end);
965 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
966 if (tr.ent && SVfloat (tr.ent, takedamage) == DAMAGE_AIM
967 && (!teamplay->int_val || SVfloat (ent, team) <= 0
968 || SVfloat (ent, team) != SVfloat (tr.ent, team))) {
969 VectorCopy (*sv_globals.v_forward, R_VECTOR (pr));
970 return;
971 }
972
973 // try all possible entities
974 VectorCopy (dir, bestdir);
975 bestdist = sv_aim->value;
976 bestent = NULL;
977
978 check = NEXT_EDICT (pr, sv.edicts);
979 for (i = 1; i < sv.num_edicts; i++, check = NEXT_EDICT (pr, check)) {
980 if (SVfloat (check, takedamage) != DAMAGE_AIM)
981 continue;
982 if (check == ent)
983 continue;
984 if (teamplay->int_val && SVfloat (ent, team) > 0
985 && SVfloat (ent, team) == SVfloat (check, team))
986 continue; // don't aim at teammate
987
988 mins = SVvector (check, mins);
989 maxs = SVvector (check, maxs);
990 org = SVvector (check, origin);
991 for (j = 0; j < 3; j++)
992 end[j] = org[j] + 0.5 * (mins[j] + maxs[j]);
993 VectorSubtract (end, start, dir);
994 VectorNormalize (dir);
995 dist = DotProduct (dir, *sv_globals.v_forward);
996 if (dist < bestdist)
997 continue; // to far to turn
998 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
999 if (tr.ent == check) { // can shoot at this one
1000 bestdist = dist;
1001 bestent = check;
1002 }
1003 }
1004
1005 if (bestent) {
1006 VectorSubtract (SVvector (bestent, origin), SVvector (ent, origin),
1007 dir);
1008 dist = DotProduct (dir, *sv_globals.v_forward);
1009 VectorScale (*sv_globals.v_forward, dist, end);
1010 end[2] = dir[2];
1011 VectorNormalize (end);
1012 VectorCopy (end, R_VECTOR (pr));
1013 } else {
1014 VectorCopy (bestdir, R_VECTOR (pr));
1015 }
1016 }
1017
1018 /*
1019 PF_changeyaw
1020
1021 This was a major timewaster in progs, so it was converted to C
1022 // void () ChangeYaw
1023 */
1024 void
PF_changeyaw(progs_t * pr)1025 PF_changeyaw (progs_t *pr)
1026 {
1027 edict_t *ent;
1028 float ideal, current, move, speed;
1029
1030 ent = PROG_TO_EDICT (pr, *sv_globals.self);
1031 current = anglemod (SVvector (ent, angles)[1]);
1032 ideal = SVfloat (ent, ideal_yaw);
1033 speed = SVfloat (ent, yaw_speed);
1034
1035 if (current == ideal)
1036 return;
1037 move = ideal - current;
1038 if (ideal > current) {
1039 if (move >= 180)
1040 move = move - 360;
1041 } else {
1042 if (move <= -180)
1043 move = move + 360;
1044 }
1045 if (move > 0) {
1046 if (move > speed)
1047 move = speed;
1048 } else {
1049 if (move < -speed)
1050 move = -speed;
1051 }
1052
1053 SVvector (ent, angles)[1] = anglemod (current + move);
1054 }
1055
1056 /* MESSAGE WRITING */
1057
1058 #define MSG_BROADCAST 0 // unreliable to all
1059 #define MSG_ONE 1 // reliable to one (msg_entity)
1060 #define MSG_ALL 2 // reliable to all
1061 #define MSG_INIT 3 // write to the init string
1062 #define MSG_MULTICAST 4 // for multicast ()
1063
1064 static sizebuf_t *
WriteDest(progs_t * pr)1065 WriteDest (progs_t *pr)
1066 {
1067 int dest;
1068
1069 dest = P_FLOAT (pr, 0);
1070 switch (dest) {
1071 case MSG_BROADCAST:
1072 return &sv.datagram;
1073
1074 case MSG_ONE:
1075 Sys_Error ("Shouldn't be at MSG_ONE");
1076
1077 case MSG_ALL:
1078 return &sv.reliable_datagram;
1079
1080 case MSG_INIT:
1081 if (sv.state != ss_loading)
1082 PR_RunError (pr, "PF_Write_*: MSG_INIT can be written in only "
1083 "spawn functions");
1084 return &sv.signon;
1085
1086 case MSG_MULTICAST:
1087 return &sv.multicast;
1088
1089 default:
1090 PR_RunError (pr, "WriteDest: bad destination");
1091 break;
1092 }
1093
1094 return NULL;
1095 }
1096
1097 static client_t *
Write_GetClient(progs_t * pr)1098 Write_GetClient (progs_t *pr)
1099 {
1100 edict_t *ent;
1101 int entnum;
1102
1103 ent = PROG_TO_EDICT (pr, *sv_globals.msg_entity);
1104 entnum = NUM_FOR_EDICT (pr, ent);
1105 if (entnum < 1 || entnum > MAX_CLIENTS)
1106 PR_RunError (pr, "Write_GetClient: not a client");
1107 return &svs.clients[entnum - 1];
1108 }
1109
1110 // void (float to, ...) WriteBytes
1111 static void
PF_WriteBytes(progs_t * pr)1112 PF_WriteBytes (progs_t *pr)
1113 {
1114 int i, p;
1115 int count = pr->pr_argc - 1;
1116 byte buf[MAX_PARMS];
1117
1118 for (i = 0; i < count; i++) {
1119 p = P_FLOAT (pr, i + 1);
1120 buf[i] = p;
1121 }
1122
1123 if (P_FLOAT (pr, 0) == MSG_ONE) {
1124 client_t *cl = Write_GetClient (pr);
1125
1126 if (cl->state != cs_server) {
1127 MSG_ReliableCheckBlock (&cl->backbuf, count);
1128 MSG_ReliableWrite_SZ (&cl->backbuf, buf, count);
1129 }
1130 if (sv.recorders) {
1131 sizebuf_t *dbuf;
1132 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, count);
1133 SZ_Write (dbuf, buf, count);
1134 }
1135 } else {
1136 sizebuf_t *msg = WriteDest (pr);
1137 SZ_Write (msg, buf, count);
1138 }
1139 }
1140
1141 // void (float to, float f) WriteByte
1142 static void
PF_WriteByte(progs_t * pr)1143 PF_WriteByte (progs_t *pr)
1144 {
1145 if (P_FLOAT (pr, 0) == MSG_ONE) {
1146 client_t *cl = Write_GetClient (pr);
1147
1148 if (cl->state != cs_server) {
1149 MSG_ReliableCheckBlock (&cl->backbuf, 1);
1150 MSG_ReliableWrite_Byte (&cl->backbuf, P_FLOAT (pr, 1));
1151 }
1152 if (sv.recorders) {
1153 sizebuf_t *dbuf;
1154 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
1155 MSG_WriteByte (dbuf, P_FLOAT (pr, 1));
1156 }
1157 } else
1158 MSG_WriteByte (WriteDest (pr), P_FLOAT (pr, 1));
1159 }
1160
1161 // void (float to, float f) WriteChar
1162 static void
PF_WriteChar(progs_t * pr)1163 PF_WriteChar (progs_t *pr)
1164 {
1165 if (P_FLOAT (pr, 0) == MSG_ONE) {
1166 client_t *cl = Write_GetClient (pr);
1167
1168 if (cl->state != cs_server) {
1169 MSG_ReliableCheckBlock (&cl->backbuf, 1);
1170 MSG_ReliableWrite_Char (&cl->backbuf, P_FLOAT (pr, 1));
1171 }
1172 if (sv.recorders) {
1173 sizebuf_t *dbuf;
1174 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
1175 MSG_WriteByte (dbuf, P_FLOAT (pr, 1));
1176 }
1177 } else
1178 MSG_WriteByte (WriteDest (pr), P_FLOAT (pr, 1));
1179 }
1180
1181 // void (float to, float f) WriteShort
1182 static void
PF_WriteShort(progs_t * pr)1183 PF_WriteShort (progs_t *pr)
1184 {
1185 if (P_FLOAT (pr, 0) == MSG_ONE) {
1186 client_t *cl = Write_GetClient (pr);
1187
1188 if (cl->state != cs_server) {
1189 MSG_ReliableCheckBlock (&cl->backbuf, 2);
1190 MSG_ReliableWrite_Short (&cl->backbuf, P_FLOAT (pr, 1));
1191 }
1192 if (sv.recorders) {
1193 sizebuf_t *dbuf;
1194 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
1195 MSG_WriteShort (dbuf, P_FLOAT (pr, 1));
1196 }
1197 } else
1198 MSG_WriteShort (WriteDest (pr), P_FLOAT (pr, 1));
1199 }
1200
1201 // void (float to, float f) WriteLong
1202 static void
PF_WriteLong(progs_t * pr)1203 PF_WriteLong (progs_t *pr)
1204 {
1205 if (P_FLOAT (pr, 0) == MSG_ONE) {
1206 client_t *cl = Write_GetClient (pr);
1207
1208 if (cl->state != cs_server) {
1209 MSG_ReliableCheckBlock (&cl->backbuf, 4);
1210 MSG_ReliableWrite_Long (&cl->backbuf, P_FLOAT (pr, 1));
1211 }
1212 if (sv.recorders) {
1213 sizebuf_t *dbuf;
1214 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 4);
1215 MSG_WriteLong (dbuf, P_FLOAT (pr, 1));
1216 }
1217 } else
1218 MSG_WriteLong (WriteDest (pr), P_FLOAT (pr, 1));
1219 }
1220
1221 // void (float to, float f) WriteAngle
1222 static void
PF_WriteAngle(progs_t * pr)1223 PF_WriteAngle (progs_t *pr)
1224 {
1225 if (P_FLOAT (pr, 0) == MSG_ONE) {
1226 client_t *cl = Write_GetClient (pr);
1227
1228 if (cl->state != cs_server) {
1229 MSG_ReliableCheckBlock (&cl->backbuf, 1);
1230 MSG_ReliableWrite_Angle (&cl->backbuf, P_FLOAT (pr, 1));
1231 }
1232 if (sv.recorders) {
1233 sizebuf_t *dbuf;
1234 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
1235 MSG_WriteAngle (dbuf, P_FLOAT (pr, 1));
1236 }
1237 } else
1238 MSG_WriteAngle (WriteDest (pr), P_FLOAT (pr, 1));
1239 }
1240
1241 // void (float to, float f) WriteCoord
1242 static void
PF_WriteCoord(progs_t * pr)1243 PF_WriteCoord (progs_t *pr)
1244 {
1245 if (P_FLOAT (pr, 0) == MSG_ONE) {
1246 client_t *cl = Write_GetClient (pr);
1247
1248 if (cl->state != cs_server) {
1249 MSG_ReliableCheckBlock (&cl->backbuf, 2);
1250 MSG_ReliableWrite_Coord (&cl->backbuf, P_FLOAT (pr, 1));
1251 }
1252 if (sv.recorders) {
1253 sizebuf_t *dbuf;
1254 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
1255 MSG_WriteCoord (dbuf, P_FLOAT (pr, 1));
1256 }
1257 } else
1258 MSG_WriteCoord (WriteDest (pr), P_FLOAT (pr, 1));
1259 }
1260
1261 // void (float to, vector v) WriteAngleV
1262 static void
PF_WriteAngleV(progs_t * pr)1263 PF_WriteAngleV (progs_t *pr)
1264 {
1265 float *ang = P_VECTOR (pr, 1);
1266
1267 if (P_FLOAT (pr, 0) == MSG_ONE) {
1268 client_t *cl = Write_GetClient (pr);
1269
1270 if (cl->state != cs_server) {
1271 MSG_ReliableCheckBlock (&cl->backbuf, 1);
1272 MSG_ReliableWrite_AngleV (&cl->backbuf, ang);
1273 }
1274 if (sv.recorders) {
1275 sizebuf_t *dbuf;
1276 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
1277 MSG_WriteAngleV (dbuf, ang);
1278 }
1279 } else
1280 MSG_WriteAngleV (WriteDest (pr), ang);
1281 }
1282
1283 // void (float to, vector v) WriteCoordV
1284 static void
PF_WriteCoordV(progs_t * pr)1285 PF_WriteCoordV (progs_t *pr)
1286 {
1287 float *coord = P_VECTOR (pr, 1);
1288
1289 if (P_FLOAT (pr, 0) == MSG_ONE) {
1290 client_t *cl = Write_GetClient (pr);
1291
1292 if (cl->state != cs_server) {
1293 MSG_ReliableCheckBlock (&cl->backbuf, 2);
1294 MSG_ReliableWrite_CoordV (&cl->backbuf, coord);
1295 }
1296 if (sv.recorders) {
1297 sizebuf_t *dbuf;
1298 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
1299 MSG_WriteCoordV (dbuf, coord);
1300 }
1301 } else
1302 MSG_WriteCoordV (WriteDest (pr), coord);
1303 }
1304
1305 // void (float to, string s) WriteString
1306 static void
PF_WriteString(progs_t * pr)1307 PF_WriteString (progs_t *pr)
1308 {
1309 const char *str = P_GSTRING (pr, 1);
1310
1311 if (P_FLOAT (pr, 0) == MSG_ONE) {
1312 client_t *cl = Write_GetClient (pr);
1313
1314 if (cl->state != cs_server) {
1315 MSG_ReliableCheckBlock (&cl->backbuf, 1 + strlen (str));
1316 MSG_ReliableWrite_String (&cl->backbuf, str);
1317 }
1318 if (sv.recorders) {
1319 sizebuf_t *dbuf;
1320 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1 + strlen (str));
1321 MSG_WriteString (dbuf, str);
1322 }
1323 } else
1324 MSG_WriteString (WriteDest (pr), str);
1325 }
1326
1327 // void (float to, entity s) WriteEntity
1328 static void
PF_WriteEntity(progs_t * pr)1329 PF_WriteEntity (progs_t *pr)
1330 {
1331 int ent = P_EDICTNUM (pr, 1);
1332
1333 if (P_FLOAT (pr, 0) == MSG_ONE) {
1334 client_t *cl = Write_GetClient (pr);
1335
1336 if (cl->state != cs_server) {
1337 MSG_ReliableCheckBlock (&cl->backbuf, 2);
1338 MSG_ReliableWrite_Short (&cl->backbuf, ent);
1339 }
1340 if (sv.recorders) {
1341 sizebuf_t *dbuf;
1342 dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
1343 MSG_WriteShort (dbuf, ent);
1344 }
1345 } else
1346 MSG_WriteShort (WriteDest (pr), ent);
1347 }
1348
1349 // void (entity e) makestatic
1350 static void
PF_makestatic(progs_t * pr)1351 PF_makestatic (progs_t *pr)
1352 {
1353 const char *model;
1354 edict_t *ent;
1355
1356 ent = P_EDICT (pr, 0);
1357
1358 // flush the signon message out to a separate buffer if nearly full
1359 SV_FlushSignon ();
1360
1361 MSG_WriteByte (&sv.signon, svc_spawnstatic);
1362
1363 model = PR_GetString (pr, SVstring (ent, model));
1364 MSG_WriteByte (&sv.signon, SV_ModelIndex (model));
1365
1366 MSG_WriteByte (&sv.signon, SVfloat (ent, frame));
1367 MSG_WriteByte (&sv.signon, SVfloat (ent, colormap));
1368 MSG_WriteByte (&sv.signon, SVfloat (ent, skin));
1369
1370 MSG_WriteCoordAngleV (&sv.signon, SVvector (ent, origin),
1371 SVvector (ent, angles));
1372
1373 // throw the entity away now
1374 ED_Free (pr, ent);
1375 }
1376
1377 // void (entity e) setspawnparms
1378 static void
PF_setspawnparms(progs_t * pr)1379 PF_setspawnparms (progs_t *pr)
1380 {
1381 client_t *client;
1382 edict_t *ent;
1383 int i;
1384
1385 ent = P_EDICT (pr, 0);
1386 i = NUM_FOR_EDICT (pr, ent);
1387 if (i < 1 || i > MAX_CLIENTS)
1388 PR_RunError (pr, "Entity is not a client");
1389
1390 // copy spawn parms out of the client_t
1391 client = svs.clients + (i - 1);
1392
1393 if (client->state == cs_server)
1394 return;
1395
1396 for (i = 0; i < NUM_SPAWN_PARMS; i++)
1397 sv_globals.parms[i] = client->spawn_parms[i];
1398 }
1399
1400 // void (string s) changelevel
1401 static void
PF_changelevel(progs_t * pr)1402 PF_changelevel (progs_t *pr)
1403 {
1404 const char *s;
1405 static int last_spawncount;
1406
1407 // make sure we don't issue two changelevels
1408 if (svs.spawncount == last_spawncount)
1409 return;
1410 last_spawncount = svs.spawncount;
1411
1412 s = P_GSTRING (pr, 0);
1413 Cbuf_AddText (sv_cbuf, va ("map %s\n", s));
1414 }
1415
1416 /*
1417 PF_logfrag
1418
1419 logfrag (killer, killee)
1420 // void (entity killer, entity killee) logfrag
1421 */
1422 static void
PF_logfrag(progs_t * pr)1423 PF_logfrag (progs_t *pr)
1424 {
1425 const char *s;
1426 edict_t *ent1, *ent2;
1427 int e1, e2;
1428
1429 ent1 = P_EDICT (pr, 0);
1430 ent2 = P_EDICT (pr, 1);
1431
1432 e1 = NUM_FOR_EDICT (pr, ent1);
1433 e2 = NUM_FOR_EDICT (pr, ent2);
1434
1435 // do gib event callback
1436 if (sv_frag_e->func) {
1437 char buf[16];
1438 char type1[2], type2[2];
1439 int u1, u2;
1440
1441 type1[1] = type2[1] = 0;
1442 if (e1 < 1 || e1 > MAX_CLIENTS ||
1443 svs.clients[e1 - 1].state == cs_server) {
1444 type1[0] = 'e';
1445 u1 = e1;
1446 } else {
1447 type1[0] = 'c';
1448 u1 = svs.clients[e1 - 1].userid;
1449 }
1450
1451 if (e2 < 1 || e2 > MAX_CLIENTS ||
1452 svs.clients[e1 - 1].state == cs_server) {
1453 type2[0] = 'e';
1454 u2 = e2;
1455 } else {
1456 type2[0] = 'c';
1457 u2 = svs.clients[e2 - 1].userid;
1458 }
1459
1460 snprintf(buf, sizeof(buf), "%d", u2);
1461
1462 GIB_Event_Callback (sv_frag_e, 4, type1, va ("%d", u1), type2, buf);
1463 }
1464
1465 if (e1 < 1 || e1 > MAX_CLIENTS || e2 < 1 || e2 > MAX_CLIENTS)
1466 return;
1467
1468 s = va ("\\%s\\%s\\\n", svs.clients[e1 - 1].name,
1469 svs.clients[e2 - 1].name);
1470
1471 SZ_Print (&svs.log[svs.logsequence & 1], s);
1472 if (sv_fraglogfile) {
1473 Qprintf (sv_fraglogfile, "%s", s);
1474 Qflush (sv_fraglogfile);
1475 }
1476 }
1477
1478 /*
1479 PF_infokey
1480
1481 string (entity e, string key) infokey
1482 // string (entity e, string key) infokey
1483 */
1484 static void
PF_infokey(progs_t * pr)1485 PF_infokey (progs_t *pr)
1486 {
1487 const char *key, *value;
1488 edict_t *e;
1489 int e1;
1490
1491 e = P_EDICT (pr, 0);
1492 e1 = NUM_FOR_EDICT (pr, e);
1493 key = P_GSTRING (pr, 1);
1494
1495 if (sv_hide_version_info->int_val
1496 && (strequal (key, "*qf_version")
1497 || strequal (key, "*qsg_version")
1498 || strequal (key, "no_pogo_stick"))) {
1499 e1 = -1;
1500 }
1501
1502 if (e1 == 0) {
1503 if ((value = Info_ValueForKey (svs.info, key)) == NULL || !*value)
1504 value = Info_ValueForKey (localinfo, key);
1505 } else if (e1 > 0 && e1 <= MAX_CLIENTS
1506 && svs.clients[e1 - 1].userinfo) {
1507 if (!strcmp (key, "ip"))
1508 value = NET_BaseAdrToString (svs.clients[e1 - 1].netchan.
1509 remote_address);
1510 else if (!strcmp (key, "ping")) {
1511 int ping = SV_CalcPing (&svs.clients[e1 - 1]);
1512
1513 value = va ("%d", ping);
1514 } else
1515 value = Info_ValueForKey (svs.clients[e1 - 1].userinfo, key);
1516 } else
1517 value = "";
1518
1519 RETURN_STRING (pr, value);
1520 }
1521
1522 /*
1523 PF_multicast
1524
1525 void (vector where, float set) multicast
1526 // void (vector where, float set) multicast
1527 */
1528 static void
PF_multicast(progs_t * pr)1529 PF_multicast (progs_t *pr)
1530 {
1531 float *o;
1532 int to;
1533
1534 o = P_VECTOR (pr, 0);
1535 to = P_FLOAT (pr, 1);
1536
1537 SV_Multicast (o, to);
1538 }
1539
1540 /*
1541 PF_cfopen
1542
1543 float (string path, string mode) cfopen
1544 // float (string path, string mode) cfopen
1545 */
1546 static void
PF_cfopen(progs_t * pr)1547 PF_cfopen (progs_t *pr)
1548 {
1549 R_FLOAT (pr) = CF_Open (P_GSTRING (pr, 0), P_GSTRING (pr, 1));
1550 }
1551
1552 /*
1553 PF_cfclose
1554
1555 void (float desc) cfclose
1556 // void (float desc) cfclose
1557 */
1558 static void
PF_cfclose(progs_t * pr)1559 PF_cfclose (progs_t *pr)
1560 {
1561 CF_Close ((int) P_FLOAT (pr, 0));
1562 }
1563
1564 /*
1565 PF_cfread
1566
1567 string (float desc) cfread
1568 // string (float desc) cfread
1569 */
1570 static void
PF_cfread(progs_t * pr)1571 PF_cfread (progs_t *pr)
1572 {
1573 RETURN_STRING (pr, CF_Read ((int) P_FLOAT (pr, 0)));
1574 }
1575
1576 /*
1577 PF_cfwrite
1578
1579 float (float desc, string buf) cfwrite
1580 // float (float desc, string buf) cfwrite
1581 */
1582 static void
PF_cfwrite(progs_t * pr)1583 PF_cfwrite (progs_t *pr)
1584 {
1585 R_FLOAT (pr) = CF_Write ((int) P_FLOAT (pr, 0), P_GSTRING (pr, 1));
1586 }
1587
1588 /*
1589 PF_cfeof
1590
1591 float () cfeof
1592 // float (float desc) cfeof
1593 */
1594 static void
PF_cfeof(progs_t * pr)1595 PF_cfeof (progs_t *pr)
1596 {
1597 R_FLOAT (pr) = CF_EOF ((int) P_FLOAT (pr, 0));
1598 }
1599
1600 /*
1601 PF_cfquota
1602
1603 float () cfquota
1604 // float () cfquota
1605 */
1606 static void
PF_cfquota(progs_t * pr)1607 PF_cfquota (progs_t *pr)
1608 {
1609 R_FLOAT (pr) = CF_Quota ();
1610 }
1611
1612 // void (entity ent, string key, string value) setinfokey
1613 static void
PF_setinfokey(progs_t * pr)1614 PF_setinfokey (progs_t *pr)
1615 {
1616 edict_t *edict = P_EDICT (pr, 0);
1617 int e1 = NUM_FOR_EDICT (pr, edict);
1618 const char *key = P_GSTRING (pr, 1);
1619 const char *value = P_GSTRING (pr, 2);
1620
1621 if (e1 == 0) {
1622 SV_SetLocalinfo (key, value);
1623 } else if (e1 <= MAX_CLIENTS) {
1624 SV_SetUserinfo (&svs.clients[e1 - 1], key, value);
1625 }
1626 }
1627
1628 // entity (entity ent) testentitypos
1629 static void
PF_testentitypos(progs_t * pr)1630 PF_testentitypos (progs_t *pr)
1631 {
1632 edict_t *ent = P_EDICT (pr, 0);
1633 ent = SV_TestEntityPosition (ent);
1634 RETURN_EDICT (pr, ent ? ent : sv.edicts);
1635 }
1636
1637 #define MAX_PF_HULLS 64 // FIXME make dynamic?
1638 clip_hull_t *pf_hull_list[MAX_PF_HULLS];
1639
1640 // integer (entity ent, vector point) hullpointcontents
1641 static void
PF_hullpointcontents(progs_t * pr)1642 PF_hullpointcontents (progs_t *pr)
1643 {
1644 edict_t *edict = P_EDICT (pr, 0);
1645 float *mins = P_VECTOR (pr, 1);
1646 float *maxs = P_VECTOR (pr, 2);
1647 float *point = P_VECTOR (pr, 3);
1648 hull_t *hull;
1649 vec3_t offset;
1650
1651 hull = SV_HullForEntity (edict, mins, maxs, 0, offset);
1652 VectorSubtract (point, offset, offset);
1653 R_INT (pr) = SV_HullPointContents (hull, 0, offset);
1654 }
1655
1656 // vector (integer hull, integer max) getboxbounds
1657 static void
PF_getboxbounds(progs_t * pr)1658 PF_getboxbounds (progs_t *pr)
1659 {
1660 clip_hull_t *ch;
1661 int h = P_INT (pr, 0) - 1;
1662
1663 if (h < 0 || h > MAX_PF_HULLS - 1 || !(ch = pf_hull_list[h]))
1664 PR_RunError (pr, "PF_getboxbounds: invalid box hull handle\n");
1665
1666 if (P_INT (pr, 1)) {
1667 VectorCopy (ch->maxs, R_VECTOR (pr));
1668 } else {
1669 VectorCopy (ch->mins, R_VECTOR (pr));
1670 }
1671 }
1672
1673 // integer () getboxhull
1674 static void
PF_getboxhull(progs_t * pr)1675 PF_getboxhull (progs_t *pr)
1676 {
1677 clip_hull_t *ch = 0;
1678 int i;
1679
1680 for (i = 0; i < MAX_PF_HULLS; i++) {
1681 if (!pf_hull_list[i]) {
1682 ch = MOD_Alloc_Hull (6, 6);
1683 break;
1684 }
1685 }
1686
1687 if (ch) {
1688 pf_hull_list[i] = ch;
1689 R_INT (pr) = i + 1;
1690 for (i = 0; i < MAX_MAP_HULLS; i++)
1691 SV_InitHull (ch->hulls[i], ch->hulls[i]->clipnodes,
1692 ch->hulls[i]->planes);
1693 } else {
1694 R_INT (pr) = 0;
1695 }
1696 }
1697
1698 // void (integer hull) freeboxhull
1699 static void
PF_freeboxhull(progs_t * pr)1700 PF_freeboxhull (progs_t *pr)
1701 {
1702 int h = P_INT (pr, 0) - 1;
1703 clip_hull_t *ch;
1704
1705 if (h < 0 || h > MAX_PF_HULLS - 1 || !(ch = pf_hull_list[h]))
1706 PR_RunError (pr, "PF_freeboxhull: invalid box hull handle\n");
1707 pf_hull_list[h] = 0;
1708 MOD_Free_Hull (ch);
1709 }
1710
1711 static vec_t
calc_dist(vec3_t p,vec3_t n,vec3_t * offsets)1712 calc_dist (vec3_t p, vec3_t n, vec3_t *offsets)
1713 {
1714 int i;
1715 vec_t d = DotProduct (p, n);
1716 vec3_t s, v;
1717
1718 VectorScale (n, d, s);
1719 for (i = 0; i < 3; i++)
1720 if (s[i] < 0)
1721 v[i] = offsets[0][i];
1722 else
1723 v[i] = offsets[1][i];
1724 VectorAdd (p, v, v);
1725 return DotProduct (v, n);
1726 }
1727
1728 // void (integer hull, vector right, vector forward, vector up, vector mins, vector maxs) rotate_bbox
1729 static void
PF_rotate_bbox(progs_t * pr)1730 PF_rotate_bbox (progs_t *pr)
1731 {
1732 clip_hull_t *ch;
1733 float l;
1734 float *mi = P_VECTOR (pr, 4);
1735 float *ma = P_VECTOR (pr, 5);
1736 float *dir[3] = {
1737 P_VECTOR (pr, 1),
1738 P_VECTOR (pr, 2),
1739 P_VECTOR (pr, 3),
1740 };
1741
1742 hull_t *hull;
1743 int i, j;
1744 int h = P_INT (pr, 0) - 1;
1745
1746 vec3_t mins, maxs, d;
1747 float *verts[6] = {maxs, mins, maxs, mins, maxs, mins};
1748 vec3_t v[8];
1749 vec3_t offsets[3][2] = {
1750 { { 0, 0, 0 }, { 0, 0, 0} },
1751 { { -16, -16, -32 }, { 16, 16, 24} },
1752 { { -32, -32, -64 }, { 32, 32, 24} },
1753 };
1754
1755 if (h < 0 || h > MAX_PF_HULLS - 1 || !(ch = pf_hull_list[h]))
1756 PR_RunError (pr, "PF_rotate_bbox: invalid box hull handle\n");
1757
1758 // set up the rotation matrix. the three orientation vectors form the
1759 // columns of the rotation matrix
1760 for (i = 0; i < 3; i++) {
1761 for (j = 0; j < 3; j++) {
1762 ch->axis[i][j] = dir[j][i];
1763 }
1764 }
1765 // rotate the bounding box points
1766 for (i = 0; i < 3; i++) {
1767 mins[i] = DotProduct (ch->axis[i], mi);
1768 maxs[i] = DotProduct (ch->axis[i], ma);
1769 }
1770 // find all 8 corners of the rotated box
1771 VectorCopy (mins, v[0]);
1772 VectorCopy (maxs, v[1]);
1773 VectorSubtract (maxs, mins, d);
1774 for (i = 0; i < 3; i++) {
1775 vec3_t x;
1776
1777 l = DotProduct (d, dir[i]);
1778 VectorScale (dir[i], l, x);
1779 VectorAdd (mins, x, v[2 + i * 2]);
1780 VectorSubtract (maxs, x, v[3 + i * 2]);
1781 }
1782 // now find the aligned bounding box
1783 VectorCopy (v[0], ch->mins);
1784 VectorCopy (v[0], ch->maxs);
1785 for (i = 0; i < 8; i++) {
1786 for (j = 0; j < 3; j++) {
1787 ch->mins[j] = min (ch->mins[j], v[i][j]);
1788 ch->maxs[j] = max (ch->maxs[j], v[i][j]);
1789 }
1790 }
1791
1792 // set up the 3 size based hulls
1793 for (j = 0; j < 3; j++) {
1794 hull = ch->hulls[j];
1795 VectorScale (offsets[j][1], -1, hull->clip_mins);
1796 VectorScale (offsets[j][0], -1, hull->clip_maxs);
1797 // set up the clip planes
1798 for (i = 0; i < 6; i++) {
1799 hull->planes[i].dist = calc_dist (verts[i], dir[i / 2],
1800 offsets[j]);
1801 hull->planes[i].type = 4;
1802 VectorCopy (dir[i / 2], hull->planes[i].normal);
1803 }
1804 }
1805 }
1806
1807 // float () checkextension
1808 static void
PF_checkextension(progs_t * pr)1809 PF_checkextension (progs_t *pr)
1810 {
1811 R_FLOAT (pr) = 0; // FIXME: make this function actually useful :P
1812 }
1813
1814 static void
PF_sv_cvar(progs_t * pr)1815 PF_sv_cvar (progs_t *pr)
1816 {
1817 const char *str;
1818
1819 str = P_GSTRING (pr, 0);
1820
1821 if (sv_hide_version_info->int_val
1822 && strequal (str, "sv_hide_version_info")) {
1823 R_FLOAT (pr) = 0;
1824 } else {
1825 R_FLOAT (pr) = Cvar_VariableValue (str);
1826 }
1827 }
1828
1829 // entity () SV_AllocClient
1830 static void
PF_SV_AllocClient(progs_t * pr)1831 PF_SV_AllocClient (progs_t *pr)
1832 {
1833 client_t *cl = SV_AllocClient (0, 1);
1834
1835 if (!cl) {
1836 R_var (pr, entity) = 0;
1837 return;
1838 }
1839
1840 //XXX netchan? Netchan_Setup (&newcl->netchan, adr, qport, NC_READ_QPORT);
1841 cl->state = cs_server;
1842 cl->spectator = 0;
1843 cl->connection_started = realtime;
1844 RETURN_EDICT (pr, cl->edict);
1845 }
1846
1847 // void (entity cl) SV_FreeClient
1848 static void
PF_SV_FreeClient(progs_t * pr)1849 PF_SV_FreeClient (progs_t *pr)
1850 {
1851 int entnum = P_EDICTNUM (pr, 0);
1852 client_t *cl = svs.clients + entnum - 1;
1853
1854 if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1855 PR_RunError (pr, "not a server client");
1856
1857 if (cl->userinfo)
1858 Info_Destroy (cl->userinfo);
1859 cl->userinfo = 0;
1860 SV_FullClientUpdate (cl, &sv.reliable_datagram);
1861 cl->state = cs_free;
1862
1863 //if (sv_client_disconnect_e->func)
1864 // GIB_Event_Callback (sv_client_disconnect_e, 2, va ("%u", cl->userid),
1865 // "server");
1866 }
1867
1868 // void (entity cl, string userinfo) SV_SetUserinfo
1869 static void
PF_SV_SetUserinfo(progs_t * pr)1870 PF_SV_SetUserinfo (progs_t *pr)
1871 {
1872 int entnum = P_EDICTNUM (pr, 0);
1873 client_t *cl = svs.clients + entnum - 1;
1874 const char *str = P_GSTRING (pr, 1);
1875
1876 if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1877 PR_RunError (pr, "not a server client");
1878
1879 cl->userinfo = Info_ParseString (str, 1023, !sv_highchars->int_val);
1880 cl->sendinfo = true;
1881 SV_ExtractFromUserinfo (cl);
1882 }
1883
1884 // void (entity cl, integer ping) SV_SetPing
1885 static void
PR_SV_SetPing(progs_t * pr)1886 PR_SV_SetPing (progs_t *pr)
1887 {
1888 int entnum = P_EDICTNUM (pr, 0);
1889 client_t *cl = svs.clients + entnum - 1;
1890
1891 if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1892 PR_RunError (pr, "not a server client");
1893 cl->ping = P_INT (pr, 1);
1894 }
1895
1896 // void (entity cl, float secs, vector angles, vector move, integer buttons, integer impulse) SV_UserCmd
1897 static void
PR_SV_UserCmd(progs_t * pr)1898 PR_SV_UserCmd (progs_t *pr)
1899 {
1900 usercmd_t ucmd;
1901 int entnum = P_EDICTNUM (pr, 0);
1902 client_t *cl = svs.clients + entnum - 1;
1903
1904 if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1905 PR_RunError (pr, "not a server client");
1906
1907 host_client = cl;
1908 sv_player = host_client->edict;
1909 ucmd.msec = 1000 * P_FLOAT (pr, 1);
1910 VectorCopy (P_VECTOR (pr, 2), ucmd.angles);
1911 VectorCopy (P_VECTOR (pr, 3), &ucmd.forwardmove); //FIXME right order?
1912 ucmd.buttons = P_INT (pr, 4);
1913 ucmd.impulse = P_INT (pr, 5);
1914 cl->localtime = sv.time;
1915 SV_PreRunCmd ();
1916 SV_RunCmd (&ucmd, 0);
1917 SV_PostRunCmd ();
1918 cl->lastcmd = ucmd;
1919 cl->lastcmd.buttons = 0; // avoid multiple fires on lag
1920 }
1921
1922 // void (entity cl) SV_Spawn
1923 static void
PR_SV_Spawn(progs_t * pr)1924 PR_SV_Spawn (progs_t *pr)
1925 {
1926 int entnum = P_EDICTNUM (pr, 0);
1927 client_t *cl = svs.clients + entnum - 1;
1928
1929 if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1930 PR_RunError (pr, "not a server client");
1931
1932 SV_Spawn (cl);
1933 }
1934
1935 #define QF (PR_RANGE_QF << PR_RANGE_SHIFT) |
1936
1937 static builtin_t builtins[] = {
1938 {"makevectors", PF_makevectors, 1},
1939 {"setorigin", PF_setorigin, 2},
1940 {"setmodel", PF_setmodel, 3},
1941 {"setsize", PF_setsize, 4},
1942
1943 {"sound", PF_sound, 8},
1944
1945 {"error", PF_error, 10},
1946 {"objerror", PF_objerror, 11},
1947 {"spawn", PF_Spawn, 14},
1948 {"remove", PF_Remove, 15},
1949 {"traceline", PF_traceline, 16},
1950 {"checkclient", PF_checkclient, 17},
1951
1952 {"precache_sound", PF_precache_sound, 19},
1953 {"precache_model", PF_precache_model, 20},
1954 {"stuffcmd", PF_stuffcmd, 21},
1955 {"findradius", PF_findradius, 22},
1956 {"bprint", PF_bprint, 23},
1957 {"sprint", PF_sprint, 24},
1958
1959 {"walkmove", PF_walkmove, 32},
1960
1961 {"droptofloor", PF_droptofloor, 34},
1962 {"lightstyle", PF_lightstyle, 35},
1963
1964 {"checkbottom", PF_checkbottom, 40},
1965 {"pointcontents", PF_pointcontents, 41},
1966
1967 {"aim", PF_aim, 44},
1968
1969 {"localcmd", PF_localcmd, 46},
1970
1971 {"changeyaw", PF_changeyaw, 49},
1972
1973 {"writebyte", PF_WriteByte, 52},
1974 {"WriteBytes", PF_WriteBytes, -1},
1975 {"writechar", PF_WriteChar, 53},
1976 {"writeshort", PF_WriteShort, 54},
1977 {"writelong", PF_WriteLong, 55},
1978 {"writecoord", PF_WriteCoord, 56},
1979 {"writeangle", PF_WriteAngle, 57},
1980 {"WriteCoordV", PF_WriteCoordV, -1},
1981 {"WriteAngleV", PF_WriteAngleV, -1},
1982 {"writestring", PF_WriteString, 58},
1983 {"writeentity", PF_WriteEntity, 59},
1984
1985 {"movetogoal", SV_MoveToGoal, 67},
1986 {"precache_file", PF_precache_file, 68},
1987 {"makestatic", PF_makestatic, 69},
1988 {"changelevel", PF_changelevel, 70},
1989
1990 {"centerprint", PF_centerprint, 73},
1991 {"ambientsound", PF_ambientsound, 74},
1992 {"precache_model2", PF_precache_model, 75},
1993 {"precache_sound2", PF_precache_sound, 76},
1994 {"precache_file2", PF_precache_file, 77},
1995 {"setspawnparms", PF_setspawnparms, 78},
1996
1997 {"logfrag", PF_logfrag, 79},
1998 {"infokey", PF_infokey, 80},
1999 {"multicast", PF_multicast, 82},
2000
2001 {"testentitypos", PF_testentitypos, QF 92},
2002 {"hullpointcontents", PF_hullpointcontents, QF 93},
2003 {"getboxbounds", PF_getboxbounds, QF 94},
2004 {"getboxhull", PF_getboxhull, QF 95},
2005 {"freeboxhull", PF_freeboxhull, QF 96},
2006 {"rotate_bbox", PF_rotate_bbox, QF 97},
2007 {"tracebox", PF_tracebox, QF 98},
2008 {"checkextension", PF_checkextension, QF 99},
2009 {"setinfokey", PF_setinfokey, QF 102},
2010 {"cfopen", PF_cfopen, QF 103},
2011 {"cfclose", PF_cfclose, QF 104},
2012 {"cfread", PF_cfread, QF 105},
2013 {"cfwrite", PF_cfwrite, QF 106},
2014 {"cfeof", PF_cfeof, QF 107},
2015 {"cfquota", PF_cfquota, QF 108},
2016
2017 {"SV_AllocClient", PF_SV_AllocClient, -1},
2018 {"SV_FreeClient", PF_SV_FreeClient, -1},
2019 {"SV_SetUserinfo", PF_SV_SetUserinfo, -1},
2020 {"SV_SetPing", PR_SV_SetPing, -1},
2021 {"SV_UserCmd", PR_SV_UserCmd, -1},
2022 {"SV_Spawn", PR_SV_Spawn, -1},
2023
2024 {"EntityParseFunction", ED_EntityParseFunction, -1},
2025
2026 {0}
2027 };
2028
2029 void
SV_PR_Cmds_Init()2030 SV_PR_Cmds_Init ()
2031 {
2032 builtin_t *bi;
2033
2034 RUA_Init (&sv_pr_state, 1);
2035
2036 PR_Cmds_Init (&sv_pr_state);
2037 // (override standard builtin)
2038 // float (string s) cvar
2039 bi = PR_FindBuiltin (&sv_pr_state, "cvar");
2040 bi->proc = PF_sv_cvar;
2041
2042 PR_RegisterBuiltins (&sv_pr_state, builtins);
2043 }
2044