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