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