1 /*
2 pr_cmds.c
3
4 (description)
5
6 Copyright (C) 1996-1997 Id Software, Inc.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to:
21
22 Free Software Foundation, Inc.
23 59 Temple Place - Suite 330
24 Boston, MA 02111-1307, USA
25
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_ERRNO_H
32 # include <errno.h>
33 #endif
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #endif
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif
40
41 #include <stdlib.h>
42
43 #include "QF/cvar.h"
44 #include "QF/dstring.h"
45 #include "QF/mathlib.h"
46 #include "QF/progs.h"
47 #include "QF/sys.h"
48 #include "QF/zone.h"
49
50 #include "compat.h"
51
52 VISIBLE const char *pr_gametype = "";
53
54 /* BUILT-IN FUNCTIONS */
55
56 VISIBLE char *
PF_VarString(progs_t * pr,int first)57 PF_VarString (progs_t *pr, int first)
58 {
59 char *out, *dst;
60 const char *src;
61 int len, i;
62
63 for (len = 0, i = first; i < pr->pr_argc; i++)
64 len += strlen (P_GSTRING (pr, i));
65 dst = out = Hunk_TempAlloc (len + 1);
66 for (i = first; i < pr->pr_argc; i++) {
67 src = P_GSTRING (pr, i);
68 while (*src)
69 *dst++ = *src++;
70 }
71 *dst = 0;
72 return out;
73 }
74
75 /*
76 vector (vector v) normalize
77 */
78 static void
PF_normalize(progs_t * pr)79 PF_normalize (progs_t *pr)
80 {
81 float new;
82 float *value1;
83 vec3_t newvalue;
84
85 value1 = P_VECTOR (pr, 0);
86
87 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2] *
88 value1[2];
89 new = sqrt (new);
90
91 if (new == 0)
92 newvalue[0] = newvalue[1] = newvalue[2] = 0;
93 else {
94 new = 1 / new;
95 newvalue[0] = value1[0] * new;
96 newvalue[1] = value1[1] * new;
97 newvalue[2] = value1[2] * new;
98 }
99
100 VectorCopy (newvalue, R_VECTOR (pr));
101 }
102
103 /*
104 float (vector v) vlen
105 */
106 static void
PF_vlen(progs_t * pr)107 PF_vlen (progs_t *pr)
108 {
109 float new;
110 float *value1;
111
112 value1 = P_VECTOR (pr, 0);
113
114 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2] *
115 value1[2];
116 new = sqrt (new);
117
118 R_FLOAT (pr) = new;
119 }
120
121 /*
122 float (vector v) vectoyaw
123 */
124 static void
PF_vectoyaw(progs_t * pr)125 PF_vectoyaw (progs_t *pr)
126 {
127 float yaw;
128 float *value1;
129
130 value1 = P_VECTOR (pr, 0);
131
132 if (value1[1] == 0 && value1[0] == 0)
133 yaw = 0;
134 else {
135 yaw = (int) (atan2 (value1[1], value1[0]) * 180 / M_PI);
136 if (yaw < 0)
137 yaw += 360;
138 }
139
140 R_FLOAT (pr) = yaw;
141 }
142
143 /*
144 vector (vector v) vectoangles
145 */
146 static void
PF_vectoangles(progs_t * pr)147 PF_vectoangles (progs_t *pr)
148 {
149 float forward, pitch, yaw;
150 float *value1;
151
152 value1 = P_VECTOR (pr, 0);
153
154 if (value1[1] == 0 && value1[0] == 0) {
155 yaw = 0;
156 if (value1[2] > 0)
157 pitch = 90;
158 else
159 pitch = 270;
160 } else {
161 yaw = (int) (atan2 (value1[1], value1[0]) * 180 / M_PI);
162 if (yaw < 0)
163 yaw += 360;
164
165 forward = sqrt (value1[0] * value1[0] + value1[1] * value1[1]);
166 pitch = (int) (atan2 (value1[2], forward) * 180 / M_PI);
167 if (pitch < 0)
168 pitch += 360;
169 }
170
171 R_VECTOR (pr)[0] = pitch;
172 R_VECTOR (pr)[1] = yaw;
173 R_VECTOR (pr)[2] = 0;
174 }
175
176 /*
177 float () random
178
179 Returns a number from 0<= num < 1
180 */
181 static void
PF_random(progs_t * pr)182 PF_random (progs_t *pr)
183 {
184 float num;
185
186 num = (rand () & 0x7fff) / ((float) 0x7fff);
187
188 R_FLOAT (pr) = num;
189 }
190
191 /*
192 void () break
193 */
194 static void
PF_break(progs_t * pr)195 PF_break (progs_t *pr)
196 {
197 Sys_Printf ("break statement\n");
198 PR_DumpState (pr);
199 }
200
201 /*
202 float (string s) cvar
203 */
204 static void
PF_cvar(progs_t * pr)205 PF_cvar (progs_t *pr)
206 {
207 const char *str;
208
209 str = P_GSTRING (pr, 0);
210
211 R_FLOAT (pr) = Cvar_VariableValue (str);
212 }
213
214 /*
215 void (string var, string val) cvar_set
216 */
217 static void
PF_cvar_set(progs_t * pr)218 PF_cvar_set (progs_t *pr)
219 {
220 const char *var_name, *val;
221 cvar_t *var;
222
223 var_name = P_GSTRING (pr, 0);
224 val = P_GSTRING (pr, 1);
225 var = Cvar_FindVar (var_name);
226 if (!var)
227 var = Cvar_FindAlias (var_name);
228 if (!var) {
229 Sys_Printf ("PF_cvar_set: variable %s not found\n", var_name);
230 return;
231 }
232
233 Cvar_Set (var, val);
234 }
235
236 /*
237 float (float f) fabs
238 */
239 static void
PF_fabs(progs_t * pr)240 PF_fabs (progs_t *pr)
241 {
242 float v;
243
244 v = P_FLOAT (pr, 0);
245 R_FLOAT (pr) = fabs (v);
246 }
247
248 /*
249 entity (entity start, .(...) fld, ... match) find
250 */
251 static void
PF_Find(progs_t * pr)252 PF_Find (progs_t *pr)
253 {
254 const char *s = 0, *t; // ev_string
255 int i; // ev_vector
256 int e, f;
257 etype_t type;
258 ddef_t *field_def;
259 edict_t *ed;
260
261 e = P_EDICTNUM (pr, 0);
262 f = P_INT (pr, 1);
263 field_def = PR_FieldAtOfs (pr, f);
264 if (!field_def)
265 PR_RunError (pr, "PF_Find: bad search field: %d", f);
266 type = field_def->type & ~DEF_SAVEGLOBAL;
267
268 if (type == ev_string) {
269 s = P_GSTRING (pr, 2);
270 if (!s)
271 PR_RunError (pr, "PF_Find: bad search string");
272 }
273
274 for (e++; e < *pr->num_edicts; e++) {
275 ed = EDICT_NUM (pr, e);
276 if (ed->free)
277 continue;
278 switch (type) {
279 case ev_string:
280 t = E_GSTRING (pr, ed, f);
281 if (!t)
282 continue;
283 if (strcmp (t, s))
284 continue;
285 RETURN_EDICT (pr, ed);
286 return;
287 case ev_float:
288 if (P_FLOAT (pr, 2) != E_FLOAT (ed, f))
289 continue;
290 RETURN_EDICT (pr, ed);
291 return;
292 case ev_vector:
293 for (i = 0; i <= 2; i++)
294 if (P_FLOAT (pr, 2 + i) != E_FLOAT (ed, f + i))
295 continue;
296 RETURN_EDICT (pr, ed);
297 return;
298 case ev_integer:
299 case ev_entity:
300 if (P_INT (pr, 2) != E_INT (ed, f))
301 continue;
302 RETURN_EDICT (pr, ed);
303 return;
304 default:
305 PR_Error (pr, "PF_Find: unsupported search field");
306 }
307 }
308
309 RETURN_EDICT (pr, *pr->edicts);
310 }
311
312 /*
313 void () coredump
314 */
315 static void
PF_coredump(progs_t * pr)316 PF_coredump (progs_t *pr)
317 {
318 ED_PrintEdicts (pr, "");
319 }
320
321 /*
322 void () traceon
323 */
324 static void
PF_traceon(progs_t * pr)325 PF_traceon (progs_t *pr)
326 {
327 pr->pr_trace = true;
328 pr->pr_trace_depth = pr->pr_depth;
329 }
330
331 /*
332 void () traceoff
333 */
334 static void
PF_traceoff(progs_t * pr)335 PF_traceoff (progs_t *pr)
336 {
337 pr->pr_trace = false;
338 }
339
340 /*
341 void (entity e) eprint
342 */
343 static void
PF_eprint(progs_t * pr)344 PF_eprint (progs_t *pr)
345 {
346 ED_PrintNum (pr, P_EDICTNUM (pr, 0));
347 }
348
349 /*
350 void (string s) dprint
351 */
352 static void
PF_dprint(progs_t * pr)353 PF_dprint (progs_t *pr)
354 {
355 Sys_Printf ("%s", PF_VarString (pr, 0));
356 }
357
358 /*
359 float (float v) rint
360 */
361 static void
PF_rint(progs_t * pr)362 PF_rint (progs_t *pr)
363 {
364 float f;
365
366 f = P_FLOAT (pr, 0);
367 if (f > 0)
368 R_FLOAT (pr) = (int) (f + 0.5);
369 else
370 R_FLOAT (pr) = (int) (f - 0.5);
371 }
372
373 /*
374 float (float v) floor
375 */
376 static void
PF_floor(progs_t * pr)377 PF_floor (progs_t *pr)
378 {
379 R_FLOAT (pr) = floor (P_FLOAT (pr, 0));
380 }
381
382 /*
383 float (float v) ceil
384 */
385 static void
PF_ceil(progs_t * pr)386 PF_ceil (progs_t *pr)
387 {
388 R_FLOAT (pr) = ceil (P_FLOAT (pr, 0));
389 }
390
391 /*
392 entity (entity e) nextent
393 */
394 static void
PF_nextent(progs_t * pr)395 PF_nextent (progs_t *pr)
396 {
397 int i;
398 edict_t *ent;
399
400 i = P_EDICTNUM (pr, 0);
401 while (1) {
402 i++;
403 if (i == *pr->num_edicts) {
404 RETURN_EDICT (pr, *pr->edicts);
405 return;
406 }
407 ent = EDICT_NUM (pr, i);
408 if (!ent->free) {
409 RETURN_EDICT (pr, ent);
410 return;
411 }
412 }
413 }
414
415 // we assume that ints are smaller than floats
416 #ifdef FLT_MAX_10_EXP
417 # define STRING_BUF (FLT_MAX_10_EXP + 8)
418 #else
419 # define STRING_BUF 128
420 #endif
421
422 /*
423 integer (float f) ftoi
424 */
425 static void
PF_ftoi(progs_t * pr)426 PF_ftoi (progs_t *pr)
427 {
428 R_INT (pr) = P_FLOAT (pr, 0);
429 }
430
431 /*
432 string (float f) ftos
433 */
434 static void
PF_ftos(progs_t * pr)435 PF_ftos (progs_t *pr)
436 {
437 char string[STRING_BUF];
438 int i;
439
440 // trimming 0s idea thanks to Maddes
441 i = snprintf (string, sizeof (string), "%1.6f", P_FLOAT (pr, 0)) - 1;
442 for (; i > 0; i--) {
443 if (string[i] == '0')
444 string[i] = '\0';
445 else if (string[i] == '.') {
446 string[i] = '\0';
447 break;
448 } else
449 break;
450 }
451
452 RETURN_STRING (pr, string);
453 }
454
455 /*
456 float (integer i) itof
457 */
458 static void
PF_itof(progs_t * pr)459 PF_itof (progs_t *pr)
460 {
461 R_FLOAT (pr) = P_INT (pr, 0);
462 }
463
464 /*
465 string (integer i) itos
466 */
467 static void
PF_itos(progs_t * pr)468 PF_itos (progs_t *pr)
469 {
470 char string[STRING_BUF];
471
472 snprintf (string, sizeof (string), "%d", P_INT (pr, 0));
473
474 RETURN_STRING (pr, string);
475 }
476
477 /*
478 float (string s) stof
479 */
480 static void
PF_stof(progs_t * pr)481 PF_stof (progs_t *pr)
482 {
483 R_FLOAT (pr) = atof (P_GSTRING (pr, 0));
484 }
485
486 /*
487 integer (string s) stoi
488 */
489 static void
PF_stoi(progs_t * pr)490 PF_stoi (progs_t *pr)
491 {
492 R_INT (pr) = atoi (P_GSTRING (pr, 0));
493 }
494
495 /*
496 vector (string s) stov
497 */
498 static void
PF_stov(progs_t * pr)499 PF_stov (progs_t *pr)
500 {
501 float v[3] = {0, 0, 0};
502
503 sscanf (P_GSTRING (pr, 0), "'%f %f %f'", v, v + 1, v + 2);
504
505 RETURN_VECTOR (pr, v);
506 }
507
508 /*
509 string (vector v) vtos
510 */
511 static void
PF_vtos(progs_t * pr)512 PF_vtos (progs_t *pr)
513 {
514 char string[STRING_BUF * 3 + 5];
515
516 snprintf (string, sizeof (string), "'%5.1f %5.1f %5.1f'",
517 P_VECTOR (pr, 0)[0],
518 P_VECTOR (pr, 0)[1],
519 P_VECTOR (pr, 0)[2]);
520
521 RETURN_STRING (pr, string);
522 }
523
524 /*
525 float (string s) strlen
526 */
527 static void
PF_strlen(progs_t * pr)528 PF_strlen (progs_t *pr)
529 {
530 const char *s;
531
532 s = P_GSTRING (pr, 0);
533 R_FLOAT (pr) = strlen(s);
534 }
535
536 /*
537 float (string char, string s) charcount
538 */
539 static void
PF_charcount(progs_t * pr)540 PF_charcount (progs_t *pr)
541 {
542 char goal;
543 const char *s;
544 int count;
545
546 goal = (P_GSTRING (pr, 0))[0];
547 if (goal == '\0') {
548 R_FLOAT (pr) = 0;
549 return;
550 }
551
552 count = 0;
553 s = P_GSTRING (pr, 1);
554 while (*s) {
555 if (*s == goal)
556 count++;
557 s++;
558 }
559 R_FLOAT (pr) = count;
560 }
561
562 #if (INT_MAX == 2147483647) && (INT_MIN == -2147483648)
563 # define INT_WIDTH 11
564 #else /* I hope... */
565 # define INT_WIDTH 20
566 #endif
567
568 #define MAX_ARG 7
569 /*
570 string (...) sprintf
571 */
572 static void
PF_sprintf(progs_t * pr)573 PF_sprintf (progs_t *pr)
574 {
575 const char *fmt = P_GSTRING (pr, 0);
576 int count = pr->pr_argc - 1;
577 pr_type_t **args = pr->pr_params + 1;
578 dstring_t *dstr;
579
580 dstr = dstring_newstr ();
581 PR_Sprintf (pr, dstr, "PF_sprintf", fmt, count, args);
582 RETURN_STRING (pr, dstr->str);
583 dstring_delete (dstr);
584 }
585
586 /*
587 string () gametype
588 */
589 static void
PR_gametype(progs_t * pr)590 PR_gametype (progs_t *pr)
591 {
592 RETURN_STRING (pr, pr_gametype);
593 }
594
595 static void
PF_PR_SetField(progs_t * pr)596 PF_PR_SetField (progs_t *pr)
597 {
598 edict_t *ent = P_EDICT (pr, 0);
599 ddef_t *field = PR_FindField (pr, P_GSTRING (pr, 1));
600 const char *value = P_GSTRING (pr, 2);
601
602 R_INT (pr) = 0;
603 if (field)
604 R_INT (pr) = ED_ParseEpair (pr, ent->v, field, value);
605 }
606
607 static void
PF_PR_FindFunction(progs_t * pr)608 PF_PR_FindFunction (progs_t *pr)
609 {
610 dfunction_t *func = PR_FindFunction (pr, P_GSTRING (pr, 0));
611 R_FUNCTION (pr) = 0;
612 if (func)
613 R_FUNCTION (pr) = func - pr->pr_functions;
614 }
615
616 #define QF (PR_RANGE_QF << PR_RANGE_SHIFT) |
617
618 static builtin_t builtins[] = {
619 {"break", PF_break, 6},
620 {"random", PF_random, 7},
621 {"normalize", PF_normalize, 9},
622 {"vlen", PF_vlen, 12},
623 {"vectoyaw", PF_vectoyaw, 13},
624 {"find", PF_Find, 18},
625 {"dprint", PF_dprint, 25},
626 {"ftos", PF_ftos, 26},
627 {"vtos", PF_vtos, 27},
628 {"coredump", PF_coredump, 28},
629 {"traceon", PF_traceon, 29},
630 {"traceoff", PF_traceoff, 30},
631 {"eprint", PF_eprint, 31},
632 {"rint", PF_rint, 36},
633 {"floor", PF_floor, 37},
634 {"ceil", PF_ceil, 38},
635 {"fabs", PF_fabs, 43},
636 {"cvar", PF_cvar, 45},
637 {"nextent", PF_nextent, 47},
638 {"vectoangles", PF_vectoangles, 51},
639 {"cvar_set", PF_cvar_set, 72},
640 {"stof", PF_stof, 81},
641
642
643 {"strlen", PF_strlen, QF 100},
644 {"charcount", PF_charcount, QF 101},
645 {"sprintf", PF_sprintf, QF 109},
646 {"ftoi", PF_ftoi, QF 110},
647 {"itof", PF_itof, QF 111},
648 {"itos", PF_itos, QF 112},
649 {"stoi", PF_stoi, QF 113},
650 {"stov", PF_stov, QF 114},
651 {"gametype", PR_gametype, QF 115},
652
653 {"PR_SetField", PF_PR_SetField, -1},
654 {"PR_FindFunction", PF_PR_FindFunction, -1},
655 {0}
656 };
657
658 VISIBLE void
PR_Cmds_Init(progs_t * pr)659 PR_Cmds_Init (progs_t *pr)
660 {
661 PR_RegisterBuiltins (pr, builtins);
662 }
663