1
2 #include "quakedef.h"
3
4 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
5
6 /*
7 ===============================================================================
8
9 BUILT-IN FUNCTIONS
10
11 ===============================================================================
12 */
13
PF_VarString(int first)14 char *PF_VarString (int first)
15 {
16 int i;
17 static char out[256];
18
19 out[0] = 0;
20 for (i=first ; i<pr_argc ; i++)
21 {
22 strcat (out, G_STRING((OFS_PARM0+i*3)));
23 }
24 return out;
25 }
26
27
28 /*
29 =================
30 PF_errror
31
32 This is a TERMINAL error, which will kill off the entire server.
33 Dumps self.
34
35 error(value)
36 =================
37 */
PF_error(void)38 void PF_error (void)
39 {
40 char *s;
41 edict_t *ed;
42
43 s = PF_VarString(0);
44 Con_Printf ("======SERVER ERROR in %s:\n%s\n"
45 ,pr_strings + pr_xfunction->s_name,s);
46 ed = PROG_TO_EDICT(pr_global_struct->self);
47 ED_Print (ed);
48
49 Host_Error ("Program error");
50 }
51
52 /*
53 =================
54 PF_objerror
55
56 Dumps out self, then an error message. The program is aborted and self is
57 removed, but the level can continue.
58
59 objerror(value)
60 =================
61 */
PF_objerror(void)62 void PF_objerror (void)
63 {
64 char *s;
65 edict_t *ed;
66
67 s = PF_VarString(0);
68 Con_Printf ("======OBJECT ERROR in %s:\n%s\n"
69 ,pr_strings + pr_xfunction->s_name,s);
70 ed = PROG_TO_EDICT(pr_global_struct->self);
71 ED_Print (ed);
72 ED_Free (ed);
73
74 Host_Error ("Program error");
75 }
76
77
78
79 /*
80 ==============
81 PF_makevectors
82
83 Writes new values for v_forward, v_up, and v_right based on angles
84 makevectors(vector)
85 ==============
86 */
PF_makevectors(void)87 void PF_makevectors (void)
88 {
89 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
90 }
91
92 /*
93 =================
94 PF_setorigin
95
96 This is the only valid way to move an object without using the physics of the world (setting velocity and waiting). Directly changing origin will not set internal links correctly, so clipping would be messed up. This should be called when an object is spawned, and then only if it is teleported.
97
98 setorigin (entity, origin)
99 =================
100 */
PF_setorigin(void)101 void PF_setorigin (void)
102 {
103 edict_t *e;
104 float *org;
105
106 e = G_EDICT(OFS_PARM0);
107 org = G_VECTOR(OFS_PARM1);
108 VectorCopy (org, e->v.origin);
109 SV_LinkEdict (e, false);
110 }
111
112
SetMinMaxSize(edict_t * e,float * min,float * max,qboolean rotate)113 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
114 {
115 float *angles;
116 vec3_t rmin, rmax;
117 float bounds[2][3];
118 float xvector[2], yvector[2];
119 float a;
120 vec3_t base, transformed;
121 int i, j, k, l;
122
123 for (i=0 ; i<3 ; i++)
124 if (min[i] > max[i])
125 PR_RunError ("backwards mins/maxs");
126
127 rotate = false; // FIXME: implement rotation properly again
128
129 if (!rotate)
130 {
131 VectorCopy (min, rmin);
132 VectorCopy (max, rmax);
133 }
134 else
135 {
136 // find min / max for rotations
137 angles = e->v.angles;
138
139 a = angles[1]/180 * M_PI;
140
141 xvector[0] = cos(a);
142 xvector[1] = sin(a);
143 yvector[0] = -sin(a);
144 yvector[1] = cos(a);
145
146 VectorCopy (min, bounds[0]);
147 VectorCopy (max, bounds[1]);
148
149 rmin[0] = rmin[1] = rmin[2] = 9999;
150 rmax[0] = rmax[1] = rmax[2] = -9999;
151
152 for (i=0 ; i<= 1 ; i++)
153 {
154 base[0] = bounds[i][0];
155 for (j=0 ; j<= 1 ; j++)
156 {
157 base[1] = bounds[j][1];
158 for (k=0 ; k<= 1 ; k++)
159 {
160 base[2] = bounds[k][2];
161
162 // transform the point
163 transformed[0] = xvector[0]*base[0] + yvector[0]*base[1];
164 transformed[1] = xvector[1]*base[0] + yvector[1]*base[1];
165 transformed[2] = base[2];
166
167 for (l=0 ; l<3 ; l++)
168 {
169 if (transformed[l] < rmin[l])
170 rmin[l] = transformed[l];
171 if (transformed[l] > rmax[l])
172 rmax[l] = transformed[l];
173 }
174 }
175 }
176 }
177 }
178
179 // set derived values
180 VectorCopy (rmin, e->v.mins);
181 VectorCopy (rmax, e->v.maxs);
182 VectorSubtract (max, min, e->v.size);
183
184 SV_LinkEdict (e, false);
185 }
186
187 /*
188 =================
189 PF_setsize
190
191 the size box is rotated by the current angle
192
193 setsize (entity, minvector, maxvector)
194 =================
195 */
PF_setsize(void)196 void PF_setsize (void)
197 {
198 edict_t *e;
199 float *min, *max;
200
201 e = G_EDICT(OFS_PARM0);
202 min = G_VECTOR(OFS_PARM1);
203 max = G_VECTOR(OFS_PARM2);
204 SetMinMaxSize (e, min, max, false);
205 }
206
207
208 /*
209 =================
210 PF_setmodel
211
212 setmodel(entity, model)
213 =================
214 */
PF_setmodel(void)215 void PF_setmodel (void)
216 {
217 edict_t *e;
218 char *m, **check;
219 model_t *mod;
220 int i;
221
222 e = G_EDICT(OFS_PARM0);
223 m = G_STRING(OFS_PARM1);
224
225 // check to see if model was properly precached
226 for (i=0, check = sv.model_precache ; *check ; i++, check++)
227 if (!strcmp(*check, m))
228 break;
229
230 if (!*check)
231 PR_RunError ("no precache: %s\n", m);
232
233
234 e->v.model = m - pr_strings;
235 e->v.modelindex = i; //SV_ModelIndex (m);
236
237 mod = sv.models[ (int)e->v.modelindex]; // Mod_ForName (m, true);
238
239 if (mod)
240 SetMinMaxSize (e, mod->mins, mod->maxs, true);
241 else
242 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
243 }
244
245 /*
246 =================
247 PF_bprint
248
249 broadcast print to everyone on server
250
251 bprint(value)
252 =================
253 */
PF_bprint(void)254 void PF_bprint (void)
255 {
256 char *s;
257
258 s = PF_VarString(0);
259 SV_BroadcastPrintf (s);
260 }
261
262 /*
263 =================
264 PF_sprint
265
266 single print to a specific client
267
268 sprint(clientent, value)
269 =================
270 */
PF_sprint(void)271 void PF_sprint (void)
272 {
273 char *s;
274 client_t *client;
275 int entnum;
276
277 entnum = G_EDICTNUM(OFS_PARM0);
278 s = PF_VarString(1);
279
280 if (entnum < 1 || entnum > svs.maxclients)
281 {
282 Con_Printf ("tried to sprint to a non-client\n");
283 return;
284 }
285
286 client = &svs.clients[entnum-1];
287
288 MSG_WriteChar (&client->message,svc_print);
289 MSG_WriteString (&client->message, s );
290 }
291
292
293 /*
294 =================
295 PF_centerprint
296
297 single print to a specific client
298
299 centerprint(clientent, value)
300 =================
301 */
PF_centerprint(void)302 void PF_centerprint (void)
303 {
304 char *s;
305 client_t *client;
306 int entnum;
307
308 entnum = G_EDICTNUM(OFS_PARM0);
309 s = PF_VarString(1);
310
311 if (entnum < 1 || entnum > svs.maxclients)
312 {
313 Con_Printf ("tried to sprint to a non-client\n");
314 return;
315 }
316
317 client = &svs.clients[entnum-1];
318
319 MSG_WriteChar (&client->message,svc_centerprint);
320 MSG_WriteString (&client->message, s );
321 }
322
323
324 /*
325 =================
326 PF_normalize
327
328 vector normalize(vector)
329 =================
330 */
PF_normalize(void)331 void PF_normalize (void)
332 {
333 float *value1;
334 vec3_t newvalue;
335 float new;
336
337 value1 = G_VECTOR(OFS_PARM0);
338
339 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
340 new = sqrt(new);
341
342 if (new == 0)
343 newvalue[0] = newvalue[1] = newvalue[2] = 0;
344 else
345 {
346 new = 1/new;
347 newvalue[0] = value1[0] * new;
348 newvalue[1] = value1[1] * new;
349 newvalue[2] = value1[2] * new;
350 }
351
352 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
353 }
354
355 /*
356 =================
357 PF_vlen
358
359 scalar vlen(vector)
360 =================
361 */
PF_vlen(void)362 void PF_vlen (void)
363 {
364 float *value1;
365 float new;
366
367 value1 = G_VECTOR(OFS_PARM0);
368
369 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
370 new = sqrt(new);
371
372 G_FLOAT(OFS_RETURN) = new;
373 }
374
375 /*
376 =================
377 PF_vectoyaw
378
379 float vectoyaw(vector)
380 =================
381 */
PF_vectoyaw(void)382 void PF_vectoyaw (void)
383 {
384 float *value1;
385 float yaw;
386
387 value1 = G_VECTOR(OFS_PARM0);
388
389 if (value1[1] == 0 && value1[0] == 0)
390 yaw = 0;
391 else
392 {
393 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
394 if (yaw < 0)
395 yaw += 360;
396 }
397
398 G_FLOAT(OFS_RETURN) = yaw;
399 }
400
401
402 /*
403 =================
404 PF_vectoangles
405
406 vector vectoangles(vector)
407 =================
408 */
PF_vectoangles(void)409 void PF_vectoangles (void)
410 {
411 float *value1;
412 float forward;
413 float yaw, pitch;
414
415 value1 = G_VECTOR(OFS_PARM0);
416
417 if (value1[1] == 0 && value1[0] == 0)
418 {
419 yaw = 0;
420 if (value1[2] > 0)
421 pitch = 90;
422 else
423 pitch = 270;
424 }
425 else
426 {
427 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
428 if (yaw < 0)
429 yaw += 360;
430
431 forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
432 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
433 if (pitch < 0)
434 pitch += 360;
435 }
436
437 G_FLOAT(OFS_RETURN+0) = pitch;
438 G_FLOAT(OFS_RETURN+1) = yaw;
439 G_FLOAT(OFS_RETURN+2) = 0;
440 }
441
442 /*
443 =================
444 PF_Random
445
446 Returns a number from 0<= num < 1
447
448 random()
449 =================
450 */
PF_random(void)451 void PF_random (void)
452 {
453 float num;
454
455 num = (rand ()&0x7fff) / ((float)0x7fff);
456
457 G_FLOAT(OFS_RETURN) = num;
458 }
459
460 /*
461 =================
462 PF_particle
463
464 particle(origin, color, count)
465 =================
466 */
PF_particle(void)467 void PF_particle (void)
468 {
469 float *org, *dir;
470 float color;
471 float count;
472
473 org = G_VECTOR(OFS_PARM0);
474 dir = G_VECTOR(OFS_PARM1);
475 color = G_FLOAT(OFS_PARM2);
476 count = G_FLOAT(OFS_PARM3);
477 SV_StartParticle (org, dir, color, count);
478 }
479
480
481 /*
482 =================
483 PF_ambientsound
484
485 =================
486 */
PF_ambientsound(void)487 void PF_ambientsound (void)
488 {
489 char **check;
490 char *samp;
491 float *pos;
492 float vol, attenuation;
493 int i, soundnum;
494
495 pos = G_VECTOR (OFS_PARM0);
496 samp = G_STRING(OFS_PARM1);
497 vol = G_FLOAT(OFS_PARM2);
498 attenuation = G_FLOAT(OFS_PARM3);
499
500 // check to see if samp was properly precached
501 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
502 if (!strcmp(*check,samp))
503 break;
504
505 if (!*check)
506 {
507 Con_Printf ("no precache: %s\n", samp);
508 return;
509 }
510
511 // add an svc_spawnambient command to the level signon packet
512
513 MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
514 for (i=0 ; i<3 ; i++)
515 MSG_WriteCoord(&sv.signon, pos[i]);
516
517 MSG_WriteByte (&sv.signon, soundnum);
518
519 MSG_WriteByte (&sv.signon, vol*255);
520 MSG_WriteByte (&sv.signon, attenuation*64);
521
522 }
523
524 /*
525 =================
526 PF_sound
527
528 Each entity can have eight independant sound sources, like voice,
529 weapon, feet, etc.
530
531 Channel 0 is an auto-allocate channel, the others override anything
532 allready running on that entity/channel pair.
533
534 An attenuation of 0 will play full volume everywhere in the level.
535 Larger attenuations will drop off.
536
537 =================
538 */
PF_sound(void)539 void PF_sound (void)
540 {
541 char *sample;
542 int channel;
543 edict_t *entity;
544 int volume;
545 float attenuation;
546
547 entity = G_EDICT(OFS_PARM0);
548 channel = G_FLOAT(OFS_PARM1);
549 sample = G_STRING(OFS_PARM2);
550 volume = G_FLOAT(OFS_PARM3) * 255;
551 attenuation = G_FLOAT(OFS_PARM4);
552
553 if (volume < 0 || volume > 255)
554 Sys_Error ("SV_StartSound: volume = %i", volume);
555
556 if (attenuation < 0 || attenuation > 4)
557 Sys_Error ("SV_StartSound: attenuation = %f", attenuation);
558
559 if (channel < 0 || channel > 7)
560 Sys_Error ("SV_StartSound: channel = %i", channel);
561
562 SV_StartSound (entity, channel, sample, volume, attenuation);
563 }
564
565 /*
566 =================
567 PF_break
568
569 break()
570 =================
571 */
PF_break(void)572 void PF_break (void)
573 {
574 Con_Printf ("break statement\n");
575 *(int *)-4 = 0; // dump to debugger
576 // PR_RunError ("break statement");
577 }
578
579 /*
580 =================
581 PF_traceline
582
583 Used for use tracing and shot targeting
584 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
585 if the tryents flag is set.
586
587 traceline (vector1, vector2, tryents)
588 =================
589 */
PF_traceline(void)590 void PF_traceline (void)
591 {
592 float *v1, *v2;
593 trace_t trace;
594 int nomonsters;
595 edict_t *ent;
596
597 v1 = G_VECTOR(OFS_PARM0);
598 v2 = G_VECTOR(OFS_PARM1);
599 nomonsters = G_FLOAT(OFS_PARM2);
600 ent = G_EDICT(OFS_PARM3);
601
602 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
603
604 pr_global_struct->trace_allsolid = trace.allsolid;
605 pr_global_struct->trace_startsolid = trace.startsolid;
606 pr_global_struct->trace_fraction = trace.fraction;
607 pr_global_struct->trace_inwater = trace.inwater;
608 pr_global_struct->trace_inopen = trace.inopen;
609 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
610 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
611 pr_global_struct->trace_plane_dist = trace.plane.dist;
612 if (trace.ent)
613 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
614 else
615 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
616 }
617
618 /*
619 =================
620 PF_checkpos
621
622 Returns true if the given entity can move to the given position from it's
623 current position by walking or rolling.
624 FIXME: make work...
625 scalar checkpos (entity, vector)
626 =================
627 */
PF_checkpos(void)628 void PF_checkpos (void)
629 {
630 }
631
632 //============================================================================
633
634 byte checkpvs[MAX_MAP_LEAFS/8];
635
PF_newcheckclient(int check)636 int PF_newcheckclient (int check)
637 {
638 int i;
639 byte *pvs;
640 edict_t *ent;
641 mleaf_t *leaf;
642 vec3_t org;
643
644 // cycle to the next one
645
646 if (check < 1)
647 check = 1;
648 if (check > svs.maxclients)
649 check = svs.maxclients;
650
651 if (check == svs.maxclients)
652 i = 1;
653 else
654 i = check + 1;
655
656 for ( ; ; i++)
657 {
658 if (i == svs.maxclients+1)
659 i = 1;
660
661 ent = EDICT_NUM(i);
662
663 if (i == check)
664 break; // didn't find anything else
665
666 if (ent->free)
667 continue;
668 if (ent->v.health <= 0)
669 continue;
670 if ((int)ent->v.flags & FL_NOTARGET)
671 continue;
672
673 // anything that is a client, or has a client as an enemy
674 break;
675 }
676
677 // get the PVS for the entity
678 VectorAdd (ent->v.origin, ent->v.view_ofs, org);
679 leaf = Mod_PointInLeaf (org, sv.worldmodel);
680 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
681 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
682
683 return i;
684 }
685
686 /*
687 =================
688 PF_checkclient
689
690 Returns a client (or object that has a client enemy) that would be a
691 valid target.
692
693 If there are more than one valid options, they are cycled each frame
694
695 If (self.origin + self.viewofs) is not in the PVS of the current target,
696 it is not returned at all.
697
698 name checkclient ()
699 =================
700 */
701 #define MAX_CHECK 16
702 int c_invis, c_notvis;
PF_checkclient(void)703 void PF_checkclient (void)
704 {
705 edict_t *ent, *self;
706 mleaf_t *leaf;
707 int l;
708 vec3_t view;
709
710 // find a new check if on a new frame
711 if (sv.time - sv.lastchecktime >= 0.1)
712 {
713 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
714 sv.lastchecktime = sv.time;
715 }
716
717 // return check if it might be visible
718 ent = EDICT_NUM(sv.lastcheck);
719 if (ent->free || ent->v.health <= 0)
720 {
721 RETURN_EDICT(sv.edicts);
722 return;
723 }
724
725 // if current entity can't possibly see the check entity, return 0
726 self = PROG_TO_EDICT(pr_global_struct->self);
727 VectorAdd (self->v.origin, self->v.view_ofs, view);
728 leaf = Mod_PointInLeaf (view, sv.worldmodel);
729 l = (leaf - sv.worldmodel->leafs) - 1;
730 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
731 {
732 c_notvis++;
733 RETURN_EDICT(sv.edicts);
734 return;
735 }
736
737 // might be able to see it
738 c_invis++;
739 RETURN_EDICT(ent);
740 }
741
742 //============================================================================
743
744
745 /*
746 =================
747 PF_stuffcmd
748
749 Sends text over to the client's execution buffer
750
751 stuffcmd (clientent, value)
752 =================
753 */
PF_stuffcmd(void)754 void PF_stuffcmd (void)
755 {
756 int entnum;
757 char *str;
758 client_t *old;
759
760 entnum = G_EDICTNUM(OFS_PARM0);
761 if (entnum < 1 || entnum > svs.maxclients)
762 PR_RunError ("Parm 0 not a client");
763 str = G_STRING(OFS_PARM1);
764
765 old = host_client;
766 host_client = &svs.clients[entnum-1];
767 Host_ClientCommands ("%s", str);
768 host_client = old;
769 }
770
771 /*
772 =================
773 PF_localcmd
774
775 Sends text over to the client's execution buffer
776
777 localcmd (string)
778 =================
779 */
PF_localcmd(void)780 void PF_localcmd (void)
781 {
782 char *str;
783
784 str = G_STRING(OFS_PARM0);
785 Cbuf_AddText (str);
786 }
787
788 /*
789 =================
790 PF_cvar
791
792 float cvar (string)
793 =================
794 */
PF_cvar(void)795 void PF_cvar (void)
796 {
797 char *str;
798
799 str = G_STRING(OFS_PARM0);
800
801 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
802 }
803
804 /*
805 =================
806 PF_cvar_set
807
808 float cvar (string)
809 =================
810 */
PF_cvar_set(void)811 void PF_cvar_set (void)
812 {
813 char *var, *val;
814
815 var = G_STRING(OFS_PARM0);
816 val = G_STRING(OFS_PARM1);
817
818 Cvar_Set (var, val);
819 }
820
821 /*
822 =================
823 PF_findradius
824
825 Returns a chain of entities that have origins within a spherical area
826
827 findradius (origin, radius)
828 =================
829 */
PF_findradius(void)830 void PF_findradius (void)
831 {
832 edict_t *ent, *chain;
833 float rad;
834 float *org;
835 vec3_t eorg;
836 int i, j;
837
838 chain = (edict_t *)sv.edicts;
839
840 org = G_VECTOR(OFS_PARM0);
841 rad = G_FLOAT(OFS_PARM1);
842
843 ent = NEXT_EDICT(sv.edicts);
844 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
845 {
846 if (ent->free)
847 continue;
848 if (ent->v.solid == SOLID_NOT)
849 continue;
850 for (j=0 ; j<3 ; j++)
851 eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5);
852 if (Length(eorg) > rad)
853 continue;
854
855 ent->v.chain = EDICT_TO_PROG(chain);
856 chain = ent;
857 }
858
859 RETURN_EDICT(chain);
860 }
861
862
863 /*
864 =========
865 PF_dprint
866 =========
867 */
PF_dprint(void)868 void PF_dprint (void)
869 {
870 Con_Printf ("%s",PF_VarString(0));
871 }
872
873 char pr_string_temp[128];
874
PF_ftos(void)875 void PF_ftos (void)
876 {
877 float v;
878 v = G_FLOAT(OFS_PARM0);
879
880 if (v == (int)v)
881 sprintf (pr_string_temp, "%d",(int)v);
882 else
883 sprintf (pr_string_temp, "%5.1f",v);
884 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
885 }
886
PF_fabs(void)887 void PF_fabs (void)
888 {
889 float v;
890 v = G_FLOAT(OFS_PARM0);
891 G_FLOAT(OFS_RETURN) = fabs(v);
892 }
893
PF_vtos(void)894 void PF_vtos (void)
895 {
896 sprintf (pr_string_temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
897 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
898 }
899
PF_Spawn(void)900 void PF_Spawn (void)
901 {
902 edict_t *ed;
903 ed = ED_Alloc();
904 RETURN_EDICT(ed);
905 }
906
PF_Remove(void)907 void PF_Remove (void)
908 {
909 edict_t *ed;
910
911 ed = G_EDICT(OFS_PARM0);
912 ED_Free (ed);
913 }
914
915
916 // entity (entity start, .string field, string match) find = #5;
PF_Find(void)917 void PF_Find (void)
918 {
919 int e;
920 int f;
921 char *s, *t;
922 edict_t *ed;
923
924 e = G_EDICTNUM(OFS_PARM0);
925 f = G_INT(OFS_PARM1);
926 s = G_STRING(OFS_PARM2);
927 if (!s)
928 PR_RunError ("PF_Find: bad search string");
929
930 for (e++ ; e < sv.num_edicts ; e++)
931 {
932 ed = EDICT_NUM(e);
933 if (ed->free)
934 continue;
935 t = E_STRING(ed,f);
936 if (!t)
937 continue;
938 if (!strcmp(t,s))
939 {
940 RETURN_EDICT(ed);
941 return;
942 }
943 }
944
945 RETURN_EDICT(sv.edicts);
946 }
947
PR_CheckEmptyString(char * s)948 void PR_CheckEmptyString (char *s)
949 {
950 if (s[0] <= ' ')
951 PR_RunError ("Bad string");
952 }
953
PF_precache_file(void)954 void PF_precache_file (void)
955 { // precache_file is only used to copy files with qcc, it does nothing
956 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
957 }
958
PF_precache_sound(void)959 void PF_precache_sound (void)
960 {
961 char *s;
962 int i;
963
964 if (sv.state != ss_loading)
965 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
966
967 s = G_STRING(OFS_PARM0);
968 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
969 PR_CheckEmptyString (s);
970
971 for (i=0 ; i<MAX_SOUNDS ; i++)
972 {
973 if (!sv.sound_precache[i])
974 {
975 sv.sound_precache[i] = s;
976 return;
977 }
978 if (!strcmp(sv.sound_precache[i], s))
979 return;
980 }
981 PR_RunError ("PF_precache_sound: overflow");
982 }
983
PF_precache_model(void)984 void PF_precache_model (void)
985 {
986 char *s;
987 int i;
988
989 if (sv.state != ss_loading)
990 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
991
992 s = G_STRING(OFS_PARM0);
993 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
994 PR_CheckEmptyString (s);
995
996 for (i=0 ; i<MAX_MODELS ; i++)
997 {
998 if (!sv.model_precache[i])
999 {
1000 sv.model_precache[i] = s;
1001 sv.models[i] = Mod_ForName (s, true);
1002 return;
1003 }
1004 if (!strcmp(sv.model_precache[i], s))
1005 return;
1006 }
1007 PR_RunError ("PF_precache_model: overflow");
1008 }
1009
1010
PF_coredump(void)1011 void PF_coredump (void)
1012 {
1013 ED_PrintEdicts ();
1014 }
1015
PF_traceon(void)1016 void PF_traceon (void)
1017 {
1018 pr_trace = true;
1019 }
1020
PF_traceoff(void)1021 void PF_traceoff (void)
1022 {
1023 pr_trace = false;
1024 }
1025
PF_eprint(void)1026 void PF_eprint (void)
1027 {
1028 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1029 }
1030
1031 /*
1032 ===============
1033 PF_walkmove
1034
1035 float(float yaw, float dist) walkmove
1036 ===============
1037 */
PF_walkmove(void)1038 void PF_walkmove (void)
1039 {
1040 edict_t *ent;
1041 float yaw, dist;
1042 vec3_t move;
1043 dfunction_t *oldf;
1044 int oldself;
1045
1046 ent = PROG_TO_EDICT(pr_global_struct->self);
1047 yaw = G_FLOAT(OFS_PARM0);
1048 dist = G_FLOAT(OFS_PARM1);
1049
1050 if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1051 {
1052 G_FLOAT(OFS_RETURN) = 0;
1053 return;
1054 }
1055
1056 yaw = yaw*M_PI*2 / 360;
1057
1058 move[0] = cos(yaw)*dist;
1059 move[1] = sin(yaw)*dist;
1060 move[2] = 0;
1061
1062 // save program state, because SV_movestep may call other progs
1063 oldf = pr_xfunction;
1064 oldself = pr_global_struct->self;
1065
1066 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1067
1068
1069 // restore program state
1070 pr_xfunction = oldf;
1071 pr_global_struct->self = oldself;
1072 }
1073
1074 /*
1075 ===============
1076 PF_droptofloor
1077
1078 void() droptofloor
1079 ===============
1080 */
PF_droptofloor(void)1081 void PF_droptofloor (void)
1082 {
1083 edict_t *ent;
1084 vec3_t end;
1085 trace_t trace;
1086
1087 ent = PROG_TO_EDICT(pr_global_struct->self);
1088
1089 VectorCopy (ent->v.origin, end);
1090 end[2] -= 256;
1091
1092 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
1093
1094 if (trace.fraction == 1 || trace.allsolid)
1095 G_FLOAT(OFS_RETURN) = 0;
1096 else
1097 {
1098 VectorCopy (trace.endpos, ent->v.origin);
1099 SV_LinkEdict (ent, false);
1100 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1101 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1102 G_FLOAT(OFS_RETURN) = 1;
1103 }
1104 }
1105
1106 /*
1107 ===============
1108 PF_lightstyle
1109
1110 void(float style, string value) lightstyle
1111 ===============
1112 */
PF_lightstyle(void)1113 void PF_lightstyle (void)
1114 {
1115 int style;
1116 char *val;
1117 client_t *client;
1118 int j;
1119
1120 style = G_FLOAT(OFS_PARM0);
1121 val = G_STRING(OFS_PARM1);
1122
1123 // change the string in sv
1124 sv.lightstyles[style] = val;
1125
1126 // send message to all clients on this server
1127 if (sv.state != ss_active)
1128 return;
1129
1130 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1131 if (client->active || client->spawned)
1132 {
1133 MSG_WriteChar (&client->message, svc_lightstyle);
1134 MSG_WriteChar (&client->message,style);
1135 MSG_WriteString (&client->message, val);
1136 }
1137 }
1138
PF_rint(void)1139 void PF_rint (void)
1140 {
1141 float f;
1142 f = G_FLOAT(OFS_PARM0);
1143 if (f > 0)
1144 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1145 else
1146 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1147 }
PF_floor(void)1148 void PF_floor (void)
1149 {
1150 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1151 }
PF_ceil(void)1152 void PF_ceil (void)
1153 {
1154 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1155 }
1156
1157
1158 /*
1159 =============
1160 PF_checkbottom
1161 =============
1162 */
PF_checkbottom(void)1163 void PF_checkbottom (void)
1164 {
1165 edict_t *ent;
1166
1167 ent = G_EDICT(OFS_PARM0);
1168
1169 G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent);
1170 }
1171
1172 /*
1173 =============
1174 PF_pointcontents
1175 =============
1176 */
PF_pointcontents(void)1177 void PF_pointcontents (void)
1178 {
1179 float *v;
1180
1181 v = G_VECTOR(OFS_PARM0);
1182
1183 G_FLOAT(OFS_RETURN) = SV_PointContents (v);
1184 }
1185
1186 /*
1187 =============
1188 PF_nextent
1189
1190 entity nextent(entity)
1191 =============
1192 */
PF_nextent(void)1193 void PF_nextent (void)
1194 {
1195 int i;
1196 edict_t *ent;
1197
1198 i = G_EDICTNUM(OFS_PARM0);
1199 while (1)
1200 {
1201 i++;
1202 if (i == sv.num_edicts)
1203 {
1204 RETURN_EDICT(sv.edicts);
1205 return;
1206 }
1207 ent = EDICT_NUM(i);
1208 if (!ent->free)
1209 {
1210 RETURN_EDICT(ent);
1211 return;
1212 }
1213 }
1214 }
1215
1216 /*
1217 =============
1218 PF_aim
1219
1220 Pick a vector for the player to shoot along
1221 vector aim(entity, missilespeed)
1222 =============
1223 */
1224 cvar_t sv_aim = {"sv_aim", "0.93"};
PF_aim(void)1225 void PF_aim (void)
1226 {
1227 edict_t *ent, *check, *bestent;
1228 vec3_t start, dir, end, bestdir;
1229 int i, j;
1230 trace_t tr;
1231 float dist, bestdist;
1232 float speed;
1233
1234 ent = G_EDICT(OFS_PARM0);
1235 speed = G_FLOAT(OFS_PARM1);
1236
1237 VectorCopy (ent->v.origin, start);
1238 start[2] += 20;
1239
1240 // try sending a trace straight
1241 VectorCopy (pr_global_struct->v_forward, dir);
1242 VectorMA (start, 2048, dir, end);
1243 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1244 if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM
1245 && (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) )
1246 {
1247 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1248 return;
1249 }
1250
1251
1252 // try all possible entities
1253 VectorCopy (dir, bestdir);
1254 bestdist = sv_aim.value;
1255 bestent = NULL;
1256
1257 check = NEXT_EDICT(sv.edicts);
1258 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1259 {
1260 if (check->v.takedamage != DAMAGE_AIM)
1261 continue;
1262 if (check == ent)
1263 continue;
1264 if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)
1265 continue; // don't aim at teammate
1266 for (j=0 ; j<3 ; j++)
1267 end[j] = check->v.origin[j]
1268 + 0.5*(check->v.mins[j] + check->v.maxs[j]);
1269 VectorSubtract (end, start, dir);
1270 VectorNormalize (dir);
1271 dist = DotProduct (dir, pr_global_struct->v_forward);
1272 if (dist < bestdist)
1273 continue; // to far to turn
1274 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1275 if (tr.ent == check)
1276 { // can shoot at this one
1277 bestdist = dist;
1278 bestent = check;
1279 }
1280 }
1281
1282 if (bestent)
1283 {
1284 VectorSubtract (bestent->v.origin, ent->v.origin, dir);
1285 dist = DotProduct (dir, pr_global_struct->v_forward);
1286 VectorScale (pr_global_struct->v_forward, dist, end);
1287 end[2] = dir[2];
1288 VectorNormalize (end);
1289 VectorCopy (end, G_VECTOR(OFS_RETURN));
1290 }
1291 else
1292 {
1293 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1294 }
1295 }
1296
1297 /*
1298 ==============
1299 PF_changeyaw
1300
1301 This was a major timewaster in progs, so it was converted to C
1302 ==============
1303 */
PF_changeyaw(void)1304 void PF_changeyaw (void)
1305 {
1306 edict_t *ent;
1307 float ideal, current, move, speed;
1308
1309 ent = PROG_TO_EDICT(pr_global_struct->self);
1310 current = anglemod( ent->v.angles[1] );
1311 ideal = ent->v.ideal_yaw;
1312 speed = ent->v.yaw_speed;
1313
1314 if (current == ideal)
1315 return;
1316 move = ideal - current;
1317 if (ideal > current)
1318 {
1319 if (move >= 180)
1320 move = move - 360;
1321 }
1322 else
1323 {
1324 if (move <= -180)
1325 move = move + 360;
1326 }
1327 if (move > 0)
1328 {
1329 if (move > speed)
1330 move = speed;
1331 }
1332 else
1333 {
1334 if (move < -speed)
1335 move = -speed;
1336 }
1337
1338 ent->v.angles[1] = anglemod (current + move);
1339 }
1340
1341 /*
1342 ===============================================================================
1343
1344 MESSAGE WRITING
1345
1346 ===============================================================================
1347 */
1348
1349 #define MSG_BROADCAST 0 // unreliable to all
1350 #define MSG_ONE 1 // reliable to one (msg_entity)
1351 #define MSG_ALL 2 // reliable to all
1352 #define MSG_INIT 3 // write to the init string
1353
WriteDest(void)1354 sizebuf_t *WriteDest (void)
1355 {
1356 int entnum;
1357 int dest;
1358 edict_t *ent;
1359
1360 dest = G_FLOAT(OFS_PARM0);
1361 switch (dest)
1362 {
1363 case MSG_BROADCAST:
1364 return &sv.datagram;
1365
1366 case MSG_ONE:
1367 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1368 entnum = NUM_FOR_EDICT(ent);
1369 if (entnum < 1 || entnum > svs.maxclients)
1370 PR_RunError ("WriteDest: not a client");
1371 return &svs.clients[entnum-1].message;
1372
1373 case MSG_ALL:
1374 return &sv.reliable_datagram;
1375
1376 case MSG_INIT:
1377 return &sv.signon;
1378
1379 default:
1380 PR_RunError ("WriteDest: bad destination");
1381 break;
1382 }
1383
1384 return NULL;
1385 }
1386
PF_WriteByte(void)1387 void PF_WriteByte (void)
1388 {
1389 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1390 }
1391
PF_WriteChar(void)1392 void PF_WriteChar (void)
1393 {
1394 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1395 }
1396
PF_WriteShort(void)1397 void PF_WriteShort (void)
1398 {
1399 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1400 }
1401
PF_WriteLong(void)1402 void PF_WriteLong (void)
1403 {
1404 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1405 }
1406
PF_WriteAngle(void)1407 void PF_WriteAngle (void)
1408 {
1409 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1410 }
1411
PF_WriteCoord(void)1412 void PF_WriteCoord (void)
1413 {
1414 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1415 }
1416
PF_WriteString(void)1417 void PF_WriteString (void)
1418 {
1419 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1420 }
1421
1422
PF_WriteEntity(void)1423 void PF_WriteEntity (void)
1424 {
1425 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1426 }
1427
1428 //=============================================================================
1429
1430 int SV_ModelIndex (char *name);
1431
PF_makestatic(void)1432 void PF_makestatic (void)
1433 {
1434 edict_t *ent;
1435 int i;
1436
1437 ent = G_EDICT(OFS_PARM0);
1438
1439 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1440
1441 MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model));
1442
1443 MSG_WriteByte (&sv.signon, ent->v.frame);
1444 MSG_WriteByte (&sv.signon, ent->v.colormap);
1445 MSG_WriteByte (&sv.signon, ent->v.skin);
1446 for (i=0 ; i<3 ; i++)
1447 {
1448 MSG_WriteCoord(&sv.signon, ent->v.origin[i]);
1449 MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
1450 }
1451
1452 // throw the entity away now
1453 ED_Free (ent);
1454 }
1455
1456 //=============================================================================
1457
1458 /*
1459 ==============
1460 PF_setspawnparms
1461 ==============
1462 */
PF_setspawnparms(void)1463 void PF_setspawnparms (void)
1464 {
1465 edict_t *ent;
1466 int i;
1467 client_t *client;
1468
1469 ent = G_EDICT(OFS_PARM0);
1470 i = NUM_FOR_EDICT(ent);
1471 if (i < 1 || i > svs.maxclients)
1472 PR_RunError ("Entity is not a client");
1473
1474 // copy spawn parms out of the client_t
1475 client = svs.clients + (i-1);
1476
1477 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1478 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1479 }
1480
1481 /*
1482 ==============
1483 PF_changelevel
1484 ==============
1485 */
PF_changelevel(void)1486 void PF_changelevel (void)
1487 {
1488 char *s;
1489
1490 // make sure we don't issue two changelevels
1491 if (svs.changelevel_issued)
1492 return;
1493 svs.changelevel_issued = true;
1494
1495 s = G_STRING(OFS_PARM0);
1496 Cbuf_AddText (va("changelevel %s\n",s));
1497 }
1498
1499
PF_Fixme(void)1500 void PF_Fixme (void)
1501 {
1502 PR_RunError ("unimplemented bulitin");
1503 }
1504
1505
1506
1507 builtin_t pr_builtin[] =
1508 {
1509 PF_Fixme,
1510 PF_makevectors, // void(entity e) makevectors = #1;
1511 PF_setorigin, // void(entity e, vector o) setorigin = #2;
1512 PF_setmodel, // void(entity e, string m) setmodel = #3;
1513 PF_setsize, // void(entity e, vector min, vector max) setsize = #4;
1514 PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5;
1515 PF_break, // void() break = #6;
1516 PF_random, // float() random = #7;
1517 PF_sound, // void(entity e, float chan, string samp) sound = #8;
1518 PF_normalize, // vector(vector v) normalize = #9;
1519 PF_error, // void(string e) error = #10;
1520 PF_objerror, // void(string e) objerror = #11;
1521 PF_vlen, // float(vector v) vlen = #12;
1522 PF_vectoyaw, // float(vector v) vectoyaw = #13;
1523 PF_Spawn, // entity() spawn = #14;
1524 PF_Remove, // void(entity e) remove = #15;
1525 PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16;
1526 PF_checkclient, // entity() clientlist = #17;
1527 PF_Find, // entity(entity start, .string fld, string match) find = #18;
1528 PF_precache_sound, // void(string s) precache_sound = #19;
1529 PF_precache_model, // void(string s) precache_model = #20;
1530 PF_stuffcmd, // void(entity client, string s)stuffcmd = #21;
1531 PF_findradius, // entity(vector org, float rad) findradius = #22;
1532 PF_bprint, // void(string s) bprint = #23;
1533 PF_sprint, // void(entity client, string s) sprint = #24;
1534 PF_dprint, // void(string s) dprint = #25;
1535 PF_ftos, // void(string s) ftos = #26;
1536 PF_vtos, // void(string s) vtos = #27;
1537 PF_coredump,
1538 PF_traceon,
1539 PF_traceoff,
1540 PF_eprint, // void(entity e) debug print an entire entity
1541 PF_walkmove, // float(float yaw, float dist) walkmove
1542 PF_Fixme, // float(float yaw, float dist) walkmove
1543 PF_droptofloor,
1544 PF_lightstyle,
1545 PF_rint,
1546 PF_floor,
1547 PF_ceil,
1548 PF_Fixme,
1549 PF_checkbottom,
1550 PF_pointcontents,
1551 PF_Fixme,
1552 PF_fabs,
1553 PF_aim,
1554 PF_cvar,
1555 PF_localcmd,
1556 PF_nextent,
1557 PF_particle,
1558 PF_changeyaw,
1559 PF_Fixme,
1560 PF_vectoangles,
1561
1562 PF_WriteByte,
1563 PF_WriteChar,
1564 PF_WriteShort,
1565 PF_WriteLong,
1566 PF_WriteCoord,
1567 PF_WriteAngle,
1568 PF_WriteString,
1569 PF_WriteEntity,
1570
1571 PF_Fixme,
1572 PF_Fixme,
1573 PF_Fixme,
1574 PF_Fixme,
1575 PF_Fixme,
1576 PF_Fixme,
1577 PF_Fixme,
1578
1579 SV_MoveToGoal,
1580 PF_precache_file,
1581 PF_makestatic,
1582
1583 PF_changelevel,
1584 PF_Fixme,
1585
1586 PF_cvar_set,
1587 PF_centerprint,
1588
1589 PF_ambientsound,
1590
1591 PF_precache_model,
1592 PF_precache_sound, // precache_sound2 is different only for qcc
1593 PF_precache_file,
1594
1595 PF_setspawnparms
1596 };
1597
1598 builtin_t *pr_builtins = pr_builtin;
1599 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
1600
1601