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 "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 34char *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================= 50PF_errror 51 52This is a TERMINAL error, which will kill off the entire server. 53Dumps self. 54 55error(value) 56================= 57*/ 58void 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================= 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", 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============== 99PF_makevectors 100 101Writes new values for v_forward, v_up, and v_right based on angles 102makevectors(vector) 103============== 104*/ 105void 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================= 112PF_setorigin 113 114This 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 116setorigin (entity, origin) 117================= 118*/ 119void 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================= 133PF_setsize 134 135the size box is rotated by the current angle 136 137setsize (entity, minvector, maxvector) 138================= 139*/ 140void 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================= 157PF_setmodel 158 159setmodel(entity, model) 160Also sets size, mins, and maxs for inline bmodels 161================= 162*/ 163void 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================= 198PF_bprint 199 200broadcast print to everyone on server 201 202bprint(value) 203================= 204*/ 205void 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================= 218PF_sprint 219 220single print to a specific client 221 222sprint(clientent, value) 223================= 224*/ 225void 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================= 251PF_centerprint 252 253single print to a specific client 254 255centerprint(clientent, value) 256================= 257*/ 258void 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================= 282PF_normalize 283 284vector normalize(vector) 285================= 286*/ 287void 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================= 313PF_vlen 314 315scalar vlen(vector) 316================= 317*/ 318void 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================= 333PF_vectoyaw 334 335float vectoyaw(vector) 336================= 337*/ 338void 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================= 360PF_vectoangles 361 362vector vectoangles(vector) 363================= 364*/ 365void 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================= 400PF_Random 401 402Returns a number from 0<= num < 1 403 404random() 405================= 406*/ 407void 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================= 419PF_ambientsound 420 421================= 422*/ 423void 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================= 462PF_sound 463 464Each entity can have eight independant sound sources, like voice, 465weapon, feet, etc. 466 467Channel 0 is an auto-allocate channel, the others override anything 468allready running on that entity/channel pair. 469 470An attenuation of 0 will play full volume everywhere in the level. 471Larger attenuations will drop off. 472 473================= 474*/ 475void 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================= 494PF_break 495 496break() 497================= 498*/ 499void PF_break (void) 500{ 501Con_Printf ("break statement\n"); 502*(int *)-4 = 0; // dump to debugger 503// PR_RunError ("break statement"); 504} 505 506/* 507================= 508PF_traceline 509 510Used for use tracing and shot targeting 511Traces are blocked by bbox and exact bsp entityes, and also slide box entities 512if the tryents flag is set. 513 514traceline (vector1, vector2, tryents) 515================= 516*/ 517void 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================= 547PF_checkpos 548 549Returns true if the given entity can move to the given position from it's 550current position by walking or rolling. 551FIXME: make work... 552scalar checkpos (entity, vector) 553================= 554*/ 555void PF_checkpos (void) 556{ 557} 558 559//============================================================================ 560 561byte checkpvs[MAX_MAP_LEAFS/8]; 562 563int 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================= 615PF_checkclient 616 617Returns a client (or object that has a client enemy) that would be a 618valid target. 619 620If there are more than one valid options, they are cycled each frame 621 622If (self.origin + self.viewofs) is not in the PVS of the current target, 623it is not returned at all. 624 625name checkclient () 626================= 627*/ 628#define MAX_CHECK 16 629int c_invis, c_notvis; 630void 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 { 659c_notvis++; 660 RETURN_EDICT(sv.edicts); 661 return; 662 } 663 664// might be able to see it 665c_invis++; 666 RETURN_EDICT(ent); 667} 668 669//============================================================================ 670 671 672/* 673================= 674PF_stuffcmd 675 676Sends text over to the client's execution buffer 677 678stuffcmd (clientent, value) 679================= 680*/ 681void 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================= 706PF_localcmd 707 708Sends text over to the client's execution buffer 709 710localcmd (string) 711================= 712*/ 713void PF_localcmd (void) 714{ 715 char *str; 716 717 str = G_STRING(OFS_PARM0); 718 Cbuf_AddText (str); 719} 720 721/* 722================= 723PF_cvar 724 725float cvar (string) 726================= 727*/ 728void 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================= 739PF_cvar_set 740 741float cvar (string) 742================= 743*/ 744void 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================= 756PF_findradius 757 758Returns a chain of entities that have origins within a spherical area 759 760findradius (origin, radius) 761================= 762*/ 763void 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========= 798PF_dprint 799========= 800*/ 801void PF_dprint (void) 802{ 803 Con_Printf ("%s",PF_VarString(0)); 804} 805 806char pr_string_temp[128]; 807 808void 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 820void PF_fabs (void) 821{ 822 float v; 823 v = G_FLOAT(OFS_PARM0); 824 G_FLOAT(OFS_RETURN) = fabs(v); 825} 826 827void 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 833void PF_Spawn (void) 834{ 835 edict_t *ed; 836 ed = ED_Alloc(); 837 RETURN_EDICT(ed); 838} 839 840void 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; 850void 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 881void PR_CheckEmptyString (char *s) 882{ 883 if (s[0] <= ' ') 884 PR_RunError ("Bad string"); 885} 886 887void 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 892void 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 917void 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 943void PF_coredump (void) 944{ 945 ED_PrintEdicts (); 946} 947 948void PF_traceon (void) 949{ 950 pr_trace = true; 951} 952 953void PF_traceoff (void) 954{ 955 pr_trace = false; 956} 957 958void PF_eprint (void) 959{ 960 ED_PrintNum (G_EDICTNUM(OFS_PARM0)); 961} 962 963/* 964=============== 965PF_walkmove 966 967float(float yaw, float dist) walkmove 968=============== 969*/ 970void 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=============== 1008PF_droptofloor 1009 1010void() droptofloor 1011=============== 1012*/ 1013void 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=============== 1040PF_lightstyle 1041 1042void(float style, string value) lightstyle 1043=============== 1044*/ 1045void 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 1071void 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} 1080void PF_floor (void) 1081{ 1082 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0)); 1083} 1084void PF_ceil (void) 1085{ 1086 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0)); 1087} 1088 1089 1090/* 1091============= 1092PF_checkbottom 1093============= 1094*/ 1095void 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============= 1106PF_pointcontents 1107============= 1108*/ 1109void 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============= 1120PF_nextent 1121 1122entity nextent(entity) 1123============= 1124*/ 1125void 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============= 1150PF_aim 1151 1152Pick a vector for the player to shoot along 1153vector aim(entity, missilespeed) 1154============= 1155*/ 1156//cvar_t sv_aim = {"sv_aim", "0.93"}; 1157cvar_t sv_aim = {"sv_aim", "2"}; 1158void 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============== 1245PF_changeyaw 1246 1247This was a major timewaster in progs, so it was converted to C 1248============== 1249*/ 1250void 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 1290MESSAGE 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 1301sizebuf_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 1342static 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 1355void 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 1365void 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 1375void 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 1385void 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 1395void 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 1405void 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 1415void 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 1426void 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 1438int SV_ModelIndex (char *name); 1439 1440void 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============== 1468PF_setspawnparms 1469============== 1470*/ 1471void 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============== 1491PF_changelevel 1492============== 1493*/ 1494void 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============== 1511PF_logfrag 1512 1513logfrag (killer, killee) 1514============== 1515*/ 1516void 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============== 1544PF_infokey 1545 1546string(entity e, string key) infokey 1547============== 1548*/ 1549void 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============== 1582PF_stof 1583 1584float(string s) stof 1585============== 1586*/ 1587void 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============== 1599PF_multicast 1600 1601void(vector where, float set) multicast 1602============== 1603*/ 1604void 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 1616void PF_Fixme (void) 1617{ 1618 PR_RunError ("unimplemented bulitin"); 1619} 1620 1621 1622 1623builtin_t pr_builtin[] = 1624{ 1625 PF_Fixme, 1626PF_makevectors, // void(entity e) makevectors = #1; 1627PF_setorigin, // void(entity e, vector o) setorigin = #2; 1628PF_setmodel, // void(entity e, string m) setmodel = #3; 1629PF_setsize, // void(entity e, vector min, vector max) setsize = #4; 1630PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5; 1631PF_break, // void() break = #6; 1632PF_random, // float() random = #7; 1633PF_sound, // void(entity e, float chan, string samp) sound = #8; 1634PF_normalize, // vector(vector v) normalize = #9; 1635PF_error, // void(string e) error = #10; 1636PF_objerror, // void(string e) objerror = #11; 1637PF_vlen, // float(vector v) vlen = #12; 1638PF_vectoyaw, // float(vector v) vectoyaw = #13; 1639PF_Spawn, // entity() spawn = #14; 1640PF_Remove, // void(entity e) remove = #15; 1641PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16; 1642PF_checkclient, // entity() clientlist = #17; 1643PF_Find, // entity(entity start, .string fld, string match) find = #18; 1644PF_precache_sound, // void(string s) precache_sound = #19; 1645PF_precache_model, // void(string s) precache_model = #20; 1646PF_stuffcmd, // void(entity client, string s)stuffcmd = #21; 1647PF_findradius, // entity(vector org, float rad) findradius = #22; 1648PF_bprint, // void(string s) bprint = #23; 1649PF_sprint, // void(entity client, string s) sprint = #24; 1650PF_dprint, // void(string s) dprint = #25; 1651PF_ftos, // void(string s) ftos = #26; 1652PF_vtos, // void(string s) vtos = #27; 1653PF_coredump, 1654PF_traceon, 1655PF_traceoff, 1656PF_eprint, // void(entity e) debug print an entire entity 1657PF_walkmove, // float(float yaw, float dist) walkmove 1658PF_Fixme, // float(float yaw, float dist) walkmove 1659PF_droptofloor, 1660PF_lightstyle, 1661PF_rint, 1662PF_floor, 1663PF_ceil, 1664PF_Fixme, 1665PF_checkbottom, 1666PF_pointcontents, 1667PF_Fixme, 1668PF_fabs, 1669PF_aim, 1670PF_cvar, 1671PF_localcmd, 1672PF_nextent, 1673PF_Fixme, 1674PF_changeyaw, 1675PF_Fixme, 1676PF_vectoangles, 1677 1678PF_WriteByte, 1679PF_WriteChar, 1680PF_WriteShort, 1681PF_WriteLong, 1682PF_WriteCoord, 1683PF_WriteAngle, 1684PF_WriteString, 1685PF_WriteEntity, 1686 1687PF_Fixme, 1688PF_Fixme, 1689PF_Fixme, 1690PF_Fixme, 1691PF_Fixme, 1692PF_Fixme, 1693PF_Fixme, 1694 1695SV_MoveToGoal, 1696PF_precache_file, 1697PF_makestatic, 1698 1699PF_changelevel, 1700PF_Fixme, 1701 1702PF_cvar_set, 1703PF_centerprint, 1704 1705PF_ambientsound, 1706 1707PF_precache_model, 1708PF_precache_sound, // precache_sound2 is different only for qcc 1709PF_precache_file, 1710 1711PF_setspawnparms, 1712 1713PF_logfrag, 1714 1715PF_infokey, 1716PF_stof, 1717PF_multicast 1718}; 1719 1720builtin_t *pr_builtins = pr_builtin; 1721int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]); 1722 1723