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