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